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