| OLD | NEW |
| 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 Loading... |
| 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 |
| OLD | NEW |