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