Commit c9a0f733 authored by hmuller@adobe.com's avatar hmuller@adobe.com

<https://webkit.org/b/119849> [CSS Shapes] Complete RasterShape::firstIncludedIntervalLogicalTop()

Reviewed by Alexandru Chiculita.

Source/WebCore:

Completed the implementation of RasterShape::firstIncludedIntervalLogicalTop(). The
method now computes first logical top location where a line segment can be laid
out within a RasterShape, i.e. a shape derived from an image valued URL resource.

A detailed description of the algorithm can be found in
http://hansmuller-webkit.blogspot.com/2013/08/first-fit-location-for-image-shapes.html.

The new tests exposed a bug in the existing getIncludedIntervals() method. A shape
with a vertical gap that spans the entire line now causes the method to short circuit
and return an empty interval list.

Tests: fast/shapes/shape-inside/shape-inside-image-003.html
       fast/shapes/shape-inside/shape-inside-image-004.html
       fast/shapes/shape-inside/shape-inside-image-005.html

* rendering/shapes/RasterShape.cpp:
(WebCore::RasterShapeIntervals::firstIncludedIntervalY):
(WebCore::RasterShapeIntervals::getIncludedIntervals):
(WebCore::RasterShape::firstIncludedIntervalLogicalTop):
* rendering/shapes/RasterShape.h:

LayoutTests:

Verify that the first fit algorithm works correctly for complex image shapes.
For this set of tests the image is specified with an SVG file.

* fast/shapes/resources/svg-shape-001.svg: Added.
* fast/shapes/shape-inside/shape-inside-image-003-expected.html: Added.
* fast/shapes/shape-inside/shape-inside-image-003.html: Added.
* fast/shapes/shape-inside/shape-inside-image-004-expected.html: Added.
* fast/shapes/shape-inside/shape-inside-image-004.html: Added.
* fast/shapes/shape-inside/shape-inside-image-005-expected.html: Added.
* fast/shapes/shape-inside/shape-inside-image-005.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@154349 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 469f39e9
2013-08-20 Hans Muller <hmuller@adobe.com>
<https://webkit.org/b/119849> [CSS Shapes] Complete RasterShape::firstIncludedIntervalLogicalTop()
Reviewed by Alexandru Chiculita.
Verify that the first fit algorithm works correctly for complex image shapes.
For this set of tests the image is specified with an SVG file.
* fast/shapes/resources/svg-shape-001.svg: Added.
* fast/shapes/shape-inside/shape-inside-image-003-expected.html: Added.
* fast/shapes/shape-inside/shape-inside-image-003.html: Added.
* fast/shapes/shape-inside/shape-inside-image-004-expected.html: Added.
* fast/shapes/shape-inside/shape-inside-image-004.html: Added.
* fast/shapes/shape-inside/shape-inside-image-005-expected.html: Added.
* fast/shapes/shape-inside/shape-inside-image-005.html: Added.
2013-08-20 Michael Saboff <msaboff@apple.com>
https://bugs.webkit.org/show_bug.cgi?id=120075
<svg fill="blue" width="400px" height="400px" xmlns="http://www.w3.org/2000/svg">
<!--
This file defines a shape that's a small symmetrical stack of 3 rectilinear polygons.
The shape looks like the following text, where each X represents a 50x50 block of blue pixels:
XXXXX
XXX
X
XXX
XXXXX
-->
<rect x="0" y="0" width="250" height="50"/>
<rect x="50" y="100" width="150" height="50"/>
<rect x="100" y="150" width="50" height="50"/>
<rect x="50" y="200" width="150" height="50"/>
<rect x="0" y="300" width="250" height="50"/>
</svg>
<!DOCTYPE html>
<html>
<head>
<style>
#image-shape {
font: 50px/1 Ahem, sans-serif;
margin: 0px;
color: green;
width: 350px;
height: 350px;
background-image: url("../resources/svg-shape-001.svg");
background-repeat: no-repeat;
}
</style>
<body>
<p id="informative-text">
This test requires the Ahem font. It uses svg-shape-001.svg to define a shape-inside.
The content should just cover the blue background shape with solid green.</p>
<pre id="image-shape">
XXXXX
XXX
X
XXX
XXXXX
</pre>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script>
if (window.internals)
window.internals.settings.setCSSShapesEnabled(true);
</script>
<style>
#image-shape {
font: 50px/1 Ahem, sans-serif;
color: green;
width: 250px;
height: 350px;
-webkit-shape-inside: url("../resources/svg-shape-001.svg");
background-image: url("../resources/svg-shape-001.svg");
background-repeat: no-repeat;
}
</style>
<body>
<p id="informative-text">
This test requires the Ahem font. It uses svg-shape-001.svg to define a shape-inside.
The content should just cover the blue background shape with solid green.</p>
<div id="image-shape">XXXXX XXX X XXX XXXXX</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<style>
#image-shape {
font: 50px/1 Ahem, sans-serif;
margin: 0px;
color: green;
width: 350px;
height: 350px;
background-image: url("../resources/svg-shape-001.svg");
background-repeat: no-repeat;
}
</style>
<body>
<p id="informative-text">
This test requires the Ahem font. It uses svg-shape-001.svg to define a shape-inside.
If the first-fit algorithm is working correctly, the single green 50x50 char should
appear in the center of the blue background shape, which is defined by the same SVG.</p>
<pre id="image-shape">
X
</pre>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script>
if (window.internals)
window.internals.settings.setCSSShapesEnabled(true);
</script>
<style>
#image-shape {
font: 50px/150px Ahem, sans-serif;
color: green;
width: 250px;
height: 350px;
-webkit-shape-inside: url("../resources/svg-shape-001.svg");
background-image: url("../resources/svg-shape-001.svg");
background-repeat: no-repeat;
}
</style>
<body>
<p id="informative-text">
This test requires the Ahem font. It uses svg-shape-001.svg to define a shape-inside.
If the first-fit algorithm is working correctly, the single green 50x50 char should
appear in the center of the blue background shape, which is defined by the same SVG.</p>
<div id="image-shape">X</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<style>
#image-shape {
font: 50px/1 Ahem, sans-serif;
margin: 0px;
color: green;
width: 350px;
height: 350px;
background-image: url("../resources/svg-shape-001.svg");
background-repeat: no-repeat;
}
</style>
<body>
<p id="informative-text">
This test requires the Ahem font. It uses svg-shape-001.svg to define a shape-inside.
If the first-fit algorithm is working correctly, the second and fourth rows of the
blue SVG shape should be covered by green rectangles.</p>
<pre id="image-shape">
XXX
XXX
</pre>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script>
if (window.internals)
window.internals.settings.setCSSShapesEnabled(true);
</script>
<style>
#image-shape {
font: 50px/1 Ahem, sans-serif;
color: green;
width: 250px;
height: 350px;
-webkit-shape-inside: url("../resources/svg-shape-001.svg");
background-image: url("../resources/svg-shape-001.svg");
background-repeat: no-repeat;
}
</style>
<body>
<p id="informative-text">
This test requires the Ahem font. It uses svg-shape-001.svg to define a shape-inside.
If the first-fit algorithm is working correctly, the second and fourth rows of the
blue SVG shape should be covered by green rectangles.</p>
<div id="image-shape"></br>XXX XXX</div>
</body>
</html>
2013-08-20 Hans Muller <hmuller@adobe.com>
<https://webkit.org/b/119849> [CSS Shapes] Complete RasterShape::firstIncludedIntervalLogicalTop()
Reviewed by Alexandru Chiculita.
Completed the implementation of RasterShape::firstIncludedIntervalLogicalTop(). The
method now computes first logical top location where a line segment can be laid
out within a RasterShape, i.e. a shape derived from an image valued URL resource.
A detailed description of the algorithm can be found in
http://hansmuller-webkit.blogspot.com/2013/08/first-fit-location-for-image-shapes.html.
The new tests exposed a bug in the existing getIncludedIntervals() method. A shape
with a vertical gap that spans the entire line now causes the method to short circuit
and return an empty interval list.
Tests: fast/shapes/shape-inside/shape-inside-image-003.html
fast/shapes/shape-inside/shape-inside-image-004.html
fast/shapes/shape-inside/shape-inside-image-005.html
* rendering/shapes/RasterShape.cpp:
(WebCore::RasterShapeIntervals::firstIncludedIntervalY):
(WebCore::RasterShapeIntervals::getIncludedIntervals):
(WebCore::RasterShape::firstIncludedIntervalLogicalTop):
* rendering/shapes/RasterShape.h:
2013-08-20 Pratik Solanki <psolanki@apple.com>
<https://webkit.org/b/120029> Document::markers() should return a reference
......@@ -48,6 +48,28 @@ void RasterShapeIntervals::addInterval(int y, int x1, int x2)
m_bounds.clear();
}
bool RasterShapeIntervals::firstIncludedIntervalY(int minY, const IntSize& minSize, LayoutUnit& result) const
{
for (int y = minY; y <= bounds().maxY() - minSize.height(); y++) {
Region lineRegion(IntRect(bounds().x(), y, bounds().width(), minSize.height()));
lineRegion.intersect(m_region);
if (lineRegion.isEmpty())
continue;
const Vector<IntRect>& lineRects = lineRegion.rects();
ASSERT(lineRects.size() > 0);
for (unsigned i = 0; i < lineRects.size(); i++) {
IntRect rect = lineRects[i];
if (rect.width() >= minSize.width() && lineRegion.contains(Region(IntRect(IntPoint(rect.x(), y), minSize)))) {
result = y;
return true;
}
}
}
return false;
}
static inline IntRect alignedRect(IntRect r, int y1, int y2)
{
return IntRect(r.x(), y1, r.width(), y2 - y1);
......@@ -63,7 +85,7 @@ void RasterShapeIntervals::getIncludedIntervals(int y1, int y2, SegmentList& res
if (lineRegion.isEmpty())
return;
Vector<IntRect> lineRects = lineRegion.rects();
const Vector<IntRect>& lineRects = lineRegion.rects();
ASSERT(lineRects.size() > 0);
Region segmentsRegion(lineRect);
......@@ -71,19 +93,28 @@ void RasterShapeIntervals::getIncludedIntervals(int y1, int y2, SegmentList& res
// The loop below uses Regions to compute the intersection of the horizontal
// shape intervals that fall within the line's box.
int lineY = lineRects[0].y();
int currentLineY = lineRects[0].y();
int currentLineMaxY = lineRects[0].maxY();
for (unsigned i = 0; i < lineRects.size(); ++i) {
if (lineRects[i].y() != lineY) {
int lineY = lineRects[i].y();
ASSERT(lineY >= currentLineY);
if (lineY > currentLineMaxY) {
// We've encountered a vertical gap in lineRects, there are no included intervals.
return;
}
if (lineY > currentLineY) {
currentLineY = lineY;
currentLineMaxY = lineRects[i].maxY();
segmentsRegion.intersect(intervalsRegion);
intervalsRegion = Region();
}
} else
currentLineMaxY = std::max<int>(currentLineMaxY, lineRects[i].maxY());
intervalsRegion.unite(Region(alignedRect(lineRects[i], y1, y2)));
lineY = lineRects[i].y();
}
if (!intervalsRegion.isEmpty())
segmentsRegion.intersect(intervalsRegion);
Vector<IntRect> segmentRects = segmentsRegion.rects();
const Vector<IntRect>& segmentRects = segmentsRegion.rects();
for (unsigned i = 0; i < segmentRects.size(); ++i)
result.append(LineSegment(segmentRects[i].x(), segmentRects[i].maxX()));
}
......@@ -98,14 +129,14 @@ void RasterShapeIntervals::getExcludedIntervals(int y1, int y2, SegmentList& res
if (lineRegion.isEmpty())
return;
Vector<IntRect> lineRects = lineRegion.rects();
const Vector<IntRect>& lineRects = lineRegion.rects();
ASSERT(lineRects.size() > 0);
Region segmentsRegion;
for (unsigned i = 0; i < lineRects.size(); i++)
segmentsRegion.unite(Region(alignedRect(lineRects[i], y1, y2)));
Vector<IntRect> segmentRects = segmentsRegion.rects();
const Vector<IntRect>& segmentRects = segmentsRegion.rects();
for (unsigned i = 0; i < segmentRects.size(); i++)
result.append(LineSegment(segmentRects[i].x(), segmentRects[i].maxX() + 1));
}
......@@ -172,13 +203,10 @@ bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalT
float minY = std::max<float>(intervals.bounds().y(), minIntervalTop);
float maxY = minY + minIntervalHeight;
if (maxY > intervals.bounds().maxY())
return false;
// FIXME: Complete this method, see https://bugs.webkit.org/show_bug.cgi?id=116348.
result = minY;
return true;
return intervals.firstIncludedIntervalY(minY, flooredIntSize(minLogicalIntervalSize), result);
}
} // namespace WebCore
......@@ -47,6 +47,7 @@ public:
void addInterval(int y, int x1, int x2);
void getIncludedIntervals(int y1, int y2, SegmentList&) const;
void getExcludedIntervals(int y1, int y2, SegmentList&) const;
bool firstIncludedIntervalY(int minY, const IntSize& minIntervalSize, LayoutUnit&) const;
private:
Region m_region;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment