Skip to content
Permalink
Browse files
[CSS Exclusions] shape-outside on floats fails to respect shape-margi…
…n's vertical extent

https://bugs.webkit.org/show_bug.cgi?id=113600

Reviewed by Dirk Schulze.

Source/WebCore:

ExclusionShapeInsideInfo classes need to depend on the ExclusionShape's padded boundary and
ExclusionShapeOutsideInfo classes should depend on the ExclusionShape's margin boundary. Added
a virtual method to the ExclusionShapeInfo that returns the ExclusionShape's logical bounding box -
computedShapeLogicalBoundingBox() - and overrode that method in the subclasses to return the
value of the appropriate ExclusionShape method. Added shapeMarginLogicalBoundingBox() and
shapePaddingLogicalBoundingBox() methods to ExclusionShape and removed the shapeLogicalBoundingBox()
method, which did not take shape-margin or shape-padding into account.

Test: fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-bottom.html

* rendering/ExclusionPolygon.h: Defined the padding and margin bounding box virtual methods.
* rendering/ExclusionRectangle.h: Defined the padding and margin bounding box virtual methods.
* rendering/ExclusionShape.h: Added the padding and margin bounding box virtual abstract methods. Removed shapeLogicalBoundingBox().
(ExclusionShape):
* rendering/ExclusionShapeInfo.h:
(WebCore::ExclusionShapeInfo::shapeLogicalTop): Now calls computedShapeLogicalBoundingBox().
(WebCore::ExclusionShapeInfo::shapeLogicalBottom): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalLeft): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalRight): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalWidth): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalHeight): Ditto.
(ExclusionShapeInfo): Added computedShapeLogicalBoundingBox().
* rendering/ExclusionShapeInsideInfo.h:
(ExclusionShapeInsideInfo):
(WebCore::ExclusionShapeInsideInfo::computedShapeLogicalBoundingBox): Gets the padded shape's bounding box.
* rendering/ExclusionShapeOutsideInfo.h:
(ExclusionShapeOutsideInfo):
(WebCore::ExclusionShapeOutsideInfo::computedShapeLogicalBoundingBox): Gets the margin shape's bounding box.

LayoutTests:

Corrected the expected values in the ellipse-margin-left and ellipse-margin-right tests because the
shape-outside float layout code now (correctly) takes into account the shape's margin boundary.

* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-bottom-expected.html: Added.
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-bottom.html: Added.
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-left-expected.txt:
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-left.html:
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-right-expected.txt:
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-right.html:


Canonical link: https://commits.webkit.org/132066@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@147384 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Hans Muller committed Apr 2, 2013
1 parent f9d6734 commit db818ad42348521cced06628de590adaff864589
Showing 14 changed files with 208 additions and 39 deletions.
@@ -1,3 +1,20 @@
2013-04-01 Hans Muller <hmuller@adobe.com>

[CSS Exclusions] shape-outside on floats fails to respect shape-margin's vertical extent
https://bugs.webkit.org/show_bug.cgi?id=113600

Reviewed by Dirk Schulze.

Corrected the expected values in the ellipse-margin-left and ellipse-margin-right tests because the
shape-outside float layout code now (correctly) takes into account the shape's margin boundary.

* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-bottom-expected.html: Added.
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-bottom.html: Added.
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-left-expected.txt:
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-left.html:
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-right-expected.txt:
* fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-right.html:

2013-04-01 Adam Barth <abarth@webkit.org>

Assertion failure !m_lastChunkBeforeScript in HTMLDocumentParser during inspector/debugger/pause-in-inline-script.html
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<style>
#container-border {
border: 1px solid black;
margin: 10px;
width: 500px;
}

#container {
font: 50px/1 Ahem, sans-serif;
color: grey;
width: 500px;
height: 300px;
overflow: hidden;
}

#float-left {
float: left;
position: relative;
overflow: visible;
}

#svg-shape-ellipse {
position: absolute;
display:block;
top: 0px;
left: 0px;
width: 500px;
height: 300px;
}
</style>
<body>
<p>The five square grey Ahem-font characters should appear below outermost ellipse boundary, which is defined by the shape-margin.</p>
<div id="container-border">
<div id="container">
<div id="float-left">
<svg id="svg-shape-ellipse" xmlns="http://www.w3.org/2000/">
<ellipse cx="225" cy="125" rx="200" ry="100" fill="green"></ellipse>
<ellipse cx="225" cy="125" rx="225" ry="125" fill="none" stroke="green"></ellipse>
</svg>
</div>
<br/>
<br/>
<br/>
<br/>
<br/>
X X X X X
</div>
</body>
</html>

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<script>
if (window.internals)
window.internals.settings.setCSSExclusionsEnabled(true);
</script>

<style>
#container-border {
border: 1px solid black;
margin: 10px;
width: 500px;
}

#container {
font: 50px/1 Ahem, sans-serif;
color: grey;
width: 500px;
height: 300px;
overflow: hidden;
}

#float-left {
float: left;
position: relative;
overflow: visible;
-webkit-shape-outside: ellipse(200px, 100px, 200px, 100px);
-webkit-shape-margin: 25px;
}

#svg-shape-ellipse {
position: absolute;
display:block;
top: -25px;
left: -25px;
width: 500px;
height: 300px;
}
</style>
<body>
<p>The five square grey Ahem-font characters should appear below outermost ellipse boundary, which is defined by the shape-margin.</p>
<div id="container-border">
<div id="container">
<div id="float-left">
<svg id="svg-shape-ellipse" xmlns="http://www.w3.org/2000/">
<ellipse cx="225" cy="125" rx="200" ry="100" fill="green"></ellipse>
<ellipse cx="225" cy="125" rx="225" ry="125" fill="none" stroke="green"></ellipse>
</svg>
</div>
<br/>
<br/>
<br/>
<br/>
<br/>
X X X X X
</div>
</body>
</html>

@@ -1,9 +1,9 @@
PASS elementRect('s1').top is 0
PASS elementRect('s1').left is 373
PASS elementRect('s1').left is 347
PASS elementRect('s2').top is 20
PASS elementRect('s2').left is 397
PASS elementRect('s2').left is 390
PASS elementRect('s3').top is 40
PASS elementRect('s3').left is 413
PASS elementRect('s3').left is 417
The left edges of the three black squares should follow the outer ellipse boundary and each square should appear on a subsequent line.

X
@@ -32,8 +32,8 @@
#svg-shape-ellipse {
position: absolute;
display:block;
top: 0px;
left: 0px;
top: -25px;
left: -25px;
width: 500px;
height: 300px;
}
@@ -45,8 +45,8 @@
<div id="container">
<div id="float-left">
<svg id="svg-shape-ellipse" xmlns="http://www.w3.org/2000/">
<ellipse cx="200" cy="100" rx="200" ry="100" fill="green"></ellipse>
<ellipse cx="200" cy="100" rx="225" ry="125" fill="none" stroke="green"></ellipse>
<ellipse cx="225" cy="125" rx="200" ry="100" fill="green"></ellipse>
<ellipse cx="225" cy="125" rx="225" ry="125" fill="none" stroke="green"></ellipse>
</svg>
</div>
<span id="s1">X</span></br><span id="s2">X</span><br/><span id="s3">X</span>
@@ -63,14 +63,10 @@

// You'll find the equation for the X intercept of an elliptical arc here (among other places):
// http://hansmuller-webkit.blogspot.com/2012/07/computing-horizonal-rounded-rectangle.html
//
// Note also: only the "ellipse(200px, 100px, 200px, 100px)" itself fits within the container element. The margin
// ellipse extends above and to the left by another 25 pixels. The +25 adjustment to Y accounts for this.


function marginEllipseLeftXIntercept(y, cx, rx, ry)
{
return String( SubPixelLayout.roundLineLeft(cx + rx * Math.sqrt(1 - Math.pow((ry - (y + 25)) / ry, 2))) );
return String( SubPixelLayout.roundLineLeft(cx + rx * Math.sqrt(1 - Math.pow((ry - y) / ry, 2))) );
}

// In the ".left" tests below, it's the lower edge of the 20px Ahem glyph that that defines the element rect's left edge.
@@ -79,13 +75,13 @@
SubPixelLayout.initSubPixelLayout();

shouldBe("elementRect('s1').top", "0");
shouldBe("elementRect('s1').left", marginEllipseLeftXIntercept(20, 200, 225, 125));
shouldBe("elementRect('s1').left", marginEllipseLeftXIntercept(20, 225, 225, 125));

shouldBe("elementRect('s2').top", "20");
shouldBe("elementRect('s2').left", marginEllipseLeftXIntercept(40, 200, 225, 125));
shouldBe("elementRect('s2').left", marginEllipseLeftXIntercept(40, 225, 225, 125));

shouldBe("elementRect('s3').top", "40");
shouldBe("elementRect('s3').left", marginEllipseLeftXIntercept(60, 200, 225, 125));
shouldBe("elementRect('s3').left", marginEllipseLeftXIntercept(60, 225, 225, 125));

</script>
</html>
@@ -1,9 +1,9 @@
PASS elementRect('s1').top is 0
PASS elementRect('s1').right is 127
PASS elementRect('s1').right is 152
PASS elementRect('s2').top is 20
PASS elementRect('s2').right is 102
PASS elementRect('s2').right is 110
PASS elementRect('s3').top is 40
PASS elementRect('s3').right is 86
PASS elementRect('s3').right is 82
The right edges of the three black squares should follow the outer ellipse boundary and each square should appear on a subsequent line.

X
@@ -33,8 +33,8 @@
#svg-shape-ellipse {
position: absolute;
display:block;
top: 0px;
left: -50px;
top: -25px;
left: -25px;
width: 500px;
height: 300px;
}
@@ -46,8 +46,8 @@
<div id="container">
<div id="float-right">
<svg id="svg-shape-ellipse" xmlns="http://www.w3.org/2000/">
<ellipse cx="250" cy="100" rx="200" ry="100" fill="green"></ellipse>
<ellipse cx="250" cy="100" rx="225" ry="125" fill="none" stroke="green"></ellipse>
<ellipse cx="225" cy="125" rx="200" ry="100" fill="green"></ellipse>
<ellipse cx="225" cy="125" rx="225" ry="125" fill="none" stroke="green"></ellipse>
</svg>
</div>
<span id="s1">X</span></br><span id="s2">X</span><br/><span id="s3">X</span>
@@ -64,15 +64,11 @@

// You'll find the equation for the X intercept of an elliptical arc here (among other places):
// http://hansmuller-webkit.blogspot.com/2012/07/computing-horizonal-rounded-rectangle.html
//
// Note also: only the "ellipse(200px, 100px, 200px, 100px)" itself fits within the container element. The margin
// ellipse extends above and to the left by another 25 pixels. The +25 adjustment to Y accounts for this.


function marginEllipseRightXIntercept(y, cx, rx, ry)
{
var containerWidth = document.getElementById("container").getBoundingClientRect().width;
return String( SubPixelLayout.roundLineRight(containerWidth - (cx + rx * Math.sqrt(1 - Math.pow((ry - (y + 25)) / ry, 2)))) );
return String( SubPixelLayout.roundLineRight(containerWidth - (cx + rx * Math.sqrt(1 - Math.pow((ry - y) / ry, 2)))) );
}

// In the ".right" tests below, it's the lower edge of the 20px Ahem glyph that that defines the element rect's left edge.
@@ -81,13 +77,13 @@
SubPixelLayout.initSubPixelLayout();

shouldBe("elementRect('s1').top", "0");
shouldBe("elementRect('s1').right", marginEllipseRightXIntercept(20, 200, 225, 125));
shouldBe("elementRect('s1').right", marginEllipseRightXIntercept(20, 225, 225, 125));

shouldBe("elementRect('s2').top", "20");
shouldBe("elementRect('s2').right", marginEllipseRightXIntercept(40, 200, 225, 125));
shouldBe("elementRect('s2').right", marginEllipseRightXIntercept(40, 225, 225, 125));

shouldBe("elementRect('s3').top", "40");
shouldBe("elementRect('s3').right", marginEllipseRightXIntercept(60, 200, 225, 125));
shouldBe("elementRect('s3').right", marginEllipseRightXIntercept(60, 225, 225, 125));

</script>
</html>
@@ -1,3 +1,39 @@
2013-04-01 Hans Muller <hmuller@adobe.com>

[CSS Exclusions] shape-outside on floats fails to respect shape-margin's vertical extent
https://bugs.webkit.org/show_bug.cgi?id=113600

Reviewed by Dirk Schulze.

ExclusionShapeInsideInfo classes need to depend on the ExclusionShape's padded boundary and
ExclusionShapeOutsideInfo classes should depend on the ExclusionShape's margin boundary. Added
a virtual method to the ExclusionShapeInfo that returns the ExclusionShape's logical bounding box -
computedShapeLogicalBoundingBox() - and overrode that method in the subclasses to return the
value of the appropriate ExclusionShape method. Added shapeMarginLogicalBoundingBox() and
shapePaddingLogicalBoundingBox() methods to ExclusionShape and removed the shapeLogicalBoundingBox()
method, which did not take shape-margin or shape-padding into account.

Test: fast/exclusions/shape-outside-floats/shape-outside-floats-ellipse-margin-bottom.html

* rendering/ExclusionPolygon.h: Defined the padding and margin bounding box virtual methods.
* rendering/ExclusionRectangle.h: Defined the padding and margin bounding box virtual methods.
* rendering/ExclusionShape.h: Added the padding and margin bounding box virtual abstract methods. Removed shapeLogicalBoundingBox().
(ExclusionShape):
* rendering/ExclusionShapeInfo.h:
(WebCore::ExclusionShapeInfo::shapeLogicalTop): Now calls computedShapeLogicalBoundingBox().
(WebCore::ExclusionShapeInfo::shapeLogicalBottom): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalLeft): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalRight): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalWidth): Ditto.
(WebCore::ExclusionShapeInfo::shapeLogicalHeight): Ditto.
(ExclusionShapeInfo): Added computedShapeLogicalBoundingBox().
* rendering/ExclusionShapeInsideInfo.h:
(ExclusionShapeInsideInfo):
(WebCore::ExclusionShapeInsideInfo::computedShapeLogicalBoundingBox): Gets the padded shape's bounding box.
* rendering/ExclusionShapeOutsideInfo.h:
(ExclusionShapeOutsideInfo):
(WebCore::ExclusionShapeOutsideInfo::computedShapeLogicalBoundingBox): Gets the margin shape's bounding box.

2013-04-01 Adam Barth <abarth@webkit.org>

Assertion failure !m_lastChunkBeforeScript in HTMLDocumentParser during inspector/debugger/pause-in-inline-script.html
@@ -80,7 +80,8 @@ class ExclusionPolygon : public ExclusionShape {
{
}

virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return m_polygon.boundingBox(); }
virtual FloatRect shapeMarginLogicalBoundingBox() const OVERRIDE { return shapeMarginBounds().boundingBox(); }
virtual FloatRect shapePaddingLogicalBoundingBox() const OVERRIDE { return shapePaddingBounds().boundingBox(); }
virtual bool isEmpty() const OVERRIDE { return m_polygon.isEmpty(); }
virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
@@ -68,7 +68,8 @@ class ExclusionRectangle : public ExclusionShape {
{
}

virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return m_bounds; }
virtual FloatRect shapeMarginLogicalBoundingBox() const OVERRIDE { return shapeMarginBounds(); }
virtual FloatRect shapePaddingLogicalBoundingBox() const OVERRIDE { return shapePaddingBounds(); }
virtual bool isEmpty() const OVERRIDE { return m_bounds.isEmpty(); }
virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const OVERRIDE;
@@ -65,7 +65,8 @@ class ExclusionShape {

float shapeMargin() const { return m_margin; }
float shapePadding() const { return m_padding; }
virtual FloatRect shapeLogicalBoundingBox() const = 0;
virtual FloatRect shapeMarginLogicalBoundingBox() const = 0;
virtual FloatRect shapePaddingLogicalBoundingBox() const = 0;
virtual bool isEmpty() const = 0;
virtual void getIncludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const = 0;
virtual void getExcludedIntervals(float logicalTop, float logicalHeight, SegmentList&) const = 0;
@@ -86,12 +86,12 @@ class ExclusionShapeInfo {

virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight);

LayoutUnit shapeLogicalTop() const { return floatLogicalTopToLayoutUnit(computedShape()->shapeLogicalBoundingBox().y()) + logicalTopOffset(); }
LayoutUnit shapeLogicalBottom() const { return floatLogicalBottomToLayoutUnit(computedShape()->shapeLogicalBoundingBox().maxY()) + logicalTopOffset(); }
LayoutUnit shapeLogicalLeft() const { return computedShape()->shapeLogicalBoundingBox().x() + logicalLeftOffset(); }
LayoutUnit shapeLogicalRight() const { return computedShape()->shapeLogicalBoundingBox().maxX() + logicalLeftOffset(); }
LayoutUnit shapeLogicalWidth() const { return computedShape()->shapeLogicalBoundingBox().width(); }
LayoutUnit shapeLogicalHeight() const { return computedShape()->shapeLogicalBoundingBox().height(); }
LayoutUnit shapeLogicalTop() const { return floatLogicalTopToLayoutUnit(computedShapeLogicalBoundingBox().y()) + logicalTopOffset(); }
LayoutUnit shapeLogicalBottom() const { return floatLogicalBottomToLayoutUnit(computedShapeLogicalBoundingBox().maxY()) + logicalTopOffset(); }
LayoutUnit shapeLogicalLeft() const { return computedShapeLogicalBoundingBox().x() + logicalLeftOffset(); }
LayoutUnit shapeLogicalRight() const { return computedShapeLogicalBoundingBox().maxX() + logicalLeftOffset(); }
LayoutUnit shapeLogicalWidth() const { return computedShapeLogicalBoundingBox().width(); }
LayoutUnit shapeLogicalHeight() const { return computedShapeLogicalBoundingBox().height(); }

LayoutUnit logicalLineTop() const { return m_shapeLineTop + logicalTopOffset(); }
LayoutUnit logicalLineBottom() const { return m_shapeLineTop + m_lineHeight + logicalTopOffset(); }
@@ -106,6 +106,7 @@ class ExclusionShapeInfo {
ExclusionShapeInfo(const RenderType* renderer): m_renderer(renderer) { }

const ExclusionShape* computedShape() const;
virtual FloatRect computedShapeLogicalBoundingBox() const = 0;

// Use ceil and floor to ensure that the returned LayoutUnit value is within the shape's bounds.
LayoutUnit floatLogicalTopToLayoutUnit(float logicalTop) const { return LayoutUnit::fromFloatCeil(logicalTop); }
@@ -97,6 +97,9 @@ class ExclusionShapeInsideInfo : public ExclusionShapeInfo<RenderBlock, &RenderS
void setNeedsLayout(bool value) { m_needsLayout = value; }
bool needsLayout() { return m_needsLayout; }

protected:
virtual FloatRect computedShapeLogicalBoundingBox() const OVERRIDE { return computedShape()->shapePaddingLogicalBoundingBox(); }

private:
ExclusionShapeInsideInfo(const RenderBlock* renderer)
: ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &ExclusionShape::getIncludedIntervals> (renderer)
@@ -50,6 +50,10 @@ class ExclusionShapeOutsideInfo : public ExclusionShapeInfo<RenderBox, &RenderSt

static PassOwnPtr<ExclusionShapeOutsideInfo> createInfo(const RenderBox* renderer) { return adoptPtr(new ExclusionShapeOutsideInfo(renderer)); }
static bool isEnabledFor(const RenderBox*);

protected:
virtual FloatRect computedShapeLogicalBoundingBox() const OVERRIDE { return computedShape()->shapeMarginLogicalBoundingBox(); }

private:
ExclusionShapeOutsideInfo(const RenderBox* renderer) : ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside, &ExclusionShape::getExcludedIntervals>(renderer) { }

0 comments on commit db818ad

Please sign in to comment.