1/*
2 * Copyright 2006, 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#include "WebCoreFrameBridge.h"
30
31#include "Arena.h"
32#include "AtomicString.h"
33#include "BackForwardList.h"
34#include "Cache.h"
35#include "CString.h"
36#include "Chrome.h"
37#include "ChromeClientAndroid.h"
38#include "ContextMenuClientAndroid.h"
39#include "Document.h"
40#include "DocumentLoader.h"
41#include "DragClientAndroid.h"
42#include "EditorClientAndroid.h"
43#include "Element.h"
44#include "Font.h"
45#include "FormState.h"
46#include "Frame.h"
47#include "FrameLoader.h"
48#include "FrameLoaderClientAndroid.h"
49#include "FrameLoadRequest.h"
50#include "FrameTree.h"
51#include "FrameView.h"
52#include "GraphicsContext.h"
53#include "HistoryItem.h"
54#include "HTMLCollection.h"
55#include "HTMLElement.h"
56#include "HTMLFormElement.h"
57#include "HTMLInputElement.h"
58#include "HTMLNames.h"
59#include "IconDatabase.h"
60#include "Image.h"
61#include "InspectorClientAndroid.h"
62#include "KURL.h"
63#include "Page.h"
64#include "PageCache.h"
65#include "PlatformString.h"
66#include "RenderPart.h"
67#include "RenderSkinAndroid.h"
68#include "RenderTreeAsText.h"
69#include "RenderView.h"
70#include "ResourceHandle.h"
71#include "ResourceHandleInternal.h"
72#include "ScriptController.h"
73#include "ScriptValue.h"
74#include "SecurityOrigin.h"
75#include "SelectionController.h"
76#include "Settings.h"
77#include "SubstituteData.h"
78#include "WebCoreJni.h"
79#include "WebCoreResourceLoader.h"
80#include "WebHistory.h"
81#include "WebIconDatabase.h"
82#include "WebFrameView.h"
83#include "WebViewCore.h"
84#include "android_graphics.h"
85#include "jni.h"
86#include "wds/DebugServer.h"
87
88#include <JNIUtility.h>
89#include <JNIHelp.h>
90#include <SkGraphics.h>
91#include <android_runtime/android_util_AssetManager.h>
92#include <utils/misc.h>
93#include <utils/AssetManager.h>
94#include <wtf/CurrentTime.h>
95#include <wtf/Platform.h>
96
97#if USE(JSC)
98#include "GCController.h"
99#include "JSDOMWindow.h"
100#include "JavaInstanceJSC.h"
101#include <runtime_object.h>
102#include <runtime_root.h>
103#include <runtime/JSLock.h>
104#elif USE(V8)
105#include "JavaNPObjectV8.h"
106#include "JavaInstanceV8.h"
107#include "V8Counters.h"
108#endif  // USE(JSC)
109
110#ifdef ANDROID_INSTRUMENT
111#include "TimeCounter.h"
112#endif
113
114using namespace JSC::Bindings;
115
116static String* gUploadFileLabel;
117static String* gResetLabel;
118static String* gSubmitLabel;
119
120String* WebCore::PlatformBridge::globalLocalizedName(
121        WebCore::PlatformBridge::rawResId resId)
122{
123    switch (resId) {
124    case WebCore::PlatformBridge::FileUploadLabel:
125        return gUploadFileLabel;
126    case WebCore::PlatformBridge::ResetLabel:
127        return gResetLabel;
128    case WebCore::PlatformBridge::SubmitLabel:
129        return gSubmitLabel;
130    default:
131        return 0;
132    }
133}
134/**
135 * Instantiate the localized name desired.
136 */
137void initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId,
138        android::WebFrame* webFrame)
139{
140    String** pointer;
141    switch (resId) {
142    case WebCore::PlatformBridge::FileUploadLabel:
143        pointer = &gUploadFileLabel;
144        break;
145    case WebCore::PlatformBridge::ResetLabel:
146        pointer = &gResetLabel;
147        break;
148    case WebCore::PlatformBridge::SubmitLabel:
149        pointer = &gSubmitLabel;
150        break;
151    default:
152        return;
153    }
154    if (!(*pointer) && webFrame) {
155        (*pointer) = new String(webFrame->getRawResourceFilename(resId).impl());
156    }
157}
158
159namespace android {
160
161// ----------------------------------------------------------------------------
162
163#define WEBCORE_MEMORY_CAP 15 * 1024 * 1024
164
165// ----------------------------------------------------------------------------
166
167struct WebFrame::JavaBrowserFrame
168{
169    jweak       mObj;
170    jweak       mHistoryList; // WebBackForwardList object
171    jmethodID   mStartLoadingResource;
172    jmethodID   mLoadStarted;
173    jmethodID   mTransitionToCommitted;
174    jmethodID   mLoadFinished;
175    jmethodID   mReportError;
176    jmethodID   mSetTitle;
177    jmethodID   mWindowObjectCleared;
178    jmethodID   mSetProgress;
179    jmethodID   mDidReceiveIcon;
180    jmethodID   mDidReceiveTouchIconUrl;
181    jmethodID   mUpdateVisitedHistory;
182    jmethodID   mHandleUrl;
183    jmethodID   mCreateWindow;
184    jmethodID   mCloseWindow;
185    jmethodID   mDecidePolicyForFormResubmission;
186    jmethodID   mRequestFocus;
187    jmethodID   mGetRawResFilename;
188    jmethodID   mDensity;
189    jmethodID   mGetFileSize;
190    jmethodID   mGetFile;
191    AutoJObject frame(JNIEnv* env) {
192        return getRealObject(env, mObj);
193    }
194    AutoJObject history(JNIEnv* env) {
195        return getRealObject(env, mHistoryList);
196    }
197};
198
199static jfieldID gFrameField;
200#define GET_NATIVE_FRAME(env, obj) ((WebCore::Frame*)env->GetIntField(obj, gFrameField))
201#define SET_NATIVE_FRAME(env, obj, frame) (env->SetIntField(obj, gFrameField, frame))
202
203// ----------------------------------------------------------------------------
204
205WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page)
206    : mPage(page)
207{
208    jclass clazz = env->GetObjectClass(obj);
209    mJavaFrame = new JavaBrowserFrame;
210    mJavaFrame->mObj = env->NewWeakGlobalRef(obj);
211    mJavaFrame->mHistoryList = env->NewWeakGlobalRef(historyList);
212    mJavaFrame->mStartLoadingResource = env->GetMethodID(clazz, "startLoadingResource",
213            "(ILjava/lang/String;Ljava/lang/String;Ljava/util/HashMap;[BJIZZZLjava/lang/String;Ljava/lang/String;)Landroid/webkit/LoadListener;");
214    mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted",
215            "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V");
216    mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted",
217            "(IZ)V");
218    mJavaFrame->mLoadFinished = env->GetMethodID(clazz, "loadFinished",
219            "(Ljava/lang/String;IZ)V");
220    mJavaFrame->mReportError = env->GetMethodID(clazz, "reportError",
221            "(ILjava/lang/String;Ljava/lang/String;)V");
222    mJavaFrame->mSetTitle = env->GetMethodID(clazz, "setTitle",
223            "(Ljava/lang/String;)V");
224    mJavaFrame->mWindowObjectCleared = env->GetMethodID(clazz, "windowObjectCleared",
225            "(I)V");
226    mJavaFrame->mSetProgress = env->GetMethodID(clazz, "setProgress",
227            "(I)V");
228    mJavaFrame->mDidReceiveIcon = env->GetMethodID(clazz, "didReceiveIcon",
229            "(Landroid/graphics/Bitmap;)V");
230    mJavaFrame->mDidReceiveTouchIconUrl = env->GetMethodID(clazz, "didReceiveTouchIconUrl",
231            "(Ljava/lang/String;Z)V");
232    mJavaFrame->mUpdateVisitedHistory = env->GetMethodID(clazz, "updateVisitedHistory",
233            "(Ljava/lang/String;Z)V");
234    mJavaFrame->mHandleUrl = env->GetMethodID(clazz, "handleUrl",
235            "(Ljava/lang/String;)Z");
236    mJavaFrame->mCreateWindow = env->GetMethodID(clazz, "createWindow",
237            "(ZZ)Landroid/webkit/BrowserFrame;");
238    mJavaFrame->mCloseWindow = env->GetMethodID(clazz, "closeWindow",
239            "(Landroid/webkit/WebViewCore;)V");
240    mJavaFrame->mDecidePolicyForFormResubmission = env->GetMethodID(clazz,
241            "decidePolicyForFormResubmission", "(I)V");
242    mJavaFrame->mRequestFocus = env->GetMethodID(clazz, "requestFocus",
243            "()V");
244    mJavaFrame->mGetRawResFilename = env->GetMethodID(clazz, "getRawResFilename",
245            "(I)Ljava/lang/String;");
246    mJavaFrame->mDensity = env->GetMethodID(clazz, "density","()F");
247    mJavaFrame->mGetFileSize = env->GetMethodID(clazz, "getFileSize", "(Ljava/lang/String;)I");
248    mJavaFrame->mGetFile = env->GetMethodID(clazz, "getFile", "(Ljava/lang/String;[BII)I");
249
250    LOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource");
251    LOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted");
252    LOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted");
253    LOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished");
254    LOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError");
255    LOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle");
256    LOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared");
257    LOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress");
258    LOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon");
259    LOG_ASSERT(mJavaFrame->mDidReceiveTouchIconUrl, "Could not find method didReceiveTouchIconUrl");
260    LOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory");
261    LOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl");
262    LOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow");
263    LOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow");
264    LOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission");
265    LOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus");
266    LOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename");
267    LOG_ASSERT(mJavaFrame->mDensity, "Could not find method density");
268    LOG_ASSERT(mJavaFrame->mGetFileSize, "Could not find method getFileSize");
269    LOG_ASSERT(mJavaFrame->mGetFile, "Could not find method getFile");
270
271    mUserAgent = WebCore::String();
272    mUserInitiatedClick = false;
273}
274
275WebFrame::~WebFrame()
276{
277    if (mJavaFrame->mObj) {
278        JNIEnv* env = getJNIEnv();
279        env->DeleteWeakGlobalRef(mJavaFrame->mObj);
280        env->DeleteWeakGlobalRef(mJavaFrame->mHistoryList);
281        mJavaFrame->mObj = 0;
282    }
283    delete mJavaFrame;
284}
285
286WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame)
287{
288    FrameLoaderClientAndroid* client =
289            static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
290    return client->webFrame();
291}
292
293static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map)
294{
295    jclass mapClass = env->FindClass("java/util/HashMap");
296    LOG_ASSERT(mapClass, "Could not find HashMap class!");
297    jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
298    LOG_ASSERT(init, "Could not find constructor for HashMap");
299    jobject hashMap = env->NewObject(mapClass, init, map.size());
300    LOG_ASSERT(hashMap, "Could not create a new HashMap");
301    jmethodID put = env->GetMethodID(mapClass, "put",
302            "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
303    LOG_ASSERT(put, "Could not find put method on HashMap");
304
305    WebCore::HTTPHeaderMap::const_iterator end = map.end();
306    for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) {
307        if (i->first.length() == 0 || i->second.length() == 0)
308            continue;
309        jstring key = env->NewString((unsigned short *)i->first.characters(), i->first.length());
310        jstring val = env->NewString((unsigned short *)i->second.characters(), i->second.length());
311        if (key && val) {
312            env->CallObjectMethod(hashMap, put, key, val);
313            env->DeleteLocalRef(key);
314            env->DeleteLocalRef(val);
315        }
316    }
317
318    env->DeleteLocalRef(mapClass);
319
320    return hashMap;
321}
322
323// In WebViewCore.java, we artificially append the filename to the URI so that
324// webkit treats the actual display name of the file as the filename, rather
325// than the last segment of the URI (which will simply be a number).  When we
326// pass the URI up to BrowserFrame, we no longer need the appended name (in fact
327// it causes problems), so remove it here.
328// FIXME: If we rewrite pathGetFileName (the current version is in
329// FileSystemPOSIX), we can get the filename that way rather than appending it.
330static jstring uriFromUriFileName(JNIEnv* env, const WebCore::String& name)
331{
332    const WebCore::String fileName = name.left(name.reverseFind('/'));
333    return env->NewString(fileName.characters(), fileName.length());
334}
335
336// This class stores the URI and the size of each file for upload.  The URI is
337// stored so we do not have to create it again.  The size is stored so we can
338// compare the actual size of the file with the stated size.  If the actual size
339// is larger, we will not copy it, since we will not have enough space in our
340// buffer.
341class FileInfo {
342public:
343    FileInfo(JNIEnv* env, const WebCore::String& name) {
344        m_uri = uriFromUriFileName(env, name);
345        checkException(env);
346        m_size = 0;
347        m_env = env;
348    }
349    ~FileInfo() {
350        m_env->DeleteLocalRef(m_uri);
351    }
352    int getSize() { return m_size; }
353    jstring getUri() { return m_uri; }
354    void setSize(int size) { m_size = size; }
355private:
356    // This is only a pointer to the JNIEnv* returned by
357    // JSC::Bindings::getJNIEnv().  Used to delete the jstring when finished.
358    JNIEnv* m_env;
359    jstring m_uri;
360    int m_size;
361};
362
363PassRefPtr<WebCore::ResourceLoaderAndroid>
364WebFrame::startLoadingResource(WebCore::ResourceHandle* loader,
365                                  const WebCore::ResourceRequest& request,
366                                  bool mainResource,
367                                  bool synchronous)
368{
369#ifdef ANDROID_INSTRUMENT
370    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
371#endif
372    LOGV("::WebCore:: startLoadingResource(%p, %s)",
373            loader, request.url().string().latin1().data());
374
375    WebCore::String method = request.httpMethod();
376    WebCore::HTTPHeaderMap headers = request.httpHeaderFields();
377
378    JNIEnv* env = getJNIEnv();
379    WebCore::String urlStr = request.url().string();
380    int colon = urlStr.find(':');
381    bool allLower = true;
382    for (int index = 0; index < colon; index++) {
383        UChar ch = urlStr[index];
384        if (!WTF::isASCIIAlpha(ch))
385            break;
386        allLower &= WTF::isASCIILower(ch);
387        if (index == colon - 1 && !allLower) {
388            urlStr = urlStr.substring(0, colon).lower()
389                    + urlStr.substring(colon);
390        }
391    }
392    LOGV("%s lower=%s", __FUNCTION__, urlStr.latin1().data());
393    jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
394    jstring jMethodStr = NULL;
395    if (!method.isEmpty())
396        jMethodStr = env->NewString(method.characters(), method.length());
397    jbyteArray jPostDataStr = NULL;
398    WebCore::FormData* formdata = request.httpBody();
399    AutoJObject obj = mJavaFrame->frame(env);
400    if (formdata) {
401        // We can use the formdata->flatten() but it will result in two
402        // memcpys, first through loading up the vector with the form data
403        // then another to copy it out of the vector and into the java byte
404        // array. Instead, we copy the form data ourselves below saving a
405        // memcpy.
406        const WTF::Vector<WebCore::FormDataElement>& elements =
407                formdata->elements();
408
409        // Sizing pass
410        int size = 0;
411        size_t n = elements.size();
412        FileInfo** fileinfos = new FileInfo*[n];
413        for (size_t i = 0; i < n; ++i) {
414            fileinfos[i] = 0;
415            const WebCore::FormDataElement& e = elements[i];
416            if (e.m_type == WebCore::FormDataElement::data) {
417                size += e.m_data.size();
418            } else if (e.m_type == WebCore::FormDataElement::encodedFile) {
419                fileinfos[i] = new FileInfo(env, e.m_filename);
420                int delta = env->CallIntMethod(obj.get(),
421                    mJavaFrame->mGetFileSize, fileinfos[i]->getUri());
422                checkException(env);
423                fileinfos[i]->setSize(delta);
424                size += delta;
425            }
426        }
427
428        // Only create the byte array if there is POST data to pass up.
429        // The Java code is expecting null if there is no data.
430        if (size > 0) {
431            // Copy the actual form data.
432            jPostDataStr = env->NewByteArray(size);
433            if (jPostDataStr) {
434                // Write  the form data to the java array.
435                jbyte* bytes = env->GetByteArrayElements(jPostDataStr, NULL);
436                int offset = 0;
437                for (size_t i = 0; i < n; ++i) {
438                    const WebCore::FormDataElement& e = elements[i];
439                    if (e.m_type == WebCore::FormDataElement::data) {
440                        int delta = e.m_data.size();
441                        memcpy(bytes + offset, e.m_data.data(), delta);
442                        offset += delta;
443                    } else if (e.m_type
444                            == WebCore::FormDataElement::encodedFile) {
445                        int delta = env->CallIntMethod(obj.get(),
446                            mJavaFrame->mGetFile, fileinfos[i]->getUri(),
447                            jPostDataStr, offset, fileinfos[i]->getSize());
448                        checkException(env);
449                        offset += delta;
450                    }
451                }
452                env->ReleaseByteArrayElements(jPostDataStr, bytes, 0);
453            }
454        }
455        delete[] fileinfos;
456    }
457
458    jobject jHeaderMap = createJavaMapFromHTTPHeaders(env, headers);
459
460    // Convert the WebCore Cache Policy to a WebView Cache Policy.
461    int cacheMode = 0;  // WebSettings.LOAD_NORMAL
462    switch (request.cachePolicy()) {
463        case WebCore::ReloadIgnoringCacheData:
464            cacheMode = 2; // WebSettings.LOAD_NO_CACHE
465            break;
466        case WebCore::ReturnCacheDataDontLoad:
467            cacheMode = 3; // WebSettings.LOAD_CACHE_ONLY
468            break;
469        case WebCore::ReturnCacheDataElseLoad:
470            cacheMode = 1;   // WebSettings.LOAD_CACHE_ELSE_NETWORK
471            break;
472        case WebCore::UseProtocolCachePolicy:
473        default:
474            break;
475    }
476
477    LOGV("::WebCore:: startLoadingResource %s with cacheMode %d", urlStr.ascii().data(), cacheMode);
478
479    ResourceHandleInternal* loaderInternal = loader->getInternal();
480    jstring jUsernameString = loaderInternal->m_user.isEmpty() ?
481            NULL : env->NewString(loaderInternal->m_user.characters(), loaderInternal->m_user.length());
482    jstring jPasswordString = loaderInternal->m_pass.isEmpty() ?
483            NULL : env->NewString(loaderInternal->m_pass.characters(), loaderInternal->m_pass.length());
484
485    jobject jLoadListener =
486        env->CallObjectMethod(obj.get(), mJavaFrame->mStartLoadingResource,
487                (int)loader, jUrlStr, jMethodStr, jHeaderMap,
488                jPostDataStr, formdata ? formdata->identifier(): 0,
489                cacheMode, mainResource, request.getUserGesture(),
490                synchronous, jUsernameString, jPasswordString);
491
492    env->DeleteLocalRef(jUrlStr);
493    env->DeleteLocalRef(jMethodStr);
494    env->DeleteLocalRef(jPostDataStr);
495    env->DeleteLocalRef(jHeaderMap);
496    env->DeleteLocalRef(jUsernameString);
497    env->DeleteLocalRef(jPasswordString);
498    if (checkException(env))
499        return NULL;
500
501    PassRefPtr<WebCore::ResourceLoaderAndroid> h;
502    if (jLoadListener)
503        h = WebCoreResourceLoader::create(env, jLoadListener);
504    env->DeleteLocalRef(jLoadListener);
505    return h;
506}
507
508void
509WebFrame::reportError(int errorCode, const WebCore::String& description,
510        const WebCore::String& failingUrl)
511{
512#ifdef ANDROID_INSTRUMENT
513    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
514#endif
515    LOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data());
516    JNIEnv* env = getJNIEnv();
517
518    jstring descStr = env->NewString((unsigned short*)description.characters(), description.length());
519    jstring failUrl = env->NewString((unsigned short*)failingUrl.characters(), failingUrl.length());
520    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mReportError,
521            errorCode, descStr, failUrl);
522    env->DeleteLocalRef(descStr);
523    env->DeleteLocalRef(failUrl);
524}
525
526void
527WebFrame::loadStarted(WebCore::Frame* frame)
528{
529#ifdef ANDROID_INSTRUMENT
530    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
531#endif
532    const WebCore::KURL& url = frame->loader()->activeDocumentLoader()->url();
533    if (url.isEmpty())
534        return;
535    LOGV("::WebCore:: loadStarted %s", url.string().ascii().data());
536
537    bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
538    WebCore::FrameLoadType loadType = frame->loader()->loadType();
539
540    if (loadType == WebCore::FrameLoadTypeReplace ||
541            loadType == WebCore::FrameLoadTypeSame ||
542            (loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList &&
543             !isMainFrame))
544        return;
545
546    JNIEnv* env = getJNIEnv();
547    WebCore::String urlString(url.string());
548    // If this is the main frame and we already have a favicon in the database,
549    // send it along with the page started notification.
550    jobject favicon = NULL;
551    if (isMainFrame) {
552        WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(urlString, WebCore::IntSize(16, 16));
553        if (icon)
554            favicon = webcoreImageToJavaBitmap(env, icon);
555        LOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data());
556    }
557    jstring urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
558
559    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadStarted, urlStr, favicon,
560            (int)loadType, isMainFrame);
561    checkException(env);
562    env->DeleteLocalRef(urlStr);
563    if (favicon)
564        env->DeleteLocalRef(favicon);
565
566    // Inform the client that the main frame has started a new load.
567    if (isMainFrame && mPage) {
568        Chrome* chrome = mPage->chrome();
569        if (chrome) {
570            ChromeClientAndroid* client = static_cast<ChromeClientAndroid*>(chrome->client());
571            if (client)
572                client->onMainFrameLoadStarted();
573        }
574    }
575}
576
577void
578WebFrame::transitionToCommitted(WebCore::Frame* frame)
579{
580#ifdef ANDROID_INSTRUMENT
581    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
582#endif
583    JNIEnv* env = getJNIEnv();
584    WebCore::FrameLoadType loadType = frame->loader()->loadType();
585    bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
586    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mTransitionToCommitted,
587            (int)loadType, isMainFrame);
588    checkException(env);
589}
590
591void
592WebFrame::didFinishLoad(WebCore::Frame* frame)
593{
594#ifdef ANDROID_INSTRUMENT
595    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
596#endif
597    JNIEnv* env = getJNIEnv();
598    WebCore::FrameLoader* loader = frame->loader();
599    const WebCore::KURL& url = loader->activeDocumentLoader()->url();
600    if (url.isEmpty())
601        return;
602    LOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data());
603
604    bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
605    WebCore::FrameLoadType loadType = loader->loadType();
606    WebCore::String urlString(url.string());
607    jstring urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
608    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mLoadFinished, urlStr,
609            (int)loadType, isMainFrame);
610    checkException(env);
611    env->DeleteLocalRef(urlStr);
612}
613
614void
615WebFrame::addHistoryItem(WebCore::HistoryItem* item)
616{
617#ifdef ANDROID_INSTRUMENT
618    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
619#endif
620    LOGV("::WebCore:: addHistoryItem");
621    JNIEnv* env = getJNIEnv();
622    WebHistory::AddItem(mJavaFrame->history(env), item);
623}
624
625void
626WebFrame::removeHistoryItem(int index)
627{
628#ifdef ANDROID_INSTRUMENT
629    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
630#endif
631    LOGV("::WebCore:: removeHistoryItem at %d", index);
632    JNIEnv* env = getJNIEnv();
633    WebHistory::RemoveItem(mJavaFrame->history(env), index);
634}
635
636void
637WebFrame::updateHistoryIndex(int newIndex)
638{
639#ifdef ANDROID_INSTRUMENT
640    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
641#endif
642    LOGV("::WebCore:: updateHistoryIndex to %d", newIndex);
643    JNIEnv* env = getJNIEnv();
644    WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex);
645}
646
647void
648WebFrame::setTitle(const WebCore::String& title)
649{
650#ifdef ANDROID_INSTRUMENT
651    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
652#endif
653#ifndef NDEBUG
654    LOGV("setTitle(%s)", title.ascii().data());
655#endif
656    JNIEnv* env = getJNIEnv();
657    jstring jTitleStr = env->NewString((unsigned short *)title.characters(), title.length());
658
659    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetTitle,
660                                        jTitleStr);
661    checkException(env);
662    env->DeleteLocalRef(jTitleStr);
663}
664
665void
666WebFrame::windowObjectCleared(WebCore::Frame* frame)
667{
668#ifdef ANDROID_INSTRUMENT
669    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
670#endif
671    LOGV("::WebCore:: windowObjectCleared");
672    JNIEnv* env = getJNIEnv();
673
674    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mWindowObjectCleared, (int)frame);
675    checkException(env);
676}
677
678void
679WebFrame::setProgress(float newProgress)
680{
681#ifdef ANDROID_INSTRUMENT
682    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
683#endif
684    JNIEnv* env = getJNIEnv();
685    int progress = (int) (100 * newProgress);
686    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mSetProgress, progress);
687    checkException(env);
688}
689
690const WebCore::String
691WebFrame::userAgentForURL(const WebCore::KURL* url)
692{
693    return mUserAgent;
694}
695
696void
697WebFrame::didReceiveIcon(WebCore::Image* icon)
698{
699#ifdef ANDROID_INSTRUMENT
700    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
701#endif
702    LOG_ASSERT(icon, "DidReceiveIcon called without an image!");
703    JNIEnv* env = getJNIEnv();
704    jobject bitmap = webcoreImageToJavaBitmap(env, icon);
705    if (!bitmap)
706        return;
707
708    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDidReceiveIcon, bitmap);
709    env->DeleteLocalRef(bitmap);
710    checkException(env);
711}
712
713void
714WebFrame::didReceiveTouchIconURL(const WebCore::String& url, bool precomposed)
715{
716#ifdef ANDROID_INSTRUMENT
717    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
718#endif
719    JNIEnv* env = getJNIEnv();
720    jstring jUrlStr = env->NewString((unsigned short*)url.characters(),
721            url.length());
722
723    env->CallVoidMethod(mJavaFrame->frame(env).get(),
724            mJavaFrame->mDidReceiveTouchIconUrl, jUrlStr, precomposed);
725    checkException(env);
726}
727
728void
729WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload)
730{
731#ifdef ANDROID_INSTRUMENT
732    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
733#endif
734    WebCore::String urlStr(url.string());
735    JNIEnv* env = getJNIEnv();
736    jstring jUrlStr = env->NewString((unsigned short*)urlStr.characters(), urlStr.length());
737
738    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload);
739    checkException(env);
740}
741
742bool
743WebFrame::canHandleRequest(const WebCore::ResourceRequest& request)
744{
745#ifdef ANDROID_INSTRUMENT
746    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
747#endif
748    // always handle "POST" in place
749    if (equalIgnoringCase(request.httpMethod(), "POST"))
750        return true;
751    WebCore::KURL requestUrl = request.url();
752    if (!mUserInitiatedClick && !request.getUserGesture() &&
753        (requestUrl.protocolIs("http") || requestUrl.protocolIs("https") ||
754            requestUrl.protocolIs("file") || requestUrl.protocolIs("about") ||
755            WebCore::protocolIsJavaScript(requestUrl.string())))
756        return true;
757    WebCore::String url(request.url().string());
758    // Empty urls should not be sent to java
759    if (url.isEmpty())
760        return true;
761    JNIEnv* env = getJNIEnv();
762    jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
763
764    // check to see whether browser app wants to hijack url loading.
765    // if browser app handles the url, we will return false to bail out WebCore loading
766    jboolean ret = env->CallBooleanMethod(mJavaFrame->frame(env).get(), mJavaFrame->mHandleUrl, jUrlStr);
767    checkException(env);
768    return (ret == 0);
769}
770
771WebCore::Frame*
772WebFrame::createWindow(bool dialog, bool userGesture)
773{
774#ifdef ANDROID_INSTRUMENT
775    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
776#endif
777    JNIEnv* env = getJNIEnv();
778    jobject obj = env->CallObjectMethod(mJavaFrame->frame(env).get(),
779            mJavaFrame->mCreateWindow, dialog, userGesture);
780    if (obj) {
781        WebCore::Frame* frame = GET_NATIVE_FRAME(env, obj);
782        return frame;
783    }
784    return NULL;
785}
786
787void
788WebFrame::requestFocus() const
789{
790#ifdef ANDROID_INSTRUMENT
791    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
792#endif
793    JNIEnv* env = getJNIEnv();
794    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mRequestFocus);
795    checkException(env);
796}
797
798void
799WebFrame::closeWindow(WebViewCore* webViewCore)
800{
801#ifdef ANDROID_INSTRUMENT
802    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
803#endif
804    assert(webViewCore);
805    JNIEnv* env = getJNIEnv();
806    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mCloseWindow,
807            webViewCore->getJavaObject().get());
808}
809
810struct PolicyFunctionWrapper {
811    WebCore::FramePolicyFunction func;
812};
813
814void
815WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func)
816{
817#ifdef ANDROID_INSTRUMENT
818    TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
819#endif
820    JNIEnv* env = getJNIEnv();
821    PolicyFunctionWrapper* p = new PolicyFunctionWrapper;
822    p->func = func;
823    env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDecidePolicyForFormResubmission, p);
824}
825
826WebCore::String
827WebFrame::getRawResourceFilename(WebCore::PlatformBridge::rawResId id) const
828{
829    JNIEnv* env = getJNIEnv();
830    jstring ret = (jstring) env->CallObjectMethod(mJavaFrame->frame(env).get(),
831            mJavaFrame->mGetRawResFilename, (int)id);
832
833    return to_string(env, ret);
834}
835
836float
837WebFrame::density() const
838{
839    JNIEnv* env = getJNIEnv();
840    jfloat dpi = env->CallFloatMethod(mJavaFrame->frame(env).get(), mJavaFrame->mDensity);
841    checkException(env);
842    return dpi;
843}
844
845// ----------------------------------------------------------------------------
846static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decision)
847{
848#ifdef ANDROID_INSTRUMENT
849    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
850#endif
851    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
852    LOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!");
853    PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func;
854    LOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!");
855
856    // If we are resending the form then we should reset the multiple submission protection.
857    if (decision == WebCore::PolicyUse)
858        pFrame->loader()->resetMultipleFormSubmissionProtection();
859
860    (pFrame->loader()->policyChecker()->*(pFunc->func))((WebCore::PolicyAction)decision);
861}
862
863static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAssetManager, jobject historyList)
864{
865    ScriptController::initializeThreading();
866
867#ifdef ANDROID_INSTRUMENT
868#if USE(V8)
869    V8Counters::initCounters();
870#endif
871    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
872#endif
873    ChromeClientAndroid*      chromeC = new ChromeClientAndroid;
874    EditorClientAndroid*      editorC = new EditorClientAndroid;
875    WebCore::ContextMenuClient* contextMenuC = new ContextMenuClientAndroid;
876    WebCore::DragClient*        dragC = new DragClientAndroid;
877    InspectorClientAndroid* inspectorC = new InspectorClientAndroid;
878    // Create a new page
879    WebCore::Page* page = new WebCore::Page(chromeC,
880                                            contextMenuC,
881                                            editorC,
882                                            dragC,
883                                            inspectorC,
884                                            0, // PluginHalterClient
885                                            0); // GeolocationControllerClient
886    // css files without explicit MIMETYPE is treated as generic text files in
887    // the Java side. So we can't enforce CSS MIMETYPE.
888    page->settings()->setEnforceCSSMIMETypeInStrictMode(false);
889    editorC->setPage(page);
890    page->setGroupName("android.webkit");
891
892    // Create a WebFrame to access the Java BrowserFrame associated with this page
893    WebFrame* webFrame = new WebFrame(env, obj, historyList, page);
894    // Attach webFrame to chromeC and release our ownership
895    chromeC->setWebFrame(webFrame);
896    Release(webFrame);
897
898    FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(webFrame);
899    // Create a Frame and the page holds its reference
900    WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get();
901    loaderC->setFrame(frame);
902#if ENABLE(WDS)
903    WDS::server()->addFrame(frame);
904#endif
905
906    // Create a WebViewCore to access the Java WebViewCore associated with this page
907    WebViewCore* webViewCore = new WebViewCore(env, javaview, frame);
908
909    // Create a FrameView
910    RefPtr<WebCore::FrameView> frameView = WebCore::FrameView::create(frame);
911    // Create a WebFrameView
912    WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore);
913    // As webFrameView Retains webViewCore, release our ownership
914    Release(webViewCore);
915    // As frameView Retains webFrameView, release our ownership
916    Release(webFrameView);
917    // Attach the frameView to the frame and release our ownership
918    frame->setView(frameView);
919    // Set the frame to active to turn on keyboard focus.
920    frame->init();
921    frame->selection()->setFocused(true);
922
923    // Allow local access to file:/// and substitute data
924    WebCore::SecurityOrigin::setLocalLoadPolicy(
925            WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData);
926
927    LOGV("::WebCore:: createFrame %p", frame);
928
929    // Set the mNativeFrame field in Frame
930    SET_NATIVE_FRAME(env, obj, (int)frame);
931
932    String directory = webFrame->getRawResourceFilename(
933            WebCore::PlatformBridge::DrawableDir);
934    if (directory.isEmpty())
935        LOGE("Can't find the drawable directory");
936    else {
937        // Setup the asset manager.
938        AssetManager* am = assetManagerForJavaObject(env, jAssetManager);
939        // Initialize our skinning classes
940        WebCore::RenderSkinAndroid::Init(am, directory);
941    }
942    for (int i = WebCore::PlatformBridge::FileUploadLabel;
943            i <= WebCore::PlatformBridge::SubmitLabel; i++)
944        initGlobalLocalizedName(
945                static_cast<WebCore::PlatformBridge::rawResId>(i), webFrame);
946}
947
948static void DestroyFrame(JNIEnv* env, jobject obj)
949{
950#ifdef ANDROID_INSTRUMENT
951    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
952#endif
953    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
954    LOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!");
955
956    LOGV("::WebCore:: deleting frame %p", pFrame);
957
958    WebCore::FrameView* view = pFrame->view();
959    view->ref();
960    // detachFromParent will cause the page to be closed.
961    WebCore::FrameLoader* fl = pFrame->loader();
962    // retain a pointer because detachFromParent will set the page to null.
963    WebCore::Page* page = pFrame->page();
964    if (fl)
965        fl->detachFromParent();
966    delete page;
967    view->deref();
968
969    SET_NATIVE_FRAME(env, obj, 0);
970#if ENABLE(WDS)
971    WDS::server()->removeFrame(pFrame);
972#endif
973}
974
975static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers)
976{
977#ifdef ANDROID_INSTRUMENT
978    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
979#endif
980    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
981    LOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!");
982
983    WebCore::String webcoreUrl = to_string(env, url);
984    WebCore::KURL kurl(WebCore::KURL(), webcoreUrl);
985    WebCore::ResourceRequest request(kurl);
986    if (headers) {
987        // dalvikvm will raise exception if any of these fail
988        jclass mapClass = env->FindClass("java/util/Map");
989        jmethodID entrySet = env->GetMethodID(mapClass, "entrySet",
990                "()Ljava/util/Set;");
991        jobject set = env->CallObjectMethod(headers, entrySet);
992
993        jclass setClass = env->FindClass("java/util/Set");
994        jmethodID iterator = env->GetMethodID(setClass, "iterator",
995                "()Ljava/util/Iterator;");
996        jobject iter = env->CallObjectMethod(set, iterator);
997
998        jclass iteratorClass = env->FindClass("java/util/Iterator");
999        jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
1000        jmethodID next = env->GetMethodID(iteratorClass, "next",
1001                "()Ljava/lang/Object;");
1002        jclass entryClass = env->FindClass("java/util/Map$Entry");
1003        jmethodID getKey = env->GetMethodID(entryClass, "getKey",
1004                "()Ljava/lang/Object;");
1005        jmethodID getValue = env->GetMethodID(entryClass, "getValue",
1006                "()Ljava/lang/Object;");
1007
1008        while (env->CallBooleanMethod(iter, hasNext)) {
1009            jobject entry = env->CallObjectMethod(iter, next);
1010            jstring key = (jstring) env->CallObjectMethod(entry, getKey);
1011            jstring value = (jstring) env->CallObjectMethod(entry, getValue);
1012            request.setHTTPHeaderField(to_string(env, key), to_string(env, value));
1013            env->DeleteLocalRef(entry);
1014            env->DeleteLocalRef(key);
1015            env->DeleteLocalRef(value);
1016        }
1017
1018        env->DeleteLocalRef(entryClass);
1019        env->DeleteLocalRef(iteratorClass);
1020        env->DeleteLocalRef(iter);
1021        env->DeleteLocalRef(setClass);
1022        env->DeleteLocalRef(set);
1023        env->DeleteLocalRef(mapClass);
1024    }
1025    LOGV("LoadUrl %s", kurl.string().latin1().data());
1026    pFrame->loader()->load(request, false);
1027}
1028
1029static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData)
1030{
1031#ifdef ANDROID_INSTRUMENT
1032    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1033#endif
1034    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1035    LOG_ASSERT(pFrame, "nativePostUrl must take a valid frame pointer!");
1036
1037    WebCore::KURL kurl(WebCore::KURL(), to_string(env, url));
1038    WebCore::ResourceRequest request(kurl);
1039    request.setHTTPMethod("POST");
1040    request.setHTTPContentType("application/x-www-form-urlencoded");
1041
1042    if (postData) {
1043        jsize size = env->GetArrayLength(postData);
1044        jbyte* bytes = env->GetByteArrayElements(postData, NULL);
1045        RefPtr<FormData> formData = FormData::create((const void*)bytes, size);
1046        // the identifier uses the same logic as generateFormDataIdentifier() in
1047        // HTMLFormElement.cpp
1048        formData->setIdentifier(static_cast<int64_t>(WTF::currentTime() * 1000000.0));
1049        request.setHTTPBody(formData);
1050        env->ReleaseByteArrayElements(postData, bytes, 0);
1051    }
1052
1053    LOGV("PostUrl %s", kurl.string().latin1().data());
1054    WebCore::FrameLoadRequest frameRequest(request);
1055    pFrame->loader()->loadFrameRequest(frameRequest, false, false, 0, 0, WebCore::SendReferrer);
1056}
1057
1058static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data,
1059        jstring mimeType, jstring encoding, jstring failUrl)
1060{
1061#ifdef ANDROID_INSTRUMENT
1062    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1063#endif
1064    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1065    LOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!");
1066
1067    // Setup the resource request
1068    WebCore::ResourceRequest request(to_string(env, baseUrl));
1069
1070    // Setup the substituteData
1071    const char* dataStr = env->GetStringUTFChars(data, NULL);
1072    WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer =
1073        WebCore::SharedBuffer::create();
1074    LOG_ASSERT(dataStr, "nativeLoadData has a null data string.");
1075    sharedBuffer->append(dataStr, strlen(dataStr));
1076    env->ReleaseStringUTFChars(data, dataStr);
1077
1078    WebCore::SubstituteData substituteData(sharedBuffer,
1079            to_string(env, mimeType), to_string(env, encoding),
1080            WebCore::KURL(ParsedURLString, to_string(env, failUrl)));
1081
1082    // Perform the load
1083    pFrame->loader()->load(request, substituteData, false);
1084}
1085
1086static void StopLoading(JNIEnv *env, jobject obj)
1087{
1088#ifdef ANDROID_INSTRUMENT
1089    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1090#endif
1091    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1092    LOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!");
1093    LOGV("::WebCore:: stopLoading %p", pFrame);
1094
1095    // Stop loading the page and do not send an unload event
1096    pFrame->loader()->stopForUserCancel();
1097}
1098
1099static jstring ExternalRepresentation(JNIEnv *env, jobject obj)
1100{
1101#ifdef ANDROID_INSTRUMENT
1102    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1103#endif
1104    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1105    LOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!");
1106
1107    // Request external representation of the render tree
1108    WebCore::String renderDump = WebCore::externalRepresentation(pFrame);
1109    unsigned len = renderDump.length();
1110    if (!len)
1111        return NULL;
1112    return env->NewString(renderDump.characters(), len);
1113}
1114
1115static jstring DocumentAsText(JNIEnv *env, jobject obj)
1116{
1117#ifdef ANDROID_INSTRUMENT
1118    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1119#endif
1120    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1121    LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
1122
1123    WebCore::Element *documentElement = pFrame->document()->documentElement();
1124    if (!documentElement)
1125        return NULL;
1126    WebCore::String renderDump = ((WebCore::HTMLElement*)documentElement)->innerText();
1127    renderDump.append("\n");
1128    unsigned len = renderDump.length();
1129    if (!len)
1130        return NULL;
1131    return env->NewString((unsigned short*)renderDump.characters(), len);
1132}
1133
1134static void Reload(JNIEnv *env, jobject obj, jboolean allowStale)
1135{
1136#ifdef ANDROID_INSTRUMENT
1137    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1138#endif
1139    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1140    LOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!");
1141
1142    WebCore::FrameLoader* loader = pFrame->loader();
1143    if (allowStale) {
1144        // load the current page with FrameLoadTypeIndexedBackForward so that it
1145        // will use cache when it is possible
1146        WebCore::Page* page = pFrame->page();
1147        WebCore::HistoryItem* item = page->backForwardList()->currentItem();
1148        if (item)
1149            page->goToItem(item, FrameLoadTypeIndexedBackForward);
1150    } else
1151        loader->reload(true);
1152}
1153
1154static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos)
1155{
1156#ifdef ANDROID_INSTRUMENT
1157    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1158#endif
1159    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1160    LOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!");
1161
1162    if (pos == 1)
1163        pFrame->page()->goForward();
1164    else if (pos == -1)
1165        pFrame->page()->goBack();
1166    else
1167        pFrame->page()->goBackOrForward(pos);
1168}
1169
1170static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, jstring script)
1171{
1172#ifdef ANDROID_INSTRUMENT
1173    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1174#endif
1175    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1176    LOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!");
1177
1178    WebCore::ScriptValue value =
1179            pFrame->script()->executeScript(to_string(env, script), true);
1180    WebCore::String result = WebCore::String();
1181    ScriptState* scriptState = mainWorldScriptState(pFrame);
1182    if (!value.getString(scriptState, result))
1183        return NULL;
1184    unsigned len = result.length();
1185    if (len == 0)
1186        return NULL;
1187    return env->NewString((unsigned short*)result.characters(), len);
1188}
1189
1190// Wrap the JavaInstance used when binding custom javascript interfaces. Use a
1191// weak reference so that the gc can collect the WebView. Override virtualBegin
1192// and virtualEnd and swap the weak reference for the real object.
1193class WeakJavaInstance : public JavaInstance {
1194public:
1195#if USE(JSC)
1196    static PassRefPtr<WeakJavaInstance> create(jobject obj, PassRefPtr<RootObject> root)
1197    {
1198        return adoptRef(new WeakJavaInstance(obj, root));
1199    }
1200#elif USE(V8)
1201    static PassRefPtr<WeakJavaInstance> create(jobject obj)
1202    {
1203        return adoptRef(new WeakJavaInstance(obj));
1204    }
1205#endif
1206
1207private:
1208#if USE(JSC)
1209    WeakJavaInstance(jobject instance, PassRefPtr<RootObject> rootObject)
1210        : JavaInstance(instance, rootObject)
1211#elif USE(V8)
1212    WeakJavaInstance(jobject instance)
1213        : JavaInstance(instance)
1214#endif
1215        , m_beginEndDepth(0)
1216    {
1217        JNIEnv* env = getJNIEnv();
1218        // JavaInstance creates a global ref to instance in its constructor.
1219        env->DeleteGlobalRef(m_instance->instance());
1220        // Set the object to a weak reference.
1221        m_instance->setInstance(env->NewWeakGlobalRef(instance));
1222    }
1223    ~WeakJavaInstance()
1224    {
1225        JNIEnv* env = getJNIEnv();
1226        // Store the weak reference so we can delete it later.
1227        jweak weak = m_instance->instance();
1228        // The JavaInstance destructor attempts to delete the global ref stored
1229        // in m_instance. Since we replaced it in our constructor with a weak
1230        // reference, restore the global ref here so the vm will not complain.
1231        m_instance->setInstance(env->NewGlobalRef(
1232                getRealObject(env, m_instance->instance()).get()));
1233        // Delete the weak reference.
1234        env->DeleteWeakGlobalRef(weak);
1235    }
1236
1237    virtual void virtualBegin()
1238    {
1239        if (m_beginEndDepth++ > 0)
1240            return;
1241        m_weakRef = m_instance->instance();
1242        JNIEnv* env = getJNIEnv();
1243        // This is odd. getRealObject returns an AutoJObject which is used to
1244        // cleanly create and delete a local reference. But, here we need to
1245        // maintain the local reference across calls to virtualBegin() and
1246        // virtualEnd(). So, release the local reference from the AutoJObject
1247        // and delete the local reference in virtualEnd().
1248        m_realObject = getRealObject(env, m_weakRef).release();
1249        // Point to the real object
1250        m_instance->setInstance(m_realObject);
1251        // Call the base class method
1252        INHERITED::virtualBegin();
1253    }
1254
1255    virtual void virtualEnd()
1256    {
1257        if (--m_beginEndDepth > 0)
1258            return;
1259        // Call the base class method first to pop the local frame.
1260        INHERITED::virtualEnd();
1261        // Get rid of the local reference to the real object.
1262        getJNIEnv()->DeleteLocalRef(m_realObject);
1263        // Point back to the WeakReference.
1264        m_instance->setInstance(m_weakRef);
1265    }
1266
1267private:
1268    typedef JavaInstance INHERITED;
1269    jobject m_realObject;
1270    jweak m_weakRef;
1271    // The current depth of nested calls to virtualBegin and virtualEnd.
1272    int m_beginEndDepth;
1273};
1274
1275static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer,
1276        jobject javascriptObj, jstring interfaceName)
1277{
1278#ifdef ANDROID_INSTRUMENT
1279    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1280#endif
1281    WebCore::Frame* pFrame = 0;
1282    if (nativeFramePointer == 0)
1283        pFrame = GET_NATIVE_FRAME(env, obj);
1284    else
1285        pFrame = (WebCore::Frame*)nativeFramePointer;
1286    LOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!");
1287
1288    JavaVM* vm;
1289    env->GetJavaVM(&vm);
1290    LOGV("::WebCore:: addJSInterface: %p", pFrame);
1291
1292#if USE(JSC)
1293    // Copied from qwebframe.cpp
1294    JSC::JSLock lock(false);
1295    WebCore::JSDOMWindow *window = WebCore::toJSDOMWindow(pFrame, mainThreadNormalWorld());
1296    if (window) {
1297        RootObject *root = pFrame->script()->bindingRootObject();
1298        setJavaVM(vm);
1299        // Add the binding to JS environment
1300        JSC::ExecState* exec = window->globalExec();
1301        JSC::JSObject* addedObject = WeakJavaInstance::create(javascriptObj,
1302                root)->createRuntimeObject(exec);
1303        const jchar* s = env->GetStringChars(interfaceName, NULL);
1304        if (s) {
1305            // Add the binding name to the window's table of child objects.
1306            JSC::PutPropertySlot slot;
1307            window->put(exec, JSC::Identifier(exec, (const UChar *)s,
1308                    env->GetStringLength(interfaceName)), addedObject, slot);
1309            env->ReleaseStringChars(interfaceName, s);
1310            checkException(env);
1311        }
1312    }
1313#elif USE(V8)
1314    if (pFrame) {
1315        PassRefPtr<JavaInstance> addedObject = WeakJavaInstance::create(javascriptObj);
1316        const char* name = getCharactersFromJStringInEnv(env, interfaceName);
1317        // Pass ownership of the added object to bindToWindowObject.
1318        NPObject* npObject = JavaInstanceToNPObject(addedObject);
1319        pFrame->script()->bindToWindowObject(pFrame, name, npObject);
1320        // bindToWindowObject calls NPN_RetainObject on the
1321        // returned one (see createV8ObjectForNPObject in V8NPObject.cpp).
1322        // bindToWindowObject also increases obj's ref count and decreases
1323        // the ref count when the object is not reachable from JavaScript
1324        // side. Code here must release the reference count increased by
1325        // bindToWindowObject.
1326
1327        // Note that while this function is declared in WebCore/bridge/npruntime.h, for V8 builds
1328        // we use WebCore/bindings/v8/npruntime.cpp (rather than
1329        // WebCore/bridge/npruntime.cpp), so the function is implemented there.
1330        // TODO: Combine the two versions of these NPAPI files.
1331        NPN_ReleaseObject(npObject);
1332        releaseCharactersForJString(interfaceName, name);
1333    }
1334#endif
1335
1336}
1337
1338static void SetCacheDisabled(JNIEnv *env, jobject obj, jboolean disabled)
1339{
1340#ifdef ANDROID_INSTRUMENT
1341    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1342#endif
1343    WebCore::cache()->setDisabled(disabled);
1344}
1345
1346static jboolean CacheDisabled(JNIEnv *env, jobject obj)
1347{
1348#ifdef ANDROID_INSTRUMENT
1349    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1350#endif
1351    return WebCore::cache()->disabled();
1352}
1353
1354static void ClearCache(JNIEnv *env, jobject obj)
1355{
1356#ifdef ANDROID_INSTRUMENT
1357    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1358#if USE(JSC)
1359    JSC::JSLock lock(false);
1360    JSC::Heap::Statistics jsHeapStatistics = WebCore::JSDOMWindow::commonJSGlobalData()->heap.statistics();
1361    LOGD("About to gc and JavaScript heap size is %d and has %d bytes free",
1362            jsHeapStatistics.size, jsHeapStatistics.free);
1363#endif  // USE(JSC)
1364    LOGD("About to clear cache and current cache has %d bytes live and %d bytes dead",
1365            cache()->getLiveSize(), cache()->getDeadSize());
1366#endif  // ANDROID_INSTRUMENT
1367    if (!WebCore::cache()->disabled()) {
1368        // Disabling the cache will remove all resources from the cache.  They may
1369        // still live on if they are referenced by some Web page though.
1370        WebCore::cache()->setDisabled(true);
1371        WebCore::cache()->setDisabled(false);
1372    }
1373
1374    // clear page cache
1375    int pageCapacity = WebCore::pageCache()->capacity();
1376    // Setting size to 0, makes all pages be released.
1377    WebCore::pageCache()->setCapacity(0);
1378    WebCore::pageCache()->releaseAutoreleasedPagesNow();
1379    WebCore::pageCache()->setCapacity(pageCapacity);
1380
1381#if USE(JSC)
1382    // force JavaScript to GC when clear cache
1383    WebCore::gcController().garbageCollectSoon();
1384#elif USE(V8)
1385    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1386    pFrame->script()->lowMemoryNotification();
1387#endif  // USE(JSC)
1388}
1389
1390static jboolean DocumentHasImages(JNIEnv *env, jobject obj)
1391{
1392#ifdef ANDROID_INSTRUMENT
1393    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1394#endif
1395    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1396    LOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!");
1397
1398    return pFrame->document()->images()->length() > 0;
1399}
1400
1401static jboolean HasPasswordField(JNIEnv *env, jobject obj)
1402{
1403#ifdef ANDROID_INSTRUMENT
1404    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1405#endif
1406    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1407    LOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!");
1408
1409    bool found = false;
1410    WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1411    WebCore::Node* node = form->firstItem();
1412    // Null/Empty namespace means that node is not created in HTMLFormElement
1413    // class, but just normal Element class.
1414    while (node && !found && !node->namespaceURI().isNull() &&
1415           !node->namespaceURI().isEmpty()) {
1416        WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
1417        		((WebCore::HTMLFormElement*)node)->formElements;
1418        size_t size = elements.size();
1419        for (size_t i = 0; i< size && !found; i++) {
1420            WebCore::HTMLFormControlElement* e = elements[i];
1421            if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1422                if (((WebCore::HTMLInputElement*)e)->inputType() ==
1423                		WebCore::HTMLInputElement::PASSWORD)
1424                    found = true;
1425            }
1426        }
1427        node = form->nextItem();
1428    }
1429    return found;
1430}
1431
1432static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
1433{
1434#ifdef ANDROID_INSTRUMENT
1435    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1436#endif
1437    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1438    LOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!");
1439    jobjectArray strArray = NULL;
1440
1441    WebCore::String username, password;
1442    bool found = false;
1443    WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1444    WebCore::Node* node = form->firstItem();
1445    while (node && !found && !node->namespaceURI().isNull() &&
1446           !node->namespaceURI().isEmpty()) {
1447        WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
1448        		((WebCore::HTMLFormElement*)node)->formElements;
1449        size_t size = elements.size();
1450        for (size_t i = 0; i< size && !found; i++) {
1451            WebCore::HTMLFormControlElement* e = elements[i];
1452            if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1453                WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
1454                if (input->autoComplete() == false)
1455                    continue;
1456                if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
1457                    password = input->value();
1458                else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
1459                    username = input->value();
1460                if (!username.isNull() && !password.isNull())
1461                    found = true;
1462            }
1463        }
1464        node = form->nextItem();
1465    }
1466    if (found) {
1467        jclass stringClass = env->FindClass("java/lang/String");
1468        strArray = env->NewObjectArray(2, stringClass, NULL);
1469        env->SetObjectArrayElement(strArray, 0, env->NewString((unsigned short *)
1470                username.characters(), username.length()));
1471        env->SetObjectArrayElement(strArray, 1, env->NewString((unsigned short *)
1472                password.characters(), password.length()));
1473    }
1474    return strArray;
1475}
1476
1477static void SetUsernamePassword(JNIEnv *env, jobject obj,
1478    jstring username, jstring password)
1479{
1480#ifdef ANDROID_INSTRUMENT
1481    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1482#endif
1483    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1484    LOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!");
1485
1486    WebCore::HTMLInputElement* usernameEle = NULL;
1487    WebCore::HTMLInputElement* passwordEle = NULL;
1488    bool found = false;
1489    WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1490    WebCore::Node* node = form->firstItem();
1491    while (node && !found && !node->namespaceURI().isNull() &&
1492           !node->namespaceURI().isEmpty()) {
1493        WTF::Vector<WebCore::HTMLFormControlElement*>& elements =
1494        		((WebCore::HTMLFormElement*)node)->formElements;
1495        size_t size = elements.size();
1496        for (size_t i = 0; i< size && !found; i++) {
1497            WebCore::HTMLFormControlElement* e = elements[i];
1498            if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1499                WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
1500                if (input->autoComplete() == false)
1501                    continue;
1502                if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
1503                    passwordEle = input;
1504                else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
1505                    usernameEle = input;
1506                if (usernameEle != NULL && passwordEle != NULL)
1507                    found = true;
1508            }
1509        }
1510        node = form->nextItem();
1511    }
1512    if (found) {
1513        usernameEle->setValue(to_string(env, username));
1514        passwordEle->setValue(to_string(env, password));
1515    }
1516}
1517
1518static jobject GetFormTextData(JNIEnv *env, jobject obj)
1519{
1520#ifdef ANDROID_INSTRUMENT
1521    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1522#endif
1523    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1524    LOG_ASSERT(pFrame, "GetFormTextData must take a valid frame pointer!");
1525    jobject hashMap = NULL;
1526
1527    WTF::PassRefPtr<WebCore::HTMLCollection> collection = pFrame->document()->forms();
1528    if (collection->length() > 0) {
1529        jclass mapClass = env->FindClass("java/util/HashMap");
1530        LOG_ASSERT(mapClass, "Could not find HashMap class!");
1531        jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
1532        LOG_ASSERT(init, "Could not find constructor for HashMap");
1533        hashMap = env->NewObject(mapClass, init, 1);
1534        LOG_ASSERT(hashMap, "Could not create a new HashMap");
1535        jmethodID put = env->GetMethodID(mapClass, "put",
1536                "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1537        LOG_ASSERT(put, "Could not find put method on HashMap");
1538
1539        WebCore::HTMLFormElement* form;
1540        WebCore::HTMLInputElement* input;
1541        for (WebCore::Node* node = collection->firstItem();
1542             node && !node->namespaceURI().isNull() && !node->namespaceURI().isEmpty();
1543             node = collection->nextItem()) {
1544            form = static_cast<WebCore::HTMLFormElement*>(node);
1545            if (form->autoComplete()) {
1546                WTF::Vector<WebCore::HTMLFormControlElement*> elements = form->formElements;
1547                size_t size = elements.size();
1548                for (size_t i = 0; i < size; i++) {
1549                    WebCore::HTMLFormControlElement* e = elements[i];
1550                    if (e->hasTagName(WebCore::HTMLNames::inputTag)) {
1551                        input = static_cast<WebCore::HTMLInputElement*>(e);
1552                        if (input->isTextField() && !input->isPasswordField()
1553                                && input->autoComplete()) {
1554                            WebCore::String value = input->value();
1555                            int len = value.length();
1556                            if (len) {
1557                                const WebCore::AtomicString& name = input->name();
1558                                jstring key = env->NewString((jchar *)name.characters(), name.length());
1559                                jstring val = env->NewString((jchar *)value.characters(), len);
1560                                LOG_ASSERT(key && val, "name or value not set");
1561                                env->CallObjectMethod(hashMap, put, key, val);
1562                                env->DeleteLocalRef(key);
1563                                env->DeleteLocalRef(val);
1564                            }
1565                        }
1566                    }
1567                }
1568            }
1569        }
1570        env->DeleteLocalRef(mapClass);
1571
1572    }
1573    return hashMap;
1574}
1575
1576static void OrientationChanged(JNIEnv *env, jobject obj, int orientation)
1577{
1578#ifdef ANDROID_INSTRUMENT
1579    TimeCounterAuto counter(TimeCounter::NativeCallbackTimeCounter);
1580#endif
1581    WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1582    LOGV("Sending orientation: %d", orientation);
1583    pFrame->sendOrientationChangeEvent(orientation);
1584}
1585
1586// ----------------------------------------------------------------------------
1587
1588/*
1589 * JNI registration.
1590 */
1591static JNINativeMethod gBrowserFrameNativeMethods[] = {
1592    /* name, signature, funcPtr */
1593    { "nativeCallPolicyFunction", "(II)V",
1594        (void*) CallPolicyFunction },
1595    { "nativeCreateFrame", "(Landroid/webkit/WebViewCore;Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V",
1596        (void*) CreateFrame },
1597    { "nativeDestroyFrame", "()V",
1598        (void*) DestroyFrame },
1599    { "nativeStopLoading", "()V",
1600        (void*) StopLoading },
1601    { "nativeLoadUrl", "(Ljava/lang/String;Ljava/util/Map;)V",
1602        (void*) LoadUrl },
1603    { "nativePostUrl", "(Ljava/lang/String;[B)V",
1604        (void*) PostUrl },
1605    { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
1606        (void*) LoadData },
1607    { "externalRepresentation", "()Ljava/lang/String;",
1608        (void*) ExternalRepresentation },
1609    { "documentAsText", "()Ljava/lang/String;",
1610        (void*) DocumentAsText },
1611    { "reload", "(Z)V",
1612        (void*) Reload },
1613    { "nativeGoBackOrForward", "(I)V",
1614        (void*) GoBackOrForward },
1615    { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;)V",
1616        (void*) AddJavascriptInterface },
1617    { "stringByEvaluatingJavaScriptFromString",
1618            "(Ljava/lang/String;)Ljava/lang/String;",
1619        (void*) StringByEvaluatingJavaScriptFromString },
1620    { "setCacheDisabled", "(Z)V",
1621        (void*) SetCacheDisabled },
1622    { "cacheDisabled", "()Z",
1623        (void*) CacheDisabled },
1624    { "clearCache", "()V",
1625        (void*) ClearCache },
1626    { "documentHasImages", "()Z",
1627        (void*) DocumentHasImages },
1628    { "hasPasswordField", "()Z",
1629        (void*) HasPasswordField },
1630    { "getUsernamePassword", "()[Ljava/lang/String;",
1631        (void*) GetUsernamePassword },
1632    { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V",
1633        (void*) SetUsernamePassword },
1634    { "getFormTextData", "()Ljava/util/HashMap;",
1635        (void*) GetFormTextData },
1636    { "nativeOrientationChanged", "(I)V",
1637        (void*) OrientationChanged }
1638};
1639
1640int register_webframe(JNIEnv* env)
1641{
1642    jclass clazz = env->FindClass("android/webkit/BrowserFrame");
1643    LOG_ASSERT(clazz, "Cannot find BrowserFrame");
1644    gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I");
1645    LOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame");
1646
1647    return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame",
1648            gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods));
1649}
1650
1651} /* namespace android */
1652