1 /* 2 * Copyright 2007, 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 "webviewglue" 27 28 #include "config.h" 29 30 #include "AndroidAnimation.h" 31 #include "AndroidLog.h" 32 #include "BaseLayerAndroid.h" 33 #include "CachedFrame.h" 34 #include "CachedNode.h" 35 #include "CachedRoot.h" 36 #include "DrawExtra.h" 37 #include "FindCanvas.h" 38 #include "Frame.h" 39 #include "GraphicsJNI.h" 40 #include "HTMLInputElement.h" 41 #include "IntPoint.h" 42 #include "IntRect.h" 43 #include "LayerAndroid.h" 44 #include "Node.h" 45 #include "utils/Functor.h" 46 #include "private/hwui/DrawGlInfo.h" 47 #include "PlatformGraphicsContext.h" 48 #include "PlatformString.h" 49 #include "ScrollableLayerAndroid.h" 50 #include "SelectText.h" 51 #include "SkCanvas.h" 52 #include "SkDumpCanvas.h" 53 #include "SkPicture.h" 54 #include "SkRect.h" 55 #include "SkTime.h" 56 #ifdef ANDROID_INSTRUMENT 57 #include "TimeCounter.h" 58 #endif 59 #include "TilesManager.h" 60 #include "WebCoreJni.h" 61 #include "WebRequestContext.h" 62 #include "WebViewCore.h" 63 #include "android_graphics.h" 64 65 #ifdef GET_NATIVE_VIEW 66 #undef GET_NATIVE_VIEW 67 #endif 68 69 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField)) 70 71 #include <JNIUtility.h> 72 #include <JNIHelp.h> 73 #include <jni.h> 74 #include <ui/KeycodeLabels.h> 75 #include <wtf/text/AtomicString.h> 76 #include <wtf/text/CString.h> 77 78 // Free as much as we possible can 79 #define TRIM_MEMORY_COMPLETE 80 80 // Free a lot (all textures gone) 81 #define TRIM_MEMORY_MODERATE 60 82 // More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures) 83 #define TRIM_MEMORY_BACKGROUND 40 84 // Moderate free (clear cached tiles, keep visible ones) 85 #define TRIM_MEMORY_UI_HIDDEN 20 86 // Duration to show the pressed cursor ring 87 #define PRESSED_STATE_DURATION 400 88 89 namespace android { 90 91 static jfieldID gWebViewField; 92 93 //------------------------------------- 94 95 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 96 { 97 jmethodID m = env->GetMethodID(clazz, name, signature); 98 LOG_ASSERT(m, "Could not find method %s", name); 99 return m; 100 } 101 102 //------------------------------------- 103 // This class provides JNI for making calls into native code from the UI side 104 // of the multi-threaded WebView. 105 class WebView 106 { 107 public: 108 enum FrameCachePermission { 109 DontAllowNewer, 110 AllowNewer 111 }; 112 113 enum DrawExtras { // keep this in sync with WebView.java 114 DrawExtrasNone = 0, 115 DrawExtrasFind = 1, 116 DrawExtrasSelection = 2, 117 DrawExtrasCursorRing = 3 118 }; 119 120 struct JavaGlue { 121 jweak m_obj; 122 jmethodID m_overrideLoading; 123 jmethodID m_scrollBy; 124 jmethodID m_sendMoveFocus; 125 jmethodID m_sendMoveMouse; 126 jmethodID m_sendMoveMouseIfLatest; 127 jmethodID m_sendMotionUp; 128 jmethodID m_domChangedFocus; 129 jmethodID m_getScaledMaxXScroll; 130 jmethodID m_getScaledMaxYScroll; 131 jmethodID m_getVisibleRect; 132 jmethodID m_rebuildWebTextView; 133 jmethodID m_viewInvalidate; 134 jmethodID m_viewInvalidateRect; 135 jmethodID m_postInvalidateDelayed; 136 jmethodID m_pageSwapCallback; 137 jmethodID m_inFullScreenMode; 138 jfieldID m_rectLeft; 139 jfieldID m_rectTop; 140 jmethodID m_rectWidth; 141 jmethodID m_rectHeight; 142 jfieldID m_rectFLeft; 143 jfieldID m_rectFTop; 144 jmethodID m_rectFWidth; 145 jmethodID m_rectFHeight; 146 jmethodID m_getTextHandleScale; 147 AutoJObject object(JNIEnv* env) { 148 return getRealObject(env, m_obj); 149 } 150 } m_javaGlue; 151 152 WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, 153 bool isHighEndGfx) : 154 m_ring((WebViewCore*) viewImpl) 155 , m_isHighEndGfx(isHighEndGfx) 156 { 157 jclass clazz = env->FindClass("android/webkit/WebView"); 158 // m_javaGlue = new JavaGlue; 159 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); 160 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); 161 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); 162 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); 163 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); 164 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V"); 165 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V"); 166 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V"); 167 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); 168 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); 169 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); 170 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); 171 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); 172 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); 173 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, 174 "viewInvalidateDelayed", "(JIIII)V"); 175 m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V"); 176 m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z"); 177 m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F"); 178 env->DeleteLocalRef(clazz); 179 180 jclass rectClass = env->FindClass("android/graphics/Rect"); 181 LOG_ASSERT(rectClass, "Could not find Rect class"); 182 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); 183 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); 184 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); 185 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); 186 env->DeleteLocalRef(rectClass); 187 188 jclass rectClassF = env->FindClass("android/graphics/RectF"); 189 LOG_ASSERT(rectClassF, "Could not find RectF class"); 190 m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F"); 191 m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F"); 192 m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F"); 193 m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F"); 194 env->DeleteLocalRef(rectClassF); 195 196 env->SetIntField(javaWebView, gWebViewField, (jint)this); 197 m_viewImpl = (WebViewCore*) viewImpl; 198 m_frameCacheUI = 0; 199 m_navPictureUI = 0; 200 m_generation = 0; 201 m_heightCanMeasure = false; 202 m_lastDx = 0; 203 m_lastDxTime = 0; 204 m_ringAnimationEnd = 0; 205 m_baseLayer = 0; 206 m_glDrawFunctor = 0; 207 m_isDrawingPaused = false; 208 m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir); 209 #if USE(ACCELERATED_COMPOSITING) 210 m_glWebViewState = 0; 211 m_pageSwapCallbackRegistered = false; 212 #endif 213 } 214 215 ~WebView() 216 { 217 if (m_javaGlue.m_obj) 218 { 219 JNIEnv* env = JSC::Bindings::getJNIEnv(); 220 env->DeleteWeakGlobalRef(m_javaGlue.m_obj); 221 m_javaGlue.m_obj = 0; 222 } 223 #if USE(ACCELERATED_COMPOSITING) 224 // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we 225 // do not remove it here, we risk having BaseTiles trying to paint using a 226 // deallocated base layer. 227 stopGL(); 228 #endif 229 delete m_frameCacheUI; 230 delete m_navPictureUI; 231 SkSafeUnref(m_baseLayer); 232 delete m_glDrawFunctor; 233 delete m_buttonSkin; 234 } 235 236 void stopGL() 237 { 238 #if USE(ACCELERATED_COMPOSITING) 239 delete m_glWebViewState; 240 m_glWebViewState = 0; 241 #endif 242 } 243 244 WebViewCore* getWebViewCore() const { 245 return m_viewImpl; 246 } 247 248 float getTextHandleScale() 249 { 250 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 251 JNIEnv* env = JSC::Bindings::getJNIEnv(); 252 AutoJObject javaObject = m_javaGlue.object(env); 253 if (!javaObject.get()) 254 return 0; 255 float result = env->CallFloatMethod(javaObject.get(), m_javaGlue.m_getTextHandleScale); 256 checkException(env); 257 return result; 258 } 259 260 void updateSelectionHandles() 261 { 262 if (!m_baseLayer) 263 return; 264 // Adjust for device density & scale 265 m_selectText.updateHandleScale(getTextHandleScale()); 266 } 267 268 // removes the cursor altogether (e.g., when going to a new page) 269 void clearCursor() 270 { 271 CachedRoot* root = getFrameCache(AllowNewer); 272 if (!root) 273 return; 274 DBG_NAV_LOG(""); 275 m_viewImpl->m_hasCursorBounds = false; 276 root->clearCursor(); 277 viewInvalidate(); 278 } 279 280 // leaves the cursor where it is, but suppresses drawing it 281 void hideCursor() 282 { 283 CachedRoot* root = getFrameCache(AllowNewer); 284 if (!root) 285 return; 286 DBG_NAV_LOG(""); 287 hideCursor(root); 288 viewInvalidate(); 289 } 290 291 void hideCursor(CachedRoot* root) 292 { 293 DBG_NAV_LOG("inner"); 294 m_viewImpl->m_hasCursorBounds = false; 295 root->hideCursor(); 296 } 297 298 #if DUMP_NAV_CACHE 299 void debugDump() 300 { 301 CachedRoot* root = getFrameCache(DontAllowNewer); 302 if (root) 303 root->mDebug.print(); 304 } 305 #endif 306 307 void scrollToCurrentMatch() 308 { 309 if (!m_findOnPage.currentMatchIsInLayer()) { 310 scrollRectOnScreen(m_findOnPage.currentMatchBounds()); 311 return; 312 } 313 314 SkRect matchBounds = m_findOnPage.currentMatchBounds(); 315 LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer(); 316 Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId()); 317 ASSERT(layerContainingMatch); 318 319 // If the match is in a fixed position layer, there's nothing to do. 320 if (layerContainingMatch->shouldInheritFromRootTransform()) 321 return; 322 323 // If the match is in a scrollable layer or a descendant of such a layer, 324 // there may be a range of of scroll configurations that will make the 325 // current match visible. Our approach is the simplest possible. Starting at 326 // the layer in which the match is found, we move up the layer tree, 327 // scrolling any scrollable layers as little as possible to make sure that 328 // the current match is in view. This approach has the disadvantage that we 329 // may end up scrolling a larger number of elements than is necessary, which 330 // may be visually jarring. However, minimising the number of layers 331 // scrolled would complicate the code significantly. 332 333 bool didScrollLayer = false; 334 for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) { 335 ASSERT(layer->getParent() || layer == rootLayer); 336 337 if (layer->contentIsScrollable()) { 338 // Convert the match location to layer's local space and scroll it. 339 // Repeatedly calling Layer::localToAncestor() is inefficient as 340 // each call repeats part of the calculation. It would be more 341 // efficient to maintain the transform here and update it on each 342 // iteration, but that would mean duplicating logic from 343 // Layer::localToAncestor() and would complicate things. 344 SkMatrix transform; 345 layerContainingMatch->localToAncestor(layer, &transform); 346 SkRect transformedMatchBounds; 347 transform.mapRect(&transformedMatchBounds, matchBounds); 348 SkIRect roundedTransformedMatchBounds; 349 transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); 350 // Only ScrollableLayerAndroid returns true for contentIsScrollable(). 351 didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds); 352 } 353 } 354 // Invalidate, as the call below to scroll the main page may be a no-op. 355 if (didScrollLayer) 356 viewInvalidate(); 357 358 // Convert matchBounds to the global space so we can scroll the main page. 359 SkMatrix transform; 360 layerContainingMatch->localToGlobal(&transform); 361 SkRect transformedMatchBounds; 362 transform.mapRect(&transformedMatchBounds, matchBounds); 363 SkIRect roundedTransformedMatchBounds; 364 transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); 365 scrollRectOnScreen(roundedTransformedMatchBounds); 366 } 367 368 void scrollRectOnScreen(const IntRect& rect) 369 { 370 if (rect.isEmpty()) 371 return; 372 int dx = 0; 373 int left = rect.x(); 374 int right = rect.maxX(); 375 if (left < m_visibleRect.fLeft) 376 dx = left - m_visibleRect.fLeft; 377 // Only scroll right if the entire width can fit on screen. 378 else if (right > m_visibleRect.fRight 379 && right - left < m_visibleRect.width()) 380 dx = right - m_visibleRect.fRight; 381 int dy = 0; 382 int top = rect.y(); 383 int bottom = rect.maxY(); 384 if (top < m_visibleRect.fTop) 385 dy = top - m_visibleRect.fTop; 386 // Only scroll down if the entire height can fit on screen 387 else if (bottom > m_visibleRect.fBottom 388 && bottom - top < m_visibleRect.height()) 389 dy = bottom - m_visibleRect.fBottom; 390 if ((dx|dy) == 0 || !scrollBy(dx, dy)) 391 return; 392 viewInvalidate(); 393 } 394 395 void resetCursorRing() 396 { 397 m_ringAnimationEnd = 0; 398 m_viewImpl->m_hasCursorBounds = false; 399 } 400 401 bool drawCursorPreamble(CachedRoot* root) 402 { 403 if (!root) return false; 404 const CachedFrame* frame; 405 const CachedNode* node = root->currentCursor(&frame); 406 if (!node) { 407 DBG_NAV_LOGV("%s", "!node"); 408 resetCursorRing(); 409 return false; 410 } 411 m_ring.setIsButton(node); 412 if (node->isHidden()) { 413 DBG_NAV_LOG("node->isHidden()"); 414 m_viewImpl->m_hasCursorBounds = false; 415 return false; 416 } 417 #if USE(ACCELERATED_COMPOSITING) 418 if (node->isInLayer() && root->rootLayer()) { 419 LayerAndroid* layer = root->rootLayer(); 420 layer->updateFixedLayersPositions(m_visibleRect); 421 layer->updatePositions(); 422 } 423 #endif 424 setVisibleRect(root); 425 m_ring.m_root = root; 426 m_ring.m_frame = frame; 427 m_ring.m_node = node; 428 SkMSec time = SkTime::GetMSecs(); 429 m_ring.m_isPressed = time < m_ringAnimationEnd 430 && m_ringAnimationEnd != UINT_MAX; 431 return true; 432 } 433 434 void drawCursorPostamble() 435 { 436 if (m_ringAnimationEnd == UINT_MAX) 437 return; 438 SkMSec time = SkTime::GetMSecs(); 439 if (time < m_ringAnimationEnd) { 440 // views assume that inval bounds coordinates are non-negative 441 WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX); 442 invalBounds.intersect(m_ring.m_absBounds); 443 postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds); 444 } else { 445 hideCursor(const_cast<CachedRoot*>(m_ring.m_root)); 446 } 447 } 448 449 bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, 450 WebCore::IntRect& webViewRect, int titleBarHeight, 451 WebCore::IntRect& clip, float scale, int extras) 452 { 453 #if USE(ACCELERATED_COMPOSITING) 454 if (!m_baseLayer || inFullScreenMode()) 455 return false; 456 457 if (!m_glWebViewState) { 458 m_glWebViewState = new GLWebViewState(); 459 m_glWebViewState->setHighEndGfx(m_isHighEndGfx); 460 m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring); 461 m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage); 462 if (m_baseLayer->content()) { 463 SkRegion region; 464 SkIRect rect; 465 rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height()); 466 region.setRect(rect); 467 m_glWebViewState->setBaseLayer(m_baseLayer, region, false, true); 468 } 469 } 470 471 CachedRoot* root = getFrameCache(AllowNewer); 472 if (!root) { 473 DBG_NAV_LOG("!root"); 474 if (extras == DrawExtrasCursorRing) 475 resetCursorRing(); 476 } 477 DrawExtra* extra = 0; 478 switch (extras) { 479 case DrawExtrasFind: 480 extra = &m_findOnPage; 481 break; 482 case DrawExtrasSelection: 483 // This will involve a JNI call, but under normal circumstances we will 484 // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled 485 // in WebView.java will we hit this (so really debug only) 486 updateSelectionHandles(); 487 extra = &m_selectText; 488 break; 489 case DrawExtrasCursorRing: 490 if (drawCursorPreamble(root) && m_ring.setup()) { 491 if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX) 492 extra = &m_ring; 493 drawCursorPostamble(); 494 } 495 break; 496 default: 497 ; 498 } 499 500 unsigned int pic = m_glWebViewState->currentPictureCounter(); 501 m_glWebViewState->glExtras()->setDrawExtra(extra); 502 503 // Make sure we have valid coordinates. We might not have valid coords 504 // if the zoom manager is still initializing. We will be redrawn 505 // once the correct scale is set 506 if (!m_visibleRect.hasValidCoordinates()) 507 return false; 508 bool treesSwapped = false; 509 bool newTreeHasAnim = false; 510 bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect, 511 webViewRect, titleBarHeight, clip, scale, 512 &treesSwapped, &newTreeHasAnim); 513 if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) { 514 m_pageSwapCallbackRegistered = false; 515 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 516 JNIEnv* env = JSC::Bindings::getJNIEnv(); 517 AutoJObject javaObject = m_javaGlue.object(env); 518 if (javaObject.get()) { 519 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim); 520 checkException(env); 521 } 522 } 523 if (ret || m_glWebViewState->currentPictureCounter() != pic) 524 return !m_isDrawingPaused; 525 #endif 526 return false; 527 } 528 529 PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) 530 { 531 PictureSet* ret = 0; 532 if (!m_baseLayer) { 533 canvas->drawColor(bgColor); 534 return ret; 535 } 536 537 // draw the content of the base layer first 538 PictureSet* content = m_baseLayer->content(); 539 int sc = canvas->save(SkCanvas::kClip_SaveFlag); 540 canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), 541 content->height()), SkRegion::kDifference_Op); 542 canvas->drawColor(bgColor); 543 canvas->restoreToCount(sc); 544 if (content->draw(canvas)) 545 ret = split ? new PictureSet(*content) : 0; 546 547 CachedRoot* root = getFrameCache(AllowNewer); 548 if (!root) { 549 DBG_NAV_LOG("!root"); 550 if (extras == DrawExtrasCursorRing) 551 resetCursorRing(); 552 } 553 LayerAndroid mainPicture(m_navPictureUI); 554 DrawExtra* extra = 0; 555 switch (extras) { 556 case DrawExtrasFind: 557 extra = &m_findOnPage; 558 break; 559 case DrawExtrasSelection: 560 // This will involve a JNI call, but under normal circumstances we will 561 // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled 562 // in WebView.java will we hit this (so really debug only) 563 updateSelectionHandles(); 564 extra = &m_selectText; 565 break; 566 case DrawExtrasCursorRing: 567 if (drawCursorPreamble(root) && m_ring.setup()) { 568 extra = &m_ring; 569 drawCursorPostamble(); 570 } 571 break; 572 default: 573 ; 574 } 575 #if USE(ACCELERATED_COMPOSITING) 576 LayerAndroid* compositeLayer = compositeRoot(); 577 if (compositeLayer) { 578 // call this to be sure we've adjusted for any scrolling or animations 579 // before we actually draw 580 compositeLayer->updateFixedLayersPositions(m_visibleRect); 581 compositeLayer->updatePositions(); 582 // We have to set the canvas' matrix on the base layer 583 // (to have fixed layers work as intended) 584 SkAutoCanvasRestore restore(canvas, true); 585 m_baseLayer->setMatrix(canvas->getTotalMatrix()); 586 canvas->resetMatrix(); 587 m_baseLayer->draw(canvas); 588 } 589 #endif 590 if (extra) { 591 IntRect dummy; // inval area, unused for now 592 extra->draw(canvas, &mainPicture, &dummy); 593 } 594 return ret; 595 } 596 597 598 bool cursorIsTextInput(FrameCachePermission allowNewer) 599 { 600 CachedRoot* root = getFrameCache(allowNewer); 601 if (!root) { 602 DBG_NAV_LOG("!root"); 603 return false; 604 } 605 const CachedNode* cursor = root->currentCursor(); 606 if (!cursor) { 607 DBG_NAV_LOG("!cursor"); 608 return false; 609 } 610 DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false"); 611 return cursor->isTextInput(); 612 } 613 614 void cursorRingBounds(WebCore::IntRect* bounds) 615 { 616 DBG_NAV_LOGD("%s", ""); 617 CachedRoot* root = getFrameCache(DontAllowNewer); 618 if (root) { 619 const CachedFrame* cachedFrame; 620 const CachedNode* cachedNode = root->currentCursor(&cachedFrame); 621 if (cachedNode) { 622 *bounds = cachedNode->cursorRingBounds(cachedFrame); 623 DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(), 624 bounds->width(), bounds->height()); 625 return; 626 } 627 } 628 *bounds = WebCore::IntRect(0, 0, 0, 0); 629 } 630 631 void fixCursor() 632 { 633 m_viewImpl->gCursorBoundsMutex.lock(); 634 bool hasCursorBounds = m_viewImpl->m_hasCursorBounds; 635 IntRect bounds = m_viewImpl->m_cursorBounds; 636 m_viewImpl->gCursorBoundsMutex.unlock(); 637 if (!hasCursorBounds) 638 return; 639 int x, y; 640 const CachedFrame* frame; 641 const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true); 642 if (!node) 643 return; 644 // require that node have approximately the same bounds (+/- 4) and the same 645 // center (+/- 2) 646 IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1), 647 bounds.y() + (bounds.height() >> 1)); 648 IntRect newBounds = node->bounds(frame); 649 IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1), 650 newBounds.y() + (newBounds.height() >> 1)); 651 DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)" 652 " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)", 653 oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(), 654 bounds.x(), bounds.y(), bounds.width(), bounds.height(), 655 newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height()); 656 if (abs(oldCenter.x() - newCenter.x()) > 2) 657 return; 658 if (abs(oldCenter.y() - newCenter.y()) > 2) 659 return; 660 if (abs(bounds.x() - newBounds.x()) > 4) 661 return; 662 if (abs(bounds.y() - newBounds.y()) > 4) 663 return; 664 if (abs(bounds.maxX() - newBounds.maxX()) > 4) 665 return; 666 if (abs(bounds.maxY() - newBounds.maxY()) > 4) 667 return; 668 DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)", 669 node, frame, x, y, bounds.x(), bounds.y(), bounds.width(), 670 bounds.height()); 671 m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame), 672 const_cast<CachedNode*>(node)); 673 } 674 675 CachedRoot* getFrameCache(FrameCachePermission allowNewer) 676 { 677 if (!m_viewImpl->m_updatedFrameCache) { 678 DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache"); 679 return m_frameCacheUI; 680 } 681 if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) { 682 DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d" 683 " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation); 684 return m_frameCacheUI; 685 } 686 DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true"); 687 const CachedFrame* oldCursorFrame; 688 const CachedNode* oldCursorNode = m_frameCacheUI ? 689 m_frameCacheUI->currentCursor(&oldCursorFrame) : 0; 690 #if USE(ACCELERATED_COMPOSITING) 691 int layerId = -1; 692 if (oldCursorNode && oldCursorNode->isInLayer()) { 693 const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode) 694 ->layer(m_frameCacheUI->rootLayer()); 695 if (cursorLayer) 696 layerId = cursorLayer->uniqueId(); 697 } 698 #endif 699 // get id from old layer and use to find new layer 700 bool oldFocusIsTextInput = false; 701 void* oldFocusNodePointer = 0; 702 if (m_frameCacheUI) { 703 const CachedNode* oldFocus = m_frameCacheUI->currentFocus(); 704 if (oldFocus) { 705 oldFocusIsTextInput = oldFocus->isTextInput(); 706 oldFocusNodePointer = oldFocus->nodePointer(); 707 } 708 } 709 m_viewImpl->gFrameCacheMutex.lock(); 710 delete m_frameCacheUI; 711 SkSafeUnref(m_navPictureUI); 712 m_viewImpl->m_updatedFrameCache = false; 713 m_frameCacheUI = m_viewImpl->m_frameCacheKit; 714 m_navPictureUI = m_viewImpl->m_navPictureKit; 715 m_viewImpl->m_frameCacheKit = 0; 716 m_viewImpl->m_navPictureKit = 0; 717 m_viewImpl->gFrameCacheMutex.unlock(); 718 if (m_frameCacheUI) 719 m_frameCacheUI->setRootLayer(compositeRoot()); 720 #if USE(ACCELERATED_COMPOSITING) 721 if (layerId >= 0) { 722 LayerAndroid* layer = const_cast<LayerAndroid*>( 723 m_frameCacheUI->rootLayer()); 724 if (layer) { 725 layer->updateFixedLayersPositions(m_visibleRect); 726 layer->updatePositions(); 727 } 728 } 729 #endif 730 fixCursor(); 731 if (oldFocusIsTextInput) { 732 const CachedNode* newFocus = m_frameCacheUI->currentFocus(); 733 if (newFocus && oldFocusNodePointer != newFocus->nodePointer() 734 && newFocus->isTextInput() 735 && newFocus != m_frameCacheUI->currentCursor()) { 736 // The focus has changed. We may need to update things. 737 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 738 JNIEnv* env = JSC::Bindings::getJNIEnv(); 739 AutoJObject javaObject = m_javaGlue.object(env); 740 if (javaObject.get()) { 741 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_domChangedFocus); 742 checkException(env); 743 } 744 } 745 } 746 if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) 747 viewInvalidate(); // redraw in case cursor ring is still visible 748 return m_frameCacheUI; 749 } 750 751 int getScaledMaxXScroll() 752 { 753 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 754 JNIEnv* env = JSC::Bindings::getJNIEnv(); 755 AutoJObject javaObject = m_javaGlue.object(env); 756 if (!javaObject.get()) 757 return 0; 758 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll); 759 checkException(env); 760 return result; 761 } 762 763 int getScaledMaxYScroll() 764 { 765 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 766 JNIEnv* env = JSC::Bindings::getJNIEnv(); 767 AutoJObject javaObject = m_javaGlue.object(env); 768 if (!javaObject.get()) 769 return 0; 770 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll); 771 checkException(env); 772 return result; 773 } 774 775 IntRect getVisibleRect() 776 { 777 IntRect rect; 778 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 779 JNIEnv* env = JSC::Bindings::getJNIEnv(); 780 AutoJObject javaObject = m_javaGlue.object(env); 781 if (!javaObject.get()) 782 return rect; 783 jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect); 784 checkException(env); 785 rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft)); 786 checkException(env); 787 rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop)); 788 checkException(env); 789 rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth)); 790 checkException(env); 791 rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight)); 792 checkException(env); 793 env->DeleteLocalRef(jRect); 794 checkException(env); 795 return rect; 796 } 797 798 static CachedFrame::Direction KeyToDirection(int32_t keyCode) 799 { 800 switch (keyCode) { 801 case AKEYCODE_DPAD_RIGHT: 802 DBG_NAV_LOGD("keyCode=%s", "right"); 803 return CachedFrame::RIGHT; 804 case AKEYCODE_DPAD_LEFT: 805 DBG_NAV_LOGD("keyCode=%s", "left"); 806 return CachedFrame::LEFT; 807 case AKEYCODE_DPAD_DOWN: 808 DBG_NAV_LOGD("keyCode=%s", "down"); 809 return CachedFrame::DOWN; 810 case AKEYCODE_DPAD_UP: 811 DBG_NAV_LOGD("keyCode=%s", "up"); 812 return CachedFrame::UP; 813 default: 814 DBG_NAV_LOGD("bad key %d sent", keyCode); 815 return CachedFrame::UNINITIALIZED; 816 } 817 } 818 819 WTF::String imageURI(int x, int y) 820 { 821 const CachedRoot* root = getFrameCache(DontAllowNewer); 822 return root ? root->imageURI(x, y) : WTF::String(); 823 } 824 825 bool cursorWantsKeyEvents() 826 { 827 const CachedRoot* root = getFrameCache(DontAllowNewer); 828 if (root) { 829 const CachedNode* focus = root->currentCursor(); 830 if (focus) 831 return focus->wantsKeyEvents(); 832 } 833 return false; 834 } 835 836 837 /* returns true if the key had no effect (neither scrolled nor changed cursor) */ 838 bool moveCursor(int keyCode, int count, bool ignoreScroll) 839 { 840 CachedRoot* root = getFrameCache(AllowNewer); 841 if (!root) { 842 DBG_NAV_LOG("!root"); 843 return true; 844 } 845 846 m_viewImpl->m_moveGeneration++; 847 CachedFrame::Direction direction = KeyToDirection(keyCode); 848 const CachedFrame* cachedFrame, * oldFrame = 0; 849 const CachedNode* cursor = root->currentCursor(&oldFrame); 850 WebCore::IntPoint cursorLocation = root->cursorLocation(); 851 DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", 852 cursor ? cursor->index() : 0, 853 cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); 854 WebCore::IntRect visibleRect = setVisibleRect(root); 855 int xMax = getScaledMaxXScroll(); 856 int yMax = getScaledMaxYScroll(); 857 root->setMaxScroll(xMax, yMax); 858 const CachedNode* cachedNode = 0; 859 int dx = 0; 860 int dy = 0; 861 int counter = count; 862 while (--counter >= 0) { 863 WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); 864 cachedNode = root->moveCursor(direction, &cachedFrame, &scroll); 865 dx += scroll.x(); 866 dy += scroll.y(); 867 } 868 DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}" 869 "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, 870 cachedNode ? cachedNode->nodePointer() : 0, 871 root->cursorLocation().x(), root->cursorLocation().y(), 872 cachedNode ? cachedNode->bounds(cachedFrame).x() : 0, 873 cachedNode ? cachedNode->bounds(cachedFrame).y() : 0, 874 cachedNode ? cachedNode->bounds(cachedFrame).width() : 0, 875 cachedNode ? cachedNode->bounds(cachedFrame).height() : 0); 876 // If !m_heightCanMeasure (such as in the browser), we want to scroll no 877 // matter what 878 if (!ignoreScroll && (!m_heightCanMeasure || 879 !cachedNode || 880 (cursor && cursor->nodePointer() == cachedNode->nodePointer()))) 881 { 882 if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx && 883 SkTime::GetMSecs() - m_lastDxTime < 1000) 884 root->checkForJiggle(&dx); 885 DBG_NAV_LOGD("scrollBy %d,%d", dx, dy); 886 if ((dx | dy)) 887 this->scrollBy(dx, dy); 888 m_lastDx = dx; 889 m_lastDxTime = SkTime::GetMSecs(); 890 } 891 bool result = false; 892 if (cachedNode) { 893 showCursorUntimed(); 894 m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode); 895 root->setCursor(const_cast<CachedFrame*>(cachedFrame), 896 const_cast<CachedNode*>(cachedNode)); 897 const CachedNode* focus = root->currentFocus(); 898 bool clearTextEntry = cachedNode != focus && focus 899 && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput(); 900 // Stop painting the caret if the old focus was a text input and so is the new cursor. 901 bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents(); 902 sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret); 903 } else { 904 int docHeight = root->documentHeight(); 905 int docWidth = root->documentWidth(); 906 if (visibleRect.maxY() + dy > docHeight) 907 dy = docHeight - visibleRect.maxY(); 908 else if (visibleRect.y() + dy < 0) 909 dy = -visibleRect.y(); 910 if (visibleRect.maxX() + dx > docWidth) 911 dx = docWidth - visibleRect.maxX(); 912 else if (visibleRect.x() < 0) 913 dx = -visibleRect.x(); 914 result = direction == CachedFrame::LEFT ? dx >= 0 : 915 direction == CachedFrame::RIGHT ? dx <= 0 : 916 direction == CachedFrame::UP ? dy >= 0 : dy <= 0; 917 } 918 return result; 919 } 920 921 void notifyProgressFinished() 922 { 923 DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer)); 924 rebuildWebTextView(); 925 #if DEBUG_NAV_UI 926 if (m_frameCacheUI) { 927 const CachedNode* focus = m_frameCacheUI->currentFocus(); 928 DBG_NAV_LOGD("focus %d (nativeNode=%p)", 929 focus ? focus->index() : 0, 930 focus ? focus->nodePointer() : 0); 931 } 932 #endif 933 } 934 935 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect, 936 const CachedFrame** framePtr, int* rxPtr, int* ryPtr) 937 { 938 *rxPtr = 0; 939 *ryPtr = 0; 940 *framePtr = 0; 941 if (!root) 942 return 0; 943 setVisibleRect(root); 944 return root->findAt(rect, framePtr, rxPtr, ryPtr, true); 945 } 946 947 IntRect setVisibleRect(CachedRoot* root) 948 { 949 IntRect visibleRect = getVisibleRect(); 950 DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d", 951 visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height()); 952 root->setVisibleRect(visibleRect); 953 return visibleRect; 954 } 955 956 void selectBestAt(const WebCore::IntRect& rect) 957 { 958 const CachedFrame* frame; 959 int rx, ry; 960 CachedRoot* root = getFrameCache(AllowNewer); 961 if (!root) 962 return; 963 const CachedNode* node = findAt(root, rect, &frame, &rx, &ry); 964 if (!node) { 965 DBG_NAV_LOGD("no nodes found root=%p", root); 966 root->rootHistory()->setMouseBounds(rect); 967 m_viewImpl->m_hasCursorBounds = false; 968 root->setCursor(0, 0); 969 viewInvalidate(); 970 } else { 971 DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); 972 WebCore::IntRect bounds = node->bounds(frame); 973 root->rootHistory()->setMouseBounds(bounds); 974 m_viewImpl->updateCursorBounds(root, frame, node); 975 showCursorTimed(); 976 root->setCursor(const_cast<CachedFrame*>(frame), 977 const_cast<CachedNode*>(node)); 978 } 979 sendMoveMouseIfLatest(false, false); 980 } 981 982 const CachedNode* m_cacheHitNode; 983 const CachedFrame* m_cacheHitFrame; 984 985 bool pointInNavCache(int x, int y, int slop) 986 { 987 CachedRoot* root = getFrameCache(AllowNewer); 988 if (!root) 989 return false; 990 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); 991 int rx, ry; 992 return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry)); 993 } 994 995 bool motionUp(int x, int y, int slop) 996 { 997 bool pageScrolled = false; 998 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); 999 int rx, ry; 1000 CachedRoot* root = getFrameCache(AllowNewer); 1001 if (!root) 1002 return 0; 1003 const CachedFrame* frame = 0; 1004 const CachedNode* result = findAt(root, rect, &frame, &rx, &ry); 1005 CachedHistory* history = root->rootHistory(); 1006 if (!result) { 1007 DBG_NAV_LOGD("no nodes found root=%p", root); 1008 history->setNavBounds(rect); 1009 m_viewImpl->m_hasCursorBounds = false; 1010 root->hideCursor(); 1011 int dx = root->checkForCenter(x, y); 1012 if (dx) { 1013 scrollBy(dx, 0); 1014 pageScrolled = true; 1015 } 1016 sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0, 1017 0, x, y); 1018 viewInvalidate(); 1019 return pageScrolled; 1020 } 1021 DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result, 1022 result->index(), x, y, rx, ry); 1023 WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1); 1024 history->setNavBounds(navBounds); 1025 history->setMouseBounds(navBounds); 1026 m_viewImpl->updateCursorBounds(root, frame, result); 1027 root->setCursor(const_cast<CachedFrame*>(frame), 1028 const_cast<CachedNode*>(result)); 1029 if (result->isSyntheticLink()) 1030 overrideUrlLoading(result->getExport()); 1031 else { 1032 sendMotionUp( 1033 (WebCore::Frame*) frame->framePointer(), 1034 (WebCore::Node*) result->nodePointer(), rx, ry); 1035 } 1036 if (result->isTextInput() || result->isSelect() 1037 || result->isContentEditable()) { 1038 showCursorUntimed(); 1039 } else 1040 showCursorTimed(); 1041 return pageScrolled; 1042 } 1043 1044 #if USE(ACCELERATED_COMPOSITING) 1045 static const ScrollableLayerAndroid* findScrollableLayer( 1046 const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) { 1047 SkRect bounds; 1048 parent->bounds(&bounds); 1049 // Check the parent bounds first; this will clip to within a masking layer's 1050 // bounds. 1051 if (parent->masksToBounds() && !bounds.contains(x, y)) 1052 return 0; 1053 // Move the hit test local to parent. 1054 x -= bounds.fLeft; 1055 y -= bounds.fTop; 1056 int count = parent->countChildren(); 1057 while (count--) { 1058 const LayerAndroid* child = parent->getChild(count); 1059 const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, 1060 foundBounds); 1061 if (result) { 1062 foundBounds->offset(bounds.fLeft, bounds.fTop); 1063 if (parent->masksToBounds()) { 1064 if (bounds.width() < foundBounds->width()) 1065 foundBounds->fRight = foundBounds->fLeft + bounds.width(); 1066 if (bounds.height() < foundBounds->height()) 1067 foundBounds->fBottom = foundBounds->fTop + bounds.height(); 1068 } 1069 return result; 1070 } 1071 } 1072 if (parent->contentIsScrollable()) { 1073 foundBounds->set(0, 0, bounds.width(), bounds.height()); 1074 return static_cast<const ScrollableLayerAndroid*>(parent); 1075 } 1076 return 0; 1077 } 1078 #endif 1079 1080 int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds) 1081 { 1082 #if USE(ACCELERATED_COMPOSITING) 1083 const LayerAndroid* layerRoot = compositeRoot(); 1084 if (!layerRoot) 1085 return 0; 1086 const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y, 1087 bounds); 1088 if (result) { 1089 result->getScrollRect(layerRect); 1090 return result->uniqueId(); 1091 } 1092 #endif 1093 return 0; 1094 } 1095 1096 void scrollLayer(int layerId, int x, int y) 1097 { 1098 if (m_glWebViewState) 1099 m_glWebViewState->scrollLayer(layerId, x, y); 1100 } 1101 1102 int getBlockLeftEdge(int x, int y, float scale) 1103 { 1104 CachedRoot* root = getFrameCache(AllowNewer); 1105 if (root) 1106 return root->getBlockLeftEdge(x, y, scale); 1107 return -1; 1108 } 1109 1110 void overrideUrlLoading(const WTF::String& url) 1111 { 1112 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1113 AutoJObject javaObject = m_javaGlue.object(env); 1114 if (!javaObject.get()) 1115 return; 1116 jstring jName = wtfStringToJstring(env, url); 1117 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName); 1118 env->DeleteLocalRef(jName); 1119 } 1120 1121 void setFindIsUp(bool up) 1122 { 1123 DBG_NAV_LOGD("up=%d", up); 1124 m_viewImpl->m_findIsUp = up; 1125 } 1126 1127 void setFindIsEmpty() 1128 { 1129 DBG_NAV_LOG(""); 1130 m_findOnPage.clearCurrentLocation(); 1131 } 1132 1133 void showCursorTimed() 1134 { 1135 DBG_NAV_LOG(""); 1136 m_ringAnimationEnd = SkTime::GetMSecs() + PRESSED_STATE_DURATION; 1137 viewInvalidate(); 1138 } 1139 1140 void showCursorUntimed() 1141 { 1142 DBG_NAV_LOG(""); 1143 m_ring.m_isPressed = false; 1144 m_ringAnimationEnd = UINT_MAX; 1145 viewInvalidate(); 1146 } 1147 1148 void setHeightCanMeasure(bool measure) 1149 { 1150 m_heightCanMeasure = measure; 1151 } 1152 1153 String getSelection() 1154 { 1155 return m_selectText.getSelection(); 1156 } 1157 1158 void moveSelection(int x, int y) 1159 { 1160 m_selectText.moveSelection(getVisibleRect(), x, y); 1161 } 1162 1163 IntPoint selectableText() 1164 { 1165 const CachedRoot* root = getFrameCache(DontAllowNewer); 1166 if (!root) 1167 return IntPoint(0, 0); 1168 return m_selectText.selectableText(root); 1169 } 1170 1171 void selectAll() 1172 { 1173 m_selectText.selectAll(); 1174 } 1175 1176 int selectionX() 1177 { 1178 return m_selectText.selectionX(); 1179 } 1180 1181 int selectionY() 1182 { 1183 return m_selectText.selectionY(); 1184 } 1185 1186 void resetSelection() 1187 { 1188 m_selectText.reset(); 1189 } 1190 1191 bool startSelection(int x, int y) 1192 { 1193 const CachedRoot* root = getFrameCache(DontAllowNewer); 1194 if (!root) 1195 return false; 1196 updateSelectionHandles(); 1197 return m_selectText.startSelection(root, getVisibleRect(), x, y); 1198 } 1199 1200 bool wordSelection(int x, int y) 1201 { 1202 const CachedRoot* root = getFrameCache(DontAllowNewer); 1203 if (!root) 1204 return false; 1205 updateSelectionHandles(); 1206 return m_selectText.wordSelection(root, getVisibleRect(), x, y); 1207 } 1208 1209 bool extendSelection(int x, int y) 1210 { 1211 m_selectText.extendSelection(getVisibleRect(), x, y); 1212 return true; 1213 } 1214 1215 bool hitSelection(int x, int y) 1216 { 1217 updateSelectionHandles(); 1218 return m_selectText.hitSelection(x, y); 1219 } 1220 1221 void setExtendSelection() 1222 { 1223 m_selectText.setExtendSelection(true); 1224 } 1225 1226 void setSelectionPointer(bool set, float scale, int x, int y) 1227 { 1228 m_selectText.setDrawPointer(set); 1229 if (!set) 1230 return; 1231 m_selectText.m_inverseScale = scale; 1232 m_selectText.m_selectX = x; 1233 m_selectText.m_selectY = y; 1234 } 1235 1236 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) 1237 { 1238 DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr); 1239 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1240 AutoJObject javaObject = m_javaGlue.object(env); 1241 if (!javaObject.get()) 1242 return; 1243 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr); 1244 checkException(env); 1245 } 1246 1247 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) 1248 { 1249 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); 1250 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1251 AutoJObject javaObject = m_javaGlue.object(env); 1252 if (!javaObject.get()) 1253 return; 1254 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y); 1255 checkException(env); 1256 } 1257 1258 void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) 1259 { 1260 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 1261 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1262 AutoJObject javaObject = m_javaGlue.object(env); 1263 if (!javaObject.get()) 1264 return; 1265 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret); 1266 checkException(env); 1267 } 1268 1269 void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) 1270 { 1271 DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y); 1272 LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); 1273 1274 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1275 AutoJObject javaObject = m_javaGlue.object(env); 1276 if (!javaObject.get()) 1277 return; 1278 m_viewImpl->m_touchGeneration = ++m_generation; 1279 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y); 1280 checkException(env); 1281 } 1282 1283 void findNext(bool forward) 1284 { 1285 m_findOnPage.findNext(forward); 1286 scrollToCurrentMatch(); 1287 viewInvalidate(); 1288 } 1289 1290 // With this call, WebView takes ownership of matches, and is responsible for 1291 // deleting it. 1292 void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch) 1293 { 1294 // If this search is the same as the last one, check against the old 1295 // location to determine whether to scroll. If the same word is found 1296 // in the same place, then do not scroll. 1297 IntRect oldLocation; 1298 bool checkAgainstOldLocation = false; 1299 if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) { 1300 oldLocation = m_findOnPage.currentMatchBounds(); 1301 checkAgainstOldLocation = true; 1302 } 1303 1304 m_findOnPage.setMatches(matches); 1305 1306 if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds()) 1307 scrollToCurrentMatch(); 1308 viewInvalidate(); 1309 } 1310 1311 int currentMatchIndex() 1312 { 1313 return m_findOnPage.currentMatchIndex(); 1314 } 1315 1316 bool scrollBy(int dx, int dy) 1317 { 1318 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 1319 1320 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1321 AutoJObject javaObject = m_javaGlue.object(env); 1322 if (!javaObject.get()) 1323 return false; 1324 bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true); 1325 checkException(env); 1326 return result; 1327 } 1328 1329 void setIsScrolling(bool isScrolling) 1330 { 1331 #if USE(ACCELERATED_COMPOSITING) 1332 if (m_glWebViewState) 1333 m_glWebViewState->setIsScrolling(isScrolling); 1334 #endif 1335 } 1336 1337 bool hasCursorNode() 1338 { 1339 CachedRoot* root = getFrameCache(DontAllowNewer); 1340 if (!root) { 1341 DBG_NAV_LOG("!root"); 1342 return false; 1343 } 1344 const CachedNode* cursorNode = root->currentCursor(); 1345 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)", 1346 cursorNode ? cursorNode->index() : -1, 1347 cursorNode ? cursorNode->nodePointer() : 0); 1348 return cursorNode; 1349 } 1350 1351 bool hasFocusNode() 1352 { 1353 CachedRoot* root = getFrameCache(DontAllowNewer); 1354 if (!root) { 1355 DBG_NAV_LOG("!root"); 1356 return false; 1357 } 1358 const CachedNode* focusNode = root->currentFocus(); 1359 DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)", 1360 focusNode ? focusNode->index() : -1, 1361 focusNode ? focusNode->nodePointer() : 0); 1362 return focusNode; 1363 } 1364 1365 void rebuildWebTextView() 1366 { 1367 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1368 AutoJObject javaObject = m_javaGlue.object(env); 1369 if (!javaObject.get()) 1370 return; 1371 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView); 1372 checkException(env); 1373 } 1374 1375 void viewInvalidate() 1376 { 1377 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1378 AutoJObject javaObject = m_javaGlue.object(env); 1379 if (!javaObject.get()) 1380 return; 1381 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate); 1382 checkException(env); 1383 } 1384 1385 void viewInvalidateRect(int l, int t, int r, int b) 1386 { 1387 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1388 AutoJObject javaObject = m_javaGlue.object(env); 1389 if (!javaObject.get()) 1390 return; 1391 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); 1392 checkException(env); 1393 } 1394 1395 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) 1396 { 1397 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1398 AutoJObject javaObject = m_javaGlue.object(env); 1399 if (!javaObject.get()) 1400 return; 1401 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed, 1402 delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY()); 1403 checkException(env); 1404 } 1405 1406 bool inFullScreenMode() 1407 { 1408 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1409 AutoJObject javaObject = m_javaGlue.object(env); 1410 if (!javaObject.get()) 1411 return false; 1412 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_inFullScreenMode); 1413 checkException(env); 1414 return result; 1415 } 1416 1417 int moveGeneration() 1418 { 1419 return m_viewImpl->m_moveGeneration; 1420 } 1421 1422 LayerAndroid* compositeRoot() const 1423 { 1424 LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, 1425 "base layer can't have more than one child %s", __FUNCTION__); 1426 if (m_baseLayer && m_baseLayer->countChildren() == 1) 1427 return static_cast<LayerAndroid*>(m_baseLayer->getChild(0)); 1428 else 1429 return 0; 1430 } 1431 1432 #if ENABLE(ANDROID_OVERFLOW_SCROLL) 1433 static void copyScrollPositionRecursive(const LayerAndroid* from, 1434 LayerAndroid* root) 1435 { 1436 if (!from || !root) 1437 return; 1438 for (int i = 0; i < from->countChildren(); i++) { 1439 const LayerAndroid* l = from->getChild(i); 1440 if (l->contentIsScrollable()) { 1441 const SkPoint& pos = l->getPosition(); 1442 LayerAndroid* match = root->findById(l->uniqueId()); 1443 if (match && match->contentIsScrollable()) 1444 match->setPosition(pos.fX, pos.fY); 1445 } 1446 copyScrollPositionRecursive(l, root); 1447 } 1448 } 1449 #endif 1450 1451 void registerPageSwapCallback() 1452 { 1453 m_pageSwapCallbackRegistered = true; 1454 } 1455 1456 void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator, 1457 bool isPictureAfterFirstLayout, bool registerPageSwapCallback) 1458 { 1459 #if USE(ACCELERATED_COMPOSITING) 1460 if (m_glWebViewState) 1461 m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator, 1462 isPictureAfterFirstLayout); 1463 m_pageSwapCallbackRegistered |= registerPageSwapCallback; 1464 #endif 1465 1466 #if ENABLE(ANDROID_OVERFLOW_SCROLL) 1467 if (layer) { 1468 // TODO: the below tree copies are only necessary in software rendering 1469 LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0)); 1470 copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); 1471 } 1472 #endif 1473 SkSafeUnref(m_baseLayer); 1474 m_baseLayer = layer; 1475 CachedRoot* root = getFrameCache(DontAllowNewer); 1476 if (!root) 1477 return; 1478 root->resetLayers(); 1479 root->setRootLayer(compositeRoot()); 1480 } 1481 1482 void getTextSelectionRegion(SkRegion *region) 1483 { 1484 m_selectText.getSelectionRegion(getVisibleRect(), region, compositeRoot()); 1485 } 1486 1487 void getTextSelectionHandles(int* handles) 1488 { 1489 m_selectText.getSelectionHandles(handles, compositeRoot()); 1490 } 1491 1492 void replaceBaseContent(PictureSet* set) 1493 { 1494 if (!m_baseLayer) 1495 return; 1496 m_baseLayer->setContent(*set); 1497 delete set; 1498 } 1499 1500 void copyBaseContentToPicture(SkPicture* picture) 1501 { 1502 if (!m_baseLayer) 1503 return; 1504 PictureSet* content = m_baseLayer->content(); 1505 m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(), 1506 SkPicture::kUsePathBoundsForClip_RecordingFlag)); 1507 picture->endRecording(); 1508 } 1509 1510 bool hasContent() { 1511 if (!m_baseLayer) 1512 return false; 1513 return !m_baseLayer->content()->isEmpty(); 1514 } 1515 1516 void setFunctor(Functor* functor) { 1517 delete m_glDrawFunctor; 1518 m_glDrawFunctor = functor; 1519 } 1520 1521 Functor* getFunctor() { 1522 return m_glDrawFunctor; 1523 } 1524 1525 BaseLayerAndroid* getBaseLayer() { 1526 return m_baseLayer; 1527 } 1528 1529 void setVisibleRect(SkRect& visibleRect) { 1530 m_visibleRect = visibleRect; 1531 } 1532 1533 bool m_isDrawingPaused; 1534 private: // local state for WebView 1535 // private to getFrameCache(); other functions operate in a different thread 1536 CachedRoot* m_frameCacheUI; // navigation data ready for use 1537 WebViewCore* m_viewImpl; 1538 int m_generation; // associate unique ID with sent kit focus to match with ui 1539 SkPicture* m_navPictureUI; 1540 SkMSec m_ringAnimationEnd; 1541 // Corresponds to the same-named boolean on the java side. 1542 bool m_heightCanMeasure; 1543 int m_lastDx; 1544 SkMSec m_lastDxTime; 1545 SelectText m_selectText; 1546 FindOnPage m_findOnPage; 1547 CursorRing m_ring; 1548 BaseLayerAndroid* m_baseLayer; 1549 Functor* m_glDrawFunctor; 1550 #if USE(ACCELERATED_COMPOSITING) 1551 GLWebViewState* m_glWebViewState; 1552 bool m_pageSwapCallbackRegistered; 1553 #endif 1554 RenderSkinButton* m_buttonSkin; 1555 SkRect m_visibleRect; 1556 bool m_isHighEndGfx; 1557 }; // end of WebView class 1558 1559 1560 /** 1561 * This class holds a function pointer and parameters for calling drawGL into a specific 1562 * viewport. The pointer to the Functor will be put on a framework display list to be called 1563 * when the display list is replayed. 1564 */ 1565 class GLDrawFunctor : Functor { 1566 public: 1567 GLDrawFunctor(WebView* _wvInstance, 1568 bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 1569 WebCore::IntRect&, int, WebCore::IntRect&, 1570 jfloat, jint), 1571 WebCore::IntRect _viewRect, float _scale, int _extras) { 1572 wvInstance = _wvInstance; 1573 funcPtr = _funcPtr; 1574 viewRect = _viewRect; 1575 scale = _scale; 1576 extras = _extras; 1577 }; 1578 status_t operator()(int messageId, void* data) { 1579 if (viewRect.isEmpty()) { 1580 // NOOP operation if viewport is empty 1581 return 0; 1582 } 1583 1584 WebCore::IntRect inval; 1585 int titlebarHeight = webViewRect.height() - viewRect.height(); 1586 1587 uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data); 1588 WebCore::IntRect localViewRect = viewRect; 1589 if (info->isLayer) 1590 localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y()); 1591 1592 WebCore::IntRect clip(info->clipLeft, info->clipTop, 1593 info->clipRight - info->clipLeft, 1594 info->clipBottom - info->clipTop); 1595 TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer); 1596 1597 bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, 1598 titlebarHeight, clip, scale, extras); 1599 if (retVal) { 1600 IntRect finalInval; 1601 if (inval.isEmpty()) { 1602 finalInval = webViewRect; 1603 retVal = true; 1604 } else { 1605 finalInval.setX(webViewRect.x() + inval.x()); 1606 finalInval.setY(webViewRect.y() + titlebarHeight + inval.y()); 1607 finalInval.setWidth(inval.width()); 1608 finalInval.setHeight(inval.height()); 1609 } 1610 info->dirtyLeft = finalInval.x(); 1611 info->dirtyTop = finalInval.y(); 1612 info->dirtyRight = finalInval.maxX(); 1613 info->dirtyBottom = finalInval.maxY(); 1614 } 1615 // return 1 if invalidation needed, 0 otherwise 1616 return retVal ? 1 : 0; 1617 } 1618 void updateRect(WebCore::IntRect& _viewRect) { 1619 viewRect = _viewRect; 1620 } 1621 void updateViewRect(WebCore::IntRect& _viewRect) { 1622 webViewRect = _viewRect; 1623 } 1624 private: 1625 WebView* wvInstance; 1626 bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, 1627 WebCore::IntRect&, int, WebCore::IntRect&, float, int); 1628 WebCore::IntRect viewRect; 1629 WebCore::IntRect webViewRect; 1630 jfloat scale; 1631 jint extras; 1632 }; 1633 1634 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom) 1635 { 1636 jclass rectClass = env->FindClass("android/graphics/Rect"); 1637 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1638 jobject rect = env->NewObject(rectClass, init, x, y, right, bottom); 1639 env->DeleteLocalRef(rectClass); 1640 return rect; 1641 } 1642 1643 /* 1644 * Native JNI methods 1645 */ 1646 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) 1647 { 1648 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) 1649 ->m_cacheHitFrame->framePointer()); 1650 } 1651 1652 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) 1653 { 1654 WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj) 1655 ->m_cacheHitNode->originalAbsoluteBounds(); 1656 return createJavaRect(env, bounds.x(), bounds.y(), 1657 bounds.maxX(), bounds.maxY()); 1658 } 1659 1660 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) 1661 { 1662 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) 1663 ->m_cacheHitNode->nodePointer()); 1664 } 1665 1666 static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj) 1667 { 1668 return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin(); 1669 } 1670 1671 static void nativeClearCursor(JNIEnv *env, jobject obj) 1672 { 1673 WebView* view = GET_NATIVE_VIEW(env, obj); 1674 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1675 view->clearCursor(); 1676 } 1677 1678 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, 1679 jstring drawableDir, jboolean isHighEndGfx) 1680 { 1681 WTF::String dir = jstringToWtfString(env, drawableDir); 1682 WebView* webview = new WebView(env, obj, viewImpl, dir, isHighEndGfx); 1683 // NEED THIS OR SOMETHING LIKE IT! 1684 //Release(obj); 1685 } 1686 1687 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj) 1688 { 1689 WebView* view = GET_NATIVE_VIEW(env, obj); 1690 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1691 if (!root) 1692 return 0; 1693 const CachedFrame* frame = 0; 1694 (void) root->currentCursor(&frame); 1695 return reinterpret_cast<int>(frame ? frame->framePointer() : 0); 1696 } 1697 1698 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) 1699 { 1700 WebView* view = GET_NATIVE_VIEW(env, obj); 1701 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1702 return root ? root->currentCursor() : 0; 1703 } 1704 1705 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, 1706 const CachedFrame** frame) 1707 { 1708 WebView* view = GET_NATIVE_VIEW(env, obj); 1709 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1710 return root ? root->currentCursor(frame) : 0; 1711 } 1712 1713 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, 1714 const CachedFrame** frame) 1715 { 1716 WebView* view = GET_NATIVE_VIEW(env, obj); 1717 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1718 if (!root) 1719 return 0; 1720 const CachedNode* cursor = root->currentCursor(frame); 1721 if (cursor && cursor->wantsKeyEvents()) 1722 return cursor; 1723 return root->currentFocus(frame); 1724 } 1725 1726 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) 1727 { 1728 WebView* view = GET_NATIVE_VIEW(env, obj); 1729 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1730 if (!root) 1731 return false; 1732 const CachedNode* cursor = root->currentCursor(); 1733 if (!cursor || !cursor->isTextInput()) 1734 cursor = root->currentFocus(); 1735 if (!cursor || !cursor->isTextInput()) return false; 1736 return root->nextTextField(cursor, 0); 1737 } 1738 1739 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) 1740 { 1741 WebView* view = GET_NATIVE_VIEW(env, obj); 1742 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1743 return root ? root->currentFocus() : 0; 1744 } 1745 1746 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj, 1747 const CachedFrame** frame) 1748 { 1749 WebView* view = GET_NATIVE_VIEW(env, obj); 1750 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1751 return root ? root->currentFocus(frame) : 0; 1752 } 1753 1754 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj) 1755 { 1756 WebView* view = GET_NATIVE_VIEW(env, obj); 1757 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1758 if (!root) 1759 return 0; 1760 const CachedFrame* frame; 1761 const CachedNode* cursor = root->currentCursor(&frame); 1762 if (!cursor || !cursor->wantsKeyEvents()) 1763 cursor = root->currentFocus(&frame); 1764 return cursor ? frame->textInput(cursor) : 0; 1765 } 1766 1767 static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj) 1768 { 1769 const CachedNode* focus = getFocusNode(env, obj); 1770 if (!focus) return false; 1771 // Plugins handle shift and arrows whether or not they have focus. 1772 if (focus->isPlugin()) return true; 1773 const CachedNode* cursor = getCursorNode(env, obj); 1774 // ContentEditable nodes should only receive shift and arrows if they have 1775 // both the cursor and the focus. 1776 return cursor && cursor->nodePointer() == focus->nodePointer() 1777 && cursor->isContentEditable(); 1778 } 1779 1780 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) 1781 { 1782 const CachedFrame* frame; 1783 const CachedNode* node = getCursorNode(env, obj, &frame); 1784 WebCore::IntRect bounds = node ? node->bounds(frame) 1785 : WebCore::IntRect(0, 0, 0, 0); 1786 return createJavaRect(env, bounds.x(), bounds.y(), 1787 bounds.maxX(), bounds.maxY()); 1788 } 1789 1790 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) 1791 { 1792 const CachedNode* node = getCursorNode(env, obj); 1793 return reinterpret_cast<int>(node ? node->nodePointer() : 0); 1794 } 1795 1796 static jobject nativeCursorPosition(JNIEnv *env, jobject obj) 1797 { 1798 WebView* view = GET_NATIVE_VIEW(env, obj); 1799 const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1800 WebCore::IntPoint pos = WebCore::IntPoint(0, 0); 1801 if (root) 1802 root->getSimulatedMousePosition(&pos); 1803 jclass pointClass = env->FindClass("android/graphics/Point"); 1804 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); 1805 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); 1806 env->DeleteLocalRef(pointClass); 1807 return point; 1808 } 1809 1810 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 1811 { 1812 if (obj) { 1813 int L, T, R, B; 1814 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 1815 return WebCore::IntRect(L, T, R - L, B - T); 1816 } else 1817 return WebCore::IntRect(); 1818 } 1819 1820 static SkRect jrectf_to_rect(JNIEnv* env, jobject obj) 1821 { 1822 SkRect rect = SkRect::MakeEmpty(); 1823 if (obj) 1824 GraphicsJNI::jrectf_to_rect(env, obj, &rect); 1825 return rect; 1826 } 1827 1828 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) 1829 { 1830 const CachedFrame* frame; 1831 const CachedNode* node = getCursorNode(env, obj, &frame); 1832 return node ? node->bounds(frame).intersects( 1833 jrect_to_webrect(env, visRect)) : false; 1834 } 1835 1836 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) 1837 { 1838 const CachedNode* node = getCursorNode(env, obj); 1839 return node ? node->isAnchor() : false; 1840 } 1841 1842 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) 1843 { 1844 const CachedNode* node = getCursorNode(env, obj); 1845 return node ? node->isTextInput() : false; 1846 } 1847 1848 static jobject nativeCursorText(JNIEnv *env, jobject obj) 1849 { 1850 const CachedNode* node = getCursorNode(env, obj); 1851 if (!node) 1852 return 0; 1853 WTF::String value = node->getExport(); 1854 return wtfStringToJstring(env, value); 1855 } 1856 1857 static void nativeDebugDump(JNIEnv *env, jobject obj) 1858 { 1859 #if DUMP_NAV_CACHE 1860 WebView* view = GET_NATIVE_VIEW(env, obj); 1861 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1862 view->debugDump(); 1863 #endif 1864 } 1865 1866 static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, 1867 jobject visible, jint color, 1868 jint extras, jboolean split) { 1869 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); 1870 WebView* webView = GET_NATIVE_VIEW(env, obj); 1871 SkRect visibleRect = jrectf_to_rect(env, visible); 1872 webView->setVisibleRect(visibleRect); 1873 PictureSet* pictureSet = webView->draw(canvas, color, extras, split); 1874 return reinterpret_cast<jint>(pictureSet); 1875 } 1876 1877 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, 1878 jobject jrect, jobject jviewrect, 1879 jobject jvisiblerect, 1880 jfloat scale, jint extras) { 1881 WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); 1882 WebView *wvInstance = (WebView*) nativeView; 1883 SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); 1884 wvInstance->setVisibleRect(visibleRect); 1885 1886 GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, 1887 &android::WebView::drawGL, viewRect, scale, extras); 1888 wvInstance->setFunctor((Functor*) functor); 1889 1890 WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); 1891 functor->updateViewRect(webViewRect); 1892 1893 return (jint)functor; 1894 } 1895 1896 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, 1897 jobject jviewrect, jobject jvisiblerect) { 1898 WebView *wvInstance = GET_NATIVE_VIEW(env, obj); 1899 if (wvInstance) { 1900 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); 1901 if (functor) { 1902 WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); 1903 functor->updateRect(viewRect); 1904 1905 SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); 1906 wvInstance->setVisibleRect(visibleRect); 1907 1908 WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); 1909 functor->updateViewRect(webViewRect); 1910 } 1911 } 1912 } 1913 1914 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint nativeView) 1915 { 1916 // only call in software rendering, initialize and evaluate animations 1917 #if USE(ACCELERATED_COMPOSITING) 1918 LayerAndroid* root = ((WebView*)nativeView)->compositeRoot(); 1919 if (root) { 1920 root->initAnimations(); 1921 return root->evaluateAnimations(); 1922 } 1923 #endif 1924 return false; 1925 } 1926 1927 static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval, 1928 jboolean showVisualIndicator, 1929 jboolean isPictureAfterFirstLayout, 1930 jboolean registerPageSwapCallback) 1931 { 1932 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); 1933 SkRegion invalRegion; 1934 if (inval) 1935 invalRegion = *GraphicsJNI::getNativeRegion(env, inval); 1936 GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator, 1937 isPictureAfterFirstLayout, 1938 registerPageSwapCallback); 1939 } 1940 1941 static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jint view, 1942 jobject region) 1943 { 1944 if (!region) 1945 return; 1946 SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region); 1947 ((WebView*)view)->getTextSelectionRegion(nregion); 1948 } 1949 1950 static void nativeGetSelectionHandles(JNIEnv *env, jobject obj, jint view, 1951 jintArray arr) 1952 { 1953 int handles[4]; 1954 ((WebView*)view)->getTextSelectionHandles(handles); 1955 env->SetIntArrayRegion(arr, 0, 4, handles); 1956 checkException(env); 1957 } 1958 1959 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj) 1960 { 1961 return GET_NATIVE_VIEW(env, obj)->getBaseLayer(); 1962 } 1963 1964 static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content) 1965 { 1966 PictureSet* set = reinterpret_cast<PictureSet*>(content); 1967 GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set); 1968 } 1969 1970 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) 1971 { 1972 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); 1973 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); 1974 } 1975 1976 static bool nativeHasContent(JNIEnv *env, jobject obj) 1977 { 1978 return GET_NATIVE_VIEW(env, obj)->hasContent(); 1979 } 1980 1981 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) 1982 { 1983 WebView* view = GET_NATIVE_VIEW(env, obj); 1984 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1985 WTF::String uri = view->imageURI(x, y); 1986 return wtfStringToJstring(env, uri); 1987 } 1988 1989 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) 1990 { 1991 WebView* view = GET_NATIVE_VIEW(env, obj); 1992 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1993 if (!root) 1994 return 0; 1995 const CachedFrame* frame = 0; 1996 const CachedNode* cursor = root->currentCursor(&frame); 1997 if (!cursor || !cursor->wantsKeyEvents()) 1998 (void) root->currentFocus(&frame); 1999 return reinterpret_cast<int>(frame ? frame->framePointer() : 0); 2000 } 2001 2002 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) 2003 { 2004 const CachedInput* input = getInputCandidate(env, obj); 2005 return input && input->getType() == CachedInput::PASSWORD; 2006 } 2007 2008 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) 2009 { 2010 const CachedInput* input = getInputCandidate(env, obj); 2011 return input ? input->isRtlText() : false; 2012 } 2013 2014 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) 2015 { 2016 const CachedNode* node = getFocusCandidate(env, obj, 0); 2017 return node ? node->isTextInput() : false; 2018 } 2019 2020 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) 2021 { 2022 const CachedInput* input = getInputCandidate(env, obj); 2023 return input ? input->maxLength() : false; 2024 } 2025 2026 static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj) 2027 { 2028 const CachedInput* input = getInputCandidate(env, obj); 2029 return input ? input->autoComplete() : false; 2030 } 2031 2032 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) 2033 { 2034 const CachedInput* input = getInputCandidate(env, obj); 2035 if (!input) 2036 return 0; 2037 const WTF::String& name = input->name(); 2038 return wtfStringToJstring(env, name); 2039 } 2040 2041 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) 2042 { 2043 const CachedFrame* frame; 2044 const CachedNode* node = getFocusCandidate(env, obj, &frame); 2045 WebCore::IntRect bounds = node ? node->originalAbsoluteBounds() 2046 : WebCore::IntRect(0, 0, 0, 0); 2047 // Inset the rect by 1 unit, so that the focus candidate's border can still 2048 // be seen behind it. 2049 return createJavaRect(env, bounds.x(), bounds.y(), 2050 bounds.maxX(), bounds.maxY()); 2051 } 2052 2053 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) 2054 { 2055 const CachedInput* input = getInputCandidate(env, obj); 2056 if (!input) 2057 return 0; 2058 // Note that the Java Rect is being used to pass four integers, rather than 2059 // being used as an actual rectangle. 2060 return createJavaRect(env, input->paddingLeft(), input->paddingTop(), 2061 input->paddingRight(), input->paddingBottom()); 2062 } 2063 2064 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) 2065 { 2066 const CachedNode* node = getFocusCandidate(env, obj, 0); 2067 return reinterpret_cast<int>(node ? node->nodePointer() : 0); 2068 } 2069 2070 static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj) 2071 { 2072 const CachedInput* input = getInputCandidate(env, obj); 2073 return input ? input->spellcheck() : false; 2074 } 2075 2076 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) 2077 { 2078 const CachedNode* node = getFocusCandidate(env, obj, 0); 2079 if (!node) 2080 return 0; 2081 WTF::String value = node->getExport(); 2082 return wtfStringToJstring(env, value); 2083 } 2084 2085 static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj) 2086 { 2087 const CachedInput* input = getInputCandidate(env, obj); 2088 return input ? input->lineHeight() : 0; 2089 } 2090 2091 static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) 2092 { 2093 const CachedInput* input = getInputCandidate(env, obj); 2094 return input ? input->textSize() : 0.f; 2095 } 2096 2097 static int nativeFocusCandidateType(JNIEnv *env, jobject obj) 2098 { 2099 const CachedInput* input = getInputCandidate(env, obj); 2100 if (!input) 2101 return CachedInput::NONE; 2102 2103 if (input->isTextArea()) 2104 return CachedInput::TEXT_AREA; 2105 2106 return input->getType(); 2107 } 2108 2109 static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj) 2110 { 2111 const CachedFrame* frame = 0; 2112 const CachedNode* node = getFocusNode(env, obj, &frame); 2113 if (!node || !frame) 2114 return -1; 2115 const CachedLayer* layer = frame->layer(node); 2116 if (!layer) 2117 return -1; 2118 return layer->uniqueId(); 2119 } 2120 2121 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) 2122 { 2123 const CachedNode* node = getFocusNode(env, obj); 2124 return node ? node->isPlugin() : false; 2125 } 2126 2127 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj) 2128 { 2129 const CachedFrame* frame; 2130 const CachedNode* node = getFocusNode(env, obj, &frame); 2131 WebCore::IntRect bounds = node ? node->bounds(frame) 2132 : WebCore::IntRect(0, 0, 0, 0); 2133 return createJavaRect(env, bounds.x(), bounds.y(), 2134 bounds.maxX(), bounds.maxY()); 2135 } 2136 2137 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) 2138 { 2139 const CachedNode* node = getFocusNode(env, obj); 2140 return node ? reinterpret_cast<int>(node->nodePointer()) : 0; 2141 } 2142 2143 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { 2144 WebView* view = GET_NATIVE_VIEW(env, jwebview); 2145 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2146 return view->cursorWantsKeyEvents(); 2147 } 2148 2149 static void nativeHideCursor(JNIEnv *env, jobject obj) 2150 { 2151 WebView* view = GET_NATIVE_VIEW(env, obj); 2152 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2153 view->hideCursor(); 2154 } 2155 2156 static void nativeInstrumentReport(JNIEnv *env, jobject obj) 2157 { 2158 #ifdef ANDROID_INSTRUMENT 2159 TimeCounter::reportNow(); 2160 #endif 2161 } 2162 2163 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) 2164 { 2165 WebView* view = GET_NATIVE_VIEW(env, obj); 2166 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2167 WebCore::IntRect rect = jrect_to_webrect(env, jrect); 2168 view->selectBestAt(rect); 2169 } 2170 2171 static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y) 2172 { 2173 WebView* view = GET_NATIVE_VIEW(env, obj); 2174 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2175 WebCore::IntRect rect = IntRect(x, y , 1, 1); 2176 view->selectBestAt(rect); 2177 if (view->hasCursorNode()) 2178 view->showCursorUntimed(); 2179 } 2180 2181 static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer) 2182 { 2183 SkRect r; 2184 #if USE(ACCELERATED_COMPOSITING) 2185 LayerAndroid* layer = (LayerAndroid*) jlayer; 2186 r = layer->bounds(); 2187 #else 2188 r.setEmpty(); 2189 #endif 2190 SkIRect irect; 2191 r.round(&irect); 2192 jclass rectClass = env->FindClass("android/graphics/Rect"); 2193 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 2194 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, 2195 irect.fRight, irect.fBottom); 2196 env->DeleteLocalRef(rectClass); 2197 return rect; 2198 } 2199 2200 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) 2201 { 2202 SkIRect irect = jrect_to_webrect(env, jrect); 2203 #if USE(ACCELERATED_COMPOSITING) 2204 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); 2205 if (root) { 2206 SkRect rect; 2207 rect.set(irect); 2208 rect = root->subtractLayers(rect); 2209 rect.round(&irect); 2210 } 2211 #endif 2212 jclass rectClass = env->FindClass("android/graphics/Rect"); 2213 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 2214 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, 2215 irect.fRight, irect.fBottom); 2216 env->DeleteLocalRef(rectClass); 2217 return rect; 2218 } 2219 2220 static jint nativeTextGeneration(JNIEnv *env, jobject obj) 2221 { 2222 WebView* view = GET_NATIVE_VIEW(env, obj); 2223 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 2224 return root ? root->textGeneration() : 0; 2225 } 2226 2227 static bool nativePointInNavCache(JNIEnv *env, jobject obj, 2228 int x, int y, int slop) 2229 { 2230 return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop); 2231 } 2232 2233 static bool nativeMotionUp(JNIEnv *env, jobject obj, 2234 int x, int y, int slop) 2235 { 2236 WebView* view = GET_NATIVE_VIEW(env, obj); 2237 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2238 return view->motionUp(x, y, slop); 2239 } 2240 2241 static bool nativeHasCursorNode(JNIEnv *env, jobject obj) 2242 { 2243 return GET_NATIVE_VIEW(env, obj)->hasCursorNode(); 2244 } 2245 2246 static bool nativeHasFocusNode(JNIEnv *env, jobject obj) 2247 { 2248 return GET_NATIVE_VIEW(env, obj)->hasFocusNode(); 2249 } 2250 2251 static bool nativeMoveCursor(JNIEnv *env, jobject obj, 2252 int key, int count, bool ignoreScroll) 2253 { 2254 WebView* view = GET_NATIVE_VIEW(env, obj); 2255 DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); 2256 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2257 return view->moveCursor(key, count, ignoreScroll); 2258 } 2259 2260 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) 2261 { 2262 WebView* view = GET_NATIVE_VIEW(env, obj); 2263 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2264 view->setFindIsUp(isUp); 2265 } 2266 2267 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj) 2268 { 2269 GET_NATIVE_VIEW(env, obj)->setFindIsEmpty(); 2270 } 2271 2272 static void nativeShowCursorTimed(JNIEnv *env, jobject obj) 2273 { 2274 GET_NATIVE_VIEW(env, obj)->showCursorTimed(); 2275 } 2276 2277 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) 2278 { 2279 WebView* view = GET_NATIVE_VIEW(env, obj); 2280 LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); 2281 view->setHeightCanMeasure(measure); 2282 } 2283 2284 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj) 2285 { 2286 WebView* view = GET_NATIVE_VIEW(env, obj); 2287 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2288 jclass rectClass = env->FindClass("android/graphics/Rect"); 2289 LOG_ASSERT(rectClass, "Could not find Rect class!"); 2290 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 2291 LOG_ASSERT(init, "Could not find constructor for Rect"); 2292 WebCore::IntRect webRect; 2293 view->cursorRingBounds(&webRect); 2294 jobject rect = env->NewObject(rectClass, init, webRect.x(), 2295 webRect.y(), webRect.maxX(), webRect.maxY()); 2296 env->DeleteLocalRef(rectClass); 2297 return rect; 2298 } 2299 2300 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, 2301 jstring findUpper, jboolean sameAsLastSearch) 2302 { 2303 // If one or the other is null, do not search. 2304 if (!(findLower && findUpper)) 2305 return 0; 2306 // Obtain the characters for both the lower case string and the upper case 2307 // string representing the same word. 2308 const jchar* findLowerChars = env->GetStringChars(findLower, 0); 2309 const jchar* findUpperChars = env->GetStringChars(findUpper, 0); 2310 // If one or the other is null, do not search. 2311 if (!(findLowerChars && findUpperChars)) { 2312 if (findLowerChars) 2313 env->ReleaseStringChars(findLower, findLowerChars); 2314 if (findUpperChars) 2315 env->ReleaseStringChars(findUpper, findUpperChars); 2316 checkException(env); 2317 return 0; 2318 } 2319 WebView* view = GET_NATIVE_VIEW(env, obj); 2320 LOG_ASSERT(view, "view not set in nativeFindAll"); 2321 CachedRoot* root = view->getFrameCache(WebView::AllowNewer); 2322 if (!root) { 2323 env->ReleaseStringChars(findLower, findLowerChars); 2324 env->ReleaseStringChars(findUpper, findUpperChars); 2325 checkException(env); 2326 return 0; 2327 } 2328 int length = env->GetStringLength(findLower); 2329 // If the lengths of the strings do not match, then they are not the same 2330 // word, so do not search. 2331 if (!length || env->GetStringLength(findUpper) != length) { 2332 env->ReleaseStringChars(findLower, findLowerChars); 2333 env->ReleaseStringChars(findUpper, findUpperChars); 2334 checkException(env); 2335 return 0; 2336 } 2337 int width = root->documentWidth(); 2338 int height = root->documentHeight(); 2339 // Create a FindCanvas, which allows us to fake draw into it so we can 2340 // figure out where our search string is rendered (and how many times). 2341 FindCanvas canvas(width, height, (const UChar*) findLowerChars, 2342 (const UChar*) findUpperChars, length << 1); 2343 SkBitmap bitmap; 2344 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); 2345 canvas.setBitmapDevice(bitmap); 2346 root->draw(canvas); 2347 WTF::Vector<MatchInfo>* matches = canvas.detachMatches(); 2348 // With setMatches, the WebView takes ownership of matches 2349 view->setMatches(matches, sameAsLastSearch); 2350 2351 env->ReleaseStringChars(findLower, findLowerChars); 2352 env->ReleaseStringChars(findUpper, findUpperChars); 2353 checkException(env); 2354 return canvas.found(); 2355 } 2356 2357 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward) 2358 { 2359 WebView* view = GET_NATIVE_VIEW(env, obj); 2360 LOG_ASSERT(view, "view not set in nativeFindNext"); 2361 view->findNext(forward); 2362 } 2363 2364 static int nativeFindIndex(JNIEnv *env, jobject obj) 2365 { 2366 WebView* view = GET_NATIVE_VIEW(env, obj); 2367 LOG_ASSERT(view, "view not set in nativeFindIndex"); 2368 return view->currentMatchIndex(); 2369 } 2370 2371 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation) 2372 { 2373 WebView* view = GET_NATIVE_VIEW(env, obj); 2374 LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield"); 2375 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 2376 if (!root) 2377 return; 2378 const CachedNode* cachedFocusNode = root->currentFocus(); 2379 if (!cachedFocusNode || !cachedFocusNode->isTextInput()) 2380 return; 2381 WTF::String webcoreString = jstringToWtfString(env, updatedText); 2382 (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString); 2383 root->setTextGeneration(generation); 2384 checkException(env); 2385 } 2386 2387 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y, 2388 jfloat scale) 2389 { 2390 WebView* view = GET_NATIVE_VIEW(env, obj); 2391 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2392 if (!view) 2393 return -1; 2394 return view->getBlockLeftEdge(x, y, scale); 2395 } 2396 2397 static void nativeDestroy(JNIEnv *env, jobject obj) 2398 { 2399 WebView* view = GET_NATIVE_VIEW(env, obj); 2400 LOGD("nativeDestroy view: %p", view); 2401 LOG_ASSERT(view, "view not set in nativeDestroy"); 2402 delete view; 2403 } 2404 2405 static void nativeStopGL(JNIEnv *env, jobject obj) 2406 { 2407 GET_NATIVE_VIEW(env, obj)->stopGL(); 2408 } 2409 2410 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) 2411 { 2412 WebView* view = GET_NATIVE_VIEW(env, obj); 2413 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 2414 if (!root) 2415 return false; 2416 const CachedNode* current = root->currentCursor(); 2417 if (!current || !current->isTextInput()) 2418 current = root->currentFocus(); 2419 if (!current || !current->isTextInput()) 2420 return false; 2421 const CachedFrame* frame; 2422 const CachedNode* next = root->nextTextField(current, &frame); 2423 if (!next) 2424 return false; 2425 const WebCore::IntRect& bounds = next->bounds(frame); 2426 root->rootHistory()->setMouseBounds(bounds); 2427 view->getWebViewCore()->updateCursorBounds(root, frame, next); 2428 view->showCursorUntimed(); 2429 root->setCursor(const_cast<CachedFrame*>(frame), 2430 const_cast<CachedNode*>(next)); 2431 view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()), 2432 static_cast<WebCore::Node*>(next->nodePointer())); 2433 if (!next->isInLayer()) 2434 view->scrollRectOnScreen(bounds); 2435 view->getWebViewCore()->m_moveGeneration++; 2436 return true; 2437 } 2438 2439 static int nativeMoveGeneration(JNIEnv *env, jobject obj) 2440 { 2441 WebView* view = GET_NATIVE_VIEW(env, obj); 2442 if (!view) 2443 return 0; 2444 return view->moveGeneration(); 2445 } 2446 2447 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y) 2448 { 2449 GET_NATIVE_VIEW(env, obj)->moveSelection(x, y); 2450 } 2451 2452 static void nativeResetSelection(JNIEnv *env, jobject obj) 2453 { 2454 return GET_NATIVE_VIEW(env, obj)->resetSelection(); 2455 } 2456 2457 static jobject nativeSelectableText(JNIEnv* env, jobject obj) 2458 { 2459 IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText(); 2460 jclass pointClass = env->FindClass("android/graphics/Point"); 2461 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); 2462 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); 2463 env->DeleteLocalRef(pointClass); 2464 return point; 2465 } 2466 2467 static void nativeSelectAll(JNIEnv* env, jobject obj) 2468 { 2469 GET_NATIVE_VIEW(env, obj)->selectAll(); 2470 } 2471 2472 static void nativeSetExtendSelection(JNIEnv *env, jobject obj) 2473 { 2474 GET_NATIVE_VIEW(env, obj)->setExtendSelection(); 2475 } 2476 2477 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y) 2478 { 2479 return GET_NATIVE_VIEW(env, obj)->startSelection(x, y); 2480 } 2481 2482 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y) 2483 { 2484 return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y); 2485 } 2486 2487 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y) 2488 { 2489 GET_NATIVE_VIEW(env, obj)->extendSelection(x, y); 2490 } 2491 2492 static jobject nativeGetSelection(JNIEnv *env, jobject obj) 2493 { 2494 WebView* view = GET_NATIVE_VIEW(env, obj); 2495 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2496 String selection = view->getSelection(); 2497 return wtfStringToJstring(env, selection); 2498 } 2499 2500 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y) 2501 { 2502 return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y); 2503 } 2504 2505 static jint nativeSelectionX(JNIEnv *env, jobject obj) 2506 { 2507 return GET_NATIVE_VIEW(env, obj)->selectionX(); 2508 } 2509 2510 static jint nativeSelectionY(JNIEnv *env, jobject obj) 2511 { 2512 return GET_NATIVE_VIEW(env, obj)->selectionY(); 2513 } 2514 2515 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jint nativeView, 2516 jboolean set, jfloat scale, jint x, jint y) 2517 { 2518 ((WebView*)nativeView)->setSelectionPointer(set, scale, x, y); 2519 } 2520 2521 static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj) 2522 { 2523 GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback(); 2524 } 2525 2526 static void nativeTileProfilingStart(JNIEnv *env, jobject obj) 2527 { 2528 TilesManager::instance()->getProfiler()->start(); 2529 } 2530 2531 static float nativeTileProfilingStop(JNIEnv *env, jobject obj) 2532 { 2533 return TilesManager::instance()->getProfiler()->stop(); 2534 } 2535 2536 static void nativeTileProfilingClear(JNIEnv *env, jobject obj) 2537 { 2538 TilesManager::instance()->getProfiler()->clear(); 2539 } 2540 2541 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj) 2542 { 2543 return TilesManager::instance()->getProfiler()->numFrames(); 2544 } 2545 2546 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame) 2547 { 2548 return TilesManager::instance()->getProfiler()->numTilesInFrame(frame); 2549 } 2550 2551 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 2552 { 2553 WTF::String key = jstringToWtfString(env, jkey); 2554 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 2555 2556 if (key == "left") 2557 return record->left; 2558 if (key == "top") 2559 return record->top; 2560 if (key == "right") 2561 return record->right; 2562 if (key == "bottom") 2563 return record->bottom; 2564 if (key == "level") 2565 return record->level; 2566 if (key == "isReady") 2567 return record->isReady ? 1 : 0; 2568 return -1; 2569 } 2570 2571 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey) 2572 { 2573 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile); 2574 return record->scale; 2575 } 2576 2577 #ifdef ANDROID_DUMP_DISPLAY_TREE 2578 static void dumpToFile(const char text[], void* file) { 2579 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file)); 2580 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file)); 2581 } 2582 #endif 2583 2584 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue) 2585 { 2586 WTF::String key = jstringToWtfString(env, jkey); 2587 WTF::String value = jstringToWtfString(env, jvalue); 2588 if (key == "inverted") { 2589 if (value == "true") 2590 TilesManager::instance()->setInvertedScreen(true); 2591 else 2592 TilesManager::instance()->setInvertedScreen(false); 2593 return true; 2594 } 2595 else if (key == "inverted_contrast") { 2596 float contrast = value.toFloat(); 2597 TilesManager::instance()->setInvertedScreenContrast(contrast); 2598 return true; 2599 } 2600 else if (key == "enable_cpu_upload_path") { 2601 TilesManager::instance()->transferQueue()->setTextureUploadType( 2602 value == "true" ? CpuUpload : GpuUpload); 2603 return true; 2604 } 2605 else if (key == "use_minimal_memory") { 2606 TilesManager::instance()->setUseMinimalMemory(value == "true"); 2607 return true; 2608 } 2609 return false; 2610 } 2611 2612 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key) 2613 { 2614 return 0; 2615 } 2616 2617 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level) 2618 { 2619 if (TilesManager::hardwareAccelerationEnabled()) { 2620 bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN); 2621 TilesManager::instance()->deallocateTextures(freeAllTextures); 2622 } 2623 } 2624 2625 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) 2626 { 2627 #ifdef ANDROID_DUMP_DISPLAY_TREE 2628 WebView* view = GET_NATIVE_VIEW(env, jwebview); 2629 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2630 2631 if (view && view->getWebViewCore()) { 2632 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); 2633 if (file) { 2634 SkFormatDumper dumper(dumpToFile, file); 2635 // dump the URL 2636 if (jurl) { 2637 const char* str = env->GetStringUTFChars(jurl, 0); 2638 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); 2639 dumpToFile(str, file); 2640 env->ReleaseStringUTFChars(jurl, str); 2641 } 2642 // now dump the display tree 2643 SkDumpCanvas canvas(&dumper); 2644 // this will playback the picture into the canvas, which will 2645 // spew its contents to the dumper 2646 view->draw(&canvas, 0, 0, false); 2647 // we're done with the file now 2648 fwrite("\n", 1, 1, file); 2649 fclose(file); 2650 } 2651 #if USE(ACCELERATED_COMPOSITING) 2652 const LayerAndroid* rootLayer = view->compositeRoot(); 2653 if (rootLayer) { 2654 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); 2655 if (file) { 2656 rootLayer->dumpLayers(file, 0); 2657 fclose(file); 2658 } 2659 } 2660 #endif 2661 } 2662 #endif 2663 } 2664 2665 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y, 2666 jobject rect, jobject bounds) 2667 { 2668 WebView* view = GET_NATIVE_VIEW(env, jwebview); 2669 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2670 SkIRect nativeRect, nativeBounds; 2671 int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds); 2672 if (rect) 2673 GraphicsJNI::irect_to_jrect(nativeRect, env, rect); 2674 if (bounds) 2675 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds); 2676 return id; 2677 } 2678 2679 static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, 2680 jint y) 2681 { 2682 #if ENABLE(ANDROID_OVERFLOW_SCROLL) 2683 WebView* view = GET_NATIVE_VIEW(env, obj); 2684 view->scrollLayer(layerId, x, y); 2685 2686 //TODO: the below only needed for the SW rendering path 2687 LayerAndroid* root = view->compositeRoot(); 2688 if (!root) 2689 return false; 2690 LayerAndroid* layer = root->findById(layerId); 2691 if (!layer || !layer->contentIsScrollable()) 2692 return false; 2693 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); 2694 #endif 2695 return false; 2696 } 2697 2698 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling) 2699 { 2700 WebView* view = GET_NATIVE_VIEW(env, jwebview); 2701 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 2702 view->setIsScrolling(isScrolling); 2703 } 2704 2705 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled) 2706 { 2707 BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster); 2708 } 2709 2710 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj) 2711 { 2712 WebView* view = GET_NATIVE_VIEW(env, obj); 2713 BaseLayerAndroid* baseLayer = view->getBaseLayer(); 2714 if (baseLayer) { 2715 WebCore::Color color = baseLayer->getBackgroundColor(); 2716 if (color.isValid()) 2717 return SkColorSetARGB(color.alpha(), color.red(), 2718 color.green(), color.blue()); 2719 } 2720 return SK_ColorWHITE; 2721 } 2722 2723 static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView, 2724 jboolean pause) 2725 { 2726 ((WebView*)nativeView)->m_isDrawingPaused = pause; 2727 } 2728 2729 /* 2730 * JNI registration 2731 */ 2732 static JNINativeMethod gJavaWebViewMethods[] = { 2733 { "nativeCacheHitFramePointer", "()I", 2734 (void*) nativeCacheHitFramePointer }, 2735 { "nativeCacheHitIsPlugin", "()Z", 2736 (void*) nativeCacheHitIsPlugin }, 2737 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;", 2738 (void*) nativeCacheHitNodeBounds }, 2739 { "nativeCacheHitNodePointer", "()I", 2740 (void*) nativeCacheHitNodePointer }, 2741 { "nativeClearCursor", "()V", 2742 (void*) nativeClearCursor }, 2743 { "nativeCreate", "(ILjava/lang/String;Z)V", 2744 (void*) nativeCreate }, 2745 { "nativeCursorFramePointer", "()I", 2746 (void*) nativeCursorFramePointer }, 2747 { "nativePageShouldHandleShiftAndArrows", "()Z", 2748 (void*) nativePageShouldHandleShiftAndArrows }, 2749 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;", 2750 (void*) nativeCursorNodeBounds }, 2751 { "nativeCursorNodePointer", "()I", 2752 (void*) nativeCursorNodePointer }, 2753 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z", 2754 (void*) nativeCursorIntersects }, 2755 { "nativeCursorIsAnchor", "()Z", 2756 (void*) nativeCursorIsAnchor }, 2757 { "nativeCursorIsTextInput", "()Z", 2758 (void*) nativeCursorIsTextInput }, 2759 { "nativeCursorPosition", "()Landroid/graphics/Point;", 2760 (void*) nativeCursorPosition }, 2761 { "nativeCursorText", "()Ljava/lang/String;", 2762 (void*) nativeCursorText }, 2763 { "nativeCursorWantsKeyEvents", "()Z", 2764 (void*)nativeCursorWantsKeyEvents }, 2765 { "nativeDebugDump", "()V", 2766 (void*) nativeDebugDump }, 2767 { "nativeDestroy", "()V", 2768 (void*) nativeDestroy }, 2769 { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I", 2770 (void*) nativeDraw }, 2771 { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", 2772 (void*) nativeGetDrawGLFunction }, 2773 { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;)V", 2774 (void*) nativeUpdateDrawGLFunction }, 2775 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", 2776 (void*) nativeDumpDisplayTree }, 2777 { "nativeEvaluateLayersAnimations", "(I)Z", 2778 (void*) nativeEvaluateLayersAnimations }, 2779 { "nativeExtendSelection", "(II)V", 2780 (void*) nativeExtendSelection }, 2781 { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I", 2782 (void*) nativeFindAll }, 2783 { "nativeFindNext", "(Z)V", 2784 (void*) nativeFindNext }, 2785 { "nativeFindIndex", "()I", 2786 (void*) nativeFindIndex}, 2787 { "nativeFocusCandidateFramePointer", "()I", 2788 (void*) nativeFocusCandidateFramePointer }, 2789 { "nativeFocusCandidateHasNextTextfield", "()Z", 2790 (void*) focusCandidateHasNextTextfield }, 2791 { "nativeFocusCandidateIsPassword", "()Z", 2792 (void*) nativeFocusCandidateIsPassword }, 2793 { "nativeFocusCandidateIsRtlText", "()Z", 2794 (void*) nativeFocusCandidateIsRtlText }, 2795 { "nativeFocusCandidateIsTextInput", "()Z", 2796 (void*) nativeFocusCandidateIsTextInput }, 2797 { "nativeFocusCandidateLineHeight", "()I", 2798 (void*) nativeFocusCandidateLineHeight }, 2799 { "nativeFocusCandidateMaxLength", "()I", 2800 (void*) nativeFocusCandidateMaxLength }, 2801 { "nativeFocusCandidateIsAutoComplete", "()Z", 2802 (void*) nativeFocusCandidateIsAutoComplete }, 2803 { "nativeFocusCandidateIsSpellcheck", "()Z", 2804 (void*) nativeFocusCandidateIsSpellcheck }, 2805 { "nativeFocusCandidateName", "()Ljava/lang/String;", 2806 (void*) nativeFocusCandidateName }, 2807 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;", 2808 (void*) nativeFocusCandidateNodeBounds }, 2809 { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;", 2810 (void*) nativeFocusCandidatePaddingRect }, 2811 { "nativeFocusCandidatePointer", "()I", 2812 (void*) nativeFocusCandidatePointer }, 2813 { "nativeFocusCandidateText", "()Ljava/lang/String;", 2814 (void*) nativeFocusCandidateText }, 2815 { "nativeFocusCandidateTextSize", "()F", 2816 (void*) nativeFocusCandidateTextSize }, 2817 { "nativeFocusCandidateType", "()I", 2818 (void*) nativeFocusCandidateType }, 2819 { "nativeFocusCandidateLayerId", "()I", 2820 (void*) nativeFocusCandidateLayerId }, 2821 { "nativeFocusIsPlugin", "()Z", 2822 (void*) nativeFocusIsPlugin }, 2823 { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;", 2824 (void*) nativeFocusNodeBounds }, 2825 { "nativeFocusNodePointer", "()I", 2826 (void*) nativeFocusNodePointer }, 2827 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", 2828 (void*) nativeGetCursorRingBounds }, 2829 { "nativeGetSelection", "()Ljava/lang/String;", 2830 (void*) nativeGetSelection }, 2831 { "nativeHasCursorNode", "()Z", 2832 (void*) nativeHasCursorNode }, 2833 { "nativeHasFocusNode", "()Z", 2834 (void*) nativeHasFocusNode }, 2835 { "nativeHideCursor", "()V", 2836 (void*) nativeHideCursor }, 2837 { "nativeHitSelection", "(II)Z", 2838 (void*) nativeHitSelection }, 2839 { "nativeImageURI", "(II)Ljava/lang/String;", 2840 (void*) nativeImageURI }, 2841 { "nativeInstrumentReport", "()V", 2842 (void*) nativeInstrumentReport }, 2843 { "nativeLayerBounds", "(I)Landroid/graphics/Rect;", 2844 (void*) nativeLayerBounds }, 2845 { "nativeMotionUp", "(III)Z", 2846 (void*) nativeMotionUp }, 2847 { "nativeMoveCursor", "(IIZ)Z", 2848 (void*) nativeMoveCursor }, 2849 { "nativeMoveCursorToNextTextInput", "()Z", 2850 (void*) nativeMoveCursorToNextTextInput }, 2851 { "nativeMoveGeneration", "()I", 2852 (void*) nativeMoveGeneration }, 2853 { "nativeMoveSelection", "(II)V", 2854 (void*) nativeMoveSelection }, 2855 { "nativePointInNavCache", "(III)Z", 2856 (void*) nativePointInNavCache }, 2857 { "nativeResetSelection", "()V", 2858 (void*) nativeResetSelection }, 2859 { "nativeSelectableText", "()Landroid/graphics/Point;", 2860 (void*) nativeSelectableText }, 2861 { "nativeSelectAll", "()V", 2862 (void*) nativeSelectAll }, 2863 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V", 2864 (void*) nativeSelectBestAt }, 2865 { "nativeSelectAt", "(II)V", 2866 (void*) nativeSelectAt }, 2867 { "nativeSelectionX", "()I", 2868 (void*) nativeSelectionX }, 2869 { "nativeSelectionY", "()I", 2870 (void*) nativeSelectionY }, 2871 { "nativeSetExtendSelection", "()V", 2872 (void*) nativeSetExtendSelection }, 2873 { "nativeSetFindIsEmpty", "()V", 2874 (void*) nativeSetFindIsEmpty }, 2875 { "nativeSetFindIsUp", "(Z)V", 2876 (void*) nativeSetFindIsUp }, 2877 { "nativeSetHeightCanMeasure", "(Z)V", 2878 (void*) nativeSetHeightCanMeasure }, 2879 { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V", 2880 (void*) nativeSetBaseLayer }, 2881 { "nativeGetTextSelectionRegion", "(ILandroid/graphics/Region;)V", 2882 (void*) nativeGetTextSelectionRegion }, 2883 { "nativeGetSelectionHandles", "(I[I)V", 2884 (void*) nativeGetSelectionHandles }, 2885 { "nativeGetBaseLayer", "()I", 2886 (void*) nativeGetBaseLayer }, 2887 { "nativeReplaceBaseContent", "(I)V", 2888 (void*) nativeReplaceBaseContent }, 2889 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", 2890 (void*) nativeCopyBaseContentToPicture }, 2891 { "nativeHasContent", "()Z", 2892 (void*) nativeHasContent }, 2893 { "nativeSetSelectionPointer", "(IZFII)V", 2894 (void*) nativeSetSelectionPointer }, 2895 { "nativeShowCursorTimed", "()V", 2896 (void*) nativeShowCursorTimed }, 2897 { "nativeRegisterPageSwapCallback", "()V", 2898 (void*) nativeRegisterPageSwapCallback }, 2899 { "nativeTileProfilingStart", "()V", 2900 (void*) nativeTileProfilingStart }, 2901 { "nativeTileProfilingStop", "()F", 2902 (void*) nativeTileProfilingStop }, 2903 { "nativeTileProfilingClear", "()V", 2904 (void*) nativeTileProfilingClear }, 2905 { "nativeTileProfilingNumFrames", "()I", 2906 (void*) nativeTileProfilingNumFrames }, 2907 { "nativeTileProfilingNumTilesInFrame", "(I)I", 2908 (void*) nativeTileProfilingNumTilesInFrame }, 2909 { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I", 2910 (void*) nativeTileProfilingGetInt }, 2911 { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F", 2912 (void*) nativeTileProfilingGetFloat }, 2913 { "nativeStartSelection", "(II)Z", 2914 (void*) nativeStartSelection }, 2915 { "nativeStopGL", "()V", 2916 (void*) nativeStopGL }, 2917 { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;", 2918 (void*) nativeSubtractLayers }, 2919 { "nativeTextGeneration", "()I", 2920 (void*) nativeTextGeneration }, 2921 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", 2922 (void*) nativeUpdateCachedTextfield }, 2923 { "nativeWordSelection", "(II)Z", 2924 (void*) nativeWordSelection }, 2925 { "nativeGetBlockLeftEdge", "(IIF)I", 2926 (void*) nativeGetBlockLeftEdge }, 2927 { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I", 2928 (void*) nativeScrollableLayer }, 2929 { "nativeScrollLayer", "(III)Z", 2930 (void*) nativeScrollLayer }, 2931 { "nativeSetIsScrolling", "(Z)V", 2932 (void*) nativeSetIsScrolling }, 2933 { "nativeUseHardwareAccelSkia", "(Z)V", 2934 (void*) nativeUseHardwareAccelSkia }, 2935 { "nativeGetBackgroundColor", "()I", 2936 (void*) nativeGetBackgroundColor }, 2937 { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", 2938 (void*) nativeSetProperty }, 2939 { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;", 2940 (void*) nativeGetProperty }, 2941 { "nativeOnTrimMemory", "(I)V", 2942 (void*) nativeOnTrimMemory }, 2943 { "nativeSetPauseDrawing", "(IZ)V", 2944 (void*) nativeSetPauseDrawing }, 2945 }; 2946 2947 int registerWebView(JNIEnv* env) 2948 { 2949 jclass clazz = env->FindClass("android/webkit/WebView"); 2950 LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView"); 2951 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I"); 2952 LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass"); 2953 env->DeleteLocalRef(clazz); 2954 2955 return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); 2956 } 2957 2958 } // namespace android 2959