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