Home | History | Annotate | Download | only in jni
      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 
    114 using namespace JSC::Bindings;
    115 
    116 static String* gUploadFileLabel;
    117 static String* gResetLabel;
    118 static String* gSubmitLabel;
    119 
    120 String* 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  */
    137 void 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 
    159 namespace android {
    160 
    161 // ----------------------------------------------------------------------------
    162 
    163 #define WEBCORE_MEMORY_CAP 15 * 1024 * 1024
    164 
    165 // ----------------------------------------------------------------------------
    166 
    167 struct 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 
    199 static 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 
    205 WebFrame::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 
    275 WebFrame::~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 
    286 WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame)
    287 {
    288     FrameLoaderClientAndroid* client =
    289             static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
    290     return client->webFrame();
    291 }
    292 
    293 static 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.
    330 static 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.
    341 class FileInfo {
    342 public:
    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; }
    355 private:
    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 
    363 PassRefPtr<WebCore::ResourceLoaderAndroid>
    364 WebFrame::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 
    508 void
    509 WebFrame::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 
    526 void
    527 WebFrame::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 
    577 void
    578 WebFrame::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 
    591 void
    592 WebFrame::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 
    614 void
    615 WebFrame::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 
    625 void
    626 WebFrame::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 
    636 void
    637 WebFrame::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 
    647 void
    648 WebFrame::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 
    665 void
    666 WebFrame::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 
    678 void
    679 WebFrame::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 
    690 const WebCore::String
    691 WebFrame::userAgentForURL(const WebCore::KURL* url)
    692 {
    693     return mUserAgent;
    694 }
    695 
    696 void
    697 WebFrame::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 
    713 void
    714 WebFrame::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 
    728 void
    729 WebFrame::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 
    742 bool
    743 WebFrame::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 
    771 WebCore::Frame*
    772 WebFrame::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 
    787 void
    788 WebFrame::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 
    798 void
    799 WebFrame::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 
    810 struct PolicyFunctionWrapper {
    811     WebCore::FramePolicyFunction func;
    812 };
    813 
    814 void
    815 WebFrame::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 
    826 WebCore::String
    827 WebFrame::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 
    836 float
    837 WebFrame::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 // ----------------------------------------------------------------------------
    846 static 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 
    863 static 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 
    948 static 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 
    975 static 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 
   1029 static 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 
   1058 static 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 
   1086 static 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 
   1099 static 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 
   1115 static 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 
   1134 static 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 
   1154 static 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 
   1170 static 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.
   1193 class WeakJavaInstance : public JavaInstance {
   1194 public:
   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 
   1207 private:
   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 
   1267 private:
   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 
   1275 static 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 
   1338 static 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 
   1346 static 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 
   1354 static 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 
   1390 static 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 
   1401 static 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 
   1432 static 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 
   1477 static 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 
   1518 static 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 
   1576 static 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  */
   1591 static 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 
   1640 int 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