LayoutTests/ChangeLog

 12012-09-27 Hans Muller <hmuller@adobe.com>
 2
 3 [CSS Exclusions] Add support for polygonal shapes
 4 https://bugs.webkit.org/show_bug.cgi?id=96811
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Verify that a rectangular shape-inside specified as a polygon works as expected for all writing-modes.
 9
 10 * fast/exclusions/shape-inside/shape-inside-polygon-rectangle-expected.html: Added.
 11 * fast/exclusions/shape-inside/shape-inside-polygon-rectangle.html: Added.
 12
1132012-09-27 Peter Beverloo <peter@chromium.org>
214
315 [Chromium] Rebaseline several test directories for Android/.

LayoutTests/fast/exclusions/shape-inside/shape-inside-polygon-rectangle-expected.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4<style>
 5 #shape-inside-horizontal {
 6 padding: 20px 35px 25px 15px;
 7 width: 150px;
 8 height: 175px;
 9 position: relative;
 10 }
 11 #shape-inside-vertical-lr {
 12 padding: 20px 35px 25px 15px;
 13 width: 150px;
 14 height: 175px;
 15 -webkit-writing-mode: vertical-lr;
 16 position: relative;
 17 }
 18 #shape-inside-vertical-rl {
 19 padding: 20px 35px 25px 15px;
 20 width: 150px;
 21 height: 175px;
 22 -webkit-writing-mode: vertical-rl;
 23 position: relative;
 24 }
 25 #border {
 26 position: absolute;
 27 top: 13px;
 28 left: 18px;
 29 width: 150px;
 30 height: 175px;
 31 border: 2px solid blue;
 32 }
 33</style>
 34</head>
 35<body>
 36 <div id="shape-inside-horizontal">
 37 <div id="border"></div>
 38 This text should be contained by the blue square.
 39 </div>
 40 <div id="shape-inside-vertical-lr">
 41 <div id="border"></div>
 42 This text should be contained by the blue square.
 43 </div>
 44 <div id="shape-inside-vertical-rl">
 45 <div id="border"></div>
 46 This text should be contained by the blue square.
 47 </div>
 48</body>
 49</html>

LayoutTests/fast/exclusions/shape-inside/shape-inside-polygon-rectangle.html

 1<!DOCTYPE html>
 2<html>
 3<head>
 4<script>
 5 if (window.internals)
 6 window.internals.settings.setCSSExclusionsEnabled(true);
 7</script>
 8<style>
 9 #shape-inside-horizontal {
 10 width: 200px;
 11 height: 220px;
 12 -webkit-shape-inside: polygon(15px 20px, 165px 20px, 165px 195px, 15px 195px);
 13 position: relative;
 14 }
 15 #shape-inside-vertical-lr {
 16 width: 200px;
 17 height: 220px;
 18 -webkit-shape-inside: polygon(15px 20px, 165px 20px, 165px 195px, 15px 195px);
 19 -webkit-writing-mode: vertical-lr;
 20 position: relative;
 21 }
 22 #shape-inside-vertical-rl {
 23 width: 200px;
 24 height: 220px;
 25 -webkit-shape-inside: polygon(15px 20px, 165px 20px, 165px 195px, 15px 195px);
 26 -webkit-writing-mode: vertical-rl;
 27 position: relative;
 28 }
 29 #border {
 30 position: absolute;
 31 top: 13px;
 32 left: 18px;
 33 width: 150px;
 34 height: 175px;
 35 border: 2px solid blue;
 36 }
 37</style>
 38</head>
 39<body>
 40 <div id="shape-inside-horizontal">
 41 <div id="border"></div>
 42 This text should be contained by the blue square.
 43 </div>
 44 <div id="shape-inside-vertical-lr">
 45 <div id="border"></div>
 46 This text should be contained by the blue square.
 47 </div>
 48 <div id="shape-inside-vertical-rl">
 49 <div id="border"></div>
 50 This text should be contained by the blue square.
 51 </div>
 52</body>
 53</html>

Source/WebCore/CMakeLists.txt

@@SET(WebCore_SOURCES
20182018 rendering/CounterNode.cpp
20192019 rendering/EllipsisBox.cpp
20202020 rendering/ExclusionInterval.cpp
 2021 rendering/ExclusionPolygon.cpp
20212022 rendering/ExclusionRectangle.cpp
20222023 rendering/ExclusionShape.cpp
20232024 rendering/ExclusionShapeInsideInfo.cpp

Source/WebCore/ChangeLog

 12012-09-27 Hans Muller <hmuller@adobe.com>
 2
 3 [CSS Exclusions] Add support for polygonal shapes
 4 https://bugs.webkit.org/show_bug.cgi?id=96811
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Initial version of the layout support for polygonal exclusion shapes: the ExclusionPolygon class.
 9 Supports the public ExclusionShape operations using the algorithm described here:
 10 http://hansmuller-webkit.blogspot.com/2012/06/horizontal-box-polygon-intersection-for.html.
 11 Although both the "included" and "excluded" operations are supported, only the former is
 12 used, since only shape-inside is supported at the moment.
 13
 14 Polygon edges are represented by the ExclusionPolygonEdge class, which records the indices of
 15 the pair of vertices joined by the edge.
 16
 17 The ExclusionPolygon class stores the polygon's edges in an interval tree implementation called
 18 ExclusionPolygonEdgeTree. Each tree node stores a list of edges whose Y coordinates are completely above,
 19 overlap, or below a "center" value. The above and below lists are recursively subdivided until
 20 no above/below edges remain. Finding all of the edges that overlap a Y value, or a Y interval is
 21 O(log n).
 22
 23 Although the implementation supports complex polygons, the layout code is limited to
 24 essentially rectangular shapes until a patch for https://bugs.webkit.org/show_bug.cgi?id=96813
 25 lands.
 26
 27 Test: fast/exclusions/shape-inside/shape-inside-polygon-rectangle.html
 28
 29 * CMakeLists.txt:
 30 * GNUmakefile.list.am:
 31 * Target.pri:
 32 * WebCore.gypi:
 33 * WebCore.vcproj/WebCore.vcproj:
 34 * WebCore.xcodeproj/project.pbxproj:
 35 * rendering/ExclusionPolygon.cpp: Added.
 36 (WebCore):
 37 (EdgeIntersection):
 38 (WebCore::EdgeMinYComparator::operator()):
 39 (EdgeMinYComparator):
 40 (WebCore::IntersectionXComparator::operator()):
 41 (WebCore::ExclusionPolygonEdgeTree::ExclusionPolygonEdgeTree): see above for a description of this type
 42 (WebCore::ExclusionPolygonEdgeTree::initEdgeTree): recursively create the tree's substructure
 43 (WebCore::ExclusionPolygonEdgeTree::findEdgesThatOverlapY):
 44 (WebCore::ExclusionPolygonEdgeTree::findEdgesThatOverlapInterval):
 45 (WebCore::ExclusionPolygon::ExclusionPolygon): see above for a description of this type
 46 (WebCore::computeXIntersection): find and classify the X intercept of a polygon edge for some Y value, if any
 47 (WebCore::ExclusionPolygon::rightVertexY): used to decide if a horizontal line "crosses" a vertex
 48 (WebCore::appendIntervalX): append the start or end X coordinates of an ExclusionInterval
 49 (WebCore::ExclusionPolygon::computeXIntersections): all of the intersections of a horizontal line and the polygon's edges
 50 (WebCore::ExclusionPolygon::computeEdgeIntersections): the X projections of the edges that overlap a horizonal rectangle
 51 (WebCore::ExclusionPolygon::getExcludedIntervals): X intervals within a horizontal rectangle that overlap the polygon
 52 (WebCore::ExclusionPolygon::getIncludedIntervals): X intervals within a horizontal rectangle that fit inside the polygon
 53 * rendering/ExclusionPolygon.h: Added.
 54 (WebCore):
 55 (ExclusionPolygon):
 56 (WebCore::ExclusionPolygon::getXAt): X coordinate of a polygon vertex
 57 (WebCore::ExclusionPolygon::getYAt): Y coordinate of a polygon vertex
 58 (WebCore::ExclusionPolygon::numberOfVertices):
 59 (WebCore::ExclusionPolygon::fillRule): defines "inside" for self-intersecting polygons
 60 (ExclusionPolygonEdge):
 61 (WebCore::ExclusionPolygonEdge::ExclusionPolygonEdge):
 62 (WebCore::ExclusionPolygonEdge::x1): X coordinate of the edges 1st vertex
 63 (WebCore::ExclusionPolygonEdge::y1): Y coordinate of the edges 1st vertex
 64 (WebCore::ExclusionPolygonEdge::x2): X coordinate of the edges 2nd vertex
 65 (WebCore::ExclusionPolygonEdge::y2): Y coordinate of the edges 2nd vertex
 66 (WebCore::ExclusionPolygonEdge::minX):
 67 (WebCore::ExclusionPolygonEdge::minY):
 68 (WebCore::ExclusionPolygonEdge::maxX):
 69 (WebCore::ExclusionPolygonEdge::maxY):
 70 (ExclusionPolygonEdgeTree):
 71 * rendering/ExclusionShape.cpp:
 72 (WebCore::createExclusionPolygon):
 73 (WebCore):
 74 (WebCore::ExclusionShape::createExclusionShape):
 75 * rendering/ExclusionShapeInsideInfo.cpp:
 76 (WebCore::ExclusionShapeInsideInfo::isExclusionShapeInsideInfoEnabledForRenderBlock): allow BASIC_SHAPE_POLYGON shapes
 77 * rendering/ExclusionShapeInsideInfo.h:
 78 (WebCore::ExclusionShapeInsideInfo::shapeLogicalTop):
 79
1802012-09-27 Andreas Kling <kling@webkit.org>
281
382 332kB below DocumentEventQueue::create() on Membuster3.

Source/WebCore/GNUmakefile.list.am

@@webcore_sources += \
48894889 Source/WebCore/rendering/EllipsisBox.h \
48904890 Source/WebCore/rendering/ExclusionInterval.cpp \
48914891 Source/WebCore/rendering/ExclusionInterval.h \
 4892 Source/WebCore/rendering/ExclusionPolygon.cpp \
 4893 Source/WebCore/rendering/ExclusionPolygon.h \
48924894 Source/WebCore/rendering/ExclusionRectangle.cpp \
48934895 Source/WebCore/rendering/ExclusionRectangle.h \
48944896 Source/WebCore/rendering/ExclusionShape.cpp \

Source/WebCore/Target.pri

@@SOURCES += \
11011101 rendering/CounterNode.cpp \
11021102 rendering/EllipsisBox.cpp \
11031103 rendering/ExclusionInterval.cpp \
 1104 rendering/ExclusionPolygon.cpp \
11041105 rendering/ExclusionRectangle.cpp \
11051106 rendering/ExclusionShape.cpp \
11061107 rendering/ExclusionShapeInsideInfo.cpp \

@@HEADERS += \
22912292 rendering/CounterNode.h \
22922293 rendering/EllipsisBox.h \
22932294 rendering/ExclusionInterval.h \
 2295 rendering/ExclusionPolygon.h \
22942296 rendering/ExclusionRectangle.h \
22952297 rendering/ExclusionShape.h \
22962298 rendering/ExclusionShapeInsideInfo.h \

Source/WebCore/WebCore.gypi

32923292 'rendering/EllipsisBox.h',
32933293 'rendering/ExclusionInterval.cpp',
32943294 'rendering/ExclusionInterval.h',
 3295 'rendering/ExclusionPolygon.cpp',
 3296 'rendering/ExclusionPolygon.h',
32953297 'rendering/ExclusionRectangle.cpp',
32963298 'rendering/ExclusionRectangle.h',
32973299 'rendering/ExclusionShape.cpp',

Source/WebCore/WebCore.vcproj/WebCore.vcproj

3843138431 >
3843238432 </File>
3843338433 <File
 38434 RelativePath="..\rendering\ExclusionPolygon.cpp"
 38435 >
 38436 </File>
 38437 <File
 38438 RelativePath="..\rendering\ExclusionPolygon.h"
 38439 >
 38440 </File>
 38441 <File
3843438442 RelativePath="..\rendering\ExclusionRectangle.cpp"
3843538443 >
3843638444 </File>

Source/WebCore/WebCore.xcodeproj/project.pbxproj

18441844 6E8798BD15F81E4A00BFE4AA /* ExclusionRectangle.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E8798B715F81E4A00BFE4AA /* ExclusionRectangle.h */; };
18451845 6E8798BE15F81E4A00BFE4AA /* ExclusionShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6E8798B815F81E4A00BFE4AA /* ExclusionShape.cpp */; };
18461846 6E8798BF15F81E4A00BFE4AA /* ExclusionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E8798B915F81E4A00BFE4AA /* ExclusionShape.h */; settings = {ATTRIBUTES = (Private, ); }; };
 1847 6EAF340F1613869A00859625 /* ExclusionPolygon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EAF340D1613869A00859625 /* ExclusionPolygon.cpp */; };
 1848 6EAF34101613869A00859625 /* ExclusionPolygon.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EAF340E1613869A00859625 /* ExclusionPolygon.h */; };
18471849 6EBC5EAF138B50F200A0CF8A /* JSFloat64Array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EBC5EAD138B50F200A0CF8A /* JSFloat64Array.cpp */; };
18481850 6EBC5EB0138B50F200A0CF8A /* JSFloat64Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EBC5EAE138B50F200A0CF8A /* JSFloat64Array.h */; };
18491851 6EBF0E4812A8926100DB1709 /* OESTextureFloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EBF0E4512A8926100DB1709 /* OESTextureFloat.cpp */; };

90449046 6E8798B715F81E4A00BFE4AA /* ExclusionRectangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExclusionRectangle.h; sourceTree = "<group>"; };
90459047 6E8798B815F81E4A00BFE4AA /* ExclusionShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExclusionShape.cpp; sourceTree = "<group>"; };
90469048 6E8798B915F81E4A00BFE4AA /* ExclusionShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExclusionShape.h; sourceTree = "<group>"; };
 9049 6EAF340D1613869A00859625 /* ExclusionPolygon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExclusionPolygon.cpp; sourceTree = "<group>"; };
 9050 6EAF340E1613869A00859625 /* ExclusionPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExclusionPolygon.h; sourceTree = "<group>"; };
90479051 6EBC5D80138B4C4E00A0CF8A /* Float64Array.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Float64Array.idl; path = canvas/Float64Array.idl; sourceTree = "<group>"; };
90489052 6EBC5EAD138B50F200A0CF8A /* JSFloat64Array.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFloat64Array.cpp; sourceTree = "<group>"; };
90499053 6EBC5EAE138B50F200A0CF8A /* JSFloat64Array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFloat64Array.h; sourceTree = "<group>"; };

2134821352 A8CFF6BD0A156118000A4234 /* EllipsisBox.h */,
2134921353 6E8798B415F81E4A00BFE4AA /* ExclusionInterval.cpp */,
2135021354 6E8798B515F81E4A00BFE4AA /* ExclusionInterval.h */,
 21355 6EAF340D1613869A00859625 /* ExclusionPolygon.cpp */,
 21356 6EAF340E1613869A00859625 /* ExclusionPolygon.h */,
2135121357 6E8798B615F81E4A00BFE4AA /* ExclusionRectangle.cpp */,
2135221358 6E8798B715F81E4A00BFE4AA /* ExclusionRectangle.h */,
2135321359 6E8798B815F81E4A00BFE4AA /* ExclusionShape.cpp */,

2557425580 FB92DF4B15FED08700994433 /* ClipPathOperation.h in Headers */,
2557525581 4F7B4A6615FF6D6A006B5F22 /* PlatformMemoryInstrumentation.h in Headers */,
2557625582 931D72F615FE695300C4C07E /* LayoutMilestones.h in Headers */,
 25583 6EAF34101613869A00859625 /* ExclusionPolygon.h in Headers */,
2557725584 );
2557825585 runOnlyForDeploymentPostprocessing = 0;
2557925586 };

2867328680 FD537352137B651800008DCE /* ZeroPole.cpp in Sources */,
2867428681 E47E276816036EDC00EE2AFB /* DocumentStyleSheetCollection.cpp in Sources */,
2867528682 4F1D11BF15FF37200026E908 /* PlatformMemoryInstrumentation.cpp in Sources */,
 28683 6EAF340F1613869A00859625 /* ExclusionPolygon.cpp in Sources */,
2867628684 );
2867728685 runOnlyForDeploymentPostprocessing = 0;
2867828686 };

Source/WebCore/rendering/ExclusionPolygon.cpp

 1/*
 2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 *
 8 * 1. Redistributions of source code must retain the above
 9 * copyright notice, this list of conditions and the following
 10 * disclaimer.
 11 * 2. Redistributions in binary form must reproduce the above
 12 * copyright notice, this list of conditions and the following
 13 * disclaimer in the documentation and/or other materials
 14 * provided with the distribution.
 15 *
 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 20 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 27 * OF THE POSSIBILITY OF SUCH DAMAGE.
 28 */
 29
 30#include "config.h"
 31#include "ExclusionPolygon.h"
 32
 33#include <wtf/MathExtras.h>
 34
 35namespace WebCore {
 36
 37enum EdgeIntersectionType {
 38 Normal = 0,
 39 VertexYMin = 1,
 40 VertexYMax = 2,
 41 VertexYBoth = 3
 42};
 43
 44struct EdgeIntersection {
 45 const ExclusionPolygonEdge* edge;
 46 float x;
 47 float y;
 48 EdgeIntersectionType type;
 49};
 50
 51struct EdgeMinYComparator {
 52 bool operator() (const ExclusionPolygonEdge* e1, const ExclusionPolygonEdge* e2) const
 53 {
 54 return e1->minY() < e2->minY();
 55 }
 56
 57 bool operator() (const ExclusionPolygonEdge* e, float y) const
 58 {
 59 return e->minY() < y;
 60 }
 61};
 62struct IntersectionXComparator {
 63 bool operator() (const EdgeIntersection& i1, const EdgeIntersection& i2) const
 64 {
 65 return (i1.x == i2.x) ? i1.type < i2.type : i1.x < i2.x;
 66 }
 67};
 68
 69ExclusionPolygonEdgeTree::ExclusionPolygonEdgeTree(const Vector<ExclusionPolygonEdge*>& sortedEdges)
 70 : center(0)
 71{
 72 if (sortedEdges.size() > 0)
 73 initEdgeTree(this, sortedEdges);
 74}
 75
 76void ExclusionPolygonEdgeTree::initEdgeTree(ExclusionPolygonEdgeTree* node, const Vector<ExclusionPolygonEdge*>& edges)
 77{
 78 size_t edgesSize = edges.size();
 79 size_t centerIndex = edgesSize / 2;
 80 node->center = (edges[centerIndex]->minY() + edges[centerIndex]->maxY()) / 2;
 81
 82 Vector<ExclusionPolygonEdge*> aboveCenterEdges;
 83 Vector<ExclusionPolygonEdge*> belowCenterEdges;
 84
 85 // FIXME: minSubtreeSize - don't bother creating subtrees for less than N edges, https://bugs.webkit.org/show_bug.cgi?id=97795
 86
 87 for (size_t i = 0; i < edgesSize; i++) {
 88 ExclusionPolygonEdge* edge = edges[i];
 89 if (edge->maxY() < node->center)
 90 aboveCenterEdges.append(edge);
 91 else if (edge->minY() > node->center)
 92 belowCenterEdges.append(edge);
 93 else
 94 node->overlapCenter.append(edge);
 95 }
 96
 97 // FIXME: create two sorted copies of overlapCenter: overlapCenterMinY, overlapCenterMaxY, https://bugs.webkit.org/show_bug.cgi?id=97797
 98
 99 if (aboveCenterEdges.size() > 0)
 100 node->aboveCenter = adoptPtr(new ExclusionPolygonEdgeTree(aboveCenterEdges));
 101 if (belowCenterEdges.size() > 0)
 102 node->belowCenter = adoptPtr(new ExclusionPolygonEdgeTree(belowCenterEdges));
 103}
 104
 105void ExclusionPolygonEdgeTree::findEdgesThatOverlapY(float y, Vector<ExclusionPolygonEdge*>& result) const
 106{
 107 if (y < center) {
 108 if (aboveCenter)
 109 aboveCenter->findEdgesThatOverlapY(y, result);
 110 } else if (y > center) {
 111 if (belowCenter)
 112 belowCenter->findEdgesThatOverlapY(y, result);
 113 }
 114
 115 size_t overlapEdgesSize = overlapCenter.size();
 116 for (size_t i = 0; i < overlapEdgesSize; i++) {
 117 ExclusionPolygonEdge* edge = overlapCenter[i];
 118 if (y >= edge->minY() && y <= edge->maxY())
 119 result.append(edge);
 120 }
 121}
 122
 123void ExclusionPolygonEdgeTree::findEdgesThatOverlapInterval(float y1, float y2, Vector<ExclusionPolygonEdge*>& result) const
 124{
 125 if ((y1 < center) && aboveCenter)
 126 aboveCenter->findEdgesThatOverlapInterval(y1, y2, result);
 127
 128 if ((y2 > center) && belowCenter)
 129 belowCenter->findEdgesThatOverlapInterval(y1, y2, result);
 130
 131 size_t overlapEdgesSize = overlapCenter.size();
 132 for (size_t i = 0; i < overlapEdgesSize; i++) {
 133 ExclusionPolygonEdge* edge = overlapCenter[i];
 134 if (y2 > edge->minY() && y1 < edge->maxY())
 135 result.append(edge);
 136 }
 137}
 138
 139ExclusionPolygon::ExclusionPolygon(PassOwnPtr<Vector<float> > coordinates, WindRule fillRule)
 140 : ExclusionShape()
 141 , m_coordinates(coordinates)
 142 , m_fillRule(fillRule)
 143{
 144 // FIXME: handle special cases: less than 3 non-colinear vertices
 145 // FIXME: assuming open polygons for now
 146
 147 size_t nVertices = numberOfVertices();
 148 m_edges.resize(nVertices);
 149 Vector<ExclusionPolygonEdge*> sortedEdgesMinY(nVertices);
 150
 151 float minX = getXAt(0);
 152 float minY = getYAt(0);
 153 float maxX = minX;
 154 float maxY = minY;
 155
 156 for (size_t i = 0; i < nVertices; i++) {
 157 float x = getXAt(i);
 158 float y = getYAt(i);
 159
 160 minX = std::min(x, minX);
 161 maxX = std::max(x, maxX);
 162 minY = std::min(y, minY);
 163 maxY = std::max(y, maxY);
 164
 165 m_edges[i].polygon = this;
 166 m_edges[i].i1 = i;
 167 m_edges[i].i2 = (i+1) % nVertices;
 168
 169 sortedEdgesMinY[i] = &m_edges[i];
 170 }
 171
 172 m_boundingBox.setX(minX);
 173 m_boundingBox.setY(minY);
 174 m_boundingBox.setWidth(maxX - minX);
 175 m_boundingBox.setHeight(maxY - minY);
 176
 177 std::sort(sortedEdgesMinY.begin(), sortedEdgesMinY.end(), EdgeMinYComparator());
 178 m_edgeTree = adoptPtr(new ExclusionPolygonEdgeTree(sortedEdgesMinY));
 179}
 180
 181static bool computeXIntersection(const ExclusionPolygonEdge* ep, float y, EdgeIntersection& result)
 182{
 183 const ExclusionPolygonEdge& e = *ep;
 184
 185 if (e.minY() > y || e.maxY() < y)
 186 return false;
 187
 188 float x1 = e.x1();
 189 float y1 = e.y1();
 190 float x2 = e.x2();
 191 float y2 = e.y2();
 192 float dy = y2 - y1;
 193
 194 result.edge = ep;
 195 result.y = y;
 196
 197 if (!dy) {
 198 result.type = VertexYBoth;
 199 result.x = e.minX();
 200 } else if (y == e.minY()) {
 201 result.type = VertexYMin;
 202 result.x = (y1 < y2) ? x1 : x2;
 203 } else if (y == e.maxY()) {
 204 result.type = VertexYMax;
 205 result.x = (y1 > y2) ? x1 : x2;
 206 } else {
 207 result.type = Normal;
 208 result.x = ((y - y1) * (x2 - x1) / dy) + x1;
 209 }
 210
 211 return true;
 212}
 213
 214float ExclusionPolygon::rightVertexY(size_t index) const
 215{
 216 size_t nVertices = numberOfVertices();
 217 size_t i1 = (index + 1) % nVertices;
 218 size_t i2 = (index - 1) % nVertices;
 219
 220 if (getXAt(i1) == getXAt(i2))
 221 return getYAt(i1) > getYAt(i2) ? getYAt(i1) : getYAt(i2);
 222
 223 return getXAt(i1) > getXAt(i2) ? getYAt(i1) : getYAt(i2);
 224}
 225
 226static bool appendIntervalX(float x, bool inside, Vector<ExclusionInterval>& result)
 227{
 228 if (!inside)
 229 result.append(ExclusionInterval(x));
 230 else
 231 result[result.size() - 1].x2 = x;
 232
 233 return !inside;
 234}
 235
 236void ExclusionPolygon::computeXIntersections(float y, Vector<ExclusionInterval>& result) const
 237{
 238 Vector<ExclusionPolygonEdge*> overlappingEdges;
 239 m_edgeTree->findEdgesThatOverlapY(y, overlappingEdges);
 240
 241 Vector<EdgeIntersection> intersections;
 242 EdgeIntersection intersection;
 243 for (size_t i = 0; i < overlappingEdges.size(); i++) {
 244 if (computeXIntersection(overlappingEdges[i], y, intersection))
 245 intersections.append(intersection);
 246 }
 247 if (intersections.size() < 2)
 248 return;
 249
 250 std::sort(intersections.begin(), intersections.end(), IntersectionXComparator());
 251
 252 size_t index = 0;
 253 int windCount = 0;
 254 bool inside = false;
 255
 256 while (index < intersections.size()) {
 257 const EdgeIntersection& thisIntersection = intersections[index];
 258
 259 if (index + 1 < intersections.size()) {
 260 const EdgeIntersection& nextIntersection = intersections[index +1];
 261 if ((thisIntersection.x == nextIntersection.x) && (thisIntersection.type == VertexYMin || thisIntersection.type == VertexYMax)) {
 262 if (thisIntersection.type == nextIntersection.type) {
 263 // skip VertexYMax,VertexYMax and VertexYMin,VertexYMin
 264 index += 2;
 265 } else {
 266 // VertexYMin,VertexYMax or VertexYMax,VertexYMin => VertexYMin
 267 if (nextIntersection.type == VertexYMax)
 268 intersections[index + 1] = thisIntersection;
 269 index += 1;
 270 }
 271 continue;
 272 }
 273 }
 274
 275 const ExclusionPolygonEdge& thisEdge = *thisIntersection.edge;
 276 bool crossing = !windCount;
 277
 278 if (fillRule() == RULE_EVENODD) {
 279 windCount += (getYAt(thisEdge.i2) > getYAt(thisEdge.i1)) ? +1 : -1;
 280 crossing = crossing || !windCount;
 281 }
 282
 283 if ((thisIntersection.type == Normal) || (thisIntersection.type == VertexYMin)) {
 284 if (crossing)
 285 inside = appendIntervalX(thisIntersection.x, inside, result);
 286 } else if (thisIntersection.type == VertexYMax) {
 287 int vertexIndex = (getYAt(thisEdge.i2) > getYAt(thisEdge.i1)) ? thisEdge.i2 : thisEdge.i1;
 288 if (crossing && rightVertexY(vertexIndex) > y)
 289 inside = appendIntervalX(thisEdge.maxX(), inside, result);
 290 } else if (thisIntersection.type == VertexYBoth)
 291 result.append(ExclusionInterval(thisEdge.minX(), thisEdge.maxX()));
 292
 293 index += 1;
 294 }
 295}
 296
 297// Return the X projections of the edges that overlap y1,y2.
 298void ExclusionPolygon::computeEdgeIntersections(float y1, float y2, Vector<ExclusionInterval>& result) const
 299{
 300 Vector<ExclusionPolygonEdge *> overlappingEdges;
 301 m_edgeTree->findEdgesThatOverlapInterval(y1, y2, overlappingEdges);
 302
 303 EdgeIntersection intersection;
 304 for (size_t i = 0; i < overlappingEdges.size(); i++) {
 305 const ExclusionPolygonEdge& edge = *overlappingEdges[i];
 306 float x1, x2;
 307
 308 if (edge.minY() < y1) {
 309 computeXIntersection(overlappingEdges[i], y1, intersection);
 310 x1 = intersection.x;
 311 } else
 312 x1 = (edge.y1() < edge.y2()) ? edge.x1() : edge.x2();
 313
 314 if (edge.maxY() > y2) {
 315 computeXIntersection(overlappingEdges[i], y2, intersection);
 316 x2 = intersection.x;
 317 } else
 318 x2 = (edge.y1() > edge.y2()) ? edge.x1() : edge.x2();
 319
 320 if (x1 > x2)
 321 std::swap(x1, x2);
 322
 323 result.append(ExclusionInterval(x1, x2));
 324 }
 325
 326 sortExclusionIntervals(result);
 327}
 328
 329void ExclusionPolygon::getExcludedIntervals(float logicalTop, float logicalBottom, SegmentList& result) const
 330{
 331 float y1 = minYForLogicalLine(logicalTop, logicalBottom);
 332 float y2 = maxYForLogicalLine(logicalTop, logicalBottom);
 333
 334 Vector<ExclusionInterval> y1XIntervals, y2XIntervals;
 335 computeXIntersections(y1, y1XIntervals);
 336 computeXIntersections(y2, y2XIntervals);
 337
 338 Vector<ExclusionInterval> mergedIntervals;
 339 mergeExclusionIntervals(y1XIntervals, y2XIntervals, mergedIntervals);
 340
 341 Vector<ExclusionInterval> edgeIntervals;
 342 computeEdgeIntersections(y1, y2, edgeIntervals);
 343
 344 Vector<ExclusionInterval> excludedIntervals;
 345 mergeExclusionIntervals(mergedIntervals, edgeIntervals, excludedIntervals);
 346
 347 for (size_t i = 0; i < excludedIntervals.size(); i++) {
 348 ExclusionInterval interval = excludedIntervals[i];
 349 result.append(LineSegment(interval.x1, interval.x2));
 350 }
 351}
 352
 353void ExclusionPolygon::getIncludedIntervals(float logicalTop, float logicalBottom, SegmentList& result) const
 354{
 355 float y1 = minYForLogicalLine(logicalTop, logicalBottom);
 356 float y2 = maxYForLogicalLine(logicalTop, logicalBottom);
 357
 358 Vector<ExclusionInterval> y1XIntervals, y2XIntervals;
 359 computeXIntersections(y1, y1XIntervals);
 360 computeXIntersections(y2, y2XIntervals);
 361
 362 Vector<ExclusionInterval> commonIntervals;
 363 intersectExclusionIntervals(y1XIntervals, y2XIntervals, commonIntervals);
 364
 365 Vector<ExclusionInterval> edgeIntervals;
 366 computeEdgeIntersections(y1, y2, edgeIntervals);
 367
 368 Vector<ExclusionInterval> includedIntervals;
 369 subtractExclusionIntervals(commonIntervals, edgeIntervals, includedIntervals);
 370
 371 for (size_t i = 0; i < includedIntervals.size(); i++) {
 372 ExclusionInterval interval = includedIntervals[i];
 373 result.append(LineSegment(interval.x1, interval.x2));
 374 }
 375}
 376
 377} // namespace WebCore

Source/WebCore/rendering/ExclusionPolygon.h

 1/*
 2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 *
 8 * 1. Redistributions of source code must retain the above
 9 * copyright notice, this list of conditions and the following
 10 * disclaimer.
 11 * 2. Redistributions in binary form must reproduce the above
 12 * copyright notice, this list of conditions and the following
 13 * disclaimer in the documentation and/or other materials
 14 * provided with the distribution.
 15 *
 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 20 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 27 * OF THE POSSIBILITY OF SUCH DAMAGE.
 28 */
 29
 30#ifndef ExclusionPolygon_h
 31#define ExclusionPolygon_h
 32
 33#include "ExclusionInterval.h"
 34#include "ExclusionShape.h"
 35#include "FloatRect.h"
 36#include "WindRule.h"
 37#include <wtf/MathExtras.h>
 38#include <wtf/OwnPtr.h>
 39#include <wtf/PassOwnPtr.h>
 40#include <wtf/Vector.h>
 41
 42namespace WebCore {
 43
 44struct ExclusionPolygonEdge;
 45struct ExclusionPolygonEdgeTree;
 46
 47class ExclusionPolygon : public ExclusionShape {
 48public:
 49 ExclusionPolygon(PassOwnPtr<Vector<float> > coordinates, WindRule fillRule);
 50
 51 float getXAt(size_t i) const { return m_coordinates->at(i*2); }
 52 float getYAt(size_t i) const { return m_coordinates->at(i*2 + 1); }
 53 size_t numberOfVertices() const { return m_coordinates->size() / 2; }
 54 WindRule fillRule() const { return m_fillRule; }
 55
 56 virtual FloatRect shapeLogicalBoundingBox() const OVERRIDE { return internalToLogicalBoundingBox(m_boundingBox); }
 57 virtual void getExcludedIntervals(float logicalTop, float logicalBottom, SegmentList&) const OVERRIDE;
 58 virtual void getIncludedIntervals(float logicalTop, float logicalBottom, SegmentList&) const OVERRIDE;
 59
 60private:
 61 float rightVertexY(size_t) const;
 62 void computeXIntersections(float y, Vector<ExclusionInterval>&) const;
 63 void computeEdgeIntersections(float yMin, float yMax, Vector<ExclusionInterval>&) const;
 64
 65 OwnPtr<Vector<float> > m_coordinates;
 66 WindRule m_fillRule;
 67 FloatRect m_boundingBox;
 68 Vector<ExclusionPolygonEdge> m_edges;
 69 OwnPtr<ExclusionPolygonEdgeTree> m_edgeTree;
 70};
 71
 72struct ExclusionPolygonEdge {
 73 const ExclusionPolygon* polygon;
 74 size_t i1;
 75 size_t i2;
 76
 77 ExclusionPolygonEdge()
 78 : polygon(0)
 79 , i1(0)
 80 , i2(0)
 81 {
 82 }
 83
 84 float x1() const { return polygon->getXAt(i1); }
 85 float y1() const { return polygon->getYAt(i1); }
 86 float x2() const { return polygon->getXAt(i2); }
 87 float y2() const { return polygon->getYAt(i2); }
 88
 89 float minX() const { return std::min(x1(), x2()); }
 90 float minY() const { return std::min(y1(), y2()); }
 91 float maxX() const { return std::max(x1(), x2()); }
 92 float maxY() const { return std::max(y1(), y2()); }
 93};
 94
 95// an "interval tree"
 96struct ExclusionPolygonEdgeTree {
 97private:
 98 float center;
 99 Vector<ExclusionPolygonEdge*> overlapCenter;
 100 OwnPtr<ExclusionPolygonEdgeTree> aboveCenter;
 101 OwnPtr<ExclusionPolygonEdgeTree> belowCenter;
 102
 103 static void initEdgeTree(ExclusionPolygonEdgeTree*, const Vector<ExclusionPolygonEdge*>& sortedEdges);
 104
 105public:
 106 ExclusionPolygonEdgeTree(const Vector<ExclusionPolygonEdge*>& sortedEdges);
 107
 108 void findEdgesThatOverlapY(float y, Vector<ExclusionPolygonEdge*>&) const;
 109 void findEdgesThatOverlapInterval(float minY, float maxY, Vector<ExclusionPolygonEdge*>&) const;
 110};
 111
 112} // namespace WebCore
 113
 114#endif // ExclusionPolygon_h

Source/WebCore/rendering/ExclusionShape.cpp

3131#include "ExclusionShape.h"
3232
3333#include "BasicShapeFunctions.h"
 34#include "ExclusionPolygon.h"
3435#include "ExclusionRectangle.h"
3536#include "FloatSize.h"
3637#include "LengthFunctions.h"
37 #include "NotImplemented.h"
3838#include "WindRule.h"
3939#include <wtf/MathExtras.h>
4040#include <wtf/OwnPtr.h>

@@static PassOwnPtr<ExclusionShape> createExclusionEllipse(const FloatPoint& cente
6060 return adoptPtr(new ExclusionRectangle(FloatRect(center.x() - radii.width(), center.y() - radii.height(), radii.width()*2, radii.height()*2), radii));
6161}
6262
 63static PassOwnPtr<ExclusionShape> createExclusionPolygon(PassOwnPtr<Vector<float> > coordinates, WindRule fillRule)
 64{
 65 ASSERT(!(coordinates->size() % 2));
 66 return adoptPtr(new ExclusionPolygon(coordinates, fillRule));
 67}
 68
6369// If the writingMode is vertical, then the BasicShape's (physical) x and y coordinates are swapped, so that
6470// line segments are parallel to the internal coordinate system's X axis.
6571

@@PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape
8793 float radiusY = radiusYLength.isUndefined() ? 0 : floatValueForLength(radiusYLength, boxHeight);
8894
8995 exclusionShape = horizontalWritingMode
90  ? createExclusionRectangle(FloatRect(x, y, width, height), FloatSize(radiusX, radiusY))
91  : createExclusionRectangle(FloatRect(y, x, height, width), FloatSize(radiusY, radiusX));
 96 ? createExclusionRectangle(FloatRect(x, y, width, height), FloatSize(radiusX, radiusY))
 97 : createExclusionRectangle(FloatRect(y, x, height, width), FloatSize(radiusY, radiusX));
9298 break;
9399 }
94100

@@PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape
99105 float radius = floatValueForLength(circle->radius(), std::max(boxHeight, boxWidth));
100106
101107 exclusionShape = horizontalWritingMode
102  ? createExclusionCircle(FloatPoint(centerX, centerY), radius)
103  : createExclusionCircle(FloatPoint(centerY, centerX), radius);
 108 ? createExclusionCircle(FloatPoint(centerX, centerY), radius)
 109 : createExclusionCircle(FloatPoint(centerY, centerX), radius);
104110 break;
105111 }
106112

@@PassOwnPtr<ExclusionShape> ExclusionShape::createExclusionShape(const BasicShape
112118 float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight);
113119
114120 exclusionShape = horizontalWritingMode
115  ? createExclusionEllipse(FloatPoint(centerX, centerY), FloatSize(radiusX, radiusY))
116  : createExclusionEllipse(FloatPoint(centerY, centerX), FloatSize(radiusY, radiusX));
 121 ? createExclusionEllipse(FloatPoint(centerX, centerY), FloatSize(radiusX, radiusY))
 122 : createExclusionEllipse(FloatPoint(centerY, centerX), FloatSize(radiusY, radiusX));
117123 break;
118124 }
119125
120  case BasicShape::BASIC_SHAPE_POLYGON:
121  notImplemented();
 126 case BasicShape::BASIC_SHAPE_POLYGON: {
 127 const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape);
 128 const Vector<Length>& values = polygon->values();
 129 size_t valuesSize = values.size();
 130 Vector<float>* coordinates = new Vector<float>(valuesSize);
 131 for (unsigned i = 0; i < valuesSize; i += 2) {
 132 float vertexX = floatValueForLength(values.at(i), boxWidth);
 133 float vertexY = floatValueForLength(values.at(i+1), boxHeight);
 134 if (horizontalWritingMode) {
 135 coordinates->at(i) = vertexX;
 136 coordinates->at(i+1) = vertexY;
 137 } else {
 138 coordinates->at(i) = vertexY;
 139 coordinates->at(i+1) = vertexX;
 140 }
 141 }
 142 exclusionShape = createExclusionPolygon(adoptPtr(coordinates), polygon->windRule());
 143 break;
 144 }
122145
123146 default:
124147 ASSERT_NOT_REACHED();

Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp

@@bool ExclusionShapeInsideInfo::isExclusionShapeInsideInfoEnabledForRenderBlock(c
7373{
7474 // FIXME: Bug 89707: Enable shape inside for non-rectangular shapes
7575 BasicShape* shape = block->style()->wrapShapeInside();
76  return (shape && shape->type() == BasicShape::BASIC_SHAPE_RECTANGLE);
 76 return shape && (shape->type() == BasicShape::BASIC_SHAPE_RECTANGLE || shape->type() == BasicShape::BASIC_SHAPE_POLYGON);
7777}
7878
7979void ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(const RenderBlock* block)

Source/WebCore/rendering/ExclusionShapeInsideInfo.h

@@public:
5454 static void removeExclusionShapeInsideInfoForRenderBlock(const RenderBlock*);
5555 static bool isExclusionShapeInsideInfoEnabledForRenderBlock(const RenderBlock*);
5656
57  LayoutUnit shapeLogicalTop() const
58  {
 57 LayoutUnit shapeLogicalTop() const
 58 {
5959 ASSERT(m_shape);
6060 return m_shape->shapeLogicalBoundingBox().y();
6161 }