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 "PlatformGraphicsContext.h"
46 #include "PlatformString.h"
47 #include "ScrollableLayerAndroid.h"
48 #include "SelectText.h"
50 #include "SkDumpCanvas.h"
51 #include "SkPicture.h"
54 #ifdef ANDROID_INSTRUMENT
55 #include "TimeCounter.h"
57 #include "TilesManager.h"
58 #include "WebCoreJni.h"
59 #include "WebRequestContext.h"
60 #include "WebViewCore.h"
61 #include "android_graphics.h"
63 #ifdef GET_NATIVE_VIEW
64 #undef GET_NATIVE_VIEW
67 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
69 #include <JNIUtility.h>
72 #include <ui/KeycodeLabels.h>
73 #include <wtf/text/AtomicString.h>
74 #include <wtf/text/CString.h>
78 static jfieldID gWebViewField;
80 //-------------------------------------
82 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
84 jmethodID m = env->GetMethodID(clazz, name, signature);
85 LOG_ASSERT(m, "Could not find method %s", name);
89 //-------------------------------------
90 // This class provides JNI for making calls into native code from the UI side
91 // of the multi-threaded WebView.
95 enum FrameCachePermission {
101 enum DrawExtras { // keep this in sync with WebView.java
104 DrawExtrasSelection = 2,
105 DrawExtrasCursorRing = 3
110 jmethodID m_calcOurContentVisibleRectF;
111 jmethodID m_overrideLoading;
112 jmethodID m_scrollBy;
113 jmethodID m_sendMoveFocus;
114 jmethodID m_sendMoveMouse;
115 jmethodID m_sendMoveMouseIfLatest;
116 jmethodID m_sendMoveSelection;
117 jmethodID m_sendMotionUp;
118 jmethodID m_domChangedFocus;
119 jmethodID m_getScaledMaxXScroll;
120 jmethodID m_getScaledMaxYScroll;
121 jmethodID m_getVisibleRect;
122 jmethodID m_rebuildWebTextView;
123 jmethodID m_viewInvalidate;
124 jmethodID m_viewInvalidateRect;
125 jmethodID m_postInvalidateDelayed;
128 jmethodID m_rectWidth;
129 jmethodID m_rectHeight;
130 jfieldID m_rectFLeft;
132 jmethodID m_rectFWidth;
133 jmethodID m_rectFHeight;
134 AutoJObject object(JNIEnv* env) {
135 return getRealObject(env, m_obj);
139 WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
140 m_ring((WebViewCore*) viewImpl)
142 jclass clazz = env->FindClass("android/webkit/WebView");
143 // m_javaGlue = new JavaGlue;
144 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
145 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
146 m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
147 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
148 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
149 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
150 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V");
151 m_javaGlue.m_sendMoveSelection = GetJMethod(env, clazz, "sendMoveSelection", "(II)V");
152 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
153 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
154 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
155 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
156 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
157 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
158 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
159 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
160 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
161 "viewInvalidateDelayed", "(JIIII)V");
162 env->DeleteLocalRef(clazz);
164 jclass rectClass = env->FindClass("android/graphics/Rect");
165 LOG_ASSERT(rectClass, "Could not find Rect class");
166 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
167 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
168 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
169 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
170 env->DeleteLocalRef(rectClass);
172 jclass rectClassF = env->FindClass("android/graphics/RectF");
173 LOG_ASSERT(rectClassF, "Could not find RectF class");
174 m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
175 m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
176 m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
177 m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
178 env->DeleteLocalRef(rectClassF);
180 env->SetIntField(javaWebView, gWebViewField, (jint)this);
181 m_viewImpl = (WebViewCore*) viewImpl;
185 m_heightCanMeasure = false;
188 m_ringAnimationEnd = 0;
190 #if USE(ACCELERATED_COMPOSITING)
191 m_glWebViewState = 0;
197 if (m_javaGlue.m_obj)
199 JNIEnv* env = JSC::Bindings::getJNIEnv();
200 env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
201 m_javaGlue.m_obj = 0;
203 #if USE(ACCELERATED_COMPOSITING)
204 // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
205 // do not remove it here, we risk having BaseTiles trying to paint using a
206 // deallocated base layer.
207 delete m_glWebViewState;
209 delete m_frameCacheUI;
210 delete m_navPictureUI;
214 WebViewCore* getWebViewCore() const {
218 // removes the cursor altogether (e.g., when going to a new page)
221 CachedRoot* root = getFrameCache(AllowNewer);
225 m_viewImpl->m_hasCursorBounds = false;
230 // leaves the cursor where it is, but suppresses drawing it
233 CachedRoot* root = getFrameCache(AllowNewer);
240 void hideCursor(CachedRoot* root)
242 DBG_NAV_LOG("inner");
243 m_viewImpl->m_hasCursorBounds = false;
251 CachedRoot* root = getFrameCache(DontAllowNewer);
253 root->mDebug.print();
257 // Traverse our stored array of buttons that are in our picture, and update
258 // their subpictures according to their current state.
259 // Called from the UI thread. This is the one place in the UI thread where we
260 // access the buttons stored in the WebCore thread.
261 // hasFocus keeps track of whether the WebView has focus && windowFocus.
262 // If not, we do not want to draw the button in a selected or pressed state
263 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
265 bool cursorIsOnButton = false;
266 const CachedFrame* cachedFrame;
267 const CachedNode* cachedCursor = 0;
268 // Lock the mutex, since we now share with the WebCore thread.
269 m_viewImpl->gButtonMutex.lock();
270 if (m_viewImpl->m_buttons.size()) {
271 // FIXME: In a future change, we should keep track of whether the selection
272 // has changed to short circuit (note that we would still need to update
273 // if we received new buttons from the WebCore thread).
274 WebCore::Node* cursor = 0;
275 CachedRoot* root = getFrameCache(DontAllowNewer);
277 cachedCursor = root->currentCursor(&cachedFrame);
279 cursor = (WebCore::Node*) cachedCursor->nodePointer();
282 // Traverse the array, and update each button, depending on whether it
284 Container* end = m_viewImpl->m_buttons.end();
285 for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
286 RenderSkinAndroid::State state = RenderSkinAndroid::kNormal;
287 if (ptr->matches(cursor)) {
288 cursorIsOnButton = true;
289 // If the WebView is out of focus/window focus, set the state to
290 // normal, but still keep track of the fact that the selected is a
293 if (pressed || m_ring.m_isPressed)
294 state = RenderSkinAndroid::kPressed;
295 else if (SkTime::GetMSecs() < m_ringAnimationEnd
296 && m_ringAnimationEnd != UINT_MAX) {
297 state = RenderSkinAndroid::kFocused;
301 ptr->updateFocusState(state);
304 m_viewImpl->gButtonMutex.unlock();
305 if (invalidate && cachedCursor && cursorIsOnButton) {
306 const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
307 viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom());
311 // The caller has already determined that the desired document rect corresponds
312 // to the main picture, and not a layer
313 void scrollRectOnScreen(const IntRect& rect)
318 calcOurContentVisibleRect(&visible);
319 #if USE(ACCELERATED_COMPOSITING)
320 LayerAndroid* root = compositeRoot();
322 root->updateFixedLayersPositions(visible);
323 root->updatePositions();
324 visible = root->subtractLayers(visible);
329 int right = rect.right();
330 if (left < visible.fLeft) {
331 dx = left - visible.fLeft;
332 // Only scroll right if the entire width can fit on screen.
333 } else if (right > visible.fRight && right - left < visible.width()) {
334 dx = right - visible.fRight;
338 int bottom = rect.bottom();
339 if (top < visible.fTop) {
340 dy = top - visible.fTop;
341 // Only scroll down if the entire height can fit on screen
342 } else if (bottom > visible.fBottom && bottom - top < visible.height()) {
343 dy = bottom - visible.fBottom;
345 if ((dx|dy) == 0 || !scrollBy(dx, dy))
350 void calcOurContentVisibleRect(SkRect* r)
352 JNIEnv* env = JSC::Bindings::getJNIEnv();
353 jclass rectClass = env->FindClass("android/graphics/RectF");
354 jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V");
355 jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0);
356 env->CallVoidMethod(m_javaGlue.object(env).get(),
357 m_javaGlue.m_calcOurContentVisibleRectF, jRect);
358 r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft);
359 r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop);
360 r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth);
361 r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight);
362 env->DeleteLocalRef(rectClass);
363 env->DeleteLocalRef(jRect);
367 void resetCursorRing()
369 m_ringAnimationEnd = 0;
370 m_viewImpl->m_hasCursorBounds = false;
373 bool drawCursorPreamble(CachedRoot* root)
375 const CachedFrame* frame;
376 const CachedNode* node = root->currentCursor(&frame);
378 DBG_NAV_LOGV("%s", "!node");
382 if (node->isHidden()) {
383 DBG_NAV_LOG("node->isHidden()");
384 m_viewImpl->m_hasCursorBounds = false;
387 #if USE(ACCELERATED_COMPOSITING)
388 if (node->isInLayer() && root->rootLayer()) {
389 LayerAndroid* layer = const_cast<LayerAndroid*>(root->rootLayer());
391 calcOurContentVisibleRect(&visible);
392 layer->updateFixedLayersPositions(visible);
393 layer->updatePositions();
396 setVisibleRect(root);
397 m_ring.m_root = root;
398 m_ring.m_frame = frame;
399 m_ring.m_node = node;
400 SkMSec time = SkTime::GetMSecs();
401 m_ring.m_isPressed = time < m_ringAnimationEnd
402 && m_ringAnimationEnd != UINT_MAX;
406 void drawCursorPostamble()
408 if (m_ringAnimationEnd == UINT_MAX)
410 SkMSec time = SkTime::GetMSecs();
411 if (time < m_ringAnimationEnd) {
412 // views assume that inval bounds coordinates are non-negative
413 WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
414 invalBounds.intersect(m_ring.m_absBounds);
415 postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
417 hideCursor(const_cast<CachedRoot*>(m_ring.m_root));
421 bool drawGL(WebCore::IntRect& viewRect, float scale, int extras)
423 #if USE(ACCELERATED_COMPOSITING)
427 if (!m_glWebViewState) {
428 m_glWebViewState = new GLWebViewState();
429 if (m_baseLayer->content()) {
430 IntRect rect(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
431 m_glWebViewState->setBaseLayer(m_baseLayer, rect);
435 CachedRoot* root = getFrameCache(AllowNewer);
437 DBG_NAV_LOG("!root");
438 if (extras == DrawExtrasCursorRing)
442 DrawExtra* extra = 0;
445 extra = &m_findOnPage;
447 case DrawExtrasSelection:
448 extra = &m_selectText;
450 case DrawExtrasCursorRing:
451 if (drawCursorPreamble(root) && m_ring.setup()) {
452 if (!m_ring.m_isButton)
454 drawCursorPostamble();
461 unsigned int pic = m_glWebViewState->currentPictureCounter();
464 IntRect rect(0, 0, 0, 0);
466 LayerAndroid mainPicture(m_navPictureUI);
467 PictureSet* content = m_baseLayer->content();
468 SkCanvas* canvas = picture.beginRecording(content->width(),
470 extra->draw(canvas, &mainPicture, &rect);
471 picture.endRecording();
473 m_glWebViewState->setExtra(m_baseLayer, picture, rect);
475 calcOurContentVisibleRect(&visibleRect);
476 bool ret = m_baseLayer->drawGL(viewRect, visibleRect, scale);
477 if (ret || m_glWebViewState->currentPictureCounter() != pic)
483 PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
487 canvas->drawColor(bgColor);
491 // draw the content of the base layer first
492 PictureSet* content = m_baseLayer->content();
493 int sc = canvas->save(SkCanvas::kClip_SaveFlag);
494 canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
495 content->height()), SkRegion::kDifference_Op);
496 canvas->drawColor(bgColor);
497 canvas->restoreToCount(sc);
498 if (content->draw(canvas))
499 ret = split ? new PictureSet(*content) : 0;
501 CachedRoot* root = getFrameCache(AllowNewer);
503 DBG_NAV_LOG("!root");
504 if (extras == DrawExtrasCursorRing)
508 LayerAndroid mainPicture(m_navPictureUI);
509 DrawExtra* extra = 0;
512 extra = &m_findOnPage;
514 case DrawExtrasSelection:
515 extra = &m_selectText;
517 case DrawExtrasCursorRing:
518 if (drawCursorPreamble(root) && m_ring.setup()) {
519 if (!m_ring.m_isButton)
521 drawCursorPostamble();
528 IntRect dummy; // inval area, unused for now
529 extra->draw(canvas, &mainPicture, &dummy);
531 #if USE(ACCELERATED_COMPOSITING)
532 LayerAndroid* compositeLayer = compositeRoot();
535 compositeLayer->setExtra(extra);
537 calcOurContentVisibleRect(&visible);
538 // call this to be sure we've adjusted for any scrolling or animations
539 // before we actually draw
540 compositeLayer->updateFixedLayersPositions(visible);
541 compositeLayer->updatePositions();
542 // We have to set the canvas' matrix on the base layer
543 // (to have fixed layers work as intended)
544 SkAutoCanvasRestore restore(canvas, true);
545 m_baseLayer->setMatrix(canvas->getTotalMatrix());
546 canvas->resetMatrix();
547 m_baseLayer->draw(canvas);
553 bool cursorIsTextInput(FrameCachePermission allowNewer)
555 CachedRoot* root = getFrameCache(allowNewer);
557 DBG_NAV_LOG("!root");
560 const CachedNode* cursor = root->currentCursor();
562 DBG_NAV_LOG("!cursor");
565 DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
566 return cursor->isTextInput();
569 void cursorRingBounds(WebCore::IntRect* bounds)
571 DBG_NAV_LOGD("%s", "");
572 CachedRoot* root = getFrameCache(DontAllowNewer);
574 const CachedFrame* cachedFrame;
575 const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
577 *bounds = cachedNode->cursorRingBounds(cachedFrame);
578 DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
579 bounds->width(), bounds->height());
583 *bounds = WebCore::IntRect(0, 0, 0, 0);
588 m_viewImpl->gCursorBoundsMutex.lock();
589 bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
590 IntRect bounds = m_viewImpl->m_cursorBounds;
591 m_viewImpl->gCursorBoundsMutex.unlock();
592 if (!hasCursorBounds)
595 const CachedFrame* frame;
596 const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true);
599 // require that node have approximately the same bounds (+/- 4) and the same
601 IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
602 bounds.y() + (bounds.height() >> 1));
603 IntRect newBounds = node->bounds(frame);
604 IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
605 newBounds.y() + (newBounds.height() >> 1));
606 DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
607 " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
608 oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
609 bounds.x(), bounds.y(), bounds.width(), bounds.height(),
610 newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
611 if (abs(oldCenter.x() - newCenter.x()) > 2)
613 if (abs(oldCenter.y() - newCenter.y()) > 2)
615 if (abs(bounds.x() - newBounds.x()) > 4)
617 if (abs(bounds.y() - newBounds.y()) > 4)
619 if (abs(bounds.right() - newBounds.right()) > 4)
621 if (abs(bounds.bottom() - newBounds.bottom()) > 4)
623 DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
624 node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
626 m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
627 const_cast<CachedNode*>(node));
630 CachedRoot* getFrameCache(FrameCachePermission allowNewer)
632 if (!m_viewImpl->m_updatedFrameCache) {
633 DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
634 return m_frameCacheUI;
636 if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
637 DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
638 " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
639 return m_frameCacheUI;
641 DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
642 const CachedFrame* oldCursorFrame;
643 const CachedNode* oldCursorNode = m_frameCacheUI ?
644 m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
645 #if USE(ACCELERATED_COMPOSITING)
647 if (oldCursorNode && oldCursorNode->isInLayer()) {
648 const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
649 ->layer(m_frameCacheUI->rootLayer());
651 layerId = cursorLayer->uniqueId();
654 // get id from old layer and use to find new layer
655 bool oldFocusIsTextInput = false;
656 void* oldFocusNodePointer = 0;
657 if (m_frameCacheUI) {
658 const CachedNode* oldFocus = m_frameCacheUI->currentFocus();
660 oldFocusIsTextInput = oldFocus->isTextInput();
661 oldFocusNodePointer = oldFocus->nodePointer();
664 m_viewImpl->gFrameCacheMutex.lock();
665 delete m_frameCacheUI;
666 m_navPictureUI->safeUnref();
667 m_viewImpl->m_updatedFrameCache = false;
668 m_frameCacheUI = m_viewImpl->m_frameCacheKit;
669 m_navPictureUI = m_viewImpl->m_navPictureKit;
670 m_viewImpl->m_frameCacheKit = 0;
671 m_viewImpl->m_navPictureKit = 0;
672 m_viewImpl->gFrameCacheMutex.unlock();
674 m_frameCacheUI->setRootLayer(compositeRoot());
675 #if USE(ACCELERATED_COMPOSITING)
678 calcOurContentVisibleRect(&visible);
679 LayerAndroid* layer = const_cast<LayerAndroid*>(
680 m_frameCacheUI->rootLayer());
682 layer->updateFixedLayersPositions(visible);
683 layer->updatePositions();
688 if (oldFocusIsTextInput) {
689 const CachedNode* newFocus = m_frameCacheUI->currentFocus();
690 if (newFocus && oldFocusNodePointer != newFocus->nodePointer()
691 && newFocus->isTextInput()
692 && newFocus != m_frameCacheUI->currentCursor()) {
693 // The focus has changed. We may need to update things.
694 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
695 JNIEnv* env = JSC::Bindings::getJNIEnv();
696 env->CallVoidMethod(m_javaGlue.object(env).get(),
697 m_javaGlue.m_domChangedFocus);
701 if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
702 viewInvalidate(); // redraw in case cursor ring is still visible
703 return m_frameCacheUI;
706 int getScaledMaxXScroll()
708 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
709 JNIEnv* env = JSC::Bindings::getJNIEnv();
710 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll);
715 int getScaledMaxYScroll()
717 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
718 JNIEnv* env = JSC::Bindings::getJNIEnv();
719 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll);
724 IntRect getVisibleRect()
727 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
728 JNIEnv* env = JSC::Bindings::getJNIEnv();
729 jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect);
731 rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
733 rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
735 rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
737 rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
739 env->DeleteLocalRef(jRect);
744 static CachedFrame::Direction KeyToDirection(int32_t keyCode)
747 case AKEYCODE_DPAD_RIGHT:
748 DBG_NAV_LOGD("keyCode=%s", "right");
749 return CachedFrame::RIGHT;
750 case AKEYCODE_DPAD_LEFT:
751 DBG_NAV_LOGD("keyCode=%s", "left");
752 return CachedFrame::LEFT;
753 case AKEYCODE_DPAD_DOWN:
754 DBG_NAV_LOGD("keyCode=%s", "down");
755 return CachedFrame::DOWN;
756 case AKEYCODE_DPAD_UP:
757 DBG_NAV_LOGD("keyCode=%s", "up");
758 return CachedFrame::UP;
760 DBG_NAV_LOGD("bad key %d sent", keyCode);
761 return CachedFrame::UNINITIALIZED;
765 WTF::String imageURI(int x, int y)
767 const CachedRoot* root = getFrameCache(DontAllowNewer);
768 return root ? root->imageURI(x, y) : WTF::String();
771 bool cursorWantsKeyEvents()
773 const CachedRoot* root = getFrameCache(DontAllowNewer);
775 const CachedNode* focus = root->currentCursor();
777 return focus->wantsKeyEvents();
783 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
784 bool moveCursor(int keyCode, int count, bool ignoreScroll)
786 CachedRoot* root = getFrameCache(AllowNewer);
788 DBG_NAV_LOG("!root");
792 m_viewImpl->m_moveGeneration++;
793 CachedFrame::Direction direction = KeyToDirection(keyCode);
794 const CachedFrame* cachedFrame, * oldFrame = 0;
795 const CachedNode* cursor = root->currentCursor(&oldFrame);
796 WebCore::IntPoint cursorLocation = root->cursorLocation();
797 DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
798 cursor ? cursor->index() : 0,
799 cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
800 WebCore::IntRect visibleRect = setVisibleRect(root);
801 int xMax = getScaledMaxXScroll();
802 int yMax = getScaledMaxYScroll();
803 root->setMaxScroll(xMax, yMax);
804 const CachedNode* cachedNode = 0;
808 while (--counter >= 0) {
809 WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
810 cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
814 DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
815 "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
816 cachedNode ? cachedNode->nodePointer() : 0,
817 root->cursorLocation().x(), root->cursorLocation().y(),
818 cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
819 cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
820 cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
821 cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
822 // If !m_heightCanMeasure (such as in the browser), we want to scroll no
824 if (!ignoreScroll && (!m_heightCanMeasure ||
826 (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
828 if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
829 SkTime::GetMSecs() - m_lastDxTime < 1000)
830 root->checkForJiggle(&dx);
831 DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
833 this->scrollBy(dx, dy);
835 m_lastDxTime = SkTime::GetMSecs();
840 m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
841 root->setCursor(const_cast<CachedFrame*>(cachedFrame),
842 const_cast<CachedNode*>(cachedNode));
843 const CachedNode* focus = root->currentFocus();
844 bool clearTextEntry = cachedNode != focus
845 && focus->isTextInput();
846 sendMoveMouseIfLatest(clearTextEntry);
847 sendMoveSelection((WebCore::Frame*) cachedFrame->framePointer(),
848 (WebCore::Node*) cachedNode->nodePointer());
850 int docHeight = root->documentHeight();
851 int docWidth = root->documentWidth();
852 if (visibleRect.bottom() + dy > docHeight)
853 dy = docHeight - visibleRect.bottom();
854 else if (visibleRect.y() + dy < 0)
855 dy = -visibleRect.y();
856 if (visibleRect.right() + dx > docWidth)
857 dx = docWidth - visibleRect.right();
858 else if (visibleRect.x() < 0)
859 dx = -visibleRect.x();
860 result = direction == CachedFrame::LEFT ? dx >= 0 :
861 direction == CachedFrame::RIGHT ? dx <= 0 :
862 direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
867 void notifyProgressFinished()
869 DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
870 rebuildWebTextView();
872 if (m_frameCacheUI) {
873 const CachedNode* focus = m_frameCacheUI->currentFocus();
874 DBG_NAV_LOGD("focus %d (nativeNode=%p)",
875 focus ? focus->index() : 0,
876 focus ? focus->nodePointer() : 0);
881 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
882 const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
889 setVisibleRect(root);
890 return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
893 IntRect setVisibleRect(CachedRoot* root)
895 IntRect visibleRect = getVisibleRect();
896 DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
897 visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
898 root->setVisibleRect(visibleRect);
902 void selectBestAt(const WebCore::IntRect& rect)
904 const CachedFrame* frame;
906 CachedRoot* root = getFrameCache(AllowNewer);
909 const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
912 DBG_NAV_LOGD("no nodes found root=%p", root);
913 m_viewImpl->m_hasCursorBounds = false;
914 root->setCursor(0, 0);
917 DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
918 WebCore::IntRect bounds = node->bounds(frame);
919 root->rootHistory()->setMouseBounds(frame->unadjustBounds(node, bounds));
920 m_viewImpl->updateCursorBounds(root, frame, node);
922 root->setCursor(const_cast<CachedFrame*>(frame),
923 const_cast<CachedNode*>(node));
925 sendMoveMouseIfLatest(false);
928 sendMoveSelection((WebCore::Frame*) frame->framePointer(),
929 (WebCore::Node*) node->nodePointer());
932 const CachedNode* m_cacheHitNode;
933 const CachedFrame* m_cacheHitFrame;
935 bool pointInNavCache(int x, int y, int slop)
937 CachedRoot* root = getFrameCache(AllowNewer);
940 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
942 return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
945 bool motionUp(int x, int y, int slop)
947 bool pageScrolled = false;
948 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
950 CachedRoot* root = getFrameCache(AllowNewer);
953 const CachedFrame* frame = 0;
954 const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
955 CachedHistory* history = root->rootHistory();
957 DBG_NAV_LOGD("no nodes found root=%p", root);
958 history->setNavBounds(rect);
959 m_viewImpl->m_hasCursorBounds = false;
961 int dx = root->checkForCenter(x, y);
966 sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
971 DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
972 result->index(), x, y, rx, ry);
973 // No need to call unadjustBounds below. rx and ry are already adjusted to
974 // the absolute position of the node.
975 WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
976 history->setNavBounds(navBounds);
977 history->setMouseBounds(navBounds);
978 m_viewImpl->updateCursorBounds(root, frame, result);
979 root->setCursor(const_cast<CachedFrame*>(frame),
980 const_cast<CachedNode*>(result));
981 if (result->isSyntheticLink())
982 overrideUrlLoading(result->getExport());
985 (WebCore::Frame*) frame->framePointer(),
986 (WebCore::Node*) result->nodePointer(), rx, ry);
988 if (result->isTextInput() || result->isSelect()
989 || result->isContentEditable()) {
996 #if USE(ACCELERATED_COMPOSITING)
997 static const ScrollableLayerAndroid* findScrollableLayer(
998 const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
1000 parent->bounds(&bounds);
1001 // Check the parent bounds first; this will clip to within a masking layer's
1003 if (parent->masksToBounds() && !bounds.contains(x, y))
1005 // Move the hit test local to parent.
1008 int count = parent->countChildren();
1009 for (int i = 0; i < count; i++) {
1010 const LayerAndroid* child = parent->getChild(i);
1011 const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
1014 foundBounds->offset(bounds.fLeft, bounds.fTop);
1015 if (parent->masksToBounds()) {
1016 if (bounds.width() < foundBounds->width())
1017 foundBounds->fRight = foundBounds->fLeft + bounds.width();
1018 if (bounds.height() < foundBounds->height())
1019 foundBounds->fBottom = foundBounds->fTop + bounds.height();
1024 if (parent->contentIsScrollable()) {
1025 foundBounds->set(0, 0, bounds.width(), bounds.height());
1026 return static_cast<const ScrollableLayerAndroid*>(parent);
1032 int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
1034 #if USE(ACCELERATED_COMPOSITING)
1035 const LayerAndroid* layerRoot = compositeRoot();
1038 const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
1041 result->getScrollRect(layerRect);
1042 return result->uniqueId();
1048 int getBlockLeftEdge(int x, int y, float scale)
1050 CachedRoot* root = getFrameCache(AllowNewer);
1052 return root->getBlockLeftEdge(x, y, scale);
1056 void overrideUrlLoading(const WTF::String& url)
1058 JNIEnv* env = JSC::Bindings::getJNIEnv();
1059 jstring jName = wtfStringToJstring(env, url);
1060 env->CallVoidMethod(m_javaGlue.object(env).get(),
1061 m_javaGlue.m_overrideLoading, jName);
1062 env->DeleteLocalRef(jName);
1065 void setFindIsUp(bool up)
1067 DBG_NAV_LOGD("up=%d", up);
1068 m_viewImpl->m_findIsUp = up;
1071 void setFindIsEmpty()
1074 m_findOnPage.clearCurrentLocation();
1077 void showCursorTimed()
1080 m_ringAnimationEnd = SkTime::GetMSecs() + 500;
1084 void showCursorUntimed()
1087 m_ring.m_isPressed = false;
1088 m_ringAnimationEnd = UINT_MAX;
1092 void setHeightCanMeasure(bool measure)
1094 m_heightCanMeasure = measure;
1097 String getSelection()
1099 return m_selectText.getSelection();
1102 void moveSelection(int x, int y)
1104 m_selectText.moveSelection(getVisibleRect(), x, y);
1107 IntPoint selectableText()
1109 const CachedRoot* root = getFrameCache(DontAllowNewer);
1111 return IntPoint(0, 0);
1112 return m_selectText.selectableText(root);
1117 m_selectText.selectAll();
1122 return m_selectText.selectionX();
1127 return m_selectText.selectionY();
1130 void resetSelection()
1132 m_selectText.reset();
1135 bool startSelection(int x, int y)
1137 const CachedRoot* root = getFrameCache(DontAllowNewer);
1140 return m_selectText.startSelection(root, getVisibleRect(), x, y);
1143 bool wordSelection(int x, int y)
1145 const CachedRoot* root = getFrameCache(DontAllowNewer);
1148 return m_selectText.wordSelection(root, getVisibleRect(), x, y);
1151 bool extendSelection(int x, int y)
1153 m_selectText.extendSelection(getVisibleRect(), x, y);
1157 bool hitSelection(int x, int y)
1159 return m_selectText.hitSelection(x, y);
1162 void setExtendSelection()
1164 m_selectText.setExtendSelection(true);
1167 void setSelectionPointer(bool set, float scale, int x, int y)
1169 m_selectText.setDrawPointer(set);
1172 m_selectText.m_inverseScale = scale;
1173 m_selectText.m_selectX = x;
1174 m_selectText.m_selectY = y;
1177 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
1179 DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
1180 JNIEnv* env = JSC::Bindings::getJNIEnv();
1181 env->CallVoidMethod(m_javaGlue.object(env).get(),
1182 m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
1183 checkException(env);
1186 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1188 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
1189 JNIEnv* env = JSC::Bindings::getJNIEnv();
1190 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse,
1191 (jint) framePtr, (jint) nodePtr, x, y);
1192 checkException(env);
1195 void sendMoveMouseIfLatest(bool clearTextEntry)
1197 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1198 JNIEnv* env = JSC::Bindings::getJNIEnv();
1199 env->CallVoidMethod(m_javaGlue.object(env).get(),
1200 m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry);
1201 checkException(env);
1204 void sendMoveSelection(WebCore::Frame* frame, WebCore::Node* node)
1206 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", frame, node);
1207 JNIEnv* env = JSC::Bindings::getJNIEnv();
1208 env->CallVoidMethod(m_javaGlue.object(env).get(),
1209 m_javaGlue.m_sendMoveSelection, (jint) frame, (jint) node);
1210 checkException(env);
1214 WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1216 m_viewImpl->m_touchGeneration = ++m_generation;
1217 DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d",
1218 m_generation, framePtr, nodePtr, x, y);
1219 LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
1220 JNIEnv* env = JSC::Bindings::getJNIEnv();
1221 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp,
1222 m_generation, (jint) framePtr, (jint) nodePtr, x, y);
1223 checkException(env);
1226 void findNext(bool forward)
1228 m_findOnPage.findNext(forward);
1229 if (!m_findOnPage.currentMatchIsInLayer())
1230 scrollRectOnScreen(m_findOnPage.currentMatchBounds());
1234 // With this call, WebView takes ownership of matches, and is responsible for
1236 void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch)
1238 // If this search is the same as the last one, check against the old
1239 // location to determine whether to scroll. If the same word is found
1240 // in the same place, then do not scroll.
1241 IntRect oldLocation;
1242 bool checkAgainstOldLocation;
1243 if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) {
1244 oldLocation = m_findOnPage.currentMatchBounds();
1245 checkAgainstOldLocation = true;
1247 checkAgainstOldLocation = false;
1249 m_findOnPage.setMatches(matches);
1251 if (!checkAgainstOldLocation
1252 || oldLocation != m_findOnPage.currentMatchBounds()) {
1253 // FIXME: Need to scroll if the match is in a layer.
1254 if (!m_findOnPage.currentMatchIsInLayer())
1255 scrollRectOnScreen(m_findOnPage.currentMatchBounds());
1260 int currentMatchIndex()
1262 return m_findOnPage.currentMatchIndex();
1265 bool scrollBy(int dx, int dy)
1267 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1269 JNIEnv* env = JSC::Bindings::getJNIEnv();
1270 bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(),
1271 m_javaGlue.m_scrollBy, dx, dy, true);
1272 checkException(env);
1276 bool hasCursorNode()
1278 CachedRoot* root = getFrameCache(DontAllowNewer);
1280 DBG_NAV_LOG("!root");
1283 const CachedNode* cursorNode = root->currentCursor();
1284 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
1285 cursorNode ? cursorNode->index() : -1,
1286 cursorNode ? cursorNode->nodePointer() : 0);
1292 CachedRoot* root = getFrameCache(DontAllowNewer);
1294 DBG_NAV_LOG("!root");
1297 const CachedNode* focusNode = root->currentFocus();
1298 DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
1299 focusNode ? focusNode->index() : -1,
1300 focusNode ? focusNode->nodePointer() : 0);
1304 void rebuildWebTextView()
1306 JNIEnv* env = JSC::Bindings::getJNIEnv();
1307 env->CallVoidMethod(m_javaGlue.object(env).get(),
1308 m_javaGlue.m_rebuildWebTextView);
1309 checkException(env);
1312 void viewInvalidate()
1314 JNIEnv* env = JSC::Bindings::getJNIEnv();
1315 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate);
1316 checkException(env);
1319 void viewInvalidateRect(int l, int t, int r, int b)
1321 JNIEnv* env = JSC::Bindings::getJNIEnv();
1322 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
1323 checkException(env);
1326 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
1328 JNIEnv* env = JSC::Bindings::getJNIEnv();
1329 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed,
1330 delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
1331 checkException(env);
1334 int moveGeneration()
1336 return m_viewImpl->m_moveGeneration;
1339 LayerAndroid* compositeRoot() const
1341 LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
1342 "base layer can't have more than one child %s", __FUNCTION__);
1343 if (m_baseLayer && m_baseLayer->countChildren() == 1)
1344 return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
1349 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1350 static void copyScrollPositionRecursive(const LayerAndroid* from,
1355 for (int i = 0; i < from->countChildren(); i++) {
1356 const LayerAndroid* l = from->getChild(i);
1357 if (l->contentIsScrollable()) {
1358 const SkPoint& pos = l->getPosition();
1359 LayerAndroid* match = root->findById(l->uniqueId());
1360 if (match && match->contentIsScrollable())
1361 match->setPosition(pos.fX, pos.fY);
1363 copyScrollPositionRecursive(l, root);
1368 void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect)
1370 #if USE(ACCELERATED_COMPOSITING)
1371 if (m_glWebViewState)
1372 m_glWebViewState->setBaseLayer(layer, rect);
1375 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1377 LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
1378 copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
1382 m_baseLayer = layer;
1383 CachedRoot* root = getFrameCache(DontAllowNewer);
1386 root->resetLayers();
1387 root->setRootLayer(compositeRoot());
1390 void replaceBaseContent(PictureSet* set)
1394 m_baseLayer->setContent(*set);
1398 void copyBaseContentToPicture(SkPicture* picture)
1402 PictureSet* content = m_baseLayer->content();
1403 m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
1404 SkPicture::kUsePathBoundsForClip_RecordingFlag));
1405 picture->endRecording();
1411 return !m_baseLayer->content()->isEmpty();
1414 private: // local state for WebView
1415 // private to getFrameCache(); other functions operate in a different thread
1416 CachedRoot* m_frameCacheUI; // navigation data ready for use
1417 WebViewCore* m_viewImpl;
1418 int m_generation; // associate unique ID with sent kit focus to match with ui
1419 SkPicture* m_navPictureUI;
1420 SkMSec m_ringAnimationEnd;
1421 // Corresponds to the same-named boolean on the java side.
1422 bool m_heightCanMeasure;
1424 SkMSec m_lastDxTime;
1425 SelectText m_selectText;
1426 FindOnPage m_findOnPage;
1428 BaseLayerAndroid* m_baseLayer;
1429 #if USE(ACCELERATED_COMPOSITING)
1430 GLWebViewState* m_glWebViewState;
1432 }; // end of WebView class
1435 * Native JNI methods
1437 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
1439 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1440 ->m_cacheHitFrame->framePointer());
1443 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
1445 WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
1446 ->m_cacheHitNode->originalAbsoluteBounds();
1447 jclass rectClass = env->FindClass("android/graphics/Rect");
1448 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1449 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1450 bounds.y(), bounds.right(), bounds.bottom());
1451 env->DeleteLocalRef(rectClass);
1455 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
1457 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1458 ->m_cacheHitNode->nodePointer());
1461 static void nativeClearCursor(JNIEnv *env, jobject obj)
1463 WebView* view = GET_NATIVE_VIEW(env, obj);
1464 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1465 view->clearCursor();
1468 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl)
1470 WebView* webview = new WebView(env, obj, viewImpl);
1471 // NEED THIS OR SOMETHING LIKE IT!
1475 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
1477 WebView* view = GET_NATIVE_VIEW(env, obj);
1478 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1481 const CachedFrame* frame = 0;
1482 (void) root->currentCursor(&frame);
1483 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1486 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
1488 WebView* view = GET_NATIVE_VIEW(env, obj);
1489 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1490 return root ? root->currentCursor() : 0;
1493 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
1494 const CachedFrame** frame)
1496 WebView* view = GET_NATIVE_VIEW(env, obj);
1497 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1498 return root ? root->currentCursor(frame) : 0;
1501 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
1502 const CachedFrame** frame)
1504 WebView* view = GET_NATIVE_VIEW(env, obj);
1505 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1508 const CachedNode* cursor = root->currentCursor(frame);
1509 if (cursor && cursor->wantsKeyEvents())
1511 return root->currentFocus();
1514 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
1516 WebView* view = GET_NATIVE_VIEW(env, obj);
1517 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1520 const CachedNode* cursor = root->currentCursor();
1521 if (!cursor || !cursor->isTextInput())
1522 cursor = root->currentFocus();
1523 if (!cursor || !cursor->isTextInput()) return false;
1524 return root->nextTextField(cursor, 0);
1527 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
1529 WebView* view = GET_NATIVE_VIEW(env, obj);
1530 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1531 return root ? root->currentFocus() : 0;
1534 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
1535 const CachedFrame** frame)
1537 WebView* view = GET_NATIVE_VIEW(env, obj);
1538 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1539 return root ? root->currentFocus(frame) : 0;
1542 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
1544 WebView* view = GET_NATIVE_VIEW(env, obj);
1545 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1548 const CachedFrame* frame;
1549 const CachedNode* cursor = root->currentCursor(&frame);
1550 if (!cursor || !cursor->wantsKeyEvents())
1551 cursor = root->currentFocus(&frame);
1552 return cursor ? frame->textInput(cursor) : 0;
1555 static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
1557 const CachedNode* focus = getFocusNode(env, obj);
1558 if (!focus) return false;
1559 // Plugins handle shift and arrows whether or not they have focus.
1560 if (focus->isPlugin()) return true;
1561 const CachedNode* cursor = getCursorNode(env, obj);
1562 // ContentEditable nodes should only receive shift and arrows if they have
1563 // both the cursor and the focus.
1564 return cursor && cursor->nodePointer() == focus->nodePointer()
1565 && cursor->isContentEditable();
1568 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
1570 const CachedFrame* frame;
1571 const CachedNode* node = getCursorNode(env, obj, &frame);
1572 WebCore::IntRect bounds = node ? node->bounds(frame)
1573 : WebCore::IntRect(0, 0, 0, 0);
1574 jclass rectClass = env->FindClass("android/graphics/Rect");
1575 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1576 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1577 bounds.y(), bounds.right(), bounds.bottom());
1578 env->DeleteLocalRef(rectClass);
1582 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
1584 const CachedNode* node = getCursorNode(env, obj);
1585 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1588 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
1590 WebView* view = GET_NATIVE_VIEW(env, obj);
1591 const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1592 WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
1594 root->getSimulatedMousePosition(&pos);
1595 jclass pointClass = env->FindClass("android/graphics/Point");
1596 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
1597 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
1598 env->DeleteLocalRef(pointClass);
1602 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
1605 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
1606 return WebCore::IntRect(L, T, R - L, B - T);
1609 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
1611 const CachedFrame* frame;
1612 const CachedNode* node = getCursorNode(env, obj, &frame);
1613 return node ? node->bounds(frame).intersects(
1614 jrect_to_webrect(env, visRect)) : false;
1617 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
1619 const CachedNode* node = getCursorNode(env, obj);
1620 return node ? node->isAnchor() : false;
1623 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
1625 const CachedNode* node = getCursorNode(env, obj);
1626 return node ? node->isTextInput() : false;
1629 static jobject nativeCursorText(JNIEnv *env, jobject obj)
1631 const CachedNode* node = getCursorNode(env, obj);
1634 WTF::String value = node->getExport();
1635 return wtfStringToJstring(env, value);
1638 static void nativeDebugDump(JNIEnv *env, jobject obj)
1641 WebView* view = GET_NATIVE_VIEW(env, obj);
1642 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1647 static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
1648 jint extras, jboolean split) {
1649 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1650 return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
1653 static bool nativeDrawGL(JNIEnv *env, jobject obj, jobject jrect,
1654 jfloat scale, jint extras)
1656 WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
1657 return GET_NATIVE_VIEW(env, obj)->drawGL(viewRect, scale, extras);
1660 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
1662 #if USE(ACCELERATED_COMPOSITING)
1663 const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
1665 return root->evaluateAnimations();
1670 static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject jrect)
1672 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
1673 WebCore::IntRect rect = jrect_to_webrect(env, jrect);
1674 GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, rect);
1677 static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
1679 PictureSet* set = reinterpret_cast<PictureSet*>(content);
1680 GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
1683 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
1685 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
1686 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
1689 static bool nativeHasContent(JNIEnv *env, jobject obj)
1691 return GET_NATIVE_VIEW(env, obj)->hasContent();
1694 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
1696 WebView* view = GET_NATIVE_VIEW(env, obj);
1697 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1698 WTF::String uri = view->imageURI(x, y);
1699 return wtfStringToJstring(env, uri);
1702 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
1704 WebView* view = GET_NATIVE_VIEW(env, obj);
1705 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1708 const CachedFrame* frame = 0;
1709 const CachedNode* cursor = root->currentCursor(&frame);
1710 if (!cursor || !cursor->wantsKeyEvents())
1711 (void) root->currentFocus(&frame);
1712 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1715 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
1717 const CachedInput* input = getInputCandidate(env, obj);
1718 return input && input->getType() == CachedInput::PASSWORD;
1721 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
1723 const CachedInput* input = getInputCandidate(env, obj);
1724 return input ? input->isRtlText() : false;
1727 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
1729 const CachedNode* node = getFocusCandidate(env, obj, 0);
1730 return node ? node->isTextInput() : false;
1733 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
1735 const CachedInput* input = getInputCandidate(env, obj);
1736 return input ? input->maxLength() : false;
1739 static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
1741 const CachedInput* input = getInputCandidate(env, obj);
1742 return input ? input->autoComplete() : false;
1745 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
1747 const CachedInput* input = getInputCandidate(env, obj);
1750 const WTF::String& name = input->name();
1751 return wtfStringToJstring(env, name);
1754 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
1756 jclass rectClass = env->FindClass("android/graphics/Rect");
1757 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1758 jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
1759 env->DeleteLocalRef(rectClass);
1763 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
1765 const CachedFrame* frame;
1766 const CachedNode* node = getFocusCandidate(env, obj, &frame);
1767 WebCore::IntRect bounds = node ? node->bounds(frame)
1768 : WebCore::IntRect(0, 0, 0, 0);
1769 return createJavaRect(env, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
1772 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
1774 const CachedInput* input = getInputCandidate(env, obj);
1777 // Note that the Java Rect is being used to pass four integers, rather than
1778 // being used as an actual rectangle.
1779 return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
1780 input->paddingRight(), input->paddingBottom());
1783 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
1785 const CachedNode* node = getFocusCandidate(env, obj, 0);
1786 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1789 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
1791 const CachedNode* node = getFocusCandidate(env, obj, 0);
1794 WTF::String value = node->getExport();
1795 return wtfStringToJstring(env, value);
1798 static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
1800 const CachedInput* input = getInputCandidate(env, obj);
1801 return input ? input->lineHeight() : 0;
1804 static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
1806 const CachedInput* input = getInputCandidate(env, obj);
1807 return input ? input->textSize() : 0.f;
1810 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
1812 const CachedInput* input = getInputCandidate(env, obj);
1814 return CachedInput::NONE;
1816 if (input->isTextArea())
1817 return CachedInput::TEXT_AREA;
1819 return input->getType();
1822 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
1824 const CachedNode* node = getFocusNode(env, obj);
1825 return node ? node->isPlugin() : false;
1828 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
1830 const CachedFrame* frame;
1831 const CachedNode* node = getFocusNode(env, obj, &frame);
1832 WebCore::IntRect bounds = node ? node->bounds(frame)
1833 : WebCore::IntRect(0, 0, 0, 0);
1834 jclass rectClass = env->FindClass("android/graphics/Rect");
1835 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1836 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1837 bounds.y(), bounds.right(), bounds.bottom());
1838 env->DeleteLocalRef(rectClass);
1842 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
1844 const CachedNode* node = getFocusNode(env, obj);
1845 return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
1848 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
1849 WebView* view = GET_NATIVE_VIEW(env, jwebview);
1850 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1851 return view->cursorWantsKeyEvents();
1854 static void nativeHideCursor(JNIEnv *env, jobject obj)
1856 WebView* view = GET_NATIVE_VIEW(env, obj);
1857 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1861 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
1863 #ifdef ANDROID_INSTRUMENT
1864 TimeCounter::reportNow();
1868 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
1870 WebView* view = GET_NATIVE_VIEW(env, obj);
1871 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1872 WebCore::IntRect rect = jrect_to_webrect(env, jrect);
1873 view->selectBestAt(rect);
1876 static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
1879 #if USE(ACCELERATED_COMPOSITING)
1880 LayerAndroid* layer = (LayerAndroid*) jlayer;
1881 r = layer->bounds();
1887 jclass rectClass = env->FindClass("android/graphics/Rect");
1888 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1889 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
1890 irect.fRight, irect.fBottom);
1891 env->DeleteLocalRef(rectClass);
1895 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
1897 SkIRect irect = jrect_to_webrect(env, jrect);
1898 #if USE(ACCELERATED_COMPOSITING)
1899 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
1903 rect = root->subtractLayers(rect);
1907 jclass rectClass = env->FindClass("android/graphics/Rect");
1908 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1909 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
1910 irect.fRight, irect.fBottom);
1911 env->DeleteLocalRef(rectClass);
1915 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
1917 WebView* view = GET_NATIVE_VIEW(env, obj);
1918 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1919 return root ? root->textGeneration() : 0;
1922 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
1923 int x, int y, int slop)
1925 return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
1928 static bool nativeMotionUp(JNIEnv *env, jobject obj,
1929 int x, int y, int slop)
1931 WebView* view = GET_NATIVE_VIEW(env, obj);
1932 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1933 return view->motionUp(x, y, slop);
1936 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
1938 return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
1941 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
1943 return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
1946 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
1947 int key, int count, bool ignoreScroll)
1949 WebView* view = GET_NATIVE_VIEW(env, obj);
1950 DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
1951 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1952 return view->moveCursor(key, count, ignoreScroll);
1955 static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
1956 bool pressed, bool invalidate)
1958 WebView* view = GET_NATIVE_VIEW(env, obj);
1959 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1960 view->nativeRecordButtons(hasFocus, pressed, invalidate);
1963 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
1965 WebView* view = GET_NATIVE_VIEW(env, obj);
1966 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1967 view->setFindIsUp(isUp);
1970 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
1972 GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
1975 static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
1977 GET_NATIVE_VIEW(env, obj)->showCursorTimed();
1980 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
1982 WebView* view = GET_NATIVE_VIEW(env, obj);
1983 LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
1984 view->setHeightCanMeasure(measure);
1987 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
1989 WebView* view = GET_NATIVE_VIEW(env, obj);
1990 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1991 jclass rectClass = env->FindClass("android/graphics/Rect");
1992 LOG_ASSERT(rectClass, "Could not find Rect class!");
1993 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1994 LOG_ASSERT(init, "Could not find constructor for Rect");
1995 WebCore::IntRect webRect;
1996 view->cursorRingBounds(&webRect);
1997 jobject rect = env->NewObject(rectClass, init, webRect.x(),
1998 webRect.y(), webRect.right(), webRect.bottom());
1999 env->DeleteLocalRef(rectClass);
2003 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
2004 jstring findUpper, jboolean sameAsLastSearch)
2006 // If one or the other is null, do not search.
2007 if (!(findLower && findUpper))
2009 // Obtain the characters for both the lower case string and the upper case
2010 // string representing the same word.
2011 const jchar* findLowerChars = env->GetStringChars(findLower, 0);
2012 const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
2013 // If one or the other is null, do not search.
2014 if (!(findLowerChars && findUpperChars)) {
2016 env->ReleaseStringChars(findLower, findLowerChars);
2018 env->ReleaseStringChars(findUpper, findUpperChars);
2019 checkException(env);
2022 WebView* view = GET_NATIVE_VIEW(env, obj);
2023 LOG_ASSERT(view, "view not set in nativeFindAll");
2024 CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
2026 env->ReleaseStringChars(findLower, findLowerChars);
2027 env->ReleaseStringChars(findUpper, findUpperChars);
2028 checkException(env);
2031 int length = env->GetStringLength(findLower);
2032 // If the lengths of the strings do not match, then they are not the same
2033 // word, so do not search.
2034 if (!length || env->GetStringLength(findUpper) != length) {
2035 env->ReleaseStringChars(findLower, findLowerChars);
2036 env->ReleaseStringChars(findUpper, findUpperChars);
2037 checkException(env);
2040 int width = root->documentWidth();
2041 int height = root->documentHeight();
2042 // Create a FindCanvas, which allows us to fake draw into it so we can
2043 // figure out where our search string is rendered (and how many times).
2044 FindCanvas canvas(width, height, (const UChar*) findLowerChars,
2045 (const UChar*) findUpperChars, length << 1);
2047 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
2048 canvas.setBitmapDevice(bitmap);
2050 WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
2051 // With setMatches, the WebView takes ownership of matches
2052 view->setMatches(matches, sameAsLastSearch);
2054 env->ReleaseStringChars(findLower, findLowerChars);
2055 env->ReleaseStringChars(findUpper, findUpperChars);
2056 checkException(env);
2057 return canvas.found();
2060 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
2062 WebView* view = GET_NATIVE_VIEW(env, obj);
2063 LOG_ASSERT(view, "view not set in nativeFindNext");
2064 view->findNext(forward);
2067 static int nativeFindIndex(JNIEnv *env, jobject obj)
2069 WebView* view = GET_NATIVE_VIEW(env, obj);
2070 LOG_ASSERT(view, "view not set in nativeFindIndex");
2071 return view->currentMatchIndex();
2074 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
2076 WebView* view = GET_NATIVE_VIEW(env, obj);
2077 LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
2078 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2081 const CachedNode* cachedFocusNode = root->currentFocus();
2082 if (!cachedFocusNode || !cachedFocusNode->isTextInput())
2084 WTF::String webcoreString = jstringToWtfString(env, updatedText);
2085 (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
2086 root->setTextGeneration(generation);
2087 checkException(env);
2090 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
2093 WebView* view = GET_NATIVE_VIEW(env, obj);
2094 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2097 return view->getBlockLeftEdge(x, y, scale);
2100 static void nativeDestroy(JNIEnv *env, jobject obj)
2102 WebView* view = GET_NATIVE_VIEW(env, obj);
2103 LOGD("nativeDestroy view: %p", view);
2104 LOG_ASSERT(view, "view not set in nativeDestroy");
2108 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
2110 WebView* view = GET_NATIVE_VIEW(env, obj);
2111 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2114 const CachedNode* current = root->currentCursor();
2115 if (!current || !current->isTextInput())
2116 current = root->currentFocus();
2117 if (!current || !current->isTextInput())
2119 const CachedFrame* frame;
2120 const CachedNode* next = root->nextTextField(current, &frame);
2123 const WebCore::IntRect& bounds = next->bounds(frame);
2124 root->rootHistory()->setMouseBounds(frame->unadjustBounds(next, bounds));
2125 view->getWebViewCore()->updateCursorBounds(root, frame, next);
2126 view->showCursorUntimed();
2127 root->setCursor(const_cast<CachedFrame*>(frame),
2128 const_cast<CachedNode*>(next));
2129 view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
2130 static_cast<WebCore::Node*>(next->nodePointer()));
2131 if (!next->isInLayer())
2132 view->scrollRectOnScreen(bounds);
2133 view->getWebViewCore()->m_moveGeneration++;
2137 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
2139 WebView* view = GET_NATIVE_VIEW(env, obj);
2142 return view->moveGeneration();
2145 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
2147 GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
2150 static void nativeResetSelection(JNIEnv *env, jobject obj)
2152 return GET_NATIVE_VIEW(env, obj)->resetSelection();
2155 static jobject nativeSelectableText(JNIEnv* env, jobject obj)
2157 IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
2158 jclass pointClass = env->FindClass("android/graphics/Point");
2159 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
2160 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
2161 env->DeleteLocalRef(pointClass);
2165 static void nativeSelectAll(JNIEnv* env, jobject obj)
2167 GET_NATIVE_VIEW(env, obj)->selectAll();
2170 static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
2172 GET_NATIVE_VIEW(env, obj)->setExtendSelection();
2175 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
2177 return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
2180 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
2182 return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
2185 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
2187 GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
2190 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
2192 WebView* view = GET_NATIVE_VIEW(env, obj);
2193 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2194 String selection = view->getSelection();
2195 return wtfStringToJstring(env, selection);
2198 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
2200 return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
2203 static jint nativeSelectionX(JNIEnv *env, jobject obj)
2205 return GET_NATIVE_VIEW(env, obj)->selectionX();
2208 static jint nativeSelectionY(JNIEnv *env, jobject obj)
2210 return GET_NATIVE_VIEW(env, obj)->selectionY();
2213 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
2214 jfloat scale, jint x, jint y)
2216 GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y);
2219 #ifdef ANDROID_DUMP_DISPLAY_TREE
2220 static void dumpToFile(const char text[], void* file) {
2221 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
2222 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
2226 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
2228 #ifdef ANDROID_DUMP_DISPLAY_TREE
2229 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2230 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2232 if (view && view->getWebViewCore()) {
2233 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
2235 SkFormatDumper dumper(dumpToFile, file);
2238 const char* str = env->GetStringUTFChars(jurl, 0);
2239 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
2240 dumpToFile(str, file);
2241 env->ReleaseStringUTFChars(jurl, str);
2243 // now dump the display tree
2244 SkDumpCanvas canvas(&dumper);
2245 // this will playback the picture into the canvas, which will
2246 // spew its contents to the dumper
2247 view->draw(&canvas, 0, 0, false);
2248 // we're done with the file now
2249 fwrite("\n", 1, 1, file);
2252 #if USE(ACCELERATED_COMPOSITING)
2253 const LayerAndroid* rootLayer = view->compositeRoot();
2255 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
2257 rootLayer->dumpLayers(file, 0);
2266 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
2267 jobject rect, jobject bounds)
2269 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2270 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2271 SkIRect nativeRect, nativeBounds;
2272 int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
2273 GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
2274 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
2278 static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
2281 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
2282 WebView* view = GET_NATIVE_VIEW(env, obj);
2283 LayerAndroid* root = view->compositeRoot();
2286 LayerAndroid* layer = root->findById(layerId);
2287 if (!layer || !layer->contentIsScrollable())
2289 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
2297 static JNINativeMethod gJavaWebViewMethods[] = {
2298 { "nativeCacheHitFramePointer", "()I",
2299 (void*) nativeCacheHitFramePointer },
2300 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
2301 (void*) nativeCacheHitNodeBounds },
2302 { "nativeCacheHitNodePointer", "()I",
2303 (void*) nativeCacheHitNodePointer },
2304 { "nativeClearCursor", "()V",
2305 (void*) nativeClearCursor },
2306 { "nativeCreate", "(I)V",
2307 (void*) nativeCreate },
2308 { "nativeCursorFramePointer", "()I",
2309 (void*) nativeCursorFramePointer },
2310 { "nativePageShouldHandleShiftAndArrows", "()Z",
2311 (void*) nativePageShouldHandleShiftAndArrows },
2312 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
2313 (void*) nativeCursorNodeBounds },
2314 { "nativeCursorNodePointer", "()I",
2315 (void*) nativeCursorNodePointer },
2316 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
2317 (void*) nativeCursorIntersects },
2318 { "nativeCursorIsAnchor", "()Z",
2319 (void*) nativeCursorIsAnchor },
2320 { "nativeCursorIsTextInput", "()Z",
2321 (void*) nativeCursorIsTextInput },
2322 { "nativeCursorPosition", "()Landroid/graphics/Point;",
2323 (void*) nativeCursorPosition },
2324 { "nativeCursorText", "()Ljava/lang/String;",
2325 (void*) nativeCursorText },
2326 { "nativeCursorWantsKeyEvents", "()Z",
2327 (void*)nativeCursorWantsKeyEvents },
2328 { "nativeDebugDump", "()V",
2329 (void*) nativeDebugDump },
2330 { "nativeDestroy", "()V",
2331 (void*) nativeDestroy },
2332 { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
2333 (void*) nativeDraw },
2334 { "nativeDrawGL", "(Landroid/graphics/Rect;FI)Z",
2335 (void*) nativeDrawGL },
2336 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
2337 (void*) nativeDumpDisplayTree },
2338 { "nativeEvaluateLayersAnimations", "()Z",
2339 (void*) nativeEvaluateLayersAnimations },
2340 { "nativeExtendSelection", "(II)V",
2341 (void*) nativeExtendSelection },
2342 { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
2343 (void*) nativeFindAll },
2344 { "nativeFindNext", "(Z)V",
2345 (void*) nativeFindNext },
2346 { "nativeFindIndex", "()I",
2347 (void*) nativeFindIndex},
2348 { "nativeFocusCandidateFramePointer", "()I",
2349 (void*) nativeFocusCandidateFramePointer },
2350 { "nativeFocusCandidateHasNextTextfield", "()Z",
2351 (void*) focusCandidateHasNextTextfield },
2352 { "nativeFocusCandidateIsPassword", "()Z",
2353 (void*) nativeFocusCandidateIsPassword },
2354 { "nativeFocusCandidateIsRtlText", "()Z",
2355 (void*) nativeFocusCandidateIsRtlText },
2356 { "nativeFocusCandidateIsTextInput", "()Z",
2357 (void*) nativeFocusCandidateIsTextInput },
2358 { "nativeFocusCandidateLineHeight", "()I",
2359 (void*) nativeFocusCandidateLineHeight },
2360 { "nativeFocusCandidateMaxLength", "()I",
2361 (void*) nativeFocusCandidateMaxLength },
2362 { "nativeFocusCandidateIsAutoComplete", "()Z",
2363 (void*) nativeFocusCandidateIsAutoComplete },
2364 { "nativeFocusCandidateName", "()Ljava/lang/String;",
2365 (void*) nativeFocusCandidateName },
2366 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
2367 (void*) nativeFocusCandidateNodeBounds },
2368 { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
2369 (void*) nativeFocusCandidatePaddingRect },
2370 { "nativeFocusCandidatePointer", "()I",
2371 (void*) nativeFocusCandidatePointer },
2372 { "nativeFocusCandidateText", "()Ljava/lang/String;",
2373 (void*) nativeFocusCandidateText },
2374 { "nativeFocusCandidateTextSize", "()F",
2375 (void*) nativeFocusCandidateTextSize },
2376 { "nativeFocusCandidateType", "()I",
2377 (void*) nativeFocusCandidateType },
2378 { "nativeFocusIsPlugin", "()Z",
2379 (void*) nativeFocusIsPlugin },
2380 { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
2381 (void*) nativeFocusNodeBounds },
2382 { "nativeFocusNodePointer", "()I",
2383 (void*) nativeFocusNodePointer },
2384 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
2385 (void*) nativeGetCursorRingBounds },
2386 { "nativeGetSelection", "()Ljava/lang/String;",
2387 (void*) nativeGetSelection },
2388 { "nativeHasCursorNode", "()Z",
2389 (void*) nativeHasCursorNode },
2390 { "nativeHasFocusNode", "()Z",
2391 (void*) nativeHasFocusNode },
2392 { "nativeHideCursor", "()V",
2393 (void*) nativeHideCursor },
2394 { "nativeHitSelection", "(II)Z",
2395 (void*) nativeHitSelection },
2396 { "nativeImageURI", "(II)Ljava/lang/String;",
2397 (void*) nativeImageURI },
2398 { "nativeInstrumentReport", "()V",
2399 (void*) nativeInstrumentReport },
2400 { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
2401 (void*) nativeLayerBounds },
2402 { "nativeMotionUp", "(III)Z",
2403 (void*) nativeMotionUp },
2404 { "nativeMoveCursor", "(IIZ)Z",
2405 (void*) nativeMoveCursor },
2406 { "nativeMoveCursorToNextTextInput", "()Z",
2407 (void*) nativeMoveCursorToNextTextInput },
2408 { "nativeMoveGeneration", "()I",
2409 (void*) nativeMoveGeneration },
2410 { "nativeMoveSelection", "(II)V",
2411 (void*) nativeMoveSelection },
2412 { "nativePointInNavCache", "(III)Z",
2413 (void*) nativePointInNavCache },
2414 { "nativeRecordButtons", "(ZZZ)V",
2415 (void*) nativeRecordButtons },
2416 { "nativeResetSelection", "()V",
2417 (void*) nativeResetSelection },
2418 { "nativeSelectableText", "()Landroid/graphics/Point;",
2419 (void*) nativeSelectableText },
2420 { "nativeSelectAll", "()V",
2421 (void*) nativeSelectAll },
2422 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
2423 (void*) nativeSelectBestAt },
2424 { "nativeSelectionX", "()I",
2425 (void*) nativeSelectionX },
2426 { "nativeSelectionY", "()I",
2427 (void*) nativeSelectionY },
2428 { "nativeSetExtendSelection", "()V",
2429 (void*) nativeSetExtendSelection },
2430 { "nativeSetFindIsEmpty", "()V",
2431 (void*) nativeSetFindIsEmpty },
2432 { "nativeSetFindIsUp", "(Z)V",
2433 (void*) nativeSetFindIsUp },
2434 { "nativeSetHeightCanMeasure", "(Z)V",
2435 (void*) nativeSetHeightCanMeasure },
2436 { "nativeSetBaseLayer", "(ILandroid/graphics/Rect;)V",
2437 (void*) nativeSetBaseLayer },
2438 { "nativeReplaceBaseContent", "(I)V",
2439 (void*) nativeReplaceBaseContent },
2440 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
2441 (void*) nativeCopyBaseContentToPicture },
2442 { "nativeHasContent", "()Z",
2443 (void*) nativeHasContent },
2444 { "nativeSetSelectionPointer", "(ZFII)V",
2445 (void*) nativeSetSelectionPointer },
2446 { "nativeShowCursorTimed", "()V",
2447 (void*) nativeShowCursorTimed },
2448 { "nativeStartSelection", "(II)Z",
2449 (void*) nativeStartSelection },
2450 { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
2451 (void*) nativeSubtractLayers },
2452 { "nativeTextGeneration", "()I",
2453 (void*) nativeTextGeneration },
2454 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
2455 (void*) nativeUpdateCachedTextfield },
2456 { "nativeWordSelection", "(II)Z",
2457 (void*) nativeWordSelection },
2458 { "nativeGetBlockLeftEdge", "(IIF)I",
2459 (void*) nativeGetBlockLeftEdge },
2460 { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
2461 (void*) nativeScrollableLayer },
2462 { "nativeScrollLayer", "(III)Z",
2463 (void*) nativeScrollLayer },
2466 int registerWebView(JNIEnv* env)
2468 jclass clazz = env->FindClass("android/webkit/WebView");
2469 LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
2470 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
2471 LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
2472 env->DeleteLocalRef(clazz);
2474 return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
2477 } // namespace android