| 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 |