Changeset 164449 in webkit


Ignore:
Timestamp:
Feb 20, 2014 3:04:20 PM (10 years ago)
Author:
Alan Bujtas
Message:

Subpixel rendering: Enable compositing RenderLayer painting on device pixel position.
https://bugs.webkit.org/show_bug.cgi?id=128509

Reviewed by Simon Fraser.

GraphicsLayer is now positioned on device pixel boundary. This enables us to put
compositing layers on a subpixel position and animate them with device pixel
precision.

Source/WebCore:

Tests: fast/sub-pixel/compositing-layers-on-subpixel-position.html

fast/sub-pixel/simple-clipping.html

  • platform/LayoutUnit.h:

(WebCore::ceilToDevicePixel):

  • platform/graphics/LayoutPoint.h:

(WebCore::flooredForPainting):
(WebCore::ceiledForPainting):

  • platform/graphics/LayoutRect.cpp:

(WebCore::enclosingRectForPainting):

  • platform/graphics/LayoutRect.h:
  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::clipToRect):

  • rendering/RenderLayerBacking.cpp:

(WebCore::clipBox):
(WebCore::pixelFractionForLayerPainting):
(WebCore::calculateDevicePixelOffsetFromRenderer):
(WebCore::RenderLayerBacking::updateGraphicsLayerGeometry):
(WebCore::RenderLayerBacking::paintIntoLayer):

  • rendering/RenderLayerBacking.h:

LayoutTests:

  • TestExpectations:
  • fast/sub-pixel/compositing-layers-on-subpixel-position-expected.html: Added.
  • fast/sub-pixel/compositing-layers-on-subpixel-position.html: Added.
  • fast/sub-pixel/simple-clipping-expected.html: Added.
  • fast/sub-pixel/simple-clipping.html: Added.
  • platform/mac/compositing/layer-creation/overlap-animation-container-expected.txt:
Location:
trunk
Files:
4 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r164437 r164449  
     12014-02-20  Zalan Bujtas  <zalan@apple.com>
     2
     3        Subpixel rendering: Enable compositing RenderLayer painting on device pixel position.
     4        https://bugs.webkit.org/show_bug.cgi?id=128509
     5
     6        Reviewed by Simon Fraser.
     7
     8        GraphicsLayer is now positioned on device pixel boundary. This enables us to put
     9        compositing layers on a subpixel position and animate them with device pixel
     10        precision.
     11
     12        * TestExpectations:
     13        * fast/sub-pixel/compositing-layers-on-subpixel-position-expected.html: Added.
     14        * fast/sub-pixel/compositing-layers-on-subpixel-position.html: Added.
     15        * fast/sub-pixel/simple-clipping-expected.html: Added.
     16        * fast/sub-pixel/simple-clipping.html: Added.
     17        * platform/mac/compositing/layer-creation/overlap-animation-container-expected.txt:
     18
    1192014-02-20  Mark Hahnenberg  <mhahnenberg@apple.com>
    220
  • trunk/LayoutTests/TestExpectations

    r164437 r164449  
    103103
    104104webkit.org/b/129057 media/controls-styling-strict.html [ Pass Failure ]
     105
     106#subpixel failure on non-retina displays.
     107webkit.org/b/129050 fast/sub-pixel/compositing-layers-on-subpixel-position.html [ Failure ]
     108webkit.org/b/129113 fast/multicol/newmulticol/clipping.html [ Failure ]
  • trunk/LayoutTests/platform/mac/compositing/layer-creation/overlap-animation-container-expected.txt

    r161884 r164449  
    1313        )
    1414        (GraphicsLayer
    15           (position 47.00 229.00)
    16           (bounds 144.00 454.00)
     15          (position 46.00 229.00)
     16          (bounds 146.00 454.00)
    1717          (drawsContent 1)
    1818          (children 1
    1919            (GraphicsLayer
    20               (position 21.00 11.00)
     20              (position 21.13 11.00)
    2121              (bounds 102.00 102.00)
    2222              (transform [1.00 0.00 0.00 0.00] [0.00 1.00 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 -1.00 1.00])
  • trunk/Source/WebCore/ChangeLog

    r164441 r164449  
     12014-02-20  Zalan Bujtas  <zalan@apple.com>
     2
     3        Subpixel rendering: Enable compositing RenderLayer painting on device pixel position.
     4        https://bugs.webkit.org/show_bug.cgi?id=128509
     5
     6        Reviewed by Simon Fraser.
     7
     8        GraphicsLayer is now positioned on device pixel boundary. This enables us to put
     9        compositing layers on a subpixel position and animate them with device pixel
     10        precision.
     11
     12        Tests: fast/sub-pixel/compositing-layers-on-subpixel-position.html
     13               fast/sub-pixel/simple-clipping.html
     14
     15        * platform/LayoutUnit.h:
     16        (WebCore::ceilToDevicePixel):
     17        * platform/graphics/LayoutPoint.h:
     18        (WebCore::flooredForPainting):
     19        (WebCore::ceiledForPainting):
     20        * platform/graphics/LayoutRect.cpp:
     21        (WebCore::enclosingRectForPainting):
     22        * platform/graphics/LayoutRect.h:
     23        * rendering/RenderLayer.cpp:
     24        (WebCore::RenderLayer::clipToRect):
     25        * rendering/RenderLayerBacking.cpp:
     26        (WebCore::clipBox):
     27        (WebCore::pixelFractionForLayerPainting):
     28        (WebCore::calculateDevicePixelOffsetFromRenderer):
     29        (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry):
     30        (WebCore::RenderLayerBacking::paintIntoLayer):
     31        * rendering/RenderLayerBacking.h:
     32
    1332014-02-20  Bem Jones-Bey  <bjonesbe@adobe.com>
    234
  • trunk/Source/WebCore/platform/LayoutUnit.h

    r163278 r164449  
    946946}
    947947
     948inline float ceilToDevicePixel(LayoutUnit value, float pixelSnappingFactor)
     949{
     950    return ceilf((value.rawValue() * pixelSnappingFactor) / kEffectiveFixedPointDenominator) / pixelSnappingFactor;
     951}
     952
    948953inline float snapSizeToDevicePixel(LayoutUnit size, LayoutUnit location, float pixelSnappingFactor)
    949954{
  • trunk/Source/WebCore/platform/graphics/LayoutPoint.h

    r163973 r164449  
    186186}
    187187
     188inline FloatPoint flooredForPainting(const LayoutPoint& point, float pixelSnappingFactor)
     189{
     190#if ENABLE(SUBPIXEL_LAYOUT)
     191    return FloatPoint(floorToDevicePixel(point.x(), pixelSnappingFactor), floorToDevicePixel(point.y(), pixelSnappingFactor));
     192#else
     193    UNUSED_PARAM(pixelSnappingFactor);
     194    return FloatPoint(point);
     195#endif
     196}
     197
     198inline FloatPoint ceiledForPainting(const LayoutPoint& point, float pixelSnappingFactor)
     199{
     200#if ENABLE(SUBPIXEL_LAYOUT)
     201    return FloatPoint(ceilToDevicePixel(point.x(), pixelSnappingFactor), ceilToDevicePixel(point.y(), pixelSnappingFactor));
     202#else
     203    UNUSED_PARAM(pixelSnappingFactor);
     204    return FloatPoint(point);
     205#endif
     206}
     207
    188208inline LayoutPoint roundedLayoutPoint(const FloatPoint& p)
    189209{
  • trunk/Source/WebCore/platform/graphics/LayoutRect.cpp

    r157971 r164449  
    148148}
    149149
     150FloatRect enclosingRectForPainting(const LayoutRect& rect, float pixelSnappingFactor)
     151{
     152    FloatPoint location = flooredForPainting(rect.minXMinYCorner(), pixelSnappingFactor);
     153    FloatPoint maxPoint = ceiledForPainting(rect.maxXMaxYCorner(), pixelSnappingFactor);
     154
     155    return FloatRect(location, maxPoint - location);
     156}
     157
    150158} // namespace WebCore
  • trunk/Source/WebCore/platform/graphics/LayoutRect.h

    r163265 r164449  
    215215IntRect enclosingIntRect(const LayoutRect&);
    216216LayoutRect enclosingLayoutRect(const FloatRect&);
    217 
     217FloatRect enclosingRectForPainting(const LayoutRect&, float pixelSnappingFactor);
    218218
    219219inline IntRect pixelSnappedIntRect(LayoutUnit left, LayoutUnit top, LayoutUnit width, LayoutUnit height)
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r164441 r164449  
    35733573    if (clipRect.rect() != paintDirtyRect || clipRect.hasRadius()) {
    35743574        context->save();
    3575         context->clip(pixelSnappedIntRect(clipRect.rect()));
     3575        context->clip(clipRect.rect());
    35763576    }
    35773577
  • trunk/Source/WebCore/rendering/RenderLayerBacking.cpp

    r164415 r164449  
    643643        result.intersect(renderer.clipRect(LayoutPoint(), 0)); // FIXME: Incorrect for CSS regions.
    644644
    645     return pixelSnappedIntRect(result);
     645    return result;
     646}
     647
     648static FloatSize pixelFractionForLayerPainting(const LayoutPoint& point, float pixelSnappingFactor)
     649{
     650    LayoutUnit x = point.x();
     651    LayoutUnit y = point.y();
     652    x = x >= 0 ? floorToDevicePixel(x, pixelSnappingFactor) : ceilToDevicePixel(x, pixelSnappingFactor);
     653    y = y >= 0 ? floorToDevicePixel(y, pixelSnappingFactor) : ceilToDevicePixel(y, pixelSnappingFactor);
     654    return point - LayoutPoint(x, y);
     655}
     656
     657static void calculateDevicePixelOffsetFromRenderer(const LayoutSize& rendererOffsetFromGraphicsLayer, FloatSize& devicePixelOffsetFromRenderer,
     658    LayoutSize& devicePixelFractionFromRenderer, float deviceScaleFactor)
     659{
     660    devicePixelFractionFromRenderer = LayoutSize(pixelFractionForLayerPainting(toLayoutPoint(rendererOffsetFromGraphicsLayer), deviceScaleFactor));
     661    devicePixelOffsetFromRenderer = rendererOffsetFromGraphicsLayer - devicePixelFractionFromRenderer;
    646662}
    647663
     
    690706    if (compAncestor) {
    691707        ASSERT(compAncestor->backing());
    692         ancestorCompositingBounds = pixelSnappedIntRect(compAncestor->backing()->compositedBounds());
    693     }
    694 
    695     LayoutRect localRawCompositingBounds = compositedBounds();
    696     LayoutPoint rawDelta;
    697     m_owningLayer.convertToLayerCoords(compAncestor, rawDelta, RenderLayer::AdjustForColumns);
    698     IntPoint delta = flooredIntPoint(rawDelta);
    699     m_subpixelAccumulation = toLayoutSize(rawDelta.fraction());
    700     // Move the bounds by the subpixel accumulation so that it pixel-snaps relative to absolute pixels instead of local coordinates.
    701     localRawCompositingBounds.move(m_subpixelAccumulation);
    702 
    703     LayoutRect localCompositingBounds = pixelSnappedIntRect(localRawCompositingBounds);
     708        ancestorCompositingBounds = compAncestor->backing()->compositedBounds();
     709    }
     710
     711    /*
     712    * GraphicsLayer: device pixel positioned. Floored, enclosing rect.
     713    * RenderLayer: subpixel positioned.
     714    * Offset from renderer (GraphicsLayer <-> RenderLayer::renderer()): subpixel based offset.
     715    *
     716    *     relativeCompositingBounds
     717    *      _______________________________________
     718    *     |\          GraphicsLayer               |
     719    *     | \                                     |
     720    *     |  \ offset from renderer: (device pixel + subpixel)
     721    *     |   \                                   |
     722    *     |    \______________________________    |
     723    *     |    | localCompositingBounds       |   |
     724    *     |    |                              |   |
     725    *     |    |   RenderLayer::renderer()    |   |
     726    *     |    |                              |   |
     727    *
     728    * localCompositingBounds: this RenderLayer relative to its renderer().
     729    * relativeCompositingBounds: this RenderLayer relative to its parent compositing layer.
     730    * enclosingRelativeCompositingBounds: this RenderLayer relative to its parent but floored to device pixel position.
     731    * rendererOffsetFromGraphicsLayer: RenderLayer::renderer()'s offset from its enclosing GraphicsLayer.
     732    * devicePixelOffsetFromRenderer: rendererOffsetFromGraphicsLayer's device pixel part. (6.9px -> 6.5px in case of 2x display)
     733    * devicePixelFractionFromRenderer: rendererOffsetFromGraphicsLayer's fractional part (6.9px -> 0.4px in case of 2x display)
     734    */
     735    float deviceScaleFactor = this->deviceScaleFactor();
     736    LayoutRect localCompositingBounds = compositedBounds();
    704737    LayoutRect relativeCompositingBounds(localCompositingBounds);
    705     relativeCompositingBounds.moveBy(delta);
     738
     739    LayoutPoint offsetFromParent;
     740    m_owningLayer.convertToLayerCoords(compAncestor, offsetFromParent, RenderLayer::AdjustForColumns);
     741    relativeCompositingBounds.moveBy(offsetFromParent);
     742
     743    LayoutRect enclosingRelativeCompositingBounds = LayoutRect(enclosingRectForPainting(relativeCompositingBounds, deviceScaleFactor));
     744    LayoutSize subpixelOffsetAdjustment = enclosingRelativeCompositingBounds.location() - relativeCompositingBounds.location();
     745    LayoutSize rendererOffsetFromGraphicsLayer =  toLayoutSize(localCompositingBounds.location()) + subpixelOffsetAdjustment;
     746
     747    FloatSize devicePixelOffsetFromRenderer;
     748    LayoutSize devicePixelFractionFromRenderer;
     749    calculateDevicePixelOffsetFromRenderer(rendererOffsetFromGraphicsLayer, devicePixelOffsetFromRenderer, devicePixelFractionFromRenderer, deviceScaleFactor);
     750    m_devicePixelFractionFromRenderer = LayoutSize(fabs(devicePixelFractionFromRenderer.width().toFloat()), fabs(devicePixelFractionFromRenderer.height().toFloat()));
    706751
    707752    adjustAncestorCompositingBoundsForFlowThread(ancestorCompositingBounds, compAncestor);
     
    742787        // for a compositing layer, rootLayer is the layer itself.
    743788        RenderLayer::ClipRectsContext clipRectsContext(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, IgnoreOverflowClip);
    744         LayoutRect parentClipRect = pixelSnappedIntRect(m_owningLayer.backgroundClipRect(clipRectsContext).rect()); // FIXME: Incorrect for CSS regions.
     789        LayoutRect parentClipRect = m_owningLayer.backgroundClipRect(clipRectsContext).rect(); // FIXME: Incorrect for CSS regions.
    745790        ASSERT(parentClipRect != LayoutRect::infiniteRect());
    746791        m_ancestorClippingLayer->setPosition(FloatPoint(parentClipRect.location() - graphicsLayerParentLocation));
     
    748793
    749794        // backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords.
    750         m_ancestorClippingLayer->setOffsetFromRenderer(parentClipRect.location() - delta);
     795        m_ancestorClippingLayer->setOffsetFromRenderer(parentClipRect.location() - offsetFromParent);
    751796
    752797        // The primary layer is then parented in, and positioned relative to this clipping layer.
     
    754799    }
    755800
    756     LayoutSize contentsSize = relativeCompositingBounds.size();
     801    LayoutSize contentsSize = enclosingRelativeCompositingBounds.size();
    757802   
    758803    if (m_contentsContainmentLayer) {
    759804        m_contentsContainmentLayer->setPreserves3D(preserves3D);
    760         m_contentsContainmentLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation));
     805        m_contentsContainmentLayer->setPosition(FloatPoint(enclosingRelativeCompositingBounds.location() - graphicsLayerParentLocation));
    761806        // Use the same size as m_graphicsLayer so transforms behave correctly.
    762807        m_contentsContainmentLayer->setSize(contentsSize);
    763         graphicsLayerParentLocation = relativeCompositingBounds.location();
    764     }
    765 
    766     m_graphicsLayer->setPosition(FloatPoint(relativeCompositingBounds.location() - graphicsLayerParentLocation));
     808        graphicsLayerParentLocation = enclosingRelativeCompositingBounds.location();
     809    }
     810
     811    m_graphicsLayer->setPosition(FloatPoint(enclosingRelativeCompositingBounds.location() - graphicsLayerParentLocation));
    767812    m_graphicsLayer->setSize(contentsSize);
    768     FloatSize offsetFromRenderer = toLayoutSize(localCompositingBounds.location());
    769     if (offsetFromRenderer != m_graphicsLayer->offsetFromRenderer()) {
    770         m_graphicsLayer->setOffsetFromRenderer(offsetFromRenderer);
     813    if (devicePixelOffsetFromRenderer != m_graphicsLayer->offsetFromRenderer()) {
     814        m_graphicsLayer->setOffsetFromRenderer(devicePixelOffsetFromRenderer);
    771815        positionOverflowControlsLayers();
    772816    }
     
    775819        // For non-root layers, background is always painted by the primary graphics layer.
    776820        ASSERT(!m_backgroundLayer);
    777         bool hadSubpixelRounding = relativeCompositingBounds.size() != localRawCompositingBounds.size();
     821        bool hadSubpixelRounding = !m_devicePixelFractionFromRenderer.isEmpty();
    778822        m_graphicsLayer->setContentsOpaque(!hadSubpixelRounding && m_owningLayer.backgroundIsKnownToBeOpaqueInRect(localCompositingBounds));
    779823    }
     
    798842
    799843        // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds.
    800         LayoutRect layerBounds(delta, borderBox.size());
     844        LayoutRect layerBounds(offsetFromParent, borderBox.size());
    801845
    802846        // Update properties that depend on layer dimensions
    803847        FloatPoint3D transformOrigin = computeTransformOrigin(borderBox);
    804848        // Compute the anchor point, which is in the center of the renderer box unless transform-origin is set.
    805         FloatPoint3D anchor(relativeCompositingBounds.width()  != 0.0f ? ((layerBounds.x() - relativeCompositingBounds.x()) + transformOrigin.x()) / relativeCompositingBounds.width()  : 0.5f,
    806                             relativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - relativeCompositingBounds.y()) + transformOrigin.y()) / relativeCompositingBounds.height() : 0.5f,
    807                             transformOrigin.z());
     849        FloatPoint3D anchor(enclosingRelativeCompositingBounds.width() != 0.0f ? ((layerBounds.x() - enclosingRelativeCompositingBounds.x()) + transformOrigin.x())
     850            / enclosingRelativeCompositingBounds.width() : 0.5f, enclosingRelativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - enclosingRelativeCompositingBounds.y())
     851            + transformOrigin.y()) / enclosingRelativeCompositingBounds.height() : 0.5f, transformOrigin.z());
    808852        if (m_contentsContainmentLayer)
    809853            m_contentsContainmentLayer->setAnchorPoint(anchor);
     
    877921        ASSERT(m_scrollingContentsLayer);
    878922        RenderBox& renderBox = toRenderBox(renderer());
    879         IntRect paddingBox(renderBox.borderLeft(), renderBox.borderTop(), renderBox.width() - renderBox.borderLeft() - renderBox.borderRight(), renderBox.height() - renderBox.borderTop() - renderBox.borderBottom());
    880         IntSize scrollOffset = m_owningLayer.scrollOffset();
     923        LayoutRect paddingBox(renderBox.borderLeft(), renderBox.borderTop(), renderBox.width() - renderBox.borderLeft() - renderBox.borderRight(), renderBox.height() - renderBox.borderTop() - renderBox.borderBottom());
     924        LayoutSize scrollOffset = m_owningLayer.scrollOffset();
    881925
    882926        m_scrollingLayer->setPosition(FloatPoint(paddingBox.location() - localCompositingBounds.location()));
     
    885929#if PLATFORM(IOS)
    886930        FloatSize oldScrollingLayerOffset = m_scrollingLayer->offsetFromRenderer();
    887         m_scrollingLayer->setOffsetFromRenderer(IntPoint() - paddingBox.location());
     931        m_scrollingLayer->setOffsetFromRenderer(FloatPoint() - paddingBox.location());
    888932        bool paddingBoxOffsetChanged = oldScrollingLayerOffset != m_scrollingLayer->offsetFromRenderer();
    889933
     
    915959
    916960        FloatSize oldScrollingLayerOffset = m_scrollingLayer->offsetFromRenderer();
    917         m_scrollingLayer->setOffsetFromRenderer(-toIntSize(paddingBox.location()));
     961        m_scrollingLayer->setOffsetFromRenderer(-toFloatSize(paddingBox.location()));
    918962
    919963        bool paddingBoxOffsetChanged = oldScrollingLayerOffset != m_scrollingLayer->offsetFromRenderer();
     
    923967            m_scrollingContentsLayer->setNeedsDisplay();
    924968
    925         IntSize scrollingContentsOffset = toIntSize(paddingBox.location() - scrollOffset);
     969        LayoutSize scrollingContentsOffset = toLayoutSize(paddingBox.location() - scrollOffset);
    926970        if (scrollingContentsOffset != m_scrollingContentsLayer->offsetFromRenderer() || scrollSize != m_scrollingContentsLayer->size())
    927971            compositor().scrollingLayerDidChange(m_owningLayer);
     
    939983
    940984    // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store.
    941     setRequiresOwnBackingStore(compositor().requiresOwnBackingStore(m_owningLayer, compAncestor, relativeCompositingBounds, ancestorCompositingBounds));
     985    setRequiresOwnBackingStore(compositor().requiresOwnBackingStore(m_owningLayer, compAncestor, enclosingRelativeCompositingBounds, ancestorCompositingBounds));
    942986
    943987    bool didUpdateContentsRect = false;
     
    21622206   
    21632207    // FIXME: GraphicsLayers need a way to split for RenderRegions.
    2164     RenderLayer::LayerPaintingInfo paintingInfo(&m_owningLayer, paintDirtyRect, paintBehavior, m_subpixelAccumulation);
     2208    RenderLayer::LayerPaintingInfo paintingInfo(&m_owningLayer, paintDirtyRect, paintBehavior, m_devicePixelFractionFromRenderer);
    21652209    m_owningLayer.paintLayerContents(context, paintingInfo, paintFlags);
    21662210
  • trunk/Source/WebCore/rendering/RenderLayerBacking.h

    r164415 r164449  
    312312
    313313    LayoutRect m_compositedBounds;
    314     LayoutSize m_subpixelAccumulation; // The accumulated subpixel offset of the compositedBounds compared to absolute coordinates.
     314    LayoutSize m_devicePixelFractionFromRenderer;
    315315
    316316    bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work
Note: See TracChangeset for help on using the changeset viewer.