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