| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* |  | 
| 2  * Copyright 2015 Google Inc. |  | 
| 3  * |  | 
| 4  * Use of this source code is governed by a BSD-style license that can be |  | 
| 5  * found in the LICENSE file. |  | 
| 6  */ |  | 
| 7 |  | 
| 8 #include "GrAAConvexTessellator.h" |  | 
| 9 #include "SkCanvas.h" |  | 
| 10 #include "SkPath.h" |  | 
| 11 #include "SkPoint.h" |  | 
| 12 #include "SkString.h" |  | 
| 13 #include "GrPathUtils.h" |  | 
| 14 |  | 
| 15 // Next steps: |  | 
| 16 //  add an interactive sample app slide |  | 
| 17 //  add debug check that all points are suitably far apart |  | 
| 18 //  test more degenerate cases |  | 
| 19 |  | 
| 20 // The tolerance for fusing vertices and eliminating colinear lines (It is in de
      vice space). |  | 
| 21 static const SkScalar kClose = (SK_Scalar1 / 16); |  | 
| 22 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); |  | 
| 23 |  | 
| 24 // tesselation tolerance values, in device space pixels |  | 
| 25 static const SkScalar kQuadTolerance = 0.2f; |  | 
| 26 static const SkScalar kCubicTolerance = 0.2f; |  | 
| 27 static const SkScalar kConicTolerance = 0.5f; |  | 
| 28 |  | 
| 29 // dot product below which we use a round cap between curve segments |  | 
| 30 static const SkScalar kRoundCapThreshold = 0.8f; |  | 
| 31 |  | 
| 32 static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, |  | 
| 33                           const SkPoint& p1, const SkPoint& n1) { |  | 
| 34     const SkPoint v = p1 - p0; |  | 
| 35     SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; |  | 
| 36     return (v.fX * n1.fY - v.fY * n1.fX) / perpDot; |  | 
| 37 } |  | 
| 38 |  | 
| 39 // This is a special case version of intersect where we have the vector |  | 
| 40 // perpendicular to the second line rather than the vector parallel to it. |  | 
| 41 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, |  | 
| 42                                const SkPoint& p1, const SkPoint& perp) { |  | 
| 43     const SkPoint v = p1 - p0; |  | 
| 44     SkScalar perpDot = n0.dot(perp); |  | 
| 45     return v.dot(perp) / perpDot; |  | 
| 46 } |  | 
| 47 |  | 
| 48 static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { |  | 
| 49     SkScalar distSq = p0.distanceToSqd(p1); |  | 
| 50     return distSq < kCloseSqd; |  | 
| 51 } |  | 
| 52 |  | 
| 53 static SkScalar abs_dist_from_line(const SkPoint& p0, const SkVector& v, const S
      kPoint& test) { |  | 
| 54     SkPoint testV = test - p0; |  | 
| 55     SkScalar dist = testV.fX * v.fY - testV.fY * v.fX; |  | 
| 56     return SkScalarAbs(dist); |  | 
| 57 } |  | 
| 58 |  | 
| 59 int GrAAConvexTessellator::addPt(const SkPoint& pt, |  | 
| 60                                  SkScalar depth, |  | 
| 61                                  SkScalar coverage, |  | 
| 62                                  bool movable, |  | 
| 63                                  bool isCurve) { |  | 
| 64     this->validate(); |  | 
| 65 |  | 
| 66     int index = fPts.count(); |  | 
| 67     *fPts.push() = pt; |  | 
| 68     *fCoverages.push() = coverage; |  | 
| 69     *fMovable.push() = movable; |  | 
| 70     *fIsCurve.push() = isCurve; |  | 
| 71 |  | 
| 72     this->validate(); |  | 
| 73     return index; |  | 
| 74 } |  | 
| 75 |  | 
| 76 void GrAAConvexTessellator::popLastPt() { |  | 
| 77     this->validate(); |  | 
| 78 |  | 
| 79     fPts.pop(); |  | 
| 80     fCoverages.pop(); |  | 
| 81     fMovable.pop(); |  | 
| 82 |  | 
| 83     this->validate(); |  | 
| 84 } |  | 
| 85 |  | 
| 86 void GrAAConvexTessellator::popFirstPtShuffle() { |  | 
| 87     this->validate(); |  | 
| 88 |  | 
| 89     fPts.removeShuffle(0); |  | 
| 90     fCoverages.removeShuffle(0); |  | 
| 91     fMovable.removeShuffle(0); |  | 
| 92 |  | 
| 93     this->validate(); |  | 
| 94 } |  | 
| 95 |  | 
| 96 void GrAAConvexTessellator::updatePt(int index, |  | 
| 97                                      const SkPoint& pt, |  | 
| 98                                      SkScalar depth, |  | 
| 99                                      SkScalar coverage) { |  | 
| 100     this->validate(); |  | 
| 101     SkASSERT(fMovable[index]); |  | 
| 102 |  | 
| 103     fPts[index] = pt; |  | 
| 104     fCoverages[index] = coverage; |  | 
| 105 } |  | 
| 106 |  | 
| 107 void GrAAConvexTessellator::addTri(int i0, int i1, int i2) { |  | 
| 108     if (i0 == i1 || i1 == i2 || i2 == i0) { |  | 
| 109         return; |  | 
| 110     } |  | 
| 111 |  | 
| 112     *fIndices.push() = i0; |  | 
| 113     *fIndices.push() = i1; |  | 
| 114     *fIndices.push() = i2; |  | 
| 115 } |  | 
| 116 |  | 
| 117 void GrAAConvexTessellator::rewind() { |  | 
| 118     fPts.rewind(); |  | 
| 119     fCoverages.rewind(); |  | 
| 120     fMovable.rewind(); |  | 
| 121     fIndices.rewind(); |  | 
| 122     fNorms.rewind(); |  | 
| 123     fInitialRing.rewind(); |  | 
| 124     fCandidateVerts.rewind(); |  | 
| 125 #if GR_AA_CONVEX_TESSELLATOR_VIZ |  | 
| 126     fRings.rewind();        // TODO: leak in this case! |  | 
| 127 #else |  | 
| 128     fRings[0].rewind(); |  | 
| 129     fRings[1].rewind(); |  | 
| 130 #endif |  | 
| 131 } |  | 
| 132 |  | 
| 133 void GrAAConvexTessellator::computeBisectors() { |  | 
| 134     fBisectors.setCount(fNorms.count()); |  | 
| 135 |  | 
| 136     int prev = fBisectors.count() - 1; |  | 
| 137     for (int cur = 0; cur < fBisectors.count(); prev = cur, ++cur) { |  | 
| 138         fBisectors[cur] = fNorms[cur] + fNorms[prev]; |  | 
| 139         if (!fBisectors[cur].normalize()) { |  | 
| 140             SkASSERT(SkPoint::kLeft_Side == fSide || SkPoint::kRight_Side == fSi
      de); |  | 
| 141             fBisectors[cur].setOrthog(fNorms[cur], (SkPoint::Side)-fSide); |  | 
| 142             SkVector other; |  | 
| 143             other.setOrthog(fNorms[prev], fSide); |  | 
| 144             fBisectors[cur] += other; |  | 
| 145             SkAssertResult(fBisectors[cur].normalize()); |  | 
| 146         } else { |  | 
| 147             fBisectors[cur].negate();      // make the bisector face in |  | 
| 148         } |  | 
| 149 |  | 
| 150         SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); |  | 
| 151     } |  | 
| 152 } |  | 
| 153 |  | 
| 154 // Create as many rings as we need to (up to a predefined limit) to reach the sp
      ecified target |  | 
| 155 // depth. If we are in fill mode, the final ring will automatically be fanned. |  | 
| 156 bool GrAAConvexTessellator::createInsetRings(Ring& previousRing, SkScalar initia
      lDepth, |  | 
| 157                                              SkScalar initialCoverage, SkScalar 
      targetDepth, |  | 
| 158                                              SkScalar targetCoverage, Ring** fin
      alRing) { |  | 
| 159     static const int kMaxNumRings = 8; |  | 
| 160 |  | 
| 161     if (previousRing.numPts() < 3) { |  | 
| 162         return false; |  | 
| 163     } |  | 
| 164     Ring* currentRing = &previousRing; |  | 
| 165     int i; |  | 
| 166     for (i = 0; i < kMaxNumRings; ++i) { |  | 
| 167         Ring* nextRing = this->getNextRing(currentRing); |  | 
| 168         SkASSERT(nextRing != currentRing); |  | 
| 169 |  | 
| 170         bool done = this->createInsetRing(*currentRing, nextRing, initialDepth, 
      initialCoverage, |  | 
| 171                                           targetDepth, targetCoverage, i == 0); |  | 
| 172         currentRing = nextRing; |  | 
| 173         if (done) { |  | 
| 174             break; |  | 
| 175         } |  | 
| 176         currentRing->init(*this); |  | 
| 177     } |  | 
| 178 |  | 
| 179     if (kMaxNumRings == i) { |  | 
| 180         // Bail if we've exceeded the amount of time we want to throw at this. |  | 
| 181         this->terminate(*currentRing); |  | 
| 182         return false; |  | 
| 183     } |  | 
| 184     bool done = currentRing->numPts() >= 3; |  | 
| 185     if (done) { |  | 
| 186         currentRing->init(*this); |  | 
| 187     } |  | 
| 188     *finalRing = currentRing; |  | 
| 189     return done; |  | 
| 190 } |  | 
| 191 |  | 
| 192 // The general idea here is to, conceptually, start with the original polygon an
      d slide |  | 
| 193 // the vertices along the bisectors until the first intersection. At that |  | 
| 194 // point two of the edges collapse and the process repeats on the new polygon. |  | 
| 195 // The polygon state is captured in the Ring class while the GrAAConvexTessellat
      or |  | 
| 196 // controls the iteration. The CandidateVerts holds the formative points for the |  | 
| 197 // next ring. |  | 
| 198 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { |  | 
| 199     if (!this->extractFromPath(m, path)) { |  | 
| 200         return false; |  | 
| 201     } |  | 
| 202 |  | 
| 203     SkScalar coverage = 1.0f; |  | 
| 204     SkScalar scaleFactor = 0.0f; |  | 
| 205     if (fStrokeWidth >= 0.0f) { |  | 
| 206         SkASSERT(m.isSimilarity()); |  | 
| 207         scaleFactor = m.getMaxScale(); // x and y scale are the same |  | 
| 208         SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |  | 
| 209         Ring outerStrokeRing; |  | 
| 210         this->createOuterRing(fInitialRing, effectiveStrokeWidth / 2 - kAntialia
      singRadius, |  | 
| 211                               coverage, &outerStrokeRing); |  | 
| 212         outerStrokeRing.init(*this); |  | 
| 213         Ring outerAARing; |  | 
| 214         this->createOuterRing(outerStrokeRing, kAntialiasingRadius * 2, 0.0f, &o
      uterAARing); |  | 
| 215     } else { |  | 
| 216         Ring outerAARing; |  | 
| 217         this->createOuterRing(fInitialRing, kAntialiasingRadius, 0.0f, &outerAAR
      ing); |  | 
| 218     } |  | 
| 219 |  | 
| 220     // the bisectors are only needed for the computation of the outer ring |  | 
| 221     fBisectors.rewind(); |  | 
| 222     if (fStrokeWidth >= 0.0f && fInitialRing.numPts() > 2) { |  | 
| 223         SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |  | 
| 224         Ring* insetStrokeRing; |  | 
| 225         SkScalar strokeDepth = effectiveStrokeWidth / 2 - kAntialiasingRadius; |  | 
| 226         if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, co
      verage, |  | 
| 227                              &insetStrokeRing)) { |  | 
| 228             Ring* insetAARing; |  | 
| 229             this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, stro
      keDepth + |  | 
| 230                              kAntialiasingRadius * 2, 0.0f, &insetAARing); |  | 
| 231         } |  | 
| 232     } else { |  | 
| 233         Ring* insetAARing; |  | 
| 234         this->createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1.
      0f, &insetAARing); |  | 
| 235     } |  | 
| 236 |  | 
| 237     SkDEBUGCODE(this->validate();) |  | 
| 238     return true; |  | 
| 239 } |  | 
| 240 |  | 
| 241 SkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint&
       p) const { |  | 
| 242     SkASSERT(edgeIdx < fNorms.count()); |  | 
| 243 |  | 
| 244     SkPoint v = p - fPts[edgeIdx]; |  | 
| 245     SkScalar depth = -fNorms[edgeIdx].dot(v); |  | 
| 246     return depth; |  | 
| 247 } |  | 
| 248 |  | 
| 249 // Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies |  | 
| 250 // along the 'bisector' from the 'startIdx'-th point. |  | 
| 251 bool GrAAConvexTessellator::computePtAlongBisector(int startIdx, |  | 
| 252                                                    const SkVector& bisector, |  | 
| 253                                                    int edgeIdx, |  | 
| 254                                                    SkScalar desiredDepth, |  | 
| 255                                                    SkPoint* result) const { |  | 
| 256     const SkPoint& norm = fNorms[edgeIdx]; |  | 
| 257 |  | 
| 258     // First find the point where the edge and the bisector intersect |  | 
| 259     SkPoint newP; |  | 
| 260 |  | 
| 261     SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm); |  | 
| 262     if (SkScalarNearlyEqual(t, 0.0f)) { |  | 
| 263         // the start point was one of the original ring points |  | 
| 264         SkASSERT(startIdx < fPts.count()); |  | 
| 265         newP = fPts[startIdx]; |  | 
| 266     } else if (t < 0.0f) { |  | 
| 267         newP = bisector; |  | 
| 268         newP.scale(t); |  | 
| 269         newP += fPts[startIdx]; |  | 
| 270     } else { |  | 
| 271         return false; |  | 
| 272     } |  | 
| 273 |  | 
| 274     // Then offset along the bisector from that point the correct distance |  | 
| 275     SkScalar dot = bisector.dot(norm); |  | 
| 276     t = -desiredDepth / dot; |  | 
| 277     *result = bisector; |  | 
| 278     result->scale(t); |  | 
| 279     *result += newP; |  | 
| 280 |  | 
| 281     return true; |  | 
| 282 } |  | 
| 283 |  | 
| 284 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat
      h) { |  | 
| 285     SkASSERT(SkPath::kConvex_Convexity == path.getConvexity()); |  | 
| 286 |  | 
| 287     // Outer ring: 3*numPts |  | 
| 288     // Middle ring: numPts |  | 
| 289     // Presumptive inner ring: numPts |  | 
| 290     this->reservePts(5*path.countPoints()); |  | 
| 291     // Outer ring: 12*numPts |  | 
| 292     // Middle ring: 0 |  | 
| 293     // Presumptive inner ring: 6*numPts + 6 |  | 
| 294     fIndices.setReserve(18*path.countPoints() + 6); |  | 
| 295 |  | 
| 296     fNorms.setReserve(path.countPoints()); |  | 
| 297 |  | 
| 298     // TODO: is there a faster way to extract the points from the path? Perhaps |  | 
| 299     // get all the points via a new entry point, transform them all in bulk |  | 
| 300     // and then walk them to find duplicates? |  | 
| 301     SkPath::Iter iter(path, true); |  | 
| 302     SkPoint pts[4]; |  | 
| 303     SkPath::Verb verb; |  | 
| 304     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |  | 
| 305         switch (verb) { |  | 
| 306             case SkPath::kLine_Verb: |  | 
| 307                 this->lineTo(m, pts[1], false); |  | 
| 308                 break; |  | 
| 309             case SkPath::kQuad_Verb: |  | 
| 310                 this->quadTo(m, pts); |  | 
| 311                 break; |  | 
| 312             case SkPath::kCubic_Verb: |  | 
| 313                 this->cubicTo(m, pts); |  | 
| 314                 break; |  | 
| 315             case SkPath::kConic_Verb: |  | 
| 316                 this->conicTo(m, pts, iter.conicWeight()); |  | 
| 317                 break; |  | 
| 318             case SkPath::kMove_Verb: |  | 
| 319             case SkPath::kClose_Verb: |  | 
| 320             case SkPath::kDone_Verb: |  | 
| 321                 break; |  | 
| 322         } |  | 
| 323     } |  | 
| 324 |  | 
| 325     if (this->numPts() < 2) { |  | 
| 326         return false; |  | 
| 327     } |  | 
| 328 |  | 
| 329     // check if last point is a duplicate of the first point. If so, remove it. |  | 
| 330     if (duplicate_pt(fPts[this->numPts()-1], fPts[0])) { |  | 
| 331         this->popLastPt(); |  | 
| 332         fNorms.pop(); |  | 
| 333     } |  | 
| 334 |  | 
| 335     SkASSERT(fPts.count() == fNorms.count()+1); |  | 
| 336     if (this->numPts() >= 3) { |  | 
| 337         if (abs_dist_from_line(fPts.top(), fNorms.top(), fPts[0]) < kClose) { |  | 
| 338             // The last point is on the line from the second to last to the firs
      t point. |  | 
| 339             this->popLastPt(); |  | 
| 340             fNorms.pop(); |  | 
| 341         } |  | 
| 342 |  | 
| 343         *fNorms.push() = fPts[0] - fPts.top(); |  | 
| 344         SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); |  | 
| 345         SkASSERT(len > 0.0f); |  | 
| 346         SkASSERT(fPts.count() == fNorms.count()); |  | 
| 347     } |  | 
| 348 |  | 
| 349     if (this->numPts() >= 3 && abs_dist_from_line(fPts[0], fNorms.top(), fPts[1]
      ) < kClose) { |  | 
| 350         // The first point is on the line from the last to the second. |  | 
| 351         this->popFirstPtShuffle(); |  | 
| 352         fNorms.removeShuffle(0); |  | 
| 353         fNorms[0] = fPts[1] - fPts[0]; |  | 
| 354         SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[0]); |  | 
| 355         SkASSERT(len > 0.0f); |  | 
| 356         SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length())); |  | 
| 357     } |  | 
| 358 |  | 
| 359     if (this->numPts() >= 3) { |  | 
| 360         // Check the cross product of the final trio |  | 
| 361         SkScalar cross = SkPoint::CrossProduct(fNorms[0], fNorms.top()); |  | 
| 362         if (cross > 0.0f) { |  | 
| 363             fSide = SkPoint::kRight_Side; |  | 
| 364         } else { |  | 
| 365             fSide = SkPoint::kLeft_Side; |  | 
| 366         } |  | 
| 367 |  | 
| 368         // Make all the normals face outwards rather than along the edge |  | 
| 369         for (int cur = 0; cur < fNorms.count(); ++cur) { |  | 
| 370             fNorms[cur].setOrthog(fNorms[cur], fSide); |  | 
| 371             SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); |  | 
| 372         } |  | 
| 373 |  | 
| 374         this->computeBisectors(); |  | 
| 375     } else if (this->numPts() == 2) { |  | 
| 376         // We've got two points, so we're degenerate. |  | 
| 377         if (fStrokeWidth < 0.0f) { |  | 
| 378             // it's a fill, so we don't need to worry about degenerate paths |  | 
| 379             return false; |  | 
| 380         } |  | 
| 381         // For stroking, we still need to process the degenerate path, so fix it
       up |  | 
| 382         fSide = SkPoint::kLeft_Side; |  | 
| 383 |  | 
| 384         // Make all the normals face outwards rather than along the edge |  | 
| 385         for (int cur = 0; cur < fNorms.count(); ++cur) { |  | 
| 386             fNorms[cur].setOrthog(fNorms[cur], fSide); |  | 
| 387             SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); |  | 
| 388         } |  | 
| 389 |  | 
| 390         fNorms.push(SkPoint::Make(-fNorms[0].fX, -fNorms[0].fY)); |  | 
| 391         // we won't actually use the bisectors, so just push zeroes |  | 
| 392         fBisectors.push(SkPoint::Make(0.0, 0.0)); |  | 
| 393         fBisectors.push(SkPoint::Make(0.0, 0.0)); |  | 
| 394     } else { |  | 
| 395         return false; |  | 
| 396     } |  | 
| 397 |  | 
| 398     fCandidateVerts.setReserve(this->numPts()); |  | 
| 399     fInitialRing.setReserve(this->numPts()); |  | 
| 400     for (int i = 0; i < this->numPts(); ++i) { |  | 
| 401         fInitialRing.addIdx(i, i); |  | 
| 402     } |  | 
| 403     fInitialRing.init(fNorms, fBisectors); |  | 
| 404 |  | 
| 405     this->validate(); |  | 
| 406     return true; |  | 
| 407 } |  | 
| 408 |  | 
| 409 GrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) 
      { |  | 
| 410 #if GR_AA_CONVEX_TESSELLATOR_VIZ |  | 
| 411     Ring* ring = *fRings.push() = new Ring; |  | 
| 412     ring->setReserve(fInitialRing.numPts()); |  | 
| 413     ring->rewind(); |  | 
| 414     return ring; |  | 
| 415 #else |  | 
| 416     // Flip flop back and forth between fRings[0] & fRings[1] |  | 
| 417     int nextRing = (lastRing == &fRings[0]) ? 1 : 0; |  | 
| 418     fRings[nextRing].setReserve(fInitialRing.numPts()); |  | 
| 419     fRings[nextRing].rewind(); |  | 
| 420     return &fRings[nextRing]; |  | 
| 421 #endif |  | 
| 422 } |  | 
| 423 |  | 
| 424 void GrAAConvexTessellator::fanRing(const Ring& ring) { |  | 
| 425     // fan out from point 0 |  | 
| 426     int startIdx = ring.index(0); |  | 
| 427     for (int cur = ring.numPts() - 2; cur >= 0; --cur) { |  | 
| 428         this->addTri(startIdx, ring.index(cur), ring.index(cur + 1)); |  | 
| 429     } |  | 
| 430 } |  | 
| 431 |  | 
| 432 void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o
      utset, |  | 
| 433                                             SkScalar coverage, Ring* nextRing) { |  | 
| 434     const int numPts = previousRing.numPts(); |  | 
| 435     if (numPts == 0) { |  | 
| 436         return; |  | 
| 437     } |  | 
| 438 |  | 
| 439     int prev = numPts - 1; |  | 
| 440     int lastPerpIdx = -1, firstPerpIdx = -1; |  | 
| 441 |  | 
| 442     const SkScalar outsetSq = SkScalarMul(outset, outset); |  | 
| 443     SkScalar miterLimitSq = SkScalarMul(outset, fMiterLimit); |  | 
| 444     miterLimitSq = SkScalarMul(miterLimitSq, miterLimitSq); |  | 
| 445     for (int cur = 0; cur < numPts; ++cur) { |  | 
| 446         int originalIdx = previousRing.index(cur); |  | 
| 447         // For each vertex of the original polygon we add at least two points to
       the |  | 
| 448         // outset polygon - one extending perpendicular to each impinging edge. 
      Connecting these |  | 
| 449         // two points yields a bevel join. We need one additional point for a mi
      tered join, and |  | 
| 450         // a round join requires one or more points depending upon curvature. |  | 
| 451 |  | 
| 452         // The perpendicular point for the last edge |  | 
| 453         SkPoint normal1 = previousRing.norm(prev); |  | 
| 454         SkPoint perp1 = normal1; |  | 
| 455         perp1.scale(outset); |  | 
| 456         perp1 += this->point(originalIdx); |  | 
| 457 |  | 
| 458         // The perpendicular point for the next edge. |  | 
| 459         SkPoint normal2 = previousRing.norm(cur); |  | 
| 460         SkPoint perp2 = normal2; |  | 
| 461         perp2.scale(outset); |  | 
| 462         perp2 += fPts[originalIdx]; |  | 
| 463 |  | 
| 464         bool isCurve = fIsCurve[originalIdx]; |  | 
| 465 |  | 
| 466         // We know it isn't a duplicate of the prior point (since it and this |  | 
| 467         // one are just perpendicular offsets from the non-merged polygon points
      ) |  | 
| 468         int perp1Idx = this->addPt(perp1, -outset, coverage, false, isCurve); |  | 
| 469         nextRing->addIdx(perp1Idx, originalIdx); |  | 
| 470 |  | 
| 471         int perp2Idx; |  | 
| 472         // For very shallow angles all the corner points could fuse. |  | 
| 473         if (duplicate_pt(perp2, this->point(perp1Idx))) { |  | 
| 474             perp2Idx = perp1Idx; |  | 
| 475         } else { |  | 
| 476             perp2Idx = this->addPt(perp2, -outset, coverage, false, isCurve); |  | 
| 477         } |  | 
| 478 |  | 
| 479         if (perp2Idx != perp1Idx) { |  | 
| 480             if (isCurve) { |  | 
| 481                 // bevel or round depending upon curvature |  | 
| 482                 SkScalar dotProd = normal1.dot(normal2); |  | 
| 483                 if (dotProd < kRoundCapThreshold) { |  | 
| 484                     // Currently we "round" by creating a single extra point, wh
      ich produces |  | 
| 485                     // good results for common cases. For thick strokes with hig
      h curvature, we will |  | 
| 486                     // need to add more points; for the time being we simply fal
      l back to software |  | 
| 487                     // rendering for thick strokes. |  | 
| 488                     SkPoint miter = previousRing.bisector(cur); |  | 
| 489                     miter.setLength(-outset); |  | 
| 490                     miter += fPts[originalIdx]; |  | 
| 491 |  | 
| 492                     // For very shallow angles all the corner points could fuse |  | 
| 493                     if (!duplicate_pt(miter, this->point(perp1Idx))) { |  | 
| 494                         int miterIdx; |  | 
| 495                         miterIdx = this->addPt(miter, -outset, coverage, false, 
      false); |  | 
| 496                         nextRing->addIdx(miterIdx, originalIdx); |  | 
| 497                         // The two triangles for the corner |  | 
| 498                         this->addTri(originalIdx, perp1Idx, miterIdx); |  | 
| 499                         this->addTri(originalIdx, miterIdx, perp2Idx); |  | 
| 500                     } |  | 
| 501                 } else { |  | 
| 502                     this->addTri(originalIdx, perp1Idx, perp2Idx); |  | 
| 503                 } |  | 
| 504             } else { |  | 
| 505                 switch (fJoin) { |  | 
| 506                     case SkPaint::Join::kMiter_Join: { |  | 
| 507                         // The bisector outset point |  | 
| 508                         SkPoint miter = previousRing.bisector(cur); |  | 
| 509                         SkScalar dotProd = normal1.dot(normal2); |  | 
| 510                         SkScalar sinHalfAngleSq = SkScalarHalf(SK_Scalar1 + dotP
      rod); |  | 
| 511                         SkScalar lengthSq = outsetSq / sinHalfAngleSq; |  | 
| 512                         if (lengthSq > miterLimitSq) { |  | 
| 513                             // just bevel it |  | 
| 514                             this->addTri(originalIdx, perp1Idx, perp2Idx); |  | 
| 515                             break; |  | 
| 516                         } |  | 
| 517                         miter.setLength(-SkScalarSqrt(lengthSq)); |  | 
| 518                         miter += fPts[originalIdx]; |  | 
| 519 |  | 
| 520                         // For very shallow angles all the corner points could f
      use |  | 
| 521                         if (!duplicate_pt(miter, this->point(perp1Idx))) { |  | 
| 522                             int miterIdx; |  | 
| 523                             miterIdx = this->addPt(miter, -outset, coverage, fal
      se, false); |  | 
| 524                             nextRing->addIdx(miterIdx, originalIdx); |  | 
| 525                             // The two triangles for the corner |  | 
| 526                             this->addTri(originalIdx, perp1Idx, miterIdx); |  | 
| 527                             this->addTri(originalIdx, miterIdx, perp2Idx); |  | 
| 528                         } |  | 
| 529                         break; |  | 
| 530                     } |  | 
| 531                     case SkPaint::Join::kBevel_Join: |  | 
| 532                         this->addTri(originalIdx, perp1Idx, perp2Idx); |  | 
| 533                         break; |  | 
| 534                     default: |  | 
| 535                         // kRound_Join is unsupported for now. GrAALinearizingCo
      nvexPathRenderer is |  | 
| 536                         // only willing to draw mitered or beveled, so we should
       never get here. |  | 
| 537                         SkASSERT(false); |  | 
| 538                 } |  | 
| 539             } |  | 
| 540 |  | 
| 541             nextRing->addIdx(perp2Idx, originalIdx); |  | 
| 542         } |  | 
| 543 |  | 
| 544         if (0 == cur) { |  | 
| 545             // Store the index of the first perpendicular point to finish up |  | 
| 546             firstPerpIdx = perp1Idx; |  | 
| 547             SkASSERT(-1 == lastPerpIdx); |  | 
| 548         } else { |  | 
| 549             // The triangles for the previous edge |  | 
| 550             int prevIdx = previousRing.index(prev); |  | 
| 551             this->addTri(prevIdx, perp1Idx, originalIdx); |  | 
| 552             this->addTri(prevIdx, lastPerpIdx, perp1Idx); |  | 
| 553         } |  | 
| 554 |  | 
| 555         // Track the last perpendicular outset point so we can construct the |  | 
| 556         // trailing edge triangles. |  | 
| 557         lastPerpIdx = perp2Idx; |  | 
| 558         prev = cur; |  | 
| 559     } |  | 
| 560 |  | 
| 561     // pick up the final edge rect |  | 
| 562     int lastIdx = previousRing.index(numPts - 1); |  | 
| 563     this->addTri(lastIdx, firstPerpIdx, previousRing.index(0)); |  | 
| 564     this->addTri(lastIdx, lastPerpIdx, firstPerpIdx); |  | 
| 565 |  | 
| 566     this->validate(); |  | 
| 567 } |  | 
| 568 |  | 
| 569 // Something went wrong in the creation of the next ring. If we're filling the s
      hape, just go ahead |  | 
| 570 // and fan it. |  | 
| 571 void GrAAConvexTessellator::terminate(const Ring& ring) { |  | 
| 572     if (fStrokeWidth < 0.0f) { |  | 
| 573         this->fanRing(ring); |  | 
| 574     } |  | 
| 575 } |  | 
| 576 |  | 
| 577 static SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar
       initialCoverage, |  | 
| 578                                 SkScalar targetDepth, SkScalar targetCoverage) { |  | 
| 579     if (SkScalarNearlyEqual(initialDepth, targetDepth)) { |  | 
| 580         return targetCoverage; |  | 
| 581     } |  | 
| 582     SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) * |  | 
| 583             (targetCoverage - initialCoverage) + initialCoverage; |  | 
| 584     return SkScalarClampMax(result, 1.0f); |  | 
| 585 } |  | 
| 586 |  | 
| 587 // return true when processing is complete |  | 
| 588 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing
      , |  | 
| 589                                             SkScalar initialDepth, SkScalar init
      ialCoverage, |  | 
| 590                                             SkScalar targetDepth, SkScalar targe
      tCoverage, |  | 
| 591                                             bool forceNew) { |  | 
| 592     bool done = false; |  | 
| 593 |  | 
| 594     fCandidateVerts.rewind(); |  | 
| 595 |  | 
| 596     // Loop through all the points in the ring and find the intersection with th
      e smallest depth |  | 
| 597     SkScalar minDist = SK_ScalarMax, minT = 0.0f; |  | 
| 598     int minEdgeIdx = -1; |  | 
| 599 |  | 
| 600     for (int cur = 0; cur < lastRing.numPts(); ++cur) { |  | 
| 601         int next = (cur + 1) % lastRing.numPts(); |  | 
| 602         SkScalar t = intersect(this->point(lastRing.index(cur)),  lastRing.bisec
      tor(cur), |  | 
| 603                                this->point(lastRing.index(next)), lastRing.bisec
      tor(next)); |  | 
| 604         SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); |  | 
| 605 |  | 
| 606         if (minDist > dist) { |  | 
| 607             minDist = dist; |  | 
| 608             minT = t; |  | 
| 609             minEdgeIdx = cur; |  | 
| 610         } |  | 
| 611     } |  | 
| 612 |  | 
| 613     if (minEdgeIdx == -1) { |  | 
| 614         return false; |  | 
| 615     } |  | 
| 616     SkPoint newPt = lastRing.bisector(minEdgeIdx); |  | 
| 617     newPt.scale(minT); |  | 
| 618     newPt += this->point(lastRing.index(minEdgeIdx)); |  | 
| 619 |  | 
| 620     SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx),
       newPt); |  | 
| 621     if (depth >= targetDepth) { |  | 
| 622         // None of the bisectors intersect before reaching the desired depth. |  | 
| 623         // Just step them all to the desired depth |  | 
| 624         depth = targetDepth; |  | 
| 625         done = true; |  | 
| 626     } |  | 
| 627 |  | 
| 628     // 'dst' stores where each point in the last ring maps to/transforms into |  | 
| 629     // in the next ring. |  | 
| 630     SkTDArray<int> dst; |  | 
| 631     dst.setCount(lastRing.numPts()); |  | 
| 632 |  | 
| 633     // Create the first point (who compares with no one) |  | 
| 634     if (!this->computePtAlongBisector(lastRing.index(0), |  | 
| 635                                       lastRing.bisector(0), |  | 
| 636                                       lastRing.origEdgeID(0), |  | 
| 637                                       depth, &newPt)) { |  | 
| 638         this->terminate(lastRing); |  | 
| 639         return true; |  | 
| 640     } |  | 
| 641     dst[0] = fCandidateVerts.addNewPt(newPt, |  | 
| 642                                       lastRing.index(0), lastRing.origEdgeID(0), |  | 
| 643                                       !this->movable(lastRing.index(0))); |  | 
| 644 |  | 
| 645     // Handle the middle points (who only compare with the prior point) |  | 
| 646     for (int cur = 1; cur < lastRing.numPts()-1; ++cur) { |  | 
| 647         if (!this->computePtAlongBisector(lastRing.index(cur), |  | 
| 648                                           lastRing.bisector(cur), |  | 
| 649                                           lastRing.origEdgeID(cur), |  | 
| 650                                           depth, &newPt)) { |  | 
| 651             this->terminate(lastRing); |  | 
| 652             return true; |  | 
| 653         } |  | 
| 654         if (!duplicate_pt(newPt, fCandidateVerts.lastPoint())) { |  | 
| 655             dst[cur] = fCandidateVerts.addNewPt(newPt, |  | 
| 656                                                 lastRing.index(cur), lastRing.or
      igEdgeID(cur), |  | 
| 657                                                 !this->movable(lastRing.index(cu
      r))); |  | 
| 658         } else { |  | 
| 659             dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); |  | 
| 660         } |  | 
| 661     } |  | 
| 662 |  | 
| 663     // Check on the last point (handling the wrap around) |  | 
| 664     int cur = lastRing.numPts()-1; |  | 
| 665     if  (!this->computePtAlongBisector(lastRing.index(cur), |  | 
| 666                                        lastRing.bisector(cur), |  | 
| 667                                        lastRing.origEdgeID(cur), |  | 
| 668                                        depth, &newPt)) { |  | 
| 669         this->terminate(lastRing); |  | 
| 670         return true; |  | 
| 671     } |  | 
| 672     bool dupPrev = duplicate_pt(newPt, fCandidateVerts.lastPoint()); |  | 
| 673     bool dupNext = duplicate_pt(newPt, fCandidateVerts.firstPoint()); |  | 
| 674 |  | 
| 675     if (!dupPrev && !dupNext) { |  | 
| 676         dst[cur] = fCandidateVerts.addNewPt(newPt, |  | 
| 677                                             lastRing.index(cur), lastRing.origEd
      geID(cur), |  | 
| 678                                             !this->movable(lastRing.index(cur)))
      ; |  | 
| 679     } else if (dupPrev && !dupNext) { |  | 
| 680         dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); |  | 
| 681     } else if (!dupPrev && dupNext) { |  | 
| 682         dst[cur] = fCandidateVerts.fuseWithNext(); |  | 
| 683     } else { |  | 
| 684         bool dupPrevVsNext = duplicate_pt(fCandidateVerts.firstPoint(), fCandida
      teVerts.lastPoint()); |  | 
| 685 |  | 
| 686         if (!dupPrevVsNext) { |  | 
| 687             dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); |  | 
| 688         } else { |  | 
| 689             const int fused = fCandidateVerts.fuseWithBoth(); |  | 
| 690             dst[cur] = fused; |  | 
| 691             const int targetIdx = dst[cur - 1]; |  | 
| 692             for (int i = cur - 1; i >= 0 && dst[i] == targetIdx; i--) { |  | 
| 693                 dst[i] = fused; |  | 
| 694             } |  | 
| 695         } |  | 
| 696     } |  | 
| 697 |  | 
| 698     // Fold the new ring's points into the global pool |  | 
| 699     for (int i = 0; i < fCandidateVerts.numPts(); ++i) { |  | 
| 700         int newIdx; |  | 
| 701         if (fCandidateVerts.needsToBeNew(i) || forceNew) { |  | 
| 702             // if the originating index is still valid then this point wasn't |  | 
| 703             // fused (and is thus movable) |  | 
| 704             SkScalar coverage = compute_coverage(depth, initialDepth, initialCov
      erage, |  | 
| 705                                                  targetDepth, targetCoverage); |  | 
| 706             newIdx = this->addPt(fCandidateVerts.point(i), depth, coverage, |  | 
| 707                                  fCandidateVerts.originatingIdx(i) != -1, false)
      ; |  | 
| 708         } else { |  | 
| 709             SkASSERT(fCandidateVerts.originatingIdx(i) != -1); |  | 
| 710             this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po
      int(i), depth, |  | 
| 711                            targetCoverage); |  | 
| 712             newIdx = fCandidateVerts.originatingIdx(i); |  | 
| 713         } |  | 
| 714 |  | 
| 715         nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i)); |  | 
| 716     } |  | 
| 717 |  | 
| 718     // 'dst' currently has indices into the ring. Remap these to be indices |  | 
| 719     // into the global pool since the triangulation operates in that space. |  | 
| 720     for (int i = 0; i < dst.count(); ++i) { |  | 
| 721         dst[i] = nextRing->index(dst[i]); |  | 
| 722     } |  | 
| 723 |  | 
| 724     for (int cur = 0; cur < lastRing.numPts(); ++cur) { |  | 
| 725         int next = (cur + 1) % lastRing.numPts(); |  | 
| 726 |  | 
| 727         this->addTri(lastRing.index(cur), lastRing.index(next), dst[next]); |  | 
| 728         this->addTri(lastRing.index(cur), dst[next], dst[cur]); |  | 
| 729     } |  | 
| 730 |  | 
| 731     if (done && fStrokeWidth < 0.0f) { |  | 
| 732         // fill |  | 
| 733         this->fanRing(*nextRing); |  | 
| 734     } |  | 
| 735 |  | 
| 736     if (nextRing->numPts() < 3) { |  | 
| 737         done = true; |  | 
| 738     } |  | 
| 739     return done; |  | 
| 740 } |  | 
| 741 |  | 
| 742 void GrAAConvexTessellator::validate() const { |  | 
| 743     SkASSERT(fPts.count() == fMovable.count()); |  | 
| 744     SkASSERT(0 == (fIndices.count() % 3)); |  | 
| 745 } |  | 
| 746 |  | 
| 747 ////////////////////////////////////////////////////////////////////////////// |  | 
| 748 void GrAAConvexTessellator::Ring::init(const GrAAConvexTessellator& tess) { |  | 
| 749     this->computeNormals(tess); |  | 
| 750     this->computeBisectors(tess); |  | 
| 751 } |  | 
| 752 |  | 
| 753 void GrAAConvexTessellator::Ring::init(const SkTDArray<SkVector>& norms, |  | 
| 754                                        const SkTDArray<SkVector>& bisectors) { |  | 
| 755     for (int i = 0; i < fPts.count(); ++i) { |  | 
| 756         fPts[i].fNorm = norms[i]; |  | 
| 757         fPts[i].fBisector = bisectors[i]; |  | 
| 758     } |  | 
| 759 } |  | 
| 760 |  | 
| 761 // Compute the outward facing normal at each vertex. |  | 
| 762 void GrAAConvexTessellator::Ring::computeNormals(const GrAAConvexTessellator& te
      ss) { |  | 
| 763     for (int cur = 0; cur < fPts.count(); ++cur) { |  | 
| 764         int next = (cur + 1) % fPts.count(); |  | 
| 765 |  | 
| 766         fPts[cur].fNorm = tess.point(fPts[next].fIndex) - tess.point(fPts[cur].f
      Index); |  | 
| 767         SkPoint::Normalize(&fPts[cur].fNorm); |  | 
| 768         fPts[cur].fNorm.setOrthog(fPts[cur].fNorm, tess.side()); |  | 
| 769     } |  | 
| 770 } |  | 
| 771 |  | 
| 772 void GrAAConvexTessellator::Ring::computeBisectors(const GrAAConvexTessellator& 
      tess) { |  | 
| 773     int prev = fPts.count() - 1; |  | 
| 774     for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) { |  | 
| 775         fPts[cur].fBisector = fPts[cur].fNorm + fPts[prev].fNorm; |  | 
| 776         if (!fPts[cur].fBisector.normalize()) { |  | 
| 777             SkASSERT(SkPoint::kLeft_Side == tess.side() || SkPoint::kRight_Side 
      == tess.side()); |  | 
| 778             fPts[cur].fBisector.setOrthog(fPts[cur].fNorm, (SkPoint::Side)-tess.
      side()); |  | 
| 779             SkVector other; |  | 
| 780             other.setOrthog(fPts[prev].fNorm, tess.side()); |  | 
| 781             fPts[cur].fBisector += other; |  | 
| 782             SkAssertResult(fPts[cur].fBisector.normalize()); |  | 
| 783         } else { |  | 
| 784             fPts[cur].fBisector.negate();      // make the bisector face in |  | 
| 785         } |  | 
| 786     } |  | 
| 787 } |  | 
| 788 |  | 
| 789 ////////////////////////////////////////////////////////////////////////////// |  | 
| 790 #ifdef SK_DEBUG |  | 
| 791 // Is this ring convex? |  | 
| 792 bool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) co
      nst { |  | 
| 793     if (fPts.count() < 3) { |  | 
| 794         return true; |  | 
| 795     } |  | 
| 796 |  | 
| 797     SkPoint prev = tess.point(fPts[0].fIndex) - tess.point(fPts.top().fIndex); |  | 
| 798     SkPoint cur  = tess.point(fPts[1].fIndex) - tess.point(fPts[0].fIndex); |  | 
| 799     SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX; |  | 
| 800     SkScalar maxDot = minDot; |  | 
| 801 |  | 
| 802     prev = cur; |  | 
| 803     for (int i = 1; i < fPts.count(); ++i) { |  | 
| 804         int next = (i + 1) % fPts.count(); |  | 
| 805 |  | 
| 806         cur  = tess.point(fPts[next].fIndex) - tess.point(fPts[i].fIndex); |  | 
| 807         SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX; |  | 
| 808 |  | 
| 809         minDot = SkMinScalar(minDot, dot); |  | 
| 810         maxDot = SkMaxScalar(maxDot, dot); |  | 
| 811 |  | 
| 812         prev = cur; |  | 
| 813     } |  | 
| 814 |  | 
| 815     if (SkScalarNearlyEqual(maxDot, 0.0f, 0.005f)) { |  | 
| 816         maxDot = 0; |  | 
| 817     } |  | 
| 818     if (SkScalarNearlyEqual(minDot, 0.0f, 0.005f)) { |  | 
| 819         minDot = 0; |  | 
| 820     } |  | 
| 821     return (maxDot >= 0.0f) == (minDot >= 0.0f); |  | 
| 822 } |  | 
| 823 |  | 
| 824 #endif |  | 
| 825 |  | 
| 826 void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { |  | 
| 827     if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) { |  | 
| 828         return; |  | 
| 829     } |  | 
| 830 |  | 
| 831     SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1); |  | 
| 832     if (this->numPts() >= 2 && |  | 
| 833         abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) { |  | 
| 834         // The old last point is on the line from the second to last to the new 
      point |  | 
| 835         this->popLastPt(); |  | 
| 836         fNorms.pop(); |  | 
| 837         fIsCurve.pop(); |  | 
| 838     } |  | 
| 839     SkScalar initialRingCoverage = fStrokeWidth < 0.0f ? 0.5f : 1.0f; |  | 
| 840     this->addPt(p, 0.0f, initialRingCoverage, false, isCurve); |  | 
| 841     if (this->numPts() > 1) { |  | 
| 842         *fNorms.push() = fPts.top() - fPts[fPts.count()-2]; |  | 
| 843         SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); |  | 
| 844         SkASSERT(len > 0.0f); |  | 
| 845         SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length())); |  | 
| 846     } |  | 
| 847 } |  | 
| 848 |  | 
| 849 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) { |  | 
| 850     m.mapPoints(&p, 1); |  | 
| 851     this->lineTo(p, isCurve); |  | 
| 852 } |  | 
| 853 |  | 
| 854 void GrAAConvexTessellator::quadTo(SkPoint pts[3]) { |  | 
| 855     int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); |  | 
| 856     fPointBuffer.setReserve(maxCount); |  | 
| 857     SkPoint* target = fPointBuffer.begin(); |  | 
| 858     int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], |  | 
| 859             kQuadTolerance, &target, maxCount); |  | 
| 860     fPointBuffer.setCount(count); |  | 
| 861     for (int i = 0; i < count; i++) { |  | 
| 862         lineTo(fPointBuffer[i], true); |  | 
| 863     } |  | 
| 864 } |  | 
| 865 |  | 
| 866 void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) { |  | 
| 867     SkPoint transformed[3]; |  | 
| 868     transformed[0] = pts[0]; |  | 
| 869     transformed[1] = pts[1]; |  | 
| 870     transformed[2] = pts[2]; |  | 
| 871     m.mapPoints(transformed, 3); |  | 
| 872     quadTo(transformed); |  | 
| 873 } |  | 
| 874 |  | 
| 875 void GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) { |  | 
| 876     m.mapPoints(pts, 4); |  | 
| 877     int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); |  | 
| 878     fPointBuffer.setReserve(maxCount); |  | 
| 879     SkPoint* target = fPointBuffer.begin(); |  | 
| 880     int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], |  | 
| 881             kCubicTolerance, &target, maxCount); |  | 
| 882     fPointBuffer.setCount(count); |  | 
| 883     for (int i = 0; i < count; i++) { |  | 
| 884         lineTo(fPointBuffer[i], true); |  | 
| 885     } |  | 
| 886 } |  | 
| 887 |  | 
| 888 // include down here to avoid compilation errors caused by "-" overload in SkGeo
      metry.h |  | 
| 889 #include "SkGeometry.h" |  | 
| 890 |  | 
| 891 void GrAAConvexTessellator::conicTo(const SkMatrix& m, SkPoint pts[3], SkScalar 
      w) { |  | 
| 892     m.mapPoints(pts, 3); |  | 
| 893     SkAutoConicToQuads quadder; |  | 
| 894     const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance); |  | 
| 895     SkPoint lastPoint = *(quads++); |  | 
| 896     int count = quadder.countQuads(); |  | 
| 897     for (int i = 0; i < count; ++i) { |  | 
| 898         SkPoint quadPts[3]; |  | 
| 899         quadPts[0] = lastPoint; |  | 
| 900         quadPts[1] = quads[0]; |  | 
| 901         quadPts[2] = i == count - 1 ? pts[2] : quads[1]; |  | 
| 902         quadTo(quadPts); |  | 
| 903         lastPoint = quadPts[2]; |  | 
| 904         quads += 2; |  | 
| 905     } |  | 
| 906 } |  | 
| 907 |  | 
| 908 ////////////////////////////////////////////////////////////////////////////// |  | 
| 909 #if GR_AA_CONVEX_TESSELLATOR_VIZ |  | 
| 910 static const SkScalar kPointRadius = 0.02f; |  | 
| 911 static const SkScalar kArrowStrokeWidth = 0.0f; |  | 
| 912 static const SkScalar kArrowLength = 0.2f; |  | 
| 913 static const SkScalar kEdgeTextSize = 0.1f; |  | 
| 914 static const SkScalar kPointTextSize = 0.02f; |  | 
| 915 |  | 
| 916 static void draw_point(SkCanvas* canvas, const SkPoint& p, SkScalar paramValue, 
      bool stroke) { |  | 
| 917     SkPaint paint; |  | 
| 918     SkASSERT(paramValue <= 1.0f); |  | 
| 919     int gs = int(255*paramValue); |  | 
| 920     paint.setARGB(255, gs, gs, gs); |  | 
| 921 |  | 
| 922     canvas->drawCircle(p.fX, p.fY, kPointRadius, paint); |  | 
| 923 |  | 
| 924     if (stroke) { |  | 
| 925         SkPaint stroke; |  | 
| 926         stroke.setColor(SK_ColorYELLOW); |  | 
| 927         stroke.setStyle(SkPaint::kStroke_Style); |  | 
| 928         stroke.setStrokeWidth(kPointRadius/3.0f); |  | 
| 929         canvas->drawCircle(p.fX, p.fY, kPointRadius, stroke); |  | 
| 930     } |  | 
| 931 } |  | 
| 932 |  | 
| 933 static void draw_line(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1, Sk
      Color color) { |  | 
| 934     SkPaint p; |  | 
| 935     p.setColor(color); |  | 
| 936 |  | 
| 937     canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, p); |  | 
| 938 } |  | 
| 939 |  | 
| 940 static void draw_arrow(SkCanvas*canvas, const SkPoint& p, const SkPoint &n, |  | 
| 941                        SkScalar len, SkColor color) { |  | 
| 942     SkPaint paint; |  | 
| 943     paint.setColor(color); |  | 
| 944     paint.setStrokeWidth(kArrowStrokeWidth); |  | 
| 945     paint.setStyle(SkPaint::kStroke_Style); |  | 
| 946 |  | 
| 947     canvas->drawLine(p.fX, p.fY, |  | 
| 948                      p.fX + len * n.fX, p.fY + len * n.fY, |  | 
| 949                      paint); |  | 
| 950 } |  | 
| 951 |  | 
| 952 void GrAAConvexTessellator::Ring::draw(SkCanvas* canvas, const GrAAConvexTessell
      ator& tess) const { |  | 
| 953     SkPaint paint; |  | 
| 954     paint.setTextSize(kEdgeTextSize); |  | 
| 955 |  | 
| 956     for (int cur = 0; cur < fPts.count(); ++cur) { |  | 
| 957         int next = (cur + 1) % fPts.count(); |  | 
| 958 |  | 
| 959         draw_line(canvas, |  | 
| 960                   tess.point(fPts[cur].fIndex), |  | 
| 961                   tess.point(fPts[next].fIndex), |  | 
| 962                   SK_ColorGREEN); |  | 
| 963 |  | 
| 964         SkPoint mid = tess.point(fPts[cur].fIndex) + tess.point(fPts[next].fInde
      x); |  | 
| 965         mid.scale(0.5f); |  | 
| 966 |  | 
| 967         if (fPts.count()) { |  | 
| 968             draw_arrow(canvas, mid, fPts[cur].fNorm, kArrowLength, SK_ColorRED); |  | 
| 969             mid.fX += (kArrowLength/2) * fPts[cur].fNorm.fX; |  | 
| 970             mid.fY += (kArrowLength/2) * fPts[cur].fNorm.fY; |  | 
| 971         } |  | 
| 972 |  | 
| 973         SkString num; |  | 
| 974         num.printf("%d", this->origEdgeID(cur)); |  | 
| 975         canvas->drawText(num.c_str(), num.size(), mid.fX, mid.fY, paint); |  | 
| 976 |  | 
| 977         if (fPts.count()) { |  | 
| 978             draw_arrow(canvas, tess.point(fPts[cur].fIndex), fPts[cur].fBisector
      , |  | 
| 979                        kArrowLength, SK_ColorBLUE); |  | 
| 980         } |  | 
| 981     } |  | 
| 982 } |  | 
| 983 |  | 
| 984 void GrAAConvexTessellator::draw(SkCanvas* canvas) const { |  | 
| 985     for (int i = 0; i < fIndices.count(); i += 3) { |  | 
| 986         SkASSERT(fIndices[i] < this->numPts()) ; |  | 
| 987         SkASSERT(fIndices[i+1] < this->numPts()) ; |  | 
| 988         SkASSERT(fIndices[i+2] < this->numPts()) ; |  | 
| 989 |  | 
| 990         draw_line(canvas, |  | 
| 991                   this->point(this->fIndices[i]), this->point(this->fIndices[i+1
      ]), |  | 
| 992                   SK_ColorBLACK); |  | 
| 993         draw_line(canvas, |  | 
| 994                   this->point(this->fIndices[i+1]), this->point(this->fIndices[i
      +2]), |  | 
| 995                   SK_ColorBLACK); |  | 
| 996         draw_line(canvas, |  | 
| 997                   this->point(this->fIndices[i+2]), this->point(this->fIndices[i
      ]), |  | 
| 998                   SK_ColorBLACK); |  | 
| 999     } |  | 
| 1000 |  | 
| 1001     fInitialRing.draw(canvas, *this); |  | 
| 1002     for (int i = 0; i < fRings.count(); ++i) { |  | 
| 1003         fRings[i]->draw(canvas, *this); |  | 
| 1004     } |  | 
| 1005 |  | 
| 1006     for (int i = 0; i < this->numPts(); ++i) { |  | 
| 1007         draw_point(canvas, |  | 
| 1008                    this->point(i), 0.5f + (this->depth(i)/(2 * kAntialiasingRadi
      us)), |  | 
| 1009                    !this->movable(i)); |  | 
| 1010 |  | 
| 1011         SkPaint paint; |  | 
| 1012         paint.setTextSize(kPointTextSize); |  | 
| 1013         paint.setTextAlign(SkPaint::kCenter_Align); |  | 
| 1014         if (this->depth(i) <= -kAntialiasingRadius) { |  | 
| 1015             paint.setColor(SK_ColorWHITE); |  | 
| 1016         } |  | 
| 1017 |  | 
| 1018         SkString num; |  | 
| 1019         num.printf("%d", i); |  | 
| 1020         canvas->drawText(num.c_str(), num.size(), |  | 
| 1021                          this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f
      ), |  | 
| 1022                          paint); |  | 
| 1023     } |  | 
| 1024 } |  | 
| 1025 |  | 
| 1026 #endif |  | 
| 1027 |  | 
| OLD | NEW | 
|---|