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 "DragClientAndroid.h" 35#include "EditorClientAndroid.h" 36#include "Frame.h" 37#include "FrameLoader.h" 38#include "FrameLoaderClientAndroid.h" 39#include "FrameView.h" 40#include "GraphicsContext.h" 41#include "HistoryItem.h" 42#include "InspectorClientAndroid.h" 43#include "IntRect.h" 44#include "JavaSharedClient.h" 45#include "Page.h" 46#include "PlatformGraphicsContext.h" 47#include "ResourceRequest.h" 48#include "ScriptController.h" 49#include "SecurityOrigin.h" 50#include "SelectionController.h" 51#include "Settings.h" 52#include "SharedBuffer.h" 53#include "SkBitmap.h" 54#include "SkCanvas.h" 55#include "SkImageEncoder.h" 56#include "SubstituteData.h" 57#include "TimerClient.h" 58#include "TextEncoding.h" 59#include "WebCoreViewBridge.h" 60#include "WebFrameView.h" 61#include "WebViewCore.h" 62#include "benchmark/Intercept.h" 63#include "benchmark/MyJavaVM.h" 64 65#include <JNIUtility.h> 66#include <jni.h> 67#include <utils/Log.h> 68 69namespace android { 70 71extern int register_webframe(JNIEnv*); 72extern int register_javabridge(JNIEnv*); 73extern int register_resource_loader(JNIEnv*); 74extern int register_webviewcore(JNIEnv*); 75extern int register_webhistory(JNIEnv*); 76extern int register_webicondatabase(JNIEnv*); 77extern int register_websettings(JNIEnv*); 78extern int register_webview(JNIEnv*); 79#if ENABLE(DATABASE) 80extern int register_webstorage(JNIEnv*); 81#endif 82extern int register_geolocation_permissions(JNIEnv*); 83extern int register_mock_geolocation(JNIEnv*); 84#if ENABLE(VIDEO) 85extern int register_mediaplayer(JNIEnv*); 86#endif 87 88} 89 90struct RegistrationMethod { 91 const char* name; 92 int (*func)(JNIEnv*); 93}; 94 95static RegistrationMethod gWebCoreRegMethods[] = { 96 { "JavaBridge", android::register_javabridge }, 97 { "WebFrame", android::register_webframe }, 98 { "WebCoreResourceLoader", android::register_resource_loader }, 99 { "WebViewCore", android::register_webviewcore }, 100 { "WebHistory", android::register_webhistory }, 101 { "WebIconDatabase", android::register_webicondatabase }, 102 { "WebSettings", android::register_websettings }, 103#if ENABLE(DATABASE) 104 { "WebStorage", android::register_webstorage }, 105#endif 106 { "WebView", android::register_webview }, 107 { "GeolocationPermissions", android::register_geolocation_permissions }, 108 { "MockGeolocation", android::register_mock_geolocation }, 109#if ENABLE(VIDEO) 110 { "HTML5VideoViewProxy", android::register_mediaplayer }, 111#endif 112}; 113 114EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) 115{ 116 // Save the JavaVM pointer for use globally. 117 JSC::Bindings::setJavaVM(vm); 118 119 JNIEnv* env = NULL; 120 jint result = -1; 121 122 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 123 LOGE("GetEnv failed!"); 124 return result; 125 } 126 LOG_ASSERT(env, "Could not retrieve the env!"); 127 128 const RegistrationMethod* method = gWebCoreRegMethods; 129 const RegistrationMethod* end = method + sizeof(gWebCoreRegMethods)/sizeof(RegistrationMethod); 130 while (method != end) { 131 if (method->func(env) < 0) { 132 LOGE("%s registration failed!", method->name); 133 return result; 134 } 135 method++; 136 } 137 138 // Initialize rand() function. The rand() function is used in 139 // FileSystemAndroid to create a random temporary filename. 140 srand(time(NULL)); 141 142 return JNI_VERSION_1_4; 143} 144 145class MyJavaSharedClient : public TimerClient, public CookieClient { 146public: 147 MyJavaSharedClient() : m_hasTimer(false) {} 148 virtual void setSharedTimer(long long timemillis) { m_hasTimer = true; } 149 virtual void stopSharedTimer() { m_hasTimer = false; } 150 virtual void setSharedTimerCallback(void (*f)()) { m_func = f; } 151 virtual void signalServiceFuncPtrQueue() {} 152 153 // Cookie methods that do nothing. 154 virtual void setCookies(const KURL&, const String&) {} 155 virtual String cookies(const KURL&) { return ""; } 156 virtual bool cookiesEnabled() { return false; } 157 158 bool m_hasTimer; 159 void (*m_func)(); 160}; 161 162static void historyItemChanged(HistoryItem* i) { 163 if (i->bridge()) 164 i->bridge()->updateHistoryItem(i); 165} 166 167namespace android { 168 169EXPORT void benchmark(const char* url, int reloadCount, int width, int height) { 170 ScriptController::initializeThreading(); 171 172 // Setting this allows data: urls to load from a local file. 173 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll); 174 175 // Create the fake JNIEnv and JavaVM 176 InitializeJavaVM(); 177 178 // The real function is private to libwebcore but we know what it does. 179 notifyHistoryItemChanged = historyItemChanged; 180 181 // Implement the shared timer callback 182 MyJavaSharedClient client; 183 JavaSharedClient::SetTimerClient(&client); 184 JavaSharedClient::SetCookieClient(&client); 185 186 // Create the page with all the various clients 187 ChromeClientAndroid* chrome = new ChromeClientAndroid; 188 EditorClientAndroid* editor = new EditorClientAndroid; 189 Page* page = new Page(chrome, 190 new ContextMenuClientAndroid, 191 editor, 192 new DragClientAndroid, 193 new InspectorClientAndroid, 194 0, // PluginHalterClient 195 0); // GeolocationControllerClient 196 editor->setPage(page); 197 198 // Create MyWebFrame that intercepts network requests 199 MyWebFrame* webFrame = new MyWebFrame(page); 200 webFrame->setUserAgent("Performance testing"); // needs to be non-empty 201 chrome->setWebFrame(webFrame); 202 // ChromeClientAndroid maintains the reference. 203 Release(webFrame); 204 205 // Create the Frame and the FrameLoaderClient 206 FrameLoaderClientAndroid* loader = new FrameLoaderClientAndroid(webFrame); 207 RefPtr<Frame> frame = Frame::create(page, NULL, loader); 208 loader->setFrame(frame.get()); 209 210 // Build our View system, resize it to the given dimensions and release our 211 // references. Note: We keep a referenec to frameView so we can layout and 212 // draw later without risk of it being deleted. 213 WebViewCore* webViewCore = new WebViewCore(JSC::Bindings::getJNIEnv(), 214 MY_JOBJECT, frame.get()); 215 RefPtr<FrameView> frameView = FrameView::create(frame.get()); 216 WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); 217 frame->setView(frameView); 218 frameView->resize(width, height); 219 Release(webViewCore); 220 Release(webFrameView); 221 222 // Initialize the frame and turn of low-bandwidth display (it fails an 223 // assertion in the Cache code) 224 frame->init(); 225 frame->selection()->setFocused(true); 226 227 // Set all the default settings the Browser normally uses. 228 Settings* s = frame->settings(); 229 s->setLayoutAlgorithm(Settings::kLayoutNormal); // Normal layout for now 230 s->setStandardFontFamily("sans-serif"); 231 s->setFixedFontFamily("monospace"); 232 s->setSansSerifFontFamily("sans-serif"); 233 s->setSerifFontFamily("serif"); 234 s->setCursiveFontFamily("cursive"); 235 s->setFantasyFontFamily("fantasy"); 236 s->setMinimumFontSize(8); 237 s->setMinimumLogicalFontSize(8); 238 s->setDefaultFontSize(16); 239 s->setDefaultFixedFontSize(13); 240 s->setLoadsImagesAutomatically(true); 241 s->setJavaScriptEnabled(true); 242 s->setDefaultTextEncodingName("latin1"); 243 s->setPluginsEnabled(false); 244 s->setShrinksStandaloneImagesToFit(false); 245 s->setUseWideViewport(false); 246 247 // Finally, load the actual data 248 ResourceRequest req(url); 249 frame->loader()->load(req, false); 250 251 do { 252 // Layout the page and service the timer 253 frame->view()->layout(); 254 while (client.m_hasTimer) { 255 client.m_func(); 256 JavaSharedClient::ServiceFunctionPtrQueue(); 257 } 258 JavaSharedClient::ServiceFunctionPtrQueue(); 259 260 // Layout more if needed. 261 while (frame->view()->needsLayout()) 262 frame->view()->layout(); 263 JavaSharedClient::ServiceFunctionPtrQueue(); 264 265 if (reloadCount) 266 frame->loader()->reload(true); 267 } while (reloadCount--); 268 269 // Draw into an offscreen bitmap 270 SkBitmap bmp; 271 bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height); 272 bmp.allocPixels(); 273 SkCanvas canvas(bmp); 274 PlatformGraphicsContext ctx(&canvas, NULL); 275 GraphicsContext gc(&ctx); 276 frame->view()->paintContents(&gc, IntRect(0, 0, width, height)); 277 278 // Write the bitmap to the sdcard 279 SkImageEncoder* enc = SkImageEncoder::Create(SkImageEncoder::kPNG_Type); 280 enc->encodeFile("/sdcard/webcore_test.png", bmp, 100); 281 delete enc; 282 283 // Tear down the world. 284 frame->loader()->detachFromParent(); 285 delete page; 286} 287 288} // namespace android 289