Title: [155002] trunk
Revision
155002
Author
betra...@adobe.com
Date
2013-09-03 15:14:51 -0700 (Tue, 03 Sep 2013)

Log Message

[CSS Shapes] Shape's content gets extra left offset when left-border is positive on the content box
https://bugs.webkit.org/show_bug.cgi?id=117573

Reviewed by David Hyatt.

Source/WebCore:

Nested blocks need to take into account their offset from the shape-inside container.
The new code calculates the offset from the shape-inside container, then applies the
offset to the computed segments. The line must be moved down by the offset's height,
and each segment must be moved left by the offset's width.

Test: fast/shapes/shape-inside/shape-inside-offset-block-children.html

* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::relayoutShapeDescendantIfMoved): Relayout a block child if its
new logical left would cause it to rest at a new position within a shape container.
(WebCore::RenderBlock::logicalOffsetFromShapeAncestorContainer): Calculate the logical
offset form a shape inside ancestor container.
(WebCore::RenderBlock::layoutBlockChild): Call relayoutShapeDescendantIfMoved with the
new position offset.
* rendering/RenderBlock.h:
* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlock::updateShapeAndSegmentsForCurrentLine): Use layout offset, rather
than just vertical offset.
(WebCore::RenderBlock::updateShapeAndSegmentsForCurrentLineInFlowThread): Ditto.
(WebCore::RenderBlock::layoutRunsAndFloatsInRange): Ditto.
* rendering/shapes/ShapeInsideInfo.h:
(WebCore::ShapeInsideInfo::computeSegmentsForLine): Shift segments logically left when
there is an inline offset.

LayoutTests:

Test that nested children with padding correctly apply an ancestor's shape-inside
across different writing modes.

* fast/shapes/shape-inside/shape-inside-offset-block-children-expected.html: Added.
* fast/shapes/shape-inside/shape-inside-offset-block-children.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (155001 => 155002)


--- trunk/LayoutTests/ChangeLog	2013-09-03 22:08:49 UTC (rev 155001)
+++ trunk/LayoutTests/ChangeLog	2013-09-03 22:14:51 UTC (rev 155002)
@@ -1,3 +1,16 @@
+2013-09-03  Bear Travis  <betra...@adobe.com>
+
+        [CSS Shapes] Shape's content gets extra left offset when left-border is positive on the content box
+        https://bugs.webkit.org/show_bug.cgi?id=117573
+
+        Reviewed by David Hyatt.
+
+        Test that nested children with padding correctly apply an ancestor's shape-inside
+        across different writing modes.
+
+        * fast/shapes/shape-inside/shape-inside-offset-block-children-expected.html: Added.
+        * fast/shapes/shape-inside/shape-inside-offset-block-children.html: Added.
+
 2013-09-03  Antoine Quint  <grao...@apple.com>
 
         Web Inspector: exceptions triggered from console evaluation do not pause the debugger

Added: trunk/LayoutTests/fast/shapes/shape-inside/shape-inside-offset-block-children-expected.html (0 => 155002)


--- trunk/LayoutTests/fast/shapes/shape-inside/shape-inside-offset-block-children-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shapes/shape-inside/shape-inside-offset-block-children-expected.html	2013-09-03 22:14:51 UTC (rev 155002)
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style id='stylesheet'>
+.shape-inside {
+    font: 50px/1 Ahem, sans-serif;
+    color: green;
+    float: left;
+}
+</style>
+<script src=''></script>
+<script>
+    ids = [
+        'shape-inside',
+        'shape-inside-rl',
+        'shape-inside-lr',
+        'shape-inside-tb-lr-tb',
+        'shape-inside-lr-rl-lr'
+    ];
+    ids.forEach(function(id) {
+        drawExpectedRectangle(id, 'stylesheet', { width: 300, height: 300 }, { x: 100, y: 100, width: 100, height: 100 }, 'px', null);
+    });
+</script>
+</head>
+<body>
+<p>This test ensures that shape-inside takes into account padding on nested child blocks in different writing modes. You should see several green squares within a blue outline. The test requires the Ahem font.</p>
+<div id='shape-inside' class='shape-inside'>xxxx</div>
+<div id='shape-inside-rl' class='shape-inside'>xxxx</div>
+<div id='shape-inside-lr' class='shape-inside'>xxxx</div>
+<div id='shape-inside-tb-lr-tb' class='shape-inside'>xxxx</div>
+<div id='shape-inside-lr-rl-lr' class='shape-inside'>xxxx</div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/shapes/shape-inside/shape-inside-offset-block-children.html (0 => 155002)


--- trunk/LayoutTests/fast/shapes/shape-inside/shape-inside-offset-block-children.html	                        (rev 0)
+++ trunk/LayoutTests/fast/shapes/shape-inside/shape-inside-offset-block-children.html	2013-09-03 22:14:51 UTC (rev 155002)
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style id='stylesheet'>
+.shape-inside {
+    font: 50px/1 Ahem, sans-serif;
+    color: green;
+    float: left;
+}
+.horizontal.tb {
+    -webkit-writing-mode: horizontal-tb;
+}
+.vertical.rl {
+    -webkit-writing-mode: vertical-rl;
+}
+.vertical.lr {
+    -webkit-writing-mode: vertical-lr;
+}
+.shape-inside * {
+    padding: 5px 10px 15px 20px;
+}
+</style>
+<script src=''></script>
+<script>
+window._onload_ = function() {
+    ids = [
+        'shape-inside',
+        'shape-inside-rl',
+        'shape-inside-lr',
+        'shape-inside-tb-lr-tb',
+        'shape-inside-lr-rl-lr'
+    ];
+    ids.forEach(function(id) {
+        drawTextRectangle(id, 'stylesheet', { width: 300, height: 300 }, { x: 100, y: 100, width: 100, height: 100 }, 'px', null);
+    });
+}
+</script>
+</head>
+<body>
+<p>This test ensures that shape-inside takes into account padding on nested child blocks in different writing modes. You should see several green squares within a blue outline. The test requires the Ahem font.</p>
+<div id='shape-inside' class='shape-inside'><div><div>xxxx</div></div></div>
+<div id='shape-inside-rl' class='shape-inside vertical lr'><div><div>xxxx</div></div></div>
+<div id='shape-inside-lr' class='shape-inside vertical rl'><div><div>xxxx</div></div></div>
+<div id='shape-inside-tb-lr-tb' class='shape-inside'><div class='vertical lr'><div class='horizontal tb'>xxxx</div></div></div>
+<div id='shape-inside-lr-rl-lr' class='shape-inside vertical rl'><div class='vertical lr'><div class='vertical rl'>xxxx</div></div></div>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (155001 => 155002)


--- trunk/Source/WebCore/ChangeLog	2013-09-03 22:08:49 UTC (rev 155001)
+++ trunk/Source/WebCore/ChangeLog	2013-09-03 22:14:51 UTC (rev 155002)
@@ -1,3 +1,34 @@
+2013-09-03  Bear Travis  <betra...@adobe.com>
+
+        [CSS Shapes] Shape's content gets extra left offset when left-border is positive on the content box
+        https://bugs.webkit.org/show_bug.cgi?id=117573
+
+        Reviewed by David Hyatt.
+
+        Nested blocks need to take into account their offset from the shape-inside container.
+        The new code calculates the offset from the shape-inside container, then applies the
+        offset to the computed segments. The line must be moved down by the offset's height,
+        and each segment must be moved left by the offset's width.
+
+        Test: fast/shapes/shape-inside/shape-inside-offset-block-children.html
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::relayoutShapeDescendantIfMoved): Relayout a block child if its
+        new logical left would cause it to rest at a new position within a shape container.
+        (WebCore::RenderBlock::logicalOffsetFromShapeAncestorContainer): Calculate the logical
+        offset form a shape inside ancestor container.
+        (WebCore::RenderBlock::layoutBlockChild): Call relayoutShapeDescendantIfMoved with the
+        new position offset.
+        * rendering/RenderBlock.h:
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlock::updateShapeAndSegmentsForCurrentLine): Use layout offset, rather
+        than just vertical offset.
+        (WebCore::RenderBlock::updateShapeAndSegmentsForCurrentLineInFlowThread): Ditto.
+        (WebCore::RenderBlock::layoutRunsAndFloatsInRange): Ditto.
+        * rendering/shapes/ShapeInsideInfo.h:
+        (WebCore::ShapeInsideInfo::computeSegmentsForLine): Shift segments logically left when
+        there is an inline offset.
+
 2013-09-03  Antoine Quint  <grao...@apple.com>
 
         Web Inspector: exceptions triggered from console evaluation do not pause the debugger

Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (155001 => 155002)


--- trunk/Source/WebCore/rendering/RenderBlock.cpp	2013-09-03 22:08:49 UTC (rev 155001)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp	2013-09-03 22:14:51 UTC (rev 155002)
@@ -1434,6 +1434,50 @@
 }
 
 #if ENABLE(CSS_SHAPES)
+void RenderBlock::relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset)
+{
+    LayoutUnit left = isHorizontalWritingMode() ? offset.width() : offset.height();
+    if (!left || !child || child->shapeInsideInfo() || !layoutShapeInsideInfo())
+        return;
+    // Propagate layout markers only up to the child, as we are still in the middle
+    // of a layout pass
+    child->setNormalChildNeedsLayout(true);
+    child->markShapeInsideDescendantsForLayout();
+    child->layoutIfNeeded();
+}
+
+LayoutSize RenderBlock::logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const
+{
+    const RenderBlock* currentBlock = this;
+    LayoutRect blockRect(currentBlock->borderBoxRect());
+    while (currentBlock && !currentBlock->isRenderFlowThread() && currentBlock != container) {
+        RenderBlock* containerBlock = currentBlock->containingBlock();
+        ASSERT(containerBlock);
+        if (!containerBlock)
+            return LayoutSize();
+
+        if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
+            // We have to put the block rect in container coordinates
+            // and we have to take into account both the container and current block flipping modes
+            // Bug 118073: Flipping inline and block directions at the same time will not work,
+            // as one of the flipped dimensions will not yet have been set to its final size
+            if (containerBlock->style()->isFlippedBlocksWritingMode()) {
+                if (containerBlock->isHorizontalWritingMode())
+                    blockRect.setY(currentBlock->height() - blockRect.maxY());
+                else
+                    blockRect.setX(currentBlock->width() - blockRect.maxX());
+            }
+            currentBlock->flipForWritingMode(blockRect);
+        }
+
+        blockRect.moveBy(currentBlock->location());
+        currentBlock = containerBlock;
+    }
+
+    LayoutSize result = isHorizontalWritingMode() ? LayoutSize(blockRect.x(), blockRect.y()) : LayoutSize(blockRect.y(), blockRect.x());
+    return result;
+}
+
 void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*)
 {
     RenderBox::imageChanged(image);
@@ -2729,6 +2773,11 @@
     // Now place the child in the correct left position
     determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
 
+    LayoutSize childOffset = child->location() - oldRect.location();
+#if ENABLE(CSS_SHAPES)
+    relayoutShapeDescendantIfMoved(childRenderBlock, childOffset);
+#endif
+
     // Update our height now that the child has been placed in the correct position.
     setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
     if (mustSeparateMarginAfterForChild(child)) {
@@ -2740,7 +2789,6 @@
     if (childRenderBlock && childRenderBlock->containsFloats())
         maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
 
-    LayoutSize childOffset = child->location() - oldRect.location();
     if (childOffset.width() || childOffset.height()) {
         view().addLayoutDelta(childOffset);
 

Modified: trunk/Source/WebCore/rendering/RenderBlock.h (155001 => 155002)


--- trunk/Source/WebCore/rendering/RenderBlock.h	2013-09-03 22:08:49 UTC (rev 155001)
+++ trunk/Source/WebCore/rendering/RenderBlock.h	2013-09-03 22:14:51 UTC (rev 155002)
@@ -618,6 +618,8 @@
 #if ENABLE(CSS_SHAPES)
     void computeShapeSize();
     void updateShapeInsideInfoAfterStyleChange(const ShapeValue*, const ShapeValue* oldShape);
+    void relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset);
+    LayoutSize logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const;
 #endif
     virtual RenderObjectChildList* virtualChildren() { return children(); }
     virtual const RenderObjectChildList* virtualChildren() const { return children(); }
@@ -1118,7 +1120,7 @@
     void layoutRunsAndFloats(LineLayoutState&, bool hasInlineChild);
     void layoutRunsAndFloatsInRange(LineLayoutState&, InlineBidiResolver&, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines);
 #if ENABLE(CSS_SHAPES)
-    void updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*&, LayoutUnit&, LineLayoutState&);
+    void updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*&, const LayoutSize&, LineLayoutState&);
     void updateShapeAndSegmentsForCurrentLineInFlowThread(ShapeInsideInfo*&, LineLayoutState&);
     bool adjustLogicalLineTopAndLogicalHeightIfNeeded(ShapeInsideInfo*, LayoutUnit, LineLayoutState&, InlineBidiResolver&, FloatingObject*, InlineIterator&, WordMeasurements&);
 #endif

Modified: trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp (155001 => 155002)


--- trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp	2013-09-03 22:08:49 UTC (rev 155001)
+++ trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp	2013-09-03 22:14:51 UTC (rev 155002)
@@ -1678,7 +1678,7 @@
     block->setLogicalHeight(newLogicalHeight);
 }
 
-void RenderBlock::updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*& shapeInsideInfo, LayoutUnit& absoluteLogicalTop, LineLayoutState& layoutState)
+void RenderBlock::updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*& shapeInsideInfo, const LayoutSize& logicalOffsetFromShapeContainer, LineLayoutState& layoutState)
 {
     if (layoutState.flowThread())
         return updateShapeAndSegmentsForCurrentLineInFlowThread(shapeInsideInfo, layoutState);
@@ -1686,11 +1686,12 @@
     if (!shapeInsideInfo)
         return;
 
-    LayoutUnit lineTop = logicalHeight() + absoluteLogicalTop;
+    LayoutUnit lineTop = logicalHeight() + logicalOffsetFromShapeContainer.height();
+    LayoutUnit lineLeft = logicalOffsetFromShapeContainer.width();
     LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
 
     // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which case these segments may be incorrect.
-    shapeInsideInfo->computeSegmentsForLine(lineTop, lineHeight);
+    shapeInsideInfo->computeSegmentsForLine(LayoutSize(lineLeft, lineTop), lineHeight);
 
     pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
 }
@@ -1761,8 +1762,10 @@
     }
 
     LayoutUnit lineTop = logicalLineTopInFlowThread - currentRegion->logicalTopForFlowThreadContent() + currentRegion->borderAndPaddingBefore();
-    shapeInsideInfo->computeSegmentsForLine(lineTop, lineHeight);
 
+    // FIXME: 118571 - Shape inside on a region does not yet take into account its padding for nested flow blocks
+    shapeInsideInfo->computeSegmentsForLine(LayoutSize(0, lineTop), lineHeight);
+
     if (currentRegion->isLastRegion())
         pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
 }
@@ -1799,18 +1802,18 @@
     LineBreaker lineBreaker(this);
 
 #if ENABLE(CSS_SHAPES)
-    LayoutUnit absoluteLogicalTop;
+    LayoutSize logicalOffsetFromShapeContainer;
     ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
     if (shapeInsideInfo) {
         ASSERT(shapeInsideInfo->owner() == this || allowsShapeInsideInfoSharing());
         if (shapeInsideInfo != this->shapeInsideInfo()) {
             // FIXME Bug 100284: If subsequent LayoutStates are pushed, we will have to add
             // their offsets from the original shape-inside container.
-            absoluteLogicalTop = logicalTop();
+            logicalOffsetFromShapeContainer = logicalOffsetFromShapeAncestorContainer(shapeInsideInfo->owner());
         }
         // Begin layout at the logical top of our shape inside.
-        if (logicalHeight() + absoluteLogicalTop < shapeInsideInfo->shapeLogicalTop()) {
-            LayoutUnit logicalHeight = shapeInsideInfo->shapeLogicalTop() - absoluteLogicalTop;
+        if (logicalHeight() + logicalOffsetFromShapeContainer.height() < shapeInsideInfo->shapeLogicalTop()) {
+            LayoutUnit logicalHeight = shapeInsideInfo->shapeLogicalTop() - logicalOffsetFromShapeContainer.height();
             if (layoutState.flowThread())
                 logicalHeight -= shapeInsideInfo->owner()->borderAndPaddingBefore();
             setLogicalHeight(logicalHeight);
@@ -1838,7 +1841,7 @@
         FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last() : 0;
 
 #if ENABLE(CSS_SHAPES)
-        updateShapeAndSegmentsForCurrentLine(shapeInsideInfo, absoluteLogicalTop, layoutState);
+        updateShapeAndSegmentsForCurrentLine(shapeInsideInfo, logicalOffsetFromShapeContainer, layoutState);
 #endif
         WordMeasurements wordMeasurements;
         end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
@@ -1854,7 +1857,7 @@
         }
 
 #if ENABLE(CSS_SHAPES)
-        if (adjustLogicalLineTopAndLogicalHeightIfNeeded(shapeInsideInfo, absoluteLogicalTop, layoutState, resolver, lastFloatFromPreviousLine, end, wordMeasurements))
+        if (adjustLogicalLineTopAndLogicalHeightIfNeeded(shapeInsideInfo, logicalOffsetFromShapeContainer.height(), layoutState, resolver, lastFloatFromPreviousLine, end, wordMeasurements))
             continue;
 #endif
         ASSERT(end != resolver.position());

Modified: trunk/Source/WebCore/rendering/shapes/ShapeInsideInfo.h (155001 => 155002)


--- trunk/Source/WebCore/rendering/shapes/ShapeInsideInfo.h	2013-09-03 22:08:49 UTC (rev 155001)
+++ trunk/Source/WebCore/rendering/shapes/ShapeInsideInfo.h	2013-09-03 22:14:51 UTC (rev 155002)
@@ -68,6 +68,17 @@
 
     static bool isEnabledFor(const RenderBlock* renderer);
 
+    bool computeSegmentsForLine(LayoutSize lineOffset, LayoutUnit lineHeight)
+    {
+        m_segmentRanges.clear();
+        bool result = ShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &Shape::getIncludedIntervals>::computeSegmentsForLine(lineOffset.height(), lineHeight);
+        for (size_t i = 0; i < m_segments.size(); i++) {
+            m_segments[i].logicalLeft -= lineOffset.width();
+            m_segments[i].logicalRight -= lineOffset.width();
+        }
+        return result;
+    }
+
     virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) OVERRIDE
     {
         m_segmentRanges.clear();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to