diff options
-rw-r--r-- | gm/dashcircle.cpp | 78 | ||||
-rw-r--r-- | include/core/SkPathMeasure.h | 6 | ||||
-rw-r--r-- | samplecode/SampleQuadStroker.cpp | 98 | ||||
-rw-r--r-- | src/core/SkGeometry.cpp | 44 | ||||
-rw-r--r-- | src/core/SkGeometry.h | 109 | ||||
-rw-r--r-- | src/core/SkPathMeasure.cpp | 119 | ||||
-rw-r--r-- | tests/PathMeasureTest.cpp | 16 |
7 files changed, 424 insertions, 46 deletions
diff --git a/gm/dashcircle.cpp b/gm/dashcircle.cpp new file mode 100644 index 0000000000..cddd913723 --- /dev/null +++ b/gm/dashcircle.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" +#include "SkPath.h" +#include "SkDashPathEffect.h" + +int dash1[] = { 1, 1 }; +int dash2[] = { 1, 3 }; +int dash3[] = { 1, 1, 3, 3 }; +int dash4[] = { 1, 3, 2, 4 }; + +struct DashExample { + int* pattern; + int length; +} dashExamples[] = { + { dash1, SK_ARRAY_COUNT(dash1) }, + { dash2, SK_ARRAY_COUNT(dash2) }, + { dash3, SK_ARRAY_COUNT(dash3) }, + { dash4, SK_ARRAY_COUNT(dash4) } +}; + +DEF_SIMPLE_GM(dashcircle, canvas, 900, 1200) { + SkPaint refPaint; + refPaint.setAntiAlias(true); + refPaint.setColor(0xFFbf3f7f); + refPaint.setStyle(SkPaint::kStroke_Style); + refPaint.setStrokeWidth(1); + const SkScalar radius = 125; + SkRect oval = SkRect::MakeLTRB(-radius - 20, -radius - 20, radius + 20, radius + 20); + SkPath circle; + circle.addCircle(0, 0, radius); + SkScalar circumference = radius * SK_ScalarPI * 2; + int wedges[] = { 6, 12, 36 }; + canvas->translate(radius + 20, radius + 20); + for (int wedge : wedges) { + SkScalar arcLength = 360.f / wedge; + canvas->save(); + for (const DashExample& dashExample : dashExamples) { + SkPath refPath; + int dashUnits = 0; + for (int index = 0; index < dashExample.length; ++index) { + dashUnits += dashExample.pattern[index]; + } + SkScalar unitLength = arcLength / dashUnits; + SkScalar angle = 0; + for (int index = 0; index < wedge; ++index) { + for (int i2 = 0; i2 < dashExample.length; i2 += 2) { + SkScalar span = dashExample.pattern[i2] * unitLength; + refPath.moveTo(0, 0); + refPath.arcTo(oval, angle, span, false); + refPath.close(); + angle += span + (dashExample.pattern[i2 + 1]) * unitLength; + } + } + canvas->drawPath(refPath, refPaint); + SkPaint p; + p.setAntiAlias(true); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(10); + SkScalar intervals[4]; + int intervalCount = dashExample.length; + SkScalar dashLength = circumference / wedge / dashUnits; + for (int index = 0; index < dashExample.length; ++index) { + intervals[index] = dashExample.pattern[index] * dashLength; + } + p.setPathEffect(SkDashPathEffect::Create(intervals, intervalCount, 0))->unref(); + canvas->drawPath(circle, p); + canvas->translate(0, radius * 2 + 50); + } + canvas->restore(); + canvas->translate(radius * 2 + 50, 0); + } +} diff --git a/include/core/SkPathMeasure.h b/include/core/SkPathMeasure.h index 7528736ba8..415ee2709c 100644 --- a/include/core/SkPathMeasure.h +++ b/include/core/SkPathMeasure.h @@ -107,7 +107,13 @@ private: void buildSegments(); SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance, int mint, int maxt, int ptIndex); +#ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE SkScalar compute_conic_segs(const SkConic&, SkScalar distance, int mint, int maxt, int ptIndex); +#else + SkScalar compute_conic_segs(const SkConic&, SkScalar distance, + int mint, const SkPoint& minPt, + int maxt, const SkPoint& maxPt, int ptIndex); +#endif SkScalar compute_cubic_segs(const SkPoint pts[3], SkScalar distance, int mint, int maxt, int ptIndex); const Segment* distanceToSegment(SkScalar distance, SkScalar* t); diff --git a/samplecode/SampleQuadStroker.cpp b/samplecode/SampleQuadStroker.cpp index 3b029804ad..88f7dfd4ae 100644 --- a/samplecode/SampleQuadStroker.cpp +++ b/samplecode/SampleQuadStroker.cpp @@ -9,6 +9,7 @@ #include "SampleCode.h" #include "SkView.h" #include "SkCanvas.h" +#include "SkGeometry.h" #include "SkPathMeasure.h" #include "SkRandom.h" #include "SkRRect.h" @@ -122,6 +123,7 @@ class QuadStrokerView : public SampleView { bool fAnimate; bool fDrawRibs; bool fDrawTangents; + bool fDrawTDivs; #ifdef SK_DEBUG #define kStrokerErrorMin 0.001f #define kStrokerErrorMax 5 @@ -288,16 +290,84 @@ protected: SkScalar total = meas.getLength(); SkScalar delta = 8; - SkPaint paint; + SkPaint paint, labelP; paint.setColor(color); - + labelP.setColor(color & 0xff5f9f5f); SkPoint pos, tan; + int index = 0; for (SkScalar dist = 0; dist <= total; dist += delta) { if (meas.getPosTan(dist, &pos, &tan)) { tan.scale(radius); tan.rotateCCW(); canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(), pos.x() - tan.x(), pos.y() - tan.y(), paint); + if (0 == index % 10) { + SkString label; + label.appendS32(index); + SkRect dot = SkRect::MakeXYWH(pos.x() - 2, pos.y() - 2, 4, 4); + canvas->drawRect(dot, labelP); + canvas->drawText(label.c_str(), label.size(), + pos.x() - tan.x() * 1.25f, pos.y() - tan.y() * 1.25f, labelP); + } + } + ++index; + } + } + + void draw_t_divs(SkCanvas* canvas, const SkPath& path, SkScalar width, SkColor color) { + const SkScalar radius = width / 2; + SkPaint paint; + paint.setColor(color); + SkPathMeasure meas(path, false); + SkScalar total = meas.getLength(); + SkScalar delta = 8; + int ribs = 0; + for (SkScalar dist = 0; dist <= total; dist += delta) { + ++ribs; + } + SkPath::RawIter iter(path); + SkPoint pts[4]; + if (SkPath::kMove_Verb != iter.next(pts)) { + SkASSERT(0); + return; + } + SkPath::Verb verb = iter.next(pts); + SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb); + SkPoint pos, tan; + for (int index = 0; index < ribs; ++index) { + SkScalar t = (SkScalar) index / ribs; + switch (verb) { + case SkPath::kLine_Verb: + tan = pts[1] - pts[0]; + pos = pts[0]; + pos.fX += tan.fX * t; + pos.fY += tan.fY * t; + break; + case SkPath::kQuad_Verb: + pos = SkEvalQuadAt(pts, t); + tan = SkEvalQuadTangentAt(pts, t); + break; + case SkPath::kConic_Verb: { + SkConic conic(pts, iter.conicWeight()); + pos = conic.evalAt(t); + tan = conic.evalTangentAt(t); + } break; + case SkPath::kCubic_Verb: + SkEvalCubicAt(pts, t, &pos, &tan, nullptr); + break; + default: + SkASSERT(0); + return; + } + tan.setLength(radius); + tan.rotateCCW(); + canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(), + pos.x() - tan.x(), pos.y() - tan.y(), paint); + if (0 == index % 10) { + SkString label; + label.appendS32(index); + canvas->drawText(label.c_str(), label.size(), + pos.x() + tan.x() * 1.25f, pos.y() + tan.y() * 1.25f, paint); } } } @@ -343,6 +413,10 @@ protected: draw_ribs(canvas, scaled, width, 0xFF00FF00); } + if (fDrawTDivs) { + draw_t_divs(canvas, scaled, width, 0xFF3F3F00); + } + SkPath fill; SkPaint p; @@ -428,17 +502,24 @@ protected: void setForGeometry() { fDrawRibs = true; fDrawTangents = true; + fDrawTDivs = false; fWidthScale = 1; } void setForText() { - fDrawRibs = fDrawTangents = false; + fDrawRibs = fDrawTangents = fDrawTDivs = false; fWidthScale = 0.002f; } + void setForSingles() { + setForGeometry(); + fDrawTDivs = true; + } + void setAsNeeded() { - if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled - || fRRectButton.fEnabled || fCircleButton.fEnabled) { + if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled) { + setForSingles(); + } else if (fRRectButton.fEnabled || fCircleButton.fEnabled) { setForGeometry(); } else { setForText(); @@ -452,14 +533,15 @@ protected: if (fCubicButton.fEnabled) { path.moveTo(fPts[0]); path.cubicTo(fPts[1], fPts[2], fPts[3]); - setForGeometry(); + setForSingles(); draw_stroke(canvas, path, width, 950, false); } if (fConicButton.fEnabled) { + path.reset(); path.moveTo(fPts[4]); path.conicTo(fPts[5], fPts[6], fWeight); - setForGeometry(); + setForSingles(); draw_stroke(canvas, path, width, 950, false); } @@ -467,7 +549,7 @@ protected: path.reset(); path.moveTo(fPts[7]); path.quadTo(fPts[8], fPts[9]); - setForGeometry(); + setForSingles(); draw_stroke(canvas, path, width, 950, false); } diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp index c25e18641a..2ea3095198 100644 --- a/src/core/SkGeometry.cpp +++ b/src/core/SkGeometry.cpp @@ -9,18 +9,6 @@ #include "SkMatrix.h" #include "SkNx.h" -#if 0 -static Sk2s from_point(const SkPoint& point) { - return Sk2s::Load(&point.fX); -} - -static SkPoint to_point(const Sk2s& x) { - SkPoint point; - x.store(&point.fX); - return point; -} -#endif - static SkVector to_vector(const Sk2s& x) { SkVector vector; x.store(&vector.fX); @@ -220,7 +208,7 @@ void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t) { } void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]) { - SkChopQuadAt(src, dst, 0.5f); return; + SkChopQuadAt(src, dst, 0.5f); } /** Quad'(t) = At + B, where @@ -1246,8 +1234,34 @@ void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { dst[1].fW = tmp2[2].fZ / root; } -static Sk2s times_2(const Sk2s& value) { - return value + value; +void SkConic::chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const { + if (0 == t1 || 1 == t2) { + if (0 == t1 && 1 == t2) { + *dst = *this; + } else { + SkConic pair[2]; + this->chopAt(t1 ? t1 : t2, pair); + *dst = pair[SkToBool(t1)]; + } + return; + } + SkConicCoeff coeff(*this); + Sk2s tt1(t1); + Sk2s aXY = coeff.fNumer.eval(tt1); + Sk2s aZZ = coeff.fDenom.eval(tt1); + Sk2s midTT((t1 + t2) / 2); + Sk2s dXY = coeff.fNumer.eval(midTT); + Sk2s dZZ = coeff.fDenom.eval(midTT); + Sk2s tt2(t2); + Sk2s cXY = coeff.fNumer.eval(tt2); + Sk2s cZZ = coeff.fDenom.eval(tt2); + Sk2s bXY = times_2(dXY) - (aXY + cXY) * Sk2s(0.5f); + Sk2s bZZ = times_2(dZZ) - (aZZ + cZZ) * Sk2s(0.5f); + dst->fPts[0] = to_point(aXY / aZZ); + dst->fPts[1] = to_point(bXY / bZZ); + dst->fPts[2] = to_point(cXY / cZZ); + Sk2s ww = bZZ / (aZZ * cZZ).sqrt(); + dst->fW = ww.kth<0>(); } SkPoint SkConic::evalAt(SkScalar t) const { diff --git a/src/core/SkGeometry.h b/src/core/SkGeometry.h index 79cad2eee0..0fd5a61711 100644 --- a/src/core/SkGeometry.h +++ b/src/core/SkGeometry.h @@ -23,7 +23,11 @@ static inline SkPoint to_point(const Sk2s& x) { static inline Sk2s sk2s_cubic_eval(const Sk2s& A, const Sk2s& B, const Sk2s& C, const Sk2s& D, const Sk2s& t) { - return ((A * t + B) * t + C) * t + D; + return ((A * t + B) * t + C) * t + D; +} + +static Sk2s times_2(const Sk2s& value) { + return value + value; } /** Given a quadratic equation Ax^2 + Bx + C = 0, return 0, 1, 2 roots for the @@ -42,10 +46,10 @@ SkPoint SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t); void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent = nullptr); /** - * output is : eval(t) == coeff[0] * t^2 + coeff[1] * t + coeff[2] - */ + * output is : eval(t) == coeff[0] * t^2 + coeff[1] * t + coeff[2] + */ void SkQuadToCoeff(const SkPoint pts[3], SkPoint coeff[3]); - + /** * output is : eval(t) == coeff[0] * t^3 + coeff[1] * t^2 + coeff[2] * t + coeff[3] */ @@ -241,6 +245,7 @@ struct SkConic { */ void evalAt(SkScalar t, SkPoint* pos, SkVector* tangent = nullptr) const; void chopAt(SkScalar t, SkConic dst[2]) const; + void chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const; void chop(SkConic dst[2]) const; SkPoint evalAt(SkScalar t) const; @@ -287,6 +292,102 @@ struct SkConic { const SkMatrix*, SkConic conics[kMaxConicsForArc]); }; +// inline helpers are contained in a namespace to avoid external leakage to fragile SkNx members +namespace { + +/** + * use for : eval(t) == A * t^2 + B * t + C + */ +struct SkQuadCoeff { + SkQuadCoeff() {} + + SkQuadCoeff(const Sk2s& A, const Sk2s& B, const Sk2s& C) + : fA(A) + , fB(B) + , fC(C) + { + } + + SkQuadCoeff(const SkPoint src[3]) { + fC = from_point(src[0]); + Sk2s P1 = from_point(src[1]); + Sk2s P2 = from_point(src[2]); + fB = times_2(P1 - fC); + fA = P2 - times_2(P1) + fC; + } + + Sk2s eval(SkScalar t) { + Sk2s tt(t); + return eval(tt); + } + + Sk2s eval(const Sk2s& tt) { + return (fA * tt + fB) * tt + fC; + } + + Sk2s fA; + Sk2s fB; + Sk2s fC; +}; + +struct SkConicCoeff { + SkConicCoeff(const SkConic& conic) { + Sk2s p0 = from_point(conic.fPts[0]); + Sk2s p1 = from_point(conic.fPts[1]); + Sk2s p2 = from_point(conic.fPts[2]); + Sk2s ww(conic.fW); + + Sk2s p1w = p1 * ww; + fNumer.fC = p0; + fNumer.fA = p2 - times_2(p1w) + p0; + fNumer.fB = times_2(p1w - p0); + + fDenom.fC = Sk2s(1); + fDenom.fB = times_2(ww - fDenom.fC); + fDenom.fA = Sk2s(0) - fDenom.fB; + } + + Sk2s eval(SkScalar t) { + Sk2s tt(t); + Sk2s numer = fNumer.eval(tt); + Sk2s denom = fDenom.eval(tt); + return numer / denom; + } + + SkQuadCoeff fNumer; + SkQuadCoeff fDenom; +}; + +struct SkCubicCoeff { + SkCubicCoeff(const SkPoint src[4]) { + Sk2s P0 = from_point(src[0]); + Sk2s P1 = from_point(src[1]); + Sk2s P2 = from_point(src[2]); + Sk2s P3 = from_point(src[3]); + Sk2s three(3); + fA = P3 + three * (P1 - P2) - P0; + fB = three * (P2 - times_2(P1) + P0); + fC = three * (P1 - P0); + fD = P0; + } + + Sk2s eval(SkScalar t) { + Sk2s tt(t); + return eval(tt); + } + + Sk2s eval(const Sk2s& t) { + return ((fA * t + fB) * t + fC) * t + fD; + } + + Sk2s fA; + Sk2s fB; + Sk2s fC; + Sk2s fD; +}; + +} + #include "SkTemplates.h" /** diff --git a/src/core/SkPathMeasure.cpp b/src/core/SkPathMeasure.cpp index eb80cf3b83..bc5350373c 100644 --- a/src/core/SkPathMeasure.cpp +++ b/src/core/SkPathMeasure.cpp @@ -73,6 +73,15 @@ static bool quad_too_curvy(const SkPoint pts[3]) { return dist > CHEAP_DIST_LIMIT; } +static bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt, + const SkPoint& lastPt) { + SkPoint midEnds = firstPt + lastPt; + midEnds *= 0.5f; + SkVector dxy = midTPt - midEnds; + SkScalar dist = SkMaxScalar(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY)); + return dist > CHEAP_DIST_LIMIT; +} + static bool cheap_dist_exceeds_limit(const SkPoint& pt, SkScalar x, SkScalar y) { SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY)); @@ -90,28 +99,58 @@ static bool cubic_too_curvy(const SkPoint pts[4]) { SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3)); } +static SkScalar quad_folded_len(const SkPoint pts[3]) { + SkScalar t = SkFindQuadMaxCurvature(pts); + SkPoint pt = SkEvalQuadAt(pts, t); + SkVector a = pts[2] - pt; + SkScalar result = a.length(); + if (0 != t) { + SkVector b = pts[0] - pt; + result += b.length(); + } + SkASSERT(SkScalarIsFinite(result)); + return result; +} + /* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */ +/* This works -- more needs to be done to see if it is performant on all platforms. + To use this to measure parts of quads requires recomputing everything -- perhaps + a chop-like interface can start from a larger measurement and get two new measurements + with one call here. + */ static SkScalar compute_quad_len(const SkPoint pts[3]) { - SkPoint a,b; - a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; - a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; - b.fX = 2 * (pts[1].fX - pts[0].fX); - b.fY = 2 * (pts[1].fY - pts[0].fY); - SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); - SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); - SkScalar C = b.fX * b.fX + b.fY * b.fY; - - SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); - SkScalar A_2 = SkScalarSqrt(A); - SkScalar A_32 = 2 * A * A_2; - SkScalar C_2 = 2 * SkScalarSqrt(C); - SkScalar BA = B / A_2; - - return (A_32 * Sabc + A_2 * B * (Sabc - C_2) + - (4 * C * A - B * B) * SkScalarLog((2 * A_2 + BA + Sabc) / (BA + C_2))) / (4 * A_32); + SkPoint a,b; + a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; + a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; + SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); + if (0 == A) { + a = pts[2] - pts[0]; + return a.length(); + } + b.fX = 2 * (pts[1].fX - pts[0].fX); + b.fY = 2 * (pts[1].fY - pts[0].fY); + SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); + SkScalar C = b.fX * b.fX + b.fY * b.fY; + SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); + SkScalar A_2 = SkScalarSqrt(A); + SkScalar A_32 = 2 * A * A_2; + SkScalar C_2 = 2 * SkScalarSqrt(C); + SkScalar BA = B / A_2; + if (0 == BA + C_2) { + return quad_folded_len(pts); + } + SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2); + SkScalar K = 4 * C * A - B * B; + SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2); + if (L <= 0) { + return quad_folded_len(pts); + } + SkScalar M = SkScalarLog(L); + SkScalar result = (J + K * M) / (4 * A_32); + SkASSERT(SkScalarIsFinite(result)); + return result; } - SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], SkScalar distance, int mint, int maxt, int ptIndex) { if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) { @@ -136,6 +175,7 @@ SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], return distance; } +#ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distance, int mint, int maxt, int ptIndex) { if (tspan_big_enough(maxt - mint) && quad_too_curvy(conic.fPts)) { @@ -159,6 +199,30 @@ SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, } return distance; } +#else +SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distance, + int mint, const SkPoint& minPt, + int maxt, const SkPoint& maxPt, int ptIndex) { + int halft = (mint + maxt) >> 1; + SkPoint halfPt = conic.evalAt(tValue2Scalar(halft)); + if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt)) { + distance = this->compute_conic_segs(conic, distance, mint, minPt, halft, halfPt, ptIndex); + distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt, maxPt, ptIndex); + } else { + SkScalar d = SkPoint::Distance(minPt, maxPt); + SkScalar prevD = distance; + distance += d; + if (distance > prevD) { + Segment* seg = fSegments.append(); + seg->fDistance = distance; + seg->fPtIndex = ptIndex; + seg->fType = kConic_SegType; + seg->fTValue = maxt; + } + } + return distance; +} +#endif SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], SkScalar distance, int mint, int maxt, int ptIndex) { @@ -253,7 +317,12 @@ void SkPathMeasure::buildSegments() { case SkPath::kConic_Verb: { const SkConic conic(pts, fIter.conicWeight()); SkScalar prevD = distance; +#ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE distance = this->compute_conic_segs(conic, distance, 0, kMaxTValue, ptIndex); +#else + distance = this->compute_conic_segs(conic, distance, 0, conic.fPts[0], + kMaxTValue, conic.fPts[2], ptIndex); +#endif if (distance > prevD) { // we store the conic weight in our next point, followed by the last 2 pts // thus to reconstitue a conic, you'd need to say @@ -406,7 +475,8 @@ static void seg_to(const SkPoint pts[], int segType, dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); } } else { - SkConic tmp1[2]; +#ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE + SkConic tmp1[2]; conic.chopAt(startT, tmp1); if (SK_Scalar1 == stopT) { dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); @@ -415,6 +485,17 @@ static void seg_to(const SkPoint pts[], int segType, tmp1[1].chopAt((stopT - startT) / (SK_Scalar1 - startT), tmp2); dst->conicTo(tmp2[0].fPts[1], tmp2[0].fPts[2], tmp2[0].fW); } +#else + if (SK_Scalar1 == stopT) { + SkConic tmp1[2]; + conic.chopAt(startT, tmp1); + dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); + } else { + SkConic tmp; + conic.chopAt(startT, stopT, &tmp); + dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW); + } +#endif } } break; case kCubic_SegType: diff --git a/tests/PathMeasureTest.cpp b/tests/PathMeasureTest.cpp index 578f4eb74f..df66578f1b 100644 --- a/tests/PathMeasureTest.cpp +++ b/tests/PathMeasureTest.cpp @@ -201,3 +201,19 @@ DEF_TEST(PathMeasure, reporter) { test_small_segment2(); test_small_segment3(); } + +DEF_TEST(PathMeasureConic, reporter) { + SkPoint stdP, hiP, pts[] = {{0,0}, {100,0}, {100,0}}; + SkPath p; + p.moveTo(0, 0); + p.conicTo(pts[1], pts[2], 1); + SkPathMeasure stdm(p, false); + REPORTER_ASSERT(reporter, stdm.getPosTan(20, &stdP, nullptr)); + p.reset(); + p.moveTo(0, 0); + p.conicTo(pts[1], pts[2], 10); + stdm.setPath(&p, false); + REPORTER_ASSERT(reporter, stdm.getPosTan(20, &hiP, nullptr)); + REPORTER_ASSERT(reporter, 19.5f < stdP.fX && stdP.fX < 20.5f); + REPORTER_ASSERT(reporter, 19.5f < hiP.fX && hiP.fX < 20.5f); +} |