2 * Copyright 2007, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #define LOG_TAG "webviewglue"
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"
39 #include "GraphicsJNI.h"
40 #include "HTMLInputElement.h"
43 #include "LayerAndroid.h"
45 #include "utils/Functor.h"
46 #include "PlatformGraphicsContext.h"
47 #include "PlatformString.h"
48 #include "ScrollableLayerAndroid.h"
49 #include "SelectText.h"
51 #include "SkDumpCanvas.h"
52 #include "SkPicture.h"
55 #ifdef ANDROID_INSTRUMENT
56 #include "TimeCounter.h"
58 #include "TilesManager.h"
59 #include "WebCoreJni.h"
60 #include "WebRequestContext.h"
61 #include "WebViewCore.h"
62 #include "android_graphics.h"
64 #ifdef GET_NATIVE_VIEW
65 #undef GET_NATIVE_VIEW
68 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
70 #include <JNIUtility.h>
73 #include <android_runtime/android_util_AssetManager.h>
74 #include <ui/KeycodeLabels.h>
75 #include <utils/AssetManager.h>
76 #include <wtf/text/AtomicString.h>
77 #include <wtf/text/CString.h>
81 static jfieldID gWebViewField;
83 //-------------------------------------
85 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
87 jmethodID m = env->GetMethodID(clazz, name, signature);
88 LOG_ASSERT(m, "Could not find method %s", name);
92 //-------------------------------------
93 // This class provides JNI for making calls into native code from the UI side
94 // of the multi-threaded WebView.
98 enum FrameCachePermission {
104 enum DrawExtras { // keep this in sync with WebView.java
107 DrawExtrasSelection = 2,
108 DrawExtrasCursorRing = 3
113 jmethodID m_calcOurContentVisibleRectF;
114 jmethodID m_overrideLoading;
115 jmethodID m_scrollBy;
116 jmethodID m_sendMoveFocus;
117 jmethodID m_sendMoveMouse;
118 jmethodID m_sendMoveMouseIfLatest;
119 jmethodID m_sendMotionUp;
120 jmethodID m_domChangedFocus;
121 jmethodID m_getScaledMaxXScroll;
122 jmethodID m_getScaledMaxYScroll;
123 jmethodID m_getVisibleRect;
124 jmethodID m_rebuildWebTextView;
125 jmethodID m_viewInvalidate;
126 jmethodID m_viewInvalidateRect;
127 jmethodID m_postInvalidateDelayed;
128 jmethodID m_inFullScreenMode;
131 jmethodID m_rectWidth;
132 jmethodID m_rectHeight;
133 jfieldID m_rectFLeft;
135 jmethodID m_rectFWidth;
136 jmethodID m_rectFHeight;
137 AutoJObject object(JNIEnv* env) {
138 return getRealObject(env, m_obj);
142 WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, AssetManager* am) :
143 m_ring((WebViewCore*) viewImpl)
145 jclass clazz = env->FindClass("android/webkit/WebView");
146 // m_javaGlue = new JavaGlue;
147 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
148 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
149 m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
150 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
151 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
152 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
153 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V");
154 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
155 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
156 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
157 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
158 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
159 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
160 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
161 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
162 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
163 "viewInvalidateDelayed", "(JIIII)V");
164 m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
165 env->DeleteLocalRef(clazz);
167 jclass rectClass = env->FindClass("android/graphics/Rect");
168 LOG_ASSERT(rectClass, "Could not find Rect class");
169 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
170 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
171 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
172 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
173 env->DeleteLocalRef(rectClass);
175 jclass rectClassF = env->FindClass("android/graphics/RectF");
176 LOG_ASSERT(rectClassF, "Could not find RectF class");
177 m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
178 m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
179 m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
180 m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
181 env->DeleteLocalRef(rectClassF);
183 env->SetIntField(javaWebView, gWebViewField, (jint)this);
184 m_viewImpl = (WebViewCore*) viewImpl;
188 m_heightCanMeasure = false;
191 m_ringAnimationEnd = 0;
194 if (drawableDir.isEmpty())
197 m_buttonSkin = new RenderSkinButton(am, drawableDir);
198 #if USE(ACCELERATED_COMPOSITING)
199 m_glWebViewState = 0;
205 if (m_javaGlue.m_obj)
207 JNIEnv* env = JSC::Bindings::getJNIEnv();
208 env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
209 m_javaGlue.m_obj = 0;
211 #if USE(ACCELERATED_COMPOSITING)
212 // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
213 // do not remove it here, we risk having BaseTiles trying to paint using a
214 // deallocated base layer.
217 delete m_frameCacheUI;
218 delete m_navPictureUI;
219 SkSafeUnref(m_baseLayer);
220 delete m_glDrawFunctor;
226 #if USE(ACCELERATED_COMPOSITING)
227 delete m_glWebViewState;
228 m_glWebViewState = 0;
232 WebViewCore* getWebViewCore() const {
236 // removes the cursor altogether (e.g., when going to a new page)
239 CachedRoot* root = getFrameCache(AllowNewer);
243 m_viewImpl->m_hasCursorBounds = false;
248 // leaves the cursor where it is, but suppresses drawing it
251 CachedRoot* root = getFrameCache(AllowNewer);
258 void hideCursor(CachedRoot* root)
260 DBG_NAV_LOG("inner");
261 m_viewImpl->m_hasCursorBounds = false;
269 CachedRoot* root = getFrameCache(DontAllowNewer);
271 root->mDebug.print();
275 // Traverse our stored array of buttons that are in our picture, and update
276 // their subpictures according to their current state.
277 // Called from the UI thread. This is the one place in the UI thread where we
278 // access the buttons stored in the WebCore thread.
279 // hasFocus keeps track of whether the WebView has focus && windowFocus.
280 // If not, we do not want to draw the button in a selected or pressed state
281 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
283 bool cursorIsOnButton = false;
284 const CachedFrame* cachedFrame;
285 const CachedNode* cachedCursor = 0;
286 // Lock the mutex, since we now share with the WebCore thread.
287 m_viewImpl->gButtonMutex.lock();
288 if (m_viewImpl->m_buttons.size() && m_buttonSkin) {
289 // FIXME: In a future change, we should keep track of whether the selection
290 // has changed to short circuit (note that we would still need to update
291 // if we received new buttons from the WebCore thread).
292 WebCore::Node* cursor = 0;
293 CachedRoot* root = getFrameCache(DontAllowNewer);
295 cachedCursor = root->currentCursor(&cachedFrame);
297 cursor = (WebCore::Node*) cachedCursor->nodePointer();
300 // Traverse the array, and update each button, depending on whether it
302 Container* end = m_viewImpl->m_buttons.end();
303 for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
304 RenderSkinAndroid::State state = RenderSkinAndroid::kNormal;
305 if (ptr->matches(cursor)) {
306 cursorIsOnButton = true;
307 // If the WebView is out of focus/window focus, set the state to
308 // normal, but still keep track of the fact that the selected is a
311 if (pressed || m_ring.m_isPressed)
312 state = RenderSkinAndroid::kPressed;
313 else if (SkTime::GetMSecs() < m_ringAnimationEnd)
314 state = RenderSkinAndroid::kFocused;
317 ptr->updateFocusState(state, m_buttonSkin);
320 m_viewImpl->gButtonMutex.unlock();
321 if (invalidate && cachedCursor && cursorIsOnButton) {
322 const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
323 viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom());
327 // The caller has already determined that the desired document rect corresponds
328 // to the main picture, and not a layer
329 void scrollRectOnScreen(const IntRect& rect)
334 calcOurContentVisibleRect(&visible);
335 #if USE(ACCELERATED_COMPOSITING)
336 LayerAndroid* root = compositeRoot();
338 root->updateFixedLayersPositions(visible);
339 root->updatePositions();
340 visible = root->subtractLayers(visible);
345 int right = rect.right();
346 if (left < visible.fLeft) {
347 dx = left - visible.fLeft;
348 // Only scroll right if the entire width can fit on screen.
349 } else if (right > visible.fRight && right - left < visible.width()) {
350 dx = right - visible.fRight;
354 int bottom = rect.bottom();
355 if (top < visible.fTop) {
356 dy = top - visible.fTop;
357 // Only scroll down if the entire height can fit on screen
358 } else if (bottom > visible.fBottom && bottom - top < visible.height()) {
359 dy = bottom - visible.fBottom;
361 if ((dx|dy) == 0 || !scrollBy(dx, dy))
366 void calcOurContentVisibleRect(SkRect* r)
368 JNIEnv* env = JSC::Bindings::getJNIEnv();
369 jclass rectClass = env->FindClass("android/graphics/RectF");
370 jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V");
371 jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0);
372 env->CallVoidMethod(m_javaGlue.object(env).get(),
373 m_javaGlue.m_calcOurContentVisibleRectF, jRect);
374 r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft);
375 r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop);
376 r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth);
377 r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight);
378 env->DeleteLocalRef(rectClass);
379 env->DeleteLocalRef(jRect);
383 void resetCursorRing()
385 m_ringAnimationEnd = 0;
386 m_viewImpl->m_hasCursorBounds = false;
389 bool drawCursorPreamble(CachedRoot* root)
391 const CachedFrame* frame;
392 const CachedNode* node = root->currentCursor(&frame);
394 DBG_NAV_LOGV("%s", "!node");
398 m_ring.setIsButton(node);
399 if (node->isHidden()) {
400 DBG_NAV_LOG("node->isHidden()");
401 m_viewImpl->m_hasCursorBounds = false;
404 #if USE(ACCELERATED_COMPOSITING)
405 if (node->isInLayer() && root->rootLayer()) {
406 LayerAndroid* layer = const_cast<LayerAndroid*>(root->rootLayer());
408 calcOurContentVisibleRect(&visible);
409 layer->updateFixedLayersPositions(visible);
410 layer->updatePositions();
413 setVisibleRect(root);
414 m_ring.m_root = root;
415 m_ring.m_frame = frame;
416 m_ring.m_node = node;
417 SkMSec time = SkTime::GetMSecs();
418 m_ring.m_isPressed = time < m_ringAnimationEnd
419 && m_ringAnimationEnd != UINT_MAX;
423 void drawCursorPostamble()
425 if (m_ringAnimationEnd == UINT_MAX)
427 SkMSec time = SkTime::GetMSecs();
428 if (time < m_ringAnimationEnd) {
429 // views assume that inval bounds coordinates are non-negative
430 WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
431 invalBounds.intersect(m_ring.m_absBounds);
432 postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
434 hideCursor(const_cast<CachedRoot*>(m_ring.m_root));
438 bool drawGL(WebCore::IntRect& viewRect, float scale, int extras)
440 #if USE(ACCELERATED_COMPOSITING)
441 if (!m_baseLayer || inFullScreenMode())
444 if (!m_glWebViewState) {
445 m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex);
446 if (m_baseLayer->content()) {
449 rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
450 region.setRect(rect);
451 m_glWebViewState->setBaseLayer(m_baseLayer, region, false, false);
455 CachedRoot* root = getFrameCache(AllowNewer);
457 DBG_NAV_LOG("!root");
458 if (extras == DrawExtrasCursorRing)
462 DrawExtra* extra = 0;
465 extra = &m_findOnPage;
467 case DrawExtrasSelection:
468 extra = &m_selectText;
470 case DrawExtrasCursorRing:
471 if (drawCursorPreamble(root) && m_ring.setup()) {
472 if (!m_ring.m_isButton)
474 drawCursorPostamble();
481 unsigned int pic = m_glWebViewState->currentPictureCounter();
484 IntRect rect(0, 0, 0, 0);
485 bool allowSame = false;
487 LayerAndroid mainPicture(m_navPictureUI);
488 PictureSet* content = m_baseLayer->content();
489 SkCanvas* canvas = picture.beginRecording(content->width(),
491 extra->draw(canvas, &mainPicture, &rect);
492 picture.endRecording();
493 } else if (extras == DrawExtrasCursorRing && m_ring.m_isButton) {
494 const CachedFrame* cachedFrame;
495 const CachedNode* cachedCursor = root->currentCursor(&cachedFrame);
497 rect = cachedCursor->bounds(cachedFrame);
501 m_glWebViewState->setExtra(m_baseLayer, picture, rect, allowSame);
503 LayerAndroid* compositeLayer = compositeRoot();
505 compositeLayer->setExtra(extra);
508 calcOurContentVisibleRect(&visibleRect);
509 bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, scale);
510 if (ret || m_glWebViewState->currentPictureCounter() != pic)
516 PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
520 canvas->drawColor(bgColor);
524 // draw the content of the base layer first
525 PictureSet* content = m_baseLayer->content();
526 int sc = canvas->save(SkCanvas::kClip_SaveFlag);
527 canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
528 content->height()), SkRegion::kDifference_Op);
529 canvas->drawColor(bgColor);
530 canvas->restoreToCount(sc);
531 if (content->draw(canvas))
532 ret = split ? new PictureSet(*content) : 0;
534 CachedRoot* root = getFrameCache(AllowNewer);
536 DBG_NAV_LOG("!root");
537 if (extras == DrawExtrasCursorRing)
541 LayerAndroid mainPicture(m_navPictureUI);
542 DrawExtra* extra = 0;
545 extra = &m_findOnPage;
547 case DrawExtrasSelection:
548 extra = &m_selectText;
550 case DrawExtrasCursorRing:
551 if (drawCursorPreamble(root) && m_ring.setup()) {
552 if (!m_ring.m_isButton)
554 drawCursorPostamble();
561 IntRect dummy; // inval area, unused for now
562 extra->draw(canvas, &mainPicture, &dummy);
564 #if USE(ACCELERATED_COMPOSITING)
565 LayerAndroid* compositeLayer = compositeRoot();
568 compositeLayer->setExtra(extra);
570 calcOurContentVisibleRect(&visible);
571 // call this to be sure we've adjusted for any scrolling or animations
572 // before we actually draw
573 compositeLayer->updateFixedLayersPositions(visible);
574 compositeLayer->updatePositions();
575 // We have to set the canvas' matrix on the base layer
576 // (to have fixed layers work as intended)
577 SkAutoCanvasRestore restore(canvas, true);
578 m_baseLayer->setMatrix(canvas->getTotalMatrix());
579 canvas->resetMatrix();
580 m_baseLayer->draw(canvas);
586 bool cursorIsTextInput(FrameCachePermission allowNewer)
588 CachedRoot* root = getFrameCache(allowNewer);
590 DBG_NAV_LOG("!root");
593 const CachedNode* cursor = root->currentCursor();
595 DBG_NAV_LOG("!cursor");
598 DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
599 return cursor->isTextInput();
602 void cursorRingBounds(WebCore::IntRect* bounds)
604 DBG_NAV_LOGD("%s", "");
605 CachedRoot* root = getFrameCache(DontAllowNewer);
607 const CachedFrame* cachedFrame;
608 const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
610 *bounds = cachedNode->cursorRingBounds(cachedFrame);
611 DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
612 bounds->width(), bounds->height());
616 *bounds = WebCore::IntRect(0, 0, 0, 0);
621 m_viewImpl->gCursorBoundsMutex.lock();
622 bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
623 IntRect bounds = m_viewImpl->m_cursorBounds;
624 m_viewImpl->gCursorBoundsMutex.unlock();
625 if (!hasCursorBounds)
628 const CachedFrame* frame;
629 const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true);
632 // require that node have approximately the same bounds (+/- 4) and the same
634 IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
635 bounds.y() + (bounds.height() >> 1));
636 IntRect newBounds = node->bounds(frame);
637 IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
638 newBounds.y() + (newBounds.height() >> 1));
639 DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
640 " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
641 oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
642 bounds.x(), bounds.y(), bounds.width(), bounds.height(),
643 newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
644 if (abs(oldCenter.x() - newCenter.x()) > 2)
646 if (abs(oldCenter.y() - newCenter.y()) > 2)
648 if (abs(bounds.x() - newBounds.x()) > 4)
650 if (abs(bounds.y() - newBounds.y()) > 4)
652 if (abs(bounds.right() - newBounds.right()) > 4)
654 if (abs(bounds.bottom() - newBounds.bottom()) > 4)
656 DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
657 node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
659 m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
660 const_cast<CachedNode*>(node));
663 CachedRoot* getFrameCache(FrameCachePermission allowNewer)
665 if (!m_viewImpl->m_updatedFrameCache) {
666 DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
667 return m_frameCacheUI;
669 if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
670 DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
671 " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
672 return m_frameCacheUI;
674 DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
675 const CachedFrame* oldCursorFrame;
676 const CachedNode* oldCursorNode = m_frameCacheUI ?
677 m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
678 #if USE(ACCELERATED_COMPOSITING)
680 if (oldCursorNode && oldCursorNode->isInLayer()) {
681 const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
682 ->layer(m_frameCacheUI->rootLayer());
684 layerId = cursorLayer->uniqueId();
687 // get id from old layer and use to find new layer
688 bool oldFocusIsTextInput = false;
689 void* oldFocusNodePointer = 0;
690 if (m_frameCacheUI) {
691 const CachedNode* oldFocus = m_frameCacheUI->currentFocus();
693 oldFocusIsTextInput = oldFocus->isTextInput();
694 oldFocusNodePointer = oldFocus->nodePointer();
697 m_viewImpl->gFrameCacheMutex.lock();
698 delete m_frameCacheUI;
699 SkSafeUnref(m_navPictureUI);
700 m_viewImpl->m_updatedFrameCache = false;
701 m_frameCacheUI = m_viewImpl->m_frameCacheKit;
702 m_navPictureUI = m_viewImpl->m_navPictureKit;
703 m_viewImpl->m_frameCacheKit = 0;
704 m_viewImpl->m_navPictureKit = 0;
705 m_viewImpl->gFrameCacheMutex.unlock();
707 m_frameCacheUI->setRootLayer(compositeRoot());
708 #if USE(ACCELERATED_COMPOSITING)
711 calcOurContentVisibleRect(&visible);
712 LayerAndroid* layer = const_cast<LayerAndroid*>(
713 m_frameCacheUI->rootLayer());
715 layer->updateFixedLayersPositions(visible);
716 layer->updatePositions();
721 if (oldFocusIsTextInput) {
722 const CachedNode* newFocus = m_frameCacheUI->currentFocus();
723 if (newFocus && oldFocusNodePointer != newFocus->nodePointer()
724 && newFocus->isTextInput()
725 && newFocus != m_frameCacheUI->currentCursor()) {
726 // The focus has changed. We may need to update things.
727 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
728 JNIEnv* env = JSC::Bindings::getJNIEnv();
729 env->CallVoidMethod(m_javaGlue.object(env).get(),
730 m_javaGlue.m_domChangedFocus);
734 if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
735 viewInvalidate(); // redraw in case cursor ring is still visible
736 return m_frameCacheUI;
739 int getScaledMaxXScroll()
741 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
742 JNIEnv* env = JSC::Bindings::getJNIEnv();
743 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll);
748 int getScaledMaxYScroll()
750 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
751 JNIEnv* env = JSC::Bindings::getJNIEnv();
752 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll);
757 IntRect getVisibleRect()
760 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
761 JNIEnv* env = JSC::Bindings::getJNIEnv();
762 jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect);
764 rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
766 rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
768 rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
770 rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
772 env->DeleteLocalRef(jRect);
777 static CachedFrame::Direction KeyToDirection(int32_t keyCode)
780 case AKEYCODE_DPAD_RIGHT:
781 DBG_NAV_LOGD("keyCode=%s", "right");
782 return CachedFrame::RIGHT;
783 case AKEYCODE_DPAD_LEFT:
784 DBG_NAV_LOGD("keyCode=%s", "left");
785 return CachedFrame::LEFT;
786 case AKEYCODE_DPAD_DOWN:
787 DBG_NAV_LOGD("keyCode=%s", "down");
788 return CachedFrame::DOWN;
789 case AKEYCODE_DPAD_UP:
790 DBG_NAV_LOGD("keyCode=%s", "up");
791 return CachedFrame::UP;
793 DBG_NAV_LOGD("bad key %d sent", keyCode);
794 return CachedFrame::UNINITIALIZED;
798 WTF::String imageURI(int x, int y)
800 const CachedRoot* root = getFrameCache(DontAllowNewer);
801 return root ? root->imageURI(x, y) : WTF::String();
804 bool cursorWantsKeyEvents()
806 const CachedRoot* root = getFrameCache(DontAllowNewer);
808 const CachedNode* focus = root->currentCursor();
810 return focus->wantsKeyEvents();
816 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
817 bool moveCursor(int keyCode, int count, bool ignoreScroll)
819 CachedRoot* root = getFrameCache(AllowNewer);
821 DBG_NAV_LOG("!root");
825 m_viewImpl->m_moveGeneration++;
826 CachedFrame::Direction direction = KeyToDirection(keyCode);
827 const CachedFrame* cachedFrame, * oldFrame = 0;
828 const CachedNode* cursor = root->currentCursor(&oldFrame);
829 WebCore::IntPoint cursorLocation = root->cursorLocation();
830 DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
831 cursor ? cursor->index() : 0,
832 cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
833 WebCore::IntRect visibleRect = setVisibleRect(root);
834 int xMax = getScaledMaxXScroll();
835 int yMax = getScaledMaxYScroll();
836 root->setMaxScroll(xMax, yMax);
837 const CachedNode* cachedNode = 0;
841 while (--counter >= 0) {
842 WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
843 cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
847 DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
848 "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
849 cachedNode ? cachedNode->nodePointer() : 0,
850 root->cursorLocation().x(), root->cursorLocation().y(),
851 cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
852 cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
853 cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
854 cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
855 // If !m_heightCanMeasure (such as in the browser), we want to scroll no
857 if (!ignoreScroll && (!m_heightCanMeasure ||
859 (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
861 if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
862 SkTime::GetMSecs() - m_lastDxTime < 1000)
863 root->checkForJiggle(&dx);
864 DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
866 this->scrollBy(dx, dy);
868 m_lastDxTime = SkTime::GetMSecs();
873 m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
874 root->setCursor(const_cast<CachedFrame*>(cachedFrame),
875 const_cast<CachedNode*>(cachedNode));
876 const CachedNode* focus = root->currentFocus();
877 bool clearTextEntry = cachedNode != focus && focus
878 && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput();
879 // Stop painting the caret if the old focus was a text input and so is the new cursor.
880 bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents();
881 sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret);
883 int docHeight = root->documentHeight();
884 int docWidth = root->documentWidth();
885 if (visibleRect.bottom() + dy > docHeight)
886 dy = docHeight - visibleRect.bottom();
887 else if (visibleRect.y() + dy < 0)
888 dy = -visibleRect.y();
889 if (visibleRect.right() + dx > docWidth)
890 dx = docWidth - visibleRect.right();
891 else if (visibleRect.x() < 0)
892 dx = -visibleRect.x();
893 result = direction == CachedFrame::LEFT ? dx >= 0 :
894 direction == CachedFrame::RIGHT ? dx <= 0 :
895 direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
900 void notifyProgressFinished()
902 DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
903 rebuildWebTextView();
905 if (m_frameCacheUI) {
906 const CachedNode* focus = m_frameCacheUI->currentFocus();
907 DBG_NAV_LOGD("focus %d (nativeNode=%p)",
908 focus ? focus->index() : 0,
909 focus ? focus->nodePointer() : 0);
914 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
915 const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
922 setVisibleRect(root);
923 return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
926 IntRect setVisibleRect(CachedRoot* root)
928 IntRect visibleRect = getVisibleRect();
929 DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
930 visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
931 root->setVisibleRect(visibleRect);
935 void selectBestAt(const WebCore::IntRect& rect)
937 const CachedFrame* frame;
939 CachedRoot* root = getFrameCache(AllowNewer);
942 const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
944 DBG_NAV_LOGD("no nodes found root=%p", root);
945 m_viewImpl->m_hasCursorBounds = false;
946 root->setCursor(0, 0);
949 DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
950 WebCore::IntRect bounds = node->bounds(frame);
951 root->rootHistory()->setMouseBounds(bounds);
952 m_viewImpl->updateCursorBounds(root, frame, node);
954 root->setCursor(const_cast<CachedFrame*>(frame),
955 const_cast<CachedNode*>(node));
957 sendMoveMouseIfLatest(false, false);
962 const CachedNode* m_cacheHitNode;
963 const CachedFrame* m_cacheHitFrame;
965 bool pointInNavCache(int x, int y, int slop)
967 CachedRoot* root = getFrameCache(AllowNewer);
970 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
972 return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
975 bool motionUp(int x, int y, int slop)
977 bool pageScrolled = false;
978 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
980 CachedRoot* root = getFrameCache(AllowNewer);
983 const CachedFrame* frame = 0;
984 const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
985 CachedHistory* history = root->rootHistory();
987 DBG_NAV_LOGD("no nodes found root=%p", root);
988 history->setNavBounds(rect);
989 m_viewImpl->m_hasCursorBounds = false;
991 int dx = root->checkForCenter(x, y);
996 sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
1001 DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
1002 result->index(), x, y, rx, ry);
1003 WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
1004 history->setNavBounds(navBounds);
1005 history->setMouseBounds(navBounds);
1006 m_viewImpl->updateCursorBounds(root, frame, result);
1007 root->setCursor(const_cast<CachedFrame*>(frame),
1008 const_cast<CachedNode*>(result));
1009 if (result->isSyntheticLink())
1010 overrideUrlLoading(result->getExport());
1013 (WebCore::Frame*) frame->framePointer(),
1014 (WebCore::Node*) result->nodePointer(), rx, ry);
1016 if (result->isTextInput() || result->isSelect()
1017 || result->isContentEditable()) {
1018 showCursorUntimed();
1021 return pageScrolled;
1024 #if USE(ACCELERATED_COMPOSITING)
1025 static const ScrollableLayerAndroid* findScrollableLayer(
1026 const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
1028 parent->bounds(&bounds);
1029 // Check the parent bounds first; this will clip to within a masking layer's
1031 if (parent->masksToBounds() && !bounds.contains(x, y))
1033 // Move the hit test local to parent.
1036 int count = parent->countChildren();
1038 const LayerAndroid* child = parent->getChild(count);
1039 const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
1042 foundBounds->offset(bounds.fLeft, bounds.fTop);
1043 if (parent->masksToBounds()) {
1044 if (bounds.width() < foundBounds->width())
1045 foundBounds->fRight = foundBounds->fLeft + bounds.width();
1046 if (bounds.height() < foundBounds->height())
1047 foundBounds->fBottom = foundBounds->fTop + bounds.height();
1052 if (parent->contentIsScrollable()) {
1053 foundBounds->set(0, 0, bounds.width(), bounds.height());
1054 return static_cast<const ScrollableLayerAndroid*>(parent);
1060 int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
1062 #if USE(ACCELERATED_COMPOSITING)
1063 const LayerAndroid* layerRoot = compositeRoot();
1066 const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
1069 result->getScrollRect(layerRect);
1070 return result->uniqueId();
1076 int getBlockLeftEdge(int x, int y, float scale)
1078 CachedRoot* root = getFrameCache(AllowNewer);
1080 return root->getBlockLeftEdge(x, y, scale);
1084 void overrideUrlLoading(const WTF::String& url)
1086 JNIEnv* env = JSC::Bindings::getJNIEnv();
1087 jstring jName = wtfStringToJstring(env, url);
1088 env->CallVoidMethod(m_javaGlue.object(env).get(),
1089 m_javaGlue.m_overrideLoading, jName);
1090 env->DeleteLocalRef(jName);
1093 void setFindIsUp(bool up)
1095 DBG_NAV_LOGD("up=%d", up);
1096 m_viewImpl->m_findIsUp = up;
1099 void setFindIsEmpty()
1102 m_findOnPage.clearCurrentLocation();
1105 void showCursorTimed()
1108 m_ringAnimationEnd = SkTime::GetMSecs() + 500;
1112 void showCursorUntimed()
1115 m_ring.m_isPressed = false;
1116 m_ringAnimationEnd = UINT_MAX;
1120 void setHeightCanMeasure(bool measure)
1122 m_heightCanMeasure = measure;
1125 String getSelection()
1127 return m_selectText.getSelection();
1130 void moveSelection(int x, int y)
1132 m_selectText.moveSelection(getVisibleRect(), x, y);
1135 IntPoint selectableText()
1137 const CachedRoot* root = getFrameCache(DontAllowNewer);
1139 return IntPoint(0, 0);
1140 return m_selectText.selectableText(root);
1145 m_selectText.selectAll();
1150 return m_selectText.selectionX();
1155 return m_selectText.selectionY();
1158 void resetSelection()
1160 m_selectText.reset();
1163 bool startSelection(int x, int y)
1165 const CachedRoot* root = getFrameCache(DontAllowNewer);
1168 return m_selectText.startSelection(root, getVisibleRect(), x, y);
1171 bool wordSelection(int x, int y)
1173 const CachedRoot* root = getFrameCache(DontAllowNewer);
1176 return m_selectText.wordSelection(root, getVisibleRect(), x, y);
1179 bool extendSelection(int x, int y)
1181 m_selectText.extendSelection(getVisibleRect(), x, y);
1185 bool hitSelection(int x, int y)
1187 return m_selectText.hitSelection(x, y);
1190 void setExtendSelection()
1192 m_selectText.setExtendSelection(true);
1195 void setSelectionPointer(bool set, float scale, int x, int y)
1197 m_selectText.setDrawPointer(set);
1200 m_selectText.m_inverseScale = scale;
1201 m_selectText.m_selectX = x;
1202 m_selectText.m_selectY = y;
1205 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
1207 DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
1208 JNIEnv* env = JSC::Bindings::getJNIEnv();
1209 env->CallVoidMethod(m_javaGlue.object(env).get(),
1210 m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
1211 checkException(env);
1214 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1216 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
1217 JNIEnv* env = JSC::Bindings::getJNIEnv();
1218 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse,
1219 (jint) framePtr, (jint) nodePtr, x, y);
1220 checkException(env);
1223 void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret)
1225 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1226 JNIEnv* env = JSC::Bindings::getJNIEnv();
1227 env->CallVoidMethod(m_javaGlue.object(env).get(),
1228 m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret);
1229 checkException(env);
1233 WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1235 m_viewImpl->m_touchGeneration = ++m_generation;
1236 DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d",
1237 m_generation, framePtr, nodePtr, x, y);
1238 LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
1239 JNIEnv* env = JSC::Bindings::getJNIEnv();
1240 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp,
1241 m_generation, (jint) framePtr, (jint) nodePtr, x, y);
1242 checkException(env);
1245 void findNext(bool forward)
1247 m_findOnPage.findNext(forward);
1248 if (!m_findOnPage.currentMatchIsInLayer())
1249 scrollRectOnScreen(m_findOnPage.currentMatchBounds());
1253 // With this call, WebView takes ownership of matches, and is responsible for
1255 void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch)
1257 // If this search is the same as the last one, check against the old
1258 // location to determine whether to scroll. If the same word is found
1259 // in the same place, then do not scroll.
1260 IntRect oldLocation;
1261 bool checkAgainstOldLocation;
1262 if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) {
1263 oldLocation = m_findOnPage.currentMatchBounds();
1264 checkAgainstOldLocation = true;
1266 checkAgainstOldLocation = false;
1268 m_findOnPage.setMatches(matches);
1270 if (!checkAgainstOldLocation
1271 || oldLocation != m_findOnPage.currentMatchBounds()) {
1272 // FIXME: Need to scroll if the match is in a layer.
1273 if (!m_findOnPage.currentMatchIsInLayer())
1274 scrollRectOnScreen(m_findOnPage.currentMatchBounds());
1279 int currentMatchIndex()
1281 return m_findOnPage.currentMatchIndex();
1284 bool scrollBy(int dx, int dy)
1286 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1288 JNIEnv* env = JSC::Bindings::getJNIEnv();
1289 bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(),
1290 m_javaGlue.m_scrollBy, dx, dy, true);
1291 checkException(env);
1295 bool hasCursorNode()
1297 CachedRoot* root = getFrameCache(DontAllowNewer);
1299 DBG_NAV_LOG("!root");
1302 const CachedNode* cursorNode = root->currentCursor();
1303 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
1304 cursorNode ? cursorNode->index() : -1,
1305 cursorNode ? cursorNode->nodePointer() : 0);
1311 CachedRoot* root = getFrameCache(DontAllowNewer);
1313 DBG_NAV_LOG("!root");
1316 const CachedNode* focusNode = root->currentFocus();
1317 DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
1318 focusNode ? focusNode->index() : -1,
1319 focusNode ? focusNode->nodePointer() : 0);
1323 void rebuildWebTextView()
1325 JNIEnv* env = JSC::Bindings::getJNIEnv();
1326 env->CallVoidMethod(m_javaGlue.object(env).get(),
1327 m_javaGlue.m_rebuildWebTextView);
1328 checkException(env);
1331 void viewInvalidate()
1333 JNIEnv* env = JSC::Bindings::getJNIEnv();
1334 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate);
1335 checkException(env);
1338 void viewInvalidateRect(int l, int t, int r, int b)
1340 JNIEnv* env = JSC::Bindings::getJNIEnv();
1341 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
1342 checkException(env);
1345 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
1347 JNIEnv* env = JSC::Bindings::getJNIEnv();
1348 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed,
1349 delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
1350 checkException(env);
1353 bool inFullScreenMode()
1355 JNIEnv* env = JSC::Bindings::getJNIEnv();
1356 jboolean result = env->CallBooleanMethod(m_javaGlue.object(env).get(),
1357 m_javaGlue.m_inFullScreenMode);
1358 checkException(env);
1362 int moveGeneration()
1364 return m_viewImpl->m_moveGeneration;
1367 LayerAndroid* compositeRoot() const
1369 LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
1370 "base layer can't have more than one child %s", __FUNCTION__);
1371 if (m_baseLayer && m_baseLayer->countChildren() == 1)
1372 return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
1377 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1378 static void copyScrollPositionRecursive(const LayerAndroid* from,
1383 for (int i = 0; i < from->countChildren(); i++) {
1384 const LayerAndroid* l = from->getChild(i);
1385 if (l->contentIsScrollable()) {
1386 const SkPoint& pos = l->getPosition();
1387 LayerAndroid* match = root->findById(l->uniqueId());
1388 if (match && match->contentIsScrollable())
1389 match->setPosition(pos.fX, pos.fY);
1391 copyScrollPositionRecursive(l, root);
1396 void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator,
1397 bool isPictureAfterFirstLayout)
1399 #if USE(ACCELERATED_COMPOSITING)
1400 if (m_glWebViewState)
1401 m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator,
1402 isPictureAfterFirstLayout);
1405 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1407 LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
1408 copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
1411 SkSafeUnref(m_baseLayer);
1412 m_baseLayer = layer;
1413 CachedRoot* root = getFrameCache(DontAllowNewer);
1416 root->resetLayers();
1417 root->setRootLayer(compositeRoot());
1420 void replaceBaseContent(PictureSet* set)
1424 m_baseLayer->setContent(*set);
1428 void copyBaseContentToPicture(SkPicture* picture)
1432 PictureSet* content = m_baseLayer->content();
1433 m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
1434 SkPicture::kUsePathBoundsForClip_RecordingFlag));
1435 picture->endRecording();
1441 return !m_baseLayer->content()->isEmpty();
1444 void setFunctor(Functor* functor) {
1445 delete m_glDrawFunctor;
1446 m_glDrawFunctor = functor;
1449 Functor* getFunctor() {
1450 return m_glDrawFunctor;
1453 private: // local state for WebView
1454 // private to getFrameCache(); other functions operate in a different thread
1455 CachedRoot* m_frameCacheUI; // navigation data ready for use
1456 WebViewCore* m_viewImpl;
1457 int m_generation; // associate unique ID with sent kit focus to match with ui
1458 SkPicture* m_navPictureUI;
1459 SkMSec m_ringAnimationEnd;
1460 // Corresponds to the same-named boolean on the java side.
1461 bool m_heightCanMeasure;
1463 SkMSec m_lastDxTime;
1464 SelectText m_selectText;
1465 FindOnPage m_findOnPage;
1467 BaseLayerAndroid* m_baseLayer;
1468 Functor* m_glDrawFunctor;
1469 #if USE(ACCELERATED_COMPOSITING)
1470 GLWebViewState* m_glWebViewState;
1472 const RenderSkinButton* m_buttonSkin;
1473 }; // end of WebView class
1477 * This class holds a function pointer and parameters for calling drawGL into a specific
1478 * viewport. The pointer to the Functor will be put on a framework display list to be called
1479 * when the display list is replayed.
1481 class GLDrawFunctor : Functor {
1483 GLDrawFunctor(WebView* _wvInstance,
1484 bool(WebView::*_funcPtr)(WebCore::IntRect&, jfloat, jint),
1485 WebCore::IntRect _viewRect, float _scale, int _extras) {
1486 wvInstance = _wvInstance;
1488 viewRect = _viewRect;
1492 status_t operator()(float* dirty, uint32_t len) {
1493 if (viewRect.isEmpty() || len != 4) {
1494 // NOOP operation if viewport is empty
1497 bool retVal = (*wvInstance.*funcPtr)(viewRect, scale, extras);
1499 dirty[0] = webViewRect.x();
1500 dirty[1] = webViewRect.y();
1501 dirty[2] = webViewRect.right();
1502 dirty[3] = webViewRect.bottom();
1504 // return 1 if invalidation needed, 0 otherwise
1505 return retVal ? 1 : 0;
1507 void updateRect(WebCore::IntRect& _viewRect) {
1508 viewRect = _viewRect;
1510 void updateViewRect(WebCore::IntRect& _viewRect) {
1511 webViewRect = _viewRect;
1514 WebView* wvInstance;
1515 bool (WebView::*funcPtr)(WebCore::IntRect&, float, int);
1516 WebCore::IntRect viewRect;
1517 WebCore::IntRect webViewRect;
1525 * Native JNI methods
1527 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
1529 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1530 ->m_cacheHitFrame->framePointer());
1533 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
1535 WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
1536 ->m_cacheHitNode->originalAbsoluteBounds();
1537 jclass rectClass = env->FindClass("android/graphics/Rect");
1538 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1539 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1540 bounds.y(), bounds.right(), bounds.bottom());
1541 env->DeleteLocalRef(rectClass);
1545 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
1547 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1548 ->m_cacheHitNode->nodePointer());
1551 static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj)
1553 return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin();
1556 static void nativeClearCursor(JNIEnv *env, jobject obj)
1558 WebView* view = GET_NATIVE_VIEW(env, obj);
1559 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1560 view->clearCursor();
1563 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir,
1564 jobject jAssetManager)
1566 AssetManager* am = assetManagerForJavaObject(env, jAssetManager);
1567 WTF::String dir = jstringToWtfString(env, drawableDir);
1568 WebView* webview = new WebView(env, obj, viewImpl, dir, am);
1569 // NEED THIS OR SOMETHING LIKE IT!
1573 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
1575 WebView* view = GET_NATIVE_VIEW(env, obj);
1576 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1579 const CachedFrame* frame = 0;
1580 (void) root->currentCursor(&frame);
1581 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1584 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
1586 WebView* view = GET_NATIVE_VIEW(env, obj);
1587 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1588 return root ? root->currentCursor() : 0;
1591 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
1592 const CachedFrame** frame)
1594 WebView* view = GET_NATIVE_VIEW(env, obj);
1595 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1596 return root ? root->currentCursor(frame) : 0;
1599 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
1600 const CachedFrame** frame)
1602 WebView* view = GET_NATIVE_VIEW(env, obj);
1603 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1606 const CachedNode* cursor = root->currentCursor(frame);
1607 if (cursor && cursor->wantsKeyEvents())
1609 return root->currentFocus(frame);
1612 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
1614 WebView* view = GET_NATIVE_VIEW(env, obj);
1615 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1618 const CachedNode* cursor = root->currentCursor();
1619 if (!cursor || !cursor->isTextInput())
1620 cursor = root->currentFocus();
1621 if (!cursor || !cursor->isTextInput()) return false;
1622 return root->nextTextField(cursor, 0);
1625 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
1627 WebView* view = GET_NATIVE_VIEW(env, obj);
1628 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1629 return root ? root->currentFocus() : 0;
1632 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
1633 const CachedFrame** frame)
1635 WebView* view = GET_NATIVE_VIEW(env, obj);
1636 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1637 return root ? root->currentFocus(frame) : 0;
1640 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
1642 WebView* view = GET_NATIVE_VIEW(env, obj);
1643 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1646 const CachedFrame* frame;
1647 const CachedNode* cursor = root->currentCursor(&frame);
1648 if (!cursor || !cursor->wantsKeyEvents())
1649 cursor = root->currentFocus(&frame);
1650 return cursor ? frame->textInput(cursor) : 0;
1653 static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
1655 const CachedNode* focus = getFocusNode(env, obj);
1656 if (!focus) return false;
1657 // Plugins handle shift and arrows whether or not they have focus.
1658 if (focus->isPlugin()) return true;
1659 const CachedNode* cursor = getCursorNode(env, obj);
1660 // ContentEditable nodes should only receive shift and arrows if they have
1661 // both the cursor and the focus.
1662 return cursor && cursor->nodePointer() == focus->nodePointer()
1663 && cursor->isContentEditable();
1666 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
1668 const CachedFrame* frame;
1669 const CachedNode* node = getCursorNode(env, obj, &frame);
1670 WebCore::IntRect bounds = node ? node->bounds(frame)
1671 : WebCore::IntRect(0, 0, 0, 0);
1672 jclass rectClass = env->FindClass("android/graphics/Rect");
1673 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1674 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1675 bounds.y(), bounds.right(), bounds.bottom());
1676 env->DeleteLocalRef(rectClass);
1680 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
1682 const CachedNode* node = getCursorNode(env, obj);
1683 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1686 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
1688 WebView* view = GET_NATIVE_VIEW(env, obj);
1689 const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1690 WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
1692 root->getSimulatedMousePosition(&pos);
1693 jclass pointClass = env->FindClass("android/graphics/Point");
1694 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
1695 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
1696 env->DeleteLocalRef(pointClass);
1700 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
1703 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
1704 return WebCore::IntRect(L, T, R - L, B - T);
1707 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
1709 const CachedFrame* frame;
1710 const CachedNode* node = getCursorNode(env, obj, &frame);
1711 return node ? node->bounds(frame).intersects(
1712 jrect_to_webrect(env, visRect)) : false;
1715 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
1717 const CachedNode* node = getCursorNode(env, obj);
1718 return node ? node->isAnchor() : false;
1721 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
1723 const CachedNode* node = getCursorNode(env, obj);
1724 return node ? node->isTextInput() : false;
1727 static jobject nativeCursorText(JNIEnv *env, jobject obj)
1729 const CachedNode* node = getCursorNode(env, obj);
1732 WTF::String value = node->getExport();
1733 return wtfStringToJstring(env, value);
1736 static void nativeDebugDump(JNIEnv *env, jobject obj)
1739 WebView* view = GET_NATIVE_VIEW(env, obj);
1740 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1745 static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
1746 jint extras, jboolean split) {
1747 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1748 return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
1751 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect,
1752 jfloat scale, jint extras) {
1753 WebCore::IntRect viewRect;
1754 if (jrect == NULL) {
1755 viewRect = WebCore::IntRect();
1757 viewRect = jrect_to_webrect(env, jrect);
1759 WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
1760 GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
1761 viewRect, scale, extras);
1762 wvInstance->setFunctor((Functor*) functor);
1764 WebCore::IntRect webViewRect;
1765 if (jviewrect == NULL) {
1766 webViewRect = WebCore::IntRect();
1768 webViewRect = jrect_to_webrect(env, jviewrect);
1770 functor->updateViewRect(webViewRect);
1772 return (jint)functor;
1775 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) {
1776 WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
1777 if (wvInstance != NULL) {
1778 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
1779 if (functor != NULL) {
1780 WebCore::IntRect viewRect;
1781 if (jrect == NULL) {
1782 viewRect = WebCore::IntRect();
1784 viewRect = jrect_to_webrect(env, jrect);
1786 functor->updateRect(viewRect);
1788 WebCore::IntRect webViewRect;
1789 if (jviewrect == NULL) {
1790 webViewRect = WebCore::IntRect();
1792 webViewRect = jrect_to_webrect(env, jviewrect);
1794 functor->updateViewRect(webViewRect);
1799 static bool nativeDrawGL(JNIEnv *env, jobject obj, jobject jrect,
1800 jfloat scale, jint extras)
1802 WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
1803 return GET_NATIVE_VIEW(env, obj)->drawGL(viewRect, scale, extras);
1806 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
1808 #if USE(ACCELERATED_COMPOSITING)
1809 const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
1811 return root->evaluateAnimations();
1816 static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval,
1817 jboolean showVisualIndicator,
1818 jboolean isPictureAfterFirstLayout)
1820 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
1821 SkRegion invalRegion;
1823 invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
1824 GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
1825 isPictureAfterFirstLayout);
1828 static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
1830 PictureSet* set = reinterpret_cast<PictureSet*>(content);
1831 GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
1834 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
1836 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
1837 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
1840 static bool nativeHasContent(JNIEnv *env, jobject obj)
1842 return GET_NATIVE_VIEW(env, obj)->hasContent();
1845 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
1847 WebView* view = GET_NATIVE_VIEW(env, obj);
1848 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1849 WTF::String uri = view->imageURI(x, y);
1850 return wtfStringToJstring(env, uri);
1853 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
1855 WebView* view = GET_NATIVE_VIEW(env, obj);
1856 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1859 const CachedFrame* frame = 0;
1860 const CachedNode* cursor = root->currentCursor(&frame);
1861 if (!cursor || !cursor->wantsKeyEvents())
1862 (void) root->currentFocus(&frame);
1863 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1866 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
1868 const CachedInput* input = getInputCandidate(env, obj);
1869 return input && input->getType() == CachedInput::PASSWORD;
1872 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
1874 const CachedInput* input = getInputCandidate(env, obj);
1875 return input ? input->isRtlText() : false;
1878 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
1880 const CachedNode* node = getFocusCandidate(env, obj, 0);
1881 return node ? node->isTextInput() : false;
1884 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
1886 const CachedInput* input = getInputCandidate(env, obj);
1887 return input ? input->maxLength() : false;
1890 static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
1892 const CachedInput* input = getInputCandidate(env, obj);
1893 return input ? input->autoComplete() : false;
1896 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
1898 const CachedInput* input = getInputCandidate(env, obj);
1901 const WTF::String& name = input->name();
1902 return wtfStringToJstring(env, name);
1905 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
1907 jclass rectClass = env->FindClass("android/graphics/Rect");
1908 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1909 jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
1910 env->DeleteLocalRef(rectClass);
1914 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
1916 const CachedFrame* frame;
1917 const CachedNode* node = getFocusCandidate(env, obj, &frame);
1918 WebCore::IntRect bounds = node ? node->bounds(frame)
1919 : WebCore::IntRect(0, 0, 0, 0);
1920 return createJavaRect(env, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
1923 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
1925 const CachedInput* input = getInputCandidate(env, obj);
1928 // Note that the Java Rect is being used to pass four integers, rather than
1929 // being used as an actual rectangle.
1930 return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
1931 input->paddingRight(), input->paddingBottom());
1934 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
1936 const CachedNode* node = getFocusCandidate(env, obj, 0);
1937 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1940 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
1942 const CachedNode* node = getFocusCandidate(env, obj, 0);
1945 WTF::String value = node->getExport();
1946 return wtfStringToJstring(env, value);
1949 static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
1951 const CachedInput* input = getInputCandidate(env, obj);
1952 return input ? input->lineHeight() : 0;
1955 static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
1957 const CachedInput* input = getInputCandidate(env, obj);
1958 return input ? input->textSize() : 0.f;
1961 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
1963 const CachedInput* input = getInputCandidate(env, obj);
1965 return CachedInput::NONE;
1967 if (input->isTextArea())
1968 return CachedInput::TEXT_AREA;
1970 return input->getType();
1973 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
1975 const CachedNode* node = getFocusNode(env, obj);
1976 return node ? node->isPlugin() : false;
1979 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
1981 const CachedFrame* frame;
1982 const CachedNode* node = getFocusNode(env, obj, &frame);
1983 WebCore::IntRect bounds = node ? node->bounds(frame)
1984 : WebCore::IntRect(0, 0, 0, 0);
1985 jclass rectClass = env->FindClass("android/graphics/Rect");
1986 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1987 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1988 bounds.y(), bounds.right(), bounds.bottom());
1989 env->DeleteLocalRef(rectClass);
1993 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
1995 const CachedNode* node = getFocusNode(env, obj);
1996 return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
1999 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
2000 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2001 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2002 return view->cursorWantsKeyEvents();
2005 static void nativeHideCursor(JNIEnv *env, jobject obj)
2007 WebView* view = GET_NATIVE_VIEW(env, obj);
2008 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2012 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
2014 #ifdef ANDROID_INSTRUMENT
2015 TimeCounter::reportNow();
2019 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
2021 WebView* view = GET_NATIVE_VIEW(env, obj);
2022 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2023 WebCore::IntRect rect = jrect_to_webrect(env, jrect);
2024 view->selectBestAt(rect);
2027 static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
2029 WebView* view = GET_NATIVE_VIEW(env, obj);
2030 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2031 WebCore::IntRect rect = IntRect(x, y , 1, 1);
2032 view->selectBestAt(rect);
2033 if (view->hasCursorNode())
2034 view->showCursorUntimed();
2037 static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
2040 #if USE(ACCELERATED_COMPOSITING)
2041 LayerAndroid* layer = (LayerAndroid*) jlayer;
2042 r = layer->bounds();
2048 jclass rectClass = env->FindClass("android/graphics/Rect");
2049 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2050 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2051 irect.fRight, irect.fBottom);
2052 env->DeleteLocalRef(rectClass);
2056 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
2058 SkIRect irect = jrect_to_webrect(env, jrect);
2059 #if USE(ACCELERATED_COMPOSITING)
2060 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
2064 rect = root->subtractLayers(rect);
2068 jclass rectClass = env->FindClass("android/graphics/Rect");
2069 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2070 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2071 irect.fRight, irect.fBottom);
2072 env->DeleteLocalRef(rectClass);
2076 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
2078 WebView* view = GET_NATIVE_VIEW(env, obj);
2079 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2080 return root ? root->textGeneration() : 0;
2083 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
2084 int x, int y, int slop)
2086 return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
2089 static bool nativeMotionUp(JNIEnv *env, jobject obj,
2090 int x, int y, int slop)
2092 WebView* view = GET_NATIVE_VIEW(env, obj);
2093 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2094 return view->motionUp(x, y, slop);
2097 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
2099 return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
2102 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
2104 return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
2107 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
2108 int key, int count, bool ignoreScroll)
2110 WebView* view = GET_NATIVE_VIEW(env, obj);
2111 DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
2112 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2113 return view->moveCursor(key, count, ignoreScroll);
2116 static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
2117 bool pressed, bool invalidate)
2119 WebView* view = GET_NATIVE_VIEW(env, obj);
2120 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2121 view->nativeRecordButtons(hasFocus, pressed, invalidate);
2124 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
2126 WebView* view = GET_NATIVE_VIEW(env, obj);
2127 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2128 view->setFindIsUp(isUp);
2131 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
2133 GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
2136 static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
2138 GET_NATIVE_VIEW(env, obj)->showCursorTimed();
2141 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
2143 WebView* view = GET_NATIVE_VIEW(env, obj);
2144 LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
2145 view->setHeightCanMeasure(measure);
2148 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
2150 WebView* view = GET_NATIVE_VIEW(env, obj);
2151 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2152 jclass rectClass = env->FindClass("android/graphics/Rect");
2153 LOG_ASSERT(rectClass, "Could not find Rect class!");
2154 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2155 LOG_ASSERT(init, "Could not find constructor for Rect");
2156 WebCore::IntRect webRect;
2157 view->cursorRingBounds(&webRect);
2158 jobject rect = env->NewObject(rectClass, init, webRect.x(),
2159 webRect.y(), webRect.right(), webRect.bottom());
2160 env->DeleteLocalRef(rectClass);
2164 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
2165 jstring findUpper, jboolean sameAsLastSearch)
2167 // If one or the other is null, do not search.
2168 if (!(findLower && findUpper))
2170 // Obtain the characters for both the lower case string and the upper case
2171 // string representing the same word.
2172 const jchar* findLowerChars = env->GetStringChars(findLower, 0);
2173 const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
2174 // If one or the other is null, do not search.
2175 if (!(findLowerChars && findUpperChars)) {
2177 env->ReleaseStringChars(findLower, findLowerChars);
2179 env->ReleaseStringChars(findUpper, findUpperChars);
2180 checkException(env);
2183 WebView* view = GET_NATIVE_VIEW(env, obj);
2184 LOG_ASSERT(view, "view not set in nativeFindAll");
2185 CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
2187 env->ReleaseStringChars(findLower, findLowerChars);
2188 env->ReleaseStringChars(findUpper, findUpperChars);
2189 checkException(env);
2192 int length = env->GetStringLength(findLower);
2193 // If the lengths of the strings do not match, then they are not the same
2194 // word, so do not search.
2195 if (!length || env->GetStringLength(findUpper) != length) {
2196 env->ReleaseStringChars(findLower, findLowerChars);
2197 env->ReleaseStringChars(findUpper, findUpperChars);
2198 checkException(env);
2201 int width = root->documentWidth();
2202 int height = root->documentHeight();
2203 // Create a FindCanvas, which allows us to fake draw into it so we can
2204 // figure out where our search string is rendered (and how many times).
2205 FindCanvas canvas(width, height, (const UChar*) findLowerChars,
2206 (const UChar*) findUpperChars, length << 1);
2208 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
2209 canvas.setBitmapDevice(bitmap);
2211 WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
2212 // With setMatches, the WebView takes ownership of matches
2213 view->setMatches(matches, sameAsLastSearch);
2215 env->ReleaseStringChars(findLower, findLowerChars);
2216 env->ReleaseStringChars(findUpper, findUpperChars);
2217 checkException(env);
2218 return canvas.found();
2221 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
2223 WebView* view = GET_NATIVE_VIEW(env, obj);
2224 LOG_ASSERT(view, "view not set in nativeFindNext");
2225 view->findNext(forward);
2228 static int nativeFindIndex(JNIEnv *env, jobject obj)
2230 WebView* view = GET_NATIVE_VIEW(env, obj);
2231 LOG_ASSERT(view, "view not set in nativeFindIndex");
2232 return view->currentMatchIndex();
2235 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
2237 WebView* view = GET_NATIVE_VIEW(env, obj);
2238 LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
2239 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2242 const CachedNode* cachedFocusNode = root->currentFocus();
2243 if (!cachedFocusNode || !cachedFocusNode->isTextInput())
2245 WTF::String webcoreString = jstringToWtfString(env, updatedText);
2246 (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
2247 root->setTextGeneration(generation);
2248 checkException(env);
2251 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
2254 WebView* view = GET_NATIVE_VIEW(env, obj);
2255 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2258 return view->getBlockLeftEdge(x, y, scale);
2261 static void nativeDestroy(JNIEnv *env, jobject obj)
2263 WebView* view = GET_NATIVE_VIEW(env, obj);
2264 LOGD("nativeDestroy view: %p", view);
2265 LOG_ASSERT(view, "view not set in nativeDestroy");
2269 static void nativeStopGL(JNIEnv *env, jobject obj)
2271 GET_NATIVE_VIEW(env, obj)->stopGL();
2274 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
2276 WebView* view = GET_NATIVE_VIEW(env, obj);
2277 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2280 const CachedNode* current = root->currentCursor();
2281 if (!current || !current->isTextInput())
2282 current = root->currentFocus();
2283 if (!current || !current->isTextInput())
2285 const CachedFrame* frame;
2286 const CachedNode* next = root->nextTextField(current, &frame);
2289 const WebCore::IntRect& bounds = next->bounds(frame);
2290 root->rootHistory()->setMouseBounds(bounds);
2291 view->getWebViewCore()->updateCursorBounds(root, frame, next);
2292 view->showCursorUntimed();
2293 root->setCursor(const_cast<CachedFrame*>(frame),
2294 const_cast<CachedNode*>(next));
2295 view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
2296 static_cast<WebCore::Node*>(next->nodePointer()));
2297 if (!next->isInLayer())
2298 view->scrollRectOnScreen(bounds);
2299 view->getWebViewCore()->m_moveGeneration++;
2303 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
2305 WebView* view = GET_NATIVE_VIEW(env, obj);
2308 return view->moveGeneration();
2311 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
2313 GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
2316 static void nativeResetSelection(JNIEnv *env, jobject obj)
2318 return GET_NATIVE_VIEW(env, obj)->resetSelection();
2321 static jobject nativeSelectableText(JNIEnv* env, jobject obj)
2323 IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
2324 jclass pointClass = env->FindClass("android/graphics/Point");
2325 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
2326 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
2327 env->DeleteLocalRef(pointClass);
2331 static void nativeSelectAll(JNIEnv* env, jobject obj)
2333 GET_NATIVE_VIEW(env, obj)->selectAll();
2336 static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
2338 GET_NATIVE_VIEW(env, obj)->setExtendSelection();
2341 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
2343 return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
2346 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
2348 return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
2351 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
2353 GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
2356 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
2358 WebView* view = GET_NATIVE_VIEW(env, obj);
2359 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2360 String selection = view->getSelection();
2361 return wtfStringToJstring(env, selection);
2364 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
2366 return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
2369 static jint nativeSelectionX(JNIEnv *env, jobject obj)
2371 return GET_NATIVE_VIEW(env, obj)->selectionX();
2374 static jint nativeSelectionY(JNIEnv *env, jobject obj)
2376 return GET_NATIVE_VIEW(env, obj)->selectionY();
2379 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
2380 jfloat scale, jint x, jint y)
2382 GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y);
2385 #ifdef ANDROID_DUMP_DISPLAY_TREE
2386 static void dumpToFile(const char text[], void* file) {
2387 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
2388 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
2392 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
2394 #ifdef ANDROID_DUMP_DISPLAY_TREE
2395 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2396 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2398 if (view && view->getWebViewCore()) {
2399 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
2401 SkFormatDumper dumper(dumpToFile, file);
2404 const char* str = env->GetStringUTFChars(jurl, 0);
2405 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
2406 dumpToFile(str, file);
2407 env->ReleaseStringUTFChars(jurl, str);
2409 // now dump the display tree
2410 SkDumpCanvas canvas(&dumper);
2411 // this will playback the picture into the canvas, which will
2412 // spew its contents to the dumper
2413 view->draw(&canvas, 0, 0, false);
2414 // we're done with the file now
2415 fwrite("\n", 1, 1, file);
2418 #if USE(ACCELERATED_COMPOSITING)
2419 const LayerAndroid* rootLayer = view->compositeRoot();
2421 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
2423 rootLayer->dumpLayers(file, 0);
2432 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
2433 jobject rect, jobject bounds)
2435 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2436 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2437 SkIRect nativeRect, nativeBounds;
2438 int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
2440 GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
2442 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
2446 static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
2449 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
2450 WebView* view = GET_NATIVE_VIEW(env, obj);
2451 LayerAndroid* root = view->compositeRoot();
2454 LayerAndroid* layer = root->findById(layerId);
2455 if (!layer || !layer->contentIsScrollable())
2457 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
2462 static void nativeSetExpandedTileBounds(JNIEnv*, jobject, jboolean enabled)
2464 TilesManager::instance()->setExpandedTileBounds(enabled);
2470 static JNINativeMethod gJavaWebViewMethods[] = {
2471 { "nativeCacheHitFramePointer", "()I",
2472 (void*) nativeCacheHitFramePointer },
2473 { "nativeCacheHitIsPlugin", "()Z",
2474 (void*) nativeCacheHitIsPlugin },
2475 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
2476 (void*) nativeCacheHitNodeBounds },
2477 { "nativeCacheHitNodePointer", "()I",
2478 (void*) nativeCacheHitNodePointer },
2479 { "nativeClearCursor", "()V",
2480 (void*) nativeClearCursor },
2481 { "nativeCreate", "(ILjava/lang/String;Landroid/content/res/AssetManager;)V",
2482 (void*) nativeCreate },
2483 { "nativeCursorFramePointer", "()I",
2484 (void*) nativeCursorFramePointer },
2485 { "nativePageShouldHandleShiftAndArrows", "()Z",
2486 (void*) nativePageShouldHandleShiftAndArrows },
2487 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
2488 (void*) nativeCursorNodeBounds },
2489 { "nativeCursorNodePointer", "()I",
2490 (void*) nativeCursorNodePointer },
2491 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
2492 (void*) nativeCursorIntersects },
2493 { "nativeCursorIsAnchor", "()Z",
2494 (void*) nativeCursorIsAnchor },
2495 { "nativeCursorIsTextInput", "()Z",
2496 (void*) nativeCursorIsTextInput },
2497 { "nativeCursorPosition", "()Landroid/graphics/Point;",
2498 (void*) nativeCursorPosition },
2499 { "nativeCursorText", "()Ljava/lang/String;",
2500 (void*) nativeCursorText },
2501 { "nativeCursorWantsKeyEvents", "()Z",
2502 (void*)nativeCursorWantsKeyEvents },
2503 { "nativeDebugDump", "()V",
2504 (void*) nativeDebugDump },
2505 { "nativeDestroy", "()V",
2506 (void*) nativeDestroy },
2507 { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
2508 (void*) nativeDraw },
2509 { "nativeGetDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;FI)I",
2510 (void*) nativeGetDrawGLFunction },
2511 { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V",
2512 (void*) nativeUpdateDrawGLFunction },
2513 { "nativeDrawGL", "(Landroid/graphics/Rect;FI)Z",
2514 (void*) nativeDrawGL },
2515 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
2516 (void*) nativeDumpDisplayTree },
2517 { "nativeEvaluateLayersAnimations", "()Z",
2518 (void*) nativeEvaluateLayersAnimations },
2519 { "nativeExtendSelection", "(II)V",
2520 (void*) nativeExtendSelection },
2521 { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
2522 (void*) nativeFindAll },
2523 { "nativeFindNext", "(Z)V",
2524 (void*) nativeFindNext },
2525 { "nativeFindIndex", "()I",
2526 (void*) nativeFindIndex},
2527 { "nativeFocusCandidateFramePointer", "()I",
2528 (void*) nativeFocusCandidateFramePointer },
2529 { "nativeFocusCandidateHasNextTextfield", "()Z",
2530 (void*) focusCandidateHasNextTextfield },
2531 { "nativeFocusCandidateIsPassword", "()Z",
2532 (void*) nativeFocusCandidateIsPassword },
2533 { "nativeFocusCandidateIsRtlText", "()Z",
2534 (void*) nativeFocusCandidateIsRtlText },
2535 { "nativeFocusCandidateIsTextInput", "()Z",
2536 (void*) nativeFocusCandidateIsTextInput },
2537 { "nativeFocusCandidateLineHeight", "()I",
2538 (void*) nativeFocusCandidateLineHeight },
2539 { "nativeFocusCandidateMaxLength", "()I",
2540 (void*) nativeFocusCandidateMaxLength },
2541 { "nativeFocusCandidateIsAutoComplete", "()Z",
2542 (void*) nativeFocusCandidateIsAutoComplete },
2543 { "nativeFocusCandidateName", "()Ljava/lang/String;",
2544 (void*) nativeFocusCandidateName },
2545 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
2546 (void*) nativeFocusCandidateNodeBounds },
2547 { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
2548 (void*) nativeFocusCandidatePaddingRect },
2549 { "nativeFocusCandidatePointer", "()I",
2550 (void*) nativeFocusCandidatePointer },
2551 { "nativeFocusCandidateText", "()Ljava/lang/String;",
2552 (void*) nativeFocusCandidateText },
2553 { "nativeFocusCandidateTextSize", "()F",
2554 (void*) nativeFocusCandidateTextSize },
2555 { "nativeFocusCandidateType", "()I",
2556 (void*) nativeFocusCandidateType },
2557 { "nativeFocusIsPlugin", "()Z",
2558 (void*) nativeFocusIsPlugin },
2559 { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
2560 (void*) nativeFocusNodeBounds },
2561 { "nativeFocusNodePointer", "()I",
2562 (void*) nativeFocusNodePointer },
2563 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
2564 (void*) nativeGetCursorRingBounds },
2565 { "nativeGetSelection", "()Ljava/lang/String;",
2566 (void*) nativeGetSelection },
2567 { "nativeHasCursorNode", "()Z",
2568 (void*) nativeHasCursorNode },
2569 { "nativeHasFocusNode", "()Z",
2570 (void*) nativeHasFocusNode },
2571 { "nativeHideCursor", "()V",
2572 (void*) nativeHideCursor },
2573 { "nativeHitSelection", "(II)Z",
2574 (void*) nativeHitSelection },
2575 { "nativeImageURI", "(II)Ljava/lang/String;",
2576 (void*) nativeImageURI },
2577 { "nativeInstrumentReport", "()V",
2578 (void*) nativeInstrumentReport },
2579 { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
2580 (void*) nativeLayerBounds },
2581 { "nativeMotionUp", "(III)Z",
2582 (void*) nativeMotionUp },
2583 { "nativeMoveCursor", "(IIZ)Z",
2584 (void*) nativeMoveCursor },
2585 { "nativeMoveCursorToNextTextInput", "()Z",
2586 (void*) nativeMoveCursorToNextTextInput },
2587 { "nativeMoveGeneration", "()I",
2588 (void*) nativeMoveGeneration },
2589 { "nativeMoveSelection", "(II)V",
2590 (void*) nativeMoveSelection },
2591 { "nativePointInNavCache", "(III)Z",
2592 (void*) nativePointInNavCache },
2593 { "nativeRecordButtons", "(ZZZ)V",
2594 (void*) nativeRecordButtons },
2595 { "nativeResetSelection", "()V",
2596 (void*) nativeResetSelection },
2597 { "nativeSelectableText", "()Landroid/graphics/Point;",
2598 (void*) nativeSelectableText },
2599 { "nativeSelectAll", "()V",
2600 (void*) nativeSelectAll },
2601 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
2602 (void*) nativeSelectBestAt },
2603 { "nativeSelectAt", "(II)V",
2604 (void*) nativeSelectAt },
2605 { "nativeSelectionX", "()I",
2606 (void*) nativeSelectionX },
2607 { "nativeSelectionY", "()I",
2608 (void*) nativeSelectionY },
2609 { "nativeSetExtendSelection", "()V",
2610 (void*) nativeSetExtendSelection },
2611 { "nativeSetFindIsEmpty", "()V",
2612 (void*) nativeSetFindIsEmpty },
2613 { "nativeSetFindIsUp", "(Z)V",
2614 (void*) nativeSetFindIsUp },
2615 { "nativeSetHeightCanMeasure", "(Z)V",
2616 (void*) nativeSetHeightCanMeasure },
2617 { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZ)V",
2618 (void*) nativeSetBaseLayer },
2619 { "nativeReplaceBaseContent", "(I)V",
2620 (void*) nativeReplaceBaseContent },
2621 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
2622 (void*) nativeCopyBaseContentToPicture },
2623 { "nativeHasContent", "()Z",
2624 (void*) nativeHasContent },
2625 { "nativeSetSelectionPointer", "(ZFII)V",
2626 (void*) nativeSetSelectionPointer },
2627 { "nativeShowCursorTimed", "()V",
2628 (void*) nativeShowCursorTimed },
2629 { "nativeStartSelection", "(II)Z",
2630 (void*) nativeStartSelection },
2631 { "nativeStopGL", "()V",
2632 (void*) nativeStopGL },
2633 { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
2634 (void*) nativeSubtractLayers },
2635 { "nativeTextGeneration", "()I",
2636 (void*) nativeTextGeneration },
2637 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
2638 (void*) nativeUpdateCachedTextfield },
2639 { "nativeWordSelection", "(II)Z",
2640 (void*) nativeWordSelection },
2641 { "nativeGetBlockLeftEdge", "(IIF)I",
2642 (void*) nativeGetBlockLeftEdge },
2643 { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
2644 (void*) nativeScrollableLayer },
2645 { "nativeScrollLayer", "(III)Z",
2646 (void*) nativeScrollLayer },
2647 { "nativeSetExpandedTileBounds", "(Z)V",
2648 (void*) nativeSetExpandedTileBounds },
2651 int registerWebView(JNIEnv* env)
2653 jclass clazz = env->FindClass("android/webkit/WebView");
2654 LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
2655 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
2656 LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
2657 env->DeleteLocalRef(clazz);
2659 return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
2662 } // namespace android