2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "LoopBlinnPathProcessor.h"
30 #include "FloatPoint.h"
31 #include "FloatRect.h"
32 #include "LoopBlinnClassifier.h"
33 #include "LoopBlinnConstants.h"
34 #include "LoopBlinnLocalTriangulator.h"
35 #include "LoopBlinnMathUtils.h"
36 #include "LoopBlinnPathCache.h"
37 #include "LoopBlinnTextureCoords.h"
39 #include "PODIntervalTree.h"
41 #include "internal_glu.h"
43 #include <wtf/Assertions.h>
44 #include <wtf/FastMalloc.h>
45 #include <wtf/UnusedParam.h>
49 #include "SkGeometry.h"
53 // Must port to your platform.
58 using LoopBlinnMathUtils::XRay;
59 using LoopBlinnMathUtils::chopCubicAt;
60 using LoopBlinnMathUtils::numXRayCrossingsForCubic;
61 using LoopBlinnMathUtils::trianglesOverlap;
62 using LoopBlinnMathUtils::xRayCrossesLine;
63 using LoopBlinnPathProcessorImplementation::Contour;
64 using LoopBlinnPathProcessorImplementation::Segment;
69 String valueToString(const FloatRect& arg)
71 StringBuilder builder;
72 builder.append("[FloatRect x=");
73 builder.append(String::number(arg.x()));
74 builder.append(" y=");
75 builder.append(String::number(arg.y()));
76 builder.append(" maxX=");
77 builder.append(String::number(arg.maxX()));
78 builder.append(" maxY=");
79 builder.append(String::number(arg.maxY()));
81 return builder.toString();
87 } // anonymous namespace
89 namespace LoopBlinnPathProcessorImplementation {
94 // Routines needed to print the types of IntervalNodes we instantiate
97 struct ValueToString<float> {
98 static String string(const float& value)
100 return String::number(value);
105 struct ValueToString<SweepData*> {
106 static String string(SweepData* const& value)
108 return String::format("0x%p", value);
113 struct ValueToString<LoopBlinnPathProcessorImplementation::Segment*> {
114 static String string(LoopBlinnPathProcessorImplementation::Segment* const& value)
116 return String::format("0x%p", value);
121 namespace LoopBlinnPathProcessorImplementation {
123 //----------------------------------------------------------------------
127 // Describes a segment of the path: either a cubic or a line segment.
128 // These are stored in a doubly linked list to speed up curve
129 // subdivision, which occurs due to either rendering artifacts in the
130 // loop case or due to overlapping triangles.
132 WTF_MAKE_NONCOPYABLE(Segment);
139 // No-argument constructor allows construction by the PODArena class.
147 , m_markedForSubdivision(false)
151 // Initializer for cubic curve segments.
152 void setup(PODArena* arena,
166 computeBoundingBox();
169 // Initializer for line segments.
170 void setup(PODArena* arena,
180 computeBoundingBox();
183 Kind kind() const { return m_kind; }
185 // Returns the i'th control point, 0 <= i < 4.
186 const FloatPoint& getPoint(int i)
188 ASSERT(i >= 0 && i < 4);
192 Segment* next() const { return m_next; }
193 Segment* prev() const { return m_prev; }
195 void setNext(Segment* next) { m_next = next; }
196 void setPrev(Segment* prev) { m_prev = prev; }
198 // The contour this segment belongs to.
199 Contour* contour() const { return m_contour; }
201 // Subdivides the current segment at the given parameter value (0 <=
202 // t <= 1) and replaces it with the two newly created Segments in
203 // the linked list, if possible. Returns a pointer to the leftmost
205 Segment* subdivide(float param)
208 chopCubicAt(m_points, dst, param);
209 Segment* left = m_arena->allocateObject<Segment>();
210 Segment* right = m_arena->allocateObject<Segment>();
211 left->setup(m_arena, m_contour, dst[0], dst[1], dst[2], dst[3]);
212 right->setup(m_arena, m_contour, dst[3], dst[4], dst[5], dst[6]);
213 left->setNext(right);
214 right->setPrev(left);
215 // Try to set up a link between "this->prev()" and "left".
217 left->setPrev(prev());
218 prev()->setNext(left);
220 // Try to set up a link between "this->next()" and "right".
226 // Set up a link between "this" and "left"; this is only to
227 // provide a certain amount of continuity during forward iteration.
232 // Subdivides the current segment at the halfway point and replaces
233 // it with the two newly created Segments in the linked list, if
234 // possible. Returns a pointer to the leftmost Segment.
235 Segment* subdivide() { return subdivide(0.5f); }
237 const FloatRect& boundingBox() const { return m_boundingBox; }
239 // Computes the number of times a query line starting at the given
240 // point and extending to x=+infinity crosses this segment. Outgoing
241 // "ambiguous" argument indicates whether the query intersected an
242 // endpoint or tangent point of the segment, indicating that another
243 // query point is preferred.
244 int numCrossingsForXRay(const XRay& xRay, bool& ambiguous) const
247 // Should consider caching the monotonic cubics.
248 return numXRayCrossingsForCubic(xRay, m_points, ambiguous);
250 return xRayCrossesLine(xRay, m_points, ambiguous) ? 1 : 0;
253 // Performs a local triangulation of the control points in this
254 // segment. This operation only makes sense for cubic type segments.
255 // texCoords may be null when the klm coordinates have not been
257 void triangulate(LoopBlinnLocalTriangulator::InsideEdgeComputation computeInsideEdges,
258 const LoopBlinnTextureCoords::Result* texCoords);
260 // Returns the number of control point triangles associated with
262 int numberOfTriangles() const
266 return m_triangulator->numberOfTriangles();
269 // Fetches the given control point triangle for this segment.
270 LoopBlinnLocalTriangulator::Triangle* getTriangle(int index)
272 ASSERT(m_triangulator);
273 return m_triangulator->getTriangle(index);
276 // Number of vertices along the inside edge of this segment. This
277 // can be called either for line or cubic type segments.
278 int numberOfInteriorVertices() const
280 if (m_kind == Cubic) {
282 return m_triangulator->numberOfInteriorVertices();
290 // Returns the given interior vertex, 0 <= index < numberOfInteriorVertices().
291 FloatPoint getInteriorVertex(int index) const
293 ASSERT(index >= 0 && index < numberOfInteriorVertices());
294 if (m_kind == Cubic) {
296 if (m_triangulator) {
297 LoopBlinnLocalTriangulator::Vertex* vertex = m_triangulator->getInteriorVertex(index);
299 res.set(vertex->xyCoordinates().x(), vertex->xyCoordinates().y());
304 return m_points[index];
307 // State to assist with curve subdivision.
308 bool markedForSubdivision() const { return m_markedForSubdivision; }
309 void setMarkedForSubdivision(bool markedForSubdivision) { m_markedForSubdivision = markedForSubdivision; }
312 // Suppport for printing Segments.
313 String toString() const
315 StringBuilder builder;
316 builder.append("[Segment kind=");
317 builder.append(kind() == Line ? "line" : "cubic");
318 builder.append(" boundingBox=");
319 builder.append(valueToString(boundingBox()));
320 builder.append(" contour=0x");
321 builder.append(String::format("%p", contour()));
322 builder.append(" markedForSubdivision=");
323 builder.append(markedForSubdivision() ? "true" : "false");
325 return builder.toString();
330 // Computes the bounding box of this Segment.
331 void computeBoundingBox()
335 m_boundingBox.fitToPoints(m_points[0], m_points[1], m_points[2], m_points[3]);
339 m_boundingBox.fitToPoints(m_points[0], m_points[1]);
346 FloatPoint m_points[4];
350 FloatRect m_boundingBox;
351 LoopBlinnLocalTriangulator* m_triangulator;
352 bool m_markedForSubdivision;
355 //----------------------------------------------------------------------
359 // Describes a closed contour of the path.
361 WTF_MAKE_NONCOPYABLE(Contour);
365 m_first = &m_sentinel;
366 m_first->setNext(m_first);
367 m_first->setPrev(m_first);
368 m_isOrientedCounterClockwise = true;
369 m_boundingBoxDirty = false;
370 m_fillSide = LoopBlinnConstants::RightSide;
373 void add(Segment* segment)
375 if (m_first == &m_sentinel) {
376 // First element is the sentinel. Replace it with the incoming
378 segment->setNext(m_first);
379 segment->setPrev(m_first);
380 m_first->setNext(segment);
381 m_first->setPrev(segment);
384 // m_first->prev() is the sentinel.
385 ASSERT(m_first->prev() == &m_sentinel);
386 Segment* last = m_sentinel.prev();
387 last->setNext(segment);
388 segment->setPrev(last);
389 segment->setNext(&m_sentinel);
390 m_sentinel.setPrev(segment);
392 m_boundingBoxDirty = true;
395 // Subdivides the given segment at the given parametric value.
396 // Returns a pointer to the first of the two portions of the
397 // subdivided segment.
398 Segment* subdivide(Segment* segment, float param)
400 Segment* left = segment->subdivide(param);
401 if (m_first == segment)
406 // Subdivides the given segment at the halfway point. Returns a
407 // pointer to the first of the two portions of the subdivided
409 Segment* subdivide(Segment* segment)
411 Segment* left = segment->subdivide();
412 if (m_first == segment)
417 // Returns the first segment in the contour for iteration.
418 Segment* begin() const { return m_first; }
420 // Returns the last segment in the contour for iteration. Callers
421 // should not iterate over this segment. In other words:
422 // for (Segment* cur = contour->begin();
423 // cur != contour->end();
424 // cur = cur->next()) {
425 // // .. process cur ...
429 ASSERT(m_first->prev() == &m_sentinel);
433 bool isOrientedCounterClockwise() const { return m_isOrientedCounterClockwise; }
434 void setIsOrientedCounterClockwise(bool isOrientedCounterClockwise) { m_isOrientedCounterClockwise = isOrientedCounterClockwise; }
436 const FloatRect& boundingBox()
438 if (m_boundingBoxDirty) {
440 for (Segment* cur = begin(); cur != end(); cur = cur->next()) {
442 m_boundingBox = cur->boundingBox();
444 m_boundingBox.unite(cur->boundingBox());
448 m_boundingBoxDirty = false;
450 return m_boundingBox;
453 // Returns which side of this contour is filled.
454 LoopBlinnConstants::FillSide fillSide() const
459 void setFillSide(LoopBlinnConstants::FillSide fillSide)
461 m_fillSide = fillSide;
465 // The start of the segment chain. The segments are kept in a
466 // circular doubly linked list for rapid access to the beginning and
470 // The sentinel element at the end of the chain, needed for
471 // reasonable iteration semantics.
474 bool m_isOrientedCounterClockwise;
476 FloatRect m_boundingBox;
477 bool m_boundingBoxDirty;
479 // Which side of this contour should be filled.
480 LoopBlinnConstants::FillSide m_fillSide;
483 //----------------------------------------------------------------------
487 // Definition of Segment::triangulate(), which must come after
488 // declaration of Contour.
489 void Segment::triangulate(LoopBlinnLocalTriangulator::InsideEdgeComputation computeInsideEdges,
490 const LoopBlinnTextureCoords::Result* texCoords)
492 ASSERT(m_kind == Cubic);
494 m_triangulator = m_arena->allocateObject<LoopBlinnLocalTriangulator>();
495 m_triangulator->reset();
496 for (int i = 0; i < 4; i++) {
497 LoopBlinnLocalTriangulator::Vertex* vertex = m_triangulator->getVertex(i);
499 vertex->set(getPoint(i).x(),
501 texCoords->klmCoordinates[i].x(),
502 texCoords->klmCoordinates[i].y(),
503 texCoords->klmCoordinates[i].z());
505 vertex->set(getPoint(i).x(),
507 // No texture coordinates yet
511 m_triangulator->triangulate(computeInsideEdges, contour()->fillSide());
514 } // namespace LoopBlinnPathProcessorImplementation
516 //----------------------------------------------------------------------
517 // LoopBlinnPathProcessor
520 LoopBlinnPathProcessor::LoopBlinnPathProcessor()
521 : m_arena(PODArena::create())
523 , m_verboseLogging(false)
528 LoopBlinnPathProcessor::LoopBlinnPathProcessor(PassRefPtr<PODArena> arena)
531 , m_verboseLogging(false)
536 LoopBlinnPathProcessor::~LoopBlinnPathProcessor()
540 void LoopBlinnPathProcessor::process(const Path& path, LoopBlinnPathCache& cache)
544 // Run plane-sweep algorithm to determine overlaps of control point
545 // curves and subdivide curves appropriately.
548 // Determine orientations of countours. Based on orientation and the
549 // number of curve crossings at a random point on the contour,
550 // determine whether to fill the left or right side of the contour.
551 determineSidesToFill();
553 // Classify curves, compute texture coordinates and subdivide as
554 // necessary to eliminate rendering artifacts. Do the final
555 // triangulation of the curve segments, determining the path along
556 // the interior of the shape.
557 for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) {
558 Contour* cur = *iter;
559 for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) {
560 if (seg->kind() == Segment::Cubic) {
561 LoopBlinnClassifier::Result classification = LoopBlinnClassifier::classify(seg->getPoint(0),
566 if (m_verboseLogging)
567 LOG_ERROR("Classification: %d", (int) classification.curveType);
569 LoopBlinnTextureCoords::Result texCoords =
570 LoopBlinnTextureCoords::compute(classification, cur->fillSide());
571 if (texCoords.hasRenderingArtifact) {
572 // FIXME: there is a problem where the algorithm
573 // sometimes fails to converge when splitting at the
574 // subdivision parameter value. For the time being,
577 // Next iteration will handle the newly subdivided curves
579 if (!texCoords.isLineOrPoint) {
580 seg->triangulate(LoopBlinnLocalTriangulator::ComputeInsideEdges, &texCoords);
581 for (int i = 0; i < seg->numberOfTriangles(); i++) {
582 LoopBlinnLocalTriangulator::Triangle* triangle = seg->getTriangle(i);
583 for (int j = 0; j < 3; j++) {
584 LoopBlinnLocalTriangulator::Vertex* vert = triangle->getVertex(j);
585 cache.addVertex(vert->xyCoordinates().x(),
586 vert->xyCoordinates().y(),
587 vert->klmCoordinates().x(),
588 vert->klmCoordinates().y(),
589 vert->klmCoordinates().z());
592 #ifdef LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES
593 // Show the end user the interior edges as well
594 for (int i = 1; i < seg->numberOfInteriorVertices(); i++) {
595 FloatPoint vert = seg->getInteriorVertex(i);
596 // Duplicate previous vertex to be able to draw GL_LINES
597 FloatPoint prev = seg->getInteriorVertex(i - 1);
598 cache.addInteriorEdgeVertex(prev.x(), prev.y());
599 cache.addInteriorEdgeVertex(vert.x(), vert.y());
601 #endif // LOOP_BLINN_PATH_CACHE_DEBUG_INTERIOR_EDGES
608 // Run the interior paths through a tessellation algorithm
609 // supporting multiple contours.
610 tessellateInterior(cache);
613 void LoopBlinnPathProcessor::buildContours(const Path& path)
615 // Clear out the contours
618 SkPath::Iter iter(*path.platformPath(), false);
621 Contour* contour = 0;
622 SkPoint curPoint = { 0 };
623 SkPoint moveToPoint = { 0 };
625 verb = iter.next(points);
626 if (verb != SkPath::kMove_Verb) {
628 contour = m_arena->allocateObject<Contour>();
629 m_contours.append(contour);
633 case SkPath::kMove_Verb: {
634 contour = m_arena->allocateObject<Contour>();
635 m_contours.append(contour);
636 curPoint = points[0];
637 moveToPoint = points[0];
639 if (m_verboseLogging)
640 LOG_ERROR("MoveTo (%f, %f)", points[0].fX, points[0].fY);
644 case SkPath::kLine_Verb: {
645 Segment* segment = m_arena->allocateObject<Segment>();
646 if (iter.isCloseLine()) {
647 segment->setup(m_arena.get(), contour, curPoint, points[1]);
649 if (m_verboseLogging)
650 LOG_ERROR("CloseLineTo (%f, %f), (%f, %f)", curPoint.fX, curPoint.fY, points[1].fX, points[1].fY);
652 contour->add(segment);
655 segment->setup(m_arena.get(), contour, points[0], points[1]);
657 if (m_verboseLogging)
658 LOG_ERROR("LineTo (%f, %f), (%f, %f)", points[0].fX, points[0].fY, points[1].fX, points[1].fY);
660 contour->add(segment);
661 curPoint = points[1];
665 case SkPath::kQuad_Verb: {
666 // Need to degree elevate the quadratic into a cubic
668 SkConvertQuadToCubic(points, cubic);
669 Segment* segment = m_arena->allocateObject<Segment>();
670 segment->setup(m_arena.get(), contour,
671 cubic[0], cubic[1], cubic[2], cubic[3]);
673 if (m_verboseLogging)
674 LOG_ERROR("Quad->CubicTo (%f, %f), (%f, %f), (%f, %f), (%f, %f)", cubic[0].fX, cubic[0].fY, cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY);
676 contour->add(segment);
680 case SkPath::kCubic_Verb: {
681 Segment* segment = m_arena->allocateObject<Segment>();
682 segment->setup(m_arena.get(), contour, points[0], points[1], points[2], points[3]);
684 if (m_verboseLogging)
685 LOG_ERROR("CubicTo (%f, %f), (%f, %f), (%f, %f), (%f, %f)", points[0].fX, points[0].fY, points[1].fX, points[1].fY, points[2].fX, points[2].fY, points[3].fX, points[3].fY);
687 contour->add(segment);
688 curPoint = points[3];
691 case SkPath::kClose_Verb: {
692 Segment* segment = m_arena->allocateObject<Segment>();
693 segment->setup(m_arena.get(), contour, curPoint, moveToPoint);
695 if (m_verboseLogging)
696 LOG_ERROR("Close (%f, %f) -> (%f, %f)", curPoint.fX, curPoint.fY, moveToPoint.fX, moveToPoint.fY);
698 contour->add(segment);
701 case SkPath::kDone_Verb:
704 } while (verb != SkPath::kDone_Verb);
707 // Must port to your platform.
708 ASSERT_NOT_REACHED();
713 Vector<Segment*> LoopBlinnPathProcessor::allSegmentsOverlappingY(Contour* queryContour, float x, float y)
715 Vector<Segment*> res;
716 for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) {
717 Contour* cur = *iter;
718 for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) {
719 const FloatRect& boundingBox = seg->boundingBox();
720 if (boundingBox.y() <= y && y <= boundingBox.maxY())
728 // Uncomment this to debug the orientation computation.
729 // #define GPU_PATH_PROCESSOR_DEBUG_ORIENTATION
731 void LoopBlinnPathProcessor::determineSidesToFill()
733 // Loop and Blinn's algorithm can only easily emulate the even/odd
734 // fill rule, and only for non-intersecting curves. We can determine
735 // which side of each curve segment to fill based on its
736 // clockwise/counterclockwise orientation and how many other
737 // contours surround it.
739 // To optimize the query of all curve segments intersecting a
740 // horizontal line going to x=+infinity, we build up an interval
741 // tree whose keys are the y extents of the segments.
742 PODIntervalTree<float, Segment*> tree(m_arena);
743 typedef PODIntervalTree<float, Segment*>::IntervalType IntervalType;
745 for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) {
746 Contour* cur = *iter;
747 determineOrientation(cur);
748 for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) {
749 const FloatRect& boundingBox = seg->boundingBox();
750 tree.add(tree.createInterval(boundingBox.y(), boundingBox.maxY(), seg));
754 // Now iterate through the contours and pick a random segment (in
755 // this case we use the first) and a random point on that segment.
756 // Find all segments from other contours which intersect this one
757 // and count the number of crossings a horizontal line to
758 // x=+infinity makes with those contours. This combined with the
759 // orientation of the curve tells us which side to fill -- again,
760 // assuming an even/odd fill rule, which is all we can easily
762 for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) {
763 Contour* cur = *iter;
765 bool ambiguous = true;
766 int numCrossings = 0;
768 // For each contour, attempt to find a point on the contour which,
769 // when we cast an XRay, does not intersect the other contours at
770 // an ambiguous point (the junction between two curves or at a
771 // tangent point). Ambiguous points make the determination of
772 // whether this contour is contained within another fragile. Note
773 // that this loop is only an approximation to the selection of a
774 // good casting point. We could as well evaluate a segment to
775 // determine a point upon it.
776 for (Segment* seg = cur->begin();
777 ambiguous && seg != cur->end();
780 // We use a zero-sized vertical interval for the query.
781 Vector<IntervalType> overlaps = tree.allOverlaps(tree.createInterval(seg->getPoint(0).y(),
782 seg->getPoint(0).y(),
784 #if defined(GPU_PATH_PROCESSOR_DEBUG_ORIENTATION) && !defined(NDEBUG)
785 Vector<Segment*> slowOverlaps = allSegmentsOverlappingY(cur, seg->getPoint(0).x(), seg->getPoint(0).y());
786 if (overlaps.size() != slowOverlaps.size()) {
787 LOG_ERROR("For query point (%f, %f) on contour 0x%p:", seg->getPoint(0).x(), seg->getPoint(0).y(), cur);
788 LOG_ERROR(" overlaps:");
789 for (size_t i = 0; i < overlaps.size(); i++)
790 LOG_ERROR(" %d: %s", i+1, overlaps[i].data()->toString().ascii().data());
791 LOG_ERROR(" slowOverlaps:");
792 for (size_t i = 0; i < slowOverlaps.size(); i++)
793 LOG_ERROR(" %d: %s", (i+1) slowOverlaps[i]->toString());
794 LOG_ERROR("Interval tree:");
797 ASSERT(overlaps.size() == slowOverlaps.size());
798 #endif // defined(GPU_PATH_PROCESSOR_DEBUG_ORIENTATION) && !defined(NDEBUG)
799 for (Vector<IntervalType>::iterator iter = overlaps.begin(); iter != overlaps.end(); ++iter) {
800 const IntervalType& interval = *iter;
801 Segment* querySegment = interval.data();
802 // Ignore segments coming from the same contour.
803 if (querySegment->contour() != cur) {
804 // Only perform queries that can affect the computation.
805 const FloatRect& boundingBox = querySegment->contour()->boundingBox();
806 if (seg->getPoint(0).x() >= boundingBox.x()
807 && seg->getPoint(0).x() <= boundingBox.maxX()) {
808 numCrossings += querySegment->numCrossingsForXRay(seg->getPoint(0),
812 if (m_verboseLogging) {
813 LOG_ERROR("Ambiguous intersection query at point (%f, %f)", seg->getPoint(0).x(), seg->getPoint(0).y());
814 LOG_ERROR("Query segment: %s", querySegment->toString().ascii().data());
817 break; // Abort iteration over overlaps.
822 } // for (Segment* seg = cur->begin(); ...
824 cur->setFillSide((cur->isOrientedCounterClockwise() ^ (numCrossings & 1)) ? LoopBlinnConstants::LeftSide : LoopBlinnConstants::RightSide);
828 void LoopBlinnPathProcessor::determineOrientation(Contour* contour)
830 // Determine signed area of the polygon represented by the points
831 // along the segments. Consider this an approximation to the true
832 // orientation of the polygon; it probably won't handle
833 // self-intersecting curves correctly.
835 // There is also a pretty basic assumption here that the contour is
837 float signedArea = 0;
838 for (Segment* seg = contour->begin();
839 seg != contour->end();
841 int limit = (seg->kind() == Segment::Cubic) ? 4 : 2;
842 for (int i = 1; i < limit; i++) {
843 const FloatPoint& prevPoint = seg->getPoint(i - 1);
844 const FloatPoint& point = seg->getPoint(i);
845 float curArea = prevPoint.x() * point.y() - prevPoint.y() * point.x();
847 if (m_verboseLogging)
848 LOG_ERROR("Adding to signed area (%f, %f) -> (%f, %f) = %f", prevPoint.x(), prevPoint.y(), point.x(), point.y(), curArea);
850 signedArea += curArea;
855 contour->setIsOrientedCounterClockwise(true);
857 contour->setIsOrientedCounterClockwise(false);
862 //----------------------------------------------------------------------
863 // Classes and typedefs needed for curve subdivision. These can't be scoped
864 // within the subdivideCurves() method itself, because templates then fail
867 // The user data which is placed in the PODIntervalTree.
875 // The triangle this interval is associated with
876 LoopBlinnLocalTriangulator::Triangle* triangle;
877 // The segment the triangle is associated with
881 typedef PODIntervalTree<float, SweepData*> SweepTree;
882 typedef SweepTree::IntervalType SweepInterval;
884 // The entry / exit events which occur at the minimum and maximum x
885 // coordinates of the control point triangles' bounding boxes.
887 // Note that this class requires its copy constructor and assignment
888 // operator since it needs to be stored in a Vector.
894 , m_interval(0, 0, 0)
898 // Initializes the SweepEvent.
899 void setup(float x, bool entry, SweepInterval interval)
903 m_interval = interval;
906 float x() const { return m_x; }
907 bool entry() const { return m_entry; }
908 const SweepInterval& interval() const { return m_interval; }
910 bool operator<(const SweepEvent& other) const
912 return m_x < other.m_x;
918 SweepInterval m_interval;
921 bool trianglesOverlap(LoopBlinnLocalTriangulator::Triangle* t0,
922 LoopBlinnLocalTriangulator::Triangle* t1)
924 return trianglesOverlap(t0->getVertex(0)->xyCoordinates(),
925 t0->getVertex(1)->xyCoordinates(),
926 t0->getVertex(2)->xyCoordinates(),
927 t1->getVertex(0)->xyCoordinates(),
928 t1->getVertex(1)->xyCoordinates(),
929 t1->getVertex(2)->xyCoordinates());
932 } // anonymous namespace
934 void LoopBlinnPathProcessor::subdivideCurves()
936 // We need to determine all overlaps of all control point triangles
937 // (from different segments, not the same segment) and, if any
938 // exist, subdivide the associated curves.
940 // The plane-sweep algorithm determines all overlaps of a set of
941 // rectangles in the 2D plane. Our problem maps very well to this
942 // algorithm and significantly reduces the complexity compared to a
943 // naive implementation.
945 // Each bounding box of a control point triangle is converted into
946 // an "entry" event at its smallest X coordinate and an "exit" event
947 // at its largest X coordinate. Each event has an associated
948 // one-dimensional interval representing the Y span of the bounding
949 // box. We sort these events by increasing X coordinate. We then
950 // iterate through them. For each entry event we add the interval to
951 // a side interval tree, and query this tree for overlapping
952 // intervals. Any overlapping interval corresponds to an overlapping
953 // bounding box. For each exit event we remove the associated
954 // interval from the interval tree.
956 Vector<Segment*> curSegments;
957 Vector<Segment*> nextSegments;
959 // Start things off by considering all of the segments
960 for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) {
961 Contour* cur = *iter;
962 for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) {
963 if (seg->kind() == Segment::Cubic) {
964 seg->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0);
965 curSegments.append(seg);
970 // Subdivide curves at most this many times
971 const int MaxIterations = 5;
972 Vector<SweepInterval> overlaps;
974 for (int currentIteration = 0; currentIteration < MaxIterations; ++currentIteration) {
975 if (!curSegments.size())
979 Vector<SweepEvent> events;
980 SweepTree tree(m_arena);
981 for (Vector<Segment*>::iterator iter = curSegments.begin(); iter != curSegments.end(); ++iter) {
982 Segment* seg = *iter;
983 ASSERT(seg->kind() == Segment::Cubic);
984 for (int i = 0; i < seg->numberOfTriangles(); i++) {
985 LoopBlinnLocalTriangulator::Triangle* triangle = seg->getTriangle(i);
986 FloatRect boundingBox;
987 boundingBox.fitToPoints(triangle->getVertex(0)->xyCoordinates(),
988 triangle->getVertex(1)->xyCoordinates(),
989 triangle->getVertex(2)->xyCoordinates());
990 // Ignore zero-width triangles to avoid issues with
991 // coincident entry and exit events for the same triangle
992 if (boundingBox.maxX() > boundingBox.x()) {
993 SweepData* data = m_arena->allocateObject<SweepData>();
994 data->triangle = triangle;
996 SweepInterval interval = tree.createInterval(boundingBox.y(), boundingBox.maxY(), data);
997 // Add entry and exit events
999 event.setup(boundingBox.x(), true, interval);
1000 events.append(event);
1001 event.setup(boundingBox.maxX(), false, interval);
1002 events.append(event);
1007 // Sort events by increasing X coordinate
1008 std::sort(events.begin(), events.end());
1010 for (size_t ii = 1; ii < events.size(); ++ii)
1011 ASSERT(events[ii - 1].x() <= events[ii].x());
1014 // Now iterate through the events
1015 for (Vector<SweepEvent>::iterator iter = events.begin(); iter != events.end(); ++iter) {
1016 SweepEvent event = *iter;
1017 if (event.entry()) {
1018 // See whether the associated segment has been subdivided yet
1019 if (!event.interval().data()->segment->markedForSubdivision()) {
1022 tree.allOverlaps(event.interval(), overlaps);
1023 // Now see exactly which triangles overlap this one
1024 for (Vector<SweepInterval>::iterator iter = overlaps.begin(); iter != overlaps.end(); ++iter) {
1025 SweepInterval overlap = *iter;
1026 // Only pay attention to overlaps from a different Segment
1027 if (event.interval().data()->segment != overlap.data()->segment) {
1028 // See whether the triangles actually overlap
1029 if (trianglesOverlap(event.interval().data()->triangle,
1030 overlap.data()->triangle)) {
1031 // Actually subdivide the segments.
1032 // Each one might already have been subdivided.
1033 Segment* seg = event.interval().data()->segment;
1034 conditionallySubdivide(seg, nextSegments);
1035 seg = overlap.data()->segment;
1036 conditionallySubdivide(seg, nextSegments);
1041 // Add this interval into the tree
1042 tree.add(event.interval());
1044 // Remove this interval from the tree
1045 tree.remove(event.interval());
1049 curSegments.swap(nextSegments);
1050 nextSegments.clear();
1054 void LoopBlinnPathProcessor::conditionallySubdivide(Segment* seg, Vector<Segment*>& nextSegments)
1056 if (!seg->markedForSubdivision()) {
1057 seg->setMarkedForSubdivision(true);
1058 Segment* next = seg->contour()->subdivide(seg);
1059 // Triangulate the newly subdivided segments.
1060 next->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0);
1061 next->next()->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0);
1062 // Add them for the next iteration.
1063 nextSegments.append(next);
1064 nextSegments.append(next->next());
1069 void LoopBlinnPathProcessor::subdivideCurvesSlow()
1071 // Alternate, significantly slower algorithm for curve subdivision
1072 // for use in debugging.
1073 Vector<Segment*> curSegments;
1074 Vector<Segment*> nextSegments;
1076 // Start things off by considering all of the segments
1077 for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) {
1078 Contour* cur = *iter;
1079 for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) {
1080 if (seg->kind() == Segment::Cubic) {
1081 seg->triangulate(LoopBlinnLocalTriangulator::DontComputeInsideEdges, 0);
1082 curSegments.append(seg);
1087 // Subdivide curves at most this many times
1088 const int MaxIterations = 5;
1090 for (int currentIteration = 0; currentIteration < MaxIterations; ++currentIteration) {
1091 if (!curSegments.size())
1095 for (Vector<Segment*>::iterator iter = curSegments.begin(); iter != curSegments.end(); ++iter) {
1096 Segment* seg = *iter;
1097 ASSERT(seg->kind() == Segment::Cubic);
1098 for (Vector<Segment*>::iterator iter2 = curSegments.begin();
1099 iter2 != curSegments.end();
1101 Segment* seg2 = *iter2;
1102 ASSERT(seg2->kind() == Segment::Cubic);
1104 for (int i = 0; i < seg->numberOfTriangles(); i++) {
1105 LoopBlinnLocalTriangulator::Triangle* triangle = seg->getTriangle(i);
1106 for (int j = 0; j < seg2->numberOfTriangles(); j++) {
1107 LoopBlinnLocalTriangulator::Triangle* triangle2 = seg2->getTriangle(j);
1108 if (trianglesOverlap(triangle, triangle2)) {
1109 conditionallySubdivide(seg, nextSegments);
1110 conditionallySubdivide(seg2, nextSegments);
1118 curSegments.swap(nextSegments);
1119 nextSegments.clear();
1126 //----------------------------------------------------------------------
1127 // Structures and callbacks for tessellation of the interior region of
1130 // The user data for the GLU tessellator.
1131 struct TessellationState {
1132 TessellationState(LoopBlinnPathCache& inputCache)
1133 : cache(inputCache) { }
1135 LoopBlinnPathCache& cache;
1136 Vector<void*> allocatedPointers;
1139 static void vertexCallback(void* vertexData, void* data)
1141 TessellationState* state = static_cast<TessellationState*>(data);
1142 GLdouble* location = static_cast<GLdouble*>(vertexData);
1143 state->cache.addInteriorVertex(static_cast<float>(location[0]),
1144 static_cast<float>(location[1]));
1147 static void combineCallback(GLdouble coords[3], void* vertexData[4],
1148 GLfloat weight[4], void** outData,
1151 UNUSED_PARAM(vertexData);
1152 UNUSED_PARAM(weight);
1153 TessellationState* state = static_cast<TessellationState*>(polygonData);
1154 GLdouble* outVertex = static_cast<GLdouble*>(fastMalloc(3 * sizeof(GLdouble)));
1155 state->allocatedPointers.append(outVertex);
1156 outVertex[0] = coords[0];
1157 outVertex[1] = coords[1];
1158 outVertex[2] = coords[2];
1159 *outData = outVertex;
1162 static void edgeFlagCallback(GLboolean)
1164 // No-op just to prevent triangle strips and fans from being passed to us.
1165 // See the OpenGL Programming Guide, Chapter 11, "Tessellators and Quadrics".
1168 } // anonymous namespace
1170 void LoopBlinnPathProcessor::tessellateInterior(LoopBlinnPathCache& cache)
1172 // Because the GLU tessellator requires its input in
1173 // double-precision format, we need to make a separate copy of the
1175 Vector<GLdouble> vertexData;
1176 Vector<size_t> contourEndings;
1177 // For avoiding adding coincident vertices.
1178 float curX = 0, curY = 0;
1179 for (Vector<Contour*>::iterator iter = m_contours.begin(); iter != m_contours.end(); ++iter) {
1180 Contour* cur = *iter;
1182 for (Segment* seg = cur->begin(); seg != cur->end(); seg = seg->next()) {
1183 int numberOfInteriorVertices = seg->numberOfInteriorVertices();
1184 for (int i = 0; i < numberOfInteriorVertices - 1; i++) {
1185 FloatPoint point = seg->getInteriorVertex(i);
1188 vertexData.append(point.x());
1189 vertexData.append(point.y());
1190 vertexData.append(0);
1193 } else if (point.x() != curX || point.y() != curY) {
1194 vertexData.append(point.x());
1195 vertexData.append(point.y());
1196 vertexData.append(0);
1202 contourEndings.append(vertexData.size());
1204 // Now that we have all of the vertex data in a stable location in
1205 // memory, call the tessellator.
1206 GLUtesselator* tess = internal_gluNewTess();
1207 TessellationState state(cache);
1208 internal_gluTessCallback(tess, GLU_TESS_VERTEX_DATA,
1209 reinterpret_cast<GLvoid (*)()>(vertexCallback));
1210 internal_gluTessCallback(tess, GLU_TESS_COMBINE_DATA,
1211 reinterpret_cast<GLvoid (*)()>(combineCallback));
1212 internal_gluTessCallback(tess, GLU_TESS_EDGE_FLAG,
1213 reinterpret_cast<GLvoid (*)()>(edgeFlagCallback));
1214 internal_gluTessBeginPolygon(tess, &state);
1215 internal_gluTessBeginContour(tess);
1216 GLdouble* base = vertexData.data();
1217 int contourIndex = 0;
1218 for (size_t i = 0; i < vertexData.size(); i += 3) {
1219 if (i == contourEndings[contourIndex]) {
1220 internal_gluTessEndContour(tess);
1221 internal_gluTessBeginContour(tess);
1224 internal_gluTessVertex(tess, &base[i], &base[i]);
1226 internal_gluTessEndContour(tess);
1227 internal_gluTessEndPolygon(tess);
1228 for (size_t i = 0; i < state.allocatedPointers.size(); i++)
1229 fastFree(state.allocatedPointers[i]);
1230 internal_gluDeleteTess(tess);
1233 } // namespace WebCore