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
114using namespace JSC::Bindings;
115
116static String* gUploadFileLabel;
117static String* gResetLabel;
118static String* gSubmitLabel;
119static String* gNoFileChosenLabel;
120
121String* 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 */
141void 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
166namespace android {
167
168// ----------------------------------------------------------------------------
169
170#define WEBCORE_MEMORY_CAP 15 * 1024 * 1024
171
172// ----------------------------------------------------------------------------
173
174struct 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
218static 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
224WebFrame::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
323WebFrame::~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
335WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame)
336{
337    FrameLoaderClientAndroid* client =
338            static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
339    return client->webFrame();
340}
341
342static 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.
377class FileInfo {
378public:
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; }
391private:
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
399UrlInterceptResponse*
400WebFrame::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
419void
420WebFrame::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
436WTF::String
437WebFrame::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
454void
455WebFrame::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
511void
512WebFrame::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
525void
526WebFrame::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
553void
554WebFrame::addHistoryItem(WebCore::HistoryItem* item)
555{
556    ALOGV("::WebCore:: addHistoryItem");
557    JNIEnv* env = getJNIEnv();
558    WebHistory::AddItem(mJavaFrame->history(env), item);
559}
560
561void
562WebFrame::removeHistoryItem(int index)
563{
564    ALOGV("::WebCore:: removeHistoryItem at %d", index);
565    JNIEnv* env = getJNIEnv();
566    WebHistory::RemoveItem(mJavaFrame->history(env), index);
567}
568
569void
570WebFrame::updateHistoryIndex(int newIndex)
571{
572    ALOGV("::WebCore:: updateHistoryIndex to %d", newIndex);
573    JNIEnv* env = getJNIEnv();
574    WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex);
575}
576
577void
578WebFrame::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
595void
596WebFrame::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
608void
609WebFrame::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
621const WTF::String
622WebFrame::userAgentForURL(const WebCore::KURL* url)
623{
624    return mUserAgent;
625}
626
627void
628WebFrame::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
645void
646WebFrame::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
660void
661WebFrame::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
676bool
677WebFrame::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
704bool
705WebFrame::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
716WebCore::Frame*
717WebFrame::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
729void
730WebFrame::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
740void
741WebFrame::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
754struct PolicyFunctionWrapper {
755    WebCore::FramePolicyFunction func;
756};
757
758void
759WebFrame::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
770WTF::String
771WebFrame::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
782float
783WebFrame::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
794void
795WebFrame::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
811void
812WebFrame::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
831void
832WebFrame::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
844void
845WebFrame::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
865void
866WebFrame::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
879void
880WebFrame::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
890void 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
906void 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
951void 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
978bool 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
1007jbyteArray 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
1076static 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
1090static 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
1178static 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
1206static 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
1257static 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
1283static 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
1308static 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)
1319static 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
1356static 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
1405static 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
1415static 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
1437static 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
1446static 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
1459static 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
1476static 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
1489static 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.
1506class WeakJavaInstance : public JavaInstanceJobject {
1507public:
1508    static PassRefPtr<WeakJavaInstance> create(jobject obj)
1509    {
1510        return adoptRef(new WeakJavaInstance(obj));
1511    }
1512
1513private:
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
1564private:
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
1571static 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
1607static 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
1624static void ClearWebViewCache()
1625{
1626    WebCache::get(false /*privateBrowsing*/)->clear();
1627}
1628
1629static 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
1637static 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
1645static 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
1672static 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
1689static 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
1727void
1728WebFrame::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
1774static 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
1781static 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
1801static 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
1809static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle)
1810{
1811    WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1812    client->cancelAuth();
1813}
1814
1815static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle)
1816{
1817    WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1818    client->proceedSslCertError();
1819}
1820
1821static 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
1827static 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
1869static 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
1904static 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 */
1926static 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
1987int 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