[CSS Exclusions] shape-inside layout fails to adjust first line correctly for writing...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Dec 2012 19:08:41 +0000 (19:08 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Dec 2012 19:08:41 +0000 (19:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=104419

Patch by Hans Muller <hmuller@adobe.com> on 2012-12-18
Reviewed by Dirk Schulze.

Source/WebCore:

ExclusionShapes no longer maintain a private "internal" coordinate system,
they're now defined in logical coordinates. The createExclusionShape() method
now handles the one-time conversion from physical to logical coordinates.

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

* rendering/ExclusionPolygon.cpp:
(WebCore::ExclusionPolygon::getExcludedIntervals): Removed logical to internal coordinate conversions.
(WebCore::ExclusionPolygon::getIncludedIntervals): Ditto.
(WebCore::ExclusionPolygon::firstIncludedIntervalLogicalTop): Ditto.
* rendering/ExclusionPolygon.h:
* rendering/ExclusionRectangle.cpp:
(WebCore::ExclusionRectangle::getExcludedIntervals): Removed logical to internal coordinate conversions.
(WebCore::ExclusionRectangle::getIncludedIntervals): Ditto.
(WebCore::ExclusionRectangle::firstIncludedIntervalLogicalTop): Ditto.
* rendering/ExclusionRectangle.h:
* rendering/ExclusionShape.cpp:
(WebCore::physicalRectToLogical): Convert a FloatRect defined with coordinates to logical coordinates.
(WebCore::physicalPointToLogical): Similar.
(WebCore::physicalSizeToLogical): Simlar.
(WebCore::ExclusionShape::createExclusionShape): Convert shapes from physical to logical coordinates.
* rendering/ExclusionShape.h:
(ExclusionShape): Removed internal to logical coordinate conversion utility methods.

LayoutTests:

For the vertical writing modes, verify that rounded rectangle shape-inside content is
adjusted in the logical down direction when it will not fit betwen the rounded corners.

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

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

LayoutTests/ChangeLog
LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003-expected.html [new file with mode: 0644]
LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/ExclusionPolygon.cpp
Source/WebCore/rendering/ExclusionPolygon.h
Source/WebCore/rendering/ExclusionRectangle.cpp
Source/WebCore/rendering/ExclusionRectangle.h
Source/WebCore/rendering/ExclusionShape.cpp
Source/WebCore/rendering/ExclusionShape.h

index 7c47e9d..c3ef12b 100644 (file)
@@ -1,3 +1,16 @@
+2012-12-18  Hans Muller  <hmuller@adobe.com>
+
+        [CSS Exclusions] shape-inside layout fails to adjust first line correctly for writing-mode: vertical-rl
+        https://bugs.webkit.org/show_bug.cgi?id=104419
+
+        Reviewed by Dirk Schulze.
+
+        For the vertical writing modes, verify that rounded rectangle shape-inside content is
+        adjusted in the logical down direction when it will not fit betwen the rounded corners.
+
+        * fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003-expected.html: Added.
+        * fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003.html: Added.
+
 2012-12-18  Bear Travis  <betravis@adobe.com>
 
         [CSS Exclusions] Blocks should not re-use their parent's ExclusionShapeInsideInfo
diff --git a/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003-expected.html b/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003-expected.html
new file mode 100644 (file)
index 0000000..66f4f6f
--- /dev/null
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+    if (window.internals)
+        window.internals.settings.setCSSExclusionsEnabled(true);
+</script>
+<style>
+.shape-container {
+    position: relative;
+    width: 400px;
+    height: 200px;
+    margin: 10px;
+}
+
+.shape-background {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    width: 400px;
+    height: 200px;
+    border-radius: 50px / 50px;
+    background-color: rgb(200,200,200);
+}
+
+.shape-inside-vertical-rl {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    width: 400px;
+    height: 200px;
+    -webkit-writing-mode: vertical-rl;
+    font: 50px/1 Ahem, sans-serif;
+    color: green;
+}
+
+.shape-inside-vertical-lr {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    width: 400px;
+    height: 200px;
+    -webkit-writing-mode: vertical-lr;
+    font: 50px/1 Ahem, sans-serif;
+    color: green;
+}
+</style>
+</head>
+<body>
+<p>The green rectangle should appear just to the left of the grey rounded rectangle's upper corners.</p>
+<div class="shape-container">
+  <div class="shape-background"></div>
+  <div class="shape-inside-vertical-rl"><br/>XXXX</div>
+</div>
+</p>
+
+<p>The green rectangle should appear just to the left of the grey rounded rectangle's upper corners.</p>
+<div class="shape-container">
+  <div class="shape-background"></div>
+  <div class="shape-inside-vertical-lr"><br/>XXXX</div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003.html b/LayoutTests/fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003.html
new file mode 100644 (file)
index 0000000..9e9ce81
--- /dev/null
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+    if (window.internals)
+        window.internals.settings.setCSSExclusionsEnabled(true);
+</script>
+<style>
+.shape-container {
+    position: relative;
+    width: 400px;
+    height: 200px;
+    margin: 10px;
+}
+
+.shape-background {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    width: 400px;
+    height: 200px;
+    border-radius: 50px / 50px;
+    background-color: rgb(200,200,200);
+}
+
+.shape-inside-vertical-rl {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    width: 400px;
+    height: 200px;
+    -webkit-shape-inside: rectangle(0px, 0px, 400px, 200px, 50px, 50px);
+    -webkit-writing-mode: vertical-rl;
+    font: 50px/1 Ahem, sans-serif;
+    color: green;
+}
+
+.shape-inside-vertical-lr {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    width: 400px;
+    height: 200px;
+    -webkit-shape-inside: rectangle(0px, 0px, 400px, 200px, 50px, 50px);
+    -webkit-writing-mode: vertical-lr;
+    font: 50px/1 Ahem, sans-serif;
+    color: green;
+}
+</style>
+</head>
+<body>
+<p>The green rectangle should appear just to the left of the grey rounded rectangle's upper corners.</p>
+<div class="shape-container">
+  <div class="shape-background"></div>
+  <div class="shape-inside-vertical-rl">XXXX</div>
+</div>
+</p>
+
+<p>The green rectangle should appear just to the left of the grey rounded rectangle's upper corners.</p>
+<div class="shape-container">
+  <div class="shape-background"></div>
+  <div class="shape-inside-vertical-lr">XXXX</div>
+</div>
+</body>
+</html>
index d3c324b..7f489a6 100644 (file)
@@ -1,3 +1,34 @@
+2012-12-18  Hans Muller  <hmuller@adobe.com>
+
+        [CSS Exclusions] shape-inside layout fails to adjust first line correctly for writing-mode: vertical-rl
+        https://bugs.webkit.org/show_bug.cgi?id=104419
+
+        Reviewed by Dirk Schulze.
+
+        ExclusionShapes no longer maintain a private "internal" coordinate system,
+        they're now defined in logical coordinates. The createExclusionShape() method
+        now handles the one-time conversion from physical to logical coordinates.
+
+        Test: fast/exclusions/shape-inside/shape-inside-rounded-rectangle-fit-003.html
+
+        * rendering/ExclusionPolygon.cpp:
+        (WebCore::ExclusionPolygon::getExcludedIntervals): Removed logical to internal coordinate conversions.
+        (WebCore::ExclusionPolygon::getIncludedIntervals): Ditto.
+        (WebCore::ExclusionPolygon::firstIncludedIntervalLogicalTop): Ditto.
+        * rendering/ExclusionPolygon.h:
+        * rendering/ExclusionRectangle.cpp:
+        (WebCore::ExclusionRectangle::getExcludedIntervals): Removed logical to internal coordinate conversions.
+        (WebCore::ExclusionRectangle::getIncludedIntervals): Ditto.
+        (WebCore::ExclusionRectangle::firstIncludedIntervalLogicalTop): Ditto.
+        * rendering/ExclusionRectangle.h:
+        * rendering/ExclusionShape.cpp:
+        (WebCore::physicalRectToLogical): Convert a FloatRect defined with coordinates to logical coordinates.
+        (WebCore::physicalPointToLogical): Similar.
+        (WebCore::physicalSizeToLogical): Simlar.
+        (WebCore::ExclusionShape::createExclusionShape): Convert shapes from physical to logical coordinates.
+        * rendering/ExclusionShape.h:
+        (ExclusionShape): Removed internal to logical coordinate conversion utility methods.
+
 2012-12-17  Emil A Eklund  <eae@chromium.org>
 
         Optimize LayoutUnit::boundedMultiply
index 94b93dc..b6aec08 100644 (file)
@@ -327,8 +327,8 @@ void ExclusionPolygon::getExcludedIntervals(float logicalTop, float logicalHeigh
     if (isEmpty())
         return;
 
-    float y1 = minYForLogicalLine(logicalTop, logicalHeight);
-    float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
+    float y1 = logicalTop;
+    float y2 = y1 + logicalHeight;
 
     Vector<ExclusionInterval> y1XIntervals, y2XIntervals;
     computeXIntersections(y1, true, y1XIntervals);
@@ -354,8 +354,8 @@ void ExclusionPolygon::getIncludedIntervals(float logicalTop, float logicalHeigh
     if (isEmpty())
         return;
 
-    float y1 = minYForLogicalLine(logicalTop, logicalHeight);
-    float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
+    float y1 = logicalTop;
+    float y2 = y1 + logicalHeight;
 
     Vector<ExclusionInterval> y1XIntervals, y2XIntervals;
     computeXIntersections(y1, true, y1XIntervals);
@@ -383,8 +383,8 @@ bool ExclusionPolygon::firstIncludedIntervalLogicalTop(float minLogicalIntervalT
     if (minLogicalIntervalSize.width() > m_boundingBox.width())
         return false;
 
-    float minY = minYForLogicalLine(minLogicalIntervalTop, minLogicalIntervalSize.height());
-    float maxY = maxYForLogicalLine(minLogicalIntervalTop, minLogicalIntervalSize.height());
+    float minY = std::max(m_boundingBox.y(), minLogicalIntervalTop);
+    float maxY = minY + minLogicalIntervalSize.height();
     if (minY < m_boundingBox.y() || maxY > m_boundingBox.maxY())
         return false;
 
index 25fc6f7..ce2fb55 100644 (file)
@@ -62,7 +62,7 @@ public:
     const ExclusionPolygonEdge& edgeAt(unsigned index) const { return m_edges[index]; }
     unsigned numberOfEdges() const { return m_edges.size(); }
 
-    virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return internalToLogicalBoundingBox(m_boundingBox); }
+    virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return m_boundingBox; }
     virtual bool isEmpty() const OVERRIDE { return m_empty; }
     virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
     virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
index 9bd22d5..ebe6a84 100644 (file)
@@ -51,8 +51,8 @@ void ExclusionRectangle::getExcludedIntervals(float logicalTop, float logicalHei
     if (isEmpty())
         return;
 
-    float y1 = minYForLogicalLine(logicalTop, logicalHeight);
-    float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
+    float y1 = logicalTop;
+    float y2 = y1 + logicalHeight;
 
     if (y2 < m_y || y1 >= m_y + m_height)
         return;
@@ -82,8 +82,8 @@ void ExclusionRectangle::getIncludedIntervals(float logicalTop, float logicalHei
     if (isEmpty())
         return;
 
-    float y1 = minYForLogicalLine(logicalTop, logicalHeight);
-    float y2 = maxYForLogicalLine(logicalTop, logicalHeight);
+    float y1 = logicalTop;
+    float y2 = y1 + logicalHeight;
 
     if (y1 < m_y || y2 > m_y + m_height)
         return;
@@ -133,8 +133,9 @@ bool ExclusionRectangle::firstIncludedIntervalLogicalTop(float minLogicalInterva
     if (minLogicalIntervalSize.width() > m_width)
         return false;
 
-    float minY = std::max(m_y, minYForLogicalLine(minLogicalIntervalTop, minLogicalIntervalSize.height()));
+    float minY = std::max(m_y, minLogicalIntervalTop);
     float maxY = minY + minLogicalIntervalSize.height();
+
     if (maxY > m_y + m_height)
         return false;
 
@@ -142,7 +143,7 @@ bool ExclusionRectangle::firstIncludedIntervalLogicalTop(float minLogicalInterva
     bool intervalOverlapsMaxCorner = maxY > m_y + m_height - m_ry;
 
     if (!intervalOverlapsMinCorner && !intervalOverlapsMaxCorner) {
-        result = logicalTopForMinY(minY, minLogicalIntervalSize.height());
+        result = minY;
         return true;
     }
 
@@ -153,18 +154,18 @@ bool ExclusionRectangle::firstIncludedIntervalLogicalTop(float minLogicalInterva
 
     if (intervalOverlapsMinCorner && (!intervalOverlapsMaxCorner || minCornerDefinesX)) {
         if (intervalFitsWithinCorners || m_y + cornerIntercept.y() < minY) {
-            result = logicalTopForMinY(minY, minLogicalIntervalSize.height());
+            result = minY;
             return true;
         }
         if (minLogicalIntervalSize.height() < m_height - (2 * cornerIntercept.y())) {
-            result = logicalTopForMinY(m_y + cornerIntercept.y(), minLogicalIntervalSize.height());
+            result = m_y + cornerIntercept.y();
             return true;
         }
     }
 
     if (intervalOverlapsMaxCorner && (!intervalOverlapsMinCorner || !minCornerDefinesX)) {
         if (intervalFitsWithinCorners || minY <=  m_y + m_height - cornerIntercept.y() - minLogicalIntervalSize.height()) {
-            result = logicalTopForMinY(minY, minLogicalIntervalSize.height());
+            result = minY;
             return true;
         }
     }
index 66382c8..c8a6538 100644 (file)
@@ -51,7 +51,7 @@ public:
     {
     }
 
-    virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return internalToLogicalBoundingBox(FloatRect(m_x, m_y, m_width, m_height)); }
+    virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return FloatRect(m_x, m_y, m_width, m_height); }
     virtual bool isEmpty() const OVERRIDE { return m_width <= 0 || m_height <= 0; }
     virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
     virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
index 5e0ea8b..2b31581 100644 (file)
@@ -65,8 +65,30 @@ static PassOwnPtr<ExclusionShape> createExclusionPolygon(PassOwnPtr<Vector<Float
     return adoptPtr(new ExclusionPolygon(vertices, fillRule));
 }
 
-// If the writingMode is vertical, then the BasicShape's (physical) x and y coordinates are swapped, so that
-// line segments are parallel to the internal coordinate system's X axis.
+static inline FloatRect physicalRectToLogical(const FloatRect& rect, float logicalBoxHeight, WritingMode writingMode)
+{
+    if (isHorizontalWritingMode(writingMode))
+        return rect;
+    if (isFlippedBlocksWritingMode(writingMode))
+        return FloatRect(rect.y(), logicalBoxHeight - rect.maxX(), rect.height(), rect.width());
+    return rect.transposedRect();
+}
+
+static inline FloatPoint physicalPointToLogical(const FloatPoint& point, float logicalBoxHeight, WritingMode writingMode)
+{
+    if (isHorizontalWritingMode(writingMode))
+        return point;
+    if (isFlippedBlocksWritingMode(writingMode))
+        return FloatPoint(point.y(), logicalBoxHeight - point.x());
+    return point.transposedPoint();
+}
+
+static inline FloatSize physicalSizeToLogical(const FloatSize& size, WritingMode writingMode)
+{
+    if (isHorizontalWritingMode(writingMode))
+        return size;
+    return size.transposedSize();
+}
 
 PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape* basicShape, float logicalBoxWidth, float logicalBoxHeight, WritingMode writingMode)
 {
@@ -91,11 +113,10 @@ PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape
         FloatSize cornerRadii(
             radiusXLength.isUndefined() ? 0 : floatValueForLength(radiusXLength, boxWidth),
             radiusYLength.isUndefined() ? 0 : floatValueForLength(radiusYLength, boxHeight));
+        FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxHeight, writingMode);
 
-        exclusionShape = horizontalWritingMode
-            ? createExclusionRectangle(bounds, cornerRadii)
-            : createExclusionRectangle(bounds.transposedRect(), cornerRadii.transposedSize());
-        exclusionShape->m_boundingBox = bounds;
+        exclusionShape = createExclusionRectangle(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode));
+        exclusionShape->m_boundingBox = logicalBounds;
         break;
     }
 
@@ -104,11 +125,10 @@ PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape
         float centerX = floatValueForLength(circle->centerX(), boxWidth);
         float centerY = floatValueForLength(circle->centerY(), boxHeight);
         float radius =  floatValueForLength(circle->radius(), std::max(boxHeight, boxWidth));
+        FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxHeight, writingMode);
 
-        exclusionShape = horizontalWritingMode
-            ? createExclusionCircle(FloatPoint(centerX, centerY), radius)
-            : createExclusionCircle(FloatPoint(centerY, centerX), radius);
-        exclusionShape->m_boundingBox = FloatRect(centerX - radius, centerY - radius, radius * 2, radius * 2);
+        exclusionShape = createExclusionCircle(logicalCenter, radius);
+        exclusionShape->m_boundingBox = FloatRect(logicalCenter.x() - radius, logicalCenter.y() - radius, radius * 2, radius * 2);
         break;
     }
 
@@ -118,11 +138,11 @@ PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape
         float centerY = floatValueForLength(ellipse->centerY(), boxHeight);
         float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth);
         float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight);
+        FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxHeight, writingMode);
+        FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode);
 
-        exclusionShape = horizontalWritingMode
-            ? createExclusionEllipse(FloatPoint(centerX, centerY), FloatSize(radiusX, radiusY))
-            : createExclusionEllipse(FloatPoint(centerY, centerX), FloatSize(radiusY, radiusX));
-        exclusionShape->m_boundingBox = FloatRect(centerX - radiusX, centerY - radiusY, radiusX * 2, radiusY * 2);
+        exclusionShape = createExclusionEllipse(logicalCenter, logicalRadii);
+        exclusionShape->m_boundingBox = FloatRect(logicalCenter - logicalRadii, logicalRadii + logicalRadii);
         break;
     }
 
@@ -137,7 +157,7 @@ PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape
             FloatPoint vertex(
                 floatValueForLength(values.at(i), boxWidth),
                 floatValueForLength(values.at(i + 1), boxHeight));
-            (*vertices)[i / 2] = horizontalWritingMode ? vertex : vertex.transposedPoint();
+            (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxHeight, writingMode);
             if (!i)
                 boundingBox.setLocation(vertex);
             else
index 36dc1b6..b2da3c6 100644 (file)
@@ -69,12 +69,6 @@ public:
     virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const = 0;
     virtual bool firstIncludedIntervalLogicalTop(float minLogicalIntervalTop, const FloatSize& minLogicalIntervalSize, float& result) const = 0;
 
-protected:
-    float minYForLogicalLine(float logicalTop, float logicalHeight) const { return isFlippedBlocksWritingMode(m_writingMode) ? m_logicalBoxHeight - logicalTop - logicalHeight : logicalTop; }
-    float maxYForLogicalLine(float logicalTop, float logicalHeight) const { return  isFlippedBlocksWritingMode(m_writingMode) ? m_logicalBoxHeight - logicalTop : logicalTop + logicalHeight; }
-    FloatRect internalToLogicalBoundingBox(const FloatRect& r) const { return isFlippedBlocksWritingMode(m_writingMode) ? FloatRect(r.x(), m_logicalBoxHeight - r.maxY(), r.width(), r.height()) : r; }
-    float logicalTopForMinY(float minY, float logicalHeight) const { return isFlippedBlocksWritingMode(m_writingMode) ? m_logicalBoxHeight - minY - logicalHeight : minY; }
-
 private:
     WritingMode m_writingMode;
     float m_logicalBoxWidth;