1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 #include "PathOpsTestCommon.h" 8 #include "SkPathOpsBounds.h" 9 #include "SkPathOpsCubic.h" 10 #include "SkPathOpsLine.h" 11 #include "SkPathOpsQuad.h" 12 #include "SkPathOpsTriangle.h" 13 14 void CubicToQuads(const SkDCubic& cubic, double precision, SkTArray<SkDQuad, true>& quads) { 15 SkTArray<double, true> ts; 16 cubic.toQuadraticTs(precision, &ts); 17 if (ts.count() <= 0) { 18 SkDQuad quad = cubic.toQuad(); 19 quads.push_back(quad); 20 return; 21 } 22 double tStart = 0; 23 for (int i1 = 0; i1 <= ts.count(); ++i1) { 24 const double tEnd = i1 < ts.count() ? ts[i1] : 1; 25 SkDCubic part = cubic.subDivide(tStart, tEnd); 26 SkDQuad quad = part.toQuad(); 27 quads.push_back(quad); 28 tStart = tEnd; 29 } 30 } 31 32 void CubicPathToQuads(const SkPath& cubicPath, SkPath* quadPath) { 33 quadPath->reset(); 34 SkDCubic cubic; 35 SkTArray<SkDQuad, true> quads; 36 SkPath::RawIter iter(cubicPath); 37 uint8_t verb; 38 SkPoint pts[4]; 39 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 40 switch (verb) { 41 case SkPath::kMove_Verb: 42 quadPath->moveTo(pts[0].fX, pts[0].fY); 43 continue; 44 case SkPath::kLine_Verb: 45 quadPath->lineTo(pts[1].fX, pts[1].fY); 46 break; 47 case SkPath::kQuad_Verb: 48 quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); 49 break; 50 case SkPath::kCubic_Verb: 51 quads.reset(); 52 cubic.set(pts); 53 CubicToQuads(cubic, cubic.calcPrecision(), quads); 54 for (int index = 0; index < quads.count(); ++index) { 55 SkPoint qPts[2] = { 56 quads[index][1].asSkPoint(), 57 quads[index][2].asSkPoint() 58 }; 59 quadPath->quadTo(qPts[0].fX, qPts[0].fY, qPts[1].fX, qPts[1].fY); 60 } 61 break; 62 case SkPath::kClose_Verb: 63 quadPath->close(); 64 break; 65 default: 66 SkDEBUGFAIL("bad verb"); 67 return; 68 } 69 } 70 } 71 72 void CubicPathToSimple(const SkPath& cubicPath, SkPath* simplePath) { 73 simplePath->reset(); 74 SkDCubic cubic; 75 SkPath::RawIter iter(cubicPath); 76 uint8_t verb; 77 SkPoint pts[4]; 78 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 79 switch (verb) { 80 case SkPath::kMove_Verb: 81 simplePath->moveTo(pts[0].fX, pts[0].fY); 82 continue; 83 case SkPath::kLine_Verb: 84 simplePath->lineTo(pts[1].fX, pts[1].fY); 85 break; 86 case SkPath::kQuad_Verb: 87 simplePath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY); 88 break; 89 case SkPath::kCubic_Verb: { 90 cubic.set(pts); 91 double tInflects[2]; 92 int inflections = cubic.findInflections(tInflects); 93 if (inflections > 1 && tInflects[0] > tInflects[1]) { 94 SkTSwap(tInflects[0], tInflects[1]); 95 } 96 double lo = 0; 97 for (int index = 0; index <= inflections; ++index) { 98 double hi = index < inflections ? tInflects[index] : 1; 99 SkDCubic part = cubic.subDivide(lo, hi); 100 SkPoint cPts[3]; 101 cPts[0] = part[1].asSkPoint(); 102 cPts[1] = part[2].asSkPoint(); 103 cPts[2] = part[3].asSkPoint(); 104 simplePath->cubicTo(cPts[0].fX, cPts[0].fY, cPts[1].fX, cPts[1].fY, 105 cPts[2].fX, cPts[2].fY); 106 lo = hi; 107 } 108 break; 109 } 110 case SkPath::kClose_Verb: 111 simplePath->close(); 112 break; 113 default: 114 SkDEBUGFAIL("bad verb"); 115 return; 116 } 117 } 118 } 119 120 static bool SkDoubleIsNaN(double x) { 121 return x != x; 122 } 123 124 bool ValidBounds(const SkPathOpsBounds& bounds) { 125 if (SkScalarIsNaN(bounds.fLeft)) { 126 return false; 127 } 128 if (SkScalarIsNaN(bounds.fTop)) { 129 return false; 130 } 131 if (SkScalarIsNaN(bounds.fRight)) { 132 return false; 133 } 134 return !SkScalarIsNaN(bounds.fBottom); 135 } 136 137 bool ValidCubic(const SkDCubic& cubic) { 138 for (int index = 0; index < 4; ++index) { 139 if (!ValidPoint(cubic[index])) { 140 return false; 141 } 142 } 143 return true; 144 } 145 146 bool ValidLine(const SkDLine& line) { 147 for (int index = 0; index < 2; ++index) { 148 if (!ValidPoint(line[index])) { 149 return false; 150 } 151 } 152 return true; 153 } 154 155 bool ValidPoint(const SkDPoint& pt) { 156 if (SkDoubleIsNaN(pt.fX)) { 157 return false; 158 } 159 return !SkDoubleIsNaN(pt.fY); 160 } 161 162 bool ValidPoints(const SkPoint* pts, int count) { 163 for (int index = 0; index < count; ++index) { 164 if (SkScalarIsNaN(pts[index].fX)) { 165 return false; 166 } 167 if (SkScalarIsNaN(pts[index].fY)) { 168 return false; 169 } 170 } 171 return true; 172 } 173 174 bool ValidQuad(const SkDQuad& quad) { 175 for (int index = 0; index < 3; ++index) { 176 if (!ValidPoint(quad[index])) { 177 return false; 178 } 179 } 180 return true; 181 } 182 183 bool ValidTriangle(const SkDTriangle& triangle) { 184 for (int index = 0; index < 3; ++index) { 185 if (!ValidPoint(triangle.fPts[index])) { 186 return false; 187 } 188 } 189 return true; 190 } 191 192 bool ValidVector(const SkDVector& v) { 193 if (SkDoubleIsNaN(v.fX)) { 194 return false; 195 } 196 return !SkDoubleIsNaN(v.fY); 197 } 198