Title: [129590] trunk
Revision
129590
Author
[email protected]
Date
2012-09-25 20:38:54 -0700 (Tue, 25 Sep 2012)

Log Message

[CSS Exclusions] shape-inside line segment layout should be based on line position and height
https://bugs.webkit.org/show_bug.cgi?id=95479

Patch by Bear Travis <[email protected]> on 2012-09-25
Reviewed by Levi Weintraub.

Source/WebCore:

This patch adds line height to line top to calculate line segments using the line's upper
and lower logical edges. The last line in a shape is allowed to overflow the shape,
using line top and shape bottom to calculate the available line segments. Overflow
behavior will develop in greater detail as the specification advances. For more on
overflow, see:
- http://dev.w3.org/csswg/css3-exclusions/#shape-inside-property and
- https://www.w3.org/Bugs/Public/show_bug.cgi?id=16460

As more shapes are added, line positions within a shape are no longer guaranteed to
have segments (eg, the first line in a circular shape inside), and so many instances
of lineState were replaced with hasSegments. Layout code also uses lineOverlapsShapeBounds
rather than lineState, now that lines may partially overlap a shape without being
completely contained by it. Because layout begins at the shape's logical top, however,
we only run into this edge case laying out the last line within a shape-inside.

Test: fast/exclusions/shape-inside/shape-inside-rounded-rectangle.html

* rendering/RenderBlockLineLayout.cpp:
(WebCore::LineWidth::LineWidth): Use WrapShapeInfo::hasSegments rather than
WrapShapeInfo::lineState, as line positions within a shape are no longer
guaranteed to always have line segments.
(WebCore::RenderBlock::computeInlineDirectionPositionsForLine): Ditto.
(WebCore::RenderBlock::layoutRunsAndFloatsInRange): Pass lineBottom as well as lineTop
to computeSegmentsForLine.
* rendering/WrapShapeInfo.cpp:
(WebCore::WrapShapeInfo::computeSegmentsForLine): Pass lineBottom as well as lineTop
to ExclusionShape::getInsideIntervals.
* rendering/WrapShapeInfo.h:
(WrapShapeInfo):
(WebCore::WrapShapeInfo::shapeLogicalBottom): Calculate the logical bottom of an
Exclusion Shape.
(WebCore::WrapShapeInfo::hasSegments): Allow hasSegments to be called even when
a line does not overlap a shape.
(WebCore::WrapShapeInfo::lineOverlapsShapeBounds): Test whether a line's top/bottom
overlap a shape's top/bottom. This includes lines that begin before or end after
a shape but still overlap it.

LayoutTests:

Test that line bottom as well as line top is used when calculating line segments
for a rounded rectangle.

* fast/exclusions/shape-inside/shape-inside-rounded-rectangle-expected.html: Added.
* fast/exclusions/shape-inside/shape-inside-rounded-rectangle.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (129589 => 129590)


--- trunk/LayoutTests/ChangeLog	2012-09-26 03:18:52 UTC (rev 129589)
+++ trunk/LayoutTests/ChangeLog	2012-09-26 03:38:54 UTC (rev 129590)
@@ -1,3 +1,16 @@
+2012-09-25  Bear Travis  <[email protected]>
+
+        [CSS Exclusions] shape-inside line segment layout should be based on line position and height
+        https://bugs.webkit.org/show_bug.cgi?id=95479
+
+        Reviewed by Levi Weintraub.
+
+        Test that line bottom as well as line top is used when calculating line segments
+        for a rounded rectangle.
+
+        * fast/exclusions/shape-inside/shape-inside-rounded-rectangle-expected.html: Added.
+        * fast/exclusions/shape-inside/shape-inside-rounded-rectangle.html: Added.
+
 2012-09-25  Filip Pizlo  <[email protected]>
 
         DFG ArrayPush, ArrayPop don't handle clobbering or having a bad time correctly

Added: trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-expected.html (0 => 129590)


--- trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-expected.html	2012-09-26 03:38:54 UTC (rev 129590)
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #shape-inside {
+        font: 100px/1 Ahem, sans-serif;
+        white-space: pre;
+        color: green;
+        width: 300px;
+        height: 300px;
+    }
+</style>
+</head>
+<body>
+    Requires Ahem font. Tests that inline content avoids the border radius of a rounded rectangle.
+    Should display five green boxes in the shape of a plus.
+    <div id="shape-inside"> X <br/>XXX<br/> X </div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle.html (0 => 129590)


--- trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle.html	                        (rev 0)
+++ trunk/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle.html	2012-09-26 03:38:54 UTC (rev 129590)
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+    if (window.internals)
+        window.internals.settings.setCSSExclusionsEnabled(true);
+</script>
+<style>
+    #shape-inside {
+        font: 100px/1 Ahem, sans-serif;
+        color: green;
+        word-wrap: break-word;
+        width: 300px;
+        height: 300px;
+        -webkit-shape-inside: rectangle(0, 0, 300px, 300px, 100px, 100px);
+    }
+</style>
+</head>
+<body>
+    Requires Ahem font. Tests that inline content avoids the border radius of a rounded rectangle.
+    Should display five green boxes in the shape of a plus.
+    <div id="shape-inside">XXXXX</div>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (129589 => 129590)


--- trunk/Source/WebCore/ChangeLog	2012-09-26 03:18:52 UTC (rev 129589)
+++ trunk/Source/WebCore/ChangeLog	2012-09-26 03:38:54 UTC (rev 129590)
@@ -1,3 +1,47 @@
+2012-09-25  Bear Travis  <[email protected]>
+
+        [CSS Exclusions] shape-inside line segment layout should be based on line position and height
+        https://bugs.webkit.org/show_bug.cgi?id=95479
+
+        Reviewed by Levi Weintraub.
+
+        This patch adds line height to line top to calculate line segments using the line's upper
+        and lower logical edges. The last line in a shape is allowed to overflow the shape,
+        using line top and shape bottom to calculate the available line segments. Overflow
+        behavior will develop in greater detail as the specification advances. For more on
+        overflow, see:
+        - http://dev.w3.org/csswg/css3-exclusions/#shape-inside-property and
+        - https://www.w3.org/Bugs/Public/show_bug.cgi?id=16460
+
+        As more shapes are added, line positions within a shape are no longer guaranteed to
+        have segments (eg, the first line in a circular shape inside), and so many instances
+        of lineState were replaced with hasSegments. Layout code also uses lineOverlapsShapeBounds
+        rather than lineState, now that lines may partially overlap a shape without being
+        completely contained by it. Because layout begins at the shape's logical top, however,
+        we only run into this edge case laying out the last line within a shape-inside.
+
+        Test: fast/exclusions/shape-inside/shape-inside-rounded-rectangle.html
+
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::LineWidth::LineWidth): Use WrapShapeInfo::hasSegments rather than
+        WrapShapeInfo::lineState, as line positions within a shape are no longer
+        guaranteed to always have line segments. 
+        (WebCore::RenderBlock::computeInlineDirectionPositionsForLine): Ditto.
+        (WebCore::RenderBlock::layoutRunsAndFloatsInRange): Pass lineBottom as well as lineTop
+        to computeSegmentsForLine.
+        * rendering/WrapShapeInfo.cpp:
+        (WebCore::WrapShapeInfo::computeSegmentsForLine): Pass lineBottom as well as lineTop
+        to ExclusionShape::getInsideIntervals.
+        * rendering/WrapShapeInfo.h:
+        (WrapShapeInfo):
+        (WebCore::WrapShapeInfo::shapeLogicalBottom): Calculate the logical bottom of an
+        Exclusion Shape.
+        (WebCore::WrapShapeInfo::hasSegments): Allow hasSegments to be called even when
+        a line does not overlap a shape.
+        (WebCore::WrapShapeInfo::lineOverlapsShapeBounds): Test whether a line's top/bottom
+        overlap a shape's top/bottom. This includes lines that begin before or end after
+        a shape but still overlap it.
+
 2012-09-25  Adam Barth  <[email protected]>
 
         [Chromium] Network requests without a networking context can be started

Modified: trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp (129589 => 129590)


--- trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp	2012-09-26 03:18:52 UTC (rev 129589)
+++ trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp	2012-09-26 03:38:54 UTC (rev 129590)
@@ -89,11 +89,8 @@
 #if ENABLE(CSS_EXCLUSIONS)
         WrapShapeInfo* wrapShapeInfo = layoutWrapShapeInfo(m_block);
         // FIXME: Bug 91878: Add support for multiple segments, currently we only support one
-        if (wrapShapeInfo && wrapShapeInfo->lineState() == WrapShapeInfo::LINE_INSIDE_SHAPE) {
-            // All interior shape positions should have at least one segment
-            ASSERT(wrapShapeInfo->hasSegments());
+        if (wrapShapeInfo && wrapShapeInfo->hasSegments())
             m_segment = &wrapShapeInfo->segments()[0];
-        }
 #endif
         updateAvailableWidth();
     }
@@ -812,7 +809,7 @@
     float logicalRight = pixelSnappedLogicalRightOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight);
 #if ENABLE(CSS_EXCLUSIONS)
     WrapShapeInfo* wrapShapeInfo = layoutWrapShapeInfo(this);
-    if (wrapShapeInfo && wrapShapeInfo->lineState() == WrapShapeInfo::LINE_INSIDE_SHAPE) {
+    if (wrapShapeInfo && wrapShapeInfo->hasSegments()) {
         logicalLeft = max<float>(roundToInt(wrapShapeInfo->segments()[0].logicalLeft), logicalLeft);
         logicalRight = min<float>(floorToInt(wrapShapeInfo->segments()[0].logicalRight), logicalRight);
     }
@@ -1336,8 +1333,13 @@
         bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
         FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0;
 #if ENABLE(CSS_EXCLUSIONS)
-        if (wrapShapeInfo)
-            wrapShapeInfo->computeSegmentsForLine(logicalHeight() + absoluteLogicalTop);
+        // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which
+        // case these segments may be incorrect.
+        if (wrapShapeInfo) {
+            LayoutUnit lineTop = logicalHeight() + absoluteLogicalTop;
+            LayoutUnit lineBottom = lineTop + lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
+            wrapShapeInfo->computeSegmentsForLine(lineTop, lineBottom);
+        }
 #endif
         end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines);
         if (resolver.position().atEnd()) {

Modified: trunk/Source/WebCore/rendering/WrapShapeInfo.cpp (129589 => 129590)


--- trunk/Source/WebCore/rendering/WrapShapeInfo.cpp	2012-09-26 03:18:52 UTC (rev 129589)
+++ trunk/Source/WebCore/rendering/WrapShapeInfo.cpp	2012-09-26 03:38:54 UTC (rev 129590)
@@ -83,13 +83,6 @@
     wrapShapeInfoMap().remove(block);
 }
 
-bool WrapShapeInfo::hasSegments() const
-{
-    // All line positions within a shape should have at least one segment
-    ASSERT(lineState() != LINE_INSIDE_SHAPE || m_segments.size());
-    return m_segments.size();
-}
-
 void WrapShapeInfo::computeShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight)
 {
     if (!m_wrapShapeSizeDirty && logicalWidth == m_logicalWidth && logicalHeight == m_logicalHeight)
@@ -107,14 +100,16 @@
     ASSERT(m_shape);
 }
 
-bool WrapShapeInfo::computeSegmentsForLine(LayoutUnit lineTop)
+bool WrapShapeInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineBottom)
 {
+    ASSERT(lineTop <= lineBottom);
     m_lineTop = lineTop;
+    m_lineBottom = lineBottom;
     m_segments.clear();
 
-    if (lineState() == LINE_INSIDE_SHAPE) {
+    if (lineOverlapsShapeBounds()) {
         ASSERT(m_shape);
-        m_shape->getIncludedIntervals(lineTop, lineTop, m_segments); // FIXME: Bug 95479, workaround for now
+        m_shape->getIncludedIntervals(lineTop, std::min(lineBottom, shapeLogicalBottom()), m_segments);
     }
     return m_segments.size();
 }

Modified: trunk/Source/WebCore/rendering/WrapShapeInfo.h (129589 => 129590)


--- trunk/Source/WebCore/rendering/WrapShapeInfo.h	2012-09-26 03:18:52 UTC (rev 129589)
+++ trunk/Source/WebCore/rendering/WrapShapeInfo.h	2012-09-26 03:38:54 UTC (rev 129590)
@@ -46,12 +46,6 @@
 class WrapShapeInfo {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    enum LineState {
-        LINE_BEFORE_SHAPE,
-        LINE_INSIDE_SHAPE,
-        LINE_AFTER_SHAPE
-    };
-
     ~WrapShapeInfo();
 
     static PassOwnPtr<WrapShapeInfo> create(RenderBlock* block) { return adoptPtr(new WrapShapeInfo(block)); }
@@ -65,14 +59,22 @@
         ASSERT(m_shape);
         return m_shape->shapeLogicalBoundingBox().y();
     }
-    bool hasSegments() const;
+    LayoutUnit shapeLogicalBottom() const
+    {
+        ASSERT(m_shape);
+        return m_shape->shapeLogicalBoundingBox().maxY();
+    }
+    bool hasSegments() const
+    {
+        return lineOverlapsShapeBounds() && m_segments.size();
+    }
     const SegmentList& segments() const
     {
         ASSERT(hasSegments());
         return m_segments;
     }
-    bool computeSegmentsForLine(LayoutUnit lineTop);
-    LineState lineState() const;
+    bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineBottom);
+    bool lineOverlapsShapeBounds() const;
     void computeShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight);
     void dirtyWrapShapeSize() { m_wrapShapeSizeDirty = true; }
 
@@ -83,6 +85,7 @@
     OwnPtr<ExclusionShape> m_shape;
 
     LayoutUnit m_lineTop;
+    LayoutUnit m_lineBottom;
     LayoutUnit m_logicalWidth;
     LayoutUnit m_logicalHeight;
 
@@ -90,18 +93,11 @@
     bool m_wrapShapeSizeDirty;
 };
 
-inline WrapShapeInfo::LineState WrapShapeInfo::lineState() const
+inline bool WrapShapeInfo::lineOverlapsShapeBounds() const
 {
     ASSERT(m_shape);
     FloatRect shapeBounds = m_shape->shapeLogicalBoundingBox();
-
-    if (m_lineTop < shapeBounds.y())
-        return LINE_BEFORE_SHAPE;
-
-    if (m_lineTop < shapeBounds.maxY())
-        return LINE_INSIDE_SHAPE;
-
-    return LINE_AFTER_SHAPE;
+    return m_lineTop <= shapeBounds.maxY() && m_lineBottom >= shapeBounds.y();
 }
 
 }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to