OSDN Git Service

A couple of fixes for scrolling layers.
authorPatrick Scott <phanna@android.com>
Tue, 15 Feb 2011 16:21:28 +0000 (11:21 -0500)
committerPatrick Scott <phanna@android.com>
Tue, 15 Feb 2011 18:07:49 +0000 (13:07 -0500)
Update the layer structure during compositing sync. Make sure to turn off
scrolling if it changes.

Since I replace the content layer with a different structure, append the
children to the foreground layer so they move with the content. Remove the
clipping layer in the compositor for scrollable layers.

For children of scrollable layers, add back in the content scroll offset so that
layers are positioned relative to 0,0.

Bug: 3416512
Change-Id: I74de90aac2dcf67bd969d0b85f440343123ecab9

WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
WebCore/platform/graphics/android/GraphicsLayerAndroid.h
WebCore/rendering/RenderLayerBacking.cpp
WebCore/rendering/RenderLayerCompositor.cpp
WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp

index e887964..49f20ab 100644 (file)
@@ -271,7 +271,17 @@ void GraphicsLayerAndroid::setPosition(const FloatPoint& point)
     if (point == m_position)
         return;
 
-    GraphicsLayer::setPosition(point);
+    FloatPoint pos(point);
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+    // Add the scroll position back in. When scrolling a layer, all the children
+    // are positioned based on the content scroll. Adding the scroll position
+    // back in allows the children to draw based on 0,0.
+    RenderLayer* layer = renderLayerFromClient(m_client);
+    if (layer && layer->parent() && layer->parent()->hasOverflowScroll())
+        pos += layer->parent()->scrolledContentOffset();
+#endif
+
+    GraphicsLayer::setPosition(pos);
 
 #ifdef LAYER_DEBUG_2
     LOG("(%x) setPosition(%.2f,%.2f) pos(%.2f, %.2f) anchor(%.2f,%.2f) size(%.2f, %.2f)",
@@ -279,7 +289,7 @@ void GraphicsLayerAndroid::setPosition(const FloatPoint& point)
         m_anchorPoint.x(), m_anchorPoint.y(), m_size.width(), m_size.height());
 #endif
     updateFixedPosition();
-    m_contentLayer->setPosition(point.x(), point.y());
+    m_contentLayer->setPosition(pos.x(), pos.y());
     askForSync();
 }
 
@@ -368,31 +378,6 @@ void GraphicsLayerAndroid::setDrawsContent(bool drawsContent)
     if (m_contentLayer->isRootLayer())
         return;
     if (m_drawsContent) {
-#if ENABLE(ANDROID_OVERFLOW_SCROLL)
-        RenderLayer* layer = renderLayerFromClient(m_client);
-        if (layer) {
-            if (layer->hasOverflowScroll() && !m_foregroundLayer) {
-                m_foregroundLayer = new ScrollableLayerAndroid();
-                m_foregroundClipLayer = new LayerAndroid(false);
-                m_foregroundClipLayer->setMasksToBounds(true);
-
-                m_foregroundClipLayer->addChild(m_foregroundLayer);
-                m_contentLayer->addChild(m_foregroundClipLayer);
-            } else if (layer->isRootLayer()
-                       && layer->renderer()->frame()->ownerRenderer()) {
-                // We have to do another check for scrollable content since an
-                // iframe might be compositing for other reasons.
-                FrameView* view = layer->renderer()->frame()->view();
-                if (view->hasOverflowScroll()) {
-                    // Replace the content layer with a scrollable layer.
-                    LayerAndroid* layer = new ScrollableLayerAndroid(*m_contentLayer);
-                    m_contentLayer->unref();
-                    m_contentLayer = layer;
-                }
-            }
-        }
-#endif
-
         m_haveContents = true;
         setNeedsDisplay();
     }
@@ -478,6 +463,79 @@ private:
     GraphicsLayerPaintingPhase m_originalPhase;
 };
 
+void GraphicsLayerAndroid::updateScrollingLayers()
+{
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+    RenderLayer* layer = renderLayerFromClient(m_client);
+    if (!layer)
+        return;
+    bool hasOverflowScroll = m_foregroundLayer || m_contentLayer->contentIsScrollable();
+    bool layerNeedsOverflow = layer->hasOverflowScroll();
+    bool iframeNeedsOverflow = layer->isRootLayer() &&
+        layer->renderer()->frame()->ownerRenderer() &&
+        layer->renderer()->frame()->view()->hasOverflowScroll();
+
+    if (hasOverflowScroll && (layerNeedsOverflow || iframeNeedsOverflow)) {
+        // Already has overflow layers.
+        return;
+    }
+    if (!hasOverflowScroll && !layerNeedsOverflow && !iframeNeedsOverflow) {
+        // Does not need overflow layers.
+        return;
+    }
+    if (layerNeedsOverflow || iframeNeedsOverflow) {
+        ASSERT(!hasOverflowScroll);
+        if (layerNeedsOverflow) {
+            ASSERT(!m_foregroundLayer && !m_foregroundClipLayer);
+            m_foregroundLayer = new ScrollableLayerAndroid();
+            m_foregroundClipLayer = new LayerAndroid(false);
+            m_foregroundClipLayer->setMasksToBounds(true);
+            m_foregroundClipLayer->addChild(m_foregroundLayer);
+            m_contentLayer->addChild(m_foregroundClipLayer);
+        } else {
+            ASSERT(iframeNeedsOverflow && !m_contentLayer->contentIsScrollable());
+            // No need to copy the children as they will be removed and synced.
+            m_contentLayer->removeChildren();
+            // Replace the content layer with a scrollable layer.
+            LayerAndroid* layer = new ScrollableLayerAndroid(*m_contentLayer);
+            m_contentLayer->unref();
+            m_contentLayer = layer;
+            if (m_parent) {
+                // The content layer has changed so the parent needs to sync
+                // children.
+                static_cast<GraphicsLayerAndroid*>(m_parent)->m_needsSyncChildren = true;
+            }
+        }
+        // Need to rebuild our children based on the new structure.
+        m_needsSyncChildren = true;
+        askForSync();
+    } else {
+        ASSERT(hasOverflowScroll && !layerNeedsOverflow && !iframeNeedsOverflow);
+        ASSERT(m_contentLayer);
+        // Remove the foreground layers.
+        if (m_foregroundLayer) {
+            m_foregroundLayer->unref();
+            m_foregroundLayer = 0;
+            m_foregroundClipLayer->unref();
+            m_foregroundClipLayer = 0;
+        }
+        // No need to copy over children.
+        m_contentLayer->removeChildren();
+        LayerAndroid* layer = new LayerAndroid(*m_contentLayer);
+        m_contentLayer->unref();
+        m_contentLayer = layer;
+        if (m_parent) {
+            // The content layer has changed so the parent needs to sync
+            // children.
+            static_cast<GraphicsLayerAndroid*>(m_parent)->m_needsSyncChildren = true;
+        }
+        // Children are all re-parented.
+        m_needsSyncChildren = true;
+        askForSync();
+    }
+#endif
+}
+
 bool GraphicsLayerAndroid::repaint()
 {
     LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ",
@@ -506,8 +564,13 @@ bool GraphicsLayerAndroid::repaint()
             m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height());
             // Paint everything else into the main recording canvas.
             phase.clear(GraphicsLayerPaintBackground);
-            if (!paintContext(m_foregroundLayer->recordContext(), contentsRect))
-                return false;
+
+            // Paint at 0,0.
+            IntSize scroll = layer->scrolledContentOffset();
+            layer->scrollToOffset(0, 0, true, false);
+            // At this point, it doesn't matter if painting failed.
+            (void) paintContext(m_foregroundLayer->recordContext(), contentsRect);
+            layer->scrollToOffset(scroll.width(), scroll.height(), true, false);
 
             // Construct the clip layer for masking the contents.
             IntRect clip = layer->renderer()->absoluteBoundingBoxRect();
@@ -830,10 +893,16 @@ void GraphicsLayerAndroid::syncChildren()
 {
     if (m_needsSyncChildren) {
         m_contentLayer->removeChildren();
-        if (m_foregroundClipLayer)
+        LayerAndroid* layer = m_contentLayer;
+        if (m_foregroundClipLayer) {
             m_contentLayer->addChild(m_foregroundClipLayer);
+            // Use the scrollable content layer as the parent of the children so
+            // that they move with the content.
+            layer = m_foregroundLayer;
+            layer->removeChildren();
+        }
         for (unsigned int i = 0; i < m_children.size(); i++)
-            m_contentLayer->addChild(m_children[i]->platformLayer());
+            layer->addChild(m_children[i]->platformLayer());
         m_needsSyncChildren = false;
     }
 }
@@ -857,6 +926,7 @@ void GraphicsLayerAndroid::syncCompositingState()
     for (unsigned int i = 0; i < m_children.size(); i++)
         m_children[i]->syncCompositingState();
 
+    updateScrollingLayers();
     syncChildren();
     syncMask();
 
index ce6bac1..da247ca 100644 (file)
@@ -127,6 +127,7 @@ private:
     void syncMask();
 
     void updateFixedPosition();
+    void updateScrollingLayers();
 
     // with SkPicture, we always repaint the entire layer's content.
     bool repaint();
index 48aa3ec..0d39f7a 100644 (file)
@@ -1021,14 +1021,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
     bool selectionOnly  = paintBehavior & PaintBehaviorSelectionOnly;
 
     if (shouldPaint && (paintingPhase & GraphicsLayerPaintForeground)) {
-#if ENABLE(ANDROID_OVERFLOW_SCROLL)
-        // Scroll to 0,0 and paint the entire contents, then scroll back the
-        // the original offset.
-        int x = m_owningLayer->scrollXOffset();
-        int y = m_owningLayer->scrollYOffset();
-        if (m_owningLayer->hasOverflowScroll())
-            m_owningLayer->scrollToOffset(0, 0, false, false);
-#endif
         // Set up the clip used when painting our children.
         setClip(context, paintDirtyRect, clipRectToApply);
         PaintInfo paintInfo(context, clipRectToApply, 
@@ -1067,10 +1059,6 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
 
         // Now walk the sorted list of children with positive z-indices.
         m_owningLayer->paintList(m_owningLayer->posZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, 0, 0);
-#if ENABLE(ANDROID_OVERFLOW_SCROLL)
-        if (m_owningLayer->hasOverflowScroll())
-            m_owningLayer->scrollToOffset(x, y, false, false);
-#endif
     }
     
     if (shouldPaint && (paintingPhase & GraphicsLayerPaintMask)) {
index f31ab9d..9775134 100644 (file)
@@ -1288,6 +1288,10 @@ bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const
 // into the hierarchy between this layer and its children in the z-order hierarchy.
 bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const
 {
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+    if (layer->hasOverflowScroll())
+        return false;
+#endif
     return layer->hasCompositingDescendant() &&
            (layer->renderer()->hasOverflowClip() || layer->renderer()->hasClip());
 }
index fb5701a..980c03e 100644 (file)
@@ -87,8 +87,6 @@ void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::Grap
 {
     // frame is not used in Android as we should only get root graphics layer for the main frame
     m_rootGraphicsLayer = layer;
-    if (!layer)
-        return;
     scheduleCompositingLayerSync();
 }