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