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