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