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_audio(JNIEnv*);
86extern int register_mediaplayer_video(JNIEnv*);
87#endif
88
89}
90
91struct RegistrationMethod {
92    const char* name;
93    int (*func)(JNIEnv*);
94};
95
96static 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
116EXPORT 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
147class MyJavaSharedClient : public TimerClient, public CookieClient {
148public:
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
164static void historyItemChanged(HistoryItem* i) {
165    if (i->bridge())
166        i->bridge()->updateHistoryItem(i);
167}
168
169namespace android {
170
171EXPORT 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