184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips/* 284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips * Copyright 2015 Google Inc. 384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips * 484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips * Use of this source code is governed by a BSD-style license that can be 584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips * found in the LICENSE file. 684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips */ 784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#include "GrAAConvexTessellator.h" 984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#include "SkCanvas.h" 1084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#include "SkPath.h" 1184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#include "SkPoint.h" 1284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#include "SkString.h" 131a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "GrPathUtils.h" 1484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 1584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// Next steps: 1684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// add an interactive sample app slide 1784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// add debug check that all points are suitably far apart 1884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// test more degenerate cases 1984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 2084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// The tolerance for fusing vertices and eliminating colinear lines (It is in device space). 2184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic const SkScalar kClose = (SK_Scalar1 / 16); 228be952ad8c9deefe19cff36f9ad217563400f817Mike Reedstatic const SkScalar kCloseSqd = kClose * kClose; 2384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 24bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// tesselation tolerance values, in device space pixels 25bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitastatic const SkScalar kQuadTolerance = 0.2f; 26bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitastatic const SkScalar kCubicTolerance = 0.2f; 27bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitastatic const SkScalar kConicTolerance = 0.5f; 28bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 29bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// dot product below which we use a round cap between curve segments 30bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitastatic const SkScalar kRoundCapThreshold = 0.8f; 31bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 32fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas// dot product above which we consider two adjacent curves to be part of the "same" curve 33fc6cb7366493665dce96c5d66e67e94924b21cb6ethannicholasstatic const SkScalar kCurveConnectionThreshold = 0.8f; 34fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas 358c170971f182d47bc9af71fc88a607740d03dfd5robertphillipsstatic bool intersect(const SkPoint& p0, const SkPoint& n0, 368c170971f182d47bc9af71fc88a607740d03dfd5robertphillips const SkPoint& p1, const SkPoint& n1, 378c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkScalar* t) { 3884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips const SkPoint v = p1 - p0; 3984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; 408c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (SkScalarNearlyZero(perpDot)) { 418c170971f182d47bc9af71fc88a607740d03dfd5robertphillips return false; 428c170971f182d47bc9af71fc88a607740d03dfd5robertphillips } 438c170971f182d47bc9af71fc88a607740d03dfd5robertphillips *t = (v.fX * n1.fY - v.fY * n1.fX) / perpDot; 448c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkASSERT(SkScalarIsFinite(*t)); 458c170971f182d47bc9af71fc88a607740d03dfd5robertphillips return true; 4684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 4784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 489d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary// This is a special case version of intersect where we have the vector 4984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// perpendicular to the second line rather than the vector parallel to it. 5084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, 5184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips const SkPoint& p1, const SkPoint& perp) { 5284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips const SkPoint v = p1 - p0; 5384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar perpDot = n0.dot(perp); 5484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return v.dot(perp) / perpDot; 5584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 5684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 5784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { 5884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar distSq = p0.distanceToSqd(p1); 5984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return distSq < kCloseSqd; 6084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 6184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 6284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic SkScalar abs_dist_from_line(const SkPoint& p0, const SkVector& v, const SkPoint& test) { 6384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint testV = test - p0; 6484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar dist = testV.fX * v.fY - testV.fY * v.fX; 6584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return SkScalarAbs(dist); 6684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 6784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 6884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsint GrAAConvexTessellator::addPt(const SkPoint& pt, 6984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar depth, 70bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar coverage, 711a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas bool movable, 72fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas CurveState curve) { 7384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 7484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 7584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int index = fPts.count(); 7684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips *fPts.push() = pt; 77bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita *fCoverages.push() = coverage; 7884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips *fMovable.push() = movable; 79fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas *fCurveState.push() = curve; 8084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 8184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 8284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return index; 8384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 8484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 8584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::popLastPt() { 8684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 8784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 8884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts.pop(); 89bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fCoverages.pop(); 9084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fMovable.pop(); 911d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips fCurveState.pop(); 9284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 9384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 9484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 9584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 9684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::popFirstPtShuffle() { 9784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 9884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 9984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts.removeShuffle(0); 100bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fCoverages.removeShuffle(0); 10184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fMovable.removeShuffle(0); 1021d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips fCurveState.removeShuffle(0); 10384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 10484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 10584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 10684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 10784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::updatePt(int index, 10884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips const SkPoint& pt, 109bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar depth, 110bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar coverage) { 11184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 11284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(fMovable[index]); 11384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 11484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts[index] = pt; 115bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fCoverages[index] = coverage; 11684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 11784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 11884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::addTri(int i0, int i1, int i2) { 11984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (i0 == i1 || i1 == i2 || i2 == i0) { 12084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return; 12184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 12284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 12384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips *fIndices.push() = i0; 12484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips *fIndices.push() = i1; 12584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips *fIndices.push() = i2; 12684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 12784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 12884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::rewind() { 12984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts.rewind(); 130bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fCoverages.rewind(); 13184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fMovable.rewind(); 13284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fIndices.rewind(); 13384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fNorms.rewind(); 1341d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips fCurveState.rewind(); 13584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fInitialRing.rewind(); 13684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fCandidateVerts.rewind(); 13784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#if GR_AA_CONVEX_TESSELLATOR_VIZ 13884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fRings.rewind(); // TODO: leak in this case! 13984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#else 14084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fRings[0].rewind(); 14184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fRings[1].rewind(); 14284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#endif 14384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 14484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 14584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::computeBisectors() { 14684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fBisectors.setCount(fNorms.count()); 14784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 14884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int prev = fBisectors.count() - 1; 14984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int cur = 0; cur < fBisectors.count(); prev = cur, ++cur) { 15084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fBisectors[cur] = fNorms[cur] + fNorms[prev]; 151364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips if (!fBisectors[cur].normalize()) { 152364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips SkASSERT(SkPoint::kLeft_Side == fSide || SkPoint::kRight_Side == fSide); 153364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips fBisectors[cur].setOrthog(fNorms[cur], (SkPoint::Side)-fSide); 154364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips SkVector other; 155364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips other.setOrthog(fNorms[prev], fSide); 156364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips fBisectors[cur] += other; 1579d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary SkAssertResult(fBisectors[cur].normalize()); 158364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips } else { 159364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips fBisectors[cur].negate(); // make the bisector face in 160364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips } 161fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas if (fCurveState[prev] == kIndeterminate_CurveState) { 162fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas if (fCurveState[cur] == kSharp_CurveState) { 163fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas fCurveState[prev] = kSharp_CurveState; 164fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas } else { 165fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas if (SkScalarAbs(fNorms[cur].dot(fNorms[prev])) > kCurveConnectionThreshold) { 166fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas fCurveState[prev] = kCurve_CurveState; 167fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas fCurveState[cur] = kCurve_CurveState; 168fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas } else { 169fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas fCurveState[prev] = kSharp_CurveState; 170fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas fCurveState[cur] = kSharp_CurveState; 171fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas } 172fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas } 173fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas } 17484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 17584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); 17684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 17784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 17884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 179bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// Create as many rings as we need to (up to a predefined limit) to reach the specified target 180bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// depth. If we are in fill mode, the final ring will automatically be fanned. 181bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitabool GrAAConvexTessellator::createInsetRings(Ring& previousRing, SkScalar initialDepth, 1829d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary SkScalar initialCoverage, SkScalar targetDepth, 183bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar targetCoverage, Ring** finalRing) { 184bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita static const int kMaxNumRings = 8; 185bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 186bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (previousRing.numPts() < 3) { 187bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return false; 188bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 189bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring* currentRing = &previousRing; 190bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int i; 191bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita for (i = 0; i < kMaxNumRings; ++i) { 192bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring* nextRing = this->getNextRing(currentRing); 193bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(nextRing != currentRing); 194bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 1959d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary bool done = this->createInsetRing(*currentRing, nextRing, initialDepth, initialCoverage, 196bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita targetDepth, targetCoverage, i == 0); 197bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita currentRing = nextRing; 198bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (done) { 199bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita break; 200bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 201bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita currentRing->init(*this); 202bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 203bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 204bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (kMaxNumRings == i) { 205bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // Bail if we've exceeded the amount of time we want to throw at this. 206bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->terminate(*currentRing); 207bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return false; 208bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 209bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita bool done = currentRing->numPts() >= 3; 210bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (done) { 211bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita currentRing->init(*this); 212bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 213bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita *finalRing = currentRing; 214bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return done; 215bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita} 216bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 21784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// The general idea here is to, conceptually, start with the original polygon and slide 21884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// the vertices along the bisectors until the first intersection. At that 21984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// point two of the edges collapse and the process repeats on the new polygon. 22084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// The polygon state is captured in the Ring class while the GrAAConvexTessellator 22184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// controls the iteration. The CandidateVerts holds the formative points for the 22284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// next ring. 22384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsbool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { 22484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (!this->extractFromPath(m, path)) { 22584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return false; 22684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 22784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 228bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar coverage = 1.0f; 229fea7763140ba74b78f2c30028452e250140b6f21ethannicholas SkScalar scaleFactor = 0.0f; 2308c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2318c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (SkStrokeRec::kStrokeAndFill_Style == fStyle) { 2328c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkASSERT(m.isSimilarity()); 2338c170971f182d47bc9af71fc88a607740d03dfd5robertphillips scaleFactor = m.getMaxScale(); // x and y scale are the same 2348c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; 2358c170971f182d47bc9af71fc88a607740d03dfd5robertphillips Ring outerStrokeAndAARing; 2368c170971f182d47bc9af71fc88a607740d03dfd5robertphillips this->createOuterRing(fInitialRing, 2378c170971f182d47bc9af71fc88a607740d03dfd5robertphillips effectiveStrokeWidth / 2 + kAntialiasingRadius, 0.0, 2388c170971f182d47bc9af71fc88a607740d03dfd5robertphillips &outerStrokeAndAARing); 2398c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2408c170971f182d47bc9af71fc88a607740d03dfd5robertphillips // discard all the triangles added between the originating ring and the new outer ring 2418c170971f182d47bc9af71fc88a607740d03dfd5robertphillips fIndices.rewind(); 2428c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2438c170971f182d47bc9af71fc88a607740d03dfd5robertphillips outerStrokeAndAARing.init(*this); 2448c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2458c170971f182d47bc9af71fc88a607740d03dfd5robertphillips outerStrokeAndAARing.makeOriginalRing(); 2468c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2478c170971f182d47bc9af71fc88a607740d03dfd5robertphillips // Add the outer stroke ring's normals to the originating ring's normals 2488c170971f182d47bc9af71fc88a607740d03dfd5robertphillips // so it can also act as an originating ring 2498c170971f182d47bc9af71fc88a607740d03dfd5robertphillips fNorms.setCount(fNorms.count() + outerStrokeAndAARing.numPts()); 2508c170971f182d47bc9af71fc88a607740d03dfd5robertphillips for (int i = 0; i < outerStrokeAndAARing.numPts(); ++i) { 2518c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkASSERT(outerStrokeAndAARing.index(i) < fNorms.count()); 2528c170971f182d47bc9af71fc88a607740d03dfd5robertphillips fNorms[outerStrokeAndAARing.index(i)] = outerStrokeAndAARing.norm(i); 2538c170971f182d47bc9af71fc88a607740d03dfd5robertphillips } 2548c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2558c170971f182d47bc9af71fc88a607740d03dfd5robertphillips // the bisectors are only needed for the computation of the outer ring 2568c170971f182d47bc9af71fc88a607740d03dfd5robertphillips fBisectors.rewind(); 2578c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2588c170971f182d47bc9af71fc88a607740d03dfd5robertphillips Ring* insetAARing; 2598c170971f182d47bc9af71fc88a607740d03dfd5robertphillips this->createInsetRings(outerStrokeAndAARing, 2608c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 0.0f, 0.0f, 2*kAntialiasingRadius, 1.0f, 2618c170971f182d47bc9af71fc88a607740d03dfd5robertphillips &insetAARing); 2628c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2638c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkDEBUGCODE(this->validate();) 2648c170971f182d47bc9af71fc88a607740d03dfd5robertphillips return true; 2658c170971f182d47bc9af71fc88a607740d03dfd5robertphillips } 2668c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 2678c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (SkStrokeRec::kStroke_Style == fStyle) { 2688c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkASSERT(fStrokeWidth >= 0.0f); 2699d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary SkASSERT(m.isSimilarity()); 270fea7763140ba74b78f2c30028452e250140b6f21ethannicholas scaleFactor = m.getMaxScale(); // x and y scale are the same 271fea7763140ba74b78f2c30028452e250140b6f21ethannicholas SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; 272bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring outerStrokeRing; 2739d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary this->createOuterRing(fInitialRing, effectiveStrokeWidth / 2 - kAntialiasingRadius, 274fea7763140ba74b78f2c30028452e250140b6f21ethannicholas coverage, &outerStrokeRing); 275bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita outerStrokeRing.init(*this); 276bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring outerAARing; 277bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->createOuterRing(outerStrokeRing, kAntialiasingRadius * 2, 0.0f, &outerAARing); 278bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else { 279bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring outerAARing; 280bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->createOuterRing(fInitialRing, kAntialiasingRadius, 0.0f, &outerAARing); 281bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 28284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 28384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // the bisectors are only needed for the computation of the outer ring 28484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fBisectors.rewind(); 2858c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (SkStrokeRec::kStroke_Style == fStyle && fInitialRing.numPts() > 2) { 2868c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkASSERT(fStrokeWidth >= 0.0f); 287fea7763140ba74b78f2c30028452e250140b6f21ethannicholas SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; 288bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring* insetStrokeRing; 289fea7763140ba74b78f2c30028452e250140b6f21ethannicholas SkScalar strokeDepth = effectiveStrokeWidth / 2 - kAntialiasingRadius; 2909d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, coverage, 2918c170971f182d47bc9af71fc88a607740d03dfd5robertphillips &insetStrokeRing)) { 292bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring* insetAARing; 2939d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, strokeDepth + 2948c170971f182d47bc9af71fc88a607740d03dfd5robertphillips kAntialiasingRadius * 2, 0.0f, &insetAARing); 29584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 296bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else { 297bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita Ring* insetAARing; 298bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1.0f, &insetAARing); 29984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 30084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 301bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkDEBUGCODE(this->validate();) 30284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return true; 30384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 30484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 30584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsSkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint& p) const { 30684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(edgeIdx < fNorms.count()); 30784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 30884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint v = p - fPts[edgeIdx]; 30984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar depth = -fNorms[edgeIdx].dot(v); 31084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return depth; 31184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 31284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 31384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies 31484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// along the 'bisector' from the 'startIdx'-th point. 31584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsbool GrAAConvexTessellator::computePtAlongBisector(int startIdx, 31684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips const SkVector& bisector, 31784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int edgeIdx, 31884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar desiredDepth, 31984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint* result) const { 32084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips const SkPoint& norm = fNorms[edgeIdx]; 32184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 32284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // First find the point where the edge and the bisector intersect 32384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint newP; 324bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 32584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm); 32684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (SkScalarNearlyEqual(t, 0.0f)) { 32784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // the start point was one of the original ring points 328bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(startIdx < fPts.count()); 32984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips newP = fPts[startIdx]; 330bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else if (t < 0.0f) { 33184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips newP = bisector; 33284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips newP.scale(t); 33384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips newP += fPts[startIdx]; 33484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } else { 33584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return false; 33684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 33784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 33884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Then offset along the bisector from that point the correct distance 339bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar dot = bisector.dot(norm); 340bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita t = -desiredDepth / dot; 34184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips *result = bisector; 34284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips result->scale(t); 34384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips *result += newP; 34484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 34584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return true; 34684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 34784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 34884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsbool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& path) { 34984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(SkPath::kConvex_Convexity == path.getConvexity()); 35084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 35184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Outer ring: 3*numPts 35284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Middle ring: numPts 35384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Presumptive inner ring: numPts 35484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->reservePts(5*path.countPoints()); 35584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Outer ring: 12*numPts 35684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Middle ring: 0 35784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Presumptive inner ring: 6*numPts + 6 35884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fIndices.setReserve(18*path.countPoints() + 6); 35984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 36084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fNorms.setReserve(path.countPoints()); 36184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 36284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // TODO: is there a faster way to extract the points from the path? Perhaps 36384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // get all the points via a new entry point, transform them all in bulk 36484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // and then walk them to find duplicates? 36584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPath::Iter iter(path, true); 36684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint pts[4]; 36784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPath::Verb verb; 36897042bfd9f4a1ff825a92ac13965b80fd712d4f2Brian Salomon while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) { 36984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips switch (verb) { 37084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips case SkPath::kLine_Verb: 371fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas this->lineTo(m, pts[1], kSharp_CurveState); 37284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips break; 37384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips case SkPath::kQuad_Verb: 3741a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas this->quadTo(m, pts); 3751a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas break; 37684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips case SkPath::kCubic_Verb: 3771a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas this->cubicTo(m, pts); 3781a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas break; 3791a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas case SkPath::kConic_Verb: 3801a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas this->conicTo(m, pts, iter.conicWeight()); 38184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips break; 38284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips case SkPath::kMove_Verb: 38384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips case SkPath::kClose_Verb: 38484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips case SkPath::kDone_Verb: 38584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips break; 38684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 38784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 38884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 389bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (this->numPts() < 2) { 39084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return false; 39184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 39284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 39384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // check if last point is a duplicate of the first point. If so, remove it. 39484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (duplicate_pt(fPts[this->numPts()-1], fPts[0])) { 39584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->popLastPt(); 39684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fNorms.pop(); 39784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 39884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 39984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(fPts.count() == fNorms.count()+1); 400bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (this->numPts() >= 3) { 401bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (abs_dist_from_line(fPts.top(), fNorms.top(), fPts[0]) < kClose) { 402bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // The last point is on the line from the second to last to the first point. 403bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->popLastPt(); 404bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fNorms.pop(); 405bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 40684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 407bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita *fNorms.push() = fPts[0] - fPts.top(); 408bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); 409bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(len > 0.0f); 410bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(fPts.count() == fNorms.count()); 41184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 41284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 413bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (this->numPts() >= 3 && abs_dist_from_line(fPts[0], fNorms.top(), fPts[1]) < kClose) { 41484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // The first point is on the line from the last to the second. 41584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->popFirstPtShuffle(); 41684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fNorms.removeShuffle(0); 41784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fNorms[0] = fPts[1] - fPts[0]; 41884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[0]); 41984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(len > 0.0f); 42084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length())); 42184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 42284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 423bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (this->numPts() >= 3) { 424bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // Check the cross product of the final trio 425bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar cross = SkPoint::CrossProduct(fNorms[0], fNorms.top()); 426bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (cross > 0.0f) { 427bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fSide = SkPoint::kRight_Side; 428bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else { 429bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fSide = SkPoint::kLeft_Side; 430bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 4312436f191e6602953b32a51cf50f2d7a4e2af90fdethannicholas 432bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // Make all the normals face outwards rather than along the edge 433bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita for (int cur = 0; cur < fNorms.count(); ++cur) { 434bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fNorms[cur].setOrthog(fNorms[cur], fSide); 435bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); 436bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 437bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 438bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->computeBisectors(); 439bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else if (this->numPts() == 2) { 4409d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary // We've got two points, so we're degenerate. 4418c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (fStyle == SkStrokeRec::kFill_Style) { 442bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // it's a fill, so we don't need to worry about degenerate paths 443bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return false; 444bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 445bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // For stroking, we still need to process the degenerate path, so fix it up 44684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fSide = SkPoint::kLeft_Side; 44784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 448bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // Make all the normals face outwards rather than along the edge 449bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita for (int cur = 0; cur < fNorms.count(); ++cur) { 450bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fNorms[cur].setOrthog(fNorms[cur], fSide); 451bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); 452bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 45384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 454bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fNorms.push(SkPoint::Make(-fNorms[0].fX, -fNorms[0].fY)); 455bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // we won't actually use the bisectors, so just push zeroes 456bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fBisectors.push(SkPoint::Make(0.0, 0.0)); 457bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita fBisectors.push(SkPoint::Make(0.0, 0.0)); 458bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else { 459bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return false; 460bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 4619730f4a663534009d216c2f6d834bd534dd44a3dreed 46284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fCandidateVerts.setReserve(this->numPts()); 46384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fInitialRing.setReserve(this->numPts()); 46484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 0; i < this->numPts(); ++i) { 46584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fInitialRing.addIdx(i, i); 46684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 46784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fInitialRing.init(fNorms, fBisectors); 46884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 46984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 47084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return true; 47184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 47284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 47384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsGrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) { 47484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#if GR_AA_CONVEX_TESSELLATOR_VIZ 475385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary Ring* ring = *fRings.push() = new Ring; 47684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips ring->setReserve(fInitialRing.numPts()); 47784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips ring->rewind(); 47884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return ring; 47984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#else 48084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Flip flop back and forth between fRings[0] & fRings[1] 48184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int nextRing = (lastRing == &fRings[0]) ? 1 : 0; 48284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fRings[nextRing].setReserve(fInitialRing.numPts()); 48384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fRings[nextRing].rewind(); 48484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return &fRings[nextRing]; 48584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#endif 48684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 48784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 48884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::fanRing(const Ring& ring) { 48984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // fan out from point 0 490bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int startIdx = ring.index(0); 491bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita for (int cur = ring.numPts() - 2; cur >= 0; --cur) { 492bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(startIdx, ring.index(cur), ring.index(cur + 1)); 49384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 49484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 49584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 4969d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanaryvoid GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar outset, 497bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar coverage, Ring* nextRing) { 498bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita const int numPts = previousRing.numPts(); 499bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (numPts == 0) { 500bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return; 501bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 5021a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 5039730f4a663534009d216c2f6d834bd534dd44a3dreed int prev = numPts - 1; 504bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int lastPerpIdx = -1, firstPerpIdx = -1; 5059730f4a663534009d216c2f6d834bd534dd44a3dreed 5068be952ad8c9deefe19cff36f9ad217563400f817Mike Reed const SkScalar outsetSq = outset * outset; 5078be952ad8c9deefe19cff36f9ad217563400f817Mike Reed SkScalar miterLimitSq = outset * fMiterLimit; 5088be952ad8c9deefe19cff36f9ad217563400f817Mike Reed miterLimitSq = miterLimitSq * miterLimitSq; 509bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita for (int cur = 0; cur < numPts; ++cur) { 510bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int originalIdx = previousRing.index(cur); 5119d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary // For each vertex of the original polygon we add at least two points to the 512bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // outset polygon - one extending perpendicular to each impinging edge. Connecting these 5139d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary // two points yields a bevel join. We need one additional point for a mitered join, and 514bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // a round join requires one or more points depending upon curvature. 515bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 516bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // The perpendicular point for the last edge 517bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkPoint normal1 = previousRing.norm(prev); 518bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkPoint perp1 = normal1; 519bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita perp1.scale(outset); 520bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita perp1 += this->point(originalIdx); 521bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 522bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // The perpendicular point for the next edge. 523bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkPoint normal2 = previousRing.norm(cur); 524bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkPoint perp2 = normal2; 525bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita perp2.scale(outset); 526bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita perp2 += fPts[originalIdx]; 527bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 528fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas CurveState curve = fCurveState[originalIdx]; 529bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 530bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // We know it isn't a duplicate of the prior point (since it and this 531bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // one are just perpendicular offsets from the non-merged polygon points) 532fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas int perp1Idx = this->addPt(perp1, -outset, coverage, false, curve); 533bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita nextRing->addIdx(perp1Idx, originalIdx); 534bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 535bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int perp2Idx; 536bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // For very shallow angles all the corner points could fuse. 537bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (duplicate_pt(perp2, this->point(perp1Idx))) { 538bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita perp2Idx = perp1Idx; 539bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else { 540fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas perp2Idx = this->addPt(perp2, -outset, coverage, false, curve); 54184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 5421a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 543bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (perp2Idx != perp1Idx) { 544fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas if (curve == kCurve_CurveState) { 545bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // bevel or round depending upon curvature 546bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar dotProd = normal1.dot(normal2); 547bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (dotProd < kRoundCapThreshold) { 548bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // Currently we "round" by creating a single extra point, which produces 549bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // good results for common cases. For thick strokes with high curvature, we will 550bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // need to add more points; for the time being we simply fall back to software 551bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // rendering for thick strokes. 552bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkPoint miter = previousRing.bisector(cur); 553bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita miter.setLength(-outset); 554bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita miter += fPts[originalIdx]; 555bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 556bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // For very shallow angles all the corner points could fuse 557bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (!duplicate_pt(miter, this->point(perp1Idx))) { 558bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int miterIdx; 559fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas miterIdx = this->addPt(miter, -outset, coverage, false, kSharp_CurveState); 560bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita nextRing->addIdx(miterIdx, originalIdx); 561bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // The two triangles for the corner 562bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(originalIdx, perp1Idx, miterIdx); 563bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(originalIdx, miterIdx, perp2Idx); 564bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 565bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else { 566bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(originalIdx, perp1Idx, perp2Idx); 567bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 5689730f4a663534009d216c2f6d834bd534dd44a3dreed } else { 569bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita switch (fJoin) { 570bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita case SkPaint::Join::kMiter_Join: { 571bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // The bisector outset point 572bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkPoint miter = previousRing.bisector(cur); 573bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar dotProd = normal1.dot(normal2); 574bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar sinHalfAngleSq = SkScalarHalf(SK_Scalar1 + dotProd); 575bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar lengthSq = outsetSq / sinHalfAngleSq; 576bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (lengthSq > miterLimitSq) { 577bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // just bevel it 578bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(originalIdx, perp1Idx, perp2Idx); 579bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita break; 580bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 581bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita miter.setLength(-SkScalarSqrt(lengthSq)); 582bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita miter += fPts[originalIdx]; 583bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 584bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // For very shallow angles all the corner points could fuse 585bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (!duplicate_pt(miter, this->point(perp1Idx))) { 586bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int miterIdx; 587fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas miterIdx = this->addPt(miter, -outset, coverage, false, 588fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas kSharp_CurveState); 589bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita nextRing->addIdx(miterIdx, originalIdx); 590bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // The two triangles for the corner 591bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(originalIdx, perp1Idx, miterIdx); 592bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(originalIdx, miterIdx, perp2Idx); 593bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 594bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita break; 595bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 596bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita case SkPaint::Join::kBevel_Join: 597bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(originalIdx, perp1Idx, perp2Idx); 598bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita break; 599bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita default: 6009d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary // kRound_Join is unsupported for now. GrAALinearizingConvexPathRenderer is 601bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // only willing to draw mitered or beveled, so we should never get here. 602bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(false); 603bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 6049730f4a663534009d216c2f6d834bd534dd44a3dreed } 6051a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 606bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita nextRing->addIdx(perp2Idx, originalIdx); 607bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 6082436f191e6602953b32a51cf50f2d7a4e2af90fdethannicholas 609bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (0 == cur) { 610bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // Store the index of the first perpendicular point to finish up 611bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita firstPerpIdx = perp1Idx; 612bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkASSERT(-1 == lastPerpIdx); 613bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } else { 614bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // The triangles for the previous edge 615bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int prevIdx = previousRing.index(prev); 616bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(prevIdx, perp1Idx, originalIdx); 617bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(prevIdx, lastPerpIdx, perp1Idx); 6189730f4a663534009d216c2f6d834bd534dd44a3dreed } 619bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 620bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // Track the last perpendicular outset point so we can construct the 621bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita // trailing edge triangles. 622bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita lastPerpIdx = perp2Idx; 623bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita prev = cur; 62484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 62584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 62684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // pick up the final edge rect 627bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita int lastIdx = previousRing.index(numPts - 1); 628bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(lastIdx, firstPerpIdx, previousRing.index(0)); 629bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->addTri(lastIdx, lastPerpIdx, firstPerpIdx); 63084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 63184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->validate(); 63284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 63384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 634bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// Something went wrong in the creation of the next ring. If we're filling the shape, just go ahead 635bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita// and fan it. 63684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::terminate(const Ring& ring) { 6378c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (fStyle != SkStrokeRec::kStroke_Style) { 638bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->fanRing(ring); 63984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 640bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita} 64184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 6429d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanarystatic SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar initialCoverage, 643bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkScalar targetDepth, SkScalar targetCoverage) { 644bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (SkScalarNearlyEqual(initialDepth, targetDepth)) { 645bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return targetCoverage; 646bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 6479d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) * 648bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita (targetCoverage - initialCoverage) + initialCoverage; 649bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return SkScalarClampMax(result, 1.0f); 65084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 65184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 65284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// return true when processing is complete 6539d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanarybool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing, 6549d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary SkScalar initialDepth, SkScalar initialCoverage, 6559d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary SkScalar targetDepth, SkScalar targetCoverage, 656bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita bool forceNew) { 65784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips bool done = false; 65884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 65984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fCandidateVerts.rewind(); 66084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 66184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Loop through all the points in the ring and find the intersection with the smallest depth 66284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar minDist = SK_ScalarMax, minT = 0.0f; 66384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int minEdgeIdx = -1; 66484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 66584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int cur = 0; cur < lastRing.numPts(); ++cur) { 66684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int next = (cur + 1) % lastRing.numPts(); 6678c170971f182d47bc9af71fc88a607740d03dfd5robertphillips 6688c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkScalar t; 6698c170971f182d47bc9af71fc88a607740d03dfd5robertphillips bool result = intersect(this->point(lastRing.index(cur)), lastRing.bisector(cur), 6708c170971f182d47bc9af71fc88a607740d03dfd5robertphillips this->point(lastRing.index(next)), lastRing.bisector(next), 6718c170971f182d47bc9af71fc88a607740d03dfd5robertphillips &t); 6728c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (!result) { 6738c170971f182d47bc9af71fc88a607740d03dfd5robertphillips continue; 6748c170971f182d47bc9af71fc88a607740d03dfd5robertphillips } 67584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); 67684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 67784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (minDist > dist) { 67884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips minDist = dist; 67984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips minT = t; 68084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips minEdgeIdx = cur; 68184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 68284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 68384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 684bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (minEdgeIdx == -1) { 685bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return false; 686bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 68784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint newPt = lastRing.bisector(minEdgeIdx); 68884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips newPt.scale(minT); 68984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips newPt += this->point(lastRing.index(minEdgeIdx)); 69084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 69184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx), newPt); 692bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (depth >= targetDepth) { 69384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // None of the bisectors intersect before reaching the desired depth. 69484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Just step them all to the desired depth 695bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita depth = targetDepth; 69684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips done = true; 69784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 69884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 69984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // 'dst' stores where each point in the last ring maps to/transforms into 70084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // in the next ring. 70184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkTDArray<int> dst; 70284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst.setCount(lastRing.numPts()); 70384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 70484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Create the first point (who compares with no one) 70584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (!this->computePtAlongBisector(lastRing.index(0), 70684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.bisector(0), 70784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.origEdgeID(0), 70884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips depth, &newPt)) { 70984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->terminate(lastRing); 71084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return true; 71184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 71284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[0] = fCandidateVerts.addNewPt(newPt, 71384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.index(0), lastRing.origEdgeID(0), 71484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips !this->movable(lastRing.index(0))); 71584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 71684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Handle the middle points (who only compare with the prior point) 71784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int cur = 1; cur < lastRing.numPts()-1; ++cur) { 71884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (!this->computePtAlongBisector(lastRing.index(cur), 71984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.bisector(cur), 72084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.origEdgeID(cur), 72184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips depth, &newPt)) { 72284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->terminate(lastRing); 72384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return true; 72484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 72584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (!duplicate_pt(newPt, fCandidateVerts.lastPoint())) { 72684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[cur] = fCandidateVerts.addNewPt(newPt, 72784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.index(cur), lastRing.origEdgeID(cur), 72884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips !this->movable(lastRing.index(cur))); 72984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } else { 73084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 73184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 73284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 73384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 73484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Check on the last point (handling the wrap around) 73584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int cur = lastRing.numPts()-1; 73684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (!this->computePtAlongBisector(lastRing.index(cur), 73784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.bisector(cur), 73884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.origEdgeID(cur), 73984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips depth, &newPt)) { 74084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->terminate(lastRing); 74184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return true; 74284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 74384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips bool dupPrev = duplicate_pt(newPt, fCandidateVerts.lastPoint()); 74484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips bool dupNext = duplicate_pt(newPt, fCandidateVerts.firstPoint()); 74584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 74684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (!dupPrev && !dupNext) { 74784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[cur] = fCandidateVerts.addNewPt(newPt, 74884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips lastRing.index(cur), lastRing.origEdgeID(cur), 74984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips !this->movable(lastRing.index(cur))); 75084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } else if (dupPrev && !dupNext) { 75184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 75284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } else if (!dupPrev && dupNext) { 75384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[cur] = fCandidateVerts.fuseWithNext(); 75484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } else { 75584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips bool dupPrevVsNext = duplicate_pt(fCandidateVerts.firstPoint(), fCandidateVerts.lastPoint()); 75684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 75784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (!dupPrevVsNext) { 75884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 75984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } else { 7600dacc6708d5db4fbe755d7b1d0716b51fe703058ethannicholas const int fused = fCandidateVerts.fuseWithBoth(); 7610dacc6708d5db4fbe755d7b1d0716b51fe703058ethannicholas dst[cur] = fused; 7620dacc6708d5db4fbe755d7b1d0716b51fe703058ethannicholas const int targetIdx = dst[cur - 1]; 7630dacc6708d5db4fbe755d7b1d0716b51fe703058ethannicholas for (int i = cur - 1; i >= 0 && dst[i] == targetIdx; i--) { 7640dacc6708d5db4fbe755d7b1d0716b51fe703058ethannicholas dst[i] = fused; 7650dacc6708d5db4fbe755d7b1d0716b51fe703058ethannicholas } 76684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 76784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 76884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 76984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // Fold the new ring's points into the global pool 77084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 0; i < fCandidateVerts.numPts(); ++i) { 77184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int newIdx; 772bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (fCandidateVerts.needsToBeNew(i) || forceNew) { 7739d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary // if the originating index is still valid then this point wasn't 77484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // fused (and is thus movable) 7759d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary SkScalar coverage = compute_coverage(depth, initialDepth, initialCoverage, 776bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita targetDepth, targetCoverage); 777bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita newIdx = this->addPt(fCandidateVerts.point(i), depth, coverage, 778fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas fCandidateVerts.originatingIdx(i) != -1, kSharp_CurveState); 77984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } else { 78084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(fCandidateVerts.originatingIdx(i) != -1); 781bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.point(i), depth, 782bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita targetCoverage); 78384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips newIdx = fCandidateVerts.originatingIdx(i); 78484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 78584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 78684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i)); 78784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 78884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 78984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // 'dst' currently has indices into the ring. Remap these to be indices 79084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips // into the global pool since the triangulation operates in that space. 79184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 0; i < dst.count(); ++i) { 79284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips dst[i] = nextRing->index(dst[i]); 79384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 79484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 79544c3128bd892d32f797810d93ef1ed392e0b902drobertphillips for (int i = 0; i < lastRing.numPts(); ++i) { 79644c3128bd892d32f797810d93ef1ed392e0b902drobertphillips int next = (i + 1) % lastRing.numPts(); 79784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 79844c3128bd892d32f797810d93ef1ed392e0b902drobertphillips this->addTri(lastRing.index(i), lastRing.index(next), dst[next]); 79944c3128bd892d32f797810d93ef1ed392e0b902drobertphillips this->addTri(lastRing.index(i), dst[next], dst[i]); 80084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 80184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 8028c170971f182d47bc9af71fc88a607740d03dfd5robertphillips if (done && fStyle != SkStrokeRec::kStroke_Style) { 8038c170971f182d47bc9af71fc88a607740d03dfd5robertphillips // fill or stroke-and-fill 80484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->fanRing(*nextRing); 80584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 80684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 80784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (nextRing->numPts() < 3) { 80884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips done = true; 80984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 81084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips return done; 81184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 81284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 81384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::validate() const { 81484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(fPts.count() == fMovable.count()); 8151d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips SkASSERT(fPts.count() == fCoverages.count()); 8161d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips SkASSERT(fPts.count() == fCurveState.count()); 81784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(0 == (fIndices.count() % 3)); 8181d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips SkASSERT(!fBisectors.count() || fBisectors.count() == fNorms.count()); 81984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 82084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 82184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips////////////////////////////////////////////////////////////////////////////// 82284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::Ring::init(const GrAAConvexTessellator& tess) { 82384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->computeNormals(tess); 824364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips this->computeBisectors(tess); 82584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 82684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 82784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::Ring::init(const SkTDArray<SkVector>& norms, 82884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips const SkTDArray<SkVector>& bisectors) { 82984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 0; i < fPts.count(); ++i) { 83084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts[i].fNorm = norms[i]; 83184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts[i].fBisector = bisectors[i]; 83284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 83384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 83484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 83584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// Compute the outward facing normal at each vertex. 83684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::Ring::computeNormals(const GrAAConvexTessellator& tess) { 83784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int cur = 0; cur < fPts.count(); ++cur) { 83884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int next = (cur + 1) % fPts.count(); 83984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 84084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts[cur].fNorm = tess.point(fPts[next].fIndex) - tess.point(fPts[cur].fIndex); 841bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita SkPoint::Normalize(&fPts[cur].fNorm); 84284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts[cur].fNorm.setOrthog(fPts[cur].fNorm, tess.side()); 84384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 84484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 84584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 846364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillipsvoid GrAAConvexTessellator::Ring::computeBisectors(const GrAAConvexTessellator& tess) { 84784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int prev = fPts.count() - 1; 84884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) { 84984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fPts[cur].fBisector = fPts[cur].fNorm + fPts[prev].fNorm; 850364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips if (!fPts[cur].fBisector.normalize()) { 851364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips SkASSERT(SkPoint::kLeft_Side == tess.side() || SkPoint::kRight_Side == tess.side()); 852364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips fPts[cur].fBisector.setOrthog(fPts[cur].fNorm, (SkPoint::Side)-tess.side()); 853364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips SkVector other; 854364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips other.setOrthog(fPts[prev].fNorm, tess.side()); 855364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips fPts[cur].fBisector += other; 856364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips SkAssertResult(fPts[cur].fBisector.normalize()); 857364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips } else { 858364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips fPts[cur].fBisector.negate(); // make the bisector face in 859364ad00446923d1cbc963c7358cd9b01efc53d3erobertphillips } 860bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita } 86184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 86284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 86384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips////////////////////////////////////////////////////////////////////////////// 86484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#ifdef SK_DEBUG 86584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips// Is this ring convex? 86684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsbool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) const { 86784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (fPts.count() < 3) { 868bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return true; 86984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 87084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 87184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint prev = tess.point(fPts[0].fIndex) - tess.point(fPts.top().fIndex); 87284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint cur = tess.point(fPts[1].fIndex) - tess.point(fPts[0].fIndex); 87384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX; 87484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar maxDot = minDot; 87584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 87684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips prev = cur; 87784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 1; i < fPts.count(); ++i) { 87884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int next = (i + 1) % fPts.count(); 87984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 88084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips cur = tess.point(fPts[next].fIndex) - tess.point(fPts[i].fIndex); 88184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX; 88284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 88384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips minDot = SkMinScalar(minDot, dot); 88484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips maxDot = SkMaxScalar(maxDot, dot); 88584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 88684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips prev = cur; 88784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 88884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 889bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (SkScalarNearlyEqual(maxDot, 0.0f, 0.005f)) { 890bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita maxDot = 0; 89184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 892bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (SkScalarNearlyEqual(minDot, 0.0f, 0.005f)) { 893bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita minDot = 0; 89484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 895bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita return (maxDot >= 0.0f) == (minDot >= 0.0f); 89684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 89784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 89884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#endif 89984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 9001d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillipsvoid GrAAConvexTessellator::lineTo(const SkPoint& p, CurveState curve) { 9011a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) { 9021a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas return; 9031a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas } 9041a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 9051a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1); 9061d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips if (this->numPts() >= 2 && abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) { 9071a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas // The old last point is on the line from the second to last to the new point 9081a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas this->popLastPt(); 9091a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas fNorms.pop(); 9101bcbc8f8c0747691496d779055675bc47ca65c86ethannicholas // double-check that the new last point is not a duplicate of the new point. In an ideal 9111bcbc8f8c0747691496d779055675bc47ca65c86ethannicholas // world this wouldn't be necessary (since it's only possible for non-convex paths), but 9121d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips // floating point precision issues mean it can actually happen on paths that were 9131d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips // determined to be convex. 9141bcbc8f8c0747691496d779055675bc47ca65c86ethannicholas if (duplicate_pt(p, this->lastPoint())) { 9151bcbc8f8c0747691496d779055675bc47ca65c86ethannicholas return; 9161bcbc8f8c0747691496d779055675bc47ca65c86ethannicholas } 9171a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas } 9188c170971f182d47bc9af71fc88a607740d03dfd5robertphillips SkScalar initialRingCoverage = (SkStrokeRec::kFill_Style == fStyle) ? 0.5f : 1.0f; 919fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas this->addPt(p, 0.0f, initialRingCoverage, false, curve); 9201a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas if (this->numPts() > 1) { 9211a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas *fNorms.push() = fPts.top() - fPts[fPts.count()-2]; 9221a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); 9231a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkASSERT(len > 0.0f); 9241a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length())); 9251a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas } 9261a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas} 9271a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 928fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholasvoid GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, CurveState curve) { 929bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita m.mapPoints(&p, 1); 930fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas this->lineTo(p, curve); 931bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita} 932bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 9331d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillipsvoid GrAAConvexTessellator::quadTo(const SkPoint pts[3]) { 9341a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); 9351a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas fPointBuffer.setReserve(maxCount); 9361a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkPoint* target = fPointBuffer.begin(); 9379d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], 9381d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips kQuadTolerance, &target, maxCount); 9391a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas fPointBuffer.setCount(count); 940fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas for (int i = 0; i < count - 1; i++) { 9411d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips this->lineTo(fPointBuffer[i], kCurve_CurveState); 9421a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas } 9431d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips this->lineTo(fPointBuffer[count - 1], kIndeterminate_CurveState); 9441a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas} 9451a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 946bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitavoid GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) { 9471d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips m.mapPoints(pts, 3); 9481d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips this->quadTo(pts); 949bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita} 950bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita 9511a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholasvoid GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) { 952bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita m.mapPoints(pts, 4); 9531a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); 9541a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas fPointBuffer.setReserve(maxCount); 9551a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkPoint* target = fPointBuffer.begin(); 9569d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], 9571a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas kCubicTolerance, &target, maxCount); 9581a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas fPointBuffer.setCount(count); 959fab4a9b9882bfd1c2d8c3fd5eeaf691caeba0f31ethannicholas for (int i = 0; i < count - 1; i++) { 9601d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips this->lineTo(fPointBuffer[i], kCurve_CurveState); 9611a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas } 9621d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips this->lineTo(fPointBuffer[count - 1], kIndeterminate_CurveState); 9631a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas} 9641a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 9651a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas// include down here to avoid compilation errors caused by "-" overload in SkGeometry.h 9661a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas#include "SkGeometry.h" 9671a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 968bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalitavoid GrAAConvexTessellator::conicTo(const SkMatrix& m, SkPoint pts[3], SkScalar w) { 969bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita m.mapPoints(pts, 3); 9701a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkAutoConicToQuads quadder; 9711a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance); 9721a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkPoint lastPoint = *(quads++); 9731a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas int count = quadder.countQuads(); 9741a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas for (int i = 0; i < count; ++i) { 9751a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas SkPoint quadPts[3]; 9761a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas quadPts[0] = lastPoint; 9771a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas quadPts[1] = quads[0]; 9781a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas quadPts[2] = i == count - 1 ? pts[2] : quads[1]; 9791d08998e4fb81755978f3d1c11744a6c77ddab2eRobert Phillips this->quadTo(quadPts); 9801a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas lastPoint = quadPts[2]; 9811a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas quads += 2; 9821a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas } 9831a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas} 9841a1b3ac0d4feecb0fefa8a07c7abf3471c96f545ethannicholas 98584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips////////////////////////////////////////////////////////////////////////////// 98684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#if GR_AA_CONVEX_TESSELLATOR_VIZ 98784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic const SkScalar kPointRadius = 0.02f; 98884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic const SkScalar kArrowStrokeWidth = 0.0f; 98984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic const SkScalar kArrowLength = 0.2f; 99084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic const SkScalar kEdgeTextSize = 0.1f; 99184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic const SkScalar kPointTextSize = 0.02f; 99284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 99384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic void draw_point(SkCanvas* canvas, const SkPoint& p, SkScalar paramValue, bool stroke) { 99484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPaint paint; 99584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(paramValue <= 1.0f); 99684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int gs = int(255*paramValue); 99784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setARGB(255, gs, gs, gs); 99884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 99984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips canvas->drawCircle(p.fX, p.fY, kPointRadius, paint); 100084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 100184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (stroke) { 100284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPaint stroke; 100384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips stroke.setColor(SK_ColorYELLOW); 100484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips stroke.setStyle(SkPaint::kStroke_Style); 100584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips stroke.setStrokeWidth(kPointRadius/3.0f); 10069d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary canvas->drawCircle(p.fX, p.fY, kPointRadius, stroke); 100784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 100884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 100984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 101084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic void draw_line(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1, SkColor color) { 101184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPaint p; 101284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips p.setColor(color); 101384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 101484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, p); 101584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 101684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 101784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsstatic void draw_arrow(SkCanvas*canvas, const SkPoint& p, const SkPoint &n, 101884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkScalar len, SkColor color) { 101984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPaint paint; 102084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setColor(color); 102184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setStrokeWidth(kArrowStrokeWidth); 102284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setStyle(SkPaint::kStroke_Style); 102384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 102484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips canvas->drawLine(p.fX, p.fY, 102584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips p.fX + len * n.fX, p.fY + len * n.fY, 102684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint); 102784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 102884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 102984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::Ring::draw(SkCanvas* canvas, const GrAAConvexTessellator& tess) const { 103084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPaint paint; 103184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setTextSize(kEdgeTextSize); 103284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 103384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int cur = 0; cur < fPts.count(); ++cur) { 103484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips int next = (cur + 1) % fPts.count(); 103584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 103684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips draw_line(canvas, 103784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips tess.point(fPts[cur].fIndex), 103884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips tess.point(fPts[next].fIndex), 103984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SK_ColorGREEN); 104084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 104184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPoint mid = tess.point(fPts[cur].fIndex) + tess.point(fPts[next].fIndex); 104284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips mid.scale(0.5f); 104384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 104484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (fPts.count()) { 104584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips draw_arrow(canvas, mid, fPts[cur].fNorm, kArrowLength, SK_ColorRED); 104684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips mid.fX += (kArrowLength/2) * fPts[cur].fNorm.fX; 104784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips mid.fY += (kArrowLength/2) * fPts[cur].fNorm.fY; 104884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 104984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 105084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkString num; 105184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips num.printf("%d", this->origEdgeID(cur)); 105284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips canvas->drawText(num.c_str(), num.size(), mid.fX, mid.fY, paint); 105384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 105484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips if (fPts.count()) { 105584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips draw_arrow(canvas, tess.point(fPts[cur].fIndex), fPts[cur].fBisector, 105684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips kArrowLength, SK_ColorBLUE); 105784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 10589d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary } 105984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 106084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 106184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillipsvoid GrAAConvexTessellator::draw(SkCanvas* canvas) const { 106284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 0; i < fIndices.count(); i += 3) { 106384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(fIndices[i] < this->numPts()) ; 106484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(fIndices[i+1] < this->numPts()) ; 106584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkASSERT(fIndices[i+2] < this->numPts()) ; 106684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 106784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips draw_line(canvas, 106884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->point(this->fIndices[i]), this->point(this->fIndices[i+1]), 106984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SK_ColorBLACK); 107084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips draw_line(canvas, 107184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->point(this->fIndices[i+1]), this->point(this->fIndices[i+2]), 107284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SK_ColorBLACK); 107384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips draw_line(canvas, 107484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips this->point(this->fIndices[i+2]), this->point(this->fIndices[i]), 107584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SK_ColorBLACK); 107684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 107784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 107884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fInitialRing.draw(canvas, *this); 107984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 0; i < fRings.count(); ++i) { 108084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips fRings[i]->draw(canvas, *this); 108184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 108284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 108384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips for (int i = 0; i < this->numPts(); ++i) { 108484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips draw_point(canvas, 10859d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary this->point(i), 0.5f + (this->depth(i)/(2 * kAntialiasingRadius)), 108684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips !this->movable(i)); 108784b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 108884b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkPaint paint; 108984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setTextSize(kPointTextSize); 109084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setTextAlign(SkPaint::kCenter_Align); 1091bd5d7e75c1ef08816bfd8eed52150cd716e15d5bfmalita if (this->depth(i) <= -kAntialiasingRadius) { 109284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint.setColor(SK_ColorWHITE); 109384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 109484b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 109584b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips SkString num; 109684b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips num.printf("%d", i); 10979d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary canvas->drawText(num.c_str(), num.size(), 10989d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f), 109984b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips paint); 110084b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips } 110184b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips} 110284b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips 110384b008873b5bdf35eba9185038fb3b5580a8b9a8robertphillips#endif 1104