1/* 2 * Copyright 2021 Google LLC. 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 8#include "src/gpu/tessellate/Tessellation.h" 9 10#include "include/core/SkPath.h" 11#include "src/core/SkGeometry.h" 12#include "src/core/SkPathPriv.h" 13#include "src/gpu/BufferWriter.h" 14#include "src/gpu/tessellate/CullTest.h" 15#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h" 16#include "src/gpu/tessellate/WangsFormula.h" 17 18namespace skgpu { 19 20namespace { 21 22// Writes a new path, chopping as necessary so no verbs require more segments than 23// kMaxTessellationSegmentsPerCurve. Curves completely outside the viewport are flattened into 24// lines. 25class PathChopper { 26public: 27 PathChopper(const SkMatrix& matrix, const SkRect& viewport) 28 : fCullTest(viewport, matrix) 29 , fVectorXform(matrix) { 30 fPath.setIsVolatile(true); 31 } 32 33 SkPath path() const { return fPath; } 34 35 void moveTo(SkPoint p) { fPath.moveTo(p); } 36 void lineTo(SkPoint p1) { fPath.lineTo(p1); } 37 void close() { fPath.close(); } 38 39 void quadTo(const SkPoint p[3]) { 40 if (!fCullTest.areVisible3(p)) { 41 this->lineTo(p[2]); 42 return; 43 } 44 float n = wangs_formula::quadratic_pow4(kTessellationPrecision, p, fVectorXform); 45 if (n > pow4(kMaxTessellationSegmentsPerCurve)) { 46 SkPoint chops[5]; 47 SkChopQuadAtHalf(p, chops); 48 this->quadTo(chops); 49 this->quadTo(chops + 2); 50 return; 51 } 52 fPath.quadTo(p[1], p[2]); 53 } 54 55 void conicTo(const SkPoint p[3], float w) { 56 if (!fCullTest.areVisible3(p)) { 57 this->lineTo(p[2]); 58 return; 59 } 60 float n = wangs_formula::conic_pow2(kTessellationPrecision, p, w, fVectorXform); 61 if (n > pow2(kMaxTessellationSegmentsPerCurve)) { 62 SkConic chops[2]; 63 if (!SkConic(p,w).chopAt(.5, chops)) { 64 this->lineTo(p[2]); 65 return; 66 } 67 this->conicTo(chops[0].fPts, chops[0].fW); 68 this->conicTo(chops[1].fPts, chops[1].fW); 69 return; 70 } 71 fPath.conicTo(p[1], p[2], w); 72 } 73 74 void cubicTo(const SkPoint p[4]) { 75 if (!fCullTest.areVisible4(p)) { 76 this->lineTo(p[3]); 77 return; 78 } 79 float n = wangs_formula::cubic_pow4(kTessellationPrecision, p, fVectorXform); 80 if (n > pow4(kMaxTessellationSegmentsPerCurve)) { 81 SkPoint chops[7]; 82 SkChopCubicAtHalf(p, chops); 83 this->cubicTo(chops); 84 this->cubicTo(chops + 3); 85 return; 86 } 87 fPath.cubicTo(p[1], p[2], p[3]); 88 } 89 90private: 91 const CullTest fCullTest; 92 const wangs_formula::VectorXform fVectorXform; 93 SkPath fPath; 94}; 95 96} // namespace 97 98SkPath PreChopPathCurves(const SkPath& path, const SkMatrix& matrix, const SkRect& viewport) { 99 PathChopper chopper(matrix, viewport); 100 for (auto [verb, p, w] : SkPathPriv::Iterate(path)) { 101 switch (verb) { 102 case SkPathVerb::kMove: 103 chopper.moveTo(p[0]); 104 break; 105 case SkPathVerb::kLine: 106 chopper.lineTo(p[1]); 107 break; 108 case SkPathVerb::kQuad: 109 chopper.quadTo(p); 110 break; 111 case SkPathVerb::kConic: 112 chopper.conicTo(p, *w); 113 break; 114 case SkPathVerb::kCubic: 115 chopper.cubicTo(p); 116 break; 117 case SkPathVerb::kClose: 118 chopper.close(); 119 break; 120 } 121 } 122 return chopper.path(); 123} 124 125} // namespace skgpu 126