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