2011-01-12 Chris Marrin <cmarrin@apple.com>
authorcmarrin@apple.com <cmarrin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jan 2011 22:27:27 +0000 (22:27 +0000)
committercmarrin@apple.com <cmarrin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jan 2011 22:27:27 +0000 (22:27 +0000)
        Reviewed by Simon Fraser.

        Pages with accelerated layers lose subpixel-AA and become blurry when a scale factor is applied
        rdar://problem/8824974

        When scaled, WebKit renders the page content at the scaled up size, so there are no
        scaling artifacts. But content drawn into a layer's backing store does not scale up.
        This is made worse by the fact that the root page contents become layered when there
        are other accelerated compositing layers present (video, plugins, etc.).

        Plumb scaling factor from Frame::scalePage() down into all layers with content. It
        eventually calls CALayer::setContentsScale which renders to a backing store whose dimensions
        are scaled, causing them to render larger and appear pixel perfect at the scaled
        page size.

         * page/Frame.cpp:
         (WebCore::Frame::updateContentsScale):
         (WebCore::Frame::scalePage):
         * page/Frame.h:
         * platform/graphics/GraphicsLayer.h:
         * platform/graphics/ca/GraphicsLayerCA.cpp:
         (WebCore::GraphicsLayerCA::setContentsScale):
         (WebCore::GraphicsLayerCA::clampedContentsScaleForScale):
         * platform/graphics/ca/GraphicsLayerCA.h:
         (WebCore::GraphicsLayerCA::contentsScale):
         * platform/graphics/ca/PlatformCALayer.h:
         * platform/graphics/ca/mac/PlatformCALayerMac.mm:
         (PlatformCALayer::contentsScale):
         (PlatformCALayer::setContentsScale):
         * rendering/RenderLayer.cpp:
         (WebCore::RenderLayer::updateContentsScale):
         * rendering/RenderLayer.h:
         * rendering/RenderLayerBacking.cpp:
         (WebCore::RenderLayerBacking::createGraphicsLayer):
         (WebCore::RenderLayerBacking::updateForegroundLayer):
         (WebCore::RenderLayerBacking::updateMaskLayer):
         (WebCore::RenderLayerBacking::updateContentsScale):
         * rendering/RenderLayerBacking.h:
         * rendering/RenderLayerCompositor.cpp:
         (WebCore::RenderLayerCompositor::updateContentsScale):
         * rendering/RenderLayerCompositor.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@75639 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/Frame.cpp
Source/WebCore/page/Frame.h
Source/WebCore/platform/graphics/GraphicsLayer.h
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h
Source/WebCore/platform/graphics/ca/PlatformCALayer.h
Source/WebCore/platform/graphics/ca/mac/PlatformCALayerMac.mm
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerBacking.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h

index b23c4ad..d7b4c77 100644 (file)
@@ -1,3 +1,47 @@
+2011-01-12  Chris Marrin  <cmarrin@apple.com>
+
+        Reviewed by Simon Fraser.
+        
+        Pages with accelerated layers lose subpixel-AA and become blurry when a scale factor is applied
+        rdar://problem/8824974
+
+        When scaled, WebKit renders the page content at the scaled up size, so there are no
+        scaling artifacts. But content drawn into a layer's backing store does not scale up.
+        This is made worse by the fact that the root page contents become layered when there
+        are other accelerated compositing layers present (video, plugins, etc.).
+        
+        Plumb scaling factor from Frame::scalePage() down into all layers with content. It
+        eventually calls CALayer::setContentsScale which renders to a backing store whose dimensions
+        are scaled, causing them to render larger and appear pixel perfect at the scaled
+        page size.
+         * page/Frame.cpp:
+         (WebCore::Frame::updateContentsScale):
+         (WebCore::Frame::scalePage):
+         * page/Frame.h:
+         * platform/graphics/GraphicsLayer.h:
+         * platform/graphics/ca/GraphicsLayerCA.cpp:
+         (WebCore::GraphicsLayerCA::setContentsScale):
+         (WebCore::GraphicsLayerCA::clampedContentsScaleForScale):
+         * platform/graphics/ca/GraphicsLayerCA.h:
+         (WebCore::GraphicsLayerCA::contentsScale):
+         * platform/graphics/ca/PlatformCALayer.h:
+         * platform/graphics/ca/mac/PlatformCALayerMac.mm:
+         (PlatformCALayer::contentsScale):
+         (PlatformCALayer::setContentsScale):
+         * rendering/RenderLayer.cpp:
+         (WebCore::RenderLayer::updateContentsScale):
+         * rendering/RenderLayer.h:
+         * rendering/RenderLayerBacking.cpp:
+         (WebCore::RenderLayerBacking::createGraphicsLayer):
+         (WebCore::RenderLayerBacking::updateForegroundLayer):
+         (WebCore::RenderLayerBacking::updateMaskLayer):
+         (WebCore::RenderLayerBacking::updateContentsScale):
+         * rendering/RenderLayerBacking.h:
+         * rendering/RenderLayerCompositor.cpp:
+         (WebCore::RenderLayerCompositor::updateContentsScale):
+         * rendering/RenderLayerCompositor.h:
 2011-01-12  Stephen White  <senorblanco@chromium.org>
 
         Reviewed by James Robinson.
index e6f4866..afff62e 100644 (file)
@@ -975,6 +975,16 @@ void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor
     }
 }
 
+void Frame::updateContentsScale(float scale)
+{
+    for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+        child->updateContentsScale(scale);
+
+    RenderView* root = contentRenderer();
+    if (root && root->compositor())
+        root->compositor()->updateContentsScale(scale);
+}
+
 void Frame::scalePage(float scale, const IntPoint& origin)
 {
     Document* document = this->document();
@@ -988,6 +998,8 @@ void Frame::scalePage(float scale, const IntPoint& origin)
 
     document->recalcStyle(Node::Force);
 
+    updateContentsScale(scale);
+
     if (FrameView* view = this->view()) {
         if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
             view->layout();
index 7741a82..540c1a8 100644 (file)
@@ -208,6 +208,8 @@ namespace WebCore {
         void injectUserScriptsForWorld(DOMWrapperWorld*, const UserScriptVector&, UserScriptInjectionTime);
         void lifeSupportTimerFired(Timer<Frame>*);
 
+        void updateContentsScale(float);
+
         HashSet<FrameDestructionObserver*> m_destructionObservers;
 
         Page* m_page;
index fdc8811..f3ddea2 100644 (file)
@@ -316,6 +316,11 @@ public:
     // For hosting this GraphicsLayer in a native layer hierarchy.
     virtual PlatformLayer* platformLayer() const { return 0; }
     
+    // Change the scale at which the contents are rendered. Note that contentsScale may not return
+    // the same value passed to setContentsScale(), because of clamping and hysteresis.
+    virtual float contentsScale() const = 0;
+    virtual void setContentsScale(float) = 0;
+
     void dumpLayer(TextStream&, int indent = 0, LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const;
 
     int repaintCount() const { return m_repaintCount; }
index 37385c0..f131436 100644 (file)
@@ -1897,6 +1897,43 @@ GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedProperty
     return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones();
 }
 
+void GraphicsLayerCA::setContentsScale(float scale)
+{
+    float newScale = clampedContentsScaleForScale(scale);
+    if (newScale == m_contentsScale)
+        return;
+
+    m_contentsScale = newScale;
+    noteLayerPropertyChanged(ContentsScaleChanged);
+}
+
+float GraphicsLayerCA::clampedContentsScaleForScale(float scale) const
+{
+    // Define some limits as a sanity check for the incoming scale value
+    // those too small to see.
+    const float maxScale = 5.0f;
+    const float minScale = 0.01f;
+    
+    // Avoid very slight scale changes that would be doing extra work for no benefit
+    const float maxAllowableDelta = 0.05;
+
+    // Clamp
+    float result = max(minScale, min(scale, maxScale));
+
+    // If it hasn't changed much, don't do any work
+    return ((fabs(result - m_contentsScale) / m_contentsScale) < maxAllowableDelta) ? m_contentsScale : result;
+}
+
+void GraphicsLayerCA::updateContentsScale()
+{
+    bool needTiledLayer = requiresTiledLayer(m_size);
+    if (needTiledLayer != m_usingTiledLayer)
+        swapFromOrToTiledLayer(needTiledLayer);
+
+    m_layer->setContentsScale(m_contentsScale);
+    m_layer->setNeedsDisplay();
+}
+
 void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
 {    
     if (color.isValid())
@@ -1950,9 +1987,7 @@ bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
 
 void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
 {
-    if (useTiledLayer == m_usingTiledLayer)
-        return;
-
+    ASSERT(useTiledLayer != m_usingTiledLayer);
     RefPtr<PlatformCALayer> oldLayer = m_layer;
     
     m_layer = PlatformCALayer::create(useTiledLayer ? PlatformCALayer::LayerTypeWebTiledLayer : PlatformCALayer::LayerTypeWebLayer, this);
index 13cbdd1..2c39c0a 100644 (file)
@@ -56,6 +56,9 @@ public:
     virtual PlatformLayer* platformLayer() const;
     virtual PlatformCALayer* platformCALayer() const { return primaryLayer(); }
 
+    virtual float contentsScale() const { return m_contentsScale; }
+    virtual void setContentsScale(float);
+
     virtual bool setChildren(const Vector<GraphicsLayer*>&);
     virtual void addChild(GraphicsLayer*);
     virtual void addChildAtIndex(GraphicsLayer*, int index);
@@ -278,6 +281,7 @@ private:
     void updateLayerAnimations();
     void updateContentsNeedsDisplay();
     void updateAcceleratesDrawing();
+    void updateContentsScale();
     
     enum StructuralLayerPurpose {
         NoStructuralLayer = 0,
@@ -320,7 +324,8 @@ private:
         MaskLayerChanged = 1 << 21,
         ReplicatedLayerChanged = 1 << 22,
         ContentsNeedsDisplay = 1 << 23,
-        AcceleratesDrawingChanged = 1 << 24
+        AcceleratesDrawingChanged = 1 << 24,
+        ContentsScaleChanged = 1 << 25
     };
     typedef unsigned LayerChangeFlags;
     void noteLayerPropertyChanged(LayerChangeFlags flags);
@@ -391,6 +396,9 @@ private:
     Vector<FloatRect> m_dirtyRects;
     
     LayerChangeFlags m_uncommittedChanges;
+
+    float clampedContentsScaleForScale(float) const;
+    float m_contentsScale;
 };
 
 } // namespace WebCore
index 46f4bbf..68566b3 100644 (file)
@@ -182,6 +182,9 @@ public:
 
     CFTimeInterval timeOffset() const;
     void setTimeOffset(CFTimeInterval);
+    
+    float contentsScale() const;
+    void setContentsScale(float);
 
 #if PLATFORM(WIN) && !defined(NDEBUG)
     void printTree() const;
index 28460a7..ed04972 100644 (file)
@@ -723,4 +723,22 @@ void PlatformCALayer::setTimeOffset(CFTimeInterval value)
     END_BLOCK_OBJC_EXCEPTIONS
 }
 
+float PlatformCALayer::contentsScale() const
+{
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    return [m_layer.get() contentsScale];
+#else
+    return 1;
+#endif
+}
+
+void PlatformCALayer::setContentsScale(float value)
+{
+#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+    BEGIN_BLOCK_OBJC_EXCEPTIONS
+    [m_layer.get() setContentsScale:value];
+    END_BLOCK_OBJC_EXCEPTIONS
+#endif
+}
+
 #endif // USE(ACCELERATED_COMPOSITING)
index ed4639e..633ce7a 100644 (file)
@@ -3936,6 +3936,14 @@ void RenderLayer::updateReflectionStyle()
     m_reflection->setStyle(newStyle.release());
 }
 
+void RenderLayer::updateContentsScale(float scale)
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (m_backing)
+        m_backing->updateContentsScale(scale);
+#endif
+}
+
 } // namespace WebCore
 
 #ifndef NDEBUG
index e4be767..04fbe3f 100644 (file)
@@ -574,6 +574,8 @@ private:
     void setMustOverlapCompositedLayers(bool b) { m_mustOverlapCompositedLayers = b; }
 #endif
 
+    void updateContentsScale(float);
+
 private:
     friend class RenderLayerBacking;
     friend class RenderLayerCompositor;
index 112f348..ddb95c1 100644 (file)
@@ -105,6 +105,12 @@ void RenderLayerBacking::createGraphicsLayer()
     m_graphicsLayer->setName(nameForLayer());
 #endif  // NDEBUG
 
+#if USE(ACCELERATED_COMPOSITING)
+    ASSERT(renderer() && renderer()->document() && renderer()->document()->frame());
+    if (Frame* frame = renderer()->document()->frame())
+        m_graphicsLayer->setContentsScale(frame->pageScaleFactor());
+#endif
+
     updateLayerOpacity(renderer()->style());
     updateLayerTransform(renderer()->style());
 }
@@ -543,6 +549,8 @@ bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
 #endif
             m_foregroundLayer->setDrawsContent(true);
             m_foregroundLayer->setPaintingPhase(GraphicsLayerPaintForeground);
+            if (Frame* frame = renderer()->document()->frame())
+                m_foregroundLayer->setContentsScale(frame->pageScaleFactor());
             layerChanged = true;
         }
     } else if (m_foregroundLayer) {
@@ -568,6 +576,8 @@ bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer)
 #endif
             m_maskLayer->setDrawsContent(true);
             m_maskLayer->setPaintingPhase(GraphicsLayerPaintMask);
+            if (Frame* frame = renderer()->document()->frame())
+                m_maskLayer->setContentsScale(frame->pageScaleFactor());
             layerChanged = true;
         }
     } else if (m_maskLayer) {
@@ -1340,6 +1350,18 @@ CompositingLayerType RenderLayerBacking::compositingLayerType() const
     return ContainerCompositingLayer;
 }
 
+void RenderLayerBacking::updateContentsScale(float scale)
+{
+    if (m_graphicsLayer)
+        m_graphicsLayer->setContentsScale(scale);
+
+    if (m_foregroundLayer)
+        m_foregroundLayer->setContentsScale(scale);
+
+    if (m_maskLayer)
+        m_maskLayer->setContentsScale(scale);
+}
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
index c5489f3..5c6ed12 100644 (file)
@@ -139,6 +139,8 @@ public:
     // For informative purposes only.
     CompositingLayerType compositingLayerType() const;
     
+    void updateContentsScale(float);
+
 private:
     void createGraphicsLayer();
     void destroyGraphicsLayer();
index de6cef2..931008d 100644 (file)
@@ -1574,6 +1574,34 @@ bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const
     return false;
 }
 
+void RenderLayerCompositor::updateContentsScale(float scale, RenderLayer* layer)
+{
+    if (!layer)
+        layer = rootRenderLayer();
+
+    layer->updateContentsScale(scale);
+
+    if (layer->isStackingContext()) {
+        if (Vector<RenderLayer*>* negZOrderList = layer->negZOrderList()) {
+            size_t listSize = negZOrderList->size();
+            for (size_t i = 0; i < listSize; ++i)
+                updateContentsScale(scale, negZOrderList->at(i));
+        }
+
+        if (Vector<RenderLayer*>* posZOrderList = layer->posZOrderList()) {
+            size_t listSize = posZOrderList->size();
+            for (size_t i = 0; i < listSize; ++i)
+                updateContentsScale(scale, posZOrderList->at(i));
+        }
+    }
+
+    if (Vector<RenderLayer*>* normalFlowList = layer->normalFlowList()) {
+        size_t listSize = normalFlowList->size();
+        for (size_t i = 0; i < listSize; ++i)
+            updateContentsScale(scale, normalFlowList->at(i));
+    }
+}
+
 } // namespace WebCore
 
 #endif // USE(ACCELERATED_COMPOSITING)
index 6218c04..49759b5 100644 (file)
@@ -174,6 +174,8 @@ public:
     bool compositorShowDebugBorders() const { return m_showDebugBorders; }
     bool compositorShowRepaintCounter() const { return m_showRepaintCounter; }
 
+    void updateContentsScale(float, RenderLayer* = 0);
+
 private:
     // GraphicsLayerClient Implementation
     virtual void notifyAnimationStarted(const GraphicsLayer*, double) { }