Changeset 171210 in webkit


Ignore:
Timestamp:
Jul 17, 2014 6:56:12 PM (10 years ago)
Author:
Alan Bujtas
Message:

Subpixel rendering: Embedded non-compositing rotate transform paints to wrong position.
https://bugs.webkit.org/show_bug.cgi?id=135028

Reviewed by Simon Fraser.

CTM always translates to where the layer's renderer() is going to paint.
It ensures that the pixel snapped renderer() always end up painting to (0, 0) which is
required to be able to position properly on transformed context.

Source/WebCore:
Test: fast/layers/hidpi-transform-on-child-content-is-mispositioned.html

  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::beginTransparencyLayers):
(WebCore::RenderLayer::clipToRect):
(WebCore::RenderLayer::paintLayerByApplyingTransform):
(WebCore::RenderLayer::paintBackgroundForFragments):
(WebCore::RenderLayer::paintForegroundForFragmentsWithPhase):
(WebCore::RenderLayer::paintOutlineForFragments):
(WebCore::RenderLayer::paintMaskForFragments):
(WebCore::RenderLayer::paintOverflowControlsForFragments):
(WebCore::RenderLayer::calculateClipRects):

  • rendering/RenderLayer.h:

LayoutTests:

  • fast/layers/hidpi-transform-on-child-content-is-mispositioned-expected.html: Added.
  • fast/layers/hidpi-transform-on-child-content-is-mispositioned.html: Added.
Location:
trunk
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r171198 r171210  
     12014-07-17  Zalan Bujtas  <zalan@apple.com>
     2
     3        Subpixel rendering: Embedded non-compositing rotate transform paints to wrong position.
     4        https://bugs.webkit.org/show_bug.cgi?id=135028
     5
     6        Reviewed by Simon Fraser.
     7
     8        CTM always translates to where the layer's renderer() is going to paint.
     9        It ensures that the pixel snapped renderer() always end up painting to (0, 0) which is
     10        required to be able to position properly on transformed context.
     11
     12        * fast/layers/hidpi-transform-on-child-content-is-mispositioned-expected.html: Added.
     13        * fast/layers/hidpi-transform-on-child-content-is-mispositioned.html: Added.
     14
    1152014-07-17  Alexey Proskuryakov  <ap@apple.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r171207 r171210  
     12014-07-17  Zalan Bujtas  <zalan@apple.com>
     2
     3        Subpixel rendering: Embedded non-compositing rotate transform paints to wrong position.
     4        https://bugs.webkit.org/show_bug.cgi?id=135028
     5
     6        Reviewed by Simon Fraser.
     7
     8        CTM always translates to where the layer's renderer() is going to paint.
     9        It ensures that the pixel snapped renderer() always end up painting to (0, 0) which is
     10        required to be able to position properly on transformed context.
     11
     12        Test: fast/layers/hidpi-transform-on-child-content-is-mispositioned.html
     13
     14        * rendering/RenderLayer.cpp:
     15        (WebCore::RenderLayer::beginTransparencyLayers):
     16        (WebCore::RenderLayer::clipToRect):
     17        (WebCore::RenderLayer::paintLayerByApplyingTransform):
     18        (WebCore::RenderLayer::paintBackgroundForFragments):
     19        (WebCore::RenderLayer::paintForegroundForFragmentsWithPhase):
     20        (WebCore::RenderLayer::paintOutlineForFragments):
     21        (WebCore::RenderLayer::paintMaskForFragments):
     22        (WebCore::RenderLayer::paintOverflowControlsForFragments):
     23        (WebCore::RenderLayer::calculateClipRects):
     24        * rendering/RenderLayer.h:
     25
    1262014-07-17  Beth Dakin  <bdakin@apple.com>
    227
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r171074 r171210  
    16951695        context->save();
    16961696        LayoutRect adjustedClipRect = paintingExtent(*this, paintingInfo.rootLayer, dirtyRect, paintingInfo.paintBehavior);
    1697         adjustedClipRect.move(paintingInfo.subPixelAccumulation);
     1697        adjustedClipRect.move(paintingInfo.subpixelAccumulation);
    16981698        FloatRect pixelSnappedClipRect = pixelSnappedForPainting(adjustedClipRect, renderer().document().deviceScaleFactor());
    16991699        context->clip(pixelSnappedClipRect);
     
    35903590        context->save();
    35913591        LayoutRect adjustedClipRect = clipRect.rect();
    3592         adjustedClipRect.move(paintingInfo.subPixelAccumulation);
     3592        adjustedClipRect.move(paintingInfo.subpixelAccumulation);
    35933593        context->clip(pixelSnappedForPainting(adjustedClipRect, deviceScaleFactor));
    35943594    }
     
    36033603        if (layer->renderer().hasOverflowClip() && layer->renderer().style().hasBorderRadius() && inContainingBlockChain(this, layer)) {
    36043604            LayoutRect adjustedClipRect = LayoutRect(toLayoutPoint(layer->offsetFromAncestor(paintingInfo.rootLayer)), layer->size());
    3605             adjustedClipRect.move(paintingInfo.subPixelAccumulation);
     3605            adjustedClipRect.move(paintingInfo.subpixelAccumulation);
    36063606            context->clipRoundedRect(layer->renderer().style().getRoundedInnerBorderFor(adjustedClipRect).pixelSnappedRoundedRectForPainting(deviceScaleFactor));
    36073607        }
     
    41504150    offsetFromParent += translationOffset;
    41514151    TransformationMatrix transform(renderableTransform(paintingInfo.paintBehavior));
    4152     FloatSize devicePixelSnappedOffsetFromParent = toFloatSize(roundedForPainting(toLayoutPoint(offsetFromParent), deviceScaleFactor));
     4152    // Add the subpixel accumulation to the current layer's offset so that we can always snap the translateRight value to where the renderer() is supposed to be painting.
     4153    LayoutSize offsetForThisLayer = offsetFromParent + paintingInfo.subpixelAccumulation;
     4154    FloatSize devicePixelSnappedOffsetForThisLayer = toFloatSize(roundedForPainting(toLayoutPoint(offsetForThisLayer), deviceScaleFactor));
     4155    // We handle accumulated subpixels through nested layers here. Since the context gets translated to device pixels,
     4156    // all we need to do is add the delta to the accumulated pixels coming from ancestor layers.
    41534157    // Translate the graphics context to the snapping position to avoid off-device-pixel positing.
    4154     transform.translateRight(devicePixelSnappedOffsetFromParent.width(), devicePixelSnappedOffsetFromParent.height());
    4155     // We handle accumulated subpixels through nested layers here. Since the context gets translated to device pixels,
    4156     // all we need to do is add the delta to the accumulated pixels coming from ancestor layers. With deep nesting of subpixel positioned
    4157     // boxes, this could grow to a relatively large number, but the translateRight() balances it.
    4158     FloatSize delta = offsetFromParent - devicePixelSnappedOffsetFromParent;
    4159     LayoutSize adjustedSubPixelAccumulation = paintingInfo.subPixelAccumulation + LayoutSize(delta);
     4158    transform.translateRight(devicePixelSnappedOffsetForThisLayer.width(), devicePixelSnappedOffsetForThisLayer.height());
    41604159    // Apply the transform.
    41614160    GraphicsContextStateSaver stateSaver(*context);
     
    41634162
    41644163    // Now do a paint with the root layer shifted to be us.
    4165     LayerPaintingInfo transformedPaintingInfo(this, LayoutRect(enclosingRectForPainting(transform.inverse().mapRect(paintingInfo.paintDirtyRect), deviceScaleFactor)), paintingInfo.paintBehavior,
    4166         adjustedSubPixelAccumulation, paintingInfo.subtreePaintRoot, paintingInfo.overlapTestRequests);
     4164    LayoutSize adjustedSubpixelAccumulation = offsetForThisLayer - LayoutSize(devicePixelSnappedOffsetForThisLayer);
     4165    LayerPaintingInfo transformedPaintingInfo(this, LayoutRect(enclosingRectForPainting(transform.inverse().mapRect(paintingInfo.paintDirtyRect), deviceScaleFactor)),
     4166        paintingInfo.paintBehavior, adjustedSubpixelAccumulation, paintingInfo.subtreePaintRoot, paintingInfo.overlapTestRequests);
    41674167    paintLayerContentsAndReflection(context, transformedPaintingInfo, paintFlags);
    41684168}
     
    44204420        // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
    44214421        PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhaseBlockBackground, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer());
    4422         renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
     4422        renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelAccumulation));
    44234423
    44244424        if (localPaintingInfo.clipToDirtyRect)
     
    44954495        if (phase == PaintPhaseForeground)
    44964496            paintInfo.overlapTestRequests = localPaintingInfo.overlapTestRequests;
    4497         renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
     4497        renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelAccumulation));
    44984498       
    44994499        if (shouldClip)
     
    45134513        PaintInfo paintInfo(context, fragment.outlineRect.rect(), PaintPhaseSelfOutline, paintBehavior, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer());
    45144514        clipToRect(localPaintingInfo, context, fragment.outlineRect, DoNotIncludeSelfForBorderRadius);
    4515         renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
     4515        renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelAccumulation));
    45164516        restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.outlineRect);
    45174517    }
     
    45324532        // FIXME: Eventually we will collect the region from the fragment itself instead of just from the paint info.
    45334533        PaintInfo paintInfo(context, fragment.backgroundRect.rect(), PaintPhaseMask, PaintBehaviorNormal, subtreePaintRootForRenderer, nullptr, nullptr, &localPaintingInfo.rootLayer->renderer());
    4534         renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation));
     4534        renderer().paint(paintInfo, toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelAccumulation));
    45354535       
    45364536        if (localPaintingInfo.clipToDirtyRect)
     
    45444544        const LayerFragment& fragment = layerFragments.at(i);
    45454545        clipToRect(localPaintingInfo, context, fragment.backgroundRect);
    4546         paintOverflowControls(context, roundedIntPoint(toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subPixelAccumulation)),
     4546        paintOverflowControls(context, roundedIntPoint(toLayoutPoint(fragment.layerBounds.location() - renderBoxLocation() + localPaintingInfo.subpixelAccumulation)),
    45474547            pixelSnappedIntRect(fragment.backgroundRect.rect()), true);
    45484548        restoreClip(context, localPaintingInfo.paintDirtyRect, fragment.backgroundRect);
     
    67326732            clipToRect(paintingInfo, context, clipRect);
    67336733
    6734         flowThreadLayer->paintNamedFlowThreadInsideRegion(context, flowFragment, paintingInfo.paintDirtyRect, fragment.layerBounds.location() + paintingInfo.subPixelAccumulation, paintingInfo.paintBehavior, paintFlags);
     6734        flowThreadLayer->paintNamedFlowThreadInsideRegion(context, flowFragment, paintingInfo.paintDirtyRect, fragment.layerBounds.location() + paintingInfo.subpixelAccumulation,
     6735            paintingInfo.paintBehavior, paintFlags);
    67356736
    67366737        if (shouldClip)
  • trunk/Source/WebCore/rendering/RenderLayer.h

    r171074 r171210  
    888888
    889889    struct LayerPaintingInfo {
    890         LayerPaintingInfo(RenderLayer* inRootLayer, const LayoutRect& inDirtyRect, PaintBehavior inPaintBehavior, const LayoutSize& inSubPixelAccumulation, RenderObject* inSubtreePaintRoot = nullptr, OverlapTestRequestMap* inOverlapTestRequests = nullptr)
     890        LayerPaintingInfo(RenderLayer* inRootLayer, const LayoutRect& inDirtyRect, PaintBehavior inPaintBehavior, const LayoutSize& inSubpixelAccumulation, RenderObject* inSubtreePaintRoot = nullptr, OverlapTestRequestMap* inOverlapTestRequests = nullptr)
    891891            : rootLayer(inRootLayer)
    892892            , subtreePaintRoot(inSubtreePaintRoot)
    893893            , paintDirtyRect(inDirtyRect)
    894             , subPixelAccumulation(inSubPixelAccumulation)
     894            , subpixelAccumulation(inSubpixelAccumulation)
    895895            , overlapTestRequests(inOverlapTestRequests)
    896896            , paintBehavior(inPaintBehavior)
     
    900900        RenderObject* subtreePaintRoot; // only paint descendants of this object
    901901        LayoutRect paintDirtyRect; // relative to rootLayer;
    902         LayoutSize subPixelAccumulation;
     902        LayoutSize subpixelAccumulation;
    903903        OverlapTestRequestMap* overlapTestRequests; // May be null.
    904904        PaintBehavior paintBehavior;
Note: See TracChangeset for help on using the changeset viewer.