|  | /* | 
|  | * 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 "PathOpsTestCommon.h" | 
|  | #include "SkPathOpsBounds.h" | 
|  | #include "SkPathOpsCubic.h" | 
|  | #include "SkPathOpsLine.h" | 
|  | #include "SkPathOpsQuad.h" | 
|  | #include "SkPathOpsTriangle.h" | 
|  |  | 
|  | void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads) { | 
|  | SkTArray<double, true> ts; | 
|  | cubic.toQuadraticTs(precision, &ts); | 
|  | if (ts.count() <= 0) { | 
|  | SkDQuad quad = cubic.toQuad(); | 
|  | quads.push_back(quad); | 
|  | return; | 
|  | } | 
|  | double tStart = 0; | 
|  | for (int i1 = 0; i1 <= ts.count(); ++i1) { | 
|  | const double tEnd = i1 < ts.count() ? ts[i1] : 1; | 
|  | SkDCubic part = cubic.subDivide(tStart, tEnd); | 
|  | SkDQuad quad = part.toQuad(); | 
|  | quads.push_back(quad); | 
|  | tStart = tEnd; | 
|  | } | 
|  | } | 
|  |  | 
|  | void CubicPathToQuads(const SkPath& cubicPath, SkPath* quadPath) { | 
|  | quadPath->reset(); | 
|  | SkDCubic cubic; | 
|  | SkTArray<SkDQuad, true> quads; | 
|  | SkPath::RawIter iter(cubicPath); | 
|  | uint8_t verb; | 
|  | SkPoint pts[4]; | 
|  | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 
|  | switch (verb) { | 
|  | case SkPath::kMove_Verb: | 
|  | quadPath->moveTo(pts[0].fX, pts[0].fY); | 
|  | continue; | 
|  | case SkPath::kLine_Verb: | 
|  | quadPath->lineTo(pts[1].fX, pts[1].fY); | 
|  | break; | 
|  | case SkPath::kQuad_Verb: | 
|  | quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); | 
|  | break; | 
|  | case SkPath::kCubic_Verb: | 
|  | quads.reset(); | 
|  | cubic.set(pts); | 
|  | CubicToQuads(cubic, cubic.calcPrecision(), quads); | 
|  | for (int index = 0; index < quads.count(); ++index) { | 
|  | SkPoint qPts[2] = { | 
|  | quads[index][1].asSkPoint(), | 
|  | quads[index][2].asSkPoint() | 
|  | }; | 
|  | quadPath->quadTo(qPts[0].fX, qPts[0].fY, qPts[1].fX, qPts[1].fY); | 
|  | } | 
|  | break; | 
|  | case SkPath::kClose_Verb: | 
|  | quadPath->close(); | 
|  | break; | 
|  | default: | 
|  | SkDEBUGFAIL("bad verb"); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void CubicPathToSimple(const SkPath& cubicPath, SkPath* simplePath) { | 
|  | simplePath->reset(); | 
|  | SkDCubic cubic; | 
|  | SkPath::RawIter iter(cubicPath); | 
|  | uint8_t verb; | 
|  | SkPoint pts[4]; | 
|  | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 
|  | switch (verb) { | 
|  | case SkPath::kMove_Verb: | 
|  | simplePath->moveTo(pts[0].fX, pts[0].fY); | 
|  | continue; | 
|  | case SkPath::kLine_Verb: | 
|  | simplePath->lineTo(pts[1].fX, pts[1].fY); | 
|  | break; | 
|  | case SkPath::kQuad_Verb: | 
|  | simplePath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); | 
|  | break; | 
|  | case SkPath::kCubic_Verb: { | 
|  | cubic.set(pts); | 
|  | double tInflects[2]; | 
|  | int inflections = cubic.findInflections(tInflects); | 
|  | if (inflections > 1 && tInflects[0] > tInflects[1]) { | 
|  | SkTSwap(tInflects[0], tInflects[1]); | 
|  | } | 
|  | double lo = 0; | 
|  | for (int index = 0; index <= inflections; ++index) { | 
|  | double hi = index < inflections ? tInflects[index] : 1; | 
|  | SkDCubic part = cubic.subDivide(lo, hi); | 
|  | SkPoint cPts[3]; | 
|  | cPts[0] = part[1].asSkPoint(); | 
|  | cPts[1] = part[2].asSkPoint(); | 
|  | cPts[2] = part[3].asSkPoint(); | 
|  | simplePath->cubicTo(cPts[0].fX, cPts[0].fY, cPts[1].fX, cPts[1].fY, | 
|  | cPts[2].fX, cPts[2].fY); | 
|  | lo = hi; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case SkPath::kClose_Verb: | 
|  | simplePath->close(); | 
|  | break; | 
|  | default: | 
|  | SkDEBUGFAIL("bad verb"); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool SkDoubleIsNaN(double x) { | 
|  | return x != x; | 
|  | } | 
|  |  | 
|  | bool ValidBounds(const SkPathOpsBounds& bounds) { | 
|  | if (SkScalarIsNaN(bounds.fLeft)) { | 
|  | return false; | 
|  | } | 
|  | if (SkScalarIsNaN(bounds.fTop)) { | 
|  | return false; | 
|  | } | 
|  | if (SkScalarIsNaN(bounds.fRight)) { | 
|  | return false; | 
|  | } | 
|  | return !SkScalarIsNaN(bounds.fBottom); | 
|  | } | 
|  |  | 
|  | bool ValidCubic(const SkDCubic& cubic) { | 
|  | for (int index = 0; index < 4; ++index) { | 
|  | if (!ValidPoint(cubic[index])) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ValidLine(const SkDLine& line) { | 
|  | for (int index = 0; index < 2; ++index) { | 
|  | if (!ValidPoint(line[index])) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ValidPoint(const SkDPoint& pt) { | 
|  | if (SkDoubleIsNaN(pt.fX)) { | 
|  | return false; | 
|  | } | 
|  | return !SkDoubleIsNaN(pt.fY); | 
|  | } | 
|  |  | 
|  | bool ValidPoints(const SkPoint* pts, int count) { | 
|  | for (int index = 0; index < count; ++index) { | 
|  | if (SkScalarIsNaN(pts[index].fX)) { | 
|  | return false; | 
|  | } | 
|  | if (SkScalarIsNaN(pts[index].fY)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ValidQuad(const SkDQuad& quad) { | 
|  | for (int index = 0; index < 3; ++index) { | 
|  | if (!ValidPoint(quad[index])) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ValidTriangle(const SkDTriangle& triangle) { | 
|  | for (int index = 0; index < 3; ++index) { | 
|  | if (!ValidPoint(triangle.fPts[index])) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ValidVector(const SkDVector& v) { | 
|  | if (SkDoubleIsNaN(v.fX)) { | 
|  | return false; | 
|  | } | 
|  | return !SkDoubleIsNaN(v.fY); | 
|  | } |