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
89 static jfieldID gWebViewField;
91 //-------------------------------------
93 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
95 jmethodID m = env->GetMethodID(clazz, name, signature);
96 LOG_ASSERT(m, "Could not find method %s", name);
100 //-------------------------------------
101 // This class provides JNI for making calls into native code from the UI side
102 // of the multi-threaded WebView.
106 enum FrameCachePermission {
111 enum DrawExtras { // keep this in sync with WebView.java
114 DrawExtrasSelection = 2,
115 DrawExtrasCursorRing = 3
120 jmethodID m_calcOurContentVisibleRectF;
121 jmethodID m_overrideLoading;
122 jmethodID m_scrollBy;
123 jmethodID m_sendMoveFocus;
124 jmethodID m_sendMoveMouse;
125 jmethodID m_sendMoveMouseIfLatest;
126 jmethodID m_sendMotionUp;
127 jmethodID m_domChangedFocus;
128 jmethodID m_getScaledMaxXScroll;
129 jmethodID m_getScaledMaxYScroll;
130 jmethodID m_getVisibleRect;
131 jmethodID m_rebuildWebTextView;
132 jmethodID m_viewInvalidate;
133 jmethodID m_viewInvalidateRect;
134 jmethodID m_postInvalidateDelayed;
135 jmethodID m_pageSwapCallback;
136 jmethodID m_inFullScreenMode;
139 jmethodID m_rectWidth;
140 jmethodID m_rectHeight;
141 jfieldID m_rectFLeft;
143 jmethodID m_rectFWidth;
144 jmethodID m_rectFHeight;
145 AutoJObject object(JNIEnv* env) {
146 return getRealObject(env, m_obj);
150 WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir) :
151 m_ring((WebViewCore*) viewImpl)
153 jclass clazz = env->FindClass("android/webkit/WebView");
154 // m_javaGlue = new JavaGlue;
155 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
156 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
157 m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
158 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
159 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
160 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
161 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V");
162 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
163 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
164 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
165 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
166 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
167 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
168 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
169 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
170 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
171 "viewInvalidateDelayed", "(JIIII)V");
172 m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "()V");
173 m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
174 env->DeleteLocalRef(clazz);
176 jclass rectClass = env->FindClass("android/graphics/Rect");
177 LOG_ASSERT(rectClass, "Could not find Rect class");
178 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
179 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
180 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
181 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
182 env->DeleteLocalRef(rectClass);
184 jclass rectClassF = env->FindClass("android/graphics/RectF");
185 LOG_ASSERT(rectClassF, "Could not find RectF class");
186 m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F");
187 m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F");
188 m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F");
189 m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F");
190 env->DeleteLocalRef(rectClassF);
192 env->SetIntField(javaWebView, gWebViewField, (jint)this);
193 m_viewImpl = (WebViewCore*) viewImpl;
197 m_heightCanMeasure = false;
200 m_ringAnimationEnd = 0;
203 m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir);
204 #if USE(ACCELERATED_COMPOSITING)
205 m_glWebViewState = 0;
206 m_pageSwapCallbackRegistered = false;
212 if (m_javaGlue.m_obj)
214 JNIEnv* env = JSC::Bindings::getJNIEnv();
215 env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
216 m_javaGlue.m_obj = 0;
218 #if USE(ACCELERATED_COMPOSITING)
219 // We must remove the m_glWebViewState prior to deleting m_baseLayer. If we
220 // do not remove it here, we risk having BaseTiles trying to paint using a
221 // deallocated base layer.
224 delete m_frameCacheUI;
225 delete m_navPictureUI;
226 SkSafeUnref(m_baseLayer);
227 delete m_glDrawFunctor;
233 #if USE(ACCELERATED_COMPOSITING)
234 delete m_glWebViewState;
235 m_glWebViewState = 0;
239 WebViewCore* getWebViewCore() const {
243 // removes the cursor altogether (e.g., when going to a new page)
246 CachedRoot* root = getFrameCache(AllowNewer);
250 m_viewImpl->m_hasCursorBounds = false;
255 // leaves the cursor where it is, but suppresses drawing it
258 CachedRoot* root = getFrameCache(AllowNewer);
265 void hideCursor(CachedRoot* root)
267 DBG_NAV_LOG("inner");
268 m_viewImpl->m_hasCursorBounds = false;
276 CachedRoot* root = getFrameCache(DontAllowNewer);
278 root->mDebug.print();
282 // Traverse our stored array of buttons that are in our picture, and update
283 // their subpictures according to their current state.
284 // Called from the UI thread. This is the one place in the UI thread where we
285 // access the buttons stored in the WebCore thread.
286 // hasFocus keeps track of whether the WebView has focus && windowFocus.
287 // If not, we do not want to draw the button in a selected or pressed state
288 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
290 bool cursorIsOnButton = false;
291 const CachedFrame* cachedFrame;
292 const CachedNode* cachedCursor = 0;
293 // Lock the mutex, since we now share with the WebCore thread.
294 m_viewImpl->gButtonMutex.lock();
295 if (m_viewImpl->m_buttons.size() && m_buttonSkin) {
296 // FIXME: In a future change, we should keep track of whether the selection
297 // has changed to short circuit (note that we would still need to update
298 // if we received new buttons from the WebCore thread).
299 WebCore::Node* cursor = 0;
300 CachedRoot* root = getFrameCache(DontAllowNewer);
302 cachedCursor = root->currentCursor(&cachedFrame);
304 cursor = (WebCore::Node*) cachedCursor->nodePointer();
307 // Traverse the array, and update each button, depending on whether it
309 Container* end = m_viewImpl->m_buttons.end();
310 for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
311 RenderSkinAndroid::State state = RenderSkinAndroid::kNormal;
312 if (ptr->matches(cursor)) {
313 cursorIsOnButton = true;
314 // If the WebView is out of focus/window focus, set the state to
315 // normal, but still keep track of the fact that the selected is a
318 if (pressed || m_ring.m_isPressed)
319 state = RenderSkinAndroid::kPressed;
320 else if (SkTime::GetMSecs() < m_ringAnimationEnd)
321 state = RenderSkinAndroid::kFocused;
324 ptr->updateFocusState(state, m_buttonSkin);
327 m_viewImpl->gButtonMutex.unlock();
328 if (invalidate && cachedCursor && cursorIsOnButton) {
329 const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
330 viewInvalidateRect(b.x(), b.y(), b.maxX(), b.maxY());
334 void scrollToCurrentMatch()
336 if (!m_findOnPage.currentMatchIsInLayer()) {
337 scrollRectOnScreen(m_findOnPage.currentMatchBounds());
341 SkRect matchBounds = m_findOnPage.currentMatchBounds();
342 LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer();
343 Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId());
344 ASSERT(layerContainingMatch);
346 // If the match is in a fixed position layer, there's nothing to do.
347 if (layerContainingMatch->shouldInheritFromRootTransform())
350 // If the match is in a scrollable layer or a descendant of such a layer,
351 // there may be a range of of scroll configurations that will make the
352 // current match visible. Our approach is the simplest possible. Starting at
353 // the layer in which the match is found, we move up the layer tree,
354 // scrolling any scrollable layers as little as possible to make sure that
355 // the current match is in view. This approach has the disadvantage that we
356 // may end up scrolling a larger number of elements than is necessary, which
357 // may be visually jarring. However, minimising the number of layers
358 // scrolled would complicate the code significantly.
360 bool didScrollLayer = false;
361 for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) {
362 ASSERT(layer->getParent() || layer == rootLayer);
364 if (layer->contentIsScrollable()) {
365 // Convert the match location to layer's local space and scroll it.
366 // Repeatedly calling Layer::localToAncestor() is inefficient as
367 // each call repeats part of the calculation. It would be more
368 // efficient to maintain the transform here and update it on each
369 // iteration, but that would mean duplicating logic from
370 // Layer::localToAncestor() and would complicate things.
372 layerContainingMatch->localToAncestor(layer, &transform);
373 SkRect transformedMatchBounds;
374 transform.mapRect(&transformedMatchBounds, matchBounds);
375 SkIRect roundedTransformedMatchBounds;
376 transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
377 // Only ScrollableLayerAndroid returns true for contentIsScrollable().
378 didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds);
381 // Invalidate, as the call below to scroll the main page may be a no-op.
385 // Convert matchBounds to the global space so we can scroll the main page.
387 layerContainingMatch->localToGlobal(&transform);
388 SkRect transformedMatchBounds;
389 transform.mapRect(&transformedMatchBounds, matchBounds);
390 SkIRect roundedTransformedMatchBounds;
391 transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
392 scrollRectOnScreen(roundedTransformedMatchBounds);
395 void scrollRectOnScreen(const IntRect& rect)
400 calcOurContentVisibleRect(&visible);
403 int right = rect.maxX();
404 if (left < visible.fLeft) {
405 dx = left - visible.fLeft;
406 // Only scroll right if the entire width can fit on screen.
407 } else if (right > visible.fRight && right - left < visible.width()) {
408 dx = right - visible.fRight;
412 int bottom = rect.maxY();
413 if (top < visible.fTop) {
414 dy = top - visible.fTop;
415 // Only scroll down if the entire height can fit on screen
416 } else if (bottom > visible.fBottom && bottom - top < visible.height()) {
417 dy = bottom - visible.fBottom;
419 if ((dx|dy) == 0 || !scrollBy(dx, dy))
424 void calcOurContentVisibleRect(SkRect* r)
426 JNIEnv* env = JSC::Bindings::getJNIEnv();
427 AutoJObject javaObject = m_javaGlue.object(env);
428 if (!javaObject.get())
430 jclass rectClass = env->FindClass("android/graphics/RectF");
431 jmethodID init = env->GetMethodID(rectClass, "<init>", "(FFFF)V");
432 jobject jRect = env->NewObject(rectClass, init, 0, 0, 0, 0);
433 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_calcOurContentVisibleRectF, jRect);
434 r->fLeft = env->GetFloatField(jRect, m_javaGlue.m_rectFLeft);
435 r->fTop = env->GetFloatField(jRect, m_javaGlue.m_rectFTop);
436 r->fRight = r->fLeft + env->CallFloatMethod(jRect, m_javaGlue.m_rectFWidth);
437 r->fBottom = r->fTop + env->CallFloatMethod(jRect, m_javaGlue.m_rectFHeight);
438 env->DeleteLocalRef(rectClass);
439 env->DeleteLocalRef(jRect);
443 void resetCursorRing()
445 m_ringAnimationEnd = 0;
446 m_viewImpl->m_hasCursorBounds = false;
449 bool drawCursorPreamble(CachedRoot* root)
451 if (!root) return false;
452 const CachedFrame* frame;
453 const CachedNode* node = root->currentCursor(&frame);
455 DBG_NAV_LOGV("%s", "!node");
459 m_ring.setIsButton(node);
460 if (node->isHidden()) {
461 DBG_NAV_LOG("node->isHidden()");
462 m_viewImpl->m_hasCursorBounds = false;
465 #if USE(ACCELERATED_COMPOSITING)
466 if (node->isInLayer() && root->rootLayer()) {
467 LayerAndroid* layer = root->rootLayer();
469 calcOurContentVisibleRect(&visible);
470 layer->updateFixedLayersPositions(visible);
471 layer->updatePositions();
474 setVisibleRect(root);
475 m_ring.m_root = root;
476 m_ring.m_frame = frame;
477 m_ring.m_node = node;
478 SkMSec time = SkTime::GetMSecs();
479 m_ring.m_isPressed = time < m_ringAnimationEnd
480 && m_ringAnimationEnd != UINT_MAX;
484 void drawCursorPostamble()
486 if (m_ringAnimationEnd == UINT_MAX)
488 SkMSec time = SkTime::GetMSecs();
489 if (time < m_ringAnimationEnd) {
490 // views assume that inval bounds coordinates are non-negative
491 WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
492 invalBounds.intersect(m_ring.m_absBounds);
493 postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
495 hideCursor(const_cast<CachedRoot*>(m_ring.m_root));
499 bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::IntRect& webViewRect,
500 int titleBarHeight, WebCore::IntRect& clip, float scale, int extras)
502 #if USE(ACCELERATED_COMPOSITING)
503 if (!m_baseLayer || inFullScreenMode())
506 if (!m_glWebViewState) {
507 m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex);
508 if (m_baseLayer->content()) {
511 rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
512 region.setRect(rect);
513 m_glWebViewState->setBaseLayer(m_baseLayer, region, false, true);
517 CachedRoot* root = getFrameCache(AllowNewer);
519 DBG_NAV_LOG("!root");
520 if (extras == DrawExtrasCursorRing)
523 DrawExtra* extra = 0;
526 extra = &m_findOnPage;
528 case DrawExtrasSelection:
529 extra = &m_selectText;
531 case DrawExtrasCursorRing:
532 if (drawCursorPreamble(root) && m_ring.setup()) {
533 if (!m_ring.m_isButton)
535 drawCursorPostamble();
542 unsigned int pic = m_glWebViewState->currentPictureCounter();
545 IntRect rect(0, 0, 0, 0);
546 bool allowSame = false;
547 m_glWebViewState->resetRings();
549 if (extra == &m_ring) {
550 WTF::Vector<IntRect> rings;
551 if (root == m_ring.m_frame)
552 rings = m_ring.rings();
554 // TODO: Fix the navcache to work with layers correctly
555 // In the meantime, this works around the bug. However, the rings
556 // it produces are not as nice for some reason, thus we use
557 // m_ring.rings() above for the base layer instead of the below
558 for (size_t i = 0; i < m_ring.m_node->rings().size(); i++) {
559 IntRect rect = m_ring.m_node->rings().at(i);
560 rect = m_ring.m_frame->adjustBounds(m_ring.m_node, rect);
565 m_glWebViewState->setRings(rings, m_ring.m_isPressed);
568 LayerAndroid mainPicture(m_navPictureUI);
569 PictureSet* content = m_baseLayer->content();
570 SkCanvas* canvas = picture.beginRecording(content->width(),
572 extra->draw(canvas, &mainPicture, &rect);
573 picture.endRecording();
575 } else if (root && extras == DrawExtrasCursorRing && m_ring.m_isButton) {
576 const CachedFrame* cachedFrame;
577 const CachedNode* cachedCursor = root->currentCursor(&cachedFrame);
579 rect = cachedCursor->bounds(cachedFrame);
583 m_glWebViewState->setExtra(m_baseLayer, picture, rect, allowSame);
585 LayerAndroid* compositeLayer = compositeRoot();
587 compositeLayer->setExtra(extra);
590 calcOurContentVisibleRect(&visibleRect);
591 // Make sure we have valid coordinates. We might not have valid coords
592 // if the zoom manager is still initializing. We will be redrawn
593 // once the correct scale is set
594 if (!visibleRect.hasValidCoordinates())
596 bool pagesSwapped = false;
597 bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect,
598 webViewRect, titleBarHeight, clip, scale,
600 if (m_pageSwapCallbackRegistered && pagesSwapped) {
601 m_pageSwapCallbackRegistered = false;
602 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
603 JNIEnv* env = JSC::Bindings::getJNIEnv();
604 AutoJObject javaObject = m_javaGlue.object(env);
605 if (javaObject.get()) {
606 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback);
610 if (ret || m_glWebViewState->currentPictureCounter() != pic)
616 PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
620 canvas->drawColor(bgColor);
624 // draw the content of the base layer first
625 PictureSet* content = m_baseLayer->content();
626 int sc = canvas->save(SkCanvas::kClip_SaveFlag);
627 canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
628 content->height()), SkRegion::kDifference_Op);
629 canvas->drawColor(bgColor);
630 canvas->restoreToCount(sc);
631 if (content->draw(canvas))
632 ret = split ? new PictureSet(*content) : 0;
634 CachedRoot* root = getFrameCache(AllowNewer);
636 DBG_NAV_LOG("!root");
637 if (extras == DrawExtrasCursorRing)
640 LayerAndroid mainPicture(m_navPictureUI);
641 DrawExtra* extra = 0;
644 extra = &m_findOnPage;
646 case DrawExtrasSelection:
647 extra = &m_selectText;
649 case DrawExtrasCursorRing:
650 if (drawCursorPreamble(root) && m_ring.setup()) {
651 if (!m_ring.m_isButton)
653 drawCursorPostamble();
660 IntRect dummy; // inval area, unused for now
661 extra->draw(canvas, &mainPicture, &dummy);
663 #if USE(ACCELERATED_COMPOSITING)
664 LayerAndroid* compositeLayer = compositeRoot();
667 compositeLayer->setExtra(extra);
669 calcOurContentVisibleRect(&visible);
670 // call this to be sure we've adjusted for any scrolling or animations
671 // before we actually draw
672 compositeLayer->updateFixedLayersPositions(visible);
673 compositeLayer->updatePositions();
674 // We have to set the canvas' matrix on the base layer
675 // (to have fixed layers work as intended)
676 SkAutoCanvasRestore restore(canvas, true);
677 m_baseLayer->setMatrix(canvas->getTotalMatrix());
678 canvas->resetMatrix();
679 m_baseLayer->draw(canvas);
685 bool cursorIsTextInput(FrameCachePermission allowNewer)
687 CachedRoot* root = getFrameCache(allowNewer);
689 DBG_NAV_LOG("!root");
692 const CachedNode* cursor = root->currentCursor();
694 DBG_NAV_LOG("!cursor");
697 DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
698 return cursor->isTextInput();
701 void cursorRingBounds(WebCore::IntRect* bounds)
703 DBG_NAV_LOGD("%s", "");
704 CachedRoot* root = getFrameCache(DontAllowNewer);
706 const CachedFrame* cachedFrame;
707 const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
709 *bounds = cachedNode->cursorRingBounds(cachedFrame);
710 DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
711 bounds->width(), bounds->height());
715 *bounds = WebCore::IntRect(0, 0, 0, 0);
720 m_viewImpl->gCursorBoundsMutex.lock();
721 bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
722 IntRect bounds = m_viewImpl->m_cursorBounds;
723 m_viewImpl->gCursorBoundsMutex.unlock();
724 if (!hasCursorBounds)
727 const CachedFrame* frame;
728 const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true);
731 // require that node have approximately the same bounds (+/- 4) and the same
733 IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
734 bounds.y() + (bounds.height() >> 1));
735 IntRect newBounds = node->bounds(frame);
736 IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
737 newBounds.y() + (newBounds.height() >> 1));
738 DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
739 " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
740 oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
741 bounds.x(), bounds.y(), bounds.width(), bounds.height(),
742 newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
743 if (abs(oldCenter.x() - newCenter.x()) > 2)
745 if (abs(oldCenter.y() - newCenter.y()) > 2)
747 if (abs(bounds.x() - newBounds.x()) > 4)
749 if (abs(bounds.y() - newBounds.y()) > 4)
751 if (abs(bounds.maxX() - newBounds.maxX()) > 4)
753 if (abs(bounds.maxY() - newBounds.maxY()) > 4)
755 DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
756 node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
758 m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
759 const_cast<CachedNode*>(node));
762 CachedRoot* getFrameCache(FrameCachePermission allowNewer)
764 if (!m_viewImpl->m_updatedFrameCache) {
765 DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
766 return m_frameCacheUI;
768 if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
769 DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
770 " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
771 return m_frameCacheUI;
773 DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
774 const CachedFrame* oldCursorFrame;
775 const CachedNode* oldCursorNode = m_frameCacheUI ?
776 m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
777 #if USE(ACCELERATED_COMPOSITING)
779 if (oldCursorNode && oldCursorNode->isInLayer()) {
780 const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode)
781 ->layer(m_frameCacheUI->rootLayer());
783 layerId = cursorLayer->uniqueId();
786 // get id from old layer and use to find new layer
787 bool oldFocusIsTextInput = false;
788 void* oldFocusNodePointer = 0;
789 if (m_frameCacheUI) {
790 const CachedNode* oldFocus = m_frameCacheUI->currentFocus();
792 oldFocusIsTextInput = oldFocus->isTextInput();
793 oldFocusNodePointer = oldFocus->nodePointer();
796 m_viewImpl->gFrameCacheMutex.lock();
797 delete m_frameCacheUI;
798 SkSafeUnref(m_navPictureUI);
799 m_viewImpl->m_updatedFrameCache = false;
800 m_frameCacheUI = m_viewImpl->m_frameCacheKit;
801 m_navPictureUI = m_viewImpl->m_navPictureKit;
802 m_viewImpl->m_frameCacheKit = 0;
803 m_viewImpl->m_navPictureKit = 0;
804 m_viewImpl->gFrameCacheMutex.unlock();
806 m_frameCacheUI->setRootLayer(compositeRoot());
807 #if USE(ACCELERATED_COMPOSITING)
810 calcOurContentVisibleRect(&visible);
811 LayerAndroid* layer = const_cast<LayerAndroid*>(
812 m_frameCacheUI->rootLayer());
814 layer->updateFixedLayersPositions(visible);
815 layer->updatePositions();
820 if (oldFocusIsTextInput) {
821 const CachedNode* newFocus = m_frameCacheUI->currentFocus();
822 if (newFocus && oldFocusNodePointer != newFocus->nodePointer()
823 && newFocus->isTextInput()
824 && newFocus != m_frameCacheUI->currentCursor()) {
825 // The focus has changed. We may need to update things.
826 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
827 JNIEnv* env = JSC::Bindings::getJNIEnv();
828 AutoJObject javaObject = m_javaGlue.object(env);
829 if (javaObject.get()) {
830 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_domChangedFocus);
835 if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
836 viewInvalidate(); // redraw in case cursor ring is still visible
837 return m_frameCacheUI;
840 int getScaledMaxXScroll()
842 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
843 JNIEnv* env = JSC::Bindings::getJNIEnv();
844 AutoJObject javaObject = m_javaGlue.object(env);
845 if (!javaObject.get())
847 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxXScroll);
852 int getScaledMaxYScroll()
854 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
855 JNIEnv* env = JSC::Bindings::getJNIEnv();
856 AutoJObject javaObject = m_javaGlue.object(env);
857 if (!javaObject.get())
859 int result = env->CallIntMethod(javaObject.get(), m_javaGlue.m_getScaledMaxYScroll);
864 IntRect getVisibleRect()
867 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
868 JNIEnv* env = JSC::Bindings::getJNIEnv();
869 AutoJObject javaObject = m_javaGlue.object(env);
870 if (!javaObject.get())
872 jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect);
874 rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
876 rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
878 rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
880 rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
882 env->DeleteLocalRef(jRect);
887 static CachedFrame::Direction KeyToDirection(int32_t keyCode)
890 case AKEYCODE_DPAD_RIGHT:
891 DBG_NAV_LOGD("keyCode=%s", "right");
892 return CachedFrame::RIGHT;
893 case AKEYCODE_DPAD_LEFT:
894 DBG_NAV_LOGD("keyCode=%s", "left");
895 return CachedFrame::LEFT;
896 case AKEYCODE_DPAD_DOWN:
897 DBG_NAV_LOGD("keyCode=%s", "down");
898 return CachedFrame::DOWN;
899 case AKEYCODE_DPAD_UP:
900 DBG_NAV_LOGD("keyCode=%s", "up");
901 return CachedFrame::UP;
903 DBG_NAV_LOGD("bad key %d sent", keyCode);
904 return CachedFrame::UNINITIALIZED;
908 WTF::String imageURI(int x, int y)
910 const CachedRoot* root = getFrameCache(DontAllowNewer);
911 return root ? root->imageURI(x, y) : WTF::String();
914 bool cursorWantsKeyEvents()
916 const CachedRoot* root = getFrameCache(DontAllowNewer);
918 const CachedNode* focus = root->currentCursor();
920 return focus->wantsKeyEvents();
926 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
927 bool moveCursor(int keyCode, int count, bool ignoreScroll)
929 CachedRoot* root = getFrameCache(AllowNewer);
931 DBG_NAV_LOG("!root");
935 m_viewImpl->m_moveGeneration++;
936 CachedFrame::Direction direction = KeyToDirection(keyCode);
937 const CachedFrame* cachedFrame, * oldFrame = 0;
938 const CachedNode* cursor = root->currentCursor(&oldFrame);
939 WebCore::IntPoint cursorLocation = root->cursorLocation();
940 DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
941 cursor ? cursor->index() : 0,
942 cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
943 WebCore::IntRect visibleRect = setVisibleRect(root);
944 int xMax = getScaledMaxXScroll();
945 int yMax = getScaledMaxYScroll();
946 root->setMaxScroll(xMax, yMax);
947 const CachedNode* cachedNode = 0;
951 while (--counter >= 0) {
952 WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
953 cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
957 DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
958 "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
959 cachedNode ? cachedNode->nodePointer() : 0,
960 root->cursorLocation().x(), root->cursorLocation().y(),
961 cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
962 cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
963 cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
964 cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
965 // If !m_heightCanMeasure (such as in the browser), we want to scroll no
967 if (!ignoreScroll && (!m_heightCanMeasure ||
969 (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
971 if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
972 SkTime::GetMSecs() - m_lastDxTime < 1000)
973 root->checkForJiggle(&dx);
974 DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
976 this->scrollBy(dx, dy);
978 m_lastDxTime = SkTime::GetMSecs();
983 m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
984 root->setCursor(const_cast<CachedFrame*>(cachedFrame),
985 const_cast<CachedNode*>(cachedNode));
986 const CachedNode* focus = root->currentFocus();
987 bool clearTextEntry = cachedNode != focus && focus
988 && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput();
989 // Stop painting the caret if the old focus was a text input and so is the new cursor.
990 bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents();
991 sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret);
993 int docHeight = root->documentHeight();
994 int docWidth = root->documentWidth();
995 if (visibleRect.maxY() + dy > docHeight)
996 dy = docHeight - visibleRect.maxY();
997 else if (visibleRect.y() + dy < 0)
998 dy = -visibleRect.y();
999 if (visibleRect.maxX() + dx > docWidth)
1000 dx = docWidth - visibleRect.maxX();
1001 else if (visibleRect.x() < 0)
1002 dx = -visibleRect.x();
1003 result = direction == CachedFrame::LEFT ? dx >= 0 :
1004 direction == CachedFrame::RIGHT ? dx <= 0 :
1005 direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
1010 void notifyProgressFinished()
1012 DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
1013 rebuildWebTextView();
1015 if (m_frameCacheUI) {
1016 const CachedNode* focus = m_frameCacheUI->currentFocus();
1017 DBG_NAV_LOGD("focus %d (nativeNode=%p)",
1018 focus ? focus->index() : 0,
1019 focus ? focus->nodePointer() : 0);
1024 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
1025 const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
1032 setVisibleRect(root);
1033 return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
1036 IntRect setVisibleRect(CachedRoot* root)
1038 IntRect visibleRect = getVisibleRect();
1039 DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
1040 visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
1041 root->setVisibleRect(visibleRect);
1045 void selectBestAt(const WebCore::IntRect& rect)
1047 const CachedFrame* frame;
1049 CachedRoot* root = getFrameCache(AllowNewer);
1052 const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
1054 DBG_NAV_LOGD("no nodes found root=%p", root);
1055 root->rootHistory()->setMouseBounds(rect);
1056 m_viewImpl->m_hasCursorBounds = false;
1057 root->setCursor(0, 0);
1060 DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
1061 WebCore::IntRect bounds = node->bounds(frame);
1062 root->rootHistory()->setMouseBounds(bounds);
1063 m_viewImpl->updateCursorBounds(root, frame, node);
1065 root->setCursor(const_cast<CachedFrame*>(frame),
1066 const_cast<CachedNode*>(node));
1068 sendMoveMouseIfLatest(false, false);
1071 const CachedNode* m_cacheHitNode;
1072 const CachedFrame* m_cacheHitFrame;
1074 bool pointInNavCache(int x, int y, int slop)
1076 CachedRoot* root = getFrameCache(AllowNewer);
1079 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
1081 return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
1084 bool motionUp(int x, int y, int slop)
1086 bool pageScrolled = false;
1087 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
1089 CachedRoot* root = getFrameCache(AllowNewer);
1092 const CachedFrame* frame = 0;
1093 const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
1094 CachedHistory* history = root->rootHistory();
1096 DBG_NAV_LOGD("no nodes found root=%p", root);
1097 history->setNavBounds(rect);
1098 m_viewImpl->m_hasCursorBounds = false;
1100 int dx = root->checkForCenter(x, y);
1103 pageScrolled = true;
1105 sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
1108 return pageScrolled;
1110 DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
1111 result->index(), x, y, rx, ry);
1112 WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
1113 history->setNavBounds(navBounds);
1114 history->setMouseBounds(navBounds);
1115 m_viewImpl->updateCursorBounds(root, frame, result);
1116 root->setCursor(const_cast<CachedFrame*>(frame),
1117 const_cast<CachedNode*>(result));
1118 if (result->isSyntheticLink())
1119 overrideUrlLoading(result->getExport());
1122 (WebCore::Frame*) frame->framePointer(),
1123 (WebCore::Node*) result->nodePointer(), rx, ry);
1125 if (result->isTextInput() || result->isSelect()
1126 || result->isContentEditable()) {
1127 showCursorUntimed();
1130 return pageScrolled;
1133 #if USE(ACCELERATED_COMPOSITING)
1134 static const ScrollableLayerAndroid* findScrollableLayer(
1135 const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) {
1137 parent->bounds(&bounds);
1138 // Check the parent bounds first; this will clip to within a masking layer's
1140 if (parent->masksToBounds() && !bounds.contains(x, y))
1142 // Move the hit test local to parent.
1145 int count = parent->countChildren();
1147 const LayerAndroid* child = parent->getChild(count);
1148 const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y,
1151 foundBounds->offset(bounds.fLeft, bounds.fTop);
1152 if (parent->masksToBounds()) {
1153 if (bounds.width() < foundBounds->width())
1154 foundBounds->fRight = foundBounds->fLeft + bounds.width();
1155 if (bounds.height() < foundBounds->height())
1156 foundBounds->fBottom = foundBounds->fTop + bounds.height();
1161 if (parent->contentIsScrollable()) {
1162 foundBounds->set(0, 0, bounds.width(), bounds.height());
1163 return static_cast<const ScrollableLayerAndroid*>(parent);
1169 int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds)
1171 #if USE(ACCELERATED_COMPOSITING)
1172 const LayerAndroid* layerRoot = compositeRoot();
1175 const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y,
1178 result->getScrollRect(layerRect);
1179 return result->uniqueId();
1185 int getBlockLeftEdge(int x, int y, float scale)
1187 CachedRoot* root = getFrameCache(AllowNewer);
1189 return root->getBlockLeftEdge(x, y, scale);
1193 void overrideUrlLoading(const WTF::String& url)
1195 JNIEnv* env = JSC::Bindings::getJNIEnv();
1196 AutoJObject javaObject = m_javaGlue.object(env);
1197 if (!javaObject.get())
1199 jstring jName = wtfStringToJstring(env, url);
1200 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName);
1201 env->DeleteLocalRef(jName);
1204 void setFindIsUp(bool up)
1206 DBG_NAV_LOGD("up=%d", up);
1207 m_viewImpl->m_findIsUp = up;
1210 void setFindIsEmpty()
1213 m_findOnPage.clearCurrentLocation();
1216 void showCursorTimed()
1219 m_ringAnimationEnd = SkTime::GetMSecs() + 500;
1223 void showCursorUntimed()
1226 m_ring.m_isPressed = false;
1227 m_ringAnimationEnd = UINT_MAX;
1231 void setHeightCanMeasure(bool measure)
1233 m_heightCanMeasure = measure;
1236 String getSelection()
1238 return m_selectText.getSelection();
1241 void moveSelection(int x, int y)
1243 m_selectText.moveSelection(getVisibleRect(), x, y);
1246 IntPoint selectableText()
1248 const CachedRoot* root = getFrameCache(DontAllowNewer);
1250 return IntPoint(0, 0);
1251 return m_selectText.selectableText(root);
1256 m_selectText.selectAll();
1261 return m_selectText.selectionX();
1266 return m_selectText.selectionY();
1269 void resetSelection()
1271 m_selectText.reset();
1274 bool startSelection(int x, int y)
1276 const CachedRoot* root = getFrameCache(DontAllowNewer);
1279 return m_selectText.startSelection(root, getVisibleRect(), x, y);
1282 bool wordSelection(int x, int y)
1284 const CachedRoot* root = getFrameCache(DontAllowNewer);
1287 return m_selectText.wordSelection(root, getVisibleRect(), x, y);
1290 bool extendSelection(int x, int y)
1292 m_selectText.extendSelection(getVisibleRect(), x, y);
1296 bool hitSelection(int x, int y)
1298 return m_selectText.hitSelection(x, y);
1301 void setExtendSelection()
1303 m_selectText.setExtendSelection(true);
1306 void setSelectionPointer(bool set, float scale, int x, int y)
1308 m_selectText.setDrawPointer(set);
1311 m_selectText.m_inverseScale = scale;
1312 m_selectText.m_selectX = x;
1313 m_selectText.m_selectY = y;
1316 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
1318 DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
1319 JNIEnv* env = JSC::Bindings::getJNIEnv();
1320 AutoJObject javaObject = m_javaGlue.object(env);
1321 if (!javaObject.get())
1323 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
1324 checkException(env);
1327 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1329 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
1330 JNIEnv* env = JSC::Bindings::getJNIEnv();
1331 AutoJObject javaObject = m_javaGlue.object(env);
1332 if (!javaObject.get())
1334 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y);
1335 checkException(env);
1338 void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret)
1340 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1341 JNIEnv* env = JSC::Bindings::getJNIEnv();
1342 AutoJObject javaObject = m_javaGlue.object(env);
1343 if (!javaObject.get())
1345 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret);
1346 checkException(env);
1349 void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1351 DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y);
1352 LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
1354 JNIEnv* env = JSC::Bindings::getJNIEnv();
1355 AutoJObject javaObject = m_javaGlue.object(env);
1356 if (!javaObject.get())
1358 m_viewImpl->m_touchGeneration = ++m_generation;
1359 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y);
1360 checkException(env);
1363 void findNext(bool forward)
1365 m_findOnPage.findNext(forward);
1366 scrollToCurrentMatch();
1370 // With this call, WebView takes ownership of matches, and is responsible for
1372 void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch)
1374 // If this search is the same as the last one, check against the old
1375 // location to determine whether to scroll. If the same word is found
1376 // in the same place, then do not scroll.
1377 IntRect oldLocation;
1378 bool checkAgainstOldLocation = false;
1379 if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) {
1380 oldLocation = m_findOnPage.currentMatchBounds();
1381 checkAgainstOldLocation = true;
1384 m_findOnPage.setMatches(matches);
1386 if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds())
1387 scrollToCurrentMatch();
1391 int currentMatchIndex()
1393 return m_findOnPage.currentMatchIndex();
1396 bool scrollBy(int dx, int dy)
1398 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1400 JNIEnv* env = JSC::Bindings::getJNIEnv();
1401 AutoJObject javaObject = m_javaGlue.object(env);
1402 if (!javaObject.get())
1404 bool result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_scrollBy, dx, dy, true);
1405 checkException(env);
1409 void setIsScrolling(bool isScrolling)
1411 #if USE(ACCELERATED_COMPOSITING)
1412 if (m_glWebViewState)
1413 m_glWebViewState->setIsScrolling(isScrolling);
1417 bool hasCursorNode()
1419 CachedRoot* root = getFrameCache(DontAllowNewer);
1421 DBG_NAV_LOG("!root");
1424 const CachedNode* cursorNode = root->currentCursor();
1425 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
1426 cursorNode ? cursorNode->index() : -1,
1427 cursorNode ? cursorNode->nodePointer() : 0);
1433 CachedRoot* root = getFrameCache(DontAllowNewer);
1435 DBG_NAV_LOG("!root");
1438 const CachedNode* focusNode = root->currentFocus();
1439 DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
1440 focusNode ? focusNode->index() : -1,
1441 focusNode ? focusNode->nodePointer() : 0);
1445 void rebuildWebTextView()
1447 JNIEnv* env = JSC::Bindings::getJNIEnv();
1448 AutoJObject javaObject = m_javaGlue.object(env);
1449 if (!javaObject.get())
1451 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView);
1452 checkException(env);
1455 void viewInvalidate()
1457 JNIEnv* env = JSC::Bindings::getJNIEnv();
1458 AutoJObject javaObject = m_javaGlue.object(env);
1459 if (!javaObject.get())
1461 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidate);
1462 checkException(env);
1465 void viewInvalidateRect(int l, int t, int r, int b)
1467 JNIEnv* env = JSC::Bindings::getJNIEnv();
1468 AutoJObject javaObject = m_javaGlue.object(env);
1469 if (!javaObject.get())
1471 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
1472 checkException(env);
1475 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
1477 JNIEnv* env = JSC::Bindings::getJNIEnv();
1478 AutoJObject javaObject = m_javaGlue.object(env);
1479 if (!javaObject.get())
1481 env->CallVoidMethod(javaObject.get(), m_javaGlue.m_postInvalidateDelayed,
1482 delay, bounds.x(), bounds.y(), bounds.maxX(), bounds.maxY());
1483 checkException(env);
1486 bool inFullScreenMode()
1488 JNIEnv* env = JSC::Bindings::getJNIEnv();
1489 AutoJObject javaObject = m_javaGlue.object(env);
1490 if (!javaObject.get())
1492 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_inFullScreenMode);
1493 checkException(env);
1497 int moveGeneration()
1499 return m_viewImpl->m_moveGeneration;
1502 LayerAndroid* compositeRoot() const
1504 LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
1505 "base layer can't have more than one child %s", __FUNCTION__);
1506 if (m_baseLayer && m_baseLayer->countChildren() == 1)
1507 return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
1512 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1513 static void copyScrollPositionRecursive(const LayerAndroid* from,
1518 for (int i = 0; i < from->countChildren(); i++) {
1519 const LayerAndroid* l = from->getChild(i);
1520 if (l->contentIsScrollable()) {
1521 const SkPoint& pos = l->getPosition();
1522 LayerAndroid* match = root->findById(l->uniqueId());
1523 if (match && match->contentIsScrollable())
1524 match->setPosition(pos.fX, pos.fY);
1526 copyScrollPositionRecursive(l, root);
1531 void registerPageSwapCallback()
1533 m_pageSwapCallbackRegistered = true;
1536 void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator,
1537 bool isPictureAfterFirstLayout, bool registerPageSwapCallback)
1539 #if USE(ACCELERATED_COMPOSITING)
1540 if (m_glWebViewState)
1541 m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator,
1542 isPictureAfterFirstLayout);
1543 m_pageSwapCallbackRegistered |= registerPageSwapCallback;
1546 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
1548 LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0));
1549 copyScrollPositionRecursive(compositeRoot(), newCompositeRoot);
1552 SkSafeUnref(m_baseLayer);
1553 m_baseLayer = layer;
1554 CachedRoot* root = getFrameCache(DontAllowNewer);
1557 root->resetLayers();
1558 root->setRootLayer(compositeRoot());
1561 void getTextSelectionRegion(SkRegion *region)
1563 m_selectText.getSelectionRegion(getVisibleRect(), region);
1566 void replaceBaseContent(PictureSet* set)
1570 m_baseLayer->setContent(*set);
1574 void copyBaseContentToPicture(SkPicture* picture)
1578 PictureSet* content = m_baseLayer->content();
1579 m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(),
1580 SkPicture::kUsePathBoundsForClip_RecordingFlag));
1581 picture->endRecording();
1587 return !m_baseLayer->content()->isEmpty();
1590 void setFunctor(Functor* functor) {
1591 delete m_glDrawFunctor;
1592 m_glDrawFunctor = functor;
1595 Functor* getFunctor() {
1596 return m_glDrawFunctor;
1599 BaseLayerAndroid* getBaseLayer() {
1603 private: // local state for WebView
1604 // private to getFrameCache(); other functions operate in a different thread
1605 CachedRoot* m_frameCacheUI; // navigation data ready for use
1606 WebViewCore* m_viewImpl;
1607 int m_generation; // associate unique ID with sent kit focus to match with ui
1608 SkPicture* m_navPictureUI;
1609 SkMSec m_ringAnimationEnd;
1610 // Corresponds to the same-named boolean on the java side.
1611 bool m_heightCanMeasure;
1613 SkMSec m_lastDxTime;
1614 SelectText m_selectText;
1615 FindOnPage m_findOnPage;
1617 BaseLayerAndroid* m_baseLayer;
1618 Functor* m_glDrawFunctor;
1619 #if USE(ACCELERATED_COMPOSITING)
1620 GLWebViewState* m_glWebViewState;
1621 bool m_pageSwapCallbackRegistered;
1623 RenderSkinButton* m_buttonSkin;
1624 }; // end of WebView class
1628 * This class holds a function pointer and parameters for calling drawGL into a specific
1629 * viewport. The pointer to the Functor will be put on a framework display list to be called
1630 * when the display list is replayed.
1632 class GLDrawFunctor : Functor {
1634 GLDrawFunctor(WebView* _wvInstance,
1635 bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint),
1636 WebCore::IntRect _viewRect, float _scale, int _extras) {
1637 wvInstance = _wvInstance;
1639 viewRect = _viewRect;
1643 status_t operator()(int messageId, void* data) {
1644 if (viewRect.isEmpty()) {
1645 // NOOP operation if viewport is empty
1649 WebCore::IntRect inval;
1650 int titlebarHeight = webViewRect.height() - viewRect.height();
1652 uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data);
1653 WebCore::IntRect localViewRect = viewRect;
1655 localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y());
1657 WebCore::IntRect clip(info->clipLeft, info->clipTop,
1658 info->clipRight - info->clipLeft,
1659 info->clipBottom - info->clipTop);
1661 bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras);
1664 if (inval.isEmpty()) {
1665 finalInval = webViewRect;
1668 finalInval.setX(webViewRect.x() + inval.x());
1669 finalInval.setY(webViewRect.y() + titlebarHeight + inval.y());
1670 finalInval.setWidth(inval.width());
1671 finalInval.setHeight(inval.height());
1673 info->dirtyLeft = finalInval.x();
1674 info->dirtyTop = finalInval.y();
1675 info->dirtyRight = finalInval.maxX();
1676 info->dirtyBottom = finalInval.maxY();
1678 // return 1 if invalidation needed, 0 otherwise
1679 return retVal ? 1 : 0;
1681 void updateRect(WebCore::IntRect& _viewRect) {
1682 viewRect = _viewRect;
1684 void updateViewRect(WebCore::IntRect& _viewRect) {
1685 webViewRect = _viewRect;
1688 WebView* wvInstance;
1689 bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, WebCore::IntRect&, int, WebCore::IntRect&, float, int);
1690 WebCore::IntRect viewRect;
1691 WebCore::IntRect webViewRect;
1696 static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom)
1698 jclass rectClass = env->FindClass("android/graphics/Rect");
1699 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1700 jobject rect = env->NewObject(rectClass, init, x, y, right, bottom);
1701 env->DeleteLocalRef(rectClass);
1706 * Native JNI methods
1708 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
1710 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1711 ->m_cacheHitFrame->framePointer());
1714 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
1716 WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
1717 ->m_cacheHitNode->originalAbsoluteBounds();
1718 return createJavaRect(env, bounds.x(), bounds.y(),
1719 bounds.maxX(), bounds.maxY());
1722 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
1724 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1725 ->m_cacheHitNode->nodePointer());
1728 static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj)
1730 return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin();
1733 static void nativeClearCursor(JNIEnv *env, jobject obj)
1735 WebView* view = GET_NATIVE_VIEW(env, obj);
1736 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1737 view->clearCursor();
1740 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir)
1742 WTF::String dir = jstringToWtfString(env, drawableDir);
1743 WebView* webview = new WebView(env, obj, viewImpl, dir);
1744 // NEED THIS OR SOMETHING LIKE IT!
1748 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
1750 WebView* view = GET_NATIVE_VIEW(env, obj);
1751 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1754 const CachedFrame* frame = 0;
1755 (void) root->currentCursor(&frame);
1756 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1759 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
1761 WebView* view = GET_NATIVE_VIEW(env, obj);
1762 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1763 return root ? root->currentCursor() : 0;
1766 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
1767 const CachedFrame** frame)
1769 WebView* view = GET_NATIVE_VIEW(env, obj);
1770 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1771 return root ? root->currentCursor(frame) : 0;
1774 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
1775 const CachedFrame** frame)
1777 WebView* view = GET_NATIVE_VIEW(env, obj);
1778 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1781 const CachedNode* cursor = root->currentCursor(frame);
1782 if (cursor && cursor->wantsKeyEvents())
1784 return root->currentFocus(frame);
1787 static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj)
1789 WebView* view = GET_NATIVE_VIEW(env, obj);
1790 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1793 const CachedNode* cursor = root->currentCursor();
1794 if (!cursor || !cursor->isTextInput())
1795 cursor = root->currentFocus();
1796 if (!cursor || !cursor->isTextInput()) return false;
1797 return root->nextTextField(cursor, 0);
1800 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
1802 WebView* view = GET_NATIVE_VIEW(env, obj);
1803 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1804 return root ? root->currentFocus() : 0;
1807 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj,
1808 const CachedFrame** frame)
1810 WebView* view = GET_NATIVE_VIEW(env, obj);
1811 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1812 return root ? root->currentFocus(frame) : 0;
1815 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
1817 WebView* view = GET_NATIVE_VIEW(env, obj);
1818 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1821 const CachedFrame* frame;
1822 const CachedNode* cursor = root->currentCursor(&frame);
1823 if (!cursor || !cursor->wantsKeyEvents())
1824 cursor = root->currentFocus(&frame);
1825 return cursor ? frame->textInput(cursor) : 0;
1828 static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
1830 const CachedNode* focus = getFocusNode(env, obj);
1831 if (!focus) return false;
1832 // Plugins handle shift and arrows whether or not they have focus.
1833 if (focus->isPlugin()) return true;
1834 const CachedNode* cursor = getCursorNode(env, obj);
1835 // ContentEditable nodes should only receive shift and arrows if they have
1836 // both the cursor and the focus.
1837 return cursor && cursor->nodePointer() == focus->nodePointer()
1838 && cursor->isContentEditable();
1841 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
1843 const CachedFrame* frame;
1844 const CachedNode* node = getCursorNode(env, obj, &frame);
1845 WebCore::IntRect bounds = node ? node->bounds(frame)
1846 : WebCore::IntRect(0, 0, 0, 0);
1847 return createJavaRect(env, bounds.x(), bounds.y(),
1848 bounds.maxX(), bounds.maxY());
1851 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
1853 const CachedNode* node = getCursorNode(env, obj);
1854 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1857 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
1859 WebView* view = GET_NATIVE_VIEW(env, obj);
1860 const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1861 WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
1863 root->getSimulatedMousePosition(&pos);
1864 jclass pointClass = env->FindClass("android/graphics/Point");
1865 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
1866 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
1867 env->DeleteLocalRef(pointClass);
1871 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
1874 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
1875 return WebCore::IntRect(L, T, R - L, B - T);
1878 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
1880 const CachedFrame* frame;
1881 const CachedNode* node = getCursorNode(env, obj, &frame);
1882 return node ? node->bounds(frame).intersects(
1883 jrect_to_webrect(env, visRect)) : false;
1886 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
1888 const CachedNode* node = getCursorNode(env, obj);
1889 return node ? node->isAnchor() : false;
1892 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
1894 const CachedNode* node = getCursorNode(env, obj);
1895 return node ? node->isTextInput() : false;
1898 static jobject nativeCursorText(JNIEnv *env, jobject obj)
1900 const CachedNode* node = getCursorNode(env, obj);
1903 WTF::String value = node->getExport();
1904 return wtfStringToJstring(env, value);
1907 static void nativeDebugDump(JNIEnv *env, jobject obj)
1910 WebView* view = GET_NATIVE_VIEW(env, obj);
1911 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1916 static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
1917 jint extras, jboolean split) {
1918 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1919 return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
1922 static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect,
1923 jfloat scale, jint extras) {
1924 WebCore::IntRect viewRect;
1925 if (jrect == NULL) {
1926 viewRect = WebCore::IntRect();
1928 viewRect = jrect_to_webrect(env, jrect);
1930 WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
1931 GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL,
1932 viewRect, scale, extras);
1933 wvInstance->setFunctor((Functor*) functor);
1935 WebCore::IntRect webViewRect;
1936 if (jviewrect == NULL) {
1937 webViewRect = WebCore::IntRect();
1939 webViewRect = jrect_to_webrect(env, jviewrect);
1941 functor->updateViewRect(webViewRect);
1943 return (jint)functor;
1946 static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, jobject jviewrect) {
1947 WebView *wvInstance = GET_NATIVE_VIEW(env, obj);
1948 if (wvInstance != NULL) {
1949 GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor();
1950 if (functor != NULL) {
1951 WebCore::IntRect viewRect;
1952 if (jrect == NULL) {
1953 viewRect = WebCore::IntRect();
1955 viewRect = jrect_to_webrect(env, jrect);
1957 functor->updateRect(viewRect);
1959 WebCore::IntRect webViewRect;
1960 if (jviewrect == NULL) {
1961 webViewRect = WebCore::IntRect();
1963 webViewRect = jrect_to_webrect(env, jviewrect);
1965 functor->updateViewRect(webViewRect);
1970 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
1972 #if USE(ACCELERATED_COMPOSITING)
1973 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
1975 return root->evaluateAnimations();
1980 static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval,
1981 jboolean showVisualIndicator,
1982 jboolean isPictureAfterFirstLayout,
1983 jboolean registerPageSwapCallback)
1985 BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
1986 SkRegion invalRegion;
1988 invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
1989 GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator,
1990 isPictureAfterFirstLayout,
1991 registerPageSwapCallback);
1994 static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jobject region)
1998 SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region);
1999 GET_NATIVE_VIEW(env, obj)->getTextSelectionRegion(nregion);
2002 static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
2004 return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
2007 static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
2009 PictureSet* set = reinterpret_cast<PictureSet*>(content);
2010 GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
2013 static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
2015 SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
2016 GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
2019 static bool nativeHasContent(JNIEnv *env, jobject obj)
2021 return GET_NATIVE_VIEW(env, obj)->hasContent();
2024 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
2026 WebView* view = GET_NATIVE_VIEW(env, obj);
2027 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2028 WTF::String uri = view->imageURI(x, y);
2029 return wtfStringToJstring(env, uri);
2032 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
2034 WebView* view = GET_NATIVE_VIEW(env, obj);
2035 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2038 const CachedFrame* frame = 0;
2039 const CachedNode* cursor = root->currentCursor(&frame);
2040 if (!cursor || !cursor->wantsKeyEvents())
2041 (void) root->currentFocus(&frame);
2042 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
2045 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
2047 const CachedInput* input = getInputCandidate(env, obj);
2048 return input && input->getType() == CachedInput::PASSWORD;
2051 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
2053 const CachedInput* input = getInputCandidate(env, obj);
2054 return input ? input->isRtlText() : false;
2057 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
2059 const CachedNode* node = getFocusCandidate(env, obj, 0);
2060 return node ? node->isTextInput() : false;
2063 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
2065 const CachedInput* input = getInputCandidate(env, obj);
2066 return input ? input->maxLength() : false;
2069 static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj)
2071 const CachedInput* input = getInputCandidate(env, obj);
2072 return input ? input->autoComplete() : false;
2075 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
2077 const CachedInput* input = getInputCandidate(env, obj);
2080 const WTF::String& name = input->name();
2081 return wtfStringToJstring(env, name);
2084 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
2086 const CachedFrame* frame;
2087 const CachedNode* node = getFocusCandidate(env, obj, &frame);
2088 WebCore::IntRect bounds = node ? node->bounds(frame)
2089 : WebCore::IntRect(0, 0, 0, 0);
2090 // Inset the rect by 1 unit, so that the focus candidate's border can still
2091 // be seen behind it.
2092 return createJavaRect(env, bounds.x() + 1, bounds.y() + 1,
2093 bounds.maxX() - 1, bounds.maxY() - 1);
2096 static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj)
2098 const CachedInput* input = getInputCandidate(env, obj);
2101 // Note that the Java Rect is being used to pass four integers, rather than
2102 // being used as an actual rectangle.
2103 return createJavaRect(env, input->paddingLeft(), input->paddingTop(),
2104 input->paddingRight(), input->paddingBottom());
2107 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
2109 const CachedNode* node = getFocusCandidate(env, obj, 0);
2110 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
2113 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
2115 const CachedNode* node = getFocusCandidate(env, obj, 0);
2118 WTF::String value = node->getExport();
2119 return wtfStringToJstring(env, value);
2122 static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj)
2124 const CachedInput* input = getInputCandidate(env, obj);
2125 return input ? input->lineHeight() : 0;
2128 static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
2130 const CachedInput* input = getInputCandidate(env, obj);
2131 return input ? input->textSize() : 0.f;
2134 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
2136 const CachedInput* input = getInputCandidate(env, obj);
2138 return CachedInput::NONE;
2140 if (input->isTextArea())
2141 return CachedInput::TEXT_AREA;
2143 return input->getType();
2146 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
2148 const CachedNode* node = getFocusNode(env, obj);
2149 return node ? node->isPlugin() : false;
2152 static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj)
2154 const CachedFrame* frame;
2155 const CachedNode* node = getFocusNode(env, obj, &frame);
2156 WebCore::IntRect bounds = node ? node->bounds(frame)
2157 : WebCore::IntRect(0, 0, 0, 0);
2158 return createJavaRect(env, bounds.x(), bounds.y(),
2159 bounds.maxX(), bounds.maxY());
2162 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
2164 const CachedNode* node = getFocusNode(env, obj);
2165 return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
2168 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
2169 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2170 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2171 return view->cursorWantsKeyEvents();
2174 static void nativeHideCursor(JNIEnv *env, jobject obj)
2176 WebView* view = GET_NATIVE_VIEW(env, obj);
2177 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2181 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
2183 #ifdef ANDROID_INSTRUMENT
2184 TimeCounter::reportNow();
2188 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
2190 WebView* view = GET_NATIVE_VIEW(env, obj);
2191 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2192 WebCore::IntRect rect = jrect_to_webrect(env, jrect);
2193 view->selectBestAt(rect);
2196 static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y)
2198 WebView* view = GET_NATIVE_VIEW(env, obj);
2199 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2200 WebCore::IntRect rect = IntRect(x, y , 1, 1);
2201 view->selectBestAt(rect);
2202 if (view->hasCursorNode())
2203 view->showCursorUntimed();
2206 static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer)
2209 #if USE(ACCELERATED_COMPOSITING)
2210 LayerAndroid* layer = (LayerAndroid*) jlayer;
2211 r = layer->bounds();
2217 jclass rectClass = env->FindClass("android/graphics/Rect");
2218 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2219 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2220 irect.fRight, irect.fBottom);
2221 env->DeleteLocalRef(rectClass);
2225 static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
2227 SkIRect irect = jrect_to_webrect(env, jrect);
2228 #if USE(ACCELERATED_COMPOSITING)
2229 LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
2233 rect = root->subtractLayers(rect);
2237 jclass rectClass = env->FindClass("android/graphics/Rect");
2238 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2239 jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop,
2240 irect.fRight, irect.fBottom);
2241 env->DeleteLocalRef(rectClass);
2245 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
2247 WebView* view = GET_NATIVE_VIEW(env, obj);
2248 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2249 return root ? root->textGeneration() : 0;
2252 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
2253 int x, int y, int slop)
2255 return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
2258 static bool nativeMotionUp(JNIEnv *env, jobject obj,
2259 int x, int y, int slop)
2261 WebView* view = GET_NATIVE_VIEW(env, obj);
2262 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2263 return view->motionUp(x, y, slop);
2266 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
2268 return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
2271 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
2273 return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
2276 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
2277 int key, int count, bool ignoreScroll)
2279 WebView* view = GET_NATIVE_VIEW(env, obj);
2280 DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
2281 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2282 return view->moveCursor(key, count, ignoreScroll);
2285 static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
2286 bool pressed, bool invalidate)
2288 WebView* view = GET_NATIVE_VIEW(env, obj);
2289 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2290 view->nativeRecordButtons(hasFocus, pressed, invalidate);
2293 static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp)
2295 WebView* view = GET_NATIVE_VIEW(env, obj);
2296 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2297 view->setFindIsUp(isUp);
2300 static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
2302 GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
2305 static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
2307 GET_NATIVE_VIEW(env, obj)->showCursorTimed();
2310 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
2312 WebView* view = GET_NATIVE_VIEW(env, obj);
2313 LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
2314 view->setHeightCanMeasure(measure);
2317 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
2319 WebView* view = GET_NATIVE_VIEW(env, obj);
2320 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2321 jclass rectClass = env->FindClass("android/graphics/Rect");
2322 LOG_ASSERT(rectClass, "Could not find Rect class!");
2323 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
2324 LOG_ASSERT(init, "Could not find constructor for Rect");
2325 WebCore::IntRect webRect;
2326 view->cursorRingBounds(&webRect);
2327 jobject rect = env->NewObject(rectClass, init, webRect.x(),
2328 webRect.y(), webRect.maxX(), webRect.maxY());
2329 env->DeleteLocalRef(rectClass);
2333 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
2334 jstring findUpper, jboolean sameAsLastSearch)
2336 // If one or the other is null, do not search.
2337 if (!(findLower && findUpper))
2339 // Obtain the characters for both the lower case string and the upper case
2340 // string representing the same word.
2341 const jchar* findLowerChars = env->GetStringChars(findLower, 0);
2342 const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
2343 // If one or the other is null, do not search.
2344 if (!(findLowerChars && findUpperChars)) {
2346 env->ReleaseStringChars(findLower, findLowerChars);
2348 env->ReleaseStringChars(findUpper, findUpperChars);
2349 checkException(env);
2352 WebView* view = GET_NATIVE_VIEW(env, obj);
2353 LOG_ASSERT(view, "view not set in nativeFindAll");
2354 CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
2356 env->ReleaseStringChars(findLower, findLowerChars);
2357 env->ReleaseStringChars(findUpper, findUpperChars);
2358 checkException(env);
2361 int length = env->GetStringLength(findLower);
2362 // If the lengths of the strings do not match, then they are not the same
2363 // word, so do not search.
2364 if (!length || env->GetStringLength(findUpper) != length) {
2365 env->ReleaseStringChars(findLower, findLowerChars);
2366 env->ReleaseStringChars(findUpper, findUpperChars);
2367 checkException(env);
2370 int width = root->documentWidth();
2371 int height = root->documentHeight();
2372 // Create a FindCanvas, which allows us to fake draw into it so we can
2373 // figure out where our search string is rendered (and how many times).
2374 FindCanvas canvas(width, height, (const UChar*) findLowerChars,
2375 (const UChar*) findUpperChars, length << 1);
2377 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
2378 canvas.setBitmapDevice(bitmap);
2380 WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
2381 // With setMatches, the WebView takes ownership of matches
2382 view->setMatches(matches, sameAsLastSearch);
2384 env->ReleaseStringChars(findLower, findLowerChars);
2385 env->ReleaseStringChars(findUpper, findUpperChars);
2386 checkException(env);
2387 return canvas.found();
2390 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
2392 WebView* view = GET_NATIVE_VIEW(env, obj);
2393 LOG_ASSERT(view, "view not set in nativeFindNext");
2394 view->findNext(forward);
2397 static int nativeFindIndex(JNIEnv *env, jobject obj)
2399 WebView* view = GET_NATIVE_VIEW(env, obj);
2400 LOG_ASSERT(view, "view not set in nativeFindIndex");
2401 return view->currentMatchIndex();
2404 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
2406 WebView* view = GET_NATIVE_VIEW(env, obj);
2407 LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
2408 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2411 const CachedNode* cachedFocusNode = root->currentFocus();
2412 if (!cachedFocusNode || !cachedFocusNode->isTextInput())
2414 WTF::String webcoreString = jstringToWtfString(env, updatedText);
2415 (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
2416 root->setTextGeneration(generation);
2417 checkException(env);
2420 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
2423 WebView* view = GET_NATIVE_VIEW(env, obj);
2424 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2427 return view->getBlockLeftEdge(x, y, scale);
2430 static void nativeDestroy(JNIEnv *env, jobject obj)
2432 WebView* view = GET_NATIVE_VIEW(env, obj);
2433 LOGD("nativeDestroy view: %p", view);
2434 LOG_ASSERT(view, "view not set in nativeDestroy");
2438 static void nativeStopGL(JNIEnv *env, jobject obj)
2440 GET_NATIVE_VIEW(env, obj)->stopGL();
2443 static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
2445 WebView* view = GET_NATIVE_VIEW(env, obj);
2446 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
2449 const CachedNode* current = root->currentCursor();
2450 if (!current || !current->isTextInput())
2451 current = root->currentFocus();
2452 if (!current || !current->isTextInput())
2454 const CachedFrame* frame;
2455 const CachedNode* next = root->nextTextField(current, &frame);
2458 const WebCore::IntRect& bounds = next->bounds(frame);
2459 root->rootHistory()->setMouseBounds(bounds);
2460 view->getWebViewCore()->updateCursorBounds(root, frame, next);
2461 view->showCursorUntimed();
2462 root->setCursor(const_cast<CachedFrame*>(frame),
2463 const_cast<CachedNode*>(next));
2464 view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
2465 static_cast<WebCore::Node*>(next->nodePointer()));
2466 if (!next->isInLayer())
2467 view->scrollRectOnScreen(bounds);
2468 view->getWebViewCore()->m_moveGeneration++;
2472 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
2474 WebView* view = GET_NATIVE_VIEW(env, obj);
2477 return view->moveGeneration();
2480 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
2482 GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
2485 static void nativeResetSelection(JNIEnv *env, jobject obj)
2487 return GET_NATIVE_VIEW(env, obj)->resetSelection();
2490 static jobject nativeSelectableText(JNIEnv* env, jobject obj)
2492 IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
2493 jclass pointClass = env->FindClass("android/graphics/Point");
2494 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
2495 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
2496 env->DeleteLocalRef(pointClass);
2500 static void nativeSelectAll(JNIEnv* env, jobject obj)
2502 GET_NATIVE_VIEW(env, obj)->selectAll();
2505 static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
2507 GET_NATIVE_VIEW(env, obj)->setExtendSelection();
2510 static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
2512 return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
2515 static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
2517 return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
2520 static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
2522 GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
2525 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
2527 WebView* view = GET_NATIVE_VIEW(env, obj);
2528 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2529 String selection = view->getSelection();
2530 return wtfStringToJstring(env, selection);
2533 static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
2535 return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
2538 static jint nativeSelectionX(JNIEnv *env, jobject obj)
2540 return GET_NATIVE_VIEW(env, obj)->selectionX();
2543 static jint nativeSelectionY(JNIEnv *env, jobject obj)
2545 return GET_NATIVE_VIEW(env, obj)->selectionY();
2548 static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jboolean set,
2549 jfloat scale, jint x, jint y)
2551 GET_NATIVE_VIEW(env, obj)->setSelectionPointer(set, scale, x, y);
2554 static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj)
2556 GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback();
2559 static void nativeTileProfilingStart(JNIEnv *env, jobject obj)
2561 TilesManager::instance()->getProfiler()->start();
2564 static float nativeTileProfilingStop(JNIEnv *env, jobject obj)
2566 return TilesManager::instance()->getProfiler()->stop();
2569 static void nativeTileProfilingClear(JNIEnv *env, jobject obj)
2571 TilesManager::instance()->getProfiler()->clear();
2574 static int nativeTileProfilingNumFrames(JNIEnv *env, jobject obj)
2576 return TilesManager::instance()->getProfiler()->numFrames();
2579 static int nativeTileProfilingNumTilesInFrame(JNIEnv *env, jobject obj, int frame)
2581 return TilesManager::instance()->getProfiler()->numTilesInFrame(frame);
2584 static int nativeTileProfilingGetInt(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
2586 WTF::String key = jstringToWtfString(env, jkey);
2587 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
2590 return record->left;
2594 return record->right;
2595 if (key == "bottom")
2596 return record->bottom;
2598 return record->level;
2599 if (key == "isReady")
2600 return record->isReady ? 1 : 0;
2604 static float nativeTileProfilingGetFloat(JNIEnv *env, jobject obj, int frame, int tile, jstring jkey)
2606 TileProfileRecord* record = TilesManager::instance()->getProfiler()->getTile(frame, tile);
2607 return record->scale;
2610 #ifdef ANDROID_DUMP_DISPLAY_TREE
2611 static void dumpToFile(const char text[], void* file) {
2612 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
2613 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
2617 static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue)
2619 WTF::String key = jstringToWtfString(env, jkey);
2620 WTF::String value = jstringToWtfString(env, jvalue);
2621 if (key == "inverted") {
2622 if (value == "true")
2623 TilesManager::instance()->setInvertedScreen(true);
2625 TilesManager::instance()->setInvertedScreen(false);
2628 if (key == "inverted_contrast") {
2629 float contrast = value.toFloat();
2630 TilesManager::instance()->setInvertedScreenContrast(contrast);
2633 if (key == "enable_cpu_upload_path") {
2634 TilesManager::instance()->transferQueue()->setTextureUploadType(
2635 value == "true" ? CpuUpload : GpuUpload);
2641 static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key)
2646 static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level)
2648 if (TilesManager::hardwareAccelerationEnabled()) {
2649 bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN);
2650 TilesManager::instance()->deallocateTextures(freeAllTextures);
2654 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
2656 #ifdef ANDROID_DUMP_DISPLAY_TREE
2657 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2658 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2660 if (view && view->getWebViewCore()) {
2661 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
2663 SkFormatDumper dumper(dumpToFile, file);
2666 const char* str = env->GetStringUTFChars(jurl, 0);
2667 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
2668 dumpToFile(str, file);
2669 env->ReleaseStringUTFChars(jurl, str);
2671 // now dump the display tree
2672 SkDumpCanvas canvas(&dumper);
2673 // this will playback the picture into the canvas, which will
2674 // spew its contents to the dumper
2675 view->draw(&canvas, 0, 0, false);
2676 // we're done with the file now
2677 fwrite("\n", 1, 1, file);
2680 #if USE(ACCELERATED_COMPOSITING)
2681 const LayerAndroid* rootLayer = view->compositeRoot();
2683 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
2685 rootLayer->dumpLayers(file, 0);
2694 static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y,
2695 jobject rect, jobject bounds)
2697 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2698 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2699 SkIRect nativeRect, nativeBounds;
2700 int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds);
2702 GraphicsJNI::irect_to_jrect(nativeRect, env, rect);
2704 GraphicsJNI::irect_to_jrect(nativeBounds, env, bounds);
2708 static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x,
2711 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
2712 WebView* view = GET_NATIVE_VIEW(env, obj);
2713 LayerAndroid* root = view->compositeRoot();
2716 LayerAndroid* layer = root->findById(layerId);
2717 if (!layer || !layer->contentIsScrollable())
2719 return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
2724 static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling)
2726 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2727 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2728 view->setIsScrolling(isScrolling);
2731 static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled)
2733 BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster);
2736 static int nativeGetBackgroundColor(JNIEnv* env, jobject obj)
2738 WebView* view = GET_NATIVE_VIEW(env, obj);
2739 BaseLayerAndroid* baseLayer = view->getBaseLayer();
2741 WebCore::Color color = baseLayer->getBackgroundColor();
2742 if (color.isValid())
2743 return SkColorSetARGB(color.alpha(), color.red(),
2744 color.green(), color.blue());
2746 return SK_ColorWHITE;
2752 static JNINativeMethod gJavaWebViewMethods[] = {
2753 { "nativeCacheHitFramePointer", "()I",
2754 (void*) nativeCacheHitFramePointer },
2755 { "nativeCacheHitIsPlugin", "()Z",
2756 (void*) nativeCacheHitIsPlugin },
2757 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
2758 (void*) nativeCacheHitNodeBounds },
2759 { "nativeCacheHitNodePointer", "()I",
2760 (void*) nativeCacheHitNodePointer },
2761 { "nativeClearCursor", "()V",
2762 (void*) nativeClearCursor },
2763 { "nativeCreate", "(ILjava/lang/String;)V",
2764 (void*) nativeCreate },
2765 { "nativeCursorFramePointer", "()I",
2766 (void*) nativeCursorFramePointer },
2767 { "nativePageShouldHandleShiftAndArrows", "()Z",
2768 (void*) nativePageShouldHandleShiftAndArrows },
2769 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
2770 (void*) nativeCursorNodeBounds },
2771 { "nativeCursorNodePointer", "()I",
2772 (void*) nativeCursorNodePointer },
2773 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
2774 (void*) nativeCursorIntersects },
2775 { "nativeCursorIsAnchor", "()Z",
2776 (void*) nativeCursorIsAnchor },
2777 { "nativeCursorIsTextInput", "()Z",
2778 (void*) nativeCursorIsTextInput },
2779 { "nativeCursorPosition", "()Landroid/graphics/Point;",
2780 (void*) nativeCursorPosition },
2781 { "nativeCursorText", "()Ljava/lang/String;",
2782 (void*) nativeCursorText },
2783 { "nativeCursorWantsKeyEvents", "()Z",
2784 (void*)nativeCursorWantsKeyEvents },
2785 { "nativeDebugDump", "()V",
2786 (void*) nativeDebugDump },
2787 { "nativeDestroy", "()V",
2788 (void*) nativeDestroy },
2789 { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
2790 (void*) nativeDraw },
2791 { "nativeGetDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;FI)I",
2792 (void*) nativeGetDrawGLFunction },
2793 { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;)V",
2794 (void*) nativeUpdateDrawGLFunction },
2795 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
2796 (void*) nativeDumpDisplayTree },
2797 { "nativeEvaluateLayersAnimations", "()Z",
2798 (void*) nativeEvaluateLayersAnimations },
2799 { "nativeExtendSelection", "(II)V",
2800 (void*) nativeExtendSelection },
2801 { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
2802 (void*) nativeFindAll },
2803 { "nativeFindNext", "(Z)V",
2804 (void*) nativeFindNext },
2805 { "nativeFindIndex", "()I",
2806 (void*) nativeFindIndex},
2807 { "nativeFocusCandidateFramePointer", "()I",
2808 (void*) nativeFocusCandidateFramePointer },
2809 { "nativeFocusCandidateHasNextTextfield", "()Z",
2810 (void*) focusCandidateHasNextTextfield },
2811 { "nativeFocusCandidateIsPassword", "()Z",
2812 (void*) nativeFocusCandidateIsPassword },
2813 { "nativeFocusCandidateIsRtlText", "()Z",
2814 (void*) nativeFocusCandidateIsRtlText },
2815 { "nativeFocusCandidateIsTextInput", "()Z",
2816 (void*) nativeFocusCandidateIsTextInput },
2817 { "nativeFocusCandidateLineHeight", "()I",
2818 (void*) nativeFocusCandidateLineHeight },
2819 { "nativeFocusCandidateMaxLength", "()I",
2820 (void*) nativeFocusCandidateMaxLength },
2821 { "nativeFocusCandidateIsAutoComplete", "()Z",
2822 (void*) nativeFocusCandidateIsAutoComplete },
2823 { "nativeFocusCandidateName", "()Ljava/lang/String;",
2824 (void*) nativeFocusCandidateName },
2825 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
2826 (void*) nativeFocusCandidateNodeBounds },
2827 { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;",
2828 (void*) nativeFocusCandidatePaddingRect },
2829 { "nativeFocusCandidatePointer", "()I",
2830 (void*) nativeFocusCandidatePointer },
2831 { "nativeFocusCandidateText", "()Ljava/lang/String;",
2832 (void*) nativeFocusCandidateText },
2833 { "nativeFocusCandidateTextSize", "()F",
2834 (void*) nativeFocusCandidateTextSize },
2835 { "nativeFocusCandidateType", "()I",
2836 (void*) nativeFocusCandidateType },
2837 { "nativeFocusIsPlugin", "()Z",
2838 (void*) nativeFocusIsPlugin },
2839 { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;",
2840 (void*) nativeFocusNodeBounds },
2841 { "nativeFocusNodePointer", "()I",
2842 (void*) nativeFocusNodePointer },
2843 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
2844 (void*) nativeGetCursorRingBounds },
2845 { "nativeGetSelection", "()Ljava/lang/String;",
2846 (void*) nativeGetSelection },
2847 { "nativeHasCursorNode", "()Z",
2848 (void*) nativeHasCursorNode },
2849 { "nativeHasFocusNode", "()Z",
2850 (void*) nativeHasFocusNode },
2851 { "nativeHideCursor", "()V",
2852 (void*) nativeHideCursor },
2853 { "nativeHitSelection", "(II)Z",
2854 (void*) nativeHitSelection },
2855 { "nativeImageURI", "(II)Ljava/lang/String;",
2856 (void*) nativeImageURI },
2857 { "nativeInstrumentReport", "()V",
2858 (void*) nativeInstrumentReport },
2859 { "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
2860 (void*) nativeLayerBounds },
2861 { "nativeMotionUp", "(III)Z",
2862 (void*) nativeMotionUp },
2863 { "nativeMoveCursor", "(IIZ)Z",
2864 (void*) nativeMoveCursor },
2865 { "nativeMoveCursorToNextTextInput", "()Z",
2866 (void*) nativeMoveCursorToNextTextInput },
2867 { "nativeMoveGeneration", "()I",
2868 (void*) nativeMoveGeneration },
2869 { "nativeMoveSelection", "(II)V",
2870 (void*) nativeMoveSelection },
2871 { "nativePointInNavCache", "(III)Z",
2872 (void*) nativePointInNavCache },
2873 { "nativeRecordButtons", "(ZZZ)V",
2874 (void*) nativeRecordButtons },
2875 { "nativeResetSelection", "()V",
2876 (void*) nativeResetSelection },
2877 { "nativeSelectableText", "()Landroid/graphics/Point;",
2878 (void*) nativeSelectableText },
2879 { "nativeSelectAll", "()V",
2880 (void*) nativeSelectAll },
2881 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
2882 (void*) nativeSelectBestAt },
2883 { "nativeSelectAt", "(II)V",
2884 (void*) nativeSelectAt },
2885 { "nativeSelectionX", "()I",
2886 (void*) nativeSelectionX },
2887 { "nativeSelectionY", "()I",
2888 (void*) nativeSelectionY },
2889 { "nativeSetExtendSelection", "()V",
2890 (void*) nativeSetExtendSelection },
2891 { "nativeSetFindIsEmpty", "()V",
2892 (void*) nativeSetFindIsEmpty },
2893 { "nativeSetFindIsUp", "(Z)V",
2894 (void*) nativeSetFindIsUp },
2895 { "nativeSetHeightCanMeasure", "(Z)V",
2896 (void*) nativeSetHeightCanMeasure },
2897 { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V",
2898 (void*) nativeSetBaseLayer },
2899 { "nativeGetTextSelectionRegion", "(Landroid/graphics/Region;)V",
2900 (void*) nativeGetTextSelectionRegion },
2901 { "nativeGetBaseLayer", "()I",
2902 (void*) nativeGetBaseLayer },
2903 { "nativeReplaceBaseContent", "(I)V",
2904 (void*) nativeReplaceBaseContent },
2905 { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
2906 (void*) nativeCopyBaseContentToPicture },
2907 { "nativeHasContent", "()Z",
2908 (void*) nativeHasContent },
2909 { "nativeSetSelectionPointer", "(ZFII)V",
2910 (void*) nativeSetSelectionPointer },
2911 { "nativeShowCursorTimed", "()V",
2912 (void*) nativeShowCursorTimed },
2913 { "nativeRegisterPageSwapCallback", "()V",
2914 (void*) nativeRegisterPageSwapCallback },
2915 { "nativeTileProfilingStart", "()V",
2916 (void*) nativeTileProfilingStart },
2917 { "nativeTileProfilingStop", "()F",
2918 (void*) nativeTileProfilingStop },
2919 { "nativeTileProfilingClear", "()V",
2920 (void*) nativeTileProfilingClear },
2921 { "nativeTileProfilingNumFrames", "()I",
2922 (void*) nativeTileProfilingNumFrames },
2923 { "nativeTileProfilingNumTilesInFrame", "(I)I",
2924 (void*) nativeTileProfilingNumTilesInFrame },
2925 { "nativeTileProfilingGetInt", "(IILjava/lang/String;)I",
2926 (void*) nativeTileProfilingGetInt },
2927 { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
2928 (void*) nativeTileProfilingGetFloat },
2929 { "nativeStartSelection", "(II)Z",
2930 (void*) nativeStartSelection },
2931 { "nativeStopGL", "()V",
2932 (void*) nativeStopGL },
2933 { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
2934 (void*) nativeSubtractLayers },
2935 { "nativeTextGeneration", "()I",
2936 (void*) nativeTextGeneration },
2937 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
2938 (void*) nativeUpdateCachedTextfield },
2939 { "nativeWordSelection", "(II)Z",
2940 (void*) nativeWordSelection },
2941 { "nativeGetBlockLeftEdge", "(IIF)I",
2942 (void*) nativeGetBlockLeftEdge },
2943 { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
2944 (void*) nativeScrollableLayer },
2945 { "nativeScrollLayer", "(III)Z",
2946 (void*) nativeScrollLayer },
2947 { "nativeSetIsScrolling", "(Z)V",
2948 (void*) nativeSetIsScrolling },
2949 { "nativeUseHardwareAccelSkia", "(Z)V",
2950 (void*) nativeUseHardwareAccelSkia },
2951 { "nativeGetBackgroundColor", "()I",
2952 (void*) nativeGetBackgroundColor },
2953 { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z",
2954 (void*) nativeSetProperty },
2955 { "nativeGetProperty", "(Ljava/lang/String;)Ljava/lang/String;",
2956 (void*) nativeGetProperty },
2957 { "nativeOnTrimMemory", "(I)V",
2958 (void*) nativeOnTrimMemory },
2961 int registerWebView(JNIEnv* env)
2963 jclass clazz = env->FindClass("android/webkit/WebView");
2964 LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
2965 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
2966 LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
2967 env->DeleteLocalRef(clazz);
2969 return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
2972 } // namespace android