diff options
Diffstat (limited to 'Source/WebKit/android/nav/WebView.cpp')
-rw-r--r-- | Source/WebKit/android/nav/WebView.cpp | 2718 |
1 files changed, 2147 insertions, 571 deletions
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index a67b5fd..7cb41d9 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -30,16 +30,17 @@ #include "AndroidAnimation.h" #include "AndroidLog.h" #include "BaseLayerAndroid.h" -#include "BaseRenderer.h" +#include "CachedFrame.h" +#include "CachedNode.h" +#include "CachedRoot.h" #include "DrawExtra.h" +#include "FindCanvas.h" #include "Frame.h" -#include "GLWebViewState.h" #include "GraphicsJNI.h" #include "HTMLInputElement.h" #include "IntPoint.h" #include "IntRect.h" #include "LayerAndroid.h" -#include "LayerContent.h" #include "Node.h" #include "utils/Functor.h" #include "private/hwui/DrawGlInfo.h" @@ -52,8 +53,10 @@ #include "SkPicture.h" #include "SkRect.h" #include "SkTime.h" +#ifdef ANDROID_INSTRUMENT +#include "TimeCounter.h" +#endif #include "TilesManager.h" -#include "TransferQueue.h" #include "WebCoreJni.h" #include "WebRequestContext.h" #include "WebViewCore.h" @@ -68,7 +71,7 @@ #include <JNIUtility.h> #include <JNIHelp.h> #include <jni.h> -#include <androidfw/KeycodeLabels.h> +#include <ui/KeycodeLabels.h> #include <wtf/text/AtomicString.h> #include <wtf/text/CString.h> @@ -92,7 +95,7 @@ static jfieldID gWebViewField; static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) { jmethodID m = env->GetMethodID(clazz, name, signature); - ALOG_ASSERT(m, "Could not find method %s", name); + LOG_ASSERT(m, "Could not find method %s", name); return m; } @@ -107,81 +110,105 @@ enum FrameCachePermission { AllowNewer }; -#define DRAW_EXTRAS_SIZE 2 enum DrawExtras { // keep this in sync with WebView.java DrawExtrasNone = 0, - DrawExtrasSelection = 1, - DrawExtrasCursorRing = 2 + DrawExtrasFind = 1, + DrawExtrasSelection = 2, + DrawExtrasCursorRing = 3 }; struct JavaGlue { jweak m_obj; + jmethodID m_overrideLoading; jmethodID m_scrollBy; + jmethodID m_sendMoveFocus; + jmethodID m_sendMoveMouse; + jmethodID m_sendMoveMouseIfLatest; + jmethodID m_sendMotionUp; + jmethodID m_domChangedFocus; jmethodID m_getScaledMaxXScroll; jmethodID m_getScaledMaxYScroll; - jmethodID m_updateRectsForGL; + jmethodID m_getVisibleRect; + jmethodID m_rebuildWebTextView; jmethodID m_viewInvalidate; jmethodID m_viewInvalidateRect; jmethodID m_postInvalidateDelayed; jmethodID m_pageSwapCallback; + jmethodID m_inFullScreenMode; jfieldID m_rectLeft; jfieldID m_rectTop; jmethodID m_rectWidth; jmethodID m_rectHeight; - jfieldID m_quadFP1; - jfieldID m_quadFP2; - jfieldID m_quadFP3; - jfieldID m_quadFP4; + jfieldID m_rectFLeft; + jfieldID m_rectFTop; + jmethodID m_rectFWidth; + jmethodID m_rectFHeight; + jmethodID m_getTextHandleScale; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } } m_javaGlue; WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, - bool isHighEndGfx) - : m_isHighEndGfx(isHighEndGfx) + bool isHighEndGfx) : + m_ring((WebViewCore*) viewImpl) + , m_isHighEndGfx(isHighEndGfx) { - memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*)); - jclass clazz = env->FindClass("android/webkit/WebViewClassic"); + jclass clazz = env->FindClass("android/webkit/WebView"); + // m_javaGlue = new JavaGlue; m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); + m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); + m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); + m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); + m_javaGlue.m_sendMoveMouseIfLatest = GetJMethod(env, clazz, "sendMoveMouseIfLatest", "(ZZ)V"); + m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIII)V"); + m_javaGlue.m_domChangedFocus = GetJMethod(env, clazz, "domChangedFocus", "()V"); m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); - m_javaGlue.m_updateRectsForGL = GetJMethod(env, clazz, "updateRectsForGL", "()V"); + m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); + m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz, "viewInvalidateDelayed", "(JIIII)V"); m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V"); + m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z"); + m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F"); env->DeleteLocalRef(clazz); jclass rectClass = env->FindClass("android/graphics/Rect"); - ALOG_ASSERT(rectClass, "Could not find Rect class"); + LOG_ASSERT(rectClass, "Could not find Rect class"); m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I"); m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); env->DeleteLocalRef(rectClass); - jclass quadFClass = env->FindClass("android/webkit/QuadF"); - ALOG_ASSERT(quadFClass, "Could not find QuadF class"); - m_javaGlue.m_quadFP1 = env->GetFieldID(quadFClass, "p1", "Landroid/graphics/PointF;"); - m_javaGlue.m_quadFP2 = env->GetFieldID(quadFClass, "p2", "Landroid/graphics/PointF;"); - m_javaGlue.m_quadFP3 = env->GetFieldID(quadFClass, "p3", "Landroid/graphics/PointF;"); - m_javaGlue.m_quadFP4 = env->GetFieldID(quadFClass, "p4", "Landroid/graphics/PointF;"); - env->DeleteLocalRef(quadFClass); + jclass rectClassF = env->FindClass("android/graphics/RectF"); + LOG_ASSERT(rectClassF, "Could not find RectF class"); + m_javaGlue.m_rectFLeft = env->GetFieldID(rectClassF, "left", "F"); + m_javaGlue.m_rectFTop = env->GetFieldID(rectClassF, "top", "F"); + m_javaGlue.m_rectFWidth = GetJMethod(env, rectClassF, "width", "()F"); + m_javaGlue.m_rectFHeight = GetJMethod(env, rectClassF, "height", "()F"); + env->DeleteLocalRef(rectClassF); env->SetIntField(javaWebView, gWebViewField, (jint)this); m_viewImpl = (WebViewCore*) viewImpl; + m_frameCacheUI = 0; + m_navPictureUI = 0; m_generation = 0; m_heightCanMeasure = false; m_lastDx = 0; m_lastDxTime = 0; + m_ringAnimationEnd = 0; m_baseLayer = 0; m_glDrawFunctor = 0; m_isDrawingPaused = false; + m_buttonSkin = drawableDir.isEmpty() ? 0 : new RenderSkinButton(drawableDir); #if USE(ACCELERATED_COMPOSITING) m_glWebViewState = 0; + m_pageSwapCallbackRegistered = false; #endif } @@ -199,17 +226,11 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, // deallocated base layer. stopGL(); #endif + delete m_frameCacheUI; + delete m_navPictureUI; SkSafeUnref(m_baseLayer); delete m_glDrawFunctor; - for (int i = 0; i < DRAW_EXTRAS_SIZE; i++) - delete m_extras[i]; -} - -DrawExtra* getDrawExtra(DrawExtras extras) -{ - if (extras == DrawExtrasNone) - return 0; - return m_extras[extras - 1]; + delete m_buttonSkin; } void stopGL() @@ -224,6 +245,126 @@ WebViewCore* getWebViewCore() const { return m_viewImpl; } +float getTextHandleScale() +{ + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return 0; + float result = env->CallFloatMethod(javaObject.get(), m_javaGlue.m_getTextHandleScale); + checkException(env); + return result; +} + +void updateSelectionHandles() +{ + if (!m_baseLayer) + return; + // Adjust for device density & scale + m_selectText.updateHandleScale(getTextHandleScale()); +} + +// removes the cursor altogether (e.g., when going to a new page) +void clearCursor() +{ + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return; + DBG_NAV_LOG(""); + m_viewImpl->m_hasCursorBounds = false; + root->clearCursor(); + viewInvalidate(); +} + +// leaves the cursor where it is, but suppresses drawing it +void hideCursor() +{ + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return; + DBG_NAV_LOG(""); + hideCursor(root); + viewInvalidate(); +} + +void hideCursor(CachedRoot* root) +{ + DBG_NAV_LOG("inner"); + m_viewImpl->m_hasCursorBounds = false; + root->hideCursor(); +} + +#if DUMP_NAV_CACHE +void debugDump() +{ + CachedRoot* root = getFrameCache(DontAllowNewer); + if (root) + root->mDebug.print(); +} +#endif + +void scrollToCurrentMatch() +{ + if (!m_findOnPage.currentMatchIsInLayer()) { + scrollRectOnScreen(m_findOnPage.currentMatchBounds()); + return; + } + + SkRect matchBounds = m_findOnPage.currentMatchBounds(); + LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer(); + Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId()); + ASSERT(layerContainingMatch); + + // If the match is in a fixed position layer, there's nothing to do. + if (layerContainingMatch->shouldInheritFromRootTransform()) + return; + + // If the match is in a scrollable layer or a descendant of such a layer, + // there may be a range of of scroll configurations that will make the + // current match visible. Our approach is the simplest possible. Starting at + // the layer in which the match is found, we move up the layer tree, + // scrolling any scrollable layers as little as possible to make sure that + // the current match is in view. This approach has the disadvantage that we + // may end up scrolling a larger number of elements than is necessary, which + // may be visually jarring. However, minimising the number of layers + // scrolled would complicate the code significantly. + + bool didScrollLayer = false; + for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) { + ASSERT(layer->getParent() || layer == rootLayer); + + if (layer->contentIsScrollable()) { + // Convert the match location to layer's local space and scroll it. + // Repeatedly calling Layer::localToAncestor() is inefficient as + // each call repeats part of the calculation. It would be more + // efficient to maintain the transform here and update it on each + // iteration, but that would mean duplicating logic from + // Layer::localToAncestor() and would complicate things. + SkMatrix transform; + layerContainingMatch->localToAncestor(layer, &transform); + SkRect transformedMatchBounds; + transform.mapRect(&transformedMatchBounds, matchBounds); + SkIRect roundedTransformedMatchBounds; + transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); + // Only ScrollableLayerAndroid returns true for contentIsScrollable(). + didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds); + } + } + // Invalidate, as the call below to scroll the main page may be a no-op. + if (didScrollLayer) + viewInvalidate(); + + // Convert matchBounds to the global space so we can scroll the main page. + SkMatrix transform; + layerContainingMatch->localToGlobal(&transform); + SkRect transformedMatchBounds; + transform.mapRect(&transformedMatchBounds, matchBounds); + SkIRect roundedTransformedMatchBounds; + transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); + scrollRectOnScreen(roundedTransformedMatchBounds); +} + void scrollRectOnScreen(const IntRect& rect) { if (rect.isEmpty()) @@ -231,59 +372,147 @@ void scrollRectOnScreen(const IntRect& rect) int dx = 0; int left = rect.x(); int right = rect.maxX(); - if (left < m_visibleContentRect.fLeft) - dx = left - m_visibleContentRect.fLeft; + if (left < m_visibleRect.fLeft) + dx = left - m_visibleRect.fLeft; // Only scroll right if the entire width can fit on screen. - else if (right > m_visibleContentRect.fRight - && right - left < m_visibleContentRect.width()) - dx = right - m_visibleContentRect.fRight; + else if (right > m_visibleRect.fRight + && right - left < m_visibleRect.width()) + dx = right - m_visibleRect.fRight; int dy = 0; int top = rect.y(); int bottom = rect.maxY(); - if (top < m_visibleContentRect.fTop) - dy = top - m_visibleContentRect.fTop; + if (top < m_visibleRect.fTop) + dy = top - m_visibleRect.fTop; // Only scroll down if the entire height can fit on screen - else if (bottom > m_visibleContentRect.fBottom - && bottom - top < m_visibleContentRect.height()) - dy = bottom - m_visibleContentRect.fBottom; + else if (bottom > m_visibleRect.fBottom + && bottom - top < m_visibleRect.height()) + dy = bottom - m_visibleRect.fBottom; if ((dx|dy) == 0 || !scrollBy(dx, dy)) return; viewInvalidate(); } -int drawGL(WebCore::IntRect& invScreenRect, WebCore::IntRect* invalRect, - WebCore::IntRect& screenRect, int titleBarHeight, - WebCore::IntRect& screenClip, float scale, int extras, bool shouldDraw) +void resetCursorRing() { + m_ringAnimationEnd = 0; + m_viewImpl->m_hasCursorBounds = false; +} + +bool drawCursorPreamble(CachedRoot* root) +{ + if (!root) return false; + const CachedFrame* frame; + const CachedNode* node = root->currentCursor(&frame); + if (!node) { + DBG_NAV_LOGV("%s", "!node"); + resetCursorRing(); + return false; + } + m_ring.setIsButton(node); + if (node->isHidden()) { + DBG_NAV_LOG("node->isHidden()"); + m_viewImpl->m_hasCursorBounds = false; + return false; + } #if USE(ACCELERATED_COMPOSITING) - if (!m_baseLayer) - return 0; + if (node->isInLayer() && root->rootLayer()) { + LayerAndroid* layer = root->rootLayer(); + layer->updateFixedLayersPositions(m_visibleRect); + layer->updatePositions(); + } +#endif + setVisibleRect(root); + m_ring.m_root = root; + m_ring.m_frame = frame; + m_ring.m_node = node; + SkMSec time = SkTime::GetMSecs(); + m_ring.m_isPressed = time < m_ringAnimationEnd + && m_ringAnimationEnd != UINT_MAX; + return true; +} - if (m_viewImpl) - m_viewImpl->setPrerenderingEnabled(!m_isDrawingPaused); +void drawCursorPostamble() +{ + if (m_ringAnimationEnd == UINT_MAX) + return; + SkMSec time = SkTime::GetMSecs(); + if (time < m_ringAnimationEnd) { + // views assume that inval bounds coordinates are non-negative + WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX); + invalBounds.intersect(m_ring.m_absBounds); + postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds); + } else { + hideCursor(const_cast<CachedRoot*>(m_ring.m_root)); + } +} + +bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, + WebCore::IntRect& webViewRect, int titleBarHeight, + WebCore::IntRect& clip, float scale, int extras) +{ +#if USE(ACCELERATED_COMPOSITING) + if (!m_baseLayer || inFullScreenMode()) + return false; if (!m_glWebViewState) { - TilesManager::instance()->setHighEndGfx(m_isHighEndGfx); m_glWebViewState = new GLWebViewState(); - m_glWebViewState->setBaseLayer(m_baseLayer, false, true); + m_glWebViewState->setHighEndGfx(m_isHighEndGfx); + m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring); + m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage); + if (m_baseLayer->content()) { + SkRegion region; + SkIRect rect; + rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height()); + region.setRect(rect); + m_glWebViewState->setBaseLayer(m_baseLayer, region, false, true); + } } - DrawExtra* extra = getDrawExtra((DrawExtras) extras); + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + if (extras == DrawExtrasCursorRing) + resetCursorRing(); + } + DrawExtra* extra = 0; + switch (extras) { + case DrawExtrasFind: + extra = &m_findOnPage; + break; + case DrawExtrasSelection: + // This will involve a JNI call, but under normal circumstances we will + // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled + // in WebView.java will we hit this (so really debug only) + updateSelectionHandles(); + extra = &m_selectText; + break; + case DrawExtrasCursorRing: + if (drawCursorPreamble(root) && m_ring.setup()) { + if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX) + extra = &m_ring; + drawCursorPostamble(); + } + break; + default: + ; + } + unsigned int pic = m_glWebViewState->currentPictureCounter(); m_glWebViewState->glExtras()->setDrawExtra(extra); // Make sure we have valid coordinates. We might not have valid coords // if the zoom manager is still initializing. We will be redrawn // once the correct scale is set - if (!m_visibleContentRect.isFinite()) - return 0; + if (!m_visibleRect.isFinite()) + return false; bool treesSwapped = false; bool newTreeHasAnim = false; - int ret = m_glWebViewState->drawGL(invScreenRect, m_visibleContentRect, invalRect, - screenRect, titleBarHeight, screenClip, scale, - &treesSwapped, &newTreeHasAnim, shouldDraw); - if (treesSwapped) { - ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect, + webViewRect, titleBarHeight, clip, scale, + &treesSwapped, &newTreeHasAnim); + if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) { + m_pageSwapCallbackRegistered = false; + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (javaObject.get()) { @@ -291,45 +520,237 @@ int drawGL(WebCore::IntRect& invScreenRect, WebCore::IntRect* invalRect, checkException(env); } } - return m_isDrawingPaused ? 0 : ret; + if (ret || m_glWebViewState->currentPictureCounter() != pic) + return !m_isDrawingPaused; #endif - return 0; + return false; } -void draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras) +PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) { + PictureSet* ret = 0; if (!m_baseLayer) { canvas->drawColor(bgColor); - return; + return ret; } // draw the content of the base layer first - LayerContent* content = m_baseLayer->content(); + PictureSet* content = m_baseLayer->content(); int sc = canvas->save(SkCanvas::kClip_SaveFlag); - if (content) { - canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), content->height()), - SkRegion::kDifference_Op); - } - Color c = m_baseLayer->getBackgroundColor(); - canvas->drawColor(SkColorSetARGBInline(c.alpha(), c.red(), c.green(), c.blue())); + canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), + content->height()), SkRegion::kDifference_Op); + canvas->drawColor(bgColor); canvas->restoreToCount(sc); + if (content->draw(canvas)) + ret = split ? new PictureSet(*content) : 0; + + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + if (extras == DrawExtrasCursorRing) + resetCursorRing(); + } + LayerAndroid mainPicture(m_navPictureUI); + DrawExtra* extra = 0; + switch (extras) { + case DrawExtrasFind: + extra = &m_findOnPage; + break; + case DrawExtrasSelection: + // This will involve a JNI call, but under normal circumstances we will + // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled + // in WebView.java will we hit this (so really debug only) + updateSelectionHandles(); + extra = &m_selectText; + break; + case DrawExtrasCursorRing: + if (drawCursorPreamble(root) && m_ring.setup()) { + extra = &m_ring; + drawCursorPostamble(); + } + break; + default: + ; + } +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* compositeLayer = compositeRoot(); + if (compositeLayer) { + // call this to be sure we've adjusted for any scrolling or animations + // before we actually draw + compositeLayer->updateFixedLayersPositions(m_visibleRect); + compositeLayer->updatePositions(); + // We have to set the canvas' matrix on the base layer + // (to have fixed layers work as intended) + SkAutoCanvasRestore restore(canvas, true); + m_baseLayer->setMatrix(canvas->getTotalMatrix()); + canvas->resetMatrix(); + m_baseLayer->draw(canvas); + } +#endif + if (extra) { + IntRect dummy; // inval area, unused for now + extra->draw(canvas, &mainPicture, &dummy); + } + return ret; +} - // call this to be sure we've adjusted for any scrolling or animations - // before we actually draw - m_baseLayer->updatePositionsRecursive(m_visibleContentRect); - m_baseLayer->updatePositions(); - // We have to set the canvas' matrix on the base layer - // (to have fixed layers work as intended) - SkAutoCanvasRestore restore(canvas, true); - m_baseLayer->setMatrix(canvas->getTotalMatrix()); - canvas->resetMatrix(); - m_baseLayer->draw(canvas, getDrawExtra(extras)); +bool cursorIsTextInput(FrameCachePermission allowNewer) +{ + CachedRoot* root = getFrameCache(allowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + return false; + } + const CachedNode* cursor = root->currentCursor(); + if (!cursor) { + DBG_NAV_LOG("!cursor"); + return false; + } + DBG_NAV_LOGD("%s", cursor->isTextInput() ? "true" : "false"); + return cursor->isTextInput(); +} + +void cursorRingBounds(WebCore::IntRect* bounds) +{ + DBG_NAV_LOGD("%s", ""); + CachedRoot* root = getFrameCache(DontAllowNewer); + if (root) { + const CachedFrame* cachedFrame; + const CachedNode* cachedNode = root->currentCursor(&cachedFrame); + if (cachedNode) { + *bounds = cachedNode->cursorRingBounds(cachedFrame); + DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(), + bounds->width(), bounds->height()); + return; + } + } + *bounds = WebCore::IntRect(0, 0, 0, 0); +} + +void fixCursor() +{ + m_viewImpl->gCursorBoundsMutex.lock(); + bool hasCursorBounds = m_viewImpl->m_hasCursorBounds; + IntRect bounds = m_viewImpl->m_cursorBounds; + m_viewImpl->gCursorBoundsMutex.unlock(); + if (!hasCursorBounds) + return; + int x, y; + const CachedFrame* frame; + const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true); + if (!node) + return; + // require that node have approximately the same bounds (+/- 4) and the same + // center (+/- 2) + IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1), + bounds.y() + (bounds.height() >> 1)); + IntRect newBounds = node->bounds(frame); + IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1), + newBounds.y() + (newBounds.height() >> 1)); + DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)" + " bounds=(%d,%d,w=%d,h=%d) newBounds=(%d,%d,w=%d,h=%d)", + oldCenter.x(), oldCenter.y(), newCenter.x(), newCenter.y(), + bounds.x(), bounds.y(), bounds.width(), bounds.height(), + newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height()); + if (abs(oldCenter.x() - newCenter.x()) > 2) + return; + if (abs(oldCenter.y() - newCenter.y()) > 2) + return; + if (abs(bounds.x() - newBounds.x()) > 4) + return; + if (abs(bounds.y() - newBounds.y()) > 4) + return; + if (abs(bounds.maxX() - newBounds.maxX()) > 4) + return; + if (abs(bounds.maxY() - newBounds.maxY()) > 4) + return; + DBG_NAV_LOGD("node=%p frame=%p x=%d y=%d bounds=(%d,%d,w=%d,h=%d)", + node, frame, x, y, bounds.x(), bounds.y(), bounds.width(), + bounds.height()); + m_frameCacheUI->setCursor(const_cast<CachedFrame*>(frame), + const_cast<CachedNode*>(node)); +} + +CachedRoot* getFrameCache(FrameCachePermission allowNewer) +{ + if (!m_viewImpl->m_updatedFrameCache) { + DBG_NAV_LOGV("%s", "!m_viewImpl->m_updatedFrameCache"); + return m_frameCacheUI; + } + if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation) { + DBG_NAV_LOGD("allowNewer==DontAllowNewer m_viewImpl->m_lastGeneration=%d" + " < m_generation=%d", m_viewImpl->m_lastGeneration, m_generation); + return m_frameCacheUI; + } + DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true"); + const CachedFrame* oldCursorFrame; + const CachedNode* oldCursorNode = m_frameCacheUI ? + m_frameCacheUI->currentCursor(&oldCursorFrame) : 0; +#if USE(ACCELERATED_COMPOSITING) + int layerId = -1; + if (oldCursorNode && oldCursorNode->isInLayer()) { + const LayerAndroid* cursorLayer = oldCursorFrame->layer(oldCursorNode) + ->layer(m_frameCacheUI->rootLayer()); + if (cursorLayer) + layerId = cursorLayer->uniqueId(); + } +#endif + // get id from old layer and use to find new layer + bool oldFocusIsTextInput = false; + void* oldFocusNodePointer = 0; + if (m_frameCacheUI) { + const CachedNode* oldFocus = m_frameCacheUI->currentFocus(); + if (oldFocus) { + oldFocusIsTextInput = oldFocus->isTextInput(); + oldFocusNodePointer = oldFocus->nodePointer(); + } + } + m_viewImpl->gFrameCacheMutex.lock(); + delete m_frameCacheUI; + SkSafeUnref(m_navPictureUI); + m_viewImpl->m_updatedFrameCache = false; + m_frameCacheUI = m_viewImpl->m_frameCacheKit; + m_navPictureUI = m_viewImpl->m_navPictureKit; + m_viewImpl->m_frameCacheKit = 0; + m_viewImpl->m_navPictureKit = 0; + m_viewImpl->gFrameCacheMutex.unlock(); + if (m_frameCacheUI) + m_frameCacheUI->setRootLayer(compositeRoot()); +#if USE(ACCELERATED_COMPOSITING) + if (layerId >= 0) { + LayerAndroid* layer = const_cast<LayerAndroid*>( + m_frameCacheUI->rootLayer()); + if (layer) { + layer->updateFixedLayersPositions(m_visibleRect); + layer->updatePositions(); + } + } +#endif + fixCursor(); + if (oldFocusIsTextInput) { + const CachedNode* newFocus = m_frameCacheUI->currentFocus(); + if (newFocus && oldFocusNodePointer != newFocus->nodePointer() + && newFocus->isTextInput() + && newFocus != m_frameCacheUI->currentCursor()) { + // The focus has changed. We may need to update things. + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (javaObject.get()) { + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_domChangedFocus); + checkException(env); + } + } + } + if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) + viewInvalidate(); // redraw in case cursor ring is still visible + return m_frameCacheUI; } int getScaledMaxXScroll() { - ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -341,7 +762,7 @@ int getScaledMaxXScroll() int getScaledMaxYScroll() { - ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) @@ -351,37 +772,294 @@ int getScaledMaxYScroll() return result; } -// Call through JNI to ask Java side to update the rectangles for GL functor. -// This is called at every draw when it is not in process mode, so we should -// keep this route as efficient as possible. Currently, its average cost on Xoom -// is about 0.1ms - 0.2ms. -// Alternatively, this can be achieved by adding more listener on Java side, but -// that will be more likely causing jank when triggering GC. -void updateRectsForGL() +IntRect getVisibleRect() { + IntRect rect; + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), m_javaGlue.m_updateRectsForGL); + return rect; + jobject jRect = env->CallObjectMethod(javaObject.get(), m_javaGlue.m_getVisibleRect); + checkException(env); + rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft)); + checkException(env); + rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop)); + checkException(env); + rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth)); checkException(env); + rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight)); + checkException(env); + env->DeleteLocalRef(jRect); + checkException(env); + return rect; +} + +static CachedFrame::Direction KeyToDirection(int32_t keyCode) +{ + switch (keyCode) { + case AKEYCODE_DPAD_RIGHT: + DBG_NAV_LOGD("keyCode=%s", "right"); + return CachedFrame::RIGHT; + case AKEYCODE_DPAD_LEFT: + DBG_NAV_LOGD("keyCode=%s", "left"); + return CachedFrame::LEFT; + case AKEYCODE_DPAD_DOWN: + DBG_NAV_LOGD("keyCode=%s", "down"); + return CachedFrame::DOWN; + case AKEYCODE_DPAD_UP: + DBG_NAV_LOGD("keyCode=%s", "up"); + return CachedFrame::UP; + default: + DBG_NAV_LOGD("bad key %d sent", keyCode); + return CachedFrame::UNINITIALIZED; + } +} + +WTF::String imageURI(int x, int y) +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + return root ? root->imageURI(x, y) : WTF::String(); +} + +bool cursorWantsKeyEvents() +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + if (root) { + const CachedNode* focus = root->currentCursor(); + if (focus) + return focus->wantsKeyEvents(); + } + return false; +} + + +/* returns true if the key had no effect (neither scrolled nor changed cursor) */ +bool moveCursor(int keyCode, int count, bool ignoreScroll) +{ + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + return true; + } + + m_viewImpl->m_moveGeneration++; + CachedFrame::Direction direction = KeyToDirection(keyCode); + const CachedFrame* cachedFrame, * oldFrame = 0; + const CachedNode* cursor = root->currentCursor(&oldFrame); + WebCore::IntPoint cursorLocation = root->cursorLocation(); + DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", + cursor ? cursor->index() : 0, + cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); + WebCore::IntRect visibleRect = setVisibleRect(root); + int xMax = getScaledMaxXScroll(); + int yMax = getScaledMaxYScroll(); + root->setMaxScroll(xMax, yMax); + const CachedNode* cachedNode = 0; + int dx = 0; + int dy = 0; + int counter = count; + while (--counter >= 0) { + WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); + cachedNode = root->moveCursor(direction, &cachedFrame, &scroll); + dx += scroll.x(); + dy += scroll.y(); + } + DBG_NAV_LOGD("new cursor %d (nativeNode=%p) cursorLocation={%d, %d}" + "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, + cachedNode ? cachedNode->nodePointer() : 0, + root->cursorLocation().x(), root->cursorLocation().y(), + cachedNode ? cachedNode->bounds(cachedFrame).x() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).y() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).width() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).height() : 0); + // If !m_heightCanMeasure (such as in the browser), we want to scroll no + // matter what + if (!ignoreScroll && (!m_heightCanMeasure || + !cachedNode || + (cursor && cursor->nodePointer() == cachedNode->nodePointer()))) + { + if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx && + SkTime::GetMSecs() - m_lastDxTime < 1000) + root->checkForJiggle(&dx); + DBG_NAV_LOGD("scrollBy %d,%d", dx, dy); + if ((dx | dy)) + this->scrollBy(dx, dy); + m_lastDx = dx; + m_lastDxTime = SkTime::GetMSecs(); + } + bool result = false; + if (cachedNode) { + showCursorUntimed(); + m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode); + root->setCursor(const_cast<CachedFrame*>(cachedFrame), + const_cast<CachedNode*>(cachedNode)); + const CachedNode* focus = root->currentFocus(); + bool clearTextEntry = cachedNode != focus && focus + && cachedNode->nodePointer() != focus->nodePointer() && focus->isTextInput(); + // Stop painting the caret if the old focus was a text input and so is the new cursor. + bool stopPaintingCaret = clearTextEntry && cachedNode->wantsKeyEvents(); + sendMoveMouseIfLatest(clearTextEntry, stopPaintingCaret); + } else { + int docHeight = root->documentHeight(); + int docWidth = root->documentWidth(); + if (visibleRect.maxY() + dy > docHeight) + dy = docHeight - visibleRect.maxY(); + else if (visibleRect.y() + dy < 0) + dy = -visibleRect.y(); + if (visibleRect.maxX() + dx > docWidth) + dx = docWidth - visibleRect.maxX(); + else if (visibleRect.x() < 0) + dx = -visibleRect.x(); + result = direction == CachedFrame::LEFT ? dx >= 0 : + direction == CachedFrame::RIGHT ? dx <= 0 : + direction == CachedFrame::UP ? dy >= 0 : dy <= 0; + } + return result; +} + +void notifyProgressFinished() +{ + DBG_NAV_LOGD("cursorIsTextInput=%d", cursorIsTextInput(DontAllowNewer)); + rebuildWebTextView(); +#if DEBUG_NAV_UI + if (m_frameCacheUI) { + const CachedNode* focus = m_frameCacheUI->currentFocus(); + DBG_NAV_LOGD("focus %d (nativeNode=%p)", + focus ? focus->index() : 0, + focus ? focus->nodePointer() : 0); + } +#endif +} + +const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect, + const CachedFrame** framePtr, int* rxPtr, int* ryPtr) +{ + *rxPtr = 0; + *ryPtr = 0; + *framePtr = 0; + if (!root) + return 0; + setVisibleRect(root); + return root->findAt(rect, framePtr, rxPtr, ryPtr, true); +} + +IntRect setVisibleRect(CachedRoot* root) +{ + IntRect visibleRect = getVisibleRect(); + DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d", + visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height()); + root->setVisibleRect(visibleRect); + return visibleRect; +} + +void selectBestAt(const WebCore::IntRect& rect) +{ + const CachedFrame* frame; + int rx, ry; + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return; + const CachedNode* node = findAt(root, rect, &frame, &rx, &ry); + if (!node) { + DBG_NAV_LOGD("no nodes found root=%p", root); + root->rootHistory()->setMouseBounds(rect); + m_viewImpl->m_hasCursorBounds = false; + root->setCursor(0, 0); + viewInvalidate(); + } else { + DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); + WebCore::IntRect bounds = node->bounds(frame); + root->rootHistory()->setMouseBounds(bounds); + m_viewImpl->updateCursorBounds(root, frame, node); + showCursorTimed(); + root->setCursor(const_cast<CachedFrame*>(frame), + const_cast<CachedNode*>(node)); + } + sendMoveMouseIfLatest(false, false); +} + +const CachedNode* m_cacheHitNode; +const CachedFrame* m_cacheHitFrame; + +bool pointInNavCache(int x, int y, int slop) +{ + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return false; + IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); + int rx, ry; + return (m_cacheHitNode = findAt(root, rect, &m_cacheHitFrame, &rx, &ry)); +} + +bool motionUp(int x, int y, int slop) +{ + bool pageScrolled = false; + IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2); + int rx, ry; + CachedRoot* root = getFrameCache(AllowNewer); + if (!root) + return 0; + const CachedFrame* frame = 0; + const CachedNode* result = findAt(root, rect, &frame, &rx, &ry); + CachedHistory* history = root->rootHistory(); + if (!result) { + DBG_NAV_LOGD("no nodes found root=%p", root); + history->setNavBounds(rect); + m_viewImpl->m_hasCursorBounds = false; + root->hideCursor(); + int dx = root->checkForCenter(x, y); + if (dx) { + scrollBy(dx, 0); + pageScrolled = true; + } + sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0, + 0, x, y); + viewInvalidate(); + return pageScrolled; + } + DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result, + result->index(), x, y, rx, ry); + WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1); + history->setNavBounds(navBounds); + history->setMouseBounds(navBounds); + m_viewImpl->updateCursorBounds(root, frame, result); + root->setCursor(const_cast<CachedFrame*>(frame), + const_cast<CachedNode*>(result)); + if (result->isSyntheticLink()) + overrideUrlLoading(result->getExport()); + else { + sendMotionUp( + (WebCore::Frame*) frame->framePointer(), + (WebCore::Node*) result->nodePointer(), rx, ry); + } + if (result->isTextInput() || result->isSelect() + || result->isContentEditable()) { + showCursorUntimed(); + } else + showCursorTimed(); + return pageScrolled; } #if USE(ACCELERATED_COMPOSITING) static const ScrollableLayerAndroid* findScrollableLayer( const LayerAndroid* parent, int x, int y, SkIRect* foundBounds) { - IntRect bounds = enclosingIntRect(parent->fullContentAreaMapped()); - + SkRect bounds; + parent->bounds(&bounds); // Check the parent bounds first; this will clip to within a masking layer's // bounds. if (parent->masksToBounds() && !bounds.contains(x, y)) return 0; - + // Move the hit test local to parent. + x -= bounds.fLeft; + y -= bounds.fTop; int count = parent->countChildren(); while (count--) { const LayerAndroid* child = parent->getChild(count); - const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, foundBounds); + const ScrollableLayerAndroid* result = findScrollableLayer(child, x, y, + foundBounds); if (result) { + foundBounds->offset(bounds.fLeft, bounds.fTop); if (parent->masksToBounds()) { if (bounds.width() < foundBounds->width()) foundBounds->fRight = foundBounds->fLeft + bounds.width(); @@ -392,7 +1070,7 @@ static const ScrollableLayerAndroid* findScrollableLayer( } } if (parent->contentIsScrollable()) { - foundBounds->set(bounds.x(), bounds.y(), bounds.width(), bounds.height()); + foundBounds->set(0, 0, bounds.width(), bounds.height()); return static_cast<const ScrollableLayerAndroid*>(parent); } return 0; @@ -402,9 +1080,11 @@ static const ScrollableLayerAndroid* findScrollableLayer( int scrollableLayer(int x, int y, SkIRect* layerRect, SkIRect* bounds) { #if USE(ACCELERATED_COMPOSITING) - if (!m_baseLayer) + const LayerAndroid* layerRoot = compositeRoot(); + if (!layerRoot) return 0; - const ScrollableLayerAndroid* result = findScrollableLayer(m_baseLayer, x, y, bounds); + const ScrollableLayerAndroid* result = findScrollableLayer(layerRoot, x, y, + bounds); if (result) { result->getScrollRect(layerRect); return result->uniqueId(); @@ -419,6 +1099,52 @@ void scrollLayer(int layerId, int x, int y) m_glWebViewState->scrollLayer(layerId, x, y); } +int getBlockLeftEdge(int x, int y, float scale) +{ + CachedRoot* root = getFrameCache(AllowNewer); + if (root) + return root->getBlockLeftEdge(x, y, scale); + return -1; +} + +void overrideUrlLoading(const WTF::String& url) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return; + jstring jName = wtfStringToJstring(env, url); + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_overrideLoading, jName); + env->DeleteLocalRef(jName); +} + +void setFindIsUp(bool up) +{ + DBG_NAV_LOGD("up=%d", up); + m_viewImpl->m_findIsUp = up; +} + +void setFindIsEmpty() +{ + DBG_NAV_LOG(""); + m_findOnPage.clearCurrentLocation(); +} + +void showCursorTimed() +{ + DBG_NAV_LOG(""); + m_ringAnimationEnd = SkTime::GetMSecs() + PRESSED_STATE_DURATION; + viewInvalidate(); +} + +void showCursorUntimed() +{ + DBG_NAV_LOG(""); + m_ring.m_isPressed = false; + m_ringAnimationEnd = UINT_MAX; + viewInvalidate(); +} + void setHeightCanMeasure(bool measure) { m_heightCanMeasure = measure; @@ -426,16 +1152,170 @@ void setHeightCanMeasure(bool measure) String getSelection() { - SelectText* select = static_cast<SelectText*>( - getDrawExtra(WebView::DrawExtrasSelection)); - if (select) - return select->getText(); - return String(); + return m_selectText.getSelection(); +} + +void moveSelection(int x, int y) +{ + m_selectText.moveSelection(getVisibleRect(), x, y); +} + +IntPoint selectableText() +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return IntPoint(0, 0); + return m_selectText.selectableText(root); +} + +void selectAll() +{ + m_selectText.selectAll(); +} + +int selectionX() +{ + return m_selectText.selectionX(); +} + +int selectionY() +{ + return m_selectText.selectionY(); +} + +void resetSelection() +{ + m_selectText.reset(); +} + +bool startSelection(int x, int y) +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return false; + updateSelectionHandles(); + return m_selectText.startSelection(root, getVisibleRect(), x, y); +} + +bool wordSelection(int x, int y) +{ + const CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return false; + updateSelectionHandles(); + return m_selectText.wordSelection(root, getVisibleRect(), x, y); +} + +bool extendSelection(int x, int y) +{ + m_selectText.extendSelection(getVisibleRect(), x, y); + return true; +} + +bool hitSelection(int x, int y) +{ + updateSelectionHandles(); + return m_selectText.hitSelection(x, y); +} + +void setExtendSelection() +{ + m_selectText.setExtendSelection(true); +} + +void setSelectionPointer(bool set, float scale, int x, int y) +{ + m_selectText.setDrawPointer(set); + if (!set) + return; + m_selectText.m_inverseScale = scale; + m_selectText.m_selectX = x; + m_selectText.m_selectY = y; +} + +void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr) +{ + DBG_NAV_LOGD("framePtr=%p nodePtr=%p", framePtr, nodePtr); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return; + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveFocus, (jint) framePtr, (jint) nodePtr); + checkException(env); +} + +void sendMoveMouse(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) +{ + DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return; + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouse, reinterpret_cast<jint>(framePtr), reinterpret_cast<jint>(nodePtr), x, y); + checkException(env); +} + +void sendMoveMouseIfLatest(bool clearTextEntry, bool stopPaintingCaret) +{ + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return; + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMoveMouseIfLatest, clearTextEntry, stopPaintingCaret); + checkException(env); +} + +void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y) +{ + DBG_NAV_LOGD("m_generation=%d framePtr=%p nodePtr=%p x=%d y=%d", m_generation, framePtr, nodePtr, x, y); + LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!"); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return; + m_viewImpl->m_touchGeneration = ++m_generation; + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_sendMotionUp, m_generation, (jint) framePtr, (jint) nodePtr, x, y); + checkException(env); +} + +void findNext(bool forward) +{ + m_findOnPage.findNext(forward); + scrollToCurrentMatch(); + viewInvalidate(); +} + +// With this call, WebView takes ownership of matches, and is responsible for +// deleting it. +void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch) +{ + // If this search is the same as the last one, check against the old + // location to determine whether to scroll. If the same word is found + // in the same place, then do not scroll. + IntRect oldLocation; + bool checkAgainstOldLocation = false; + if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) { + oldLocation = m_findOnPage.currentMatchBounds(); + checkAgainstOldLocation = true; + } + + m_findOnPage.setMatches(matches); + + if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds()) + scrollToCurrentMatch(); + viewInvalidate(); +} + +int currentMatchIndex() +{ + return m_findOnPage.currentMatchIndex(); } bool scrollBy(int dx, int dy) { - ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); + LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue.object(env); @@ -454,6 +1334,44 @@ void setIsScrolling(bool isScrolling) #endif } +bool hasCursorNode() +{ + CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + return false; + } + const CachedNode* cursorNode = root->currentCursor(); + DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p)", + cursorNode ? cursorNode->index() : -1, + cursorNode ? cursorNode->nodePointer() : 0); + return cursorNode; +} + +bool hasFocusNode() +{ + CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) { + DBG_NAV_LOG("!root"); + return false; + } + const CachedNode* focusNode = root->currentFocus(); + DBG_NAV_LOGD("focusNode=%d (nodePointer=%p)", + focusNode ? focusNode->index() : -1, + focusNode ? focusNode->nodePointer() : 0); + return focusNode; +} + +void rebuildWebTextView() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return; + env->CallVoidMethod(javaObject.get(), m_javaGlue.m_rebuildWebTextView); + checkException(env); +} + void viewInvalidate() { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -485,64 +1403,112 @@ void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds) checkException(env); } +bool inFullScreenMode() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue.object(env); + if (!javaObject.get()) + return false; + jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue.m_inFullScreenMode); + checkException(env); + return result; +} + +int moveGeneration() +{ + return m_viewImpl->m_moveGeneration; +} + +LayerAndroid* compositeRoot() const +{ + LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, + "base layer can't have more than one child %s", __FUNCTION__); + if (m_baseLayer && m_baseLayer->countChildren() == 1) + return static_cast<LayerAndroid*>(m_baseLayer->getChild(0)); + else + return 0; +} + #if ENABLE(ANDROID_OVERFLOW_SCROLL) -static void copyScrollPosition(const LayerAndroid* fromRoot, - LayerAndroid* toRoot, int layerId) +static void copyScrollPositionRecursive(const LayerAndroid* from, + LayerAndroid* root) { - if (!fromRoot || !toRoot) - return; - const LayerAndroid* from = fromRoot->findById(layerId); - LayerAndroid* to = toRoot->findById(layerId); - if (!from || !to || !from->contentIsScrollable() || !to->contentIsScrollable()) - return; - // TODO: Support this for iframes. - if (to->isIFrameContent() || from->isIFrameContent()) + if (!from || !root) return; - to->setScrollOffset(from->getScrollOffset()); + for (int i = 0; i < from->countChildren(); i++) { + const LayerAndroid* l = from->getChild(i); + if (l->contentIsScrollable()) { + const SkPoint& pos = l->getPosition(); + LayerAndroid* match = root->findById(l->uniqueId()); + if (match && match->contentIsScrollable()) + match->setPosition(pos.fX, pos.fY); + } + copyScrollPositionRecursive(l, root); + } } #endif -BaseLayerAndroid* getBaseLayer() const { return m_baseLayer; } +void registerPageSwapCallback() +{ + m_pageSwapCallbackRegistered = true; +} -bool setBaseLayer(BaseLayerAndroid* newBaseLayer, bool showVisualIndicator, - bool isPictureAfterFirstLayout, int scrollingLayer) +void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator, + bool isPictureAfterFirstLayout, bool registerPageSwapCallback) { - bool queueFull = false; #if USE(ACCELERATED_COMPOSITING) if (m_glWebViewState) - queueFull = m_glWebViewState->setBaseLayer(newBaseLayer, showVisualIndicator, - isPictureAfterFirstLayout); + m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator, + isPictureAfterFirstLayout); + m_pageSwapCallbackRegistered |= registerPageSwapCallback; #endif #if ENABLE(ANDROID_OVERFLOW_SCROLL) - copyScrollPosition(m_baseLayer, newBaseLayer, scrollingLayer); + if (layer) { + // TODO: the below tree copies are only necessary in software rendering + LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0)); + copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); + } #endif SkSafeUnref(m_baseLayer); - m_baseLayer = newBaseLayer; - - return queueFull; + m_baseLayer = layer; + CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return; + root->resetLayers(); + root->setRootLayer(compositeRoot()); } -void copyBaseContentToPicture(SkPicture* picture) +void getTextSelectionRegion(SkRegion *region) { - if (!m_baseLayer || !m_baseLayer->content()) - return; - LayerContent* content = m_baseLayer->content(); - SkCanvas* canvas = picture->beginRecording(content->width(), content->height(), - SkPicture::kUsePathBoundsForClip_RecordingFlag); + m_selectText.getSelectionRegion(getVisibleRect(), region, compositeRoot()); +} - // clear the BaseLayerAndroid's previous matrix (set at each draw) - SkMatrix baseMatrix; - baseMatrix.reset(); - m_baseLayer->setMatrix(baseMatrix); +void getTextSelectionHandles(int* handles) +{ + m_selectText.getSelectionHandles(handles, compositeRoot()); +} - m_baseLayer->draw(canvas, 0); +void replaceBaseContent(PictureSet* set) +{ + if (!m_baseLayer) + return; + m_baseLayer->setContent(*set); + delete set; +} +void copyBaseContentToPicture(SkPicture* picture) +{ + if (!m_baseLayer) + return; + PictureSet* content = m_baseLayer->content(); + m_baseLayer->drawCanvas(picture->beginRecording(content->width(), content->height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag)); picture->endRecording(); } bool hasContent() { - if (!m_baseLayer || !m_baseLayer->content()) + if (!m_baseLayer) return false; return !m_baseLayer->content()->isEmpty(); } @@ -556,197 +1522,37 @@ Functor* getFunctor() { return m_glDrawFunctor; } -void setVisibleContentRect(SkRect& visibleContentRect) { - m_visibleContentRect = visibleContentRect; -} - -void setDrawExtra(DrawExtra *extra, DrawExtras type) -{ - if (type == DrawExtrasNone) - return; - DrawExtra* old = m_extras[type - 1]; - m_extras[type - 1] = extra; - if (old != extra) { - delete old; - } -} - -void setTextSelection(SelectText *selection) { - setDrawExtra(selection, DrawExtrasSelection); -} - -const TransformationMatrix* getLayerTransform(int layerId) { - if (layerId != -1 && m_baseLayer) { - LayerAndroid* layer = m_baseLayer->findById(layerId); - // We need to make sure the drawTransform is up to date as this is - // called before a draw() or drawGL() - if (layer) { - m_baseLayer->updatePositionsRecursive(m_visibleContentRect); - return layer->drawTransform(); - } - } - return 0; -} - -int getHandleLayerId(SelectText::HandleId handleId, SkIPoint& cursorPoint, - FloatQuad& textBounds) { - SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection)); - if (!selectText || !m_baseLayer) - return -1; - int layerId = selectText->caretLayerId(handleId); - IntRect cursorRect = selectText->caretRect(handleId); - IntRect textRect = selectText->textRect(handleId); - // Rects exclude the last pixel on right/bottom. We want only included pixels. - cursorPoint.set(cursorRect.x(), cursorRect.maxY() - 1); - textRect.setHeight(std::max(1, textRect.height() - 1)); - textRect.setWidth(std::max(1, textRect.width() - 1)); - textBounds = FloatQuad(textRect); - - const TransformationMatrix* transform = getLayerTransform(layerId); - if (transform) { - // We're overloading the concept of Rect to be just the two - // points (bottom-left and top-right. - cursorPoint = transform->mapPoint(cursorPoint); - textBounds = transform->mapQuad(textBounds); - } - return layerId; -} - -void mapLayerRect(int layerId, SkIRect& rect) { - const TransformationMatrix* transform = getLayerTransform(layerId); - if (transform) - rect = transform->mapRect(rect); -} - -void floatQuadToQuadF(JNIEnv* env, const FloatQuad& nativeTextQuad, - jobject textQuad) -{ - jobject p1 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP1); - jobject p2 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP2); - jobject p3 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP3); - jobject p4 = env->GetObjectField(textQuad, m_javaGlue.m_quadFP4); - GraphicsJNI::point_to_jpointf(nativeTextQuad.p1(), env, p1); - GraphicsJNI::point_to_jpointf(nativeTextQuad.p2(), env, p2); - GraphicsJNI::point_to_jpointf(nativeTextQuad.p3(), env, p3); - GraphicsJNI::point_to_jpointf(nativeTextQuad.p4(), env, p4); - env->DeleteLocalRef(p1); - env->DeleteLocalRef(p2); - env->DeleteLocalRef(p3); - env->DeleteLocalRef(p4); +BaseLayerAndroid* getBaseLayer() { + return m_baseLayer; } -// This is called when WebView switches rendering modes in a more permanent fashion -// such as when the layer type is set or the view is attached/detached from the window -int setHwAccelerated(bool hwAccelerated) { - if (!m_glWebViewState) - return 0; - LayerAndroid* root = m_baseLayer; - if (root) - return root->setHwAccelerated(hwAccelerated); - return 0; +void setVisibleRect(SkRect& visibleRect) { + m_visibleRect = visibleRect; } -void setDrawingPaused(bool isPaused) -{ - m_isDrawingPaused = isPaused; - if (m_viewImpl) - m_viewImpl->setPrerenderingEnabled(!isPaused); -} - -// Finds the rectangles within world to the left, right, top, and bottom -// of rect and adds them to rects. If no intersection exists, false is returned. -static bool findMaskedRects(const FloatRect& world, - const FloatRect& rect, Vector<FloatRect>& rects) { - if (!world.intersects(rect)) - return false; // nothing to subtract - - // left rectangle - if (rect.x() > world.x()) - rects.append(FloatRect(world.x(), world.y(), - rect.x() - world.x(), world.height())); - // top rectangle - if (rect.y() > world.y()) - rects.append(FloatRect(world.x(), world.y(), - world.width(), rect.y() - world.y())); - // right rectangle - if (rect.maxX() < world.maxX()) - rects.append(FloatRect(rect.maxX(), world.y(), - world.maxX() - rect.maxX(), world.height())); - // bottom rectangle - if (rect.maxY() < world.maxY()) - rects.append(FloatRect(world.x(), rect.maxY(), - world.width(), world.maxY() - rect.maxY())); - return true; -} - -// Returns false if layerId is a fixed position layer, otherwise -// all fixed position layer rectangles are subtracted from those within -// rects. Rects will be modified to contain rectangles that don't include -// the fixed position layer rectangles. -static bool findMaskedRectsForLayer(LayerAndroid* layer, - Vector<FloatRect>& rects, int layerId) -{ - if (layer->isPositionFixed()) { - if (layerId == layer->uniqueId()) - return false; - FloatRect layerRect = layer->fullContentAreaMapped(); - for (int i = rects.size() - 1; i >= 0; i--) - if (findMaskedRects(rects[i], layerRect, rects)) - rects.remove(i); - } - - int childIndex = 0; - while (LayerAndroid* child = layer->getChild(childIndex++)) - if (!findMaskedRectsForLayer(child, rects, layerId)) - return false; - - return true; -} - -// Finds the largest rectangle not masked by any fixed layer. -void findMaxVisibleRect(int movingLayerId, SkIRect& visibleContentRect) -{ - if (!m_baseLayer) - return; - - FloatRect visibleContentFloatRect(visibleContentRect); - m_baseLayer->updatePositionsRecursive(visibleContentFloatRect); - Vector<FloatRect> rects; - rects.append(visibleContentFloatRect); - if (findMaskedRectsForLayer(m_baseLayer, rects, movingLayerId)) { - float maxSize = 0.0; - const FloatRect* largest = 0; - for (int i = 0; i < rects.size(); i++) { - const FloatRect& rect = rects[i]; - float size = rect.width() * rect.height(); - if (size > maxSize) { - maxSize = size; - largest = ▭ - } - } - if (largest) { - SkRect largeRect = *largest; - largeRect.round(&visibleContentRect); - } - } -} - -private: // local state for WebView bool m_isDrawingPaused; +private: // local state for WebView // private to getFrameCache(); other functions operate in a different thread + CachedRoot* m_frameCacheUI; // navigation data ready for use WebViewCore* m_viewImpl; int m_generation; // associate unique ID with sent kit focus to match with ui + SkPicture* m_navPictureUI; + SkMSec m_ringAnimationEnd; // Corresponds to the same-named boolean on the java side. bool m_heightCanMeasure; int m_lastDx; SkMSec m_lastDxTime; - DrawExtra* m_extras[DRAW_EXTRAS_SIZE]; + SelectText m_selectText; + FindOnPage m_findOnPage; + CursorRing m_ring; BaseLayerAndroid* m_baseLayer; Functor* m_glDrawFunctor; #if USE(ACCELERATED_COMPOSITING) GLWebViewState* m_glWebViewState; + bool m_pageSwapCallbackRegistered; #endif - SkRect m_visibleContentRect; + RenderSkinButton* m_buttonSkin; + SkRect m_visibleRect; bool m_isHighEndGfx; }; // end of WebView class @@ -759,54 +1565,45 @@ private: // local state for WebView class GLDrawFunctor : Functor { public: GLDrawFunctor(WebView* _wvInstance, - int (WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, - WebCore::IntRect&, int, WebCore::IntRect&, jfloat, jint, bool), - WebCore::IntRect _invScreenRect, float _scale, int _extras) { + bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, + WebCore::IntRect&, int, WebCore::IntRect&, + jfloat, jint), + WebCore::IntRect _viewRect, float _scale, int _extras) { wvInstance = _wvInstance; funcPtr = _funcPtr; - invScreenRect = _invScreenRect; + viewRect = _viewRect; scale = _scale; extras = _extras; }; - status_t operator()(int messageId, void* data) { - TRACE_METHOD(); - bool shouldDraw = (messageId == uirenderer::DrawGlInfo::kModeDraw); - if (shouldDraw) - wvInstance->updateRectsForGL(); - - if (invScreenRect.isEmpty()) { + if (viewRect.isEmpty()) { // NOOP operation if viewport is empty return 0; } WebCore::IntRect inval; - int titlebarHeight = screenRect.height() - invScreenRect.height(); + int titlebarHeight = webViewRect.height() - viewRect.height(); uirenderer::DrawGlInfo* info = reinterpret_cast<uirenderer::DrawGlInfo*>(data); - WebCore::IntRect screenClip(info->clipLeft, info->clipTop, - info->clipRight - info->clipLeft, - info->clipBottom - info->clipTop); - - WebCore::IntRect localInvScreenRect = invScreenRect; - if (info->isLayer) { - // When webview is on a layer, we need to use the viewport relative - // to the FBO, rather than the screen(which will use invScreenRect). - localInvScreenRect.setX(screenClip.x()); - localInvScreenRect.setY(info->height - screenClip.y() - screenClip.height()); - } - // Send the necessary info to the shader. - TilesManager::instance()->shader()->setGLDrawInfo(info); - - int returnFlags = (*wvInstance.*funcPtr)(localInvScreenRect, &inval, screenRect, - titlebarHeight, screenClip, scale, extras, shouldDraw); - if ((returnFlags & uirenderer::DrawGlInfo::kStatusDraw) != 0) { + WebCore::IntRect localViewRect = viewRect; + if (info->isLayer) + localViewRect.move(-1 * localViewRect.x(), -1 * localViewRect.y()); + + WebCore::IntRect clip(info->clipLeft, info->clipTop, + info->clipRight - info->clipLeft, + info->clipBottom - info->clipTop); + TilesManager::instance()->shader()->setWebViewMatrix(info->transform, info->isLayer); + + bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, + titlebarHeight, clip, scale, extras); + if (retVal) { IntRect finalInval; - if (inval.isEmpty()) - finalInval = screenRect; - else { - finalInval.setX(screenRect.x() + inval.x()); - finalInval.setY(screenRect.y() + titlebarHeight + inval.y()); + if (inval.isEmpty()) { + finalInval = webViewRect; + retVal = true; + } else { + finalInval.setX(webViewRect.x() + inval.x()); + finalInval.setY(webViewRect.y() + titlebarHeight + inval.y()); finalInval.setWidth(inval.width()); finalInval.setHeight(inval.height()); } @@ -815,45 +1612,201 @@ class GLDrawFunctor : Functor { info->dirtyRight = finalInval.maxX(); info->dirtyBottom = finalInval.maxY(); } - // return 1 if invalidation needed, 2 to request non-drawing functor callback, 0 otherwise - ALOGV("returnFlags are %d, shouldDraw %d", returnFlags, shouldDraw); - return returnFlags; - } - void updateScreenRect(WebCore::IntRect& _screenRect) { - screenRect = _screenRect; + // return 1 if invalidation needed, 0 otherwise + return retVal ? 1 : 0; } - void updateInvScreenRect(WebCore::IntRect& _invScreenRect) { - invScreenRect = _invScreenRect; + void updateRect(WebCore::IntRect& _viewRect) { + viewRect = _viewRect; } - void updateScale(float _scale) { - scale = _scale; - } - void updateExtras(jint _extras) { - extras = _extras; + void updateViewRect(WebCore::IntRect& _viewRect) { + webViewRect = _viewRect; } private: WebView* wvInstance; - int (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, - WebCore::IntRect&, int, WebCore::IntRect&, float, int, bool); - WebCore::IntRect invScreenRect; - WebCore::IntRect screenRect; + bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, + WebCore::IntRect&, int, WebCore::IntRect&, float, int); + WebCore::IntRect viewRect; + WebCore::IntRect webViewRect; jfloat scale; jint extras; }; +static jobject createJavaRect(JNIEnv* env, int x, int y, int right, int bottom) +{ + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, x, y, right, bottom); + env->DeleteLocalRef(rectClass); + return rect; +} + /* * Native JNI methods */ +static int nativeCacheHitFramePointer(JNIEnv *env, jobject obj) +{ + return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) + ->m_cacheHitFrame->framePointer()); +} + +static jobject nativeCacheHitNodeBounds(JNIEnv *env, jobject obj) +{ + WebCore::IntRect bounds = GET_NATIVE_VIEW(env, obj) + ->m_cacheHitNode->originalAbsoluteBounds(); + return createJavaRect(env, bounds.x(), bounds.y(), + bounds.maxX(), bounds.maxY()); +} + +static int nativeCacheHitNodePointer(JNIEnv *env, jobject obj) +{ + return reinterpret_cast<int>(GET_NATIVE_VIEW(env, obj) + ->m_cacheHitNode->nodePointer()); +} + +static bool nativeCacheHitIsPlugin(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->m_cacheHitNode->isPlugin(); +} + +static void nativeClearCursor(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->clearCursor(); +} static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir, jboolean isHighEndGfx) { WTF::String dir = jstringToWtfString(env, drawableDir); - new WebView(env, obj, viewImpl, dir, isHighEndGfx); + WebView* webview = new WebView(env, obj, viewImpl, dir, isHighEndGfx); // NEED THIS OR SOMETHING LIKE IT! //Release(obj); } +static jint nativeCursorFramePointer(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame = 0; + (void) root->currentCursor(&frame); + return reinterpret_cast<int>(frame ? frame->framePointer() : 0); +} + +static const CachedNode* getCursorNode(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentCursor() : 0; +} + +static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, + const CachedFrame** frame) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentCursor(frame) : 0; +} + +static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, + const CachedFrame** frame) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedNode* cursor = root->currentCursor(frame); + if (cursor && cursor->wantsKeyEvents()) + return cursor; + return root->currentFocus(frame); +} + +static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return false; + const CachedNode* cursor = root->currentCursor(); + if (!cursor || !cursor->isTextInput()) + cursor = root->currentFocus(); + if (!cursor || !cursor->isTextInput()) return false; + return root->nextTextField(cursor, 0); +} + +static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentFocus() : 0; +} + +static const CachedNode* getFocusNode(JNIEnv *env, jobject obj, + const CachedFrame** frame) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->currentFocus(frame) : 0; +} + +static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame; + const CachedNode* cursor = root->currentCursor(&frame); + if (!cursor || !cursor->wantsKeyEvents()) + cursor = root->currentFocus(&frame); + return cursor ? frame->textInput(cursor) : 0; +} + +static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj) +{ + const CachedNode* focus = getFocusNode(env, obj); + if (!focus) return false; + // Plugins handle shift and arrows whether or not they have focus. + if (focus->isPlugin()) return true; + const CachedNode* cursor = getCursorNode(env, obj); + // ContentEditable nodes should only receive shift and arrows if they have + // both the cursor and the focus. + return cursor && cursor->nodePointer() == focus->nodePointer() + && cursor->isContentEditable(); +} + +static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame; + const CachedNode* node = getCursorNode(env, obj, &frame); + WebCore::IntRect bounds = node ? node->bounds(frame) + : WebCore::IntRect(0, 0, 0, 0); + return createJavaRect(env, bounds.x(), bounds.y(), + bounds.maxX(), bounds.maxY()); +} + +static jint nativeCursorNodePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return reinterpret_cast<int>(node ? node->nodePointer() : 0); +} + +static jobject nativeCursorPosition(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + const CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + WebCore::IntPoint pos = WebCore::IntPoint(0, 0); + if (root) + root->getSimulatedMousePosition(&pos); + jclass pointClass = env->FindClass("android/graphics/Point"); + jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); + jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); + env->DeleteLocalRef(pointClass); + return point; +} + static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) { if (obj) { @@ -872,67 +1825,88 @@ static SkRect jrectf_to_rect(JNIEnv* env, jobject obj) return rect; } -static void nativeDraw(JNIEnv *env, jobject obj, jobject canv, +static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) +{ + const CachedFrame* frame; + const CachedNode* node = getCursorNode(env, obj, &frame); + return node ? node->bounds(frame).intersects( + jrect_to_webrect(env, visRect)) : false; +} + +static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isAnchor() : false; +} + +static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isTextInput() : false; +} + +static jobject nativeCursorText(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + if (!node) + return 0; + WTF::String value = node->getExport(); + return wtfStringToJstring(env, value); +} + +static void nativeDebugDump(JNIEnv *env, jobject obj) +{ +#if DUMP_NAV_CACHE + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->debugDump(); +#endif +} + +static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jobject visible, jint color, - jint extras) { + jint extras, jboolean split) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); WebView* webView = GET_NATIVE_VIEW(env, obj); - SkRect visibleContentRect = jrectf_to_rect(env, visible); - webView->setVisibleContentRect(visibleContentRect); - webView->draw(canvas, color, static_cast<WebView::DrawExtras>(extras)); -} - -static jint nativeCreateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, - jobject jinvscreenrect, jobject jscreenrect, - jobject jvisiblecontentrect, - jfloat scale, jint extras) { - WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); - WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); - SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); - wvInstance->setVisibleContentRect(visibleContentRect); - - GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); - if (!functor) { - functor = new GLDrawFunctor(wvInstance, &android::WebView::drawGL, - invScreenRect, scale, extras); - wvInstance->setFunctor((Functor*) functor); - } else { - functor->updateInvScreenRect(invScreenRect); - functor->updateScale(scale); - functor->updateExtras(extras); - } + SkRect visibleRect = jrectf_to_rect(env, visible); + webView->setVisibleRect(visibleRect); + PictureSet* pictureSet = webView->draw(canvas, color, extras, split); + return reinterpret_cast<jint>(pictureSet); +} - WebCore::IntRect rect = jrect_to_webrect(env, jscreenrect); - functor->updateScreenRect(rect); +static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, + jobject jrect, jobject jviewrect, + jobject jvisiblerect, + jfloat scale, jint extras) { + WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); + WebView *wvInstance = (WebView*) nativeView; + SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); + wvInstance->setVisibleRect(visibleRect); - return (jint)functor; -} + GLDrawFunctor* functor = new GLDrawFunctor(wvInstance, + &android::WebView::drawGL, viewRect, scale, extras); + wvInstance->setFunctor((Functor*) functor); -static jint nativeGetDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView) { - WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); - if (!wvInstance) - return 0; + WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); + functor->updateViewRect(webViewRect); - return (jint) wvInstance->getFunctor(); + return (jint)functor; } -static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jint nativeView, - jobject jinvscreenrect, jobject jscreenrect, - jobject jvisiblecontentrect, jfloat scale) { - WebView *wvInstance = reinterpret_cast<WebView*>(nativeView); +static void nativeUpdateDrawGLFunction(JNIEnv *env, jobject obj, jobject jrect, + jobject jviewrect, jobject jvisiblerect) { + WebView *wvInstance = GET_NATIVE_VIEW(env, obj); if (wvInstance) { GLDrawFunctor* functor = (GLDrawFunctor*) wvInstance->getFunctor(); if (functor) { - WebCore::IntRect invScreenRect = jrect_to_webrect(env, jinvscreenrect); - functor->updateInvScreenRect(invScreenRect); - - SkRect visibleContentRect = jrectf_to_rect(env, jvisiblecontentrect); - wvInstance->setVisibleContentRect(visibleContentRect); + WebCore::IntRect viewRect = jrect_to_webrect(env, jrect); + functor->updateRect(viewRect); - WebCore::IntRect screenRect = jrect_to_webrect(env, jscreenrect); - functor->updateScreenRect(screenRect); + SkRect visibleRect = jrectf_to_rect(env, jvisiblerect); + wvInstance->setVisibleRect(visibleRect); - functor->updateScale(scale); + WebCore::IntRect webViewRect = jrect_to_webrect(env, jviewrect); + functor->updateViewRect(webViewRect); } } } @@ -941,29 +1915,56 @@ static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj, jint native { // only call in software rendering, initialize and evaluate animations #if USE(ACCELERATED_COMPOSITING) - BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(nativeView)->getBaseLayer(); - if (baseLayer) { - baseLayer->initAnimations(); - return baseLayer->evaluateAnimations(); + LayerAndroid* root = ((WebView*)nativeView)->compositeRoot(); + if (root) { + root->initAnimations(); + return root->evaluateAnimations(); } #endif return false; } -static bool nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint layer, - jboolean showVisualIndicator, - jboolean isPictureAfterFirstLayout, - jint scrollingLayer) +static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval, + jboolean showVisualIndicator, + jboolean isPictureAfterFirstLayout, + jboolean registerPageSwapCallback) { BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); - return reinterpret_cast<WebView*>(nativeView)->setBaseLayer(layerImpl, showVisualIndicator, - isPictureAfterFirstLayout, - scrollingLayer); + SkRegion invalRegion; + if (inval) + invalRegion = *GraphicsJNI::getNativeRegion(env, inval); + GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator, + isPictureAfterFirstLayout, + registerPageSwapCallback); +} + +static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jint view, + jobject region) +{ + if (!region) + return; + SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region); + ((WebView*)view)->getTextSelectionRegion(nregion); +} + +static void nativeGetSelectionHandles(JNIEnv *env, jobject obj, jint view, + jintArray arr) +{ + int handles[4]; + ((WebView*)view)->getTextSelectionHandles(handles); + env->SetIntArrayRegion(arr, 0, 4, handles); + checkException(env); +} + +static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->getBaseLayer(); } -static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj, jint nativeView) +static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content) { - return reinterpret_cast<WebView*>(nativeView)->getBaseLayer(); + PictureSet* set = reinterpret_cast<PictureSet*>(content); + GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set); } static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) @@ -977,40 +1978,549 @@ static bool nativeHasContent(JNIEnv *env, jobject obj) return GET_NATIVE_VIEW(env, obj)->hasContent(); } +static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + WTF::String uri = view->imageURI(x, y); + return wtfStringToJstring(env, uri); +} + +static jint nativeFocusCandidateFramePointer(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return 0; + const CachedFrame* frame = 0; + const CachedNode* cursor = root->currentCursor(&frame); + if (!cursor || !cursor->wantsKeyEvents()) + (void) root->currentFocus(&frame); + return reinterpret_cast<int>(frame ? frame->framePointer() : 0); +} + +static bool nativeFocusCandidateIsPassword(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input && input->getType() == CachedInput::PASSWORD; +} + +static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->isRtlText() : false; +} + +static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj, 0); + return node ? node->isTextInput() : false; +} + +static jint nativeFocusCandidateMaxLength(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->maxLength() : false; +} + +static jint nativeFocusCandidateIsAutoComplete(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->autoComplete() : false; +} + +static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + if (!input) + return 0; + const WTF::String& name = input->name(); + return wtfStringToJstring(env, name); +} + +static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame; + const CachedNode* node = getFocusCandidate(env, obj, &frame); + WebCore::IntRect bounds = node ? node->originalAbsoluteBounds() + : WebCore::IntRect(0, 0, 0, 0); + // Inset the rect by 1 unit, so that the focus candidate's border can still + // be seen behind it. + return createJavaRect(env, bounds.x(), bounds.y(), + bounds.maxX(), bounds.maxY()); +} + +static jobject nativeFocusCandidatePaddingRect(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + if (!input) + return 0; + // Note that the Java Rect is being used to pass four integers, rather than + // being used as an actual rectangle. + return createJavaRect(env, input->paddingLeft(), input->paddingTop(), + input->paddingRight(), input->paddingBottom()); +} + +static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj, 0); + return reinterpret_cast<int>(node ? node->nodePointer() : 0); +} + +static jint nativeFocusCandidateIsSpellcheck(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->spellcheck() : false; +} + +static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusCandidate(env, obj, 0); + if (!node) + return 0; + WTF::String value = node->getExport(); + return wtfStringToJstring(env, value); +} + +static int nativeFocusCandidateLineHeight(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->lineHeight() : 0; +} + +static jfloat nativeFocusCandidateTextSize(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + return input ? input->textSize() : 0.f; +} + +static int nativeFocusCandidateType(JNIEnv *env, jobject obj) +{ + const CachedInput* input = getInputCandidate(env, obj); + if (!input) + return CachedInput::NONE; + + if (input->isTextArea()) + return CachedInput::TEXT_AREA; + + return input->getType(); +} + +static int nativeFocusCandidateLayerId(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame = 0; + const CachedNode* node = getFocusNode(env, obj, &frame); + if (!node || !frame) + return -1; + const CachedLayer* layer = frame->layer(node); + if (!layer) + return -1; + return layer->uniqueId(); +} + +static bool nativeFocusIsPlugin(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusNode(env, obj); + return node ? node->isPlugin() : false; +} + +static jobject nativeFocusNodeBounds(JNIEnv *env, jobject obj) +{ + const CachedFrame* frame; + const CachedNode* node = getFocusNode(env, obj, &frame); + WebCore::IntRect bounds = node ? node->bounds(frame) + : WebCore::IntRect(0, 0, 0, 0); + return createJavaRect(env, bounds.x(), bounds.y(), + bounds.maxX(), bounds.maxY()); +} + +static jint nativeFocusNodePointer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getFocusNode(env, obj); + return node ? reinterpret_cast<int>(node->nodePointer()) : 0; +} + +static bool nativeCursorWantsKeyEvents(JNIEnv* env, jobject jwebview) { + WebView* view = GET_NATIVE_VIEW(env, jwebview); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + return view->cursorWantsKeyEvents(); +} + +static void nativeHideCursor(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->hideCursor(); +} + +static void nativeInstrumentReport(JNIEnv *env, jobject obj) +{ +#ifdef ANDROID_INSTRUMENT + TimeCounter::reportNow(); +#endif +} + +static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + WebCore::IntRect rect = jrect_to_webrect(env, jrect); + view->selectBestAt(rect); +} + +static void nativeSelectAt(JNIEnv *env, jobject obj, jint x, jint y) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + WebCore::IntRect rect = IntRect(x, y , 1, 1); + view->selectBestAt(rect); + if (view->hasCursorNode()) + view->showCursorUntimed(); +} + +static jobject nativeLayerBounds(JNIEnv* env, jobject obj, jint jlayer) +{ + SkRect r; +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* layer = (LayerAndroid*) jlayer; + r = layer->bounds(); +#else + r.setEmpty(); +#endif + SkIRect irect; + r.round(&irect); + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, + irect.fRight, irect.fBottom); + env->DeleteLocalRef(rectClass); + return rect; +} + +static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) +{ + SkIRect irect = jrect_to_webrect(env, jrect); +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); + if (root) { + SkRect rect; + rect.set(irect); + rect = root->subtractLayers(rect); + rect.round(&irect); + } +#endif + jclass rectClass = env->FindClass("android/graphics/Rect"); + jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + jobject rect = env->NewObject(rectClass, init, irect.fLeft, irect.fTop, + irect.fRight, irect.fBottom); + env->DeleteLocalRef(rectClass); + return rect; +} + +static jint nativeTextGeneration(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + return root ? root->textGeneration() : 0; +} + +static bool nativePointInNavCache(JNIEnv *env, jobject obj, + int x, int y, int slop) +{ + return GET_NATIVE_VIEW(env, obj)->pointInNavCache(x, y, slop); +} + +static bool nativeMotionUp(JNIEnv *env, jobject obj, + int x, int y, int slop) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + return view->motionUp(x, y, slop); +} + +static bool nativeHasCursorNode(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->hasCursorNode(); +} + +static bool nativeHasFocusNode(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->hasFocusNode(); +} + +static bool nativeMoveCursor(JNIEnv *env, jobject obj, + int key, int count, bool ignoreScroll) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + return view->moveCursor(key, count, ignoreScroll); +} + +static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->setFindIsUp(isUp); +} + +static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->setFindIsEmpty(); +} + +static void nativeShowCursorTimed(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->showCursorTimed(); +} + static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure) { WebView* view = GET_NATIVE_VIEW(env, obj); - ALOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); + LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure"); view->setHeightCanMeasure(measure); } -static void nativeDestroy(JNIEnv *env, jobject obj, jint ptr) +static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + jclass rectClass = env->FindClass("android/graphics/Rect"); + LOG_ASSERT(rectClass, "Could not find Rect class!"); + jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); + LOG_ASSERT(init, "Could not find constructor for Rect"); + WebCore::IntRect webRect; + view->cursorRingBounds(&webRect); + jobject rect = env->NewObject(rectClass, init, webRect.x(), + webRect.y(), webRect.maxX(), webRect.maxY()); + env->DeleteLocalRef(rectClass); + return rect; +} + +static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, + jstring findUpper, jboolean sameAsLastSearch) +{ + // If one or the other is null, do not search. + if (!(findLower && findUpper)) + return 0; + // Obtain the characters for both the lower case string and the upper case + // string representing the same word. + const jchar* findLowerChars = env->GetStringChars(findLower, 0); + const jchar* findUpperChars = env->GetStringChars(findUpper, 0); + // If one or the other is null, do not search. + if (!(findLowerChars && findUpperChars)) { + if (findLowerChars) + env->ReleaseStringChars(findLower, findLowerChars); + if (findUpperChars) + env->ReleaseStringChars(findUpper, findUpperChars); + checkException(env); + return 0; + } + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in nativeFindAll"); + CachedRoot* root = view->getFrameCache(WebView::AllowNewer); + if (!root) { + env->ReleaseStringChars(findLower, findLowerChars); + env->ReleaseStringChars(findUpper, findUpperChars); + checkException(env); + return 0; + } + int length = env->GetStringLength(findLower); + // If the lengths of the strings do not match, then they are not the same + // word, so do not search. + if (!length || env->GetStringLength(findUpper) != length) { + env->ReleaseStringChars(findLower, findLowerChars); + env->ReleaseStringChars(findUpper, findUpperChars); + checkException(env); + return 0; + } + int width = root->documentWidth(); + int height = root->documentHeight(); + // Create a FindCanvas, which allows us to fake draw into it so we can + // figure out where our search string is rendered (and how many times). + FindCanvas canvas(width, height, (const UChar*) findLowerChars, + (const UChar*) findUpperChars, length << 1); + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); + canvas.setBitmapDevice(bitmap); + root->draw(canvas); + WTF::Vector<MatchInfo>* matches = canvas.detachMatches(); + // With setMatches, the WebView takes ownership of matches + view->setMatches(matches, sameAsLastSearch); + + env->ReleaseStringChars(findLower, findLowerChars); + env->ReleaseStringChars(findUpper, findUpperChars); + checkException(env); + return canvas.found(); +} + +static void nativeFindNext(JNIEnv *env, jobject obj, bool forward) { - WebView* view = reinterpret_cast<WebView*>(ptr); - ALOGD("nativeDestroy view: %p", view); - ALOG_ASSERT(view, "view not set in nativeDestroy"); + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in nativeFindNext"); + view->findNext(forward); +} + +static int nativeFindIndex(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in nativeFindIndex"); + return view->currentMatchIndex(); +} + +static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield"); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return; + const CachedNode* cachedFocusNode = root->currentFocus(); + if (!cachedFocusNode || !cachedFocusNode->isTextInput()) + return; + WTF::String webcoreString = jstringToWtfString(env, updatedText); + (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString); + root->setTextGeneration(generation); + checkException(env); +} + +static jint nativeGetBlockLeftEdge(JNIEnv *env, jobject obj, jint x, jint y, + jfloat scale) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + if (!view) + return -1; + return view->getBlockLeftEdge(x, y, scale); +} + +static void nativeDestroy(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + LOGD("nativeDestroy view: %p", view); + LOG_ASSERT(view, "view not set in nativeDestroy"); delete view; } -static void nativeStopGL(JNIEnv *env, jobject obj, jint ptr) +static void nativeStopGL(JNIEnv *env, jobject obj) { - if (ptr) - reinterpret_cast<WebView*>(ptr)->stopGL(); + GET_NATIVE_VIEW(env, obj)->stopGL(); +} + +static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return false; + const CachedNode* current = root->currentCursor(); + if (!current || !current->isTextInput()) + current = root->currentFocus(); + if (!current || !current->isTextInput()) + return false; + const CachedFrame* frame; + const CachedNode* next = root->nextTextField(current, &frame); + if (!next) + return false; + const WebCore::IntRect& bounds = next->bounds(frame); + root->rootHistory()->setMouseBounds(bounds); + view->getWebViewCore()->updateCursorBounds(root, frame, next); + view->showCursorUntimed(); + root->setCursor(const_cast<CachedFrame*>(frame), + const_cast<CachedNode*>(next)); + view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()), + static_cast<WebCore::Node*>(next->nodePointer())); + if (!next->isInLayer()) + view->scrollRectOnScreen(bounds); + view->getWebViewCore()->m_moveGeneration++; + return true; +} + +static int nativeMoveGeneration(JNIEnv *env, jobject obj) +{ + WebView* view = GET_NATIVE_VIEW(env, obj); + if (!view) + return 0; + return view->moveGeneration(); +} + +static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y) +{ + GET_NATIVE_VIEW(env, obj)->moveSelection(x, y); +} + +static void nativeResetSelection(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->resetSelection(); +} + +static jobject nativeSelectableText(JNIEnv* env, jobject obj) +{ + IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText(); + jclass pointClass = env->FindClass("android/graphics/Point"); + jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V"); + jobject point = env->NewObject(pointClass, init, pos.x(), pos.y()); + env->DeleteLocalRef(pointClass); + return point; +} + +static void nativeSelectAll(JNIEnv* env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->selectAll(); +} + +static void nativeSetExtendSelection(JNIEnv *env, jobject obj) +{ + GET_NATIVE_VIEW(env, obj)->setExtendSelection(); +} + +static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y) +{ + return GET_NATIVE_VIEW(env, obj)->startSelection(x, y); +} + +static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y) +{ + return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y); +} + +static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y) +{ + GET_NATIVE_VIEW(env, obj)->extendSelection(x, y); } static jobject nativeGetSelection(JNIEnv *env, jobject obj) { WebView* view = GET_NATIVE_VIEW(env, obj); - ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); String selection = view->getSelection(); return wtfStringToJstring(env, selection); } -static void nativeDiscardAllTextures(JNIEnv *env, jobject obj) +static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y) +{ + return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y); +} + +static jint nativeSelectionX(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->selectionX(); +} + +static jint nativeSelectionY(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->selectionY(); +} + +static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jint nativeView, + jboolean set, jfloat scale, jint x, jint y) +{ + ((WebView*)nativeView)->setSelectionPointer(set, scale, x, y); +} + +static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj) { - //discard all textures for debugging/test purposes, but not gl backing memory - bool allTextures = true, deleteGLTextures = false; - TilesManager::instance()->discardTextures(allTextures, deleteGLTextures); + GET_NATIVE_VIEW(env, obj)->registerPageSwapCallback(); } static void nativeTileProfilingStart(JNIEnv *env, jobject obj) @@ -1071,14 +2581,15 @@ static void dumpToFile(const char text[], void* file) { } #endif -// Return true to view invalidate WebView static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jvalue) { WTF::String key = jstringToWtfString(env, jkey); WTF::String value = jstringToWtfString(env, jvalue); if (key == "inverted") { - bool shouldInvert = (value == "true"); - TilesManager::instance()->setInvertedScreen(shouldInvert); + if (value == "true") + TilesManager::instance()->setInvertedScreen(true); + else + TilesManager::instance()->setInvertedScreen(false); return true; } else if (key == "inverted_contrast") { @@ -1089,47 +2600,25 @@ static bool nativeSetProperty(JNIEnv *env, jobject obj, jstring jkey, jstring jv else if (key == "enable_cpu_upload_path") { TilesManager::instance()->transferQueue()->setTextureUploadType( value == "true" ? CpuUpload : GpuUpload); + return true; } else if (key == "use_minimal_memory") { TilesManager::instance()->setUseMinimalMemory(value == "true"); - } - else if (key == "use_double_buffering") { - TilesManager::instance()->setUseDoubleBuffering(value == "true"); - } - else if (key == "tree_updates") { - TilesManager::instance()->clearContentUpdates(); + return true; } return false; } -static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring jkey) +static jstring nativeGetProperty(JNIEnv *env, jobject obj, jstring key) { - WTF::String key = jstringToWtfString(env, jkey); - if (key == "tree_updates") { - int updates = TilesManager::instance()->getContentUpdates(); - WTF::String wtfUpdates = WTF::String::number(updates); - return wtfStringToJstring(env, wtfUpdates); - } return 0; } static void nativeOnTrimMemory(JNIEnv *env, jobject obj, jint level) { if (TilesManager::hardwareAccelerationEnabled()) { - // When we got TRIM_MEMORY_MODERATE or TRIM_MEMORY_COMPLETE, we should - // make sure the transfer queue is empty and then abandon the Surface - // Texture to avoid ANR b/c framework may destroy the EGL context. - // Refer to WindowManagerImpl.java for conditions we followed. - TilesManager* tilesManager = TilesManager::instance(); - if ((level >= TRIM_MEMORY_MODERATE - && !tilesManager->highEndGfx()) - || level >= TRIM_MEMORY_COMPLETE) { - ALOGD("OnTrimMemory with EGL Context %p", eglGetCurrentContext()); - tilesManager->cleanupGLResources(); - } - - bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN), glTextures = true; - tilesManager->discardTextures(freeAllTextures, glTextures); + bool freeAllTextures = (level > TRIM_MEMORY_UI_HIDDEN); + TilesManager::instance()->deallocateTextures(freeAllTextures); } } @@ -1137,7 +2626,7 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) { #ifdef ANDROID_DUMP_DISPLAY_TREE WebView* view = GET_NATIVE_VIEW(env, jwebview); - ALOG_ASSERT(view, "view not set in %s", __FUNCTION__); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); if (view && view->getWebViewCore()) { FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w"); @@ -1154,17 +2643,17 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) SkDumpCanvas canvas(&dumper); // this will playback the picture into the canvas, which will // spew its contents to the dumper - view->draw(&canvas, 0, WebView::DrawExtrasNone); + view->draw(&canvas, 0, 0, false); // we're done with the file now fwrite("\n", 1, 1, file); fclose(file); } #if USE(ACCELERATED_COMPOSITING) - const LayerAndroid* baseLayer = view->getBaseLayer(); - if (baseLayer) { + const LayerAndroid* rootLayer = view->compositeRoot(); + if (rootLayer) { FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); if (file) { - baseLayer->dumpLayers(file, 0); + rootLayer->dumpLayers(file, 0); fclose(file); } } @@ -1173,13 +2662,13 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) #endif } -static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView, - jint x, jint y, jobject rect, jobject bounds) +static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y, + jobject rect, jobject bounds) { - WebView* webview = reinterpret_cast<WebView*>(nativeView); - ALOG_ASSERT(webview, "webview not set in %s", __FUNCTION__); + WebView* view = GET_NATIVE_VIEW(env, jwebview); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); SkIRect nativeRect, nativeBounds; - int id = webview->scrollableLayer(x, y, &nativeRect, &nativeBounds); + int id = view->scrollableLayer(x, y, &nativeRect, &nativeBounds); if (rect) GraphicsJNI::irect_to_jrect(nativeRect, env, rect); if (bounds) @@ -1187,18 +2676,18 @@ static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint nativeView, return id; } -static bool nativeScrollLayer(JNIEnv* env, jobject obj, - jint nativeView, jint layerId, jint x, jint y) +static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint layerId, jint x, + jint y) { #if ENABLE(ANDROID_OVERFLOW_SCROLL) - WebView* webview = reinterpret_cast<WebView*>(nativeView); - webview->scrollLayer(layerId, x, y); + WebView* view = GET_NATIVE_VIEW(env, obj); + view->scrollLayer(layerId, x, y); //TODO: the below only needed for the SW rendering path - LayerAndroid* baseLayer = webview->getBaseLayer(); - if (!baseLayer) + LayerAndroid* root = view->compositeRoot(); + if (!root) return false; - LayerAndroid* layer = baseLayer->findById(layerId); + LayerAndroid* layer = root->findById(layerId); if (!layer || !layer->contentIsScrollable()) return false; return static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y); @@ -1208,10 +2697,9 @@ static bool nativeScrollLayer(JNIEnv* env, jobject obj, static void nativeSetIsScrolling(JNIEnv* env, jobject jwebview, jboolean isScrolling) { - // TODO: Pass in the native pointer instead WebView* view = GET_NATIVE_VIEW(env, jwebview); - if (view) - view->setIsScrolling(isScrolling); + LOG_ASSERT(view, "view not set in %s", __FUNCTION__); + view->setIsScrolling(isScrolling); } static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled) @@ -1219,9 +2707,9 @@ static void nativeUseHardwareAccelSkia(JNIEnv*, jobject, jboolean enabled) BaseRenderer::setCurrentRendererType(enabled ? BaseRenderer::Ganesh : BaseRenderer::Raster); } -static int nativeGetBackgroundColor(JNIEnv* env, jobject obj, jint nativeView) +static int nativeGetBackgroundColor(JNIEnv* env, jobject obj) { - WebView* view = reinterpret_cast<WebView*>(nativeView); + WebView* view = GET_NATIVE_VIEW(env, obj); BaseLayerAndroid* baseLayer = view->getBaseLayer(); if (baseLayer) { WebCore::Color color = baseLayer->getBackgroundColor(); @@ -1235,93 +2723,179 @@ static int nativeGetBackgroundColor(JNIEnv* env, jobject obj, jint nativeView) static void nativeSetPauseDrawing(JNIEnv *env, jobject obj, jint nativeView, jboolean pause) { - reinterpret_cast<WebView*>(nativeView)->setDrawingPaused(pause); -} - -static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView, - jint selectionPtr) -{ - SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr); - reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection); -} - -static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView, - jint handleIndex, jobject cursorPoint, - jobject textQuad) -{ - WebView* webview = reinterpret_cast<WebView*>(nativeView); - SkIPoint nativePoint; - FloatQuad nativeTextQuad; - int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, - nativePoint, nativeTextQuad); - if (cursorPoint) - GraphicsJNI::ipoint_to_jpoint(nativePoint, env, cursorPoint); - if (textQuad) - webview->floatQuadToQuadF(env, nativeTextQuad, textQuad); - return layerId; -} - -static void nativeMapLayerRect(JNIEnv *env, jobject obj, jint nativeView, - jint layerId, jobject rect) -{ - WebView* webview = reinterpret_cast<WebView*>(nativeView); - SkIRect nativeRect; - GraphicsJNI::jrect_to_irect(env, rect, &nativeRect); - webview->mapLayerRect(layerId, nativeRect); - GraphicsJNI::irect_to_jrect(nativeRect, env, rect); -} - -static jint nativeSetHwAccelerated(JNIEnv *env, jobject obj, jint nativeView, - jboolean hwAccelerated) -{ - WebView* webview = reinterpret_cast<WebView*>(nativeView); - return webview->setHwAccelerated(hwAccelerated); -} - -static void nativeFindMaxVisibleRect(JNIEnv *env, jobject obj, jint nativeView, - jint movingLayerId, jobject visibleContentRect) -{ - WebView* webview = reinterpret_cast<WebView*>(nativeView); - SkIRect nativeRect; - GraphicsJNI::jrect_to_irect(env, visibleContentRect, &nativeRect); - webview->findMaxVisibleRect(movingLayerId, nativeRect); - GraphicsJNI::irect_to_jrect(nativeRect, env, visibleContentRect); + ((WebView*)nativeView)->m_isDrawingPaused = pause; } /* * JNI registration */ static JNINativeMethod gJavaWebViewMethods[] = { + { "nativeCacheHitFramePointer", "()I", + (void*) nativeCacheHitFramePointer }, + { "nativeCacheHitIsPlugin", "()Z", + (void*) nativeCacheHitIsPlugin }, + { "nativeCacheHitNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeCacheHitNodeBounds }, + { "nativeCacheHitNodePointer", "()I", + (void*) nativeCacheHitNodePointer }, + { "nativeClearCursor", "()V", + (void*) nativeClearCursor }, { "nativeCreate", "(ILjava/lang/String;Z)V", (void*) nativeCreate }, - { "nativeDestroy", "(I)V", + { "nativeCursorFramePointer", "()I", + (void*) nativeCursorFramePointer }, + { "nativePageShouldHandleShiftAndArrows", "()Z", + (void*) nativePageShouldHandleShiftAndArrows }, + { "nativeCursorNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeCursorNodeBounds }, + { "nativeCursorNodePointer", "()I", + (void*) nativeCursorNodePointer }, + { "nativeCursorIntersects", "(Landroid/graphics/Rect;)Z", + (void*) nativeCursorIntersects }, + { "nativeCursorIsAnchor", "()Z", + (void*) nativeCursorIsAnchor }, + { "nativeCursorIsTextInput", "()Z", + (void*) nativeCursorIsTextInput }, + { "nativeCursorPosition", "()Landroid/graphics/Point;", + (void*) nativeCursorPosition }, + { "nativeCursorText", "()Ljava/lang/String;", + (void*) nativeCursorText }, + { "nativeCursorWantsKeyEvents", "()Z", + (void*)nativeCursorWantsKeyEvents }, + { "nativeDebugDump", "()V", + (void*) nativeDebugDump }, + { "nativeDestroy", "()V", (void*) nativeDestroy }, - { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;II)V", + { "nativeDraw", "(Landroid/graphics/Canvas;Landroid/graphics/RectF;IIZ)I", (void*) nativeDraw }, - { "nativeCreateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", - (void*) nativeCreateDrawGLFunction }, - { "nativeGetDrawGLFunction", "(I)I", + { "nativeGetDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;FI)I", (void*) nativeGetDrawGLFunction }, - { "nativeUpdateDrawGLFunction", "(ILandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;F)V", + { "nativeUpdateDrawGLFunction", "(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/RectF;)V", (void*) nativeUpdateDrawGLFunction }, { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", (void*) nativeDumpDisplayTree }, { "nativeEvaluateLayersAnimations", "(I)Z", (void*) nativeEvaluateLayersAnimations }, + { "nativeExtendSelection", "(II)V", + (void*) nativeExtendSelection }, + { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I", + (void*) nativeFindAll }, + { "nativeFindNext", "(Z)V", + (void*) nativeFindNext }, + { "nativeFindIndex", "()I", + (void*) nativeFindIndex}, + { "nativeFocusCandidateFramePointer", "()I", + (void*) nativeFocusCandidateFramePointer }, + { "nativeFocusCandidateHasNextTextfield", "()Z", + (void*) focusCandidateHasNextTextfield }, + { "nativeFocusCandidateIsPassword", "()Z", + (void*) nativeFocusCandidateIsPassword }, + { "nativeFocusCandidateIsRtlText", "()Z", + (void*) nativeFocusCandidateIsRtlText }, + { "nativeFocusCandidateIsTextInput", "()Z", + (void*) nativeFocusCandidateIsTextInput }, + { "nativeFocusCandidateLineHeight", "()I", + (void*) nativeFocusCandidateLineHeight }, + { "nativeFocusCandidateMaxLength", "()I", + (void*) nativeFocusCandidateMaxLength }, + { "nativeFocusCandidateIsAutoComplete", "()Z", + (void*) nativeFocusCandidateIsAutoComplete }, + { "nativeFocusCandidateIsSpellcheck", "()Z", + (void*) nativeFocusCandidateIsSpellcheck }, + { "nativeFocusCandidateName", "()Ljava/lang/String;", + (void*) nativeFocusCandidateName }, + { "nativeFocusCandidateNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeFocusCandidateNodeBounds }, + { "nativeFocusCandidatePaddingRect", "()Landroid/graphics/Rect;", + (void*) nativeFocusCandidatePaddingRect }, + { "nativeFocusCandidatePointer", "()I", + (void*) nativeFocusCandidatePointer }, + { "nativeFocusCandidateText", "()Ljava/lang/String;", + (void*) nativeFocusCandidateText }, + { "nativeFocusCandidateTextSize", "()F", + (void*) nativeFocusCandidateTextSize }, + { "nativeFocusCandidateType", "()I", + (void*) nativeFocusCandidateType }, + { "nativeFocusCandidateLayerId", "()I", + (void*) nativeFocusCandidateLayerId }, + { "nativeFocusIsPlugin", "()Z", + (void*) nativeFocusIsPlugin }, + { "nativeFocusNodeBounds", "()Landroid/graphics/Rect;", + (void*) nativeFocusNodeBounds }, + { "nativeFocusNodePointer", "()I", + (void*) nativeFocusNodePointer }, + { "nativeGetCursorRingBounds", "()Landroid/graphics/Rect;", + (void*) nativeGetCursorRingBounds }, { "nativeGetSelection", "()Ljava/lang/String;", (void*) nativeGetSelection }, + { "nativeHasCursorNode", "()Z", + (void*) nativeHasCursorNode }, + { "nativeHasFocusNode", "()Z", + (void*) nativeHasFocusNode }, + { "nativeHideCursor", "()V", + (void*) nativeHideCursor }, + { "nativeHitSelection", "(II)Z", + (void*) nativeHitSelection }, + { "nativeImageURI", "(II)Ljava/lang/String;", + (void*) nativeImageURI }, + { "nativeInstrumentReport", "()V", + (void*) nativeInstrumentReport }, + { "nativeLayerBounds", "(I)Landroid/graphics/Rect;", + (void*) nativeLayerBounds }, + { "nativeMotionUp", "(III)Z", + (void*) nativeMotionUp }, + { "nativeMoveCursor", "(IIZ)Z", + (void*) nativeMoveCursor }, + { "nativeMoveCursorToNextTextInput", "()Z", + (void*) nativeMoveCursorToNextTextInput }, + { "nativeMoveGeneration", "()I", + (void*) nativeMoveGeneration }, + { "nativeMoveSelection", "(II)V", + (void*) nativeMoveSelection }, + { "nativePointInNavCache", "(III)Z", + (void*) nativePointInNavCache }, + { "nativeResetSelection", "()V", + (void*) nativeResetSelection }, + { "nativeSelectableText", "()Landroid/graphics/Point;", + (void*) nativeSelectableText }, + { "nativeSelectAll", "()V", + (void*) nativeSelectAll }, + { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V", + (void*) nativeSelectBestAt }, + { "nativeSelectAt", "(II)V", + (void*) nativeSelectAt }, + { "nativeSelectionX", "()I", + (void*) nativeSelectionX }, + { "nativeSelectionY", "()I", + (void*) nativeSelectionY }, + { "nativeSetExtendSelection", "()V", + (void*) nativeSetExtendSelection }, + { "nativeSetFindIsEmpty", "()V", + (void*) nativeSetFindIsEmpty }, + { "nativeSetFindIsUp", "(Z)V", + (void*) nativeSetFindIsUp }, { "nativeSetHeightCanMeasure", "(Z)V", (void*) nativeSetHeightCanMeasure }, - { "nativeSetBaseLayer", "(IIZZI)Z", + { "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V", (void*) nativeSetBaseLayer }, - { "nativeGetBaseLayer", "(I)I", + { "nativeGetTextSelectionRegion", "(ILandroid/graphics/Region;)V", + (void*) nativeGetTextSelectionRegion }, + { "nativeGetSelectionHandles", "(I[I)V", + (void*) nativeGetSelectionHandles }, + { "nativeGetBaseLayer", "()I", (void*) nativeGetBaseLayer }, + { "nativeReplaceBaseContent", "(I)V", + (void*) nativeReplaceBaseContent }, { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", (void*) nativeCopyBaseContentToPicture }, { "nativeHasContent", "()Z", (void*) nativeHasContent }, - { "nativeDiscardAllTextures", "()V", - (void*) nativeDiscardAllTextures }, + { "nativeSetSelectionPointer", "(IZFII)V", + (void*) nativeSetSelectionPointer }, + { "nativeShowCursorTimed", "()V", + (void*) nativeShowCursorTimed }, + { "nativeRegisterPageSwapCallback", "()V", + (void*) nativeRegisterPageSwapCallback }, { "nativeTileProfilingStart", "()V", (void*) nativeTileProfilingStart }, { "nativeTileProfilingStop", "()F", @@ -1336,17 +2910,29 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeTileProfilingGetInt }, { "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F", (void*) nativeTileProfilingGetFloat }, - { "nativeStopGL", "(I)V", + { "nativeStartSelection", "(II)Z", + (void*) nativeStartSelection }, + { "nativeStopGL", "()V", (void*) nativeStopGL }, - { "nativeScrollableLayer", "(IIILandroid/graphics/Rect;Landroid/graphics/Rect;)I", + { "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;", + (void*) nativeSubtractLayers }, + { "nativeTextGeneration", "()I", + (void*) nativeTextGeneration }, + { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", + (void*) nativeUpdateCachedTextfield }, + { "nativeWordSelection", "(II)Z", + (void*) nativeWordSelection }, + { "nativeGetBlockLeftEdge", "(IIF)I", + (void*) nativeGetBlockLeftEdge }, + { "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I", (void*) nativeScrollableLayer }, - { "nativeScrollLayer", "(IIII)Z", + { "nativeScrollLayer", "(III)Z", (void*) nativeScrollLayer }, { "nativeSetIsScrolling", "(Z)V", (void*) nativeSetIsScrolling }, { "nativeUseHardwareAccelSkia", "(Z)V", (void*) nativeUseHardwareAccelSkia }, - { "nativeGetBackgroundColor", "(I)I", + { "nativeGetBackgroundColor", "()I", (void*) nativeGetBackgroundColor }, { "nativeSetProperty", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*) nativeSetProperty }, @@ -1356,27 +2942,17 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeOnTrimMemory }, { "nativeSetPauseDrawing", "(IZ)V", (void*) nativeSetPauseDrawing }, - { "nativeSetTextSelection", "(II)V", - (void*) nativeSetTextSelection }, - { "nativeGetHandleLayerId", "(IILandroid/graphics/Point;Landroid/webkit/QuadF;)I", - (void*) nativeGetHandleLayerId }, - { "nativeMapLayerRect", "(IILandroid/graphics/Rect;)V", - (void*) nativeMapLayerRect }, - { "nativeSetHwAccelerated", "(IZ)I", - (void*) nativeSetHwAccelerated }, - { "nativeFindMaxVisibleRect", "(IILandroid/graphics/Rect;)V", - (void*) nativeFindMaxVisibleRect }, }; int registerWebView(JNIEnv* env) { - jclass clazz = env->FindClass("android/webkit/WebViewClassic"); - ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebViewClassic"); + jclass clazz = env->FindClass("android/webkit/WebView"); + LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView"); gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I"); - ALOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebViewClassic.mNativeClass"); + LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass"); env->DeleteLocalRef(clazz); - return jniRegisterNativeMethods(env, "android/webkit/WebViewClassic", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); + return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods)); } } // namespace android |