1 /* 2 * Copyright 2009, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define LOG_TAG "webcoreglue" 27 28 #include "config.h" 29 30 #include "BackForwardList.h" 31 #include "ChromeClientAndroid.h" 32 #include "ContextMenuClientAndroid.h" 33 #include "CookieClient.h" 34 #include "DeviceMotionClientAndroid.h" 35 #include "DeviceOrientationClientAndroid.h" 36 #include "DragClientAndroid.h" 37 #include "EditorClientAndroid.h" 38 #include "FocusController.h" 39 #include "Frame.h" 40 #include "FrameLoader.h" 41 #include "FrameLoaderClientAndroid.h" 42 #include "FrameView.h" 43 #include "GraphicsContext.h" 44 #include "HistoryItem.h" 45 #include "InspectorClientAndroid.h" 46 #include "IntRect.h" 47 #include "JavaSharedClient.h" 48 #include "Page.h" 49 #include "PlatformGraphicsContext.h" 50 #include "ResourceRequest.h" 51 #include "ScriptController.h" 52 #include "SecurityOrigin.h" 53 #include "SelectionController.h" 54 #include "Settings.h" 55 #include "SharedBuffer.h" 56 #include "SkBitmap.h" 57 #include "SkCanvas.h" 58 #include "SkImageEncoder.h" 59 #include "SubstituteData.h" 60 #include "TimerClient.h" 61 #include "TextEncoding.h" 62 #include "WebCoreViewBridge.h" 63 #include "WebFrameView.h" 64 #include "WebViewCore.h" 65 #include "benchmark/Intercept.h" 66 #include "benchmark/MyJavaVM.h" 67 68 #include <JNIUtility.h> 69 #include <jni.h> 70 #include <utils/Log.h> 71 72 #define EXPORT __attribute__((visibility("default"))) 73 74 namespace android { 75 76 extern int registerWebFrame(JNIEnv*); 77 extern int registerJavaBridge(JNIEnv*); 78 extern int registerJniUtil(JNIEnv*); 79 extern int registerResourceLoader(JNIEnv*); 80 extern int registerWebViewCore(JNIEnv*); 81 extern int registerWebHistory(JNIEnv*); 82 extern int registerWebIconDatabase(JNIEnv*); 83 extern int registerWebSettings(JNIEnv*); 84 extern int registerWebView(JNIEnv*); 85 extern int registerViewStateSerializer(JNIEnv*); 86 #if ENABLE(DATABASE) 87 extern int registerWebStorage(JNIEnv*); 88 #endif 89 extern int registerGeolocationPermissions(JNIEnv*); 90 extern int registerMockGeolocation(JNIEnv*); 91 #if ENABLE(VIDEO) 92 extern int registerMediaPlayerAudio(JNIEnv*); 93 extern int registerMediaPlayerVideo(JNIEnv*); 94 #endif 95 extern int registerDeviceMotionAndOrientationManager(JNIEnv*); 96 extern int registerCookieManager(JNIEnv*); 97 #if USE(CHROME_NETWORK_STACK) 98 extern int registerCacheManager(JNIEnv*); 99 #endif 100 101 } 102 103 struct RegistrationMethod { 104 const char* name; 105 int (*func)(JNIEnv*); 106 }; 107 108 static RegistrationMethod gWebCoreRegMethods[] = { 109 { "JavaBridge", android::registerJavaBridge }, 110 { "JniUtil", android::registerJniUtil }, 111 { "WebFrame", android::registerWebFrame }, 112 { "WebCoreResourceLoader", android::registerResourceLoader }, 113 { "WebViewCore", android::registerWebViewCore }, 114 { "WebHistory", android::registerWebHistory }, 115 { "WebIconDatabase", android::registerWebIconDatabase }, 116 { "WebSettings", android::registerWebSettings }, 117 #if ENABLE(DATABASE) 118 { "WebStorage", android::registerWebStorage }, 119 #endif 120 { "WebView", android::registerWebView }, 121 { "ViewStateSerializer", android::registerViewStateSerializer }, 122 { "GeolocationPermissions", android::registerGeolocationPermissions }, 123 { "MockGeolocation", android::registerMockGeolocation }, 124 #if ENABLE(VIDEO) 125 { "HTML5Audio", android::registerMediaPlayerAudio }, 126 { "HTML5VideoViewProxy", android::registerMediaPlayerVideo }, 127 #endif 128 { "DeviceMotionAndOrientationManager", android::registerDeviceMotionAndOrientationManager }, 129 { "CookieManager", android::registerCookieManager }, 130 #if USE(CHROME_NETWORK_STACK) 131 { "CacheManager", android::registerCacheManager }, 132 #endif 133 }; 134 135 EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) 136 { 137 // Save the JavaVM pointer for use globally. 138 JSC::Bindings::setJavaVM(vm); 139 140 JNIEnv* env = NULL; 141 jint result = -1; 142 143 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 144 LOGE("GetEnv failed!"); 145 return result; 146 } 147 LOG_ASSERT(env, "Could not retrieve the env!"); 148 149 const RegistrationMethod* method = gWebCoreRegMethods; 150 const RegistrationMethod* end = method + sizeof(gWebCoreRegMethods)/sizeof(RegistrationMethod); 151 while (method != end) { 152 if (method->func(env) < 0) { 153 LOGE("%s registration failed!", method->name); 154 return result; 155 } 156 method++; 157 } 158 159 // Initialize rand() function. The rand() function is used in 160 // FileSystemAndroid to create a random temporary filename. 161 srand(time(NULL)); 162 163 return JNI_VERSION_1_4; 164 } 165 166 class MyJavaSharedClient : public TimerClient, public CookieClient { 167 public: 168 MyJavaSharedClient() : m_hasTimer(false) {} 169 virtual void setSharedTimer(long long timemillis) { m_hasTimer = true; } 170 virtual void stopSharedTimer() { m_hasTimer = false; } 171 virtual void setSharedTimerCallback(void (*f)()) { m_func = f; } 172 virtual void signalServiceFuncPtrQueue() {} 173 174 // Cookie methods that do nothing. 175 virtual void setCookies(const KURL&, const String&) {} 176 virtual String cookies(const KURL&) { return ""; } 177 virtual bool cookiesEnabled() { return false; } 178 179 bool m_hasTimer; 180 void (*m_func)(); 181 }; 182 183 static void historyItemChanged(HistoryItem* i) { 184 if (i->bridge()) 185 i->bridge()->updateHistoryItem(i); 186 } 187 188 namespace android { 189 190 EXPORT void benchmark(const char* url, int reloadCount, int width, int height) { 191 ScriptController::initializeThreading(); 192 193 // Setting this allows data: urls to load from a local file. 194 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll); 195 196 // Create the fake JNIEnv and JavaVM 197 InitializeJavaVM(); 198 199 // The real function is private to libwebcore but we know what it does. 200 notifyHistoryItemChanged = historyItemChanged; 201 202 // Implement the shared timer callback 203 MyJavaSharedClient client; 204 JavaSharedClient::SetTimerClient(&client); 205 JavaSharedClient::SetCookieClient(&client); 206 207 // Create the page with all the various clients 208 ChromeClientAndroid* chrome = new ChromeClientAndroid; 209 EditorClientAndroid* editor = new EditorClientAndroid; 210 DeviceMotionClientAndroid* deviceMotion = new DeviceMotionClientAndroid; 211 DeviceOrientationClientAndroid* deviceOrientation = new DeviceOrientationClientAndroid; 212 WebCore::Page::PageClients pageClients; 213 pageClients.chromeClient = chrome; 214 pageClients.contextMenuClient = new ContextMenuClientAndroid; 215 pageClients.editorClient = editor; 216 pageClients.dragClient = new DragClientAndroid; 217 pageClients.inspectorClient = new InspectorClientAndroid; 218 pageClients.deviceMotionClient = deviceMotion; 219 pageClients.deviceOrientationClient = deviceOrientation; 220 WebCore::Page* page = new WebCore::Page(pageClients); 221 editor->setPage(page); 222 223 // Create MyWebFrame that intercepts network requests 224 MyWebFrame* webFrame = new MyWebFrame(page); 225 webFrame->setUserAgent("Performance testing"); // needs to be non-empty 226 chrome->setWebFrame(webFrame); 227 // ChromeClientAndroid maintains the reference. 228 Release(webFrame); 229 230 // Create the Frame and the FrameLoaderClient 231 FrameLoaderClientAndroid* loader = new FrameLoaderClientAndroid(webFrame); 232 RefPtr<Frame> frame = Frame::create(page, NULL, loader); 233 loader->setFrame(frame.get()); 234 235 // Build our View system, resize it to the given dimensions and release our 236 // references. Note: We keep a referenec to frameView so we can layout and 237 // draw later without risk of it being deleted. 238 WebViewCore* webViewCore = new WebViewCore(JSC::Bindings::getJNIEnv(), 239 MY_JOBJECT, frame.get()); 240 RefPtr<FrameView> frameView = FrameView::create(frame.get()); 241 WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); 242 frame->setView(frameView); 243 frameView->resize(width, height); 244 Release(webViewCore); 245 Release(webFrameView); 246 247 // Initialize the frame and turn of low-bandwidth display (it fails an 248 // assertion in the Cache code) 249 frame->init(); 250 frame->selection()->setFocused(true); 251 frame->page()->focusController()->setFocused(true); 252 253 deviceMotion->setWebViewCore(webViewCore); 254 deviceOrientation->setWebViewCore(webViewCore); 255 256 // Set all the default settings the Browser normally uses. 257 Settings* s = frame->settings(); 258 #ifdef ANDROID_LAYOUT 259 s->setLayoutAlgorithm(Settings::kLayoutNormal); // Normal layout for now 260 #endif 261 s->setStandardFontFamily("sans-serif"); 262 s->setFixedFontFamily("monospace"); 263 s->setSansSerifFontFamily("sans-serif"); 264 s->setSerifFontFamily("serif"); 265 s->setCursiveFontFamily("cursive"); 266 s->setFantasyFontFamily("fantasy"); 267 s->setMinimumFontSize(8); 268 s->setMinimumLogicalFontSize(8); 269 s->setDefaultFontSize(16); 270 s->setDefaultFixedFontSize(13); 271 s->setLoadsImagesAutomatically(true); 272 s->setJavaScriptEnabled(true); 273 s->setDefaultTextEncodingName("latin1"); 274 s->setPluginsEnabled(false); 275 s->setShrinksStandaloneImagesToFit(false); 276 #ifdef ANDROID_LAYOUT 277 s->setUseWideViewport(false); 278 #endif 279 280 // Finally, load the actual data 281 ResourceRequest req(url); 282 frame->loader()->load(req, false); 283 284 do { 285 // Layout the page and service the timer 286 frame->view()->layout(); 287 while (client.m_hasTimer) { 288 client.m_func(); 289 JavaSharedClient::ServiceFunctionPtrQueue(); 290 } 291 JavaSharedClient::ServiceFunctionPtrQueue(); 292 293 // Layout more if needed. 294 while (frame->view()->needsLayout()) 295 frame->view()->layout(); 296 JavaSharedClient::ServiceFunctionPtrQueue(); 297 298 if (reloadCount) 299 frame->loader()->reload(true); 300 } while (reloadCount--); 301 302 // Draw into an offscreen bitmap 303 SkBitmap bmp; 304 bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height); 305 bmp.allocPixels(); 306 SkCanvas canvas(bmp); 307 PlatformGraphicsContext ctx(&canvas); 308 GraphicsContext gc(&ctx); 309 frame->view()->paintContents(&gc, IntRect(0, 0, width, height)); 310 311 // Write the bitmap to the sdcard 312 SkImageEncoder* enc = SkImageEncoder::Create(SkImageEncoder::kPNG_Type); 313 enc->encodeFile("/sdcard/webcore_test.png", bmp, 100); 314 delete enc; 315 316 // Tear down the world. 317 frame->loader()->detachFromParent(); 318 delete page; 319 } 320 321 } // namespace android 322