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 74namespace android { 75 76extern int registerWebFrame(JNIEnv*); 77extern int registerJavaBridge(JNIEnv*); 78extern int registerJniUtil(JNIEnv*); 79extern int registerResourceLoader(JNIEnv*); 80extern int registerWebViewCore(JNIEnv*); 81extern int registerWebHistory(JNIEnv*); 82extern int registerWebIconDatabase(JNIEnv*); 83extern int registerWebSettings(JNIEnv*); 84extern int registerWebView(JNIEnv*); 85extern int registerViewStateSerializer(JNIEnv*); 86#if ENABLE(DATABASE) 87extern int registerWebStorage(JNIEnv*); 88#endif 89extern int registerGeolocationPermissions(JNIEnv*); 90extern int registerMockGeolocation(JNIEnv*); 91#if ENABLE(VIDEO) 92extern int registerMediaPlayerAudio(JNIEnv*); 93extern int registerMediaPlayerVideo(JNIEnv*); 94#endif 95extern int registerDeviceMotionAndOrientationManager(JNIEnv*); 96extern int registerCookieManager(JNIEnv*); 97#if USE(CHROME_NETWORK_STACK) 98extern int registerCacheManager(JNIEnv*); 99#endif 100 101} 102 103struct RegistrationMethod { 104 const char* name; 105 int (*func)(JNIEnv*); 106}; 107 108static 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 135EXPORT 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 166class MyJavaSharedClient : public TimerClient, public CookieClient { 167public: 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 183static void historyItemChanged(HistoryItem* i) { 184 if (i->bridge()) 185 i->bridge()->updateHistoryItem(i); 186} 187 188namespace android { 189 190EXPORT 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