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