[New Multicolumn] Transformed objects inside fragmented transparent objects don't...
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Mar 2013 06:14:28 +0000 (06:14 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Mar 2013 06:14:28 +0000 (06:14 +0000)
https://bugs.webkit.org/show_bug.cgi?id=111221.

Reviewed by Simon Fraser.

Source/WebCore:

Improve transparencyClipBox so that it understands when moving into descendants
that it does in fact have to break up the transformed clip rect across the
fragments.

Make sure when handling fragmented transforms using multiple paints that
the test that determines the extent of the transform within the fragments
uses transparencyClipBox. This gives us an accurate set of columns that the
final transformed result will paint across.

Tests: fast/multicol/mixed-opacity-fixed-test.html
       fast/multicol/mixed-opacity-test.html
       fast/multicol/transform-inside-opacity.html

* rendering/RenderLayer.cpp:
(WebCore::transparencyClipBox):
(WebCore::expandClipRectForDescendantsAndReflection):
Break transformed boxes up into fragments when they are
being requested by an ancestor.

(WebCore::RenderLayer::collectFragments):
(WebCore::RenderLayer::paintTransformedLayerIntoFragments):
(WebCore::RenderLayer::hitTestTransformedLayerInFragments):
* rendering/RenderLayer.h:
(RenderLayer):
Modify collectFragments so that we pass in the correct range
within the columns that can possibly cover the fragmented
transformed box.

LayoutTests:

* fast/multicol/mixed-opacity-fixed-test-expected.html: Added.
* fast/multicol/mixed-opacity-fixed-test.html: Added.
* fast/multicol/mixed-opacity-test-expected.html: Added.
* fast/multicol/mixed-opacity-test.html: Added.
* fast/multicol/transform-inside-opacity-expected.html: Added.
* fast/multicol/transform-inside-opacity.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/multicol/mixed-opacity-fixed-test-expected.html [new file with mode: 0644]
LayoutTests/fast/multicol/mixed-opacity-fixed-test.html [new file with mode: 0644]
LayoutTests/fast/multicol/mixed-opacity-test-expected.html [new file with mode: 0644]
LayoutTests/fast/multicol/mixed-opacity-test.html [new file with mode: 0644]
LayoutTests/fast/multicol/transform-inside-opacity-expected.html [new file with mode: 0644]
LayoutTests/fast/multicol/transform-inside-opacity.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h

index 9d230ae..a3d5c87 100644 (file)
@@ -1,3 +1,17 @@
+2013-03-01  David Hyatt  <hyatt@apple.com>
+
+        [New Multicolumn] Transformed objects inside fragmented transparent objects don't render
+        https://bugs.webkit.org/show_bug.cgi?id=111221.
+
+        Reviewed by Simon Fraser.
+
+        * fast/multicol/mixed-opacity-fixed-test-expected.html: Added.
+        * fast/multicol/mixed-opacity-fixed-test.html: Added.
+        * fast/multicol/mixed-opacity-test-expected.html: Added.
+        * fast/multicol/mixed-opacity-test.html: Added.
+        * fast/multicol/transform-inside-opacity-expected.html: Added.
+        * fast/multicol/transform-inside-opacity.html: Added.
+
 2013-03-01  Kentaro Hara  <haraken@chromium.org>
 
         Style recalculation takes too long when adding whitespace text nodes
diff --git a/LayoutTests/fast/multicol/mixed-opacity-fixed-test-expected.html b/LayoutTests/fast/multicol/mixed-opacity-fixed-test-expected.html
new file mode 100644 (file)
index 0000000..f3662d9
--- /dev/null
@@ -0,0 +1,9 @@
+<div style="position:relative; width:420px; border:2px solid black; height:200px">
+<div style="opacity:0.5;position:relative">
+<div style="height:200px;background-color:green;position:absolute;width:200px;left:0;top:0"></div>
+<div style="height:200px;background-color:green;position:absolute;width:200px;right:0;top:0"></div>
+<div style="position:fixed;height:98px;width:98px;background-color:lightgray; left:170px; top:220px;background-color:green;border:1px solid lime">
+</div>
+</div>
+</div>
+</div>
diff --git a/LayoutTests/fast/multicol/mixed-opacity-fixed-test.html b/LayoutTests/fast/multicol/mixed-opacity-fixed-test.html
new file mode 100644 (file)
index 0000000..e3dd744
--- /dev/null
@@ -0,0 +1,11 @@
+<script>
+internals.settings.setRegionBasedColumnsEnabled(true)
+</script>
+<div style="position:relative; -webkit-column-count:2; -webkit-column-width:200px; width:420px; -webkit-column-gap:20px; border:2px solid black; height:200px">
+<div style="opacity:0.5">
+<div style="height:400px;background-color:green"></div>
+<div style="position:fixed;height:98px;width:98px;background-color:lightgray; left:170px; top:220px;background-color:green;border:1px solid lime">
+</div>
+</div>
+</div>
+</div>
diff --git a/LayoutTests/fast/multicol/mixed-opacity-test-expected.html b/LayoutTests/fast/multicol/mixed-opacity-test-expected.html
new file mode 100644 (file)
index 0000000..92b6c35
--- /dev/null
@@ -0,0 +1,9 @@
+<div style="position:relative; width:420px; border:2px solid black; height:200px">
+<div style="opacity:0.5;position:relative">
+<div style="height:200px;background-color:green;position:absolute;width:200px;left:0;top:0"></div>
+<div style="height:200px;background-color:green;position:absolute;width:200px;right:0;top:0"></div>
+<div style="position:absolute;height:98px;width:98px;background-color:lightgray; left:160px; top:50px;background-color:green;border:1px solid lime">
+</div>
+</div>
+</div>
+</div>
diff --git a/LayoutTests/fast/multicol/mixed-opacity-test.html b/LayoutTests/fast/multicol/mixed-opacity-test.html
new file mode 100644 (file)
index 0000000..d4e6a5e
--- /dev/null
@@ -0,0 +1,11 @@
+<script>
+internals.settings.setRegionBasedColumnsEnabled(true)
+</script>
+<div style="position:relative; -webkit-column-count:2; -webkit-column-width:200px; width:420px; -webkit-column-gap:20px; border:2px solid black; height:200px">
+<div style="opacity:0.5">
+<div style="height:400px;background-color:green"></div>
+<div style="position:absolute;height:98px;width:98px;background-color:lightgray; left:160px; top:50px;background-color:green;border:1px solid lime">
+</div>
+</div>
+</div>
+</div>
diff --git a/LayoutTests/fast/multicol/transform-inside-opacity-expected.html b/LayoutTests/fast/multicol/transform-inside-opacity-expected.html
new file mode 100644 (file)
index 0000000..9d7e3bf
--- /dev/null
@@ -0,0 +1,4 @@
+<div style="position:relative; width:420px;border:2px solid black; height:200px">
+<div style="opacity:0.5; position:absolute;width:200px;height:100px;background-color:green;right:0;top:0"></div>
+</div>
+</div>
diff --git a/LayoutTests/fast/multicol/transform-inside-opacity.html b/LayoutTests/fast/multicol/transform-inside-opacity.html
new file mode 100644 (file)
index 0000000..7499638
--- /dev/null
@@ -0,0 +1,15 @@
+<head>
+<script>
+internals.settings.setRegionBasedColumnsEnabled(true)
+</script>
+<style>
+.transformed { background-color:green }
+.transformed:hover { background-color:maroon }
+</style>
+</head>
+<div style="position:relative; -webkit-column-count:2; -webkit-column-width:200px; width:420px; -webkit-column-gap:20px; border:2px solid black; height:200px">
+<div style="height:100px"></div>
+<div style="opacity:0.5">
+<div class="transformed" style="float:left;width:200px;height:100px;-webkit-transform:translate(0, 100px)"></div>
+</div>
+</div>
index cd1196f..81021ef 100644 (file)
@@ -1,3 +1,38 @@
+2013-03-01  David Hyatt  <hyatt@apple.com>
+
+        [New Multicolumn] Transformed objects inside fragmented transparent objects don't render
+        https://bugs.webkit.org/show_bug.cgi?id=111221.
+
+        Reviewed by Simon Fraser.
+
+        Improve transparencyClipBox so that it understands when moving into descendants
+        that it does in fact have to break up the transformed clip rect across the
+        fragments.
+        
+        Make sure when handling fragmented transforms using multiple paints that
+        the test that determines the extent of the transform within the fragments
+        uses transparencyClipBox. This gives us an accurate set of columns that the
+        final transformed result will paint across.
+
+        Tests: fast/multicol/mixed-opacity-fixed-test.html
+               fast/multicol/mixed-opacity-test.html
+               fast/multicol/transform-inside-opacity.html
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::transparencyClipBox):
+        (WebCore::expandClipRectForDescendantsAndReflection):
+        Break transformed boxes up into fragments when they are
+        being requested by an ancestor.
+
+        (WebCore::RenderLayer::collectFragments):
+        (WebCore::RenderLayer::paintTransformedLayerIntoFragments):
+        (WebCore::RenderLayer::hitTestTransformedLayerInFragments):
+        * rendering/RenderLayer.h:
+        (RenderLayer):
+        Modify collectFragments so that we pass in the correct range
+        within the columns that can possibly cover the fragmented
+        transformed box.
+
 2013-03-01  Ilya Tikhonovsky  <loislo@chromium.org>
 
         Web Inspector: Native Memory Instrumentation: do not visit raw pointers by default.
index b0a299f..1d2e622 100644 (file)
@@ -1560,9 +1560,20 @@ RenderLayer* RenderLayer::transparentPaintingAncestor()
     return 0;
 }
 
-static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, PaintBehavior);
+enum TransparencyClipBoxBehavior {
+    PaintingTransparencyClipBox,
+    HitTestingTransparencyClipBox
+};
 
-static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
+enum TransparencyClipBoxMode {
+    DescendantsOfTransparencyClipBox,
+    RootOfTransparencyClipBox
+};
+
+static LayoutRect transparencyClipBox(const RenderLayer*, const RenderLayer* rootLayer, TransparencyClipBoxBehavior, TransparencyClipBoxMode, PaintBehavior = 0);
+
+static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, const RenderLayer* layer, const RenderLayer* rootLayer,
+    TransparencyClipBoxBehavior transparencyBehavior, PaintBehavior paintBehavior)
 {
     // If we have a mask, then the clip is limited to the border box area (and there is
     // no need to examine child layers).
@@ -1571,7 +1582,7 @@ static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons
         // a stacking container. This means we can just walk the layer tree directly.
         for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSibling()) {
             if (!layer->reflection() || layer->reflectionLayer() != curr)
-                clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior));
+                clipRect.unite(transparencyClipBox(curr, rootLayer, transparencyBehavior, DescendantsOfTransparencyClipBox, paintBehavior));
         }
     }
 
@@ -1588,32 +1599,51 @@ static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons
     }
 }
 
-static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
+static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior,
+    TransparencyClipBoxMode transparencyMode, PaintBehavior paintBehavior)
 {
     // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
     // paintDirtyRect, and that should cut down on the amount we have to paint.  Still it
     // would be better to respect clips.
     
-    if (rootLayer != layer && layer->paintsWithTransform(paintBehavior)) {
+    if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClipBox && layer->paintsWithTransform(paintBehavior))
+        || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasTransform()))) {
         // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
         // the transformed layer and all of its children.
+        const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTransparencyClipBox ? layer->enclosingPaginationLayer() : 0;
+        const RenderLayer* rootLayerForTransform = paginationLayer ? paginationLayer : rootLayer;
         LayoutPoint delta;
-        layer->convertToLayerCoords(rootLayer, delta);
+        layer->convertToLayerCoords(rootLayerForTransform, delta);
 
         TransformationMatrix transform;
         transform.translate(delta.x(), delta.y());
         transform = transform * *layer->transform();
 
-        LayoutRect clipRect = layer->boundingBox(layer, RenderLayer::UseFragmentBoxes);
-        expandClipRectForDescendantsAndReflection(clipRect, layer, layer, paintBehavior);
+        // We don't use fragment boxes when collecting a transformed layer's bounding box, since it always
+        // paints unfragmented.
+        LayoutRect clipRect = layer->boundingBox(layer);
+        expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transparencyBehavior, paintBehavior);
 #if ENABLE(CSS_FILTERS)
         layer->renderer()->style()->filterOutsets().expandRect(clipRect);
 #endif
-        return transform.mapRect(clipRect);
+        LayoutRect result = transform.mapRect(clipRect);
+        if (!paginationLayer)
+            return result;
+        
+        // We have to break up the transformed extent across our columns.
+        // Split our box up into the actual fragment boxes that render in the columns/pages and unite those together to
+        // get our true bounding box.
+        RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLayer->renderer());
+        result = enclosingFlowThread->fragmentsBoundingBox(result);
+        
+        LayoutPoint rootLayerDelta;
+        paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta);
+        result.moveBy(rootLayerDelta);
+        return result;
     }
     
     LayoutRect clipRect = layer->boundingBox(rootLayer, RenderLayer::UseFragmentBoxes);
-    expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, paintBehavior);
+    expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transparencyBehavior, paintBehavior);
 #if ENABLE(CSS_FILTERS)
     layer->renderer()->style()->filterOutsets().expandRect(clipRect);
 #endif
@@ -1622,7 +1652,7 @@ static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLaye
 
 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
 {
-    return intersection(transparencyClipBox(this, rootLayer, paintBehavior), paintDirtyRect);
+    return intersection(transparencyClipBox(this, rootLayer, PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintBehavior), paintDirtyRect);
 }
 
 void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
@@ -3888,7 +3918,8 @@ void RenderLayer::paintList(Vector<RenderLayer*>* list, GraphicsContext* context
 }
 
 void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& dirtyRect,
-    ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot)
+    ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const LayoutPoint* offsetFromRoot,
+    const LayoutRect* layerBoundingBox)
 {
     if (!enclosingPaginationLayer() || hasTransform()) {
         // For unpaginated layers, there is only one fragment.
@@ -3914,7 +3945,7 @@ void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer*
         outlineRectInFlowThread, &offsetWithinPaginatedLayer);
     
     // Take our bounding box within the flow thread and clip it.
-    LayoutRect layerBoundingBoxInFlowThread = boundingBox(enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer);
+    LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingBox : boundingBox(enclosingPaginationLayer(), 0, &offsetWithinPaginatedLayer);
     layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect());
 
     // Shift the dirty rect into flow thread coordinates.
@@ -3976,9 +4007,10 @@ void RenderLayer::paintTransformedLayerIntoFragments(GraphicsContext* context, c
 {
     LayerFragments enclosingPaginationFragments;
     LayoutPoint offsetOfPaginationLayerFromRoot;
+    LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), PaintingTransparencyClipBox, RootOfTransparencyClipBox, paintingInfo.paintBehavior);
     enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, paintingInfo.rootLayer, paintingInfo.region, paintingInfo.paintDirtyRect,
         (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
-        (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot);
+        (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
     
     for (size_t i = 0; i < enclosingPaginationFragments.size(); ++i) {
         const LayerFragment& fragment = enclosingPaginationFragments.at(i);
@@ -4609,8 +4641,9 @@ RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa
 {
     LayerFragments enclosingPaginationFragments;
     LayoutPoint offsetOfPaginationLayerFromRoot;
+    LayoutRect transformedExtent = transparencyClipBox(this, enclosingPaginationLayer(), HitTestingTransparencyClipBox, RootOfTransparencyClipBox);
     enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, rootLayer, hitTestLocation.region(), hitTestRect,
-        RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot);
+        RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip, &offsetOfPaginationLayerFromRoot, &transformedExtent);
 
     for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) {
         const LayerFragment& fragment = enclosingPaginationFragments.at(i);
index c52a319..21e56cf 100644 (file)
@@ -946,7 +946,7 @@ private:
 
     void collectFragments(LayerFragments&, const RenderLayer* rootLayer, RenderRegion*, const LayoutRect& dirtyRect,
         ClipRectsType, OverlayScrollbarSizeRelevancy inOverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize,
-        ShouldRespectOverflowClip = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0);
+        ShouldRespectOverflowClip = RespectOverflowClip, const LayoutPoint* offsetFromRoot = 0, const LayoutRect* layerBoundingBox = 0);
     void updatePaintingInfoForFragments(LayerFragments&, const LayerPaintingInfo&, PaintLayerFlags, bool shouldPaintContent, const LayoutPoint* offsetFromRoot);
     void paintBackgroundForFragments(const LayerFragments&, GraphicsContext*, GraphicsContext* transparencyLayerContext,
         const LayoutRect& transparencyPaintDirtyRect, bool haveTransparency, const LayerPaintingInfo&, PaintBehavior, RenderObject* paintingRootForRenderer);