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 pageClients.inspectorClient = new InspectorClientAndroid;
1107 pageClients.deviceMotionClient = deviceMotionC;
1108 pageClients.deviceOrientationClient = deviceOrientationC;
1109 pageClients.geolocationClient = geolocationC;
1110 WebCore::Page* page = new WebCore::Page(pageClients);
1111
1112 editorC->setPage(page);
1113 page->setGroupName("android.webkit");
1114
1115 // Create a WebFrame to access the Java BrowserFrame associated with this page
1116 WebFrame* webFrame = new WebFrame(env, obj, historyList, page);
1117 // Attach webFrame to pageClients.chromeClient and release our ownership
1118 chromeC->setWebFrame(webFrame);
1119 Release(webFrame);
1120
1121 FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(webFrame);
1122 // Create a Frame and the page holds its reference
1123 WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get();
1124 loaderC->setFrame(frame);
1125 #if ENABLE(WDS)
1126 WDS::server()->addFrame(frame);
1127 #endif
1128
1129 // Create a WebViewCore to access the Java WebViewCore associated with this page
1130 WebViewCore* webViewCore = new WebViewCore(env, javaview, frame);
1131
1132 #if ENABLE(WEB_AUTOFILL)
1133 editorC->getAutofill()->setWebViewCore(webViewCore);
1134 #endif
1135
1136 // Create a FrameView
1137 RefPtr<WebCore::FrameView> frameView = WebCore::FrameView::create(frame);
1138 // Create a WebFrameView
1139 WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore);
1140 // As webFrameView Retains webViewCore, release our ownership
1141 Release(webViewCore);
1142 // As frameView Retains webFrameView, release our ownership
1143 Release(webFrameView);
1144 // Attach the frameView to the frame and release our ownership
1145 frame->setView(frameView);
1146 // Set the frame to active to turn on keyboard focus.
1147 frame->init();
1148 frame->selection()->setFocused(true);
1149 frame->page()->focusController()->setFocused(true);
1150 deviceMotionC->setWebViewCore(webViewCore);
1151 deviceOrientationC->setWebViewCore(webViewCore);
1152 geolocationC->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,bool requireAnnotation)1508 static PassRefPtr<WeakJavaInstance> create(jobject obj, bool requireAnnotation)
1509 {
1510 return adoptRef(new WeakJavaInstance(obj, requireAnnotation));
1511 }
1512
1513 private:
WeakJavaInstance(jobject instance,bool requireAnnotation)1514 WeakJavaInstance(jobject instance, bool requireAnnotation)
1515 : JavaInstanceJobject(instance, requireAnnotation)
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,jboolean requireAnnotation)1571 static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer,
1572 jobject javascriptObj, jstring interfaceName, jboolean requireAnnotation)
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 requireAnnotation);
1588 const char* name = getCharactersFromJStringInEnv(env, interfaceName);
1589 // Pass ownership of the added object to bindToWindowObject.
1590 NPObject* npObject = JavaInstanceToNPObject(addedObject.get());
1591 pFrame->script()->bindToWindowObject(pFrame, name, npObject);
1592 // bindToWindowObject calls NPN_RetainObject on the
1593 // returned one (see createV8ObjectForNPObject in V8NPObject.cpp).
1594 // bindToWindowObject also increases obj's ref count and decreases
1595 // the ref count when the object is not reachable from JavaScript
1596 // side. Code here must release the reference count increased by
1597 // bindToWindowObject.
1598
1599 // Note that while this function is declared in WebCore/bridge/npruntime.h, for V8 builds
1600 // we use WebCore/bindings/v8/npruntime.cpp (rather than
1601 // WebCore/bridge/npruntime.cpp), so the function is implemented there.
1602 // TODO: Combine the two versions of these NPAPI files.
1603 NPN_ReleaseObject(npObject);
1604 releaseCharactersForJString(interfaceName, name);
1605 }
1606 }
1607
ClearWebCoreCache()1608 static void ClearWebCoreCache()
1609 {
1610 if (!WebCore::memoryCache()->disabled()) {
1611 // Disabling the cache will remove all resources from the cache. They may
1612 // still live on if they are referenced by some Web page though.
1613 WebCore::memoryCache()->setDisabled(true);
1614 WebCore::memoryCache()->setDisabled(false);
1615 }
1616
1617 // clear page cache
1618 int pageCapacity = WebCore::pageCache()->capacity();
1619 // Setting size to 0, makes all pages be released.
1620 WebCore::pageCache()->setCapacity(0);
1621 WebCore::pageCache()->releaseAutoreleasedPagesNow();
1622 WebCore::pageCache()->setCapacity(pageCapacity);
1623 }
1624
ClearWebViewCache()1625 static void ClearWebViewCache()
1626 {
1627 WebCache::get(false /*privateBrowsing*/)->clear();
1628 }
1629
ClearCache(JNIEnv * env,jobject obj)1630 static void ClearCache(JNIEnv *env, jobject obj)
1631 {
1632 ClearWebCoreCache();
1633 ClearWebViewCache();
1634 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1635 pFrame->script()->lowMemoryNotification();
1636 }
1637
DocumentHasImages(JNIEnv * env,jobject obj)1638 static jboolean DocumentHasImages(JNIEnv *env, jobject obj)
1639 {
1640 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1641 ALOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!");
1642
1643 return pFrame->document()->images()->length() > 0;
1644 }
1645
HasPasswordField(JNIEnv * env,jobject obj)1646 static jboolean HasPasswordField(JNIEnv *env, jobject obj)
1647 {
1648 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1649 ALOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!");
1650
1651 bool found = false;
1652 WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1653 WebCore::Node* node = form->firstItem();
1654 // Null/Empty namespace means that node is not created in HTMLFormElement
1655 // class, but just normal Element class.
1656 while (node && !found && !node->namespaceURI().isNull() &&
1657 !node->namespaceURI().isEmpty()) {
1658 const WTF::Vector<WebCore::FormAssociatedElement*>& elements =
1659 ((WebCore::HTMLFormElement*)node)->associatedElements();
1660 size_t size = elements.size();
1661 for (size_t i = 0; i< size && !found; i++) {
1662 WebCore::HTMLElement* e = toHTMLElement(elements[i]);
1663 if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1664 if (static_cast<WebCore::HTMLInputElement*>(e)->isPasswordField())
1665 found = true;
1666 }
1667 }
1668 node = form->nextItem();
1669 }
1670 return found;
1671 }
1672
GetUsernamePassword(JNIEnv * env,jobject obj)1673 static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
1674 {
1675 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1676 ALOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!");
1677 jobjectArray strArray = NULL;
1678 WTF::String username;
1679 WTF::String password;
1680 if (WebFrame::getWebFrame(pFrame)->getUsernamePasswordFromDom(pFrame, username, password)) {
1681 jclass stringClass = env->FindClass("java/lang/String");
1682 strArray = env->NewObjectArray(2, stringClass, NULL);
1683 env->DeleteLocalRef(stringClass);
1684 env->SetObjectArrayElement(strArray, 0, wtfStringToJstring(env, username));
1685 env->SetObjectArrayElement(strArray, 1, wtfStringToJstring(env, password));
1686 }
1687 return strArray;
1688 }
1689
SetUsernamePassword(JNIEnv * env,jobject obj,jstring username,jstring password)1690 static void SetUsernamePassword(JNIEnv *env, jobject obj,
1691 jstring username, jstring password)
1692 {
1693 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1694 ALOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!");
1695
1696 WebCore::HTMLInputElement* usernameEle = NULL;
1697 WebCore::HTMLInputElement* passwordEle = NULL;
1698 bool found = false;
1699 WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
1700 WebCore::Node* node = form->firstItem();
1701 while (node && !found && !node->namespaceURI().isNull() &&
1702 !node->namespaceURI().isEmpty()) {
1703 const WTF::Vector<WebCore::FormAssociatedElement*>& elements =
1704 ((WebCore::HTMLFormElement*)node)->associatedElements();
1705 size_t size = elements.size();
1706 for (size_t i = 0; i< size && !found; i++) {
1707 WebCore::HTMLElement* e = toHTMLElement(elements[i]);
1708 if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
1709 WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
1710 if (input->autoComplete() == false)
1711 continue;
1712 if (input->isPasswordField())
1713 passwordEle = input;
1714 else if (input->isTextField() || input->isEmailField())
1715 usernameEle = input;
1716 if (usernameEle != NULL && passwordEle != NULL)
1717 found = true;
1718 }
1719 }
1720 node = form->nextItem();
1721 }
1722 if (found) {
1723 usernameEle->setValue(jstringToWtfString(env, username));
1724 passwordEle->setValue(jstringToWtfString(env, password));
1725 }
1726 }
1727
1728 void
saveFormData(HTMLFormElement * form)1729 WebFrame::saveFormData(HTMLFormElement* form)
1730 {
1731 JNIEnv* env = getJNIEnv();
1732 AutoJObject javaFrame = mJavaFrame->frame(env);
1733 if (!javaFrame.get())
1734 return;
1735
1736 if (form->autoComplete()) {
1737 JNIEnv* env = getJNIEnv();
1738 jclass mapClass = env->FindClass("java/util/HashMap");
1739 ALOG_ASSERT(mapClass, "Could not find HashMap class!");
1740 jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
1741 ALOG_ASSERT(init, "Could not find constructor for HashMap");
1742 jobject hashMap = env->NewObject(mapClass, init, 1);
1743 ALOG_ASSERT(hashMap, "Could not create a new HashMap");
1744 jmethodID put = env->GetMethodID(mapClass, "put",
1745 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1746 ALOG_ASSERT(put, "Could not find put method on HashMap");
1747 WTF::Vector<WebCore::FormAssociatedElement*> elements = form->associatedElements();
1748 size_t size = elements.size();
1749 for (size_t i = 0; i < size; i++) {
1750 WebCore::HTMLElement* e = toHTMLElement(elements[i]);
1751 if (e->hasTagName(WebCore::HTMLNames::inputTag)) {
1752 WebCore::HTMLInputElement* input = static_cast<WebCore::HTMLInputElement*>(e);
1753 if (input->isTextField() && !input->isPasswordField()
1754 && input->autoComplete()) {
1755 WTF::String value = input->value();
1756 int len = value.length();
1757 if (len) {
1758 const WTF::AtomicString& name = input->name();
1759 jstring key = wtfStringToJstring(env, name);
1760 jstring val = wtfStringToJstring(env, value);
1761 ALOG_ASSERT(key && val, "name or value not set");
1762 env->CallObjectMethod(hashMap, put, key, val);
1763 env->DeleteLocalRef(key);
1764 env->DeleteLocalRef(val);
1765 }
1766 }
1767 }
1768 }
1769 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSaveFormData, hashMap);
1770 env->DeleteLocalRef(hashMap);
1771 env->DeleteLocalRef(mapClass);
1772 }
1773 }
1774
OrientationChanged(JNIEnv * env,jobject obj,int orientation)1775 static void OrientationChanged(JNIEnv *env, jobject obj, int orientation)
1776 {
1777 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj);
1778 ALOGV("Sending orientation: %d", orientation);
1779 pFrame->sendOrientationChangeEvent(orientation);
1780 }
1781
GetShouldStartScrolledRight(JNIEnv * env,jobject obj,jint browserFrame)1782 static jboolean GetShouldStartScrolledRight(JNIEnv *env, jobject obj,
1783 jint browserFrame)
1784 {
1785 jboolean startScrolledRight = false; // default is start scrolled left
1786 WebCore::Frame* frame = reinterpret_cast<WebCore::Frame*>(browserFrame);
1787 WebCore::Document* document = frame->document();
1788 if (document) {
1789 RenderStyle* style = document->renderer()->style();
1790 WritingMode writingMode = style->writingMode();
1791 ALOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode,
1792 "BottomToTopWritingMode isn't possible in any "
1793 "language and cannot be specified in w3c writing-mode.");
1794 if (writingMode == WebCore::RightToLeftWritingMode)
1795 startScrolledRight = true; // vertical-rl pages start scrolled right
1796 else if (writingMode == WebCore::TopToBottomWritingMode)
1797 startScrolledRight = !style->isLeftToRightDirection(); // RTL starts right
1798 }
1799 return startScrolledRight;
1800 }
1801
AuthenticationProceed(JNIEnv * env,jobject obj,int handle,jstring jUsername,jstring jPassword)1802 static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword)
1803 {
1804 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1805 std::string username = jstringToStdString(env, jUsername);
1806 std::string password = jstringToStdString(env, jPassword);
1807 client->setAuth(username, password);
1808 }
1809
AuthenticationCancel(JNIEnv * env,jobject obj,int handle)1810 static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle)
1811 {
1812 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1813 client->cancelAuth();
1814 }
1815
SslCertErrorProceed(JNIEnv * env,jobject obj,int handle)1816 static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle)
1817 {
1818 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1819 client->proceedSslCertError();
1820 }
1821
SslCertErrorCancel(JNIEnv * env,jobject obj,int handle,int cert_error)1822 static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error)
1823 {
1824 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1825 client->cancelSslCertError(cert_error);
1826 }
1827
getX509Cert(JNIEnv * env,jobjectArray chain)1828 static scoped_refptr<net::X509Certificate> getX509Cert(JNIEnv *env, jobjectArray chain)
1829 {
1830 // Based on Android's NativeCrypto_SSL_use_certificate
1831 int length = env->GetArrayLength(chain);
1832 if (length == 0) {
1833 return NULL;
1834 }
1835
1836 base::ScopedOpenSSL<X509, X509_free> first;
1837 ScopedVector<base::ScopedOpenSSL<X509, X509_free> > rest;
1838 for (int i = 0; i < length; i++) {
1839 ScopedLocalRef<jbyteArray> cert(env,
1840 reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(chain, i)));
1841 if (cert.get() == NULL) {
1842 return NULL;
1843 }
1844 ScopedByteArrayRO certBytes(env, cert.get());
1845 if (certBytes.get() == NULL) {
1846 return NULL;
1847 }
1848 const char* data = reinterpret_cast<const char*>(certBytes.get());
1849 int length = certBytes.size();
1850 X509* x509 = net::X509Certificate::CreateOSCertHandleFromBytes(data, length);
1851 if (x509 == NULL) {
1852 return NULL;
1853 }
1854 if (i == 0) {
1855 first.reset(x509);
1856 } else {
1857 rest.push_back(new base::ScopedOpenSSL<X509, X509_free>(x509));
1858 }
1859 }
1860
1861 std::vector<X509*> certChain(rest.size());
1862 for (size_t i = 0; i < rest.size(); i++) {
1863 certChain[i] = rest[i]->get();
1864 }
1865 return net::X509Certificate::CreateFromHandle(first.get(),
1866 net::X509Certificate::SOURCE_FROM_NETWORK,
1867 certChain);
1868 }
1869
SslClientCertPKCS8(JNIEnv * env,jobject obj,int handle,jbyteArray pkey,jobjectArray chain)1870 static void SslClientCertPKCS8(JNIEnv *env, jobject obj, int handle, jbyteArray pkey, jobjectArray chain)
1871 {
1872 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1873 if (pkey == NULL || chain == NULL) {
1874 client->sslClientCert(NULL, NULL);
1875 return;
1876 }
1877
1878 // Based on Android's NativeCrypto_SSL_use_PrivateKey
1879 ScopedByteArrayRO pkeyBytes(env, pkey);
1880 if (pkeyBytes.get() == NULL) {
1881 client->sslClientCert(NULL, NULL);
1882 return;
1883 }
1884
1885 base::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8;
1886 const unsigned char* pkeyChars = reinterpret_cast<const unsigned char*>(pkeyBytes.get());
1887 pkcs8.reset(d2i_PKCS8_PRIV_KEY_INFO(NULL, &pkeyChars, pkeyBytes.size()));
1888 if (!pkcs8.get()) {
1889 client->sslClientCert(NULL, NULL);
1890 return;
1891 }
1892 base::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> privateKey(EVP_PKCS82PKEY(pkcs8.get()));
1893 if (!privateKey.get()) {
1894 client->sslClientCert(NULL, NULL);
1895 return;
1896 }
1897 scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain);
1898 if (certificate == NULL) {
1899 client->sslClientCert(NULL, NULL);
1900 return;
1901 }
1902 client->sslClientCert(privateKey.release(), certificate);
1903 }
1904
SslClientCertCtx(JNIEnv * env,jobject obj,int handle,jint ctx,jobjectArray chain)1905 static void SslClientCertCtx(JNIEnv *env, jobject obj, int handle, jint ctx, jobjectArray chain)
1906 {
1907 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle);
1908 EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(static_cast<uintptr_t>(ctx));
1909 if (pkey == NULL || chain == NULL) {
1910 client->sslClientCert(NULL, NULL);
1911 return;
1912 }
1913 scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain);
1914 if (certificate == NULL) {
1915 client->sslClientCert(NULL, NULL);
1916 return;
1917 }
1918 CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
1919 client->sslClientCert(pkey, certificate);
1920 }
1921
1922 // ----------------------------------------------------------------------------
1923
1924 /*
1925 * JNI registration.
1926 */
1927 static JNINativeMethod gBrowserFrameNativeMethods[] = {
1928 /* name, signature, funcPtr */
1929 { "nativeCallPolicyFunction", "(II)V",
1930 (void*) CallPolicyFunction },
1931 { "nativeCreateFrame", "(Landroid/webkit/WebViewCore;Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V",
1932 (void*) CreateFrame },
1933 { "nativeDestroyFrame", "()V",
1934 (void*) DestroyFrame },
1935 { "nativeStopLoading", "()V",
1936 (void*) StopLoading },
1937 { "nativeLoadUrl", "(Ljava/lang/String;Ljava/util/Map;)V",
1938 (void*) LoadUrl },
1939 { "nativePostUrl", "(Ljava/lang/String;[B)V",
1940 (void*) PostUrl },
1941 { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
1942 (void*) LoadData },
1943 { "nativeSaveWebArchive", "(Ljava/lang/String;Z)Ljava/lang/String;",
1944 (void*) SaveWebArchive },
1945 { "externalRepresentation", "()Ljava/lang/String;",
1946 (void*) ExternalRepresentation },
1947 { "documentAsText", "()Ljava/lang/String;",
1948 (void*) DocumentAsText },
1949 { "childFramesAsText", "()Ljava/lang/String;",
1950 (void*) ChildFramesAsText },
1951 { "reload", "(Z)V",
1952 (void*) Reload },
1953 { "nativeGoBackOrForward", "(I)V",
1954 (void*) GoBackOrForward },
1955 { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;Z)V",
1956 (void*) AddJavascriptInterface },
1957 { "stringByEvaluatingJavaScriptFromString",
1958 "(Ljava/lang/String;)Ljava/lang/String;",
1959 (void*) StringByEvaluatingJavaScriptFromString },
1960 { "clearCache", "()V",
1961 (void*) ClearCache },
1962 { "documentHasImages", "()Z",
1963 (void*) DocumentHasImages },
1964 { "hasPasswordField", "()Z",
1965 (void*) HasPasswordField },
1966 { "getUsernamePassword", "()[Ljava/lang/String;",
1967 (void*) GetUsernamePassword },
1968 { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V",
1969 (void*) SetUsernamePassword },
1970 { "nativeOrientationChanged", "(I)V",
1971 (void*) OrientationChanged },
1972 { "nativeAuthenticationProceed", "(ILjava/lang/String;Ljava/lang/String;)V",
1973 (void*) AuthenticationProceed },
1974 { "nativeAuthenticationCancel", "(I)V",
1975 (void*) AuthenticationCancel },
1976 { "nativeSslCertErrorProceed", "(I)V",
1977 (void*) SslCertErrorProceed },
1978 { "nativeSslCertErrorCancel", "(II)V",
1979 (void*) SslCertErrorCancel },
1980 { "nativeSslClientCert", "(II[[B)V",
1981 (void*) SslClientCertCtx },
1982 { "nativeSslClientCert", "(I[B[[B)V",
1983 (void*) SslClientCertPKCS8 },
1984 { "nativeGetShouldStartScrolledRight", "(I)Z",
1985 (void*) GetShouldStartScrolledRight },
1986 };
1987
registerWebFrame(JNIEnv * env)1988 int registerWebFrame(JNIEnv* env)
1989 {
1990 JavaClassJobject::RegisterJavaClassJobject(env);
1991
1992 jclass clazz = env->FindClass("android/webkit/BrowserFrame");
1993 ALOG_ASSERT(clazz, "Cannot find BrowserFrame");
1994 gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I");
1995 ALOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame");
1996 env->DeleteLocalRef(clazz);
1997
1998 return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame",
1999 gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods));
2000 }
2001
2002 } /* namespace android */
2003