52 *t = (v.
fX * n1.
fY - v.
fY * n1.
fX) / perpDot;
66 *t = v.
dot(perp) / perpDot;
76 const SkPoint& c,
float* accumError) {
83 if (*accumError + distBToLineAC >=
kClose || aToC.
dot(
b -
a) <= 0.f || aToC.
dot(c -
b) <= 0.f) {
89 *accumError += distBToLineAC;
94int GrAAConvexTessellator::addPt(
const SkPoint& pt,
105 *fMovable.
append() = movable;
106 *fCurveState.
append() = curve;
112void GrAAConvexTessellator::popLastPt() {
123void GrAAConvexTessellator::popFirstPtShuffle() {
134void GrAAConvexTessellator::updatePt(
int index,
145void GrAAConvexTessellator::addTri(
int i0,
int i1,
int i2) {
146 if (i0 == i1 || i1 == i2 || i2 == i0) {
162 fInitialRing.rewind();
163 fCandidateVerts.rewind();
164#if GR_AA_CONVEX_TESSELLATOR_VIZ
172void GrAAConvexTessellator::computeNormals() {
173 auto normalToVector = [
this](
SkVector v) {
181 fNorms.append(fPts.
size());
182 fNorms[0] = fPts[1] - fPts[0];
183 fNorms.back() =
fPts[0] -
fPts.back();
186 fNorms[0] = normalToVector(fNorms[0]);
187 for (
int cur = 1; cur < fNorms.size() - 1; ++cur) {
188 fNorms[cur] = normalToVector(fPts[cur + 1] - fPts[cur]);
190 fNorms.back() = normalToVector(fNorms.back());
193void GrAAConvexTessellator::computeBisectors() {
194 fBisectors.resize(fNorms.size());
196 int prev = fBisectors.size() - 1;
197 for (
int cur = 0; cur < fBisectors.size();
prev = cur, ++cur) {
198 fBisectors[cur] = fNorms[cur] + fNorms[
prev];
204 fBisectors[cur].negate();
206 if (fCurveState[
prev] == kIndeterminate_CurveState) {
207 if (fCurveState[cur] == kSharp_CurveState) {
208 fCurveState[
prev] = kSharp_CurveState;
211 fCurveState[
prev] = kCurve_CurveState;
212 fCurveState[cur] = kCurve_CurveState;
214 fCurveState[
prev] = kSharp_CurveState;
215 fCurveState[cur] = kSharp_CurveState;
226bool GrAAConvexTessellator::createInsetRings(Ring& previousRing,
SkScalar initialDepth,
228 SkScalar targetCoverage, Ring** finalRing) {
229 static const int kMaxNumRings = 8;
231 if (previousRing.numPts() < 3) {
234 Ring* currentRing = &previousRing;
236 for (
i = 0;
i < kMaxNumRings; ++
i) {
237 Ring* nextRing = this->getNextRing(currentRing);
240 bool done = this->createInsetRing(*currentRing, nextRing, initialDepth, initialCoverage,
241 targetDepth, targetCoverage,
i == 0);
242 currentRing = nextRing;
246 currentRing->init(*
this);
249 if (kMaxNumRings ==
i) {
251 this->terminate(*currentRing);
254 bool done = currentRing->numPts() >= 3;
256 currentRing->init(*
this);
258 *finalRing = currentRing;
269 if (!this->extractFromPath(
m,
path)) {
278 scaleFactor =
m.getMaxScale();
279 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth;
280 Ring outerStrokeAndAARing;
281 this->createOuterRing(fInitialRing,
283 &outerStrokeAndAARing);
288 outerStrokeAndAARing.init(*
this);
290 outerStrokeAndAARing.makeOriginalRing();
294 fNorms.resize(
fNorms.size() + outerStrokeAndAARing.numPts());
295 for (
int i = 0;
i < outerStrokeAndAARing.numPts(); ++
i) {
297 fNorms[outerStrokeAndAARing.index(
i)] = outerStrokeAndAARing.norm(
i);
304 this->createInsetRings(outerStrokeAndAARing,
315 scaleFactor =
m.getMaxScale();
316 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth;
317 Ring outerStrokeRing;
320 outerStrokeRing.init(*
this);
332 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth;
333 Ring* insetStrokeRing;
335 if (this->createInsetRings(fInitialRing, 0.0f,
coverage, strokeDepth,
coverage,
338 this->createInsetRings(*insetStrokeRing, strokeDepth,
coverage, strokeDepth +
350SkScalar GrAAConvexTessellator::computeDepthFromEdge(
int edgeIdx,
const SkPoint&
p)
const {
360bool GrAAConvexTessellator::computePtAlongBisector(
int startIdx,
371 if (!
perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm, &t)) {
377 newP =
fPts[startIdx];
378 }
else if (t < 0.0f) {
381 newP +=
fPts[startIdx];
388 t = -desiredDepth /
dot;
410 this->reservePts(5*
path.countPoints());
417 fAccumLinearError = 0.f;
422 while (
auto e = iter.next()) {
426 this->lineTo(
m,
e.fPts[1], kSharp_CurveState);
431 this->quadTo(
m,
e.fPts);
436 this->cubicTo(
m,
e.fPts);
441 this->conicTo(
m,
e.fPts, iter.conicWeight());
457 fAccumLinearError = 0.f;
458 bool noRemovalsToDo =
false;
459 while (!noRemovalsToDo && this->
numPts() >= 3) {
461 &fAccumLinearError)) {
464 &fAccumLinearError)) {
465 this->popFirstPtShuffle();
467 noRemovalsToDo =
true;
473 if (this->
numPts() >= 3) {
474 this->computeNormals();
475 this->computeBisectors();
476 }
else if (this->
numPts() == 2) {
497 fCandidateVerts.setReserve(this->
numPts());
498 fInitialRing.setReserve(this->
numPts());
499 for (
int i = 0;
i < this->
numPts(); ++
i) {
500 fInitialRing.addIdx(
i,
i);
502 fInitialRing.init(fNorms, fBisectors);
508GrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) {
509#if GR_AA_CONVEX_TESSELLATOR_VIZ
510 Ring* ring = *fRings.push() =
new Ring;
511 ring->setReserve(fInitialRing.numPts());
516 int nextRing = (lastRing == &fRings[0]) ? 1 : 0;
517 fRings[nextRing].setReserve(fInitialRing.numPts());
518 fRings[nextRing].rewind();
519 return &fRings[nextRing];
523void GrAAConvexTessellator::fanRing(
const Ring& ring) {
525 int startIdx = ring.index(0);
526 for (
int cur = ring.numPts() - 2; cur >= 0; --cur) {
527 this->addTri(startIdx, ring.index(cur), ring.index(cur + 1));
531void GrAAConvexTessellator::createOuterRing(
const Ring& previousRing,
SkScalar outset,
533 const int numPts = previousRing.numPts();
539 int lastPerpIdx = -1, firstPerpIdx = -1;
543 miterLimitSq = miterLimitSq * miterLimitSq;
544 for (
int cur = 0; cur <
numPts; ++cur) {
545 int originalIdx = previousRing.index(cur);
555 perp1 += this->
point(originalIdx);
558 SkPoint normal2 = previousRing.norm(cur);
561 perp2 +=
fPts[originalIdx];
563 CurveState curve = fCurveState[originalIdx];
567 int perp1Idx = this->addPt(perp1, -
outset,
coverage,
false, curve);
568 nextRing->addIdx(perp1Idx, originalIdx);
578 if (perp2Idx != perp1Idx) {
579 if (curve == kCurve_CurveState) {
587 SkPoint miter = previousRing.bisector(cur);
589 miter +=
fPts[originalIdx];
594 miterIdx = this->addPt(miter, -
outset,
coverage,
false, kSharp_CurveState);
595 nextRing->addIdx(miterIdx, originalIdx);
597 this->addTri(originalIdx, perp1Idx, miterIdx);
598 this->addTri(originalIdx, miterIdx, perp2Idx);
601 this->addTri(originalIdx, perp1Idx, perp2Idx);
605 case SkPaint::Join::kMiter_Join: {
607 SkPoint miter = previousRing.bisector(cur);
613 if (lengthSq > miterLimitSq) {
615 this->addTri(originalIdx, perp1Idx, perp2Idx);
619 miter +=
fPts[originalIdx];
626 nextRing->addIdx(miterIdx, originalIdx);
628 this->addTri(originalIdx, perp1Idx, miterIdx);
629 this->addTri(originalIdx, miterIdx, perp2Idx);
633 this->addTri(originalIdx, perp1Idx, perp2Idx);
637 case SkPaint::Join::kBevel_Join:
638 this->addTri(originalIdx, perp1Idx, perp2Idx);
647 nextRing->addIdx(perp2Idx, originalIdx);
652 firstPerpIdx = perp1Idx;
656 int prevIdx = previousRing.index(
prev);
657 this->addTri(prevIdx, perp1Idx, originalIdx);
658 this->addTri(prevIdx, lastPerpIdx, perp1Idx);
663 lastPerpIdx = perp2Idx;
668 int lastIdx = previousRing.index(
numPts - 1);
669 this->addTri(lastIdx, firstPerpIdx, previousRing.index(0));
670 this->addTri(lastIdx, lastPerpIdx, firstPerpIdx);
677void GrAAConvexTessellator::terminate(
const Ring& ring) {
686 return targetCoverage;
688 SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) *
689 (targetCoverage - initialCoverage) + initialCoverage;
694bool GrAAConvexTessellator::createInsetRing(
const Ring& lastRing, Ring* nextRing,
700 fCandidateVerts.rewind();
706 for (
int cur = 0; cur < lastRing.numPts(); ++cur) {
707 int next = (cur + 1) % lastRing.numPts();
711 this->point(lastRing.index(
next)), lastRing.bisector(
next),
718 SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur));
720 if (minDist > dist) {
727 if (minEdgeIdx == -1) {
730 SkPoint newPt = lastRing.bisector(minEdgeIdx);
732 newPt += this->
point(lastRing.index(minEdgeIdx));
734 SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx), newPt);
735 if (depth >= targetDepth) {
745 dst.resize(lastRing.numPts());
748 if (!this->computePtAlongBisector(lastRing.index(0),
749 lastRing.bisector(0),
750 lastRing.origEdgeID(0),
752 this->terminate(lastRing);
755 dst[0] = fCandidateVerts.addNewPt(newPt,
756 lastRing.index(0), lastRing.origEdgeID(0),
757 !this->movable(lastRing.index(0)));
760 for (
int cur = 1; cur < lastRing.numPts()-1; ++cur) {
761 if (!this->computePtAlongBisector(lastRing.index(cur),
762 lastRing.bisector(cur),
763 lastRing.origEdgeID(cur),
765 this->terminate(lastRing);
768 if (!
duplicate_pt(newPt, fCandidateVerts.lastPoint())) {
769 dst[cur] = fCandidateVerts.addNewPt(newPt,
770 lastRing.index(cur), lastRing.origEdgeID(cur),
771 !this->movable(lastRing.index(cur)));
773 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
778 int cur = lastRing.numPts()-1;
779 if (!this->computePtAlongBisector(lastRing.index(cur),
780 lastRing.bisector(cur),
781 lastRing.origEdgeID(cur),
783 this->terminate(lastRing);
786 bool dupPrev =
duplicate_pt(newPt, fCandidateVerts.lastPoint());
787 bool dupNext =
duplicate_pt(newPt, fCandidateVerts.firstPoint());
789 if (!dupPrev && !dupNext) {
790 dst[cur] = fCandidateVerts.addNewPt(newPt,
791 lastRing.index(cur), lastRing.origEdgeID(cur),
792 !this->movable(lastRing.index(cur)));
793 }
else if (dupPrev && !dupNext) {
794 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
795 }
else if (!dupPrev && dupNext) {
796 dst[cur] = fCandidateVerts.fuseWithNext();
798 bool dupPrevVsNext =
duplicate_pt(fCandidateVerts.firstPoint(), fCandidateVerts.lastPoint());
800 if (!dupPrevVsNext) {
801 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
803 const int fused = fCandidateVerts.fuseWithBoth();
805 const int targetIdx =
dst[cur - 1];
806 for (
int i = cur - 1;
i >= 0 &&
dst[
i] == targetIdx;
i--) {
813 for (
int i = 0;
i < fCandidateVerts.numPts(); ++
i) {
815 if (fCandidateVerts.needsToBeNew(
i) || forceNew) {
819 targetDepth, targetCoverage);
820 newIdx = this->addPt(fCandidateVerts.point(
i), depth,
coverage,
821 fCandidateVerts.originatingIdx(
i) != -1, kSharp_CurveState);
823 SkASSERT(fCandidateVerts.originatingIdx(
i) != -1);
824 this->updatePt(fCandidateVerts.originatingIdx(
i), fCandidateVerts.point(
i), depth,
826 newIdx = fCandidateVerts.originatingIdx(
i);
829 nextRing->addIdx(newIdx, fCandidateVerts.origEdge(
i));
834 for (
int i = 0;
i <
dst.size(); ++
i) {
838 for (
int i = 0;
i < lastRing.numPts(); ++
i) {
839 int next = (
i + 1) % lastRing.numPts();
841 this->addTri(lastRing.index(
i), lastRing.index(
next),
dst[
next]);
847 this->fanRing(*nextRing);
850 if (nextRing->numPts() < 3) {
856void GrAAConvexTessellator::validate()
const {
861 SkASSERT(fBisectors.empty() || fBisectors.size() ==
fNorms.size());
866 this->computeNormals(
tess);
867 this->computeBisectors(
tess);
872 for (
int i = 0;
i <
fPts.size(); ++
i) {
874 fPts[
i].fBisector = bisectors[
i];
880 for (
int cur = 0; cur <
fPts.size(); ++cur) {
891 for (
int cur = 0; cur <
fPts.size();
prev = cur, ++cur) {
894 fPts[cur].fBisector =
908 if (
fPts.size() < 3) {
918 for (
int i = 1;
i <
fPts.size(); ++
i) {
936 return (maxDot >= 0.0f) == (minDot >= 0.0f);
941void GrAAConvexTessellator::lineTo(
const SkPoint&
p, CurveState curve) {
946 if (this->
numPts() >= 2 &&
948 &fAccumLinearError)) {
959 fAccumLinearError = 0.f;
962 this->addPt(
p, 0.0f, initialRingCoverage,
false, curve);
965void GrAAConvexTessellator::lineTo(
const SkMatrix&
m,
const SkPoint&
p, CurveState curve) {
966 this->lineTo(
m.mapXY(
p.fX,
p.fY), curve);
969void GrAAConvexTessellator::quadTo(
const SkPoint pts[3]) {
971 fPointBuffer.
resize(maxCount);
976 for (
int i = 0;
i <
count - 1;
i++) {
977 this->lineTo(fPointBuffer[
i], kCurve_CurveState);
979 this->lineTo(fPointBuffer[
count - 1],
980 count == 1 ? kSharp_CurveState : kIndeterminate_CurveState);
983void GrAAConvexTessellator::quadTo(
const SkMatrix&
m,
const SkPoint srcPts[3]) {
985 m.mapPoints(pts, srcPts, 3);
989void GrAAConvexTessellator::cubicTo(
const SkMatrix&
m,
const SkPoint srcPts[4]) {
991 m.mapPoints(pts, srcPts, 4);
993 fPointBuffer.
resize(maxCount);
998 for (
int i = 0;
i <
count - 1;
i++) {
999 this->lineTo(fPointBuffer[
i], kCurve_CurveState);
1001 this->lineTo(fPointBuffer[
count - 1],
1002 count == 1 ? kSharp_CurveState : kIndeterminate_CurveState);
1010 m.mapPoints(pts, srcPts, 3);
1018 quadPts[1] = quads[0];
1019 quadPts[2] =
i ==
count - 1 ? pts[2] : quads[1];
1020 this->quadTo(quadPts);
1027#if GR_AA_CONVEX_TESSELLATOR_VIZ
1028static const SkScalar kPointRadius = 0.02f;
1029static const SkScalar kArrowStrokeWidth = 0.0f;
1030static const SkScalar kArrowLength = 0.2f;
1031static const SkScalar kEdgeTextSize = 0.1f;
1032static const SkScalar kPointTextSize = 0.02f;
1037 int gs =
int(255*paramValue);
1038 paint.setARGB(255, gs, gs, gs);
1046 stroke.setStrokeWidth(kPointRadius/3.0f);
1062 paint.setStrokeWidth(kArrowStrokeWidth);
1072 paint.setTextSize(kEdgeTextSize);
1074 for (
int cur = 0; cur <
fPts.count(); ++cur) {
1075 int next = (cur + 1) %
fPts.count();
1087 mid.
fX += (kArrowLength/2) *
fPts[cur].fNorm.
fX;
1088 mid.
fY += (kArrowLength/2) *
fPts[cur].fNorm.
fY;
1092 num.
printf(
"%d", this->origEdgeID(cur));
1096 draw_arrow(canvas,
tess.point(
fPts[cur].fIndex),
fPts[cur].fBisector,
1103 for (
int i = 0;
i < fIndices.count();
i += 3) {
1109 this->
point(this->fIndices[
i]), this->
point(this->fIndices[
i+1]),
1112 this->
point(this->fIndices[
i+1]), this->
point(this->fIndices[
i+2]),
1115 this->
point(this->fIndices[
i+2]), this->
point(this->fIndices[
i]),
1119 fInitialRing.draw(canvas, *
this);
1120 for (
int i = 0;
i < fRings.count(); ++
i) {
1121 fRings[
i]->draw(canvas, *
this);
1124 for (
int i = 0;
i < this->
numPts(); ++
i) {
1130 paint.setTextSize(kPointTextSize);
1138 this->
point(i).fX, this->
point(i).fY+(kPointRadius/2.0f),
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
static bool duplicate_pt(const SkPoint &p0, const SkPoint &p1)
static constexpr SkScalar kCurveConnectionThreshold
static bool intersect(const SkPoint &p0, const SkPoint &n0, const SkPoint &p1, const SkPoint &n1, SkScalar *t)
static SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth, SkScalar targetCoverage)
static constexpr SkScalar kConicTolerance
static constexpr SkScalar kRoundCapThreshold
static constexpr SkScalar kClose
static constexpr SkScalar kQuadTolerance
static constexpr SkScalar kQuadToleranceSqd
static constexpr SkScalar kCubicToleranceSqd
static bool perp_intersect(const SkPoint &p0, const SkPoint &n0, const SkPoint &p1, const SkPoint &perp, SkScalar *t)
static constexpr SkScalar kCubicTolerance
static bool points_are_colinear_and_b_is_middle(const SkPoint &a, const SkPoint &b, const SkPoint &c, float *accumError)
static constexpr SkScalar kCloseSqd
static const SkScalar kAntialiasingRadius
static float next(float f)
static float prev(float f)
constexpr SkColor SK_ColorYELLOW
constexpr SkColor SK_ColorBLUE
constexpr SkColor SK_ColorRED
constexpr SkColor SK_ColorBLACK
constexpr SkColor SK_ColorGREEN
constexpr SkColor SK_ColorWHITE
static bool SkIsFinite(T x, Pack... values)
static constexpr float sk_ieee_float_divide(float numer, float denom)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
bool tessellate(const SkMatrix &m, const SkPath &path)
const SkPoint & lastPoint() const
SkScalar coverage(int index) const
const SkPoint & point(int index) const
int index(int index) const
const SkPoint * computeQuads(const SkConic &conic, SkScalar tol)
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
@ kStroke_Style
set to stroke geometry
static bool AllPointsEq(const SkPoint pts[], int count)
static SkPoint MakeOrthog(const SkPoint &vec, Side side=kLeft_Side)
static SkScalar DistanceToSqd(const SkPoint &pt, const SkPoint &a)
void printf(const char format[],...) SK_PRINTF_LIKE(2
void removeShuffle(int index)
static float max(float r, float g, float b)
static float min(float r, float g, float b)
static void draw_line(SkCanvas *canvas, SkImage *, const SkRect &r, sk_sp< SkImageFilter > imf)
uint32_t generateCubicPoints(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2, const SkPoint &p3, SkScalar tolSqd, SkPoint **points, uint32_t pointsLeft)
uint32_t quadraticPointCount(const SkPoint points[], SkScalar tol)
uint32_t cubicPointCount(const SkPoint points[], SkScalar tol)
uint32_t generateQuadraticPoints(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2, SkScalar tolSqd, SkPoint **points, uint32_t pointsLeft)
Optional< SkRect > bounds
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
static TessellatorLibtess tess
int64_t cross(Point d0, Point d1)
SINT T dot(const Vec< N, T > &a, const Vec< N, T > &b)
SIN Vec< N, float > normalize(const Vec< N, float > &v)
static float CrossProduct(const SkVector &a, const SkVector &b)
bool setLength(float length)
static float Normalize(SkVector *vec)
float dot(const SkVector &vec) const
static constexpr SkPoint Make(float x, float y)
void scale(float scale, SkPoint *dst) const