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