• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
globalLocalizedName(WebCore::PlatformBridge::rawResId resId)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  */
initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId,android::WebFrame * webFrame)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;
frameandroid::WebFrame::JavaBrowserFrame210     AutoJObject frame(JNIEnv* env) {
211         return getRealObject(env, mObj);
212     }
historyandroid::WebFrame::JavaBrowserFrame213     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 
WebFrame(JNIEnv * env,jobject obj,jobject historyList,WebCore::Page * page)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 
~WebFrame()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 
getWebFrame(const WebCore::Frame * frame)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 
createJavaMapFromHTTPHeaders(JNIEnv * env,const WebCore::HTTPHeaderMap & map)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:
FileInfo(JNIEnv * env,const WTF::String & name)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     }
~FileInfo()385     ~FileInfo() {
386         m_env->DeleteLocalRef(m_uri);
387     }
getSize()388     int getSize() { return m_size; }
getUri()389     jstring getUri() { return m_uri; }
setSize(int size)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*
shouldInterceptRequest(const WTF::String & url)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
reportError(int errorCode,const WTF::String & description,const WTF::String & failingUrl)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
convertIDNToUnicode(const WebCore::KURL & url)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
loadStarted(WebCore::Frame * frame)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
transitionToCommitted(WebCore::Frame * frame)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
didFinishLoad(WebCore::Frame * frame)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
addHistoryItem(WebCore::HistoryItem * item)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
removeHistoryItem(int index)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
updateHistoryIndex(int newIndex)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
setTitle(const WTF::String & title)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
windowObjectCleared(WebCore::Frame * frame)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
setProgress(float newProgress)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
userAgentForURL(const WebCore::KURL * url)622 WebFrame::userAgentForURL(const WebCore::KURL* url)
623 {
624     return mUserAgent;
625 }
626 
627 void
didReceiveIcon(WebCore::Image * icon)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
didReceiveTouchIconURL(const WTF::String & url,bool precomposed)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
updateVisitedHistory(const WebCore::KURL & url,bool reload)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
canHandleRequest(const WebCore::ResourceRequest & request)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
shouldSaveFormData()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*
createWindow(bool dialog,bool userGesture)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
requestFocus() const730 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
closeWindow(WebViewCore * webViewCore)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
decidePolicyForFormResubmission(WebCore::FramePolicyFunction func)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
getRawResourceFilename(WebCore::PlatformBridge::rawResId id) const771 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
density() const783 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
didReceiveAuthenticationChallenge(WebUrlLoaderClient * client,const std::string & host,const std::string & realm,bool useCachedCredentials,bool suppressDialog)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
reportSslCertError(WebUrlLoaderClient * client,int error,const std::string & cert,const std::string & url)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
requestClientCert(WebUrlLoaderClient * client,const std::string & hostAndPort)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
downloadStart(const std::string & url,const std::string & userAgent,const std::string & contentDisposition,const std::string & mimetype,long long contentLength)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
didReceiveData(const char * data,int size)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
didFinishLoading()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 
setCertificate(const std::string & cert)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 
autoLogin(const std::string & loginHeader)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 
maybeSavePassword(WebCore::Frame * frame,const WebCore::ResourceRequest & request)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 
getUsernamePasswordFromDom(WebCore::Frame * frame,WTF::String & username,WTF::String & password)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 
getPostData(const WebCore::ResourceRequest & request)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 
CallPolicyFunction(JNIEnv * env,jobject obj,jint func,jint decision)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 
CreateFrame(JNIEnv * env,jobject obj,jobject javaview,jobject jAssetManager,jobject historyList)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 
DestroyFrame(JNIEnv * env,jobject obj)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 
LoadUrl(JNIEnv * env,jobject obj,jstring url,jobject headers)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 
PostUrl(JNIEnv * env,jobject obj,jstring url,jbyteArray postData)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 
LoadData(JNIEnv * env,jobject obj,jstring baseUrl,jstring data,jstring mimeType,jstring encoding,jstring failUrl)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 
StopLoading(JNIEnv * env,jobject obj)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)
saveArchiveAutoname(String basename,String name,String extension)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 
SaveWebArchive(JNIEnv * env,jobject obj,jstring basename,jboolean autoname)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 
ExternalRepresentation(JNIEnv * env,jobject obj)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 
FrameAsText(WebCore::Frame * pFrame,jboolean dumpChildFrames)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 
DocumentAsText(JNIEnv * env,jobject obj)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 
ChildFramesAsText(JNIEnv * env,jobject obj)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 
Reload(JNIEnv * env,jobject obj,jboolean allowStale)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 
GoBackOrForward(JNIEnv * env,jobject obj,jint pos)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 
StringByEvaluatingJavaScriptFromString(JNIEnv * env,jobject obj,jstring script)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:
create(jobject obj)1508     static PassRefPtr<WeakJavaInstance> create(jobject obj)
1509     {
1510         return adoptRef(new WeakJavaInstance(obj));
1511     }
1512 
1513 private:
WeakJavaInstance(jobject instance)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     }
~WeakJavaInstance()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 
begin()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 
end()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 
AddJavascriptInterface(JNIEnv * env,jobject obj,jint nativeFramePointer,jobject javascriptObj,jstring interfaceName)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 
ClearWebCoreCache()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 
ClearWebViewCache()1624 static void ClearWebViewCache()
1625 {
1626     WebCache::get(false /*privateBrowsing*/)->clear();
1627 }
1628 
ClearCache(JNIEnv * env,jobject obj)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 
DocumentHasImages(JNIEnv * env,jobject obj)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 
HasPasswordField(JNIEnv * env,jobject obj)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 
GetUsernamePassword(JNIEnv * env,jobject obj)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 
SetUsernamePassword(JNIEnv * env,jobject obj,jstring username,jstring password)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
saveFormData(HTMLFormElement * form)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 
OrientationChanged(JNIEnv * env,jobject obj,int orientation)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 
GetShouldStartScrolledRight(JNIEnv * env,jobject obj,jint browserFrame)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 
AuthenticationProceed(JNIEnv * env,jobject obj,int handle,jstring jUsername,jstring jPassword)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 
AuthenticationCancel(JNIEnv * env,jobject obj,int handle)1809 static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle)
1810 {
1811     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1812     client->cancelAuth();
1813 }
1814 
SslCertErrorProceed(JNIEnv * env,jobject obj,int handle)1815 static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle)
1816 {
1817     WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1818     client->proceedSslCertError();
1819 }
1820 
SslCertErrorCancel(JNIEnv * env,jobject obj,int handle,int cert_error)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 
getX509Cert(JNIEnv * env,jobjectArray chain)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 
SslClientCertPKCS8(JNIEnv * env,jobject obj,int handle,jbyteArray pkey,jobjectArray chain)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 
SslClientCertCtx(JNIEnv * env,jobject obj,int handle,jint ctx,jobjectArray chain)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 
registerWebFrame(JNIEnv * env)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