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