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 "BackForwardList.h"
     33 #include "MemoryCache.h"
     34 #include "Chrome.h"
     35 #include "ChromeClientAndroid.h"
     36 #include "ChromiumInit.h"
     37 #include "ContextMenuClientAndroid.h"
     38 #include "DeviceMotionClientAndroid.h"
     39 #include "DeviceOrientationClientAndroid.h"
     40 #include "Document.h"
     41 #include "DocumentLoader.h"
     42 #include "DragClientAndroid.h"
     43 #include "EditorClientAndroid.h"
     44 #include "Element.h"
     45 #include "FocusController.h"
     46 #include "Font.h"
     47 #include "Frame.h"
     48 #include "FrameLoader.h"
     49 #include "FrameLoaderClientAndroid.h"
     50 #include "FrameLoadRequest.h"
     51 #include "FrameTree.h"
     52 #include "FrameView.h"
     53 #include "GeolocationClientAndroid.h"
     54 #include "GraphicsContext.h"
     55 #include "HistoryItem.h"
     56 #include "HTMLCollection.h"
     57 #include "HTMLElement.h"
     58 #include "HTMLFormElement.h"
     59 #include "HTMLInputElement.h"
     60 #include "HTMLNames.h"
     61 #include "IconDatabase.h"
     62 #include "Image.h"
     63 #include "InspectorClientAndroid.h"
     64 #include "JavaClassJobjectV8.h"
     65 #include "JavaNPObjectV8.h"
     66 #include "JavaInstanceJobjectV8.h"
     67 #include "KURL.h"
     68 #include "Page.h"
     69 #include "PageCache.h"
     70 #include "PlatformString.h"
     71 #include "RenderPart.h"
     72 #include "RenderSkinAndroid.h"
     73 #include "RenderTreeAsText.h"
     74 #include "RenderView.h"
     75 #include "ResourceHandle.h"
     76 #include "ResourceHandleInternal.h"
     77 #include "ScriptController.h"
     78 #include "ScriptValue.h"
     79 #include "SecurityOrigin.h"
     80 #include "SelectionController.h"
     81 #include "Settings.h"
     82 #include "SubstituteData.h"
     83 #include "UrlInterceptResponse.h"
     84 #include "UserGestureIndicator.h"
     85 #include "WebArchiveAndroid.h"
     86 #include "WebCache.h"
     87 #include "WebCoreJni.h"
     88 #include "WebHistory.h"
     89 #include "WebIconDatabase.h"
     90 #include "WebFrameView.h"
     91 #include "WebUrlLoaderClient.h"
     92 #include "WebViewCore.h"
     93 #include "jni.h"
     94 #include "wds/DebugServer.h"
     95 
     96 #include <JNIUtility.h>
     97 #include <JNIHelp.h>
     98 #include <ScopedPrimitiveArray.h>
     99 #include <ScopedLocalRef.h>
    100 #include <SkGraphics.h>
    101 #include <android_runtime/android_util_AssetManager.h>
    102 #include <openssl/x509.h>
    103 #include <utils/misc.h>
    104 #include <androidfw/AssetManager.h>
    105 #include <wtf/CurrentTime.h>
    106 #include <wtf/Platform.h>
    107 #include <wtf/text/AtomicString.h>
    108 #include <wtf/text/CString.h>
    109 #include <wtf/text/StringBuilder.h>
    110 
    111 #if ENABLE(WEB_AUTOFILL)
    112 #include "autofill/WebAutofill.h"
    113 #endif
    114 
    115 using namespace JSC::Bindings;
    116 
    117 static String* gUploadFileLabel;
    118 static String* gResetLabel;
    119 static String* gSubmitLabel;
    120 static String* gNoFileChosenLabel;
    121 
    122 String* WebCore::PlatformBridge::globalLocalizedName(
    123         WebCore::PlatformBridge::rawResId resId)
    124 {
    125     switch (resId) {
    126     case WebCore::PlatformBridge::FileUploadLabel:
    127         return gUploadFileLabel;
    128     case WebCore::PlatformBridge::ResetLabel:
    129         return gResetLabel;
    130     case WebCore::PlatformBridge::SubmitLabel:
    131         return gSubmitLabel;
    132     case WebCore::PlatformBridge::FileUploadNoFileChosenLabel:
    133         return gNoFileChosenLabel;
    134 
    135     default:
    136         return 0;
    137     }
    138 }
    139 /**
    140  * Instantiate the localized name desired.
    141  */
    142 void initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId,
    143         android::WebFrame* webFrame)
    144 {
    145     String** pointer;
    146     switch (resId) {
    147     case WebCore::PlatformBridge::FileUploadLabel:
    148         pointer = &gUploadFileLabel;
    149         break;
    150     case WebCore::PlatformBridge::ResetLabel:
    151         pointer = &gResetLabel;
    152         break;
    153     case WebCore::PlatformBridge::SubmitLabel:
    154         pointer = &gSubmitLabel;
    155         break;
    156     case WebCore::PlatformBridge::FileUploadNoFileChosenLabel:
    157         pointer = &gNoFileChosenLabel;
    158         break;
    159     default:
    160         return;
    161     }
    162     if (!(*pointer) && webFrame) {
    163         (*pointer) = new String(webFrame->getRawResourceFilename(resId).impl());
    164     }
    165 }
    166 
    167 namespace android {
    168 
    169 // ----------------------------------------------------------------------------
    170 
    171 #define WEBCORE_MEMORY_CAP 15 * 1024 * 1024
    172 
    173 // ----------------------------------------------------------------------------
    174 
    175 struct WebFrame::JavaBrowserFrame
    176 {
    177     jweak       mObj;
    178     jweak       mHistoryList; // WebBackForwardList object
    179     jmethodID   mStartLoadingResource;
    180     jmethodID   mMaybeSavePassword;
    181     jmethodID   mShouldInterceptRequest;
    182     jmethodID   mLoadStarted;
    183     jmethodID   mTransitionToCommitted;
    184     jmethodID   mLoadFinished;
    185     jmethodID   mReportError;
    186     jmethodID   mSetTitle;
    187     jmethodID   mWindowObjectCleared;
    188     jmethodID   mSetProgress;
    189     jmethodID   mDidReceiveIcon;
    190     jmethodID   mDidReceiveTouchIconUrl;
    191     jmethodID   mUpdateVisitedHistory;
    192     jmethodID   mHandleUrl;
    193     jmethodID   mCreateWindow;
    194     jmethodID   mCloseWindow;
    195     jmethodID   mDecidePolicyForFormResubmission;
    196     jmethodID   mRequestFocus;
    197     jmethodID   mGetRawResFilename;
    198     jmethodID   mDensity;
    199     jmethodID   mGetFileSize;
    200     jmethodID   mGetFile;
    201     jmethodID   mDidReceiveAuthenticationChallenge;
    202     jmethodID   mReportSslCertError;
    203     jmethodID   mRequestClientCert;
    204     jmethodID   mDownloadStart;
    205     jmethodID   mDidReceiveData;
    206     jmethodID   mDidFinishLoading;
    207     jmethodID   mSetCertificate;
    208     jmethodID   mShouldSaveFormData;
    209     jmethodID   mSaveFormData;
    210     jmethodID   mAutoLogin;
    211     AutoJObject frame(JNIEnv* env) {
    212         return getRealObject(env, mObj);
    213     }
    214     AutoJObject history(JNIEnv* env) {
    215         return getRealObject(env, mHistoryList);
    216     }
    217 };
    218 
    219 static jfieldID gFrameField;
    220 #define GET_NATIVE_FRAME(env, obj) ((WebCore::Frame*)env->GetIntField(obj, gFrameField))
    221 #define SET_NATIVE_FRAME(env, obj, frame) (env->SetIntField(obj, gFrameField, frame))
    222 
    223 // ----------------------------------------------------------------------------
    224 
    225 WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page)
    226     : mPage(page)
    227 {
    228     jclass clazz = env->GetObjectClass(obj);
    229     mJavaFrame = new JavaBrowserFrame;
    230     mJavaFrame->mObj = env->NewWeakGlobalRef(obj);
    231     mJavaFrame->mHistoryList = env->NewWeakGlobalRef(historyList);
    232     mJavaFrame->mMaybeSavePassword = env->GetMethodID(clazz, "maybeSavePassword",
    233             "([BLjava/lang/String;Ljava/lang/String;)V");
    234     mJavaFrame->mShouldInterceptRequest =
    235             env->GetMethodID(clazz, "shouldInterceptRequest",
    236             "(Ljava/lang/String;)Landroid/webkit/WebResourceResponse;");
    237     mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted",
    238             "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V");
    239     mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted",
    240             "(IZ)V");
    241     mJavaFrame->mLoadFinished = env->GetMethodID(clazz, "loadFinished",
    242             "(Ljava/lang/String;IZ)V");
    243     mJavaFrame->mReportError = env->GetMethodID(clazz, "reportError",
    244             "(ILjava/lang/String;Ljava/lang/String;)V");
    245     mJavaFrame->mSetTitle = env->GetMethodID(clazz, "setTitle",
    246             "(Ljava/lang/String;)V");
    247     mJavaFrame->mWindowObjectCleared = env->GetMethodID(clazz, "windowObjectCleared",
    248             "(I)V");
    249     mJavaFrame->mSetProgress = env->GetMethodID(clazz, "setProgress",
    250             "(I)V");
    251     mJavaFrame->mDidReceiveIcon = env->GetMethodID(clazz, "didReceiveIcon",
    252             "(Landroid/graphics/Bitmap;)V");
    253     mJavaFrame->mDidReceiveTouchIconUrl = env->GetMethodID(clazz, "didReceiveTouchIconUrl",
    254             "(Ljava/lang/String;Z)V");
    255     mJavaFrame->mUpdateVisitedHistory = env->GetMethodID(clazz, "updateVisitedHistory",
    256             "(Ljava/lang/String;Z)V");
    257     mJavaFrame->mHandleUrl = env->GetMethodID(clazz, "handleUrl",
    258             "(Ljava/lang/String;)Z");
    259     mJavaFrame->mCreateWindow = env->GetMethodID(clazz, "createWindow",
    260             "(ZZ)Landroid/webkit/BrowserFrame;");
    261     mJavaFrame->mCloseWindow = env->GetMethodID(clazz, "closeWindow",
    262             "(Landroid/webkit/WebViewCore;)V");
    263     mJavaFrame->mDecidePolicyForFormResubmission = env->GetMethodID(clazz,
    264             "decidePolicyForFormResubmission", "(I)V");
    265     mJavaFrame->mRequestFocus = env->GetMethodID(clazz, "requestFocus",
    266             "()V");
    267     mJavaFrame->mGetRawResFilename = env->GetMethodID(clazz, "getRawResFilename",
    268             "(I)Ljava/lang/String;");
    269     mJavaFrame->mDensity = env->GetMethodID(clazz, "density","()F");
    270     mJavaFrame->mGetFileSize = env->GetMethodID(clazz, "getFileSize", "(Ljava/lang/String;)I");
    271     mJavaFrame->mGetFile = env->GetMethodID(clazz, "getFile", "(Ljava/lang/String;[BII)I");
    272     mJavaFrame->mDidReceiveAuthenticationChallenge = env->GetMethodID(clazz, "didReceiveAuthenticationChallenge",
    273             "(ILjava/lang/String;Ljava/lang/String;ZZ)V");
    274     mJavaFrame->mReportSslCertError = env->GetMethodID(clazz, "reportSslCertError", "(II[BLjava/lang/String;)V");
    275     mJavaFrame->mRequestClientCert = env->GetMethodID(clazz, "requestClientCert", "(ILjava/lang/String;)V");
    276     mJavaFrame->mDownloadStart = env->GetMethodID(clazz, "downloadStart",
    277             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V");
    278     mJavaFrame->mDidReceiveData = env->GetMethodID(clazz, "didReceiveData", "([BI)V");
    279     mJavaFrame->mDidFinishLoading = env->GetMethodID(clazz, "didFinishLoading", "()V");
    280     mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", "([B)V");
    281     mJavaFrame->mShouldSaveFormData = env->GetMethodID(clazz, "shouldSaveFormData", "()Z");
    282     mJavaFrame->mSaveFormData = env->GetMethodID(clazz, "saveFormData", "(Ljava/util/HashMap;)V");
    283     mJavaFrame->mAutoLogin = env->GetMethodID(clazz, "autoLogin",
    284             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
    285     env->DeleteLocalRef(clazz);
    286 
    287     ALOG_ASSERT(mJavaFrame->mMaybeSavePassword, "Could not find method maybeSavePassword");
    288     ALOG_ASSERT(mJavaFrame->mShouldInterceptRequest, "Could not find method shouldInterceptRequest");
    289     ALOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted");
    290     ALOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted");
    291     ALOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished");
    292     ALOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError");
    293     ALOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle");
    294     ALOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared");
    295     ALOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress");
    296     ALOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon");
    297     ALOG_ASSERT(mJavaFrame->mDidReceiveTouchIconUrl, "Could not find method didReceiveTouchIconUrl");
    298     ALOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory");
    299     ALOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl");
    300     ALOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow");
    301     ALOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow");
    302     ALOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission");
    303     ALOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus");
    304     ALOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename");
    305     ALOG_ASSERT(mJavaFrame->mDensity, "Could not find method density");
    306     ALOG_ASSERT(mJavaFrame->mGetFileSize, "Could not find method getFileSize");
    307     ALOG_ASSERT(mJavaFrame->mGetFile, "Could not find method getFile");
    308     ALOG_ASSERT(mJavaFrame->mDidReceiveAuthenticationChallenge, "Could not find method didReceiveAuthenticationChallenge");
    309     ALOG_ASSERT(mJavaFrame->mReportSslCertError, "Could not find method reportSslCertError");
    310     ALOG_ASSERT(mJavaFrame->mRequestClientCert, "Could not find method requestClientCert");
    311     ALOG_ASSERT(mJavaFrame->mDownloadStart, "Could not find method downloadStart");
    312     ALOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData");
    313     ALOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading");
    314     ALOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate");
    315     ALOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData");
    316     ALOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData");
    317     ALOG_ASSERT(mJavaFrame->mAutoLogin, "Could not find method autoLogin");
    318 
    319     mUserAgent = WTF::String();
    320     mBlockNetworkLoads = false;
    321     m_renderSkins = 0;
    322 }
    323 
    324 WebFrame::~WebFrame()
    325 {
    326     if (mJavaFrame->mObj) {
    327         JNIEnv* env = getJNIEnv();
    328         env->DeleteWeakGlobalRef(mJavaFrame->mObj);
    329         env->DeleteWeakGlobalRef(mJavaFrame->mHistoryList);
    330         mJavaFrame->mObj = 0;
    331     }
    332     delete mJavaFrame;
    333     delete m_renderSkins;
    334 }
    335 
    336 WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame)
    337 {
    338     FrameLoaderClientAndroid* client =
    339             static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
    340     return client->webFrame();
    341 }
    342 
    343 static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map)
    344 {
    345     jclass mapClass = env->FindClass("java/util/HashMap");
    346     ALOG_ASSERT(mapClass, "Could not find HashMap class!");
    347     jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
    348     ALOG_ASSERT(init, "Could not find constructor for HashMap");
    349     jobject hashMap = env->NewObject(mapClass, init, map.size());
    350     ALOG_ASSERT(hashMap, "Could not create a new HashMap");
    351     jmethodID put = env->GetMethodID(mapClass, "put",
    352             "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
    353     ALOG_ASSERT(put, "Could not find put method on HashMap");
    354 
    355     WebCore::HTTPHeaderMap::const_iterator end = map.end();
    356     for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) {
    357         if (i->first.length() == 0 || i->second.length() == 0)
    358             continue;
    359         jstring key = wtfStringToJstring(env, i->first);
    360         jstring val = wtfStringToJstring(env, i->second);
    361         if (key && val) {
    362             env->CallObjectMethod(hashMap, put, key, val);
    363         }
    364         env->DeleteLocalRef(key);
    365         env->DeleteLocalRef(val);
    366     }
    367 
    368     env->DeleteLocalRef(mapClass);
    369 
    370     return hashMap;
    371 }
    372 
    373 // This class stores the URI and the size of each file for upload.  The URI is
    374 // stored so we do not have to create it again.  The size is stored so we can
    375 // compare the actual size of the file with the stated size.  If the actual size
    376 // is larger, we will not copy it, since we will not have enough space in our
    377 // buffer.
    378 class FileInfo {
    379 public:
    380     FileInfo(JNIEnv* env, const WTF::String& name) {
    381         m_uri = wtfStringToJstring(env, name);
    382         checkException(env);
    383         m_size = 0;
    384         m_env = env;
    385     }
    386     ~FileInfo() {
    387         m_env->DeleteLocalRef(m_uri);
    388     }
    389     int getSize() { return m_size; }
    390     jstring getUri() { return m_uri; }
    391     void setSize(int size) { m_size = size; }
    392 private:
    393     // This is only a pointer to the JNIEnv* returned by
    394     // JSC::Bindings::getJNIEnv().  Used to delete the jstring when finished.
    395     JNIEnv* m_env;
    396     jstring m_uri;
    397     int m_size;
    398 };
    399 
    400 UrlInterceptResponse*
    401 WebFrame::shouldInterceptRequest(const WTF::String& url)
    402 {
    403     ALOGV("::WebCore:: shouldInterceptRequest(%s)", url.latin1().data());
    404 
    405     JNIEnv* env = getJNIEnv();
    406     AutoJObject javaFrame = mJavaFrame->frame(env);
    407     if (!javaFrame.get())
    408         return 0;
    409 
    410     jstring urlStr = wtfStringToJstring(env, url);
    411     jobject response = env->CallObjectMethod(javaFrame.get(), mJavaFrame->mShouldInterceptRequest, urlStr);
    412     env->DeleteLocalRef(urlStr);
    413     if (response == 0)
    414         return 0;
    415     UrlInterceptResponse* result = new UrlInterceptResponse(env, response);
    416     env->DeleteLocalRef(response);
    417     return result;
    418 }
    419 
    420 void
    421 WebFrame::reportError(int errorCode, const WTF::String& description,
    422         const WTF::String& failingUrl)
    423 {
    424     ALOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data());
    425     JNIEnv* env = getJNIEnv();
    426     AutoJObject javaFrame = mJavaFrame->frame(env);
    427     if (!javaFrame.get())
    428         return;
    429 
    430     jstring descStr = wtfStringToJstring(env, description);
    431     jstring failUrl = wtfStringToJstring(env, failingUrl);
    432     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mReportError, errorCode, descStr, failUrl);
    433     env->DeleteLocalRef(descStr);
    434     env->DeleteLocalRef(failUrl);
    435 }
    436 
    437 WTF::String
    438 WebFrame::convertIDNToUnicode(const WebCore::KURL& url) {
    439     WTF::String converted = url.string();
    440     const WTF::String host = url.host();
    441     if (host.find("xn--") == notFound)  // no punycode IDN found.
    442         return converted;
    443     std::wstring languages;
    444     const WTF::CString cHost = host.utf8();
    445     std::wstring result = net::IDNToUnicode(cHost.data(), cHost.length(), languages, 0);
    446     const WTF::String convertedHost = String::fromUTF8(WideToUTF8(result).c_str());
    447     if (convertedHost.length() && convertedHost.length() != host.length()) {
    448         WebCore::KURL newUrl = url;
    449         newUrl.setHost(convertedHost);
    450         converted = newUrl.string();
    451     }
    452     return converted;
    453 }
    454 
    455 void
    456 WebFrame::loadStarted(WebCore::Frame* frame)
    457 {
    458     JNIEnv* env = getJNIEnv();
    459     AutoJObject javaFrame = mJavaFrame->frame(env);
    460     if (!javaFrame.get())
    461         return;
    462 
    463     // activeDocumentLoader() can return null.
    464     DocumentLoader* documentLoader = frame->loader()->activeDocumentLoader();
    465     if (documentLoader == NULL)
    466         return;
    467 
    468     const WebCore::KURL& url = documentLoader->url();
    469     if (url.isEmpty())
    470         return;
    471     ALOGV("::WebCore:: loadStarted %s", url.string().ascii().data());
    472 
    473     bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
    474     WebCore::FrameLoadType loadType = frame->loader()->loadType();
    475 
    476     if (loadType == WebCore::FrameLoadTypeReplace ||
    477             (loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList &&
    478              !isMainFrame))
    479         return;
    480 
    481     const WTF::String urlString = convertIDNToUnicode(url);
    482     // If this is the main frame and we already have a favicon in the database,
    483     // send it along with the page started notification.
    484     jobject favicon = NULL;
    485     if (isMainFrame) {
    486         // FIXME: This method should not be used from outside WebCore and will be removed.
    487         // http://trac.webkit.org/changeset/81484
    488         WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(urlString, WebCore::IntSize(16, 16));
    489         if (icon)
    490             favicon = webcoreImageToJavaBitmap(env, icon);
    491         ALOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data());
    492     }
    493     jstring urlStr = wtfStringToJstring(env, urlString);
    494 
    495     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mLoadStarted, urlStr, favicon, static_cast<int>(loadType), isMainFrame);
    496     checkException(env);
    497     env->DeleteLocalRef(urlStr);
    498     if (favicon)
    499         env->DeleteLocalRef(favicon);
    500 
    501     // The main frame has started a new load.
    502     if (isMainFrame && mPage)
    503         WebViewCore::getWebViewCore(mPage->mainFrame()->view())->geolocationManager()->resetRealClientTemporaryPermissionStates();
    504 }
    505 
    506 void
    507 WebFrame::transitionToCommitted(WebCore::Frame* frame)
    508 {
    509     JNIEnv* env = getJNIEnv();
    510     AutoJObject javaFrame = mJavaFrame->frame(env);
    511     if (!javaFrame.get())
    512         return;
    513 
    514     WebCore::FrameLoadType loadType = frame->loader()->loadType();
    515     bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
    516     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mTransitionToCommitted, static_cast<int>(loadType), isMainFrame);
    517     checkException(env);
    518 }
    519 
    520 void
    521 WebFrame::didFinishLoad(WebCore::Frame* frame)
    522 {
    523     JNIEnv* env = getJNIEnv();
    524     AutoJObject javaFrame = mJavaFrame->frame(env);
    525     if (!javaFrame.get())
    526         return;
    527 
    528     // activeDocumentLoader() can return null.
    529     WebCore::FrameLoader* loader = frame->loader();
    530     DocumentLoader* documentLoader = loader->activeDocumentLoader();
    531     if (documentLoader == NULL)
    532       return;
    533 
    534     const WebCore::KURL& url = documentLoader->url();
    535     if (url.isEmpty())
    536         return;
    537     ALOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data());
    538 
    539     bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
    540     WebCore::FrameLoadType loadType = loader->loadType();
    541     const WTF::String urlString = convertIDNToUnicode(url);
    542     jstring urlStr = wtfStringToJstring(env, urlString);
    543     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mLoadFinished, urlStr, static_cast<int>(loadType), isMainFrame);
    544     checkException(env);
    545     env->DeleteLocalRef(urlStr);
    546 }
    547 
    548 void
    549 WebFrame::addHistoryItem(WebCore::HistoryItem* item)
    550 {
    551     ALOGV("::WebCore:: addHistoryItem");
    552     JNIEnv* env = getJNIEnv();
    553     WebHistory::AddItem(mJavaFrame->history(env), item);
    554 }
    555 
    556 void
    557 WebFrame::removeHistoryItem(int index)
    558 {
    559     ALOGV("::WebCore:: removeHistoryItem at %d", index);
    560     JNIEnv* env = getJNIEnv();
    561     WebHistory::RemoveItem(mJavaFrame->history(env), index);
    562 }
    563 
    564 void
    565 WebFrame::updateHistoryIndex(int newIndex)
    566 {
    567     ALOGV("::WebCore:: updateHistoryIndex to %d", newIndex);
    568     JNIEnv* env = getJNIEnv();
    569     WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex);
    570 }
    571 
    572 void
    573 WebFrame::setTitle(const WTF::String& title)
    574 {
    575 #ifndef NDEBUG
    576     ALOGV("setTitle(%s)", title.ascii().data());
    577 #endif
    578     JNIEnv* env = getJNIEnv();
    579     AutoJObject javaFrame = mJavaFrame->frame(env);
    580     if (!javaFrame.get())
    581         return;
    582 
    583     jstring jTitleStr = wtfStringToJstring(env, title);
    584 
    585     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSetTitle, jTitleStr);
    586     checkException(env);
    587     env->DeleteLocalRef(jTitleStr);
    588 }
    589 
    590 void
    591 WebFrame::windowObjectCleared(WebCore::Frame* frame)
    592 {
    593     ALOGV("::WebCore:: windowObjectCleared");
    594     JNIEnv* env = getJNIEnv();
    595     AutoJObject javaFrame = mJavaFrame->frame(env);
    596     if (!javaFrame.get())
    597         return;
    598 
    599     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mWindowObjectCleared, (int)frame);
    600     checkException(env);
    601 }
    602 
    603 void
    604 WebFrame::setProgress(float newProgress)
    605 {
    606     JNIEnv* env = getJNIEnv();
    607     AutoJObject javaFrame = mJavaFrame->frame(env);
    608     if (!javaFrame.get())
    609         return;
    610 
    611     int progress = static_cast<int>(100 * newProgress);
    612     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSetProgress, progress);
    613     checkException(env);
    614 }
    615 
    616 const WTF::String
    617 WebFrame::userAgentForURL(const WebCore::KURL* url)
    618 {
    619     return mUserAgent;
    620 }
    621 
    622 void
    623 WebFrame::didReceiveIcon(WebCore::Image* icon)
    624 {
    625     ALOG_ASSERT(icon, "DidReceiveIcon called without an image!");
    626     JNIEnv* env = getJNIEnv();
    627     AutoJObject javaFrame = mJavaFrame->frame(env);
    628     if (!javaFrame.get())
    629         return;
    630 
    631     jobject bitmap = webcoreImageToJavaBitmap(env, icon);
    632     if (!bitmap)
    633         return;
    634 
    635     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveIcon, bitmap);
    636     env->DeleteLocalRef(bitmap);
    637     checkException(env);
    638 }
    639 
    640 void
    641 WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed)
    642 {
    643     JNIEnv* env = getJNIEnv();
    644     AutoJObject javaFrame = mJavaFrame->frame(env);
    645     if (!javaFrame.get())
    646         return;
    647 
    648     jstring jUrlStr = wtfStringToJstring(env, url);
    649 
    650     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveTouchIconUrl, jUrlStr, precomposed);
    651     env->DeleteLocalRef(jUrlStr);
    652     checkException(env);
    653 }
    654 
    655 void
    656 WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload)
    657 {
    658     JNIEnv* env = getJNIEnv();
    659     AutoJObject javaFrame = mJavaFrame->frame(env);
    660     if (!javaFrame.get())
    661         return;
    662 
    663     const WTF::String urlStr = convertIDNToUnicode(url);
    664     jstring jUrlStr = wtfStringToJstring(env, urlStr);
    665 
    666     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload);
    667     env->DeleteLocalRef(jUrlStr);
    668     checkException(env);
    669 }
    670 
    671 bool
    672 WebFrame::canHandleRequest(const WebCore::ResourceRequest& request)
    673 {
    674     JNIEnv* env = getJNIEnv();
    675     AutoJObject javaFrame = mJavaFrame->frame(env);
    676     if (!javaFrame.get())
    677         return true;
    678 
    679     // Always handle "POST" in place
    680     if (equalIgnoringCase(request.httpMethod(), "POST"))
    681         return true;
    682     const WebCore::KURL& requestUrl = request.url();
    683     const WTF::String& url = requestUrl.string();
    684     // Empty URLs should not be sent to Java
    685     if (url.isEmpty())
    686         return true;
    687     jstring jUrlStr = wtfStringToJstring(env, url);
    688 
    689     // Delegate to the Java side to make the decision. Note that the sense of
    690     // the return value of the Java method is reversed. It will return true if
    691     // the embedding application wishes to hijack the load and hence the WebView
    692     // should _not_ proceed with the load.
    693     jboolean ret = env->CallBooleanMethod(javaFrame.get(), mJavaFrame->mHandleUrl, jUrlStr);
    694     checkException(env);
    695     env->DeleteLocalRef(jUrlStr);
    696     return ret == JNI_FALSE;
    697 }
    698 
    699 bool
    700 WebFrame::shouldSaveFormData()
    701 {
    702     JNIEnv* env = getJNIEnv();
    703     AutoJObject javaFrame = mJavaFrame->frame(env);
    704     if (!javaFrame.get())
    705         return false;
    706     jboolean ret = env->CallBooleanMethod(javaFrame.get(), mJavaFrame->mShouldSaveFormData);
    707     checkException(env);
    708     return ret;
    709 }
    710 
    711 WebCore::Frame*
    712 WebFrame::createWindow(bool dialog, bool userGesture)
    713 {
    714     JNIEnv* env = getJNIEnv();
    715     AutoJObject javaFrame = mJavaFrame->frame(env);
    716     if (!javaFrame.get())
    717         return 0;
    718     jobject obj = env->CallObjectMethod(javaFrame.get(), mJavaFrame->mCreateWindow, dialog, userGesture);
    719     if (!obj)
    720         return 0;
    721     return GET_NATIVE_FRAME(env, obj);
    722 }
    723 
    724 void
    725 WebFrame::requestFocus() const
    726 {
    727     JNIEnv* env = getJNIEnv();
    728     AutoJObject javaFrame = mJavaFrame->frame(env);
    729     if (!javaFrame.get())
    730         return;
    731     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mRequestFocus);
    732     checkException(env);
    733 }
    734 
    735 void
    736 WebFrame::closeWindow(WebViewCore* webViewCore)
    737 {
    738     assert(webViewCore);
    739     JNIEnv* env = getJNIEnv();
    740     AutoJObject javaFrame = mJavaFrame->frame(env);
    741     if (!javaFrame.get())
    742         return;
    743     AutoJObject javaObject = webViewCore->getJavaObject();
    744     if (!javaObject.get())
    745         return;
    746     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mCloseWindow, javaObject.get());
    747 }
    748 
    749 struct PolicyFunctionWrapper {
    750     WebCore::FramePolicyFunction func;
    751 };
    752 
    753 void
    754 WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func)
    755 {
    756     JNIEnv* env = getJNIEnv();
    757     AutoJObject javaFrame = mJavaFrame->frame(env);
    758     if (!javaFrame.get())
    759         return;
    760     PolicyFunctionWrapper* p = new PolicyFunctionWrapper;
    761     p->func = func;
    762     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDecidePolicyForFormResubmission, p);
    763 }
    764 
    765 WTF::String
    766 WebFrame::getRawResourceFilename(WebCore::PlatformBridge::rawResId id) const
    767 {
    768     JNIEnv* env = getJNIEnv();
    769     AutoJObject javaFrame = mJavaFrame->frame(env);
    770     if (!javaFrame.get())
    771         return String();
    772     jstring ret = (jstring) env->CallObjectMethod(javaFrame.get(), mJavaFrame->mGetRawResFilename, static_cast<int>(id));
    773 
    774     return jstringToWtfString(env, ret);
    775 }
    776 
    777 float
    778 WebFrame::density() const
    779 {
    780     JNIEnv* env = getJNIEnv();
    781     AutoJObject javaFrame = mJavaFrame->frame(env);
    782     if (!javaFrame.get())
    783         return 0.0;
    784     jfloat dpi = env->CallFloatMethod(javaFrame.get(), mJavaFrame->mDensity);
    785     checkException(env);
    786     return dpi;
    787 }
    788 
    789 void
    790 WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const std::string& host, const std::string& realm, bool useCachedCredentials, bool suppressDialog)
    791 {
    792     JNIEnv* env = getJNIEnv();
    793     AutoJObject javaFrame = mJavaFrame->frame(env);
    794     if (!javaFrame.get())
    795         return;
    796     int jHandle = reinterpret_cast<int>(client);
    797     jstring jHost = stdStringToJstring(env, host, true);
    798     jstring jRealm = stdStringToJstring(env, realm, true);
    799 
    800     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveAuthenticationChallenge, jHandle, jHost, jRealm, useCachedCredentials, suppressDialog);
    801     env->DeleteLocalRef(jHost);
    802     env->DeleteLocalRef(jRealm);
    803     checkException(env);
    804 }
    805 
    806 void
    807 WebFrame::reportSslCertError(WebUrlLoaderClient* client, int error, const std::string& cert, const std::string& url)
    808 {
    809     JNIEnv* env = getJNIEnv();
    810     AutoJObject javaFrame = mJavaFrame->frame(env);
    811     if (!javaFrame.get())
    812         return;
    813     int jHandle = reinterpret_cast<int>(client);
    814 
    815     // Don't copy the null terminator.
    816     int len = cert.length();
    817     ScopedLocalRef<jbyteArray> jCert(env, env->NewByteArray(len));
    818     env->SetByteArrayRegion(jCert.get(), 0, len, reinterpret_cast<const jbyte*>(cert.c_str()));
    819 
    820     ScopedLocalRef<jstring> jUrl(env, env->NewStringUTF(url.c_str()));
    821 
    822     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mReportSslCertError, jHandle, error, jCert.get(), jUrl.get());
    823     checkException(env);
    824 }
    825 
    826 void
    827 WebFrame::requestClientCert(WebUrlLoaderClient* client, const std::string& hostAndPort)
    828 {
    829     JNIEnv* env = getJNIEnv();
    830     int jHandle = reinterpret_cast<int>(client);
    831 
    832     int len = hostAndPort.length();
    833     ScopedLocalRef<jstring> jHostAndPort(env, stdStringToJstring(env, hostAndPort, true));
    834 
    835     env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mRequestClientCert, jHandle, jHostAndPort.get());
    836     checkException(env);
    837 }
    838 
    839 void
    840 WebFrame::downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, const std::string& referer, long long contentLength)
    841 {
    842     JNIEnv* env = getJNIEnv();
    843     AutoJObject javaFrame = mJavaFrame->frame(env);
    844     if (!javaFrame.get())
    845         return;
    846     jstring jUrl = stdStringToJstring(env, url, true);
    847     jstring jUserAgent = stdStringToJstring(env, userAgent, true);
    848     jstring jContentDisposition = stdStringToJstring(env, contentDisposition, true);
    849     jstring jMimetype = stdStringToJstring(env, mimetype, true);
    850     jstring jReferer = stdStringToJstring(env, referer, true);
    851 
    852     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDownloadStart, jUrl, jUserAgent, jContentDisposition, jMimetype, jReferer, contentLength);
    853 
    854     env->DeleteLocalRef(jUrl);
    855     env->DeleteLocalRef(jUserAgent);
    856     env->DeleteLocalRef(jContentDisposition);
    857     env->DeleteLocalRef(jMimetype);
    858     env->DeleteLocalRef(jReferer);
    859     checkException(env);
    860 }
    861 
    862 void
    863 WebFrame::didReceiveData(const char* data, int size) {
    864     JNIEnv* env = getJNIEnv();
    865     AutoJObject javaFrame = mJavaFrame->frame(env);
    866     if (!javaFrame.get())
    867         return;
    868 
    869     ScopedLocalRef<jbyteArray> jData(env, env->NewByteArray(size));
    870     env->SetByteArrayRegion(jData.get(), 0, size, reinterpret_cast<const jbyte*>(data));
    871 
    872     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveData, jData.get(), size);
    873     checkException(env);
    874 }
    875 
    876 void
    877 WebFrame::didFinishLoading() {
    878     JNIEnv* env = getJNIEnv();
    879     AutoJObject javaFrame = mJavaFrame->frame(env);
    880     if (!javaFrame.get())
    881         return;
    882 
    883     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidFinishLoading);
    884     checkException(env);
    885 }
    886 
    887 void WebFrame::setCertificate(const std::string& cert)
    888 {
    889     JNIEnv* env = getJNIEnv();
    890     AutoJObject javaFrame = mJavaFrame->frame(env);
    891     if (!javaFrame.get())
    892         return;
    893 
    894     int len = cert.length();
    895     ScopedLocalRef<jbyteArray> jCert(env, env->NewByteArray(len));
    896     env->SetByteArrayRegion(jCert.get(), 0, len, reinterpret_cast<const jbyte*>(cert.c_str()));
    897 
    898     env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSetCertificate, jCert.get());
    899 
    900     checkException(env);
    901 }
    902 
    903 void WebFrame::autoLogin(const std::string& loginHeader)
    904 {
    905     JNIEnv* env = getJNIEnv();
    906     AutoJObject javaFrame = mJavaFrame->frame(env);
    907     if (!javaFrame.get())
    908         return;
    909 
    910     WTF::String header(loginHeader.c_str(), loginHeader.length());
    911     WTF::Vector<WTF::String> split;
    912     header.split('&', split);
    913     if (!split.isEmpty()) {
    914         WTF::String realm;
    915         WTF::String account;
    916         WTF::String args;
    917         int len = split.size();
    918         while (len--) {
    919             WTF::String& str = split[len];
    920             size_t equals = str.find('=');
    921             if (equals == WTF::notFound)
    922                 continue;
    923 
    924             WTF::String* result = 0;
    925             if (str.startsWith("realm", false))
    926                 result = &realm;
    927             else if (str.startsWith("account", false))
    928                 result = &account;
    929             else if (str.startsWith("args", false))
    930                 result = &args;
    931 
    932             if (result)
    933                 // Decode url escape sequences before sending to the app.
    934                 *result = WebCore::decodeURLEscapeSequences(str.substring(equals + 1));
    935         }
    936 
    937         // realm and args are required parameters.
    938         if (realm.isEmpty() || args.isEmpty())
    939             return;
    940 
    941         jstring jRealm = wtfStringToJstring(env, realm, true);
    942         jstring jAccount = wtfStringToJstring(env, account);
    943         jstring jArgs = wtfStringToJstring(env, args, true);
    944         env->CallVoidMethod(javaFrame.get(), mJavaFrame->mAutoLogin, jRealm, jAccount, jArgs);
    945     }
    946 }
    947 
    948 void WebFrame::maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request)
    949 {
    950     JNIEnv* env = getJNIEnv();
    951     AutoJObject javaFrame = mJavaFrame->frame(env);
    952     if (!javaFrame.get())
    953         return;
    954 
    955     if (request.httpMethod() != "POST")
    956         return;
    957 
    958     WTF::String username;
    959     WTF::String password;
    960     if (!getUsernamePasswordFromDom(frame, username, password))
    961         return;
    962 
    963     jstring jUsername = wtfStringToJstring(env, username);
    964     jstring jPassword = wtfStringToJstring(env, password);
    965     jbyteArray jPostData = getPostData(request);
    966     if (jPostData)
    967         env->CallVoidMethod(javaFrame.get(), mJavaFrame->mMaybeSavePassword, jPostData, jUsername, jPassword);
    968 
    969     env->DeleteLocalRef(jPostData);
    970     env->DeleteLocalRef(jUsername);
    971     env->DeleteLocalRef(jPassword);
    972     checkException(env);
    973 }
    974 
    975 bool WebFrame::getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password)
    976 {
    977     bool found = false;
    978     WTF::RefPtr<WebCore::HTMLCollection> form = frame->document()->forms();
    979     WebCore::Node* node = form->firstItem();
    980     while (node && !found && !node->namespaceURI().isNull() &&
    981            !node->namespaceURI().isEmpty()) {
    982         const WTF::Vector<WebCore::FormAssociatedElement*>& elements =
    983             ((WebCore::HTMLFormElement*)node)->associatedElements();
    984         size_t size = elements.size();
    985         for (size_t i = 0; i< size && !found; i++) {
    986             WebCore::HTMLElement* e = toHTMLElement(elements[i]);
    987             if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
    988                 WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
    989                 if (input->autoComplete() == false)
    990                     continue;
    991                 if (input->isPasswordField())
    992                     password = input->value();
    993                 else if (input->isTextField() || input->isEmailField())
    994                     username = input->value();
    995                 if (!username.isNull() && !password.isNull())
    996                     found = true;
    997             }
    998         }
    999         node = form->nextItem();
   1000     }
   1001     return found;
   1002 }
   1003 
   1004 jbyteArray WebFrame::getPostData(const WebCore::ResourceRequest& request)
   1005 {
   1006     JNIEnv* env = getJNIEnv();
   1007     AutoJObject javaFrame = mJavaFrame->frame(env);
   1008     if (!javaFrame.get())
   1009         return 0;
   1010 
   1011     jbyteArray jPostDataStr = 0;
   1012     WebCore::FormData* formdata = request.httpBody();
   1013     if (formdata) {
   1014         // We can use the formdata->flatten() but it will result in two
   1015         // memcpys, first through loading up the vector with the form data
   1016         // then another to copy it out of the vector and into the java byte
   1017         // array. Instead, we copy the form data ourselves below saving a
   1018         // memcpy.
   1019         const WTF::Vector<WebCore::FormDataElement>& elements =
   1020                 formdata->elements();
   1021 
   1022         // Sizing pass
   1023         int size = 0;
   1024         size_t n = elements.size();
   1025         FileInfo** fileinfos = new FileInfo*[n];
   1026         for (size_t i = 0; i < n; ++i) {
   1027             fileinfos[i] = 0;
   1028             const WebCore::FormDataElement& e = elements[i];
   1029             if (e.m_type == WebCore::FormDataElement::data) {
   1030                 size += e.m_data.size();
   1031             } else if (e.m_type == WebCore::FormDataElement::encodedFile) {
   1032                 fileinfos[i] = new FileInfo(env, e.m_filename);
   1033                 int delta = env->CallIntMethod(javaFrame.get(), mJavaFrame->mGetFileSize, fileinfos[i]->getUri());
   1034                 checkException(env);
   1035                 fileinfos[i]->setSize(delta);
   1036                 size += delta;
   1037             }
   1038         }
   1039 
   1040         // Only create the byte array if there is POST data to pass up.
   1041         // The Java code is expecting null if there is no data.
   1042         if (size > 0) {
   1043             // Copy the actual form data.
   1044             jPostDataStr = env->NewByteArray(size);
   1045             if (jPostDataStr) {
   1046                 // Write  the form data to the java array.
   1047                 jbyte* bytes = env->GetByteArrayElements(jPostDataStr, NULL);
   1048                 int offset = 0;
   1049                 for (size_t i = 0; i < n; ++i) {
   1050                     const WebCore::FormDataElement& e = elements[i];
   1051                     if (e.m_type == WebCore::FormDataElement::data) {
   1052                         int delta = e.m_data.size();
   1053                         memcpy(bytes + offset, e.m_data.data(), delta);
   1054                         offset += delta;
   1055                     } else if (e.m_type == WebCore::FormDataElement::encodedFile) {
   1056                         int delta = env->CallIntMethod(javaFrame.get(),
   1057                                 mJavaFrame->mGetFile, fileinfos[i]->getUri(),
   1058                                 jPostDataStr, offset, fileinfos[i]->getSize());
   1059                         checkException(env);
   1060                         offset += delta;
   1061                     }
   1062                 }
   1063                 env->ReleaseByteArrayElements(jPostDataStr, bytes, 0);
   1064             }
   1065         }
   1066         delete[] fileinfos;
   1067     }
   1068     return jPostDataStr;
   1069 }
   1070 
   1071 // ----------------------------------------------------------------------------
   1072 
   1073 static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decision)
   1074 {
   1075     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1076     ALOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!");
   1077     PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func;
   1078     ALOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!");
   1079 
   1080     // If we are resending the form then we should reset the multiple submission protection.
   1081     if (decision == WebCore::PolicyUse)
   1082         pFrame->loader()->resetMultipleFormSubmissionProtection();
   1083 
   1084     (pFrame->loader()->policyChecker()->*(pFunc->func))((WebCore::PolicyAction)decision);
   1085 }
   1086 
   1087 static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAssetManager, jobject historyList)
   1088 {
   1089     ScriptController::initializeThreading();
   1090 
   1091     // needs to be called before any other chromium code
   1092     initChromium();
   1093 
   1094     // Create a new page
   1095     ChromeClientAndroid* chromeC = new ChromeClientAndroid;
   1096     EditorClientAndroid* editorC = new EditorClientAndroid;
   1097     DeviceMotionClientAndroid* deviceMotionC = new DeviceMotionClientAndroid;
   1098     DeviceOrientationClientAndroid* deviceOrientationC = new DeviceOrientationClientAndroid;
   1099     GeolocationClientAndroid* geolocationC = new GeolocationClientAndroid;
   1100 
   1101     WebCore::Page::PageClients pageClients;
   1102     pageClients.chromeClient = chromeC;
   1103     pageClients.contextMenuClient = new ContextMenuClientAndroid;
   1104     pageClients.editorClient = editorC;
   1105     pageClients.dragClient = new DragClientAndroid;
   1106 #if ENABLE(INSPECTOR)
   1107     pageClients.inspectorClient = new InspectorClientAndroid;
   1108 #endif
   1109     pageClients.deviceMotionClient = deviceMotionC;
   1110     pageClients.deviceOrientationClient = deviceOrientationC;
   1111     pageClients.geolocationClient = geolocationC;
   1112     WebCore::Page* page = new WebCore::Page(pageClients);
   1113 
   1114     editorC->setPage(page);
   1115     page->setGroupName("android.webkit");
   1116 
   1117     // Create a WebFrame to access the Java BrowserFrame associated with this page
   1118     WebFrame* webFrame = new WebFrame(env, obj, historyList, page);
   1119     // Attach webFrame to pageClients.chromeClient and release our ownership
   1120     chromeC->setWebFrame(webFrame);
   1121     Release(webFrame);
   1122 
   1123     FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(webFrame);
   1124     // Create a Frame and the page holds its reference
   1125     WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get();
   1126     loaderC->setFrame(frame);
   1127 #if ENABLE(WDS)
   1128     WDS::server()->addFrame(frame);
   1129 #endif
   1130 
   1131     // Create a WebViewCore to access the Java WebViewCore associated with this page
   1132     WebViewCore* webViewCore = new WebViewCore(env, javaview, frame);
   1133 
   1134 #if ENABLE(WEB_AUTOFILL)
   1135     editorC->getAutofill()->setWebViewCore(webViewCore);
   1136 #endif
   1137 
   1138     // Create a FrameView
   1139     RefPtr<WebCore::FrameView> frameView = WebCore::FrameView::create(frame);
   1140     // Create a WebFrameView
   1141     WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore);
   1142     // As webFrameView Retains webViewCore, release our ownership
   1143     Release(webViewCore);
   1144     // As frameView Retains webFrameView, release our ownership
   1145     Release(webFrameView);
   1146     // Attach the frameView to the frame and release our ownership
   1147     frame->setView(frameView);
   1148     // Set the frame to active to turn on keyboard focus.
   1149     frame->init();
   1150     frame->selection()->setFocused(true);
   1151     frame->page()->focusController()->setFocused(true);
   1152     deviceMotionC->setWebViewCore(webViewCore);
   1153     deviceOrientationC->setWebViewCore(webViewCore);
   1154     geolocationC->setWebViewCore(webViewCore);
   1155 
   1156     // Allow local access to file:/// and substitute data
   1157     WebCore::SecurityOrigin::setLocalLoadPolicy(
   1158             WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData);
   1159 
   1160     ALOGV("::WebCore:: createFrame %p", frame);
   1161 
   1162     // Set the mNativeFrame field in Frame
   1163     SET_NATIVE_FRAME(env, obj, (int)frame);
   1164 
   1165     String directory = webFrame->getRawResourceFilename(
   1166             WebCore::PlatformBridge::DrawableDir);
   1167     if (directory.isEmpty())
   1168         ALOGE("Can't find the drawable directory");
   1169     else {
   1170         // Initialize our skinning classes
   1171         webFrame->setRenderSkins(new WebCore::RenderSkinAndroid(directory));
   1172     }
   1173 
   1174     for (int i = WebCore::PlatformBridge::FileUploadLabel;
   1175             i <= WebCore::PlatformBridge::FileUploadNoFileChosenLabel; i++)
   1176         initGlobalLocalizedName(
   1177                 static_cast<WebCore::PlatformBridge::rawResId>(i), webFrame);
   1178 }
   1179 
   1180 static void DestroyFrame(JNIEnv* env, jobject obj)
   1181 {
   1182     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1183     ALOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!");
   1184 
   1185     ALOGV("::WebCore:: deleting frame %p", pFrame);
   1186 
   1187     WebCore::FrameView* view = pFrame->view();
   1188     view->ref();
   1189     // detachFromParent will cause the page to be closed.
   1190     WebCore::FrameLoader* fl = pFrame->loader();
   1191     // retain a pointer because detachFromParent will set the page to null.
   1192     WebCore::Page* page = pFrame->page();
   1193     if (fl)
   1194         fl->detachFromParent();
   1195     delete page;
   1196 
   1197     // Force remove all deleted pages in the page cache
   1198     WebCore::pageCache()->releaseAutoreleasedPagesNow();
   1199 
   1200     view->deref();
   1201 
   1202     SET_NATIVE_FRAME(env, obj, 0);
   1203 #if ENABLE(WDS)
   1204     WDS::server()->removeFrame(pFrame);
   1205 #endif
   1206 }
   1207 
   1208 static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers)
   1209 {
   1210     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1211     ALOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!");
   1212 
   1213     WTF::String webcoreUrl = jstringToWtfString(env, url);
   1214     WebCore::KURL kurl(WebCore::KURL(), webcoreUrl);
   1215     WebCore::ResourceRequest request(kurl);
   1216     if (headers) {
   1217         // dalvikvm will raise exception if any of these fail
   1218         jclass mapClass = env->FindClass("java/util/Map");
   1219         jmethodID entrySet = env->GetMethodID(mapClass, "entrySet",
   1220                 "()Ljava/util/Set;");
   1221         jobject set = env->CallObjectMethod(headers, entrySet);
   1222 
   1223         jclass setClass = env->FindClass("java/util/Set");
   1224         jmethodID iterator = env->GetMethodID(setClass, "iterator",
   1225                 "()Ljava/util/Iterator;");
   1226         jobject iter = env->CallObjectMethod(set, iterator);
   1227 
   1228         jclass iteratorClass = env->FindClass("java/util/Iterator");
   1229         jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
   1230         jmethodID next = env->GetMethodID(iteratorClass, "next",
   1231                 "()Ljava/lang/Object;");
   1232         jclass entryClass = env->FindClass("java/util/Map$Entry");
   1233         jmethodID getKey = env->GetMethodID(entryClass, "getKey",
   1234                 "()Ljava/lang/Object;");
   1235         jmethodID getValue = env->GetMethodID(entryClass, "getValue",
   1236                 "()Ljava/lang/Object;");
   1237 
   1238         while (env->CallBooleanMethod(iter, hasNext)) {
   1239             jobject entry = env->CallObjectMethod(iter, next);
   1240             jstring key = (jstring) env->CallObjectMethod(entry, getKey);
   1241             jstring value = (jstring) env->CallObjectMethod(entry, getValue);
   1242             request.setHTTPHeaderField(jstringToWtfString(env, key), jstringToWtfString(env, value));
   1243             env->DeleteLocalRef(entry);
   1244             env->DeleteLocalRef(key);
   1245             env->DeleteLocalRef(value);
   1246         }
   1247 
   1248         env->DeleteLocalRef(entryClass);
   1249         env->DeleteLocalRef(iteratorClass);
   1250         env->DeleteLocalRef(iter);
   1251         env->DeleteLocalRef(setClass);
   1252         env->DeleteLocalRef(set);
   1253         env->DeleteLocalRef(mapClass);
   1254     }
   1255     ALOGV("LoadUrl %s", kurl.string().latin1().data());
   1256     pFrame->loader()->load(request, false);
   1257 }
   1258 
   1259 static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData)
   1260 {
   1261     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1262     ALOG_ASSERT(pFrame, "nativePostUrl must take a valid frame pointer!");
   1263 
   1264     WebCore::KURL kurl(WebCore::KURL(), jstringToWtfString(env, url));
   1265     WebCore::ResourceRequest request(kurl);
   1266     request.setHTTPMethod("POST");
   1267     request.setHTTPContentType("application/x-www-form-urlencoded");
   1268 
   1269     if (postData) {
   1270         jsize size = env->GetArrayLength(postData);
   1271         jbyte* bytes = env->GetByteArrayElements(postData, NULL);
   1272         RefPtr<FormData> formData = FormData::create((const void*)bytes, size);
   1273         // the identifier uses the same logic as generateFormDataIdentifier() in
   1274         // HTMLFormElement.cpp
   1275         formData->setIdentifier(static_cast<int64_t>(WTF::currentTime() * 1000000.0));
   1276         request.setHTTPBody(formData);
   1277         env->ReleaseByteArrayElements(postData, bytes, 0);
   1278     }
   1279 
   1280     ALOGV("PostUrl %s", kurl.string().latin1().data());
   1281     WebCore::FrameLoadRequest frameRequest(pFrame->document()->securityOrigin(), request);
   1282     pFrame->loader()->loadFrameRequest(frameRequest, false, false, 0, 0, WebCore::SendReferrer);
   1283 }
   1284 
   1285 static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data,
   1286         jstring mimeType, jstring encoding, jstring failUrl)
   1287 {
   1288     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1289     ALOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!");
   1290 
   1291     // Setup the resource request
   1292     WebCore::ResourceRequest request(jstringToWtfString(env, baseUrl));
   1293 
   1294     // Setup the substituteData
   1295     WTF::CString cData = jstringToWtfString(env, data).utf8();
   1296     const char* dataStr = cData.data();
   1297     WTF::RefPtr<WebCore::SharedBuffer> sharedBuffer =
   1298         WebCore::SharedBuffer::create();
   1299     ALOG_ASSERT(dataStr, "nativeLoadData has a null data string.");
   1300     sharedBuffer->append(dataStr, strlen(dataStr)); // copy dataStr
   1301 
   1302     WebCore::SubstituteData substituteData(sharedBuffer,
   1303             jstringToWtfString(env, mimeType), jstringToWtfString(env, encoding),
   1304             WebCore::KURL(ParsedURLString, jstringToWtfString(env, failUrl)));
   1305 
   1306     // Perform the load
   1307     pFrame->loader()->load(request, substituteData, false);
   1308 }
   1309 
   1310 static void StopLoading(JNIEnv *env, jobject obj)
   1311 {
   1312     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1313     ALOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!");
   1314     ALOGV("::WebCore:: stopLoading %p", pFrame);
   1315 
   1316     // Stop loading the page and do not send an unload event
   1317     pFrame->loader()->stopForUserCancel();
   1318 }
   1319 
   1320 #if ENABLE(WEB_ARCHIVE)
   1321 static String saveArchiveAutoname(String basename, String name, String extension) {
   1322     if (name.isNull() || name.isEmpty()) {
   1323         name = String("index");
   1324     }
   1325 
   1326     String testname = basename;
   1327     testname.append(name);
   1328     testname.append(extension);
   1329 
   1330     errno = 0;
   1331     struct stat permissions;
   1332     if (stat(testname.utf8().data(), &permissions) < 0) {
   1333         if (errno == ENOENT)
   1334             return testname;
   1335         return String();
   1336     }
   1337 
   1338     const int maxAttempts = 100;
   1339     for (int i = 1; i < maxAttempts; i++) {
   1340         String testname = basename;
   1341         testname.append(name);
   1342         testname.append("-");
   1343         testname.append(String::number(i));
   1344         testname.append(extension);
   1345 
   1346         errno = 0;
   1347         if (stat(testname.utf8().data(), &permissions) < 0) {
   1348             if (errno == ENOENT)
   1349                 return testname;
   1350             return String();
   1351         }
   1352     }
   1353 
   1354     return String();
   1355 }
   1356 #endif // ENABLE(WEB_ARCHIVE)
   1357 
   1358 static jstring SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboolean autoname)
   1359 {
   1360 #if ENABLE(WEB_ARCHIVE)
   1361     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1362     ALOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!");
   1363     String mimeType = pFrame->loader()->documentLoader()->mainResource()->mimeType();
   1364     if ((mimeType != "text/html") && (mimeType != "application/xhtml+xml"))
   1365         return NULL;
   1366 
   1367     const char* basenameNative = getCharactersFromJStringInEnv(env, basename);
   1368     String basenameString = String::fromUTF8(basenameNative);
   1369     String filename;
   1370 
   1371     if (autoname) {
   1372         String name = pFrame->loader()->documentLoader()->originalURL().lastPathComponent();
   1373         String extension = String(".webarchivexml");
   1374         filename = saveArchiveAutoname(basenameString, name, extension);
   1375     } else {
   1376         filename = basenameString;
   1377     }
   1378 
   1379     if (filename.isNull() || filename.isEmpty()) {
   1380         ALOGD("saveWebArchive: Failed to select a filename to save.");
   1381         releaseCharactersForJStringInEnv(env, basename, basenameNative);
   1382         return NULL;
   1383     }
   1384 
   1385     const int noCompression = 0;
   1386     xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.utf8().data(), noCompression);
   1387     if (writer == NULL) {
   1388         ALOGD("saveWebArchive: Failed to initialize xml writer.");
   1389         releaseCharactersForJStringInEnv(env, basename, basenameNative);
   1390         return NULL;
   1391     }
   1392 
   1393     RefPtr<WebArchiveAndroid> archive = WebCore::WebArchiveAndroid::create(pFrame);
   1394 
   1395     bool result = archive->saveWebArchive(writer);
   1396 
   1397     releaseCharactersForJStringInEnv(env, basename, basenameNative);
   1398     xmlFreeTextWriter(writer);
   1399 
   1400     if (result)
   1401         return wtfStringToJstring(env, filename);
   1402 #endif // ENABLE(WEB_ARCHIVE)
   1403 
   1404     return NULL;
   1405 }
   1406 
   1407 static jstring ExternalRepresentation(JNIEnv *env, jobject obj)
   1408 {
   1409     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1410     ALOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!");
   1411 
   1412     // Request external representation of the render tree
   1413     WTF::String renderDump = WebCore::externalRepresentation(pFrame);
   1414     return wtfStringToJstring(env, renderDump);
   1415 }
   1416 
   1417 static StringBuilder FrameAsText(WebCore::Frame *pFrame, jboolean dumpChildFrames) {
   1418     StringBuilder renderDump;
   1419     if (!pFrame)
   1420         return renderDump;
   1421     WebCore::Element *documentElement = pFrame->document()->documentElement();
   1422     if (!documentElement)
   1423         return renderDump;
   1424     if (pFrame->tree()->parent()) {
   1425         renderDump.append("\n--------\nFrame: '");
   1426         renderDump.append(pFrame->tree()->name());
   1427         renderDump.append("'\n--------\n");
   1428     }
   1429     renderDump.append(((WebCore::HTMLElement*)documentElement)->innerText());
   1430     renderDump.append("\n");
   1431     if (dumpChildFrames) {
   1432         for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) {
   1433             renderDump.append(FrameAsText(pFrame->tree()->child(i), dumpChildFrames).toString());
   1434         }
   1435     }
   1436     return renderDump;
   1437 }
   1438 
   1439 static jstring DocumentAsText(JNIEnv *env, jobject obj)
   1440 {
   1441     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1442     ALOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
   1443 
   1444     WTF::String renderDump = FrameAsText(pFrame, false /* dumpChildFrames */).toString();
   1445     return wtfStringToJstring(env, renderDump);
   1446 }
   1447 
   1448 static jstring ChildFramesAsText(JNIEnv *env, jobject obj)
   1449 {
   1450     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1451     ALOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
   1452 
   1453     StringBuilder renderDumpBuilder;
   1454     for (unsigned i = 0; i < pFrame->tree()->childCount(); ++i) {
   1455         renderDumpBuilder.append(FrameAsText(pFrame->tree()->child(i), true /* dumpChildFrames */).toString());
   1456     }
   1457     WTF::String renderDump = renderDumpBuilder.toString();
   1458     return wtfStringToJstring(env, renderDump);
   1459 }
   1460 
   1461 static void Reload(JNIEnv *env, jobject obj, jboolean allowStale)
   1462 {
   1463     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1464     ALOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!");
   1465 
   1466     WebCore::FrameLoader* loader = pFrame->loader();
   1467     if (allowStale) {
   1468         // load the current page with FrameLoadTypeIndexedBackForward so that it
   1469         // will use cache when it is possible
   1470         WebCore::Page* page = pFrame->page();
   1471         WebCore::HistoryItem* item = page->backForwardList()->currentItem();
   1472         if (item)
   1473             page->goToItem(item, FrameLoadTypeIndexedBackForward);
   1474     } else
   1475         loader->reload(true);
   1476 }
   1477 
   1478 static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos)
   1479 {
   1480     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1481     ALOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!");
   1482 
   1483     if (pos == 1)
   1484         pFrame->page()->goForward();
   1485     else if (pos == -1)
   1486         pFrame->page()->goBack();
   1487     else
   1488         pFrame->page()->goBackOrForward(pos);
   1489 }
   1490 
   1491 static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, jstring script)
   1492 {
   1493     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1494     ALOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!");
   1495 
   1496     WebCore::ScriptValue value =
   1497             pFrame->script()->executeScript(jstringToWtfString(env, script), true);
   1498     WTF::String result = WTF::String();
   1499     ScriptState* scriptState = mainWorldScriptState(pFrame);
   1500     if (!value.getString(scriptState, result))
   1501         return NULL;
   1502     return wtfStringToJstring(env, result);
   1503 }
   1504 
   1505 // Wrap the JavaInstance used when binding custom javascript interfaces. Use a
   1506 // weak reference so that the gc can collect the WebView. Override virtualBegin
   1507 // and virtualEnd and swap the weak reference for the real object.
   1508 class WeakJavaInstance : public JavaInstanceJobject {
   1509 public:
   1510     static PassRefPtr<WeakJavaInstance> create(jobject obj, bool requireAnnotation)
   1511     {
   1512         return adoptRef(new WeakJavaInstance(obj, requireAnnotation));
   1513     }
   1514 
   1515 private:
   1516     WeakJavaInstance(jobject instance, bool requireAnnotation)
   1517         : JavaInstanceJobject(instance, requireAnnotation)
   1518         , m_beginEndDepth(0)
   1519     {
   1520         JNIEnv* env = getJNIEnv();
   1521         // JavaInstance creates a global ref to instance in its constructor.
   1522         env->DeleteGlobalRef(m_instance->instance());
   1523         // Create a weak ref, cache it, and set the underlying JavaInstance to use it.
   1524         m_weakRef = env->NewWeakGlobalRef(instance);
   1525         m_instance->setInstance(m_weakRef);
   1526     }
   1527     ~WeakJavaInstance()
   1528     {
   1529         ALOG_ASSERT(!m_beginEndDepth, "Unbalanced calls to WeakJavaInstance::begin() / end()");
   1530         JNIEnv* env = getJNIEnv();
   1531         // The JavaInstance destructor attempts to delete the global ref stored
   1532         // in m_instance. Since we replaced it in our constructor with a weak
   1533         // reference, restore the global ref here so the vm will not complain.
   1534         m_instance->setInstance(env->NewGlobalRef(m_weakRef));
   1535         // Delete the weak reference.
   1536         env->DeleteWeakGlobalRef(m_weakRef);
   1537     }
   1538 
   1539     virtual void begin()
   1540     {
   1541         if (m_beginEndDepth++ > 0)
   1542             return;
   1543         JNIEnv* env = getJNIEnv();
   1544         // This is odd. getRealObject returns an AutoJObject which is used to
   1545         // cleanly create and delete a local reference. But, here we need to
   1546         // maintain the local reference across calls to virtualBegin() and
   1547         // virtualEnd(). So, release the local reference from the AutoJObject
   1548         // and delete the local reference in virtualEnd().
   1549         m_instance->setInstance(getRealObject(env, m_weakRef).release());
   1550         // Call the base class method
   1551         INHERITED::begin();
   1552     }
   1553 
   1554     virtual void end()
   1555     {
   1556         if (--m_beginEndDepth > 0)
   1557             return;
   1558         // Call the base class method first to pop the local frame.
   1559         INHERITED::end();
   1560         // Get rid of the local reference to the real object.
   1561         getJNIEnv()->DeleteLocalRef(m_instance->instance());
   1562         // Point back to the WeakReference.
   1563         m_instance->setInstance(m_weakRef);
   1564     }
   1565 
   1566 private:
   1567     typedef JavaInstanceJobject INHERITED;
   1568     jweak m_weakRef;
   1569     // The current depth of nested calls to virtualBegin and virtualEnd.
   1570     int m_beginEndDepth;
   1571 };
   1572 
   1573 static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer,
   1574         jobject javascriptObj, jstring interfaceName, jboolean requireAnnotation)
   1575 {
   1576     WebCore::Frame* pFrame = 0;
   1577     if (nativeFramePointer == 0)
   1578         pFrame = GET_NATIVE_FRAME(env, obj);
   1579     else
   1580         pFrame = (WebCore::Frame*)nativeFramePointer;
   1581     ALOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!");
   1582 
   1583     JavaVM* vm;
   1584     env->GetJavaVM(&vm);
   1585     ALOGV("::WebCore:: addJSInterface: %p", pFrame);
   1586 
   1587     if (pFrame) {
   1588         RefPtr<JavaInstance> addedObject = WeakJavaInstance::create(javascriptObj,
   1589                 requireAnnotation);
   1590         const char* name = getCharactersFromJStringInEnv(env, interfaceName);
   1591         // Pass ownership of the added object to bindToWindowObject.
   1592         NPObject* npObject = JavaInstanceToNPObject(addedObject.get());
   1593         pFrame->script()->bindToWindowObject(pFrame, name, npObject);
   1594         // bindToWindowObject calls NPN_RetainObject on the
   1595         // returned one (see createV8ObjectForNPObject in V8NPObject.cpp).
   1596         // bindToWindowObject also increases obj's ref count and decreases
   1597         // the ref count when the object is not reachable from JavaScript
   1598         // side. Code here must release the reference count increased by
   1599         // bindToWindowObject.
   1600 
   1601         // Note that while this function is declared in WebCore/bridge/npruntime.h, for V8 builds
   1602         // we use WebCore/bindings/v8/npruntime.cpp (rather than
   1603         // WebCore/bridge/npruntime.cpp), so the function is implemented there.
   1604         // TODO: Combine the two versions of these NPAPI files.
   1605         NPN_ReleaseObject(npObject);
   1606         releaseCharactersForJString(interfaceName, name);
   1607     }
   1608 }
   1609 
   1610 static void ClearWebCoreCache()
   1611 {
   1612     if (!WebCore::memoryCache()->disabled()) {
   1613         // Disabling the cache will remove all resources from the cache.  They may
   1614         // still live on if they are referenced by some Web page though.
   1615         WebCore::memoryCache()->setDisabled(true);
   1616         WebCore::memoryCache()->setDisabled(false);
   1617     }
   1618 
   1619     // clear page cache
   1620     int pageCapacity = WebCore::pageCache()->capacity();
   1621     // Setting size to 0, makes all pages be released.
   1622     WebCore::pageCache()->setCapacity(0);
   1623     WebCore::pageCache()->releaseAutoreleasedPagesNow();
   1624     WebCore::pageCache()->setCapacity(pageCapacity);
   1625 }
   1626 
   1627 static void ClearWebViewCache()
   1628 {
   1629     WebCache::get(false /*privateBrowsing*/)->clear();
   1630 }
   1631 
   1632 static void ClearCache(JNIEnv *env, jobject obj)
   1633 {
   1634     ClearWebCoreCache();
   1635     ClearWebViewCache();
   1636     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1637     pFrame->script()->lowMemoryNotification();
   1638 }
   1639 
   1640 static jboolean DocumentHasImages(JNIEnv *env, jobject obj)
   1641 {
   1642     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1643     ALOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!");
   1644 
   1645     return pFrame->document()->images()->length() > 0;
   1646 }
   1647 
   1648 static jboolean HasPasswordField(JNIEnv *env, jobject obj)
   1649 {
   1650     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1651     ALOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!");
   1652 
   1653     bool found = false;
   1654     WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
   1655     WebCore::Node* node = form->firstItem();
   1656     // Null/Empty namespace means that node is not created in HTMLFormElement
   1657     // class, but just normal Element class.
   1658     while (node && !found && !node->namespaceURI().isNull() &&
   1659            !node->namespaceURI().isEmpty()) {
   1660         const WTF::Vector<WebCore::FormAssociatedElement*>& elements =
   1661             ((WebCore::HTMLFormElement*)node)->associatedElements();
   1662         size_t size = elements.size();
   1663         for (size_t i = 0; i< size && !found; i++) {
   1664             WebCore::HTMLElement* e = toHTMLElement(elements[i]);
   1665             if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
   1666                 if (static_cast<WebCore::HTMLInputElement*>(e)->isPasswordField())
   1667                     found = true;
   1668             }
   1669         }
   1670         node = form->nextItem();
   1671     }
   1672     return found;
   1673 }
   1674 
   1675 static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
   1676 {
   1677     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1678     ALOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!");
   1679     jobjectArray strArray = NULL;
   1680     WTF::String username;
   1681     WTF::String password;
   1682     if (WebFrame::getWebFrame(pFrame)->getUsernamePasswordFromDom(pFrame, username, password)) {
   1683         jclass stringClass = env->FindClass("java/lang/String");
   1684         strArray = env->NewObjectArray(2, stringClass, NULL);
   1685         env->DeleteLocalRef(stringClass);
   1686         env->SetObjectArrayElement(strArray, 0, wtfStringToJstring(env, username));
   1687         env->SetObjectArrayElement(strArray, 1, wtfStringToJstring(env, password));
   1688     }
   1689     return strArray;
   1690 }
   1691 
   1692 static void SetUsernamePassword(JNIEnv *env, jobject obj,
   1693     jstring username, jstring password)
   1694 {
   1695     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1696     ALOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!");
   1697 
   1698     WebCore::HTMLInputElement* usernameEle = NULL;
   1699     WebCore::HTMLInputElement* passwordEle = NULL;
   1700     bool found = false;
   1701     WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
   1702     WebCore::Node* node = form->firstItem();
   1703     while (node && !found && !node->namespaceURI().isNull() &&
   1704            !node->namespaceURI().isEmpty()) {
   1705         const WTF::Vector<WebCore::FormAssociatedElement*>& elements =
   1706             ((WebCore::HTMLFormElement*)node)->associatedElements();
   1707         size_t size = elements.size();
   1708         for (size_t i = 0; i< size && !found; i++) {
   1709             WebCore::HTMLElement* e = toHTMLElement(elements[i]);
   1710             if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
   1711                 WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
   1712                 if (input->autoComplete() == false)
   1713                     continue;
   1714                 if (input->isPasswordField())
   1715                     passwordEle = input;
   1716                 else if (input->isTextField() || input->isEmailField())
   1717                     usernameEle = input;
   1718                 if (usernameEle != NULL && passwordEle != NULL)
   1719                     found = true;
   1720             }
   1721         }
   1722         node = form->nextItem();
   1723     }
   1724     if (found) {
   1725         usernameEle->setValue(jstringToWtfString(env, username));
   1726         passwordEle->setValue(jstringToWtfString(env, password));
   1727     }
   1728 }
   1729 
   1730 void
   1731 WebFrame::saveFormData(HTMLFormElement* form)
   1732 {
   1733     JNIEnv* env = getJNIEnv();
   1734     AutoJObject javaFrame = mJavaFrame->frame(env);
   1735     if (!javaFrame.get())
   1736         return;
   1737 
   1738     if (form->autoComplete()) {
   1739         JNIEnv* env = getJNIEnv();
   1740         jclass mapClass = env->FindClass("java/util/HashMap");
   1741         ALOG_ASSERT(mapClass, "Could not find HashMap class!");
   1742         jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
   1743         ALOG_ASSERT(init, "Could not find constructor for HashMap");
   1744         jobject hashMap = env->NewObject(mapClass, init, 1);
   1745         ALOG_ASSERT(hashMap, "Could not create a new HashMap");
   1746         jmethodID put = env->GetMethodID(mapClass, "put",
   1747                 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
   1748         ALOG_ASSERT(put, "Could not find put method on HashMap");
   1749         WTF::Vector<WebCore::FormAssociatedElement*> elements = form->associatedElements();
   1750         size_t size = elements.size();
   1751         for (size_t i = 0; i < size; i++) {
   1752             WebCore::HTMLElement* e = toHTMLElement(elements[i]);
   1753             if (e->hasTagName(WebCore::HTMLNames::inputTag)) {
   1754                 WebCore::HTMLInputElement* input = static_cast<WebCore::HTMLInputElement*>(e);
   1755                 if (input->isTextField() && !input->isPasswordField()
   1756                         && input->autoComplete()) {
   1757                     WTF::String value = input->value();
   1758                     int len = value.length();
   1759                     if (len) {
   1760                         const WTF::AtomicString& name = input->name();
   1761                         jstring key = wtfStringToJstring(env, name);
   1762                         jstring val = wtfStringToJstring(env, value);
   1763                         ALOG_ASSERT(key && val, "name or value not set");
   1764                         env->CallObjectMethod(hashMap, put, key, val);
   1765                         env->DeleteLocalRef(key);
   1766                         env->DeleteLocalRef(val);
   1767                     }
   1768                 }
   1769             }
   1770         }
   1771         env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSaveFormData, hashMap);
   1772         env->DeleteLocalRef(hashMap);
   1773         env->DeleteLocalRef(mapClass);
   1774     }
   1775 }
   1776 
   1777 static void OrientationChanged(JNIEnv *env, jobject obj, int orientation)
   1778 {
   1779     WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
   1780     ALOGV("Sending orientation: %d", orientation);
   1781     pFrame->sendOrientationChangeEvent(orientation);
   1782 }
   1783 
   1784 static jboolean GetShouldStartScrolledRight(JNIEnv *env, jobject obj,
   1785         jint browserFrame)
   1786 {
   1787     jboolean startScrolledRight = false; // default is start scrolled left
   1788     WebCore::Frame* frame = reinterpret_cast<WebCore::Frame*>(browserFrame);
   1789     WebCore::Document* document = frame->document();
   1790     if (document) {
   1791         RenderStyle* style = document->renderer()->style();
   1792         WritingMode writingMode = style->writingMode();
   1793         ALOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode,
   1794                 "BottomToTopWritingMode isn't possible in any "
   1795                 "language and cannot be specified in w3c writing-mode.");
   1796         if (writingMode == WebCore::RightToLeftWritingMode)
   1797             startScrolledRight = true; // vertical-rl pages start scrolled right
   1798         else if (writingMode == WebCore::TopToBottomWritingMode)
   1799             startScrolledRight = !style->isLeftToRightDirection(); // RTL starts right
   1800     }
   1801     return startScrolledRight;
   1802 }
   1803 
   1804 static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword)
   1805 {
   1806     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
   1807     std::string username = jstringToStdString(env, jUsername);
   1808     std::string password = jstringToStdString(env, jPassword);
   1809     client->setAuth(username, password);
   1810 }
   1811 
   1812 static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle)
   1813 {
   1814     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
   1815     client->cancelAuth();
   1816 }
   1817 
   1818 static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle)
   1819 {
   1820     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
   1821     client->proceedSslCertError();
   1822 }
   1823 
   1824 static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error)
   1825 {
   1826     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
   1827     client->cancelSslCertError(cert_error);
   1828 }
   1829 
   1830 static scoped_refptr<net::X509Certificate> getX509Cert(JNIEnv *env, jobjectArray chain)
   1831 {
   1832     // Based on Android's NativeCrypto_SSL_use_certificate
   1833     int length = env->GetArrayLength(chain);
   1834     if (length == 0) {
   1835         return NULL;
   1836     }
   1837 
   1838     base::ScopedOpenSSL<X509, X509_free> first;
   1839     ScopedVector<base::ScopedOpenSSL<X509, X509_free> > rest;
   1840     for (int i = 0; i < length; i++) {
   1841         ScopedLocalRef<jbyteArray> cert(env,
   1842                 reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(chain, i)));
   1843         if (cert.get() == NULL) {
   1844             return NULL;
   1845         }
   1846         ScopedByteArrayRO certBytes(env, cert.get());
   1847         if (certBytes.get() == NULL) {
   1848             return NULL;
   1849         }
   1850         const char* data = reinterpret_cast<const char*>(certBytes.get());
   1851         int length = certBytes.size();
   1852         X509* x509 = net::X509Certificate::CreateOSCertHandleFromBytes(data, length);
   1853         if (x509 == NULL) {
   1854             return NULL;
   1855         }
   1856         if (i == 0) {
   1857             first.reset(x509);
   1858         } else {
   1859             rest.push_back(new base::ScopedOpenSSL<X509, X509_free>(x509));
   1860         }
   1861     }
   1862 
   1863     std::vector<X509*> certChain(rest.size());
   1864     for (size_t i = 0; i < rest.size(); i++) {
   1865         certChain[i] = rest[i]->get();
   1866     }
   1867     return net::X509Certificate::CreateFromHandle(first.get(),
   1868                                                   net::X509Certificate::SOURCE_FROM_NETWORK,
   1869                                                   certChain);
   1870 }
   1871 
   1872 static void SslClientCertPKCS8(JNIEnv *env, jobject obj, int handle, jbyteArray pkey, jobjectArray chain)
   1873 {
   1874     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
   1875     if (pkey == NULL || chain == NULL) {
   1876         client->sslClientCert(NULL, NULL);
   1877         return;
   1878     }
   1879 
   1880     // Based on Android's NativeCrypto_SSL_use_PrivateKey
   1881     ScopedByteArrayRO pkeyBytes(env, pkey);
   1882     if (pkeyBytes.get() == NULL) {
   1883         client->sslClientCert(NULL, NULL);
   1884         return;
   1885     }
   1886 
   1887     base::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8;
   1888     const unsigned char* pkeyChars = reinterpret_cast<const unsigned char*>(pkeyBytes.get());
   1889     pkcs8.reset(d2i_PKCS8_PRIV_KEY_INFO(NULL, &pkeyChars, pkeyBytes.size()));
   1890     if (!pkcs8.get()) {
   1891         client->sslClientCert(NULL, NULL);
   1892         return;
   1893     }
   1894     base::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> privateKey(EVP_PKCS82PKEY(pkcs8.get()));
   1895     if (!privateKey.get()) {
   1896         client->sslClientCert(NULL, NULL);
   1897         return;
   1898     }
   1899     scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain);
   1900     if (certificate == NULL) {
   1901         client->sslClientCert(NULL, NULL);
   1902         return;
   1903     }
   1904     client->sslClientCert(privateKey.release(), certificate);
   1905 }
   1906 
   1907 static void SslClientCertCtx(JNIEnv *env, jobject obj, int handle, jlong ctx, jobjectArray chain)
   1908 {
   1909     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
   1910     EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(static_cast<uintptr_t>(ctx));
   1911     if (pkey == NULL || chain == NULL) {
   1912         client->sslClientCert(NULL, NULL);
   1913         return;
   1914     }
   1915     scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain);
   1916     if (certificate == NULL) {
   1917         client->sslClientCert(NULL, NULL);
   1918         return;
   1919     }
   1920     CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
   1921     client->sslClientCert(pkey, certificate);
   1922 }
   1923 
   1924 // ----------------------------------------------------------------------------
   1925 
   1926 /*
   1927  * JNI registration.
   1928  */
   1929 static JNINativeMethod gBrowserFrameNativeMethods[] = {
   1930     /* name, signature, funcPtr */
   1931     { "nativeCallPolicyFunction", "(II)V",
   1932         (void*) CallPolicyFunction },
   1933     { "nativeCreateFrame", "(Landroid/webkit/WebViewCore;Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V",
   1934         (void*) CreateFrame },
   1935     { "nativeDestroyFrame", "()V",
   1936         (void*) DestroyFrame },
   1937     { "nativeStopLoading", "()V",
   1938         (void*) StopLoading },
   1939     { "nativeLoadUrl", "(Ljava/lang/String;Ljava/util/Map;)V",
   1940         (void*) LoadUrl },
   1941     { "nativePostUrl", "(Ljava/lang/String;[B)V",
   1942         (void*) PostUrl },
   1943     { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
   1944         (void*) LoadData },
   1945     { "nativeSaveWebArchive", "(Ljava/lang/String;Z)Ljava/lang/String;",
   1946         (void*) SaveWebArchive },
   1947     { "externalRepresentation", "()Ljava/lang/String;",
   1948         (void*) ExternalRepresentation },
   1949     { "documentAsText", "()Ljava/lang/String;",
   1950         (void*) DocumentAsText },
   1951     { "childFramesAsText", "()Ljava/lang/String;",
   1952         (void*) ChildFramesAsText },
   1953     { "reload", "(Z)V",
   1954         (void*) Reload },
   1955     { "nativeGoBackOrForward", "(I)V",
   1956         (void*) GoBackOrForward },
   1957     { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;Z)V",
   1958         (void*) AddJavascriptInterface },
   1959     { "stringByEvaluatingJavaScriptFromString",
   1960             "(Ljava/lang/String;)Ljava/lang/String;",
   1961         (void*) StringByEvaluatingJavaScriptFromString },
   1962     { "clearCache", "()V",
   1963         (void*) ClearCache },
   1964     { "documentHasImages", "()Z",
   1965         (void*) DocumentHasImages },
   1966     { "hasPasswordField", "()Z",
   1967         (void*) HasPasswordField },
   1968     { "getUsernamePassword", "()[Ljava/lang/String;",
   1969         (void*) GetUsernamePassword },
   1970     { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V",
   1971         (void*) SetUsernamePassword },
   1972     { "nativeOrientationChanged", "(I)V",
   1973         (void*) OrientationChanged },
   1974     { "nativeAuthenticationProceed", "(ILjava/lang/String;Ljava/lang/String;)V",
   1975         (void*) AuthenticationProceed },
   1976     { "nativeAuthenticationCancel", "(I)V",
   1977         (void*) AuthenticationCancel },
   1978     { "nativeSslCertErrorProceed", "(I)V",
   1979         (void*) SslCertErrorProceed },
   1980     { "nativeSslCertErrorCancel", "(II)V",
   1981         (void*) SslCertErrorCancel },
   1982     { "nativeSslClientCert", "(IJ[[B)V",
   1983         (void*) SslClientCertCtx },
   1984     { "nativeSslClientCert", "(I[B[[B)V",
   1985         (void*) SslClientCertPKCS8 },
   1986     { "nativeGetShouldStartScrolledRight", "(I)Z",
   1987         (void*) GetShouldStartScrolledRight },
   1988 };
   1989 
   1990 int registerWebFrame(JNIEnv* env)
   1991 {
   1992     JavaClassJobject::RegisterJavaClassJobject(env);
   1993 
   1994     jclass clazz = env->FindClass("android/webkit/BrowserFrame");
   1995     ALOG_ASSERT(clazz, "Cannot find BrowserFrame");
   1996     gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I");
   1997     ALOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame");
   1998     env->DeleteLocalRef(clazz);
   1999 
   2000     return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame",
   2001             gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods));
   2002 }
   2003 
   2004 } /* namespace android */
   2005