Flutter Engine
The Flutter Engine
GrAAConvexTessellator.h
Go to the documentation of this file.
1/*
2 * Copyright 2015 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
8#ifndef GrAAConvexTessellator_DEFINED
9#define GrAAConvexTessellator_DEFINED
10
18
19class SkMatrix;
20class SkPath;
21
22//#define GR_AA_CONVEX_TESSELLATOR_VIZ 1
23
24// device space distance which we inset / outset points in order to create the soft antialiased edge
25static const SkScalar kAntialiasingRadius = 0.5f;
26
27// The AAConvexTessellator holds the global pool of points and the triangulation
28// that connects them. It also drives the tessellation process.
29// The outward facing normals of the original polygon are stored (in 'fNorms') to service
30// computeDepthFromEdge requests.
32public:
34 SkScalar strokeWidth = -1.0f,
35 SkPaint::Join join = SkPaint::Join::kBevel_Join,
36 SkScalar miterLimit = 0.0f)
37 : fSide(SkPointPriv::kOn_Side)
38 , fStrokeWidth(strokeWidth)
39 , fStyle(style)
40 , fJoin(join)
41 , fMiterLimit(miterLimit) {
42 }
43
44 SkPointPriv::Side side() const { return fSide; }
45
46 bool tessellate(const SkMatrix& m, const SkPath& path);
47
48 // The next five should only be called after tessellate to extract the result
49 int numPts() const { return fPts.size(); }
50 int numIndices() const { return fIndices.size(); }
51
52 const SkPoint& lastPoint() const { return fPts.back(); }
53 const SkPoint& point(int index) const { return fPts[index]; }
54 int index(int index) const { return fIndices[index]; }
55 SkScalar coverage(int index) const { return fCoverages[index]; }
56
57#if GR_AA_CONVEX_TESSELLATOR_VIZ
58 void draw(SkCanvas* canvas) const;
59#endif
60
61 // The tessellator can be reused for multiple paths by clearing in between
62 void rewind();
63
64private:
65 // CandidateVerts holds the vertices for the next ring while they are
66 // being generated. Its main function is to de-dup the points.
67 class CandidateVerts {
68 public:
69 void setReserve(int numPts) { fPts.reserve(numPts); }
70 void rewind() { fPts.clear(); }
71
72 int numPts() const { return fPts.size(); }
73
74 const SkPoint& lastPoint() const { return fPts.back().fPt; }
75 const SkPoint& firstPoint() const { return fPts[0].fPt; }
76 const SkPoint& point(int index) const { return fPts[index].fPt; }
77
78 int originatingIdx(int index) const { return fPts[index].fOriginatingIdx; }
79 int origEdge(int index) const { return fPts[index].fOrigEdgeId; }
80 bool needsToBeNew(int index) const { return fPts[index].fNeedsToBeNew; }
81
82 int addNewPt(const SkPoint& newPt, int originatingIdx, int origEdge, bool needsToBeNew) {
83 struct PointData* pt = fPts.append();
84 pt->fPt = newPt;
85 pt->fOrigEdgeId = origEdge;
86 pt->fOriginatingIdx = originatingIdx;
87 pt->fNeedsToBeNew = needsToBeNew;
88 return fPts.size() - 1;
89 }
90
91 int fuseWithPrior(int origEdgeId) {
92 fPts.back().fOrigEdgeId = origEdgeId;
93 fPts.back().fOriginatingIdx = -1;
94 fPts.back().fNeedsToBeNew = true;
95 return fPts.size() - 1;
96 }
97
98 int fuseWithNext() {
99 fPts[0].fOriginatingIdx = -1;
100 fPts[0].fNeedsToBeNew = true;
101 return 0;
102 }
103
104 int fuseWithBoth() {
105 if (fPts.size() > 1) {
106 fPts.pop_back();
107 }
108
109 fPts[0].fOriginatingIdx = -1;
110 fPts[0].fNeedsToBeNew = true;
111 return 0;
112 }
113
114 private:
115 struct PointData {
116 SkPoint fPt;
117 int fOriginatingIdx;
118 int fOrigEdgeId;
119 bool fNeedsToBeNew;
120 };
121
123 };
124
125 // The Ring holds a set of indices into the global pool that together define
126 // a single polygon inset.
127 class Ring {
128 public:
129 void setReserve(int numPts) { fPts.reserve(numPts); }
130 void rewind() { fPts.clear(); }
131
132 int numPts() const { return fPts.size(); }
133
134 void addIdx(int index, int origEdgeId) {
135 struct PointData* pt = fPts.append();
136 pt->fIndex = index;
137 pt->fOrigEdgeId = origEdgeId;
138 }
139
140 // Upgrade this ring so that it can behave like an originating ring
141 void makeOriginalRing() {
142 for (int i = 0; i < fPts.size(); ++i) {
143 fPts[i].fOrigEdgeId = fPts[i].fIndex;
144 }
145 }
146
147 // init should be called after all the indices have been added (via addIdx)
148 void init(const GrAAConvexTessellator& tess);
149 void init(const SkTDArray<SkVector>& norms, const SkTDArray<SkVector>& bisectors);
150
151 const SkPoint& norm(int index) const { return fPts[index].fNorm; }
152 const SkPoint& bisector(int index) const { return fPts[index].fBisector; }
153 int index(int index) const { return fPts[index].fIndex; }
154 int origEdgeID(int index) const { return fPts[index].fOrigEdgeId; }
155 void setOrigEdgeId(int index, int id) { fPts[index].fOrigEdgeId = id; }
156
157 #if GR_AA_CONVEX_TESSELLATOR_VIZ
158 void draw(SkCanvas* canvas, const GrAAConvexTessellator& tess) const;
159 #endif
160
161 private:
162 void computeNormals(const GrAAConvexTessellator& result);
163 void computeBisectors(const GrAAConvexTessellator& tess);
164
165 SkDEBUGCODE(bool isConvex(const GrAAConvexTessellator& tess) const;)
166
167 struct PointData {
168 SkPoint fNorm;
169 SkPoint fBisector;
170 int fIndex;
171 int fOrigEdgeId;
172 };
173
175 };
176
177 // Represents whether a given point is within a curve. A point is inside a curve only if it is
178 // an interior point within a quad, cubic, or conic, or if it is the endpoint of a quad, cubic,
179 // or conic with another curve meeting it at (more or less) the same angle.
180 enum CurveState {
181 // point is a sharp vertex
182 kSharp_CurveState,
183 // endpoint of a curve with the other side's curvature not yet determined
184 kIndeterminate_CurveState,
185 // point is in the interior of a curve
186 kCurve_CurveState
187 };
188
189 bool movable(int index) const { return fMovable[index]; }
190
191 // Movable points are those that can be slid along their bisector.
192 // Basically, a point is immovable if it is part of the original
193 // polygon or it results from the fusing of two bisectors.
194 int addPt(const SkPoint& pt, SkScalar depth, SkScalar coverage, bool movable, CurveState curve);
195 void popLastPt();
196 void popFirstPtShuffle();
197
198 void updatePt(int index, const SkPoint& pt, SkScalar depth, SkScalar coverage);
199
200 void addTri(int i0, int i1, int i2);
201
202 void reservePts(int count) {
203 fPts.reserve(count);
204 fCoverages.reserve(count);
205 fMovable.reserve(count);
206 }
207
208 SkScalar computeDepthFromEdge(int edgeIdx, const SkPoint& p) const;
209
210 bool computePtAlongBisector(int startIdx, const SkPoint& bisector,
211 int edgeIdx, SkScalar desiredDepth,
212 SkPoint* result) const;
213
214 void lineTo(const SkPoint& p, CurveState curve);
215
216 void lineTo(const SkMatrix& m, const SkPoint& p, CurveState curve);
217
218 void quadTo(const SkPoint pts[3]);
219
220 void quadTo(const SkMatrix& m, const SkPoint pts[3]);
221
222 void cubicTo(const SkMatrix& m, const SkPoint pts[4]);
223
224 void conicTo(const SkMatrix& m, const SkPoint pts[3], SkScalar w);
225
226 void terminate(const Ring& lastRing);
227
228 // return false on failure/degenerate path
229 bool extractFromPath(const SkMatrix& m, const SkPath& path);
230 void computeBisectors();
231 void computeNormals();
232
233 void fanRing(const Ring& ring);
234
235 Ring* getNextRing(Ring* lastRing);
236
237 void createOuterRing(const Ring& previousRing, SkScalar outset, SkScalar coverage,
238 Ring* nextRing);
239
240 bool createInsetRings(Ring& previousRing, SkScalar initialDepth, SkScalar initialCoverage,
241 SkScalar targetDepth, SkScalar targetCoverage, Ring** finalRing);
242
243 bool createInsetRing(const Ring& lastRing, Ring* nextRing,
244 SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth,
245 SkScalar targetCoverage, bool forceNew);
246
247 void validate() const;
248
249 // fPts, fCoverages, fMovable & fCurveState should always have the same # of elements
251 SkTDArray<SkScalar> fCoverages;
252 // movable points are those that can be slid further along their bisector
253 SkTDArray<bool> fMovable;
254 // Tracks whether a given point is interior to a curve. Such points are
255 // assumed to have shallow curvature.
256 SkTDArray<CurveState> fCurveState;
257
258 // The outward facing normals for the original polygon
260 // The inward facing bisector at each point in the original polygon. Only
261 // needed for exterior ring creation and then handed off to the initial ring.
262 SkTDArray<SkVector> fBisectors;
263
264 SkPointPriv::Side fSide; // winding of the original polygon
265
266 // The triangulation of the points
267 SkTDArray<int> fIndices;
268
269 Ring fInitialRing;
270#if GR_AA_CONVEX_TESSELLATOR_VIZ
271 // When visualizing save all the rings
272 SkTDArray<Ring*> fRings;
273#else
274 Ring fRings[2];
275#endif
276 CandidateVerts fCandidateVerts;
277
278 // the stroke width is only used for stroke or stroke-and-fill styles
279 SkScalar fStrokeWidth;
281
283
285
286 // accumulated error when removing near colinear points to prevent an
287 // overly greedy simplification
288 SkScalar fAccumLinearError;
289
290 SkTDArray<SkPoint> fPointBuffer;
291};
292
293
294#endif
SkPoint fPts[2]
SkVector fNorms[2]
SkPaint::Join fJoin
SkStrokeRec::Style fStyle
static const int outset
Definition: BlurTest.cpp:58
static const int strokeWidth
Definition: BlurTest.cpp:60
int count
Definition: FontMgrTest.cpp:50
static const SkScalar kAntialiasingRadius
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition: aaclip.cpp:27
bool tessellate(const SkMatrix &m, const SkPath &path)
const SkPoint & lastPoint() const
SkScalar coverage(int index) const
GrAAConvexTessellator(SkStrokeRec::Style style=SkStrokeRec::kFill_Style, SkScalar strokeWidth=-1.0f, SkPaint::Join join=SkPaint::Join::kBevel_Join, SkScalar miterLimit=0.0f)
SkPointPriv::Side side() const
const SkPoint & point(int index) const
int index(int index) const
Definition: SkPath.h:59
const T & back() const
Definition: SkTDArray.h:162
int size() const
Definition: SkTDArray.h:138
void reserve(int n)
Definition: SkTDArray.h:187
float SkScalar
Definition: extension.cpp:12
GAsyncResult * result
static bool init()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
static TessellatorLibtess tess
SkScalar w
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741
const uintptr_t id