Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: experimental/AndroidPathRenderer/AndroidPathRenderer.cpp

Issue 1160863006: delete experimental path renderers (Closed) Base URL: https://skia.googlesource.com/skia.git@map-buffer-option
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2012 The Android Open Source Project
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 #define LOG_TAG "PathRenderer"
9 #define LOG_NDEBUG 1
10 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
11
12 #define VERTEX_DEBUG 0
13
14 #include <SkPath.h>
15 #include <SkStrokeRec.h>
16
17 #include <stdlib.h>
18 #include <stdint.h>
19 #include <sys/types.h>
20
21 #include <SkTypes.h>
22 #include <SkTraceEvent.h>
23 #include <SkMatrix.h>
24 #include <SkPoint.h>
25
26 #ifdef VERBOSE
27 #define ALOGV SkDebugf
28 #else
29 #define ALOGV(x, ...)
30 #endif
31
32 #include "AndroidPathRenderer.h"
33 #include "Vertex.h"
34
35 namespace android {
36 namespace uirenderer {
37
38 #define THRESHOLD 0.5f
39
40 SkRect PathRenderer::ComputePathBounds(const SkPath& path, const SkPaint* paint) {
41 SkRect bounds = path.getBounds();
42 if (paint->getStyle() != SkPaint::kFill_Style) {
43 float outset = paint->getStrokeWidth() * 0.5f;
44 bounds.outset(outset, outset);
45 }
46 return bounds;
47 }
48
49 inline void computeInverseScales(const SkMatrix* transform, float &inverseScaleX , float& inverseScaleY) {
50 if (transform && transform->getType() & (SkMatrix::kScale_Mask|SkMatrix::kAf fine_Mask|SkMatrix::kPerspective_Mask)) {
51 float m00 = transform->getScaleX();
52 float m01 = transform->getSkewY();
53 float m10 = transform->getSkewX();
54 float m11 = transform->getScaleY();
55 float scaleX = sk_float_sqrt(m00 * m00 + m01 * m01);
56 float scaleY = sk_float_sqrt(m10 * m10 + m11 * m11);
57 inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
58 inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
59 } else {
60 inverseScaleX = 1.0f;
61 inverseScaleY = 1.0f;
62 }
63 }
64
65 inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) {
66 Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]);
67 }
68
69 inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
70 AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr-> alpha);
71 }
72
73 /**
74 * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset
75 * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices
76 * will be offset by 1.0
77 *
78 * Note that we can't add and normalize the two vectors, that would result in a rectangle having an
79 * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
80 *
81 * NOTE: assumes angles between normals 90 degrees or less
82 */
83 inline SkVector totalOffsetFromNormals(const SkVector& normalA, const SkVector& normalB) {
84 SkVector pseudoNormal = normalA + normalB;
85 pseudoNormal.scale(1.0f / (1.0f + sk_float_abs(normalA.dot(normalB))));
86 return pseudoNormal;
87 }
88
89 inline void scaleOffsetForStrokeWidth(SkVector& offset, float halfStrokeWidth,
90 float inverseScaleX, float inverseScaleY) {
91 if (halfStrokeWidth == 0.0f) {
92 // hairline - compensate for scale
93 offset.fX *= 0.5f * inverseScaleX;
94 offset.fY *= 0.5f * inverseScaleY;
95 } else {
96 offset.scale(halfStrokeWidth);
97 }
98 }
99
100 static void getFillVerticesFromPerimeter(const SkTArray<Vertex, true>& perimeter , VertexBuffer* vertexBuffer) {
101 Vertex* buffer = vertexBuffer->alloc<Vertex>(perimeter.count());
102
103 int currentIndex = 0;
104 // zig zag between all previous points on the inside of the hull to create a
105 // triangle strip that fills the hull
106 int srcAindex = 0;
107 int srcBindex = perimeter.count() - 1;
108 while (srcAindex <= srcBindex) {
109 copyVertex(&buffer[currentIndex++], &perimeter[srcAindex]);
110 if (srcAindex == srcBindex) break;
111 copyVertex(&buffer[currentIndex++], &perimeter[srcBindex]);
112 srcAindex++;
113 srcBindex--;
114 }
115 }
116
117 static void getStrokeVerticesFromPerimeter(const SkTArray<Vertex, true>& perimet er, float halfStrokeWidth,
118 VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
119 Vertex* buffer = vertexBuffer->alloc<Vertex>(perimeter.count() * 2 + 2);
120
121 int currentIndex = 0;
122 const Vertex* last = &(perimeter[perimeter.count() - 1]);
123 const Vertex* current = &(perimeter[0]);
124 SkVector lastNormal;
125 lastNormal.set(current->position[1] - last->position[1],
126 last->position[0] - current->position[0]);
127 lastNormal.normalize();
128 for (int i = 0; i < perimeter.count(); i++) {
129 const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1] );
130 SkVector nextNormal;
131 nextNormal.set(next->position[1] - current->position[1],
132 current->position[0] - next->position[0]);
133 nextNormal.normalize();
134
135 SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
136 scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, i nverseScaleY);
137
138 Vertex::set(&buffer[currentIndex++],
139 current->position[0] + totalOffset.fX,
140 current->position[1] + totalOffset.fY);
141
142 Vertex::set(&buffer[currentIndex++],
143 current->position[0] - totalOffset.fX,
144 current->position[1] - totalOffset.fY);
145
146 last = current;
147 current = next;
148 lastNormal = nextNormal;
149 }
150
151 // wrap around to beginning
152 copyVertex(&buffer[currentIndex++], &buffer[0]);
153 copyVertex(&buffer[currentIndex++], &buffer[1]);
154 }
155
156 static void getStrokeVerticesFromUnclosedVertices(const SkTArray<Vertex, true>& vertices, float halfStrokeWidth,
157 VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
158 Vertex* buffer = vertexBuffer->alloc<Vertex>(vertices.count() * 2);
159
160 int currentIndex = 0;
161 const Vertex* current = &(vertices[0]);
162 SkVector lastNormal;
163 for (int i = 0; i < vertices.count() - 1; i++) {
164 const Vertex* next = &(vertices[i + 1]);
165 SkVector nextNormal;
166 nextNormal.set(next->position[1] - current->position[1],
167 current->position[0] - next->position[0]);
168 nextNormal.normalize();
169
170 SkVector totalOffset;
171 if (i == 0) {
172 totalOffset = nextNormal;
173 } else {
174 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
175 }
176 scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, i nverseScaleY);
177
178 Vertex::set(&buffer[currentIndex++],
179 current->position[0] + totalOffset.fX,
180 current->position[1] + totalOffset.fY);
181
182 Vertex::set(&buffer[currentIndex++],
183 current->position[0] - totalOffset.fX,
184 current->position[1] - totalOffset.fY);
185
186 current = next;
187 lastNormal = nextNormal;
188 }
189
190 SkVector totalOffset = lastNormal;
191 scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inver seScaleY);
192
193 Vertex::set(&buffer[currentIndex++],
194 current->position[0] + totalOffset.fX,
195 current->position[1] + totalOffset.fY);
196 Vertex::set(&buffer[currentIndex++],
197 current->position[0] - totalOffset.fX,
198 current->position[1] - totalOffset.fY);
199 #if VERTEX_DEBUG
200 for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
201 SkDebugf("point at %f %f", buffer[i].position[0], buffer[i].position[1]) ;
202 }
203 #endif
204 }
205
206 static void getFillVerticesFromPerimeterAA(const SkTArray<Vertex, true>& perimet er, VertexBuffer* vertexBuffer,
207 float inverseScaleX, float inverseScaleY) {
208 AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(perimeter.count() * 3 + 2);
209
210 // generate alpha points - fill Alpha vertex gaps in between each point with
211 // alpha 0 vertex, offset by a scaled normal.
212 int currentIndex = 0;
213 const Vertex* last = &(perimeter[perimeter.count() - 1]);
214 const Vertex* current = &(perimeter[0]);
215 SkVector lastNormal;
216 lastNormal.set(current->position[1] - last->position[1],
217 last->position[0] - current->position[0]);
218 lastNormal.normalize();
219 for (int i = 0; i < perimeter.count(); i++) {
220 const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1] );
221 SkVector nextNormal;
222 nextNormal.set(next->position[1] - current->position[1],
223 current->position[0] - next->position[0]);
224 nextNormal.normalize();
225
226 // AA point offset from original point is that point's normal, such that each side is offset
227 // by .5 pixels
228 SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
229 totalOffset.fX *= 0.5f * inverseScaleX;
230 totalOffset.fY *= 0.5f * inverseScaleY;
231
232 AlphaVertex::set(&buffer[currentIndex++],
233 current->position[0] + totalOffset.fX,
234 current->position[1] + totalOffset.fY,
235 0.0f);
236 AlphaVertex::set(&buffer[currentIndex++],
237 current->position[0] - totalOffset.fX,
238 current->position[1] - totalOffset.fY,
239 1.0f);
240
241 last = current;
242 current = next;
243 lastNormal = nextNormal;
244 }
245
246 // wrap around to beginning
247 copyAlphaVertex(&buffer[currentIndex++], &buffer[0]);
248 copyAlphaVertex(&buffer[currentIndex++], &buffer[1]);
249
250 // zig zag between all previous points on the inside of the hull to create a
251 // triangle strip that fills the hull, repeating the first inner point to
252 // create degenerate tris to start inside path
253 int srcAindex = 0;
254 int srcBindex = perimeter.count() - 1;
255 while (srcAindex <= srcBindex) {
256 copyAlphaVertex(&buffer[currentIndex++], &buffer[srcAindex * 2 + 1]);
257 if (srcAindex == srcBindex) break;
258 copyAlphaVertex(&buffer[currentIndex++], &buffer[srcBindex * 2 + 1]);
259 srcAindex++;
260 srcBindex--;
261 }
262
263 #if VERTEX_DEBUG
264 for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
265 SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].po sition[1], buffer[i].alpha);
266 }
267 #endif
268 }
269
270
271 static void getStrokeVerticesFromUnclosedVerticesAA(const SkTArray<Vertex, true> & vertices, float halfStrokeWidth,
272 VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
273 AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(6 * vertices.count() + 2);
274
275 // avoid lines smaller than hairline since they break triangle based samplin g. instead reducing
276 // alpha value (TODO: support different X/Y scale)
277 float maxAlpha = 1.0f;
278 if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
279 halfStrokeWidth * inverseScaleX < 0.5f) {
280 maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
281 halfStrokeWidth = 0.0f;
282 }
283
284 // there is no outer/inner here, using them for consistency with below appro ach
285 int offset = 2 * (vertices.count() - 2);
286 int currentAAOuterIndex = 2;
287 int currentAAInnerIndex = 2 * offset + 5; // reversed
288 int currentStrokeIndex = currentAAInnerIndex + 7;
289
290 const Vertex* last = &(vertices[0]);
291 const Vertex* current = &(vertices[1]);
292 SkVector lastNormal;
293 lastNormal.set(current->position[1] - last->position[1],
294 last->position[0] - current->position[0]);
295 lastNormal.normalize();
296
297 {
298 // start cap
299 SkVector totalOffset = lastNormal;
300 SkVector AAOffset = totalOffset;
301 AAOffset.fX *= 0.5f * inverseScaleX;
302 AAOffset.fY *= 0.5f * inverseScaleY;
303
304 SkVector innerOffset = totalOffset;
305 scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, i nverseScaleY);
306 SkVector outerOffset = innerOffset + AAOffset;
307 innerOffset -= AAOffset;
308
309 // TODO: support square cap by changing this offset to incorporate halfS trokeWidth
310 SkVector capAAOffset;
311 capAAOffset.set(AAOffset.fY, -AAOffset.fX);
312 AlphaVertex::set(&buffer[0],
313 last->position[0] + outerOffset.fX + capAAOffset.fX,
314 last->position[1] + outerOffset.fY + capAAOffset.fY,
315 0.0f);
316 AlphaVertex::set(&buffer[1],
317 last->position[0] + innerOffset.fX - capAAOffset.fX,
318 last->position[1] + innerOffset.fY - capAAOffset.fY,
319 maxAlpha);
320
321 AlphaVertex::set(&buffer[2 * offset + 6],
322 last->position[0] - outerOffset.fX + capAAOffset.fX,
323 last->position[1] - outerOffset.fY + capAAOffset.fY,
324 0.0f);
325 AlphaVertex::set(&buffer[2 * offset + 7],
326 last->position[0] - innerOffset.fX - capAAOffset.fX,
327 last->position[1] - innerOffset.fY - capAAOffset.fY,
328 maxAlpha);
329 copyAlphaVertex(&buffer[2 * offset + 8], &buffer[0]);
330 copyAlphaVertex(&buffer[2 * offset + 9], &buffer[1]);
331 copyAlphaVertex(&buffer[2 * offset + 10], &buffer[1]); // degenerate tri s (the only two!)
332 copyAlphaVertex(&buffer[2 * offset + 11], &buffer[2 * offset + 7]);
333 }
334
335 for (int i = 1; i < vertices.count() - 1; i++) {
336 const Vertex* next = &(vertices[i + 1]);
337 SkVector nextNormal;
338 nextNormal.set(next->position[1] - current->position[1],
339 current->position[0] - next->position[0]);
340 nextNormal.normalize();
341
342 SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
343 SkVector AAOffset = totalOffset;
344 AAOffset.fX *= 0.5f * inverseScaleX;
345 AAOffset.fY *= 0.5f * inverseScaleY;
346
347 SkVector innerOffset = totalOffset;
348 scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, i nverseScaleY);
349 SkVector outerOffset = innerOffset + AAOffset;
350 innerOffset -= AAOffset;
351
352 AlphaVertex::set(&buffer[currentAAOuterIndex++],
353 current->position[0] + outerOffset.fX,
354 current->position[1] + outerOffset.fY,
355 0.0f);
356 AlphaVertex::set(&buffer[currentAAOuterIndex++],
357 current->position[0] + innerOffset.fX,
358 current->position[1] + innerOffset.fY,
359 maxAlpha);
360
361 AlphaVertex::set(&buffer[currentStrokeIndex++],
362 current->position[0] + innerOffset.fX,
363 current->position[1] + innerOffset.fY,
364 maxAlpha);
365 AlphaVertex::set(&buffer[currentStrokeIndex++],
366 current->position[0] - innerOffset.fX,
367 current->position[1] - innerOffset.fY,
368 maxAlpha);
369
370 AlphaVertex::set(&buffer[currentAAInnerIndex--],
371 current->position[0] - innerOffset.fX,
372 current->position[1] - innerOffset.fY,
373 maxAlpha);
374 AlphaVertex::set(&buffer[currentAAInnerIndex--],
375 current->position[0] - outerOffset.fX,
376 current->position[1] - outerOffset.fY,
377 0.0f);
378
379 last = current;
380 current = next;
381 lastNormal = nextNormal;
382 }
383
384 {
385 // end cap
386 SkVector totalOffset = lastNormal;
387 SkVector AAOffset = totalOffset;
388 AAOffset.fX *= 0.5f * inverseScaleX;
389 AAOffset.fY *= 0.5f * inverseScaleY;
390
391 SkVector innerOffset = totalOffset;
392 scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, i nverseScaleY);
393 SkVector outerOffset = innerOffset + AAOffset;
394 innerOffset -= AAOffset;
395
396 // TODO: support square cap by changing this offset to incorporate halfS trokeWidth
397 SkVector capAAOffset;
398 capAAOffset.set(-AAOffset.fY, AAOffset.fX);
399
400 AlphaVertex::set(&buffer[offset + 2],
401 current->position[0] + outerOffset.fX + capAAOffset.fX,
402 current->position[1] + outerOffset.fY + capAAOffset.fY,
403 0.0f);
404 AlphaVertex::set(&buffer[offset + 3],
405 current->position[0] + innerOffset.fX - capAAOffset.fX,
406 current->position[1] + innerOffset.fY - capAAOffset.fY,
407 maxAlpha);
408
409 AlphaVertex::set(&buffer[offset + 4],
410 current->position[0] - outerOffset.fX + capAAOffset.fX,
411 current->position[1] - outerOffset.fY + capAAOffset.fY,
412 0.0f);
413 AlphaVertex::set(&buffer[offset + 5],
414 current->position[0] - innerOffset.fX - capAAOffset.fX,
415 current->position[1] - innerOffset.fY - capAAOffset.fY,
416 maxAlpha);
417
418 copyAlphaVertex(&buffer[vertexBuffer->getSize() - 2], &buffer[offset + 3 ]);
419 copyAlphaVertex(&buffer[vertexBuffer->getSize() - 1], &buffer[offset + 5 ]);
420 }
421
422 #if VERTEX_DEBUG
423 for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
424 SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].po sition[1], buffer[i].alpha);
425 }
426 #endif
427 }
428
429
430 static void getStrokeVerticesFromPerimeterAA(const SkTArray<Vertex, true>& perim eter, float halfStrokeWidth,
431 VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
432 AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(6 * perimeter.count() + 8);
433
434 // avoid lines smaller than hairline since they break triangle based samplin g. instead reducing
435 // alpha value (TODO: support different X/Y scale)
436 float maxAlpha = 1.0f;
437 if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
438 halfStrokeWidth * inverseScaleX < 0.5f) {
439 maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
440 halfStrokeWidth = 0.0f;
441 }
442
443 int offset = 2 * perimeter.count() + 3;
444 int currentAAOuterIndex = 0;
445 int currentStrokeIndex = offset;
446 int currentAAInnerIndex = offset * 2;
447
448 const Vertex* last = &(perimeter[perimeter.count() - 1]);
449 const Vertex* current = &(perimeter[0]);
450 SkVector lastNormal;
451 lastNormal.set(current->position[1] - last->position[1],
452 last->position[0] - current->position[0]);
453 lastNormal.normalize();
454 for (int i = 0; i < perimeter.count(); i++) {
455 const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1] );
456 SkVector nextNormal;
457 nextNormal.set(next->position[1] - current->position[1],
458 current->position[0] - next->position[0]);
459 nextNormal.normalize();
460
461 SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
462 SkVector AAOffset = totalOffset;
463 AAOffset.fX *= 0.5f * inverseScaleX;
464 AAOffset.fY *= 0.5f * inverseScaleY;
465
466 SkVector innerOffset = totalOffset;
467 scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, i nverseScaleY);
468 SkVector outerOffset = innerOffset + AAOffset;
469 innerOffset -= AAOffset;
470
471 AlphaVertex::set(&buffer[currentAAOuterIndex++],
472 current->position[0] + outerOffset.fX,
473 current->position[1] + outerOffset.fY,
474 0.0f);
475 AlphaVertex::set(&buffer[currentAAOuterIndex++],
476 current->position[0] + innerOffset.fX,
477 current->position[1] + innerOffset.fY,
478 maxAlpha);
479
480 AlphaVertex::set(&buffer[currentStrokeIndex++],
481 current->position[0] + innerOffset.fX,
482 current->position[1] + innerOffset.fY,
483 maxAlpha);
484 AlphaVertex::set(&buffer[currentStrokeIndex++],
485 current->position[0] - innerOffset.fX,
486 current->position[1] - innerOffset.fY,
487 maxAlpha);
488
489 AlphaVertex::set(&buffer[currentAAInnerIndex++],
490 current->position[0] - innerOffset.fX,
491 current->position[1] - innerOffset.fY,
492 maxAlpha);
493 AlphaVertex::set(&buffer[currentAAInnerIndex++],
494 current->position[0] - outerOffset.fX,
495 current->position[1] - outerOffset.fY,
496 0.0f);
497
498 last = current;
499 current = next;
500 lastNormal = nextNormal;
501 }
502
503 // wrap each strip around to beginning, creating degenerate tris to bridge s trips
504 copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[0]);
505 copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]);
506 copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]);
507
508 copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset]);
509 copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]);
510 copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]);
511
512 copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset]);
513 copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset + 1]);
514 // don't need to create last degenerate tri
515
516 #if VERTEX_DEBUG
517 for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
518 SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].po sition[1], buffer[i].alpha);
519 }
520 #endif
521 }
522
523 void PathRenderer::ConvexPathVertices(const SkPath &path, const SkStrokeRec& str oke, bool isAA,
524 const SkMatrix* transform, VertexBuffer* vertexBuffer) {
525
526 SkStrokeRec::Style style = stroke.getStyle();
527
528 float inverseScaleX, inverseScaleY;
529 computeInverseScales(transform, inverseScaleX, inverseScaleY);
530
531 SkTArray<Vertex, true> tempVertices;
532 float threshInvScaleX = inverseScaleX;
533 float threshInvScaleY = inverseScaleY;
534 if (style == SkStrokeRec::kStroke_Style) {
535 // alter the bezier recursion threshold values we calculate in order to compensate for
536 // expansion done after the path vertices are found
537 SkRect bounds = path.getBounds();
538 if (!bounds.isEmpty()) {
539 threshInvScaleX *= bounds.width() / (bounds.width() + stroke.getWidt h());
540 threshInvScaleY *= bounds.height() / (bounds.height() + stroke.getWi dth());
541 }
542 }
543
544 // force close if we're filling the path, since fill path expects closed per imeter.
545 bool forceClose = style != SkStrokeRec::kStroke_Style;
546 bool wasClosed = ConvexPathPerimeterVertices(path, forceClose, threshInvScal eX * threshInvScaleX,
547 threshInvScaleY * threshInvScaleY, &tempVertices);
548
549 if (!tempVertices.count()) {
550 // path was empty, return without allocating vertex buffer
551 return;
552 }
553
554 #if VERTEX_DEBUG
555 for (unsigned int i = 0; i < tempVertices.count(); i++) {
556 SkDebugf("orig path: point at %f %f", tempVertices[i].position[0], tempV ertices[i].position[1]);
557 }
558 #endif
559
560 if (style == SkStrokeRec::kStroke_Style) {
561 float halfStrokeWidth = stroke.getWidth() * 0.5f;
562 if (!isAA) {
563 if (wasClosed) {
564 getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, ve rtexBuffer,
565 inverseScaleX, inverseScaleY);
566 } else {
567 getStrokeVerticesFromUnclosedVertices(tempVertices, halfStrokeWi dth, vertexBuffer,
568 inverseScaleX, inverseScaleY);
569 }
570
571 } else {
572 if (wasClosed) {
573 getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer,
574 inverseScaleX, inverseScaleY);
575 } else {
576 getStrokeVerticesFromUnclosedVerticesAA(tempVertices, halfStroke Width, vertexBuffer,
577 inverseScaleX, inverseScaleY);
578 }
579 }
580 } else {
581 // For kStrokeAndFill style, the path should be adjusted externally, as it will be treated as a fill here.
582 if (!isAA) {
583 getFillVerticesFromPerimeter(tempVertices, vertexBuffer);
584 } else {
585 getFillVerticesFromPerimeterAA(tempVertices, vertexBuffer, inverseSc aleX, inverseScaleY);
586 }
587 }
588 }
589
590
591 static void pushToVector(SkTArray<Vertex, true>* vertices, float x, float y) {
592 // TODO: make this not yuck
593 vertices->push_back();
594 Vertex* newVertex = &((*vertices)[vertices->count() - 1]);
595 Vertex::set(newVertex, x, y);
596 }
597
598 bool PathRenderer::ConvexPathPerimeterVertices(const SkPath& path, bool forceClo se,
599 float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVe rtices) {
600
601
602 // TODO: to support joins other than sharp miter, join vertices should be la belled in the
603 // perimeter, or resolved into more vertices. Reconsider forceClose-ing in t hat case.
604 SkPath::Iter iter(path, forceClose);
605 SkPoint pts[4];
606 SkPath::Verb v;
607
608 while (SkPath::kDone_Verb != (v = iter.next(pts))) {
609 switch (v) {
610 case SkPath::kMove_Verb:
611 pushToVector(outputVertices, pts[0].x(), pts[0].y());
612 ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
613 break;
614 case SkPath::kClose_Verb:
615 ALOGV("Close at pos %f %f", pts[0].x(), pts[0].y());
616 break;
617 case SkPath::kLine_Verb:
618 ALOGV("kLine_Verb %f %f -> %f %f",
619 pts[0].x(), pts[0].y(),
620 pts[1].x(), pts[1].y());
621
622 pushToVector(outputVertices, pts[1].x(), pts[1].y());
623 break;
624 case SkPath::kQuad_Verb:
625 ALOGV("kQuad_Verb");
626 RecursiveQuadraticBezierVertices(
627 pts[0].x(), pts[0].y(),
628 pts[2].x(), pts[2].y(),
629 pts[1].x(), pts[1].y(),
630 sqrInvScaleX, sqrInvScaleY, outputVertices);
631 break;
632 case SkPath::kCubic_Verb:
633 ALOGV("kCubic_Verb");
634 RecursiveCubicBezierVertices(
635 pts[0].x(), pts[0].y(),
636 pts[1].x(), pts[1].y(),
637 pts[3].x(), pts[3].y(),
638 pts[2].x(), pts[2].y(),
639 sqrInvScaleX, sqrInvScaleY, outputVertices);
640 break;
641 default:
642 break;
643 }
644 }
645
646 int size = outputVertices->count();
647 if (size >= 2 && (*outputVertices)[0].position[0] == (*outputVertices)[size - 1].position[0] &&
648 (*outputVertices)[0].position[1] == (*outputVertices)[size - 1].posi tion[1]) {
649 outputVertices->pop_back();
650 return true;
651 }
652 return false;
653 }
654
655 void PathRenderer::RecursiveCubicBezierVertices(
656 float p1x, float p1y, float c1x, float c1y,
657 float p2x, float p2y, float c2x, float c2y,
658 float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVe rtices) {
659 float dx = p2x - p1x;
660 float dy = p2y - p1y;
661 float d1 = sk_float_abs((c1x - p2x) * dy - (c1y - p2y) * dx);
662 float d2 = sk_float_abs((c2x - p2x) * dy - (c2y - p2y) * dx);
663 float d = d1 + d2;
664
665 // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional sc ale factors
666
667 if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrI nvScaleX)) {
668 // below thresh, draw line by adding endpoint
669 pushToVector(outputVertices, p2x, p2y);
670 } else {
671 float p1c1x = (p1x + c1x) * 0.5f;
672 float p1c1y = (p1y + c1y) * 0.5f;
673 float p2c2x = (p2x + c2x) * 0.5f;
674 float p2c2y = (p2y + c2y) * 0.5f;
675
676 float c1c2x = (c1x + c2x) * 0.5f;
677 float c1c2y = (c1y + c2y) * 0.5f;
678
679 float p1c1c2x = (p1c1x + c1c2x) * 0.5f;
680 float p1c1c2y = (p1c1y + c1c2y) * 0.5f;
681
682 float p2c1c2x = (p2c2x + c1c2x) * 0.5f;
683 float p2c1c2y = (p2c2y + c1c2y) * 0.5f;
684
685 float mx = (p1c1c2x + p2c1c2x) * 0.5f;
686 float my = (p1c1c2y + p2c1c2y) * 0.5f;
687
688 RecursiveCubicBezierVertices(
689 p1x, p1y, p1c1x, p1c1y,
690 mx, my, p1c1c2x, p1c1c2y,
691 sqrInvScaleX, sqrInvScaleY, outputVertices);
692 RecursiveCubicBezierVertices(
693 mx, my, p2c1c2x, p2c1c2y,
694 p2x, p2y, p2c2x, p2c2y,
695 sqrInvScaleX, sqrInvScaleY, outputVertices);
696 }
697 }
698
699 void PathRenderer::RecursiveQuadraticBezierVertices(
700 float ax, float ay,
701 float bx, float by,
702 float cx, float cy,
703 float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVe rtices) {
704 float dx = bx - ax;
705 float dy = by - ay;
706 float d = (cx - bx) * dy - (cy - by) * dx;
707
708 if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrI nvScaleX)) {
709 // below thresh, draw line by adding endpoint
710 pushToVector(outputVertices, bx, by);
711 } else {
712 float acx = (ax + cx) * 0.5f;
713 float bcx = (bx + cx) * 0.5f;
714 float acy = (ay + cy) * 0.5f;
715 float bcy = (by + cy) * 0.5f;
716
717 // midpoint
718 float mx = (acx + bcx) * 0.5f;
719 float my = (acy + bcy) * 0.5f;
720
721 RecursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
722 sqrInvScaleX, sqrInvScaleY, outputVertices);
723 RecursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
724 sqrInvScaleX, sqrInvScaleY, outputVertices);
725 }
726 }
727
728 }; // namespace uirenderer
729 }; // namespace android
OLDNEW
« no previous file with comments | « experimental/AndroidPathRenderer/AndroidPathRenderer.h ('k') | experimental/AndroidPathRenderer/GrAndroidPathRenderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698