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 "private/hwui/DrawGlInfo.h"
47 #include "PlatformGraphicsContext.h"
48 #include "PlatformString.h"
49 #include "ScrollableLayerAndroid.h"
50 #include "SelectText.h"
52 #include "SkDumpCanvas.h"
53 #include "SkPicture.h"
56 #ifdef ANDROID_INSTRUMENT
57 #include "TimeCounter.h"
59 #include "TilesManager.h"
60 #include "WebCoreJni.h"
61 #include "WebRequestContext.h"
62 #include "WebViewCore.h"
63 #include "android_graphics.h"
65 #ifdef GET_NATIVE_VIEW
66 #undef GET_NATIVE_VIEW
69 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
71 #include <JNIUtility.h>
74 #include <ui/KeycodeLabels.h>
75 #include <wtf/text/AtomicString.h>
76 #include <wtf/text/CString.h>
78 // Free as much as we possible can
79 #define TRIM_MEMORY_COMPLETE 80
80 // Free a lot (all textures gone)
81 #define TRIM_MEMORY_MODERATE 60
82 // More moderate free (keep bare minimum to restore quickly-ish - possibly clear all textures)
83 #define TRIM_MEMORY_BACKGROUND 40
84 // Moderate free (clear cached tiles, keep visible ones)
85 #define TRIM_MEMORY_UI_HIDDEN 20
86 // Duration to show the pressed cursor ring
87 #define PRESSED_STATE_DURATION 400
91 static jfieldID gWebViewField;
93 //-------------------------------------
95 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
97 jmethodID m = env->GetMethodID(clazz, name, signature);
98 LOG_ASSERT(m, "Could not find method %s", name);
102 //-------------------------------------
103 // This class provides JNI for making calls into native code from the UI side
104 // of the multi-threaded WebView.
108 enum FrameCachePermission {
113 enum DrawExtras { // keep this in sync with WebView.java
116 DrawExtrasSelection = 2,
117 DrawExtrasCursorRing = 3
122 jmethodID m_calcOurContentVisibleRectF;
123 jmethodID m_overrideLoading;
124 jmethodID m_scrollBy;
125 jmethodID m_sendMoveFocus;
126 jmethodID m_sendMoveMouse;
127 jmethodID m_sendMoveMouseIfLatest;
128 jmethodID m_sendMotionUp;
129 jmethodID m_domChangedFocus;
130 jmethodID m_getScaledMaxXScroll;
131 jmethodID m_getScaledMaxYScroll;
132 jmethodID m_getVisibleRect;
133 jmethodID m_rebuildWebTextView;
134 jmethodID m_viewInvalidate;
135 jmethodID m_viewInvalidateRect;
136 jmethodID m_postInvalidateDelayed;
137 jmethodID m_pageSwapCallback;
138 jmethodID m_inFullScreenMode;
141 jmethodID m_rectWidth;
142 jmethodID m_rectHeight;
143 jfieldID m_rectFLeft;
145 jmethodID m_rectFWidth;
146 jmethodID m_rectFHeight;
147 jmethodID m_getTextHandleScale;
148 AutoJObject object(JNIEnv* env) {
149 return getRealObject(env, m_obj);
153 WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir) :
154 m_ring((WebViewCore*) viewImpl)
156 jclass clazz = env->FindClass("android/webkit/WebView");
157 // m_javaGlue = new JavaGlue;
158 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
159 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
160 m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
161 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
162 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
163 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
164 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V");
165 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
166 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
167 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
168 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
169 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
170 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
171 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
172 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
173 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
174 "viewInvalidateDelayed", "(JIIII)V");
175 m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "()V");
176 m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
177 m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F");
178 env->DeleteLocalRef(clazz);
180 jclass rectClass = env->FindClass("android/graphics/Rect");
181 LOG_ASSERT(rectClass, "Could not find Rect class");
182 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
183 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
184 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
185 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
186 env->DeleteLocalRef(rectClass);
188 jclass rectClassF = env->FindClass("android/graphics/RectF");
189 LOG_ASSERT(rectClassF, "Could not find RectF class");
190 m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
191 m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
192 m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
193 m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
194 env->DeleteLocalRef(rectClassF);
196 env->SetIntField(javaWebView, gWebViewField, (jint)this);
197 m_viewImpl = (WebViewCore*) viewImpl;
201 m_heightCanMeasure = false;
204 m_ringAnimationEnd = 0;
207 m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir);
208 #if USE(ACCELERATED_COMPOSITING)
209 m_glWebViewState = 0;
210 m_pageSwapCallbackRegistered = false;
216 if (m_javaGlue.m_obj)
218 JNIEnv* env = JSC::Bindings::getJNIEnv();
219 env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
220 m_javaGlue.m_obj = 0;
222 #if USE(ACCELERATED_COMPOSITING)
223 // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
224 // do not remove it here, we risk having BaseTiles trying to paint using a
225 // deallocated base layer.
228 delete m_frameCacheUI;
229 delete m_navPictureUI;
230 SkSafeUnref(m_baseLayer);
231 delete m_glDrawFunctor;
237 #if USE(ACCELERATED_COMPOSITING)
238 delete m_glWebViewState;
239 m_glWebViewState = 0;
243 WebViewCore* getWebViewCore() const {
247 float getTextHandleScale()
249 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
250 JNIEnv* env = JSC::Bindings::getJNIEnv();
251 AutoJObject javaObject = m_javaGlue.object(env);
252 if (!javaObject.get())
254 float result = env->CallFloatMethod(javaObject.get(), m_javaGlue.m_getTextHandleScale);
259 void updateSelectionHandles()
263 // Adjust for device density & scale
264 m_selectText.updateHandleScale(getTextHandleScale());
267 // removes the cursor altogether (e.g., when going to a new page)
270 CachedRoot* root = getFrameCache(AllowNewer);
274 m_viewImpl->m_hasCursorBounds = false;
279 // leaves the cursor where it is, but suppresses drawing it
282 CachedRoot* root = getFrameCache(AllowNewer);
290 void hideCursor(CachedRoot* root)
292 DBG_NAV_LOG("inner");
293 m_viewImpl->m_hasCursorBounds = false;
300 CachedRoot* root = getFrameCache(DontAllowNewer);
302 root->mDebug.print();
306 // Traverse our stored array of buttons that are in our picture, and update
307 // their subpictures according to their current state.
308 // Called from the UI thread. This is the one place in the UI thread where we
309 // access the buttons stored in the WebCore thread.
310 // hasFocus keeps track of whether the WebView has focus && windowFocus.
311 // If not, we do not want to draw the button in a selected or pressed state
312 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
314 bool cursorIsOnButton = false;
315 const CachedFrame* cachedFrame;
316 const CachedNode* cachedCursor = 0;
317 // Lock the mutex, since we now share with the WebCore thread.
318 m_viewImpl->gButtonMutex.lock();
319 if (m_viewImpl->m_buttons.size() && m_buttonSkin) {
320 // FIXME: In a future change, we should keep track of whether the selection
321 // has changed to short circuit (note that we would still need to update
322 // if we received new buttons from the WebCore thread).
323 WebCore::Node* cursor = 0;
324 CachedRoot* root = getFrameCache(DontAllowNewer);
326 cachedCursor = root->currentCursor(&cachedFrame);
328 cursor = (WebCore::Node*) cachedCursor->nodePointer();
331 // Traverse the array, and update each button, depending on whether it
333 Container* end = m_viewImpl->m_buttons.end();
334 for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
335 RenderSkinAndroid::State state = RenderSkinAndroid::kNormal;
336 if (ptr->matches(cursor)) {
337 cursorIsOnButton = true;
338 // If the WebView is out of focus/window focus, set the state to
339 // normal, but still keep track of the fact that the selected is a
342 if (pressed || m_ring.m_isPressed)
343 state = RenderSkinAndroid::kPressed;
344 else if (SkTime::GetMSecs() < m_ringAnimationEnd)
345 state = RenderSkinAndroid::kFocused;
348 ptr->updateFocusState(state, m_buttonSkin);
351 m_viewImpl->gButtonMutex.unlock();
352 if (invalidate && cachedCursor && cursorIsOnButton) {
353 const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
354 viewInvalidateRect(b.x(), b.y(), b.maxX(), b.maxY());
358 void scrollToCurrentMatch()
360 if (!m_findOnPage.currentMatchIsInLayer()) {
361 scrollRectOnScreen(m_findOnPage.currentMatchBounds());
365 SkRect matchBounds = m_findOnPage.currentMatchBounds();
366 LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer();
367 Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId());
368 ASSERT(layerContainingMatch);
370 // If the match is in a fixed position layer, there's nothing to do.
371 if (layerContainingMatch->shouldInheritFromRootTransform())
374 // If the match is in a scrollable layer or a descendant of such a layer,
375 // there may be a range of of scroll configurations that will make the
376 // current match visible. Our approach is the simplest possible. Starting at
377 // the layer in which the match is found, we move up the layer tree,
378 // scrolling any scrollable layers as little as possible to make sure that
379 // the current match is in view. This approach has the disadvantage that we
380 // may end up scrolling a larger number of elements than is necessary, which
381 // may be visually jarring. However, minimising the number of layers
382 // scrolled would complicate the code significantly.
384 bool didScrollLayer = false;
385 for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) {
386 ASSERT(layer->getParent() || layer == rootLayer);
388 if (layer->contentIsScrollable()) {
389 // Convert the match location to layer's local space and scroll it.
390 // Repeatedly calling Layer::localToAncestor() is inefficient as
391 // each call repeats part of the calculation. It would be more
392 // efficient to maintain the transform here and update it on each
393 // iteration, but that would mean duplicating logic from
394 // Layer::localToAncestor() and would complicate things.
396 layerContainingMatch->localToAncestor(layer, &transform);
397 SkRect transformedMatchBounds;
398 transform.mapRect(&transformedMatchBounds, matchBounds);
399 SkIRect roundedTransformedMatchBounds;
400 transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
401 // Only ScrollableLayerAndroid returns true for contentIsScrollable().
402 didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds);
405 // Invalidate, as the call below to scroll the main page may be a no-op.
409 // Convert matchBounds to the global space so we can scroll the main page.
411 layerContainingMatch->localToGlobal(&transform);
412 SkRect transformedMatchBounds;
413 transform.mapRect(&transformedMatchBounds, matchBounds);
414 SkIRect roundedTransformedMatchBounds;
415 transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
416 scrollRectOnScreen(roundedTransformedMatchBounds);
419 void scrollRectOnScreen(const IntRect& rect)
424 calcOurContentVisibleRect(&visible);
427 int right = rect.maxX();
428 if (left < visible.fLeft) {
429 dx = left - visible.fLeft;
430 // Only scroll right if the entire width can fit on screen.
431 } else if (right > visible.fRight && right - left < visible.width()) {
432 dx = right - visible.fRight;
436 int bottom = rect.maxY();
437 if (top < visible.fTop) {
438 dy = top - visible.fTop;
439 // Only scroll down if the entire height can fit on screen
440 } else if (bottom > visible.fBottom && bottom - top < visible.height()) {
441 dy = bottom - visible.fBottom;
443 if ((dx|dy) == 0 || !scrollBy(dx, dy))
448 void calcOurContentVisibleRect(SkRect* r)
450 JNIEnv* env = JSC::Bindings::getJNIEnv();
451 AutoJObject javaObject = m_javaGlue.object(env);
452 if (!javaObject.get())
454 jclass rectClass = env->FindClass("android/graphics/RectF");
455 jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V");
456 jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0);
457 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_calcOurContentVisibleRectF, jRect);
458 r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft);
459 r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop);
460 r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth);
461 r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight);
462 env->DeleteLocalRef(rectClass);
463 env->DeleteLocalRef(jRect);
467 void resetCursorRing()
469 m_ringAnimationEnd = 0;
470 m_viewImpl->m_hasCursorBounds = false;
473 bool drawCursorPreamble(CachedRoot* root)
475 if (!root) return false;
476 const CachedFrame* frame;
477 const CachedNode* node = root->currentCursor(&frame);
479 DBG_NAV_LOGV("%s", "!node");
483 m_ring.setIsButton(node);
484 if (node->isHidden()) {
485 DBG_NAV_LOG("node->isHidden()");
486 m_viewImpl->m_hasCursorBounds = false;
489 #if USE(ACCELERATED_COMPOSITING)
490 if (node->isInLayer() && root->rootLayer()) {
491 LayerAndroid* layer = root->rootLayer();
493 calcOurContentVisibleRect(&visible);
494 layer->updateFixedLayersPositions(visible);
495 layer->updatePositions();
498 setVisibleRect(root);
499 m_ring.m_root = root;
500 m_ring.m_frame = frame;
501 m_ring.m_node = node;
502 SkMSec time = SkTime::GetMSecs();
503 m_ring.m_isPressed = time < m_ringAnimationEnd
504 && m_ringAnimationEnd != UINT_MAX;
508 void drawCursorPostamble()
510 if (m_ringAnimationEnd == UINT_MAX)
512 SkMSec time = SkTime::GetMSecs();
513 if (time < m_ringAnimationEnd) {
514 // views assume that inval bounds coordinates are non-negative
515 WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
516 invalBounds.intersect(m_ring.m_absBounds);
517 postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
519 hideCursor(const_cast<CachedRoot*>(m_ring.m_root));
523 bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::IntRect& webViewRect,
524 int titleBarHeight, WebCore::IntRect& clip, float scale, int extras)
526 #if USE(ACCELERATED_COMPOSITING)
527 if (!m_baseLayer || inFullScreenMode())
530 if (!m_glWebViewState) {
531 m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex);
532 if (m_baseLayer->content()) {
535 rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
536 region.setRect(rect);
537 m_glWebViewState->setBaseLayer(m_baseLayer, region, false, true);
541 CachedRoot* root = getFrameCache(AllowNewer);
543 DBG_NAV_LOG("!root");
544 if (extras == DrawExtrasCursorRing)
547 DrawExtra* extra = 0;
550 extra = &m_findOnPage;
552 case DrawExtrasSelection:
553 // This will involve a JNI call, but under normal circumstances we will
554 // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
555 // in WebView.java will we hit this (so really debug only)
556 updateSelectionHandles();
557 extra = &m_selectText;
559 case DrawExtrasCursorRing:
560 if (drawCursorPreamble(root) && m_ring.setup()) {
561 if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX)
563 drawCursorPostamble();
570 unsigned int pic = m_glWebViewState->currentPictureCounter();
573 IntRect rect(0, 0, 0, 0);
574 bool allowSame = false;
575 m_glWebViewState->resetRings();
577 if (extra == &m_ring) {
578 WTF::Vector<IntRect> rings;
579 if (!m_ring.m_isButton && root == m_ring.m_frame)
580 rings = m_ring.rings();
582 // TODO: Fix the navcache to work with layers correctly
583 // In the meantime, this works around the bug. However, the rings
584 // it produces are not as nice for some reason, thus we use
585 // m_ring.rings() above for the base layer instead of the below
586 for (size_t i = 0; i < m_ring.m_node->rings().size(); i++) {
587 IntRect rect = m_ring.m_node->rings().at(i);
588 rect = m_ring.m_frame->adjustBounds(m_ring.m_node, rect);
589 if (!m_ring.m_isButton)
594 m_glWebViewState->setRings(rings, m_ring.m_isPressed, m_ring.m_isButton);
597 LayerAndroid mainPicture(m_navPictureUI);
598 PictureSet* content = m_baseLayer->content();
599 SkCanvas* canvas = picture.beginRecording(content->width(),
601 extra->draw(canvas, &mainPicture, &rect);
602 picture.endRecording();
605 m_glWebViewState->setExtra(m_baseLayer, picture, rect, allowSame);
607 LayerAndroid* compositeLayer = compositeRoot();
609 compositeLayer->setExtra(extra);
612 calcOurContentVisibleRect(&visibleRect);
613 // Make sure we have valid coordinates. We might not have valid coords
614 // if the zoom manager is still initializing. We will be redrawn
615 // once the correct scale is set
616 if (!visibleRect.hasValidCoordinates())
618 bool pagesSwapped = false;
619 bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect,
620 webViewRect, titleBarHeight, clip, scale,
622 if (m_pageSwapCallbackRegistered && pagesSwapped) {
623 m_pageSwapCallbackRegistered = false;
624 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
625 JNIEnv* env = JSC::Bindings::getJNIEnv();
626 AutoJObject javaObject = m_javaGlue.object(env);
627 if (javaObject.get()) {
628 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback);
632 if (ret || m_glWebViewState->currentPictureCounter() != pic)
638 PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
642 canvas->drawColor(bgColor);
646 // draw the content of the base layer first
647 PictureSet* content = m_baseLayer->content();
648 int sc = canvas->save(SkCanvas::kClip_SaveFlag);
649 canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
650 content->height()), SkRegion::kDifference_Op);
651 canvas->drawColor(bgColor);
652 canvas->restoreToCount(sc);
653 if (content->draw(canvas))
654 ret = split ? new PictureSet(*content) : 0;
656 CachedRoot* root = getFrameCache(AllowNewer);
658 DBG_NAV_LOG("!root");
659 if (extras == DrawExtrasCursorRing)
662 LayerAndroid mainPicture(m_navPictureUI);
663 DrawExtra* extra = 0;
666 extra = &m_findOnPage;
668 case DrawExtrasSelection:
669 // This will involve a JNI call, but under normal circumstances we will
670 // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
671 // in WebView.java will we hit this (so really debug only)
672 updateSelectionHandles();
673 extra = &m_selectText;
675 case DrawExtrasCursorRing:
676 if (drawCursorPreamble(root) && m_ring.setup()) {
677 if (!m_ring.m_isButton)
679 drawCursorPostamble();
686 IntRect dummy; // inval area, unused for now
687 extra->draw(canvas, &mainPicture, &dummy);
689 #if USE(ACCELERATED_COMPOSITING)
690 LayerAndroid* compositeLayer = compositeRoot();
693 compositeLayer->setExtra(extra);
695 calcOurContentVisibleRect(&visible);
696 // call this to be sure we've adjusted for any scrolling or animations
697 // before we actually draw
698 compositeLayer->updateFixedLayersPositions(visible);
699 compositeLayer->updatePositions();
700 // We have to set the canvas' matrix on the base layer
701 // (to have fixed layers work as intended)
702 SkAutoCanvasRestore restore(canvas, true);
703 m_baseLayer->setMatrix(canvas->getTotalMatrix());
704 canvas->resetMatrix();
705 m_baseLayer->draw(canvas);
711 bool cursorIsTextInput(FrameCachePermission allowNewer)
713 CachedRoot* root = getFrameCache(allowNewer);
715 DBG_NAV_LOG("!root");
718 const CachedNode* cursor = root->currentCursor();
720 DBG_NAV_LOG("!cursor");
723 DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
724 return cursor->isTextInput();
727 void cursorRingBounds(WebCore::IntRect* bounds)
729 DBG_NAV_LOGD("%s", "");
730 CachedRoot* root = getFrameCache(DontAllowNewer);
732 const CachedFrame* cachedFrame;
733 const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
735 *bounds = cachedNode->cursorRingBounds(cachedFrame);
736 DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
737 bounds->width(), bounds->height());
741 *bounds = WebCore::IntRect(0, 0, 0, 0);
746 m_viewImpl->gCursorBoundsMutex.lock();
747 bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
748 IntRect bounds = m_viewImpl->m_cursorBounds;
749 m_viewImpl->gCursorBoundsMutex.unlock();
750 if (!hasCursorBounds)
753 const CachedFrame* frame;
754 const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true);
757 // require that node have approximately the same bounds (+/- 4) and the same
759 IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
760 bounds.y() + (bounds.height() >> 1));
761 IntRect newBounds = node->bounds(frame);
762 IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
763 newBounds.y() + (newBounds.height() >> 1));
764 DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
765 " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
766 oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
767 bounds.x(), bounds.y(), bounds.width(), bounds.height(),
768 newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
769 if (abs(oldCenter.x() - newCenter.x()) > 2)
771 if (abs(oldCenter.y() - newCenter.y()) > 2)
773 if (abs(bounds.x() - newBounds.x()) > 4)
775 if (abs(bounds.y() - newBounds.y()) > 4)
777 if (abs(bounds.maxX() - newBounds.maxX()) > 4)
779 if (abs(bounds.maxY() - newBounds.maxY()) > 4)
781 DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
782 node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
784 m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
785 const_cast<CachedNode*>(node));
788 CachedRoot* getFrameCache(FrameCachePermission allowNewer)
790 if (!m_viewImpl->m_updatedFrameCache) {
791 DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
792 return m_frameCacheUI;
794 if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
795 DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
796 " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
797 return m_frameCacheUI;
799 DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
800 const CachedFrame* oldCursorFrame;
801 const CachedNode* oldCursorNode = m_frameCacheUI ?
802 m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
803 #if USE(ACCELERATED_COMPOSITING)
805 if (oldCursorNode && oldCursorNode->isInLayer()) {
806 const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
807 ->layer(m_frameCacheUI->rootLayer());
809 layerId = cursorLayer->uniqueId();
812 // get id from old layer and use to find new layer
813 bool oldFocusIsTextInput = false;
814 void* oldFocusNodePointer = 0;
815 if (m_frameCacheUI) {
816 const CachedNode* oldFocus = m_frameCacheUI->currentFocus();
818 oldFocusIsTextInput = oldFocus->isTextInput();
819 oldFocusNodePointer = oldFocus->nodePointer();
822 m_viewImpl->gFrameCacheMutex.lock();
823 delete m_frameCacheUI;
824 SkSafeUnref(m_navPictureUI);
825 m_viewImpl->m_updatedFrameCache = false;
826 m_frameCacheUI = m_viewImpl->m_frameCacheKit;
827 m_navPictureUI = m_viewImpl->m_navPictureKit;
828 m_viewImpl->m_frameCacheKit = 0;
829 m_viewImpl->m_navPictureKit = 0;
830 m_viewImpl->gFrameCacheMutex.unlock();
832 m_frameCacheUI->setRootLayer(compositeRoot());
833 #if USE(ACCELERATED_COMPOSITING)
836 calcOurContentVisibleRect(&visible);
837 LayerAndroid* layer = const_cast<LayerAndroid*>(
838 m_frameCacheUI->rootLayer());
840 layer->updateFixedLayersPositions(visible);
841 layer->updatePositions();
846 if (oldFocusIsTextInput) {
847 const CachedNode* newFocus = m_frameCacheUI->currentFocus();
848 if (newFocus && oldFocusNodePointer != newFocus->nodePointer()
849 && newFocus->isTextInput()
850 && newFocus != m_frameCacheUI->currentCursor()) {
851 // The focus has changed. We may need to update things.
852 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
853 JNIEnv* env = JSC::Bindings::getJNIEnv();
854 AutoJObject javaObject = m_javaGlue.object(env);
855 if (javaObject.get()) {
856 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_domChangedFocus);
861 if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
862 viewInvalidate(); // redraw in case cursor ring is still visible
863 return m_frameCacheUI;
866 int getScaledMaxXScroll()
868 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
869 JNIEnv* env = JSC::Bindings::getJNIEnv();
870 AutoJObject javaObject = m_javaGlue.object(env);
871 if (!javaObject.get())
873 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll);
878 int getScaledMaxYScroll()
880 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
881 JNIEnv* env = JSC::Bindings::getJNIEnv();
882 AutoJObject javaObject = m_javaGlue.object(env);
883 if (!javaObject.get())
885 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll);
890 IntRect getVisibleRect()
893 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
894 JNIEnv* env = JSC::Bindings::getJNIEnv();
895 AutoJObject javaObject = m_javaGlue.object(env);
896 if (!javaObject.get())
898 jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect);
900 rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
902 rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
904 rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
906 rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
908 env->DeleteLocalRef(jRect);
913 static CachedFrame::Direction KeyToDirection(int32_t keyCode)
916 case AKEYCODE_DPAD_RIGHT:
917 DBG_NAV_LOGD("keyCode=%s", "right");
918 return CachedFrame::RIGHT;
919 case AKEYCODE_DPAD_LEFT:
920 DBG_NAV_LOGD("keyCode=%s", "left");
921 return CachedFrame::LEFT;
922 case AKEYCODE_DPAD_DOWN:
923 DBG_NAV_LOGD("keyCode=%s", "down");
924 return CachedFrame::DOWN;
925 case AKEYCODE_DPAD_UP:
926 DBG_NAV_LOGD("keyCode=%s", "up");
927 return CachedFrame::UP;
929 DBG_NAV_LOGD("bad key %d sent", keyCode);
930 return CachedFrame::UNINITIALIZED;
934 WTF::String imageURI(int x, int y)
936 const CachedRoot* root = getFrameCache(DontAllowNewer);
937 return root ? root->imageURI(x, y) : WTF::String();
940 bool cursorWantsKeyEvents()
942 const CachedRoot* root = getFrameCache(DontAllowNewer);
944 const CachedNode* focus = root->currentCursor();
946 return focus->wantsKeyEvents();
952 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
953 bool moveCursor(int keyCode, int count, bool ignoreScroll)
955 CachedRoot* root = getFrameCache(AllowNewer);
957 DBG_NAV_LOG("!root");
961 m_viewImpl->m_moveGeneration++;
962 CachedFrame::Direction direction = KeyToDirection(keyCode);
963 const CachedFrame* cachedFrame, * oldFrame = 0;
964 const CachedNode* cursor = root->currentCursor(&oldFrame);
965 WebCore::IntPoint cursorLocation = root->cursorLocation();
966 DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
967 cursor ? cursor->index() : 0,
968 cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
969 WebCore::IntRect visibleRect = setVisibleRect(root);
970 int xMax = getScaledMaxXScroll();
971 int yMax = getScaledMaxYScroll();
972 root->setMaxScroll(xMax, yMax);
973 const CachedNode* cachedNode = 0;
977 while (--counter >= 0) {
978 WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
979 cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
983 DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
984 "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
985 cachedNode ? cachedNode->nodePointer() : 0,
986 root->cursorLocation().x(), root->cursorLocation().y(),
987 cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
988 cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
989 cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
990 cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
991 // If !m_heightCanMeasure (such as in the browser), we want to scroll no
993 if (!ignoreScroll && (!m_heightCanMeasure ||
995 (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
997 if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
998 SkTime::GetMSecs() - m_lastDxTime < 1000)
999 root->checkForJiggle(&dx);
1000 DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
1002 this->scrollBy(dx, dy);
1004 m_lastDxTime = SkTime::GetMSecs();
1006 bool result = false;
1008 showCursorUntimed();
1009 m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
1010 root->setCursor(const_cast<CachedFrame*>(cachedFrame),
1011 const_cast<CachedNode*>(cachedNode));
1012 const CachedNode* focus = root->currentFocus();
1013 bool clearTextEntry = cachedNode != focus && focus
1014 && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput();
1015 // Stop painting the caret if the old focus was a text input and so is the new cursor.
1016 bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents();
1017 sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret);
1019 int docHeight = root->documentHeight();
1020 int docWidth = root->documentWidth();
1021 if (visibleRect.maxY() + dy > docHeight)
1022 dy = docHeight - visibleRect.maxY();
1023 else if (visibleRect.y() + dy < 0)
1024 dy = -visibleRect.y();
1025 if (visibleRect.maxX() + dx > docWidth)
1026 dx = docWidth - visibleRect.maxX();
1027 else if (visibleRect.x() < 0)
1028 dx = -visibleRect.x();
1029 result = direction == CachedFrame::LEFT ? dx >= 0 :
1030 direction == CachedFrame::RIGHT ? dx <= 0 :
1031 direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
1036 void notifyProgressFinished()
1038 DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
1039 rebuildWebTextView();
1041 if (m_frameCacheUI) {
1042 const CachedNode* focus = m_frameCacheUI->currentFocus();
1043 DBG_NAV_LOGD("focus %d (nativeNode=%p)",
1044 focus ? focus->index() : 0,
1045 focus ? focus->nodePointer() : 0);
1050 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
1051 const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
1058 setVisibleRect(root);
1059 return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
1062 IntRect setVisibleRect(CachedRoot* root)
1064 IntRect visibleRect = getVisibleRect();
1065 DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
1066 visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
1067 root->setVisibleRect(visibleRect);
1071 void selectBestAt(const WebCore::IntRect& rect)
1073 const CachedFrame* frame;
1075 CachedRoot* root = getFrameCache(AllowNewer);
1078 const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
1080 DBG_NAV_LOGD("no nodes found root=%p", root);
1081 root->rootHistory()->setMouseBounds(rect);
1082 m_viewImpl->m_hasCursorBounds = false;
1083 root->setCursor(0, 0);
1086 DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
1087 WebCore::IntRect bounds = node->bounds(frame);
1088 root->rootHistory()->setMouseBounds(bounds);
1089 m_viewImpl->updateCursorBounds(root, frame, node);
1091 root->setCursor(const_cast<CachedFrame*>(frame),
1092 const_cast<CachedNode*>(node));
1094 sendMoveMouseIfLatest(false, false);
1097 const CachedNode* m_cacheHitNode;
1098 const CachedFrame* m_cacheHitFrame;
1100 bool pointInNavCache(int x, int y, int slop)
1102 CachedRoot* root = getFrameCache(AllowNewer);
1105 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
1107 return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
1110 bool motionUp(int x, int y, int slop)
1112 bool pageScrolled = false;
1113 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
1115 CachedRoot* root = getFrameCache(AllowNewer);
1118 const CachedFrame* frame = 0;
1119 const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
1120 CachedHistory* history = root->rootHistory();
1122 DBG_NAV_LOGD("no nodes found root=%p", root);
1123 history->setNavBounds(rect);
1124 m_viewImpl->m_hasCursorBounds = false;
1126 int dx = root->checkForCenter(x, y);
1129 pageScrolled = true;
1131 sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
1134 return pageScrolled;
1136 DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
1137 result->index(), x, y, rx, ry);
1138 WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
1139 history->setNavBounds(navBounds);
1140 history->setMouseBounds(navBounds);
1141 m_viewImpl->updateCursorBounds(root, frame, result);
1142 root->setCursor(const_cast<CachedFrame*>(frame),
1143 const_cast<CachedNode*>(result));
1144 if (result->isSyntheticLink())
1145 overrideUrlLoading(result->getExport());
1148 (WebCore::Frame*) frame->framePointer(),
1149 (WebCore::Node*) result->nodePointer(), rx, ry);
1151 if (result->isTextInput() || result->isSelect()
1152 || result->isContentEditable()) {
1153 showCursorUntimed();
1156 return pageScrolled;
1159 #if USE(ACCELERATED_COMPOSITING)
1160 static const ScrollableLayerAndroid* findScrollableLayer(
1161 const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
1163 parent->bounds(&bounds);
1164 // Check the parent bounds first; this will clip to within a masking layer's
1166 if (parent->masksToBounds() && !bounds.contains(x, y))
1168 // Move the hit test local to parent.
1171 int count = parent->countChildren();
1173 const LayerAndroid* child = parent->getChild(count);
1174 const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
1177 foundBounds->offset(bounds.fLeft, bounds.fTop);
1178 if (parent->masksToBounds()) {
1179 if (bounds.width() < foundBounds->width())
1180 foundBounds->fRight = foundBounds->fLeft + bounds.width();
1181 if (bounds.height() < foundBounds->height())
1182 foundBounds->fBottom = foundBounds->fTop + bounds.height();
1187 if (parent->contentIsScrollable()) {
1188 foundBounds->set(0, 0, bounds.width(), bounds.height());
1189 return static_cast<const ScrollableLayerAndroid*>(parent);
1195 int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
1197 #if USE(ACCELERATED_COMPOSITING)
1198 const LayerAndroid* layerRoot = compositeRoot();
1201 const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
1204 result->getScrollRect(layerRect);
1205 return result->uniqueId();
1211 int getBlockLeftEdge(int x, int y, float scale)
1213 CachedRoot* root = getFrameCache(AllowNewer);
1215 return root->getBlockLeftEdge(x, y, scale);
1219 void overrideUrlLoading(const WTF::String& url)
1221 JNIEnv* env = JSC::Bindings::getJNIEnv();
1222 AutoJObject javaObject = m_javaGlue.object(env);
1223 if (!javaObject.get())
1225 jstring jName = wtfStringToJstring(env, url);
1226 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName);
1227 env->DeleteLocalRef(jName);
1230 void setFindIsUp(bool up)
1232 DBG_NAV_LOGD("up=%d", up);
1233 m_viewImpl->m_findIsUp = up;
1236 void setFindIsEmpty()
1239 m_findOnPage.clearCurrentLocation();
1242 void showCursorTimed()
1245 m_ringAnimationEnd = SkTime::GetMSecs() + PRESSED_STATE_DURATION;
1249 void showCursorUntimed()
1252 m_ring.m_isPressed = false;
1253 m_ringAnimationEnd = UINT_MAX;
1257 void setHeightCanMeasure(bool measure)
1259 m_heightCanMeasure = measure;
1262 String getSelection()
1264 return m_selectText.getSelection();
1267 void moveSelection(int x, int y)
1269 m_selectText.moveSelection(getVisibleRect(), x, y);
1272 IntPoint selectableText()
1274 const CachedRoot* root = getFrameCache(DontAllowNewer);
1276 return IntPoint(0, 0);
1277 return m_selectText.selectableText(root);
1282 m_selectText.selectAll();
1287 return m_selectText.selectionX();
1292 return m_selectText.selectionY();
1295 void resetSelection()
1297 m_selectText.reset();
1300 bool startSelection(int x, int y)
1302 const CachedRoot* root = getFrameCache(DontAllowNewer);
1305 updateSelectionHandles();
1306 return m_selectText.startSelection(root, getVisibleRect(), x, y);
1309 bool wordSelection(int x, int y)
1311 const CachedRoot* root = getFrameCache(DontAllowNewer);
1314 updateSelectionHandles();
1315 return m_selectText.wordSelection(root, getVisibleRect(), x, y);
1318 bool extendSelection(int x, int y)
1320 m_selectText.extendSelection(getVisibleRect(), x, y);
1324 bool hitSelection(int x, int y)
1326 updateSelectionHandles();
1327 return m_selectText.hitSelection(x, y);
1330 void setExtendSelection()
1332 m_selectText.setExtendSelection(true);
1335 void setSelectionPointer(bool set, float scale, int x, int y)
1337 m_selectText.setDrawPointer(set);
1340 m_selectText.m_inverseScale = scale;
1341 m_selectText.m_selectX = x;
1342 m_selectText.m_selectY = y;
1345 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
1347 DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
1348 JNIEnv* env = JSC::Bindings::getJNIEnv();
1349 AutoJObject javaObject = m_javaGlue.object(env);
1350 if (!javaObject.get())
1352 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
1353 checkException(env);
1356 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1358 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
1359 JNIEnv* env = JSC::Bindings::getJNIEnv();
1360 AutoJObject javaObject = m_javaGlue.object(env);
1361 if (!javaObject.get())
1363 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y);
1364 checkException(env);
1367 void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret)
1369 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1370 JNIEnv* env = JSC::Bindings::getJNIEnv();
1371 AutoJObject javaObject = m_javaGlue.object(env);
1372 if (!javaObject.get())
1374 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret);
1375 checkException(env);
1378 void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1380 DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y);
1381 LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
1383 JNIEnv* env = JSC::Bindings::getJNIEnv();
1384 AutoJObject javaObject = m_javaGlue.object(env);
1385 if (!javaObject.get())
1387 m_viewImpl->m_touchGeneration = ++m_generation;
1388 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y);
1389 checkException(env);
1392 void findNext(bool forward)
1394 m_findOnPage.findNext(forward);
1395 scrollToCurrentMatch();
1399 // With this call, WebView takes ownership of matches, and is responsible for
1401 void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch)
1403 // If this search is the same as the last one, check against the old
1404 // location to determine whether to scroll. If the same word is found
1405 // in the same place, then do not scroll.
1406 IntRect oldLocation;
1407 bool checkAgainstOldLocation = false;
1408 if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) {
1409 oldLocation = m_findOnPage.currentMatchBounds();
1410 checkAgainstOldLocation = true;
1413 m_findOnPage.setMatches(matches);
1415 if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds())
1416 scrollToCurrentMatch();
1420 int currentMatchIndex()
1422 return m_findOnPage.currentMatchIndex();
1425 bool scrollBy(int dx, int dy)
1427 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1429 JNIEnv* env = JSC::Bindings::getJNIEnv();
1430 AutoJObject javaObject = m_javaGlue.object(env);
1431 if (!javaObject.get())
1433 bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true);
1434 checkException(env);
1438 void setIsScrolling(bool isScrolling)
1440 #if USE(ACCELERATED_COMPOSITING)
1441 if (m_glWebViewState)
1442 m_glWebViewState->setIsScrolling(isScrolling);
1446 bool hasCursorNode()
1448 CachedRoot* root = getFrameCache(DontAllowNewer);
1450 DBG_NAV_LOG("!root");
1453 const CachedNode* cursorNode = root->currentCursor();
1454 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
1455 cursorNode ? cursorNode->index() : -1,
1456 cursorNode ? cursorNode->nodePointer() : 0);
1462 CachedRoot* root = getFrameCache(DontAllowNewer);
1464 DBG_NAV_LOG("!root");
1467 const CachedNode* focusNode = root->currentFocus();
1468 DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
1469 focusNode ? focusNode->index() : -1,
1470 focusNode ? focusNode->nodePointer() : 0);
1474 void rebuildWebTextView()
1476 JNIEnv* env = JSC::Bindings::getJNIEnv();
1477 AutoJObject javaObject = m_javaGlue.object(env);
1478 if (!javaObject.get())
1480 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView);
1481 checkException(env);
1484 void viewInvalidate()
1486 JNIEnv* env = JSC::Bindings::getJNIEnv();
1487 AutoJObject javaObject = m_javaGlue.object(env);
1488 if (!javaObject.get())
1490 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate);
1491 checkException(env);
1494 void viewInvalidateRect(int l, int t, int r, int b)
1496 JNIEnv* env = JSC::Bindings::getJNIEnv();
1497 AutoJObject javaObject = m_javaGlue.object(env);
1498 if (!javaObject.get())
1500 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
1501 checkException(env);
1504 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
1506 JNIEnv* env = JSC::Bindings::getJNIEnv();
1507 AutoJObject javaObject = m_javaGlue.object(env);
1508 if (!javaObject.get())
1510 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed,
1511 delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY());
1512 checkException(env);
1515 bool inFullScreenMode()
1517 JNIEnv* env = JSC::Bindings::getJNIEnv();
1518 AutoJObject javaObject = m_javaGlue.object(env);
1519 if (!javaObject.get())
1521 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_inFullScreenMode);
1522 checkException(env);
1526 int moveGeneration()
1528 return m_viewImpl->m_moveGeneration;
1531 LayerAndroid* compositeRoot() const
1533 LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
1534 "base layer can't have more than one child %s", __FUNCTION__);
1535 if (m_baseLayer && m_baseLayer->countChildren() == 1)
1536 return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
1541 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1542 static void copyScrollPositionRecursive(const LayerAndroid* from,
1547 for (int i = 0; i < from->countChildren(); i++) {
1548 const LayerAndroid* l = from->getChild(i);
1549 if (l->contentIsScrollable()) {
1550 const SkPoint& pos = l->getPosition();
1551 LayerAndroid* match = root->findById(l->uniqueId());
1552 if (match && match->contentIsScrollable())
1553 match->setPosition(pos.fX, pos.fY);
1555 copyScrollPositionRecursive(l, root);
1560 void registerPageSwapCallback()
1562 m_pageSwapCallbackRegistered = true;
1565 void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator,
1566 bool isPictureAfterFirstLayout, bool registerPageSwapCallback)
1568 #if USE(ACCELERATED_COMPOSITING)
1569 if (m_glWebViewState)
1570 m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator,
1571 isPictureAfterFirstLayout);
1572 m_pageSwapCallbackRegistered |= registerPageSwapCallback;
1575 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1577 LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
1578 copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
1581 SkSafeUnref(m_baseLayer);
1582 m_baseLayer = layer;
1583 CachedRoot* root = getFrameCache(DontAllowNewer);
1586 root->resetLayers();
1587 root->setRootLayer(compositeRoot());
1590 void getTextSelectionRegion(SkRegion *region)
1592 m_selectText.getSelectionRegion(getVisibleRect(), region);
1595 void replaceBaseContent(PictureSet* set)
1599 m_baseLayer->setContent(*set);
1603 void copyBaseContentToPicture(SkPicture* picture)
1607 PictureSet* content = m_baseLayer->content();
1608 m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
1609 SkPicture::kUsePathBoundsForClip_RecordingFlag));
1610 picture->endRecording();
1616 return !m_baseLayer->content()->isEmpty();
1619 void setFunctor(Functor* functor) {
1620 delete m_glDrawFunctor;
1621 m_glDrawFunctor = functor;
1624 Functor* getFunctor() {
1625 return m_glDrawFunctor;
1628 BaseLayerAndroid* getBaseLayer() {
1632 private: // local state for WebView
1633 // private to getFrameCache(); other functions operate in a different thread
1634 CachedRoot* m_frameCacheUI; // navigation data ready for use
1635 WebViewCore* m_viewImpl;
1636 int m_generation; // associate unique ID with sent kit focus to match with ui
1637 SkPicture* m_navPictureUI;
1638 SkMSec m_ringAnimationEnd;
1639 // Corresponds to the same-named boolean on the java side.
1640 bool m_heightCanMeasure;
1642 SkMSec m_lastDxTime;
1643 SelectText m_selectText;
1644 FindOnPage m_findOnPage;
1646 BaseLayerAndroid* m_baseLayer;
1647 Functor* m_glDrawFunctor;
1648 #if USE(ACCELERATED_COMPOSITING)
1649 GLWebViewState* m_glWebViewState;
1650 bool m_pageSwapCallbackRegistered;
1652 RenderSkinButton* m_buttonSkin;
1653 }; // end of WebView class
1657 * This class holds a function pointer and parameters for calling drawGL into a specific
1658 * viewport. The pointer to the Functor will be put on a framework display list to be called
1659 * when the display list is replayed.
1661 class GLDrawFunctor : Functor {
1663 GLDrawFunctor(WebView* _wvInstance,
1664 bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint),
1665 WebCore::IntRect _viewRect, float _scale, int _extras) {
1666 wvInstance = _wvInstance;
1668 viewRect = _viewRect;
1672 status_t operator()(int messageId, void* data) {
1673 if (viewRect.isEmpty()) {
1674 // NOOP operation if viewport is empty
1678 WebCore::IntRect inval;
1679 int titlebarHeight = webViewRect.height() - viewRect.height();
1681 uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
1682 WebCore::IntRect localViewRect = viewRect;
1684 localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y());
1686 WebCore::IntRect clip(info->clipLeft, info->clipTop,
1687 info->clipRight - info->clipLeft,
1688 info->clipBottom - info->clipTop);
1690 bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras);
1693 if (inval.isEmpty()) {
1694 finalInval = webViewRect;
1697 finalInval.setX(webViewRect.x() + inval.x());
1698 finalInval.setY(webViewRect.y() + titlebarHeight + inval.y());
1699 finalInval.setWidth(inval.width());
1700 finalInval.setHeight(inval.height());
1702 info->dirtyLeft = finalInval.x();
1703 info->dirtyTop = finalInval.y();
1704 info->dirtyRight = finalInval.maxX();
1705 info->dirtyBottom = finalInval.maxY();
1707 // return 1 if invalidation needed, 0 otherwise
1708 return retVal ? 1 : 0;
1710 void updateRect(WebCore::IntRect& _viewRect) {
1711 viewRect = _viewRect;
1713 void updateViewRect(WebCore::IntRect& _viewRect) {
1714 webViewRect = _viewRect;
1717 WebView* wvInstance;
1718 bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int);
1719 WebCore::IntRect viewRect;
1720 WebCore::IntRect webViewRect;
1725 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
1727 jclass rectClass = env->FindClass("android/graphics/Rect");
1728 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1729 jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
1730 env->DeleteLocalRef(rectClass);
1735 * Native JNI methods
1737 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
1739 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1740 ->m_cacheHitFrame->framePointer());
1743 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
1745 WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
1746 ->m_cacheHitNode->originalAbsoluteBounds();
1747 return createJavaRect(env, bounds.x(), bounds.y(),
1748 bounds.maxX(), bounds.maxY());
1751 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
1753 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1754 ->m_cacheHitNode->nodePointer());
1757 static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj)
1759 return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin();
1762 static void nativeClearCursor(JNIEnv *env, jobject obj)
1764 WebView* view = GET_NATIVE_VIEW(env, obj);
1765 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1766 view->clearCursor();
1769 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir)
1771 WTF::String dir = jstringToWtfString(env, drawableDir);
1772 WebView* webview = new WebView(env, obj, viewImpl, dir);
1773 // NEED THIS OR SOMETHING LIKE IT!
1777 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
1779 WebView* view = GET_NATIVE_VIEW(env, obj);
1780 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1783 const CachedFrame* frame = 0;
1784 (void) root->currentCursor(&frame);
1785 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1788 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
1790 WebView* view = GET_NATIVE_VIEW(env, obj);
1791 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1792 return root ? root->currentCursor() : 0;
1795 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
1796 const CachedFrame** frame)
1798 WebView* view = GET_NATIVE_VIEW(env, obj);
1799 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1800 return root ? root->currentCursor(frame) : 0;
1803 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
1804 const CachedFrame** frame)
1806 WebView* view = GET_NATIVE_VIEW(env, obj);
1807 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1810 const CachedNode* cursor = root->currentCursor(frame);
1811 if (cursor && cursor->wantsKeyEvents())
1813 return root->currentFocus(frame);
1816 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
1818 WebView* view = GET_NATIVE_VIEW(env, obj);
1819 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1822 const CachedNode* cursor = root->currentCursor();
1823 if (!cursor || !cursor->isTextInput())
1824 cursor = root->currentFocus();
1825 if (!cursor || !cursor->isTextInput()) return false;
1826 return root->nextTextField(cursor, 0);
1829 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
1831 WebView* view = GET_NATIVE_VIEW(env, obj);
1832 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1833 return root ? root->currentFocus() : 0;
1836 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
1837 const CachedFrame** frame)
1839 WebView* view = GET_NATIVE_VIEW(env, obj);
1840 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1841 return root ? root->currentFocus(frame) : 0;
1844 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
1846 WebView* view = GET_NATIVE_VIEW(env, obj);
1847 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1850 const CachedFrame* frame;
1851 const CachedNode* cursor = root->currentCursor(&frame);
1852 if (!cursor || !cursor->wantsKeyEvents())
1853 cursor = root->currentFocus(&frame);
1854 return cursor ? frame->textInput(cursor) : 0;
1857 static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
1859 const CachedNode* focus = getFocusNode(env, obj);
1860 if (!focus) return false;
1861 // Plugins handle shift and arrows whether or not they have focus.
1862 if (focus->isPlugin()) return true;
1863 const CachedNode* cursor = getCursorNode(env, obj);
1864 // ContentEditable nodes should only receive shift and arrows if they have
1865 // both the cursor and the focus.
1866 return cursor && cursor->nodePointer() == focus->nodePointer()
1867 && cursor->isContentEditable();
1870 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
1872 const CachedFrame* frame;
1873 const CachedNode* node = getCursorNode(env, obj, &frame);
1874 WebCore::IntRect bounds = node ? node->bounds(frame)
1875 : WebCore::IntRect(0, 0, 0, 0);
1876 return createJavaRect(env, bounds.x(), bounds.y(),
1877 bounds.maxX(), bounds.maxY());
1880 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
1882 const CachedNode* node = getCursorNode(env, obj);
1883 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1886 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
1888 WebView* view = GET_NATIVE_VIEW(env, obj);
1889 const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1890 WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
1892 root->getSimulatedMousePosition(&pos);
1893 jclass pointClass = env->FindClass("android/graphics/Point");
1894 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
1895 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
1896 env->DeleteLocalRef(pointClass);
1900 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
1903 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
1904 return WebCore::IntRect(L, T, R - L, B - T);
1907 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
1909 const CachedFrame* frame;
1910 const CachedNode* node = getCursorNode(env, obj, &frame);
1911 return node ? node->bounds(frame).intersects(
1912 jrect_to_webrect(env, visRect)) : false;
1915 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
1917 const CachedNode* node = getCursorNode(env, obj);
1918 return node ? node->isAnchor() : false;
1921 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
1923 const CachedNode* node = getCursorNode(env, obj);
1924 return node ? node->isTextInput() : false;
1927 static jobject nativeCursorText(JNIEnv *env, jobject obj)
1929 const CachedNode* node = getCursorNode(env, obj);
1932 WTF::String value = node->getExport();
1933 return wtfStringToJstring(env, value);
1936 static void nativeDebugDump(JNIEnv *env, jobject obj)
1939 WebView* view = GET_NATIVE_VIEW(env, obj);
1940 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1945 static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
1946 jint extras, jboolean split) {
1947 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1948 return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
1951 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect,
1952 jfloat scale, jint extras) {
1953 WebCore::IntRect viewRect;
1954 if (jrect == NULL) {
1955 viewRect = WebCore::IntRect();
1957 viewRect = jrect_to_webrect(env, jrect);
1959 WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
1960 GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
1961 viewRect, scale, extras);
1962 wvInstance->setFunctor((Functor*) functor);
1964 WebCore::IntRect webViewRect;
1965 if (jviewrect == NULL) {
1966 webViewRect = WebCore::IntRect();
1968 webViewRect = jrect_to_webrect(env, jviewrect);
1970 functor->updateViewRect(webViewRect);
1972 return (jint)functor;
1975 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) {
1976 WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
1977 if (wvInstance != NULL) {
1978 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
1979 if (functor != NULL) {
1980 WebCore::IntRect viewRect;
1981 if (jrect == NULL) {
1982 viewRect = WebCore::IntRect();
1984 viewRect = jrect_to_webrect(env, jrect);
1986 functor->updateRect(viewRect);
1988 WebCore::IntRect webViewRect;
1989 if (jviewrect == NULL) {
1990 webViewRect = WebCore::IntRect();
1992 webViewRect = jrect_to_webrect(env, jviewrect);
1994 functor->updateViewRect(webViewRect);
1999 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
2001 #if USE(ACCELERATED_COMPOSITING)
2002 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
2004 return root->evaluateAnimations();
2009 static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval,
2010 jboolean showVisualIndicator,
2011 jboolean isPictureAfterFirstLayout,
2012 jboolean registerPageSwapCallback)
2014 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
2015 SkRegion invalRegion;
2017 invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
2018 GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
2019 isPictureAfterFirstLayout,
2020 registerPageSwapCallback);
2023 static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jobject region)
2027 SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region);
2028 GET_NATIVE_VIEW(env, obj)->getTextSelectionRegion(nregion);
2031 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
2033 return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
2036 static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
2038 PictureSet* set = reinterpret_cast<PictureSet*>(content);
2039 GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
2042 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
2044 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
2045 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
2048 static bool nativeHasContent(JNIEnv *env, jobject obj)
2050 return GET_NATIVE_VIEW(env, obj)->hasContent();
2053 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
2055 WebView* view = GET_NATIVE_VIEW(env, obj);
2056 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2057 WTF::String uri = view->imageURI(x, y);
2058 return wtfStringToJstring(env, uri);
2061 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
2063 WebView* view = GET_NATIVE_VIEW(env, obj);
2064 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2067 const CachedFrame* frame = 0;
2068 const CachedNode* cursor = root->currentCursor(&frame);
2069 if (!cursor || !cursor->wantsKeyEvents())
2070 (void) root->currentFocus(&frame);
2071 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
2074 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
2076 const CachedInput* input = getInputCandidate(env, obj);
2077 return input && input->getType() == CachedInput::PASSWORD;
2080 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
2082 const CachedInput* input = getInputCandidate(env, obj);
2083 return input ? input->isRtlText() : false;
2086 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
2088 const CachedNode* node = getFocusCandidate(env, obj, 0);
2089 return node ? node->isTextInput() : false;
2092 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
2094 const CachedInput* input = getInputCandidate(env, obj);
2095 return input ? input->maxLength() : false;
2098 static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
2100 const CachedInput* input = getInputCandidate(env, obj);
2101 return input ? input->autoComplete() : false;
2104 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
2106 const CachedInput* input = getInputCandidate(env, obj);
2109 const WTF::String& name = input->name();
2110 return wtfStringToJstring(env, name);
2113 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
2115 const CachedFrame* frame;
2116 const CachedNode* node = getFocusCandidate(env, obj, &frame);
2117 WebCore::IntRect bounds = node ? node->bounds(frame)
2118 : WebCore::IntRect(0, 0, 0, 0);
2119 // Inset the rect by 1 unit, so that the focus candidate's border can still
2120 // be seen behind it.
2121 return createJavaRect(env, bounds.x() + 1, bounds.y() + 1,
2122 bounds.maxX() - 1, bounds.maxY() - 1);
2125 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
2127 const CachedInput* input = getInputCandidate(env, obj);
2130 // Note that the Java Rect is being used to pass four integers, rather than
2131 // being used as an actual rectangle.
2132 return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
2133 input->paddingRight(), input->paddingBottom());
2136 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
2138 const CachedNode* node = getFocusCandidate(env, obj, 0);
2139 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
2142 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
2144 const CachedNode* node = getFocusCandidate(env, obj, 0);
2147 WTF::String value = node->getExport();
2148 return wtfStringToJstring(env, value);
2151 static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
2153 const CachedInput* input = getInputCandidate(env, obj);
2154 return input ? input->lineHeight() : 0;
2157 static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
2159 const CachedInput* input = getInputCandidate(env, obj);
2160 return input ? input->textSize() : 0.f;
2163 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
2165 const CachedInput* input = getInputCandidate(env, obj);
2167 return CachedInput::NONE;
2169 if (input->isTextArea())
2170 return CachedInput::TEXT_AREA;
2172 return input->getType();
2175 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
2177 const CachedNode* node = getFocusNode(env, obj);
2178 return node ? node->isPlugin() : false;
2181 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
2183 const CachedFrame* frame;
2184 const CachedNode* node = getFocusNode(env, obj, &frame);
2185 WebCore::IntRect bounds = node ? node->bounds(frame)
2186 : WebCore::IntRect(0, 0, 0, 0);
2187 return createJavaRect(env, bounds.x(), bounds.y(),
2188 bounds.maxX(), bounds.maxY());
2191 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
2193 const CachedNode* node = getFocusNode(env, obj);
2194 return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
2197 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
2198 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2199 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2200 return view->cursorWantsKeyEvents();
2203 static void nativeHideCursor(JNIEnv *env, jobject obj)
2205 WebView* view = GET_NATIVE_VIEW(env, obj);
2206 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2210 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
2212 #ifdef ANDROID_INSTRUMENT
2213 TimeCounter::reportNow();
2217 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
2219 WebView* view = GET_NATIVE_VIEW(env, obj);
2220 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2221 WebCore::IntRect rect = jrect_to_webrect(env, jrect);
2222 view->selectBestAt(rect);
2225 static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
2227 WebView* view = GET_NATIVE_VIEW(env, obj);
2228 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2229 WebCore::IntRect rect = IntRect(x, y , 1, 1);
2230 view->selectBestAt(rect);
2231 if (view->hasCursorNode())
2232 view->showCursorUntimed();
2235 static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
2238 #if USE(ACCELERATED_COMPOSITING)
2239 LayerAndroid* layer = (LayerAndroid*) jlayer;
2240 r = layer->bounds();
2246 jclass rectClass = env->FindClass("android/graphics/Rect");
2247 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2248 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2249 irect.fRight, irect.fBottom);
2250 env->DeleteLocalRef(rectClass);
2254 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
2256 SkIRect irect = jrect_to_webrect(env, jrect);
2257 #if USE(ACCELERATED_COMPOSITING)
2258 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
2262 rect = root->subtractLayers(rect);
2266 jclass rectClass = env->FindClass("android/graphics/Rect");
2267 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2268 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2269 irect.fRight, irect.fBottom);
2270 env->DeleteLocalRef(rectClass);
2274 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
2276 WebView* view = GET_NATIVE_VIEW(env, obj);
2277 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2278 return root ? root->textGeneration() : 0;
2281 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
2282 int x, int y, int slop)
2284 return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
2287 static bool nativeMotionUp(JNIEnv *env, jobject obj,
2288 int x, int y, int slop)
2290 WebView* view = GET_NATIVE_VIEW(env, obj);
2291 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2292 return view->motionUp(x, y, slop);
2295 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
2297 return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
2300 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
2302 return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
2305 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
2306 int key, int count, bool ignoreScroll)
2308 WebView* view = GET_NATIVE_VIEW(env, obj);
2309 DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
2310 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2311 return view->moveCursor(key, count, ignoreScroll);
2314 static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
2315 bool pressed, bool invalidate)
2317 WebView* view = GET_NATIVE_VIEW(env, obj);
2318 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2319 view->nativeRecordButtons(hasFocus, pressed, invalidate);
2322 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
2324 WebView* view = GET_NATIVE_VIEW(env, obj);
2325 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2326 view->setFindIsUp(isUp);
2329 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
2331 GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
2334 static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
2336 GET_NATIVE_VIEW(env, obj)->showCursorTimed();
2339 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
2341 WebView* view = GET_NATIVE_VIEW(env, obj);
2342 LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
2343 view->setHeightCanMeasure(measure);
2346 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
2348 WebView* view = GET_NATIVE_VIEW(env, obj);
2349 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2350 jclass rectClass = env->FindClass("android/graphics/Rect");
2351 LOG_ASSERT(rectClass, "Could not find Rect class!");
2352 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2353 LOG_ASSERT(init, "Could not find constructor for Rect");
2354 WebCore::IntRect webRect;
2355 view->cursorRingBounds(&webRect);
2356 jobject rect = env->NewObject(rectClass, init, webRect.x(),
2357 webRect.y(), webRect.maxX(), webRect.maxY());
2358 env->DeleteLocalRef(rectClass);
2362 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
2363 jstring findUpper, jboolean sameAsLastSearch)
2365 // If one or the other is null, do not search.
2366 if (!(findLower && findUpper))
2368 // Obtain the characters for both the lower case string and the upper case
2369 // string representing the same word.
2370 const jchar* findLowerChars = env->GetStringChars(findLower, 0);
2371 const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
2372 // If one or the other is null, do not search.
2373 if (!(findLowerChars && findUpperChars)) {
2375 env->ReleaseStringChars(findLower, findLowerChars);
2377 env->ReleaseStringChars(findUpper, findUpperChars);
2378 checkException(env);
2381 WebView* view = GET_NATIVE_VIEW(env, obj);
2382 LOG_ASSERT(view, "view not set in nativeFindAll");
2383 CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
2385 env->ReleaseStringChars(findLower, findLowerChars);
2386 env->ReleaseStringChars(findUpper, findUpperChars);
2387 checkException(env);
2390 int length = env->GetStringLength(findLower);
2391 // If the lengths of the strings do not match, then they are not the same
2392 // word, so do not search.
2393 if (!length || env->GetStringLength(findUpper) != length) {
2394 env->ReleaseStringChars(findLower, findLowerChars);
2395 env->ReleaseStringChars(findUpper, findUpperChars);
2396 checkException(env);
2399 int width = root->documentWidth();
2400 int height = root->documentHeight();
2401 // Create a FindCanvas, which allows us to fake draw into it so we can
2402 // figure out where our search string is rendered (and how many times).
2403 FindCanvas canvas(width, height, (const UChar*) findLowerChars,
2404 (const UChar*) findUpperChars, length << 1);
2406 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
2407 canvas.setBitmapDevice(bitmap);
2409 WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
2410 // With setMatches, the WebView takes ownership of matches
2411 view->setMatches(matches, sameAsLastSearch);
2413 env->ReleaseStringChars(findLower, findLowerChars);
2414 env->ReleaseStringChars(findUpper, findUpperChars);
2415 checkException(env);
2416 return canvas.found();
2419 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
2421 WebView* view = GET_NATIVE_VIEW(env, obj);
2422 LOG_ASSERT(view, "view not set in nativeFindNext");
2423 view->findNext(forward);
2426 static int nativeFindIndex(JNIEnv *env, jobject obj)
2428 WebView* view = GET_NATIVE_VIEW(env, obj);
2429 LOG_ASSERT(view, "view not set in nativeFindIndex");
2430 return view->currentMatchIndex();
2433 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
2435 WebView* view = GET_NATIVE_VIEW(env, obj);
2436 LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
2437 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2440 const CachedNode* cachedFocusNode = root->currentFocus();
2441 if (!cachedFocusNode || !cachedFocusNode->isTextInput())
2443 WTF::String webcoreString = jstringToWtfString(env, updatedText);
2444 (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
2445 root->setTextGeneration(generation);
2446 checkException(env);
2449 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
2452 WebView* view = GET_NATIVE_VIEW(env, obj);
2453 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2456 return view->getBlockLeftEdge(x, y, scale);
2459 static void nativeDestroy(JNIEnv *env, jobject obj)
2461 WebView* view = GET_NATIVE_VIEW(env, obj);
2462 LOGD("nativeDestroy view: %p", view);
2463 LOG_ASSERT(view, "view not set in nativeDestroy");
2467 static void nativeStopGL(JNIEnv *env, jobject obj)
2469 GET_NATIVE_VIEW(env, obj)->stopGL();
2472 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
2474 WebView* view = GET_NATIVE_VIEW(env, obj);
2475 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2478 const CachedNode* current = root->currentCursor();
2479 if (!current || !current->isTextInput())
2480 current = root->currentFocus();
2481 if (!current || !current->isTextInput())
2483 const CachedFrame* frame;
2484 const CachedNode* next = root->nextTextField(current, &frame);
2487 const WebCore::IntRect& bounds = next->bounds(frame);
2488 root->rootHistory()->setMouseBounds(bounds);
2489 view->getWebViewCore()->updateCursorBounds(root, frame, next);
2490 view->showCursorUntimed();
2491 root->setCursor(const_cast<CachedFrame*>(frame),
2492 const_cast<CachedNode*>(next));
2493 view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
2494 static_cast<WebCore::Node*>(next->nodePointer()));
2495 if (!next->isInLayer())
2496 view->scrollRectOnScreen(bounds);
2497 view->getWebViewCore()->m_moveGeneration++;
2501 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
2503 WebView* view = GET_NATIVE_VIEW(env, obj);
2506 return view->moveGeneration();
2509 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
2511 GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
2514 static void nativeResetSelection(JNIEnv *env, jobject obj)
2516 return GET_NATIVE_VIEW(env, obj)->resetSelection();
2519 static jobject nativeSelectableText(JNIEnv* env, jobject obj)
2521 IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
2522 jclass pointClass = env->FindClass("android/graphics/Point");
2523 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
2524 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
2525 env->DeleteLocalRef(pointClass);
2529 static void nativeSelectAll(JNIEnv* env, jobject obj)
2531 GET_NATIVE_VIEW(env, obj)->selectAll();
2534 static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
2536 GET_NATIVE_VIEW(env, obj)->setExtendSelection();
2539 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
2541 return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
2544 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
2546 return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
2549 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
2551 GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
2554 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
2556 WebView* view = GET_NATIVE_VIEW(env, obj);
2557 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2558 String selection = view->getSelection();
2559 return wtfStringToJstring(env, selection);
2562 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
2564 return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
2567 static jint nativeSelectionX(JNIEnv *env, jobject obj)
2569 return GET_NATIVE_VIEW(env, obj)->selectionX();
2572 static jint nativeSelectionY(JNIEnv *env, jobject obj)
2574 return GET_NATIVE_VIEW(env, obj)->selectionY();
2577 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
2578 jfloat scale, jint x, jint y)
2580 GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y);
2583 static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj)
2585 GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback();
2588 static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
2590 TilesManager::instance()->getProfiler()->start();
2593 static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
2595 return TilesManager::instance()->getProfiler()->stop();
2598 static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
2600 TilesManager::instance()->getProfiler()->clear();
2603 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
2605 return TilesManager::instance()->getProfiler()->numFrames();
2608 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
2610 return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
2613 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
2615 WTF::String key = jstringToWtfString(env, jkey);
2616 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
2619 return record->left;
2623 return record->right;
2624 if (key == "bottom")
2625 return record->bottom;
2627 return record->level;
2628 if (key == "isReady")
2629 return record->isReady ? 1 : 0;
2633 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
2635 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
2636 return record->scale;
2639 #ifdef ANDROID_DUMP_DISPLAY_TREE
2640 static void dumpToFile(const char text[], void* file) {
2641 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
2642 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
2646 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
2648 WTF::String key = jstringToWtfString(env, jkey);
2649 WTF::String value = jstringToWtfString(env, jvalue);
2650 if (key == "inverted") {
2651 if (value == "true")
2652 TilesManager::instance()->setInvertedScreen(true);
2654 TilesManager::instance()->setInvertedScreen(false);
2657 if (key == "inverted_contrast") {
2658 float contrast = value.toFloat();
2659 TilesManager::instance()->setInvertedScreenContrast(contrast);
2662 if (key == "enable_cpu_upload_path") {
2663 TilesManager::instance()->transferQueue()->setTextureUploadType(
2664 value == "true" ? CpuUpload : GpuUpload);
2670 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key)
2675 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
2677 if (TilesManager::hardwareAccelerationEnabled()) {
2678 bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN);
2679 TilesManager::instance()->deallocateTextures(freeAllTextures);
2683 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
2685 #ifdef ANDROID_DUMP_DISPLAY_TREE
2686 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2687 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2689 if (view && view->getWebViewCore()) {
2690 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
2692 SkFormatDumper dumper(dumpToFile, file);
2695 const char* str = env->GetStringUTFChars(jurl, 0);
2696 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
2697 dumpToFile(str, file);
2698 env->ReleaseStringUTFChars(jurl, str);
2700 // now dump the display tree
2701 SkDumpCanvas canvas(&dumper);
2702 // this will playback the picture into the canvas, which will
2703 // spew its contents to the dumper
2704 view->draw(&canvas, 0, 0, false);
2705 // we're done with the file now
2706 fwrite("\n", 1, 1, file);
2709 #if USE(ACCELERATED_COMPOSITING)
2710 const LayerAndroid* rootLayer = view->compositeRoot();
2712 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
2714 rootLayer->dumpLayers(file, 0);
2723 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
2724 jobject rect, jobject bounds)
2726 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2727 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2728 SkIRect nativeRect, nativeBounds;
2729 int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
2731 GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
2733 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
2737 static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
2740 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
2741 WebView* view = GET_NATIVE_VIEW(env, obj);
2742 LayerAndroid* root = view->compositeRoot();
2745 LayerAndroid* layer = root->findById(layerId);
2746 if (!layer || !layer->contentIsScrollable())
2748 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
2753 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
2755 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2756 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2757 view->setIsScrolling(isScrolling);
2760 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
2762 BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
2765 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
2767 WebView* view = GET_NATIVE_VIEW(env, obj);
2768 BaseLayerAndroid* baseLayer = view->getBaseLayer();
2770 WebCore::Color color = baseLayer->getBackgroundColor();
2771 if (color.isValid())
2772 return SkColorSetARGB(color.alpha(), color.red(),
2773 color.green(), color.blue());
2775 return SK_ColorWHITE;
2781 static JNINativeMethod gJavaWebViewMethods[] = {
2782 { "nativeCacheHitFramePointer", "()I",
2783 (void*) nativeCacheHitFramePointer },
2784 { "nativeCacheHitIsPlugin", "()Z",
2785 (void*) nativeCacheHitIsPlugin },
2786 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
2787 (void*) nativeCacheHitNodeBounds },
2788 { "nativeCacheHitNodePointer", "()I",
2789 (void*) nativeCacheHitNodePointer },
2790 { "nativeClearCursor", "()V",
2791 (void*) nativeClearCursor },
2792 { "nativeCreate", "(ILjava/lang/String;)V",
2793 (void*) nativeCreate },
2794 { "nativeCursorFramePointer", "()I",
2795 (void*) nativeCursorFramePointer },
2796 { "nativePageShouldHandleShiftAndArrows", "()Z",
2797 (void*) nativePageShouldHandleShiftAndArrows },
2798 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
2799 (void*) nativeCursorNodeBounds },
2800 { "nativeCursorNodePointer", "()I",
2801 (void*) nativeCursorNodePointer },
2802 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
2803 (void*) nativeCursorIntersects },
2804 { "nativeCursorIsAnchor", "()Z",
2805 (void*) nativeCursorIsAnchor },
2806 { "nativeCursorIsTextInput", "()Z",
2807 (void*) nativeCursorIsTextInput },
2808 { "nativeCursorPosition", "()Landroid/graphics/Point;",
2809 (void*) nativeCursorPosition },
2810 { "nativeCursorText", "()Ljava/lang/String;",
2811 (void*) nativeCursorText },
2812 { "nativeCursorWantsKeyEvents", "()Z",
2813 (void*)nativeCursorWantsKeyEvents },
2814 { "nativeDebugDump", "()V",
2815 (void*) nativeDebugDump },
2816 { "nativeDestroy", "()V",
2817 (void*) nativeDestroy },
2818 { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
2819 (void*) nativeDraw },
2820 { "nativeGetDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;FI)I",
2821 (void*) nativeGetDrawGLFunction },
2822 { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V",
2823 (void*) nativeUpdateDrawGLFunction },
2824 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
2825 (void*) nativeDumpDisplayTree },
2826 { "nativeEvaluateLayersAnimations", "()Z",
2827 (void*) nativeEvaluateLayersAnimations },
2828 { "nativeExtendSelection", "(II)V",
2829 (void*) nativeExtendSelection },
2830 { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
2831 (void*) nativeFindAll },
2832 { "nativeFindNext", "(Z)V",
2833 (void*) nativeFindNext },
2834 { "nativeFindIndex", "()I",
2835 (void*) nativeFindIndex},
2836 { "nativeFocusCandidateFramePointer", "()I",
2837 (void*) nativeFocusCandidateFramePointer },
2838 { "nativeFocusCandidateHasNextTextfield", "()Z",
2839 (void*) focusCandidateHasNextTextfield },
2840 { "nativeFocusCandidateIsPassword", "()Z",
2841 (void*) nativeFocusCandidateIsPassword },
2842 { "nativeFocusCandidateIsRtlText", "()Z",
2843 (void*) nativeFocusCandidateIsRtlText },
2844 { "nativeFocusCandidateIsTextInput", "()Z",
2845 (void*) nativeFocusCandidateIsTextInput },
2846 { "nativeFocusCandidateLineHeight", "()I",
2847 (void*) nativeFocusCandidateLineHeight },
2848 { "nativeFocusCandidateMaxLength", "()I",
2849 (void*) nativeFocusCandidateMaxLength },
2850 { "nativeFocusCandidateIsAutoComplete", "()Z",
2851 (void*) nativeFocusCandidateIsAutoComplete },
2852 { "nativeFocusCandidateName", "()Ljava/lang/String;",
2853 (void*) nativeFocusCandidateName },
2854 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
2855 (void*) nativeFocusCandidateNodeBounds },
2856 { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
2857 (void*) nativeFocusCandidatePaddingRect },
2858 { "nativeFocusCandidatePointer", "()I",
2859 (void*) nativeFocusCandidatePointer },
2860 { "nativeFocusCandidateText", "()Ljava/lang/String;",
2861 (void*) nativeFocusCandidateText },
2862 { "nativeFocusCandidateTextSize", "()F",
2863 (void*) nativeFocusCandidateTextSize },
2864 { "nativeFocusCandidateType", "()I",
2865 (void*) nativeFocusCandidateType },
2866 { "nativeFocusIsPlugin", "()Z",
2867 (void*) nativeFocusIsPlugin },
2868 { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
2869 (void*) nativeFocusNodeBounds },
2870 { "nativeFocusNodePointer", "()I",
2871 (void*) nativeFocusNodePointer },
2872 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
2873 (void*) nativeGetCursorRingBounds },
2874 { "nativeGetSelection", "()Ljava/lang/String;",
2875 (void*) nativeGetSelection },
2876 { "nativeHasCursorNode", "()Z",
2877 (void*) nativeHasCursorNode },
2878 { "nativeHasFocusNode", "()Z",
2879 (void*) nativeHasFocusNode },
2880 { "nativeHideCursor", "()V",
2881 (void*) nativeHideCursor },
2882 { "nativeHitSelection", "(II)Z",
2883 (void*) nativeHitSelection },
2884 { "nativeImageURI", "(II)Ljava/lang/String;",
2885 (void*) nativeImageURI },
2886 { "nativeInstrumentReport", "()V",
2887 (void*) nativeInstrumentReport },
2888 { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
2889 (void*) nativeLayerBounds },
2890 { "nativeMotionUp", "(III)Z",
2891 (void*) nativeMotionUp },
2892 { "nativeMoveCursor", "(IIZ)Z",
2893 (void*) nativeMoveCursor },
2894 { "nativeMoveCursorToNextTextInput", "()Z",
2895 (void*) nativeMoveCursorToNextTextInput },
2896 { "nativeMoveGeneration", "()I",
2897 (void*) nativeMoveGeneration },
2898 { "nativeMoveSelection", "(II)V",
2899 (void*) nativeMoveSelection },
2900 { "nativePointInNavCache", "(III)Z",
2901 (void*) nativePointInNavCache },
2902 { "nativeRecordButtons", "(ZZZ)V",
2903 (void*) nativeRecordButtons },
2904 { "nativeResetSelection", "()V",
2905 (void*) nativeResetSelection },
2906 { "nativeSelectableText", "()Landroid/graphics/Point;",
2907 (void*) nativeSelectableText },
2908 { "nativeSelectAll", "()V",
2909 (void*) nativeSelectAll },
2910 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
2911 (void*) nativeSelectBestAt },
2912 { "nativeSelectAt", "(II)V",
2913 (void*) nativeSelectAt },
2914 { "nativeSelectionX", "()I",
2915 (void*) nativeSelectionX },
2916 { "nativeSelectionY", "()I",
2917 (void*) nativeSelectionY },
2918 { "nativeSetExtendSelection", "()V",
2919 (void*) nativeSetExtendSelection },
2920 { "nativeSetFindIsEmpty", "()V",
2921 (void*) nativeSetFindIsEmpty },
2922 { "nativeSetFindIsUp", "(Z)V",
2923 (void*) nativeSetFindIsUp },
2924 { "nativeSetHeightCanMeasure", "(Z)V",
2925 (void*) nativeSetHeightCanMeasure },
2926 { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V",
2927 (void*) nativeSetBaseLayer },
2928 { "nativeGetTextSelectionRegion", "(Landroid/graphics/Region;)V",
2929 (void*) nativeGetTextSelectionRegion },
2930 { "nativeGetBaseLayer", "()I",
2931 (void*) nativeGetBaseLayer },
2932 { "nativeReplaceBaseContent", "(I)V",
2933 (void*) nativeReplaceBaseContent },
2934 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
2935 (void*) nativeCopyBaseContentToPicture },
2936 { "nativeHasContent", "()Z",
2937 (void*) nativeHasContent },
2938 { "nativeSetSelectionPointer", "(ZFII)V",
2939 (void*) nativeSetSelectionPointer },
2940 { "nativeShowCursorTimed", "()V",
2941 (void*) nativeShowCursorTimed },
2942 { "nativeRegisterPageSwapCallback", "()V",
2943 (void*) nativeRegisterPageSwapCallback },
2944 { "nativeTileProfilingStart", "()V",
2945 (void*) nativeTileProfilingStart },
2946 { "nativeTileProfilingStop", "()F",
2947 (void*) nativeTileProfilingStop },
2948 { "nativeTileProfilingClear", "()V",
2949 (void*) nativeTileProfilingClear },
2950 { "nativeTileProfilingNumFrames", "()I",
2951 (void*) nativeTileProfilingNumFrames },
2952 { "nativeTileProfilingNumTilesInFrame", "(I)I",
2953 (void*) nativeTileProfilingNumTilesInFrame },
2954 { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
2955 (void*) nativeTileProfilingGetInt },
2956 { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
2957 (void*) nativeTileProfilingGetFloat },
2958 { "nativeStartSelection", "(II)Z",
2959 (void*) nativeStartSelection },
2960 { "nativeStopGL", "()V",
2961 (void*) nativeStopGL },
2962 { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
2963 (void*) nativeSubtractLayers },
2964 { "nativeTextGeneration", "()I",
2965 (void*) nativeTextGeneration },
2966 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
2967 (void*) nativeUpdateCachedTextfield },
2968 { "nativeWordSelection", "(II)Z",
2969 (void*) nativeWordSelection },
2970 { "nativeGetBlockLeftEdge", "(IIF)I",
2971 (void*) nativeGetBlockLeftEdge },
2972 { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
2973 (void*) nativeScrollableLayer },
2974 { "nativeScrollLayer", "(III)Z",
2975 (void*) nativeScrollLayer },
2976 { "nativeSetIsScrolling", "(Z)V",
2977 (void*) nativeSetIsScrolling },
2978 { "nativeUseHardwareAccelSkia", "(Z)V",
2979 (void*) nativeUseHardwareAccelSkia },
2980 { "nativeGetBackgroundColor", "()I",
2981 (void*) nativeGetBackgroundColor },
2982 { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
2983 (void*) nativeSetProperty },
2984 { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
2985 (void*) nativeGetProperty },
2986 { "nativeOnTrimMemory", "(I)V",
2987 (void*) nativeOnTrimMemory },
2990 int registerWebView(JNIEnv* env)
2992 jclass clazz = env->FindClass("android/webkit/WebView");
2993 LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
2994 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
2995 LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
2996 env->DeleteLocalRef(clazz);
2998 return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
3001 } // namespace android