OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrTessellatingPathRenderer.h" | 8 #include "GrTessellatingPathRenderer.h" |
9 | 9 |
10 #include "GrBatchFlushState.h" | 10 #include "GrBatchFlushState.h" |
11 #include "GrBatchTest.h" | 11 #include "GrBatchTest.h" |
12 #include "GrDefaultGeoProcFactory.h" | 12 #include "GrDefaultGeoProcFactory.h" |
13 #include "GrPathUtils.h" | 13 #include "GrPathUtils.h" |
14 #include "GrVertices.h" | 14 #include "GrVertices.h" |
15 #include "GrResourceCache.h" | 15 #include "GrResourceCache.h" |
16 #include "GrResourceProvider.h" | 16 #include "GrResourceProvider.h" |
17 #include "SkChunkAlloc.h" | 17 #include "GrTessellator.h" |
18 #include "SkGeometry.h" | 18 #include "SkGeometry.h" |
19 | 19 |
20 #include "batches/GrVertexBatch.h" | 20 #include "batches/GrVertexBatch.h" |
21 | 21 |
22 #include <stdio.h> | 22 #include <stdio.h> |
23 | 23 |
24 /* | 24 /* |
25 * This path renderer tessellates the path into triangles, uploads the triangles
to a | 25 * This path renderer tessellates the path into triangles using GrTessellator, u
ploads the triangles |
26 * vertex buffer, and renders them with a single draw call. It does not currentl
y do | 26 * to a vertex buffer, and renders them with a single draw call. It does not cur
rently do |
27 * antialiasing, so it must be used in conjunction with multisampling. | 27 * antialiasing, so it must be used in conjunction with multisampling. |
28 * | |
29 * There are six stages to the algorithm: | |
30 * | |
31 * 1) Linearize the path contours into piecewise linear segments (path_to_contou
rs()). | |
32 * 2) Build a mesh of edges connecting the vertices (build_edges()). | |
33 * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()). | |
34 * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplif
y()). | |
35 * 5) Tessellate the simplified mesh into monotone polygons (tessellate()). | |
36 * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_
triangles()). | |
37 * | |
38 * The vertex sorting in step (3) is a merge sort, since it plays well with the
linked list | |
39 * of vertices (and the necessity of inserting new vertices on intersection). | |
40 * | |
41 * Stages (4) and (5) use an active edge list, which a list of all edges for whi
ch the | |
42 * sweep line has crossed the top vertex, but not the bottom vertex. It's sorte
d | |
43 * left-to-right based on the point where both edges are active (when both top v
ertices | |
44 * have been seen, so the "lower" top vertex of the two). If the top vertices ar
e equal | |
45 * (shared), it's sorted based on the last point where both edges are active, so
the | |
46 * "upper" bottom vertex. | |
47 * | |
48 * The most complex step is the simplification (4). It's based on the Bentley-Ot
tman | |
49 * line-sweep algorithm, but due to floating point inaccuracy, the intersection
points are | |
50 * not exact and may violate the mesh topology or active edge list ordering. We | |
51 * accommodate this by adjusting the topology of the mesh and AEL to match the i
ntersection | |
52 * points. This occurs in three ways: | |
53 * | |
54 * A) Intersections may cause a shortened edge to no longer be ordered with resp
ect to its | |
55 * neighbouring edges at the top or bottom vertex. This is handled by merging
the | |
56 * edges (merge_collinear_edges()). | |
57 * B) Intersections may cause an edge to violate the left-to-right ordering of t
he | |
58 * active edge list. This is handled by splitting the neighbour edge on the | |
59 * intersected vertex (cleanup_active_edges()). | |
60 * C) Shortening an edge may cause an active edge to become inactive or an inact
ive edge | |
61 * to become active. This is handled by removing or inserting the edge in the
active | |
62 * edge list (fix_active_state()). | |
63 * | |
64 * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygon
s and | |
65 * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Not
e that it | |
66 * currently uses a linked list for the active edge list, rather than a 2-3 tree
as the | |
67 * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and remova
l also | |
68 * become O(lg N). In all the test cases, it was found that the cost of frequent
O(lg N) | |
69 * insertions and removals was greater than the cost of infrequent O(N) lookups
with the | |
70 * linked list implementation. With the latter, all removals are O(1), and most
insertions | |
71 * are O(1), since we know the adjacent edge in the active edge list based on th
e topology. | |
72 * Only type 2 vertices (see paper) require the O(N) lookups, and these are much
less | |
73 * frequent. There may be other data structures worth investigating, however. | |
74 * | |
75 * Note that the orientation of the line sweep algorithms is determined by the a
spect ratio of the | |
76 * path bounds. When the path is taller than it is wide, we sort vertices based
on increasing Y | |
77 * coordinate, and secondarily by increasing X coordinate. When the path is wide
r than it is tall, | |
78 * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordin
ate. This is so | |
79 * that the "left" and "right" orientation in the code remains correct (edges to
the left are | |
80 * increasing in Y; edges to the right are decreasing in Y). That is, the settin
g rotates 90 | |
81 * degrees counterclockwise, rather that transposing. | |
82 */ | 28 */ |
83 #define LOGGING_ENABLED 0 | |
84 #define WIREFRAME 0 | |
85 | |
86 #if LOGGING_ENABLED | |
87 #define LOG printf | |
88 #else | |
89 #define LOG(...) | |
90 #endif | |
91 | |
92 #define ALLOC_NEW(Type, args, alloc) new (alloc.allocThrow(sizeof(Type))) Type a
rgs | |
93 | |
94 namespace { | 29 namespace { |
95 | 30 |
96 struct Vertex; | |
97 struct Edge; | |
98 struct Poly; | |
99 | |
100 template <class T, T* T::*Prev, T* T::*Next> | |
101 void insert(T* t, T* prev, T* next, T** head, T** tail) { | |
102 t->*Prev = prev; | |
103 t->*Next = next; | |
104 if (prev) { | |
105 prev->*Next = t; | |
106 } else if (head) { | |
107 *head = t; | |
108 } | |
109 if (next) { | |
110 next->*Prev = t; | |
111 } else if (tail) { | |
112 *tail = t; | |
113 } | |
114 } | |
115 | |
116 template <class T, T* T::*Prev, T* T::*Next> | |
117 void remove(T* t, T** head, T** tail) { | |
118 if (t->*Prev) { | |
119 t->*Prev->*Next = t->*Next; | |
120 } else if (head) { | |
121 *head = t->*Next; | |
122 } | |
123 if (t->*Next) { | |
124 t->*Next->*Prev = t->*Prev; | |
125 } else if (tail) { | |
126 *tail = t->*Prev; | |
127 } | |
128 t->*Prev = t->*Next = nullptr; | |
129 } | |
130 | |
131 /** | |
132 * Vertices are used in three ways: first, the path contours are converted into
a | |
133 * circularly-linked list of Vertices for each contour. After edge construction,
the same Vertices | |
134 * are re-ordered by the merge sort according to the sweep_lt comparator (usuall
y, increasing | |
135 * in Y) using the same fPrev/fNext pointers that were used for the contours, to
avoid | |
136 * reallocation. Finally, MonotonePolys are built containing a circularly-linked
list of | |
137 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePoly
s, since | |
138 * an individual Vertex from the path mesh may belong to multiple | |
139 * MonotonePolys, so the original Vertices cannot be re-used. | |
140 */ | |
141 | |
142 struct Vertex { | |
143 Vertex(const SkPoint& point) | |
144 : fPoint(point), fPrev(nullptr), fNext(nullptr) | |
145 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) | |
146 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) | |
147 , fProcessed(false) | |
148 #if LOGGING_ENABLED | |
149 , fID (-1.0f) | |
150 #endif | |
151 {} | |
152 SkPoint fPoint; // Vertex position | |
153 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices
. | |
154 Vertex* fNext; // " | |
155 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex. | |
156 Edge* fLastEdgeAbove; // " | |
157 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. | |
158 Edge* fLastEdgeBelow; // " | |
159 bool fProcessed; // Has this vertex been seen in simplify()? | |
160 #if LOGGING_ENABLED | |
161 float fID; // Identifier used for logging. | |
162 #endif | |
163 }; | |
164 | |
165 /*******************************************************************************
********/ | |
166 | |
167 typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b); | |
168 | |
169 struct Comparator { | |
170 CompareFunc sweep_lt; | |
171 CompareFunc sweep_gt; | |
172 }; | |
173 | |
174 bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) { | |
175 return a.fX == b.fX ? a.fY > b.fY : a.fX < b.fX; | |
176 } | |
177 | |
178 bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) { | |
179 return a.fY == b.fY ? a.fX < b.fX : a.fY < b.fY; | |
180 } | |
181 | |
182 bool sweep_gt_horiz(const SkPoint& a, const SkPoint& b) { | |
183 return a.fX == b.fX ? a.fY < b.fY : a.fX > b.fX; | |
184 } | |
185 | |
186 bool sweep_gt_vert(const SkPoint& a, const SkPoint& b) { | |
187 return a.fY == b.fY ? a.fX > b.fX : a.fY > b.fY; | |
188 } | |
189 | |
190 inline SkPoint* emit_vertex(Vertex* v, SkPoint* data) { | |
191 *data++ = v->fPoint; | |
192 return data; | |
193 } | |
194 | |
195 SkPoint* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, SkPoint* data) { | |
196 #if WIREFRAME | |
197 data = emit_vertex(v0, data); | |
198 data = emit_vertex(v1, data); | |
199 data = emit_vertex(v1, data); | |
200 data = emit_vertex(v2, data); | |
201 data = emit_vertex(v2, data); | |
202 data = emit_vertex(v0, data); | |
203 #else | |
204 data = emit_vertex(v0, data); | |
205 data = emit_vertex(v1, data); | |
206 data = emit_vertex(v2, data); | |
207 #endif | |
208 return data; | |
209 } | |
210 | |
211 struct EdgeList { | |
212 EdgeList() : fHead(nullptr), fTail(nullptr) {} | |
213 Edge* fHead; | |
214 Edge* fTail; | |
215 }; | |
216 | |
217 /** | |
218 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of
"edges above" and | |
219 * "edge below" a vertex as well as for the active edge list is handled by isLef
tOf()/isRightOf(). | |
220 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (b
ecause floating | |
221 * point). For speed, that case is only tested by the callers which require it (
e.g., | |
222 * cleanup_active_edges()). Edges also handle checking for intersection with oth
er edges. | |
223 * Currently, this converts the edges to the parametric form, in order to avoid
doing a division | |
224 * until an intersection has been confirmed. This is slightly slower in the "fou
nd" case, but | |
225 * a lot faster in the "not found" case. | |
226 * | |
227 * The coefficients of the line equation stored in double precision to avoid cat
astrphic | |
228 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures
that the result is | |
229 * correct in float, since it's a polynomial of degree 2. The intersect() functi
on, being | |
230 * degree 5, is still subject to catastrophic cancellation. We deal with that by
assuming its | |
231 * output may be incorrect, and adjusting the mesh topology to match (see commen
t at the top of | |
232 * this file). | |
233 */ | |
234 | |
235 struct Edge { | |
236 Edge(Vertex* top, Vertex* bottom, int winding) | |
237 : fWinding(winding) | |
238 , fTop(top) | |
239 , fBottom(bottom) | |
240 , fLeft(nullptr) | |
241 , fRight(nullptr) | |
242 , fPrevEdgeAbove(nullptr) | |
243 , fNextEdgeAbove(nullptr) | |
244 , fPrevEdgeBelow(nullptr) | |
245 , fNextEdgeBelow(nullptr) | |
246 , fLeftPoly(nullptr) | |
247 , fRightPoly(nullptr) { | |
248 recompute(); | |
249 } | |
250 int fWinding; // 1 == edge goes downward; -1 = edge goes upwar
d. | |
251 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt
). | |
252 Vertex* fBottom; // The bottom vertex in vertex-sort-order. | |
253 Edge* fLeft; // The linked list of edges in the active edge l
ist. | |
254 Edge* fRight; // " | |
255 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex
's "edges above". | |
256 Edge* fNextEdgeAbove; // " | |
257 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's
"edges below". | |
258 Edge* fNextEdgeBelow; // " | |
259 Poly* fLeftPoly; // The Poly to the left of this edge, if any. | |
260 Poly* fRightPoly; // The Poly to the right of this edge, if any. | |
261 double fDX; // The line equation for this edge, in implicit
form. | |
262 double fDY; // fDY * x + fDX * y + fC = 0, for point (x, y)
on the line. | |
263 double fC; | |
264 double dist(const SkPoint& p) const { | |
265 return fDY * p.fX - fDX * p.fY + fC; | |
266 } | |
267 bool isRightOf(Vertex* v) const { | |
268 return dist(v->fPoint) < 0.0; | |
269 } | |
270 bool isLeftOf(Vertex* v) const { | |
271 return dist(v->fPoint) > 0.0; | |
272 } | |
273 void recompute() { | |
274 fDX = static_cast<double>(fBottom->fPoint.fX) - fTop->fPoint.fX; | |
275 fDY = static_cast<double>(fBottom->fPoint.fY) - fTop->fPoint.fY; | |
276 fC = static_cast<double>(fTop->fPoint.fY) * fBottom->fPoint.fX - | |
277 static_cast<double>(fTop->fPoint.fX) * fBottom->fPoint.fY; | |
278 } | |
279 bool intersect(const Edge& other, SkPoint* p) { | |
280 LOG("intersecting %g -> %g with %g -> %g\n", | |
281 fTop->fID, fBottom->fID, | |
282 other.fTop->fID, other.fBottom->fID); | |
283 if (fTop == other.fTop || fBottom == other.fBottom) { | |
284 return false; | |
285 } | |
286 double denom = fDX * other.fDY - fDY * other.fDX; | |
287 if (denom == 0.0) { | |
288 return false; | |
289 } | |
290 double dx = static_cast<double>(fTop->fPoint.fX) - other.fTop->fPoint.fX
; | |
291 double dy = static_cast<double>(fTop->fPoint.fY) - other.fTop->fPoint.fY
; | |
292 double sNumer = dy * other.fDX - dx * other.fDY; | |
293 double tNumer = dy * fDX - dx * fDY; | |
294 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early. | |
295 // This saves us doing the divide below unless absolutely necessary. | |
296 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNu
mer > denom) | |
297 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNu
mer < denom)) { | |
298 return false; | |
299 } | |
300 double s = sNumer / denom; | |
301 SkASSERT(s >= 0.0 && s <= 1.0); | |
302 p->fX = SkDoubleToScalar(fTop->fPoint.fX + s * fDX); | |
303 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fDY); | |
304 return true; | |
305 } | |
306 bool isActive(EdgeList* activeEdges) const { | |
307 return activeEdges && (fLeft || fRight || activeEdges->fHead == this); | |
308 } | |
309 }; | |
310 | |
311 /*******************************************************************************
********/ | |
312 | |
313 struct Poly { | |
314 Poly(int winding) | |
315 : fWinding(winding) | |
316 , fHead(nullptr) | |
317 , fTail(nullptr) | |
318 , fActive(nullptr) | |
319 , fNext(nullptr) | |
320 , fPartner(nullptr) | |
321 , fCount(0) | |
322 { | |
323 #if LOGGING_ENABLED | |
324 static int gID = 0; | |
325 fID = gID++; | |
326 LOG("*** created Poly %d\n", fID); | |
327 #endif | |
328 } | |
329 typedef enum { kNeither_Side, kLeft_Side, kRight_Side } Side; | |
330 struct MonotonePoly { | |
331 MonotonePoly() | |
332 : fSide(kNeither_Side) | |
333 , fHead(nullptr) | |
334 , fTail(nullptr) | |
335 , fPrev(nullptr) | |
336 , fNext(nullptr) {} | |
337 Side fSide; | |
338 Vertex* fHead; | |
339 Vertex* fTail; | |
340 MonotonePoly* fPrev; | |
341 MonotonePoly* fNext; | |
342 bool addVertex(Vertex* v, Side side, SkChunkAlloc& alloc) { | |
343 Vertex* newV = ALLOC_NEW(Vertex, (v->fPoint), alloc); | |
344 bool done = false; | |
345 if (fSide == kNeither_Side) { | |
346 fSide = side; | |
347 } else { | |
348 done = side != fSide; | |
349 } | |
350 if (fHead == nullptr) { | |
351 fHead = fTail = newV; | |
352 } else if (fSide == kRight_Side) { | |
353 newV->fPrev = fTail; | |
354 fTail->fNext = newV; | |
355 fTail = newV; | |
356 } else { | |
357 newV->fNext = fHead; | |
358 fHead->fPrev = newV; | |
359 fHead = newV; | |
360 } | |
361 return done; | |
362 } | |
363 | |
364 SkPoint* emit(SkPoint* data) { | |
365 Vertex* first = fHead; | |
366 Vertex* v = first->fNext; | |
367 while (v != fTail) { | |
368 SkASSERT(v && v->fPrev && v->fNext); | |
369 Vertex* prev = v->fPrev; | |
370 Vertex* curr = v; | |
371 Vertex* next = v->fNext; | |
372 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.
fX; | |
373 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.
fY; | |
374 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.
fX; | |
375 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.
fY; | |
376 if (ax * by - ay * bx >= 0.0) { | |
377 data = emit_triangle(prev, curr, next, data); | |
378 v->fPrev->fNext = v->fNext; | |
379 v->fNext->fPrev = v->fPrev; | |
380 if (v->fPrev == first) { | |
381 v = v->fNext; | |
382 } else { | |
383 v = v->fPrev; | |
384 } | |
385 } else { | |
386 v = v->fNext; | |
387 } | |
388 } | |
389 return data; | |
390 } | |
391 }; | |
392 Poly* addVertex(Vertex* v, Side side, SkChunkAlloc& alloc) { | |
393 LOG("addVertex() to %d at %g (%g, %g), %s side\n", fID, v->fID, v->fPoin
t.fX, v->fPoint.fY, | |
394 side == kLeft_Side ? "left" : side == kRight_Side ? "right" : "ne
ither"); | |
395 Poly* partner = fPartner; | |
396 Poly* poly = this; | |
397 if (partner) { | |
398 fPartner = partner->fPartner = nullptr; | |
399 } | |
400 if (!fActive) { | |
401 fActive = ALLOC_NEW(MonotonePoly, (), alloc); | |
402 } | |
403 if (fActive->addVertex(v, side, alloc)) { | |
404 if (fTail) { | |
405 fActive->fPrev = fTail; | |
406 fTail->fNext = fActive; | |
407 fTail = fActive; | |
408 } else { | |
409 fHead = fTail = fActive; | |
410 } | |
411 if (partner) { | |
412 partner->addVertex(v, side, alloc); | |
413 poly = partner; | |
414 } else { | |
415 Vertex* prev = fActive->fSide == Poly::kLeft_Side ? | |
416 fActive->fHead->fNext : fActive->fTail->fPrev; | |
417 fActive = ALLOC_NEW(MonotonePoly, , alloc); | |
418 fActive->addVertex(prev, Poly::kNeither_Side, alloc); | |
419 fActive->addVertex(v, side, alloc); | |
420 } | |
421 } | |
422 fCount++; | |
423 return poly; | |
424 } | |
425 void end(Vertex* v, SkChunkAlloc& alloc) { | |
426 LOG("end() %d at %g, %g\n", fID, v->fPoint.fX, v->fPoint.fY); | |
427 if (fPartner) { | |
428 fPartner = fPartner->fPartner = nullptr; | |
429 } | |
430 addVertex(v, fActive->fSide == kLeft_Side ? kRight_Side : kLeft_Side, al
loc); | |
431 } | |
432 SkPoint* emit(SkPoint *data) { | |
433 if (fCount < 3) { | |
434 return data; | |
435 } | |
436 LOG("emit() %d, size %d\n", fID, fCount); | |
437 for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) { | |
438 data = m->emit(data); | |
439 } | |
440 return data; | |
441 } | |
442 int fWinding; | |
443 MonotonePoly* fHead; | |
444 MonotonePoly* fTail; | |
445 MonotonePoly* fActive; | |
446 Poly* fNext; | |
447 Poly* fPartner; | |
448 int fCount; | |
449 #if LOGGING_ENABLED | |
450 int fID; | |
451 #endif | |
452 }; | |
453 | |
454 /*******************************************************************************
********/ | |
455 | |
456 bool coincident(const SkPoint& a, const SkPoint& b) { | |
457 return a == b; | |
458 } | |
459 | |
460 Poly* new_poly(Poly** head, Vertex* v, int winding, SkChunkAlloc& alloc) { | |
461 Poly* poly = ALLOC_NEW(Poly, (winding), alloc); | |
462 poly->addVertex(v, Poly::kNeither_Side, alloc); | |
463 poly->fNext = *head; | |
464 *head = poly; | |
465 return poly; | |
466 } | |
467 | |
468 Vertex* append_point_to_contour(const SkPoint& p, Vertex* prev, Vertex** head, | |
469 SkChunkAlloc& alloc) { | |
470 Vertex* v = ALLOC_NEW(Vertex, (p), alloc); | |
471 #if LOGGING_ENABLED | |
472 static float gID = 0.0f; | |
473 v->fID = gID++; | |
474 #endif | |
475 if (prev) { | |
476 prev->fNext = v; | |
477 v->fPrev = prev; | |
478 } else { | |
479 *head = v; | |
480 } | |
481 return v; | |
482 } | |
483 | |
484 Vertex* generate_quadratic_points(const SkPoint& p0, | |
485 const SkPoint& p1, | |
486 const SkPoint& p2, | |
487 SkScalar tolSqd, | |
488 Vertex* prev, | |
489 Vertex** head, | |
490 int pointsLeft, | |
491 SkChunkAlloc& alloc) { | |
492 SkScalar d = p1.distanceToLineSegmentBetweenSqd(p0, p2); | |
493 if (pointsLeft < 2 || d < tolSqd || !SkScalarIsFinite(d)) { | |
494 return append_point_to_contour(p2, prev, head, alloc); | |
495 } | |
496 | |
497 const SkPoint q[] = { | |
498 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, | |
499 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, | |
500 }; | |
501 const SkPoint r = { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1]
.fY) }; | |
502 | |
503 pointsLeft >>= 1; | |
504 prev = generate_quadratic_points(p0, q[0], r, tolSqd, prev, head, pointsLeft
, alloc); | |
505 prev = generate_quadratic_points(r, q[1], p2, tolSqd, prev, head, pointsLeft
, alloc); | |
506 return prev; | |
507 } | |
508 | |
509 Vertex* generate_cubic_points(const SkPoint& p0, | |
510 const SkPoint& p1, | |
511 const SkPoint& p2, | |
512 const SkPoint& p3, | |
513 SkScalar tolSqd, | |
514 Vertex* prev, | |
515 Vertex** head, | |
516 int pointsLeft, | |
517 SkChunkAlloc& alloc) { | |
518 SkScalar d1 = p1.distanceToLineSegmentBetweenSqd(p0, p3); | |
519 SkScalar d2 = p2.distanceToLineSegmentBetweenSqd(p0, p3); | |
520 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || | |
521 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) { | |
522 return append_point_to_contour(p3, prev, head, alloc); | |
523 } | |
524 const SkPoint q[] = { | |
525 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, | |
526 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, | |
527 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) } | |
528 }; | |
529 const SkPoint r[] = { | |
530 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }, | |
531 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) } | |
532 }; | |
533 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1]
.fY) }; | |
534 pointsLeft >>= 1; | |
535 prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLe
ft, alloc); | |
536 prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLe
ft, alloc); | |
537 return prev; | |
538 } | |
539 | |
540 // Stage 1: convert the input path to a set of linear contours (linked list of V
ertices). | |
541 | |
542 void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip
Bounds, | |
543 Vertex** contours, SkChunkAlloc& alloc, bool *isLinear) { | |
544 | |
545 SkScalar toleranceSqd = tolerance * tolerance; | |
546 | |
547 SkPoint pts[4]; | |
548 bool done = false; | |
549 *isLinear = true; | |
550 SkPath::Iter iter(path, false); | |
551 Vertex* prev = nullptr; | |
552 Vertex* head = nullptr; | |
553 if (path.isInverseFillType()) { | |
554 SkPoint quad[4]; | |
555 clipBounds.toQuad(quad); | |
556 for (int i = 3; i >= 0; i--) { | |
557 prev = append_point_to_contour(quad[i], prev, &head, alloc); | |
558 } | |
559 head->fPrev = prev; | |
560 prev->fNext = head; | |
561 *contours++ = head; | |
562 head = prev = nullptr; | |
563 } | |
564 SkAutoConicToQuads converter; | |
565 while (!done) { | |
566 SkPath::Verb verb = iter.next(pts); | |
567 switch (verb) { | |
568 case SkPath::kConic_Verb: { | |
569 SkScalar weight = iter.conicWeight(); | |
570 const SkPoint* quadPts = converter.computeQuads(pts, weight, tol
eranceSqd); | |
571 for (int i = 0; i < converter.countQuads(); ++i) { | |
572 int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, t
olerance); | |
573 prev = generate_quadratic_points(quadPts[0], quadPts[1], qua
dPts[2], | |
574 toleranceSqd, prev, &head,
pointsLeft, alloc); | |
575 quadPts += 2; | |
576 } | |
577 *isLinear = false; | |
578 break; | |
579 } | |
580 case SkPath::kMove_Verb: | |
581 if (head) { | |
582 head->fPrev = prev; | |
583 prev->fNext = head; | |
584 *contours++ = head; | |
585 } | |
586 head = prev = nullptr; | |
587 prev = append_point_to_contour(pts[0], prev, &head, alloc); | |
588 break; | |
589 case SkPath::kLine_Verb: { | |
590 prev = append_point_to_contour(pts[1], prev, &head, alloc); | |
591 break; | |
592 } | |
593 case SkPath::kQuad_Verb: { | |
594 int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance
); | |
595 prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleran
ceSqd, prev, | |
596 &head, pointsLeft, alloc); | |
597 *isLinear = false; | |
598 break; | |
599 } | |
600 case SkPath::kCubic_Verb: { | |
601 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); | |
602 prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], | |
603 toleranceSqd, prev, &head, pointsLeft, alloc); | |
604 *isLinear = false; | |
605 break; | |
606 } | |
607 case SkPath::kClose_Verb: | |
608 if (head) { | |
609 head->fPrev = prev; | |
610 prev->fNext = head; | |
611 *contours++ = head; | |
612 } | |
613 head = prev = nullptr; | |
614 break; | |
615 case SkPath::kDone_Verb: | |
616 if (head) { | |
617 head->fPrev = prev; | |
618 prev->fNext = head; | |
619 *contours++ = head; | |
620 } | |
621 done = true; | |
622 break; | |
623 } | |
624 } | |
625 } | |
626 | |
627 inline bool apply_fill_type(SkPath::FillType fillType, int winding) { | |
628 switch (fillType) { | |
629 case SkPath::kWinding_FillType: | |
630 return winding != 0; | |
631 case SkPath::kEvenOdd_FillType: | |
632 return (winding & 1) != 0; | |
633 case SkPath::kInverseWinding_FillType: | |
634 return winding == 1; | |
635 case SkPath::kInverseEvenOdd_FillType: | |
636 return (winding & 1) == 1; | |
637 default: | |
638 SkASSERT(false); | |
639 return false; | |
640 } | |
641 } | |
642 | |
643 Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c) { | |
644 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; | |
645 Vertex* top = winding < 0 ? next : prev; | |
646 Vertex* bottom = winding < 0 ? prev : next; | |
647 return ALLOC_NEW(Edge, (top, bottom, winding), alloc); | |
648 } | |
649 | |
650 void remove_edge(Edge* edge, EdgeList* edges) { | |
651 LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); | |
652 SkASSERT(edge->isActive(edges)); | |
653 remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &edges->fHead, &edges->fTail
); | |
654 } | |
655 | |
656 void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) { | |
657 LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); | |
658 SkASSERT(!edge->isActive(edges)); | |
659 Edge* next = prev ? prev->fRight : edges->fHead; | |
660 insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &edges->fHead, &
edges->fTail); | |
661 } | |
662 | |
663 void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right)
{ | |
664 if (v->fFirstEdgeAbove) { | |
665 *left = v->fFirstEdgeAbove->fLeft; | |
666 *right = v->fLastEdgeAbove->fRight; | |
667 return; | |
668 } | |
669 Edge* next = nullptr; | |
670 Edge* prev; | |
671 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) { | |
672 if (prev->isLeftOf(v)) { | |
673 break; | |
674 } | |
675 next = prev; | |
676 } | |
677 *left = prev; | |
678 *right = next; | |
679 return; | |
680 } | |
681 | |
682 void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** lef
t, Edge** right) { | |
683 Edge* prev = nullptr; | |
684 Edge* next; | |
685 for (next = edges->fHead; next != nullptr; next = next->fRight) { | |
686 if ((c.sweep_gt(edge->fTop->fPoint, next->fTop->fPoint) && next->isRight
Of(edge->fTop)) || | |
687 (c.sweep_gt(next->fTop->fPoint, edge->fTop->fPoint) && edge->isLeftO
f(next->fTop)) || | |
688 (c.sweep_lt(edge->fBottom->fPoint, next->fBottom->fPoint) && | |
689 next->isRightOf(edge->fBottom)) || | |
690 (c.sweep_lt(next->fBottom->fPoint, edge->fBottom->fPoint) && | |
691 edge->isLeftOf(next->fBottom))) { | |
692 break; | |
693 } | |
694 prev = next; | |
695 } | |
696 *left = prev; | |
697 *right = next; | |
698 return; | |
699 } | |
700 | |
701 void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) { | |
702 if (edge->isActive(activeEdges)) { | |
703 if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) { | |
704 remove_edge(edge, activeEdges); | |
705 } | |
706 } else if (edge->fTop->fProcessed && !edge->fBottom->fProcessed) { | |
707 Edge* left; | |
708 Edge* right; | |
709 find_enclosing_edges(edge, activeEdges, c, &left, &right); | |
710 insert_edge(edge, left, activeEdges); | |
711 } | |
712 } | |
713 | |
714 void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) { | |
715 if (edge->fTop->fPoint == edge->fBottom->fPoint || | |
716 c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { | |
717 return; | |
718 } | |
719 LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBott
om->fID, v->fID); | |
720 Edge* prev = nullptr; | |
721 Edge* next; | |
722 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) { | |
723 if (next->isRightOf(edge->fTop)) { | |
724 break; | |
725 } | |
726 prev = next; | |
727 } | |
728 insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>( | |
729 edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove); | |
730 } | |
731 | |
732 void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) { | |
733 if (edge->fTop->fPoint == edge->fBottom->fPoint || | |
734 c.sweep_gt(edge->fTop->fPoint, edge->fBottom->fPoint)) { | |
735 return; | |
736 } | |
737 LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBott
om->fID, v->fID); | |
738 Edge* prev = nullptr; | |
739 Edge* next; | |
740 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) { | |
741 if (next->isRightOf(edge->fBottom)) { | |
742 break; | |
743 } | |
744 prev = next; | |
745 } | |
746 insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>( | |
747 edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow); | |
748 } | |
749 | |
750 void remove_edge_above(Edge* edge) { | |
751 LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBo
ttom->fID, | |
752 edge->fBottom->fID); | |
753 remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>( | |
754 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove); | |
755 } | |
756 | |
757 void remove_edge_below(Edge* edge) { | |
758 LOG("removing edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBo
ttom->fID, | |
759 edge->fTop->fID); | |
760 remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>( | |
761 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow); | |
762 } | |
763 | |
764 void erase_edge_if_zero_winding(Edge* edge, EdgeList* edges) { | |
765 if (edge->fWinding != 0) { | |
766 return; | |
767 } | |
768 LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID); | |
769 remove_edge_above(edge); | |
770 remove_edge_below(edge); | |
771 if (edge->isActive(edges)) { | |
772 remove_edge(edge, edges); | |
773 } | |
774 } | |
775 | |
776 void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c); | |
777 | |
778 void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) { | |
779 remove_edge_below(edge); | |
780 edge->fTop = v; | |
781 edge->recompute(); | |
782 insert_edge_below(edge, v, c); | |
783 fix_active_state(edge, activeEdges, c); | |
784 merge_collinear_edges(edge, activeEdges, c); | |
785 } | |
786 | |
787 void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) { | |
788 remove_edge_above(edge); | |
789 edge->fBottom = v; | |
790 edge->recompute(); | |
791 insert_edge_above(edge, v, c); | |
792 fix_active_state(edge, activeEdges, c); | |
793 merge_collinear_edges(edge, activeEdges, c); | |
794 } | |
795 | |
796 void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Comparato
r& c) { | |
797 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) { | |
798 LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n", | |
799 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, | |
800 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); | |
801 other->fWinding += edge->fWinding; | |
802 erase_edge_if_zero_winding(other, activeEdges); | |
803 edge->fWinding = 0; | |
804 erase_edge_if_zero_winding(edge, activeEdges); | |
805 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) { | |
806 other->fWinding += edge->fWinding; | |
807 erase_edge_if_zero_winding(other, activeEdges); | |
808 set_bottom(edge, other->fTop, activeEdges, c); | |
809 } else { | |
810 edge->fWinding += other->fWinding; | |
811 erase_edge_if_zero_winding(edge, activeEdges); | |
812 set_bottom(other, edge->fTop, activeEdges, c); | |
813 } | |
814 } | |
815 | |
816 void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Comparato
r& c) { | |
817 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) { | |
818 LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n", | |
819 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, | |
820 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); | |
821 other->fWinding += edge->fWinding; | |
822 erase_edge_if_zero_winding(other, activeEdges); | |
823 edge->fWinding = 0; | |
824 erase_edge_if_zero_winding(edge, activeEdges); | |
825 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) { | |
826 edge->fWinding += other->fWinding; | |
827 erase_edge_if_zero_winding(edge, activeEdges); | |
828 set_top(other, edge->fBottom, activeEdges, c); | |
829 } else { | |
830 other->fWinding += edge->fWinding; | |
831 erase_edge_if_zero_winding(other, activeEdges); | |
832 set_top(edge, other->fBottom, activeEdges, c); | |
833 } | |
834 } | |
835 | |
836 void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) { | |
837 if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop || | |
838 !edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) { | |
839 merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, c); | |
840 } else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop
|| | |
841 !edge->isLeftOf(edge->fNextEdgeAbove->fT
op))) { | |
842 merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, c); | |
843 } | |
844 if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom
|| | |
845 !edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))
) { | |
846 merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, c); | |
847 } else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->f
Bottom || | |
848 !edge->isLeftOf(edge->fNextEdgeBelow->fB
ottom))) { | |
849 merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, c); | |
850 } | |
851 } | |
852 | |
853 void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkC
hunkAlloc& alloc); | |
854 | |
855 void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkCh
unkAlloc& alloc) { | |
856 Vertex* top = edge->fTop; | |
857 Vertex* bottom = edge->fBottom; | |
858 if (edge->fLeft) { | |
859 Vertex* leftTop = edge->fLeft->fTop; | |
860 Vertex* leftBottom = edge->fLeft->fBottom; | |
861 if (c.sweep_gt(top->fPoint, leftTop->fPoint) && !edge->fLeft->isLeftOf(t
op)) { | |
862 split_edge(edge->fLeft, edge->fTop, activeEdges, c, alloc); | |
863 } else if (c.sweep_gt(leftTop->fPoint, top->fPoint) && !edge->isRightOf(
leftTop)) { | |
864 split_edge(edge, leftTop, activeEdges, c, alloc); | |
865 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) && | |
866 !edge->fLeft->isLeftOf(bottom)) { | |
867 split_edge(edge->fLeft, bottom, activeEdges, c, alloc); | |
868 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRi
ghtOf(leftBottom)) { | |
869 split_edge(edge, leftBottom, activeEdges, c, alloc); | |
870 } | |
871 } | |
872 if (edge->fRight) { | |
873 Vertex* rightTop = edge->fRight->fTop; | |
874 Vertex* rightBottom = edge->fRight->fBottom; | |
875 if (c.sweep_gt(top->fPoint, rightTop->fPoint) && !edge->fRight->isRightO
f(top)) { | |
876 split_edge(edge->fRight, top, activeEdges, c, alloc); | |
877 } else if (c.sweep_gt(rightTop->fPoint, top->fPoint) && !edge->isLeftOf(
rightTop)) { | |
878 split_edge(edge, rightTop, activeEdges, c, alloc); | |
879 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) && | |
880 !edge->fRight->isRightOf(bottom)) { | |
881 split_edge(edge->fRight, bottom, activeEdges, c, alloc); | |
882 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) && | |
883 !edge->isLeftOf(rightBottom)) { | |
884 split_edge(edge, rightBottom, activeEdges, c, alloc); | |
885 } | |
886 } | |
887 } | |
888 | |
889 void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkC
hunkAlloc& alloc) { | |
890 LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n", | |
891 edge->fTop->fID, edge->fBottom->fID, | |
892 v->fID, v->fPoint.fX, v->fPoint.fY); | |
893 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) { | |
894 set_top(edge, v, activeEdges, c); | |
895 } else if (c.sweep_gt(v->fPoint, edge->fBottom->fPoint)) { | |
896 set_bottom(edge, v, activeEdges, c); | |
897 } else { | |
898 Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), allo
c); | |
899 insert_edge_below(newEdge, v, c); | |
900 insert_edge_above(newEdge, edge->fBottom, c); | |
901 set_bottom(edge, v, activeEdges, c); | |
902 cleanup_active_edges(edge, activeEdges, c, alloc); | |
903 fix_active_state(newEdge, activeEdges, c); | |
904 merge_collinear_edges(newEdge, activeEdges, c); | |
905 } | |
906 } | |
907 | |
908 void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, Comparator& c, SkCh
unkAlloc& alloc) { | |
909 LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX
, src->fPoint.fY, | |
910 src->fID, dst->fID); | |
911 for (Edge* edge = src->fFirstEdgeAbove; edge;) { | |
912 Edge* next = edge->fNextEdgeAbove; | |
913 set_bottom(edge, dst, nullptr, c); | |
914 edge = next; | |
915 } | |
916 for (Edge* edge = src->fFirstEdgeBelow; edge;) { | |
917 Edge* next = edge->fNextEdgeBelow; | |
918 set_top(edge, dst, nullptr, c); | |
919 edge = next; | |
920 } | |
921 remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(src, head, nullptr); | |
922 } | |
923 | |
924 Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, C
omparator& c, | |
925 SkChunkAlloc& alloc) { | |
926 SkPoint p; | |
927 if (!edge || !other) { | |
928 return nullptr; | |
929 } | |
930 if (edge->intersect(*other, &p)) { | |
931 Vertex* v; | |
932 LOG("found intersection, pt is %g, %g\n", p.fX, p.fY); | |
933 if (p == edge->fTop->fPoint || c.sweep_lt(p, edge->fTop->fPoint)) { | |
934 split_edge(other, edge->fTop, activeEdges, c, alloc); | |
935 v = edge->fTop; | |
936 } else if (p == edge->fBottom->fPoint || c.sweep_gt(p, edge->fBottom->fP
oint)) { | |
937 split_edge(other, edge->fBottom, activeEdges, c, alloc); | |
938 v = edge->fBottom; | |
939 } else if (p == other->fTop->fPoint || c.sweep_lt(p, other->fTop->fPoint
)) { | |
940 split_edge(edge, other->fTop, activeEdges, c, alloc); | |
941 v = other->fTop; | |
942 } else if (p == other->fBottom->fPoint || c.sweep_gt(p, other->fBottom->
fPoint)) { | |
943 split_edge(edge, other->fBottom, activeEdges, c, alloc); | |
944 v = other->fBottom; | |
945 } else { | |
946 Vertex* nextV = edge->fTop; | |
947 while (c.sweep_lt(p, nextV->fPoint)) { | |
948 nextV = nextV->fPrev; | |
949 } | |
950 while (c.sweep_lt(nextV->fPoint, p)) { | |
951 nextV = nextV->fNext; | |
952 } | |
953 Vertex* prevV = nextV->fPrev; | |
954 if (coincident(prevV->fPoint, p)) { | |
955 v = prevV; | |
956 } else if (coincident(nextV->fPoint, p)) { | |
957 v = nextV; | |
958 } else { | |
959 v = ALLOC_NEW(Vertex, (p), alloc); | |
960 LOG("inserting between %g (%g, %g) and %g (%g, %g)\n", | |
961 prevV->fID, prevV->fPoint.fX, prevV->fPoint.fY, | |
962 nextV->fID, nextV->fPoint.fX, nextV->fPoint.fY); | |
963 #if LOGGING_ENABLED | |
964 v->fID = (nextV->fID + prevV->fID) * 0.5f; | |
965 #endif | |
966 v->fPrev = prevV; | |
967 v->fNext = nextV; | |
968 prevV->fNext = v; | |
969 nextV->fPrev = v; | |
970 } | |
971 split_edge(edge, v, activeEdges, c, alloc); | |
972 split_edge(other, v, activeEdges, c, alloc); | |
973 } | |
974 return v; | |
975 } | |
976 return nullptr; | |
977 } | |
978 | |
979 void sanitize_contours(Vertex** contours, int contourCnt) { | |
980 for (int i = 0; i < contourCnt; ++i) { | |
981 SkASSERT(contours[i]); | |
982 for (Vertex* v = contours[i];;) { | |
983 if (coincident(v->fPrev->fPoint, v->fPoint)) { | |
984 LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoi
nt.fY); | |
985 if (v->fPrev == v) { | |
986 contours[i] = nullptr; | |
987 break; | |
988 } | |
989 v->fPrev->fNext = v->fNext; | |
990 v->fNext->fPrev = v->fPrev; | |
991 if (contours[i] == v) { | |
992 contours[i] = v->fNext; | |
993 } | |
994 v = v->fPrev; | |
995 } else { | |
996 v = v->fNext; | |
997 if (v == contours[i]) break; | |
998 } | |
999 } | |
1000 } | |
1001 } | |
1002 | |
1003 void merge_coincident_vertices(Vertex** vertices, Comparator& c, SkChunkAlloc& a
lloc) { | |
1004 for (Vertex* v = (*vertices)->fNext; v != nullptr; v = v->fNext) { | |
1005 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) { | |
1006 v->fPoint = v->fPrev->fPoint; | |
1007 } | |
1008 if (coincident(v->fPrev->fPoint, v->fPoint)) { | |
1009 merge_vertices(v->fPrev, v, vertices, c, alloc); | |
1010 } | |
1011 } | |
1012 } | |
1013 | |
1014 // Stage 2: convert the contours to a mesh of edges connecting the vertices. | |
1015 | |
1016 Vertex* build_edges(Vertex** contours, int contourCnt, Comparator& c, SkChunkAll
oc& alloc) { | |
1017 Vertex* vertices = nullptr; | |
1018 Vertex* prev = nullptr; | |
1019 for (int i = 0; i < contourCnt; ++i) { | |
1020 for (Vertex* v = contours[i]; v != nullptr;) { | |
1021 Vertex* vNext = v->fNext; | |
1022 Edge* edge = new_edge(v->fPrev, v, alloc, c); | |
1023 if (edge->fWinding > 0) { | |
1024 insert_edge_below(edge, v->fPrev, c); | |
1025 insert_edge_above(edge, v, c); | |
1026 } else { | |
1027 insert_edge_below(edge, v, c); | |
1028 insert_edge_above(edge, v->fPrev, c); | |
1029 } | |
1030 merge_collinear_edges(edge, nullptr, c); | |
1031 if (prev) { | |
1032 prev->fNext = v; | |
1033 v->fPrev = prev; | |
1034 } else { | |
1035 vertices = v; | |
1036 } | |
1037 prev = v; | |
1038 v = vNext; | |
1039 if (v == contours[i]) break; | |
1040 } | |
1041 } | |
1042 if (prev) { | |
1043 prev->fNext = vertices->fPrev = nullptr; | |
1044 } | |
1045 return vertices; | |
1046 } | |
1047 | |
1048 // Stage 3: sort the vertices by increasing sweep direction. | |
1049 | |
1050 Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c); | |
1051 | |
1052 void front_back_split(Vertex* v, Vertex** pFront, Vertex** pBack) { | |
1053 Vertex* fast; | |
1054 Vertex* slow; | |
1055 if (!v || !v->fNext) { | |
1056 *pFront = v; | |
1057 *pBack = nullptr; | |
1058 } else { | |
1059 slow = v; | |
1060 fast = v->fNext; | |
1061 | |
1062 while (fast != nullptr) { | |
1063 fast = fast->fNext; | |
1064 if (fast != nullptr) { | |
1065 slow = slow->fNext; | |
1066 fast = fast->fNext; | |
1067 } | |
1068 } | |
1069 | |
1070 *pFront = v; | |
1071 *pBack = slow->fNext; | |
1072 slow->fNext->fPrev = nullptr; | |
1073 slow->fNext = nullptr; | |
1074 } | |
1075 } | |
1076 | |
1077 void merge_sort(Vertex** head, Comparator& c) { | |
1078 if (!*head || !(*head)->fNext) { | |
1079 return; | |
1080 } | |
1081 | |
1082 Vertex* a; | |
1083 Vertex* b; | |
1084 front_back_split(*head, &a, &b); | |
1085 | |
1086 merge_sort(&a, c); | |
1087 merge_sort(&b, c); | |
1088 | |
1089 *head = sorted_merge(a, b, c); | |
1090 } | |
1091 | |
1092 inline void append_vertex(Vertex* v, Vertex** head, Vertex** tail) { | |
1093 insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, *tail, nullptr, head, tail
); | |
1094 } | |
1095 | |
1096 inline void append_vertex_list(Vertex* v, Vertex** head, Vertex** tail) { | |
1097 insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, *tail, v->fNext, head, tai
l); | |
1098 } | |
1099 | |
1100 Vertex* sorted_merge(Vertex* a, Vertex* b, Comparator& c) { | |
1101 Vertex* head = nullptr; | |
1102 Vertex* tail = nullptr; | |
1103 | |
1104 while (a && b) { | |
1105 if (c.sweep_lt(a->fPoint, b->fPoint)) { | |
1106 Vertex* next = a->fNext; | |
1107 append_vertex(a, &head, &tail); | |
1108 a = next; | |
1109 } else { | |
1110 Vertex* next = b->fNext; | |
1111 append_vertex(b, &head, &tail); | |
1112 b = next; | |
1113 } | |
1114 } | |
1115 if (a) { | |
1116 append_vertex_list(a, &head, &tail); | |
1117 } | |
1118 if (b) { | |
1119 append_vertex_list(b, &head, &tail); | |
1120 } | |
1121 return head; | |
1122 } | |
1123 | |
1124 // Stage 4: Simplify the mesh by inserting new vertices at intersecting edges. | |
1125 | |
1126 void simplify(Vertex* vertices, Comparator& c, SkChunkAlloc& alloc) { | |
1127 LOG("simplifying complex polygons\n"); | |
1128 EdgeList activeEdges; | |
1129 for (Vertex* v = vertices; v != nullptr; v = v->fNext) { | |
1130 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { | |
1131 continue; | |
1132 } | |
1133 #if LOGGING_ENABLED | |
1134 LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); | |
1135 #endif | |
1136 Edge* leftEnclosingEdge = nullptr; | |
1137 Edge* rightEnclosingEdge = nullptr; | |
1138 bool restartChecks; | |
1139 do { | |
1140 restartChecks = false; | |
1141 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEncl
osingEdge); | |
1142 if (v->fFirstEdgeBelow) { | |
1143 for (Edge* edge = v->fFirstEdgeBelow; edge != nullptr; edge = ed
ge->fNextEdgeBelow) { | |
1144 if (check_for_intersection(edge, leftEnclosingEdge, &activeE
dges, c, alloc)) { | |
1145 restartChecks = true; | |
1146 break; | |
1147 } | |
1148 if (check_for_intersection(edge, rightEnclosingEdge, &active
Edges, c, alloc)) { | |
1149 restartChecks = true; | |
1150 break; | |
1151 } | |
1152 } | |
1153 } else { | |
1154 if (Vertex* pv = check_for_intersection(leftEnclosingEdge, right
EnclosingEdge, | |
1155 &activeEdges, c, alloc))
{ | |
1156 if (c.sweep_lt(pv->fPoint, v->fPoint)) { | |
1157 v = pv; | |
1158 } | |
1159 restartChecks = true; | |
1160 } | |
1161 | |
1162 } | |
1163 } while (restartChecks); | |
1164 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { | |
1165 remove_edge(e, &activeEdges); | |
1166 } | |
1167 Edge* leftEdge = leftEnclosingEdge; | |
1168 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { | |
1169 insert_edge(e, leftEdge, &activeEdges); | |
1170 leftEdge = e; | |
1171 } | |
1172 v->fProcessed = true; | |
1173 } | |
1174 } | |
1175 | |
1176 // Stage 5: Tessellate the simplified mesh into monotone polygons. | |
1177 | |
1178 Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) { | |
1179 LOG("tessellating simple polygons\n"); | |
1180 EdgeList activeEdges; | |
1181 Poly* polys = nullptr; | |
1182 for (Vertex* v = vertices; v != nullptr; v = v->fNext) { | |
1183 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) { | |
1184 continue; | |
1185 } | |
1186 #if LOGGING_ENABLED | |
1187 LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); | |
1188 #endif | |
1189 Edge* leftEnclosingEdge = nullptr; | |
1190 Edge* rightEnclosingEdge = nullptr; | |
1191 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosin
gEdge); | |
1192 Poly* leftPoly = nullptr; | |
1193 Poly* rightPoly = nullptr; | |
1194 if (v->fFirstEdgeAbove) { | |
1195 leftPoly = v->fFirstEdgeAbove->fLeftPoly; | |
1196 rightPoly = v->fLastEdgeAbove->fRightPoly; | |
1197 } else { | |
1198 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullp
tr; | |
1199 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nul
lptr; | |
1200 } | |
1201 #if LOGGING_ENABLED | |
1202 LOG("edges above:\n"); | |
1203 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { | |
1204 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, | |
1205 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRight
Poly->fID : -1); | |
1206 } | |
1207 LOG("edges below:\n"); | |
1208 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { | |
1209 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, | |
1210 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRight
Poly->fID : -1); | |
1211 } | |
1212 #endif | |
1213 if (v->fFirstEdgeAbove) { | |
1214 if (leftPoly) { | |
1215 leftPoly = leftPoly->addVertex(v, Poly::kRight_Side, alloc); | |
1216 } | |
1217 if (rightPoly) { | |
1218 rightPoly = rightPoly->addVertex(v, Poly::kLeft_Side, alloc); | |
1219 } | |
1220 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fN
extEdgeAbove) { | |
1221 Edge* leftEdge = e; | |
1222 Edge* rightEdge = e->fNextEdgeAbove; | |
1223 SkASSERT(rightEdge->isRightOf(leftEdge->fTop)); | |
1224 remove_edge(leftEdge, &activeEdges); | |
1225 if (leftEdge->fRightPoly) { | |
1226 leftEdge->fRightPoly->end(v, alloc); | |
1227 } | |
1228 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != leftEdge->fR
ightPoly) { | |
1229 rightEdge->fLeftPoly->end(v, alloc); | |
1230 } | |
1231 } | |
1232 remove_edge(v->fLastEdgeAbove, &activeEdges); | |
1233 if (!v->fFirstEdgeBelow) { | |
1234 if (leftPoly && rightPoly && leftPoly != rightPoly) { | |
1235 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartne
r == nullptr); | |
1236 rightPoly->fPartner = leftPoly; | |
1237 leftPoly->fPartner = rightPoly; | |
1238 } | |
1239 } | |
1240 } | |
1241 if (v->fFirstEdgeBelow) { | |
1242 if (!v->fFirstEdgeAbove) { | |
1243 if (leftPoly && leftPoly == rightPoly) { | |
1244 // Split the poly. | |
1245 if (leftPoly->fActive->fSide == Poly::kLeft_Side) { | |
1246 leftPoly = new_poly(&polys, leftEnclosingEdge->fTop, lef
tPoly->fWinding, | |
1247 alloc); | |
1248 leftPoly->addVertex(v, Poly::kRight_Side, alloc); | |
1249 rightPoly->addVertex(v, Poly::kLeft_Side, alloc); | |
1250 leftEnclosingEdge->fRightPoly = leftPoly; | |
1251 } else { | |
1252 rightPoly = new_poly(&polys, rightEnclosingEdge->fTop, r
ightPoly->fWinding, | |
1253 alloc); | |
1254 rightPoly->addVertex(v, Poly::kLeft_Side, alloc); | |
1255 leftPoly->addVertex(v, Poly::kRight_Side, alloc); | |
1256 rightEnclosingEdge->fLeftPoly = rightPoly; | |
1257 } | |
1258 } else { | |
1259 if (leftPoly) { | |
1260 leftPoly = leftPoly->addVertex(v, Poly::kRight_Side, all
oc); | |
1261 } | |
1262 if (rightPoly) { | |
1263 rightPoly = rightPoly->addVertex(v, Poly::kLeft_Side, al
loc); | |
1264 } | |
1265 } | |
1266 } | |
1267 Edge* leftEdge = v->fFirstEdgeBelow; | |
1268 leftEdge->fLeftPoly = leftPoly; | |
1269 insert_edge(leftEdge, leftEnclosingEdge, &activeEdges); | |
1270 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge; | |
1271 rightEdge = rightEdge->fNextEdgeBelow) { | |
1272 insert_edge(rightEdge, leftEdge, &activeEdges); | |
1273 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWindin
g : 0; | |
1274 winding += leftEdge->fWinding; | |
1275 if (winding != 0) { | |
1276 Poly* poly = new_poly(&polys, v, winding, alloc); | |
1277 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly; | |
1278 } | |
1279 leftEdge = rightEdge; | |
1280 } | |
1281 v->fLastEdgeBelow->fRightPoly = rightPoly; | |
1282 } | |
1283 #if LOGGING_ENABLED | |
1284 LOG("\nactive edges:\n"); | |
1285 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) { | |
1286 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID, | |
1287 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRight
Poly->fID : -1); | |
1288 } | |
1289 #endif | |
1290 } | |
1291 return polys; | |
1292 } | |
1293 | |
1294 // This is a driver function which calls stages 2-5 in turn. | |
1295 | |
1296 Poly* contours_to_polys(Vertex** contours, int contourCnt, Comparator& c, SkChun
kAlloc& alloc) { | |
1297 #if LOGGING_ENABLED | |
1298 for (int i = 0; i < contourCnt; ++i) { | |
1299 Vertex* v = contours[i]; | |
1300 SkASSERT(v); | |
1301 LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); | |
1302 for (v = v->fNext; v != contours[i]; v = v->fNext) { | |
1303 LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); | |
1304 } | |
1305 } | |
1306 #endif | |
1307 sanitize_contours(contours, contourCnt); | |
1308 Vertex* vertices = build_edges(contours, contourCnt, c, alloc); | |
1309 if (!vertices) { | |
1310 return nullptr; | |
1311 } | |
1312 | |
1313 // Sort vertices in Y (secondarily in X). | |
1314 merge_sort(&vertices, c); | |
1315 merge_coincident_vertices(&vertices, c, alloc); | |
1316 #if LOGGING_ENABLED | |
1317 for (Vertex* v = vertices; v != nullptr; v = v->fNext) { | |
1318 static float gID = 0.0f; | |
1319 v->fID = gID++; | |
1320 } | |
1321 #endif | |
1322 simplify(vertices, c, alloc); | |
1323 return tessellate(vertices, alloc); | |
1324 } | |
1325 | |
1326 // Stage 6: Triangulate the monotone polygons into a vertex buffer. | |
1327 | |
1328 SkPoint* polys_to_triangles(Poly* polys, SkPath::FillType fillType, SkPoint* dat
a) { | |
1329 SkPoint* d = data; | |
1330 for (Poly* poly = polys; poly; poly = poly->fNext) { | |
1331 if (apply_fill_type(fillType, poly->fWinding)) { | |
1332 d = poly->emit(d); | |
1333 } | |
1334 } | |
1335 return d; | |
1336 } | |
1337 | |
1338 struct TessInfo { | 31 struct TessInfo { |
1339 SkScalar fTolerance; | 32 SkScalar fTolerance; |
1340 int fCount; | 33 int fCount; |
1341 }; | 34 }; |
1342 | 35 |
| 36 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr
ibed by key. |
| 37 class PathInvalidator : public SkPathRef::GenIDChangeListener { |
| 38 public: |
| 39 explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {} |
| 40 private: |
| 41 GrUniqueKeyInvalidatedMessage fMsg; |
| 42 |
| 43 void onChange() override { |
| 44 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); |
| 45 } |
| 46 }; |
| 47 |
1343 bool cache_match(GrVertexBuffer* vertexBuffer, SkScalar tol, int* actualCount) { | 48 bool cache_match(GrVertexBuffer* vertexBuffer, SkScalar tol, int* actualCount) { |
1344 if (!vertexBuffer) { | 49 if (!vertexBuffer) { |
1345 return false; | 50 return false; |
1346 } | 51 } |
1347 const SkData* data = vertexBuffer->getUniqueKey().getCustomData(); | 52 const SkData* data = vertexBuffer->getUniqueKey().getCustomData(); |
1348 SkASSERT(data); | 53 SkASSERT(data); |
1349 const TessInfo* info = static_cast<const TessInfo*>(data->data()); | 54 const TessInfo* info = static_cast<const TessInfo*>(data->data()); |
1350 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { | 55 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { |
1351 *actualCount = info->fCount; | 56 *actualCount = info->fCount; |
1352 return true; | 57 return true; |
1353 } | 58 } |
1354 return false; | 59 return false; |
1355 } | 60 } |
1356 | 61 |
1357 }; | 62 } // namespace |
1358 | 63 |
1359 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 64 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { |
1360 } | 65 } |
1361 | 66 |
1362 namespace { | |
1363 | |
1364 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr
ibed by key. | |
1365 class PathInvalidator : public SkPathRef::GenIDChangeListener { | |
1366 public: | |
1367 explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {} | |
1368 private: | |
1369 GrUniqueKeyInvalidatedMessage fMsg; | |
1370 | |
1371 void onChange() override { | |
1372 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); | |
1373 } | |
1374 }; | |
1375 | |
1376 } // namespace | |
1377 | |
1378 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { | 67 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { |
1379 // This path renderer can draw all fill styles, all stroke styles except hai
rlines, but does | 68 // This path renderer can draw all fill styles, all stroke styles except hai
rlines, but does |
1380 // not do antialiasing. It can do convex and concave paths, but we'll leave
the convex ones to | 69 // not do antialiasing. It can do convex and concave paths, but we'll leave
the convex ones to |
1381 // simpler algorithms. | 70 // simpler algorithms. |
1382 return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullp
tr) && | 71 return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullp
tr) && |
1383 !args.fAntiAlias && !args.fPath->isConvex(); | 72 !args.fAntiAlias && !args.fPath->isConvex(); |
1384 } | 73 } |
1385 | 74 |
1386 class TessellatingPathBatch : public GrVertexBatch { | 75 class TessellatingPathBatch : public GrVertexBatch { |
1387 public: | 76 public: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1428 } else { | 117 } else { |
1429 path = fPath; | 118 path = fPath; |
1430 } | 119 } |
1431 if (!stroke.isFillStyle()) { | 120 if (!stroke.isFillStyle()) { |
1432 stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale())); | 121 stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale())); |
1433 if (!stroke.applyToPath(&path, path)) { | 122 if (!stroke.applyToPath(&path, path)) { |
1434 return 0; | 123 return 0; |
1435 } | 124 } |
1436 stroke.setFillStyle(); | 125 stroke.setFillStyle(); |
1437 } | 126 } |
| 127 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
1438 SkRect pathBounds = path.getBounds(); | 128 SkRect pathBounds = path.getBounds(); |
1439 Comparator c; | |
1440 if (pathBounds.width() > pathBounds.height()) { | |
1441 c.sweep_lt = sweep_lt_horiz; | |
1442 c.sweep_gt = sweep_gt_horiz; | |
1443 } else { | |
1444 c.sweep_lt = sweep_lt_vert; | |
1445 c.sweep_gt = sweep_gt_vert; | |
1446 } | |
1447 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | |
1448 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, pathBounds); | 129 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, pathBounds); |
1449 int contourCnt; | |
1450 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); | |
1451 if (maxPts <= 0) { | |
1452 return 0; | |
1453 } | |
1454 if (maxPts > ((int)SK_MaxU16 + 1)) { | |
1455 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); | |
1456 return 0; | |
1457 } | |
1458 SkPath::FillType fillType = path.getFillType(); | |
1459 if (SkPath::IsInverseFillType(fillType)) { | |
1460 contourCnt++; | |
1461 } | |
1462 | 130 |
1463 LOG("got %d pts, %d contours\n", maxPts, contourCnt); | |
1464 SkAutoTDeleteArray<Vertex*> contours(new Vertex* [contourCnt]); | |
1465 | |
1466 // For the initial size of the chunk allocator, estimate based on the po
int count: | |
1467 // one vertex per point for the initial passes, plus two for the vertice
s in the | |
1468 // resulting Polys, since the same point may end up in two Polys. Assum
e minimal | |
1469 // connectivity of one Edge per Vertex (will grow for intersections). | |
1470 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); | |
1471 bool isLinear; | 131 bool isLinear; |
1472 path_to_contours(path, tol, fClipBounds, contours.get(), alloc, &isLinea
r); | 132 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, resou
rceProvider, |
1473 Poly* polys; | 133 vertexBuffer, canMapVB, &isLi
near); |
1474 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); | |
1475 int count = 0; | |
1476 for (Poly* poly = polys; poly; poly = poly->fNext) { | |
1477 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3)
{ | |
1478 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); | |
1479 } | |
1480 } | |
1481 if (0 == count) { | |
1482 return 0; | |
1483 } | |
1484 | |
1485 size_t size = count * sizeof(SkPoint); | |
1486 if (!vertexBuffer.get() || vertexBuffer->gpuMemorySize() < size) { | |
1487 vertexBuffer.reset(resourceProvider->createVertexBuffer( | |
1488 size, GrResourceProvider::kStatic_BufferUsage, 0)); | |
1489 } | |
1490 if (!vertexBuffer.get()) { | |
1491 SkDebugf("Could not allocate vertices\n"); | |
1492 return 0; | |
1493 } | |
1494 SkPoint* verts; | |
1495 if (canMapVB) { | |
1496 verts = static_cast<SkPoint*>(vertexBuffer->map()); | |
1497 } else { | |
1498 verts = new SkPoint[count]; | |
1499 } | |
1500 SkPoint* end = polys_to_triangles(polys, fillType, verts); | |
1501 int actualCount = static_cast<int>(end - verts); | |
1502 LOG("actual count: %d\n", actualCount); | |
1503 SkASSERT(actualCount <= count); | |
1504 if (canMapVB) { | |
1505 vertexBuffer->unmap(); | |
1506 } else { | |
1507 vertexBuffer->updateData(verts, actualCount * sizeof(SkPoint)); | |
1508 delete[] verts; | |
1509 } | |
1510 | |
1511 | |
1512 if (!fPath.isVolatile()) { | 134 if (!fPath.isVolatile()) { |
1513 TessInfo info; | 135 TessInfo info; |
1514 info.fTolerance = isLinear ? 0 : tol; | 136 info.fTolerance = isLinear ? 0 : tol; |
1515 info.fCount = actualCount; | 137 info.fCount = count; |
1516 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); | 138 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); |
1517 key->setCustomData(data.get()); | 139 key->setCustomData(data.get()); |
1518 resourceProvider->assignUniqueKeyToResource(*key, vertexBuffer.get()
); | 140 resourceProvider->assignUniqueKeyToResource(*key, vertexBuffer.get()
); |
1519 SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(*key))
; | 141 SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(*key))
; |
1520 } | 142 } |
1521 return actualCount; | 143 return count; |
1522 } | 144 } |
1523 | 145 |
1524 void onPrepareDraws(Target* target) const override { | 146 void onPrepareDraws(Target* target) const override { |
1525 // construct a cache key from the path's genID and the view matrix | 147 // construct a cache key from the path's genID and the view matrix |
1526 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | 148 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; |
1527 GrUniqueKey key; | 149 GrUniqueKey key; |
1528 int clipBoundsSize32 = | 150 int clipBoundsSize32 = |
1529 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) :
0; | 151 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) :
0; |
1530 int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); | 152 int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); |
1531 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strok
eDataSize32); | 153 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strok
eDataSize32); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1567 coverageType = Coverage::kNone_Type; | 189 coverageType = Coverage::kNone_Type; |
1568 } | 190 } |
1569 Coverage coverage(coverageType); | 191 Coverage coverage(coverageType); |
1570 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord
s, | 192 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord
s, |
1571 fViewMatrix)); | 193 fViewMatrix)); |
1572 } | 194 } |
1573 | 195 |
1574 target->initDraw(gp, this->pipeline()); | 196 target->initDraw(gp, this->pipeline()); |
1575 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | 197 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); |
1576 | 198 |
1577 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType | 199 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti
veType |
1578 : kTriangles_GrPrimitiveType; | 200 : kTriangles_GrPri
mitiveType; |
1579 GrVertices vertices; | 201 GrVertices vertices; |
1580 vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); | 202 vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); |
1581 target->draw(vertices); | 203 target->draw(vertices); |
1582 } | 204 } |
1583 | 205 |
1584 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } | 206 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } |
1585 | 207 |
1586 TessellatingPathBatch(const GrColor& color, | 208 TessellatingPathBatch(const GrColor& color, |
1587 const SkPath& path, | 209 const SkPath& path, |
1588 const GrStrokeInfo& stroke, | 210 const GrStrokeInfo& stroke, |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1662 bool result = viewMatrix.invert(&vmi); | 284 bool result = viewMatrix.invert(&vmi); |
1663 if (!result) { | 285 if (!result) { |
1664 SkFAIL("Cannot invert matrix\n"); | 286 SkFAIL("Cannot invert matrix\n"); |
1665 } | 287 } |
1666 vmi.mapRect(&clipBounds); | 288 vmi.mapRect(&clipBounds); |
1667 GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); | 289 GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); |
1668 return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, cl
ipBounds); | 290 return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, cl
ipBounds); |
1669 } | 291 } |
1670 | 292 |
1671 #endif | 293 #endif |
OLD | NEW |