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