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