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