1 /* 2 * Copyright 2006, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define LOG_TAG "webcoreglue" 27 28 #include "config.h" 29 #include "WebCoreFrameBridge.h" 30 31 #include "Arena.h" 32 #include "BackForwardList.h" 33 #include "MemoryCache.h" 34 #include "Chrome.h" 35 #include "ChromeClientAndroid.h" 36 #include "ChromiumInit.h" 37 #include "ContextMenuClientAndroid.h" 38 #include "DeviceMotionClientAndroid.h" 39 #include "DeviceOrientationClientAndroid.h" 40 #include "Document.h" 41 #include "DocumentLoader.h" 42 #include "DragClientAndroid.h" 43 #include "EditorClientAndroid.h" 44 #include "Element.h" 45 #include "FocusController.h" 46 #include "Font.h" 47 #include "Frame.h" 48 #include "FrameLoader.h" 49 #include "FrameLoaderClientAndroid.h" 50 #include "FrameLoadRequest.h" 51 #include "FrameTree.h" 52 #include "FrameView.h" 53 #include "GraphicsContext.h" 54 #include "HistoryItem.h" 55 #include "HTMLCollection.h" 56 #include "HTMLElement.h" 57 #include "HTMLFormElement.h" 58 #include "HTMLInputElement.h" 59 #include "HTMLNames.h" 60 #include "IconDatabase.h" 61 #include "Image.h" 62 #include "InspectorClientAndroid.h" 63 #include "JavaNPObjectV8.h" 64 #include "JavaInstanceJobjectV8.h" 65 #include "KURL.h" 66 #include "Page.h" 67 #include "PageCache.h" 68 #include "PlatformString.h" 69 #include "RenderPart.h" 70 #include "RenderSkinAndroid.h" 71 #include "RenderTreeAsText.h" 72 #include "RenderView.h" 73 #include "ResourceHandle.h" 74 #include "ResourceHandleInternal.h" 75 #include "ScriptController.h" 76 #include "ScriptValue.h" 77 #include "SecurityOrigin.h" 78 #include "SelectionController.h" 79 #include "Settings.h" 80 #include "SubstituteData.h" 81 #include "UrlInterceptResponse.h" 82 #include "UserGestureIndicator.h" 83 #include "WebArchiveAndroid.h" 84 #include "WebCache.h" 85 #include "WebCoreJni.h" 86 #include "WebHistory.h" 87 #include "WebIconDatabase.h" 88 #include "WebFrameView.h" 89 #include "WebUrlLoaderClient.h" 90 #include "WebViewCore.h" 91 #include "android_graphics.h" 92 #include "jni.h" 93 #include "wds/DebugServer.h" 94 95 #include <JNIUtility.h> 96 #include <JNIHelp.h> 97 #include <ScopedPrimitiveArray.h> 98 #include <ScopedLocalRef.h> 99 #include <SkGraphics.h> 100 #include <android_runtime/android_util_AssetManager.h> 101 #include <openssl/x509.h> 102 #include <utils/misc.h> 103 #include <androidfw/AssetManager.h> 104 #include <wtf/CurrentTime.h> 105 #include <wtf/Platform.h> 106 #include <wtf/text/AtomicString.h> 107 #include <wtf/text/CString.h> 108 #include <wtf/text/StringBuilder.h> 109 110 #if ENABLE(WEB_AUTOFILL) 111 #include "autofill/WebAutofill.h" 112 #endif 113 114 using namespace JSC::Bindings; 115 116 static String* gUploadFileLabel; 117 static String* gResetLabel; 118 static String* gSubmitLabel; 119 static String* gNoFileChosenLabel; 120 121 String* WebCore::PlatformBridge::globalLocalizedName( 122 WebCore::PlatformBridge::rawResId resId) 123 { 124 switch (resId) { 125 case WebCore::PlatformBridge::FileUploadLabel: 126 return gUploadFileLabel; 127 case WebCore::PlatformBridge::ResetLabel: 128 return gResetLabel; 129 case WebCore::PlatformBridge::SubmitLabel: 130 return gSubmitLabel; 131 case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: 132 return gNoFileChosenLabel; 133 134 default: 135 return 0; 136 } 137 } 138 /** 139 * Instantiate the localized name desired. 140 */ 141 void initGlobalLocalizedName(WebCore::PlatformBridge::rawResId resId, 142 android::WebFrame* webFrame) 143 { 144 String** pointer; 145 switch (resId) { 146 case WebCore::PlatformBridge::FileUploadLabel: 147 pointer = &gUploadFileLabel; 148 break; 149 case WebCore::PlatformBridge::ResetLabel: 150 pointer = &gResetLabel; 151 break; 152 case WebCore::PlatformBridge::SubmitLabel: 153 pointer = &gSubmitLabel; 154 break; 155 case WebCore::PlatformBridge::FileUploadNoFileChosenLabel: 156 pointer = &gNoFileChosenLabel; 157 break; 158 default: 159 return; 160 } 161 if (!(*pointer) && webFrame) { 162 (*pointer) = new String(webFrame->getRawResourceFilename(resId).impl()); 163 } 164 } 165 166 namespace android { 167 168 // ---------------------------------------------------------------------------- 169 170 #define WEBCORE_MEMORY_CAP 15 * 1024 * 1024 171 172 // ---------------------------------------------------------------------------- 173 174 struct WebFrame::JavaBrowserFrame 175 { 176 jweak mObj; 177 jweak mHistoryList; // WebBackForwardList object 178 jmethodID mStartLoadingResource; 179 jmethodID mMaybeSavePassword; 180 jmethodID mShouldInterceptRequest; 181 jmethodID mLoadStarted; 182 jmethodID mTransitionToCommitted; 183 jmethodID mLoadFinished; 184 jmethodID mReportError; 185 jmethodID mSetTitle; 186 jmethodID mWindowObjectCleared; 187 jmethodID mSetProgress; 188 jmethodID mDidReceiveIcon; 189 jmethodID mDidReceiveTouchIconUrl; 190 jmethodID mUpdateVisitedHistory; 191 jmethodID mHandleUrl; 192 jmethodID mCreateWindow; 193 jmethodID mCloseWindow; 194 jmethodID mDecidePolicyForFormResubmission; 195 jmethodID mRequestFocus; 196 jmethodID mGetRawResFilename; 197 jmethodID mDensity; 198 jmethodID mGetFileSize; 199 jmethodID mGetFile; 200 jmethodID mDidReceiveAuthenticationChallenge; 201 jmethodID mReportSslCertError; 202 jmethodID mRequestClientCert; 203 jmethodID mDownloadStart; 204 jmethodID mDidReceiveData; 205 jmethodID mDidFinishLoading; 206 jmethodID mSetCertificate; 207 jmethodID mShouldSaveFormData; 208 jmethodID mSaveFormData; 209 jmethodID mAutoLogin; 210 AutoJObject frame(JNIEnv* env) { 211 return getRealObject(env, mObj); 212 } 213 AutoJObject history(JNIEnv* env) { 214 return getRealObject(env, mHistoryList); 215 } 216 }; 217 218 static jfieldID gFrameField; 219 #define GET_NATIVE_FRAME(env, obj) ((WebCore::Frame*)env->GetIntField(obj, gFrameField)) 220 #define SET_NATIVE_FRAME(env, obj, frame) (env->SetIntField(obj, gFrameField, frame)) 221 222 // ---------------------------------------------------------------------------- 223 224 WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* page) 225 : mPage(page) 226 { 227 jclass clazz = env->GetObjectClass(obj); 228 mJavaFrame = new JavaBrowserFrame; 229 mJavaFrame->mObj = env->NewWeakGlobalRef(obj); 230 mJavaFrame->mHistoryList = env->NewWeakGlobalRef(historyList); 231 mJavaFrame->mMaybeSavePassword = env->GetMethodID(clazz, "maybeSavePassword", 232 "([BLjava/lang/String;Ljava/lang/String;)V"); 233 mJavaFrame->mShouldInterceptRequest = 234 env->GetMethodID(clazz, "shouldInterceptRequest", 235 "(Ljava/lang/String;)Landroid/webkit/WebResourceResponse;"); 236 mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted", 237 "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V"); 238 mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted", 239 "(IZ)V"); 240 mJavaFrame->mLoadFinished = env->GetMethodID(clazz, "loadFinished", 241 "(Ljava/lang/String;IZ)V"); 242 mJavaFrame->mReportError = env->GetMethodID(clazz, "reportError", 243 "(ILjava/lang/String;Ljava/lang/String;)V"); 244 mJavaFrame->mSetTitle = env->GetMethodID(clazz, "setTitle", 245 "(Ljava/lang/String;)V"); 246 mJavaFrame->mWindowObjectCleared = env->GetMethodID(clazz, "windowObjectCleared", 247 "(I)V"); 248 mJavaFrame->mSetProgress = env->GetMethodID(clazz, "setProgress", 249 "(I)V"); 250 mJavaFrame->mDidReceiveIcon = env->GetMethodID(clazz, "didReceiveIcon", 251 "(Landroid/graphics/Bitmap;)V"); 252 mJavaFrame->mDidReceiveTouchIconUrl = env->GetMethodID(clazz, "didReceiveTouchIconUrl", 253 "(Ljava/lang/String;Z)V"); 254 mJavaFrame->mUpdateVisitedHistory = env->GetMethodID(clazz, "updateVisitedHistory", 255 "(Ljava/lang/String;Z)V"); 256 mJavaFrame->mHandleUrl = env->GetMethodID(clazz, "handleUrl", 257 "(Ljava/lang/String;)Z"); 258 mJavaFrame->mCreateWindow = env->GetMethodID(clazz, "createWindow", 259 "(ZZ)Landroid/webkit/BrowserFrame;"); 260 mJavaFrame->mCloseWindow = env->GetMethodID(clazz, "closeWindow", 261 "(Landroid/webkit/WebViewCore;)V"); 262 mJavaFrame->mDecidePolicyForFormResubmission = env->GetMethodID(clazz, 263 "decidePolicyForFormResubmission", "(I)V"); 264 mJavaFrame->mRequestFocus = env->GetMethodID(clazz, "requestFocus", 265 "()V"); 266 mJavaFrame->mGetRawResFilename = env->GetMethodID(clazz, "getRawResFilename", 267 "(I)Ljava/lang/String;"); 268 mJavaFrame->mDensity = env->GetMethodID(clazz, "density","()F"); 269 mJavaFrame->mGetFileSize = env->GetMethodID(clazz, "getFileSize", "(Ljava/lang/String;)I"); 270 mJavaFrame->mGetFile = env->GetMethodID(clazz, "getFile", "(Ljava/lang/String;[BII)I"); 271 mJavaFrame->mDidReceiveAuthenticationChallenge = env->GetMethodID(clazz, "didReceiveAuthenticationChallenge", 272 "(ILjava/lang/String;Ljava/lang/String;ZZ)V"); 273 mJavaFrame->mReportSslCertError = env->GetMethodID(clazz, "reportSslCertError", "(II[BLjava/lang/String;)V"); 274 mJavaFrame->mRequestClientCert = env->GetMethodID(clazz, "requestClientCert", "(ILjava/lang/String;)V"); 275 mJavaFrame->mDownloadStart = env->GetMethodID(clazz, "downloadStart", 276 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V"); 277 mJavaFrame->mDidReceiveData = env->GetMethodID(clazz, "didReceiveData", "([BI)V"); 278 mJavaFrame->mDidFinishLoading = env->GetMethodID(clazz, "didFinishLoading", "()V"); 279 mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", "([B)V"); 280 mJavaFrame->mShouldSaveFormData = env->GetMethodID(clazz, "shouldSaveFormData", "()Z"); 281 mJavaFrame->mSaveFormData = env->GetMethodID(clazz, "saveFormData", "(Ljava/util/HashMap;)V"); 282 mJavaFrame->mAutoLogin = env->GetMethodID(clazz, "autoLogin", 283 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); 284 env->DeleteLocalRef(clazz); 285 286 ALOG_ASSERT(mJavaFrame->mMaybeSavePassword, "Could not find method maybeSavePassword"); 287 ALOG_ASSERT(mJavaFrame->mShouldInterceptRequest, "Could not find method shouldInterceptRequest"); 288 ALOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted"); 289 ALOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted"); 290 ALOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished"); 291 ALOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError"); 292 ALOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle"); 293 ALOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared"); 294 ALOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress"); 295 ALOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon"); 296 ALOG_ASSERT(mJavaFrame->mDidReceiveTouchIconUrl, "Could not find method didReceiveTouchIconUrl"); 297 ALOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory"); 298 ALOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl"); 299 ALOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow"); 300 ALOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow"); 301 ALOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission"); 302 ALOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus"); 303 ALOG_ASSERT(mJavaFrame->mGetRawResFilename, "Could not find method getRawResFilename"); 304 ALOG_ASSERT(mJavaFrame->mDensity, "Could not find method density"); 305 ALOG_ASSERT(mJavaFrame->mGetFileSize, "Could not find method getFileSize"); 306 ALOG_ASSERT(mJavaFrame->mGetFile, "Could not find method getFile"); 307 ALOG_ASSERT(mJavaFrame->mDidReceiveAuthenticationChallenge, "Could not find method didReceiveAuthenticationChallenge"); 308 ALOG_ASSERT(mJavaFrame->mReportSslCertError, "Could not find method reportSslCertError"); 309 ALOG_ASSERT(mJavaFrame->mRequestClientCert, "Could not find method requestClientCert"); 310 ALOG_ASSERT(mJavaFrame->mDownloadStart, "Could not find method downloadStart"); 311 ALOG_ASSERT(mJavaFrame->mDidReceiveData, "Could not find method didReceiveData"); 312 ALOG_ASSERT(mJavaFrame->mDidFinishLoading, "Could not find method didFinishLoading"); 313 ALOG_ASSERT(mJavaFrame->mSetCertificate, "Could not find method setCertificate"); 314 ALOG_ASSERT(mJavaFrame->mShouldSaveFormData, "Could not find method shouldSaveFormData"); 315 ALOG_ASSERT(mJavaFrame->mSaveFormData, "Could not find method saveFormData"); 316 ALOG_ASSERT(mJavaFrame->mAutoLogin, "Could not find method autoLogin"); 317 318 mUserAgent = WTF::String(); 319 mBlockNetworkLoads = false; 320 m_renderSkins = 0; 321 } 322 323 WebFrame::~WebFrame() 324 { 325 if (mJavaFrame->mObj) { 326 JNIEnv* env = getJNIEnv(); 327 env->DeleteWeakGlobalRef(mJavaFrame->mObj); 328 env->DeleteWeakGlobalRef(mJavaFrame->mHistoryList); 329 mJavaFrame->mObj = 0; 330 } 331 delete mJavaFrame; 332 delete m_renderSkins; 333 } 334 335 WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame) 336 { 337 FrameLoaderClientAndroid* client = 338 static_cast<FrameLoaderClientAndroid*> (frame->loader()->client()); 339 return client->webFrame(); 340 } 341 342 static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map) 343 { 344 jclass mapClass = env->FindClass("java/util/HashMap"); 345 ALOG_ASSERT(mapClass, "Could not find HashMap class!"); 346 jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); 347 ALOG_ASSERT(init, "Could not find constructor for HashMap"); 348 jobject hashMap = env->NewObject(mapClass, init, map.size()); 349 ALOG_ASSERT(hashMap, "Could not create a new HashMap"); 350 jmethodID put = env->GetMethodID(mapClass, "put", 351 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 352 ALOG_ASSERT(put, "Could not find put method on HashMap"); 353 354 WebCore::HTTPHeaderMap::const_iterator end = map.end(); 355 for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) { 356 if (i->first.length() == 0 || i->second.length() == 0) 357 continue; 358 jstring key = wtfStringToJstring(env, i->first); 359 jstring val = wtfStringToJstring(env, i->second); 360 if (key && val) { 361 env->CallObjectMethod(hashMap, put, key, val); 362 } 363 env->DeleteLocalRef(key); 364 env->DeleteLocalRef(val); 365 } 366 367 env->DeleteLocalRef(mapClass); 368 369 return hashMap; 370 } 371 372 // This class stores the URI and the size of each file for upload. The URI is 373 // stored so we do not have to create it again. The size is stored so we can 374 // compare the actual size of the file with the stated size. If the actual size 375 // is larger, we will not copy it, since we will not have enough space in our 376 // buffer. 377 class FileInfo { 378 public: 379 FileInfo(JNIEnv* env, const WTF::String& name) { 380 m_uri = wtfStringToJstring(env, name); 381 checkException(env); 382 m_size = 0; 383 m_env = env; 384 } 385 ~FileInfo() { 386 m_env->DeleteLocalRef(m_uri); 387 } 388 int getSize() { return m_size; } 389 jstring getUri() { return m_uri; } 390 void setSize(int size) { m_size = size; } 391 private: 392 // This is only a pointer to the JNIEnv* returned by 393 // JSC::Bindings::getJNIEnv(). Used to delete the jstring when finished. 394 JNIEnv* m_env; 395 jstring m_uri; 396 int m_size; 397 }; 398 399 UrlInterceptResponse* 400 WebFrame::shouldInterceptRequest(const WTF::String& url) 401 { 402 ALOGV("::WebCore:: shouldInterceptRequest(%s)", url.latin1().data()); 403 404 JNIEnv* env = getJNIEnv(); 405 AutoJObject javaFrame = mJavaFrame->frame(env); 406 if (!javaFrame.get()) 407 return 0; 408 409 jstring urlStr = wtfStringToJstring(env, url); 410 jobject response = env->CallObjectMethod(javaFrame.get(), mJavaFrame->mShouldInterceptRequest, urlStr); 411 env->DeleteLocalRef(urlStr); 412 if (response == 0) 413 return 0; 414 UrlInterceptResponse* result = new UrlInterceptResponse(env, response); 415 env->DeleteLocalRef(response); 416 return result; 417 } 418 419 void 420 WebFrame::reportError(int errorCode, const WTF::String& description, 421 const WTF::String& failingUrl) 422 { 423 ALOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data()); 424 JNIEnv* env = getJNIEnv(); 425 AutoJObject javaFrame = mJavaFrame->frame(env); 426 if (!javaFrame.get()) 427 return; 428 429 jstring descStr = wtfStringToJstring(env, description); 430 jstring failUrl = wtfStringToJstring(env, failingUrl); 431 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mReportError, errorCode, descStr, failUrl); 432 env->DeleteLocalRef(descStr); 433 env->DeleteLocalRef(failUrl); 434 } 435 436 WTF::String 437 WebFrame::convertIDNToUnicode(const WebCore::KURL& url) { 438 WTF::String converted = url.string(); 439 const WTF::String host = url.host(); 440 if (host.find("xn--") == notFound) // no punycode IDN found. 441 return converted; 442 std::wstring languages; 443 const WTF::CString cHost = host.utf8(); 444 std::wstring result = net::IDNToUnicode(cHost.data(), cHost.length(), languages, 0); 445 const WTF::String convertedHost = String::fromUTF8(WideToUTF8(result).c_str()); 446 if (convertedHost.length() && convertedHost.length() != host.length()) { 447 WebCore::KURL newUrl = url; 448 newUrl.setHost(convertedHost); 449 converted = newUrl.string(); 450 } 451 return converted; 452 } 453 454 void 455 WebFrame::loadStarted(WebCore::Frame* frame) 456 { 457 JNIEnv* env = getJNIEnv(); 458 AutoJObject javaFrame = mJavaFrame->frame(env); 459 if (!javaFrame.get()) 460 return; 461 462 // activeDocumentLoader() can return null. 463 DocumentLoader* documentLoader = frame->loader()->activeDocumentLoader(); 464 if (documentLoader == NULL) 465 return; 466 467 const WebCore::KURL& url = documentLoader->url(); 468 if (url.isEmpty()) 469 return; 470 ALOGV("::WebCore:: loadStarted %s", url.string().ascii().data()); 471 472 bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); 473 WebCore::FrameLoadType loadType = frame->loader()->loadType(); 474 475 if (loadType == WebCore::FrameLoadTypeReplace || 476 (loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList && 477 !isMainFrame)) 478 return; 479 480 const WTF::String urlString = convertIDNToUnicode(url); 481 // If this is the main frame and we already have a favicon in the database, 482 // send it along with the page started notification. 483 jobject favicon = NULL; 484 if (isMainFrame) { 485 // FIXME: This method should not be used from outside WebCore and will be removed. 486 // http://trac.webkit.org/changeset/81484 487 WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(urlString, WebCore::IntSize(16, 16)); 488 if (icon) 489 favicon = webcoreImageToJavaBitmap(env, icon); 490 ALOGV("favicons", "Starting load with icon %p for %s", icon, url.string().utf8().data()); 491 } 492 jstring urlStr = wtfStringToJstring(env, urlString); 493 494 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mLoadStarted, urlStr, favicon, static_cast<int>(loadType), isMainFrame); 495 checkException(env); 496 env->DeleteLocalRef(urlStr); 497 if (favicon) 498 env->DeleteLocalRef(favicon); 499 500 // Inform the client that the main frame has started a new load. 501 if (isMainFrame && mPage) { 502 Chrome* chrome = mPage->chrome(); 503 if (chrome) { 504 ChromeClientAndroid* client = static_cast<ChromeClientAndroid*>(chrome->client()); 505 if (client) 506 client->onMainFrameLoadStarted(); 507 } 508 } 509 } 510 511 void 512 WebFrame::transitionToCommitted(WebCore::Frame* frame) 513 { 514 JNIEnv* env = getJNIEnv(); 515 AutoJObject javaFrame = mJavaFrame->frame(env); 516 if (!javaFrame.get()) 517 return; 518 519 WebCore::FrameLoadType loadType = frame->loader()->loadType(); 520 bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); 521 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mTransitionToCommitted, static_cast<int>(loadType), isMainFrame); 522 checkException(env); 523 } 524 525 void 526 WebFrame::didFinishLoad(WebCore::Frame* frame) 527 { 528 JNIEnv* env = getJNIEnv(); 529 AutoJObject javaFrame = mJavaFrame->frame(env); 530 if (!javaFrame.get()) 531 return; 532 533 // activeDocumentLoader() can return null. 534 WebCore::FrameLoader* loader = frame->loader(); 535 DocumentLoader* documentLoader = loader->activeDocumentLoader(); 536 if (documentLoader == NULL) 537 return; 538 539 const WebCore::KURL& url = documentLoader->url(); 540 if (url.isEmpty()) 541 return; 542 ALOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data()); 543 544 bool isMainFrame = (!frame->tree() || !frame->tree()->parent()); 545 WebCore::FrameLoadType loadType = loader->loadType(); 546 const WTF::String urlString = convertIDNToUnicode(url); 547 jstring urlStr = wtfStringToJstring(env, urlString); 548 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mLoadFinished, urlStr, static_cast<int>(loadType), isMainFrame); 549 checkException(env); 550 env->DeleteLocalRef(urlStr); 551 } 552 553 void 554 WebFrame::addHistoryItem(WebCore::HistoryItem* item) 555 { 556 ALOGV("::WebCore:: addHistoryItem"); 557 JNIEnv* env = getJNIEnv(); 558 WebHistory::AddItem(mJavaFrame->history(env), item); 559 } 560 561 void 562 WebFrame::removeHistoryItem(int index) 563 { 564 ALOGV("::WebCore:: removeHistoryItem at %d", index); 565 JNIEnv* env = getJNIEnv(); 566 WebHistory::RemoveItem(mJavaFrame->history(env), index); 567 } 568 569 void 570 WebFrame::updateHistoryIndex(int newIndex) 571 { 572 ALOGV("::WebCore:: updateHistoryIndex to %d", newIndex); 573 JNIEnv* env = getJNIEnv(); 574 WebHistory::UpdateHistoryIndex(mJavaFrame->history(env), newIndex); 575 } 576 577 void 578 WebFrame::setTitle(const WTF::String& title) 579 { 580 #ifndef NDEBUG 581 ALOGV("setTitle(%s)", title.ascii().data()); 582 #endif 583 JNIEnv* env = getJNIEnv(); 584 AutoJObject javaFrame = mJavaFrame->frame(env); 585 if (!javaFrame.get()) 586 return; 587 588 jstring jTitleStr = wtfStringToJstring(env, title); 589 590 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSetTitle, jTitleStr); 591 checkException(env); 592 env->DeleteLocalRef(jTitleStr); 593 } 594 595 void 596 WebFrame::windowObjectCleared(WebCore::Frame* frame) 597 { 598 ALOGV("::WebCore:: windowObjectCleared"); 599 JNIEnv* env = getJNIEnv(); 600 AutoJObject javaFrame = mJavaFrame->frame(env); 601 if (!javaFrame.get()) 602 return; 603 604 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mWindowObjectCleared, (int)frame); 605 checkException(env); 606 } 607 608 void 609 WebFrame::setProgress(float newProgress) 610 { 611 JNIEnv* env = getJNIEnv(); 612 AutoJObject javaFrame = mJavaFrame->frame(env); 613 if (!javaFrame.get()) 614 return; 615 616 int progress = static_cast<int>(100 * newProgress); 617 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSetProgress, progress); 618 checkException(env); 619 } 620 621 const WTF::String 622 WebFrame::userAgentForURL(const WebCore::KURL* url) 623 { 624 return mUserAgent; 625 } 626 627 void 628 WebFrame::didReceiveIcon(WebCore::Image* icon) 629 { 630 ALOG_ASSERT(icon, "DidReceiveIcon called without an image!"); 631 JNIEnv* env = getJNIEnv(); 632 AutoJObject javaFrame = mJavaFrame->frame(env); 633 if (!javaFrame.get()) 634 return; 635 636 jobject bitmap = webcoreImageToJavaBitmap(env, icon); 637 if (!bitmap) 638 return; 639 640 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveIcon, bitmap); 641 env->DeleteLocalRef(bitmap); 642 checkException(env); 643 } 644 645 void 646 WebFrame::didReceiveTouchIconURL(const WTF::String& url, bool precomposed) 647 { 648 JNIEnv* env = getJNIEnv(); 649 AutoJObject javaFrame = mJavaFrame->frame(env); 650 if (!javaFrame.get()) 651 return; 652 653 jstring jUrlStr = wtfStringToJstring(env, url); 654 655 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveTouchIconUrl, jUrlStr, precomposed); 656 env->DeleteLocalRef(jUrlStr); 657 checkException(env); 658 } 659 660 void 661 WebFrame::updateVisitedHistory(const WebCore::KURL& url, bool reload) 662 { 663 JNIEnv* env = getJNIEnv(); 664 AutoJObject javaFrame = mJavaFrame->frame(env); 665 if (!javaFrame.get()) 666 return; 667 668 const WTF::String urlStr = convertIDNToUnicode(url); 669 jstring jUrlStr = wtfStringToJstring(env, urlStr); 670 671 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload); 672 env->DeleteLocalRef(jUrlStr); 673 checkException(env); 674 } 675 676 bool 677 WebFrame::canHandleRequest(const WebCore::ResourceRequest& request) 678 { 679 JNIEnv* env = getJNIEnv(); 680 AutoJObject javaFrame = mJavaFrame->frame(env); 681 if (!javaFrame.get()) 682 return true; 683 684 // Always handle "POST" in place 685 if (equalIgnoringCase(request.httpMethod(), "POST")) 686 return true; 687 const WebCore::KURL& requestUrl = request.url(); 688 const WTF::String& url = requestUrl.string(); 689 // Empty URLs should not be sent to Java 690 if (url.isEmpty()) 691 return true; 692 jstring jUrlStr = wtfStringToJstring(env, url); 693 694 // Delegate to the Java side to make the decision. Note that the sense of 695 // the return value of the Java method is reversed. It will return true if 696 // the embedding application wishes to hijack the load and hence the WebView 697 // should _not_ proceed with the load. 698 jboolean ret = env->CallBooleanMethod(javaFrame.get(), mJavaFrame->mHandleUrl, jUrlStr); 699 checkException(env); 700 env->DeleteLocalRef(jUrlStr); 701 return ret == JNI_FALSE; 702 } 703 704 bool 705 WebFrame::shouldSaveFormData() 706 { 707 JNIEnv* env = getJNIEnv(); 708 AutoJObject javaFrame = mJavaFrame->frame(env); 709 if (!javaFrame.get()) 710 return false; 711 jboolean ret = env->CallBooleanMethod(javaFrame.get(), mJavaFrame->mShouldSaveFormData); 712 checkException(env); 713 return ret; 714 } 715 716 WebCore::Frame* 717 WebFrame::createWindow(bool dialog, bool userGesture) 718 { 719 JNIEnv* env = getJNIEnv(); 720 AutoJObject javaFrame = mJavaFrame->frame(env); 721 if (!javaFrame.get()) 722 return 0; 723 jobject obj = env->CallObjectMethod(javaFrame.get(), mJavaFrame->mCreateWindow, dialog, userGesture); 724 if (!obj) 725 return 0; 726 return GET_NATIVE_FRAME(env, obj); 727 } 728 729 void 730 WebFrame::requestFocus() const 731 { 732 JNIEnv* env = getJNIEnv(); 733 AutoJObject javaFrame = mJavaFrame->frame(env); 734 if (!javaFrame.get()) 735 return; 736 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mRequestFocus); 737 checkException(env); 738 } 739 740 void 741 WebFrame::closeWindow(WebViewCore* webViewCore) 742 { 743 assert(webViewCore); 744 JNIEnv* env = getJNIEnv(); 745 AutoJObject javaFrame = mJavaFrame->frame(env); 746 if (!javaFrame.get()) 747 return; 748 AutoJObject javaObject = webViewCore->getJavaObject(); 749 if (!javaObject.get()) 750 return; 751 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mCloseWindow, javaObject.get()); 752 } 753 754 struct PolicyFunctionWrapper { 755 WebCore::FramePolicyFunction func; 756 }; 757 758 void 759 WebFrame::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func) 760 { 761 JNIEnv* env = getJNIEnv(); 762 AutoJObject javaFrame = mJavaFrame->frame(env); 763 if (!javaFrame.get()) 764 return; 765 PolicyFunctionWrapper* p = new PolicyFunctionWrapper; 766 p->func = func; 767 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDecidePolicyForFormResubmission, p); 768 } 769 770 WTF::String 771 WebFrame::getRawResourceFilename(WebCore::PlatformBridge::rawResId id) const 772 { 773 JNIEnv* env = getJNIEnv(); 774 AutoJObject javaFrame = mJavaFrame->frame(env); 775 if (!javaFrame.get()) 776 return String(); 777 jstring ret = (jstring) env->CallObjectMethod(javaFrame.get(), mJavaFrame->mGetRawResFilename, static_cast<int>(id)); 778 779 return jstringToWtfString(env, ret); 780 } 781 782 float 783 WebFrame::density() const 784 { 785 JNIEnv* env = getJNIEnv(); 786 AutoJObject javaFrame = mJavaFrame->frame(env); 787 if (!javaFrame.get()) 788 return 0.0; 789 jfloat dpi = env->CallFloatMethod(javaFrame.get(), mJavaFrame->mDensity); 790 checkException(env); 791 return dpi; 792 } 793 794 void 795 WebFrame::didReceiveAuthenticationChallenge(WebUrlLoaderClient* client, const std::string& host, const std::string& realm, bool useCachedCredentials, bool suppressDialog) 796 { 797 JNIEnv* env = getJNIEnv(); 798 AutoJObject javaFrame = mJavaFrame->frame(env); 799 if (!javaFrame.get()) 800 return; 801 int jHandle = reinterpret_cast<int>(client); 802 jstring jHost = stdStringToJstring(env, host, true); 803 jstring jRealm = stdStringToJstring(env, realm, true); 804 805 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveAuthenticationChallenge, jHandle, jHost, jRealm, useCachedCredentials, suppressDialog); 806 env->DeleteLocalRef(jHost); 807 env->DeleteLocalRef(jRealm); 808 checkException(env); 809 } 810 811 void 812 WebFrame::reportSslCertError(WebUrlLoaderClient* client, int error, const std::string& cert, const std::string& url) 813 { 814 JNIEnv* env = getJNIEnv(); 815 AutoJObject javaFrame = mJavaFrame->frame(env); 816 if (!javaFrame.get()) 817 return; 818 int jHandle = reinterpret_cast<int>(client); 819 820 // Don't copy the null terminator. 821 int len = cert.length(); 822 ScopedLocalRef<jbyteArray> jCert(env, env->NewByteArray(len)); 823 env->SetByteArrayRegion(jCert.get(), 0, len, reinterpret_cast<const jbyte*>(cert.c_str())); 824 825 ScopedLocalRef<jstring> jUrl(env, env->NewStringUTF(url.c_str())); 826 827 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mReportSslCertError, jHandle, error, jCert.get(), jUrl.get()); 828 checkException(env); 829 } 830 831 void 832 WebFrame::requestClientCert(WebUrlLoaderClient* client, const std::string& hostAndPort) 833 { 834 JNIEnv* env = getJNIEnv(); 835 int jHandle = reinterpret_cast<int>(client); 836 837 int len = hostAndPort.length(); 838 ScopedLocalRef<jstring> jHostAndPort(env, stdStringToJstring(env, hostAndPort, true)); 839 840 env->CallVoidMethod(mJavaFrame->frame(env).get(), mJavaFrame->mRequestClientCert, jHandle, jHostAndPort.get()); 841 checkException(env); 842 } 843 844 void 845 WebFrame::downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, long long contentLength) 846 { 847 JNIEnv* env = getJNIEnv(); 848 AutoJObject javaFrame = mJavaFrame->frame(env); 849 if (!javaFrame.get()) 850 return; 851 jstring jUrl = stdStringToJstring(env, url, true); 852 jstring jUserAgent = stdStringToJstring(env, userAgent, true); 853 jstring jContentDisposition = stdStringToJstring(env, contentDisposition, true); 854 jstring jMimetype = stdStringToJstring(env, mimetype, true); 855 856 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDownloadStart, jUrl, jUserAgent, jContentDisposition, jMimetype, contentLength); 857 858 env->DeleteLocalRef(jUrl); 859 env->DeleteLocalRef(jUserAgent); 860 env->DeleteLocalRef(jContentDisposition); 861 env->DeleteLocalRef(jMimetype); 862 checkException(env); 863 } 864 865 void 866 WebFrame::didReceiveData(const char* data, int size) { 867 JNIEnv* env = getJNIEnv(); 868 AutoJObject javaFrame = mJavaFrame->frame(env); 869 if (!javaFrame.get()) 870 return; 871 872 ScopedLocalRef<jbyteArray> jData(env, env->NewByteArray(size)); 873 env->SetByteArrayRegion(jData.get(), 0, size, reinterpret_cast<const jbyte*>(data)); 874 875 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidReceiveData, jData.get(), size); 876 checkException(env); 877 } 878 879 void 880 WebFrame::didFinishLoading() { 881 JNIEnv* env = getJNIEnv(); 882 AutoJObject javaFrame = mJavaFrame->frame(env); 883 if (!javaFrame.get()) 884 return; 885 886 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDidFinishLoading); 887 checkException(env); 888 } 889 890 void WebFrame::setCertificate(const std::string& cert) 891 { 892 JNIEnv* env = getJNIEnv(); 893 AutoJObject javaFrame = mJavaFrame->frame(env); 894 if (!javaFrame.get()) 895 return; 896 897 int len = cert.length(); 898 ScopedLocalRef<jbyteArray> jCert(env, env->NewByteArray(len)); 899 env->SetByteArrayRegion(jCert.get(), 0, len, reinterpret_cast<const jbyte*>(cert.c_str())); 900 901 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSetCertificate, jCert.get()); 902 903 checkException(env); 904 } 905 906 void WebFrame::autoLogin(const std::string& loginHeader) 907 { 908 JNIEnv* env = getJNIEnv(); 909 AutoJObject javaFrame = mJavaFrame->frame(env); 910 if (!javaFrame.get()) 911 return; 912 913 WTF::String header(loginHeader.c_str(), loginHeader.length()); 914 WTF::Vector<WTF::String> split; 915 header.split('&', split); 916 if (!split.isEmpty()) { 917 WTF::String realm; 918 WTF::String account; 919 WTF::String args; 920 int len = split.size(); 921 while (len--) { 922 WTF::String& str = split[len]; 923 size_t equals = str.find('='); 924 if (equals == WTF::notFound) 925 continue; 926 927 WTF::String* result = 0; 928 if (str.startsWith("realm", false)) 929 result = &realm; 930 else if (str.startsWith("account", false)) 931 result = &account; 932 else if (str.startsWith("args", false)) 933 result = &args; 934 935 if (result) 936 // Decode url escape sequences before sending to the app. 937 *result = WebCore::decodeURLEscapeSequences(str.substring(equals + 1)); 938 } 939 940 // realm and args are required parameters. 941 if (realm.isEmpty() || args.isEmpty()) 942 return; 943 944 jstring jRealm = wtfStringToJstring(env, realm, true); 945 jstring jAccount = wtfStringToJstring(env, account); 946 jstring jArgs = wtfStringToJstring(env, args, true); 947 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mAutoLogin, jRealm, jAccount, jArgs); 948 } 949 } 950 951 void WebFrame::maybeSavePassword(WebCore::Frame* frame, const WebCore::ResourceRequest& request) 952 { 953 JNIEnv* env = getJNIEnv(); 954 AutoJObject javaFrame = mJavaFrame->frame(env); 955 if (!javaFrame.get()) 956 return; 957 958 if (request.httpMethod() != "POST") 959 return; 960 961 WTF::String username; 962 WTF::String password; 963 if (!getUsernamePasswordFromDom(frame, username, password)) 964 return; 965 966 jstring jUsername = wtfStringToJstring(env, username); 967 jstring jPassword = wtfStringToJstring(env, password); 968 jbyteArray jPostData = getPostData(request); 969 if (jPostData) 970 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mMaybeSavePassword, jPostData, jUsername, jPassword); 971 972 env->DeleteLocalRef(jPostData); 973 env->DeleteLocalRef(jUsername); 974 env->DeleteLocalRef(jPassword); 975 checkException(env); 976 } 977 978 bool WebFrame::getUsernamePasswordFromDom(WebCore::Frame* frame, WTF::String& username, WTF::String& password) 979 { 980 bool found = false; 981 WTF::RefPtr<WebCore::HTMLCollection> form = frame->document()->forms(); 982 WebCore::Node* node = form->firstItem(); 983 while (node && !found && !node->namespaceURI().isNull() && 984 !node->namespaceURI().isEmpty()) { 985 const WTF::Vector<WebCore::FormAssociatedElement*>& elements = 986 ((WebCore::HTMLFormElement*)node)->associatedElements(); 987 size_t size = elements.size(); 988 for (size_t i = 0; i< size && !found; i++) { 989 WebCore::HTMLElement* e = toHTMLElement(elements[i]); 990 if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { 991 WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e; 992 if (input->autoComplete() == false) 993 continue; 994 if (input->isPasswordField()) 995 password = input->value(); 996 else if (input->isTextField() || input->isEmailField()) 997 username = input->value(); 998 if (!username.isNull() && !password.isNull()) 999 found = true; 1000 } 1001 } 1002 node = form->nextItem(); 1003 } 1004 return found; 1005 } 1006 1007 jbyteArray WebFrame::getPostData(const WebCore::ResourceRequest& request) 1008 { 1009 JNIEnv* env = getJNIEnv(); 1010 AutoJObject javaFrame = mJavaFrame->frame(env); 1011 if (!javaFrame.get()) 1012 return 0; 1013 1014 jbyteArray jPostDataStr = 0; 1015 WebCore::FormData* formdata = request.httpBody(); 1016 if (formdata) { 1017 // We can use the formdata->flatten() but it will result in two 1018 // memcpys, first through loading up the vector with the form data 1019 // then another to copy it out of the vector and into the java byte 1020 // array. Instead, we copy the form data ourselves below saving a 1021 // memcpy. 1022 const WTF::Vector<WebCore::FormDataElement>& elements = 1023 formdata->elements(); 1024 1025 // Sizing pass 1026 int size = 0; 1027 size_t n = elements.size(); 1028 FileInfo** fileinfos = new FileInfo*[n]; 1029 for (size_t i = 0; i < n; ++i) { 1030 fileinfos[i] = 0; 1031 const WebCore::FormDataElement& e = elements[i]; 1032 if (e.m_type == WebCore::FormDataElement::data) { 1033 size += e.m_data.size(); 1034 } else if (e.m_type == WebCore::FormDataElement::encodedFile) { 1035 fileinfos[i] = new FileInfo(env, e.m_filename); 1036 int delta = env->CallIntMethod(javaFrame.get(), mJavaFrame->mGetFileSize, fileinfos[i]->getUri()); 1037 checkException(env); 1038 fileinfos[i]->setSize(delta); 1039 size += delta; 1040 } 1041 } 1042 1043 // Only create the byte array if there is POST data to pass up. 1044 // The Java code is expecting null if there is no data. 1045 if (size > 0) { 1046 // Copy the actual form data. 1047 jPostDataStr = env->NewByteArray(size); 1048 if (jPostDataStr) { 1049 // Write the form data to the java array. 1050 jbyte* bytes = env->GetByteArrayElements(jPostDataStr, NULL); 1051 int offset = 0; 1052 for (size_t i = 0; i < n; ++i) { 1053 const WebCore::FormDataElement& e = elements[i]; 1054 if (e.m_type == WebCore::FormDataElement::data) { 1055 int delta = e.m_data.size(); 1056 memcpy(bytes + offset, e.m_data.data(), delta); 1057 offset += delta; 1058 } else if (e.m_type == WebCore::FormDataElement::encodedFile) { 1059 int delta = env->CallIntMethod(javaFrame.get(), 1060 mJavaFrame->mGetFile, fileinfos[i]->getUri(), 1061 jPostDataStr, offset, fileinfos[i]->getSize()); 1062 checkException(env); 1063 offset += delta; 1064 } 1065 } 1066 env->ReleaseByteArrayElements(jPostDataStr, bytes, 0); 1067 } 1068 } 1069 delete[] fileinfos; 1070 } 1071 return jPostDataStr; 1072 } 1073 1074 // ---------------------------------------------------------------------------- 1075 1076 static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decision) 1077 { 1078 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); 1079 ALOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!"); 1080 PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func; 1081 ALOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!"); 1082 1083 // If we are resending the form then we should reset the multiple submission protection. 1084 if (decision == WebCore::PolicyUse) 1085 pFrame->loader()->resetMultipleFormSubmissionProtection(); 1086 1087 (pFrame->loader()->policyChecker()->*(pFunc->func))((WebCore::PolicyAction)decision); 1088 } 1089 1090 static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAssetManager, jobject historyList) 1091 { 1092 ScriptController::initializeThreading(); 1093 1094 // needs to be called before any other chromium code 1095 initChromium(); 1096 1097 // Create a new page 1098 ChromeClientAndroid* chromeC = new ChromeClientAndroid; 1099 EditorClientAndroid* editorC = new EditorClientAndroid; 1100 DeviceMotionClientAndroid* deviceMotionC = new DeviceMotionClientAndroid; 1101 DeviceOrientationClientAndroid* deviceOrientationC = new DeviceOrientationClientAndroid; 1102 1103 WebCore::Page::PageClients pageClients; 1104 pageClients.chromeClient = chromeC; 1105 pageClients.contextMenuClient = new ContextMenuClientAndroid; 1106 pageClients.editorClient = editorC; 1107 pageClients.dragClient = new DragClientAndroid; 1108 pageClients.inspectorClient = new InspectorClientAndroid; 1109 pageClients.deviceMotionClient = deviceMotionC; 1110 pageClients.deviceOrientationClient = deviceOrientationC; 1111 WebCore::Page* page = new WebCore::Page(pageClients); 1112 1113 editorC->setPage(page); 1114 page->setGroupName("android.webkit"); 1115 1116 // Create a WebFrame to access the Java BrowserFrame associated with this page 1117 WebFrame* webFrame = new WebFrame(env, obj, historyList, page); 1118 // Attach webFrame to pageClients.chromeClient and release our ownership 1119 chromeC->setWebFrame(webFrame); 1120 Release(webFrame); 1121 1122 FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(webFrame); 1123 // Create a Frame and the page holds its reference 1124 WebCore::Frame* frame = WebCore::Frame::create(page, NULL, loaderC).get(); 1125 loaderC->setFrame(frame); 1126 #if ENABLE(WDS) 1127 WDS::server()->addFrame(frame); 1128 #endif 1129 1130 // Create a WebViewCore to access the Java WebViewCore associated with this page 1131 WebViewCore* webViewCore = new WebViewCore(env, javaview, frame); 1132 1133 #if ENABLE(WEB_AUTOFILL) 1134 editorC->getAutofill()->setWebViewCore(webViewCore); 1135 #endif 1136 1137 // Create a FrameView 1138 RefPtr<WebCore::FrameView> frameView = WebCore::FrameView::create(frame); 1139 // Create a WebFrameView 1140 WebFrameView* webFrameView = new WebFrameView(frameView.get(), webViewCore); 1141 // As webFrameView Retains webViewCore, release our ownership 1142 Release(webViewCore); 1143 // As frameView Retains webFrameView, release our ownership 1144 Release(webFrameView); 1145 // Attach the frameView to the frame and release our ownership 1146 frame->setView(frameView); 1147 // Set the frame to active to turn on keyboard focus. 1148 frame->init(); 1149 frame->selection()->setFocused(true); 1150 frame->page()->focusController()->setFocused(true); 1151 deviceMotionC->setWebViewCore(webViewCore); 1152 deviceOrientationC->setWebViewCore(webViewCore); 1153 1154 // Allow local access to file:/// and substitute data 1155 WebCore::SecurityOrigin::setLocalLoadPolicy( 1156 WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); 1157 1158 ALOGV("::WebCore:: createFrame %p", frame); 1159 1160 // Set the mNativeFrame field in Frame 1161 SET_NATIVE_FRAME(env, obj, (int)frame); 1162 1163 String directory = webFrame->getRawResourceFilename( 1164 WebCore::PlatformBridge::DrawableDir); 1165 if (directory.isEmpty()) 1166 ALOGE("Can't find the drawable directory"); 1167 else { 1168 // Initialize our skinning classes 1169 webFrame->setRenderSkins(new WebCore::RenderSkinAndroid(directory)); 1170 } 1171 1172 for (int i = WebCore::PlatformBridge::FileUploadLabel; 1173 i <= WebCore::PlatformBridge::FileUploadNoFileChosenLabel; i++) 1174 initGlobalLocalizedName( 1175 static_cast<WebCore::PlatformBridge::rawResId>(i), webFrame); 1176 } 1177 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 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 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 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 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) 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 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 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 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 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 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 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 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 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: 1508 static PassRefPtr<WeakJavaInstance> create(jobject obj) 1509 { 1510 return adoptRef(new WeakJavaInstance(obj)); 1511 } 1512 1513 private: 1514 WeakJavaInstance(jobject instance) 1515 : JavaInstanceJobject(instance) 1516 , m_beginEndDepth(0) 1517 { 1518 JNIEnv* env = getJNIEnv(); 1519 // JavaInstance creates a global ref to instance in its constructor. 1520 env->DeleteGlobalRef(m_instance->instance()); 1521 // Create a weak ref, cache it, and set the underlying JavaInstance to use it. 1522 m_weakRef = env->NewWeakGlobalRef(instance); 1523 m_instance->setInstance(m_weakRef); 1524 } 1525 ~WeakJavaInstance() 1526 { 1527 ALOG_ASSERT(!m_beginEndDepth, "Unbalanced calls to WeakJavaInstance::begin() / end()"); 1528 JNIEnv* env = getJNIEnv(); 1529 // The JavaInstance destructor attempts to delete the global ref stored 1530 // in m_instance. Since we replaced it in our constructor with a weak 1531 // reference, restore the global ref here so the vm will not complain. 1532 m_instance->setInstance(env->NewGlobalRef(m_weakRef)); 1533 // Delete the weak reference. 1534 env->DeleteWeakGlobalRef(m_weakRef); 1535 } 1536 1537 virtual void begin() 1538 { 1539 if (m_beginEndDepth++ > 0) 1540 return; 1541 JNIEnv* env = getJNIEnv(); 1542 // This is odd. getRealObject returns an AutoJObject which is used to 1543 // cleanly create and delete a local reference. But, here we need to 1544 // maintain the local reference across calls to virtualBegin() and 1545 // virtualEnd(). So, release the local reference from the AutoJObject 1546 // and delete the local reference in virtualEnd(). 1547 m_instance->setInstance(getRealObject(env, m_weakRef).release()); 1548 // Call the base class method 1549 INHERITED::begin(); 1550 } 1551 1552 virtual void end() 1553 { 1554 if (--m_beginEndDepth > 0) 1555 return; 1556 // Call the base class method first to pop the local frame. 1557 INHERITED::end(); 1558 // Get rid of the local reference to the real object. 1559 getJNIEnv()->DeleteLocalRef(m_instance->instance()); 1560 // Point back to the WeakReference. 1561 m_instance->setInstance(m_weakRef); 1562 } 1563 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 1571 static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer, 1572 jobject javascriptObj, jstring interfaceName) 1573 { 1574 WebCore::Frame* pFrame = 0; 1575 if (nativeFramePointer == 0) 1576 pFrame = GET_NATIVE_FRAME(env, obj); 1577 else 1578 pFrame = (WebCore::Frame*)nativeFramePointer; 1579 ALOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!"); 1580 1581 JavaVM* vm; 1582 env->GetJavaVM(&vm); 1583 ALOGV("::WebCore:: addJSInterface: %p", pFrame); 1584 1585 if (pFrame) { 1586 RefPtr<JavaInstance> addedObject = WeakJavaInstance::create(javascriptObj); 1587 const char* name = getCharactersFromJStringInEnv(env, interfaceName); 1588 // Pass ownership of the added object to bindToWindowObject. 1589 NPObject* npObject = JavaInstanceToNPObject(addedObject.get()); 1590 pFrame->script()->bindToWindowObject(pFrame, name, npObject); 1591 // bindToWindowObject calls NPN_RetainObject on the 1592 // returned one (see createV8ObjectForNPObject in V8NPObject.cpp). 1593 // bindToWindowObject also increases obj's ref count and decreases 1594 // the ref count when the object is not reachable from JavaScript 1595 // side. Code here must release the reference count increased by 1596 // bindToWindowObject. 1597 1598 // Note that while this function is declared in WebCore/bridge/npruntime.h, for V8 builds 1599 // we use WebCore/bindings/v8/npruntime.cpp (rather than 1600 // WebCore/bridge/npruntime.cpp), so the function is implemented there. 1601 // TODO: Combine the two versions of these NPAPI files. 1602 NPN_ReleaseObject(npObject); 1603 releaseCharactersForJString(interfaceName, name); 1604 } 1605 } 1606 1607 static void ClearWebCoreCache() 1608 { 1609 if (!WebCore::memoryCache()->disabled()) { 1610 // Disabling the cache will remove all resources from the cache. They may 1611 // still live on if they are referenced by some Web page though. 1612 WebCore::memoryCache()->setDisabled(true); 1613 WebCore::memoryCache()->setDisabled(false); 1614 } 1615 1616 // clear page cache 1617 int pageCapacity = WebCore::pageCache()->capacity(); 1618 // Setting size to 0, makes all pages be released. 1619 WebCore::pageCache()->setCapacity(0); 1620 WebCore::pageCache()->releaseAutoreleasedPagesNow(); 1621 WebCore::pageCache()->setCapacity(pageCapacity); 1622 } 1623 1624 static void ClearWebViewCache() 1625 { 1626 WebCache::get(false /*privateBrowsing*/)->clear(); 1627 } 1628 1629 static void ClearCache(JNIEnv *env, jobject obj) 1630 { 1631 ClearWebCoreCache(); 1632 ClearWebViewCache(); 1633 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); 1634 pFrame->script()->lowMemoryNotification(); 1635 } 1636 1637 static jboolean DocumentHasImages(JNIEnv *env, jobject obj) 1638 { 1639 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); 1640 ALOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!"); 1641 1642 return pFrame->document()->images()->length() > 0; 1643 } 1644 1645 static jboolean HasPasswordField(JNIEnv *env, jobject obj) 1646 { 1647 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); 1648 ALOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!"); 1649 1650 bool found = false; 1651 WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms(); 1652 WebCore::Node* node = form->firstItem(); 1653 // Null/Empty namespace means that node is not created in HTMLFormElement 1654 // class, but just normal Element class. 1655 while (node && !found && !node->namespaceURI().isNull() && 1656 !node->namespaceURI().isEmpty()) { 1657 const WTF::Vector<WebCore::FormAssociatedElement*>& elements = 1658 ((WebCore::HTMLFormElement*)node)->associatedElements(); 1659 size_t size = elements.size(); 1660 for (size_t i = 0; i< size && !found; i++) { 1661 WebCore::HTMLElement* e = toHTMLElement(elements[i]); 1662 if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { 1663 if (static_cast<WebCore::HTMLInputElement*>(e)->isPasswordField()) 1664 found = true; 1665 } 1666 } 1667 node = form->nextItem(); 1668 } 1669 return found; 1670 } 1671 1672 static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj) 1673 { 1674 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); 1675 ALOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!"); 1676 jobjectArray strArray = NULL; 1677 WTF::String username; 1678 WTF::String password; 1679 if (WebFrame::getWebFrame(pFrame)->getUsernamePasswordFromDom(pFrame, username, password)) { 1680 jclass stringClass = env->FindClass("java/lang/String"); 1681 strArray = env->NewObjectArray(2, stringClass, NULL); 1682 env->DeleteLocalRef(stringClass); 1683 env->SetObjectArrayElement(strArray, 0, wtfStringToJstring(env, username)); 1684 env->SetObjectArrayElement(strArray, 1, wtfStringToJstring(env, password)); 1685 } 1686 return strArray; 1687 } 1688 1689 static void SetUsernamePassword(JNIEnv *env, jobject obj, 1690 jstring username, jstring password) 1691 { 1692 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); 1693 ALOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!"); 1694 1695 WebCore::HTMLInputElement* usernameEle = NULL; 1696 WebCore::HTMLInputElement* passwordEle = NULL; 1697 bool found = false; 1698 WTF::RefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms(); 1699 WebCore::Node* node = form->firstItem(); 1700 while (node && !found && !node->namespaceURI().isNull() && 1701 !node->namespaceURI().isEmpty()) { 1702 const WTF::Vector<WebCore::FormAssociatedElement*>& elements = 1703 ((WebCore::HTMLFormElement*)node)->associatedElements(); 1704 size_t size = elements.size(); 1705 for (size_t i = 0; i< size && !found; i++) { 1706 WebCore::HTMLElement* e = toHTMLElement(elements[i]); 1707 if (e->hasLocalName(WebCore::HTMLNames::inputTag)) { 1708 WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e; 1709 if (input->autoComplete() == false) 1710 continue; 1711 if (input->isPasswordField()) 1712 passwordEle = input; 1713 else if (input->isTextField() || input->isEmailField()) 1714 usernameEle = input; 1715 if (usernameEle != NULL && passwordEle != NULL) 1716 found = true; 1717 } 1718 } 1719 node = form->nextItem(); 1720 } 1721 if (found) { 1722 usernameEle->setValue(jstringToWtfString(env, username)); 1723 passwordEle->setValue(jstringToWtfString(env, password)); 1724 } 1725 } 1726 1727 void 1728 WebFrame::saveFormData(HTMLFormElement* form) 1729 { 1730 JNIEnv* env = getJNIEnv(); 1731 AutoJObject javaFrame = mJavaFrame->frame(env); 1732 if (!javaFrame.get()) 1733 return; 1734 1735 if (form->autoComplete()) { 1736 JNIEnv* env = getJNIEnv(); 1737 jclass mapClass = env->FindClass("java/util/HashMap"); 1738 ALOG_ASSERT(mapClass, "Could not find HashMap class!"); 1739 jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V"); 1740 ALOG_ASSERT(init, "Could not find constructor for HashMap"); 1741 jobject hashMap = env->NewObject(mapClass, init, 1); 1742 ALOG_ASSERT(hashMap, "Could not create a new HashMap"); 1743 jmethodID put = env->GetMethodID(mapClass, "put", 1744 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 1745 ALOG_ASSERT(put, "Could not find put method on HashMap"); 1746 WTF::Vector<WebCore::FormAssociatedElement*> elements = form->associatedElements(); 1747 size_t size = elements.size(); 1748 for (size_t i = 0; i < size; i++) { 1749 WebCore::HTMLElement* e = toHTMLElement(elements[i]); 1750 if (e->hasTagName(WebCore::HTMLNames::inputTag)) { 1751 WebCore::HTMLInputElement* input = static_cast<WebCore::HTMLInputElement*>(e); 1752 if (input->isTextField() && !input->isPasswordField() 1753 && input->autoComplete()) { 1754 WTF::String value = input->value(); 1755 int len = value.length(); 1756 if (len) { 1757 const WTF::AtomicString& name = input->name(); 1758 jstring key = wtfStringToJstring(env, name); 1759 jstring val = wtfStringToJstring(env, value); 1760 ALOG_ASSERT(key && val, "name or value not set"); 1761 env->CallObjectMethod(hashMap, put, key, val); 1762 env->DeleteLocalRef(key); 1763 env->DeleteLocalRef(val); 1764 } 1765 } 1766 } 1767 } 1768 env->CallVoidMethod(javaFrame.get(), mJavaFrame->mSaveFormData, hashMap); 1769 env->DeleteLocalRef(hashMap); 1770 env->DeleteLocalRef(mapClass); 1771 } 1772 } 1773 1774 static void OrientationChanged(JNIEnv *env, jobject obj, int orientation) 1775 { 1776 WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); 1777 ALOGV("Sending orientation: %d", orientation); 1778 pFrame->sendOrientationChangeEvent(orientation); 1779 } 1780 1781 static jboolean GetShouldStartScrolledRight(JNIEnv *env, jobject obj, 1782 jint browserFrame) 1783 { 1784 jboolean startScrolledRight = false; // default is start scrolled left 1785 WebCore::Frame* frame = reinterpret_cast<WebCore::Frame*>(browserFrame); 1786 WebCore::Document* document = frame->document(); 1787 if (document) { 1788 RenderStyle* style = document->renderer()->style(); 1789 WritingMode writingMode = style->writingMode(); 1790 ALOG_ASSERT(writingMode != WebCore::BottomToTopWritingMode, 1791 "BottomToTopWritingMode isn't possible in any " 1792 "language and cannot be specified in w3c writing-mode."); 1793 if (writingMode == WebCore::RightToLeftWritingMode) 1794 startScrolledRight = true; // vertical-rl pages start scrolled right 1795 else if (writingMode == WebCore::TopToBottomWritingMode) 1796 startScrolledRight = !style->isLeftToRightDirection(); // RTL starts right 1797 } 1798 return startScrolledRight; 1799 } 1800 1801 static void AuthenticationProceed(JNIEnv *env, jobject obj, int handle, jstring jUsername, jstring jPassword) 1802 { 1803 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1804 std::string username = jstringToStdString(env, jUsername); 1805 std::string password = jstringToStdString(env, jPassword); 1806 client->setAuth(username, password); 1807 } 1808 1809 static void AuthenticationCancel(JNIEnv *env, jobject obj, int handle) 1810 { 1811 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1812 client->cancelAuth(); 1813 } 1814 1815 static void SslCertErrorProceed(JNIEnv *env, jobject obj, int handle) 1816 { 1817 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1818 client->proceedSslCertError(); 1819 } 1820 1821 static void SslCertErrorCancel(JNIEnv *env, jobject obj, int handle, int cert_error) 1822 { 1823 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1824 client->cancelSslCertError(cert_error); 1825 } 1826 1827 static scoped_refptr<net::X509Certificate> getX509Cert(JNIEnv *env, jobjectArray chain) 1828 { 1829 // Based on Android's NativeCrypto_SSL_use_certificate 1830 int length = env->GetArrayLength(chain); 1831 if (length == 0) { 1832 return NULL; 1833 } 1834 1835 base::ScopedOpenSSL<X509, X509_free> first; 1836 ScopedVector<base::ScopedOpenSSL<X509, X509_free> > rest; 1837 for (int i = 0; i < length; i++) { 1838 ScopedLocalRef<jbyteArray> cert(env, 1839 reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(chain, i))); 1840 if (cert.get() == NULL) { 1841 return NULL; 1842 } 1843 ScopedByteArrayRO certBytes(env, cert.get()); 1844 if (certBytes.get() == NULL) { 1845 return NULL; 1846 } 1847 const char* data = reinterpret_cast<const char*>(certBytes.get()); 1848 int length = certBytes.size(); 1849 X509* x509 = net::X509Certificate::CreateOSCertHandleFromBytes(data, length); 1850 if (x509 == NULL) { 1851 return NULL; 1852 } 1853 if (i == 0) { 1854 first.reset(x509); 1855 } else { 1856 rest.push_back(new base::ScopedOpenSSL<X509, X509_free>(x509)); 1857 } 1858 } 1859 1860 std::vector<X509*> certChain(rest.size()); 1861 for (size_t i = 0; i < rest.size(); i++) { 1862 certChain[i] = rest[i]->get(); 1863 } 1864 return net::X509Certificate::CreateFromHandle(first.get(), 1865 net::X509Certificate::SOURCE_FROM_NETWORK, 1866 certChain); 1867 } 1868 1869 static void SslClientCertPKCS8(JNIEnv *env, jobject obj, int handle, jbyteArray pkey, jobjectArray chain) 1870 { 1871 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1872 if (pkey == NULL || chain == NULL) { 1873 client->sslClientCert(NULL, NULL); 1874 return; 1875 } 1876 1877 // Based on Android's NativeCrypto_SSL_use_PrivateKey 1878 ScopedByteArrayRO pkeyBytes(env, pkey); 1879 if (pkeyBytes.get() == NULL) { 1880 client->sslClientCert(NULL, NULL); 1881 return; 1882 } 1883 1884 base::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8; 1885 const unsigned char* pkeyChars = reinterpret_cast<const unsigned char*>(pkeyBytes.get()); 1886 pkcs8.reset(d2i_PKCS8_PRIV_KEY_INFO(NULL, &pkeyChars, pkeyBytes.size())); 1887 if (!pkcs8.get()) { 1888 client->sslClientCert(NULL, NULL); 1889 return; 1890 } 1891 base::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> privateKey(EVP_PKCS82PKEY(pkcs8.get())); 1892 if (!privateKey.get()) { 1893 client->sslClientCert(NULL, NULL); 1894 return; 1895 } 1896 scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain); 1897 if (certificate == NULL) { 1898 client->sslClientCert(NULL, NULL); 1899 return; 1900 } 1901 client->sslClientCert(privateKey.release(), certificate); 1902 } 1903 1904 static void SslClientCertCtx(JNIEnv *env, jobject obj, int handle, jint ctx, jobjectArray chain) 1905 { 1906 WebUrlLoaderClient* client = reinterpret_cast<WebUrlLoaderClient*>(handle); 1907 EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(static_cast<uintptr_t>(ctx)); 1908 if (pkey == NULL || chain == NULL) { 1909 client->sslClientCert(NULL, NULL); 1910 return; 1911 } 1912 scoped_refptr<net::X509Certificate> certificate = getX509Cert(env, chain); 1913 if (certificate == NULL) { 1914 client->sslClientCert(NULL, NULL); 1915 return; 1916 } 1917 CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); 1918 client->sslClientCert(pkey, certificate); 1919 } 1920 1921 // ---------------------------------------------------------------------------- 1922 1923 /* 1924 * JNI registration. 1925 */ 1926 static JNINativeMethod gBrowserFrameNativeMethods[] = { 1927 /* name, signature, funcPtr */ 1928 { "nativeCallPolicyFunction", "(II)V", 1929 (void*) CallPolicyFunction }, 1930 { "nativeCreateFrame", "(Landroid/webkit/WebViewCore;Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V", 1931 (void*) CreateFrame }, 1932 { "nativeDestroyFrame", "()V", 1933 (void*) DestroyFrame }, 1934 { "nativeStopLoading", "()V", 1935 (void*) StopLoading }, 1936 { "nativeLoadUrl", "(Ljava/lang/String;Ljava/util/Map;)V", 1937 (void*) LoadUrl }, 1938 { "nativePostUrl", "(Ljava/lang/String;[B)V", 1939 (void*) PostUrl }, 1940 { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", 1941 (void*) LoadData }, 1942 { "nativeSaveWebArchive", "(Ljava/lang/String;Z)Ljava/lang/String;", 1943 (void*) SaveWebArchive }, 1944 { "externalRepresentation", "()Ljava/lang/String;", 1945 (void*) ExternalRepresentation }, 1946 { "documentAsText", "()Ljava/lang/String;", 1947 (void*) DocumentAsText }, 1948 { "childFramesAsText", "()Ljava/lang/String;", 1949 (void*) ChildFramesAsText }, 1950 { "reload", "(Z)V", 1951 (void*) Reload }, 1952 { "nativeGoBackOrForward", "(I)V", 1953 (void*) GoBackOrForward }, 1954 { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;)V", 1955 (void*) AddJavascriptInterface }, 1956 { "stringByEvaluatingJavaScriptFromString", 1957 "(Ljava/lang/String;)Ljava/lang/String;", 1958 (void*) StringByEvaluatingJavaScriptFromString }, 1959 { "clearCache", "()V", 1960 (void*) ClearCache }, 1961 { "documentHasImages", "()Z", 1962 (void*) DocumentHasImages }, 1963 { "hasPasswordField", "()Z", 1964 (void*) HasPasswordField }, 1965 { "getUsernamePassword", "()[Ljava/lang/String;", 1966 (void*) GetUsernamePassword }, 1967 { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V", 1968 (void*) SetUsernamePassword }, 1969 { "nativeOrientationChanged", "(I)V", 1970 (void*) OrientationChanged }, 1971 { "nativeAuthenticationProceed", "(ILjava/lang/String;Ljava/lang/String;)V", 1972 (void*) AuthenticationProceed }, 1973 { "nativeAuthenticationCancel", "(I)V", 1974 (void*) AuthenticationCancel }, 1975 { "nativeSslCertErrorProceed", "(I)V", 1976 (void*) SslCertErrorProceed }, 1977 { "nativeSslCertErrorCancel", "(II)V", 1978 (void*) SslCertErrorCancel }, 1979 { "nativeSslClientCert", "(II[[B)V", 1980 (void*) SslClientCertCtx }, 1981 { "nativeSslClientCert", "(I[B[[B)V", 1982 (void*) SslClientCertPKCS8 }, 1983 { "nativeGetShouldStartScrolledRight", "(I)Z", 1984 (void*) GetShouldStartScrolledRight }, 1985 }; 1986 1987 int registerWebFrame(JNIEnv* env) 1988 { 1989 jclass clazz = env->FindClass("android/webkit/BrowserFrame"); 1990 ALOG_ASSERT(clazz, "Cannot find BrowserFrame"); 1991 gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I"); 1992 ALOG_ASSERT(gFrameField, "Cannot find mNativeFrame on BrowserFrame"); 1993 env->DeleteLocalRef(clazz); 1994 1995 return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame", 1996 gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods)); 1997 } 1998 1999 } /* namespace android */ 2000