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