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