From aec251012542e971100e218bf463adbfb5d21d20 Mon Sep 17 00:00:00 2001 From: caryclark Date: Wed, 29 Apr 2015 08:28:30 -0700 Subject: minor fixes to cubics code and overall alignment of how bounds and tops are computed for all curve types All but 17 extended tests work. A helper function is privately added to SkPath.h to permit a test to modify a given point in a path. BUG=skia:3588 Review URL: https://codereview.chromium.org/1107353004 --- src/pathops/SkDCubicLineIntersection.cpp | 6 +- src/pathops/SkOpContour.cpp | 4 +- src/pathops/SkOpContour.h | 2 +- src/pathops/SkOpSegment.cpp | 33 ++++--- src/pathops/SkOpSegment.h | 16 +++- src/pathops/SkPathOpsBounds.cpp | 51 ----------- src/pathops/SkPathOpsBounds.h | 23 ++--- src/pathops/SkPathOpsCommon.cpp | 6 +- src/pathops/SkPathOpsCommon.h | 2 +- src/pathops/SkPathOpsConic.cpp | 22 ----- src/pathops/SkPathOpsConic.h | 6 +- src/pathops/SkPathOpsCubic.cpp | 89 +++++++++---------- src/pathops/SkPathOpsCubic.h | 6 +- src/pathops/SkPathOpsCurve.cpp | 146 +++++++++++++++++++++++++++++++ src/pathops/SkPathOpsCurve.h | 53 +++++------ src/pathops/SkPathOpsDebug.h | 10 +-- src/pathops/SkPathOpsOp.cpp | 4 +- src/pathops/SkPathOpsQuad.cpp | 31 ++----- src/pathops/SkPathOpsQuad.h | 4 +- src/pathops/SkPathOpsRect.cpp | 61 +++++++------ src/pathops/SkPathOpsRect.h | 20 ++++- src/pathops/SkPathOpsSimplify.cpp | 4 +- 22 files changed, 330 insertions(+), 269 deletions(-) delete mode 100644 src/pathops/SkPathOpsBounds.cpp create mode 100644 src/pathops/SkPathOpsCurve.cpp (limited to 'src/pathops') diff --git a/src/pathops/SkDCubicLineIntersection.cpp b/src/pathops/SkDCubicLineIntersection.cpp index f5fe01503b..f658b09f0b 100644 --- a/src/pathops/SkDCubicLineIntersection.cpp +++ b/src/pathops/SkDCubicLineIntersection.cpp @@ -135,7 +135,7 @@ public: + (fCubic[n].fX - fLine[0].fX) * adj; } double extremeTs[6]; - int extrema = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c[3].fX, extremeTs); + int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs); count = c.searchRoots(extremeTs, extrema, 0, SkDCubic::kXAxis, roots); break; } @@ -171,7 +171,7 @@ public: SkDPoint calcPt = c.ptAtT(roots[index]); if (!approximately_equal(calcPt.fY, axisIntercept)) { double extremeTs[6]; - int extrema = SkDCubic::FindExtrema(c[0].fY, c[1].fY, c[2].fY, c[3].fY, extremeTs); + int extrema = SkDCubic::FindExtrema(&c[0].fY, extremeTs); count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kYAxis, roots); break; } @@ -234,7 +234,7 @@ public: SkDPoint calcPt = c.ptAtT(roots[index]); if (!approximately_equal(calcPt.fX, axisIntercept)) { double extremeTs[6]; - int extrema = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c[3].fX, extremeTs); + int extrema = SkDCubic::FindExtrema(&c[0].fX, extremeTs); count = c.searchRoots(extremeTs, extrema, axisIntercept, SkDCubic::kXAxis, roots); break; } diff --git a/src/pathops/SkOpContour.cpp b/src/pathops/SkOpContour.cpp index ce9439ac26..107c83169b 100644 --- a/src/pathops/SkOpContour.cpp +++ b/src/pathops/SkOpContour.cpp @@ -69,7 +69,7 @@ void SkOpContour::toPath(SkPathWriter* path) const { path->close(); } -void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, +void SkOpContour::topSortableSegment(const SkDPoint& topLeft, SkDPoint* bestXY, SkOpSegment** topStart) { int segmentCount = fSortedSegments.count(); SkASSERT(segmentCount > 0); @@ -84,7 +84,7 @@ void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, continue; } fDone = false; - SkPoint testXY = testSegment->activeLeftTop(NULL); + SkDPoint testXY = testSegment->activeLeftTop(NULL); if (*topStart) { if (testXY.fY < topLeft.fY) { continue; diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h index 3d26ae84c8..9abf38238b 100644 --- a/src/pathops/SkOpContour.h +++ b/src/pathops/SkOpContour.h @@ -344,7 +344,7 @@ public: } void toPath(SkPathWriter* path) const; - void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart); + void topSortableSegment(const SkDPoint& topLeft, SkDPoint* bestXY, SkOpSegment** topStart); SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); private: diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp index a571609f53..ce35f846b3 100644 --- a/src/pathops/SkOpSegment.cpp +++ b/src/pathops/SkOpSegment.cpp @@ -102,9 +102,9 @@ SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); } -SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { +SkDPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { SkASSERT(!done()); - SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; + SkDPoint topPt = {SK_ScalarMax, SK_ScalarMax}; // see if either end is not done since we want smaller Y of the pair bool lastDone = true; SkOpSpanBase* span = &fHead; @@ -118,10 +118,11 @@ SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { *firstSpan = span; } } - if (fVerb != SkPath::kLine_Verb && !lastDone - && fCubicType != SkDCubic::kSplitAtMaxCurvature_SkDCubicType) { + if (fVerb != SkPath::kLine_Verb && !lastDone) { double curveTopT; - SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastSpan->t(), span->t(), + SkDCurve curve; + this->subDivide(lastSpan, span, &curve); + SkDPoint curveTop = (curve.*Top[fVerb])(fPts, fWeight, lastSpan->t(), span->t(), &curveTopT); if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY && topPt.fX > curveTop.fX)) { topPt = curveTop; @@ -1092,10 +1093,7 @@ SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS const SkOpSegment* next = angle->segment(); SkPathOpsBounds bounds; next->subDivideBounds(angle->end(), angle->start(), &bounds); - bool nearSame = AlmostEqualUlps(top, bounds.top()); - bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->sectorStart(); - bool lesserSector = top > bounds.fTop; - if (lesserSector && (!nearSame || lowerSector)) { + if (top > bounds.fTop) { top = bounds.fTop; firstAngle = angle; } @@ -1452,7 +1450,12 @@ bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* en } SkASSERT(fVerb == SkPath::kCubic_Verb); SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); - return dst.monotonicInY(); + if (dst.monotonicInY()) { + return true; + } + SkDCubic whole; + whole.set(fPts); + return whole.monotonicInY(); } bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start, @@ -2023,9 +2026,15 @@ bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end, SkPathOpsBounds* bounds) const { - SkOpCurve edge; + SkDCurve edge; + subDivide(start, end, &edge); + (edge.*SetBounds[fVerb])(fPts, fWeight, start->t(), end->t(), bounds); +} + +SkDPoint SkOpSegment::top(const SkOpSpanBase* start, const SkOpSpanBase* end, double* topT) const { + SkDCurve edge; subDivide(start, end, &edge); - (bounds->*SetCurveBounds[fVerb])(edge.fPts, edge.fWeight); + return (edge.*Top[fVerb])(fPts, fWeight, start->t(), end->t(), topT); } void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) { diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h index 1e9e1c44be..a762a66a5a 100644 --- a/src/pathops/SkOpSegment.h +++ b/src/pathops/SkOpSegment.h @@ -41,20 +41,24 @@ public: bool activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end, SkPathOp op, int* sumMiWinding, int* sumSuWinding); - SkPoint activeLeftTop(SkOpSpanBase** firstT); + SkDPoint activeLeftTop(SkOpSpanBase** firstT); bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end); bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding); SkOpSegment* addConic(SkPoint pts[3], SkScalar weight, SkOpContour* parent) { init(pts, weight, parent, SkPath::kConic_Verb); - fBounds.setConicBounds(pts, weight); + SkDCurve curve; + curve.fConic.set(pts, weight); + curve.setConicBounds(pts, weight, 0, 1, &fBounds); return this; } SkOpSegment* addCubic(SkPoint pts[4], SkOpContour* parent) { init(pts, 1, parent, SkPath::kCubic_Verb); - fBounds.setCubicBounds(pts, 1); + SkDCurve curve; + curve.fCubic.set(pts); + curve.setCubicBounds(pts, 1, 0, 1, &fBounds); return this; } @@ -88,7 +92,9 @@ public: SkOpSegment* addQuad(SkPoint pts[3], SkOpContour* parent) { init(pts, 1, parent, SkPath::kQuad_Verb); - fBounds.setQuadBounds(pts, 1); + SkDCurve curve; + curve.fQuad.set(pts); + curve.setQuadBounds(pts, 1, 0, 1, &fBounds); return this; } @@ -362,6 +368,8 @@ public: return start->t() * (1 - mid) + end->t() * mid; } + SkDPoint top(const SkOpSpanBase* start, const SkOpSpanBase* end, double* topT) const; + void undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end); int updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const; int updateOppWinding(const SkOpAngle* angle) const; diff --git a/src/pathops/SkPathOpsBounds.cpp b/src/pathops/SkPathOpsBounds.cpp deleted file mode 100644 index ea13e2ed2c..0000000000 --- a/src/pathops/SkPathOpsBounds.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "SkPathOpsBounds.h" -#include "SkPathOpsConic.h" -#include "SkPathOpsCubic.h" -#include "SkPathOpsLine.h" -#include "SkPathOpsQuad.h" - -void SkPathOpsBounds::setConicBounds(const SkPoint a[3], SkScalar weight) { - SkDConic conic; - conic.set(a, weight); - SkDRect dRect; - dRect.setBounds(conic); - set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), - SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); -} - -void SkPathOpsBounds::setCubicBounds(const SkPoint a[4], SkScalar ) { - SkDCubic cubic; - cubic.set(a); - SkDRect dRect; - dRect.setBounds(cubic); - set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), - SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); -} - -void SkPathOpsBounds::setLineBounds(const SkPoint a[2], SkScalar ) { - setPointBounds(a[0]); - add(a[1]); -} - -void SkPathOpsBounds::setQuadBounds(const SkPoint a[3], SkScalar ) { - SkDQuad quad; - quad.set(a); - SkDRect dRect; - dRect.setBounds(quad); - set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), - SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); -} - -void (SkPathOpsBounds::* const SetCurveBounds[])(const SkPoint[], SkScalar weight) = { - NULL, - &SkPathOpsBounds::setLineBounds, - &SkPathOpsBounds::setQuadBounds, - &SkPathOpsBounds::setConicBounds, - &SkPathOpsBounds::setCubicBounds -}; diff --git a/src/pathops/SkPathOpsBounds.h b/src/pathops/SkPathOpsBounds.h index b65d3bea03..7b9daa3671 100644 --- a/src/pathops/SkPathOpsBounds.h +++ b/src/pathops/SkPathOpsBounds.h @@ -33,11 +33,11 @@ struct SkPathOpsBounds : public SkRect { add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom); } - void add(const SkPoint& pt) { - if (pt.fX < fLeft) fLeft = pt.fX; - if (pt.fY < fTop) fTop = pt.fY; - if (pt.fX > fRight) fRight = pt.fX; - if (pt.fY > fBottom) fBottom = pt.fY; + void add(const SkDPoint& pt) { + if (pt.fX < fLeft) fLeft = SkDoubleToScalar(pt.fX); + if (pt.fY < fTop) fTop = SkDoubleToScalar(pt.fY); + if (pt.fX > fRight) fRight = SkDoubleToScalar(pt.fX); + if (pt.fY > fBottom) fBottom = SkDoubleToScalar(pt.fY); } bool almostContains(const SkPoint& pt) { @@ -55,19 +55,12 @@ struct SkPathOpsBounds : public SkRect { || (fLeft == fRight && fTop == fBottom); } - void setConicBounds(const SkPoint a[3], SkScalar weight); - void setCubicBounds(const SkPoint a[4], SkScalar ); - void setLineBounds(const SkPoint a[2], SkScalar ); - void setQuadBounds(const SkPoint a[3], SkScalar ); - - void setPointBounds(const SkPoint& pt) { - fLeft = fRight = pt.fX; - fTop = fBottom = pt.fY; + void setPointBounds(const SkDPoint& pt) { + fLeft = fRight = SkDoubleToScalar(pt.fX); + fTop = fBottom = SkDoubleToScalar(pt.fY); } typedef SkRect INHERITED; }; -extern void (SkPathOpsBounds::* const SetCurveBounds[])(const SkPoint[], SkScalar weight); - #endif diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp index 3496179e65..05b370a1df 100644 --- a/src/pathops/SkPathOpsCommon.cpp +++ b/src/pathops/SkPathOpsCommon.cpp @@ -205,13 +205,13 @@ void DebugShowActiveSpans(SkTDArray& contourList) { #endif static SkOpSegment* findTopSegment(const SkTDArray& contourList, - bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkPoint* topLeft, + bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkDPoint* topLeft, bool* unsortable, bool* done, SkChunkAlloc* allocator) { SkOpSegment* result; const SkOpSegment* lastTopStart = NULL; SkOpSpanBase* lastStart = NULL, * lastEnd = NULL; do { - SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; + SkDPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; int contourCount = contourList.count(); SkOpSegment* topStart = NULL; *done = true; @@ -300,7 +300,7 @@ struct SortableTop2 { // error if local in pre-C++11 SkOpSegment* FindSortableTop(const SkTDArray& contourList, bool firstPass, SkOpAngle::IncludeType angleIncludeType, bool* firstContour, SkOpSpanBase** startPtr, - SkOpSpanBase** endPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical, + SkOpSpanBase** endPtr, SkDPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical, SkChunkAlloc* allocator) { SkOpSegment* current = findTopSegment(contourList, firstPass, startPtr, endPtr, topLeft, unsortable, done, allocator); diff --git a/src/pathops/SkPathOpsCommon.h b/src/pathops/SkPathOpsCommon.h index 1bf17919ad..82eb5da215 100644 --- a/src/pathops/SkPathOpsCommon.h +++ b/src/pathops/SkPathOpsCommon.h @@ -19,7 +19,7 @@ SkOpSegment* FindChase(SkTDArray* chase, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); SkOpSegment* FindSortableTop(const SkTDArray& , bool firstPass, SkOpAngle::IncludeType , bool* firstContour, SkOpSpanBase** index, - SkOpSpanBase** endIndex, SkPoint* topLeft, bool* unsortable, + SkOpSpanBase** endIndex, SkDPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical, SkChunkAlloc* ); SkOpSegment* FindUndone(SkTDArray& contourList, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); diff --git a/src/pathops/SkPathOpsConic.cpp b/src/pathops/SkPathOpsConic.cpp index 869a406dce..b9b0cda0d4 100644 --- a/src/pathops/SkPathOpsConic.cpp +++ b/src/pathops/SkPathOpsConic.cpp @@ -111,25 +111,3 @@ SkDPoint SkDConic::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, do *weight = chopped.fWeight; return chopped[1]; } - -SkDPoint SkDConic::top(double startT, double endT, double* topT) const { - SkDConic sub = subDivide(startT, endT); - SkDPoint topPt = sub[0]; - *topT = startT; - if (topPt.fY > sub[2].fY || (topPt.fY == sub[2].fY && topPt.fX > sub[2].fX)) { - *topT = endT; - topPt = sub[2]; - } - if (!between(sub[0].fY, sub[1].fY, sub[2].fY)) { - double extremeT; - if (FindExtrema(&sub[0].fY, sub.fWeight, &extremeT)) { - extremeT = startT + (endT - startT) * extremeT; - SkDPoint test = ptAtT(extremeT); - if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) { - *topT = extremeT; - topPt = test; - } - } - } - return topPt; -} diff --git a/src/pathops/SkPathOpsConic.h b/src/pathops/SkPathOpsConic.h index 8251901554..bc73049c46 100644 --- a/src/pathops/SkPathOpsConic.h +++ b/src/pathops/SkPathOpsConic.h @@ -72,6 +72,10 @@ struct SkDConic { return fPts.isLinear(startIndex, endIndex); } + bool monotonicInX() const { + return fPts.monotonicInX(); + } + bool monotonicInY() const { return fPts.monotonicInY(); } @@ -109,8 +113,6 @@ struct SkDConic { return conic.subDivide(a, c, t1, t2, newWeight); } - SkDPoint top(double startT, double endT, double* topT) const; - // utilities callable by the user from the debugger when the implementation code is linked in void dump() const; void dumpID(int id) const; diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp index 63f828fb22..777298b297 100644 --- a/src/pathops/SkPathOpsCubic.cpp +++ b/src/pathops/SkPathOpsCubic.cpp @@ -75,7 +75,7 @@ double SkDCubic::calcPrecision() const { return (width > height ? width : height) / gPrecisionUnit; } -bool SkDCubic::clockwise(bool* swap) const { +bool SkDCubic::clockwise(const SkDCubic& whole, bool* swap) const { SkDPoint lastPt = fPts[kPointLast]; SkDPoint firstPt = fPts[0]; double sum = 0; @@ -105,34 +105,15 @@ bool SkDCubic::clockwise(bool* swap) const { lastPt = firstPt; firstPt = idx == 1 ? fPts[furthest] : fPts[kPointLast]; } - *swap = sum > 0 && !this->monotonicInY(); + *swap = sum > 0 && !this->monotonicInY() && !whole.monotonicInY(); return sum <= 0; } bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* swap) { SkDCubic cubic; cubic.set(pts); -#if 0 - bool flip = startT > endT; - double inflectionTs[2]; - int inflections = cubic.findInflections(inflectionTs); - for (int index = 0; index < inflections; ++index) { - double inflectionT = inflectionTs[index]; - if (between(startT, inflectionT, endT)) { - if (flip) { - if (!roughly_equal(inflectionT, endT)) { - startT = inflectionT; - } - } else { - if (!roughly_equal(inflectionT, startT)) { - endT = inflectionT; - } - } - } - } -#endif SkDCubic part = cubic.subDivide(startT, endT); - return part.clockwise(swap); + return part.clockwise(cubic, swap); } void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) { @@ -301,9 +282,14 @@ bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t, CubicType* return false; } +bool SkDCubic::monotonicInX() const { + return precisely_between(fPts[0].fX, fPts[1].fX, fPts[3].fX) + && precisely_between(fPts[0].fX, fPts[2].fX, fPts[3].fX); +} + bool SkDCubic::monotonicInY() const { - return between(fPts[0].fY, fPts[1].fY, fPts[3].fY) - && between(fPts[0].fY, fPts[2].fY, fPts[3].fY); + return precisely_between(fPts[0].fY, fPts[1].fY, fPts[3].fY) + && precisely_between(fPts[0].fY, fPts[2].fY, fPts[3].fY); } void SkDCubic::otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const { @@ -343,6 +329,28 @@ int SkDCubic::RootsValidT(double A, double B, double C, double D, double t[3]) { double s[3]; int realRoots = RootsReal(A, B, C, D, s); int foundRoots = SkDQuad::AddValidTs(s, realRoots, t); + for (int index = 0; index < realRoots; ++index) { + double tValue = s[index]; + if (!approximately_one_or_less(tValue) && between(1, tValue, 1.00005)) { + for (int idx2 = 0; idx2 < foundRoots; ++idx2) { + if (approximately_equal(t[idx2], 1)) { + goto nextRoot; + } + } + SkASSERT(foundRoots < 3); + t[foundRoots++] = 1; + } else if (!approximately_zero_or_more(tValue) && between(-0.00005, tValue, 0)) { + for (int idx2 = 0; idx2 < foundRoots; ++idx2) { + if (approximately_equal(t[idx2], 0)) { + goto nextRoot; + } + } + SkASSERT(foundRoots < 3); + t[foundRoots++] = 0; + } +nextRoot: + ; + } return foundRoots; } @@ -487,10 +495,14 @@ static void formulate_F1DotF2(const double src[], double coeff[4]) { C = 3(b - a) Solve for t, keeping only those that fit between 0 < t < 1 */ -int SkDCubic::FindExtrema(double a, double b, double c, double d, double tValues[2]) { +int SkDCubic::FindExtrema(const double src[], double tValues[2]) { // we divide A,B,C by 3 to simplify - double A = d - a + 3*(b - c); - double B = 2*(a - b - b + c); + double a = src[0]; + double b = src[2]; + double c = src[4]; + double d = src[6]; + double A = d - a + 3 * (b - c); + double B = 2 * (a - b - b + c); double C = b - a; return SkDQuad::RootsValidT(A, B, C, tValues); @@ -519,29 +531,6 @@ int SkDCubic::findMaxCurvature(double tValues[]) const { return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues); } -SkDPoint SkDCubic::top(double startT, double endT, double* topT) const { - SkDCubic sub = subDivide(startT, endT); - SkDPoint topPt = sub[0]; - *topT = startT; - if (topPt.fY > sub[3].fY || (topPt.fY == sub[3].fY && topPt.fX > sub[3].fX)) { - *topT = endT; - topPt = sub[3]; - } - double extremeTs[2]; - if (!sub.monotonicInY()) { - int roots = FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, sub[3].fY, extremeTs); - for (int index = 0; index < roots; ++index) { - double t = startT + (endT - startT) * extremeTs[index]; - SkDPoint mid = ptAtT(t); - if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) { - *topT = t; - topPt = mid; - } - } - } - return topPt; -} - SkDPoint SkDCubic::ptAtT(double t) const { if (0 == t) { return fPts[0]; diff --git a/src/pathops/SkPathOpsCubic.h b/src/pathops/SkPathOpsCubic.h index 269073ca69..f9d291056e 100644 --- a/src/pathops/SkPathOpsCubic.h +++ b/src/pathops/SkPathOpsCubic.h @@ -57,7 +57,7 @@ struct SkDCubic { double binarySearch(double min, double max, double axisIntercept, SearchAxis xAxis) const; double calcPrecision() const; SkDCubicPair chopAt(double t) const; - bool clockwise(bool* swap) const; + bool clockwise(const SkDCubic& whole, bool* swap) const; static bool Clockwise(const SkPoint* pts, double startT, double endT, bool* swap); static void Coefficients(const double* cubic, double* A, double* B, double* C, double* D); static bool ComplexBreak(const SkPoint pts[4], SkScalar* t, CubicType* cubicType); @@ -72,7 +72,7 @@ struct SkDCubic { void dumpInner() const; SkDVector dxdyAtT(double t) const; bool endsAreExtremaInXOrY() const; - static int FindExtrema(double a, double b, double c, double d, double tValue[2]); + static int FindExtrema(const double src[], double tValue[2]); int findInflections(double tValues[2]) const; static int FindInflections(const SkPoint a[kPointCount], double tValues[2]) { @@ -87,6 +87,7 @@ struct SkDCubic { bool hullIntersects(const SkDQuad& c2, bool* isLinear) const; bool hullIntersects(const SkDPoint* pts, int ptCount, bool* isLinear) const; bool isLinear(int startIndex, int endIndex) const; + bool monotonicInX() const; bool monotonicInY() const; void otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const; SkDPoint ptAtT(double t) const; @@ -121,7 +122,6 @@ struct SkDCubic { cubic.subDivide(a, d, t1, t2, p); } - SkDPoint top(double startT, double endT, double* topT) const; SkDQuad toQuad() const; static const int gPrecisionUnit; diff --git a/src/pathops/SkPathOpsCurve.cpp b/src/pathops/SkPathOpsCurve.cpp new file mode 100644 index 0000000000..651e64a908 --- /dev/null +++ b/src/pathops/SkPathOpsCurve.cpp @@ -0,0 +1,146 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "SkPathOpsBounds.h" +#include "SkPathOpsRect.h" +#include "SkPathOpsCurve.h" + +SkDPoint SkDCurve::conicTop(const SkPoint curve[3], SkScalar curveWeight, + double startT, double endT, double* topT) { + SkDPoint topPt = fConic[0]; + *topT = startT; + if (topPt.fY > fConic[2].fY || (topPt.fY == fConic[2].fY && topPt.fX > fConic[2].fX)) { + *topT = endT; + topPt = fConic[2]; + } + if (!fConic.monotonicInY()) { + double extremeT; + if (SkDConic::FindExtrema(&fConic.fPts.fPts[0].fY, fConic.fWeight, &extremeT)) { + SkDConic dCurve; + dCurve.set(curve, curveWeight); + extremeT = startT + (endT - startT) * extremeT; + SkDPoint test = dCurve.ptAtT(extremeT); + if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) { + *topT = extremeT; + topPt = test; + } + } + } + return topPt; +} + +SkDPoint SkDCurve::cubicTop(const SkPoint curve[4], SkScalar , + double startT, double endT, double* topT) { + SkDPoint topPt = fCubic[0]; + *topT = startT; + if (topPt.fY > fCubic[3].fY || (topPt.fY == fCubic[3].fY && topPt.fX > fCubic[3].fX)) { + *topT = endT; + topPt = fCubic[3]; + } + double extremeTs[2]; + if (!fCubic.monotonicInY()) { + int roots = SkDCubic::FindExtrema(&fCubic.fPts[0].fY, extremeTs); + SkDCubic dCurve; + dCurve.set(curve); + for (int index = 0; index < roots; ++index) { + double t = startT + (endT - startT) * extremeTs[index]; + SkDPoint mid = dCurve.ptAtT(t); + if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) { + *topT = t; + topPt = mid; + } + } + } + return topPt; +} + +SkDPoint SkDCurve::lineTop(const SkPoint[2], SkScalar , double startT, double endT, double* topT) { + SkDPoint topPt = fLine[0]; + *topT = startT; + if (topPt.fY > fLine[1].fY || (topPt.fY == fLine[1].fY && topPt.fX > fLine[1].fX)) { + *topT = endT; + topPt = fLine[1]; + } + return topPt; +} + +SkDPoint SkDCurve::quadTop(const SkPoint curve[3], SkScalar , + double startT, double endT, double* topT) { + SkDPoint topPt = fQuad[0]; + *topT = startT; + if (topPt.fY > fQuad[2].fY || (topPt.fY == fQuad[2].fY && topPt.fX > fQuad[2].fX)) { + *topT = endT; + topPt = fQuad[2]; + } + if (!fQuad.monotonicInY()) { + double extremeT; + if (SkDQuad::FindExtrema(&fQuad.fPts[0].fY, &extremeT)) { + SkDQuad dCurve; + dCurve.set(curve); + extremeT = startT + (endT - startT) * extremeT; + SkDPoint test = dCurve.ptAtT(extremeT); + if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) { + *topT = extremeT; + topPt = test; + } + } + } + return topPt; +} + +SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar curveWeight, + double tStart, double tEnd, double* topT) = { + NULL, + &SkDCurve::lineTop, + &SkDCurve::quadTop, + &SkDCurve::conicTop, + &SkDCurve::cubicTop +}; + +void SkDCurve::setConicBounds(const SkPoint curve[3], SkScalar curveWeight, + double tStart, double tEnd, SkPathOpsBounds* bounds) { + SkDConic dCurve; + dCurve.set(curve, curveWeight); + SkDRect dRect; + dRect.setBounds(dCurve, fConic, tStart, tEnd); + bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), + SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); +} + +void SkDCurve::setCubicBounds(const SkPoint curve[4], SkScalar , + double tStart, double tEnd, SkPathOpsBounds* bounds) { + SkDCubic dCurve; + dCurve.set(curve); + SkDRect dRect; + dRect.setBounds(dCurve, fCubic, tStart, tEnd); + bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), + SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); +} + +void SkDCurve::setLineBounds(const SkPoint[2], SkScalar , + double , double , SkPathOpsBounds* bounds) { + bounds->setPointBounds(fLine[0]); + bounds->add(fLine[1]); +} + +void SkDCurve::setQuadBounds(const SkPoint curve[3], SkScalar , + double tStart, double tEnd, SkPathOpsBounds* bounds) { + SkDQuad dCurve; + dCurve.set(curve); + SkDRect dRect; + dRect.setBounds(dCurve, fQuad, tStart, tEnd); + bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), + SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); +} + +void (SkDCurve::* const SetBounds[])(const SkPoint curve[], SkScalar curveWeight, + double tStart, double tEnd, SkPathOpsBounds* bounds) = { + NULL, + &SkDCurve::setLineBounds, + &SkDCurve::setQuadBounds, + &SkDCurve::setConicBounds, + &SkDCurve::setCubicBounds +}; diff --git a/src/pathops/SkPathOpsCurve.h b/src/pathops/SkPathOpsCurve.h index 69af91cf34..bfbc515719 100644 --- a/src/pathops/SkPathOpsCurve.h +++ b/src/pathops/SkPathOpsCurve.h @@ -16,6 +16,8 @@ #include "SkPath.h" #endif +struct SkPathOpsBounds; + struct SkOpCurve { SkPoint fPts[4]; SkScalar fWeight; @@ -43,6 +45,7 @@ struct SkOpCurve { SkDEBUGCODE(fWeight = 1); SkDEBUGCODE(fVerb = SkPath::kCubic_Verb); } + }; struct SkDCurve { @@ -64,9 +67,29 @@ struct SkDCurve { return fCubic[n]; } + SkDPoint conicTop(const SkPoint curve[3], SkScalar curveWeight, + double s, double e, double* topT); + SkDPoint cubicTop(const SkPoint curve[4], SkScalar , double s, double e, double* topT); void dumpID(int ) const; + SkDPoint lineTop(const SkPoint[2], SkScalar , double , double , double* topT); + SkDPoint quadTop(const SkPoint curve[3], SkScalar , double s, double e, double* topT); + + void setConicBounds(const SkPoint curve[3], SkScalar curveWeight, + double s, double e, SkPathOpsBounds* ); + void setCubicBounds(const SkPoint curve[4], SkScalar , + double s, double e, SkPathOpsBounds* ); + void setLineBounds(const SkPoint[2], SkScalar , double , double , SkPathOpsBounds* ); + void setQuadBounds(const SkPoint curve[3], SkScalar , + double s, double e, SkPathOpsBounds*); }; + +extern void (SkDCurve::* const SetBounds[])(const SkPoint curve[], SkScalar cWeight, + double tStart, double tEnd, SkPathOpsBounds* ); + +extern SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar cWeight, + double tStart, double tEnd, double* topT); + static SkDPoint dline_xy_at_t(const SkPoint a[2], SkScalar , double t) { SkDLine line; line.set(a); @@ -179,36 +202,6 @@ static SkVector (* const CurveSlopeAtT[])(const SkPoint[], SkScalar , double ) = fcubic_dxdy_at_t }; -static SkPoint quad_top(const SkPoint a[3], SkScalar , double startT, double endT, double* topT) { - SkDQuad quad; - quad.set(a); - SkDPoint topPt = quad.top(startT, endT, topT); - return topPt.asSkPoint(); -} - -static SkPoint conic_top(const SkPoint a[3], SkScalar weight, double startT, double endT, - double* topT) { - SkDConic conic; - conic.set(a, weight); - SkDPoint topPt = conic.top(startT, endT, topT); - return topPt.asSkPoint(); -} - -static SkPoint cubic_top(const SkPoint a[4], SkScalar , double startT, double endT, double* topT) { - SkDCubic cubic; - cubic.set(a); - SkDPoint topPt = cubic.top(startT, endT, topT); - return topPt.asSkPoint(); -} - -static SkPoint (* const CurveTop[])(const SkPoint[], SkScalar , double , double , double* ) = { - NULL, - NULL, - quad_top, - conic_top, - cubic_top -}; - static bool line_is_vertical(const SkPoint a[2], SkScalar , double startT, double endT) { SkDLine line; line.set(a); diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h index 8473d66c70..0624ad687a 100644 --- a/src/pathops/SkPathOpsDebug.h +++ b/src/pathops/SkPathOpsDebug.h @@ -37,8 +37,6 @@ #if FORCE_RELEASE -#define DEBUG_CUBIC_SWAP_TOP 0 - #define DEBUG_ACTIVE_OP 0 #define DEBUG_ACTIVE_SPANS 0 #define DEBUG_ADD_INTERSECTING_TS 0 @@ -47,23 +45,21 @@ #define DEBUG_ASSEMBLE 0 #define DEBUG_CUBIC_BINARY_SEARCH 0 #define DEBUG_CUBIC_SPLIT 0 -#define DEBUG_DUMP_SEGMENTS DEBUG_CUBIC_SWAP_TOP +#define DEBUG_DUMP_SEGMENTS 0 // 1 #define DEBUG_FLOW 0 #define DEBUG_LIMIT_WIND_SUM 0 #define DEBUG_MARK_DONE 0 #define DEBUG_PATH_CONSTRUCTION 0 #define DEBUG_PERP 0 -#define DEBUG_SHOW_TEST_NAME DEBUG_CUBIC_SWAP_TOP +#define DEBUG_SHOW_TEST_NAME 0 // 1 #define DEBUG_SORT 0 -#define DEBUG_SWAP_TOP DEBUG_CUBIC_SWAP_TOP +#define DEBUG_SWAP_TOP 0 // 1 #define DEBUG_T_SECT 0 #define DEBUG_T_SECT_DUMP 0 #define DEBUG_VALIDATE 0 #define DEBUG_WINDING 0 #define DEBUG_WINDING_AT_T 0 -#undef DEBUG_CUBIC_SWAP_TOP - #else #define DEBUG_ACTIVE_OP 1 diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp index 4e3ec4aad3..1105af5d70 100644 --- a/src/pathops/SkPathOpsOp.cpp +++ b/src/pathops/SkPathOpsOp.cpp @@ -104,8 +104,8 @@ static bool bridgeOp(SkTDArray& contourList, const SkPathOp op, bool unsortable = false; bool topUnsortable = false; bool firstPass = true; - SkPoint lastTopLeft; - SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; + SkDPoint lastTopLeft; + SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; do { SkOpSpanBase* start = NULL; SkOpSpanBase* end = NULL; diff --git a/src/pathops/SkPathOpsQuad.cpp b/src/pathops/SkPathOpsQuad.cpp index 397a3ce98a..66f191bb0e 100644 --- a/src/pathops/SkPathOpsQuad.cpp +++ b/src/pathops/SkPathOpsQuad.cpp @@ -240,6 +240,10 @@ static double interp_quad_coords(const double* src, double t) { return abc; } +bool SkDQuad::monotonicInX() const { + return between(fPts[0].fX, fPts[1].fX, fPts[2].fX); +} + bool SkDQuad::monotonicInY() const { return between(fPts[0].fY, fPts[1].fY, fPts[2].fY); } @@ -323,28 +327,6 @@ SkDPoint SkDQuad::subDivide(const SkDPoint& a, const SkDPoint& c, double t1, dou return b; } -SkDPoint SkDQuad::top(double startT, double endT, double* topT) const { - SkDQuad sub = subDivide(startT, endT); - SkDPoint topPt = sub[0]; - *topT = startT; - if (topPt.fY > sub[2].fY || (topPt.fY == sub[2].fY && topPt.fX > sub[2].fX)) { - *topT = endT; - topPt = sub[2]; - } - if (!between(sub[0].fY, sub[1].fY, sub[2].fY)) { - double extremeT; - if (FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, &extremeT)) { - extremeT = startT + (endT - startT) * extremeT; - SkDPoint test = ptAtT(extremeT); - if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) { - *topT = extremeT; - topPt = test; - } - } - } - return topPt; -} - /* classic one t subdivision */ static void interp_quad_coords(const double* src, double* dst, double t) { double ab = SkDInterp(src[0], src[2], t); @@ -397,10 +379,13 @@ static int valid_unit_divide(double numer, double denom, double* ratio) B = 2(b - a) Solve for t, only if it fits between 0 < t < 1 */ -int SkDQuad::FindExtrema(double a, double b, double c, double tValue[1]) { +int SkDQuad::FindExtrema(const double src[], double tValue[1]) { /* At + B == 0 t = -B / A */ + double a = src[0]; + double b = src[2]; + double c = src[4]; return valid_unit_divide(a - b, a - b - b + c, tValue); } diff --git a/src/pathops/SkPathOpsQuad.h b/src/pathops/SkPathOpsQuad.h index b201860f98..de4ce4baa3 100644 --- a/src/pathops/SkPathOpsQuad.h +++ b/src/pathops/SkPathOpsQuad.h @@ -62,11 +62,12 @@ struct SkDQuad { SkDQuadPair chopAt(double t) const; static bool Clockwise(const SkOpCurve& edge, bool* swap); SkDVector dxdyAtT(double t) const; - static int FindExtrema(double a, double b, double c, double tValue[1]); + static int FindExtrema(const double src[], double tValue[1]); bool hullIntersects(const SkDQuad& , bool* isLinear) const; bool hullIntersects(const SkDConic& , bool* isLinear) const; bool hullIntersects(const SkDCubic& , bool* isLinear) const; bool isLinear(int startIndex, int endIndex) const; + bool monotonicInX() const; bool monotonicInY() const; double nearestT(const SkDPoint&) const; void otherPts(int oddMan, const SkDPoint* endPt[2]) const; @@ -89,7 +90,6 @@ struct SkDQuad { } SkDConic toConic() const; SkDCubic toCubic() const; - SkDPoint top(double startT, double endT, double* topT) const; // utilities callable by the user from the debugger when the implementation code is linked in void dump() const; diff --git a/src/pathops/SkPathOpsRect.cpp b/src/pathops/SkPathOpsRect.cpp index 540db16a0e..8c01153532 100644 --- a/src/pathops/SkPathOpsRect.cpp +++ b/src/pathops/SkPathOpsRect.cpp @@ -10,54 +10,53 @@ #include "SkPathOpsQuad.h" #include "SkPathOpsRect.h" -void SkDRect::setBounds(const SkDQuad& quad) { - set(quad[0]); - add(quad[2]); +void SkDRect::setBounds(const SkDQuad& curve, const SkDQuad& sub, double startT, double endT) { + set(sub[0]); + add(sub[2]); double tValues[2]; int roots = 0; - if (!between(quad[0].fX, quad[1].fX, quad[2].fX)) { - roots = SkDQuad::FindExtrema(quad[0].fX, quad[1].fX, quad[2].fX, tValues); + if (!sub.monotonicInX()) { + roots = SkDQuad::FindExtrema(&sub[0].fX, tValues); } - if (!between(quad[0].fY, quad[1].fY, quad[2].fY)) { - roots += SkDQuad::FindExtrema(quad[0].fY, quad[1].fY, quad[2].fY, &tValues[roots]); + if (!sub.monotonicInY()) { + roots += SkDQuad::FindExtrema(&sub[0].fY, &tValues[roots]); } - for (int x = 0; x < roots; ++x) { - add(quad.ptAtT(tValues[x])); + for (int index = 0; index < roots; ++index) { + double t = startT + (endT - startT) * tValues[index]; + add(curve.ptAtT(t)); } } -void SkDRect::setBounds(const SkDConic& conic) { - set(conic[0]); - add(conic[2]); +void SkDRect::setBounds(const SkDConic& curve, const SkDConic& sub, double startT, double endT) { + set(sub[0]); + add(sub[2]); double tValues[2]; int roots = 0; - if (!between(conic[0].fX, conic[1].fX, conic[2].fX)) { - roots = SkDConic::FindExtrema(&conic[0].fX, conic.fWeight, tValues); + if (!sub.monotonicInX()) { + roots = SkDConic::FindExtrema(&sub[0].fX, sub.fWeight, tValues); } - if (!between(conic[0].fY, conic[1].fY, conic[2].fY)) { - roots += SkDConic::FindExtrema(&conic[0].fY, conic.fWeight, &tValues[roots]); + if (!sub.monotonicInY()) { + roots += SkDConic::FindExtrema(&sub[0].fY, sub.fWeight, &tValues[roots]); } - for (int x = 0; x < roots; ++x) { - add(conic.ptAtT(tValues[x])); + for (int index = 0; index < roots; ++index) { + double t = startT + (endT - startT) * tValues[index]; + add(curve.ptAtT(t)); } } -static bool is_bounded_by_end_points(double a, double b, double c, double d) { - return between(a, b, d) && between(a, c, d); -} - -void SkDRect::setBounds(const SkDCubic& c) { - set(c[0]); - add(c[3]); +void SkDRect::setBounds(const SkDCubic& curve, const SkDCubic& sub, double startT, double endT) { + set(sub[0]); + add(sub[3]); double tValues[4]; int roots = 0; - if (!is_bounded_by_end_points(c[0].fX, c[1].fX, c[2].fX, c[3].fX)) { - roots = SkDCubic::FindExtrema(c[0].fX, c[1].fX, c[2].fX, c[3].fX, tValues); + if (!sub.monotonicInX()) { + roots = SkDCubic::FindExtrema(&sub[0].fX, tValues); } - if (!is_bounded_by_end_points(c[0].fY, c[1].fY, c[2].fY, c[3].fY)) { - roots += SkDCubic::FindExtrema(c[0].fY, c[1].fY, c[2].fY, c[3].fY, &tValues[roots]); + if (!sub.monotonicInY()) { + roots += SkDCubic::FindExtrema(&sub[0].fY, &tValues[roots]); } - for (int x = 0; x < roots; ++x) { - add(c.ptAtT(tValues[x])); + for (int index = 0; index < roots; ++index) { + double t = startT + (endT - startT) * tValues[index]; + add(curve.ptAtT(t)); } } diff --git a/src/pathops/SkPathOpsRect.h b/src/pathops/SkPathOpsRect.h index f783d96b99..7fec70a32a 100644 --- a/src/pathops/SkPathOpsRect.h +++ b/src/pathops/SkPathOpsRect.h @@ -48,9 +48,23 @@ struct SkDRect { return fBottom - fTop; } - void setBounds(const SkDConic&); - void setBounds(const SkDCubic&); - void setBounds(const SkDQuad&); + void setBounds(const SkDConic& curve) { + setBounds(curve, curve, 0, 1); + } + + void setBounds(const SkDConic& curve, const SkDConic& sub, double tStart, double tEnd); + + void setBounds(const SkDCubic& curve) { + setBounds(curve, curve, 0, 1); + } + + void setBounds(const SkDCubic& curve, const SkDCubic& sub, double tStart, double tEnd); + + void setBounds(const SkDQuad& curve) { + setBounds(curve, curve, 0, 1); + } + + void setBounds(const SkDQuad& curve, const SkDQuad& sub, double tStart, double tEnd); }; #endif diff --git a/src/pathops/SkPathOpsSimplify.cpp b/src/pathops/SkPathOpsSimplify.cpp index b4f8e22142..14c6837c1b 100644 --- a/src/pathops/SkPathOpsSimplify.cpp +++ b/src/pathops/SkPathOpsSimplify.cpp @@ -16,8 +16,8 @@ static bool bridgeWinding(SkTDArray& contourList, SkPathWriter* s bool unsortable = false; bool topUnsortable = false; bool firstPass = true; - SkPoint lastTopLeft; - SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; + SkDPoint lastTopLeft; + SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; do { SkOpSpanBase* start = NULL; SkOpSpanBase* end = NULL; -- cgit v1.2.3