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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 VertexMaxY, | 42 VertexMaxY, |
43 VertexYBoth | 43 VertexYBoth |
44 }; | 44 }; |
45 | 45 |
46 struct EdgeIntersection { | 46 struct EdgeIntersection { |
47 const FloatPolygonEdge* edge; | 47 const FloatPolygonEdge* edge; |
48 FloatPoint point; | 48 FloatPoint point; |
49 EdgeIntersectionType type; | 49 EdgeIntersectionType type; |
50 }; | 50 }; |
51 | 51 |
52 static inline float leftSide(const FloatPoint& vertex1, const FloatPoint& vertex
2, const FloatPoint& point) | |
53 { | |
54 return ((point.x() - vertex1.x()) * (vertex2.y() - vertex1.y())) - ((vertex2
.x() - vertex1.x()) * (point.y() - vertex1.y())); | |
55 } | |
56 | |
57 static inline bool isReflexVertex(const FloatPoint& prevVertex, const FloatPoint
& vertex, const FloatPoint& nextVertex) | |
58 { | |
59 return leftSide(prevVertex, nextVertex, vertex) < 0; | |
60 } | |
61 | |
62 static bool computeXIntersection(const FloatPolygonEdge* edgePointer, float y, E
dgeIntersection& result) | 52 static bool computeXIntersection(const FloatPolygonEdge* edgePointer, float y, E
dgeIntersection& result) |
63 { | 53 { |
64 const FloatPolygonEdge& edge = *edgePointer; | 54 const FloatPolygonEdge& edge = *edgePointer; |
65 | 55 |
66 if (edge.minY() > y || edge.maxY() < y) | 56 if (edge.minY() > y || edge.maxY() < y) |
67 return false; | 57 return false; |
68 | 58 |
69 const FloatPoint& vertex1 = edge.vertex1(); | 59 const FloatPoint& vertex1 = edge.vertex1(); |
70 const FloatPoint& vertex2 = edge.vertex2(); | 60 const FloatPoint& vertex2 = edge.vertex2(); |
71 float dy = vertex2.y() - vertex1.y(); | 61 float dy = vertex2.y() - vertex1.y(); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 } | 119 } |
130 vertices.append(endArcVertex); | 120 vertices.append(endArcVertex); |
131 } | 121 } |
132 | 122 |
133 static inline void snapVerticesToLayoutUnitGrid(Vector<FloatPoint>& vertices) | 123 static inline void snapVerticesToLayoutUnitGrid(Vector<FloatPoint>& vertices) |
134 { | 124 { |
135 for (unsigned i = 0; i < vertices.size(); ++i) | 125 for (unsigned i = 0; i < vertices.size(); ++i) |
136 vertices[i] = flooredLayoutPoint(vertices[i]); | 126 vertices[i] = flooredLayoutPoint(vertices[i]); |
137 } | 127 } |
138 | 128 |
139 static inline PassOwnPtr<FloatPolygon> computeShapePaddingBounds(const FloatPoly
gon& polygon, float padding, WindRule fillRule) | |
140 { | |
141 OwnPtr<Vector<FloatPoint> > paddedVertices = adoptPtr(new Vector<FloatPoint>
()); | |
142 FloatPoint intersection; | |
143 | |
144 for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) { | |
145 const FloatPolygonEdge& thisEdge = polygon.edgeAt(i); | |
146 const FloatPolygonEdge& prevEdge = thisEdge.previousEdge(); | |
147 OffsetPolygonEdge thisOffsetEdge(thisEdge, inwardEdgeNormal(thisEdge) *
padding); | |
148 OffsetPolygonEdge prevOffsetEdge(prevEdge, inwardEdgeNormal(prevEdge) *
padding); | |
149 | |
150 if (prevOffsetEdge.intersection(thisOffsetEdge, intersection)) | |
151 paddedVertices->append(intersection); | |
152 else if (isReflexVertex(prevEdge.vertex1(), thisEdge.vertex1(), thisEdge
.vertex2())) | |
153 appendArc(*paddedVertices, thisEdge.vertex1(), padding, prevOffsetEd
ge.vertex2(), thisOffsetEdge.vertex1(), true); | |
154 } | |
155 | |
156 snapVerticesToLayoutUnitGrid(*paddedVertices); | |
157 return adoptPtr(new FloatPolygon(paddedVertices.release(), fillRule)); | |
158 } | |
159 | |
160 static inline PassOwnPtr<FloatPolygon> computeShapeMarginBounds(const FloatPolyg
on& polygon, float margin, WindRule fillRule) | 129 static inline PassOwnPtr<FloatPolygon> computeShapeMarginBounds(const FloatPolyg
on& polygon, float margin, WindRule fillRule) |
161 { | 130 { |
162 OwnPtr<Vector<FloatPoint> > marginVertices = adoptPtr(new Vector<FloatPoint>
()); | 131 OwnPtr<Vector<FloatPoint> > marginVertices = adoptPtr(new Vector<FloatPoint>
()); |
163 FloatPoint intersection; | 132 FloatPoint intersection; |
164 | 133 |
165 for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) { | 134 for (unsigned i = 0; i < polygon.numberOfEdges(); ++i) { |
166 const FloatPolygonEdge& thisEdge = polygon.edgeAt(i); | 135 const FloatPolygonEdge& thisEdge = polygon.edgeAt(i); |
167 const FloatPolygonEdge& prevEdge = thisEdge.previousEdge(); | 136 const FloatPolygonEdge& prevEdge = thisEdge.previousEdge(); |
168 OffsetPolygonEdge thisOffsetEdge(thisEdge, outwardEdgeNormal(thisEdge) *
margin); | 137 OffsetPolygonEdge thisOffsetEdge(thisEdge, outwardEdgeNormal(thisEdge) *
margin); |
169 OffsetPolygonEdge prevOffsetEdge(prevEdge, outwardEdgeNormal(prevEdge) *
margin); | 138 OffsetPolygonEdge prevOffsetEdge(prevEdge, outwardEdgeNormal(prevEdge) *
margin); |
170 | 139 |
171 if (prevOffsetEdge.intersection(thisOffsetEdge, intersection)) | 140 if (prevOffsetEdge.intersection(thisOffsetEdge, intersection)) |
172 marginVertices->append(intersection); | 141 marginVertices->append(intersection); |
173 else | 142 else |
174 appendArc(*marginVertices, thisEdge.vertex1(), margin, prevOffsetEdg
e.vertex2(), thisOffsetEdge.vertex1(), false); | 143 appendArc(*marginVertices, thisEdge.vertex1(), margin, prevOffsetEdg
e.vertex2(), thisOffsetEdge.vertex1(), false); |
175 } | 144 } |
176 | 145 |
177 snapVerticesToLayoutUnitGrid(*marginVertices); | 146 snapVerticesToLayoutUnitGrid(*marginVertices); |
178 return adoptPtr(new FloatPolygon(marginVertices.release(), fillRule)); | 147 return adoptPtr(new FloatPolygon(marginVertices.release(), fillRule)); |
179 } | 148 } |
180 | 149 |
181 const FloatPolygon& PolygonShape::shapePaddingBounds() const | |
182 { | |
183 ASSERT(shapePadding() >= 0); | |
184 if (!shapePadding() || m_polygon.isEmpty()) | |
185 return m_polygon; | |
186 | |
187 if (!m_paddingBounds) | |
188 m_paddingBounds = computeShapePaddingBounds(m_polygon, shapePadding(), m
_polygon.fillRule()); | |
189 | |
190 return *m_paddingBounds; | |
191 } | |
192 | |
193 const FloatPolygon& PolygonShape::shapeMarginBounds() const | 150 const FloatPolygon& PolygonShape::shapeMarginBounds() const |
194 { | 151 { |
195 ASSERT(shapeMargin() >= 0); | 152 ASSERT(shapeMargin() >= 0); |
196 if (!shapeMargin() || m_polygon.isEmpty()) | 153 if (!shapeMargin() || m_polygon.isEmpty()) |
197 return m_polygon; | 154 return m_polygon; |
198 | 155 |
199 if (!m_marginBounds) | 156 if (!m_marginBounds) |
200 m_marginBounds = computeShapeMarginBounds(m_polygon, shapeMargin(), m_po
lygon.fillRule()); | 157 m_marginBounds = computeShapeMarginBounds(m_polygon, shapeMargin(), m_po
lygon.fillRule()); |
201 | 158 |
202 return *m_marginBounds; | 159 return *m_marginBounds; |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 | 340 |
384 FloatShapeIntervals excludedIntervals; | 341 FloatShapeIntervals excludedIntervals; |
385 FloatShapeInterval::uniteShapeIntervals(mergedIntervals, edgeIntervals, excl
udedIntervals); | 342 FloatShapeInterval::uniteShapeIntervals(mergedIntervals, edgeIntervals, excl
udedIntervals); |
386 | 343 |
387 for (unsigned i = 0; i < excludedIntervals.size(); ++i) { | 344 for (unsigned i = 0; i < excludedIntervals.size(); ++i) { |
388 const FloatShapeInterval& interval = excludedIntervals[i]; | 345 const FloatShapeInterval& interval = excludedIntervals[i]; |
389 result.append(LineSegment(interval.x1(), interval.x2())); | 346 result.append(LineSegment(interval.x1(), interval.x2())); |
390 } | 347 } |
391 } | 348 } |
392 | 349 |
393 void PolygonShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logica
lHeight, SegmentList& result) const | |
394 { | |
395 const FloatPolygon& polygon = shapePaddingBounds(); | |
396 if (polygon.isEmpty()) | |
397 return; | |
398 | |
399 float y1 = logicalTop.toFloat(); | |
400 float y2 = (logicalTop + logicalHeight).toFloat(); | |
401 | |
402 FloatShapeIntervals y1XIntervals, y2XIntervals; | |
403 computeXIntersections(polygon, y1, true, y1XIntervals); | |
404 computeXIntersections(polygon, y2, false, y2XIntervals); | |
405 | |
406 FloatShapeIntervals commonIntervals; | |
407 FloatShapeInterval::intersectShapeIntervals(y1XIntervals, y2XIntervals, comm
onIntervals); | |
408 | |
409 FloatShapeIntervals edgeIntervals; | |
410 computeOverlappingEdgeXProjections(polygon, y1, y2, edgeIntervals); | |
411 | |
412 FloatShapeIntervals includedIntervals; | |
413 FloatShapeInterval::subtractShapeIntervals(commonIntervals, edgeIntervals, i
ncludedIntervals); | |
414 | |
415 for (unsigned i = 0; i < includedIntervals.size(); ++i) { | |
416 const FloatShapeInterval& interval = includedIntervals[i]; | |
417 result.append(LineSegment(interval.x1(), interval.x2())); | |
418 } | |
419 } | |
420 | |
421 static inline bool firstFitRectInPolygon(const FloatPolygon& polygon, const Floa
tRect& rect, unsigned offsetEdgeIndex1, unsigned offsetEdgeIndex2) | |
422 { | |
423 Vector<const FloatPolygonEdge*> edges; | |
424 if (!polygon.overlappingEdges(rect.y(), rect.maxY(), edges)) | |
425 return true; | |
426 | |
427 for (unsigned i = 0; i < edges.size(); ++i) { | |
428 const FloatPolygonEdge* edge = edges[i]; | |
429 if (edge->edgeIndex() != offsetEdgeIndex1 && edge->edgeIndex() != offset
EdgeIndex2 && edge->overlapsRect(rect)) | |
430 return false; | |
431 } | |
432 | |
433 return true; | |
434 } | |
435 | |
436 static inline bool aboveOrToTheLeft(const FloatRect& r1, const FloatRect& r2) | |
437 { | |
438 if (r1.y() < r2.y()) | |
439 return true; | |
440 if (r1.y() == r2.y()) | |
441 return r1.x() < r2.x(); | |
442 return false; | |
443 } | |
444 | |
445 bool PolygonShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalInterval
Top, const FloatSize& minLogicalIntervalSize, LayoutUnit& result) const | |
446 { | |
447 float minIntervalTop = minLogicalIntervalTop.toFloat(); | |
448 float minIntervalHeight = minLogicalIntervalSize.height(); | |
449 float minIntervalWidth = minLogicalIntervalSize.width(); | |
450 | |
451 const FloatPolygon& polygon = shapePaddingBounds(); | |
452 const FloatRect boundingBox = polygon.boundingBox(); | |
453 if (minIntervalWidth > boundingBox.width()) | |
454 return false; | |
455 | |
456 float minY = std::max(boundingBox.y(), minIntervalTop); | |
457 float maxY = minY + minIntervalHeight; | |
458 | |
459 if (maxY > boundingBox.maxY()) | |
460 return false; | |
461 | |
462 Vector<const FloatPolygonEdge*> edges; | |
463 polygon.overlappingEdges(minIntervalTop, boundingBox.maxY(), edges); | |
464 | |
465 float dx = minIntervalWidth / 2; | |
466 float dy = minIntervalHeight / 2; | |
467 Vector<OffsetPolygonEdge> offsetEdges; | |
468 | |
469 for (unsigned i = 0; i < edges.size(); ++i) { | |
470 const FloatPolygonEdge& edge = *(edges[i]); | |
471 const FloatPoint& vertex0 = edge.previousEdge().vertex1(); | |
472 const FloatPoint& vertex1 = edge.vertex1(); | |
473 const FloatPoint& vertex2 = edge.vertex2(); | |
474 Vector<OffsetPolygonEdge> offsetEdgeBuffer; | |
475 | |
476 if (vertex2.y() > vertex1.y() ? vertex2.x() >= vertex1.x() : vertex1.x()
>= vertex2.x()) { | |
477 offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, -dy)))
; | |
478 offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, dy)))
; | |
479 } else { | |
480 offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(dx, dy))); | |
481 offsetEdgeBuffer.append(OffsetPolygonEdge(edge, FloatSize(-dx, -dy))
); | |
482 } | |
483 | |
484 if (isReflexVertex(vertex0, vertex1, vertex2)) { | |
485 if (vertex2.x() <= vertex1.x() && vertex0.x() <= vertex1.x()) | |
486 offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(dx,
-dy), FloatSize(dx, dy))); | |
487 else if (vertex2.x() >= vertex1.x() && vertex0.x() >= vertex1.x()) | |
488 offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx
, -dy), FloatSize(-dx, dy))); | |
489 if (vertex2.y() <= vertex1.y() && vertex0.y() <= vertex1.y()) | |
490 offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx
, dy), FloatSize(dx, dy))); | |
491 else if (vertex2.y() >= vertex1.y() && vertex0.y() >= vertex1.y()) | |
492 offsetEdgeBuffer.append(OffsetPolygonEdge(vertex1, FloatSize(-dx
, -dy), FloatSize(dx, -dy))); | |
493 } | |
494 | |
495 for (unsigned j = 0; j < offsetEdgeBuffer.size(); ++j) { | |
496 if (offsetEdgeBuffer[j].maxY() >= minY) | |
497 offsetEdges.append(offsetEdgeBuffer[j]); | |
498 } | |
499 } | |
500 | |
501 offsetEdges.append(OffsetPolygonEdge(polygon, minIntervalTop, FloatSize(0, d
y))); | |
502 | |
503 FloatPoint offsetEdgesIntersection; | |
504 FloatRect firstFitRect; | |
505 bool firstFitFound = false; | |
506 | |
507 for (unsigned i = 0; i < offsetEdges.size() - 1; ++i) { | |
508 for (unsigned j = i + 1; j < offsetEdges.size(); ++j) { | |
509 if (offsetEdges[i].intersection(offsetEdges[j], offsetEdgesIntersect
ion)) { | |
510 FloatPoint potentialFirstFitLocation(offsetEdgesIntersection.x()
- dx, offsetEdgesIntersection.y() - dy); | |
511 FloatRect potentialFirstFitRect(potentialFirstFitLocation, minLo
gicalIntervalSize); | |
512 if ((offsetEdges[i].basis() == OffsetPolygonEdge::LineTop | |
513 || offsetEdges[j].basis() == OffsetPolygonEdge::LineTop | |
514 || potentialFirstFitLocation.y() >= minIntervalTop) | |
515 && (!firstFitFound || aboveOrToTheLeft(potentialFirstFitRect
, firstFitRect)) | |
516 && polygon.contains(offsetEdgesIntersection) | |
517 && firstFitRectInPolygon(polygon, potentialFirstFitRect, off
setEdges[i].edgeIndex(), offsetEdges[j].edgeIndex())) { | |
518 firstFitFound = true; | |
519 firstFitRect = potentialFirstFitRect; | |
520 } | |
521 } | |
522 } | |
523 } | |
524 | |
525 if (firstFitFound) | |
526 result = LayoutUnit::fromFloatCeil(firstFitRect.y()); | |
527 return firstFitFound; | |
528 } | |
529 | |
530 } // namespace WebCore | 350 } // namespace WebCore |
OLD | NEW |