OSDN Git Service

Add UI considerations to layers
authorCary Clark <cary@android.com>
Wed, 27 Jan 2010 22:00:54 +0000 (17:00 -0500)
committerCary Clark <cary@android.com>
Wed, 17 Feb 2010 18:13:54 +0000 (13:13 -0500)
companion fix is in framework/base

With fixed layers, parts of the web page are now
in motion relative to the document when the page
scrolls. Many routines that formerly read static
coordinates need to compute locations. In some cases,
new computations are cached for speed -- for instance,
the current cursor position is cached when it is
frequently compared.

The cursor rings and other drawing elements like
finding text on the page now to be drawn in the correct
order so that they appear both under and over layers.

There's quite a bit more work to be done. Major
pieces are drawing the text selection in the correct
order, and computing locations based on nest layers.
With this checkin, only the position of the child-
most layer is considered when computing bounds.

http://b/2369549

JavaScriptCore/wtf/Platform.h
- Turn compositing on. All routines that
reference LayerAndroid are bracketed by this
condition.

WebCore/platform/graphics/android/LayerAndroid.h
WebCore/platform/graphics/android/LayerAndroid.cpp
- Add a unique id to each layer. The unique id is
used to associate a layer created when the DOM is
parsed in the webkit thread with its copy in the
UI thread.
- Add: draw the text found on the page, as a call
out in the primary draw. The call out must follow
the drawing the layers' contents to show the found
text correctly. Note that this adds a new slot with
identical contents in every child LayerAndroid. In
a future optimization, a RootLayerAndroid could hold
data common for all child layers.
- Add:  clipArea(), which returns an array of rectangles
describing the clip for this LayerAndroid and its
children. Generally, this is the part of the webpage
which is covered by one or more fixed layers.
- Add: find(FloatPoint) that returns the deepest layer
that contains this point. This is used to match taps
to the layer that is tapped on.
- Add: draw all layer pictures and identify
which layer is being drawn. This is used to analyze
the picture contents for finding and selecting text.
- Add: find the layer that matches a given id; this is
used to map cached DOM node data back to the layer
that contains it.
- Fix up includes, delete unused interfaces

WebKit/android/jni/WebViewCore.h
WebKit/android/jni/WebViewCore.cpp
- Remove local mRootLayer; use the one in WebView.cpp
instead (which is in sync with WebView.java)

WebKit/Android.mk
WebKit/android/nav/CachedLayer.h
WebKit/android/nav/CachedLayer.cpp
- CacheLayer associates the cached node with the
LayerAndroid instance. It contains the index to the
node in the cached frame, the LayerAndroid's unique id,
and the spacial offset of the node within the layer
when the DOM information was captured. It also caches
a pointer to the LayerAndroid instance.
CacheLayer computes the node's location each time
it is called, since the fixed layer may be constantly
moving relative to the document's coordinates.

WebKit/android/nav/CacheBuilder.h
WebKit/android/nav/CacheBuilder.cpp
- Track the active layer while building the nav cache.
The 'Tracker' structs were refactored to share common
code, and a new 'LayerTracker' struct identifies when
the node walker is inside a layer.
- Added code to dump layer information for debugging.
- Note that CachedNode::cursorRingsPtr can only be called
during nav data construction
- The cache builder can limit or exclude nodes that
are clipped out -- but until I have more understanding
of layer clipping, treat contained nodes as unclipped.

WebKit/android/nav/CachedDebug.h
- Add a variant that can dump either to a log file
or the console including the function it was dumped from.

WebKit/android/nav/CachedFrame.h
WebKit/android/nav/CachedFrame.cpp
- Add an array of CacheLayer instances.
- Protect bounds from direct access since they must
always be computed.
- Remove misnamed focus parameter from many routines
since the cursor node can be read from the root frame.
- Add: adjustBounds(), which computes the bounds as the
layer moves.
- Add: checkRings(), which gets the appropriate picture
for the node.
- Remove disabled code
- Find the layer list for the matching node by
using a binary search
- Add: resetLayers() to reset the LayerAndroid pointer
in CachedLayers when the layer world changes.

WebKit/android/nav/CachedHistory.h
WebKit/android/nav/CachedHistory.cpp
- Update history data to have matching frame and node

WebKit/android/nav/CachedNode.h
WebKit/android/nav/CachedNode.cpp
- Refactor functions that directly read coordinates
to compute them. In some cases, pass the frame in so
that the layer coordinates can be found.
- Add a bit to note that the node belongs to a layer.
- Remove duplicate bounds interfaces.
- Add methods to get cursor ring data at runtime.
- Update debugging info.

WebKit/android/nav/CachedRoot.h
WebKit/android/nav/CachedRoot.cpp
- Isolate direct picture access so that the layer
picture can be returned.
- Add knowledge of how the base is covered by layers.
- Add a pointer to the root LayerAndroid.
- delete disabled code.
- Move the cursor ring into view if it is obscured
by a layer (this isn't totally working)
- Before finding the next node to move to, set
up 'cursor cache' data, including the visible picture.

WebKit/android/nav/FindCanvas.h
WebKit/android/nav/FindCanvas.cpp
- Move find code here so that it can be called from
layers.

WebKit/android/nav/WebView.cpp
- Add java interface to get viewport metrics on demand.
- Pass frame with the node.
- Remove the find on page code (now in FindCanvas).
- Compute focus rings instead of reading them directly.
- Transfer layer id when getting new nav cache.
- Set up root LayerAndroid.
- Add utility to track if cursor is in a layer.
- Simplify drawLayers() to use common view metrics.

22 files changed:
JavaScriptCore/wtf/Platform.h
WebCore/platform/graphics/android/LayerAndroid.cpp
WebCore/platform/graphics/android/LayerAndroid.h
WebKit/Android.mk
WebKit/android/jni/WebViewCore.cpp
WebKit/android/jni/WebViewCore.h
WebKit/android/nav/CacheBuilder.cpp
WebKit/android/nav/CacheBuilder.h
WebKit/android/nav/CachedDebug.h
WebKit/android/nav/CachedFrame.cpp
WebKit/android/nav/CachedFrame.h
WebKit/android/nav/CachedHistory.cpp
WebKit/android/nav/CachedHistory.h
WebKit/android/nav/CachedLayer.cpp [new file with mode: 0644]
WebKit/android/nav/CachedLayer.h [new file with mode: 0644]
WebKit/android/nav/CachedNode.cpp
WebKit/android/nav/CachedNode.h
WebKit/android/nav/CachedRoot.cpp
WebKit/android/nav/CachedRoot.h
WebKit/android/nav/FindCanvas.cpp
WebKit/android/nav/FindCanvas.h
WebKit/android/nav/WebView.cpp

index b113e79..486f60c 100644 (file)
@@ -1003,8 +1003,8 @@ on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */
 #endif
 #endif
 
-#if PLATFORM(ANDROID)
-#define WTF_USE_ACCELERATED_COMPOSITING 0
+#if PLATFORM(ANDROID) && !defined WTF_USE_ACCELERATED_COMPOSITING
+#define WTF_USE_ACCELERATED_COMPOSITING 1
 #endif
 
 #if PLATFORM(IPHONE)
index dcbb0c3..8fb335e 100644 (file)
@@ -4,13 +4,7 @@
 #if USE(ACCELERATED_COMPOSITING)
 
 #include "AndroidAnimation.h"
-#include "CString.h"
-#include "GraphicsLayerAndroid.h"
-#include "PlatformGraphicsContext.h"
-#include "RenderLayer.h"
-#include "RenderLayerBacking.h"
-#include "RenderView.h"
-#include "SkDevice.h"
+#include "FindCanvas.h"
 #include "SkDrawFilter.h"
 #include <wtf/CurrentTime.h>
 
@@ -20,6 +14,8 @@
 namespace WebCore {
 
 static int gDebugLayerAndroidInstances;
+static int gUniqueId;
+
 inline int LayerAndroid::instancesCount()
 {
     return gDebugLayerAndroidInstances;
@@ -49,7 +45,9 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(),
     m_drawsContent(true),
     m_haveImage(false),
     m_haveClip(false),
-    m_recordingPicture(0)
+    m_recordingPicture(0),
+    m_findOnPage(0),
+    m_uniqueId(++gUniqueId)
 {
     gDebugLayerAndroidInstances++;
 }
@@ -59,13 +57,15 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer),
     m_haveContents(layer.m_haveContents),
     m_drawsContent(layer.m_drawsContent),
     m_haveImage(layer.m_haveImage),
-    m_haveClip(layer.m_haveClip)
+    m_haveClip(layer.m_haveClip),
+    m_findOnPage(0),
+    m_uniqueId(layer.m_uniqueId)
 {
     m_recordingPicture = layer.m_recordingPicture;
     SkSafeRef(m_recordingPicture);
 
     for (int i = 0; i < layer.countChildren(); i++)
-        addChild(new LayerAndroid(*static_cast<LayerAndroid*>(layer.getChild(i))))->unref();
+        addChild(new LayerAndroid(*layer.getChild(i)))->unref();
 
     KeyframesMap::const_iterator end = layer.m_animations.end();
     for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it)
@@ -94,7 +94,7 @@ bool LayerAndroid::evaluateAnimations() const
 bool LayerAndroid::hasAnimations() const
 {
     for (int i = 0; i < countChildren(); i++) {
-        if (static_cast<LayerAndroid*>(getChild(i))->hasAnimations())
+        if (getChild(i)->hasAnimations())
             return true;
     }
     return !!m_animations.size();
@@ -104,7 +104,7 @@ bool LayerAndroid::evaluateAnimations(double time) const
 {
     bool hasRunningAnimations = false;
     for (int i = 0; i < countChildren(); i++) {
-        if (static_cast<LayerAndroid*>(getChild(i))->evaluateAnimations(time))
+        if (getChild(i)->evaluateAnimations(time))
             hasRunningAnimations = true;
     }
     KeyframesMap::const_iterator end = m_animations.end();
@@ -132,10 +132,8 @@ void LayerAndroid::removeAnimation(const String& name)
 void LayerAndroid::setDrawsContent(bool drawsContent)
 {
     m_drawsContent = drawsContent;
-    for (int i = 0; i < countChildren(); i++) {
-        LayerAndroid* layer = static_cast<LayerAndroid*>(getChild(i));
-        layer->setDrawsContent(drawsContent);
-    }
+    for (int i = 0; i < countChildren(); i++)
+        getChild(i)->setDrawsContent(drawsContent);
 }
 
 // We only use the bounding rect of the layer as mask...
@@ -167,13 +165,64 @@ void LayerAndroid::draw(SkCanvas* canvas, const SkRect* viewPort)
     paintChildren(viewPort, canvas, 1);
 }
 
+void LayerAndroid::bounds(SkRect* rect) const
+{
+    rect->fLeft = m_position.fX + m_translation.fX;
+    rect->fTop = m_position.fY + m_translation.fY;
+    rect->fRight = rect->fLeft + m_size.width();
+    rect->fBottom = rect->fTop + m_size.height();
+}
+
+bool LayerAndroid::boundsIsUnique(SkTDArray<SkRect>* region,
+                                  const SkRect& local) const
+{
+    for (int i = 0; i < region->count(); i++) {
+        if ((*region)[i].contains(local))
+            return false;
+    }
+    return true;
+}
+
+void LayerAndroid::clipArea(SkTDArray<SkRect>* region) const
+{
+    SkRect local;
+    local.set(0, 0, std::numeric_limits<float>::max(),
+        std::numeric_limits<float>::max());
+    clipInner(region, local);
+}
+
+void LayerAndroid::clipInner(SkTDArray<SkRect>* region,
+                             const SkRect& local) const
+{
+    SkRect localBounds;
+    bounds(&localBounds);
+    localBounds.intersect(local);
+    if (localBounds.isEmpty())
+        return;
+    if (m_recordingPicture && boundsIsUnique(region, localBounds))
+        *region->append() = localBounds;
+    for (int i = 0; i < countChildren(); i++)
+        getChild(i)->clipInner(region, m_haveClip ? localBounds : local);
+}
+
+const LayerAndroid* LayerAndroid::find(FloatPoint pos) const
+{
+    for (int i = 0; i < countChildren(); i++) {
+        const LayerAndroid* found = getChild(i)->find(pos);
+        if (found)
+            return found;
+    }
+    SkRect localBounds;
+    bounds(&localBounds);
+    if (localBounds.contains(pos))
+        return this;
+    return 0;
+}
+
 void LayerAndroid::setClip(SkCanvas* canvas)
 {
     SkRect clip;
-    clip.fLeft = m_position.fX + m_translation.fX;
-    clip.fTop = m_position.fY + m_translation.fY;
-    clip.fRight = clip.fLeft + m_size.width();
-    clip.fBottom = clip.fTop + m_size.height();
+    bounds(&clip);
     canvas->clipRect(clip);
 }
 
@@ -190,13 +239,9 @@ void LayerAndroid::paintChildren(const SkRect* viewPort, SkCanvas* canvas,
                       m_position.fY + m_translation.fY);
 
     for (int i = 0; i < countChildren(); i++) {
-        LayerAndroid* layer = static_cast<LayerAndroid*>(getChild(i));
-        if (layer) {
-            gDebugChildLevel++;
-            layer->paintChildren(viewPort,
-                                 canvas, opacity * m_opacity);
-            gDebugChildLevel--;
-        }
+        gDebugChildLevel++;
+        getChild(i)->paintChildren(viewPort, canvas, opacity * m_opacity);
+        gDebugChildLevel--;
     }
 
     canvas->restoreToCount(count);
@@ -222,7 +267,9 @@ bool LayerAndroid::calcPosition(const SkRect* viewPort,
         else if (m_fixedBottom.defined())
             y = dy + h - m_fixedBottom.calcFloatValue(h) - m_size.height();
 
-        matrix->setTranslate(x, y);
+        if (matrix)
+            matrix->setTranslate(x, y);
+        setPosition(x, y);
         return true;
     }
     return false;
@@ -283,6 +330,8 @@ void LayerAndroid::paintMe(const SkRect* viewPort,
 
     m_recordingPicture->draw(canvas);
 
+    if (m_findOnPage)
+        m_findOnPage->drawLayer(canvas, 0, m_uniqueId);
 #ifdef LAYER_DEBUG
     float w = m_size.width();
     float h = m_size.height();
@@ -400,7 +449,7 @@ void writeLength(FILE* file, int indentLevel, const char* str, SkLength length)
     fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value);
 }
 
-void LayerAndroid::dumpLayers(FILE* file, int indentLevel)
+void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const
 {
     writeln(file, indentLevel, "{");
 
@@ -429,15 +478,32 @@ void LayerAndroid::dumpLayers(FILE* file, int indentLevel)
         for (int i = 0; i < countChildren(); i++) {
             if (i > 0)
                 writeln(file, indentLevel + 1, ", ");
-            LayerAndroid* layer = static_cast<LayerAndroid*>(getChild(i));
-            if (layer)
-                layer->dumpLayers(file, indentLevel + 1);
+            getChild(i)->dumpLayers(file, indentLevel + 1);
         }
         writeln(file, indentLevel + 1, "];");
     }
     writeln(file, indentLevel, "}");
 }
 
+const LayerAndroid* LayerAndroid::findById(int match) const
+{
+    if (m_uniqueId == match)
+        return this;
+    for (int i = 0; i < countChildren(); i++) {
+        const LayerAndroid* result = getChild(i)->findById(match);
+        if (result)
+            return result;
+    }
+    return 0;
+}
+
+void LayerAndroid::setFindOnPage(FindOnPage* findOnPage)
+{
+    m_findOnPage = findOnPage;
+    for (int i = 0; i < countChildren(); i++)
+        getChild(i)->setFindOnPage(findOnPage);
+}
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
index 104c03a..deb51bc 100644 (file)
 
 #if USE(ACCELERATED_COMPOSITING)
 
-#include "Color.h"
 #include "FloatPoint.h"
-#include "FloatPoint3D.h"
-#include "FloatSize.h"
-#include "Length.h"
 #include "RefPtr.h"
+#include "SkColor.h"
 #include "SkLayer.h"
 #include "StringHash.h"
-#include "Vector.h"
 #include <wtf/HashMap.h>
 
+class FindOnPage;
 class SkCanvas;
 class SkMatrix;
 class SkPicture;
-class SkRect;
 
 namespace WebCore {
 
 class AndroidAnimation;
-class AndroidAnimationValue;
 
 class LayerAndroid : public SkLayer {
 
@@ -52,12 +47,14 @@ public:
     void setHaveContents(bool haveContents) { m_haveContents = haveContents; }
     void setHaveImage(bool haveImage) { m_haveImage = haveImage; }
     void setDrawsContent(bool drawsContent);
+    void setFindOnPage(FindOnPage* findOnPage);
     void setMaskLayer(LayerAndroid*);
     void setMasksToBounds(bool);
     virtual void setBackgroundColor(SkColor color);
     void setIsRootLayer(bool isRootLayer) { m_isRootLayer = isRootLayer; }
 
     virtual void draw(SkCanvas*, const SkRect* viewPort);
+//    GraphicsContext* paintContext();
     bool prepareContext(bool force = false);
     void startRecording();
     void stopRecording();
@@ -72,15 +69,21 @@ public:
 
     SkPicture* picture() const { return m_recordingPicture; }
 
-    void dumpLayers(FILE*, int indentLevel);
-
-private:
+    void dumpLayers(FILE*, int indentLevel) const;
 
+    void bounds(SkRect* ) const;
     bool calcPosition(const SkRect* viewPort, SkMatrix*);
-
-    void paintChildren(const SkRect* viewPort, SkCanvas* canvas,
-                       float opacity);
-
+    void clipArea(SkTDArray<SkRect>* region) const;
+    const LayerAndroid* find(FloatPoint position) const;
+    const LayerAndroid* findById(int uniqueID) const;
+    LayerAndroid* getChild(int index) const { return
+        static_cast<LayerAndroid*>(m_children[index]); }
+    bool haveClip() const { return m_haveClip; }
+    int uniqueId() const { return m_uniqueId; }
+private:
+    bool boundsIsUnique(SkTDArray<SkRect>* region, const SkRect& local) const;
+    void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const;
+    void paintChildren(const SkRect* viewPort, SkCanvas* canvas, float opacity);
     void paintMe(const SkRect* viewPort, SkCanvas* canvas,
                  float opacity);
 
@@ -94,6 +97,8 @@ private:
 
     typedef HashMap<String, RefPtr<AndroidAnimation> > KeyframesMap;
     KeyframesMap m_animations;
+    FindOnPage* m_findOnPage;
+    int m_uniqueId;
 };
 
 }
index 345bba3..2c12ed3 100644 (file)
@@ -59,6 +59,7 @@ LOCAL_SRC_FILES := \
        android/nav/CachedFrame.cpp \
        android/nav/CachedHistory.cpp \
        android/nav/CachedInput.cpp \
+       android/nav/CachedLayer.cpp \
        android/nav/CachedNode.cpp \
        android/nav/CachedRoot.cpp \
        android/nav/FindCanvas.cpp \
index d04ac30..4385f4d 100644 (file)
@@ -900,7 +900,6 @@ void WebViewCore::setRootLayer(int layer)
     env->CallVoidMethod(m_javaGlue->object(env).get(),
                         m_javaGlue->m_setRootLayer,
                         layer);
-    mRootLayer = layer;
     checkException(env);
 }
 
index a32ba0c..3085a49 100644 (file)
@@ -129,7 +129,6 @@ namespace android {
 #if USE(ACCELERATED_COMPOSITING)
         void immediateRepaint();
         void setRootLayer(int layer);
-        int rootLayer() { return mRootLayer; }
 #endif
 
         /** Invalidate the view/screen, NOT the content/DOM, but expressed in
@@ -545,10 +544,6 @@ namespace android {
         uint32_t m_now;
 #endif
 
-#if USE(ACCELERATED_COMPOSITING)
-        int mRootLayer;
-#endif
-
     private:
         // called from constructor, to add this to a global list
         static void addInstance(WebViewCore*);
index c665887..62c2771 100644 (file)
@@ -35,6 +35,7 @@
 #include "FrameTree.h"
 #include "FrameView.h"
 //#include "GraphicsContext.h"
+#include "GraphicsLayerAndroid.h"
 #include "HTMLAreaElement.h"
 #include "HTMLImageElement.h"
 #include "HTMLInputElement.h"
@@ -49,6 +50,7 @@
 #include "RegisteredEventListener.h"
 #include "RenderImage.h"
 #include "RenderInline.h"
+#include "RenderLayerBacking.h"
 #include "RenderListBox.h"
 #include "RenderSkinCombo.h"
 #include "RenderTextControl.h"
@@ -433,11 +435,17 @@ void CacheBuilder::Debug::groups() {
                 print("\"\"");
             RenderObject* renderer = node->renderer();
             int tabindex = node->isElementNode() ? node->tabIndex() : 0;
+            RenderLayer* layer = 0;
             if (renderer) {
                 const IntRect& absB = renderer->absoluteBoundingBoxRect();
+                bool hasLayer = renderer->hasLayer();
+                layer = hasLayer ? toRenderBoxModelObject(renderer)->layer() : 0;
                 snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s"
-                    ", %d},",absB.x(), absB.y(), absB.width(), absB.height(),
-                    renderer->hasOverflowClip() ? "true" : "false", tabindex);
+                    ", %d, %s, %s},",
+                    absB.x(), absB.y(), absB.width(), absB.height(),
+                    renderer->hasOverflowClip() ? "true" : "false", tabindex,
+                    hasLayer ? "true" : "false",
+                    hasLayer && layer->isComposited() ? "true" : "false");
                 // TODO: add renderer->style()->visibility()
                 print(scratch);
             } else
@@ -463,6 +471,20 @@ void CacheBuilder::Debug::groups() {
             }
             count++;
             newLine();
+#if USE(ACCELERATED_COMPOSITING)
+            if (renderer && layer) {
+                RenderLayerBacking* back = layer->backing();
+                GraphicsLayerAndroid* grLayer = static_cast
+                    <GraphicsLayerAndroid*>(back ? back->graphicsLayer() : 0);
+                LayerAndroid* aLayer = grLayer ? grLayer->contentLayer() : 0;
+                const SkPicture* pict = aLayer ? aLayer->picture() : 0;
+                snprintf(scratch, sizeof(scratch), "// layer:%p back:%p"
+                    " gLayer:%p aLayer:%p pict:%p", layer, back, grLayer,
+                    aLayer, pict);
+                print(scratch);
+                newLine();
+           }
+#endif
         } while ((node = node->traverseNextNode()) != NULL);
         DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
         DUMP_NAV_LOGD("\n");
@@ -875,22 +897,18 @@ static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) {
 void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
     CachedRoot* cachedRoot, CachedFrame* cachedFrame)
 {
-    WTF::Vector<Tracker> tracker(1);
+    WTF::Vector<FocusTracker> tracker(1); // sentinel
     {
-        Tracker* baseTracker = tracker.data(); // sentinel
-        bzero(baseTracker, sizeof(Tracker));
+        FocusTracker* baseTracker = tracker.data();
+        bzero(baseTracker, sizeof(FocusTracker));
         baseTracker->mCachedNodeIndex = -1;
     }
-    WTF::Vector<ClipColumnTracker> clipTracker(1);
-    {
-        ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel
-        bzero(baseTracker, sizeof(ClipColumnTracker));
-    }
-    WTF::Vector<TabIndexTracker> tabIndexTracker(1);
-    {
-        TabIndexTracker* baseTracker = tabIndexTracker.data(); // sentinel
-        bzero(baseTracker, sizeof(TabIndexTracker));
-    }
+    WTF::Vector<LayerTracker> layerTracker(1); // sentinel
+    bzero(layerTracker.data(), sizeof(LayerTracker));
+    WTF::Vector<ClipColumnTracker> clipTracker(1); // sentinel
+    bzero(clipTracker.data(), sizeof(ClipColumnTracker));
+    WTF::Vector<TabIndexTracker> tabIndexTracker(1); // sentinel
+    bzero(tabIndexTracker.data(), sizeof(TabIndexTracker));
 #if DUMP_NAV_CACHE
     char* frameNamePtr = cachedFrame->mDebug.mFrameName;
     Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr + 
@@ -919,7 +937,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
 #if DUMP_NAV_CACHE
         nodeIndex++;
 #endif
-        Tracker* last = &tracker.last();
+        FocusTracker* last = &tracker.last();
         int lastChildIndex = cachedFrame->size() - 1;
         while (node == last->mLastChild) {
             if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
@@ -935,6 +953,12 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
             clipTracker.removeLast();
         } while (true);
         do {
+            const LayerTracker* lastLayer = &layerTracker.last();
+            if (node != lastLayer->mLastChild)
+                break;
+            layerTracker.removeLast();
+        } while (true);
+        do {
             const TabIndexTracker* lastTabIndex = &tabIndexTracker.last();
             if (node != lastTabIndex->mLastChild)
                 break;
@@ -988,6 +1012,10 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
 #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
             hasCursorRing = style->tapHighlightColor().alpha() > 0;
 #endif
+#if USE(ACCELERATED_COMPOSITING)
+            if (nodeRenderer->hasLayer())
+                TrackLayer(layerTracker, nodeRenderer, lastChild);
+#endif
         }
         bool more = walk.mMore;
         walk.reset();
@@ -1084,7 +1112,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
                 IntRect(0, 0, INT_MAX, INT_MAX);
             if (ConstructTextRects((WebCore::Text*) node, walk.mStart, 
                     (WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX,
-                    globalOffsetY, &bounds, clip, &cachedNode.cursorRings()) == false)
+                    globalOffsetY, &bounds, clip, cachedNode.cursorRingsPtr()) == false)
                 continue;
             absBounds = bounds;
             cachedNode.setBounds(bounds);
@@ -1176,9 +1204,9 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
         cachedNode.init(node);
         if (computeCursorRings == false) {
             cachedNode.setBounds(bounds);
-            cachedNode.cursorRings().append(bounds);
+            cachedNode.cursorRingsPtr()->append(bounds);
         } else if (ConstructPartRects(node, bounds, cachedNode.boundsPtr(), 
-                globalOffsetX, globalOffsetY, &cachedNode.cursorRings()) == false)
+                globalOffsetX, globalOffsetY, cachedNode.cursorRingsPtr()) == false)
             continue;
     keepTextNode:
         IntRect clip = hasClip ? bounds : absBounds;
@@ -1204,6 +1232,21 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
             else if (cachedNode.clip(clip) == false)
                 continue; // skip this node if outside of the clip
         }
+        bool isInLayer = false;
+#if USE(ACCELERATED_COMPOSITING)
+        // FIXME: does not work for area rects
+        LayerAndroid* layer = layerTracker.last().mLayer;
+        if (layer) {
+            isInLayer = true;
+            isUnclipped = true; // FIXME: add clipping analysis before blindly setting this
+            CachedLayer cachedLayer;
+            cachedLayer.reset();
+            cachedLayer.setCachedNodeIndex(cachedFrame->size());
+            cachedLayer.setOffset(layerTracker.last().mPosition);
+            cachedLayer.setUniqueId(layer->uniqueId());
+            cachedFrame->add(cachedLayer);
+        }
+#endif
         cachedNode.setNavableRects();
         cachedNode.setExport(exported);
         cachedNode.setHasCursorRing(hasCursorRing);
@@ -1211,6 +1254,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
         cachedNode.setHitBounds(absBounds);
         cachedNode.setIndex(cacheIndex);
         cachedNode.setIsFocus(isFocus);
+        cachedNode.setIsInLayer(isInLayer);
         cachedNode.setIsTransparent(isTransparent);
         cachedNode.setIsUnclipped(isUnclipped);
         cachedNode.setOriginalAbsoluteBounds(originalAbsBounds);
@@ -1238,7 +1282,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
             }
             if (lastChild != NULL) {
                 tracker.grow(tracker.size() + 1);
-                Tracker& working = tracker.last();
+                FocusTracker& working = tracker.last();
                 working.mCachedNodeIndex = lastIndex;
                 working.mLastChild = OneAfter(lastChild);
                 last = &tracker.at(tracker.size() - 2);
@@ -1248,7 +1292,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
         cacheIndex++;
     }
     while (tracker.size() > 1) {
-        Tracker* last = &tracker.last();
+        FocusTracker* last = &tracker.last();
         int lastChildIndex = cachedFrame->size() - 1;
         if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
             cacheIndex--;
@@ -1257,7 +1301,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
 }
 
 bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame, 
-    const Tracker* last, int lastChildIndex)
+    const FocusTracker* last, int lastChildIndex)
 {
     // if outer is body, disable outer
     // or if there's more than one inner, disable outer
@@ -1272,7 +1316,7 @@ bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame,
             lastNode->hasTagName(HTMLNames::bodyTag) ||
             lastNode->hasTagName(HTMLNames::formTag)) {
         lastCached->setBounds(IntRect(0, 0, 0, 0));
-        lastCached->cursorRings().clear();
+        lastCached->cursorRingsPtr()->clear();
         lastCached->setNavableRects();
         return false;
     }
@@ -2682,6 +2726,31 @@ bool CacheBuilder::setData(CachedFrame* cachedFrame)
     return true;
 }
 
+#if USE(ACCELERATED_COMPOSITING)
+void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
+    RenderObject* nodeRenderer, Node* lastChild)
+{
+    RenderLayer* layer = toRenderBoxModelObject(nodeRenderer)->layer();
+    RenderLayerBacking* back = layer->backing();
+    if (!back)
+        return;
+    GraphicsLayerAndroid* grLayer = static_cast
+        <GraphicsLayerAndroid*>(back->graphicsLayer());
+    if (!grLayer)
+        return;
+    LayerAndroid* aLayer = grLayer->contentLayer();
+    if (!aLayer)
+        return;
+    layerTracker.grow(layerTracker.size() + 1);
+    LayerTracker& indexTracker = layerTracker.last();
+    indexTracker.mLayer = aLayer;
+    indexTracker.mPosition = nodeRenderer->absoluteBoundingBoxRect().location();
+    indexTracker.mLastChild = OneAfter(lastChild);
+    DBG_NAV_LOGD("layer=%p [%d] pos=(%d,%d)", aLayer, aLayer->uniqueId(),
+        indexTracker.mPosition.x(), indexTracker.mPosition.y());
+}
+#endif
+
 bool CacheBuilder::validNode(Frame* startFrame, void* matchFrame,
         void* matchNode)
 {
index ff395d3..9ce91a2 100644 (file)
@@ -44,6 +44,7 @@ class Document;
 class Frame;
 class HTMLAreaElement;
 class InlineTextBox;
+class LayerAndroid;
 class Node;
 class PlatformGraphicsContext;
 class RenderFlow;
@@ -183,23 +184,26 @@ private:
             mStarts[mWordCount] = mCurrentStart;
         }
     };
-    struct ClipColumnTracker {
-        IntRect mBounds;
+    struct Tracker {
         Node* mLastChild;
+    };
+    struct ClipColumnTracker : Tracker {
         Node* mNode;
+        IntRect mBounds;
         WTF::Vector<IntRect>* mColumns;
         int mColumnGap;
         TextDirection mDirection;
         bool mHasClip;
     };
-    struct TabIndexTracker {
+    struct LayerTracker : Tracker {
+        LayerAndroid* mLayer;
+        IntPoint mPosition;
+    };
+    struct TabIndexTracker : Tracker {
         int mTabIndex;
-        Node* mLastChild;
     };
-    struct Tracker {
+    struct FocusTracker : TabIndexTracker {
         int mCachedNodeIndex;
-        int mTabIndex;
-        Node* mLastChild;
         bool mSomeParentTakesFocus;
     };
     void adjustForColumns(const ClipColumnTracker& track, 
@@ -212,7 +216,7 @@ private:
     void BuildFrame(Frame* root, Frame* frame,
         CachedRoot* cachedRoot, CachedFrame* cachedFrame);
     bool CleanUpContainedNodes(CachedFrame* cachedFrame, 
-        const Tracker* last, int lastChildIndex);
+        const FocusTracker* last, int lastChildIndex);
     static bool ConstructTextRect(Text* textNode,
         InlineTextBox* textBox, int start, int relEnd, int x, int y, 
         IntRect* focusBounds, const IntRect& clip, WTF::Vector<IntRect>* result);
@@ -238,6 +242,10 @@ private:
     static bool IsRealNode(Frame* , Node* );
     int overlap(int left, int right); // returns distance scale factor as 16.16 scalar
     bool setData(CachedFrame* );
+#if USE(ACCELERATED_COMPOSITING)
+    void TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
+        RenderObject* nodeRenderer, Node* lastChild);
+#endif
     Node* tryFocus(Direction direction);
     Node* trySegment(Direction direction, int mainStart, int mainEnd);
     CachedNodeBits mAllowableTypes;
index 3dbe5ef..3d9e012 100644 (file)
@@ -57,11 +57,16 @@ extern FILE* gNavCacheLogFile;
 #define NAV_CACHE_LOG_FILE "/data/data/com.android.browser/navlog"
 #define DUMP_NAV_LOGD(...) do { if (gNavCacheLogFile) \
     fprintf(gNavCacheLogFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } while (false)
+#define DUMP_NAV_LOGX(format, ...) do { if (gNavCacheLogFile) \
+    fprintf(gNavCacheLogFile, format, __VA_ARGS__); \
+    else LOGD("%s " format, __FUNCTION__, __VA_ARGS__); } while (false)
 #else
 #define DUMP_NAV_LOGD(...) LOGD(__VA_ARGS__)
+#define DUMP_NAV_LOGX(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
 #endif
 #else
 #define DUMP_NAV_LOGD(...) ((void)0)
+#define DUMP_NAV_LOGX(...) ((void)0)
 #endif
 
 #endif
index 299dc53..de407c8 100644 (file)
 
 namespace android {
 
+WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node,
+    const WebCore::IntRect& rect) const
+{
+    DBG_NAV_LOGD("node=%p [%d] rect=(%d,%d,w=%d,h=%d)",
+        node, node->index(), rect.x(), rect.y(), rect.width(), rect.height());
+#if USE(ACCELERATED_COMPOSITING)
+    return layer(node)->adjustBounds(mRoot->rootLayer(), rect);
+#else
+    return rect;
+#endif
+}
+
 bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect,
         const WebCore::IntRect& prior, WebCore::IntRect* result)
 {
@@ -105,6 +117,13 @@ bool CachedFrame::checkBetween(BestData* best, Direction direction)
     return true;
 }
 
+bool CachedFrame::checkRings(const CachedNode* node,
+        const WTF::Vector<WebCore::IntRect>& rings,
+        const WebCore::IntRect& bounds) const
+{
+    return mRoot->checkRings(picture(node), rings, bounds);
+}
+
 bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const
 {
     return history()->checkVisited(node, direction);
@@ -121,12 +140,11 @@ void CachedFrame::clearCursor()
 }
 
 // returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown
-int CachedFrame::compare(BestData& testData, const BestData& bestData,
-    const CachedNode* cursor) const
+int CachedFrame::compare(BestData& testData, const BestData& bestData) const
 {
     if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) {
         if (testData.mNode->tabIndex() < bestData.mNode->tabIndex()
-                || (cursor && cursor->tabIndex() < bestData.mNode->tabIndex())) {
+                || (mRoot->cursor() && mRoot->cursor()->tabIndex() < bestData.mNode->tabIndex())) {
             testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX);
             return REJECT_TEST;
         }
@@ -297,7 +315,7 @@ const CachedNode* CachedFrame::currentCursor(const CachedFrame** framePtr) const
     const CachedFrame* frame = hasFrame(result);
     if (frame != NULL)
         return frame->currentCursor(framePtr);
-    (const_cast<CachedNode*>(result))->fixUpCursorRects(mRoot);
+    (const_cast<CachedNode*>(result))->fixUpCursorRects(this);
     return result;
 }
 
@@ -351,15 +369,25 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect,
         size_t parts = test->navableRects();
         BestData testData;
         testData.mNode = test;
-        testData.mMouseBounds = testData.mNodeBounds = test->getBounds();
+        testData.mFrame = this;
+        WebCore::IntRect bounds = test->bounds(this);
+        testData.setMouseBounds(bounds);
+        testData.setNodeBounds(bounds);
         bool checkForHidden = checkForHiddenStart;
         for (size_t part = 0; part < parts; part++) {
-            if (test->cursorRings().at(part).intersects(rect)) {
+            WebCore::IntRect testRect = test->ring(this, part);
+            if (test->isInLayer()) {
+                DBG_NAV_LOGD("[%d] intersects=%ss testRect=(%d,%d,w=%d,h=%d)"
+                    " rect=(%d,%d,w=%d,h=%d)", test->index(),
+                    testRect.intersects(rect) ? "true" : "false",
+                    testRect.x(), testRect.y(), testRect.width(), testRect.height(),
+                    rect.x(), rect.y(), rect.width(), rect.height());
+            }
+            if (testRect.intersects(rect)) {
                 if (checkForHidden && mRoot->maskIfHidden(&testData) == true)
                     break;
                 checkForHidden = false;
-                WebCore::IntRect testRect = test->cursorRings().at(part);
-                testRect.intersect(testData.mMouseBounds);
+                testRect.intersect(testData.mouseBounds());
                 if (testRect.contains(center)) {
                     // We have a direct hit.
                     if (*directHit == NULL) {
@@ -370,7 +398,7 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect,
                     } else {
                         // We have hit another one before
                         const CachedNode* d = *directHit;
-                        if (d->getBounds().contains(testRect)) {
+                        if (d->bounds(this).contains(testRect)) {
                             // This rectangle is inside the other one, so it is
                             // the best one.
                             *directHit = test;
@@ -455,16 +483,18 @@ const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect,
             test != mCachedNodes.begin() - 1; test--) {
         if (test->disabled())
             continue;
-        const WebCore::IntRect& testRect = test->hitBounds();
+        WebCore::IntRect testRect = test->hitBounds(this);
         if (testRect.intersects(rect) == false)
             continue;
         BestData testData;
         testData.mNode = test;
-        testData.mMouseBounds = testData.mNodeBounds = testRect;
+        testData.mFrame = this;
+        testData.setMouseBounds(testRect);
+        testData.setNodeBounds(testRect);
         if (mRoot->maskIfHidden(&testData) == true)
             continue;
-        for (unsigned i = 0; i < test->cursorRings().size(); i++) {
-            const WebCore::IntRect& cursorRect = test->cursorRings().at(i);
+        for (int i = 0; i < test->navableRects(); i++) {
+            WebCore::IntRect cursorRect = test->ring(this, i);
             if (cursorRect.intersects(rect)) {
                 WebCore::IntRect intersection(cursorRect);
                 intersection.intersect(rect);
@@ -492,13 +522,13 @@ void CachedFrame::findClosest(BestData* bestData, Direction originalDirection,
         }
         if (test->noSecondChance())
             continue;
-        if (test->isNavable(*clip) == false)
+        if (test->isNavable(this, *clip) == false)
             continue;
         if (checkVisited(test, originalDirection) == false)
             continue;
         size_t partMax = test->navableRects();
         for (size_t part = 0; part < partMax; part++) {
-            WebCore::IntRect testBounds = test->cursorRings().at(part);
+            WebCore::IntRect testBounds = test->ring(this, part);
             if (clip->intersects(testBounds) == false)
                 continue;
             if (clip->contains(testBounds) == false) {
@@ -538,8 +568,9 @@ void CachedFrame::findClosest(BestData* bestData, Direction originalDirection,
                 bestData->mNode = test;
                 bestData->mFrame = this;
                 bestData->mDistance = distance;
-                bestData->mMouseBounds = bestData->mNodeBounds =
-                    test->cursorRings().at(part);
+                WebCore::IntRect rect = test->ring(this, part);
+                bestData->setMouseBounds(rect);
+                bestData->setNodeBounds(rect);
                 CachedHistory* cachedHistory = history();
                 switch (direction) {
                     case LEFT:
@@ -577,29 +608,29 @@ void CachedFrame::finishInit()
         frameParent->setFocusIndex(indexInParent());
 }
 
-const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNode* limit, BestData* bestData,
-    const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameDown(const CachedNode* test,
+    const CachedNode* limit, BestData* bestData) const
 {
     BestData originalData = *bestData;
     do {
-        if (moveInFrame(&CachedFrame::frameDown, test, bestData, cursor))
+        if (moveInFrame(&CachedFrame::frameDown, test, bestData))
             continue;
         BestData testData;
-        if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+        if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
             continue;
         if (checkVisited(test, DOWN) == false)
             continue;
         size_t parts = test->navableRects();
         for (size_t part = 0; part < parts; part++) {
-            testData.mNodeBounds = test->cursorRings().at(part);
+            testData.setNodeBounds(test->ring(this, part));
             if (testData.setDownDirection(history()))
                 continue;
-            int result = framePartCommon(testData, test, bestData, cursor);
+            int result = framePartCommon(testData, test, bestData);
             if (result == REJECT_TEST)
                 continue;
             if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
                 BestData innerData = testData;
-                frameDown(document(), test, &innerData, cursor);
+                frameDown(document(), test, &innerData);
                 if (checkVisited(innerData.mNode, DOWN)) {
                     *bestData = innerData;
                     continue;
@@ -609,7 +640,7 @@ const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNod
                 *bestData = testData;
         }
     } while ((test = test->traverseNextNode()) != limit);
-    ASSERT(cursor == NULL || bestData->mNode != cursor);
+    ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
     // does the best contain something (or, is it contained by an area which is not the cursor?)
         // if so, is the conainer/containee should have been chosen, but wasn't -- so there's a better choice
         // in the doc list prior to this choice
@@ -617,29 +648,29 @@ const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNod
     return bestData->mNode;
 }
 
-const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNode* limit, BestData* bestData,
-    const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameLeft(const CachedNode* test,
+    const CachedNode* limit, BestData* bestData) const
 {
     BestData originalData = *bestData;
     do {
-        if (moveInFrame(&CachedFrame::frameLeft, test, bestData, cursor))
+        if (moveInFrame(&CachedFrame::frameLeft, test, bestData))
             continue;
         BestData testData;
-        if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+        if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
             continue;
         if (checkVisited(test, LEFT) == false)
             continue;
         size_t parts = test->navableRects();
         for (size_t part = 0; part < parts; part++) {
-            testData.mNodeBounds = test->cursorRings().at(part);
+            testData.setNodeBounds(test->ring(this, part));
             if (testData.setLeftDirection(history()))
                 continue;
-            int result = framePartCommon(testData, test, bestData, cursor);
+            int result = framePartCommon(testData, test, bestData);
             if (result == REJECT_TEST)
                 continue;
             if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
                 BestData innerData = testData;
-                frameLeft(document(), test, &innerData, cursor);
+                frameLeft(document(), test, &innerData);
                 if (checkVisited(innerData.mNode, LEFT)) {
                     *bestData = innerData;
                     continue;
@@ -649,12 +680,12 @@ const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNod
                 *bestData = testData;
         }
     } while ((test = test->traverseNextNode()) != limit);  // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
-    ASSERT(cursor == NULL || bestData->mNode != cursor);
+    ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
     return bestData->mNode;
 }
 
-int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, BestData* bestData, BestData* originalData,
-    const CachedNode* cursor) const
+int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test,
+    BestData* bestData, BestData* originalData) const
 {
     testData.mFrame = this;
     testData.mNode = test;
@@ -663,16 +694,21 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes
         testData.mNode->setCondition(CachedNode::DISABLED);
         return REJECT_TEST;
     }
-    if (mRoot->scrolledBounds().intersects(test->bounds()) == false) {
+    if (mRoot->scrolledBounds().intersects(test->bounds(this)) == false) {
         testData.mNode->setCondition(CachedNode::NAVABLE);
         return REJECT_TEST;
     }
+    if (mRoot->rootLayer() && !test->isInLayer()
+            && !mRoot->baseUncovered().intersects(test->bounds(this))) {
+        testData.mNode->setCondition(CachedNode::UNDER_LAYER);
+        return REJECT_TEST;
+    }
 //    if (isNavable(test, &testData.mNodeBounds, walk) == false) {
 //        testData.mNode->setCondition(CachedNode::NAVABLE);
 //        return REJECT_TEST;
 //    }
 //
-    if (test == cursor) {
+    if (test == mRoot->cursor()) {
         testData.mNode->setCondition(CachedNode::NOT_CURSOR_NODE);
         return REJECT_TEST;
     }
@@ -680,36 +716,12 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes
 //        testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
 //        return REJECT_TEST;
 //    }
-    void* par = cursor ? cursor->parentGroup() : NULL;
+    void* par = mRoot->cursor() ? mRoot->cursor()->parentGroup() : NULL;
     testData.mCursorChild = par ? test->parentGroup() == par : false;
-#if 0 // not debugged
-    if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false &&
-            cursor->bounds().contains(test->bounds()))
-        return REJECT_TEST;
-#endif
     if (bestData->mNode == NULL)
         return TEST_IS_BEST;
-#if 0 // not debugged
-    if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false &&
-            cursor->bounds().contains(test->bounds()))
-        return REJECT_TEST;
-    if (test->hasMouseOver() != bestData->mNode->hasMouseOver()) {
-        if (test->hasMouseOver()) {
-            if (test->bounds().contains(bestData->mNode->bounds())) {
-                const_cast<CachedNode*>(bestData->mNode)->setDisabled(true);
-                bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparison
-                return TEST_IS_BEST;
-            }
-        } else {
-            if (bestData->mNode->bounds().contains(test->bounds())) {
-                test->setCondition(CachedNode::ANCHOR_IN_ANCHOR);
-                return REJECT_TEST;
-            }
-        }
-    }
-#endif
-    if (cursor && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) {
-        int cursorParentIndex = cursor->parentIndex();
+    if (mRoot->cursor() && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) {
+        int cursorParentIndex = mRoot->cursor()->parentIndex();
         if (cursorParentIndex >= 0) {
             if (bestData->mNode->parentIndex() == cursorParentIndex)
                 return REJECT_TEST;
@@ -745,15 +757,17 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes
 }
 
 int CachedFrame::framePartCommon(BestData& testData,
-    const CachedNode* test, BestData* bestData, const CachedNode* cursor) const
+    const CachedNode* test, BestData* bestData) const
 {
-    if (cursor && testData.mNodeBounds.contains(cursor->bounds()) && !test->wantsKeyEvents()) {
+    if (mRoot->cursor()
+            && testData.bounds().contains(mRoot->cursorBounds())
+            && !test->wantsKeyEvents()) {
         testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
         return REJECT_TEST;
     }
     testData.setDistances();
     if (bestData->mNode != NULL) {
-        int compared = compare(testData, *bestData, cursor);
+        int compared = compare(testData, *bestData);
         if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false)
             goto pickTest;
         if (compared >= 0)
@@ -763,29 +777,29 @@ pickTest:
     return -1; // pick test
 }
 
-const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNode* limit, BestData* bestData,
-    const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameRight(const CachedNode* test,
+    const CachedNode* limit, BestData* bestData) const
 {
     BestData originalData = *bestData;
     do {
-        if (moveInFrame(&CachedFrame::frameRight, test, bestData, cursor))
+        if (moveInFrame(&CachedFrame::frameRight, test, bestData))
             continue;
         BestData testData;
-        if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+        if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
             continue;
         if (checkVisited(test, RIGHT) == false)
             continue;
         size_t parts = test->navableRects();
         for (size_t part = 0; part < parts; part++) {
-            testData.mNodeBounds = test->cursorRings().at(part);
+            testData.setNodeBounds(test->ring(this, part));
             if (testData.setRightDirection(history()))
                 continue;
-            int result = framePartCommon(testData, test, bestData, cursor);
+            int result = framePartCommon(testData, test, bestData);
             if (result == REJECT_TEST)
                 continue;
             if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
                 BestData innerData = testData;
-                frameRight(document(), test, &innerData, cursor);
+                frameRight(document(), test, &innerData);
                 if (checkVisited(innerData.mNode, RIGHT)) {
                     *bestData = innerData;
                     continue;
@@ -795,33 +809,33 @@ const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNo
                 *bestData = testData;
         }
     } while ((test = test->traverseNextNode()) != limit);
-    ASSERT(cursor == NULL || bestData->mNode != cursor);
+    ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
     return bestData->mNode;
 }
 
-const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* limit, BestData* bestData,
-    const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameUp(const CachedNode* test,
+    const CachedNode* limit, BestData* bestData) const
 {
     BestData originalData = *bestData;
     do {
-        if (moveInFrame(&CachedFrame::frameUp, test, bestData, cursor))
+        if (moveInFrame(&CachedFrame::frameUp, test, bestData))
             continue;
         BestData testData;
-        if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+        if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
             continue;
         if (checkVisited(test, UP) == false)
             continue;
         size_t parts = test->navableRects();
         for (size_t part = 0; part < parts; part++) {
-            testData.mNodeBounds = test->cursorRings().at(part);
+            testData.setNodeBounds(test->ring(this, part));
             if (testData.setUpDirection(history()))
                 continue;
-            int result = framePartCommon(testData, test, bestData, cursor);
+            int result = framePartCommon(testData, test, bestData);
             if (result == REJECT_TEST)
                 continue;
             if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
                 BestData innerData = testData;
-                frameUp(document(), test, &innerData, cursor);
+                frameUp(document(), test, &innerData);
                 if (checkVisited(innerData.mNode, UP)) {
                     *bestData = innerData;
                     continue;
@@ -831,7 +845,7 @@ const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode*
                 *bestData = testData;
         }
     } while ((test = test->traverseNextNode()) != limit);  // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
-    ASSERT(cursor == NULL || bestData->mNode != cursor);
+    ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
     return bestData->mNode;
 }
 
@@ -868,6 +882,17 @@ void CachedFrame::init(const CachedRoot* root, int childFrameIndex,
     mIndexInParent = childFrameIndex;
 }
 
+#if USE(ACCELERATED_COMPOSITING)
+const CachedLayer* CachedFrame::layer(const CachedNode* node) const
+{
+    if (!node->isInLayer())
+        return 0;
+    CachedLayer test;
+    test.setCachedNodeIndex(node->index());
+    return std::lower_bound(mCachedLayers.begin(), mCachedLayers.end(), test);
+}
+#endif
+
 int CachedFrame::minWorkingHorizontal() const
 {
     return history()->minWorkingHorizontal();
@@ -917,8 +942,7 @@ const CachedNode* CachedFrame::nextTextField(const CachedNode* start,
 }
 
 bool CachedFrame::moveInFrame(MoveInDirection moveInDirection,
-    const CachedNode* test, BestData* bestData,
-    const CachedNode* cursor) const
+    const CachedNode* test, BestData* bestData) const
 {
     const CachedFrame* frame = hasFrame(test);
     if (frame == NULL)
@@ -926,7 +950,7 @@ bool CachedFrame::moveInFrame(MoveInDirection moveInDirection,
     const CachedNode* childDoc = frame->validDocument();
     if (childDoc == NULL)
         return true;
-    (frame->*moveInDirection)(childDoc, NULL, bestData, cursor);
+    (frame->*moveInDirection)(childDoc, NULL, bestData);
     return true;
 }
 
@@ -935,6 +959,15 @@ const WebCore::IntRect& CachedFrame::_navBounds() const
     return history()->navBounds();
 }
 
+SkPicture* CachedFrame::picture(const CachedNode* node) const
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (node->isInLayer())
+        return layer(node)->picture(mRoot->rootLayer());
+#endif
+    return mRoot->getPicture();
+}
+
 void CachedFrame::resetClippedOut()
 {
     for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
@@ -950,6 +983,20 @@ void CachedFrame::resetClippedOut()
     }
 }
 
+void CachedFrame::resetLayers()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    for (CachedLayer* test = mCachedLayers.begin(); test != mCachedLayers.end();
+            test++) {
+        test->reset();
+    }
+    for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
+            frame++) {
+        frame->resetLayers();
+    }
+#endif
+}
+
 bool CachedFrame::sameFrame(const CachedFrame* test) const
 {
     ASSERT(test);
@@ -1005,9 +1052,8 @@ bool CachedFrame::setCursor(WebCore::Frame* frame, WebCore::Node* node,
             if (test->nodePointer() != node && first)
                 continue;
             size_t partMax = test->navableRects();
-            WTF::Vector<WebCore::IntRect>& cursorRings = test->cursorRings();
             for (size_t part = 0; part < partMax; part++) {
-                const WebCore::IntRect& testBounds = cursorRings.at(part);
+                WebCore::IntRect testBounds = test->ring(this, part);
                 if (testBounds.contains(x, y) == false)
                     continue;
                 if (test->isCursor()) {
@@ -1324,6 +1370,7 @@ void CachedFrame::Debug::print() const
     DEBUG_PRINT_RECT("//", CONTENTS, mContents);
     DEBUG_PRINT_RECT("", BOUNDS, mLocalViewBounds);
     DEBUG_PRINT_RECT("//", VIEW, mViewBounds);
+
     DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size());
     for (CachedNode* node = b->mCachedNodes.begin();
             node != b->mCachedNodes.end(); node++) {
@@ -1333,6 +1380,14 @@ void CachedFrame::Debug::print() const
             input->mDebug.print();
     }
     DUMP_NAV_LOGD("// }; // end of nodes\n");
+#if USE(ACCELERATED_COMPOSITING)
+    DUMP_NAV_LOGD("// CachedLayer mCachedLayers={ // count=%d\n", b->mCachedLayers.size());
+    for (CachedLayer* layer = b->mCachedLayers.begin();
+            layer != b->mCachedLayers.end(); layer++) {
+        layer->mDebug.print();
+    }
+    DUMP_NAV_LOGD("// }; // end of layers\n");
+#endif // USE(ACCELERATED_COMPOSITING)
     DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size());
     for (CachedFrame* child = b->mCachedFrames.begin();
             child != b->mCachedFrames.end(); child++)
index 7a00539..613b2eb 100644 (file)
 #define CachedFrame_H
 
 #include "CachedInput.h"
+#include "CachedLayer.h"
 #include "CachedNode.h"
 #include "IntRect.h"
 #include "SkFixed.h"
 #include "wtf/Vector.h"
 
+class SkPicture;
+
 namespace WebCore {
     class Frame;
     class Node;
@@ -68,8 +71,16 @@ public:
     };
     CachedFrame() {}
     void add(CachedInput& input) { mCachedTextInputs.append(input); }
+#if USE(ACCELERATED_COMPOSITING)
+    void add(CachedLayer& layer) { mCachedLayers.append(layer); }
+#endif
     void add(CachedNode& node) { mCachedNodes.append(node); }
     void addFrame(CachedFrame& child) { mCachedFrames.append(child); }
+    WebCore::IntRect adjustBounds(const CachedNode* ,
+        const WebCore::IntRect& ) const;
+    bool checkRings(const CachedNode* node,
+        const WTF::Vector<WebCore::IntRect>& rings,
+        const WebCore::IntRect& bounds) const;
     bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
     size_t childCount() { return mCachedFrames.size(); }
     void clearCursor();
@@ -99,6 +110,9 @@ public:
     const CachedFrame* lastChild() const { return &mCachedFrames.last(); }
     CachedNode* lastNode() { return &mCachedNodes.last(); }
     CachedFrame* lastChild() { return &mCachedFrames.last(); }
+#if USE(ACCELERATED_COMPOSITING)
+    const CachedLayer* layer(const CachedNode* ) const;
+#endif
     /**
      * Find the next textfield/textarea
      * @param start Must be a CachedNode in this CachedFrame's tree, or
@@ -113,6 +127,8 @@ public:
         const CachedFrame** framePtr, bool includeTextAreas) const;
     const CachedFrame* parent() const { return mParent; }
     CachedFrame* parent() { return mParent; }
+    SkPicture* picture(const CachedNode* ) const;
+    void resetLayers();
     bool sameFrame(const CachedFrame* ) const;
     void removeLast() { mCachedNodes.removeLast(); }
     void resetClippedOut();
@@ -132,8 +148,6 @@ public:
     const CachedNode* validDocument() const;
 protected:
     struct BestData {
-        WebCore::IntRect mNodeBounds;
-        WebCore::IntRect mMouseBounds;
         int mDistance;
         int mSideDistance;
         int mMajorDelta; // difference of center of object
@@ -160,9 +174,12 @@ protected:
         bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; }
         bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; }
         int isContainer(BestData* );
+        const WebCore::IntRect& mouseBounds() const { return mMouseBounds; }
         static SkFixed Overlap(int span, int left, int right);
         void reset() { mNode = NULL; }
         int right() const { return bounds().right(); }
+        void setMouseBounds(const WebCore::IntRect& b) { mMouseBounds = b; }
+        void setNodeBounds(const WebCore::IntRect& b) { mNodeBounds = b; }
         void setDistances();
         bool setDownDirection(const CachedHistory* );
         bool setLeftDirection(const CachedHistory* );
@@ -175,37 +192,37 @@ protected:
         int width() const { return bounds().width(); }
         int x() const { return bounds().x(); }
         int y() const { return bounds().y(); }
+private: // since computing these is complicated, protect them so that the
+         // are only written by appropriate helpers
+        WebCore::IntRect mMouseBounds;
+        WebCore::IntRect mNodeBounds;
     };
     typedef const CachedNode* (CachedFrame::*MoveInDirection)(
-        const CachedNode* test, const CachedNode* limit, BestData* bestData, 
-        const CachedNode* focus) const;
+        const CachedNode* test, const CachedNode* limit, BestData* ) const;
     void adjustToTextColumn(int* delta) const;
     static bool CheckBetween(Direction , const WebCore::IntRect& bestRect, 
         const WebCore::IntRect& prior, WebCore::IntRect* result);
     bool checkBetween(BestData* , Direction );
-    int compare(BestData& testData, const BestData& bestData, const 
-        CachedNode* focus) const;
+    int compare(BestData& testData, const BestData& bestData) const;
     void findClosest(BestData* , Direction original, Direction test,
         WebCore::IntRect* clip) const;
     int frameNodeCommon(BestData& testData, const CachedNode* test, 
-        BestData* bestData, BestData* originalData, 
-        const CachedNode* focus) const;
+        BestData* bestData, BestData* originalData) const;
     int framePartCommon(BestData& testData, const CachedNode* test, 
-        BestData* bestData, const CachedNode* focus) const;
+        BestData* ) const;
     const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit, 
-        BestData* , const CachedNode* focus) const;
+        BestData* ) const;
     const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit, 
-        BestData* , const CachedNode* focus) const;
+        BestData* ) const;
     const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit, 
-        BestData* , const CachedNode* focus) const;
+        BestData* ) const;
     const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit, 
-        BestData* , const CachedNode* focus) const;
+        BestData* ) const;
     int minWorkingHorizontal() const;
     int minWorkingVertical() const;
     int maxWorkingHorizontal() const;
     int maxWorkingVertical() const;
-    bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* best,
-        const CachedNode* focus) const;
+    bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* ) const;
     const WebCore::IntRect& _navBounds() const;
     WebCore::IntRect mContents;
     WebCore::IntRect mLocalViewBounds;
@@ -213,6 +230,9 @@ protected:
     WTF::Vector<CachedNode> mCachedNodes;
     WTF::Vector<CachedFrame> mCachedFrames;
     WTF::Vector<CachedInput> mCachedTextInputs;
+#if USE(ACCELERATED_COMPOSITING)
+    WTF::Vector<CachedLayer> mCachedLayers;
+#endif
     void* mFrame; // WebCore::Frame*, used only to compare pointers
     CachedFrame* mParent;
     int mCursorIndex;
index 47a560c..9066412 100644 (file)
@@ -91,7 +91,8 @@ void CachedHistory::reset()
 }
 
 void CachedHistory::setWorking(CachedFrame::Direction newMove, 
-    const CachedNode* cursor, const WebCore::IntRect& viewBounds)
+    const CachedFrame* cursorFrame, const CachedNode* cursor,
+    const WebCore::IntRect& viewBounds)
 {
     CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized
     CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN); 
@@ -103,8 +104,7 @@ void CachedHistory::setWorking(CachedFrame::Direction newMove,
     }
     const WebCore::IntRect* navBounds = &mNavBounds;
     if (cursor != NULL) {
-        WebCore::IntRect cursorBounds;
-        cursor->getBounds(&cursorBounds);
+        WebCore::IntRect cursorBounds = cursor->bounds(cursorFrame);
         if (cursorBounds.isEmpty() == false)
             mNavBounds = cursorBounds;
     }
index 302da4e..e8c1ad9 100644 (file)
@@ -52,8 +52,8 @@ public:
     void setDidFirstLayout(bool did) { mDidFirstLayout = did; }
     void setMouseBounds(const WebCore::IntRect& loc) { mMouseBounds = loc; }
     void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; }
-    void setWorking(CachedFrame::Direction , const CachedNode* focus,
-        const WebCore::IntRect& viewBounds);
+    void setWorking(CachedFrame::Direction , const CachedFrame* ,
+        const CachedNode* , const WebCore::IntRect& viewBounds);
     void reset();
 private:
     void pinMaxMin(const WebCore::IntRect& viewBounds);
diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp
new file mode 100644 (file)
index 0000000..f28da2b
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "CachedPrefix.h"
+
+#include "CachedLayer.h"
+#include "FloatRect.h"
+#include "LayerAndroid.h"
+
+namespace android {
+
+#if USE(ACCELERATED_COMPOSITING)
+
+IntRect CachedLayer::adjustBounds(const LayerAndroid* root,
+    const IntRect& bounds) const
+{
+    const LayerAndroid* aLayer = layer(root);
+    if (!aLayer) {
+        DBG_NAV_LOGD("no layer in root=%p uniqueId=%d", root, mUniqueId);
+#if DUMP_NAV_CACHE
+        if (root)
+            mDebug.printRootLayerAndroid(root);
+#endif
+        return bounds;
+    }
+    FloatRect temp = bounds;
+    const FloatPoint& position = aLayer->position();
+    temp.move(position.x(), position.y());
+    const FloatPoint& translation = aLayer->translation();
+    temp.move(translation.x(), translation.y());
+    IntRect result = enclosingIntRect(temp);
+    DBG_NAV_LOGD("root=%p aLayer=%p [%d]"
+        " bounds=(%d,%d,w=%d,h=%d) pos=(%g,%g) trans=(%g,%g)"
+        " result=(%d,%d,w=%d,h=%d) offset=(%d,%d)",
+        root, aLayer, aLayer->uniqueId(),
+        bounds.x(), bounds.y(), bounds.width(), bounds.height(),
+        position.x(), position.y(), translation.x(), translation.y(),
+        result.x(), result.y(), result.width(), result.height(),
+        mOffset.x(), mOffset.y());
+    result.move(-mOffset.x(), -mOffset.y());
+    return result;
+}
+
+const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const
+{
+    if (!root || mLayer)
+        return mLayer;
+    return mLayer = root->findById(mUniqueId);
+}
+
+SkPicture* CachedLayer::picture(const LayerAndroid* root) const
+{
+    const LayerAndroid* aLayer = layer(root);
+    if (!aLayer)
+        return 0;
+    DBG_NAV_LOGD("root=%p aLayer=%p [%d] picture=%p",
+        root, aLayer, aLayer->uniqueId(), aLayer->picture());
+    return aLayer->picture();
+}
+
+#if DUMP_NAV_CACHE
+
+CachedLayer* CachedLayer::Debug::base() const {
+    return (CachedLayer*) ((char*) this - OFFSETOF(CachedLayer, mDebug));
+}
+
+void CachedLayer::Debug::print() const
+{
+    CachedLayer* b = base();
+    DUMP_NAV_LOGD("    // int mCachedNodeIndex=%d;", b->mCachedNodeIndex);
+    DUMP_NAV_LOGD(" LayerAndroid* mLayer=%p;", b->mLayer);
+    DUMP_NAV_LOGD(" int mOffset=(%d, %d);", b->mOffset.x(), b->mOffset.y());
+    DUMP_NAV_LOGD(" int mUniqueId=%p;\n", b->mUniqueId);
+}
+
+#endif
+
+#if DUMP_NAV_CACHE
+
+int CachedLayer::Debug::spaces;
+
+void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer)
+{
+    ++spaces;
+    SkRect bounds;
+    layer->bounds(&bounds);
+    DUMP_NAV_LOGX("%.*s layer=%p [%d] (%g,%g,%g,%g) picture=%p clipped=%s",
+        spaces, "                   ", layer, layer->uniqueId(),
+        bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(),
+        layer->picture(), layer->haveClip() ? "true" : "false");
+    for (int i = 0; i < layer->countChildren(); i++)
+        printLayerAndroid(layer->getChild(i));
+    --spaces;
+}
+
+void CachedLayer::Debug::printRootLayerAndroid(const LayerAndroid* layer)
+{
+    spaces = 0;
+    printLayerAndroid(layer);
+}
+#endif
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+}
+
diff --git a/WebKit/android/nav/CachedLayer.h b/WebKit/android/nav/CachedLayer.h
new file mode 100644 (file)
index 0000000..d320b0c
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CachedLayer_H
+#define CachedLayer_H
+
+#include "CachedDebug.h"
+#include "IntRect.h"
+
+class SkPicture;
+
+namespace WebCore {
+    class LayerAndroid;
+}
+
+using namespace WebCore;
+
+namespace android {
+
+class CachedLayer {
+public:
+#if USE(ACCELERATED_COMPOSITING)
+    bool operator<(const CachedLayer& l) const {
+        return mCachedNodeIndex < l.mCachedNodeIndex;
+    }
+    IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const;
+    int cachedNodeIndex() const { return mCachedNodeIndex; }
+    const LayerAndroid* layer(const LayerAndroid* root) const;
+    SkPicture* picture(const LayerAndroid* root) const;
+    void reset() { mLayer = 0; }
+    void setCachedNodeIndex(int index) { mCachedNodeIndex = index; }
+    void setOffset(const IntPoint& offset) { mOffset = offset; }
+    void setUniqueId(int uniqueId) { mUniqueId = uniqueId; }
+    int uniqueId() const { return mUniqueId; }
+private:
+    int mCachedNodeIndex;
+    mutable const LayerAndroid* mLayer;
+    IntPoint mOffset;
+    int mUniqueId;
+
+#if DUMP_NAV_CACHE
+public:
+    class Debug {
+public:
+        CachedLayer* base() const;
+        void print() const;
+        static void printLayerAndroid(const LayerAndroid* );
+        static void printRootLayerAndroid(const LayerAndroid* );
+        static int spaces;
+    } mDebug;
+#endif
+#endif // USE(ACCELERATED_COMPOSITING)
+};
+
+}
+
+#endif
index 58ada58..9406db1 100644 (file)
  */
 
 #include "CachedPrefix.h"
+#include "android_graphics.h"
+#include "CachedFrame.h"
 #include "CachedHistory.h"
-#include "CachedRoot.h"
 #include "Node.h"
 #include "PlatformString.h"
 
-#include "android_graphics.h"
 #include "CachedNode.h"
 
 namespace android {
 
+WebCore::IntRect CachedNode::bounds(const CachedFrame* frame) const
+{
+    return mIsInLayer ? frame->adjustBounds(this, mBounds) : mBounds;
+}
+
 void CachedNode::clearCursor(CachedFrame* parent)
 {
     if (isFrame()) {
@@ -76,26 +81,36 @@ bool CachedNode::clip(const WebCore::IntRect& bounds)
     return Clip(bounds, &mBounds, &mCursorRing);
 }
 
-void CachedNode::cursorRingBounds(WebCore::IntRect* bounds) const
+
+void CachedNode::cursorRings(const CachedFrame* frame,
+    WTF::Vector<WebCore::IntRect>* rings) const
+{
+    rings->clear();
+    for (unsigned index = 0; index < mCursorRing.size(); index++)
+        rings->append(ring(frame, index));
+}
+
+WebCore::IntRect CachedNode::cursorRingBounds(const CachedFrame* frame) const
 {
     int partMax = mNavableRects;
     ASSERT(partMax > 0);
-    *bounds = mCursorRing[0];
+    WebCore::IntRect bounds = mCursorRing[0];
     for (int partIndex = 1; partIndex < partMax; partIndex++)
-        bounds->unite(mCursorRing[partIndex]);
-    bounds->inflate(CURSOR_RING_HIT_TEST_RADIUS);
+        bounds.unite(mCursorRing[partIndex]);
+    bounds.inflate(CURSOR_RING_HIT_TEST_RADIUS);
+    return mIsInLayer ? frame->adjustBounds(this, bounds) : bounds;
 }
 
 #define OVERLAP 3
 
-void CachedNode::fixUpCursorRects(const CachedRoot* root)
+void CachedNode::fixUpCursorRects(const CachedFrame* frame)
 {
     if (mFixedUpCursorRects)
         return;
     mFixedUpCursorRects = true;
     // if the hit-test rect doesn't intersect any other rect, use it
     if (mHitBounds != mBounds && mHitBounds.contains(mBounds) &&
-            root->checkRings(mCursorRing, mHitBounds)) {
+            frame->checkRings(this, mCursorRing, mHitBounds)) {
         DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(),
             mHitBounds.y(), mHitBounds.width(), mHitBounds.height());
         mUseHitBounds = true;
@@ -105,7 +120,7 @@ void CachedNode::fixUpCursorRects(const CachedRoot* root)
         return;
     // if there is more than 1 rect, and the bounds doesn't intersect
     // any other cursor ring bounds, use it
-    if (root->checkRings(mCursorRing, mBounds)) {
+    if (frame->checkRings(this, mCursorRing, mBounds)) {
         DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(),
             mBounds.y(), mBounds.width(), mBounds.height());
         mUseBounds = true;
@@ -204,6 +219,7 @@ tryAgain:
     } while (again);
 }
 
+
 void CachedNode::hideCursor(CachedFrame* parent)
 {
     if (isFrame()) {
@@ -213,6 +229,11 @@ void CachedNode::hideCursor(CachedFrame* parent)
     mIsHidden = true;
 }
 
+WebCore::IntRect CachedNode::hitBounds(const CachedFrame* frame) const
+{
+    return mIsInLayer ? frame->adjustBounds(this, mHitBounds) : mHitBounds;
+}
+
 void CachedNode::init(WebCore::Node* node)
 {
     bzero(this, sizeof(CachedNode));
@@ -256,6 +277,12 @@ bool CachedNode::partRectsContains(const CachedNode* other) const
     return false;
 }
 
+WebCore::IntRect CachedNode::ring(const CachedFrame* frame, size_t part) const
+{
+    const WebCore::IntRect& rect = mCursorRing.at(part);
+    return mIsInLayer ? frame->adjustBounds(this, rect) : rect;
+}
+
 #if DUMP_NAV_CACHE
 
 #define DEBUG_PRINT_BOOL(field) \
@@ -333,12 +360,15 @@ void CachedNode::Debug::print() const
     DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
     DEBUG_PRINT_RECT(mBounds);
     DEBUG_PRINT_RECT(mHitBounds);
-    const WTF::Vector<WebCore::IntRect>& rects = b->cursorRings();
-    size_t size = rects.size();
+    DEBUG_PRINT_RECT(mOriginalAbsoluteBounds);
+    const WTF::Vector<WebCore::IntRect>* rects = b->cursorRingsPtr();
+    size_t size = rects->size();
     DUMP_NAV_LOGD("// IntRect cursorRings={ // size=%d\n", size);
-    for (size_t i = 0; i < size; i++)
-        DUMP_NAV_LOGD("    // {%d, %d, %d, %d}, // %d\n", rects[i].x(), rects[i].y(),
-            rects[i].width(), rects[i].height(), i);
+    for (size_t i = 0; i < size; i++) {
+        const WebCore::IntRect& rect = (*rects)[i];
+        DUMP_NAV_LOGD("    // {%d, %d, %d, %d}, // %d\n", rect.x(), rect.y(),
+            rect.width(), rect.height(), i);
+    }
     DUMP_NAV_LOGD("// };\n");
     DUMP_NAV_LOGD("// void* mNode=%p; // (%d) \n", b->mNode, mNodeIndex);
     DUMP_NAV_LOGD("// void* mParentGroup=%p; // (%d) \n", b->mParentGroup, mParentGroupIndex);
@@ -357,6 +387,7 @@ void CachedNode::Debug::print() const
     DEBUG_PRINT_BOOL(mIsCursor);
     DEBUG_PRINT_BOOL(mIsFocus);
     DEBUG_PRINT_BOOL(mIsHidden);
+    DEBUG_PRINT_BOOL(mIsInLayer);
     DEBUG_PRINT_BOOL(mIsParentAnchor);
     DEBUG_PRINT_BOOL(mIsTransparent);
     DEBUG_PRINT_BOOL(mIsUnclipped);
index a433a47..825eab7 100644 (file)
@@ -33,6 +33,8 @@
 #include "PlatformString.h"
 #include "wtf/Vector.h"
 
+class SkPicture;
+
 namespace WebCore {
     class Node;
 }
@@ -77,6 +79,7 @@ public:
         NOT_CURSOR_NODE,
         OUTSIDE_OF_BEST, // containership
         OUTSIDE_OF_ORIGINAL, // containership
+        UNDER_LAYER,
         CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition
     };
     CachedNode() {
@@ -84,8 +87,8 @@ public:
         // constructor
     }
 
-    const WebCore::IntRect& bounds() const { return mBounds; }
-    WebCore::IntRect* boundsPtr() { return &mBounds; }
+    WebCore::IntRect bounds(const CachedFrame* ) const;
+    WebCore::IntRect* boundsPtr() { return &mBounds; } // CacheBuilder only
     int childFrameIndex() const { return isFrame() ? mDataIndex : -1; }
     void clearCondition() const { mCondition = NOT_REJECTED; }
     void clearCursor(CachedFrame* );
@@ -93,19 +96,18 @@ public:
         WTF::Vector<WebCore::IntRect>* rings);
     bool clip(const WebCore::IntRect& );
     bool clippedOut() { return mClippedOut; }
-    void cursorRingBounds(WebCore::IntRect* ) const;
-    WTF::Vector<WebCore::IntRect>& cursorRings() { return mCursorRing; }
-    const WTF::Vector<WebCore::IntRect>& cursorRings() const { return mCursorRing; }
+    WebCore::IntRect cursorRingBounds(const CachedFrame* ) const;
+    // cursorRingsPtr() only for CacheBuilder since it points to raw data
+    WTF::Vector<WebCore::IntRect>* cursorRingsPtr() { return &mCursorRing; }
+    void cursorRings(const CachedFrame* , WTF::Vector<WebCore::IntRect>* ) const;
     bool disabled() const { return mDisabled; }
     const CachedNode* document() const { return &this[-mIndex]; }
-    void fixUpCursorRects(const CachedRoot* root);
-    const WebCore::IntRect& getBounds() const { return mBounds; }
-    void getBounds(WebCore::IntRect* bounds) const { *bounds = mBounds; }
+    void fixUpCursorRects(const CachedFrame* frame);
     const WebCore::String& getExport() const { return mExport; }
     bool hasCursorRing() const { return mHasCursorRing; }
     bool hasMouseOver() const { return mHasMouseOver; }
     void hideCursor(CachedFrame* );
-    const WebCore::IntRect& hitBounds() const { return mHitBounds; }
+    WebCore::IntRect hitBounds(const CachedFrame* ) const;
     int index() const { return mIndex; }
     void init(WebCore::Node* node);
     bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; }
@@ -114,8 +116,9 @@ public:
     bool isFocus() const { return mIsFocus; }
     bool isFrame() const { return mType == FRAME_CACHEDNODETYPE; }
     bool isHidden() const { return mIsHidden; }
-    bool isNavable(const WebCore::IntRect& clip) const {
-        return clip.intersects(mBounds);
+    bool isInLayer() const { return mIsInLayer; }
+    bool isNavable(const CachedFrame* frame, const WebCore::IntRect& clip) const {
+        return clip.intersects(bounds(frame));
     }
     bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; }
     bool isSyntheticLink() const {
@@ -136,6 +139,7 @@ public:
     int parentIndex() const { return mParentIndex; }
     bool partRectsContains(const CachedNode* other) const;
     void reset();
+    WebCore::IntRect ring(const CachedFrame* , size_t part) const;
     void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; }
     void setClippedOut(bool clipped) { mClippedOut = clipped; }
     void setCondition(Condition condition) const { mCondition = condition; }
@@ -150,6 +154,7 @@ public:
     void setIndex(int index) { mIndex = index; }
     void setIsCursor(bool isCursor) { mIsCursor = isCursor; }
     void setIsFocus(bool isFocus) { mIsFocus = isFocus; }
+    void setIsInLayer(bool isInLayer) { mIsInLayer = isInLayer; }
     void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; }
     void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; }
     void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; }
@@ -189,6 +194,7 @@ private:
     bool mIsCursor : 1;
     bool mIsFocus : 1;
     bool mIsHidden : 1;
+    bool mIsInLayer : 1;
     bool mIsParentAnchor : 1;
     bool mIsTransparent : 1;
     bool mIsUnclipped : 1;
index 54e0c15..d81d764 100644 (file)
 #include "CachedHistory.h"
 #include "CachedInput.h"
 #include "CachedNode.h"
+#include "FindCanvas.h"
+#include "FloatRect.h"
+#include "LayerAndroid.h"
 #include "SkBitmap.h"
 #include "SkBounder.h"
-#include "SkCanvas.h"
 #include "SkPixelRef.h"
 #include "SkRegion.h"
 
 #include "CachedRoot.h"
 
+using std::min;
+using std::max;
+
 #ifdef DUMP_NAV_CACHE_USING_PRINTF
     extern android::Mutex gWriteLogMutex;
 #endif
@@ -693,7 +698,7 @@ bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction directio
             innerMove(document(), best, direction, scrollPtr, false);
             return true;
         }
-        newNode->cursorRingBounds(&newOutset);
+        newOutset = newNode->cursorRingBounds(best->mFrame);
     }
     int delta;
     bool newNodeInView = scrollDelta(newOutset, direction, &delta);
@@ -717,7 +722,7 @@ int CachedRoot::checkForCenter(int x, int y) const
     checker.setBitmapDevice(bitmap);
     checker.translate(SkIntToScalar(width - mViewBounds.x()),
         SkIntToScalar(-mViewBounds.y()));
-    checker.drawPicture(*mPicture);
+    checker.drawPicture(*pictureAt(x, y));
     return centerCheck.center();
 }
 
@@ -731,16 +736,18 @@ void CachedRoot::checkForJiggle(int* xDeltaPtr) const
     bitmap.setConfig(SkBitmap::kARGB_8888_Config, mViewBounds.width() +
         absDelta, mViewBounds.height());
     checker.setBitmapDevice(bitmap);
-    checker.translate(SkIntToScalar(-mViewBounds.x() -
-        (xDelta < 0 ? xDelta : 0)), SkIntToScalar(-mViewBounds.y()));
-    checker.drawPicture(*mPicture);
+    int x = -mViewBounds.x() - (xDelta < 0 ? xDelta : 0);
+    int y = -mViewBounds.y();
+    checker.translate(SkIntToScalar(x), SkIntToScalar(y));
+    checker.drawPicture(*pictureAt(x, y));
     *xDeltaPtr = jiggleCheck.jiggle();
 }
 
-bool CachedRoot::checkRings(const WTF::Vector<WebCore::IntRect>& rings,
+bool CachedRoot::checkRings(SkPicture* picture,
+        const WTF::Vector<WebCore::IntRect>& rings,
         const WebCore::IntRect& bounds) const
 {
-    if (!mPicture)
+    if (!picture)
         return false;
     RingCheck ringCheck(rings, bounds.location());
     BoundsCanvas checker(&ringCheck);
@@ -749,13 +756,24 @@ bool CachedRoot::checkRings(const WTF::Vector<WebCore::IntRect>& rings,
         bounds.height());
     checker.setBitmapDevice(bitmap);
     checker.translate(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y()));
-    checker.drawPicture(*mPicture);
+    checker.drawPicture(*picture);
     DBG_NAV_LOGD("bounds=(%d,%d,r=%d,b=%d) success=%s",
         bounds.x(), bounds.y(), bounds.right(), bounds.bottom(),
         ringCheck.success() ? "true" : "false");
     return ringCheck.success();
 }
 
+void CachedRoot::draw(FindCanvas& canvas) const
+{
+    canvas.setLayerId(-1); // overlays change the ID as their pictures draw
+    canvas.drawPicture(*mPicture);
+#if USE(ACCELERATED_COMPOSITING)
+    if (!mRootLayer)
+        return;
+    canvas.drawLayers(mRootLayer);
+#endif
+}
+
 const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect,
     const CachedFrame** framePtr, int* x, int* y, bool checkForHidden) const
 {
@@ -821,10 +839,13 @@ int CachedRoot::getBlockLeftEdge(int x, int y, float scale) const
     int fx, fy;
     const CachedNode* node = findAt(rect, &frame, &fx, &fy, true);
     if (node && node->wantsKeyEvents()) {
-        DBG_NAV_LOGD("x=%d (%s)", node->bounds().x(),
+        DBG_NAV_LOGD("x=%d (%s)", node->bounds(frame).x(),
             node->isTextInput() ? "text" : "plugin");
-        return node->bounds().x();
+        return node->bounds(frame).x();
     }
+    SkPicture* picture = node ? frame->picture(node) : pictureAt(x, y);
+    if (!picture)
+        return x;
     int halfW = (int) (mViewBounds.width() * scale * 0.5f);
     int fullW = halfW << 1;
     int halfH = (int) (mViewBounds.height() * scale * 0.5f);
@@ -835,7 +856,7 @@ int CachedRoot::getBlockLeftEdge(int x, int y, float scale) const
     bitmap.setConfig(SkBitmap::kARGB_8888_Config, fullW, fullH);
     checker.setBitmapDevice(bitmap);
     checker.translate(SkIntToScalar(fullW - x), SkIntToScalar(halfH - y));
-    checker.drawPicture(*mPicture);
+    checker.drawPicture(*picture);
     int result = x + leftCheck.left() - fullW;
     DBG_NAV_LOGD("halfW=%d halfH=%d mMostLeft=%d x=%d",
         halfW, halfH, leftCheck.mMostLeft, result);
@@ -893,7 +914,8 @@ bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const
             mScrolledBounds.setY(navTop);
         }
     }
-    frameDown(test, NULL, bestData, currentCursor());
+    setCursorCache(0, mMaxYScroll);
+    frameDown(test, NULL, bestData);
     return true;
 }
 
@@ -916,7 +938,8 @@ bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const
         if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x()))
             mScrolledBounds.setWidth(navRight - scrollLeft);
     }
-    frameLeft(test, NULL, bestData, currentCursor());
+    setCursorCache(-mMaxXScroll, 0);
+    frameLeft(test, NULL, bestData);
     return true;
 }
 
@@ -932,8 +955,9 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData,
         mHistory->reset();
         outOfCursor = true;
     }
-    const CachedNode* cursor = currentCursor();
-    mHistory->setWorking(direction, cursor, mViewBounds);
+    const CachedFrame* cursorFrame;
+    const CachedNode* cursor = currentCursor(&cursorFrame);
+    mHistory->setWorking(direction, cursorFrame, cursor, mViewBounds);
     bool findClosest = false;
     if (mScrollOnly == false) {
         switch (direction) {
@@ -968,13 +992,13 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData,
     }
     if (firstCall)
         mHistory->mPriorBounds = mHistory->mNavBounds; // bounds always advances, even if new node is ultimately NULL
-    bestData->mMouseBounds = bestData->mNodeBounds;
+    bestData->setMouseBounds(bestData->bounds());
     if (adjustForScroll(bestData, direction, scroll, findClosest))
         return;
     if (bestData->mNode != NULL) {
         mHistory->addToVisited(bestData->mNode, direction);
-        mHistory->mNavBounds = bestData->mNodeBounds;
-        mHistory->mMouseBounds = bestData->mMouseBounds;
+        mHistory->mNavBounds = bestData->bounds();
+        mHistory->mMouseBounds = bestData->mouseBounds();
     } else if (scroll->x() != 0 || scroll->y() != 0) {
         WebCore::IntRect newBounds = mHistory->mNavBounds;
         int offsetX = scroll->x();
@@ -1014,7 +1038,8 @@ bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const
             mScrolledBounds.setX(navLeft);
         }
     }
-    frameRight(test, NULL, bestData, currentCursor());
+    setCursorCache(mMaxXScroll, 0);
+    frameRight(test, NULL, bestData);
     return true;
 }
 
@@ -1037,7 +1062,8 @@ bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const
         if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y()))
             mScrolledBounds.setHeight(navBottom - scrollTop);
     }
-    frameUp(test, NULL, bestData, currentCursor());
+    setCursorCache(0, -mMaxYScroll);
+    frameUp(test, NULL, bestData);
     return true;
 }
 
@@ -1049,22 +1075,23 @@ WebCore::String CachedRoot::imageURI(int x, int y) const
     bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
     checker.setBitmapDevice(bitmap);
     checker.translate(SkIntToScalar(-x), SkIntToScalar(-y));
-    checker.drawPicture(*mPicture);
+    checker.drawPicture(*pictureAt(x, y));
     return WebCore::String(checker.mURI);
 }
 
 bool CachedRoot::maskIfHidden(BestData* best) const
 {
-    if (mPicture == NULL) {
-        DBG_NAV_LOG("missing picture");
-        return false;
-    }
     const CachedNode* bestNode = best->mNode;
     if (bestNode->isUnclipped())
         return false;
+    SkPicture* picture = best->mFrame->picture(bestNode);
+    if (picture == NULL) {
+        DBG_NAV_LOG("missing picture");
+        return false;
+    }
     // given the picture matching this nav cache
         // create an SkBitmap with dimensions of the cursor intersected w/ extended view
-    const WebCore::IntRect& nodeBounds = bestNode->getBounds();
+    const WebCore::IntRect& nodeBounds = bestNode->bounds(best->mFrame);
     WebCore::IntRect bounds = nodeBounds;
     bounds.intersect(mScrolledBounds);
     int leftMargin = bounds.x() == nodeBounds.x() ? kMargin : 0;
@@ -1090,7 +1117,7 @@ bool CachedRoot::maskIfHidden(BestData* best) const
         // ? need to know (like imdb menu bar) to give up sometimes (when?)
     checker.translate(SkIntToScalar(leftMargin - bounds.x()),
         SkIntToScalar(topMargin - bounds.y()));
-    checker.drawPicture(*mPicture);
+    checker.drawPicture(*picture);
     boundsCheck.checkLast();
     // was it not drawn or clipped out?
     CachedNode* node = const_cast<CachedNode*>(best->mNode);
@@ -1149,9 +1176,9 @@ bool CachedRoot::maskIfHidden(BestData* best) const
             orig.fLeft, orig.fTop, orig.fRight, orig.fBottom,
             base.fLeft, base.fTop, base.fRight, base.fBottom);
 #endif
-        best->mMouseBounds = WebCore::IntRect(bounds.x() + base.fLeft - kMargin,
-            bounds.y() + base.fTop - kMargin, base.width(), base.height());
-        node->clip(best->mMouseBounds);
+        best->setMouseBounds(WebCore::IntRect(bounds.x() + base.fLeft - kMargin,
+            bounds.y() + base.fTop - kMargin, base.width(), base.height()));
+        node->clip(best->mouseBounds());
         return true;
     }
     return false;
@@ -1173,10 +1200,87 @@ const CachedNode* CachedRoot::moveCursor(Direction direction, const CachedFrame*
     setData();
     BestData bestData;
     innerMove(node, &bestData, direction, scroll, true);
+    // if node is partially or fully concealed by layer, scroll it into view
+    if (mRootLayer && bestData.mNode && !bestData.mNode->isInLayer()) {
+#if USE(ACCELERATED_COMPOSITING)
+#if DUMP_NAV_CACHE
+        CachedLayer::Debug::printRootLayerAndroid(mRootLayer);
+#endif
+        SkIRect original = bestData.mNode->cursorRingBounds(bestData.mFrame);
+        DBG_NAV_LOGD("original=(%d,%d,w=%d,h=%d) scroll=(%d,%d)",
+            original.fLeft, original.fTop, original.width(), original.height(),
+            scroll->x(), scroll->y());
+        original.offset(-scroll->x(), -scroll->y());
+        SkRegion rings(original);
+        SkTDArray<SkRect> region;
+        mRootLayer->clipArea(&region);
+        SkRegion layers;
+        for (int index = 0; index < region.count(); index++) {
+            SkIRect enclosing;
+            region[index].round(&enclosing);
+            rings.op(enclosing, SkRegion::kDifference_Op);
+            layers.op(enclosing, SkRegion::kUnion_Op);
+        }
+        SkIRect layerBounds(layers.getBounds());
+        SkIRect ringBounds(rings.getBounds());
+        int scrollX = scroll->x();
+        int scrollY = scroll->y();
+        if (rings.getBounds() != original) {
+            int topOverlap = layerBounds.fBottom - original.fTop;
+            int bottomOverlap = original.fBottom - layerBounds.fTop;
+            int leftOverlap = layerBounds.fRight - original.fLeft;
+            int rightOverlap = original.fRight - layerBounds.fLeft;
+            if (direction & UP_DOWN) {
+                if (layerBounds.fLeft < original.fLeft && leftOverlap < 0)
+                    scroll->setX(leftOverlap);
+                if (original.fRight < layerBounds.fRight && rightOverlap > 0
+                        && -leftOverlap > rightOverlap)
+                    scroll->setX(rightOverlap);
+                bool topSet = scrollY > topOverlap && (direction == UP
+                    || !scrollY);
+                if (topSet)
+                    scroll->setY(topOverlap);
+                if (scrollY < bottomOverlap && (direction == DOWN || (!scrollY
+                        && (!topSet || -topOverlap > bottomOverlap))))
+                    scroll->setY(bottomOverlap);
+            } else {
+                if (layerBounds.fTop < original.fTop && topOverlap < 0)
+                    scroll->setY(topOverlap);
+                if (original.fBottom < layerBounds.fBottom && bottomOverlap > 0
+                        && -topOverlap > bottomOverlap)
+                    scroll->setY(bottomOverlap);
+                bool leftSet = scrollX > leftOverlap && (direction == LEFT
+                    || !scrollX);
+                if (leftSet)
+                    scroll->setX(leftOverlap);
+                if (scrollX < rightOverlap && (direction == RIGHT || (!scrollX
+                        && (!leftSet || -leftOverlap > rightOverlap))))
+                    scroll->setX(rightOverlap);
+           }
+            DBG_NAV_LOGD("rings=(%d,%d,w=%d,h=%d) layers=(%d,%d,w=%d,h=%d)"
+                " scroll=(%d,%d)",
+                ringBounds.fLeft, ringBounds.fTop, ringBounds.width(), ringBounds.height(),
+                layerBounds.fLeft, layerBounds.fTop, layerBounds.width(), layerBounds.height(),
+                scroll->x(), scroll->y());
+        }
+#endif
+    }
     *framePtr = bestData.mFrame;
     return const_cast<CachedNode*>(bestData.mNode);
 }
 
+SkPicture* CachedRoot::pictureAt(int x, int y) const
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (mRootLayer) {
+        const LayerAndroid* layer = mRootLayer->find(FloatPoint(x, y));
+        if (layer)
+            return layer->picture();
+    }
+#endif
+    return mPicture;
+}
+
 void CachedRoot::reset()
 {
 #ifndef NDEBUG
@@ -1184,6 +1288,7 @@ void CachedRoot::reset()
 #endif
     mContents = mViewBounds = WebCore::IntRect(0, 0, 0, 0);
     mMaxXScroll = mMaxYScroll = 0;
+    mRootLayer = 0;
     mSelectionStart = mSelectionEnd = -1;
     mScrollOnly = false;
 }
@@ -1216,7 +1321,7 @@ void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node)
     if (node == NULL)
         return;
     node->setIsFocus(true);
-    mFocusBounds = node->bounds();
+    mFocusBounds = node->bounds(frame);
     frame->setFocusIndex(node - frame->document());
     CachedFrame* parent;
     while ((parent = frame->parent()) != NULL) {
@@ -1224,10 +1329,11 @@ void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node)
         frame = parent;
     }
 #if DEBUG_NAV_UI
-    const CachedNode* focus = frame->currentFocus();
+    const CachedFrame* focusFrame;
+    const CachedNode* focus = currentFocus(&focusFrame);
     WebCore::IntRect bounds = WebCore::IntRect(0, 0, 0, 0);
     if (focus)
-        bounds = focus->bounds();
+        bounds = focus->bounds(focusFrame);
     DBG_NAV_LOGD("new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
         focus ? focus->index() : 0,
         focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(),
@@ -1238,10 +1344,11 @@ void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node)
 void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node)
 {
 #if DEBUG_NAV_UI
-    const CachedNode* cursor = currentCursor();
+    const CachedFrame* cursorFrame;
+    const CachedNode* cursor = currentCursor(&cursorFrame);
     WebCore::IntRect bounds;
     if (cursor)
-        bounds = cursor->bounds();
+        bounds = cursor->bounds(cursorFrame);
     DBG_NAV_LOGD("old cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
         cursor ? cursor->index() : 0,
         cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(),
@@ -1259,10 +1366,10 @@ void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node)
         frame = parent;
     }
 #if DEBUG_NAV_UI
-    cursor = currentCursor();
+    cursor = currentCursor(&cursorFrame);
     bounds = WebCore::IntRect(0, 0, 0, 0);
     if (cursor)
-        bounds = cursor->bounds();
+        bounds = cursor->bounds(cursorFrame);
     DBG_NAV_LOGD("new cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
         cursor ? cursor->index() : 0,
         cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(),
@@ -1270,6 +1377,44 @@ void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node)
 #endif
 }
 
+void CachedRoot::setCursorCache(int scrollX, int scrollY) const
+{
+    mCursor = currentCursor();
+    if (mCursor)
+        mCursorBounds = mCursor->bounds(this);
+    if (!mRootLayer)
+        return;
+    SkRegion baseScrolled(mScrolledBounds);
+    mBaseUncovered = SkRegion(mScrolledBounds);
+#if USE(ACCELERATED_COMPOSITING)
+#if DUMP_NAV_CACHE
+    CachedLayer::Debug::printRootLayerAndroid(mRootLayer);
+#endif
+    SkTDArray<SkRect> region;
+    mRootLayer->clipArea(&region);
+    WebCore::IntSize offset(
+        copysign(min(max(0, mContents.width() - mScrolledBounds.width()),
+        abs(scrollX)), scrollX),
+        copysign(min(max(0, mContents.height() - mScrolledBounds.height()),
+        abs(scrollY)), scrollY));
+    bool hasOffset = offset.width() || offset.height();
+    // restrict scrollBounds to that which is not under layer
+    for (int index = 0; index < region.count(); index++) {
+        SkIRect less;
+        region[index].round(&less);
+        DBG_NAV_LOGD("less=(%d,%d,w=%d,h=%d)", less.fLeft, less.fTop,
+            less.width(), less.height());
+        mBaseUncovered.op(less, SkRegion::kDifference_Op);
+        if (!hasOffset)
+            continue;
+        less.offset(offset.width(), offset.height());
+        baseScrolled.op(less, SkRegion::kDifference_Op);
+    }
+    if (hasOffset)
+        mBaseUncovered.op(baseScrolled, SkRegion::kUnion_Op);
+#endif
+}
+
 #if DUMP_NAV_CACHE
 
 #define DEBUG_PRINT_BOOL(field) \
index dc0cea8..e4461d1 100644 (file)
 #include "CachedFrame.h"
 #include "IntRect.h"
 #include "SkPicture.h"
+#include "SkRegion.h"
 #include "wtf/Vector.h"
 
+class FindCanvas;
 class SkRect;
 
+namespace WebCore {
+    class LayerAndroid;
+}
+
 namespace android {
 
 class CachedHistory;
@@ -42,18 +48,22 @@ class CachedRoot : public CachedFrame {
 public:
     bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr,
         bool findClosest);
+    const SkRegion& baseUncovered() const { return mBaseUncovered; }
     int checkForCenter(int x, int y) const;
     void checkForJiggle(int* ) const;
-    bool checkRings(const WTF::Vector<WebCore::IntRect>& rings,
+    bool checkRings(SkPicture* , const WTF::Vector<WebCore::IntRect>& rings,
         const WebCore::IntRect& bounds) const;
     WebCore::IntPoint cursorLocation() const;
+    const WebCore::IntRect& cursorBounds() const { return mCursorBounds; } // should only be called by CachedFrame
+    const CachedNode* cursor() const { return mCursor; } // should only be called by CachedFrame
     int documentHeight() { return mContents.height(); }
     int documentWidth() { return mContents.width(); }
+    void draw(FindCanvas& ) const;
     const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** ,
         int* x, int* y, bool checkForHidden) const;
     const WebCore::IntRect& focusBounds() const { return mFocusBounds; }
     WebCore::IntPoint focusLocation() const;
-    SkPicture* getPicture() { return mPicture; }
+    SkPicture* getPicture() const { return mPicture; } // should only be called by CachedFrame
     int getAndResetSelectionEnd();
     int getAndResetSelectionStart();
     int getBlockLeftEdge(int x, int y, float scale) const;
@@ -68,16 +78,20 @@ public:
     WebCore::String imageURI(int x, int y) const;
     bool maskIfHidden(BestData* ) const;
     const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll);
+    SkPicture* pictureAt(int x, int y) const;
     void reset();
     CachedHistory* rootHistory() const { return mHistory; }
+    const WebCore::LayerAndroid* rootLayer() const { return mRootLayer; }
     bool scrollDelta(WebCore::IntRect& cursorRingBounds, Direction , int* delta);
     const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; }
     void setCursor(CachedFrame* , CachedNode* );
+    void setCursorCache(int scrollX, int scrollY) const; // compute cached state used to find next cursor
     void setCachedFocus(CachedFrame* , CachedNode* );
     void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; }
     void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; }
     void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; }
     void setPicture(SkPicture* picture) { mPicture = picture; }
+    void setRootLayer(WebCore::LayerAndroid* layer) { mRootLayer = layer; }
     void setScrollOnly(bool state) { mScrollOnly = state; }
     void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; }
     void setupScrolledBounds() const { mScrolledBounds = mViewBounds; }
@@ -87,6 +101,7 @@ public:
 private:
     CachedHistory* mHistory;
     SkPicture* mPicture;
+    WebCore::LayerAndroid* mRootLayer;
     WebCore::IntRect mFocusBounds; // dom text input focus node bounds
     mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll
     int mTextGeneration;
@@ -95,6 +110,10 @@ private:
     // These two are ONLY used when the tree is rebuilt and the focus is a textfield/area
     int mSelectionStart;
     int mSelectionEnd;
+    // these four set up as cache for use by frameDown/Up/Left/Right etc
+    mutable WebCore::IntRect mCursorBounds;
+    mutable const CachedNode* mCursor;
+    mutable SkRegion mBaseUncovered;
     bool mScrollOnly;
 #if DUMP_NAV_CACHE
 public:
index 1465b91..15a8001 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define LOG_TAG "webviewglue"
+
 #include "config.h"
 #include "FindCanvas.h"
-
+#include "LayerAndroid.h"
+#include "IntRect.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCornerPathEffect.h"
 #include "SkRect.h"
 
+#include <utils/Log.h>
+
 // MatchInfo methods
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -40,13 +47,15 @@ MatchInfo::~MatchInfo() {
 }
 
 MatchInfo::MatchInfo(const MatchInfo& src) {
+    m_layerId = src.m_layerId;
     m_location = src.m_location;
     m_picture = src.m_picture;
     m_picture->safeRef();
 }
 
-void MatchInfo::set(const SkRegion& region, SkPicture* pic) {
+void MatchInfo::set(const SkRegion& region, SkPicture* pic, int layerId) {
     m_picture->safeUnref();
+    m_layerId = layerId;
     m_location = region;
     m_picture = pic;
     SkASSERT(pic);
@@ -218,6 +227,16 @@ SkRect FindCanvas::addMatchPosH(int index,
     return r;
 }
 
+void FindCanvas::drawLayers(WebCore::LayerAndroid* layer) {
+    SkPicture* picture = layer->picture();
+    if (picture) {
+        setLayerId(layer->uniqueId());
+        drawPicture(*picture);
+    }
+    for (int i = 0; i < layer->countChildren(); i++)
+        drawLayers(layer->getChild(i));
+}
+
 void FindCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
                           SkScalar y, const SkPaint& paint) {
     findHelper(text, byteLength, paint, &x, y, &FindCanvas::addMatchNormal);
@@ -456,7 +475,9 @@ void FindCanvas::insertMatchInfo(const SkRegion& region) {
     mWorkingPicture->endRecording();
     MatchInfo matchInfo;
     mMatches->append(matchInfo);
-    mMatches->last().set(region, mWorkingPicture);
+    LOGD("%s region=%p pict=%p layer=%d", __FUNCTION__,
+        region, mWorkingPicture, mLayerId);
+    mMatches->last().set(region, mWorkingPicture, mLayerId);
 }
 
 void FindCanvas::resetWorkingCanvas() {
@@ -465,3 +486,163 @@ void FindCanvas::resetWorkingCanvas() {
     // Do not need to reset mWorkingCanvas itself because we only access it via
     // getWorkingCanvas.
 }
+
+// This function sets up the paints that are used to draw the matches.
+void FindOnPage::setUpFindPaint() {
+    // Set up the foreground paint
+    m_findPaint.setAntiAlias(true);
+    const SkScalar roundiness = SkIntToScalar(2);
+    SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness);
+    m_findPaint.setPathEffect(cornerEffect);
+    m_findPaint.setARGB(255, 132, 190, 0);
+
+    // Set up the background blur paint.
+    m_findBlurPaint.setAntiAlias(true);
+    m_findBlurPaint.setARGB(204, 0, 0, 0);
+    m_findBlurPaint.setPathEffect(cornerEffect);
+    cornerEffect->unref();
+    SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1,
+            SkBlurMaskFilter::kNormal_BlurStyle);
+    m_findBlurPaint.setMaskFilter(blurFilter)->unref();
+    m_isFindPaintSetUp = true;
+}
+
+WebCore::IntRect FindOnPage::currentMatchBounds() const {
+    if (!m_matches || !m_matches->size())
+        return WebCore::IntRect(0, 0, 0, 0);
+    return (*m_matches)[m_findIndex].getLocation().getBounds();
+}
+
+// This function is only used by findNext and setMatches.  In it, we store
+// upper left corner of the match specified by m_findIndex in
+// m_currentMatchLocation.
+void FindOnPage::storeCurrentMatchLocation() {
+    SkASSERT(m_findIndex < m_matches->size());
+    const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds();
+    m_currentMatchLocation.set(bounds.fLeft, bounds.fTop);
+    m_hasCurrentLocation = true;
+}
+
+// Put a cap on the number of matches to draw.  If the current page has more
+// matches than this, only draw the focused match.
+#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
+
+void FindOnPage::drawLayer(SkCanvas* canvas, const WebCore::IntRect* visRect,
+        int layerId) {
+    if (!m_matches || !m_matches->size())
+        return;
+    if (m_findIndex >= m_matches->size())
+        m_findIndex = 0;
+    const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
+    const SkRegion& currentMatchRegion = matchInfo.getLocation();
+
+    // Set up the paints used for drawing the matches
+    if (!m_isFindPaintSetUp)
+        setUpFindPaint();
+
+    // Draw the current match
+    if (matchInfo.layerId() == layerId) {
+        drawMatch(currentMatchRegion, canvas, true);
+        // Now draw the picture, so that it shows up on top of the rectangle
+        canvas->drawPicture(*matchInfo.getPicture());
+    }
+    // Draw the rest
+    unsigned numberOfMatches = m_matches->size();
+    if (numberOfMatches > 1
+            && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
+        for(unsigned i = 0; i < numberOfMatches; i++) {
+            // The current match has already been drawn
+            if (i == m_findIndex)
+                continue;
+            if ((*m_matches)[i].layerId() != layerId)
+                continue;
+            const SkRegion& region = (*m_matches)[i].getLocation();
+            // Do not draw matches which intersect the current one, or if it is
+            // offscreen
+            if (currentMatchRegion.intersects(region)
+                    || (visRect && !region.intersects(*visRect)))
+                continue;
+            drawMatch(region, canvas, false);
+        }
+    }
+}
+
+// Draw the match specified by region to the canvas.
+void FindOnPage::drawMatch(const SkRegion& region, SkCanvas* canvas,
+        bool focused)
+{
+    // For the match which has focus, use a filled paint.  For the others, use
+    // a stroked paint.
+    if (focused) {
+        m_findPaint.setStyle(SkPaint::kFill_Style);
+        m_findBlurPaint.setStyle(SkPaint::kFill_Style);
+    } else {
+        m_findPaint.setStyle(SkPaint::kStroke_Style);
+        m_findPaint.setStrokeWidth(SK_Scalar1);
+        m_findBlurPaint.setStyle(SkPaint::kStroke_Style);
+        m_findBlurPaint.setStrokeWidth(SkIntToScalar(2));
+    }
+    // Find the path for the current match
+    SkPath matchPath;
+    region.getBoundaryPath(&matchPath);
+    // Offset the path for a blurred shadow
+    SkPath blurPath;
+    matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath);
+    int saveCount = 0;
+    if (!focused) {
+        saveCount = canvas->save();
+        canvas->clipPath(matchPath, SkRegion::kDifference_Op);
+    }
+    // Draw the blurred background
+    canvas->drawPath(blurPath, m_findBlurPaint);
+    if (!focused)
+        canvas->restoreToCount(saveCount);
+    // Draw the foreground
+    canvas->drawPath(matchPath, m_findPaint);
+}
+
+void FindOnPage::findNext(bool forward)
+{
+    if (!m_matches || !m_matches->size())
+        return;
+    if (forward) {
+        m_findIndex++;
+        if (m_findIndex == m_matches->size())
+            m_findIndex = 0;
+    } else {
+        if (m_findIndex == 0) {
+            m_findIndex = m_matches->size() - 1;
+        } else {
+            m_findIndex--;
+        }
+    }
+    storeCurrentMatchLocation();
+}
+
+// With this call, WebView takes ownership of matches, and is responsible for
+// deleting it.
+void FindOnPage::setMatches(WTF::Vector<MatchInfo>* matches)
+{
+    if (m_matches)
+        delete m_matches;
+    m_matches = matches;
+    if (m_matches->size()) {
+        if (m_hasCurrentLocation) {
+            for (unsigned i = 0; i < m_matches->size(); i++) {
+                const SkIRect& rect = (*m_matches)[i].getLocation().getBounds();
+                if (rect.fLeft == m_currentMatchLocation.fX
+                        && rect.fTop == m_currentMatchLocation.fY) {
+                    m_findIndex = i;
+                    return;
+                }
+            }
+        }
+        // If we did not have a stored location, or if we were unable to restore
+        // it, store the new one.
+        m_findIndex = 0;
+        storeCurrentMatchLocation();
+    } else {
+        m_hasCurrentLocation = false;
+    }
+}
+
index d357a2a..fd04bd0 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef Find_Canvas_h
 #define Find_Canvas_h
 
+#include "IntRect.h"
 #include "SkBounder.h"
 #include "SkCanvas.h"
 #include "SkPicture.h"
 #include "icu/unicode/umachine.h"
 #include "wtf/Vector.h"
 
-class SkRect;
-class SkTypeface;
+// class SkIRect;
+// class SkRect;
+// class SkTypeface;
+
+namespace WebCore {
+    class LayerAndroid;
+}
 
 // Stores both region information and an SkPicture of the match, so that the
 // region can be drawn, followed by drawing the matching text on top of it.
@@ -51,11 +57,14 @@ public:
     SkPicture* getPicture() const { return m_picture; }
     // This will make a copy of the region, and increase the ref count on the
     // SkPicture.  If this MatchInfo already had one, unref it.
-    void set(const SkRegion& region, SkPicture* pic);
+    bool isInLayer() const { return m_layerId >= 0; }
+    int layerId() const { return m_layerId; }
+    void set(const SkRegion& region, SkPicture* pic, int layerId);
 private:
     MatchInfo& operator=(MatchInfo& src);
     SkRegion    m_location;
     SkPicture*  m_picture;
+    int         m_layerId;
 };
 
 // A class containing a typeface for reference, the length in glyphs, and
@@ -135,7 +144,9 @@ public:
                                 const SkPaint& paint) {
     }
 
+    void drawLayers(WebCore::LayerAndroid* );
     int found() const { return mNumFound; }
+    void setLayerId(int layerId) { mLayerId = layerId; }
 
     // This method detaches our array of matches and passes ownership to
     // the caller, who is then responsible for deleting them.
@@ -201,6 +212,38 @@ private:
     SkCanvas*               mWorkingCanvas;
     SkRegion                mWorkingRegion;
     int                     mWorkingIndex;
+    int                     mLayerId;
+};
+
+class FindOnPage {
+public:
+    FindOnPage() {
+        m_matches = 0;
+        m_hasCurrentLocation = false;
+        m_isFindPaintSetUp = false;
+    }
+    ~FindOnPage() { delete m_matches; }
+    void clearCurrentLocation() { m_hasCurrentLocation = false; }
+    WebCore::IntRect currentMatchBounds() const;
+    void drawLayer(SkCanvas* canvas, const WebCore::IntRect* vis, int layerId);
+    void findNext(bool forward);
+    void setMatches(WTF::Vector<MatchInfo>* matches);
+private:
+    void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused);
+    void setUpFindPaint();
+    void storeCurrentMatchLocation();
+    WTF::Vector<MatchInfo>* m_matches;
+    // Stores the location of the current match.
+    SkIPoint m_currentMatchLocation;
+    // Tells whether the value in m_currentMatchLocation is valid.
+    bool m_hasCurrentLocation;
+    // Tells whether we have done the setup to draw the Find matches.
+    bool m_isFindPaintSetUp;
+    // Paint used to draw our Find matches.
+    SkPaint m_findPaint;
+    // Paint used for the background of our Find matches.
+    SkPaint m_findBlurPaint;
+    unsigned m_findIndex;
 };
 
 #endif  // Find_Canvas_h
index d334589..41dfedb 100644 (file)
@@ -45,9 +45,7 @@
 #include "PlatformGraphicsContext.h"
 #include "PlatformString.h"
 #include "SelectText.h"
-#include "SkBlurMaskFilter.h"
 #include "SkCanvas.h"
-#include "SkCornerPathEffect.h"
 #include "SkDumpCanvas.h"
 #include "SkPath.h"
 #include "SkPicture.h"
@@ -110,6 +108,7 @@ struct JavaGlue {
     jmethodID   m_getScaledMaxXScroll;
     jmethodID   m_getScaledMaxYScroll;
     jmethodID   m_getVisibleRect;
+    jmethodID   m_getViewMetrics;
     jmethodID   m_rebuildWebTextView;
     jmethodID   m_viewInvalidate;
     jmethodID   m_viewInvalidateRect;
@@ -118,6 +117,11 @@ struct JavaGlue {
     jfieldID    m_rectTop;
     jmethodID   m_rectWidth;
     jmethodID   m_rectHeight;
+    jfieldID    m_metricsScrollX;
+    jfieldID    m_metricsScrollY;
+    jfieldID    m_metricsWidth;
+    jfieldID    m_metricsHeight;
+    jfieldID    m_metricsScale;
     AutoJObject object(JNIEnv* env) {
         return getRealObject(env, m_obj);
     }
@@ -139,6 +143,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
     m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
     m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
     m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
+    m_javaGlue.m_getViewMetrics = GetJMethod(env, clazz, "getViewMetrics", "()Landroid/webkit/WebView$Metrics;");
     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");
@@ -150,6 +155,12 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
     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");
+    jclass metricsClass = env->FindClass("android/webkit/WebView$Metrics");
+    m_javaGlue.m_metricsScrollX = env->GetFieldID(metricsClass, "mScrollX", "I");
+    m_javaGlue.m_metricsScrollY = env->GetFieldID(metricsClass, "mScrollY", "I");
+    m_javaGlue.m_metricsWidth = env->GetFieldID(metricsClass, "mWidth", "I");
+    m_javaGlue.m_metricsHeight = env->GetFieldID(metricsClass, "mHeight", "I");
+    m_javaGlue.m_metricsScale = env->GetFieldID(metricsClass, "mScale", "F");
 
     env->SetIntField(javaWebView, gWebViewField, (jint)this);
     m_viewImpl = (WebViewCore*) viewImpl;
@@ -163,9 +174,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
     m_ringAnimationEnd = 0;
     m_selStart.setEmpty();
     m_selEnd.setEmpty();
-    m_matches = 0;
-    m_hasCurrentLocation = false;
-    m_isFindPaintSetUp = false;
+    m_rootLayer = 0;
 }
 
 ~WebView()
@@ -178,8 +187,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
     }
     delete m_frameCacheUI;
     delete m_navPictureUI;
-    if (m_matches)
-        delete m_matches;
 }
 
 WebViewCore* getWebViewCore() const {
@@ -236,6 +243,7 @@ void debugDump()
 void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
 {
     bool cursorIsOnButton = false;
+    const CachedFrame* cachedFrame;
     const CachedNode* cachedCursor = 0;
     // Lock the mutex, since we now share with the WebCore thread.
     m_viewImpl->gButtonMutex.lock();
@@ -246,7 +254,7 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
         WebCore::Node* cursor = 0;
         CachedRoot* root = getFrameCache(DontAllowNewer);
         if (root) {
-            cachedCursor = root->currentCursor();
+            cachedCursor = root->currentCursor(&cachedFrame);
             if (cachedCursor)
                 cursor = (WebCore::Node*) cachedCursor->nodePointer();
         }
@@ -276,68 +284,11 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
     }
     m_viewImpl->gButtonMutex.unlock();
     if (invalidate && cachedCursor && cursorIsOnButton) {
-        const WebCore::IntRect& b = cachedCursor->getBounds();
+        const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
         viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom());
     }
 }
 
-// These two functions separate out the particular look of the drawn find
-// matches from the code that draws them.  This function sets up the paints that
-// are used to draw the matches.
-void setUpFindPaint()
-{
-    // Set up the foreground paint
-    m_findPaint.setAntiAlias(true);
-    const SkScalar roundiness = SkIntToScalar(2);
-    SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness);
-    m_findPaint.setPathEffect(cornerEffect);
-    m_findPaint.setARGB(255, 132, 190, 0);
-
-    // Set up the background blur paint.
-    m_findBlurPaint.setAntiAlias(true);
-    m_findBlurPaint.setARGB(204, 0, 0, 0);
-    m_findBlurPaint.setPathEffect(cornerEffect);
-    cornerEffect->unref();
-    SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1,
-            SkBlurMaskFilter::kNormal_BlurStyle);
-    m_findBlurPaint.setMaskFilter(blurFilter)->unref();
-    m_isFindPaintSetUp = true;
-}
-
-// Draw the match specified by region to the canvas.
-void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused)
-{
-    // For the match which has focus, use a filled paint.  For the others, use
-    // a stroked paint.
-    if (focused) {
-        m_findPaint.setStyle(SkPaint::kFill_Style);
-        m_findBlurPaint.setStyle(SkPaint::kFill_Style);
-    } else {
-        m_findPaint.setStyle(SkPaint::kStroke_Style);
-        m_findPaint.setStrokeWidth(SK_Scalar1);
-        m_findBlurPaint.setStyle(SkPaint::kStroke_Style);
-        m_findBlurPaint.setStrokeWidth(SkIntToScalar(2));
-    }
-    // Find the path for the current match
-    SkPath matchPath;
-    region.getBoundaryPath(&matchPath);
-    // Offset the path for a blurred shadow
-    SkPath blurPath;
-    matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath);
-    int saveCount = 0;
-    if (!focused) {
-        saveCount = canvas->save();
-        canvas->clipPath(matchPath, SkRegion::kDifference_Op);
-    }
-    // Draw the blurred background
-    canvas->drawPath(blurPath, m_findBlurPaint);
-    if (!focused) {
-        canvas->restoreToCount(saveCount);
-    }
-    // Draw the foreground
-    canvas->drawPath(matchPath, m_findPaint);
-}
-
 bool scrollRectOnScreen(int left, int top, int right, int bottom)
 {
     WebCore::IntRect visible;
@@ -362,52 +313,22 @@ bool scrollRectOnScreen(int left, int top, int right, int bottom)
     return true;
 }
 
-// Put a cap on the number of matches to draw.  If the current page has more
-// matches than this, only draw the focused match.
-#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
-
+// draws the root matches only. Matches over layers are drawn by LayerAndroid
 void drawMatches(SkCanvas* canvas)
 {
-    if (!m_matches || !m_matches->size())
-        return;
-    if (m_findIndex >= m_matches->size())
-        m_findIndex = 0;
-    const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
-    const SkRegion& currentMatchRegion = matchInfo.getLocation();
-    const SkIRect& currentMatchBounds = currentMatchRegion.getBounds();
-    if (scrollRectOnScreen(currentMatchBounds.fLeft, currentMatchBounds.fTop,
-            currentMatchBounds.fRight, currentMatchBounds.fBottom))
+    WebCore::IntRect visible;
+    getVisibleRect(&visible);
+    m_findOnPage.drawLayer(canvas, &visible, -1);
+    WebCore::IntRect currentMatchBounds = m_findOnPage.currentMatchBounds();
+    if (currentMatchBounds.isEmpty())
         return;
+    scrollRectOnScreen(currentMatchBounds.x(), currentMatchBounds.y(),
+        currentMatchBounds.right(), currentMatchBounds.bottom());
+}
 
-    // Set up the paints used for drawing the matches
-    if (!m_isFindPaintSetUp)
-        setUpFindPaint();
-
-    // Draw the current match
-    drawMatch(currentMatchRegion, canvas, true);
-    // Now draw the picture, so that it shows up on top of the rectangle
-    canvas->drawPicture(*matchInfo.getPicture());
-
-    // Draw the rest
-    unsigned numberOfMatches = m_matches->size();
-    if (numberOfMatches > 1
-            && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
-        WebCore::IntRect visible;
-        getVisibleRect(&visible);
-        SkIRect visibleIRect(visible);
-        for(unsigned i = 0; i < numberOfMatches; i++) {
-            // The current match has already been drawn
-            if (i == m_findIndex)
-                continue;
-            const SkRegion& region = (*m_matches)[i].getLocation();
-            // Do not draw matches which intersect the current one, or if it is
-            // offscreen
-            if (currentMatchRegion.intersects(region)
-                    || !region.intersects(visibleIRect))
-                continue;
-            drawMatch(region, canvas, false);
-        }
-    }
+FindOnPage* findOnPage()
+{
+    return m_viewImpl->m_findIsUp ? &m_findOnPage : 0;
 }
 
 void resetCursorRing()
@@ -418,7 +339,7 @@ void resetCursorRing()
 
 void drawCursorRing(SkCanvas* canvas)
 {
-    const CachedRoot* root = getFrameCache(AllowNewer);
+    CachedRoot* root = getFrameCache(AllowNewer);
     if (!root) {
         DBG_NAV_LOG("!root");
         resetCursorRing();
@@ -436,9 +357,11 @@ void drawCursorRing(SkCanvas* canvas)
         m_viewImpl->m_hasCursorBounds = false;
         return;
     }
-    const WTF::Vector<WebCore::IntRect>* rings = &node->cursorRings();
-    if (!rings->size()) {
-        DBG_NAV_LOG("!rings->size()");
+    setVisibleRect(root);
+    WTF::Vector<WebCore::IntRect> rings;
+    node->cursorRings(frame, &rings);
+    if (!rings.size()) {
+        DBG_NAV_LOG("!rings.size()");
         m_viewImpl->m_hasCursorBounds = false;
         return;
     }
@@ -459,17 +382,16 @@ void drawCursorRing(SkCanvas* canvas)
         }
     }
     m_viewImpl->gButtonMutex.unlock();
-    WebCore::IntRect bounds = node->bounds();
+    WebCore::IntRect bounds = node->bounds(frame);
     updateCursorBounds(root, frame, node);
 
-    WTF::Vector<WebCore::IntRect> oneRing;
     bool useHitBounds = node->useHitBounds();
     if (useHitBounds) {
-        bounds = node->hitBounds();
+        bounds = node->hitBounds(frame);
     }
     if (useHitBounds || node->useBounds()) {
-        oneRing.append(bounds);
-        rings = &oneRing;
+        rings.clear();
+        rings.append(bounds);
     }
     bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER));
     if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) {
@@ -490,14 +412,14 @@ void drawCursorRing(SkCanvas* canvas)
                     (flavor + CursorRing::NORMAL_ANIMATING);
         }
 #if DEBUG_NAV_UI
-        const WebCore::IntRect& ring = (*rings)[0];
+        const WebCore::IntRect& ring = rings[0];
         DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d"
             " (%d, %d, %d, %d) isPlugin=%s",
             node->index(), node->nodePointer(),
             flavor == CursorRing::FAKE_FLAVOR ? "FAKE_FLAVOR" :
             flavor == CursorRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
             flavor == CursorRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR",
-            rings->size(), ring.x(), ring.y(), ring.width(), ring.height(),
+            rings.size(), ring.x(), ring.y(), ring.width(), ring.height(),
             node->isPlugin() ? "true" : "false");
 #endif
     }
@@ -516,7 +438,7 @@ void drawCursorRing(SkCanvas* canvas)
         }
     }
     if (!isButton)
-        CursorRing::DrawRing(canvas, *rings, flavor);
+        CursorRing::DrawRing(canvas, rings, flavor);
 }
 
 bool cursorIsTextInput(FrameCachePermission allowNewer)
@@ -540,9 +462,10 @@ void cursorRingBounds(WebCore::IntRect* bounds)
     DBG_NAV_LOGD("%s", "");
     CachedRoot* root = getFrameCache(DontAllowNewer);
     if (root) {
-        const CachedNode* cachedNode = root->currentCursor();
+        const CachedFrame* cachedFrame;
+        const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
         if (cachedNode) {
-            cachedNode->cursorRingBounds(bounds);
+            *bounds = cachedNode->cursorRingBounds(cachedFrame);
             DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
                 bounds->width(), bounds->height());
             return;
@@ -568,7 +491,7 @@ void fixCursor()
     // center (+/- 2)
     IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
         bounds.y() + (bounds.height() >> 1));
-    IntRect newBounds = node->bounds();
+    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)"
@@ -607,7 +530,15 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer)
         return m_frameCacheUI;
     }
     DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
-    bool hadCursor = m_frameCacheUI && m_frameCacheUI->currentCursor();
+    const CachedFrame* oldCursorFrame;
+    const CachedNode* oldCursorNode = m_frameCacheUI ?
+        m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
+#if USE(ACCELERATED_COMPOSITING)
+    int layerId = oldCursorNode && oldCursorNode->isInLayer() ?
+        oldCursorFrame->layer(oldCursorNode)->layer(
+        m_frameCacheUI->rootLayer())->uniqueId() : -1;
+#endif
+    // get id from old layer and use to find new layer
     const CachedNode* oldFocus = m_frameCacheUI ? m_frameCacheUI->currentFocus() : 0;
     m_viewImpl->gFrameCacheMutex.lock();
     delete m_frameCacheUI;
@@ -618,6 +549,17 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer)
     m_viewImpl->m_frameCacheKit = 0;
     m_viewImpl->m_navPictureKit = 0;
     m_viewImpl->gFrameCacheMutex.unlock();
+    if (m_frameCacheUI)
+        m_frameCacheUI->setRootLayer(m_rootLayer);
+#if USE(ACCELERATED_COMPOSITING)
+    if (layerId >= 0) {
+        SkRect viewMetrics;
+        getViewMetrics(&viewMetrics);
+        LayerAndroid* layer = const_cast<LayerAndroid*>(
+            m_frameCacheUI->rootLayer()->findById(layerId));
+        layer->calcPosition(&viewMetrics, 0);
+    }
+#endif
     fixCursor();
     if (oldFocus && m_frameCacheUI) {
         const CachedNode* newFocus = m_frameCacheUI->currentFocus();
@@ -632,7 +574,7 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer)
             checkException(env);
         }
     }
-    if (hadCursor && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
+    if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
         viewInvalidate(); // redraw in case cursor ring is still visible
     return m_frameCacheUI;
 }
@@ -677,6 +619,23 @@ void getVisibleRect(WebCore::IntRect* rect)
     checkException(env);
 }
 
+void getViewMetrics(SkRect* viewMetrics)
+{
+    JNIEnv* env = JSC::Bindings::getJNIEnv();
+    jobject jMetrics = env->CallObjectMethod(m_javaGlue.object(env).get(),
+        m_javaGlue.m_getViewMetrics);
+    checkException(env);
+    int scrollX = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollX);
+    int scrollY = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollY);
+    int width = env->GetIntField(jMetrics, m_javaGlue.m_metricsWidth);
+    int height = env->GetIntField(jMetrics, m_javaGlue.m_metricsHeight);
+    int scale = env->GetFloatField(jMetrics, m_javaGlue.m_metricsScale);
+    *viewMetrics = IntRect(scrollX / scale, scrollY / scale,
+            width / scale, height / scale);
+    env->DeleteLocalRef(jMetrics);
+    checkException(env);
+}
+
 static CachedFrame::Direction KeyToDirection(KeyCode keyCode)
 {
     switch (keyCode) {
@@ -730,12 +689,12 @@ void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame,
     // If m_viewImpl->m_hasCursorBounds is false, we never look at the other
     // values, so do not bother setting them.
     if (m_viewImpl->m_hasCursorBounds) {
-        WebCore::IntRect bounds = cachedNode->bounds();
+        WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
         if (m_viewImpl->m_cursorBounds != bounds)
             DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
-        m_viewImpl->m_cursorBounds = cachedNode->bounds();
-        m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds();
+        m_viewImpl->m_cursorBounds = bounds;
+        m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
         m_viewImpl->m_cursorFrame = cachedFrame->framePointer();
         root->getSimulatedMousePosition(&m_viewImpl->m_cursorLocation);
         m_viewImpl->m_cursorNode = cachedNode->nodePointer();
@@ -760,11 +719,7 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll)
     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;
-    getVisibleRect(&visibleRect);
-    DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
-        visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
-    root->setVisibleRect(visibleRect);
+    WebCore::IntRect visibleRect = setVisibleRect(root);
     int xMax = getScaledMaxXScroll();
     int yMax = getScaledMaxYScroll();
     root->setMaxScroll(xMax, yMax);
@@ -784,10 +739,10 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll)
         "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
         cachedNode ? cachedNode->nodePointer() : 0,
             root->cursorLocation().x(), root->cursorLocation().y(),
-            cachedNode ? cachedNode->bounds().x() : 0,
-            cachedNode ? cachedNode->bounds().y() : 0,
-            cachedNode ? cachedNode->bounds().width() : 0,
-            cachedNode ? cachedNode->bounds().height() : 0);
+            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 ||
@@ -852,10 +807,18 @@ const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
     *framePtr = 0;
     if (!root)
         return 0;
-    WebCore::IntRect visibleRect;
+    setVisibleRect(root);
+    return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
+}
+
+IntRect setVisibleRect(CachedRoot* root)
+{
+    IntRect visibleRect;
     getVisibleRect(&visibleRect);
+    DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
+        visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
     root->setVisibleRect(visibleRect);
-    return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
+    return visibleRect;
 }
 
 void selectBestAt(const WebCore::IntRect& rect)
@@ -874,7 +837,7 @@ void selectBestAt(const WebCore::IntRect& rect)
             root->setCursor(0, 0);
     } else {
         DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
-        root->rootHistory()->setMouseBounds(node->bounds());
+        root->rootHistory()->setMouseBounds(node->bounds(frame));
         updateCursorBounds(root, frame, node);
         root->setCursor(const_cast<CachedFrame*>(frame),
                 const_cast<CachedNode*>(node));
@@ -988,7 +951,7 @@ void setFindIsUp(bool up)
 {
     m_viewImpl->m_findIsUp = up;
     if (!up)
-        m_hasCurrentLocation = false;
+        m_findOnPage.clearCurrentLocation();
 }
 
 void setFollowedLink(bool followed)
@@ -1148,33 +1111,9 @@ void sendMotionUp(
     checkException(env);
 }
 
-// This function is only used by findNext and setMatches.  In it, we store
-// upper left corner of the match specified by m_findIndex in
-// m_currentMatchLocation.
-void inline storeCurrentMatchLocation()
-{
-    SkASSERT(m_findIndex < m_matches->size());
-    const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds();
-    m_currentMatchLocation.set(bounds.fLeft, bounds.fTop);
-    m_hasCurrentLocation = true;
-}
-
 void findNext(bool forward)
 {
-    if (!m_matches || !m_matches->size())
-        return;
-    if (forward) {
-        m_findIndex++;
-        if (m_findIndex == m_matches->size())
-            m_findIndex = 0;
-    } else {
-        if (m_findIndex == 0) {
-            m_findIndex = m_matches->size() - 1;
-        } else {
-            m_findIndex--;
-        }
-    }
-    storeCurrentMatchLocation();
+    m_findOnPage.findNext(forward);
     viewInvalidate();
 }
 
@@ -1182,28 +1121,7 @@ void findNext(bool forward)
 // deleting it.
 void setMatches(WTF::Vector<MatchInfo>* matches)
 {
-    if (m_matches)
-        delete m_matches;
-    m_matches = matches;
-    if (m_matches->size()) {
-        if (m_hasCurrentLocation) {
-            for (unsigned i = 0; i < m_matches->size(); i++) {
-                const SkIRect& rect = (*m_matches)[i].getLocation().getBounds();
-                if (rect.fLeft == m_currentMatchLocation.fX
-                        && rect.fTop == m_currentMatchLocation.fY) {
-                    m_findIndex = i;
-                    viewInvalidate();
-                    return;
-                }
-            }
-        }
-        // If we did not have a stored location, or if we were unable to restore
-        // it, store the new one.
-        m_findIndex = 0;
-        storeCurrentMatchLocation();
-    } else {
-        m_hasCurrentLocation = false;
-    }
+    m_findOnPage.setMatches(matches);
     viewInvalidate();
 }
 
@@ -1281,6 +1199,21 @@ int moveGeneration()
     return m_viewImpl->m_moveGeneration;
 }
 
+const LayerAndroid* rootLayer() const
+{
+    return m_rootLayer;
+}
+
+void setRootLayer(LayerAndroid* layer)
+{
+    m_rootLayer = layer;
+    CachedRoot* root = getFrameCache(DontAllowNewer);
+    if (!root)
+        return;
+    root->resetLayers();
+    root->setRootLayer(m_rootLayer);
+}
+
 private: // local state for WebView
     // private to getFrameCache(); other functions operate in a different thread
     CachedRoot* m_frameCacheUI; // navigation data ready for use
@@ -1293,18 +1226,8 @@ private: // local state for WebView
     bool m_heightCanMeasure;
     int m_lastDx;
     SkMSec m_lastDxTime;
-    WTF::Vector<MatchInfo>* m_matches;
-    // Stores the location of the current match.
-    SkIPoint m_currentMatchLocation;
-    // Tells whether the value in m_currentMatchLocation is valid.
-    bool m_hasCurrentLocation;
-    // Tells whether we have done the setup to draw the Find matches.
-    bool m_isFindPaintSetUp;
-    // Paint used to draw our Find matches.
-    SkPaint m_findPaint;
-    // Paint used for the background of our Find matches.
-    SkPaint m_findBlurPaint;
-    unsigned m_findIndex;
+    FindOnPage m_findOnPage;
+    LayerAndroid* m_rootLayer;
 }; // end of WebView class
 
 /*
@@ -1383,13 +1306,14 @@ static const CachedNode* getCursorNode(JNIEnv *env, jobject obj,
     return root ? root->currentCursor(frame) : 0;
 }
 
-static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj)
+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();
+    const CachedNode* cursor = root->currentCursor(frame);
     if (cursor && cursor->wantsKeyEvents())
         return cursor;
     return root->currentFocus();
@@ -1424,8 +1348,9 @@ static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj)
 
 static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
 {
-    const CachedNode* node = getCursorNode(env, obj);
-    WebCore::IntRect bounds = node ? node->getBounds()
+    const CachedFrame* frame;
+    const CachedNode* node = getCursorNode(env, obj, &frame);
+    WebCore::IntRect bounds = node ? node->bounds(frame)
         : WebCore::IntRect(0, 0, 0, 0);
     jclass rectClass = env->FindClass("android/graphics/Rect");
     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
@@ -1462,9 +1387,10 @@ static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
 
 static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
 {
-    const CachedNode* node = getCursorNode(env, obj);
-    return node ? node->getBounds().intersects(jrect_to_webrect(env, visRect))
-        : false;
+    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)
@@ -1473,6 +1399,12 @@ static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
     return node ? node->isAnchor() : false;
 }
 
+static bool nativeCursorIsInLayer(JNIEnv *env, jobject obj)
+{
+    const CachedNode* node = getCursorNode(env, obj);
+    return node ? node->isInLayer() : false;
+}
+
 static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
 {
     const CachedNode* node = getCursorNode(env, obj);
@@ -1513,14 +1445,7 @@ static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv)
     view->drawMatches(canvas);
 }
 
-static void setXYWH(SkRect* r, SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
-    r->set(x, y, x + w, y + h);
-}
-
-static void nativeDrawLayers(JNIEnv *env, jobject obj,
-    jint layer, jint scrollX, jint scrollY,
-    jint width, jint height,
-    jfloat scale, jobject canv)
+static void nativeDrawLayers(JNIEnv *env, jobject obj, jint layer, jobject canv)
 {
     if (!env)
         return;
@@ -1532,13 +1457,11 @@ static void nativeDrawLayers(JNIEnv *env, jobject obj,
 #if USE(ACCELERATED_COMPOSITING)
     LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
-    if (canvas) {
-        SkRect viewPort;
-        setXYWH(&viewPort,
-                scrollX / scale, scrollY / scale,
-                width / scale, height / scale);
-        layerImpl->draw(canvas, &viewPort);
-    }
+    WebView* view = GET_NATIVE_VIEW(env, obj);
+    SkRect viewMetrics;
+    view->getViewMetrics(&viewMetrics);
+    layerImpl->setFindOnPage(view->findOnPage());
+    layerImpl->draw(canvas, &viewMetrics);
 #endif
 }
 
@@ -1568,6 +1491,14 @@ static void nativeDestroyLayer(JNIEnv *env, jobject obj, jint layer)
 #endif
 }
 
+static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer)
+{
+#if USE(ACCELERATED_COMPOSITING)
+    LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
+    GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl);
+#endif
+}
+
 static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv)
 {
     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
@@ -1655,7 +1586,7 @@ static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj)
 
 static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
 {
-    const CachedNode* node = getFocusCandidate(env, obj);
+    const CachedNode* node = getFocusCandidate(env, obj, 0);
     return node ? node->isTextInput() : false;
 }
 
@@ -1676,8 +1607,9 @@ static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
 
 static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
 {
-    const CachedNode* node = getFocusCandidate(env, obj);
-    WebCore::IntRect bounds = node ? node->getBounds()
+    const CachedFrame* frame;
+    const CachedNode* node = getFocusCandidate(env, obj, &frame);
+    WebCore::IntRect bounds = node ? node->bounds(frame)
         : WebCore::IntRect(0, 0, 0, 0);
     jclass rectClass = env->FindClass("android/graphics/Rect");
     jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
@@ -1688,13 +1620,13 @@ static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
 
 static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
 {
-    const CachedNode* node = getFocusCandidate(env, obj);
+    const CachedNode* node = getFocusCandidate(env, obj, 0);
     return reinterpret_cast<int>(node ? node->nodePointer() : 0);
 }
 
 static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
 {
-    const CachedNode* node = getFocusCandidate(env, obj);
+    const CachedNode* node = getFocusCandidate(env, obj, 0);
     if (!node)
         return 0;
     WebCore::String value = node->getExport();
@@ -1914,7 +1846,7 @@ static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
     SkBitmap bitmap;
     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
     canvas.setBitmapDevice(bitmap);
-    canvas.drawPicture(*(root->getPicture()));
+    root->draw(canvas);
     WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
     // With setMatches, the WebView takes ownership of matches
     view->setMatches(matches);
@@ -1983,7 +1915,7 @@ static void nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
             true);
     if (!next)
         return;
-    const WebCore::IntRect& bounds = next->bounds();
+    const WebCore::IntRect& bounds = next->bounds(frame);
     root->rootHistory()->setMouseBounds(bounds);
     view->updateCursorBounds(root, frame, next);
     root->setCursor(const_cast<CachedFrame*>(frame),
@@ -2052,9 +1984,8 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
             fclose(file);
         }
 #if USE(ACCELERATED_COMPOSITING)
-        int pRootLayer = view->getWebViewCore()->rootLayer();
-        if (pRootLayer) {
-          LayerAndroid* rootLayer = reinterpret_cast<LayerAndroid*>(pRootLayer);
+        const LayerAndroid* rootLayer = view->rootLayer();
+        if (rootLayer) {
           FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
           if (file) {
               rootLayer->dumpLayers(file, 0);
@@ -2092,6 +2023,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
         (void*) nativeCursorIntersects },
     { "nativeCursorIsAnchor", "()Z",
         (void*) nativeCursorIsAnchor },
+    { "nativeCursorIsInLayer", "()Z",
+        (void*) nativeCursorIsInLayer },
     { "nativeCursorIsTextInput", "()Z",
         (void*) nativeCursorIsTextInput },
     { "nativeCursorPosition", "()Landroid/graphics/Point;",
@@ -2108,7 +2041,7 @@ static JNINativeMethod gJavaWebViewMethods[] = {
         (void*) nativeDrawCursorRing },
     { "nativeDestroyLayer", "(I)V",
         (void*) nativeDestroyLayer },
-    { "nativeDrawLayers", "(IIIIIFLandroid/graphics/Canvas;)V",
+    { "nativeDrawLayers", "(ILandroid/graphics/Canvas;)V",
         (void*) nativeDrawLayers },
     { "nativeEvaluateLayersAnimations", "(I)Z",
         (void*) nativeEvaluateLayersAnimations },
@@ -2186,6 +2119,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
         (void*) nativeSetFollowedLink },
     { "nativeSetHeightCanMeasure", "(Z)V",
         (void*) nativeSetHeightCanMeasure },
+    { "nativeSetRootLayer", "(I)V",
+        (void*) nativeSetRootLayer },
     { "nativeTextGeneration", "()I",
         (void*) nativeTextGeneration },
     { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",