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 "AtomicString.h"
33 #include "CachedFrame.h"
34 #include "CachedNode.h"
35 #include "CachedRoot.h"
37 #include "FindCanvas.h"
39 #include "GraphicsJNI.h"
40 #include "HTMLInputElement.h"
43 #include "LayerAndroid.h"
45 #include "PlatformGraphicsContext.h"
46 #include "PlatformString.h"
47 #include "SelectText.h"
48 #include "SkBlurMaskFilter.h"
50 #include "SkCornerPathEffect.h"
51 #include "SkDumpCanvas.h"
53 #include "SkPicture.h"
54 #include "SkPixelXorXfermode.h"
57 #ifdef ANDROID_INSTRUMENT
58 #include "TimeCounter.h"
60 #include "WebCoreJni.h"
61 #include "WebViewCore.h"
62 #include "android_graphics.h"
64 #ifdef GET_NATIVE_VIEW
65 #undef GET_NATIVE_VIEW
68 #define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
70 #include <JNIUtility.h>
73 #include <ui/KeycodeLabels.h>
77 static jfieldID gWebViewField;
79 //-------------------------------------
81 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
83 jmethodID m = env->GetMethodID(clazz, name, signature);
84 LOG_ASSERT(m, "Could not find method %s", name);
88 //-------------------------------------
89 // This class provides JNI for making calls into native code from the UI side
90 // of the multi-threaded WebView.
94 enum FrameCachePermission {
102 jmethodID m_clearTextEntry;
103 jmethodID m_overrideLoading;
104 jmethodID m_scrollBy;
105 jmethodID m_sendMoveFocus;
106 jmethodID m_sendMoveMouse;
107 jmethodID m_sendMoveMouseIfLatest;
108 jmethodID m_sendMotionUp;
109 jmethodID m_domChangedFocus;
110 jmethodID m_getScaledMaxXScroll;
111 jmethodID m_getScaledMaxYScroll;
112 jmethodID m_getVisibleRect;
113 jmethodID m_rebuildWebTextView;
114 jmethodID m_viewInvalidate;
115 jmethodID m_viewInvalidateRect;
116 jmethodID m_postInvalidateDelayed;
119 jmethodID m_rectWidth;
120 jmethodID m_rectHeight;
121 AutoJObject object(JNIEnv* env) {
122 return getRealObject(env, m_obj);
126 WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
128 jclass clazz = env->FindClass("android/webkit/WebView");
129 // m_javaGlue = new JavaGlue;
130 m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
131 m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
132 m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
133 m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
134 m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
135 m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
136 m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(Z)V");
137 m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V");
138 m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V");
139 m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
140 m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
141 m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
142 m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
143 m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
144 m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
145 m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
146 "viewInvalidateDelayed", "(JIIII)V");
147 jclass rectClass = env->FindClass("android/graphics/Rect");
148 LOG_ASSERT(rectClass, "Could not find Rect class");
149 m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
150 m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
151 m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
152 m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
154 env->SetIntField(javaWebView, gWebViewField, (jint)this);
155 m_viewImpl = (WebViewCore*) viewImpl;
159 m_heightCanMeasure = false;
160 m_followedLink = false;
163 m_ringAnimationEnd = 0;
164 m_selStart.setEmpty();
167 m_hasCurrentLocation = false;
168 m_isFindPaintSetUp = false;
173 if (m_javaGlue.m_obj)
175 JNIEnv* env = JSC::Bindings::getJNIEnv();
176 env->DeleteWeakGlobalRef(m_javaGlue.m_obj);
177 m_javaGlue.m_obj = 0;
179 delete m_frameCacheUI;
180 delete m_navPictureUI;
185 WebViewCore* getWebViewCore() const {
189 // removes the cursor altogether (e.g., when going to a new page)
192 CachedRoot* root = getFrameCache(AllowNewer);
196 m_viewImpl->m_hasCursorBounds = false;
201 // leaves the cursor where it is, but suppresses drawing it
204 CachedRoot* root = getFrameCache(AllowNewer);
208 m_viewImpl->m_hasCursorBounds = false;
213 void clearTextEntry()
215 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
216 JNIEnv* env = JSC::Bindings::getJNIEnv();
217 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_clearTextEntry);
224 CachedRoot* root = getFrameCache(DontAllowNewer);
226 root->mDebug.print();
230 // Traverse our stored array of buttons that are in our picture, and update
231 // their subpictures according to their current state.
232 // Called from the UI thread. This is the one place in the UI thread where we
233 // access the buttons stored in the WebCore thread.
234 // hasFocus keeps track of whether the WebView has focus && windowFocus.
235 // If not, we do not want to draw the button in a selected or pressed state
236 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
238 bool cursorIsOnButton = false;
239 const CachedNode* cachedCursor = 0;
240 // Lock the mutex, since we now share with the WebCore thread.
241 m_viewImpl->gButtonMutex.lock();
242 if (m_viewImpl->m_buttons.size()) {
243 // FIXME: In a future change, we should keep track of whether the selection
244 // has changed to short circuit (note that we would still need to update
245 // if we received new buttons from the WebCore thread).
246 WebCore::Node* cursor = 0;
247 CachedRoot* root = getFrameCache(DontAllowNewer);
249 cachedCursor = root->currentCursor();
251 cursor = (WebCore::Node*) cachedCursor->nodePointer();
254 // Traverse the array, and update each button, depending on whether it
256 Container* end = m_viewImpl->m_buttons.end();
257 for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
258 WebCore::RenderSkinAndroid::State state;
259 if (ptr->matches(cursor)) {
260 cursorIsOnButton = true;
261 // If the WebView is out of focus/window focus, set the state to
262 // normal, but still keep track of the fact that the selected is a
265 state = WebCore::RenderSkinAndroid::kNormal;
266 } else if (m_followedLink || pressed) {
267 state = WebCore::RenderSkinAndroid::kPressed;
269 state = WebCore::RenderSkinAndroid::kFocused;
272 state = WebCore::RenderSkinAndroid::kNormal;
274 ptr->updateFocusState(state);
277 m_viewImpl->gButtonMutex.unlock();
278 if (invalidate && cachedCursor && cursorIsOnButton) {
279 const WebCore::IntRect& b = cachedCursor->getBounds();
280 viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom());
284 // These two functions separate out the particular look of the drawn find
285 // matches from the code that draws them. This function sets up the paints that
286 // are used to draw the matches.
287 void setUpFindPaint()
289 // Set up the foreground paint
290 m_findPaint.setAntiAlias(true);
291 const SkScalar roundiness = SkIntToScalar(2);
292 SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness);
293 m_findPaint.setPathEffect(cornerEffect);
294 m_findPaint.setARGB(255, 132, 190, 0);
296 // Set up the background blur paint.
297 m_findBlurPaint.setAntiAlias(true);
298 m_findBlurPaint.setARGB(204, 0, 0, 0);
299 m_findBlurPaint.setPathEffect(cornerEffect);
300 cornerEffect->unref();
301 SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1,
302 SkBlurMaskFilter::kNormal_BlurStyle);
303 m_findBlurPaint.setMaskFilter(blurFilter)->unref();
304 m_isFindPaintSetUp = true;
307 // Draw the match specified by region to the canvas.
308 void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused)
310 // For the match which has focus, use a filled paint. For the others, use
313 m_findPaint.setStyle(SkPaint::kFill_Style);
314 m_findBlurPaint.setStyle(SkPaint::kFill_Style);
316 m_findPaint.setStyle(SkPaint::kStroke_Style);
317 m_findPaint.setStrokeWidth(SK_Scalar1);
318 m_findBlurPaint.setStyle(SkPaint::kStroke_Style);
319 m_findBlurPaint.setStrokeWidth(SkIntToScalar(2));
321 // Find the path for the current match
323 region.getBoundaryPath(&matchPath);
324 // Offset the path for a blurred shadow
326 matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath);
329 saveCount = canvas->save();
330 canvas->clipPath(matchPath, SkRegion::kDifference_Op);
332 // Draw the blurred background
333 canvas->drawPath(blurPath, m_findBlurPaint);
335 canvas->restoreToCount(saveCount);
337 // Draw the foreground
338 canvas->drawPath(matchPath, m_findPaint);
341 bool scrollRectOnScreen(int left, int top, int right, int bottom)
343 WebCore::IntRect visible;
344 getVisibleRect(&visible);
346 if (left < visible.x()) {
347 dx = left - visible.x();
348 // Only scroll right if the entire width can fit on screen.
349 } else if (right > visible.right() && right - left < visible.width()) {
350 dx = right - visible.right();
353 if (top < visible.y()) {
354 dy = top - visible.y();
355 // Only scroll down if the entire height can fit on screen
356 } else if (bottom > visible.bottom() && bottom - top < visible.height()) {
357 dy = bottom - visible.bottom();
359 if ((dx|dy) == 0 || !scrollBy(dx, dy))
365 // Put a cap on the number of matches to draw. If the current page has more
366 // matches than this, only draw the focused match.
367 #define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
369 void drawMatches(SkCanvas* canvas)
371 if (!m_matches || !m_matches->size())
373 if (m_findIndex >= m_matches->size())
375 const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
376 const SkRegion& currentMatchRegion = matchInfo.getLocation();
377 const SkIRect& currentMatchBounds = currentMatchRegion.getBounds();
378 if (scrollRectOnScreen(currentMatchBounds.fLeft, currentMatchBounds.fTop,
379 currentMatchBounds.fRight, currentMatchBounds.fBottom))
382 // Set up the paints used for drawing the matches
383 if (!m_isFindPaintSetUp)
386 // Draw the current match
387 drawMatch(currentMatchRegion, canvas, true);
388 // Now draw the picture, so that it shows up on top of the rectangle
389 canvas->drawPicture(*matchInfo.getPicture());
392 unsigned numberOfMatches = m_matches->size();
393 if (numberOfMatches > 1
394 && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
395 WebCore::IntRect visible;
396 getVisibleRect(&visible);
397 SkIRect visibleIRect(visible);
398 for(unsigned i = 0; i < numberOfMatches; i++) {
399 // The current match has already been drawn
400 if (i == m_findIndex)
402 const SkRegion& region = (*m_matches)[i].getLocation();
403 // Do not draw matches which intersect the current one, or if it is
405 if (currentMatchRegion.intersects(region)
406 || !region.intersects(visibleIRect))
408 drawMatch(region, canvas, false);
413 void resetCursorRing()
415 m_followedLink = false;
416 m_viewImpl->m_hasCursorBounds = false;
419 void drawCursorRing(SkCanvas* canvas)
421 const CachedRoot* root = getFrameCache(AllowNewer);
423 DBG_NAV_LOG("!root");
427 const CachedFrame* frame;
428 const CachedNode* node = root->currentCursor(&frame);
430 DBG_NAV_LOGV("%s", "!node");
434 if (node->isHidden()) {
435 DBG_NAV_LOG("node->isHidden()");
436 m_viewImpl->m_hasCursorBounds = false;
439 const WTF::Vector<WebCore::IntRect>* rings = &node->cursorRings();
440 if (!rings->size()) {
441 DBG_NAV_LOG("!rings->size()");
442 m_viewImpl->m_hasCursorBounds = false;
445 bool isButton = false;
446 m_viewImpl->gButtonMutex.lock();
447 // If this is a button drawn by us (rather than webkit) do not draw the
448 // cursor ring, since its cursor will be shown by a change in what we draw.
449 // Should be in sync with recordButtons, since that will be called
451 if (m_viewImpl->m_buttons.size() > 0) {
452 WebCore::Node* cursorPointer = (WebCore::Node*) node->nodePointer();
453 Container* end = m_viewImpl->m_buttons.end();
454 for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
455 if (ptr->matches(cursorPointer)) {
461 m_viewImpl->gButtonMutex.unlock();
462 WebCore::IntRect bounds = node->bounds();
463 updateCursorBounds(root, frame, node);
465 WTF::Vector<WebCore::IntRect> oneRing;
466 bool useHitBounds = node->useHitBounds();
468 bounds = node->hitBounds();
470 if (useHitBounds || node->useBounds()) {
471 oneRing.append(bounds);
474 bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER));
475 if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) {
476 DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)"
477 " bounds=(%d,%d,w=%d,h=%d)", node->index(), node->nodePointer(),
478 bounds.x(), bounds.y(), bounds.width(), bounds.height());
479 m_followedLink = false;
482 if (!node->hasCursorRing() || (node->isPlugin() && node->isFocus()))
484 CursorRing::Flavor flavor = CursorRing::NORMAL_FLAVOR;
486 flavor = node->isSyntheticLink()
487 ? CursorRing::FAKE_FLAVOR : CursorRing::NORMAL_FLAVOR;
488 if (m_followedLink) {
489 flavor = static_cast<CursorRing::Flavor>
490 (flavor + CursorRing::NORMAL_ANIMATING);
493 const WebCore::IntRect& ring = (*rings)[0];
494 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d"
495 " (%d, %d, %d, %d) isPlugin=%s",
496 node->index(), node->nodePointer(),
497 flavor == CursorRing::FAKE_FLAVOR ? "FAKE_FLAVOR" :
498 flavor == CursorRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
499 flavor == CursorRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR",
500 rings->size(), ring.x(), ring.y(), ring.width(), ring.height(),
501 node->isPlugin() ? "true" : "false");
504 if (isButton || flavor >= CursorRing::NORMAL_ANIMATING) {
505 SkMSec time = SkTime::GetMSecs();
506 if (time < m_ringAnimationEnd) {
507 // views assume that inval bounds coordinates are non-negative
508 bounds.intersect(WebCore::IntRect(0, 0, INT_MAX, INT_MAX));
509 postInvalidateDelayed(m_ringAnimationEnd - time, bounds);
513 m_followedLink = false;
514 flavor = static_cast<CursorRing::Flavor>
515 (flavor - CursorRing::NORMAL_ANIMATING);
519 CursorRing::DrawRing(canvas, *rings, flavor);
522 bool cursorIsTextInput(FrameCachePermission allowNewer)
524 CachedRoot* root = getFrameCache(allowNewer);
526 DBG_NAV_LOG("!root");
529 const CachedNode* cursor = root->currentCursor();
531 DBG_NAV_LOG("!cursor");
534 DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false");
535 return cursor->isTextInput();
538 void cursorRingBounds(WebCore::IntRect* bounds)
540 DBG_NAV_LOGD("%s", "");
541 CachedRoot* root = getFrameCache(DontAllowNewer);
543 const CachedNode* cachedNode = root->currentCursor();
545 cachedNode->cursorRingBounds(bounds);
546 DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
547 bounds->width(), bounds->height());
551 *bounds = WebCore::IntRect(0, 0, 0, 0);
556 m_viewImpl->gCursorBoundsMutex.lock();
557 bool hasCursorBounds = m_viewImpl->m_hasCursorBounds;
558 IntRect bounds = m_viewImpl->m_cursorBounds;
559 m_viewImpl->gCursorBoundsMutex.unlock();
560 if (!hasCursorBounds)
563 const CachedFrame* frame;
564 const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, false);
567 // require that node have approximately the same bounds (+/- 4) and the same
569 IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
570 bounds.y() + (bounds.height() >> 1));
571 IntRect newBounds = node->bounds();
572 IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
573 newBounds.y() + (newBounds.height() >> 1));
574 DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
575 " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)",
576 oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(),
577 bounds.x(), bounds.y(), bounds.width(), bounds.height(),
578 newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
579 if (abs(oldCenter.x() - newCenter.x()) > 2)
581 if (abs(oldCenter.y() - newCenter.y()) > 2)
583 if (abs(bounds.x() - newBounds.x()) > 4)
585 if (abs(bounds.y() - newBounds.y()) > 4)
587 if (abs(bounds.right() - newBounds.right()) > 4)
589 if (abs(bounds.bottom() - newBounds.bottom()) > 4)
591 DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)",
592 node, frame, x, y, bounds.x(), bounds.y(), bounds.width(),
594 m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame),
595 const_cast<CachedNode*>(node));
598 CachedRoot* getFrameCache(FrameCachePermission allowNewer)
600 if (!m_viewImpl->m_updatedFrameCache) {
601 DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache");
602 return m_frameCacheUI;
604 if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) {
605 DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d"
606 " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation);
607 return m_frameCacheUI;
609 DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
610 bool hadCursor = m_frameCacheUI && m_frameCacheUI->currentCursor();
611 const CachedNode* oldFocus = m_frameCacheUI ? m_frameCacheUI->currentFocus() : 0;
612 m_viewImpl->gFrameCacheMutex.lock();
613 delete m_frameCacheUI;
614 delete m_navPictureUI;
615 m_viewImpl->m_updatedFrameCache = false;
616 m_frameCacheUI = m_viewImpl->m_frameCacheKit;
617 m_navPictureUI = m_viewImpl->m_navPictureKit;
618 m_viewImpl->m_frameCacheKit = 0;
619 m_viewImpl->m_navPictureKit = 0;
620 m_viewImpl->gFrameCacheMutex.unlock();
622 if (oldFocus && m_frameCacheUI) {
623 const CachedNode* newFocus = m_frameCacheUI->currentFocus();
624 if (newFocus && oldFocus->nodePointer() != newFocus->nodePointer()
625 && oldFocus->isTextInput() && newFocus->isTextInput()
626 && newFocus != m_frameCacheUI->currentCursor()) {
627 // The focus has changed. We may need to update things.
628 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
629 JNIEnv* env = JSC::Bindings::getJNIEnv();
630 env->CallVoidMethod(m_javaGlue.object(env).get(),
631 m_javaGlue.m_domChangedFocus);
635 if (hadCursor && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
636 viewInvalidate(); // redraw in case cursor ring is still visible
637 return m_frameCacheUI;
640 int getScaledMaxXScroll()
642 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
643 JNIEnv* env = JSC::Bindings::getJNIEnv();
644 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll);
649 int getScaledMaxYScroll()
651 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
652 JNIEnv* env = JSC::Bindings::getJNIEnv();
653 int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll);
658 void getVisibleRect(WebCore::IntRect* rect)
660 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
661 JNIEnv* env = JSC::Bindings::getJNIEnv();
662 jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect);
664 int left = (int) env->GetIntField(jRect, m_javaGlue.m_rectLeft);
667 int top = (int) env->GetIntField(jRect, m_javaGlue.m_rectTop);
670 int width = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectWidth);
672 rect->setWidth(width);
673 int height = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectHeight);
675 rect->setHeight(height);
676 env->DeleteLocalRef(jRect);
680 static CachedFrame::Direction KeyToDirection(KeyCode keyCode)
683 case kKeyCodeDpadRight:
684 DBG_NAV_LOGD("keyCode=%s", "right");
685 return CachedFrame::RIGHT;
686 case kKeyCodeDpadLeft:
687 DBG_NAV_LOGD("keyCode=%s", "left");
688 return CachedFrame::LEFT;
689 case kKeyCodeDpadDown:
690 DBG_NAV_LOGD("keyCode=%s", "down");
691 return CachedFrame::DOWN;
693 DBG_NAV_LOGD("keyCode=%s", "up");
694 return CachedFrame::UP;
696 DBG_NAV_LOGD("bad key %d sent", keyCode);
697 return CachedFrame::UNINITIALIZED;
701 WebCore::String imageURI(int x, int y)
703 const CachedRoot* root = getFrameCache(DontAllowNewer);
704 return root ? root->imageURI(x, y) : WebCore::String();
707 bool cursorWantsKeyEvents()
709 const CachedRoot* root = getFrameCache(DontAllowNewer);
711 const CachedNode* focus = root->currentCursor();
713 return focus->wantsKeyEvents();
718 // This needs to be called each time we call CachedRoot::setCursor() with
719 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
720 // about the cursor is incorrect. When we call setCursor(0,0), we need
721 // to set m_viewImpl->hasCursorBounds to false.
722 void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame,
723 const CachedNode* cachedNode)
725 LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
726 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
727 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
728 m_viewImpl->gCursorBoundsMutex.lock();
729 m_viewImpl->m_hasCursorBounds = !cachedNode->isHidden();
730 // If m_viewImpl->m_hasCursorBounds is false, we never look at the other
731 // values, so do not bother setting them.
732 if (m_viewImpl->m_hasCursorBounds) {
733 WebCore::IntRect bounds = cachedNode->bounds();
734 if (m_viewImpl->m_cursorBounds != bounds)
735 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
736 bounds.x(), bounds.y(), bounds.width(), bounds.height());
737 m_viewImpl->m_cursorBounds = cachedNode->bounds();
738 m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds();
739 m_viewImpl->m_cursorFrame = cachedFrame->framePointer();
740 root->getSimulatedMousePosition(&m_viewImpl->m_cursorLocation);
741 m_viewImpl->m_cursorNode = cachedNode->nodePointer();
743 m_viewImpl->gCursorBoundsMutex.unlock();
746 /* returns true if the key had no effect (neither scrolled nor changed cursor) */
747 bool moveCursor(int keyCode, int count, bool ignoreScroll)
749 CachedRoot* root = getFrameCache(AllowNewer);
751 DBG_NAV_LOG("!root");
755 m_viewImpl->m_moveGeneration++;
756 CachedFrame::Direction direction = KeyToDirection((KeyCode) keyCode);
757 const CachedFrame* cachedFrame, * oldFrame = 0;
758 const CachedNode* cursor = root->currentCursor(&oldFrame);
759 WebCore::IntPoint cursorLocation = root->cursorLocation();
760 DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
761 cursor ? cursor->index() : 0,
762 cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
763 WebCore::IntRect visibleRect;
764 getVisibleRect(&visibleRect);
765 DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
766 visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
767 root->setVisibleRect(visibleRect);
768 int xMax = getScaledMaxXScroll();
769 int yMax = getScaledMaxYScroll();
770 root->setMaxScroll(xMax, yMax);
771 const CachedNode* cachedNode = 0;
775 if (!cursor || !m_followedLink)
776 root->setScrollOnly(m_followedLink);
777 while (--counter >= 0) {
778 WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
779 cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
783 DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}"
784 "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
785 cachedNode ? cachedNode->nodePointer() : 0,
786 root->cursorLocation().x(), root->cursorLocation().y(),
787 cachedNode ? cachedNode->bounds().x() : 0,
788 cachedNode ? cachedNode->bounds().y() : 0,
789 cachedNode ? cachedNode->bounds().width() : 0,
790 cachedNode ? cachedNode->bounds().height() : 0);
791 // If !m_heightCanMeasure (such as in the browser), we want to scroll no
793 if (!ignoreScroll && (!m_heightCanMeasure ||
795 (cursor && cursor->nodePointer() == cachedNode->nodePointer())))
797 if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
798 SkTime::GetMSecs() - m_lastDxTime < 1000)
799 root->checkForJiggle(&dx);
800 DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
802 this->scrollBy(dx, dy);
804 m_lastDxTime = SkTime::GetMSecs();
808 updateCursorBounds(root, cachedFrame, cachedNode);
809 root->setCursor(const_cast<CachedFrame*>(cachedFrame),
810 const_cast<CachedNode*>(cachedNode));
811 bool disableFocusController = cachedNode != root->currentFocus()
812 && cachedNode->wantsKeyEvents();
813 sendMoveMouseIfLatest(disableFocusController);
816 int docHeight = root->documentHeight();
817 int docWidth = root->documentWidth();
818 if (visibleRect.bottom() + dy > docHeight)
819 dy = docHeight - visibleRect.bottom();
820 else if (visibleRect.y() + dy < 0)
821 dy = -visibleRect.y();
822 if (visibleRect.right() + dx > docWidth)
823 dx = docWidth - visibleRect.right();
824 else if (visibleRect.x() < 0)
825 dx = -visibleRect.x();
826 result = direction == CachedFrame::LEFT ? dx >= 0 :
827 direction == CachedFrame::RIGHT ? dx <= 0 :
828 direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
833 void notifyProgressFinished()
835 DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer));
836 rebuildWebTextView();
838 if (m_frameCacheUI) {
839 const CachedNode* focus = m_frameCacheUI->currentFocus();
840 DBG_NAV_LOGD("focus %d (nativeNode=%p)",
841 focus ? focus->index() : 0,
842 focus ? focus->nodePointer() : 0);
847 const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
848 const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
855 WebCore::IntRect visibleRect;
856 getVisibleRect(&visibleRect);
857 root->setVisibleRect(visibleRect);
858 return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
861 void selectBestAt(const WebCore::IntRect& rect)
863 const CachedFrame* frame;
865 bool disableFocusController = false;
866 CachedRoot* root = getFrameCache(DontAllowNewer);
867 const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
870 DBG_NAV_LOGD("no nodes found root=%p", root);
871 disableFocusController = true;
872 m_viewImpl->m_hasCursorBounds = false;
874 root->setCursor(0, 0);
876 DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
877 root->rootHistory()->setMouseBounds(node->bounds());
878 updateCursorBounds(root, frame, node);
879 root->setCursor(const_cast<CachedFrame*>(frame),
880 const_cast<CachedNode*>(node));
881 if (!node->wantsKeyEvents()) {
882 disableFocusController = true;
885 sendMoveMouseIfLatest(disableFocusController);
889 WebCore::IntRect getNavBounds()
891 CachedRoot* root = getFrameCache(DontAllowNewer);
892 return root ? root->rootHistory()->navBounds() :
893 WebCore::IntRect(0, 0, 0, 0);
896 void setNavBounds(const WebCore::IntRect& rect)
898 CachedRoot* root = getFrameCache(DontAllowNewer);
901 root->rootHistory()->setNavBounds(rect);
906 const CachedNode* m_cacheHitNode;
907 const CachedFrame* m_cacheHitFrame;
909 bool pointInNavCache(int x, int y, int slop)
911 CachedRoot* root = getFrameCache(AllowNewer);
914 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
916 return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry));
919 bool motionUp(int x, int y, int slop)
921 bool pageScrolled = false;
922 m_followedLink = false;
923 IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
925 CachedRoot* root = getFrameCache(AllowNewer);
928 const CachedFrame* frame = 0;
929 const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
931 DBG_NAV_LOGD("no nodes found root=%p", root);
933 m_viewImpl->m_hasCursorBounds = false;
935 int dx = root->checkForCenter(x, y);
940 sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
946 DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
947 result->index(), x, y, rx, ry);
948 WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
949 setNavBounds(navBounds);
950 root->rootHistory()->setMouseBounds(navBounds);
951 updateCursorBounds(root, frame, result);
952 root->setCursor(const_cast<CachedFrame*>(frame),
953 const_cast<CachedNode*>(result));
954 bool syntheticLink = result->isSyntheticLink();
955 if (!syntheticLink) {
957 (WebCore::Frame*) frame->framePointer(),
958 (WebCore::Node*) result->nodePointer(), rx, ry);
961 if (!result->isTextInput()) {
963 setFollowedLink(true);
965 overrideUrlLoading(result->getExport());
970 int getBlockLeftEdge(int x, int y, float scale)
972 CachedRoot* root = getFrameCache(AllowNewer);
974 return root->getBlockLeftEdge(x, y, scale);
978 void overrideUrlLoading(const WebCore::String& url)
980 JNIEnv* env = JSC::Bindings::getJNIEnv();
981 jstring jName = env->NewString((jchar*) url.characters(), url.length());
982 env->CallVoidMethod(m_javaGlue.object(env).get(),
983 m_javaGlue.m_overrideLoading, jName);
984 env->DeleteLocalRef(jName);
987 void setFindIsUp(bool up)
989 m_viewImpl->m_findIsUp = up;
991 m_hasCurrentLocation = false;
994 void setFollowedLink(bool followed)
996 if ((m_followedLink = followed) != false) {
997 m_ringAnimationEnd = SkTime::GetMSecs() + 500;
1002 void setHeightCanMeasure(bool measure)
1004 m_heightCanMeasure = measure;
1007 SkIRect m_selStart, m_selEnd;
1008 SkRegion m_selRegion;
1009 #define MIN_ARROW_DISTANCE (20 * 20)
1011 void moveSelection(int x, int y, bool extendSelection)
1013 CachedRoot* root = getFrameCache(DontAllowNewer);
1016 const SkPicture& picture = *m_navPictureUI;
1020 area.set(r.x(), r.y(), r.right(), r.bottom());
1021 m_selEnd = CopyPaste::findClosest(picture, area, x, y);
1022 if (!extendSelection)
1023 m_selStart = m_selEnd;
1024 DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
1025 " m_selEnd=(%d, %d, %d, %d)", x, y, extendSelection ? "true" : "false",
1026 m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
1027 m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
1030 const String getSelection()
1035 area.set(r.x(), r.y(), r.right(), r.bottom());
1036 String result = CopyPaste::text(*m_navPictureUI, area, m_selRegion);
1037 DBG_NAV_LOGD("text=%s", result.latin1().data());
1041 void drawSelectionRegion(SkCanvas* canvas)
1043 CachedRoot* root = getFrameCache(DontAllowNewer);
1049 area.set(r.x(), r.y(), r.right(), r.bottom());
1050 m_selRegion.setEmpty();
1051 CopyPaste::buildSelection(*m_navPictureUI, area, m_selStart, m_selEnd, &m_selRegion);
1053 m_selRegion.getBoundaryPath(&path);
1055 paint.setAntiAlias(true);
1056 paint.setColor(SkColorSetARGB(0x40, 255, 51, 204));
1057 canvas->drawPath(path, paint);
1060 void drawSelectionPointer(SkCanvas* canvas, float scale, int x, int y, bool ex)
1064 getSelectionCaret(&path);
1066 getSelectionArrow(&path);
1068 paint.setAntiAlias(true);
1069 paint.setStyle(SkPaint::kStroke_Style);
1070 paint.setColor(SK_ColorBLACK);
1071 SkPixelXorXfermode xorMode(SK_ColorWHITE);
1073 paint.setXfermode(&xorMode);
1075 paint.setStrokeWidth(SK_Scalar1 * 2);
1076 int sc = canvas->save();
1077 canvas->scale(scale, scale);
1078 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
1079 canvas->drawPath(path, paint);
1081 paint.setStyle(SkPaint::kFill_Style);
1082 paint.setColor(SK_ColorWHITE);
1083 canvas->drawPath(path, paint);
1085 canvas->restoreToCount(sc);
1088 void getSelectionArrow(SkPath* path)
1090 const int arrow[] = {
1091 0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
1093 for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
1094 path->lineTo(SkIntToScalar(arrow[index]), SkIntToScalar(arrow[index + 1]));
1098 void getSelectionCaret(SkPath* path)
1100 SkScalar height = SkIntToScalar(m_selStart.fBottom - m_selStart.fTop);
1101 SkScalar dist = height / 4;
1102 path->moveTo(0, -height / 2);
1103 path->rLineTo(0, height);
1104 path->rLineTo(-dist, dist);
1105 path->rMoveTo(0, -SK_Scalar1/2);
1106 path->rLineTo(dist * 2, 0);
1107 path->rMoveTo(0, SK_Scalar1/2);
1108 path->rLineTo(-dist, -dist);
1111 void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
1113 DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr);
1114 JNIEnv* env = JSC::Bindings::getJNIEnv();
1115 env->CallVoidMethod(m_javaGlue.object(env).get(),
1116 m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr);
1117 checkException(env);
1120 void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1122 DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
1123 JNIEnv* env = JSC::Bindings::getJNIEnv();
1124 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMoveMouse,
1125 (jint) framePtr, (jint) nodePtr, x, y);
1126 checkException(env);
1129 void sendMoveMouseIfLatest(bool disableFocusController)
1131 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1132 JNIEnv* env = JSC::Bindings::getJNIEnv();
1133 env->CallVoidMethod(m_javaGlue.object(env).get(),
1134 m_javaGlue.m_sendMoveMouseIfLatest, disableFocusController);
1135 checkException(env);
1139 WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
1141 m_viewImpl->m_touchGeneration = ++m_generation;
1142 DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d",
1143 m_generation, framePtr, nodePtr, x, y);
1144 LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
1145 JNIEnv* env = JSC::Bindings::getJNIEnv();
1146 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp,
1147 m_generation, (jint) framePtr, (jint) nodePtr, x, y);
1148 checkException(env);
1151 // This function is only used by findNext and setMatches. In it, we store
1152 // upper left corner of the match specified by m_findIndex in
1153 // m_currentMatchLocation.
1154 void inline storeCurrentMatchLocation()
1156 SkASSERT(m_findIndex < m_matches->size());
1157 const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds();
1158 m_currentMatchLocation.set(bounds.fLeft, bounds.fTop);
1159 m_hasCurrentLocation = true;
1162 void findNext(bool forward)
1164 if (!m_matches || !m_matches->size())
1168 if (m_findIndex == m_matches->size())
1171 if (m_findIndex == 0) {
1172 m_findIndex = m_matches->size() - 1;
1177 storeCurrentMatchLocation();
1181 // With this call, WebView takes ownership of matches, and is responsible for
1183 void setMatches(WTF::Vector<MatchInfo>* matches)
1187 m_matches = matches;
1188 if (m_matches->size()) {
1189 if (m_hasCurrentLocation) {
1190 for (unsigned i = 0; i < m_matches->size(); i++) {
1191 const SkIRect& rect = (*m_matches)[i].getLocation().getBounds();
1192 if (rect.fLeft == m_currentMatchLocation.fX
1193 && rect.fTop == m_currentMatchLocation.fY) {
1200 // If we did not have a stored location, or if we were unable to restore
1201 // it, store the new one.
1203 storeCurrentMatchLocation();
1205 m_hasCurrentLocation = false;
1210 bool scrollBy(int dx, int dy)
1212 LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
1214 JNIEnv* env = JSC::Bindings::getJNIEnv();
1215 bool result = env->CallBooleanMethod(m_javaGlue.object(env).get(),
1216 m_javaGlue.m_scrollBy, dx, dy, true);
1217 checkException(env);
1221 bool hasCursorNode()
1223 CachedRoot* root = getFrameCache(DontAllowNewer);
1225 DBG_NAV_LOG("!root");
1228 const CachedNode* cursorNode = root->currentCursor();
1229 DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)",
1230 cursorNode ? cursorNode->index() : -1,
1231 cursorNode ? cursorNode->nodePointer() : 0);
1237 CachedRoot* root = getFrameCache(DontAllowNewer);
1239 DBG_NAV_LOG("!root");
1242 const CachedNode* focusNode = root->currentFocus();
1243 DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)",
1244 focusNode ? focusNode->index() : -1,
1245 focusNode ? focusNode->nodePointer() : 0);
1249 void rebuildWebTextView()
1251 JNIEnv* env = JSC::Bindings::getJNIEnv();
1252 env->CallVoidMethod(m_javaGlue.object(env).get(),
1253 m_javaGlue.m_rebuildWebTextView);
1254 checkException(env);
1257 void viewInvalidate()
1259 JNIEnv* env = JSC::Bindings::getJNIEnv();
1260 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate);
1261 checkException(env);
1264 void viewInvalidateRect(int l, int t, int r, int b)
1266 JNIEnv* env = JSC::Bindings::getJNIEnv();
1267 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
1268 checkException(env);
1271 void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
1273 JNIEnv* env = JSC::Bindings::getJNIEnv();
1274 env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed,
1275 delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
1276 checkException(env);
1279 int moveGeneration()
1281 return m_viewImpl->m_moveGeneration;
1284 private: // local state for WebView
1285 // private to getFrameCache(); other functions operate in a different thread
1286 CachedRoot* m_frameCacheUI; // navigation data ready for use
1287 WebViewCore* m_viewImpl;
1288 int m_generation; // associate unique ID with sent kit focus to match with ui
1289 SkPicture* m_navPictureUI;
1290 bool m_followedLink;
1291 SkMSec m_ringAnimationEnd;
1292 // Corresponds to the same-named boolean on the java side.
1293 bool m_heightCanMeasure;
1295 SkMSec m_lastDxTime;
1296 WTF::Vector<MatchInfo>* m_matches;
1297 // Stores the location of the current match.
1298 SkIPoint m_currentMatchLocation;
1299 // Tells whether the value in m_currentMatchLocation is valid.
1300 bool m_hasCurrentLocation;
1301 // Tells whether we have done the setup to draw the Find matches.
1302 bool m_isFindPaintSetUp;
1303 // Paint used to draw our Find matches.
1304 SkPaint m_findPaint;
1305 // Paint used for the background of our Find matches.
1306 SkPaint m_findBlurPaint;
1307 unsigned m_findIndex;
1308 }; // end of WebView class
1311 * Native JNI methods
1313 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
1315 int length = string.length();
1318 jstring ret = env->NewString((jchar *)string.characters(), length);
1319 env->DeleteLocalRef(ret);
1323 static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj)
1325 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1326 ->m_cacheHitFrame->framePointer());
1329 static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj)
1331 WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj)
1332 ->m_cacheHitNode->originalAbsoluteBounds();
1333 jclass rectClass = env->FindClass("android/graphics/Rect");
1334 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1335 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1336 bounds.y(), bounds.right(), bounds.bottom());
1340 static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj)
1342 return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj)
1343 ->m_cacheHitNode->nodePointer());
1346 static void nativeClearCursor(JNIEnv *env, jobject obj)
1348 WebView* view = GET_NATIVE_VIEW(env, obj);
1349 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1350 view->clearCursor();
1353 static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl)
1355 WebView* webview = new WebView(env, obj, viewImpl);
1356 // NEED THIS OR SOMETHING LIKE IT!
1360 static jint nativeCursorFramePointer(JNIEnv *env, jobject obj)
1362 WebView* view = GET_NATIVE_VIEW(env, obj);
1363 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1366 const CachedFrame* frame = 0;
1367 (void) root->currentCursor(&frame);
1368 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1371 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj)
1373 WebView* view = GET_NATIVE_VIEW(env, obj);
1374 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1375 return root ? root->currentCursor() : 0;
1378 static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
1379 const CachedFrame** frame)
1381 WebView* view = GET_NATIVE_VIEW(env, obj);
1382 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1383 return root ? root->currentCursor(frame) : 0;
1386 static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj)
1388 WebView* view = GET_NATIVE_VIEW(env, obj);
1389 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1392 const CachedNode* cursor = root->currentCursor();
1393 if (cursor && cursor->wantsKeyEvents())
1395 return root->currentFocus();
1398 static const CachedNode* getFocusNode(JNIEnv *env, jobject obj)
1400 WebView* view = GET_NATIVE_VIEW(env, obj);
1401 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1402 return root ? root->currentFocus() : 0;
1405 static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
1407 WebView* view = GET_NATIVE_VIEW(env, obj);
1408 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1411 const CachedFrame* frame;
1412 const CachedNode* cursor = root->currentCursor(&frame);
1413 if (!cursor || !cursor->wantsKeyEvents())
1414 cursor = root->currentFocus(&frame);
1415 return cursor ? frame->textInput(cursor) : 0;
1418 static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj)
1420 const CachedNode* cursor = getCursorNode(env, obj);
1421 const CachedNode* focus = getFocusNode(env, obj);
1422 return cursor && focus && cursor->nodePointer() == focus->nodePointer();
1425 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
1427 const CachedNode* node = getCursorNode(env, obj);
1428 WebCore::IntRect bounds = node ? node->getBounds()
1429 : WebCore::IntRect(0, 0, 0, 0);
1430 jclass rectClass = env->FindClass("android/graphics/Rect");
1431 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1432 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1433 bounds.y(), bounds.right(), bounds.bottom());
1437 static jint nativeCursorNodePointer(JNIEnv *env, jobject obj)
1439 const CachedNode* node = getCursorNode(env, obj);
1440 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1443 static jobject nativeCursorPosition(JNIEnv *env, jobject obj)
1445 WebView* view = GET_NATIVE_VIEW(env, obj);
1446 const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1447 WebCore::IntPoint pos = WebCore::IntPoint(0, 0);
1449 root->getSimulatedMousePosition(&pos);
1450 jclass pointClass = env->FindClass("android/graphics/Point");
1451 jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
1452 jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
1456 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
1459 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
1460 return WebCore::IntRect(L, T, R - L, B - T);
1463 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
1465 const CachedNode* node = getCursorNode(env, obj);
1466 return node ? node->getBounds().intersects(jrect_to_webrect(env, visRect))
1470 static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
1472 const CachedNode* node = getCursorNode(env, obj);
1473 return node ? node->isAnchor() : false;
1476 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
1478 const CachedNode* node = getCursorNode(env, obj);
1479 return node ? node->isTextInput() : false;
1482 static jobject nativeCursorText(JNIEnv *env, jobject obj)
1484 const CachedNode* node = getCursorNode(env, obj);
1487 WebCore::String value = node->getExport();
1488 return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
1489 value.length()) : 0;
1492 static void nativeDebugDump(JNIEnv *env, jobject obj)
1495 WebView* view = GET_NATIVE_VIEW(env, obj);
1496 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1501 static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv)
1503 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1505 DBG_NAV_LOG("!canv");
1508 WebView* view = GET_NATIVE_VIEW(env, obj);
1510 DBG_NAV_LOG("!view");
1513 view->drawMatches(canvas);
1516 static void setXYWH(SkRect* r, SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
1517 r->set(x, y, x + w, y + h);
1520 static void nativeDrawLayers(JNIEnv *env, jobject obj,
1521 jint layer, jint scrollX, jint scrollY,
1522 jint width, jint height,
1523 jfloat scale, jobject canv)
1532 #if USE(ACCELERATED_COMPOSITING)
1533 LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
1534 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1538 scrollX / scale, scrollY / scale,
1539 width / scale, height / scale);
1540 layerImpl->draw(canvas, &viewPort);
1545 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint layer)
1551 #if USE(ACCELERATED_COMPOSITING)
1552 LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
1553 return layerImpl->evaluateAnimations();
1559 static void nativeDestroyLayer(JNIEnv *env, jobject obj, jint layer)
1565 #if USE(ACCELERATED_COMPOSITING)
1566 LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
1571 static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv)
1573 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1575 DBG_NAV_LOG("!canv");
1578 WebView* view = GET_NATIVE_VIEW(env, obj);
1580 DBG_NAV_LOG("!view");
1583 view->drawCursorRing(canvas);
1586 static void nativeDrawSelectionPointer(JNIEnv *env, jobject obj,
1587 jobject canv, jfloat scale, jint x, jint y, bool ex)
1589 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1591 DBG_NAV_LOG("!canv");
1594 WebView* view = GET_NATIVE_VIEW(env, obj);
1596 DBG_NAV_LOG("!view");
1599 view->drawSelectionPointer(canvas, scale, x, y, ex);
1602 static void nativeDrawSelectionRegion(JNIEnv *env, jobject obj, jobject canv)
1604 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
1606 DBG_NAV_LOG("!canv");
1609 WebView* view = GET_NATIVE_VIEW(env, obj);
1611 DBG_NAV_LOG("!view");
1614 view->drawSelectionRegion(canvas);
1617 static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
1619 WebView* view = GET_NATIVE_VIEW(env, obj);
1620 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1621 WebCore::String uri = view->imageURI(x, y);
1623 unsigned len = uri.length();
1625 ret = env->NewString((jchar*) uri.characters(), len);
1626 env->DeleteLocalRef(ret);
1631 static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj)
1633 WebView* view = GET_NATIVE_VIEW(env, obj);
1634 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1637 const CachedFrame* frame = 0;
1638 const CachedNode* cursor = root->currentCursor(&frame);
1639 if (!cursor || !cursor->wantsKeyEvents())
1640 (void) root->currentFocus(&frame);
1641 return reinterpret_cast<int>(frame ? frame->framePointer() : 0);
1644 static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj)
1646 const CachedInput* input = getInputCandidate(env, obj);
1647 return input && input->inputType() == WebCore::HTMLInputElement::PASSWORD;
1650 static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
1652 const CachedInput* input = getInputCandidate(env, obj);
1653 return input ? input->isRtlText() : false;
1656 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
1658 const CachedNode* node = getFocusCandidate(env, obj);
1659 return node ? node->isTextInput() : false;
1662 static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj)
1664 const CachedInput* input = getInputCandidate(env, obj);
1665 return input ? input->maxLength() : false;
1668 static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
1670 const CachedInput* input = getInputCandidate(env, obj);
1673 const WebCore::String& name = input->name();
1674 return env->NewString((jchar*)name.characters(), name.length());
1677 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
1679 const CachedNode* node = getFocusCandidate(env, obj);
1680 WebCore::IntRect bounds = node ? node->getBounds()
1681 : WebCore::IntRect(0, 0, 0, 0);
1682 jclass rectClass = env->FindClass("android/graphics/Rect");
1683 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1684 jobject rect = env->NewObject(rectClass, init, bounds.x(),
1685 bounds.y(), bounds.right(), bounds.bottom());
1689 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
1691 const CachedNode* node = getFocusCandidate(env, obj);
1692 return reinterpret_cast<int>(node ? node->nodePointer() : 0);
1695 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
1697 const CachedNode* node = getFocusCandidate(env, obj);
1700 WebCore::String value = node->getExport();
1701 return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
1702 value.length()) : 0;
1705 static jint nativeFocusCandidateTextSize(JNIEnv *env, jobject obj)
1707 const CachedInput* input = getInputCandidate(env, obj);
1708 return input ? input->textSize() : 0;
1713 NORMAL_TEXT_FIELD = 0,
1723 static int nativeFocusCandidateType(JNIEnv *env, jobject obj)
1725 const CachedInput* input = getInputCandidate(env, obj);
1726 if (!input) return NONE;
1727 if (!input->isTextField()) return TEXT_AREA;
1728 switch (input->inputType()) {
1729 case HTMLInputElement::PASSWORD:
1731 case HTMLInputElement::SEARCH:
1733 case HTMLInputElement::EMAIL:
1735 case HTMLInputElement::NUMBER:
1737 case HTMLInputElement::TELEPHONE:
1739 case HTMLInputElement::URL:
1742 return NORMAL_TEXT_FIELD;
1746 static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj)
1748 const CachedNode* node = getFocusNode(env, obj);
1749 return node ? node->isPlugin() : false;
1752 static jint nativeFocusNodePointer(JNIEnv *env, jobject obj)
1754 const CachedNode* node = getFocusNode(env, obj);
1755 return node ? reinterpret_cast<int>(node->nodePointer()) : 0;
1758 static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) {
1759 WebView* view = GET_NATIVE_VIEW(env, jwebview);
1760 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1761 return view->cursorWantsKeyEvents();
1764 static void nativeHideCursor(JNIEnv *env, jobject obj)
1766 WebView* view = GET_NATIVE_VIEW(env, obj);
1767 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1771 static void nativeInstrumentReport(JNIEnv *env, jobject obj)
1773 #ifdef ANDROID_INSTRUMENT
1774 TimeCounter::reportNow();
1778 static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
1780 WebView* view = GET_NATIVE_VIEW(env, obj);
1781 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1782 WebCore::IntRect rect = jrect_to_webrect(env, jrect);
1783 view->selectBestAt(rect);
1786 static jint nativeTextGeneration(JNIEnv *env, jobject obj)
1788 WebView* view = GET_NATIVE_VIEW(env, obj);
1789 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1790 return root ? root->textGeneration() : 0;
1793 static bool nativePointInNavCache(JNIEnv *env, jobject obj,
1794 int x, int y, int slop)
1796 return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop);
1799 static bool nativeMotionUp(JNIEnv *env, jobject obj,
1800 int x, int y, int slop)
1802 WebView* view = GET_NATIVE_VIEW(env, obj);
1803 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1804 return view->motionUp(x, y, slop);
1807 static bool nativeHasCursorNode(JNIEnv *env, jobject obj)
1809 return GET_NATIVE_VIEW(env, obj)->hasCursorNode();
1812 static bool nativeHasFocusNode(JNIEnv *env, jobject obj)
1814 return GET_NATIVE_VIEW(env, obj)->hasFocusNode();
1817 static bool nativeMoveCursor(JNIEnv *env, jobject obj,
1818 int key, int count, bool ignoreScroll)
1820 WebView* view = GET_NATIVE_VIEW(env, obj);
1821 DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
1822 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1823 return view->moveCursor(key, count, ignoreScroll);
1826 static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
1827 bool pressed, bool invalidate)
1829 WebView* view = GET_NATIVE_VIEW(env, obj);
1830 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1831 view->nativeRecordButtons(hasFocus, pressed, invalidate);
1834 static void nativeSetFindIsUp(JNIEnv *env, jobject obj)
1836 WebView* view = GET_NATIVE_VIEW(env, obj);
1837 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1838 view->setFindIsUp(false);
1841 static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed)
1843 WebView* view = GET_NATIVE_VIEW(env, obj);
1844 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1845 view->setFollowedLink(followed);
1848 static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
1850 WebView* view = GET_NATIVE_VIEW(env, obj);
1851 LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
1852 view->setHeightCanMeasure(measure);
1855 static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
1857 WebView* view = GET_NATIVE_VIEW(env, obj);
1858 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1859 jclass rectClass = env->FindClass("android/graphics/Rect");
1860 LOG_ASSERT(rectClass, "Could not find Rect class!");
1861 jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
1862 LOG_ASSERT(init, "Could not find constructor for Rect");
1863 WebCore::IntRect webRect;
1864 view->cursorRingBounds(&webRect);
1865 jobject rect = env->NewObject(rectClass, init, webRect.x(),
1866 webRect.y(), webRect.right(), webRect.bottom());
1870 static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
1873 // If one or the other is null, do not search.
1874 if (!(findLower && findUpper))
1876 // Obtain the characters for both the lower case string and the upper case
1877 // string representing the same word.
1878 const jchar* findLowerChars = env->GetStringChars(findLower, 0);
1879 const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
1880 // If one or the other is null, do not search.
1881 if (!(findLowerChars && findUpperChars)) {
1883 env->ReleaseStringChars(findLower, findLowerChars);
1885 env->ReleaseStringChars(findUpper, findUpperChars);
1886 checkException(env);
1889 WebView* view = GET_NATIVE_VIEW(env, obj);
1890 LOG_ASSERT(view, "view not set in nativeFindAll");
1891 view->setFindIsUp(true);
1892 CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
1894 env->ReleaseStringChars(findLower, findLowerChars);
1895 env->ReleaseStringChars(findUpper, findUpperChars);
1896 checkException(env);
1899 int length = env->GetStringLength(findLower);
1900 // If the lengths of the strings do not match, then they are not the same
1901 // word, so do not search.
1902 if (!length || env->GetStringLength(findUpper) != length) {
1903 env->ReleaseStringChars(findLower, findLowerChars);
1904 env->ReleaseStringChars(findUpper, findUpperChars);
1905 checkException(env);
1908 int width = root->documentWidth();
1909 int height = root->documentHeight();
1910 // Create a FindCanvas, which allows us to fake draw into it so we can
1911 // figure out where our search string is rendered (and how many times).
1912 FindCanvas canvas(width, height, (const UChar*) findLowerChars,
1913 (const UChar*) findUpperChars, length << 1);
1915 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
1916 canvas.setBitmapDevice(bitmap);
1917 canvas.drawPicture(*(root->getPicture()));
1918 WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
1919 // With setMatches, the WebView takes ownership of matches
1920 view->setMatches(matches);
1922 env->ReleaseStringChars(findLower, findLowerChars);
1923 env->ReleaseStringChars(findUpper, findUpperChars);
1924 checkException(env);
1925 return canvas.found();
1928 static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
1930 WebView* view = GET_NATIVE_VIEW(env, obj);
1931 LOG_ASSERT(view, "view not set in nativeFindNext");
1932 view->findNext(forward);
1935 static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
1937 WebView* view = GET_NATIVE_VIEW(env, obj);
1938 LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
1939 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1942 const CachedNode* cachedFocusNode = root->currentFocus();
1943 if (!cachedFocusNode || !cachedFocusNode->isTextInput())
1945 WebCore::String webcoreString = to_string(env, updatedText);
1946 (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
1947 root->setTextGeneration(generation);
1948 checkException(env);
1951 static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y,
1954 WebView* view = GET_NATIVE_VIEW(env, obj);
1955 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
1958 return view->getBlockLeftEdge(x, y, scale);
1961 static void nativeDestroy(JNIEnv *env, jobject obj)
1963 WebView* view = GET_NATIVE_VIEW(env, obj);
1964 LOGD("nativeDestroy view: %p", view);
1965 LOG_ASSERT(view, "view not set in nativeDestroy");
1969 static void nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
1971 WebView* view = GET_NATIVE_VIEW(env, obj);
1972 CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
1975 const CachedFrame* containingFrame;
1976 const CachedNode* current = root->currentCursor(&containingFrame);
1978 current = root->currentFocus(&containingFrame);
1981 const CachedFrame* frame;
1982 const CachedNode* next = containingFrame->nextTextField(current, &frame,
1986 const WebCore::IntRect& bounds = next->bounds();
1987 root->rootHistory()->setMouseBounds(bounds);
1988 view->updateCursorBounds(root, frame, next);
1989 root->setCursor(const_cast<CachedFrame*>(frame),
1990 const_cast<CachedNode*>(next));
1991 view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
1992 static_cast<WebCore::Node*>(next->nodePointer()));
1993 view->scrollRectOnScreen(bounds.x(), bounds.y(), bounds.right(),
1995 view->getWebViewCore()->m_moveGeneration++;
1998 static int nativeMoveGeneration(JNIEnv *env, jobject obj)
2000 WebView* view = GET_NATIVE_VIEW(env, obj);
2003 return view->moveGeneration();
2006 static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex)
2008 WebView* view = GET_NATIVE_VIEW(env, obj);
2009 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2010 view->moveSelection(x, y, ex);
2013 static jobject nativeGetSelection(JNIEnv *env, jobject obj)
2015 WebView* view = GET_NATIVE_VIEW(env, obj);
2016 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2017 String selection = view->getSelection();
2018 return env->NewString((jchar*)selection.characters(), selection.length());
2021 #ifdef ANDROID_DUMP_DISPLAY_TREE
2022 static void dumpToFile(const char text[], void* file) {
2023 fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
2024 fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
2028 static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
2030 #ifdef ANDROID_DUMP_DISPLAY_TREE
2031 WebView* view = GET_NATIVE_VIEW(env, jwebview);
2032 LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
2034 if (view && view->getWebViewCore()) {
2035 FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
2037 SkFormatDumper dumper(dumpToFile, file);
2040 const char* str = env->GetStringUTFChars(jurl, 0);
2041 SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
2042 dumpToFile(str, file);
2043 env->ReleaseStringUTFChars(jurl, str);
2045 // now dump the display tree
2046 SkDumpCanvas canvas(&dumper);
2047 // this will playback the picture into the canvas, which will
2048 // spew its contents to the dumper
2049 view->getWebViewCore()->drawContent(&canvas, 0);
2050 // we're done with the file now
2051 fwrite("\n", 1, 1, file);
2054 #if USE(ACCELERATED_COMPOSITING)
2055 int pRootLayer = view->getWebViewCore()->rootLayer();
2057 LayerAndroid* rootLayer = reinterpret_cast<LayerAndroid*>(pRootLayer);
2058 FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
2060 rootLayer->dumpLayers(file, 0);
2072 static JNINativeMethod gJavaWebViewMethods[] = {
2073 { "nativeCacheHitFramePointer", "()I",
2074 (void*) nativeCacheHitFramePointer },
2075 { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;",
2076 (void*) nativeCacheHitNodeBounds },
2077 { "nativeCacheHitNodePointer", "()I",
2078 (void*) nativeCacheHitNodePointer },
2079 { "nativeClearCursor", "()V",
2080 (void*) nativeClearCursor },
2081 { "nativeCreate", "(I)V",
2082 (void*) nativeCreate },
2083 { "nativeCursorFramePointer", "()I",
2084 (void*) nativeCursorFramePointer },
2085 { "nativeCursorMatchesFocus", "()Z",
2086 (void*) nativeCursorMatchesFocus },
2087 { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
2088 (void*) nativeCursorNodeBounds },
2089 { "nativeCursorNodePointer", "()I",
2090 (void*) nativeCursorNodePointer },
2091 { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z",
2092 (void*) nativeCursorIntersects },
2093 { "nativeCursorIsAnchor", "()Z",
2094 (void*) nativeCursorIsAnchor },
2095 { "nativeCursorIsTextInput", "()Z",
2096 (void*) nativeCursorIsTextInput },
2097 { "nativeCursorPosition", "()Landroid/graphics/Point;",
2098 (void*) nativeCursorPosition },
2099 { "nativeCursorText", "()Ljava/lang/String;",
2100 (void*) nativeCursorText },
2101 { "nativeCursorWantsKeyEvents", "()Z",
2102 (void*)nativeCursorWantsKeyEvents },
2103 { "nativeDebugDump", "()V",
2104 (void*) nativeDebugDump },
2105 { "nativeDestroy", "()V",
2106 (void*) nativeDestroy },
2107 { "nativeDrawCursorRing", "(Landroid/graphics/Canvas;)V",
2108 (void*) nativeDrawCursorRing },
2109 { "nativeDestroyLayer", "(I)V",
2110 (void*) nativeDestroyLayer },
2111 { "nativeDrawLayers", "(IIIIIFLandroid/graphics/Canvas;)V",
2112 (void*) nativeDrawLayers },
2113 { "nativeEvaluateLayersAnimations", "(I)Z",
2114 (void*) nativeEvaluateLayersAnimations },
2115 { "nativeDrawMatches", "(Landroid/graphics/Canvas;)V",
2116 (void*) nativeDrawMatches },
2117 { "nativeDrawSelectionPointer", "(Landroid/graphics/Canvas;FIIZ)V",
2118 (void*) nativeDrawSelectionPointer },
2119 { "nativeDrawSelectionRegion", "(Landroid/graphics/Canvas;)V",
2120 (void*) nativeDrawSelectionRegion },
2121 { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
2122 (void*) nativeDumpDisplayTree },
2123 { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I",
2124 (void*) nativeFindAll },
2125 { "nativeFindNext", "(Z)V",
2126 (void*) nativeFindNext },
2127 { "nativeFocusCandidateFramePointer", "()I",
2128 (void*) nativeFocusCandidateFramePointer },
2129 { "nativeFocusCandidateIsPassword", "()Z",
2130 (void*) nativeFocusCandidateIsPassword },
2131 { "nativeFocusCandidateIsRtlText", "()Z",
2132 (void*) nativeFocusCandidateIsRtlText },
2133 { "nativeFocusCandidateIsTextInput", "()Z",
2134 (void*) nativeFocusCandidateIsTextInput },
2135 { "nativeFocusCandidateMaxLength", "()I",
2136 (void*) nativeFocusCandidateMaxLength },
2137 { "nativeFocusCandidateName", "()Ljava/lang/String;",
2138 (void*) nativeFocusCandidateName },
2139 { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;",
2140 (void*) nativeFocusCandidateNodeBounds },
2141 { "nativeFocusCandidatePointer", "()I",
2142 (void*) nativeFocusCandidatePointer },
2143 { "nativeFocusCandidateText", "()Ljava/lang/String;",
2144 (void*) nativeFocusCandidateText },
2145 { "nativeFocusCandidateTextSize", "()I",
2146 (void*) nativeFocusCandidateTextSize },
2147 { "nativeFocusCandidateType", "()I",
2148 (void*) nativeFocusCandidateType },
2149 { "nativeFocusIsPlugin", "()Z",
2150 (void*) nativeFocusIsPlugin },
2151 { "nativeFocusNodePointer", "()I",
2152 (void*) nativeFocusNodePointer },
2153 { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;",
2154 (void*) nativeGetCursorRingBounds },
2155 { "nativeGetSelection", "()Ljava/lang/String;",
2156 (void*) nativeGetSelection },
2157 { "nativeHasCursorNode", "()Z",
2158 (void*) nativeHasCursorNode },
2159 { "nativeHasFocusNode", "()Z",
2160 (void*) nativeHasFocusNode },
2161 { "nativeHideCursor", "()V",
2162 (void*) nativeHideCursor },
2163 { "nativeImageURI", "(II)Ljava/lang/String;",
2164 (void*) nativeImageURI },
2165 { "nativeInstrumentReport", "()V",
2166 (void*) nativeInstrumentReport },
2167 { "nativeMotionUp", "(III)Z",
2168 (void*) nativeMotionUp },
2169 { "nativeMoveCursor", "(IIZ)Z",
2170 (void*) nativeMoveCursor },
2171 { "nativeMoveCursorToNextTextInput", "()V",
2172 (void*) nativeMoveCursorToNextTextInput },
2173 { "nativeMoveGeneration", "()I",
2174 (void*) nativeMoveGeneration },
2175 { "nativeMoveSelection", "(IIZ)V",
2176 (void*) nativeMoveSelection },
2177 { "nativePointInNavCache", "(III)Z",
2178 (void*) nativePointInNavCache },
2179 { "nativeRecordButtons", "(ZZZ)V",
2180 (void*) nativeRecordButtons },
2181 { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
2182 (void*) nativeSelectBestAt },
2183 { "nativeSetFindIsUp", "()V",
2184 (void*) nativeSetFindIsUp },
2185 { "nativeSetFollowedLink", "(Z)V",
2186 (void*) nativeSetFollowedLink },
2187 { "nativeSetHeightCanMeasure", "(Z)V",
2188 (void*) nativeSetHeightCanMeasure },
2189 { "nativeTextGeneration", "()I",
2190 (void*) nativeTextGeneration },
2191 { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
2192 (void*) nativeUpdateCachedTextfield },
2193 { "nativeGetBlockLeftEdge", "(IIF)I",
2194 (void*) nativeGetBlockLeftEdge },
2197 int register_webview(JNIEnv* env)
2199 jclass clazz = env->FindClass("android/webkit/WebView");
2200 LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
2201 gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
2202 LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
2204 return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
2207 } // namespace android