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