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 "AtomicString.h" 33 #include "CachedFrame.h" 34 #include "CachedNode.h" 35 #include "CachedRoot.h" 36 #include "CString.h" 37 #include "DrawExtra.h" 38 #include "FindCanvas.h" 39 #include "Frame.h" 40 #include "GraphicsJNI.h" 41 #include "HTMLInputElement.h" 42 #include "IntPoint.h" 43 #include "IntRect.h" 44 #include "LayerAndroid.h" 45 #include "Node.h" 46 #include "PlatformGraphicsContext.h" 47 #include "PlatformString.h" 48 #include "SelectText.h" 49 #include "SkCanvas.h" 50 #include "SkDumpCanvas.h" 51 #include "SkPicture.h" 52 #include "SkRect.h" 53 #include "SkTime.h" 54 #ifdef ANDROID_INSTRUMENT 55 #include "TimeCounter.h" 56 #endif 57 #include "WebCoreJni.h" 58 #include "WebViewCore.h" 59 #include "android_graphics.h" 60 61 #ifdef GET_NATIVE_VIEW 62 #undef GET_NATIVE_VIEW 63 #endif 64 65 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField)) 66 67 #include <JNIUtility.h> 68 #include <JNIHelp.h> 69 #include <jni.h> 70 #include <ui/KeycodeLabels.h> 71 72 namespace android { 73 74 static jfieldID gWebViewField; 75 76 //------------------------------------- 77 78 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) 79 { 80 jmethodID m = env->GetMethodID(clazz, name, signature); 81 LOG_ASSERT(m, "Could not find method %s", name); 82 return m; 83 } 84 85 //------------------------------------- 86 // This class provides JNI for making calls into native code from the UI side 87 // of the multi-threaded WebView. 88 class WebView 89 { 90 public: 91 enum FrameCachePermission { 92 DontAllowNewer, 93 AllowNewer, 94 AllowNewest 95 }; 96 97 enum DrawExtras { // keep this in sync with WebView.java 98 DrawExtrasNone = 0, 99 DrawExtrasFind = 1, 100 DrawExtrasSelection = 2, 101 DrawExtrasCursorRing = 3 102 }; 103 104 struct JavaGlue { 105 jweak m_obj; 106 jmethodID m_calcOurContentVisibleRectF; 107 jmethodID m_clearTextEntry; 108 jmethodID m_overrideLoading; 109 jmethodID m_scrollBy; 110 jmethodID m_sendMoveFocus; 111 jmethodID m_sendMoveMouse; 112 jmethodID m_sendMoveMouseIfLatest; 113 jmethodID m_sendMotionUp; 114 jmethodID m_domChangedFocus; 115 jmethodID m_getScaledMaxXScroll; 116 jmethodID m_getScaledMaxYScroll; 117 jmethodID m_getVisibleRect; 118 jmethodID m_rebuildWebTextView; 119 jmethodID m_viewInvalidate; 120 jmethodID m_viewInvalidateRect; 121 jmethodID m_postInvalidateDelayed; 122 jfieldID m_rectLeft; 123 jfieldID m_rectTop; 124 jmethodID m_rectWidth; 125 jmethodID m_rectHeight; 126 jfieldID m_rectFLeft; 127 jfieldID m_rectFTop; 128 jmethodID m_rectFWidth; 129 jmethodID m_rectFHeight; 130 AutoJObject object(JNIEnv* env) { 131 return getRealObject(env, m_obj); 132 } 133 } m_javaGlue; 134 135 WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : 136 m_ring((WebViewCore*) viewImpl) 137 { 138 jclass clazz = env->FindClass("android/webkit/WebView"); 139 // m_javaGlue = new JavaGlue; 140 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); 141 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); 142 m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V"); 143 m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "(Z)V"); 144 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); 145 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); 146 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); 147 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V"); 148 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V"); 149 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V"); 150 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); 151 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); 152 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); 153 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); 154 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); 155 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); 156 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, 157 "viewInvalidateDelayed", "(JIIII)V"); 158 jclass rectClass = env->FindClass("android/graphics/Rect"); 159 LOG_ASSERT(rectClass, "Could not find Rect class"); 160 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); 161 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); 162 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); 163 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); 164 jclass rectClassF = env->FindClass("android/graphics/RectF"); 165 LOG_ASSERT(rectClassF, "Could not find RectF class"); 166 m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F"); 167 m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F"); 168 m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F"); 169 m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F"); 170 env->SetIntField(javaWebView, gWebViewField, (jint)this); 171 m_viewImpl = (WebViewCore*) viewImpl; 172 m_frameCacheUI = 0; 173 m_navPictureUI = 0; 174 m_generation = 0; 175 m_heightCanMeasure = false; 176 m_ring.m_followedLink = false; 177 m_lastDx = 0; 178 m_lastDxTime = 0; 179 m_ringAnimationEnd = 0; 180 m_rootLayer = 0; 181 } 182 183 ~WebView() 184 { 185 if (m_javaGlue.m_obj) 186 { 187 JNIEnv* env = JSC::Bindings::getJNIEnv(); 188 env->DeleteWeakGlobalRef(m_javaGlue.m_obj); 189 m_javaGlue.m_obj = 0; 190 } 191 delete m_frameCacheUI; 192 delete m_navPictureUI; 193 delete m_rootLayer; 194 } 195 196 WebViewCore* getWebViewCore() const { 197 return m_viewImpl; 198 } 199 200 // removes the cursor altogether (e.g., when going to a new page) 201 void clearCursor() 202 { 203 CachedRoot* root = getFrameCache(AllowNewer); 204 if (!root) 205 return; 206 DBG_NAV_LOG(""); 207 m_viewImpl->m_hasCursorBounds = false; 208 root->clearCursor(); 209 viewInvalidate(); 210 } 211 212 // leaves the cursor where it is, but suppresses drawing it 213 void hideCursor() 214 { 215 CachedRoot* root = getFrameCache(AllowNewer); 216 if (!root) 217 return; 218 DBG_NAV_LOG(""); 219 m_viewImpl->m_hasCursorBounds = false; 220 root->hideCursor(); 221 viewInvalidate(); 222 } 223 224 void clearTextEntry() 225 { 226 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); 227 JNIEnv* env = JSC::Bindings::getJNIEnv(); 228 env->CallVoidMethod(m_javaGlue.object(env).get(), 229 m_javaGlue.m_clearTextEntry, true); 230 checkException(env); 231 } 232 233 #if DUMP_NAV_CACHE 234 void debugDump() 235 { 236 CachedRoot* root = getFrameCache(DontAllowNewer); 237 if (root) 238 root->mDebug.print(); 239 } 240 #endif 241 242 // Traverse our stored array of buttons that are in our picture, and update 243 // their subpictures according to their current state. 244 // Called from the UI thread. This is the one place in the UI thread where we 245 // access the buttons stored in the WebCore thread. 246 // hasFocus keeps track of whether the WebView has focus && windowFocus. 247 // If not, we do not want to draw the button in a selected or pressed state 248 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) 249 { 250 bool cursorIsOnButton = false; 251 const CachedFrame* cachedFrame; 252 const CachedNode* cachedCursor = 0; 253 // Lock the mutex, since we now share with the WebCore thread. 254 m_viewImpl->gButtonMutex.lock(); 255 if (m_viewImpl->m_buttons.size()) { 256 // FIXME: In a future change, we should keep track of whether the selection 257 // has changed to short circuit (note that we would still need to update 258 // if we received new buttons from the WebCore thread). 259 WebCore::Node* cursor = 0; 260 CachedRoot* root = getFrameCache(DontAllowNewer); 261 if (root) { 262 cachedCursor = root->currentCursor(&cachedFrame); 263 if (cachedCursor) 264 cursor = (WebCore::Node*) cachedCursor->nodePointer(); 265 } 266 267 // Traverse the array, and update each button, depending on whether it 268 // is selected. 269 Container* end = m_viewImpl->m_buttons.end(); 270 for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) { 271 WebCore::RenderSkinAndroid::State state; 272 if (ptr->matches(cursor)) { 273 cursorIsOnButton = true; 274 // If the WebView is out of focus/window focus, set the state to 275 // normal, but still keep track of the fact that the selected is a 276 // button 277 if (!hasFocus) { 278 state = WebCore::RenderSkinAndroid::kNormal; 279 } else if (m_ring.m_followedLink || pressed) { 280 state = WebCore::RenderSkinAndroid::kPressed; 281 } else { 282 state = WebCore::RenderSkinAndroid::kFocused; 283 } 284 } else { 285 state = WebCore::RenderSkinAndroid::kNormal; 286 } 287 ptr->updateFocusState(state); 288 } 289 } 290 m_viewImpl->gButtonMutex.unlock(); 291 if (invalidate && cachedCursor && cursorIsOnButton) { 292 const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame); 293 viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom()); 294 } 295 } 296 297 // The caller has already determined that the desired document rect corresponds 298 // to the main picture, and not a layer 299 void scrollRectOnScreen(const IntRect& rect) 300 { 301 if (rect.isEmpty()) 302 return; 303 SkRect visible; 304 calcOurContentVisibleRect(&visible); 305 #if USE(ACCELERATED_COMPOSITING) 306 if (m_rootLayer) { 307 m_rootLayer->updateFixedLayersPositions(visible); 308 m_rootLayer->updatePositions(); 309 visible = m_rootLayer->subtractLayers(visible); 310 } 311 #endif 312 int dx = 0; 313 int left = rect.x(); 314 int right = rect.right(); 315 if (left < visible.fLeft) { 316 dx = left - visible.fLeft; 317 // Only scroll right if the entire width can fit on screen. 318 } else if (right > visible.fRight && right - left < visible.width()) { 319 dx = right - visible.fRight; 320 } 321 int dy = 0; 322 int top = rect.y(); 323 int bottom = rect.bottom(); 324 if (top < visible.fTop) { 325 dy = top - visible.fTop; 326 // Only scroll down if the entire height can fit on screen 327 } else if (bottom > visible.fBottom && bottom - top < visible.height()) { 328 dy = bottom - visible.fBottom; 329 } 330 if ((dx|dy) == 0 || !scrollBy(dx, dy)) 331 return; 332 viewInvalidate(); 333 } 334 335 void calcOurContentVisibleRect(SkRect* r) 336 { 337 JNIEnv* env = JSC::Bindings::getJNIEnv(); 338 jclass rectClass = env->FindClass("android/graphics/RectF"); 339 jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V"); 340 jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0); 341 env->CallVoidMethod(m_javaGlue.object(env).get(), 342 m_javaGlue.m_calcOurContentVisibleRectF, jRect); 343 r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft); 344 r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop); 345 r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth); 346 r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight); 347 env->DeleteLocalRef(jRect); 348 checkException(env); 349 } 350 351 void resetCursorRing() 352 { 353 m_ring.m_followedLink = false; 354 m_viewImpl->m_hasCursorBounds = false; 355 } 356 357 bool drawCursorPreamble(CachedRoot* root) 358 { 359 const CachedFrame* frame; 360 const CachedNode* node = root->currentCursor(&frame); 361 if (!node) { 362 DBG_NAV_LOGV("%s", "!node"); 363 resetCursorRing(); 364 return false; 365 } 366 if (node->isHidden()) { 367 DBG_NAV_LOG("node->isHidden()"); 368 m_viewImpl->m_hasCursorBounds = false; 369 return false; 370 } 371 setVisibleRect(root); 372 m_ring.m_root = root; 373 m_ring.m_frame = frame; 374 m_ring.m_node = node; 375 return true; 376 } 377 378 void drawCursorPostamble() 379 { 380 if (!m_ring.m_isButton && m_ring.m_flavor < CursorRing::NORMAL_ANIMATING) 381 return; 382 SkMSec time = SkTime::GetMSecs(); 383 if (time < m_ringAnimationEnd) { 384 // views assume that inval bounds coordinates are non-negative 385 WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX); 386 invalBounds.intersect(m_ring.m_bounds); 387 postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds); 388 } else { 389 if (m_ring.m_followedLink) 390 hideCursor(); 391 m_ring.m_followedLink = false; 392 m_ring.m_flavor = static_cast<CursorRing::Flavor> 393 (m_ring.m_flavor - CursorRing::NORMAL_ANIMATING); 394 } 395 } 396 397 void drawExtras(SkCanvas* canvas, int extras) 398 { 399 CachedRoot* root = getFrameCache(AllowNewer); 400 if (!root) { 401 DBG_NAV_LOG("!root"); 402 if (extras == DrawExtrasCursorRing) 403 resetCursorRing(); 404 return; 405 } 406 LayerAndroid mainPicture(m_navPictureUI); 407 DrawExtra* extra = 0; 408 switch (extras) { 409 case DrawExtrasFind: 410 extra = &m_findOnPage; 411 break; 412 case DrawExtrasSelection: 413 extra = &m_selectText; 414 break; 415 case DrawExtrasCursorRing: 416 if (drawCursorPreamble(root) && m_ring.setup()) { 417 if (!m_ring.m_isButton) 418 extra = &m_ring; 419 drawCursorPostamble(); 420 } 421 break; 422 default: 423 ; 424 } 425 if (extra) 426 extra->draw(canvas, &mainPicture); 427 #if USE(ACCELERATED_COMPOSITING) 428 if (!m_rootLayer) 429 return; 430 m_rootLayer->setExtra(extra); 431 SkRect visible; 432 calcOurContentVisibleRect(&visible); 433 // call this to be sure we've adjusted for any scrolling or animations 434 // before we actually draw 435 m_rootLayer->updateFixedLayersPositions(visible); 436 m_rootLayer->updatePositions(); 437 // We have to set the canvas' matrix on the root layer 438 // (to have fixed layers work as intended) 439 SkAutoCanvasRestore restore(canvas, true); 440 m_rootLayer->setMatrix(canvas->getTotalMatrix()); 441 canvas->resetMatrix(); 442 m_rootLayer->draw(canvas); 443 #endif 444 } 445 446 447 bool cursorIsTextInput(FrameCachePermission allowNewer) 448 { 449 CachedRoot* root = getFrameCache(allowNewer); 450 if (!root) { 451 DBG_NAV_LOG("!root"); 452 return false; 453 } 454 const CachedNode* cursor = root->currentCursor(); 455 if (!cursor) { 456 DBG_NAV_LOG("!cursor"); 457 return false; 458 } 459 DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false"); 460 return cursor->isTextInput(); 461 } 462 463 void cursorRingBounds(WebCore::IntRect* bounds) 464 { 465 DBG_NAV_LOGD("%s", ""); 466 CachedRoot* root = getFrameCache(DontAllowNewer); 467 if (root) { 468 const CachedFrame* cachedFrame; 469 const CachedNode* cachedNode = root->currentCursor(&cachedFrame); 470 if (cachedNode) { 471 *bounds = cachedNode->cursorRingBounds(cachedFrame); 472 DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(), 473 bounds->width(), bounds->height()); 474 return; 475 } 476 } 477 *bounds = WebCore::IntRect(0, 0, 0, 0); 478 } 479 480 void fixCursor() 481 { 482 m_viewImpl->gCursorBoundsMutex.lock(); 483 bool hasCursorBounds = m_viewImpl->m_hasCursorBounds; 484 IntRect bounds = m_viewImpl->m_cursorBounds; 485 m_viewImpl->gCursorBoundsMutex.unlock(); 486 if (!hasCursorBounds) 487 return; 488 int x, y; 489 const CachedFrame* frame; 490 const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, false); 491 if (!node) 492 return; 493 // require that node have approximately the same bounds (+/- 4) and the same 494 // center (+/- 2) 495 IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1), 496 bounds.y() + (bounds.height() >> 1)); 497 IntRect newBounds = node->bounds(frame); 498 IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1), 499 newBounds.y() + (newBounds.height() >> 1)); 500 DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)" 501 " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)", 502 oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(), 503 bounds.x(), bounds.y(), bounds.width(), bounds.height(), 504 newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height()); 505 if (abs(oldCenter.x() - newCenter.x()) > 2) 506 return; 507 if (abs(oldCenter.y() - newCenter.y()) > 2) 508 return; 509 if (abs(bounds.x() - newBounds.x()) > 4) 510 return; 511 if (abs(bounds.y() - newBounds.y()) > 4) 512 return; 513 if (abs(bounds.right() - newBounds.right()) > 4) 514 return; 515 if (abs(bounds.bottom() - newBounds.bottom()) > 4) 516 return; 517 DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)", 518 node, frame, x, y, bounds.x(), bounds.y(), bounds.width(), 519 bounds.height()); 520 m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame), 521 const_cast<CachedNode*>(node)); 522 } 523 524 CachedRoot* getFrameCache(FrameCachePermission allowNewer) 525 { 526 if (!m_viewImpl->m_updatedFrameCache) { 527 DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache"); 528 return m_frameCacheUI; 529 } 530 if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) { 531 DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d" 532 " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation); 533 return m_frameCacheUI; 534 } 535 DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true"); 536 const CachedFrame* oldCursorFrame; 537 const CachedNode* oldCursorNode = m_frameCacheUI ? 538 m_frameCacheUI->currentCursor(&oldCursorFrame) : 0; 539 #if USE(ACCELERATED_COMPOSITING) 540 int layerId = -1; 541 if (oldCursorNode && oldCursorNode->isInLayer()) { 542 const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode) 543 ->layer(m_frameCacheUI->rootLayer()); 544 if (cursorLayer) 545 layerId = cursorLayer->uniqueId(); 546 } 547 #endif 548 // get id from old layer and use to find new layer 549 bool oldFocusIsTextInput = false; 550 void* oldFocusNodePointer = 0; 551 if (m_frameCacheUI) { 552 const CachedNode* oldFocus = m_frameCacheUI->currentFocus(); 553 if (oldFocus) { 554 oldFocusIsTextInput = oldFocus->isTextInput(); 555 oldFocusNodePointer = oldFocus->nodePointer(); 556 } 557 } 558 m_viewImpl->gFrameCacheMutex.lock(); 559 delete m_frameCacheUI; 560 delete m_navPictureUI; 561 m_viewImpl->m_updatedFrameCache = false; 562 m_frameCacheUI = m_viewImpl->m_frameCacheKit; 563 m_navPictureUI = m_viewImpl->m_navPictureKit; 564 m_viewImpl->m_frameCacheKit = 0; 565 m_viewImpl->m_navPictureKit = 0; 566 m_viewImpl->gFrameCacheMutex.unlock(); 567 if (m_frameCacheUI) 568 m_frameCacheUI->setRootLayer(m_rootLayer); 569 #if USE(ACCELERATED_COMPOSITING) 570 if (layerId >= 0) { 571 SkRect visible; 572 calcOurContentVisibleRect(&visible); 573 LayerAndroid* layer = const_cast<LayerAndroid*>( 574 m_frameCacheUI->rootLayer()); 575 if (layer) { 576 layer->updateFixedLayersPositions(visible); 577 layer->updatePositions(); 578 } 579 } 580 #endif 581 fixCursor(); 582 if (oldFocusIsTextInput) { 583 const CachedNode* newFocus = m_frameCacheUI->currentFocus(); 584 if (newFocus && oldFocusNodePointer != newFocus->nodePointer() 585 && newFocus->isTextInput() 586 && newFocus != m_frameCacheUI->currentCursor()) { 587 // The focus has changed. We may need to update things. 588 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 589 JNIEnv* env = JSC::Bindings::getJNIEnv(); 590 env->CallVoidMethod(m_javaGlue.object(env).get(), 591 m_javaGlue.m_domChangedFocus); 592 checkException(env); 593 } 594 } 595 if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) 596 viewInvalidate(); // redraw in case cursor ring is still visible 597 return m_frameCacheUI; 598 } 599 600 int getScaledMaxXScroll() 601 { 602 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 603 JNIEnv* env = JSC::Bindings::getJNIEnv(); 604 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll); 605 checkException(env); 606 return result; 607 } 608 609 int getScaledMaxYScroll() 610 { 611 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 612 JNIEnv* env = JSC::Bindings::getJNIEnv(); 613 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll); 614 checkException(env); 615 return result; 616 } 617 618 void getVisibleRect(WebCore::IntRect* rect) 619 { 620 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 621 JNIEnv* env = JSC::Bindings::getJNIEnv(); 622 jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect); 623 checkException(env); 624 int left = (int) env->GetIntField(jRect, m_javaGlue.m_rectLeft); 625 checkException(env); 626 rect->setX(left); 627 int top = (int) env->GetIntField(jRect, m_javaGlue.m_rectTop); 628 checkException(env); 629 rect->setY(top); 630 int width = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectWidth); 631 checkException(env); 632 rect->setWidth(width); 633 int height = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectHeight); 634 checkException(env); 635 rect->setHeight(height); 636 env->DeleteLocalRef(jRect); 637 checkException(env); 638 } 639 640 static CachedFrame::Direction KeyToDirection(int32_t keyCode) 641 { 642 switch (keyCode) { 643 case AKEYCODE_DPAD_RIGHT: 644 DBG_NAV_LOGD("keyCode=%s", "right"); 645 return CachedFrame::RIGHT; 646 case AKEYCODE_DPAD_LEFT: 647 DBG_NAV_LOGD("keyCode=%s", "left"); 648 return CachedFrame::LEFT; 649 case AKEYCODE_DPAD_DOWN: 650 DBG_NAV_LOGD("keyCode=%s", "down"); 651 return CachedFrame::DOWN; 652 case AKEYCODE_DPAD_UP: 653 DBG_NAV_LOGD("keyCode=%s", "up"); 654 return CachedFrame::UP; 655 default: 656 DBG_NAV_LOGD("bad key %d sent", keyCode); 657 return CachedFrame::UNINITIALIZED; 658 } 659 } 660 661 WebCore::String imageURI(int x, int y) 662 { 663 const CachedRoot* root = getFrameCache(DontAllowNewer); 664 return root ? root->imageURI(x, y) : WebCore::String(); 665 } 666 667 bool cursorWantsKeyEvents() 668 { 669 const CachedRoot* root = getFrameCache(DontAllowNewer); 670 if (root) { 671 const CachedNode* focus = root->currentCursor(); 672 if (focus) 673 return focus->wantsKeyEvents(); 674 } 675 return false; 676 } 677 678 679 /* returns true if the key had no effect (neither scrolled nor changed cursor) */ 680 bool moveCursor(int keyCode, int count, bool ignoreScroll) 681 { 682 CachedRoot* root = getFrameCache(AllowNewer); 683 if (!root) { 684 DBG_NAV_LOG("!root"); 685 return true; 686 } 687 688 m_viewImpl->m_moveGeneration++; 689 CachedFrame::Direction direction = KeyToDirection(keyCode); 690 const CachedFrame* cachedFrame, * oldFrame = 0; 691 const CachedNode* cursor = root->currentCursor(&oldFrame); 692 WebCore::IntPoint cursorLocation = root->cursorLocation(); 693 DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", 694 cursor ? cursor->index() : 0, 695 cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); 696 WebCore::IntRect visibleRect = setVisibleRect(root); 697 int xMax = getScaledMaxXScroll(); 698 int yMax = getScaledMaxYScroll(); 699 root->setMaxScroll(xMax, yMax); 700 const CachedNode* cachedNode = 0; 701 int dx = 0; 702 int dy = 0; 703 int counter = count; 704 if (!cursor || !m_ring.m_followedLink) 705 root->setScrollOnly(m_ring.m_followedLink); 706 while (--counter >= 0) { 707 WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); 708 cachedNode = root->moveCursor(direction, &cachedFrame, &scroll); 709 dx += scroll.x(); 710 dy += scroll.y(); 711 } 712 DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}" 713 "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, 714 cachedNode ? cachedNode->nodePointer() : 0, 715 root->cursorLocation().x(), root->cursorLocation().y(), 716 cachedNode ? cachedNode->bounds(cachedFrame).x() : 0, 717 cachedNode ? cachedNode->bounds(cachedFrame).y() : 0, 718 cachedNode ? cachedNode->bounds(cachedFrame).width() : 0, 719 cachedNode ? cachedNode->bounds(cachedFrame).height() : 0); 720 // If !m_heightCanMeasure (such as in the browser), we want to scroll no 721 // matter what 722 if (!ignoreScroll && (!m_heightCanMeasure || 723 !cachedNode || 724 (cursor && cursor->nodePointer() == cachedNode->nodePointer()))) 725 { 726 if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx && 727 SkTime::GetMSecs() - m_lastDxTime < 1000) 728 root->checkForJiggle(&dx); 729 DBG_NAV_LOGD("scrollBy %d,%d", dx, dy); 730 if ((dx | dy)) 731 this->scrollBy(dx, dy); 732 m_lastDx = dx; 733 m_lastDxTime = SkTime::GetMSecs(); 734 } 735 bool result = false; 736 if (cachedNode) { 737 m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode); 738 root->setCursor(const_cast<CachedFrame*>(cachedFrame), 739 const_cast<CachedNode*>(cachedNode)); 740 bool disableFocusController = cachedNode != root->currentFocus() 741 && cachedNode->wantsKeyEvents(); 742 sendMoveMouseIfLatest(disableFocusController); 743 viewInvalidate(); 744 } else { 745 int docHeight = root->documentHeight(); 746 int docWidth = root->documentWidth(); 747 if (visibleRect.bottom() + dy > docHeight) 748 dy = docHeight - visibleRect.bottom(); 749 else if (visibleRect.y() + dy < 0) 750 dy = -visibleRect.y(); 751 if (visibleRect.right() + dx > docWidth) 752 dx = docWidth - visibleRect.right(); 753 else if (visibleRect.x() < 0) 754 dx = -visibleRect.x(); 755 result = direction == CachedFrame::LEFT ? dx >= 0 : 756 direction == CachedFrame::RIGHT ? dx <= 0 : 757 direction == CachedFrame::UP ? dy >= 0 : dy <= 0; 758 } 759 return result; 760 } 761 762 void notifyProgressFinished() 763 { 764 DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer)); 765 rebuildWebTextView(); 766 #if DEBUG_NAV_UI 767 if (m_frameCacheUI) { 768 const CachedNode* focus = m_frameCacheUI->currentFocus(); 769 DBG_NAV_LOGD("focus %d (nativeNode=%p)", 770 focus ? focus->index() : 0, 771 focus ? focus->nodePointer() : 0); 772 } 773 #endif 774 } 775 776 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect, 777 const CachedFrame** framePtr, int* rxPtr, int* ryPtr) 778 { 779 *rxPtr = 0; 780 *ryPtr = 0; 781 *framePtr = 0; 782 if (!root) 783 return 0; 784 setVisibleRect(root); 785 return root->findAt(rect, framePtr, rxPtr, ryPtr, true); 786 } 787 788 IntRect setVisibleRect(CachedRoot* root) 789 { 790 IntRect visibleRect; 791 getVisibleRect(&visibleRect); 792 DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d", 793 visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height()); 794 root->setVisibleRect(visibleRect); 795 return visibleRect; 796 } 797 798 void selectBestAt(const WebCore::IntRect& rect) 799 { 800 const CachedFrame* frame; 801 int rx, ry; 802 CachedRoot* root = getFrameCache(DontAllowNewer); 803 const CachedNode* node = findAt(root, rect, &frame, &rx, &ry); 804 805 if (!node) { 806 DBG_NAV_LOGD("no nodes found root=%p", root); 807 m_viewImpl->m_hasCursorBounds = false; 808 if (root) 809 root->setCursor(0, 0); 810 } else { 811 DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); 812 root->rootHistory()->setMouseBounds(node->bounds(frame)); 813 m_viewImpl->updateCursorBounds(root, frame, node); 814 root->setCursor(const_cast<CachedFrame*>(frame), 815 const_cast<CachedNode*>(node)); 816 } 817 sendMoveMouseIfLatest(false); 818 viewInvalidate(); 819 } 820 821 WebCore::IntRect getNavBounds() 822 { 823 CachedRoot* root = getFrameCache(DontAllowNewer); 824 return root ? root->rootHistory()->navBounds() : 825 WebCore::IntRect(0, 0, 0, 0); 826 } 827 828 void setNavBounds(const WebCore::IntRect& rect) 829 { 830 CachedRoot* root = getFrameCache(DontAllowNewer); 831 if (!root) 832 return; 833 root->rootHistory()->setNavBounds(rect); 834 } 835 836 837 838 const CachedNode* m_cacheHitNode; 839 const CachedFrame* m_cacheHitFrame; 840 841 bool pointInNavCache(int x, int y, int slop) 842 { 843 CachedRoot* root = getFrameCache(AllowNewer); 844 if (!root) 845 return false; 846 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); 847 int rx, ry; 848 return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry)); 849 } 850 851 bool motionUp(int x, int y, int slop) 852 { 853 bool pageScrolled = false; 854 m_ring.m_followedLink = false; 855 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); 856 int rx, ry; 857 CachedRoot* root = getFrameCache(AllowNewer); 858 if (!root) 859 return 0; 860 const CachedFrame* frame = 0; 861 const CachedNode* result = findAt(root, rect, &frame, &rx, &ry); 862 if (!result) { 863 DBG_NAV_LOGD("no nodes found root=%p", root); 864 setNavBounds(rect); 865 m_viewImpl->m_hasCursorBounds = false; 866 root->hideCursor(); 867 int dx = root->checkForCenter(x, y); 868 if (dx) { 869 scrollBy(dx, 0); 870 pageScrolled = true; 871 } 872 sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0, 873 0, x, y); 874 viewInvalidate(); 875 clearTextEntry(); 876 return pageScrolled; 877 } 878 DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result, 879 result->index(), x, y, rx, ry); 880 WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1); 881 setNavBounds(navBounds); 882 root->rootHistory()->setMouseBounds(navBounds); 883 m_viewImpl->updateCursorBounds(root, frame, result); 884 root->setCursor(const_cast<CachedFrame*>(frame), 885 const_cast<CachedNode*>(result)); 886 bool syntheticLink = result->isSyntheticLink(); 887 if (!syntheticLink) { 888 sendMotionUp( 889 (WebCore::Frame*) frame->framePointer(), 890 (WebCore::Node*) result->nodePointer(), rx, ry); 891 } 892 viewInvalidate(); 893 if (!result->isTextInput()) { 894 clearTextEntry(); 895 setFollowedLink(true); 896 if (syntheticLink) 897 overrideUrlLoading(result->getExport()); 898 } 899 return pageScrolled; 900 } 901 902 int getBlockLeftEdge(int x, int y, float scale) 903 { 904 CachedRoot* root = getFrameCache(AllowNewer); 905 if (root) 906 return root->getBlockLeftEdge(x, y, scale); 907 return -1; 908 } 909 910 void overrideUrlLoading(const WebCore::String& url) 911 { 912 JNIEnv* env = JSC::Bindings::getJNIEnv(); 913 jstring jName = env->NewString((jchar*) url.characters(), url.length()); 914 env->CallVoidMethod(m_javaGlue.object(env).get(), 915 m_javaGlue.m_overrideLoading, jName); 916 env->DeleteLocalRef(jName); 917 } 918 919 void setFindIsUp(bool up) 920 { 921 DBG_NAV_LOGD("up=%d", up); 922 m_viewImpl->m_findIsUp = up; 923 } 924 925 void setFindIsEmpty() 926 { 927 DBG_NAV_LOG(""); 928 m_findOnPage.clearCurrentLocation(); 929 } 930 931 void setFollowedLink(bool followed) 932 { 933 if ((m_ring.m_followedLink = followed) != false) { 934 m_ringAnimationEnd = SkTime::GetMSecs() + 500; 935 viewInvalidate(); 936 } 937 } 938 939 void setHeightCanMeasure(bool measure) 940 { 941 m_heightCanMeasure = measure; 942 } 943 944 String getSelection() 945 { 946 return m_selectText.getSelection(); 947 } 948 949 void moveSelection(int x, int y) 950 { 951 const CachedRoot* root = getFrameCache(DontAllowNewer); 952 if (!root) 953 return; 954 SkPicture* picture = root->pictureAt(x, y); 955 // FIXME: use the visibleRect only for the main picture 956 // for layer pictures, use the equivalent of the canvas clipping rect 957 IntRect visibleRect; 958 getVisibleRect(&visibleRect); 959 m_selectText.setVisibleRect(visibleRect); 960 m_selectText.moveSelection(picture, x, y); 961 } 962 963 void selectAll() 964 { 965 const CachedRoot* root = getFrameCache(DontAllowNewer); 966 if (!root) 967 return; 968 SkPicture* picture = root->pictureAt(0, 0); 969 m_selectText.selectAll(picture); 970 } 971 972 int selectionX() 973 { 974 return m_selectText.selectionX(); 975 } 976 977 int selectionY() 978 { 979 return m_selectText.selectionY(); 980 } 981 982 void resetSelection() 983 { 984 m_selectText.reset(); 985 } 986 987 bool startSelection(int x, int y) 988 { 989 return m_selectText.startSelection(x, y); 990 } 991 992 bool wordSelection(int x, int y) 993 { 994 startSelection(x, y); 995 if (!extendSelection(x, y)) 996 return false; 997 m_selectText.setDrawPointer(false); 998 SkPicture* picture = getFrameCache(DontAllowNewer)->pictureAt(x, y); 999 return m_selectText.wordSelection(picture); 1000 } 1001 1002 bool extendSelection(int x, int y) 1003 { 1004 const CachedRoot* root = getFrameCache(DontAllowNewer); 1005 if (!root) 1006 return false; 1007 SkPicture* picture = root->pictureAt(x, y); 1008 IntRect visibleRect; 1009 getVisibleRect(&visibleRect); 1010 m_selectText.setVisibleRect(visibleRect); 1011 m_selectText.extendSelection(picture, x, y); 1012 return true; 1013 } 1014 1015 bool hitSelection(int x, int y) 1016 { 1017 return m_selectText.hitSelection(x, y); 1018 } 1019 1020 void setExtendSelection() 1021 { 1022 m_selectText.setExtendSelection(true); 1023 } 1024 1025 void setSelectionPointer(bool set, float scale, int x, int y) 1026 { 1027 m_selectText.setDrawPointer(set); 1028 if (!set) 1029 return; 1030 m_selectText.m_inverseScale = scale; 1031 m_selectText.m_selectX = x; 1032 m_selectText.m_selectY = y; 1033 } 1034 1035 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) 1036 { 1037 DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr); 1038 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1039 env->CallVoidMethod(m_javaGlue.object(env).get(), 1040 m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr); 1041 checkException(env); 1042 } 1043 1044 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) 1045 { 1046 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); 1047 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1048 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse, 1049 (jint) framePtr, (jint) nodePtr, x, y); 1050 checkException(env); 1051 } 1052 1053 void sendMoveMouseIfLatest(bool disableFocusController) 1054 { 1055 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 1056 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1057 env->CallVoidMethod(m_javaGlue.object(env).get(), 1058 m_javaGlue.m_sendMoveMouseIfLatest, disableFocusController); 1059 checkException(env); 1060 } 1061 1062 void sendMotionUp( 1063 WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) 1064 { 1065 m_viewImpl->m_touchGeneration = ++m_generation; 1066 DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", 1067 m_generation, framePtr, nodePtr, x, y); 1068 LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); 1069 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1070 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp, 1071 m_generation, (jint) framePtr, (jint) nodePtr, x, y); 1072 checkException(env); 1073 } 1074 1075 void findNext(bool forward) 1076 { 1077 m_findOnPage.findNext(forward); 1078 if (!m_findOnPage.currentMatchIsInLayer()) 1079 scrollRectOnScreen(m_findOnPage.currentMatchBounds()); 1080 viewInvalidate(); 1081 } 1082 1083 // With this call, WebView takes ownership of matches, and is responsible for 1084 // deleting it. 1085 void setMatches(WTF::Vector<MatchInfo>* matches) 1086 { 1087 m_findOnPage.setMatches(matches); 1088 if (!m_findOnPage.currentMatchIsInLayer()) 1089 scrollRectOnScreen(m_findOnPage.currentMatchBounds()); 1090 viewInvalidate(); 1091 } 1092 1093 int currentMatchIndex() 1094 { 1095 return m_findOnPage.currentMatchIndex(); 1096 } 1097 1098 bool scrollBy(int dx, int dy) 1099 { 1100 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); 1101 1102 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1103 bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(), 1104 m_javaGlue.m_scrollBy, dx, dy, true); 1105 checkException(env); 1106 return result; 1107 } 1108 1109 bool hasCursorNode() 1110 { 1111 CachedRoot* root = getFrameCache(DontAllowNewer); 1112 if (!root) { 1113 DBG_NAV_LOG("!root"); 1114 return false; 1115 } 1116 const CachedNode* cursorNode = root->currentCursor(); 1117 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)", 1118 cursorNode ? cursorNode->index() : -1, 1119 cursorNode ? cursorNode->nodePointer() : 0); 1120 return cursorNode; 1121 } 1122 1123 bool hasFocusNode() 1124 { 1125 CachedRoot* root = getFrameCache(DontAllowNewer); 1126 if (!root) { 1127 DBG_NAV_LOG("!root"); 1128 return false; 1129 } 1130 const CachedNode* focusNode = root->currentFocus(); 1131 DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)", 1132 focusNode ? focusNode->index() : -1, 1133 focusNode ? focusNode->nodePointer() : 0); 1134 return focusNode; 1135 } 1136 1137 void rebuildWebTextView() 1138 { 1139 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1140 env->CallVoidMethod(m_javaGlue.object(env).get(), 1141 m_javaGlue.m_rebuildWebTextView); 1142 checkException(env); 1143 } 1144 1145 void viewInvalidate() 1146 { 1147 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1148 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate); 1149 checkException(env); 1150 } 1151 1152 void viewInvalidateRect(int l, int t, int r, int b) 1153 { 1154 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1155 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b); 1156 checkException(env); 1157 } 1158 1159 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) 1160 { 1161 JNIEnv* env = JSC::Bindings::getJNIEnv(); 1162 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed, 1163 delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); 1164 checkException(env); 1165 } 1166 1167 int moveGeneration() 1168 { 1169 return m_viewImpl->m_moveGeneration; 1170 } 1171 1172 LayerAndroid* rootLayer() const 1173 { 1174 return m_rootLayer; 1175 } 1176 1177 void setRootLayer(LayerAndroid* layer) 1178 { 1179 delete m_rootLayer; 1180 m_rootLayer = layer; 1181 CachedRoot* root = getFrameCache(DontAllowNewer); 1182 if (!root) 1183 return; 1184 root->resetLayers(); 1185 root->setRootLayer(m_rootLayer); 1186 } 1187 1188 private: // local state for WebView 1189 // private to getFrameCache(); other functions operate in a different thread 1190 CachedRoot* m_frameCacheUI; // navigation data ready for use 1191 WebViewCore* m_viewImpl; 1192 int m_generation; // associate unique ID with sent kit focus to match with ui 1193 SkPicture* m_navPictureUI; 1194 SkMSec m_ringAnimationEnd; 1195 // Corresponds to the same-named boolean on the java side. 1196 bool m_heightCanMeasure; 1197 int m_lastDx; 1198 SkMSec m_lastDxTime; 1199 SelectText m_selectText; 1200 FindOnPage m_findOnPage; 1201 CursorRing m_ring; 1202 LayerAndroid* m_rootLayer; 1203 }; // end of WebView class 1204 1205 /* 1206 * Native JNI methods 1207 */ 1208 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string) 1209 { 1210 int length = string.length(); 1211 if (!length) 1212 return 0; 1213 jstring ret = env->NewString((jchar *)string.characters(), length); 1214 env->DeleteLocalRef(ret); 1215 return ret; 1216 } 1217 1218 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) 1219 { 1220 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) 1221 ->m_cacheHitFrame->framePointer()); 1222 } 1223 1224 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) 1225 { 1226 WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj) 1227 ->m_cacheHitNode->originalAbsoluteBounds(); 1228 jclass rectClass = env->FindClass("android/graphics/Rect"); 1229 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1230 jobject rect = env->NewObject(rectClass, init, bounds.x(), 1231 bounds.y(), bounds.right(), bounds.bottom()); 1232 return rect; 1233 } 1234 1235 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) 1236 { 1237 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) 1238 ->m_cacheHitNode->nodePointer()); 1239 } 1240 1241 static void nativeClearCursor(JNIEnv *env, jobject obj) 1242 { 1243 WebView* view = GET_NATIVE_VIEW(env, obj); 1244 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1245 view->clearCursor(); 1246 } 1247 1248 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl) 1249 { 1250 WebView* webview = new WebView(env, obj, viewImpl); 1251 // NEED THIS OR SOMETHING LIKE IT! 1252 //Release(obj); 1253 } 1254 1255 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj) 1256 { 1257 WebView* view = GET_NATIVE_VIEW(env, obj); 1258 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1259 if (!root) 1260 return 0; 1261 const CachedFrame* frame = 0; 1262 (void) root->currentCursor(&frame); 1263 return reinterpret_cast<int>(frame ? frame->framePointer() : 0); 1264 } 1265 1266 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) 1267 { 1268 WebView* view = GET_NATIVE_VIEW(env, obj); 1269 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1270 return root ? root->currentCursor() : 0; 1271 } 1272 1273 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, 1274 const CachedFrame** frame) 1275 { 1276 WebView* view = GET_NATIVE_VIEW(env, obj); 1277 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1278 return root ? root->currentCursor(frame) : 0; 1279 } 1280 1281 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, 1282 const CachedFrame** frame) 1283 { 1284 WebView* view = GET_NATIVE_VIEW(env, obj); 1285 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1286 if (!root) 1287 return 0; 1288 const CachedNode* cursor = root->currentCursor(frame); 1289 if (cursor && cursor->wantsKeyEvents()) 1290 return cursor; 1291 return root->currentFocus(); 1292 } 1293 1294 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) 1295 { 1296 WebView* view = GET_NATIVE_VIEW(env, obj); 1297 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1298 if (!root) 1299 return false; 1300 const CachedNode* cursor = root->currentCursor(); 1301 if (!cursor || !cursor->isTextInput()) 1302 cursor = root->currentFocus(); 1303 if (!cursor || !cursor->isTextInput()) return false; 1304 return root->nextTextField(cursor, 0); 1305 } 1306 1307 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) 1308 { 1309 WebView* view = GET_NATIVE_VIEW(env, obj); 1310 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1311 return root ? root->currentFocus() : 0; 1312 } 1313 1314 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj, 1315 const CachedFrame** frame) 1316 { 1317 WebView* view = GET_NATIVE_VIEW(env, obj); 1318 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1319 return root ? root->currentFocus(frame) : 0; 1320 } 1321 1322 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj) 1323 { 1324 WebView* view = GET_NATIVE_VIEW(env, obj); 1325 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1326 if (!root) 1327 return 0; 1328 const CachedFrame* frame; 1329 const CachedNode* cursor = root->currentCursor(&frame); 1330 if (!cursor || !cursor->wantsKeyEvents()) 1331 cursor = root->currentFocus(&frame); 1332 return cursor ? frame->textInput(cursor) : 0; 1333 } 1334 1335 static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj) 1336 { 1337 const CachedNode* cursor = getCursorNode(env, obj); 1338 const CachedNode* focus = getFocusNode(env, obj); 1339 return cursor && focus && cursor->nodePointer() == focus->nodePointer(); 1340 } 1341 1342 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) 1343 { 1344 const CachedFrame* frame; 1345 const CachedNode* node = getCursorNode(env, obj, &frame); 1346 WebCore::IntRect bounds = node ? node->bounds(frame) 1347 : WebCore::IntRect(0, 0, 0, 0); 1348 jclass rectClass = env->FindClass("android/graphics/Rect"); 1349 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1350 jobject rect = env->NewObject(rectClass, init, bounds.x(), 1351 bounds.y(), bounds.right(), bounds.bottom()); 1352 return rect; 1353 } 1354 1355 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) 1356 { 1357 const CachedNode* node = getCursorNode(env, obj); 1358 return reinterpret_cast<int>(node ? node->nodePointer() : 0); 1359 } 1360 1361 static jobject nativeCursorPosition(JNIEnv *env, jobject obj) 1362 { 1363 WebView* view = GET_NATIVE_VIEW(env, obj); 1364 const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1365 WebCore::IntPoint pos = WebCore::IntPoint(0, 0); 1366 if (root) 1367 root->getSimulatedMousePosition(&pos); 1368 jclass pointClass = env->FindClass("android/graphics/Point"); 1369 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); 1370 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); 1371 return point; 1372 } 1373 1374 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) 1375 { 1376 int L, T, R, B; 1377 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); 1378 return WebCore::IntRect(L, T, R - L, B - T); 1379 } 1380 1381 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) 1382 { 1383 const CachedFrame* frame; 1384 const CachedNode* node = getCursorNode(env, obj, &frame); 1385 return node ? node->bounds(frame).intersects( 1386 jrect_to_webrect(env, visRect)) : false; 1387 } 1388 1389 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) 1390 { 1391 const CachedNode* node = getCursorNode(env, obj); 1392 return node ? node->isAnchor() : false; 1393 } 1394 1395 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) 1396 { 1397 const CachedNode* node = getCursorNode(env, obj); 1398 return node ? node->isTextInput() : false; 1399 } 1400 1401 static jobject nativeCursorText(JNIEnv *env, jobject obj) 1402 { 1403 const CachedNode* node = getCursorNode(env, obj); 1404 if (!node) 1405 return 0; 1406 WebCore::String value = node->getExport(); 1407 return !value.isEmpty() ? env->NewString((jchar *)value.characters(), 1408 value.length()) : 0; 1409 } 1410 1411 static void nativeDebugDump(JNIEnv *env, jobject obj) 1412 { 1413 #if DUMP_NAV_CACHE 1414 WebView* view = GET_NATIVE_VIEW(env, obj); 1415 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1416 view->debugDump(); 1417 #endif 1418 } 1419 1420 static void nativeDrawExtras(JNIEnv *env, jobject obj, jobject canv, jint extras) 1421 { 1422 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); 1423 GET_NATIVE_VIEW(env, obj)->drawExtras(canvas, extras); 1424 } 1425 1426 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj) 1427 { 1428 #if USE(ACCELERATED_COMPOSITING) 1429 const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer(); 1430 if (root) 1431 return root->evaluateAnimations(); 1432 #endif 1433 return false; 1434 } 1435 1436 static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer) 1437 { 1438 #if USE(ACCELERATED_COMPOSITING) 1439 LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); 1440 GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl); 1441 #endif 1442 } 1443 1444 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) 1445 { 1446 WebView* view = GET_NATIVE_VIEW(env, obj); 1447 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1448 WebCore::String uri = view->imageURI(x, y); 1449 jstring ret = 0; 1450 unsigned len = uri.length(); 1451 if (len) { 1452 ret = env->NewString((jchar*) uri.characters(), len); 1453 env->DeleteLocalRef(ret); 1454 } 1455 return ret; 1456 } 1457 1458 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) 1459 { 1460 WebView* view = GET_NATIVE_VIEW(env, obj); 1461 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1462 if (!root) 1463 return 0; 1464 const CachedFrame* frame = 0; 1465 const CachedNode* cursor = root->currentCursor(&frame); 1466 if (!cursor || !cursor->wantsKeyEvents()) 1467 (void) root->currentFocus(&frame); 1468 return reinterpret_cast<int>(frame ? frame->framePointer() : 0); 1469 } 1470 1471 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) 1472 { 1473 const CachedInput* input = getInputCandidate(env, obj); 1474 return input && input->inputType() == WebCore::HTMLInputElement::PASSWORD; 1475 } 1476 1477 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) 1478 { 1479 const CachedInput* input = getInputCandidate(env, obj); 1480 return input ? input->isRtlText() : false; 1481 } 1482 1483 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) 1484 { 1485 const CachedNode* node = getFocusCandidate(env, obj, 0); 1486 return node ? node->isTextInput() : false; 1487 } 1488 1489 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) 1490 { 1491 const CachedInput* input = getInputCandidate(env, obj); 1492 return input ? input->maxLength() : false; 1493 } 1494 1495 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) 1496 { 1497 const CachedInput* input = getInputCandidate(env, obj); 1498 if (!input) 1499 return 0; 1500 const WebCore::String& name = input->name(); 1501 return env->NewString((jchar*)name.characters(), name.length()); 1502 } 1503 1504 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom) 1505 { 1506 jclass rectClass = env->FindClass("android/graphics/Rect"); 1507 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1508 jobject rect = env->NewObject(rectClass, init, x, y, right, bottom); 1509 return rect; 1510 } 1511 1512 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) 1513 { 1514 const CachedFrame* frame; 1515 const CachedNode* node = getFocusCandidate(env, obj, &frame); 1516 WebCore::IntRect bounds = node ? node->bounds(frame) 1517 : WebCore::IntRect(0, 0, 0, 0); 1518 return createJavaRect(env, bounds.x(), bounds.y(), bounds.right(), bounds.bottom()); 1519 } 1520 1521 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) 1522 { 1523 const CachedInput* input = getInputCandidate(env, obj); 1524 if (!input) 1525 return 0; 1526 // Note that the Java Rect is being used to pass four integers, rather than 1527 // being used as an actual rectangle. 1528 return createJavaRect(env, input->paddingLeft(), input->paddingTop(), 1529 input->paddingRight(), input->paddingBottom()); 1530 } 1531 1532 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) 1533 { 1534 const CachedNode* node = getFocusCandidate(env, obj, 0); 1535 return reinterpret_cast<int>(node ? node->nodePointer() : 0); 1536 } 1537 1538 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) 1539 { 1540 const CachedNode* node = getFocusCandidate(env, obj, 0); 1541 if (!node) 1542 return 0; 1543 WebCore::String value = node->getExport(); 1544 return !value.isEmpty() ? env->NewString((jchar *)value.characters(), 1545 value.length()) : 0; 1546 } 1547 1548 static jint nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) 1549 { 1550 const CachedInput* input = getInputCandidate(env, obj); 1551 return input ? input->textSize() : 0; 1552 } 1553 1554 enum type { 1555 NONE = -1, 1556 NORMAL_TEXT_FIELD = 0, 1557 TEXT_AREA = 1, 1558 PASSWORD = 2, 1559 SEARCH = 3, 1560 EMAIL = 4, 1561 NUMBER = 5, 1562 TELEPHONE = 6, 1563 URL = 7 1564 }; 1565 1566 static int nativeFocusCandidateType(JNIEnv *env, jobject obj) 1567 { 1568 const CachedInput* input = getInputCandidate(env, obj); 1569 if (!input) return NONE; 1570 if (!input->isTextField()) return TEXT_AREA; 1571 switch (input->inputType()) { 1572 case HTMLInputElement::PASSWORD: 1573 return PASSWORD; 1574 case HTMLInputElement::SEARCH: 1575 return SEARCH; 1576 case HTMLInputElement::EMAIL: 1577 return EMAIL; 1578 case HTMLInputElement::NUMBER: 1579 return NUMBER; 1580 case HTMLInputElement::TELEPHONE: 1581 return TELEPHONE; 1582 case HTMLInputElement::URL: 1583 return URL; 1584 default: 1585 return NORMAL_TEXT_FIELD; 1586 } 1587 } 1588 1589 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) 1590 { 1591 const CachedNode* node = getFocusNode(env, obj); 1592 return node ? node->isPlugin() : false; 1593 } 1594 1595 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj) 1596 { 1597 const CachedFrame* frame; 1598 const CachedNode* node = getFocusNode(env, obj, &frame); 1599 WebCore::IntRect bounds = node ? node->bounds(frame) 1600 : WebCore::IntRect(0, 0, 0, 0); 1601 jclass rectClass = env->FindClass("android/graphics/Rect"); 1602 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1603 jobject rect = env->NewObject(rectClass, init, bounds.x(), 1604 bounds.y(), bounds.right(), bounds.bottom()); 1605 return rect; 1606 } 1607 1608 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) 1609 { 1610 const CachedNode* node = getFocusNode(env, obj); 1611 return node ? reinterpret_cast<int>(node->nodePointer()) : 0; 1612 } 1613 1614 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { 1615 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1616 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1617 return view->cursorWantsKeyEvents(); 1618 } 1619 1620 static void nativeHideCursor(JNIEnv *env, jobject obj) 1621 { 1622 WebView* view = GET_NATIVE_VIEW(env, obj); 1623 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1624 view->hideCursor(); 1625 } 1626 1627 static void nativeInstrumentReport(JNIEnv *env, jobject obj) 1628 { 1629 #ifdef ANDROID_INSTRUMENT 1630 TimeCounter::reportNow(); 1631 #endif 1632 } 1633 1634 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) 1635 { 1636 WebView* view = GET_NATIVE_VIEW(env, obj); 1637 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1638 WebCore::IntRect rect = jrect_to_webrect(env, jrect); 1639 view->selectBestAt(rect); 1640 } 1641 1642 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) 1643 { 1644 SkIRect irect = jrect_to_webrect(env, jrect); 1645 #if USE(ACCELERATED_COMPOSITING) 1646 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer(); 1647 if (root) { 1648 SkRect rect; 1649 rect.set(irect); 1650 rect = root->subtractLayers(rect); 1651 rect.round(&irect); 1652 } 1653 #endif 1654 jclass rectClass = env->FindClass("android/graphics/Rect"); 1655 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1656 return env->NewObject(rectClass, init, irect.fLeft, irect.fTop, 1657 irect.fRight, irect.fBottom); 1658 } 1659 1660 static jint nativeTextGeneration(JNIEnv *env, jobject obj) 1661 { 1662 WebView* view = GET_NATIVE_VIEW(env, obj); 1663 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1664 return root ? root->textGeneration() : 0; 1665 } 1666 1667 static bool nativePointInNavCache(JNIEnv *env, jobject obj, 1668 int x, int y, int slop) 1669 { 1670 return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop); 1671 } 1672 1673 static bool nativeMotionUp(JNIEnv *env, jobject obj, 1674 int x, int y, int slop) 1675 { 1676 WebView* view = GET_NATIVE_VIEW(env, obj); 1677 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1678 return view->motionUp(x, y, slop); 1679 } 1680 1681 static bool nativeHasCursorNode(JNIEnv *env, jobject obj) 1682 { 1683 return GET_NATIVE_VIEW(env, obj)->hasCursorNode(); 1684 } 1685 1686 static bool nativeHasFocusNode(JNIEnv *env, jobject obj) 1687 { 1688 return GET_NATIVE_VIEW(env, obj)->hasFocusNode(); 1689 } 1690 1691 static bool nativeMoveCursor(JNIEnv *env, jobject obj, 1692 int key, int count, bool ignoreScroll) 1693 { 1694 WebView* view = GET_NATIVE_VIEW(env, obj); 1695 DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); 1696 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1697 return view->moveCursor(key, count, ignoreScroll); 1698 } 1699 1700 static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus, 1701 bool pressed, bool invalidate) 1702 { 1703 WebView* view = GET_NATIVE_VIEW(env, obj); 1704 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1705 view->nativeRecordButtons(hasFocus, pressed, invalidate); 1706 } 1707 1708 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) 1709 { 1710 WebView* view = GET_NATIVE_VIEW(env, obj); 1711 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1712 view->setFindIsUp(isUp); 1713 } 1714 1715 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj) 1716 { 1717 GET_NATIVE_VIEW(env, obj)->setFindIsEmpty(); 1718 } 1719 1720 static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed) 1721 { 1722 WebView* view = GET_NATIVE_VIEW(env, obj); 1723 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1724 view->setFollowedLink(followed); 1725 } 1726 1727 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) 1728 { 1729 WebView* view = GET_NATIVE_VIEW(env, obj); 1730 LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); 1731 view->setHeightCanMeasure(measure); 1732 } 1733 1734 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj) 1735 { 1736 WebView* view = GET_NATIVE_VIEW(env, obj); 1737 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1738 jclass rectClass = env->FindClass("android/graphics/Rect"); 1739 LOG_ASSERT(rectClass, "Could not find Rect class!"); 1740 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); 1741 LOG_ASSERT(init, "Could not find constructor for Rect"); 1742 WebCore::IntRect webRect; 1743 view->cursorRingBounds(&webRect); 1744 jobject rect = env->NewObject(rectClass, init, webRect.x(), 1745 webRect.y(), webRect.right(), webRect.bottom()); 1746 return rect; 1747 } 1748 1749 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, 1750 jstring findUpper) 1751 { 1752 // If one or the other is null, do not search. 1753 if (!(findLower && findUpper)) 1754 return 0; 1755 // Obtain the characters for both the lower case string and the upper case 1756 // string representing the same word. 1757 const jchar* findLowerChars = env->GetStringChars(findLower, 0); 1758 const jchar* findUpperChars = env->GetStringChars(findUpper, 0); 1759 // If one or the other is null, do not search. 1760 if (!(findLowerChars && findUpperChars)) { 1761 if (findLowerChars) 1762 env->ReleaseStringChars(findLower, findLowerChars); 1763 if (findUpperChars) 1764 env->ReleaseStringChars(findUpper, findUpperChars); 1765 checkException(env); 1766 return 0; 1767 } 1768 WebView* view = GET_NATIVE_VIEW(env, obj); 1769 LOG_ASSERT(view, "view not set in nativeFindAll"); 1770 CachedRoot* root = view->getFrameCache(WebView::AllowNewer); 1771 if (!root) { 1772 env->ReleaseStringChars(findLower, findLowerChars); 1773 env->ReleaseStringChars(findUpper, findUpperChars); 1774 checkException(env); 1775 return 0; 1776 } 1777 int length = env->GetStringLength(findLower); 1778 // If the lengths of the strings do not match, then they are not the same 1779 // word, so do not search. 1780 if (!length || env->GetStringLength(findUpper) != length) { 1781 env->ReleaseStringChars(findLower, findLowerChars); 1782 env->ReleaseStringChars(findUpper, findUpperChars); 1783 checkException(env); 1784 return 0; 1785 } 1786 int width = root->documentWidth(); 1787 int height = root->documentHeight(); 1788 // Create a FindCanvas, which allows us to fake draw into it so we can 1789 // figure out where our search string is rendered (and how many times). 1790 FindCanvas canvas(width, height, (const UChar*) findLowerChars, 1791 (const UChar*) findUpperChars, length << 1); 1792 SkBitmap bitmap; 1793 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); 1794 canvas.setBitmapDevice(bitmap); 1795 root->draw(canvas); 1796 WTF::Vector<MatchInfo>* matches = canvas.detachMatches(); 1797 // With setMatches, the WebView takes ownership of matches 1798 view->setMatches(matches); 1799 1800 env->ReleaseStringChars(findLower, findLowerChars); 1801 env->ReleaseStringChars(findUpper, findUpperChars); 1802 checkException(env); 1803 return canvas.found(); 1804 } 1805 1806 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward) 1807 { 1808 WebView* view = GET_NATIVE_VIEW(env, obj); 1809 LOG_ASSERT(view, "view not set in nativeFindNext"); 1810 view->findNext(forward); 1811 } 1812 1813 static int nativeFindIndex(JNIEnv *env, jobject obj) 1814 { 1815 WebView* view = GET_NATIVE_VIEW(env, obj); 1816 LOG_ASSERT(view, "view not set in nativeFindIndex"); 1817 return view->currentMatchIndex(); 1818 } 1819 1820 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation) 1821 { 1822 WebView* view = GET_NATIVE_VIEW(env, obj); 1823 LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield"); 1824 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1825 if (!root) 1826 return; 1827 const CachedNode* cachedFocusNode = root->currentFocus(); 1828 if (!cachedFocusNode || !cachedFocusNode->isTextInput()) 1829 return; 1830 WebCore::String webcoreString = to_string(env, updatedText); 1831 (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString); 1832 root->setTextGeneration(generation); 1833 checkException(env); 1834 } 1835 1836 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y, 1837 jfloat scale) 1838 { 1839 WebView* view = GET_NATIVE_VIEW(env, obj); 1840 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1841 if (!view) 1842 return -1; 1843 return view->getBlockLeftEdge(x, y, scale); 1844 } 1845 1846 static void nativeDestroy(JNIEnv *env, jobject obj) 1847 { 1848 WebView* view = GET_NATIVE_VIEW(env, obj); 1849 LOGD("nativeDestroy view: %p", view); 1850 LOG_ASSERT(view, "view not set in nativeDestroy"); 1851 delete view; 1852 } 1853 1854 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) 1855 { 1856 WebView* view = GET_NATIVE_VIEW(env, obj); 1857 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); 1858 if (!root) 1859 return false; 1860 const CachedNode* current = root->currentCursor(); 1861 if (!current || !current->isTextInput()) 1862 current = root->currentFocus(); 1863 if (!current || !current->isTextInput()) 1864 return false; 1865 const CachedFrame* frame; 1866 const CachedNode* next = root->nextTextField(current, &frame); 1867 if (!next) 1868 return false; 1869 const WebCore::IntRect& bounds = next->bounds(frame); 1870 root->rootHistory()->setMouseBounds(bounds); 1871 view->getWebViewCore()->updateCursorBounds(root, frame, next); 1872 root->setCursor(const_cast<CachedFrame*>(frame), 1873 const_cast<CachedNode*>(next)); 1874 view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()), 1875 static_cast<WebCore::Node*>(next->nodePointer())); 1876 if (!next->isInLayer()) 1877 view->scrollRectOnScreen(bounds); 1878 view->getWebViewCore()->m_moveGeneration++; 1879 return true; 1880 } 1881 1882 static int nativeMoveGeneration(JNIEnv *env, jobject obj) 1883 { 1884 WebView* view = GET_NATIVE_VIEW(env, obj); 1885 if (!view) 1886 return 0; 1887 return view->moveGeneration(); 1888 } 1889 1890 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y) 1891 { 1892 GET_NATIVE_VIEW(env, obj)->moveSelection(x, y); 1893 } 1894 1895 static void nativeResetSelection(JNIEnv *env, jobject obj) 1896 { 1897 return GET_NATIVE_VIEW(env, obj)->resetSelection(); 1898 } 1899 1900 static void nativeSelectAll(JNIEnv* env, jobject obj) 1901 { 1902 GET_NATIVE_VIEW(env, obj)->selectAll(); 1903 } 1904 1905 static void nativeSetExtendSelection(JNIEnv *env, jobject obj) 1906 { 1907 GET_NATIVE_VIEW(env, obj)->setExtendSelection(); 1908 } 1909 1910 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y) 1911 { 1912 return GET_NATIVE_VIEW(env, obj)->startSelection(x, y); 1913 } 1914 1915 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y) 1916 { 1917 return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y); 1918 } 1919 1920 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y) 1921 { 1922 GET_NATIVE_VIEW(env, obj)->extendSelection(x, y); 1923 } 1924 1925 static jobject nativeGetSelection(JNIEnv *env, jobject obj) 1926 { 1927 WebView* view = GET_NATIVE_VIEW(env, obj); 1928 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1929 String selection = view->getSelection(); 1930 return env->NewString((jchar*)selection.characters(), selection.length()); 1931 } 1932 1933 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y) 1934 { 1935 return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y); 1936 } 1937 1938 static jint nativeSelectionX(JNIEnv *env, jobject obj) 1939 { 1940 return GET_NATIVE_VIEW(env, obj)->selectionX(); 1941 } 1942 1943 static jint nativeSelectionY(JNIEnv *env, jobject obj) 1944 { 1945 return GET_NATIVE_VIEW(env, obj)->selectionY(); 1946 } 1947 1948 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set, 1949 jfloat scale, jint x, jint y) 1950 { 1951 GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y); 1952 } 1953 1954 #ifdef ANDROID_DUMP_DISPLAY_TREE 1955 static void dumpToFile(const char text[], void* file) { 1956 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file)); 1957 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file)); 1958 } 1959 #endif 1960 1961 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) 1962 { 1963 #ifdef ANDROID_DUMP_DISPLAY_TREE 1964 WebView* view = GET_NATIVE_VIEW(env, jwebview); 1965 LOG_ASSERT(view, "view not set in %s", __FUNCTION__); 1966 1967 if (view && view->getWebViewCore()) { 1968 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); 1969 if (file) { 1970 SkFormatDumper dumper(dumpToFile, file); 1971 // dump the URL 1972 if (jurl) { 1973 const char* str = env->GetStringUTFChars(jurl, 0); 1974 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE); 1975 dumpToFile(str, file); 1976 env->ReleaseStringUTFChars(jurl, str); 1977 } 1978 // now dump the display tree 1979 SkDumpCanvas canvas(&dumper); 1980 // this will playback the picture into the canvas, which will 1981 // spew its contents to the dumper 1982 view->getWebViewCore()->drawContent(&canvas, 0); 1983 #if USE(ACCELERATED_COMPOSITING) 1984 if (true) { 1985 LayerAndroid* rootLayer = view->rootLayer(); 1986 if (rootLayer) { 1987 // We have to set the canvas' matrix on the root layer 1988 // (to have fixed layers work as intended) 1989 SkAutoCanvasRestore restore(&canvas, true); 1990 rootLayer->setMatrix(canvas.getTotalMatrix()); 1991 canvas.resetMatrix(); 1992 rootLayer->draw(&canvas); 1993 } 1994 } 1995 #endif 1996 // we're done with the file now 1997 fwrite("\n", 1, 1, file); 1998 fclose(file); 1999 } 2000 #if USE(ACCELERATED_COMPOSITING) 2001 const LayerAndroid* rootLayer = view->rootLayer(); 2002 if (rootLayer) { 2003 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); 2004 if (file) { 2005 rootLayer->dumpLayers(file, 0); 2006 fclose(file); 2007 } 2008 } 2009 #endif 2010 } 2011 #endif 2012 } 2013 2014 /* 2015 * JNI registration 2016 */ 2017 static JNINativeMethod gJavaWebViewMethods[] = { 2018 { "nativeCacheHitFramePointer", "()I", 2019 (void*) nativeCacheHitFramePointer }, 2020 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;", 2021 (void*) nativeCacheHitNodeBounds }, 2022 { "nativeCacheHitNodePointer", "()I", 2023 (void*) nativeCacheHitNodePointer }, 2024 { "nativeClearCursor", "()V", 2025 (void*) nativeClearCursor }, 2026 { "nativeCreate", "(I)V", 2027 (void*) nativeCreate }, 2028 { "nativeCursorFramePointer", "()I", 2029 (void*) nativeCursorFramePointer }, 2030 { "nativeCursorMatchesFocus", "()Z", 2031 (void*) nativeCursorMatchesFocus }, 2032 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;", 2033 (void*) nativeCursorNodeBounds }, 2034 { "nativeCursorNodePointer", "()I", 2035 (void*) nativeCursorNodePointer }, 2036 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z", 2037 (void*) nativeCursorIntersects }, 2038 { "nativeCursorIsAnchor", "()Z", 2039 (void*) nativeCursorIsAnchor }, 2040 { "nativeCursorIsTextInput", "()Z", 2041 (void*) nativeCursorIsTextInput }, 2042 { "nativeCursorPosition", "()Landroid/graphics/Point;", 2043 (void*) nativeCursorPosition }, 2044 { "nativeCursorText", "()Ljava/lang/String;", 2045 (void*) nativeCursorText }, 2046 { "nativeCursorWantsKeyEvents", "()Z", 2047 (void*)nativeCursorWantsKeyEvents }, 2048 { "nativeDebugDump", "()V", 2049 (void*) nativeDebugDump }, 2050 { "nativeDestroy", "()V", 2051 (void*) nativeDestroy }, 2052 { "nativeDrawExtras", "(Landroid/graphics/Canvas;I)V", 2053 (void*) nativeDrawExtras }, 2054 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", 2055 (void*) nativeDumpDisplayTree }, 2056 { "nativeEvaluateLayersAnimations", "()Z", 2057 (void*) nativeEvaluateLayersAnimations }, 2058 { "nativeExtendSelection", "(II)V", 2059 (void*) nativeExtendSelection }, 2060 { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I", 2061 (void*) nativeFindAll }, 2062 { "nativeFindNext", "(Z)V", 2063 (void*) nativeFindNext }, 2064 { "nativeFindIndex", "()I", 2065 (void*) nativeFindIndex}, 2066 { "nativeFocusCandidateFramePointer", "()I", 2067 (void*) nativeFocusCandidateFramePointer }, 2068 { "nativeFocusCandidateHasNextTextfield", "()Z", 2069 (void*) focusCandidateHasNextTextfield }, 2070 { "nativeFocusCandidateIsPassword", "()Z", 2071 (void*) nativeFocusCandidateIsPassword }, 2072 { "nativeFocusCandidateIsRtlText", "()Z", 2073 (void*) nativeFocusCandidateIsRtlText }, 2074 { "nativeFocusCandidateIsTextInput", "()Z", 2075 (void*) nativeFocusCandidateIsTextInput }, 2076 { "nativeFocusCandidateMaxLength", "()I", 2077 (void*) nativeFocusCandidateMaxLength }, 2078 { "nativeFocusCandidateName", "()Ljava/lang/String;", 2079 (void*) nativeFocusCandidateName }, 2080 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;", 2081 (void*) nativeFocusCandidateNodeBounds }, 2082 { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;", 2083 (void*) nativeFocusCandidatePaddingRect }, 2084 { "nativeFocusCandidatePointer", "()I", 2085 (void*) nativeFocusCandidatePointer }, 2086 { "nativeFocusCandidateText", "()Ljava/lang/String;", 2087 (void*) nativeFocusCandidateText }, 2088 { "nativeFocusCandidateTextSize", "()I", 2089 (void*) nativeFocusCandidateTextSize }, 2090 { "nativeFocusCandidateType", "()I", 2091 (void*) nativeFocusCandidateType }, 2092 { "nativeFocusIsPlugin", "()Z", 2093 (void*) nativeFocusIsPlugin }, 2094 { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;", 2095 (void*) nativeFocusNodeBounds }, 2096 { "nativeFocusNodePointer", "()I", 2097 (void*) nativeFocusNodePointer }, 2098 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", 2099 (void*) nativeGetCursorRingBounds }, 2100 { "nativeGetSelection", "()Ljava/lang/String;", 2101 (void*) nativeGetSelection }, 2102 { "nativeHasCursorNode", "()Z", 2103 (void*) nativeHasCursorNode }, 2104 { "nativeHasFocusNode", "()Z", 2105 (void*) nativeHasFocusNode }, 2106 { "nativeHideCursor", "()V", 2107 (void*) nativeHideCursor }, 2108 { "nativeHitSelection", "(II)Z", 2109 (void*) nativeHitSelection }, 2110 { "nativeImageURI", "(II)Ljava/lang/String;", 2111 (void*) nativeImageURI }, 2112 { "nativeInstrumentReport", "()V", 2113 (void*) nativeInstrumentReport }, 2114 { "nativeMotionUp", "(III)Z", 2115 (void*) nativeMotionUp }, 2116 { "nativeMoveCursor", "(IIZ)Z", 2117 (void*) nativeMoveCursor }, 2118 { "nativeMoveCursorToNextTextInput", "()Z", 2119 (void*) nativeMoveCursorToNextTextInput }, 2120 { "nativeMoveGeneration", "()I", 2121 (void*) nativeMoveGeneration }, 2122 { "nativeMoveSelection", "(II)V", 2123 (void*) nativeMoveSelection }, 2124 { "nativePointInNavCache", "(III)Z", 2125 (void*) nativePointInNavCache }, 2126 { "nativeRecordButtons", "(ZZZ)V", 2127 (void*) nativeRecordButtons }, 2128 { "nativeResetSelection", "()V", 2129 (void*) nativeResetSelection }, 2130 { "nativeSelectAll", "()V", 2131 (void*) nativeSelectAll }, 2132 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V", 2133 (void*) nativeSelectBestAt }, 2134 { "nativeSelectionX", "()I", 2135 (void*) nativeSelectionX }, 2136 { "nativeSelectionY", "()I", 2137 (void*) nativeSelectionY }, 2138 { "nativeSetExtendSelection", "()V", 2139 (void*) nativeSetExtendSelection }, 2140 { "nativeSetFindIsEmpty", "()V", 2141 (void*) nativeSetFindIsEmpty }, 2142 { "nativeSetFindIsUp", "(Z)V", 2143 (void*) nativeSetFindIsUp }, 2144 { "nativeSetFollowedLink", "(Z)V", 2145 (void*) nativeSetFollowedLink }, 2146 { "nativeSetHeightCanMeasure", "(Z)V", 2147 (void*) nativeSetHeightCanMeasure }, 2148 { "nativeSetRootLayer", "(I)V", 2149 (void*) nativeSetRootLayer }, 2150 { "nativeSetSelectionPointer", "(ZFII)V", 2151 (void*) nativeSetSelectionPointer }, 2152 { "nativeStartSelection", "(II)Z", 2153 (void*) nativeStartSelection }, 2154 { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;", 2155 (void*) nativeSubtractLayers }, 2156 { "nativeTextGeneration", "()I", 2157 (void*) nativeTextGeneration }, 2158 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", 2159 (void*) nativeUpdateCachedTextfield }, 2160 { "nativeWordSelection", "(II)Z", 2161 (void*) nativeWordSelection }, 2162 { "nativeGetBlockLeftEdge", "(IIF)I", 2163 (void*) nativeGetBlockLeftEdge }, 2164 }; 2165 2166 int register_webview(JNIEnv* env) 2167 { 2168 jclass clazz = env->FindClass("android/webkit/WebView"); 2169 LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView"); 2170 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I"); 2171 LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass"); 2172 2173 return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); 2174 } 2175 2176 } // namespace android 2177