Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: Source/core/rendering/shapes/PolygonShape.cpp

Issue 226363003: [CSS Shapes] Simplify Polygon implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Don't change FloatRect.h Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. 2 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above 8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following 9 * copyright notice, this list of conditions and the following
10 * disclaimer. 10 * disclaimer.
(...skipping 12 matching lines...) Expand all
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 * OF THE POSSIBILITY OF SUCH DAMAGE. 27 * OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29 29
30 #include "config.h" 30 #include "config.h"
31 #include "core/rendering/shapes/PolygonShape.h" 31 #include "core/rendering/shapes/PolygonShape.h"
32 32
33 #include "core/rendering/shapes/ShapeInterval.h"
34 #include "platform/geometry/LayoutPoint.h" 33 #include "platform/geometry/LayoutPoint.h"
35 #include "wtf/MathExtras.h" 34 #include "wtf/MathExtras.h"
36 35
37 namespace WebCore { 36 namespace WebCore {
38 37
39 enum EdgeIntersectionType {
40 Normal,
41 VertexMinY,
42 VertexMaxY,
43 VertexYBoth
44 };
45
46 struct EdgeIntersection {
47 const FloatPolygonEdge* edge;
48 FloatPoint point;
49 EdgeIntersectionType type;
50 };
51
52 static bool computeXIntersection(const FloatPolygonEdge* edgePointer, float y, E dgeIntersection& result)
53 {
54 const FloatPolygonEdge& edge = *edgePointer;
55
56 if (edge.minY() > y || edge.maxY() < y)
57 return false;
58
59 const FloatPoint& vertex1 = edge.vertex1();
60 const FloatPoint& vertex2 = edge.vertex2();
61 float dy = vertex2.y() - vertex1.y();
62
63 float intersectionX;
64 EdgeIntersectionType intersectionType;
65
66 if (!dy) {
67 intersectionType = VertexYBoth;
68 intersectionX = edge.minX();
69 } else if (y == edge.minY()) {
70 intersectionType = VertexMinY;
71 intersectionX = (vertex1.y() < vertex2.y()) ? vertex1.x() : vertex2.x();
72 } else if (y == edge.maxY()) {
73 intersectionType = VertexMaxY;
74 intersectionX = (vertex1.y() > vertex2.y()) ? vertex1.x() : vertex2.x();
75 } else {
76 intersectionType = Normal;
77 intersectionX = ((y - vertex1.y()) * (vertex2.x() - vertex1.x()) / dy) + vertex1.x();
78 }
79
80 result.edge = edgePointer;
81 result.type = intersectionType;
82 result.point.set(intersectionX, y);
83
84 return true;
85 }
86
87 static inline FloatSize inwardEdgeNormal(const FloatPolygonEdge& edge) 38 static inline FloatSize inwardEdgeNormal(const FloatPolygonEdge& edge)
88 { 39 {
89 FloatSize edgeDelta = edge.vertex2() - edge.vertex1(); 40 FloatSize edgeDelta = edge.vertex2() - edge.vertex1();
90 if (!edgeDelta.width()) 41 if (!edgeDelta.width())
91 return FloatSize((edgeDelta.height() > 0 ? -1 : 1), 0); 42 return FloatSize((edgeDelta.height() > 0 ? -1 : 1), 0);
92 if (!edgeDelta.height()) 43 if (!edgeDelta.height())
93 return FloatSize(0, (edgeDelta.width() > 0 ? 1 : -1)); 44 return FloatSize(0, (edgeDelta.width() > 0 ? 1 : -1));
94 float edgeLength = edgeDelta.diagonalLength(); 45 float edgeLength = edgeDelta.diagonalLength();
95 return FloatSize(-edgeDelta.height() / edgeLength, edgeDelta.width() / edgeL ength); 46 return FloatSize(-edgeDelta.height() / edgeLength, edgeDelta.width() / edgeL ength);
96 } 47 }
97 48
98 static inline FloatSize outwardEdgeNormal(const FloatPolygonEdge& edge) 49 static inline FloatSize outwardEdgeNormal(const FloatPolygonEdge& edge)
99 { 50 {
100 return -inwardEdgeNormal(edge); 51 return -inwardEdgeNormal(edge);
101 } 52 }
102 53
103 static inline void appendArc(Vector<FloatPoint>& vertices, const FloatPoint& arc Center, float arcRadius, const FloatPoint& startArcVertex, const FloatPoint& end ArcVertex, bool padding) 54 static inline bool overlapsYRange(const FloatRect& rect, float y1, float y2) { r eturn !rect.isEmpty() && y2 >= y1 && y2 >= rect.y() && y1 <= rect.maxY(); }
55
56 float OffsetPolygonEdge::xIntercept(float y) const
104 { 57 {
105 float startAngle = atan2(startArcVertex.y() - arcCenter.y(), startArcVertex. x() - arcCenter.x()); 58 ASSERT(y >= minY() && y <= maxY());
106 float endAngle = atan2(endArcVertex.y() - arcCenter.y(), endArcVertex.x() - arcCenter.x());
107 if (startAngle < 0)
108 startAngle += twoPiFloat;
109 if (endAngle < 0)
110 endAngle += twoPiFloat;
111 float angle = (startAngle > endAngle) ? (startAngle - endAngle) : (startAngl e + twoPiFloat - endAngle);
112 const float arcSegmentCount = 6; // An even number so that one arc vertex wi ll be eactly arcRadius from arcCenter.
113 float arcSegmentAngle = ((padding) ? -angle : twoPiFloat - angle) / arcSegm entCount;
114 59
115 vertices.append(startArcVertex); 60 if (vertex1().y() == vertex2().y() || vertex1().x() == vertex2().x())
116 for (unsigned i = 1; i < arcSegmentCount; ++i) { 61 return minX();
117 float angle = startAngle + arcSegmentAngle * i; 62 if (y == minY())
118 vertices.append(arcCenter + FloatPoint(cos(angle) * arcRadius, sin(angle ) * arcRadius)); 63 return vertex1().y() < vertex2().y() ? vertex1().x() : vertex2().x();
119 } 64 if (y == maxY())
120 vertices.append(endArcVertex); 65 return vertex1().y() > vertex2().y() ? vertex1().x() : vertex2().x();
66
67 return vertex1().x() + ((y - vertex1().y()) * (vertex2().x() - vertex1().x() ) / (vertex2().y() - vertex1().y()));
121 } 68 }
122 69
123 static inline void snapVerticesToLayoutUnitGrid(Vector<FloatPoint>& vertices) 70 FloatShapeInterval OffsetPolygonEdge::clippedEdgeXRange(float y1, float y2) cons t
124 { 71 {
125 for (unsigned i = 0; i < vertices.size(); ++i) 72 if (!overlapsYRange(y1, y2))
126 vertices[i] = flooredLayoutPoint(vertices[i]); 73 return FloatShapeInterval();
74
75 if (isWithinYRange(y1, y2))
76 return FloatShapeInterval(minX(), maxX());
77
78 // Clip the edge line segment to the vertical range y1,y2 and then return
79 // the clipped line segment's horizontal range.
80
81 FloatPoint minYVertex;
82 FloatPoint maxYVertex;
83 if (vertex1().y() < vertex2().y()) {
84 minYVertex = vertex1();
85 maxYVertex = vertex2();
86 } else {
87 minYVertex = vertex2();
88 maxYVertex = vertex1();
89 }
90 float xForY1 = (minYVertex.y() < y1) ? xIntercept(y1) : minYVertex.x();
91 float xForY2 = (maxYVertex.y() > y2) ? xIntercept(y2) : maxYVertex.x();
92 return FloatShapeInterval(std::min(xForY1, xForY2), std::max(xForY1, xForY2) );
127 } 93 }
128 94
129 static inline PassOwnPtr<FloatPolygon> computeShapeMarginBounds(const FloatPolyg on& polygon, float margin, WindRule fillRule) 95 static float circleXIntercept(float y, float radius)
130 { 96 {
131 OwnPtr<Vector<FloatPoint> > marginVertices = adoptPtr(new Vector<FloatPoint> ()); 97 ASSERT(radius > 0);
132 FloatPoint intersection; 98 return radius * sqrt(1 - (y * y) / (radius * radius));
133
134 for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) {
135 const FloatPolygonEdge& thisEdge = polygon.edgeAt(i);
136 const FloatPolygonEdge& prevEdge = thisEdge.previousEdge();
137 OffsetPolygonEdge thisOffsetEdge(thisEdge, outwardEdgeNormal(thisEdge) * margin);
138 OffsetPolygonEdge prevOffsetEdge(prevEdge, outwardEdgeNormal(prevEdge) * margin);
139
140 if (prevOffsetEdge.intersection(thisOffsetEdge, intersection))
141 marginVertices->append(intersection);
142 else
143 appendArc(*marginVertices, thisEdge.vertex1(), margin, prevOffsetEdg e.vertex2(), thisOffsetEdge.vertex1(), false);
144 }
145
146 snapVerticesToLayoutUnitGrid(*marginVertices);
147 return adoptPtr(new FloatPolygon(marginVertices.release(), fillRule));
148 } 99 }
149 100
150 const FloatPolygon& PolygonShape::shapeMarginBounds() const 101 static FloatShapeInterval clippedCircleXRange(const FloatPoint& center, float ra dius, float y1, float y2)
151 { 102 {
152 ASSERT(shapeMargin() >= 0); 103 if (y1 > center.y() + radius || y2 < center.y() - radius)
153 if (!shapeMargin() || m_polygon.isEmpty()) 104 return FloatShapeInterval();
154 return m_polygon;
155 105
156 if (!m_marginBounds) 106 if (center.y() >= y1 && center.y() <= y2)
157 m_marginBounds = computeShapeMarginBounds(m_polygon, shapeMargin(), m_po lygon.fillRule()); 107 return FloatShapeInterval(center.x() - radius, center.x() + radius);
158 108
159 return *m_marginBounds; 109 // Clip the circle to the vertical range y1,y2 and return the extent of the clipped circle's
110 // projection on the X axis
111
112 float xi = circleXIntercept((y2 < center.y() ? y2 : y1) - center.y(), radiu s);
113 return FloatShapeInterval(center.x() - xi, center.x() + xi);
160 } 114 }
161 115
162 static inline bool getVertexIntersectionVertices(const EdgeIntersection& interse ction, FloatPoint& prevVertex, FloatPoint& thisVertex, FloatPoint& nextVertex) 116 LayoutRect PolygonShape::shapeMarginLogicalBoundingBox() const
163 { 117 {
164 if (intersection.type != VertexMinY && intersection.type != VertexMaxY) 118 FloatRect box = m_polygon.boundingBox();
165 return false; 119 box.inflate(shapeMargin());
166 120 return LayoutRect(box);
167 ASSERT(intersection.edge && intersection.edge->polygon());
168 const FloatPolygon& polygon = *(intersection.edge->polygon());
169 const FloatPolygonEdge& thisEdge = *(intersection.edge);
170
171 if ((intersection.type == VertexMinY && (thisEdge.vertex1().y() < thisEdge.v ertex2().y()))
172 || (intersection.type == VertexMaxY && (thisEdge.vertex1().y() > thisEdg e.vertex2().y()))) {
173 prevVertex = polygon.vertexAt(thisEdge.previousEdge().vertexIndex1());
174 thisVertex = polygon.vertexAt(thisEdge.vertexIndex1());
175 nextVertex = polygon.vertexAt(thisEdge.vertexIndex2());
176 } else {
177 prevVertex = polygon.vertexAt(thisEdge.vertexIndex1());
178 thisVertex = polygon.vertexAt(thisEdge.vertexIndex2());
179 nextVertex = polygon.vertexAt(thisEdge.nextEdge().vertexIndex2());
180 }
181
182 return true;
183 }
184
185 static inline bool appendIntervalX(float x, bool inside, FloatShapeIntervals& re sult)
186 {
187 if (!inside)
188 result.append(FloatShapeInterval(x, x));
189 else
190 result.last().setX2(x);
191
192 return !inside;
193 }
194
195 static bool compareEdgeIntersectionX(const EdgeIntersection& intersection1, cons t EdgeIntersection& intersection2)
196 {
197 float x1 = intersection1.point.x();
198 float x2 = intersection2.point.x();
199 return (x1 == x2) ? intersection1.type < intersection2.type : x1 < x2;
200 }
201
202 static void computeXIntersections(const FloatPolygon& polygon, float y, bool isM inY, FloatShapeIntervals& result)
203 {
204 Vector<const FloatPolygonEdge*> edges;
205 if (!polygon.overlappingEdges(y, y, edges))
206 return;
207
208 Vector<EdgeIntersection> intersections;
209 EdgeIntersection intersection;
210 for (unsigned i = 0; i < edges.size(); ++i) {
211 if (computeXIntersection(edges[i], y, intersection) && intersection.type != VertexYBoth)
212 intersections.append(intersection);
213 }
214
215 if (intersections.size() < 2)
216 return;
217
218 std::sort(intersections.begin(), intersections.end(), WebCore::compareEdgeIn tersectionX);
219
220 unsigned index = 0;
221 int windCount = 0;
222 bool inside = false;
223
224 while (index < intersections.size()) {
225 const EdgeIntersection& thisIntersection = intersections[index];
226 if (index + 1 < intersections.size()) {
227 const EdgeIntersection& nextIntersection = intersections[index + 1];
228 if ((thisIntersection.point.x() == nextIntersection.point.x()) && (t hisIntersection.type == VertexMinY || thisIntersection.type == VertexMaxY)) {
229 if (thisIntersection.type == nextIntersection.type) {
230 // Skip pairs of intersections whose types are VertexMaxY,Ve rtexMaxY and VertexMinY,VertexMinY.
231 index += 2;
232 } else {
233 // Replace pairs of intersections whose types are VertexMinY ,VertexMaxY or VertexMaxY,VertexMinY with one intersection.
234 ++index;
235 }
236 continue;
237 }
238 }
239
240 bool edgeCrossing = thisIntersection.type == Normal;
241 if (!edgeCrossing) {
242 FloatPoint prevVertex;
243 FloatPoint thisVertex;
244 FloatPoint nextVertex;
245
246 if (getVertexIntersectionVertices(thisIntersection, prevVertex, this Vertex, nextVertex)) {
247 if (nextVertex.y() == y)
248 edgeCrossing = (isMinY) ? prevVertex.y() > y : prevVertex.y( ) < y;
249 else if (prevVertex.y() == y)
250 edgeCrossing = (isMinY) ? nextVertex.y() > y : nextVertex.y( ) < y;
251 else
252 edgeCrossing = true;
253 }
254 }
255
256 if (edgeCrossing && polygon.fillRule() == RULE_NONZERO) {
257 const FloatPolygonEdge& thisEdge = *thisIntersection.edge;
258 windCount += (thisEdge.vertex2().y() > thisEdge.vertex1().y()) ? 1 : -1;
259 }
260
261 if (edgeCrossing && (!inside || !windCount))
262 inside = appendIntervalX(thisIntersection.point.x(), inside, result) ;
263
264 ++index;
265 }
266 }
267
268 static bool compareX1(const FloatShapeInterval a, const FloatShapeInterval& b) { return a.x1() < b.x1(); }
269
270 static void sortAndMergeShapeIntervals(FloatShapeIntervals& intervals)
271 {
272 std::sort(intervals.begin(), intervals.end(), compareX1);
273
274 for (unsigned i = 1; i < intervals.size(); ) {
275 const FloatShapeInterval& thisInterval = intervals[i];
276 FloatShapeInterval& previousInterval = intervals[i - 1];
277 if (thisInterval.overlaps(previousInterval)) {
278 previousInterval.setX2(std::max<float>(previousInterval.x2(), thisIn terval.x2()));
279 intervals.remove(i);
280 } else {
281 ++i;
282 }
283 }
284 }
285
286 static void computeOverlappingEdgeXProjections(const FloatPolygon& polygon, floa t y1, float y2, FloatShapeIntervals& result)
287 {
288 Vector<const FloatPolygonEdge*> edges;
289 if (!polygon.overlappingEdges(y1, y2, edges))
290 return;
291
292 EdgeIntersection intersection;
293 for (unsigned i = 0; i < edges.size(); ++i) {
294 const FloatPolygonEdge *edge = edges[i];
295 float x1;
296 float x2;
297
298 if (edge->minY() < y1) {
299 computeXIntersection(edge, y1, intersection);
300 x1 = intersection.point.x();
301 } else {
302 x1 = (edge->vertex1().y() < edge->vertex2().y()) ? edge->vertex1().x () : edge->vertex2().x();
303 }
304
305 if (edge->maxY() > y2) {
306 computeXIntersection(edge, y2, intersection);
307 x2 = intersection.point.x();
308 } else {
309 x2 = (edge->vertex1().y() > edge->vertex2().y()) ? edge->vertex1().x () : edge->vertex2().x();
310 }
311
312 if (x1 > x2)
313 std::swap(x1, x2);
314
315 if (x2 > x1)
316 result.append(FloatShapeInterval(x1, x2));
317 }
318
319 sortAndMergeShapeIntervals(result);
320 } 121 }
321 122
322 void PolygonShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logica lHeight, SegmentList& result) const 123 void PolygonShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logica lHeight, SegmentList& result) const
323 { 124 {
324 const FloatPolygon& polygon = shapeMarginBounds(); 125 float y1 = logicalTop.toFloat();
325 if (polygon.isEmpty()) 126 float y2 = logicalTop.toFloat() + logicalHeight.toFloat();
127
128 if (m_polygon.isEmpty() || !overlapsYRange(m_polygon.boundingBox(), y1 - sha peMargin(), y2 + shapeMargin()))
326 return; 129 return;
327 130
328 float y1 = logicalTop.toFloat(); 131 Vector<const FloatPolygonEdge*> overlappingEdges;
329 float y2 = (logicalTop + logicalHeight).toFloat(); 132 if (!m_polygon.overlappingEdges(y1 - shapeMargin(), y2 + shapeMargin(), over lappingEdges))
133 return;
330 134
331 FloatShapeIntervals y1XIntervals, y2XIntervals; 135 FloatShapeInterval excludedInterval;
332 computeXIntersections(polygon, y1, true, y1XIntervals); 136 for (unsigned i = 0; i < overlappingEdges.size(); i++) {
333 computeXIntersections(polygon, y2, false, y2XIntervals); 137 const FloatPolygonEdge& edge = *(overlappingEdges[i]);
138 if (!shapeMargin()) {
139 excludedInterval.unite(OffsetPolygonEdge(edge, FloatSize()).clippedE dgeXRange(y1, y2));
140 } else {
141 excludedInterval.unite(OffsetPolygonEdge(edge, outwardEdgeNormal(edg e) * shapeMargin()).clippedEdgeXRange(y1, y2));
142 excludedInterval.unite(OffsetPolygonEdge(edge, inwardEdgeNormal(edge ) * shapeMargin()).clippedEdgeXRange(y1, y2));
143 excludedInterval.unite(clippedCircleXRange(edge.vertex1(), shapeMarg in(), y1, y2));
144 }
145 }
334 146
335 FloatShapeIntervals mergedIntervals; 147 if (!excludedInterval.isEmpty())
336 FloatShapeInterval::uniteShapeIntervals(y1XIntervals, y2XIntervals, mergedIn tervals); 148 result.append(LineSegment(excludedInterval.x1(), excludedInterval.x2())) ;
337
338 FloatShapeIntervals edgeIntervals;
339 computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals);
340
341 FloatShapeIntervals excludedIntervals;
342 FloatShapeInterval::uniteShapeIntervals(mergedIntervals, edgeIntervals, excl udedIntervals);
343
344 for (unsigned i = 0; i < excludedIntervals.size(); ++i) {
345 const FloatShapeInterval& interval = excludedIntervals[i];
346 result.append(LineSegment(interval.x1(), interval.x2()));
347 }
348 } 149 }
349 150
350 } // namespace WebCore 151 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698