[CSS Shapes] Image valued shape-outside that extends vertically into the margin-box...
authorhmuller@adobe.com <hmuller@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Nov 2013 23:46:57 +0000 (23:46 +0000)
committerhmuller@adobe.com <hmuller@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Nov 2013 23:46:57 +0000 (23:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=123769

Reviewed by Dirk Schulze.

Source/WebCore:

Remove the assumption that Y coordinates are >= 0 from the RasterShapeIntervals class
and correct its computeShapeMarginIntervals() method. The computeShapeMarginIntervals()
method now generates intervals with Y coordinates that begin at the image shape's
bounds.y - shape-margin, which may be less than 0.

The RasterShapeIntervals::intervalsAt() method now offsets its Y coordinate parameter
by the shape-margin. A non-const overload of the method was added to centralize all
access to m_intervalLists.

Test: fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004.html
      fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005.html

* rendering/shapes/RasterShape.cpp:
(WebCore::MarginIntervalGenerator::intervalAt): Don't clip X coordinates to 0 since they can extend into the margin-box.
(WebCore::RasterShapeIntervals::appendInterval): Use the non-const intervalsAt() method.
(WebCore::RasterShapeIntervals::uniteMarginInterval): Ditto.
(WebCore::RasterShapeIntervals::computeShapeMarginIntervals): See above.
* rendering/shapes/RasterShape.h:
(WebCore::RasterShapeIntervals::RasterShapeIntervals): Added a field for the margin.
(WebCore::RasterShapeIntervals::intervalsAt): Offset y coordinates by the margin; added a non-const overload.

LayoutTests:

Verify that lines overlap a shape-outside that extends into the top of the margin-box
do wrap around the top of the shape as well its side and bottom.

* fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004-expected.html: Added.
* fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004.html: Added.
* fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005-expected.html: Added.
* fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004-expected.html [new file with mode: 0644]
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004.html [new file with mode: 0644]
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005-expected.html [new file with mode: 0644]
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/shapes/RasterShape.cpp
Source/WebCore/rendering/shapes/RasterShape.h

index d193520..32e07f8 100644 (file)
@@ -1,3 +1,18 @@
+2013-11-08  Hans Muller  <hmuller@adobe.com>
+
+        [CSS Shapes] Image valued shape-outside that extends vertically into the margin-box is top-clipped
+        https://bugs.webkit.org/show_bug.cgi?id=123769
+
+        Reviewed by Dirk Schulze.
+
+        Verify that lines overlap a shape-outside that extends into the top of the margin-box
+        do wrap around the top of the shape as well its side and bottom.
+
+        * fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004-expected.html: Added.
+        * fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004.html: Added.
+        * fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005-expected.html: Added.
+        * fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005.html: Added.
+
 2013-11-08  Piotr Grad  <p.grad@samsung.com>
 
         Ended event should work also when playback rate is negative
diff --git a/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004-expected.html b/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004-expected.html
new file mode 100644 (file)
index 0000000..597ae18
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #content {
+        font: 25px / 1 Ahem, sans-serif;
+        color: green;
+    }
+
+    #image-shape {
+        float: left;
+        width: 100px;
+        height: 100px;
+        margin: 25px;
+        background-color: blue;
+    }
+</style>
+</head>
+<body>
+  <p>The green rectangles should wrap around the blue 100x100 rectangle and a 25 pixel margin.</p>
+  <div id="content">
+      <div id="image-shape"></div>
+      X<br>X<br>X<br>X<br>X<br>X<br>X
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004.html b/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004.html
new file mode 100644 (file)
index 0000000..9bfde8f
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #content {
+        font: 25px / 1 Ahem, sans-serif;
+        color: green;
+    }
+
+    #image-shape {
+        float: left;
+        -webkit-shape-outside: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100px' height='100px'><rect width='100' height='100' fill='green'/></svg>");
+        -webkit-shape-margin: 100px; /* overflow the margin box */
+        width: 100px;
+        height: 100px;
+        margin: 25px;
+        background-color: blue;
+    }
+</style>
+</head>
+<body>
+  <p>The green rectangles should wrap around the blue 100x100 rectangle and a 25 pixel margin.</p>
+  <div id="content">
+      <div id="image-shape"></div>
+      X<br>X<br>X<br>X<br>X<br>X<br>X
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005-expected.html b/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005-expected.html
new file mode 100644 (file)
index 0000000..3bfe18a
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #content {
+        font: 25px / 1 Ahem, sans-serif;
+        color: green;
+        text-align: right;
+    }
+
+    #image-shape {
+        float: right;
+        width: 100px;
+        height: 100px;
+        margin: 25px;
+        background-color: blue;
+    }
+</style>
+</head>
+<body>
+  <p>The green rectangles should wrap around the blue 100x100 rectangle and a 25 pixel margin.</p>
+  <div id="content">
+      <div id="image-shape"></div>
+      X<br>X<br>X<br>X<br>X<br>X<br>X
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005.html b/LayoutTests/fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005.html
new file mode 100644 (file)
index 0000000..6e9790d
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #content {
+        font: 25px / 1 Ahem, sans-serif;
+        color: green;
+        text-align: right;
+    }
+
+    #image-shape {
+        float: right;
+        -webkit-shape-outside: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100px' height='100px'><rect width='100' height='100' fill='green'/></svg>");
+        -webkit-shape-margin: 100px; /* overflow the margin box */
+        width: 100px;
+        height: 100px;
+        margin: 25px;
+        background-color: blue;
+    }
+</style>
+</head>
+<body>
+  <p>The green rectangles should wrap around the blue 100x100 rectangle and a 25 pixel margin.</p>
+  <div id="content">
+      <div id="image-shape"></div>
+      X<br>X<br>X<br>X<br>X<br>X<br>X
+  </div>
+</body>
+</html>
index d3e619a..eab0285 100644 (file)
@@ -1,3 +1,31 @@
+2013-11-08  Hans Muller  <hmuller@adobe.com>
+
+        [CSS Shapes] Image valued shape-outside that extends vertically into the margin-box is top-clipped
+        https://bugs.webkit.org/show_bug.cgi?id=123769
+
+        Reviewed by Dirk Schulze.
+
+        Remove the assumption that Y coordinates are >= 0 from the RasterShapeIntervals class
+        and correct its computeShapeMarginIntervals() method. The computeShapeMarginIntervals()
+        method now generates intervals with Y coordinates that begin at the image shape's
+        bounds.y - shape-margin, which may be less than 0.
+
+        The RasterShapeIntervals::intervalsAt() method now offsets its Y coordinate parameter
+        by the shape-margin. A non-const overload of the method was added to centralize all
+        access to m_intervalLists.
+
+        Test: fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-004.html
+              fast/shapes/shape-outside-floats/shape-outside-floats-image-margin-005.html
+
+        * rendering/shapes/RasterShape.cpp:
+        (WebCore::MarginIntervalGenerator::intervalAt): Don't clip X coordinates to 0 since they can extend into the margin-box.
+        (WebCore::RasterShapeIntervals::appendInterval): Use the non-const intervalsAt() method.
+        (WebCore::RasterShapeIntervals::uniteMarginInterval): Ditto.
+        (WebCore::RasterShapeIntervals::computeShapeMarginIntervals): See above.
+        * rendering/shapes/RasterShape.h:
+        (WebCore::RasterShapeIntervals::RasterShapeIntervals): Added a field for the margin.
+        (WebCore::RasterShapeIntervals::intervalsAt): Offset y coordinates by the margin; added a non-const overload.
+
 2013-11-08  Piotr Grad  <p.grad@samsung.com>
 
         Ended event should work also when playback rate is negative
index 90509cb..b7fefdf 100644 (file)
@@ -70,25 +70,24 @@ IntShapeInterval MarginIntervalGenerator::intervalAt(int y) const
 {
     unsigned xInterceptsIndex = abs(y - m_y);
     int dx = (xInterceptsIndex >= m_xIntercepts.size()) ? 0 : m_xIntercepts[xInterceptsIndex];
-    return IntShapeInterval(std::max(0, m_x1 - dx), m_x2 + dx);
+    return IntShapeInterval(m_x1 - dx, m_x2 + dx);
 }
 
 void RasterShapeIntervals::appendInterval(int y, int x1, int x2)
 {
-    ASSERT(y >= 0 && y < size() && x1 >= 0 && x2 > x1 && (m_intervalLists[y].isEmpty() || x1 > m_intervalLists[y].last().x2()));
-
+    ASSERT(x2 > x1 && (intervalsAt(y).isEmpty() || x1 > intervalsAt(y).last().x2()));
     m_bounds.unite(IntRect(x1, y, x2 - x1, 1));
-    m_intervalLists[y].append(IntShapeInterval(x1, x2));
+    intervalsAt(y).append(IntShapeInterval(x1, x2));
 }
 
 void RasterShapeIntervals::uniteMarginInterval(int y, const IntShapeInterval& interval)
 {
-    ASSERT(m_intervalLists[y].size() <= 1); // Each m_intervalLists entry has 0 or one interval.
+    ASSERT(intervalsAt(y).size() <= 1); // Each m_intervalLists entry has 0 or one interval.
 
-    if (m_intervalLists[y].isEmpty())
-        m_intervalLists[y].append(interval);
+    if (intervalsAt(y).isEmpty())
+        intervalsAt(y).append(interval);
     else {
-        IntShapeInterval& resultInterval = m_intervalLists[y][0];
+        IntShapeInterval& resultInterval = intervalsAt(y)[0];
         resultInterval.set(std::min(resultInterval.x1(), interval.x1()), std::max(resultInterval.x2(), interval.x2()));
     }
 
@@ -218,22 +217,25 @@ void RasterShapeIntervals::getExcludedIntervals(int y1, int y2, IntShapeInterval
 
 // Currently limited to computing the margin boundary for shape-outside for floats, see https://bugs.webkit.org/show_bug.cgi?id=116348.
 
-PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(unsigned margin) const
+PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginIntervals(unsigned shapeMargin) const
 {
-    OwnPtr<RasterShapeIntervals> result = adoptPtr(new RasterShapeIntervals(size() + margin));
-    MarginIntervalGenerator marginIntervalGenerator(margin);
+    OwnPtr<RasterShapeIntervals> result = adoptPtr(new RasterShapeIntervals(size(), shapeMargin));
+    MarginIntervalGenerator marginIntervalGenerator(shapeMargin);
+
+    int minY = bounds().y();
+    int maxY = bounds().maxY();
 
-    for (int y = bounds().y(); y < bounds().maxY(); ++y) {
+    for (int y = minY; y < maxY; ++y) {
         const IntShapeInterval& intervalAtY = limitIntervalAt(y);
         if (intervalAtY.isEmpty())
             continue;
 
         marginIntervalGenerator.set(y, intervalAtY);
-        int marginY0 = std::max(0, clampToPositiveInteger(y - margin));
-        int marginY1 = std::min(result->size() - 1, clampToPositiveInteger(y + margin));
+        int marginY0 = y - clampToInteger(shapeMargin);
+        int marginY1 = y + clampToInteger(shapeMargin);
 
         for (int marginY = y - 1; marginY >= marginY0; --marginY) {
-            if (limitIntervalAt(marginY).contains(intervalAtY))
+            if (marginY > minY && limitIntervalAt(marginY).contains(intervalAtY))
                 break;
             result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY));
         }
@@ -241,7 +243,7 @@ PassOwnPtr<RasterShapeIntervals> RasterShapeIntervals::computeShapeMarginInterva
         result->uniteMarginInterval(y, marginIntervalGenerator.intervalAt(y));
 
         for (int marginY = y + 1; marginY <= marginY1; ++marginY) {
-            if (marginY < size() && limitIntervalAt(marginY).contains(intervalAtY))
+            if (marginY < maxY && limitIntervalAt(marginY).contains(intervalAtY))
                 break;
             result->uniteMarginInterval(marginY, marginIntervalGenerator.intervalAt(marginY));
         }
index e448949..5c0190d 100644 (file)
@@ -40,9 +40,10 @@ namespace WebCore {
 
 class RasterShapeIntervals {
 public:
-    RasterShapeIntervals(unsigned size)
+    RasterShapeIntervals(unsigned size, unsigned shapeMargin = 0)
+        : m_shapeMargin(shapeMargin)
     {
-        m_intervalLists.resize(size);
+        m_intervalLists.resize(size + shapeMargin * 2);
     }
 
     const IntRect& bounds() const { return m_bounds; }
@@ -52,15 +53,21 @@ public:
     void getIncludedIntervals(int y1, int y2, IntShapeIntervals& result) const;
     void getExcludedIntervals(int y1, int y2, IntShapeIntervals& result) const;
     bool firstIncludedIntervalY(int minY, const IntSize& minSize, LayoutUnit& result) const;
-    PassOwnPtr<RasterShapeIntervals> computeShapeMarginIntervals(unsigned margin) const;
+    PassOwnPtr<RasterShapeIntervals> computeShapeMarginIntervals(unsigned shapeMargin) const;
 
 private:
     int size() const { return m_intervalLists.size(); }
 
+    IntShapeIntervals& intervalsAt(int y)
+    {
+        ASSERT(y + m_shapeMargin >= 0 && y + m_shapeMargin < m_intervalLists.size());
+        return m_intervalLists[y + m_shapeMargin];
+    }
+
     const IntShapeIntervals& intervalsAt(int y) const
     {
-        ASSERT(y >= 0 && y < size());
-        return m_intervalLists[y];
+        ASSERT(y + m_shapeMargin >= 0 && y + m_shapeMargin < m_intervalLists.size());
+        return m_intervalLists[y + m_shapeMargin];
     }
 
     IntShapeInterval limitIntervalAt(int y) const
@@ -74,6 +81,7 @@ private:
     void uniteMarginInterval(int y, const IntShapeInterval&);
     IntRect m_bounds;
     Vector<IntShapeIntervals> m_intervalLists;
+    unsigned m_shapeMargin;
 };
 
 class RasterShape : public Shape {