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 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 */ 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; 211 AutoJObject frame(JNIEnv* env) { 212 return getRealObject(env, mObj); 213 } 214 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 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 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 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 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: 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 } 386 ~FileInfo() { 387 m_env->DeleteLocalRef(m_uri); 388 } 389 int getSize() { return m_size; } 390 jstring getUri() { return m_uri; } 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* 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 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 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 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 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 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 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 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 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 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 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 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 617 WebFrame::userAgentForURL(const WebCore::KURL* url) 618 { 619 return mUserAgent; 620 } 621 622 void 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 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 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 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 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* 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 725 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 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 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 766 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 778 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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) 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 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 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 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 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 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 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 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 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: 1510 static PassRefPtr<WeakJavaInstance> create(jobject obj, bool requireAnnotation) 1511 { 1512 return adoptRef(new WeakJavaInstance(obj, requireAnnotation)); 1513 } 1514 1515 private: 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 } 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 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 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 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 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 1627 static void ClearWebViewCache() 1628 { 1629 WebCache::get(false /*privateBrowsing*/)->clear(); 1630 } 1631 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 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 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 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 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 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 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 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 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 1812 static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle) 1813 { 1814 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1815 client->cancelAuth(); 1816 } 1817 1818 static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle) 1819 { 1820 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1821 client->proceedSslCertError(); 1822 } 1823 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 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 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 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 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