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