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 "WebViewCore.h" 30 31 #include "AtomicString.h" 32 #include "CachedNode.h" 33 #include "CachedRoot.h" 34 #include "Chrome.h" 35 #include "ChromeClientAndroid.h" 36 #include "Color.h" 37 #include "DatabaseTracker.h" 38 #include "Document.h" 39 #include "DOMWindow.h" 40 #include "Element.h" 41 #include "Editor.h" 42 #include "EditorClientAndroid.h" 43 #include "EventHandler.h" 44 #include "EventNames.h" 45 #include "FocusController.h" 46 #include "Font.h" 47 #include "Frame.h" 48 #include "FrameLoader.h" 49 #include "FrameLoaderClientAndroid.h" 50 #include "FrameTree.h" 51 #include "FrameView.h" 52 #include "Geolocation.h" 53 #include "GraphicsContext.h" 54 #include "GraphicsJNI.h" 55 #include "HTMLAnchorElement.h" 56 #include "HTMLAreaElement.h" 57 #include "HTMLElement.h" 58 #include "HTMLImageElement.h" 59 #include "HTMLInputElement.h" 60 #include "HTMLLabelElement.h" 61 #include "HTMLMapElement.h" 62 #include "HTMLNames.h" 63 #include "HTMLOptGroupElement.h" 64 #include "HTMLOptionElement.h" 65 #include "HTMLSelectElement.h" 66 #include "HTMLTextAreaElement.h" 67 #include "HistoryItem.h" 68 #include "HitTestResult.h" 69 #include "InlineTextBox.h" 70 #include "KeyboardCodes.h" 71 #include "Navigator.h" 72 #include "Node.h" 73 #include "NodeList.h" 74 #include "Page.h" 75 #include "PageGroup.h" 76 #include "PlatformKeyboardEvent.h" 77 #include "PlatformString.h" 78 #include "PluginWidgetAndroid.h" 79 #include "PluginView.h" 80 #include "Position.h" 81 #include "ProgressTracker.h" 82 #include "RenderBox.h" 83 #include "RenderLayer.h" 84 #include "RenderPart.h" 85 #include "RenderText.h" 86 #include "RenderTextControl.h" 87 #include "RenderThemeAndroid.h" 88 #include "RenderView.h" 89 #include "ResourceRequest.h" 90 #include "SelectionController.h" 91 #include "Settings.h" 92 #include "SkANP.h" 93 #include "SkTemplates.h" 94 #include "SkTDArray.h" 95 #include "SkTypes.h" 96 #include "SkCanvas.h" 97 #include "SkPicture.h" 98 #include "SkUtils.h" 99 #include "StringImpl.h" 100 #include "Text.h" 101 #include "TypingCommand.h" 102 #include "WebCoreFrameBridge.h" 103 #include "WebFrameView.h" 104 #include "android_graphics.h" 105 106 #include <JNIHelp.h> 107 #include <JNIUtility.h> 108 #include <ui/KeycodeLabels.h> 109 #include <wtf/CurrentTime.h> 110 111 #if USE(V8) 112 #include "CString.h" 113 #include "ScriptController.h" 114 #include "V8Counters.h" 115 #endif 116 117 #if DEBUG_NAV_UI 118 #include "SkTime.h" 119 #endif 120 121 #if ENABLE(TOUCH_EVENTS) // Android 122 #include "PlatformTouchEvent.h" 123 #endif 124 125 #ifdef ANDROID_DOM_LOGGING 126 #include "AndroidLog.h" 127 #include "RenderTreeAsText.h" 128 #include "CString.h" 129 130 FILE* gDomTreeFile = 0; 131 FILE* gRenderTreeFile = 0; 132 #endif 133 134 #ifdef ANDROID_INSTRUMENT 135 #include "TimeCounter.h" 136 #endif 137 138 #if USE(ACCELERATED_COMPOSITING) 139 #include "GraphicsLayerAndroid.h" 140 #include "RenderLayerCompositor.h" 141 #endif 142 143 /* We pass this flag when recording the actual content, so that we don't spend 144 time actually regionizing complex path clips, when all we really want to do 145 is record them. 146 */ 147 #define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag 148 149 //////////////////////////////////////////////////////////////////////////////////////////////// 150 151 namespace android { 152 153 static SkTDArray<WebViewCore*> gInstanceList; 154 155 void WebViewCore::addInstance(WebViewCore* inst) { 156 *gInstanceList.append() = inst; 157 } 158 159 void WebViewCore::removeInstance(WebViewCore* inst) { 160 int index = gInstanceList.find(inst); 161 LOG_ASSERT(index >= 0, "RemoveInstance inst not found"); 162 if (index >= 0) { 163 gInstanceList.removeShuffle(index); 164 } 165 } 166 167 bool WebViewCore::isInstance(WebViewCore* inst) { 168 return gInstanceList.find(inst) >= 0; 169 } 170 171 jobject WebViewCore::getApplicationContext() { 172 173 // check to see if there is a valid webviewcore object 174 if (gInstanceList.isEmpty()) 175 return 0; 176 177 // get the context from the webview 178 jobject context = gInstanceList[0]->getContext(); 179 180 if (!context) 181 return 0; 182 183 // get the application context using JNI 184 JNIEnv* env = JSC::Bindings::getJNIEnv(); 185 jclass contextClass = env->GetObjectClass(context); 186 jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;"); 187 jobject result = env->CallObjectMethod(context, appContextMethod); 188 checkException(env); 189 return result; 190 } 191 192 193 struct WebViewCoreStaticMethods { 194 jmethodID m_supportsMimeType; 195 } gWebViewCoreStaticMethods; 196 197 // Check whether a media mimeType is supported in Android media framework. 198 bool WebViewCore::supportsMimeType(const WebCore::String& mimeType) { 199 JNIEnv* env = JSC::Bindings::getJNIEnv(); 200 jstring jMimeType = env->NewString(mimeType.characters(), mimeType.length()); 201 jclass webViewCore = env->FindClass("android/webkit/WebViewCore"); 202 bool val = env->CallStaticBooleanMethod(webViewCore, 203 gWebViewCoreStaticMethods.m_supportsMimeType, jMimeType); 204 checkException(env); 205 env->DeleteLocalRef(jMimeType); 206 207 return val; 208 } 209 210 // ---------------------------------------------------------------------------- 211 212 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) 213 214 // Field ids for WebViewCore 215 struct WebViewCoreFields { 216 jfieldID m_nativeClass; 217 jfieldID m_viewportWidth; 218 jfieldID m_viewportHeight; 219 jfieldID m_viewportInitialScale; 220 jfieldID m_viewportMinimumScale; 221 jfieldID m_viewportMaximumScale; 222 jfieldID m_viewportUserScalable; 223 jfieldID m_viewportDensityDpi; 224 jfieldID m_webView; 225 } gWebViewCoreFields; 226 227 // ---------------------------------------------------------------------------- 228 229 struct WebViewCore::JavaGlue { 230 jweak m_obj; 231 jmethodID m_spawnScrollTo; 232 jmethodID m_scrollTo; 233 jmethodID m_scrollBy; 234 jmethodID m_contentDraw; 235 jmethodID m_requestListBox; 236 jmethodID m_openFileChooser; 237 jmethodID m_requestSingleListBox; 238 jmethodID m_jsAlert; 239 jmethodID m_jsConfirm; 240 jmethodID m_jsPrompt; 241 jmethodID m_jsUnload; 242 jmethodID m_jsInterrupt; 243 jmethodID m_didFirstLayout; 244 jmethodID m_updateViewport; 245 jmethodID m_sendNotifyProgressFinished; 246 jmethodID m_sendViewInvalidate; 247 jmethodID m_sendImmediateRepaint; 248 jmethodID m_setRootLayer; 249 jmethodID m_updateTextfield; 250 jmethodID m_updateTextSelection; 251 jmethodID m_clearTextEntry; 252 jmethodID m_restoreScale; 253 jmethodID m_restoreScreenWidthScale; 254 jmethodID m_needTouchEvents; 255 jmethodID m_requestKeyboard; 256 jmethodID m_requestKeyboardWithSelection; 257 jmethodID m_exceededDatabaseQuota; 258 jmethodID m_reachedMaxAppCacheSize; 259 jmethodID m_populateVisitedLinks; 260 jmethodID m_geolocationPermissionsShowPrompt; 261 jmethodID m_geolocationPermissionsHidePrompt; 262 jmethodID m_addMessageToConsole; 263 jmethodID m_getPluginClass; 264 jmethodID m_showFullScreenPlugin; 265 jmethodID m_hideFullScreenPlugin; 266 jmethodID m_addSurface; 267 jmethodID m_updateSurface; 268 jmethodID m_destroySurface; 269 jmethodID m_getContext; 270 jmethodID m_sendFindAgain; 271 jmethodID m_showRect; 272 jmethodID m_centerFitRect; 273 jmethodID m_setScrollbarModes; 274 AutoJObject object(JNIEnv* env) { 275 return getRealObject(env, m_obj); 276 } 277 }; 278 279 /* 280 * WebViewCore Implementation 281 */ 282 283 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 284 { 285 jmethodID m = env->GetMethodID(clazz, name, signature); 286 LOG_ASSERT(m, "Could not find method %s", name); 287 return m; 288 } 289 290 Mutex WebViewCore::gFrameCacheMutex; 291 Mutex WebViewCore::gButtonMutex; 292 Mutex WebViewCore::gCursorBoundsMutex; 293 Mutex WebViewCore::m_contentMutex; 294 295 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) 296 : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) 297 { 298 m_mainFrame = mainframe; 299 300 m_popupReply = 0; 301 m_moveGeneration = 0; 302 m_lastGeneration = 0; 303 m_touchGeneration = 0; 304 m_blockTextfieldUpdates = false; 305 // just initial values. These should be set by client 306 m_maxXScroll = 320/4; 307 m_maxYScroll = 240/4; 308 m_textGeneration = 0; 309 m_screenWidth = 320; 310 m_scale = 1; 311 m_screenWidthScale = 1; 312 #if ENABLE(TOUCH_EVENTS) 313 m_forwardingTouchEvents = false; 314 #endif 315 m_isPaused = false; 316 317 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); 318 319 jclass clazz = env->GetObjectClass(javaWebViewCore); 320 m_javaGlue = new JavaGlue; 321 m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); 322 m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V"); 323 m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V"); 324 m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V"); 325 m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); 326 m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); 327 m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "()Ljava/lang/String;"); 328 m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V"); 329 m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V"); 330 m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z"); 331 m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); 332 m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z"); 333 m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z"); 334 m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V"); 335 m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); 336 m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); 337 m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); 338 m_javaGlue->m_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V"); 339 m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)V"); 340 m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); 341 m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V"); 342 m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); 343 m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V"); 344 m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V"); 345 m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); 346 m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); 347 m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V"); 348 m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); 349 m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); 350 m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); 351 m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); 352 m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); 353 m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V"); 354 m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); 355 m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;I)V"); 356 m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V"); 357 m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;"); 358 m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V"); 359 m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V"); 360 m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;"); 361 m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); 362 m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); 363 m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); 364 m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); 365 366 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); 367 368 m_scrollOffsetX = m_scrollOffsetY = 0; 369 370 PageGroup::setShouldTrackVisitedLinks(true); 371 372 reset(true); 373 374 WebViewCore::addInstance(this); 375 } 376 377 WebViewCore::~WebViewCore() 378 { 379 WebViewCore::removeInstance(this); 380 381 // Release the focused view 382 Release(m_popupReply); 383 384 if (m_javaGlue->m_obj) { 385 JNIEnv* env = JSC::Bindings::getJNIEnv(); 386 env->DeleteWeakGlobalRef(m_javaGlue->m_obj); 387 m_javaGlue->m_obj = 0; 388 } 389 delete m_javaGlue; 390 delete m_frameCacheKit; 391 delete m_navPictureKit; 392 } 393 394 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) 395 { 396 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view)); 397 } 398 399 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) 400 { 401 if (!view) 402 return 0; 403 404 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget()); 405 if (!webFrameView) 406 return 0; 407 return webFrameView->webViewCore(); 408 } 409 410 void WebViewCore::reset(bool fromConstructor) 411 { 412 DBG_SET_LOG(""); 413 if (fromConstructor) { 414 m_frameCacheKit = 0; 415 m_navPictureKit = 0; 416 } else { 417 gFrameCacheMutex.lock(); 418 delete m_frameCacheKit; 419 delete m_navPictureKit; 420 m_frameCacheKit = 0; 421 m_navPictureKit = 0; 422 gFrameCacheMutex.unlock(); 423 } 424 425 m_lastFocused = 0; 426 m_lastFocusedBounds = WebCore::IntRect(0,0,0,0); 427 m_focusBoundsChanged = false; 428 m_lastFocusedSelStart = 0; 429 m_lastFocusedSelEnd = 0; 430 clearContent(); 431 m_updatedFrameCache = true; 432 m_frameCacheOutOfDate = true; 433 m_skipContentDraw = false; 434 m_findIsUp = false; 435 m_domtree_version = 0; 436 m_check_domtree_version = true; 437 m_progressDone = false; 438 m_hasCursorBounds = false; 439 440 m_scrollOffsetX = 0; 441 m_scrollOffsetY = 0; 442 m_screenWidth = 0; 443 m_screenHeight = 0; 444 m_groupForVisitedLinks = NULL; 445 } 446 447 static bool layoutIfNeededRecursive(WebCore::Frame* f) 448 { 449 if (!f) 450 return true; 451 452 WebCore::FrameView* v = f->view(); 453 if (!v) 454 return true; 455 456 if (v->needsLayout()) 457 v->layout(f->tree()->parent()); 458 459 WebCore::Frame* child = f->tree()->firstChild(); 460 bool success = true; 461 while (child) { 462 success &= layoutIfNeededRecursive(child); 463 child = child->tree()->nextSibling(); 464 } 465 466 return success && !v->needsLayout(); 467 } 468 469 CacheBuilder& WebViewCore::cacheBuilder() 470 { 471 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); 472 } 473 474 WebCore::Node* WebViewCore::currentFocus() 475 { 476 return cacheBuilder().currentFocus(); 477 } 478 479 void WebViewCore::recordPicture(SkPicture* picture) 480 { 481 // if there is no document yet, just return 482 if (!m_mainFrame->document()) { 483 DBG_NAV_LOG("no document"); 484 return; 485 } 486 // Call layout to ensure that the contentWidth and contentHeight are correct 487 if (!layoutIfNeededRecursive(m_mainFrame)) { 488 DBG_NAV_LOG("layout failed"); 489 return; 490 } 491 // draw into the picture's recording canvas 492 WebCore::FrameView* view = m_mainFrame->view(); 493 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(), 494 view->contentsHeight()); 495 SkAutoPictureRecord arp(picture, view->contentsWidth(), 496 view->contentsHeight(), PICT_RECORD_FLAGS); 497 SkAutoMemoryUsageProbe mup(__FUNCTION__); 498 499 // Copy m_buttons so we can pass it to our graphics context. 500 gButtonMutex.lock(); 501 WTF::Vector<Container> buttons(m_buttons); 502 gButtonMutex.unlock(); 503 504 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons); 505 WebCore::GraphicsContext gc(&pgc); 506 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, INT_MAX, INT_MAX)); 507 508 gButtonMutex.lock(); 509 updateButtonList(&buttons); 510 gButtonMutex.unlock(); 511 } 512 513 void WebViewCore::recordPictureSet(PictureSet* content) 514 { 515 // if there is no document yet, just return 516 if (!m_mainFrame->document()) { 517 DBG_SET_LOG("!m_mainFrame->document()"); 518 return; 519 } 520 if (m_addInval.isEmpty()) { 521 DBG_SET_LOG("m_addInval.isEmpty()"); 522 return; 523 } 524 // Call layout to ensure that the contentWidth and contentHeight are correct 525 // it's fine for layout to gather invalidates, but defeat sending a message 526 // back to java to call webkitDraw, since we're already in the middle of 527 // doing that 528 m_skipContentDraw = true; 529 bool success = layoutIfNeededRecursive(m_mainFrame); 530 m_skipContentDraw = false; 531 532 // We may be mid-layout and thus cannot draw. 533 if (!success) 534 return; 535 536 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive 537 #ifdef ANDROID_INSTRUMENT 538 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter); 539 #endif 540 541 // if the webkit page dimensions changed, discard the pictureset and redraw. 542 WebCore::FrameView* view = m_mainFrame->view(); 543 int width = view->contentsWidth(); 544 int height = view->contentsHeight(); 545 546 // Use the contents width and height as a starting point. 547 SkIRect contentRect; 548 contentRect.set(0, 0, width, height); 549 SkIRect total(contentRect); 550 551 // Traverse all the frames and add their sizes if they are in the visible 552 // rectangle. 553 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame; 554 frame = frame->tree()->traverseNext()) { 555 // If the frame doesn't have an owner then it is the top frame and the 556 // view size is the frame size. 557 WebCore::RenderPart* owner = frame->ownerRenderer(); 558 if (owner && owner->style()->visibility() == VISIBLE) { 559 int x = owner->x(); 560 int y = owner->y(); 561 562 // Traverse the tree up to the parent to find the absolute position 563 // of this frame. 564 WebCore::Frame* parent = frame->tree()->parent(); 565 while (parent) { 566 WebCore::RenderPart* parentOwner = parent->ownerRenderer(); 567 if (parentOwner) { 568 x += parentOwner->x(); 569 y += parentOwner->y(); 570 } 571 parent = parent->tree()->parent(); 572 } 573 // Use the owner dimensions so that padding and border are 574 // included. 575 int right = x + owner->width(); 576 int bottom = y + owner->height(); 577 SkIRect frameRect = {x, y, right, bottom}; 578 // Ignore a width or height that is smaller than 1. Some iframes 579 // have small dimensions in order to be hidden. The iframe 580 // expansion code does not expand in that case so we should ignore 581 // them here. 582 if (frameRect.width() > 1 && frameRect.height() > 1 583 && SkIRect::Intersects(total, frameRect)) 584 total.join(x, y, right, bottom); 585 } 586 } 587 588 // If the new total is larger than the content, resize the view to include 589 // all the content. 590 if (!contentRect.contains(total)) { 591 // Resize the view to change the overflow clip. 592 view->resize(total.fRight, total.fBottom); 593 594 // We have to force a layout in order for the clip to change. 595 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); 596 view->forceLayout(); 597 598 // Relayout similar to above 599 m_skipContentDraw = true; 600 bool success = layoutIfNeededRecursive(m_mainFrame); 601 m_skipContentDraw = false; 602 if (!success) 603 return; 604 605 // Set the computed content width 606 width = view->contentsWidth(); 607 height = view->contentsHeight(); 608 } 609 610 content->checkDimensions(width, height, &m_addInval); 611 612 // The inval region may replace existing pictures. The existing pictures 613 // may have already been split into pieces. If reuseSubdivided() returns 614 // true, the split pieces are the last entries in the picture already. They 615 // are marked as invalid, and are rebuilt by rebuildPictureSet(). 616 617 // If the new region doesn't match a set of split pieces, add it to the end. 618 if (!content->reuseSubdivided(m_addInval)) { 619 const SkIRect& inval = m_addInval.getBounds(); 620 SkPicture* picture = rebuildPicture(inval); 621 DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft, 622 inval.fTop, inval.width(), inval.height()); 623 content->add(m_addInval, picture, 0, false); 624 picture->safeUnref(); 625 } 626 // Remove any pictures already in the set that are obscured by the new one, 627 // and check to see if any already split pieces need to be redrawn. 628 if (content->build()) 629 rebuildPictureSet(content); 630 } // WebViewCoreRecordTimeCounter 631 WebCore::Node* oldFocusNode = currentFocus(); 632 m_frameCacheOutOfDate = true; 633 WebCore::IntRect oldBounds; 634 int oldSelStart = 0; 635 int oldSelEnd = 0; 636 if (oldFocusNode) { 637 oldBounds = oldFocusNode->getRect(); 638 RenderObject* renderer = oldFocusNode->renderer(); 639 if (renderer && (renderer->isTextArea() || renderer->isTextField())) { 640 WebCore::RenderTextControl* rtc = 641 static_cast<WebCore::RenderTextControl*>(renderer); 642 oldSelStart = rtc->selectionStart(); 643 oldSelEnd = rtc->selectionEnd(); 644 } 645 } else 646 oldBounds = WebCore::IntRect(0,0,0,0); 647 unsigned latestVersion = 0; 648 if (m_check_domtree_version) { 649 // as domTreeVersion only increment, we can just check the sum to see 650 // whether we need to update the frame cache 651 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { 652 latestVersion += frame->document()->domTreeVersion(); 653 } 654 } 655 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" 656 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}" 657 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}" 658 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d", 659 m_lastFocused, oldFocusNode, 660 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), 661 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), 662 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(), 663 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd, 664 m_check_domtree_version ? "true" : "false", 665 latestVersion, m_domtree_version); 666 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds 667 && m_lastFocusedSelStart == oldSelStart 668 && m_lastFocusedSelEnd == oldSelEnd 669 && !m_findIsUp 670 && (!m_check_domtree_version || latestVersion == m_domtree_version)) 671 { 672 return; 673 } 674 m_focusBoundsChanged |= m_lastFocused == oldFocusNode 675 && m_lastFocusedBounds != oldBounds; 676 m_lastFocused = oldFocusNode; 677 m_lastFocusedBounds = oldBounds; 678 m_lastFocusedSelStart = oldSelStart; 679 m_lastFocusedSelEnd = oldSelEnd; 680 m_domtree_version = latestVersion; 681 DBG_NAV_LOG("call updateFrameCache"); 682 updateFrameCache(); 683 if (m_findIsUp) { 684 LOG_ASSERT(m_javaGlue->m_obj, 685 "A Java widget was not associated with this view bridge!"); 686 JNIEnv* env = JSC::Bindings::getJNIEnv(); 687 env->CallVoidMethod(m_javaGlue->object(env).get(), 688 m_javaGlue->m_sendFindAgain); 689 checkException(env); 690 } 691 } 692 693 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons) 694 { 695 // All the entries in buttons are either updates of previous entries in 696 // m_buttons or they need to be added to it. 697 Container* end = buttons->end(); 698 for (Container* updatedContainer = buttons->begin(); 699 updatedContainer != end; updatedContainer++) { 700 bool updated = false; 701 // Search for a previous entry that references the same node as our new 702 // data 703 Container* lastPossibleMatch = m_buttons.end(); 704 for (Container* possibleMatch = m_buttons.begin(); 705 possibleMatch != lastPossibleMatch; possibleMatch++) { 706 if (updatedContainer->matches(possibleMatch->node())) { 707 // Update our record, and skip to the next one. 708 possibleMatch->setRect(updatedContainer->rect()); 709 updated = true; 710 break; 711 } 712 } 713 if (!updated) { 714 // This is a brand new button, so append it to m_buttons 715 m_buttons.append(*updatedContainer); 716 } 717 } 718 size_t i = 0; 719 // count will decrease each time one is removed, so check count each time. 720 while (i < m_buttons.size()) { 721 if (m_buttons[i].canBeRemoved()) { 722 m_buttons[i] = m_buttons.last(); 723 m_buttons.removeLast(); 724 } else { 725 i++; 726 } 727 } 728 } 729 730 // note: updateCursorBounds is called directly by the WebView thread 731 // This needs to be called each time we call CachedRoot::setCursor() with 732 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data 733 // about the cursor is incorrect. When we call setCursor(0,0), we need 734 // to set hasCursorBounds to false. 735 void WebViewCore::updateCursorBounds(const CachedRoot* root, 736 const CachedFrame* cachedFrame, const CachedNode* cachedNode) 737 { 738 LOG_ASSERT(root, "updateCursorBounds: root cannot be null"); 739 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null"); 740 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null"); 741 gCursorBoundsMutex.lock(); 742 m_hasCursorBounds = !cachedNode->isHidden(); 743 // If m_hasCursorBounds is false, we never look at the other 744 // values, so do not bother setting them. 745 if (m_hasCursorBounds) { 746 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame); 747 if (m_cursorBounds != bounds) 748 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)", 749 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 750 m_cursorBounds = bounds; 751 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame); 752 m_cursorFrame = cachedFrame->framePointer(); 753 root->getSimulatedMousePosition(&m_cursorLocation); 754 m_cursorNode = cachedNode->nodePointer(); 755 } 756 gCursorBoundsMutex.unlock(); 757 } 758 759 void WebViewCore::clearContent() 760 { 761 DBG_SET_LOG(""); 762 m_contentMutex.lock(); 763 m_content.clear(); 764 m_contentMutex.unlock(); 765 m_addInval.setEmpty(); 766 m_rebuildInval.setEmpty(); 767 } 768 769 void WebViewCore::copyContentToPicture(SkPicture* picture) 770 { 771 DBG_SET_LOG("start"); 772 m_contentMutex.lock(); 773 PictureSet copyContent = PictureSet(m_content); 774 m_contentMutex.unlock(); 775 776 int w = copyContent.width(); 777 int h = copyContent.height(); 778 copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS)); 779 picture->endRecording(); 780 DBG_SET_LOG("end"); 781 } 782 783 bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color) 784 { 785 #ifdef ANDROID_INSTRUMENT 786 TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter); 787 #endif 788 DBG_SET_LOG("start"); 789 m_contentMutex.lock(); 790 PictureSet copyContent = PictureSet(m_content); 791 m_contentMutex.unlock(); 792 int sc = canvas->save(SkCanvas::kClip_SaveFlag); 793 SkRect clip; 794 clip.set(0, 0, copyContent.width(), copyContent.height()); 795 canvas->clipRect(clip, SkRegion::kDifference_Op); 796 canvas->drawColor(color); 797 canvas->restoreToCount(sc); 798 bool tookTooLong = copyContent.draw(canvas); 799 m_contentMutex.lock(); 800 m_content.setDrawTimes(copyContent); 801 m_contentMutex.unlock(); 802 DBG_SET_LOG("end"); 803 return tookTooLong; 804 } 805 806 bool WebViewCore::focusBoundsChanged() 807 { 808 bool result = m_focusBoundsChanged; 809 m_focusBoundsChanged = false; 810 return result; 811 } 812 813 bool WebViewCore::pictureReady() 814 { 815 bool done; 816 m_contentMutex.lock(); 817 PictureSet copyContent = PictureSet(m_content); 818 done = m_progressDone; 819 m_contentMutex.unlock(); 820 DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false", 821 copyContent.isEmpty() ? "true" : "false"); 822 return done || !copyContent.isEmpty(); 823 } 824 825 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) 826 { 827 WebCore::FrameView* view = m_mainFrame->view(); 828 int width = view->contentsWidth(); 829 int height = view->contentsHeight(); 830 SkPicture* picture = new SkPicture(); 831 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS); 832 SkAutoMemoryUsageProbe mup(__FUNCTION__); 833 SkCanvas* recordingCanvas = arp.getRecordingCanvas(); 834 835 gButtonMutex.lock(); 836 WTF::Vector<Container> buttons(m_buttons); 837 gButtonMutex.unlock(); 838 839 WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons); 840 WebCore::GraphicsContext gc(&pgc); 841 recordingCanvas->translate(-inval.fLeft, -inval.fTop); 842 recordingCanvas->save(); 843 view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft, 844 inval.fTop, inval.width(), inval.height())); 845 m_rebuildInval.op(inval, SkRegion::kUnion_Op); 846 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", 847 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, 848 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom); 849 850 gButtonMutex.lock(); 851 updateButtonList(&buttons); 852 gButtonMutex.unlock(); 853 854 return picture; 855 } 856 857 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) 858 { 859 WebCore::FrameView* view = m_mainFrame->view(); 860 size_t size = pictureSet->size(); 861 for (size_t index = 0; index < size; index++) { 862 if (pictureSet->upToDate(index)) 863 continue; 864 const SkIRect& inval = pictureSet->bounds(index); 865 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, 866 inval.fLeft, inval.fTop, inval.width(), inval.height()); 867 pictureSet->setPicture(index, rebuildPicture(inval)); 868 } 869 pictureSet->validate(__FUNCTION__); 870 } 871 872 bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point) 873 { 874 DBG_SET_LOG("start"); 875 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); 876 m_contentMutex.lock(); 877 PictureSet contentCopy(m_content); 878 m_progressDone = progress <= 0.0f || progress >= 1.0f; 879 m_contentMutex.unlock(); 880 recordPictureSet(&contentCopy); 881 if (!m_progressDone && contentCopy.isEmpty()) { 882 DBG_SET_LOGD("empty (progress=%g)", progress); 883 return false; 884 } 885 region->set(m_addInval); 886 m_addInval.setEmpty(); 887 region->op(m_rebuildInval, SkRegion::kUnion_Op); 888 m_rebuildInval.setEmpty(); 889 m_contentMutex.lock(); 890 contentCopy.setDrawTimes(m_content); 891 m_content.set(contentCopy); 892 point->fX = m_content.width(); 893 point->fY = m_content.height(); 894 m_contentMutex.unlock(); 895 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, 896 region->getBounds().fTop, region->getBounds().fRight, 897 region->getBounds().fBottom); 898 DBG_SET_LOG("end"); 899 return true; 900 } 901 902 void WebViewCore::splitContent() 903 { 904 bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame); 905 LOG_ASSERT(layoutSuceeded, "Can never be called recursively"); 906 PictureSet tempPictureSet; 907 m_contentMutex.lock(); 908 m_content.split(&tempPictureSet); 909 m_contentMutex.unlock(); 910 rebuildPictureSet(&tempPictureSet); 911 m_contentMutex.lock(); 912 m_content.set(tempPictureSet); 913 m_contentMutex.unlock(); 914 } 915 916 void WebViewCore::scrollTo(int x, int y, bool animate) 917 { 918 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 919 920 // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); 921 922 JNIEnv* env = JSC::Bindings::getJNIEnv(); 923 env->CallVoidMethod(m_javaGlue->object(env).get(), 924 animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo, 925 x, y); 926 checkException(env); 927 } 928 929 void WebViewCore::sendNotifyProgressFinished() 930 { 931 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 932 JNIEnv* env = JSC::Bindings::getJNIEnv(); 933 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished); 934 checkException(env); 935 } 936 937 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) 938 { 939 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 940 JNIEnv* env = JSC::Bindings::getJNIEnv(); 941 env->CallVoidMethod(m_javaGlue->object(env).get(), 942 m_javaGlue->m_sendViewInvalidate, 943 rect.x(), rect.y(), rect.right(), rect.bottom()); 944 checkException(env); 945 } 946 947 void WebViewCore::scrollBy(int dx, int dy, bool animate) 948 { 949 if (!(dx | dy)) 950 return; 951 JNIEnv* env = JSC::Bindings::getJNIEnv(); 952 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy, 953 dx, dy, animate); 954 checkException(env); 955 } 956 957 #if USE(ACCELERATED_COMPOSITING) 958 959 void WebViewCore::immediateRepaint() 960 { 961 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 962 JNIEnv* env = JSC::Bindings::getJNIEnv(); 963 env->CallVoidMethod(m_javaGlue->object(env).get(), 964 m_javaGlue->m_sendImmediateRepaint); 965 checkException(env); 966 } 967 968 void WebViewCore::setUIRootLayer(const LayerAndroid* layer) 969 { 970 JNIEnv* env = JSC::Bindings::getJNIEnv(); 971 env->CallVoidMethod(m_javaGlue->object(env).get(), 972 m_javaGlue->m_setRootLayer, 973 reinterpret_cast<jint>(layer)); 974 checkException(env); 975 } 976 977 #endif // USE(ACCELERATED_COMPOSITING) 978 979 void WebViewCore::contentDraw() 980 { 981 JNIEnv* env = JSC::Bindings::getJNIEnv(); 982 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw); 983 checkException(env); 984 } 985 986 void WebViewCore::contentInvalidate(const WebCore::IntRect &r) 987 { 988 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); 989 SkIRect rect(r); 990 if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) 991 return; 992 m_addInval.op(rect, SkRegion::kUnion_Op); 993 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", 994 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop, 995 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom); 996 if (!m_skipContentDraw) 997 contentDraw(); 998 } 999 1000 void WebViewCore::offInvalidate(const WebCore::IntRect &r) 1001 { 1002 // FIXME: these invalidates are offscreen, and can be throttled or 1003 // deferred until the area is visible. For now, treat them as 1004 // regular invals so that drawing happens (inefficiently) for now. 1005 contentInvalidate(r); 1006 } 1007 1008 static int pin_pos(int x, int width, int targetWidth) 1009 { 1010 if (x + width > targetWidth) 1011 x = targetWidth - width; 1012 if (x < 0) 1013 x = 0; 1014 return x; 1015 } 1016 1017 void WebViewCore::didFirstLayout() 1018 { 1019 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1020 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1021 1022 WebCore::FrameLoader* loader = m_mainFrame->loader(); 1023 const WebCore::KURL& url = loader->url(); 1024 if (url.isEmpty()) 1025 return; 1026 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); 1027 1028 WebCore::FrameLoadType loadType = loader->loadType(); 1029 1030 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1031 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout, 1032 loadType == WebCore::FrameLoadTypeStandard 1033 // When redirect with locked history, we would like to reset the 1034 // scale factor. This is important for www.yahoo.com as it is 1035 // redirected to www.yahoo.com/?rs=1 on load. 1036 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList); 1037 checkException(env); 1038 1039 DBG_NAV_LOG("call updateFrameCache"); 1040 m_check_domtree_version = false; 1041 updateFrameCache(); 1042 m_history.setDidFirstLayout(true); 1043 } 1044 1045 void WebViewCore::updateViewport() 1046 { 1047 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1048 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1049 1050 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1051 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport); 1052 checkException(env); 1053 } 1054 1055 void WebViewCore::restoreScale(int scale) 1056 { 1057 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1058 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1059 1060 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1061 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale); 1062 checkException(env); 1063 } 1064 1065 void WebViewCore::restoreScreenWidthScale(int scale) 1066 { 1067 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1068 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1069 1070 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1071 env->CallVoidMethod(m_javaGlue->object(env).get(), 1072 m_javaGlue->m_restoreScreenWidthScale, scale); 1073 checkException(env); 1074 } 1075 1076 void WebViewCore::needTouchEvents(bool need) 1077 { 1078 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1079 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1080 1081 #if ENABLE(TOUCH_EVENTS) 1082 if (m_forwardingTouchEvents == need) 1083 return; 1084 1085 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1086 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need); 1087 checkException(env); 1088 1089 m_forwardingTouchEvents = need; 1090 #endif 1091 } 1092 1093 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node, 1094 int selStart, int selEnd) 1095 { 1096 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1097 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1098 1099 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1100 env->CallVoidMethod(m_javaGlue->object(env).get(), 1101 m_javaGlue->m_requestKeyboardWithSelection, 1102 reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration); 1103 checkException(env); 1104 } 1105 1106 void WebViewCore::requestKeyboard(bool showKeyboard) 1107 { 1108 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 1109 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); 1110 1111 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1112 env->CallVoidMethod(m_javaGlue->object(env).get(), 1113 m_javaGlue->m_requestKeyboard, showKeyboard); 1114 checkException(env); 1115 } 1116 1117 void WebViewCore::notifyProgressFinished() 1118 { 1119 DBG_NAV_LOG("call updateFrameCache"); 1120 m_check_domtree_version = true; 1121 updateFrameCache(); 1122 sendNotifyProgressFinished(); 1123 } 1124 1125 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) 1126 { 1127 int dx = 0, dy = 0; 1128 1129 switch (dir) { 1130 case CacheBuilder::LEFT: 1131 dx = -m_maxXScroll; 1132 break; 1133 case CacheBuilder::UP: 1134 dy = -m_maxYScroll; 1135 break; 1136 case CacheBuilder::RIGHT: 1137 dx = m_maxXScroll; 1138 break; 1139 case CacheBuilder::DOWN: 1140 dy = m_maxYScroll; 1141 break; 1142 case CacheBuilder::UNINITIALIZED: 1143 default: 1144 LOG_ASSERT(0, "unexpected focus selector"); 1145 } 1146 this->scrollBy(dx, dy, true); 1147 } 1148 1149 void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy) 1150 { 1151 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy, 1152 m_scrollOffsetX, m_scrollOffsetY); 1153 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { 1154 m_scrollOffsetX = dx; 1155 m_scrollOffsetY = dy; 1156 // The visible rect is located within our coordinate space so it 1157 // contains the actual scroll position. Setting the location makes hit 1158 // testing work correctly. 1159 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, 1160 m_scrollOffsetY); 1161 m_mainFrame->eventHandler()->sendScrollEvent(); 1162 1163 // update the currently visible screen 1164 sendPluginVisibleScreen(); 1165 } 1166 gCursorBoundsMutex.lock(); 1167 bool hasCursorBounds = m_hasCursorBounds; 1168 Frame* frame = (Frame*) m_cursorFrame; 1169 IntPoint location = m_cursorLocation; 1170 gCursorBoundsMutex.unlock(); 1171 if (!hasCursorBounds) 1172 return; 1173 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y()); 1174 } 1175 1176 void WebViewCore::setGlobalBounds(int x, int y, int h, int v) 1177 { 1178 DBG_NAV_LOGD("{%d,%d}", x, y); 1179 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v); 1180 } 1181 1182 void WebViewCore::setSizeScreenWidthAndScale(int width, int height, 1183 int screenWidth, float scale, int realScreenWidth, int screenHeight, 1184 int anchorX, int anchorY, bool ignoreHeight) 1185 { 1186 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1187 int ow = window->width(); 1188 int oh = window->height(); 1189 window->setSize(width, height); 1190 int osw = m_screenWidth; 1191 int orsw = m_screenWidth * m_screenWidthScale / m_scale; 1192 int osh = m_screenHeight; 1193 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)", 1194 ow, oh, osw, m_scale, width, height, screenWidth, scale); 1195 m_screenWidth = screenWidth; 1196 m_screenHeight = screenHeight; 1197 if (scale >= 0) { // negative means ignore 1198 m_scale = scale; 1199 if (screenWidth != realScreenWidth) 1200 m_screenWidthScale = realScreenWidth * scale / screenWidth; 1201 else 1202 m_screenWidthScale = m_scale; 1203 } 1204 m_maxXScroll = screenWidth >> 2; 1205 m_maxYScroll = (screenWidth * height / width) >> 2; 1206 if (ow != width || (!ignoreHeight && oh != height) || osw != screenWidth) { 1207 WebCore::RenderObject *r = m_mainFrame->contentRenderer(); 1208 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, 1209 realScreenWidth, screenHeight); 1210 if (r) { 1211 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY); 1212 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY); 1213 WebCore::Node* node = 0; 1214 WebCore::IntRect bounds; 1215 WebCore::IntPoint offset; 1216 // If the screen width changed, it is probably zoom change or 1217 // orientation change. Try to keep the anchor at the same place. 1218 if (osw && screenWidth && osw != screenWidth) { 1219 WebCore::HitTestResult hitTestResult = 1220 m_mainFrame->eventHandler()-> hitTestResultAtPoint( 1221 anchorPoint, false); 1222 node = hitTestResult.innerNode(); 1223 } 1224 if (node) { 1225 bounds = node->getRect(); 1226 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", 1227 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1228 // sites like nytimes.com insert a non-standard tag <nyt_text> 1229 // in the html. If it is the HitTestResult, it may have zero 1230 // width and height. In this case, use its parent node. 1231 if (bounds.width() == 0) { 1232 node = node->parent(); 1233 if (node) { 1234 bounds = node->getRect(); 1235 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)", 1236 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1237 } 1238 } 1239 } 1240 r->setNeedsLayoutAndPrefWidthsRecalc(); 1241 m_mainFrame->view()->forceLayout(); 1242 // scroll to restore current screen center 1243 if (node) { 1244 const WebCore::IntRect& newBounds = node->getRect(); 1245 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," 1246 "h=%d)", newBounds.x(), newBounds.y(), 1247 newBounds.width(), newBounds.height()); 1248 if ((orsw && osh && bounds.width() && bounds.height()) 1249 && (bounds != newBounds)) { 1250 WebCore::FrameView* view = m_mainFrame->view(); 1251 // force left align if width is not changed while height changed. 1252 // the anchorPoint is probably at some white space in the node 1253 // which is affected by text wrap around the screen width. 1254 const bool leftAlign = (osw != m_screenWidth) 1255 && (bounds.width() == newBounds.width()) 1256 && (bounds.height() != newBounds.height()); 1257 const float xPercentInDoc = 1258 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); 1259 const float xPercentInView = 1260 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / orsw; 1261 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); 1262 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; 1263 showRect(newBounds.x(), newBounds.y(), newBounds.width(), 1264 newBounds.height(), view->contentsWidth(), 1265 view->contentsHeight(), 1266 xPercentInDoc, xPercentInView, 1267 yPercentInDoc, yPercentInView); 1268 } 1269 } 1270 } 1271 } 1272 1273 // update the currently visible screen as perceived by the plugin 1274 sendPluginVisibleScreen(); 1275 } 1276 1277 void WebViewCore::dumpDomTree(bool useFile) 1278 { 1279 #ifdef ANDROID_DOM_LOGGING 1280 if (useFile) 1281 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w"); 1282 m_mainFrame->document()->showTreeForThis(); 1283 if (gDomTreeFile) { 1284 fclose(gDomTreeFile); 1285 gDomTreeFile = 0; 1286 } 1287 #endif 1288 } 1289 1290 void WebViewCore::dumpRenderTree(bool useFile) 1291 { 1292 #ifdef ANDROID_DOM_LOGGING 1293 WebCore::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); 1294 const char* data = renderDump.data(); 1295 if (useFile) { 1296 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); 1297 DUMP_RENDER_LOGD("%s", data); 1298 fclose(gRenderTreeFile); 1299 gRenderTreeFile = 0; 1300 } else { 1301 // adb log can only output 1024 characters, so write out line by line. 1302 // exclude '\n' as adb log adds it for each output. 1303 int length = renderDump.length(); 1304 for (int i = 0, last = 0; i < length; i++) { 1305 if (data[i] == '\n') { 1306 if (i != last) 1307 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last])); 1308 last = i + 1; 1309 } 1310 } 1311 } 1312 #endif 1313 } 1314 1315 void WebViewCore::dumpNavTree() 1316 { 1317 #if DUMP_NAV_CACHE 1318 cacheBuilder().mDebug.print(); 1319 #endif 1320 } 1321 1322 WebCore::HTMLAnchorElement* WebViewCore::retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node) 1323 { 1324 if (!CacheBuilder::validNode(m_mainFrame, frame, node)) 1325 return 0; 1326 if (!node->hasTagName(WebCore::HTMLNames::aTag)) 1327 return 0; 1328 return static_cast<WebCore::HTMLAnchorElement*>(node); 1329 } 1330 1331 WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node) 1332 { 1333 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node); 1334 return anchor ? anchor->href() : WebCore::String(); 1335 } 1336 1337 WebCore::String WebViewCore::retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node) 1338 { 1339 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node); 1340 return anchor ? anchor->text() : WebCore::String(); 1341 } 1342 1343 WebCore::String WebViewCore::requestLabel(WebCore::Frame* frame, 1344 WebCore::Node* node) 1345 { 1346 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { 1347 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label"); 1348 unsigned length = list->length(); 1349 for (unsigned i = 0; i < length; i++) { 1350 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>( 1351 list->item(i)); 1352 if (label->correspondingControl() == node) { 1353 Node* node = label; 1354 String result; 1355 while ((node = node->traverseNextNode(label))) { 1356 if (node->isTextNode()) { 1357 Text* textNode = static_cast<Text*>(node); 1358 result += textNode->dataImpl(); 1359 } 1360 } 1361 return result; 1362 } 1363 } 1364 } 1365 return WebCore::String(); 1366 } 1367 1368 void WebViewCore::updateCacheOnNodeChange() 1369 { 1370 gCursorBoundsMutex.lock(); 1371 bool hasCursorBounds = m_hasCursorBounds; 1372 Frame* frame = (Frame*) m_cursorFrame; 1373 Node* node = (Node*) m_cursorNode; 1374 IntRect bounds = m_cursorHitBounds; 1375 gCursorBoundsMutex.unlock(); 1376 if (!hasCursorBounds || !node) 1377 return; 1378 if (CacheBuilder::validNode(m_mainFrame, frame, node)) { 1379 RenderObject* renderer = node->renderer(); 1380 if (renderer && renderer->style()->visibility() != HIDDEN) { 1381 IntRect absBox = renderer->absoluteBoundingBoxRect(); 1382 int globalX, globalY; 1383 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY); 1384 absBox.move(globalX, globalY); 1385 if (absBox == bounds) 1386 return; 1387 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)", 1388 absBox.x(), absBox.y(), absBox.width(), absBox.height(), 1389 bounds.x(), bounds.y(), bounds.width(), bounds.height()); 1390 } 1391 } 1392 DBG_NAV_LOGD("updateFrameCache node=%p", node); 1393 updateFrameCache(); 1394 } 1395 1396 void WebViewCore::updateFrameCache() 1397 { 1398 if (!m_frameCacheOutOfDate) { 1399 DBG_NAV_LOG("!m_frameCacheOutOfDate"); 1400 return; 1401 } 1402 #ifdef ANDROID_INSTRUMENT 1403 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter); 1404 #endif 1405 m_frameCacheOutOfDate = false; 1406 #if DEBUG_NAV_UI 1407 m_now = SkTime::GetMSecs(); 1408 #endif 1409 m_temp = new CachedRoot(); 1410 m_temp->init(m_mainFrame, &m_history); 1411 #if USE(ACCELERATED_COMPOSITING) 1412 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer(); 1413 if (graphicsLayer) 1414 m_temp->setRootLayer(graphicsLayer->contentLayer()); 1415 #endif 1416 CacheBuilder& builder = cacheBuilder(); 1417 WebCore::Settings* settings = m_mainFrame->page()->settings(); 1418 builder.allowAllTextDetection(); 1419 #ifdef ANDROID_META_SUPPORT 1420 if (settings) { 1421 if (!settings->formatDetectionAddress()) 1422 builder.disallowAddressDetection(); 1423 if (!settings->formatDetectionEmail()) 1424 builder.disallowEmailDetection(); 1425 if (!settings->formatDetectionTelephone()) 1426 builder.disallowPhoneDetection(); 1427 } 1428 #endif 1429 builder.buildCache(m_temp); 1430 m_tempPict = new SkPicture(); 1431 recordPicture(m_tempPict); 1432 m_temp->setPicture(m_tempPict); 1433 m_temp->setTextGeneration(m_textGeneration); 1434 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); 1435 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX, 1436 m_scrollOffsetY, window->width(), window->height())); 1437 gFrameCacheMutex.lock(); 1438 delete m_frameCacheKit; 1439 delete m_navPictureKit; 1440 m_frameCacheKit = m_temp; 1441 m_navPictureKit = m_tempPict; 1442 m_updatedFrameCache = true; 1443 #if DEBUG_NAV_UI 1444 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus(); 1445 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)", 1446 cachedFocusNode ? cachedFocusNode->index() : 0, 1447 cachedFocusNode ? cachedFocusNode->nodePointer() : 0); 1448 #endif 1449 gFrameCacheMutex.unlock(); 1450 } 1451 1452 void WebViewCore::updateFrameCacheIfLoading() 1453 { 1454 if (!m_check_domtree_version) 1455 updateFrameCache(); 1456 } 1457 1458 /////////////////////////////////////////////////////////////////////////////// 1459 1460 void WebViewCore::addPlugin(PluginWidgetAndroid* w) 1461 { 1462 // SkDebugf("----------- addPlugin %p", w); 1463 /* The plugin must be appended to the end of the array. This ensures that if 1464 the plugin is added while iterating through the array (e.g. sendEvent(...)) 1465 that the iteration process is not corrupted. 1466 */ 1467 *m_plugins.append() = w; 1468 } 1469 1470 void WebViewCore::removePlugin(PluginWidgetAndroid* w) 1471 { 1472 // SkDebugf("----------- removePlugin %p", w); 1473 int index = m_plugins.find(w); 1474 if (index < 0) { 1475 SkDebugf("--------------- pluginwindow not found! %p\n", w); 1476 } else { 1477 m_plugins.removeShuffle(index); 1478 } 1479 } 1480 1481 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const 1482 { 1483 return m_plugins.find(w) >= 0; 1484 } 1485 1486 void WebViewCore::invalPlugin(PluginWidgetAndroid* w) 1487 { 1488 const double PLUGIN_INVAL_DELAY = 1.0 / 60; 1489 1490 if (!m_pluginInvalTimer.isActive()) { 1491 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); 1492 } 1493 } 1494 1495 void WebViewCore::drawPlugins() 1496 { 1497 SkRegion inval; // accumualte what needs to be redrawn 1498 PluginWidgetAndroid** iter = m_plugins.begin(); 1499 PluginWidgetAndroid** stop = m_plugins.end(); 1500 1501 for (; iter < stop; ++iter) { 1502 PluginWidgetAndroid* w = *iter; 1503 SkIRect dirty; 1504 if (w->isDirty(&dirty)) { 1505 w->draw(); 1506 inval.op(dirty, SkRegion::kUnion_Op); 1507 } 1508 } 1509 1510 if (!inval.isEmpty()) { 1511 // inval.getBounds() is our rectangle 1512 const SkIRect& bounds = inval.getBounds(); 1513 WebCore::IntRect r(bounds.fLeft, bounds.fTop, 1514 bounds.width(), bounds.height()); 1515 this->viewInvalidate(r); 1516 } 1517 } 1518 1519 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { 1520 // if frame is the parent then notify all plugins 1521 if (!frame->tree()->parent()) { 1522 // trigger an event notifying the plugins that the page has loaded 1523 ANPEvent event; 1524 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 1525 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 1526 sendPluginEvent(event); 1527 } 1528 // else if frame's parent has completed 1529 else if (!frame->tree()->parent()->loader()->isLoading()) { 1530 // send to all plugins who have this frame in their heirarchy 1531 PluginWidgetAndroid** iter = m_plugins.begin(); 1532 PluginWidgetAndroid** stop = m_plugins.end(); 1533 for (; iter < stop; ++iter) { 1534 Frame* currentFrame = (*iter)->pluginView()->parentFrame(); 1535 while (currentFrame) { 1536 if (frame == currentFrame) { 1537 ANPEvent event; 1538 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 1539 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; 1540 (*iter)->sendEvent(event); 1541 break; 1542 } 1543 currentFrame = currentFrame->tree()->parent(); 1544 } 1545 } 1546 } 1547 } 1548 1549 void WebViewCore::sendPluginVisibleScreen() 1550 { 1551 /* We may want to cache the previous values and only send the notification 1552 to the plugin in the event that one of the values has changed. 1553 */ 1554 1555 ANPRectI visibleRect; 1556 visibleRect.left = m_scrollOffsetX; 1557 visibleRect.top = m_scrollOffsetY; 1558 visibleRect.right = m_scrollOffsetX + m_screenWidth; 1559 visibleRect.bottom = m_scrollOffsetY + m_screenHeight; 1560 1561 PluginWidgetAndroid** iter = m_plugins.begin(); 1562 PluginWidgetAndroid** stop = m_plugins.end(); 1563 for (; iter < stop; ++iter) { 1564 (*iter)->setVisibleScreen(visibleRect, m_scale); 1565 } 1566 } 1567 1568 void WebViewCore::sendPluginEvent(const ANPEvent& evt) 1569 { 1570 /* The list of plugins may be manipulated as we iterate through the list. 1571 This implementation allows for the addition of new plugins during an 1572 iteration, but may fail if a plugin is removed. Currently, there are not 1573 any use cases where a plugin is deleted while processing this loop, but 1574 if it does occur we will have to use an alternate data structure and/or 1575 iteration mechanism. 1576 */ 1577 for (int x = 0; x < m_plugins.count(); x++) { 1578 m_plugins[x]->sendEvent(evt); 1579 } 1580 } 1581 1582 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp) 1583 { 1584 PluginWidgetAndroid** iter = m_plugins.begin(); 1585 PluginWidgetAndroid** stop = m_plugins.end(); 1586 for (; iter < stop; ++iter) { 1587 if ((*iter)->pluginView()->instance() == npp) { 1588 return (*iter); 1589 } 1590 } 1591 return NULL; 1592 } 1593 1594 static PluginView* nodeIsPlugin(Node* node) { 1595 RenderObject* renderer = node->renderer(); 1596 if (renderer && renderer->isWidget()) { 1597 Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); 1598 if (widget && widget->isPluginView()) 1599 return static_cast<PluginView*>(widget); 1600 } 1601 return 0; 1602 } 1603 1604 Node* WebViewCore::cursorNodeIsPlugin() { 1605 gCursorBoundsMutex.lock(); 1606 bool hasCursorBounds = m_hasCursorBounds; 1607 Frame* frame = (Frame*) m_cursorFrame; 1608 Node* node = (Node*) m_cursorNode; 1609 gCursorBoundsMutex.unlock(); 1610 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) 1611 && nodeIsPlugin(node)) { 1612 return node; 1613 } 1614 return 0; 1615 } 1616 1617 /////////////////////////////////////////////////////////////////////////////// 1618 void WebViewCore::moveMouseIfLatest(int moveGeneration, 1619 WebCore::Frame* frame, int x, int y) 1620 { 1621 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" 1622 " frame=%p x=%d y=%d", 1623 m_moveGeneration, moveGeneration, frame, x, y); 1624 if (m_moveGeneration > moveGeneration) { 1625 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", 1626 m_moveGeneration, moveGeneration); 1627 return; // short-circuit if a newer move has already been generated 1628 } 1629 m_lastGeneration = moveGeneration; 1630 moveMouse(frame, x, y); 1631 } 1632 1633 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) 1634 { 1635 DBG_NAV_LOGD("frame=%p node=%p", frame, node); 1636 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node) 1637 || !node->isElementNode()) 1638 return; 1639 // Code borrowed from FocusController::advanceFocus 1640 WebCore::FocusController* focusController 1641 = m_mainFrame->page()->focusController(); 1642 WebCore::Document* oldDoc 1643 = focusController->focusedOrMainFrame()->document(); 1644 if (oldDoc->focusedNode() == node) 1645 return; 1646 if (node->document() != oldDoc) 1647 oldDoc->setFocusedNode(0); 1648 focusController->setFocusedFrame(frame); 1649 static_cast<WebCore::Element*>(node)->focus(false); 1650 } 1651 1652 // Update mouse position 1653 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) 1654 { 1655 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, 1656 x, y, m_scrollOffsetX, m_scrollOffsetY); 1657 if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false) 1658 frame = m_mainFrame; 1659 // mouse event expects the position in the window coordinate 1660 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); 1661 // validNode will still return true if the node is null, as long as we have 1662 // a valid frame. Do not want to make a call on frame unless it is valid. 1663 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, 1664 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, 1665 false, WTF::currentTime()); 1666 frame->eventHandler()->handleMouseMoveEvent(mouseEvent); 1667 updateCacheOnNodeChange(); 1668 } 1669 1670 void WebViewCore::setSelection(int start, int end) 1671 { 1672 WebCore::Node* focus = currentFocus(); 1673 if (!focus) 1674 return; 1675 WebCore::RenderObject* renderer = focus->renderer(); 1676 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) 1677 return; 1678 WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer); 1679 if (start > end) { 1680 int temp = start; 1681 start = end; 1682 end = temp; 1683 } 1684 // Tell our EditorClient that this change was generated from the UI, so it 1685 // does not need to echo it to the UI. 1686 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1687 m_mainFrame->editor()->client()); 1688 client->setUiGeneratedSelectionChange(true); 1689 rtc->setSelectionRange(start, end); 1690 client->setUiGeneratedSelectionChange(false); 1691 WebCore::Frame* focusedFrame = focus->document()->frame(); 1692 focusedFrame->revealSelection(); 1693 setFocusControllerActive(focusedFrame, true); 1694 } 1695 1696 void WebViewCore::deleteSelection(int start, int end, int textGeneration) 1697 { 1698 setSelection(start, end); 1699 if (start == end) 1700 return; 1701 WebCore::Node* focus = currentFocus(); 1702 if (!focus) 1703 return; 1704 // Prevent our editor client from passing a message to change the 1705 // selection. 1706 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1707 m_mainFrame->editor()->client()); 1708 client->setUiGeneratedSelectionChange(true); 1709 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); 1710 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); 1711 key(down); 1712 key(up); 1713 client->setUiGeneratedSelectionChange(false); 1714 m_textGeneration = textGeneration; 1715 } 1716 1717 void WebViewCore::replaceTextfieldText(int oldStart, 1718 int oldEnd, const WebCore::String& replace, int start, int end, 1719 int textGeneration) 1720 { 1721 WebCore::Node* focus = currentFocus(); 1722 if (!focus) 1723 return; 1724 setSelection(oldStart, oldEnd); 1725 // Prevent our editor client from passing a message to change the 1726 // selection. 1727 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1728 m_mainFrame->editor()->client()); 1729 client->setUiGeneratedSelectionChange(true); 1730 WebCore::TypingCommand::insertText(focus->document(), replace, 1731 false); 1732 client->setUiGeneratedSelectionChange(false); 1733 setSelection(start, end); 1734 m_textGeneration = textGeneration; 1735 } 1736 1737 void WebViewCore::passToJs(int generation, const WebCore::String& current, 1738 const PlatformKeyboardEvent& event) 1739 { 1740 WebCore::Node* focus = currentFocus(); 1741 if (!focus) { 1742 DBG_NAV_LOG("!focus"); 1743 clearTextEntry(); 1744 return; 1745 } 1746 WebCore::RenderObject* renderer = focus->renderer(); 1747 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 1748 DBG_NAV_LOGD("renderer==%p || not text", renderer); 1749 clearTextEntry(); 1750 return; 1751 } 1752 // Block text field updates during a key press. 1753 m_blockTextfieldUpdates = true; 1754 // Also prevent our editor client from passing a message to change the 1755 // selection. 1756 EditorClientAndroid* client = static_cast<EditorClientAndroid*>( 1757 m_mainFrame->editor()->client()); 1758 client->setUiGeneratedSelectionChange(true); 1759 key(event); 1760 client->setUiGeneratedSelectionChange(false); 1761 m_blockTextfieldUpdates = false; 1762 m_textGeneration = generation; 1763 setFocusControllerActive(focus->document()->frame(), true); 1764 WebCore::RenderTextControl* renderText = 1765 static_cast<WebCore::RenderTextControl*>(renderer); 1766 WebCore::String test = renderText->text(); 1767 if (test == current) { 1768 DBG_NAV_LOG("test == current"); 1769 return; 1770 } 1771 // If the text changed during the key event, update the UI text field. 1772 updateTextfield(focus, false, test); 1773 } 1774 1775 void WebViewCore::scrollFocusedTextInput(float xPercent, int y) 1776 { 1777 WebCore::Node* focus = currentFocus(); 1778 if (!focus) { 1779 DBG_NAV_LOG("!focus"); 1780 clearTextEntry(); 1781 return; 1782 } 1783 WebCore::RenderObject* renderer = focus->renderer(); 1784 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { 1785 DBG_NAV_LOGD("renderer==%p || not text", renderer); 1786 clearTextEntry(); 1787 return; 1788 } 1789 WebCore::RenderTextControl* renderText = 1790 static_cast<WebCore::RenderTextControl*>(renderer); 1791 int x = (int) (xPercent * (renderText->scrollWidth() - 1792 renderText->clientWidth())); 1793 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, 1794 xPercent, renderText->scrollWidth(), renderText->clientWidth()); 1795 renderText->setScrollLeft(x); 1796 renderText->setScrollTop(y); 1797 } 1798 1799 void WebViewCore::setFocusControllerActive(WebCore::Frame* frame, bool active) 1800 { 1801 if (!frame) { 1802 WebCore::Node* focus = currentFocus(); 1803 if (focus) 1804 frame = focus->document()->frame(); 1805 else 1806 frame = m_mainFrame; 1807 } 1808 WebCore::FocusController* controller = frame->page()->focusController(); 1809 controller->setActive(active); 1810 controller->setFocused(active); 1811 } 1812 1813 void WebViewCore::saveDocumentState(WebCore::Frame* frame) 1814 { 1815 if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) 1816 frame = m_mainFrame; 1817 WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); 1818 1819 // item can be null when there is no offical URL for the current page. This happens 1820 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there 1821 // is no failing URL (common case is when content is loaded using data: scheme) 1822 if (item) { 1823 item->setDocumentState(frame->document()->formElementsState()); 1824 } 1825 } 1826 1827 // Convert a WebCore::String into an array of characters where the first 1828 // character represents the length, for easy conversion to java. 1829 static uint16_t* stringConverter(const WebCore::String& text) 1830 { 1831 size_t length = text.length(); 1832 uint16_t* itemName = new uint16_t[length+1]; 1833 itemName[0] = (uint16_t)length; 1834 uint16_t* firstChar = &(itemName[1]); 1835 memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length); 1836 return itemName; 1837 } 1838 1839 // Response to dropdown created for a listbox. 1840 class ListBoxReply : public WebCoreReply { 1841 public: 1842 ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view) 1843 : m_select(select) 1844 , m_frame(frame) 1845 , m_viewImpl(view) 1846 {} 1847 1848 // Response used if the listbox only allows single selection. 1849 // index is listIndex of the selected item, or -1 if nothing is selected. 1850 virtual void replyInt(int index) 1851 { 1852 if (-2 == index) { 1853 // Special value for cancel. Do nothing. 1854 return; 1855 } 1856 // If the select element no longer exists, due to a page change, etc, 1857 // silently return. 1858 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, 1859 m_frame, m_select)) 1860 return; 1861 // Use a pointer to HTMLSelectElement's superclass, where 1862 // listToOptionIndex is public. 1863 SelectElement* selectElement = m_select; 1864 int optionIndex = selectElement->listToOptionIndex(index); 1865 m_select->setSelectedIndex(optionIndex, true); 1866 m_select->dispatchFormControlChangeEvent(); 1867 m_viewImpl->contentInvalidate(m_select->getRect()); 1868 } 1869 1870 // Response if the listbox allows multiple selection. array stores the listIndices 1871 // of selected positions. 1872 virtual void replyIntArray(const int* array, int count) 1873 { 1874 // If the select element no longer exists, due to a page change, etc, 1875 // silently return. 1876 if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame, 1877 m_frame, m_select)) 1878 return; 1879 1880 // If count is 1 or 0, use replyInt. 1881 SkASSERT(count > 1); 1882 1883 const WTF::Vector<Element*>& items = m_select->listItems(); 1884 int totalItems = static_cast<int>(items.size()); 1885 // Keep track of the position of the value we are comparing against. 1886 int arrayIndex = 0; 1887 // The value we are comparing against. 1888 int selection = array[arrayIndex]; 1889 WebCore::HTMLOptionElement* option; 1890 for (int listIndex = 0; listIndex < totalItems; listIndex++) { 1891 if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) { 1892 option = static_cast<WebCore::HTMLOptionElement*>( 1893 items[listIndex]); 1894 if (listIndex == selection) { 1895 option->setSelectedState(true); 1896 arrayIndex++; 1897 if (arrayIndex == count) 1898 selection = -1; 1899 else 1900 selection = array[arrayIndex]; 1901 } else 1902 option->setSelectedState(false); 1903 } 1904 } 1905 m_select->dispatchFormControlChangeEvent(); 1906 m_viewImpl->contentInvalidate(m_select->getRect()); 1907 } 1908 private: 1909 // The select element associated with this listbox. 1910 WebCore::HTMLSelectElement* m_select; 1911 // The frame of this select element, to verify that it is valid. 1912 WebCore::Frame* m_frame; 1913 // For calling invalidate and checking the select element's validity 1914 WebViewCore* m_viewImpl; 1915 }; 1916 1917 // Create an array of java Strings. 1918 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) 1919 { 1920 jclass stringClass = env->FindClass("java/lang/String"); 1921 LOG_ASSERT(stringClass, "Could not find java/lang/String"); 1922 jobjectArray array = env->NewObjectArray(count, stringClass, 0); 1923 LOG_ASSERT(array, "Could not create new string array"); 1924 1925 for (size_t i = 0; i < count; i++) { 1926 jobject newString = env->NewString(&labels[i][1], labels[i][0]); 1927 env->SetObjectArrayElement(array, i, newString); 1928 env->DeleteLocalRef(newString); 1929 checkException(env); 1930 } 1931 env->DeleteLocalRef(stringClass); 1932 return array; 1933 } 1934 1935 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) { 1936 if (!chooser) 1937 return; 1938 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1939 jstring jName = (jstring) env->CallObjectMethod( 1940 m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser); 1941 checkException(env); 1942 const UChar* string = (const UChar*) env->GetStringChars(jName, NULL); 1943 if (!string) 1944 return; 1945 WebCore::String webcoreString = to_string(env, jName); 1946 env->ReleaseStringChars(jName, string); 1947 chooser->chooseFile(webcoreString); 1948 } 1949 1950 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, 1951 bool multiple, const int selected[], size_t selectedCountOrSelection) 1952 { 1953 // If m_popupReply is not null, then we already have a list showing. 1954 if (m_popupReply != 0) 1955 return; 1956 1957 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); 1958 1959 // Create an array of java Strings for the drop down. 1960 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1961 jobjectArray labelArray = makeLabelArray(env, labels, count); 1962 1963 // Create an array determining whether each item is enabled. 1964 jintArray enabledArray = env->NewIntArray(enabledCount); 1965 checkException(env); 1966 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); 1967 checkException(env); 1968 for (size_t i = 0; i < enabledCount; i++) { 1969 ptrArray[i] = enabled[i]; 1970 } 1971 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); 1972 checkException(env); 1973 1974 if (multiple) { 1975 // Pass up an array representing which items are selected. 1976 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); 1977 checkException(env); 1978 jint* selArray = env->GetIntArrayElements(selectedArray, 0); 1979 checkException(env); 1980 for (size_t i = 0; i < selectedCountOrSelection; i++) { 1981 selArray[i] = selected[i]; 1982 } 1983 env->ReleaseIntArrayElements(selectedArray, selArray, 0); 1984 1985 env->CallVoidMethod(m_javaGlue->object(env).get(), 1986 m_javaGlue->m_requestListBox, labelArray, enabledArray, 1987 selectedArray); 1988 env->DeleteLocalRef(selectedArray); 1989 } else { 1990 // Pass up the single selection. 1991 env->CallVoidMethod(m_javaGlue->object(env).get(), 1992 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, 1993 selectedCountOrSelection); 1994 } 1995 1996 env->DeleteLocalRef(labelArray); 1997 env->DeleteLocalRef(enabledArray); 1998 checkException(env); 1999 2000 Retain(reply); 2001 m_popupReply = reply; 2002 } 2003 2004 bool WebViewCore::key(const PlatformKeyboardEvent& event) 2005 { 2006 WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler(); 2007 WebCore::Node* focusNode = currentFocus(); 2008 if (focusNode) 2009 eventHandler = focusNode->document()->frame()->eventHandler(); 2010 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", 2011 event.keyIdentifier().utf8().data(), event.unichar(), focusNode); 2012 return eventHandler->keyEvent(event); 2013 } 2014 2015 // For when the user clicks the trackball 2016 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) { 2017 if (!node) { 2018 WebCore::IntPoint pt = m_mousePos; 2019 pt.move(m_scrollOffsetX, m_scrollOffsetY); 2020 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> 2021 hitTestResultAtPoint(pt, false); 2022 node = hitTestResult.innerNode(); 2023 frame = node->document()->frame(); 2024 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" 2025 " node=%p", m_mousePos.x(), m_mousePos.y(), 2026 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); 2027 } 2028 if (node) { 2029 EditorClientAndroid* client 2030 = static_cast<EditorClientAndroid*>( 2031 m_mainFrame->editor()->client()); 2032 client->setShouldChangeSelectedRange(false); 2033 handleMouseClick(frame, node); 2034 client->setShouldChangeSelectedRange(true); 2035 } 2036 } 2037 2038 #if USE(ACCELERATED_COMPOSITING) 2039 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const 2040 { 2041 RenderView* contentRenderer = m_mainFrame->contentRenderer(); 2042 if (!contentRenderer) 2043 return 0; 2044 return static_cast<GraphicsLayerAndroid*>( 2045 contentRenderer->compositor()->rootPlatformLayer()); 2046 } 2047 #endif 2048 2049 bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState) 2050 { 2051 bool preventDefault = false; 2052 2053 #if USE(ACCELERATED_COMPOSITING) 2054 GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); 2055 if (rootLayer) 2056 rootLayer->pauseDisplay(true); 2057 #endif 2058 2059 #if ENABLE(TOUCH_EVENTS) // Android 2060 WebCore::TouchEventType type = WebCore::TouchStart; 2061 WebCore::PlatformTouchPoint::State touchState = WebCore::PlatformTouchPoint::TouchPressed; 2062 switch (action) { 2063 case 0: // MotionEvent.ACTION_DOWN 2064 type = WebCore::TouchStart; 2065 break; 2066 case 1: // MotionEvent.ACTION_UP 2067 type = WebCore::TouchEnd; 2068 touchState = WebCore::PlatformTouchPoint::TouchReleased; 2069 break; 2070 case 2: // MotionEvent.ACTION_MOVE 2071 type = WebCore::TouchMove; 2072 touchState = WebCore::PlatformTouchPoint::TouchMoved; 2073 break; 2074 case 3: // MotionEvent.ACTION_CANCEL 2075 type = WebCore::TouchCancel; 2076 touchState = WebCore::PlatformTouchPoint::TouchCancelled; 2077 break; 2078 case 0x100: // WebViewCore.ACTION_LONGPRESS 2079 type = WebCore::TouchLongPress; 2080 touchState = WebCore::PlatformTouchPoint::TouchPressed; 2081 break; 2082 case 0x200: // WebViewCore.ACTION_DOUBLETAP 2083 type = WebCore::TouchDoubleTap; 2084 touchState = WebCore::PlatformTouchPoint::TouchPressed; 2085 break; 2086 default: 2087 // We do not support other kinds of touch event inside WebCore 2088 // at the moment. 2089 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); 2090 return 0; 2091 } 2092 2093 // Track previous touch and if stationary set the state. 2094 WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY); 2095 2096 // handleTouchEvent() in EventHandler.cpp doesn't handle TouchStationary, which 2097 // causes preventDefault be false when it returns. As our Java side may continue 2098 // process the events if WebKit doesn't, it can cause unexpected result. 2099 // if (type == WebCore::TouchMove && pt == m_lastTouchPoint) 2100 // touchState = WebCore::PlatformTouchPoint::TouchStationary; 2101 2102 m_lastTouchPoint = pt; 2103 2104 WebCore::PlatformTouchEvent te(pt, type, touchState, metaState); 2105 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); 2106 #endif 2107 2108 #if USE(ACCELERATED_COMPOSITING) 2109 if (rootLayer) 2110 rootLayer->pauseDisplay(false); 2111 #endif 2112 return preventDefault; 2113 } 2114 2115 void WebViewCore::touchUp(int touchGeneration, 2116 WebCore::Frame* frame, WebCore::Node* node, int x, int y) 2117 { 2118 if (m_touchGeneration > touchGeneration) { 2119 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" 2120 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); 2121 return; // short circuit if a newer touch has been generated 2122 } 2123 // This moves m_mousePos to the correct place, and handleMouseClick uses 2124 // m_mousePos to determine where the click happens. 2125 moveMouse(frame, x, y); 2126 m_lastGeneration = touchGeneration; 2127 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { 2128 frame->loader()->resetMultipleFormSubmissionProtection(); 2129 } 2130 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" 2131 " x=%d y=%d", touchGeneration, frame, node, x, y); 2132 handleMouseClick(frame, node); 2133 } 2134 2135 // Common code for both clicking with the trackball and touchUp 2136 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr) 2137 { 2138 bool valid = framePtr == NULL 2139 || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); 2140 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); 2141 if (valid && nodePtr) { 2142 // Need to special case area tags because an image map could have an area element in the middle 2143 // so when attempting to get the default, the point chosen would be follow the wrong link. 2144 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { 2145 webFrame->setUserInitiatedClick(true); 2146 nodePtr->dispatchSimulatedClick(0, true, true); 2147 webFrame->setUserInitiatedClick(false); 2148 DBG_NAV_LOG("area"); 2149 return true; 2150 } 2151 WebCore::RenderObject* renderer = nodePtr->renderer(); 2152 if (renderer && (renderer->isMenuList() || renderer->isListBox())) { 2153 WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr); 2154 const WTF::Vector<WebCore::Element*>& listItems = select->listItems(); 2155 SkTDArray<const uint16_t*> names; 2156 // Possible values for enabledArray. Keep in Sync with values in 2157 // InvokeListBox.Container in WebView.java 2158 enum OptionStatus { 2159 OPTGROUP = -1, 2160 OPTION_DISABLED = 0, 2161 OPTION_ENABLED = 1, 2162 }; 2163 SkTDArray<int> enabledArray; 2164 SkTDArray<int> selectedArray; 2165 int size = listItems.size(); 2166 bool multiple = select->multiple(); 2167 for (int i = 0; i < size; i++) { 2168 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) { 2169 WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]); 2170 *names.append() = stringConverter(option->textIndentedToRespectGroupLabel()); 2171 *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED; 2172 if (multiple && option->selected()) 2173 *selectedArray.append() = i; 2174 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) { 2175 WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]); 2176 *names.append() = stringConverter(optGroup->groupLabelText()); 2177 *enabledArray.append() = OPTGROUP; 2178 } 2179 } 2180 WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this); 2181 // Use a pointer to HTMLSelectElement's superclass, where 2182 // optionToListIndex is public. 2183 SelectElement* selectElement = select; 2184 listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(), 2185 multiple, selectedArray.begin(), multiple ? selectedArray.count() : 2186 selectElement->optionToListIndex(select->selectedIndex())); 2187 DBG_NAV_LOG("menu list"); 2188 return true; 2189 } 2190 } 2191 if (!valid || !framePtr) 2192 framePtr = m_mainFrame; 2193 webFrame->setUserInitiatedClick(true); 2194 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, 2195 WebCore::MouseEventPressed, 1, false, false, false, false, 2196 WTF::currentTime()); 2197 // ignore the return from as it will return true if the hit point can trigger selection change 2198 framePtr->eventHandler()->handleMousePressEvent(mouseDown); 2199 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, 2200 WebCore::MouseEventReleased, 1, false, false, false, false, 2201 WTF::currentTime()); 2202 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); 2203 webFrame->setUserInitiatedClick(false); 2204 2205 // If the user clicked on a textfield, make the focusController active 2206 // so we show the blinking cursor. 2207 WebCore::Node* focusNode = currentFocus(); 2208 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), 2209 m_mousePos.y(), focusNode, handled ? "true" : "false"); 2210 if (focusNode) { 2211 WebCore::RenderObject* renderer = focusNode->renderer(); 2212 if (renderer && (renderer->isTextField() || renderer->isTextArea())) { 2213 bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode)) 2214 ->readOnly(); 2215 setFocusControllerActive(framePtr, ime); 2216 if (ime) { 2217 RenderTextControl* rtc 2218 = static_cast<RenderTextControl*> (renderer); 2219 requestKeyboardWithSelection(focusNode, rtc->selectionStart(), 2220 rtc->selectionEnd()); 2221 } else { 2222 requestKeyboard(false); 2223 } 2224 } 2225 } 2226 return handled; 2227 } 2228 2229 void WebViewCore::popupReply(int index) 2230 { 2231 if (m_popupReply) { 2232 m_popupReply->replyInt(index); 2233 Release(m_popupReply); 2234 m_popupReply = 0; 2235 } 2236 } 2237 2238 void WebViewCore::popupReply(const int* array, int count) 2239 { 2240 if (m_popupReply) { 2241 m_popupReply->replyIntArray(array, count); 2242 Release(m_popupReply); 2243 m_popupReply = NULL; 2244 } 2245 } 2246 2247 void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID, int msgLevel) { 2248 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2249 jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length()); 2250 jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length()); 2251 env->CallVoidMethod(m_javaGlue->object(env).get(), 2252 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, 2253 jSourceIDStr, msgLevel); 2254 env->DeleteLocalRef(jMessageStr); 2255 env->DeleteLocalRef(jSourceIDStr); 2256 checkException(env); 2257 } 2258 2259 void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text) 2260 { 2261 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2262 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length()); 2263 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2264 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); 2265 env->DeleteLocalRef(jInputStr); 2266 env->DeleteLocalRef(jUrlStr); 2267 checkException(env); 2268 } 2269 2270 void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) 2271 { 2272 #if ENABLE(DATABASE) 2273 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2274 jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length()); 2275 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2276 env->CallVoidMethod(m_javaGlue->object(env).get(), 2277 m_javaGlue->m_exceededDatabaseQuota, jUrlStr, 2278 jDatabaseIdentifierStr, currentQuota, estimatedSize); 2279 env->DeleteLocalRef(jDatabaseIdentifierStr); 2280 env->DeleteLocalRef(jUrlStr); 2281 checkException(env); 2282 #endif 2283 } 2284 2285 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) 2286 { 2287 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 2288 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2289 env->CallVoidMethod(m_javaGlue->object(env).get(), 2290 m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); 2291 checkException(env); 2292 #endif 2293 } 2294 2295 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) 2296 { 2297 m_groupForVisitedLinks = group; 2298 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2299 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks); 2300 checkException(env); 2301 } 2302 2303 void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin) 2304 { 2305 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2306 jstring originString = env->NewString((unsigned short *)origin.characters(), origin.length()); 2307 env->CallVoidMethod(m_javaGlue->object(env).get(), 2308 m_javaGlue->m_geolocationPermissionsShowPrompt, 2309 originString); 2310 env->DeleteLocalRef(originString); 2311 checkException(env); 2312 } 2313 2314 void WebViewCore::geolocationPermissionsHidePrompt() 2315 { 2316 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2317 env->CallVoidMethod(m_javaGlue->object(env).get(), 2318 m_javaGlue->m_geolocationPermissionsHidePrompt); 2319 checkException(env); 2320 } 2321 2322 bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text) 2323 { 2324 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2325 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length()); 2326 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2327 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); 2328 env->DeleteLocalRef(jInputStr); 2329 env->DeleteLocalRef(jUrlStr); 2330 checkException(env); 2331 return result; 2332 } 2333 2334 bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result) 2335 { 2336 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2337 jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length()); 2338 jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length()); 2339 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2340 jstring returnVal = (jstring) env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr); 2341 // If returnVal is null, it means that the user cancelled the dialog. 2342 if (!returnVal) 2343 return false; 2344 2345 result = to_string(env, returnVal); 2346 env->DeleteLocalRef(jInputStr); 2347 env->DeleteLocalRef(jDefaultStr); 2348 env->DeleteLocalRef(jUrlStr); 2349 checkException(env); 2350 return true; 2351 } 2352 2353 bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message) 2354 { 2355 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2356 jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length()); 2357 jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length()); 2358 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); 2359 env->DeleteLocalRef(jInputStr); 2360 env->DeleteLocalRef(jUrlStr); 2361 checkException(env); 2362 return result; 2363 } 2364 2365 bool WebViewCore::jsInterrupt() 2366 { 2367 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2368 jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt); 2369 checkException(env); 2370 return result; 2371 } 2372 2373 AutoJObject 2374 WebViewCore::getJavaObject() 2375 { 2376 return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj); 2377 } 2378 2379 jobject 2380 WebViewCore::getWebViewJavaObject() 2381 { 2382 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2383 return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView); 2384 } 2385 2386 void WebViewCore::updateTextSelection() { 2387 WebCore::Node* focusNode = currentFocus(); 2388 if (!focusNode) 2389 return; 2390 RenderObject* renderer = focusNode->renderer(); 2391 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) 2392 return; 2393 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); 2394 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2395 env->CallVoidMethod(m_javaGlue->object(env).get(), 2396 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), 2397 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); 2398 checkException(env); 2399 } 2400 2401 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, 2402 const WebCore::String& text) 2403 { 2404 if (m_blockTextfieldUpdates) 2405 return; 2406 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2407 if (changeToPassword) { 2408 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, 2409 (int) ptr, true, 0, m_textGeneration); 2410 checkException(env); 2411 return; 2412 } 2413 int length = text.length(); 2414 jstring string = env->NewString((unsigned short *) text.characters(), length); 2415 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, 2416 (int) ptr, false, string, m_textGeneration); 2417 env->DeleteLocalRef(string); 2418 checkException(env); 2419 } 2420 2421 void WebViewCore::clearTextEntry() 2422 { 2423 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2424 env->CallVoidMethod(m_javaGlue->object(env).get(), 2425 m_javaGlue->m_clearTextEntry); 2426 } 2427 2428 void WebViewCore::setBackgroundColor(SkColor c) 2429 { 2430 WebCore::FrameView* view = m_mainFrame->view(); 2431 if (!view) 2432 return; 2433 2434 // need (int) cast to find the right constructor 2435 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), 2436 (int)SkColorGetB(c), (int)SkColorGetA(c)); 2437 view->setBaseBackgroundColor(bcolor); 2438 2439 // Background color of 0 indicates we want a transparent background 2440 if (c == 0) 2441 view->setTransparent(true); 2442 } 2443 2444 jclass WebViewCore::getPluginClass(const WebCore::String& libName, const char* className) 2445 { 2446 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2447 2448 jstring libString = env->NewString(libName.characters(), libName.length()); 2449 jstring classString = env->NewStringUTF(className); 2450 jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(), 2451 m_javaGlue->m_getPluginClass, 2452 libString, classString); 2453 checkException(env); 2454 2455 // cleanup unneeded local JNI references 2456 env->DeleteLocalRef(libString); 2457 env->DeleteLocalRef(classString); 2458 2459 if (pluginClass != NULL) { 2460 return static_cast<jclass>(pluginClass); 2461 } else { 2462 return NULL; 2463 } 2464 } 2465 2466 void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp) 2467 { 2468 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2469 AutoJObject obj = m_javaGlue->object(env); 2470 2471 env->CallVoidMethod(obj.get(), 2472 m_javaGlue->m_showFullScreenPlugin, childView, (int)npp); 2473 checkException(env); 2474 } 2475 2476 void WebViewCore::hideFullScreenPlugin() 2477 { 2478 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2479 env->CallVoidMethod(m_javaGlue->object(env).get(), 2480 m_javaGlue->m_hideFullScreenPlugin); 2481 checkException(env); 2482 } 2483 2484 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) 2485 { 2486 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2487 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), 2488 m_javaGlue->m_addSurface, 2489 view, x, y, width, height); 2490 checkException(env); 2491 return result; 2492 } 2493 2494 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) 2495 { 2496 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2497 env->CallVoidMethod(m_javaGlue->object(env).get(), 2498 m_javaGlue->m_updateSurface, childView, 2499 x, y, width, height); 2500 checkException(env); 2501 } 2502 2503 void WebViewCore::destroySurface(jobject childView) 2504 { 2505 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2506 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView); 2507 checkException(env); 2508 } 2509 2510 jobject WebViewCore::getContext() 2511 { 2512 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2513 AutoJObject obj = m_javaGlue->object(env); 2514 2515 jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext); 2516 checkException(env); 2517 return result; 2518 } 2519 2520 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 2521 const IntRect& originalAbsoluteBounds) 2522 { 2523 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); 2524 if (!valid) 2525 return false; 2526 RenderObject* renderer = node->renderer(); 2527 if (!renderer) 2528 return false; 2529 IntRect absBounds = node->hasTagName(HTMLNames::areaTag) 2530 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node)) 2531 : renderer->absoluteBoundingBoxRect(); 2532 return absBounds == originalAbsoluteBounds; 2533 } 2534 2535 void WebViewCore::showRect(int left, int top, int width, int height, 2536 int contentWidth, int contentHeight, float xPercentInDoc, 2537 float xPercentInView, float yPercentInDoc, float yPercentInView) 2538 { 2539 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2540 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect, 2541 left, top, width, height, contentWidth, contentHeight, 2542 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); 2543 checkException(env); 2544 } 2545 2546 void WebViewCore::centerFitRect(int x, int y, int width, int height) 2547 { 2548 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2549 env->CallVoidMethod(m_javaGlue->object(env).get(), 2550 m_javaGlue->m_centerFitRect, x, y, width, height); 2551 checkException(env); 2552 } 2553 2554 2555 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) 2556 { 2557 JNIEnv* env = JSC::Bindings::getJNIEnv(); 2558 env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes, 2559 horizontalMode, verticalMode); 2560 checkException(env); 2561 } 2562 2563 //---------------------------------------------------------------------- 2564 // Native JNI methods 2565 //---------------------------------------------------------------------- 2566 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string) 2567 { 2568 int length = string.length(); 2569 if (!length) 2570 return 0; 2571 jstring ret = env->NewString((jchar *)string.characters(), length); 2572 env->DeleteLocalRef(ret); 2573 return ret; 2574 } 2575 2576 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, 2577 int nodePointer) 2578 { 2579 return WebCoreStringToJString(env, GET_NATIVE_VIEW(env, obj)->requestLabel( 2580 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); 2581 } 2582 2583 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) 2584 { 2585 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); 2586 } 2587 2588 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, 2589 jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight, 2590 jint anchorX, jint anchorY, jboolean ignoreHeight) 2591 { 2592 #ifdef ANDROID_INSTRUMENT 2593 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2594 #endif 2595 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2596 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); 2597 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); 2598 viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, scale, 2599 realScreenWidth, screenHeight, anchorX, anchorY, ignoreHeight); 2600 } 2601 2602 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y) 2603 { 2604 #ifdef ANDROID_INSTRUMENT 2605 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2606 #endif 2607 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2608 LOG_ASSERT(viewImpl, "need viewImpl"); 2609 2610 viewImpl->setScrollOffset(gen, x, y); 2611 } 2612 2613 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, 2614 jint v) 2615 { 2616 #ifdef ANDROID_INSTRUMENT 2617 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2618 #endif 2619 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2620 LOG_ASSERT(viewImpl, "need viewImpl"); 2621 2622 viewImpl->setGlobalBounds(x, y, h, v); 2623 } 2624 2625 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, 2626 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, 2627 jboolean isDown) 2628 { 2629 #ifdef ANDROID_INSTRUMENT 2630 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2631 #endif 2632 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, 2633 unichar, repeatCount, isDown, isShift, isAlt, isSym)); 2634 } 2635 2636 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr) 2637 { 2638 #ifdef ANDROID_INSTRUMENT 2639 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2640 #endif 2641 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2642 LOG_ASSERT(viewImpl, "viewImpl not set in Click"); 2643 2644 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), 2645 reinterpret_cast<WebCore::Node*>(nodePtr)); 2646 } 2647 2648 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, 2649 jint textGeneration) 2650 { 2651 #ifdef ANDROID_INSTRUMENT 2652 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2653 #endif 2654 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2655 viewImpl->deleteSelection(start, end, textGeneration); 2656 } 2657 2658 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) 2659 { 2660 #ifdef ANDROID_INSTRUMENT 2661 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2662 #endif 2663 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2664 viewImpl->setSelection(start, end); 2665 } 2666 2667 2668 static void ReplaceTextfieldText(JNIEnv *env, jobject obj, 2669 jint oldStart, jint oldEnd, jstring replace, jint start, jint end, 2670 jint textGeneration) 2671 { 2672 #ifdef ANDROID_INSTRUMENT 2673 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2674 #endif 2675 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2676 WebCore::String webcoreString = to_string(env, replace); 2677 viewImpl->replaceTextfieldText(oldStart, 2678 oldEnd, webcoreString, start, end, textGeneration); 2679 } 2680 2681 static void PassToJs(JNIEnv *env, jobject obj, 2682 jint generation, jstring currentText, jint keyCode, 2683 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) 2684 { 2685 #ifdef ANDROID_INSTRUMENT 2686 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2687 #endif 2688 WebCore::String current = to_string(env, currentText); 2689 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, 2690 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); 2691 } 2692 2693 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, 2694 jint y) 2695 { 2696 #ifdef ANDROID_INSTRUMENT 2697 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2698 #endif 2699 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2700 viewImpl->scrollFocusedTextInput(xPercent, y); 2701 } 2702 2703 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) 2704 { 2705 #ifdef ANDROID_INSTRUMENT 2706 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2707 #endif 2708 LOGV("webviewcore::nativeSetFocusControllerActive()\n"); 2709 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2710 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); 2711 viewImpl->setFocusControllerActive(0, active); 2712 } 2713 2714 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) 2715 { 2716 #ifdef ANDROID_INSTRUMENT 2717 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2718 #endif 2719 LOGV("webviewcore::nativeSaveDocumentState()\n"); 2720 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2721 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); 2722 viewImpl->saveDocumentState((WebCore::Frame*) frame); 2723 } 2724 2725 void WebViewCore::addVisitedLink(const UChar* string, int length) 2726 { 2727 if (m_groupForVisitedLinks) 2728 m_groupForVisitedLinks->addVisitedLink(string, length); 2729 } 2730 2731 static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) 2732 { 2733 #ifdef ANDROID_INSTRUMENT 2734 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2735 #endif 2736 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2737 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); 2738 SkIPoint nativePt; 2739 bool result = viewImpl->recordContent(nativeRegion, &nativePt); 2740 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); 2741 return result; 2742 } 2743 2744 static void SplitContent(JNIEnv *env, jobject obj) 2745 { 2746 #ifdef ANDROID_INSTRUMENT 2747 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2748 #endif 2749 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2750 viewImpl->splitContent(); 2751 } 2752 2753 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) 2754 { 2755 #ifdef ANDROID_INSTRUMENT 2756 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2757 #endif 2758 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2759 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); 2760 viewImpl->popupReply(choice); 2761 } 2762 2763 // Set aside a predetermined amount of space in which to place the listbox 2764 // choices, to avoid unnecessary allocations. 2765 // The size here is arbitrary. We want the size to be at least as great as the 2766 // number of items in the average multiple-select listbox. 2767 #define PREPARED_LISTBOX_STORAGE 10 2768 2769 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, 2770 jint size) 2771 { 2772 #ifdef ANDROID_INSTRUMENT 2773 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2774 #endif 2775 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2776 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); 2777 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); 2778 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); 2779 int* array = storage.get(); 2780 int count = 0; 2781 for (int i = 0; i < size; i++) { 2782 if (ptrArray[i]) { 2783 array[count++] = i; 2784 } 2785 } 2786 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); 2787 viewImpl->popupReply(array, count); 2788 } 2789 2790 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, 2791 jboolean caseInsensitive) 2792 { 2793 #ifdef ANDROID_INSTRUMENT 2794 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2795 #endif 2796 if (!addr) 2797 return 0; 2798 int length = env->GetStringLength(addr); 2799 if (!length) 2800 return 0; 2801 const jchar* addrChars = env->GetStringChars(addr, 0); 2802 int start, end; 2803 bool success = CacheBuilder::FindAddress(addrChars, length, 2804 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; 2805 jstring ret = 0; 2806 if (success) { 2807 ret = env->NewString((jchar*) addrChars + start, end - start); 2808 env->DeleteLocalRef(ret); 2809 } 2810 env->ReleaseStringChars(addr, addrChars); 2811 return ret; 2812 } 2813 2814 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, jint y, jint metaState) 2815 { 2816 #ifdef ANDROID_INSTRUMENT 2817 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2818 #endif 2819 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2820 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2821 return viewImpl->handleTouchEvent(action, x, y, metaState); 2822 } 2823 2824 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, 2825 jint frame, jint node, jint x, jint y) 2826 { 2827 #ifdef ANDROID_INSTRUMENT 2828 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2829 #endif 2830 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2831 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2832 viewImpl->touchUp(touchGeneration, 2833 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); 2834 } 2835 2836 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame, 2837 jint node) 2838 { 2839 #ifdef ANDROID_INSTRUMENT 2840 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2841 #endif 2842 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2843 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2844 WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame, 2845 (WebCore::Node*) node); 2846 if (!result.isEmpty()) 2847 return WebCoreStringToJString(env, result); 2848 return 0; 2849 } 2850 2851 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint frame, 2852 jint node) 2853 { 2854 #ifdef ANDROID_INSTRUMENT 2855 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2856 #endif 2857 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2858 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2859 WebCore::String result = viewImpl->retrieveAnchorText((WebCore::Frame*) frame, 2860 (WebCore::Node*) node); 2861 if (!result.isEmpty()) 2862 return WebCoreStringToJString(env, result); 2863 return 0; 2864 } 2865 2866 2867 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) 2868 { 2869 #ifdef ANDROID_INSTRUMENT 2870 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2871 #endif 2872 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2873 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2874 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); 2875 } 2876 2877 static void MoveMouse(JNIEnv *env, jobject obj, jint frame, 2878 jint x, jint y) 2879 { 2880 #ifdef ANDROID_INSTRUMENT 2881 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2882 #endif 2883 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2884 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2885 viewImpl->moveMouse((WebCore::Frame*) frame, x, y); 2886 } 2887 2888 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, 2889 jint frame, jint x, jint y) 2890 { 2891 #ifdef ANDROID_INSTRUMENT 2892 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2893 #endif 2894 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2895 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2896 viewImpl->moveMouseIfLatest(moveGeneration, 2897 (WebCore::Frame*) frame, x, y); 2898 } 2899 2900 static void UpdateFrameCache(JNIEnv *env, jobject obj) 2901 { 2902 #ifdef ANDROID_INSTRUMENT 2903 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2904 #endif 2905 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2906 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2907 viewImpl->updateFrameCache(); 2908 } 2909 2910 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) 2911 { 2912 #ifdef ANDROID_INSTRUMENT 2913 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2914 #endif 2915 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2916 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2917 2918 WebCore::Frame* frame = viewImpl->mainFrame(); 2919 if (frame) { 2920 WebCore::Document* document = frame->document(); 2921 if (document) { 2922 WebCore::RenderObject* renderer = document->renderer(); 2923 if (renderer && renderer->isRenderView()) { 2924 return renderer->minPrefWidth(); 2925 } 2926 } 2927 } 2928 return 0; 2929 } 2930 2931 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) 2932 { 2933 #ifdef ANDROID_INSTRUMENT 2934 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2935 #endif 2936 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2937 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2938 2939 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); 2940 if (!s) 2941 return; 2942 2943 #ifdef ANDROID_META_SUPPORT 2944 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); 2945 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); 2946 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); 2947 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); 2948 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); 2949 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); 2950 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); 2951 #endif 2952 } 2953 2954 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color) 2955 { 2956 #ifdef ANDROID_INSTRUMENT 2957 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 2958 #endif 2959 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2960 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2961 2962 viewImpl->setBackgroundColor((SkColor) color); 2963 } 2964 2965 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) 2966 { 2967 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2968 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2969 2970 viewImpl->dumpDomTree(useFile); 2971 } 2972 2973 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) 2974 { 2975 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2976 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2977 2978 viewImpl->dumpRenderTree(useFile); 2979 } 2980 2981 static void DumpNavTree(JNIEnv *env, jobject obj) 2982 { 2983 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 2984 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 2985 2986 viewImpl->dumpNavTree(); 2987 } 2988 2989 static void DumpV8Counters(JNIEnv*, jobject) 2990 { 2991 #if USE(V8) 2992 #ifdef ANDROID_INSTRUMENT 2993 V8Counters::dumpCounters(); 2994 #endif 2995 #endif 2996 } 2997 2998 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) 2999 { 3000 #if USE(V8) 3001 WebCore::String flagsString = to_string(env, flags); 3002 WebCore::CString utf8String = flagsString.utf8(); 3003 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); 3004 #endif 3005 } 3006 3007 3008 // Called from the Java side to set a new quota for the origin or new appcache 3009 // max size in response to a notification that the original quota was exceeded or 3010 // that the appcache has reached its maximum size. 3011 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { 3012 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) 3013 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3014 Frame* frame = viewImpl->mainFrame(); 3015 3016 // The main thread is blocked awaiting this response, so now we can wake it 3017 // up. 3018 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 3019 chromeC->wakeUpMainThreadWithNewQuota(quota); 3020 #endif 3021 } 3022 3023 // Called from Java to provide a Geolocation permission state for the specified origin. 3024 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) { 3025 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3026 Frame* frame = viewImpl->mainFrame(); 3027 3028 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); 3029 chromeClient->provideGeolocationPermissions(to_string(env, origin), allow, remember); 3030 } 3031 3032 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { 3033 #ifdef ANDROID_INSTRUMENT 3034 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3035 #endif 3036 WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme)); 3037 } 3038 3039 static void ClearContent(JNIEnv *env, jobject obj) 3040 { 3041 #ifdef ANDROID_INSTRUMENT 3042 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3043 #endif 3044 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3045 viewImpl->clearContent(); 3046 } 3047 3048 static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict) 3049 { 3050 #ifdef ANDROID_INSTRUMENT 3051 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); 3052 #endif 3053 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3054 if (!viewImpl) 3055 return; 3056 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); 3057 viewImpl->copyContentToPicture(picture); 3058 } 3059 3060 static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color) 3061 { 3062 // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter 3063 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3064 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); 3065 return viewImpl->drawContent(canvas, color); 3066 } 3067 3068 static bool FocusBoundsChanged(JNIEnv* env, jobject obj) 3069 { 3070 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); 3071 } 3072 3073 static bool PictureReady(JNIEnv* env, jobject obj) 3074 { 3075 return GET_NATIVE_VIEW(env, obj)->pictureReady(); 3076 } 3077 3078 static void Pause(JNIEnv* env, jobject obj) 3079 { 3080 // This is called for the foreground tab when the browser is put to the 3081 // background (and also for any tab when it is put to the background of the 3082 // browser). The browser can only be killed by the system when it is in the 3083 // background, so saving the Geolocation permission state now ensures that 3084 // is maintained when the browser is killed. 3085 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client(); 3086 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); 3087 chromeClientAndroid->storeGeolocationPermissions(); 3088 3089 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 3090 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 3091 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 3092 if (geolocation) 3093 geolocation->suspend(); 3094 } 3095 3096 ANPEvent event; 3097 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 3098 event.data.lifecycle.action = kPause_ANPLifecycleAction; 3099 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 3100 3101 GET_NATIVE_VIEW(env, obj)->setIsPaused(true); 3102 } 3103 3104 static void Resume(JNIEnv* env, jobject obj) 3105 { 3106 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); 3107 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { 3108 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); 3109 if (geolocation) 3110 geolocation->resume(); 3111 } 3112 3113 ANPEvent event; 3114 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 3115 event.data.lifecycle.action = kResume_ANPLifecycleAction; 3116 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 3117 3118 GET_NATIVE_VIEW(env, obj)->setIsPaused(false); 3119 } 3120 3121 static void FreeMemory(JNIEnv* env, jobject obj) 3122 { 3123 ANPEvent event; 3124 SkANP::InitEvent(&event, kLifecycle_ANPEventType); 3125 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; 3126 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); 3127 } 3128 3129 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) 3130 { 3131 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3132 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); 3133 3134 jobjectArray array = static_cast<jobjectArray>(hist); 3135 3136 jsize len = env->GetArrayLength(array); 3137 for (jsize i = 0; i < len; i++) { 3138 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); 3139 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL)); 3140 jsize len = env->GetStringLength(item); 3141 viewImpl->addVisitedLink(str, len); 3142 env->ReleaseStringChars(item, str); 3143 env->DeleteLocalRef(item); 3144 } 3145 } 3146 3147 // Notification from the UI thread that the plugin's full-screen surface has been discarded 3148 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) 3149 { 3150 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); 3151 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); 3152 if (plugin) 3153 plugin->exitFullScreen(false); 3154 } 3155 3156 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 3157 { 3158 int L, T, R, B; 3159 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 3160 return WebCore::IntRect(L, T, R - L, B - T); 3161 } 3162 3163 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, 3164 jobject rect) 3165 { 3166 IntRect nativeRect = jrect_to_webrect(env, rect); 3167 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( 3168 reinterpret_cast<Frame*>(frame), 3169 reinterpret_cast<Node*>(node), nativeRect); 3170 } 3171 3172 // ---------------------------------------------------------------------------- 3173 3174 /* 3175 * JNI registration. 3176 */ 3177 static JNINativeMethod gJavaWebViewCoreMethods[] = { 3178 { "nativeClearContent", "()V", 3179 (void*) ClearContent }, 3180 { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V", 3181 (void*) CopyContentToPicture }, 3182 { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z", 3183 (void*) DrawContent } , 3184 { "nativeFocusBoundsChanged", "()Z", 3185 (void*) FocusBoundsChanged } , 3186 { "nativeKey", "(IIIZZZZ)Z", 3187 (void*) Key }, 3188 { "nativeClick", "(II)V", 3189 (void*) Click }, 3190 { "nativePictureReady", "()Z", 3191 (void*) PictureReady } , 3192 { "nativeSendListBoxChoices", "([ZI)V", 3193 (void*) SendListBoxChoices }, 3194 { "nativeSendListBoxChoice", "(I)V", 3195 (void*) SendListBoxChoice }, 3196 { "nativeSetSize", "(IIIFIIIIZ)V", 3197 (void*) SetSize }, 3198 { "nativeSetScrollOffset", "(III)V", 3199 (void*) SetScrollOffset }, 3200 { "nativeSetGlobalBounds", "(IIII)V", 3201 (void*) SetGlobalBounds }, 3202 { "nativeSetSelection", "(II)V", 3203 (void*) SetSelection } , 3204 { "nativeDeleteSelection", "(III)V", 3205 (void*) DeleteSelection } , 3206 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", 3207 (void*) ReplaceTextfieldText } , 3208 { "nativeMoveFocus", "(II)V", 3209 (void*) MoveFocus }, 3210 { "nativeMoveMouse", "(III)V", 3211 (void*) MoveMouse }, 3212 { "nativeMoveMouseIfLatest", "(IIII)V", 3213 (void*) MoveMouseIfLatest }, 3214 { "passToJs", "(ILjava/lang/String;IIZZZZ)V", 3215 (void*) PassToJs }, 3216 { "nativeScrollFocusedTextInput", "(FI)V", 3217 (void*) ScrollFocusedTextInput }, 3218 { "nativeSetFocusControllerActive", "(Z)V", 3219 (void*) SetFocusControllerActive }, 3220 { "nativeSaveDocumentState", "(I)V", 3221 (void*) SaveDocumentState }, 3222 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", 3223 (void*) FindAddress }, 3224 { "nativeHandleTouchEvent", "(IIII)Z", 3225 (void*) HandleTouchEvent }, 3226 { "nativeTouchUp", "(IIIII)V", 3227 (void*) TouchUp }, 3228 { "nativeRetrieveHref", "(II)Ljava/lang/String;", 3229 (void*) RetrieveHref }, 3230 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", 3231 (void*) RetrieveAnchorText }, 3232 { "nativeUpdateFrameCache", "()V", 3233 (void*) UpdateFrameCache }, 3234 { "nativeGetContentMinPrefWidth", "()I", 3235 (void*) GetContentMinPrefWidth }, 3236 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z", 3237 (void*) RecordContent }, 3238 { "setViewportSettingsFromNative", "()V", 3239 (void*) SetViewportSettingsFromNative }, 3240 { "nativeSplitContent", "()V", 3241 (void*) SplitContent }, 3242 { "nativeSetBackgroundColor", "(I)V", 3243 (void*) SetBackgroundColor }, 3244 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", 3245 (void*) RegisterURLSchemeAsLocal }, 3246 { "nativeDumpDomTree", "(Z)V", 3247 (void*) DumpDomTree }, 3248 { "nativeDumpRenderTree", "(Z)V", 3249 (void*) DumpRenderTree }, 3250 { "nativeDumpNavTree", "()V", 3251 (void*) DumpNavTree }, 3252 { "nativeDumpV8Counters", "()V", 3253 (void*) DumpV8Counters }, 3254 { "nativeSetNewStorageLimit", "(J)V", 3255 (void*) SetNewStorageLimit }, 3256 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", 3257 (void*) GeolocationPermissionsProvide }, 3258 { "nativePause", "()V", (void*) Pause }, 3259 { "nativeResume", "()V", (void*) Resume }, 3260 { "nativeFreeMemory", "()V", (void*) FreeMemory }, 3261 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, 3262 { "nativeRequestLabel", "(II)Ljava/lang/String;", 3263 (void*) RequestLabel }, 3264 { "nativeUpdateFrameCacheIfLoading", "()V", 3265 (void*) UpdateFrameCacheIfLoading }, 3266 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", 3267 (void*) ProvideVisitedHistory }, 3268 { "nativeFullScreenPluginHidden", "(I)V", 3269 (void*) FullScreenPluginHidden }, 3270 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", 3271 (void*) ValidNodeAndBounds }, 3272 }; 3273 3274 int register_webviewcore(JNIEnv* env) 3275 { 3276 jclass widget = env->FindClass("android/webkit/WebViewCore"); 3277 LOG_ASSERT(widget, 3278 "Unable to find class android/webkit/WebViewCore"); 3279 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", 3280 "I"); 3281 LOG_ASSERT(gWebViewCoreFields.m_nativeClass, 3282 "Unable to find android/webkit/WebViewCore.mNativeClass"); 3283 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, 3284 "mViewportWidth", "I"); 3285 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, 3286 "Unable to find android/webkit/WebViewCore.mViewportWidth"); 3287 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, 3288 "mViewportHeight", "I"); 3289 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, 3290 "Unable to find android/webkit/WebViewCore.mViewportHeight"); 3291 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, 3292 "mViewportInitialScale", "I"); 3293 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, 3294 "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); 3295 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, 3296 "mViewportMinimumScale", "I"); 3297 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, 3298 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); 3299 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, 3300 "mViewportMaximumScale", "I"); 3301 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, 3302 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); 3303 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, 3304 "mViewportUserScalable", "Z"); 3305 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, 3306 "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); 3307 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, 3308 "mViewportDensityDpi", "I"); 3309 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, 3310 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); 3311 gWebViewCoreFields.m_webView = env->GetFieldID(widget, 3312 "mWebView", "Landroid/webkit/WebView;"); 3313 LOG_ASSERT(gWebViewCoreFields.m_webView, 3314 "Unable to find android/webkit/WebViewCore.mWebView"); 3315 3316 gWebViewCoreStaticMethods.m_supportsMimeType = 3317 env->GetStaticMethodID(widget, "supportsMimeType", "(Ljava/lang/String;)Z"); 3318 LOG_ASSERT(gWebViewCoreStaticMethods.m_supportsMimeType == NULL, 3319 "Could not find static method supportsMimeType from WebViewCore"); 3320 3321 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", 3322 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); 3323 } 3324 3325 } /* namespace android */ 3326