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