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