blob: 28847b89515f3988bb863a945ec5691f66a537ac [file] [log] [blame]
Cary Clark73fa9722017-08-29 17:36:51 -04001#Topic Path
Cary Clark137b8742018-05-30 09:21:49 -04002#Alias Path_Reference ##
3#Alias Paths ##
Cary Clark73fa9722017-08-29 17:36:51 -04004
Cary Clark682c58d2018-05-16 07:07:07 -04005Path contains Lines and Curves which can be stroked or filled. Contour is
6composed of a series of connected Lines and Curves. Path may contain zero,
Cary Clark73fa9722017-08-29 17:36:51 -04007one, or more Contours.
8Each Line and Curve are described by Verb, Points, and optional Conic_Weight.
9
10Each pair of connected Lines and Curves share common Point; for instance, Path
Cary Clark682c58d2018-05-16 07:07:07 -040011containing two connected Lines are described the Verb sequence:
Cary Clark73fa9722017-08-29 17:36:51 -040012SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb; and a Point sequence
13with three entries, sharing
14the middle entry as the end of the first Line and the start of the second Line.
15
16Path components Arc, Rect, Round_Rect, Circle, and Oval are composed of
17Lines and Curves with as many Verbs and Points required
18for an exact description. Once added to Path, these components may lose their
Cary Clarkce101242017-09-01 15:51:02 -040019identity; although Path can be inspected to determine if it describes a single
Cary Clark73fa9722017-08-29 17:36:51 -040020Rect, Oval, Round_Rect, and so on.
21
22#Example
23#Height 192
24#Description
25Path contains three Contours: Line, Circle, and Quad. Line is stroked but
26not filled. Circle is stroked and filled; Circle stroke forms a loop. Quad
27is stroked and filled, but since it is not closed, Quad does not stroke a loop.
28##
29void draw(SkCanvas* canvas) {
30 SkPaint paint;
31 paint.setAntiAlias(true);
32 SkPath path;
33 path.moveTo(124, 108);
34 path.lineTo(172, 24);
35 path.addCircle(50, 50, 30);
36 path.moveTo(36, 148);
37 path.quadTo(66, 188, 120, 136);
38 canvas->drawPath(path, paint);
39 paint.setStyle(SkPaint::kStroke_Style);
40 paint.setColor(SK_ColorBLUE);
41 paint.setStrokeWidth(3);
42 canvas->drawPath(path, paint);
43}
44##
45
46Path contains a Fill_Type which determines whether overlapping Contours
47form fills or holes. Fill_Type also determines whether area inside or outside
48Lines and Curves is filled.
49
50#Example
51#Height 192
52#Description
53Path is drawn filled, then stroked, then stroked and filled.
54##
55void draw(SkCanvas* canvas) {
56 SkPaint paint;
57 paint.setAntiAlias(true);
58 SkPath path;
59 path.moveTo(36, 48);
60 path.quadTo(66, 88, 120, 36);
61 canvas->drawPath(path, paint);
62 paint.setStyle(SkPaint::kStroke_Style);
63 paint.setColor(SK_ColorBLUE);
64 paint.setStrokeWidth(8);
65 canvas->translate(0, 50);
66 canvas->drawPath(path, paint);
67 paint.setStyle(SkPaint::kStrokeAndFill_Style);
68 paint.setColor(SK_ColorRED);
69 canvas->translate(0, 50);
70 canvas->drawPath(path, paint);
71}
72##
73
74Path contents are never shared. Copying Path by value effectively creates
75a new Path independent of the original. Internally, the copy does not duplicate
76its contents until it is edited, to reduce memory use and improve performance.
77
Cary Clark8032b982017-07-28 11:04:54 -040078#Subtopic Contour
Cary Clark137b8742018-05-30 09:21:49 -040079#Alias Contours ##
Cary Clark08895c42018-02-01 09:37:32 -050080#Line # loop of lines and curves ##
81
Cary Clark8032b982017-07-28 11:04:54 -040082Contour contains one or more Verbs, and as many Points as
83are required to satisfy Verb_Array. First Verb in Path is always
84SkPath::kMove_Verb; each SkPath::kMove_Verb that follows starts a new Contour.
85
86#Example
Cary Clark682c58d2018-05-16 07:07:07 -040087#Description
Cary Clark73fa9722017-08-29 17:36:51 -040088Each SkPath::moveTo starts a new Contour, and content after SkPath::close()
Cary Clark682c58d2018-05-16 07:07:07 -040089also starts a new Contour. Since SkPath::conicTo is not preceded by
Cary Clark73fa9722017-08-29 17:36:51 -040090SkPath::moveTo, the first Point of the third Contour starts at the last Point
91of the second Contour.
92##
93#Height 192
94 SkPaint paint;
95 paint.setAntiAlias(true);
96 canvas->drawString("1st contour", 150, 100, paint);
97 canvas->drawString("2nd contour", 130, 160, paint);
98 canvas->drawString("3rd contour", 40, 30, paint);
99 paint.setStyle(SkPaint::kStroke_Style);
100 SkPath path;
101 path.moveTo(124, 108);
102 path.lineTo(172, 24);
103 path.moveTo(36, 148);
104 path.quadTo(66, 188, 120, 136);
105 path.close();
106 path.conicTo(70, 20, 110, 40, 0.6f);
107 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -0400108##
109
110If final Verb in Contour is SkPath::kClose_Verb, Line connects Last_Point in
Cary Clark682c58d2018-05-16 07:07:07 -0400111Contour with first Point. A closed Contour, stroked, draws
Cary Clark8032b982017-07-28 11:04:54 -0400112Paint_Stroke_Join at Last_Point and first Point. Without SkPath::kClose_Verb
113as final Verb, Last_Point and first Point are not connected; Contour
Cary Clark682c58d2018-05-16 07:07:07 -0400114remains open. An open Contour, stroked, draws Paint_Stroke_Cap at
Cary Clark8032b982017-07-28 11:04:54 -0400115Last_Point and first Point.
116
117#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400118#Height 160
119#Description
120Path is drawn stroked, with an open Contour and a closed Contour.
121##
122void draw(SkCanvas* canvas) {
123 SkPaint paint;
124 paint.setAntiAlias(true);
125 paint.setStyle(SkPaint::kStroke_Style);
126 paint.setStrokeWidth(8);
127 SkPath path;
128 path.moveTo(36, 48);
129 path.quadTo(66, 88, 120, 36);
130 canvas->drawPath(path, paint);
131 path.close();
132 canvas->translate(0, 50);
133 canvas->drawPath(path, paint);
134}
Cary Clark8032b982017-07-28 11:04:54 -0400135##
136
137#Subtopic Zero_Length
Cary Clark137b8742018-05-30 09:21:49 -0400138#Alias Zero_Length_Contour ##
Cary Clark08895c42018-02-01 09:37:32 -0500139#Line # consideration when contour has no length ##
Cary Clark8032b982017-07-28 11:04:54 -0400140Contour length is distance traveled from first Point to Last_Point,
141plus, if Contour is closed, distance from Last_Point to first Point.
142Even if Contour length is zero, stroked Lines are drawn if Paint_Stroke_Cap
143makes them visible.
144
145#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400146#Height 64
147 SkPaint paint;
148 paint.setAntiAlias(true);
149 paint.setStyle(SkPaint::kStroke_Style);
150 paint.setStrokeWidth(8);
151 paint.setStrokeCap(SkPaint::kRound_Cap);
152 SkPath path;
153 path.moveTo(36, 48);
154 path.lineTo(36, 48);
155 canvas->drawPath(path, paint);
156 path.reset();
157 paint.setStrokeCap(SkPaint::kSquare_Cap);
158 path.moveTo(56, 48);
159 path.close();
Cary Clark8032b982017-07-28 11:04:54 -0400160 canvas->drawPath(path, paint);
161##
162
163#Subtopic Zero_Length ##
164
165#Subtopic Contour ##
Cary Clark682c58d2018-05-16 07:07:07 -0400166
Cary Clark73fa9722017-08-29 17:36:51 -0400167# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400168
Cary Clark73fa9722017-08-29 17:36:51 -0400169#Class SkPath
170
171Paths contain geometry. Paths may be empty, or contain one or more Verbs that
Cary Clarka560c472017-11-27 10:44:06 -0500172outline a figure. Path always starts with a move verb to a Cartesian_Coordinate,
173and may be followed by additional verbs that add lines or curves.
Cary Clark73fa9722017-08-29 17:36:51 -0400174Adding a close verb makes the geometry into a continuous loop, a closed contour.
Cary Clarkce101242017-09-01 15:51:02 -0400175Paths may contain any number of contours, each beginning with a move verb.
Cary Clark73fa9722017-08-29 17:36:51 -0400176
177Path contours may contain only a move verb, or may also contain lines,
Cary Clarkce101242017-09-01 15:51:02 -0400178Quadratic_Beziers, Conics, and Cubic_Beziers. Path contours may be open or
Cary Clark73fa9722017-08-29 17:36:51 -0400179closed.
180
181When used to draw a filled area, Path describes whether the fill is inside or
182outside the geometry. Path also describes the winding rule used to fill
183overlapping contours.
184
185Internally, Path lazily computes metrics likes bounds and convexity. Call
Cary Clark682c58d2018-05-16 07:07:07 -0400186SkPath::updateBoundsCache to make Path thread safe.
187
188#Subtopic Overview
189#Populate
190##
Cary Clark73fa9722017-08-29 17:36:51 -0400191
Cary Clark4855f782018-02-06 09:41:53 -0500192#Subtopic Related_Function
Cary Clark08895c42018-02-01 09:37:32 -0500193#Populate
194##
Cary Clark5081eed2018-01-22 07:55:48 -0500195
Cary Clark4855f782018-02-06 09:41:53 -0500196#Subtopic Constant
Cary Clark08895c42018-02-01 09:37:32 -0500197#Populate
198##
Cary Clark73fa9722017-08-29 17:36:51 -0400199
Cary Clark682c58d2018-05-16 07:07:07 -0400200#Subtopic Class
Cary Clark08895c42018-02-01 09:37:32 -0500201#Populate
202##
Cary Clark73fa9722017-08-29 17:36:51 -0400203
Cary Clark4855f782018-02-06 09:41:53 -0500204#Subtopic Constructor
Cary Clark08895c42018-02-01 09:37:32 -0500205#Populate
206##
Cary Clark8032b982017-07-28 11:04:54 -0400207
Cary Clark4855f782018-02-06 09:41:53 -0500208#Subtopic Operator
Cary Clark08895c42018-02-01 09:37:32 -0500209#Populate
210##
Cary Clark73fa9722017-08-29 17:36:51 -0400211
Cary Clark4855f782018-02-06 09:41:53 -0500212#Subtopic Member_Function
Cary Clark08895c42018-02-01 09:37:32 -0500213#Populate
214##
Cary Clark73fa9722017-08-29 17:36:51 -0400215
Cary Clark8032b982017-07-28 11:04:54 -0400216#Subtopic Verb
Cary Clark137b8742018-05-30 09:21:49 -0400217#Alias Verbs ##
Cary Clark08895c42018-02-01 09:37:32 -0500218#Line # line and curve type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400219#Enum Verb
Cary Clark08895c42018-02-01 09:37:32 -0500220#Line # controls how Path Points are interpreted ##
Cary Clark73fa9722017-08-29 17:36:51 -0400221
222#Code
223 enum Verb {
Cary Clark682c58d2018-05-16 07:07:07 -0400224 kMove_Verb,
225 kLine_Verb,
226 kQuad_Verb,
227 kConic_Verb,
228 kCubic_Verb,
229 kClose_Verb,
230 kDone_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -0400231 };
232##
233
234Verb instructs Path how to interpret one or more Point and optional Conic_Weight;
Cary Clark8032b982017-07-28 11:04:54 -0400235manage Contour, and terminate Path.
236
Cary Clark73fa9722017-08-29 17:36:51 -0400237#Const kMove_Verb 0
Cary Clark682c58d2018-05-16 07:07:07 -0400238#Line # starts new Contour at next Point ##
239 Consecutive kMove_Verb are preserved but all but the last kMove_Verb is
240 ignored. kMove_Verb after other Verbs implicitly closes the previous Contour
241 if SkPaint::kFill_Style is set when drawn; otherwise, stroke is drawn open.
242 kMove_Verb as the last Verb is preserved but ignored.
Cary Clark73fa9722017-08-29 17:36:51 -0400243##
244#Const kLine_Verb 1
Cary Clark682c58d2018-05-16 07:07:07 -0400245#Line # adds Line from Last_Point to next Point ##
246 Line is a straight segment from Point to Point. Consecutive kLine_Verb
247 extend Contour. kLine_Verb at same position as prior kMove_Verb is
248 preserved, and draws Point if SkPaint::kStroke_Style is set, and
249 SkPaint::Cap is SkPaint::kSquare_Cap or SkPaint::kRound_Cap. kLine_Verb
250 at same position as prior line or curve Verb is preserved but is ignored.
Cary Clark73fa9722017-08-29 17:36:51 -0400251##
252#Const kQuad_Verb 2
Cary Clark682c58d2018-05-16 07:07:07 -0400253#Line # adds Quad from Last_Point ##
254 Adds Quad from Last_Point, using control Point, and end Point.
Cary Clark73fa9722017-08-29 17:36:51 -0400255 Quad is a parabolic section within tangents from Last_Point to control Point,
256 and control Point to end Point.
257##
258#Const kConic_Verb 3
Cary Clark682c58d2018-05-16 07:07:07 -0400259#Line # adds Conic from Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -0400260 Adds Conic from Last_Point, using control Point, end Point, and Conic_Weight.
Cary Clark682c58d2018-05-16 07:07:07 -0400261 Conic is a elliptical, parabolic, or hyperbolic section within tangents
Cary Clark73fa9722017-08-29 17:36:51 -0400262 from Last_Point to control Point, and control Point to end Point, constrained
263 by Conic_Weight. Conic_Weight less than one is elliptical; equal to one is
264 parabolic (and identical to Quad); greater than one hyperbolic.
265##
266#Const kCubic_Verb 4
Cary Clark682c58d2018-05-16 07:07:07 -0400267#Line # adds Cubic from Last_Point ##
268 Adds Cubic from Last_Point, using two control Points, and end Point.
Cary Clarka560c472017-11-27 10:44:06 -0500269 Cubic is a third-order Bezier_Curve section within tangents from Last_Point
270 to first control Point, and from second control Point to end Point.
Cary Clark73fa9722017-08-29 17:36:51 -0400271##
272#Const kClose_Verb 5
Cary Clark682c58d2018-05-16 07:07:07 -0400273#Line # closes Contour ##
274 Closes Contour, connecting Last_Point to kMove_Verb Point. Consecutive
275 kClose_Verb are preserved but only first has an effect. kClose_Verb after
276 kMove_Verb has no effect.
Cary Clark73fa9722017-08-29 17:36:51 -0400277##
278#Const kDone_Verb 6
Cary Clark682c58d2018-05-16 07:07:07 -0400279#Line # terminates Path ##
280 Not in Verb_Array, but returned by Path iterator.
Cary Clark8032b982017-07-28 11:04:54 -0400281##
282
283Each Verb has zero or more Points stored in Path.
284Path iterator returns complete curve descriptions, duplicating shared Points
285for consecutive entries.
286
287#Table
288#Legend
289# Verb # Allocated Points # Iterated Points # Weights ##
290##
291# kMove_Verb # 1 # 1 # 0 ##
292# kLine_Verb # 1 # 2 # 0 ##
293# kQuad_Verb # 2 # 3 # 0 ##
294# kConic_Verb # 2 # 3 # 1 ##
295# kCubic_Verb # 3 # 4 # 0 ##
296# kClose_Verb # 0 # 1 # 0 ##
297# kDone_Verb # -- # 0 # 0 ##
298##
Cary Clark73fa9722017-08-29 17:36:51 -0400299
300#Example
301void draw(SkCanvas* canvas) {
302 SkPath path;
303 path.lineTo(20, 20);
304 path.quadTo(-10, -10, 30, 30);
305 path.close();
306 path.cubicTo(1, 2, 3, 4, 5, 6);
307 path.conicTo(0, 0, 0, 0, 2);
308 uint8_t verbs[7];
309 int count = path.getVerbs(verbs, (int) SK_ARRAY_COUNT(verbs));
310 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close" };
311 SkDebugf("verb count: %d\nverbs: ", count);
312 for (int i = 0; i < count; ++i) {
313 SkDebugf("k%s_Verb ", verbStr[verbs[i]]);
314 }
315 SkDebugf("\n");
316}
317#StdOut
318verb count: 7
Cary Clark682c58d2018-05-16 07:07:07 -0400319verbs: kMove_Verb kLine_Verb kQuad_Verb kClose_Verb kMove_Verb kCubic_Verb kConic_Verb
Cary Clark73fa9722017-08-29 17:36:51 -0400320##
321##
322
323#Enum Verb ##
324#Subtopic Verb ##
325
326# ------------------------------------------------------------------------------
327#Subtopic Direction
Cary Clark682c58d2018-05-16 07:07:07 -0400328#Line # contour orientation, clockwise or counterclockwise ##
Cary Clark137b8742018-05-30 09:21:49 -0400329#Alias Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400330
331#Enum Direction
Cary Clark08895c42018-02-01 09:37:32 -0500332#Line # sets Contour clockwise or counterclockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400333
334#Code
335 enum Direction {
Cary Clark682c58d2018-05-16 07:07:07 -0400336 kCW_Direction,
337 kCCW_Direction,
Cary Clark73fa9722017-08-29 17:36:51 -0400338 };
339##
340
341Direction describes whether Contour is clockwise or counterclockwise.
342When Path contains multiple overlapping Contours, Direction together with
343Fill_Type determines whether overlaps are filled or form holes.
344
345Direction also determines how Contour is measured. For instance, dashing
346measures along Path to determine where to start and stop stroke; Direction
347will change dashed results as it steps clockwise or counterclockwise.
348
Cary Clark682c58d2018-05-16 07:07:07 -0400349Closed Contours like Rect, Round_Rect, Circle, and Oval added with
Cary Clark73fa9722017-08-29 17:36:51 -0400350kCW_Direction travel clockwise; the same added with kCCW_Direction
351travel counterclockwise.
352
353#Const kCW_Direction 0
Cary Clark682c58d2018-05-16 07:07:07 -0400354#Line # contour travels clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400355##
356#Const kCCW_Direction 1
Cary Clark682c58d2018-05-16 07:07:07 -0400357#Line # contour travels counterclockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400358##
359
360
361#Example
362#Height 100
363void draw(SkCanvas* canvas) {
364 const SkPoint arrow[] = { {40, -5}, {45, 0}, {40, 5} };
365 const SkRect rect = {10, 10, 90, 90};
366 SkPaint rectPaint;
367 rectPaint.setAntiAlias(true);
368 SkPaint textPaint(rectPaint);
369 textPaint.setTextAlign(SkPaint::kCenter_Align);
370 rectPaint.setStyle(SkPaint::kStroke_Style);
371 SkPaint arrowPaint(rectPaint);
372 SkPath arrowPath;
373 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
374 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 320, 0,
375 SkPath1DPathEffect::kRotate_Style));
376 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
377 canvas->drawRect(rect, rectPaint);
378 for (unsigned start : { 0, 1, 2, 3 } ) {
379 SkPath path;
380 path.addRect(rect, direction, start);
381 canvas->drawPath(path, arrowPaint);
382 }
383 canvas->drawString(SkPath::kCW_Direction == direction ? "CW" : "CCW", rect.centerX(),
384 rect.centerY(), textPaint);
385 canvas->translate(120, 0);
386 }
387}
388##
389
Cary Clark682c58d2018-05-16 07:07:07 -0400390#SeeAlso arcTo rArcTo isRect isNestedFillRects addRect addOval
Cary Clark73fa9722017-08-29 17:36:51 -0400391
392#Enum Direction ##
393#Subtopic Direction ##
394
395# ------------------------------------------------------------------------------
396
397#Method SkPath()
398
Cary Clarkab2621d2018-01-30 10:08:57 -0500399#Line # constructs with default values ##
Cary Clark80247e52018-07-11 16:18:41 -0400400Constucts an empty path. By default, Path has no Verbs, no Points, and no Weights.
Cary Clark73fa9722017-08-29 17:36:51 -0400401Fill_Type is set to kWinding_FillType.
402
403#Return empty Path ##
404
405#Example
406 SkPath path;
407 SkDebugf("path is " "%s" "empty", path.isEmpty() ? "" : "not ");
408#StdOut
409path is empty
410##
411##
412
413#SeeAlso reset rewind
414
415##
416
417# ------------------------------------------------------------------------------
418
419#Method SkPath(const SkPath& path)
420
Cary Clarkab2621d2018-01-30 10:08:57 -0500421#Line # makes a shallow copy ##
Cary Clark80247e52018-07-11 16:18:41 -0400422Constructs a copy of an existing path.
Cary Clark73fa9722017-08-29 17:36:51 -0400423Copy constructor makes two paths identical by value. Internally, path and
424the returned result share pointer values. The underlying Verb_Array, Point_Array
425and Weights are copied when modified.
426
427Creating a Path copy is very efficient and never allocates memory.
428Paths are always copied by value from the interface; the underlying shared
429pointers are not exposed.
430
431#Param path Path to copy by value ##
432
Cary Clarka523d2d2017-08-30 08:58:10 -0400433#Return copy of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -0400434
435#Example
436#Description
437 Modifying one path does not effect another, even if they started as copies
438 of each other.
439##
440 SkPath path;
441 path.lineTo(20, 20);
442 SkPath path2(path);
443 path2.close();
444 SkDebugf("path verbs: %d\n", path.countVerbs());
445 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
446 path.reset();
447 SkDebugf("after reset\n" "path verbs: %d\n", path.countVerbs());
448 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
449#StdOut
450path verbs: 2
451path2 verbs: 3
452after reset
453path verbs: 0
454path2 verbs: 3
455##
456##
457
458#SeeAlso operator=(const SkPath& path)
459
460##
461
462# ------------------------------------------------------------------------------
463
464#Method ~SkPath()
465
Cary Clarkab2621d2018-01-30 10:08:57 -0500466#Line # decreases Reference_Count of owned objects ##
Cary Clark73fa9722017-08-29 17:36:51 -0400467Releases ownership of any shared data and deletes data if Path is sole owner.
468
469#Example
470#Description
Cary Clarkce101242017-09-01 15:51:02 -0400471delete calls Path Destructor, but copy of original in path2 is unaffected.
Cary Clark73fa9722017-08-29 17:36:51 -0400472##
473void draw(SkCanvas* canvas) {
474 SkPath* path = new SkPath();
475 path->lineTo(20, 20);
476 SkPath path2(*path);
477 delete path;
478 SkDebugf("path2 is " "%s" "empty", path2.isEmpty() ? "" : "not ");
479}
480##
481
482#SeeAlso SkPath() SkPath(const SkPath& path) operator=(const SkPath& path)
483
484##
485
486# ------------------------------------------------------------------------------
487
488#Method SkPath& operator=(const SkPath& path)
489
Cary Clarkab2621d2018-01-30 10:08:57 -0500490#Line # makes a shallow copy ##
Cary Clark80247e52018-07-11 16:18:41 -0400491Constructs a copy of an existing path.
Cary Clark73fa9722017-08-29 17:36:51 -0400492Path assignment makes two paths identical by value. Internally, assignment
493shares pointer values. The underlying Verb_Array, Point_Array and Weights
494are copied when modified.
495
496Copying Paths by assignment is very efficient and never allocates memory.
497Paths are always copied by value from the interface; the underlying shared
498pointers are not exposed.
499
Cary Clarkce101242017-09-01 15:51:02 -0400500#Param path Verb_Array, Point_Array, Weights, and Fill_Type to copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400501
502#Return Path copied by value ##
503
504#Example
505SkPath path1;
506path1.addRect({10, 20, 30, 40});
507SkPath path2 = path1;
508const SkRect& b1 = path1.getBounds();
509SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
510const SkRect& b2 = path2.getBounds();
511SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
512#StdOut
513path1 bounds = 10, 20, 30, 40
514path2 bounds = 10, 20, 30, 40
515#StdOut ##
516##
517
518#SeeAlso swap() SkPath(const SkPath& path)
519
520##
521
522# ------------------------------------------------------------------------------
523
524#Method bool operator==(const SkPath& a, const SkPath& b)
525
Cary Clarkab2621d2018-01-30 10:08:57 -0500526#Line # compares paths for equality ##
Cary Clark73fa9722017-08-29 17:36:51 -0400527Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
528are equivalent.
529
530#Param a Path to compare ##
531#Param b Path to compare ##
532
533#Return true if Path pair are equivalent ##
534
535#Example
536#Description
537Rewind removes Verb_Array but leaves storage; since storage is not compared,
538Path pair are equivalent.
539##
540void draw(SkCanvas* canvas) {
541 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
542 SkDebugf("%s one %c= two\n", prefix, a == b ? '=' : '!');
543 };
544 SkPath one;
545 SkPath two;
546 debugster("empty", one, two);
547 one.moveTo(0, 0);
548 debugster("moveTo", one, two);
549 one.rewind();
550 debugster("rewind", one, two);
551 one.moveTo(0, 0);
552 one.reset();
553 debugster("reset", one, two);
554}
555#StdOut
556empty one == two
557moveTo one != two
558rewind one == two
559reset one == two
560##
561##
562
563##
564
565# ------------------------------------------------------------------------------
566
Cary Clark682c58d2018-05-16 07:07:07 -0400567#Method bool operator!=(const SkPath& a, const SkPath& b)
Cary Clark73fa9722017-08-29 17:36:51 -0400568
Cary Clarkab2621d2018-01-30 10:08:57 -0500569#Line # compares paths for inequality ##
Cary Clark73fa9722017-08-29 17:36:51 -0400570Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
571are not equivalent.
572
573#Param a Path to compare ##
574#Param b Path to compare ##
575
576#Return true if Path pair are not equivalent ##
577
578#Example
579#Description
580Path pair are equal though their convexity is not equal.
581##
582void draw(SkCanvas* canvas) {
583 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
584 SkDebugf("%s one %c= two\n", prefix, a != b ? '!' : '=');
585 };
586 SkPath one;
587 SkPath two;
588 debugster("empty", one, two);
589 one.addRect({10, 20, 30, 40});
590 two.addRect({10, 20, 30, 40});
591 debugster("addRect", one, two);
592 one.setConvexity(SkPath::kConcave_Convexity);
593 debugster("setConvexity", one, two);
594 SkDebugf("convexity %c=\n", one.getConvexity() == two.getConvexity() ? '=' : '!');
595}
596#StdOut
597empty one == two
598addRect one == two
599setConvexity one == two
600convexity !=
601##
602##
603
604##
605
606# ------------------------------------------------------------------------------
607
Cary Clark4855f782018-02-06 09:41:53 -0500608#Subtopic Property
609#Populate
610#Line # metrics and attributes ##
611##
Cary Clark73fa9722017-08-29 17:36:51 -0400612
Cary Clark4855f782018-02-06 09:41:53 -0500613#Method bool isInterpolatable(const SkPath& compare) const
614#In Property
615#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500616#Line # returns if pair contains equal counts of Verb_Array and Weights ##
Cary Clark80247e52018-07-11 16:18:41 -0400617Returns true if Paths contain equal Verbs and equal Weights.
Cary Clark73fa9722017-08-29 17:36:51 -0400618If Paths contain one or more Conics, the Weights must match.
619
620conicTo may add different Verbs depending on Conic_Weight, so it is not
Cary Clarkce101242017-09-01 15:51:02 -0400621trivial to interpolate a pair of Paths containing Conics with different
Cary Clark682c58d2018-05-16 07:07:07 -0400622Conic_Weight values.
Cary Clark73fa9722017-08-29 17:36:51 -0400623
624#Param compare Path to compare ##
625
626#Return true if Paths Verb_Array and Weights are equivalent ##
627
628#Example
629 SkPath path, path2;
630 path.moveTo(20, 20);
631 path.lineTo(40, 40);
632 path.lineTo(20, 20);
633 path.lineTo(40, 40);
634 path.close();
635 path2.addRect({20, 20, 40, 40});
636 SkDebugf("paths are " "%s" "interpolatable", path.isInterpolatable(path2) ? "" : "not ");
637#StdOut
638paths are interpolatable
639##
640##
641
642#SeeAlso isInterpolatable
643
644##
645
646# ------------------------------------------------------------------------------
647
Cary Clark4855f782018-02-06 09:41:53 -0500648#Subtopic Interpolate
649#Populate
650#Line # weighted average of Path pair ##
651##
Cary Clark73fa9722017-08-29 17:36:51 -0400652
Cary Clark4855f782018-02-06 09:41:53 -0500653#Method bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const
654#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500655#Line # interpolates between Path pair ##
Cary Clark80247e52018-07-11 16:18:41 -0400656Interpolates between Paths with Point_Array of equal size.
Cary Clark61dfc3a2018-01-03 08:37:53 -0500657Copy Verb_Array and Weights to out, and set out Point_Array to a weighted
658average of this Point_Array and ending Point_Array, using the formula:
Cary Clark73fa9722017-08-29 17:36:51 -0400659#Formula
Cary Clarkac47b882018-01-11 10:35:44 -0500660(Path Point * weight) + ending Point * (1 - weight)
Cary Clark73fa9722017-08-29 17:36:51 -0400661##
Cary Clark154beea2017-10-26 07:58:48 -0400662.
Cary Clark73fa9722017-08-29 17:36:51 -0400663
Cary Clark682c58d2018-05-16 07:07:07 -0400664weight is most useful when between zero (ending Point_Array) and
665one (this Point_Array); will work with values outside of this
Cary Clark73fa9722017-08-29 17:36:51 -0400666range.
667
668interpolate() returns false and leaves out unchanged if Point_Array is not
Cary Clark682c58d2018-05-16 07:07:07 -0400669the same size as ending Point_Array. Call isInterpolatable to check Path
Cary Clark73fa9722017-08-29 17:36:51 -0400670compatibility prior to calling interpolate().
671
672#Param ending Point_Array averaged with this Point_Array ##
Cary Clark682c58d2018-05-16 07:07:07 -0400673#Param weight contribution of this Point_Array, and
674 one minus contribution of ending Point_Array
Cary Clark73fa9722017-08-29 17:36:51 -0400675##
676#Param out Path replaced by interpolated averages ##
677
678#Return true if Paths contain same number of Points ##
679
680#Example
681#Height 60
682void draw(SkCanvas* canvas) {
683 SkPaint paint;
684 paint.setAntiAlias(true);
685 paint.setStyle(SkPaint::kStroke_Style);
686 SkPath path, path2;
687 path.moveTo(20, 20);
688 path.lineTo(40, 40);
689 path.lineTo(20, 40);
690 path.lineTo(40, 20);
691 path.close();
692 path2.addRect({20, 20, 40, 40});
693 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
694 SkPath interp;
695 path.interpolate(path2, i, &interp);
696 canvas->drawPath(interp, paint);
697 canvas->translate(30, 0);
698 }
699}
700##
701
702#SeeAlso isInterpolatable
703
704##
705
706# ------------------------------------------------------------------------------
707
Cary Clark682c58d2018-05-16 07:07:07 -0400708#Method bool unique() const
Cary Clark4855f782018-02-06 09:41:53 -0500709#Deprecated soon
710Only valid for Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -0400711##
712
713# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400714#Subtopic Fill_Type
Cary Clark682c58d2018-05-16 07:07:07 -0400715#Line # fill rule, normal and inverted ##
Cary Clark8032b982017-07-28 11:04:54 -0400716
Cary Clark73fa9722017-08-29 17:36:51 -0400717#Enum FillType
Cary Clark08895c42018-02-01 09:37:32 -0500718#Line # sets winding rule and inverse fill ##
Cary Clark73fa9722017-08-29 17:36:51 -0400719
720#Code
721 enum FillType {
Cary Clark682c58d2018-05-16 07:07:07 -0400722 kWinding_FillType,
723 kEvenOdd_FillType,
724 kInverseWinding_FillType,
725 kInverseEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400726 };
727##
Cary Clark8032b982017-07-28 11:04:54 -0400728
Cary Clark682c58d2018-05-16 07:07:07 -0400729Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
Cary Clark8032b982017-07-28 11:04:54 -0400730fills if the sum of Contour edges is not zero, where clockwise edges add one, and
731counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
Cary Clark682c58d2018-05-16 07:07:07 -0400732number of Contour edges is odd. Each Fill_Type has an inverse variant that
Cary Clark8032b982017-07-28 11:04:54 -0400733reverses the rule:
734kInverseWinding_FillType fills where the sum of Contour edges is zero;
735kInverseEvenOdd_FillType fills where the number of Contour edges is even.
736
737#Example
738#Height 100
739#Description
740The top row has two clockwise rectangles. The second row has one clockwise and
741one counterclockwise rectangle. The even-odd variants draw the same. The
742winding variants draw the top rectangle overlap, which has a winding of 2, the
743same as the outer parts of the top rectangles, which have a winding of 1.
744##
Cary Clark73fa9722017-08-29 17:36:51 -0400745void draw(SkCanvas* canvas) {
746 SkPath path;
747 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
748 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
749 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
750 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
751 SkPaint strokePaint;
752 strokePaint.setStyle(SkPaint::kStroke_Style);
753 SkRect clipRect = {0, 0, 51, 100};
754 canvas->drawPath(path, strokePaint);
755 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400756 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400757 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
758 canvas->translate(51, 0);
759 canvas->save();
760 canvas->clipRect(clipRect);
761 path.setFillType(fillType);
762 canvas->drawPath(path, fillPaint);
763 canvas->restore();
764 }
Cary Clark8032b982017-07-28 11:04:54 -0400765}
766##
Cary Clark73fa9722017-08-29 17:36:51 -0400767
768#Const kWinding_FillType 0
Cary Clark682c58d2018-05-16 07:07:07 -0400769#Line # is enclosed by a non-zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400770##
771#Const kEvenOdd_FillType 1
Cary Clark682c58d2018-05-16 07:07:07 -0400772#Line # is enclosed by an odd number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400773##
774#Const kInverseWinding_FillType 2
Cary Clark682c58d2018-05-16 07:07:07 -0400775#Line # is enclosed by a zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400776##
777#Const kInverseEvenOdd_FillType 3
Cary Clark682c58d2018-05-16 07:07:07 -0400778#Line # is enclosed by an even number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400779##
780
781#Example
782#Height 230
783void draw(SkCanvas* canvas) {
784 SkPath path;
785 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
786 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
787 SkPaint strokePaint;
788 strokePaint.setStyle(SkPaint::kStroke_Style);
789 SkRect clipRect = {0, 0, 128, 128};
790 canvas->drawPath(path, strokePaint);
791 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
792 SkPaint textPaint;
793 textPaint.setAntiAlias(true);
794 textPaint.setTextAlign(SkPaint::kCenter_Align);
795 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
796 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
797 textPaint.setTextSize(18);
798 canvas->translate(0, 128);
799 canvas->scale(.5f, .5f);
800 canvas->drawString("inverse", 384, 150, textPaint);
801 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400802 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400803 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
804 canvas->save();
805 canvas->clipRect(clipRect);
806 path.setFillType(fillType);
807 canvas->drawPath(path, fillPaint);
808 canvas->restore();
809 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
810 canvas->translate(128, 0);
811 }
812}
813##
814
815#SeeAlso SkPaint::Style Direction getFillType setFillType
816
817##
818
819# ------------------------------------------------------------------------------
820
Cary Clark682c58d2018-05-16 07:07:07 -0400821#Method FillType getFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400822
Cary Clarkab2621d2018-01-30 10:08:57 -0500823#In Fill_Type
824#Line # returns Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400825Returns FillType, the rule used to fill Path. FillType of a new Path is
826kWinding_FillType.
827
Cary Clark682c58d2018-05-16 07:07:07 -0400828#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
829kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400830##
831
832#Example
833 SkPath path;
834 SkDebugf("default path fill type is %s\n",
835 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
Cary Clark682c58d2018-05-16 07:07:07 -0400836 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
Cary Clark73fa9722017-08-29 17:36:51 -0400837 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
838 "kInverseEvenOdd_FillType");
839#StdOut
840default path fill type is kWinding_FillType
841##
842##
843
844#SeeAlso FillType setFillType isInverseFillType
845
846##
847
848# ------------------------------------------------------------------------------
849
Cary Clark682c58d2018-05-16 07:07:07 -0400850#Method void setFillType(FillType ft)
Cary Clark73fa9722017-08-29 17:36:51 -0400851
Cary Clarkab2621d2018-01-30 10:08:57 -0500852#In Fill_Type
853#Line # sets Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400854Sets FillType, the rule used to fill Path. While there is no check
855that ft is legal, values outside of FillType are not supported.
856
Cary Clark682c58d2018-05-16 07:07:07 -0400857#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
858kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400859##
860
861#Example
862#Description
863If empty Path is set to inverse FillType, it fills all pixels.
864##
865#Height 64
866 SkPath path;
867 path.setFillType(SkPath::kInverseWinding_FillType);
868 SkPaint paint;
869 paint.setColor(SK_ColorBLUE);
870 canvas->drawPath(path, paint);
871##
872
873#SeeAlso FillType getFillType toggleInverseFillType
874
875##
876
877# ------------------------------------------------------------------------------
878
Cary Clark682c58d2018-05-16 07:07:07 -0400879#Method bool isInverseFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400880
Cary Clarkab2621d2018-01-30 10:08:57 -0500881#In Fill_Type
882#Line # returns if Fill_Type fills outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -0400883Returns if FillType describes area outside Path geometry. The inverse fill area
884extends indefinitely.
885
886#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType ##
887
888#Example
889 SkPath path;
890 SkDebugf("default path fill type is inverse: %s\n",
891 path.isInverseFillType() ? "true" : "false");
892#StdOut
893default path fill type is inverse: false
894##
895##
896
897#SeeAlso FillType getFillType setFillType toggleInverseFillType
898
899##
900
901# ------------------------------------------------------------------------------
902
Cary Clark682c58d2018-05-16 07:07:07 -0400903#Method void toggleInverseFillType()
Cary Clark73fa9722017-08-29 17:36:51 -0400904
Cary Clarkab2621d2018-01-30 10:08:57 -0500905#In Fill_Type
906#Line # toggles Fill_Type between inside and outside geometry ##
Cary Clark80247e52018-07-11 16:18:41 -0400907Replaces FillType with its inverse. The inverse of FillType describes the area
Cary Clark73fa9722017-08-29 17:36:51 -0400908unmodified by the original FillType.
909
Cary Clark682c58d2018-05-16 07:07:07 -0400910#Table
Cary Clark73fa9722017-08-29 17:36:51 -0400911#Legend
Cary Clark682c58d2018-05-16 07:07:07 -0400912# FillType # toggled FillType ##
Cary Clark73fa9722017-08-29 17:36:51 -0400913##
914# kWinding_FillType # kInverseWinding_FillType ##
915# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
916# kInverseWinding_FillType # kWinding_FillType ##
917# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
918##
919
920#Example
921#Description
922Path drawn normally and through its inverse touches every pixel once.
923##
924#Height 100
925SkPath path;
926SkPaint paint;
927paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -0400928paint.setTextSize(80);
929paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -0400930canvas->drawPath(path, paint);
931path.toggleInverseFillType();
932paint.setColor(SK_ColorGREEN);
933canvas->drawPath(path, paint);
934##
935
936#SeeAlso FillType getFillType setFillType isInverseFillType
937
938##
939
Cary Clark8032b982017-07-28 11:04:54 -0400940#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400941
942# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400943
944#Subtopic Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500945#Line # if Path is concave or convex ##
Cary Clark73fa9722017-08-29 17:36:51 -0400946
947#Enum Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500948#Line # returns if Path is convex or concave ##
Cary Clark73fa9722017-08-29 17:36:51 -0400949
950#Code
Cary Clark884dd7d2017-10-11 10:37:52 -0400951 enum Convexity : uint8_t {
Cary Clark682c58d2018-05-16 07:07:07 -0400952 kUnknown_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400953 kConvex_Convexity,
Cary Clark682c58d2018-05-16 07:07:07 -0400954 kConcave_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400955 };
956##
957
Cary Clark682c58d2018-05-16 07:07:07 -0400958Path is convex if it contains one Contour and Contour loops no more than
959360 degrees, and Contour angles all have same Direction. Convex Path
Cary Clark8032b982017-07-28 11:04:54 -0400960may have better performance and require fewer resources on GPU_Surface.
961
Cary Clark73fa9722017-08-29 17:36:51 -0400962Path is concave when either at least one Direction change is clockwise and
963another is counterclockwise, or the sum of the changes in Direction is not 360
964degrees.
965
Cary Clark682c58d2018-05-16 07:07:07 -0400966Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
Cary Clark73fa9722017-08-29 17:36:51 -0400967if needed by destination Surface.
968
969#Const kUnknown_Convexity 0
Cary Clark682c58d2018-05-16 07:07:07 -0400970#Line # indicates Convexity has not been determined ##
Cary Clark73fa9722017-08-29 17:36:51 -0400971##
972#Const kConvex_Convexity 1
Cary Clark682c58d2018-05-16 07:07:07 -0400973#Line # one Contour made of a simple geometry without indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400974##
975#Const kConcave_Convexity 2
Cary Clark682c58d2018-05-16 07:07:07 -0400976#Line # more than one Contour, or a geometry with indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400977##
978
979#Example
980void draw(SkCanvas* canvas) {
981 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400982 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400983 const char* labels[] = { "unknown", "convex", "concave" };
984 for (SkScalar x : { 40, 100 } ) {
985 SkPath path;
986 quad[0].fX = x;
987 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
988 canvas->drawPath(path, paint);
989 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
990 canvas->translate(100, 100);
991 }
992}
993##
994
995#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
996
997#Enum Convexity ##
998
Cary Clark682c58d2018-05-16 07:07:07 -0400999#Method Convexity getConvexity() const
Cary Clark73fa9722017-08-29 17:36:51 -04001000
Cary Clarkab2621d2018-01-30 10:08:57 -05001001#In Convexity
1002#Line # returns geometry convexity, computing if necessary ##
Cary Clark682c58d2018-05-16 07:07:07 -04001003Computes Convexity if required, and returns stored value.
Cary Clark73fa9722017-08-29 17:36:51 -04001004Convexity is computed if stored value is kUnknown_Convexity,
1005or if Path has been altered since Convexity was computed or set.
1006
Cary Clarka523d2d2017-08-30 08:58:10 -04001007#Return computed or stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001008
1009#Example
1010void draw(SkCanvas* canvas) {
1011 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001012 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001013 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1014 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1015 SkPath path;
1016 debugster("initial", path);
1017 path.lineTo(50, 0);
1018 debugster("first line", path);
1019 path.lineTo(50, 50);
1020 debugster("second line", path);
1021 path.lineTo(100, 50);
1022 debugster("third line", path);
1023}
1024##
1025
1026#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
1027
1028##
1029
1030# ------------------------------------------------------------------------------
1031
Cary Clark682c58d2018-05-16 07:07:07 -04001032#Method Convexity getConvexityOrUnknown() const
Cary Clark73fa9722017-08-29 17:36:51 -04001033
Cary Clarkab2621d2018-01-30 10:08:57 -05001034#In Convexity
1035#Line # returns geometry convexity if known ##
Cary Clark682c58d2018-05-16 07:07:07 -04001036Returns last computed Convexity, or kUnknown_Convexity if
Cary Clark73fa9722017-08-29 17:36:51 -04001037Path has been altered since Convexity was computed or set.
1038
Cary Clarka523d2d2017-08-30 08:58:10 -04001039#Return stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001040
1041#Example
1042#Description
1043Convexity is unknown unless getConvexity is called without a subsequent call
1044that alters the path.
1045##
1046void draw(SkCanvas* canvas) {
1047 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001048 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001049 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
1050 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
1051 SkPath path;
1052 debugster("initial", path);
1053 path.lineTo(50, 0);
1054 debugster("first line", path);
1055 path.getConvexity();
1056 path.lineTo(50, 50);
1057 debugster("second line", path);
1058 path.lineTo(100, 50);
1059 path.getConvexity();
1060 debugster("third line", path);
1061}
1062##
1063
1064#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
1065
1066##
1067
1068# ------------------------------------------------------------------------------
1069
1070#Method void setConvexity(Convexity convexity)
1071
Cary Clarkab2621d2018-01-30 10:08:57 -05001072#In Convexity
1073#Line # sets if geometry is convex to avoid future computation ##
Cary Clark73fa9722017-08-29 17:36:51 -04001074Stores convexity so that it is later returned by getConvexity or getConvexityOrUnknown.
1075convexity may differ from getConvexity, although setting an incorrect value may
1076cause incorrect or inefficient drawing.
1077
1078If convexity is kUnknown_Convexity: getConvexity will
1079compute Convexity, and getConvexityOrUnknown will return kUnknown_Convexity.
1080
1081If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity
1082and getConvexityOrUnknown will return convexity until the path is
1083altered.
1084
1085#Param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity ##
1086
1087#Example
1088void draw(SkCanvas* canvas) {
1089 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001090 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001091 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1092 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
Cary Clark682c58d2018-05-16 07:07:07 -04001093 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001094 SkPath path;
1095 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1096 debugster("initial", path);
1097 path.setConvexity(SkPath::kConcave_Convexity);
1098 debugster("after forcing concave", path);
1099 path.setConvexity(SkPath::kUnknown_Convexity);
1100 debugster("after forcing unknown", path);
1101}
1102##
1103
1104#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
1105
1106##
1107
1108# ------------------------------------------------------------------------------
1109
Cary Clark682c58d2018-05-16 07:07:07 -04001110#Method bool isConvex() const
Cary Clark73fa9722017-08-29 17:36:51 -04001111
Cary Clarkab2621d2018-01-30 10:08:57 -05001112#In Convexity
1113#Line # returns if geometry is convex ##
Cary Clark73fa9722017-08-29 17:36:51 -04001114Computes Convexity if required, and returns true if value is kConvex_Convexity.
1115If setConvexity was called with kConvex_Convexity or kConcave_Convexity, and
1116the path has not been altered, Convexity is not recomputed.
1117
1118#Return true if Convexity stored or computed is kConvex_Convexity ##
1119
1120#Example
1121#Description
Cary Clark682c58d2018-05-16 07:07:07 -04001122Concave shape is erroneously considered convex after a forced call to
Cary Clark73fa9722017-08-29 17:36:51 -04001123setConvexity.
1124##
1125void draw(SkCanvas* canvas) {
1126 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -04001127 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001128 for (SkScalar x : { 40, 100 } ) {
1129 SkPath path;
1130 quad[0].fX = x;
1131 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1132 path.setConvexity(SkPath::kConvex_Convexity);
1133 canvas->drawPath(path, paint);
1134 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
1135 canvas->translate(100, 100);
1136 }
1137}
1138##
1139
1140#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
1141
1142##
1143
Cary Clark73fa9722017-08-29 17:36:51 -04001144#Subtopic Convexity ##
1145
1146# ------------------------------------------------------------------------------
1147
Mike Reed0c3137c2018-02-20 13:57:05 -05001148#Method bool isOval(SkRect* bounds) const
Cary Clark4855f782018-02-06 09:41:53 -05001149#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001150#Line # returns if describes Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04001151
Mike Reed0c3137c2018-02-20 13:57:05 -05001152Returns true if this path is recognized as an oval or circle.
Cary Clark73fa9722017-08-29 17:36:51 -04001153
Mike Reed0c3137c2018-02-20 13:57:05 -05001154bounds receives bounds of Oval.
Cary Clark73fa9722017-08-29 17:36:51 -04001155
Mike Reed0c3137c2018-02-20 13:57:05 -05001156bounds is unmodified if Oval is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001157
Mike Reed0c3137c2018-02-20 13:57:05 -05001158#Param bounds storage for bounding Rect of Oval; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001159
Mike Reed0c3137c2018-02-20 13:57:05 -05001160#Return true if Path is recognized as an oval or circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04001161
1162#Example
1163void draw(SkCanvas* canvas) {
1164 SkPaint paint;
1165 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001166 path.addOval({20, 20, 220, 220});
Cary Clark73fa9722017-08-29 17:36:51 -04001167 SkRect bounds;
Mike Reed0c3137c2018-02-20 13:57:05 -05001168 if (path.isOval(&bounds)) {
1169 paint.setColor(0xFF9FBFFF);
1170 canvas->drawRect(bounds, paint);
1171 }
Cary Clark73fa9722017-08-29 17:36:51 -04001172 paint.setColor(0x3f000000);
1173 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001174}
1175##
1176
1177#SeeAlso Oval addCircle addOval
1178
1179##
1180
1181# ------------------------------------------------------------------------------
1182
Mike Reed0c3137c2018-02-20 13:57:05 -05001183#Method bool isRRect(SkRRect* rrect) const
Cary Clark4855f782018-02-06 09:41:53 -05001184#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001185#Line # returns if describes Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001186
Mike Reed0c3137c2018-02-20 13:57:05 -05001187Returns true if this path is recognized as a SkRRect (but not an oval/circle or rect).
Cary Clark73fa9722017-08-29 17:36:51 -04001188
1189rrect receives bounds of Round_Rect.
Cary Clark73fa9722017-08-29 17:36:51 -04001190
Mike Reed0c3137c2018-02-20 13:57:05 -05001191rrect is unmodified if Round_Rect is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001192
1193#Param rrect storage for bounding Rect of Round_Rect; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001194
Cary Clarkce101242017-09-01 15:51:02 -04001195#Return true if Path contains only Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001196
1197#Example
Cary Clarkce101242017-09-01 15:51:02 -04001198#Description
Mike Reed0c3137c2018-02-20 13:57:05 -05001199Draw rounded rectangle and its bounds.
Cary Clarkce101242017-09-01 15:51:02 -04001200##
Cary Clark73fa9722017-08-29 17:36:51 -04001201void draw(SkCanvas* canvas) {
1202 SkPaint paint;
1203 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001204 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50));
Cary Clark73fa9722017-08-29 17:36:51 -04001205 SkRRect rrect;
Mike Reed0c3137c2018-02-20 13:57:05 -05001206 if (path.isRRect(&rrect)) {
1207 const SkRect& bounds = rrect.rect();
1208 paint.setColor(0xFF9FBFFF);
1209 canvas->drawRect(bounds, paint);
1210 }
Cary Clark73fa9722017-08-29 17:36:51 -04001211 paint.setColor(0x3f000000);
1212 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001213}
1214##
1215
Cary Clark682c58d2018-05-16 07:07:07 -04001216#SeeAlso Round_Rect addRoundRect addRRect
Cary Clark73fa9722017-08-29 17:36:51 -04001217
1218##
1219
1220# ------------------------------------------------------------------------------
1221
1222#Method void reset()
Cary Clark4855f782018-02-06 09:41:53 -05001223#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001224#Line # removes Verb_Array, Point_Array, and Weights; frees memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001225Sets Path to its initial state.
Cary Clark73fa9722017-08-29 17:36:51 -04001226Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1227Internal storage associated with Path is released.
1228
1229#Example
1230 SkPath path1, path2;
1231 path1.setFillType(SkPath::kInverseWinding_FillType);
1232 path1.addRect({10, 20, 30, 40});
1233 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1234 path1.reset();
1235 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1236##
1237
1238#SeeAlso rewind()
1239
1240##
1241
1242# ------------------------------------------------------------------------------
1243
1244#Method void rewind()
Cary Clark4855f782018-02-06 09:41:53 -05001245#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001246#Line # removes Verb_Array, Point_Array, and Weights, keeping memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001247Sets Path to its initial state, preserving internal storage.
Cary Clark73fa9722017-08-29 17:36:51 -04001248Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1249Internal storage associated with Path is retained.
1250
1251Use rewind() instead of reset() if Path storage will be reused and performance
Cary Clark682c58d2018-05-16 07:07:07 -04001252is critical.
Cary Clark73fa9722017-08-29 17:36:51 -04001253
1254#Example
1255#Description
1256Although path1 retains its internal storage, it is indistinguishable from
1257a newly initialized path.
1258##
1259 SkPath path1, path2;
1260 path1.setFillType(SkPath::kInverseWinding_FillType);
1261 path1.addRect({10, 20, 30, 40});
1262 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1263 path1.rewind();
1264 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1265##
1266
1267#SeeAlso reset()
1268
1269##
1270
1271# ------------------------------------------------------------------------------
1272
Cary Clark682c58d2018-05-16 07:07:07 -04001273#Method bool isEmpty() const
Cary Clark4855f782018-02-06 09:41:53 -05001274#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001275#Line # returns if verb count is zero ##
Cary Clark80247e52018-07-11 16:18:41 -04001276Returns if Path is empty.
Cary Clark73fa9722017-08-29 17:36:51 -04001277Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
Cary Clark682c58d2018-05-16 07:07:07 -04001278SkPath() constructs empty Path; reset() and (rewind) make Path empty.
Cary Clark73fa9722017-08-29 17:36:51 -04001279
1280#Return true if the path contains no Verb array ##
1281
1282#Example
1283void draw(SkCanvas* canvas) {
1284 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1285 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
1286 };
1287 SkPath path;
1288 debugster("initial", path);
1289 path.moveTo(0, 0);
1290 debugster("after moveTo", path);
1291 path.rewind();
1292 debugster("after rewind", path);
1293 path.lineTo(0, 0);
1294 debugster("after lineTo", path);
1295 path.reset();
1296 debugster("after reset", path);
1297}
1298#StdOut
1299initial path is empty
1300after moveTo path is not empty
1301after rewind path is empty
1302after lineTo path is not empty
1303after reset path is empty
1304##
1305##
1306
1307#SeeAlso SkPath() reset() rewind()
1308
1309##
1310
1311# ------------------------------------------------------------------------------
1312
1313#Method bool isLastContourClosed() const
Cary Clark4855f782018-02-06 09:41:53 -05001314#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001315#Line # returns if final Contour forms a loop ##
Cary Clark80247e52018-07-11 16:18:41 -04001316Returns if Contour is closed.
Cary Clark73fa9722017-08-29 17:36:51 -04001317Contour is closed if Path Verb array was last modified by close(). When stroked,
Cary Clark682c58d2018-05-16 07:07:07 -04001318closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
Cary Clark73fa9722017-08-29 17:36:51 -04001319
1320#Return true if the last Contour ends with a kClose_Verb ##
1321
1322#Example
1323#Description
1324close() has no effect if Path is empty; isLastContourClosed() returns
1325false until Path has geometry followed by close().
1326##
1327void draw(SkCanvas* canvas) {
1328 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1329 SkDebugf("%s last contour is %s" "closed\n", prefix,
1330 path.isLastContourClosed() ? "" : "not ");
1331 };
1332 SkPath path;
1333 debugster("initial", path);
1334 path.close();
1335 debugster("after close", path);
1336 path.lineTo(0, 0);
1337 debugster("after lineTo", path);
1338 path.close();
1339 debugster("after close", path);
1340}
1341#StdOut
1342initial last contour is not closed
1343after close last contour is not closed
1344after lineTo last contour is not closed
1345after close last contour is closed
1346##
1347##
1348
1349#SeeAlso close()
1350
1351##
1352
1353# ------------------------------------------------------------------------------
1354
Cary Clark682c58d2018-05-16 07:07:07 -04001355#Method bool isFinite() const
Cary Clark4855f782018-02-06 09:41:53 -05001356#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001357#Line # returns if all Point values are finite ##
Cary Clark73fa9722017-08-29 17:36:51 -04001358Returns true for finite Point array values between negative SK_ScalarMax and
1359positive SK_ScalarMax. Returns false for any Point array value of
1360SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
1361
1362#Return true if all Point values are finite ##
1363
1364#Example
1365void draw(SkCanvas* canvas) {
1366 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1367 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1368 };
1369 SkPath path;
1370 debugster("initial", path);
1371 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1372 debugster("after line", path);
1373 SkMatrix matrix;
1374 matrix.setScale(2, 2);
1375 path.transform(matrix);
1376 debugster("after scale", path);
1377}
1378#StdOut
1379initial path is finite
1380after line path is finite
1381after scale path is not finite
1382##
1383##
1384
1385#SeeAlso SkScalar
1386##
1387
1388# ------------------------------------------------------------------------------
1389
Cary Clark682c58d2018-05-16 07:07:07 -04001390#Method bool isVolatile() const
Cary Clark4855f782018-02-06 09:41:53 -05001391#In Property
1392#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001393#Line # returns if Device should not cache ##
Cary Clark73fa9722017-08-29 17:36:51 -04001394Returns true if the path is volatile; it will not be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001395by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001396Surface to attach a cache of data which speeds repeated drawing. If true, Surface
1397may not speed repeated drawing.
1398
1399#Return true if caller will alter Path after drawing ##
1400
1401#Example
1402 SkPath path;
1403 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1404#StdOut
1405volatile by default is false
1406##
1407##
1408
1409#SeeAlso setIsVolatile
1410
1411##
1412
1413# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001414#Subtopic Volatile
1415#Populate
1416#Line # caching attribute ##
1417##
Cary Clark73fa9722017-08-29 17:36:51 -04001418
Cary Clark682c58d2018-05-16 07:07:07 -04001419#Method void setIsVolatile(bool isVolatile)
Cary Clark4855f782018-02-06 09:41:53 -05001420#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001421#Line # sets if Device should not cache ##
Cary Clark80247e52018-07-11 16:18:41 -04001422Specifies whether Path is volatile; whether it will be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001423by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001424Device to attach a cache of data which speeds repeated drawing.
1425
1426Mark temporary paths, discarded or modified after use, as volatile
1427to inform Device that the path need not be cached.
1428
1429Mark animating Path volatile to improve performance.
Cary Clarkce101242017-09-01 15:51:02 -04001430Mark unchanging Path non-volatile to improve repeated rendering.
Cary Clark73fa9722017-08-29 17:36:51 -04001431
1432Raster_Surface Path draws are affected by volatile for some shadows.
1433GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
1434
1435#Param isVolatile true if caller will alter Path after drawing ##
1436
1437#Example
1438#Height 50
1439#Width 50
1440 SkPaint paint;
1441 paint.setStyle(SkPaint::kStroke_Style);
1442 SkPath path;
1443 path.setIsVolatile(true);
1444 path.lineTo(40, 40);
1445 canvas->drawPath(path, paint);
1446 path.rewind();
1447 path.moveTo(0, 40);
1448 path.lineTo(40, 0);
1449 canvas->drawPath(path, paint);
1450##
1451
1452#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1453
1454#SeeAlso isVolatile
1455
1456##
1457
1458# ------------------------------------------------------------------------------
1459
Cary Clark682c58d2018-05-16 07:07:07 -04001460#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001461#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001462#Line # returns if Line is very small ##
Cary Clark80247e52018-07-11 16:18:41 -04001463Tests if Line between Point pair is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001464Line with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001465treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001466
Cary Clarka523d2d2017-08-30 08:58:10 -04001467exact changes the equality test. If true, returns true only if p1 equals p2.
1468If false, returns true if p1 equals or nearly equals p2.
1469
Cary Clark73fa9722017-08-29 17:36:51 -04001470#Param p1 line start point ##
1471#Param p2 line end point ##
Cary Clarka523d2d2017-08-30 08:58:10 -04001472#Param exact if false, allow nearly equals ##
Cary Clark73fa9722017-08-29 17:36:51 -04001473
1474#Return true if Line is degenerate; its length is effectively zero ##
1475
1476#Example
1477#Description
Cary Clarkce101242017-09-01 15:51:02 -04001478As single precision floats, 100 and 100.000001 have the same bit representation,
1479and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001480are not exactly equal, but are nearly equal.
1481##
1482void draw(SkCanvas* canvas) {
1483 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1484 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1485 for (bool exact : { false, true } ) {
1486 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1487 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1488 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1489 ? "" : "not ", exact ? "exactly" : "nearly");
1490 }
1491 }
1492}
1493#StdOut
1494line from (100,100) to (100,100) is degenerate, nearly
1495line from (100,100) to (100,100) is degenerate, exactly
1496line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1497line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1498#StdOut ##
1499##
1500
Cary Clark682c58d2018-05-16 07:07:07 -04001501#SeeAlso IsQuadDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001502##
1503
1504# ------------------------------------------------------------------------------
1505
1506#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001507 const SkPoint& p3, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001508#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001509#Line # returns if Quad is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001510
Cary Clark80247e52018-07-11 16:18:41 -04001511Tests if Quad is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001512Quad with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001513treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001514
Cary Clarkce101242017-09-01 15:51:02 -04001515#Param p1 Quad start point ##
1516#Param p2 Quad control point ##
1517#Param p3 Quad end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001518#Param exact if true, returns true only if p1, p2, and p3 are equal;
1519 if false, returns true if p1, p2, and p3 are equal or nearly equal
Cary Clark73fa9722017-08-29 17:36:51 -04001520##
1521
1522#Return true if Quad is degenerate; its length is effectively zero ##
1523
1524#Example
1525#Description
Cary Clarkce101242017-09-01 15:51:02 -04001526As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001527but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001528the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001529##
1530void draw(SkCanvas* canvas) {
1531 auto debugster = [](const SkPath& path, bool exact) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001532 SkDebugf("quad (%1.8g,%1.8g), (%1.8g,%1.8g), (%1.8g,%1.8g) is %s" "degenerate, %s\n",
Cary Clark73fa9722017-08-29 17:36:51 -04001533 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1534 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1535 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1536 "" : "not ", exact ? "exactly" : "nearly");
1537 };
1538 SkPath path, offset;
1539 path.moveTo({100, 100});
1540 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1541 offset.addPath(path, 1000, 1000);
1542 for (bool exact : { false, true } ) {
1543 debugster(path, exact);
1544 debugster(offset, exact);
1545 }
1546}
1547#StdOut
1548quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1549quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1550quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1551quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1552#StdOut ##
1553##
1554
Cary Clark682c58d2018-05-16 07:07:07 -04001555#SeeAlso IsLineDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001556##
1557
1558# ------------------------------------------------------------------------------
1559
1560#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001561 const SkPoint& p3, const SkPoint& p4, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001562#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001563#Line # returns if Cubic is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001564
Cary Clark80247e52018-07-11 16:18:41 -04001565Tests if Cubic is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001566Cubic with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001567treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001568
Cary Clarkce101242017-09-01 15:51:02 -04001569#Param p1 Cubic start point ##
1570#Param p2 Cubic control point 1 ##
1571#Param p3 Cubic control point 2 ##
1572#Param p4 Cubic end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001573#Param exact if true, returns true only if p1, p2, p3, and p4 are equal;
Cary Clark73fa9722017-08-29 17:36:51 -04001574 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
1575##
1576
1577#Return true if Cubic is degenerate; its length is effectively zero ##
1578
1579#Example
1580void draw(SkCanvas* canvas) {
1581 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1582 SkScalar step = 1;
Cary Clark75fd4492018-06-20 12:45:16 -04001583 SkScalar prior, length = 0, degenerate = 0;
Cary Clark73fa9722017-08-29 17:36:51 -04001584 do {
1585 prior = points[0].fX;
1586 step /= 2;
1587 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1588 degenerate = prior;
1589 points[0].fX += step;
1590 } else {
1591 length = prior;
1592 points[0].fX -= step;
1593 }
1594 } while (prior != points[0].fX);
1595 SkDebugf("%1.8g is degenerate\n", degenerate);
1596 SkDebugf("%1.8g is length\n", length);
1597}
1598#StdOut
15990.00024414062 is degenerate
16000.00024414065 is length
1601#StdOut ##
1602##
1603
1604##
1605
1606# ------------------------------------------------------------------------------
1607
1608#Method bool isLine(SkPoint line[2]) const
Cary Clark4855f782018-02-06 09:41:53 -05001609#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001610#Line # returns if describes Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04001611Returns true if Path contains only one Line;
Cary Clark682c58d2018-05-16 07:07:07 -04001612Path_Verb array has two entries: kMove_Verb, kLine_Verb.
1613If Path contains one Line and line is not nullptr, line is set to
Cary Clark73fa9722017-08-29 17:36:51 -04001614Line start point and Line end point.
1615Returns false if Path is not one Line; line is unaltered.
1616
1617#Param line storage for Line. May be nullptr ##
1618
1619#Return true if Path contains exactly one Line ##
1620
1621#Example
1622void draw(SkCanvas* canvas) {
1623 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1624 SkPoint line[2];
1625 if (path.isLine(line)) {
1626 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1627 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1628 } else {
1629 SkDebugf("%s is not line\n", prefix);
1630 }
1631 };
1632 SkPath path;
1633 debugster("empty", path);
1634 path.lineTo(0, 0);
1635 debugster("zero line", path);
1636 path.rewind();
1637 path.moveTo(10, 10);
1638 path.lineTo(20, 20);
1639 debugster("line", path);
1640 path.moveTo(20, 20);
1641 debugster("second move", path);
1642}
1643#StdOut
1644empty is not line
1645zero line is line (0,0) (0,0)
1646line is line (10,10) (20,20)
1647second move is not line
1648##
1649##
1650
1651##
1652
1653# ------------------------------------------------------------------------------
1654
Cary Clark8032b982017-07-28 11:04:54 -04001655#Subtopic Point_Array
Cary Clark08895c42018-02-01 09:37:32 -05001656#Line # end points and control points for lines and curves ##
Cary Clark61dfc3a2018-01-03 08:37:53 -05001657#Substitute SkPoint array
Cary Clark8032b982017-07-28 11:04:54 -04001658
1659Point_Array contains Points satisfying the allocated Points for
1660each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001661and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001662one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1663
1664Point_Array may be read directly from Path with getPoints, or inspected with
1665getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001666
1667#Method int getPoints(SkPoint points[], int max) const
1668
Cary Clarkab2621d2018-01-30 10:08:57 -05001669#In Point_Array
1670#Line # returns Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001671Returns number of points in Path. Up to max points are copied.
1672points may be nullptr; then, max must be zero.
Cary Clark682c58d2018-05-16 07:07:07 -04001673If max is greater than number of points, excess points storage is unaltered.
Cary Clark73fa9722017-08-29 17:36:51 -04001674
1675#Param points storage for Path Point array. May be nullptr ##
1676#Param max maximum to copy; must be greater than or equal to zero ##
1677
1678#Return Path Point array length ##
1679
1680#Example
1681void draw(SkCanvas* canvas) {
1682 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1683 int count = path.getPoints(points, max);
1684 SkDebugf("%s point count: %d ", prefix, count);
1685 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1686 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1687 }
1688 SkDebugf("\n");
1689 };
1690 SkPath path;
1691 path.lineTo(20, 20);
1692 path.lineTo(-10, -10);
1693 SkPoint points[3];
1694 debugster("no points", path, nullptr, 0);
1695 debugster("zero max", path, points, 0);
1696 debugster("too small", path, points, 2);
1697 debugster("just right", path, points, path.countPoints());
1698}
1699#StdOut
1700no points point count: 3
1701zero max point count: 3
1702too small point count: 3 (0,0) (20,20)
1703just right point count: 3 (0,0) (20,20) (-10,-10)
1704##
1705##
1706
1707#SeeAlso countPoints getPoint
1708##
1709
1710#Method int countPoints() const
1711
Cary Clarkab2621d2018-01-30 10:08:57 -05001712#In Point_Array
1713#Line # returns Point_Array length ##
Cary Clark73fa9722017-08-29 17:36:51 -04001714Returns the number of points in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001715Point count is initially zero.
Cary Clark73fa9722017-08-29 17:36:51 -04001716
1717#Return Path Point array length ##
1718
1719#Example
1720void draw(SkCanvas* canvas) {
1721 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1722 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1723 };
1724 SkPath path;
1725 debugster("empty", path);
1726 path.lineTo(0, 0);
1727 debugster("zero line", path);
1728 path.rewind();
1729 path.moveTo(10, 10);
1730 path.lineTo(20, 20);
1731 debugster("line", path);
1732 path.moveTo(20, 20);
1733 debugster("second move", path);
1734}
1735#StdOut
1736empty point count: 0
1737zero line point count: 2
1738line point count: 2
1739second move point count: 3
1740##
1741##
1742
1743#SeeAlso getPoints
1744##
1745
1746#Method SkPoint getPoint(int index) const
1747
Cary Clarkab2621d2018-01-30 10:08:57 -05001748#In Point_Array
1749#Line # returns entry from Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001750Returns Point at index in Point_Array. Valid range for index is
17510 to countPoints - 1.
Cary Clark682c58d2018-05-16 07:07:07 -04001752Returns (0, 0) if index is out of range.
Cary Clark73fa9722017-08-29 17:36:51 -04001753
1754#Param index Point array element selector ##
1755
1756#Return Point array value or (0, 0) ##
1757
1758#Example
1759void draw(SkCanvas* canvas) {
Cary Clark73fa9722017-08-29 17:36:51 -04001760 SkPath path;
1761 path.lineTo(20, 20);
1762 path.offset(-10, -10);
1763 for (int i= 0; i < path.countPoints(); ++i) {
1764 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
Cary Clark682c58d2018-05-16 07:07:07 -04001765 }
Cary Clark73fa9722017-08-29 17:36:51 -04001766}
1767#StdOut
1768point 0: (-10,-10)
1769point 1: (10,10)
1770##
1771##
1772
1773#SeeAlso countPoints getPoints
1774##
1775
1776
1777#Subtopic Point_Array ##
1778
1779# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001780#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001781#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001782
1783Verb_Array always starts with kMove_Verb.
1784If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1785the quantity of kMove_Verb equals the Contour count.
1786Verb_Array does not include or count kDone_Verb; it is a convenience
1787returned when iterating through Verb_Array.
1788
Cary Clark682c58d2018-05-16 07:07:07 -04001789Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
Cary Clark8032b982017-07-28 11:04:54 -04001790or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001791
1792#Method int countVerbs() const
1793
Cary Clarkab2621d2018-01-30 10:08:57 -05001794#In Verb_Array
1795#Line # returns Verb_Array length ##
Cary Clark682c58d2018-05-16 07:07:07 -04001796Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -04001797kCubic_Verb, and kClose_Verb; added to Path.
1798
1799#Return length of Verb_Array ##
1800
1801#Example
1802SkPath path;
1803SkDebugf("empty verb count: %d\n", path.countVerbs());
1804path.addRoundRect({10, 20, 30, 40}, 5, 5);
1805SkDebugf("round rect verb count: %d\n", path.countVerbs());
1806#StdOut
1807empty verb count: 0
1808round rect verb count: 10
1809##
1810##
1811
1812#SeeAlso getVerbs Iter RawIter
1813
1814##
1815
1816#Method int getVerbs(uint8_t verbs[], int max) const
1817
Cary Clarkab2621d2018-01-30 10:08:57 -05001818#In Verb_Array
1819#Line # returns Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001820Returns the number of verbs in the path. Up to max verbs are copied. The
1821verbs are copied as one byte per verb.
1822
1823#Param verbs storage for verbs, may be nullptr ##
1824#Param max maximum number to copy into verbs ##
1825
1826#Return the actual number of verbs in the path ##
1827
1828#Example
1829void draw(SkCanvas* canvas) {
1830 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1831 int count = path.getVerbs(verbs, max);
1832 SkDebugf("%s verb count: %d ", prefix, count);
1833 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1834 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1835 SkDebugf("%s ", verbStr[verbs[i]]);
1836 }
1837 SkDebugf("\n");
1838 };
1839 SkPath path;
1840 path.lineTo(20, 20);
1841 path.lineTo(-10, -10);
1842 uint8_t verbs[3];
1843 debugster("no verbs", path, nullptr, 0);
1844 debugster("zero max", path, verbs, 0);
1845 debugster("too small", path, verbs, 2);
1846 debugster("just right", path, verbs, path.countVerbs());
1847}
1848#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04001849no verbs verb count: 3
1850zero max verb count: 3
1851too small verb count: 3 move line
1852just right verb count: 3 move line line
Cary Clark73fa9722017-08-29 17:36:51 -04001853##
1854##
1855
1856#SeeAlso countVerbs getPoints Iter RawIter
1857##
Cary Clark8032b982017-07-28 11:04:54 -04001858
1859#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001860
1861# ------------------------------------------------------------------------------
1862
1863#Method void swap(SkPath& other)
Cary Clark4855f782018-02-06 09:41:53 -05001864#In Operator
Cary Clarkab2621d2018-01-30 10:08:57 -05001865#Line # exchanges Path pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04001866Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1867Cached state is also exchanged. swap() internally exchanges pointers, so
1868it is lightweight and does not allocate memory.
1869
1870swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001871Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001872making assignment as efficient as swap().
1873
1874#Param other Path exchanged by value ##
1875
1876#Example
1877SkPath path1, path2;
1878path1.addRect({10, 20, 30, 40});
1879path1.swap(path2);
1880const SkRect& b1 = path1.getBounds();
1881SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1882const SkRect& b2 = path2.getBounds();
1883SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1884#StdOut
1885path1 bounds = 0, 0, 0, 0
1886path2 bounds = 10, 20, 30, 40
1887#StdOut ##
1888##
1889
1890#SeeAlso operator=(const SkPath& path)
1891
1892##
1893
1894# ------------------------------------------------------------------------------
1895
Cary Clark682c58d2018-05-16 07:07:07 -04001896#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001897#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001898#Line # returns maximum and minimum of Point_Array ##
Cary Clark5538c132018-06-14 12:28:14 -04001899Returns minimum and maximum axes values of Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04001900Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1901be larger or smaller than area affected when Path is drawn.
1902
1903Rect returned includes all Points added to Path, including Points associated with
1904kMove_Verb that define empty Contours.
1905
1906#Return bounds of all Points in Point_Array ##
1907
1908#Example
1909#Description
1910Bounds of upright Circle can be predicted from center and radius.
1911Bounds of rotated Circle includes control Points outside of filled area.
1912##
1913 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1914 const SkRect& bounds = path.getBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001915 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001916 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1917 };
1918 SkPath path;
1919 debugster("empty", path);
1920 path.addCircle(50, 45, 25);
1921 debugster("circle", path);
1922 SkMatrix matrix;
1923 matrix.setRotate(45, 50, 45);
1924 path.transform(matrix);
1925 debugster("rotated circle", path);
1926#StdOut
1927empty bounds = 0, 0, 0, 0
1928circle bounds = 25, 20, 75, 70
1929rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1930##
1931##
1932
1933#SeeAlso computeTightBounds updateBoundsCache
1934
1935##
1936
1937# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001938#Subtopic Utility
1939#Populate
1940#Line # rarely called management functions ##
1941##
Cary Clark73fa9722017-08-29 17:36:51 -04001942
Cary Clark682c58d2018-05-16 07:07:07 -04001943#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001944#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001945#Line # refreshes result of getBounds ##
Cary Clark80247e52018-07-11 16:18:41 -04001946Updates internal bounds so that subsequent calls to getBounds are instantaneous.
Cary Clark73fa9722017-08-29 17:36:51 -04001947Unaltered copies of Path may also access cached bounds through getBounds.
1948
1949For now, identical to calling getBounds and ignoring the returned value.
1950
Cary Clark682c58d2018-05-16 07:07:07 -04001951Call to prepare Path subsequently drawn from multiple threads,
Cary Clark73fa9722017-08-29 17:36:51 -04001952to avoid a race condition where each draw separately computes the bounds.
1953
1954#Example
1955 double times[2] = { 0, 0 };
1956 for (int i = 0; i < 10000; ++i) {
1957 SkPath path;
1958 for (int j = 1; j < 100; ++ j) {
1959 path.addCircle(50 + j, 45 + j, 25 + j);
1960 }
1961 if (1 & i) {
1962 path.updateBoundsCache();
1963 }
1964 double start = SkTime::GetNSecs();
1965 (void) path.getBounds();
1966 times[1 & i] += SkTime::GetNSecs() - start;
1967 }
1968 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1969 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1970#StdOut
1971#Volatile
1972uncached avg: 0.18048 ms
1973cached avg: 0.182784 ms
1974##
1975##
1976
1977#SeeAlso getBounds
1978#ToDo the results don't make sense, need to profile to figure this out ##
1979
1980##
1981
1982# ------------------------------------------------------------------------------
1983
1984#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001985#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001986#Line # returns extent of geometry ##
Cary Clark5538c132018-06-14 12:28:14 -04001987Returns minimum and maximum axes values of the lines and curves in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001988Returns (0, 0, 0, 0) if Path contains no points.
1989Returned bounds width and height may be larger or smaller than area affected
Cary Clark73fa9722017-08-29 17:36:51 -04001990when Path is drawn.
1991
1992Includes Points associated with kMove_Verb that define empty
1993Contours.
1994
1995Behaves identically to getBounds when Path contains
1996only lines. If Path contains curves, computed bounds includes
1997the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
1998and unlike getBounds, does not cache the result.
1999
2000#Return tight bounds of curves in Path ##
2001
2002#Example
2003 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2004 const SkRect& bounds = path.computeTightBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04002005 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04002006 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2007 };
2008 SkPath path;
2009 debugster("empty", path);
2010 path.addCircle(50, 45, 25);
2011 debugster("circle", path);
2012 SkMatrix matrix;
2013 matrix.setRotate(45, 50, 45);
2014 path.transform(matrix);
2015 debugster("rotated circle", path);
2016#StdOut
2017empty bounds = 0, 0, 0, 0
2018circle bounds = 25, 20, 75, 70
2019rotated circle bounds = 25, 20, 75, 70
2020##
2021##
2022
2023#SeeAlso getBounds
2024
2025##
2026
2027# ------------------------------------------------------------------------------
2028
2029#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05002030#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002031#Line # returns true if Rect may be inside ##
Cary Clark682c58d2018-05-16 07:07:07 -04002032Returns true if rect is contained by Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002033May return false when rect is contained by Path.
2034
2035For now, only returns true if Path has one Contour and is convex.
2036rect may share points and edges with Path and be contained.
2037Returns true if rect is empty, that is, it has zero width or height; and
2038the Point or Line described by rect is contained by Path.
2039
2040#Param rect Rect, Line, or Point checked for containment ##
2041
2042#Return true if rect is contained ##
2043
2044#Example
2045#Height 140
2046#Description
2047Rect is drawn in blue if it is contained by red Path.
2048##
2049void draw(SkCanvas* canvas) {
2050 SkPath path;
2051 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2052 SkRect tests[] = {
2053 { 10, 40, 54, 80 },
2054 { 25, 20, 39, 120 },
2055 { 15, 25, 49, 115 },
2056 { 13, 27, 51, 113 },
2057 };
2058 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2059 SkPaint paint;
2060 paint.setColor(SK_ColorRED);
2061 canvas->drawPath(path, paint);
2062 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2063 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2064 canvas->drawRect(tests[i], paint);
2065 canvas->translate(64, 0);
2066 }
2067}
2068##
2069
2070#SeeAlso contains Op Rect Convexity
2071
2072##
2073
2074# ------------------------------------------------------------------------------
2075
2076#Method void incReserve(unsigned extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05002077#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002078#Line # reserves space for additional data ##
Cary Clark80247e52018-07-11 16:18:41 -04002079Grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
Cary Clark73fa9722017-08-29 17:36:51 -04002080May improve performance and use less memory by
2081reducing the number and size of allocations when creating Path.
2082
Cary Clarkce101242017-09-01 15:51:02 -04002083#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002084
2085#Example
2086#Height 192
2087void draw(SkCanvas* canvas) {
2088 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2089 path->moveTo(size, 0);
2090 for (int i = 1; i < sides; i++) {
2091 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2092 path->lineTo(c * size, s * size);
2093 }
2094 path->close();
2095 };
2096 SkPath path;
2097 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2098 for (int sides = 3; sides < 10; ++sides) {
2099 addPoly(sides, sides, &path);
2100 }
2101 SkMatrix matrix;
2102 matrix.setScale(10, 10, -10, -10);
2103 path.transform(matrix);
2104 SkPaint paint;
2105 paint.setStyle(SkPaint::kStroke_Style);
2106 canvas->drawPath(path, paint);
2107}
2108##
2109
2110#SeeAlso Point_Array
2111
2112##
2113
2114# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05002115#Subtopic Build
2116#Populate
2117#Line # adds points and verbs to path ##
2118##
Cary Clark73fa9722017-08-29 17:36:51 -04002119
2120#Method void moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002121#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002122#Line # starts Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -04002123Adds beginning of Contour at Point (x, y).
2124
Cary Clark5538c132018-06-14 12:28:14 -04002125#Param x x-axis value of Contour start ##
2126#Param y y-axis value of Contour start ##
Cary Clark73fa9722017-08-29 17:36:51 -04002127
2128#Example
2129 #Width 140
2130 #Height 100
2131 void draw(SkCanvas* canvas) {
2132 SkRect rect = { 20, 20, 120, 80 };
2133 SkPath path;
2134 path.addRect(rect);
2135 path.moveTo(rect.fLeft, rect.fTop);
2136 path.lineTo(rect.fRight, rect.fBottom);
2137 path.moveTo(rect.fLeft, rect.fBottom);
2138 path.lineTo(rect.fRight, rect.fTop);
2139 SkPaint paint;
2140 paint.setStyle(SkPaint::kStroke_Style);
2141 canvas->drawPath(path, paint);
2142 }
2143##
2144
2145#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2146
2147##
2148
Cary Clark682c58d2018-05-16 07:07:07 -04002149#Method void moveTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002150
2151Adds beginning of Contour at Point p.
2152
2153#Param p contour start ##
2154
2155#Example
2156 #Width 128
2157 #Height 128
2158void draw(SkCanvas* canvas) {
Cary Clark682c58d2018-05-16 07:07:07 -04002159 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
Cary Clark73fa9722017-08-29 17:36:51 -04002160 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2161 SkPath path;
2162 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2163 path.moveTo(data[i][0]);
2164 path.lineTo(data[i][1]);
2165 path.lineTo(data[i][2]);
2166 }
2167 SkPaint paint;
2168 paint.setStyle(SkPaint::kStroke_Style);
2169 canvas->drawPath(path, paint);
2170}
2171##
2172
2173#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2174
2175##
2176
2177#Method void rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002178#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002179#Line # starts Contour relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002180Adds beginning of Contour relative to Last_Point.
2181If Path is empty, starts Contour at (dx, dy).
Cary Clark682c58d2018-05-16 07:07:07 -04002182Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002183Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002184
Cary Clark5538c132018-06-14 12:28:14 -04002185#Param dx offset from Last_Point to Contour start on x-axis ##
2186#Param dy offset from Last_Point to Contour start on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002187
2188#Example
2189 #Height 100
2190 SkPath path;
2191 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2192 path.rMoveTo(25, 2);
2193 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2194 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2195 path.rLineTo(arrow[i].fX, arrow[i].fY);
2196 }
2197 SkPaint paint;
2198 canvas->drawPath(path, paint);
2199 SkPoint lastPt;
2200 path.getLastPt(&lastPt);
2201 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2202##
2203
2204#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2205
2206##
2207
2208# ------------------------------------------------------------------------------
2209
2210#Method void lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002211#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002212#Line # appends Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04002213Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2214kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2215
2216lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2217lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
Cary Clark682c58d2018-05-16 07:07:07 -04002218
Cary Clark73fa9722017-08-29 17:36:51 -04002219#Param x end of added Line in x ##
2220#Param y end of added Line in y ##
2221
2222#Example
2223#Height 100
2224###$
2225void draw(SkCanvas* canvas) {
2226 SkPaint paint;
2227 paint.setAntiAlias(true);
2228 paint.setTextSize(72);
2229 canvas->drawString("#", 120, 80, paint);
2230 paint.setStyle(SkPaint::kStroke_Style);
2231 paint.setStrokeWidth(5);
2232 SkPath path;
2233 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2234 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2235 unsigned o = 0;
2236 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2237 for (unsigned j = 0; j < 2; o++, j++) {
2238 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2239 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2240 }
2241 }
2242 canvas->drawPath(path, paint);
2243}
2244$$$#
2245##
2246
2247#SeeAlso Contour moveTo rLineTo addRect
2248
2249##
2250
2251# ------------------------------------------------------------------------------
2252
Cary Clark682c58d2018-05-16 07:07:07 -04002253#Method void lineTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002254
2255Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2256kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2257
2258lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2259lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2260
2261#Param p end Point of added Line ##
2262
2263#Example
2264#Height 100
2265 SkPath path;
2266 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2267 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2268 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2269 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2270 path.moveTo(oxo[i]);
2271 path.lineTo(oxo[i + 1]);
2272 }
2273 SkPaint paint;
2274 paint.setStyle(SkPaint::kStroke_Style);
2275 canvas->drawPath(path, paint);
2276##
2277
2278#SeeAlso Contour moveTo rLineTo addRect
2279
2280##
2281
2282# ------------------------------------------------------------------------------
2283
2284#Method void rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002285#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002286#Line # appends Line relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002287Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2288kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2289
2290Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2291then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2292Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002293Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002294
Cary Clark5538c132018-06-14 12:28:14 -04002295#Param dx offset from Last_Point to Line end on x-axis ##
2296#Param dy offset from Last_Point to Line end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002297
2298#Example
2299#Height 128
2300void draw(SkCanvas* canvas) {
2301 SkPaint paint;
2302 paint.setAntiAlias(true);
2303 paint.setStyle(SkPaint::kStroke_Style);
2304 SkPath path;
2305 path.moveTo(10, 98);
2306 SkScalar x = 0, y = 0;
2307 for (int i = 10; i < 100; i += 5) {
2308 x += i * ((i & 2) - 1);
2309 y += i * (((i + 1) & 2) - 1);
2310 path.rLineTo(x, y);
Cary Clark682c58d2018-05-16 07:07:07 -04002311
Cary Clark73fa9722017-08-29 17:36:51 -04002312 }
2313 canvas->drawPath(path, paint);
2314}
2315##
2316
2317#SeeAlso Contour moveTo lineTo addRect
2318
2319##
2320
2321# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002322#Subtopic Quad
Cary Clark137b8742018-05-30 09:21:49 -04002323#Alias Quad ##
2324#Alias Quads ##
2325#Alias Quadratic_Bezier ##
2326#Alias Quadratic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002327#Line # curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002328
2329Quad describes a quadratic Bezier, a second-order curve identical to a section
2330of a parabola. Quad begins at a start Point, curves towards a control Point,
2331and then curves to an end Point.
2332
2333#Example
2334#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002335void draw(SkCanvas* canvas) {
2336 SkPaint paint;
2337 paint.setAntiAlias(true);
2338 paint.setStyle(SkPaint::kStroke_Style);
2339 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2340 canvas->drawLine(quadPts[0], quadPts[1], paint);
2341 canvas->drawLine(quadPts[1], quadPts[2], paint);
2342 SkPath path;
2343 path.moveTo(quadPts[0]);
2344 path.quadTo(quadPts[1], quadPts[2]);
2345 paint.setStrokeWidth(3);
2346 canvas->drawPath(path, paint);
2347}
Cary Clark8032b982017-07-28 11:04:54 -04002348##
2349
2350Quad is a special case of Conic where Conic_Weight is set to one.
2351
2352Quad is always contained by the triangle connecting its three Points. Quad
2353begins tangent to the line between start Point and control Point, and ends
2354tangent to the line between control Point and end Point.
2355
2356#Example
2357#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002358void draw(SkCanvas* canvas) {
2359 SkPaint paint;
2360 paint.setAntiAlias(true);
2361 paint.setStyle(SkPaint::kStroke_Style);
2362 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2363 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2364 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2365 paint.setColor(0x7fffffff & colors[i]);
2366 paint.setStrokeWidth(1);
2367 canvas->drawLine(quadPts[0], quadPts[1], paint);
2368 canvas->drawLine(quadPts[1], quadPts[2], paint);
2369 SkPath path;
2370 path.moveTo(quadPts[0]);
2371 path.quadTo(quadPts[1], quadPts[2]);
2372 paint.setStrokeWidth(3);
2373 paint.setColor(colors[i]);
2374 canvas->drawPath(path, paint);
2375 quadPts[1].fY += 30;
2376 }
Cary Clark8032b982017-07-28 11:04:54 -04002377}
2378##
Cary Clark73fa9722017-08-29 17:36:51 -04002379
2380#Method void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
2381
Cary Clarkab2621d2018-01-30 10:08:57 -05002382#In Quad
2383#Line # appends Quad ##
Cary Clark682c58d2018-05-16 07:07:07 -04002384 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
Cary Clark73fa9722017-08-29 17:36:51 -04002385 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2386 before adding Quad.
2387
2388 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2389 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2390 to Point_Array.
2391
2392 #Param x1 control Point of Quad in x ##
2393 #Param y1 control Point of Quad in y ##
2394 #Param x2 end Point of Quad in x ##
2395 #Param y2 end Point of Quad in y ##
2396
2397 #Example
2398 void draw(SkCanvas* canvas) {
2399 SkPaint paint;
2400 paint.setAntiAlias(true);
2401 paint.setStyle(SkPaint::kStroke_Style);
2402 SkPath path;
2403 path.moveTo(0, -10);
2404 for (int i = 0; i < 128; i += 16) {
2405 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2406 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2407 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2408 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2409 }
2410 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002411 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002412 }
2413 ##
2414
2415 #SeeAlso Contour moveTo conicTo rQuadTo
2416
2417##
2418
Cary Clark682c58d2018-05-16 07:07:07 -04002419#Method void quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05002420#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002421#In Quad
Cary Clark682c58d2018-05-16 07:07:07 -04002422 Adds Quad from Last_Point towards Point p1, to Point p2.
Cary Clark73fa9722017-08-29 17:36:51 -04002423 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2424 before adding Quad.
2425
2426 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2427 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2428 to Point_Array.
2429
2430 #Param p1 control Point of added Quad ##
2431 #Param p2 end Point of added Quad ##
2432
2433 #Example
2434 void draw(SkCanvas* canvas) {
2435 SkPaint paint;
2436 paint.setStyle(SkPaint::kStroke_Style);
2437 paint.setAntiAlias(true);
2438 SkPath path;
2439 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2440 path.moveTo(pts[1]);
2441 for (int i = 0; i < 3; ++i) {
2442 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2443 }
2444 canvas->drawPath(path, paint);
2445 }
2446 ##
2447
2448 #SeeAlso Contour moveTo conicTo rQuadTo
2449
2450##
2451
2452#Method void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05002453#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002454#In Quad
2455#Line # appends Quad relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002456 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2457 If Path is empty, or last Verb
2458 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2459
2460 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2461 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2462 control and Quad end to Point_Array.
2463 Quad control is Last_Point plus Vector (dx1, dy1).
2464 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002465 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002466
Cary Clark5538c132018-06-14 12:28:14 -04002467 #Param dx1 offset from Last_Point to Quad control on x-axis ##
2468 #Param dy1 offset from Last_Point to Quad control on y-axis ##
2469 #Param dx2 offset from Last_Point to Quad end on x-axis ##
2470 #Param dy2 offset from Last_Point to Quad end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002471
2472 #Example
2473 void draw(SkCanvas* canvas) {
2474 SkPaint paint;
2475 paint.setAntiAlias(true);
2476 SkPath path;
2477 path.moveTo(128, 20);
2478 path.rQuadTo(-6, 10, -7, 10);
2479 for (int i = 1; i < 32; i += 4) {
2480 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2481 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2482 }
2483 path.quadTo(92, 220, 128, 215);
2484 canvas->drawPath(path, paint);
2485 }
2486 ##
2487
2488 #SeeAlso Contour moveTo conicTo quadTo
2489
2490##
2491
Cary Clark78de7512018-02-07 07:27:09 -05002492#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002493
2494# ------------------------------------------------------------------------------
2495
Cary Clark78de7512018-02-07 07:27:09 -05002496#Subtopic Conic
Cary Clark08895c42018-02-01 09:37:32 -05002497#Line # conic section defined by three points and a weight ##
Cary Clark137b8742018-05-30 09:21:49 -04002498#Alias Conics ##
Cary Clark8032b982017-07-28 11:04:54 -04002499
2500Conic describes a conical section: a piece of an ellipse, or a piece of a
Cary Clark682c58d2018-05-16 07:07:07 -04002501parabola, or a piece of a hyperbola. Conic begins at a start Point,
Cary Clark8032b982017-07-28 11:04:54 -04002502curves towards a control Point, and then curves to an end Point. The influence
2503of the control Point is determined by Conic_Weight.
2504
Cary Clark73fa9722017-08-29 17:36:51 -04002505Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2506may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002507
2508#Subtopic Weight
Cary Clark137b8742018-05-30 09:21:49 -04002509#Alias Conic_Weights ##
2510#Alias Weights ##
Cary Clark08895c42018-02-01 09:37:32 -05002511#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002512
2513Weight determines both the strength of the control Point and the type of Conic.
Cary Clark682c58d2018-05-16 07:07:07 -04002514Weight varies from zero to infinity. At zero, Weight causes the control Point to
2515have no effect; Conic is identical to a line segment from start Point to end
2516point. If Weight is less than one, Conic follows an elliptical arc.
2517If Weight is exactly one, then Conic is identical to Quad; Conic follows a
2518parabolic arc. If Weight is greater than one, Conic follows a hyperbolic
Cary Clark137b8742018-05-30 09:21:49 -04002519arc. If Weight is infinity, Conic is identical to two line segments, connecting
Cary Clark682c58d2018-05-16 07:07:07 -04002520start Point to control Point, and control Point to end Point.
Cary Clark8032b982017-07-28 11:04:54 -04002521
2522#Example
2523#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002524When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002525##
Cary Clark73fa9722017-08-29 17:36:51 -04002526void draw(SkCanvas* canvas) {
2527 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2528 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2529 SkPath path;
2530 path.conicTo(20, 30, 50, 60, 1);
2531 SkPath::Iter iter(path, false);
2532 SkPath::Verb verb;
2533 do {
2534 SkPoint points[4];
2535 verb = iter.next(points);
2536 SkDebugf("%s ", verbNames[(int) verb]);
2537 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2538 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2539 }
2540 if (SkPath::kConic_Verb == verb) {
2541 SkDebugf("weight = %g", iter.conicWeight());
2542 }
2543 SkDebugf("\n");
2544 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002545}
2546#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002547move {0, 0},
2548quad {0, 0}, {20, 30}, {50, 60},
2549done
Cary Clark8032b982017-07-28 11:04:54 -04002550##
2551##
2552
2553If weight is less than one, Conic is an elliptical segment.
2554
Cary Clark682c58d2018-05-16 07:07:07 -04002555#Example
Cary Clark8032b982017-07-28 11:04:54 -04002556#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002557A 90 degree circular arc has the weight
Cary Clark8032b982017-07-28 11:04:54 -04002558#Formula
25591 / sqrt(2)
2560##
Cary Clark6fc50412017-09-21 12:31:06 -04002561.
Cary Clark8032b982017-07-28 11:04:54 -04002562##
Cary Clark73fa9722017-08-29 17:36:51 -04002563void draw(SkCanvas* canvas) {
2564 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2565 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2566 SkPath path;
2567 path.arcTo(20, 0, 20, 20, 20);
2568 SkPath::Iter iter(path, false);
2569 SkPath::Verb verb;
2570 do {
2571 SkPoint points[4];
2572 verb = iter.next(points);
2573 SkDebugf("%s ", verbNames[(int) verb]);
2574 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2575 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2576 }
2577 if (SkPath::kConic_Verb == verb) {
2578 SkDebugf("weight = %g", iter.conicWeight());
2579 }
2580 SkDebugf("\n");
2581 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002582}
2583#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002584move {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04002585conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark682c58d2018-05-16 07:07:07 -04002586done
Cary Clark8032b982017-07-28 11:04:54 -04002587##
2588##
2589
Cary Clarkce101242017-09-01 15:51:02 -04002590If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002591a hyperbolic segment can be approximated by straight lines connecting the
2592control Point with the end Points.
2593
2594#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002595void draw(SkCanvas* canvas) {
2596 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2597 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2598 SkPath path;
2599 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2600 SkPath::Iter iter(path, false);
2601 SkPath::Verb verb;
2602 do {
2603 SkPoint points[4];
2604 verb = iter.next(points);
2605 SkDebugf("%s ", verbNames[(int) verb]);
2606 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2607 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2608 }
2609 if (SkPath::kConic_Verb == verb) {
2610 SkDebugf("weight = %g", iter.conicWeight());
2611 }
2612 SkDebugf("\n");
2613 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002614}
2615#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002616move {0, 0},
2617line {0, 0}, {20, 0},
2618line {20, 0}, {20, 20},
2619done
Cary Clark8032b982017-07-28 11:04:54 -04002620##
2621##
2622
2623#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002624
2625#Method void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2626 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002627#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002628#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002629#Line # appends Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002630
Cary Clark682c58d2018-05-16 07:07:07 -04002631 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002632 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2633 before adding Conic.
2634
2635 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2636
2637 If w is finite and not one, appends kConic_Verb to Verb_Array;
2638 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2639
2640 If w is one, appends kQuad_Verb to Verb_Array, and
2641 (x1, y1), (x2, y2) to Point_Array.
2642
2643 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2644 (x1, y1), (x2, y2) to Point_Array.
2645
2646 #Param x1 control Point of Conic in x ##
2647 #Param y1 control Point of Conic in y ##
2648 #Param x2 end Point of Conic in x ##
2649 #Param y2 end Point of Conic in y ##
2650 #Param w weight of added Conic ##
2651
2652 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002653 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002654 #Description
Cary Clark682c58d2018-05-16 07:07:07 -04002655 As weight increases, curve is pulled towards control point.
Cary Clark73fa9722017-08-29 17:36:51 -04002656 The bottom two curves are elliptical; the next is parabolic; the
2657 top curve is hyperbolic.
2658 ##
2659void draw(SkCanvas* canvas) {
2660 SkPaint paint;
2661 paint.setAntiAlias(true);
2662 paint.setStyle(SkPaint::kStroke_Style);
2663 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2664 canvas->drawLine(conicPts[0], conicPts[1], paint);
2665 canvas->drawLine(conicPts[1], conicPts[2], paint);
2666 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2667 paint.setStrokeWidth(3);
2668 SkScalar weight = 0.5f;
2669 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2670 SkPath path;
2671 path.moveTo(conicPts[0]);
2672 path.conicTo(conicPts[1], conicPts[2], weight);
2673 paint.setColor(colors[i]);
2674 canvas->drawPath(path, paint);
2675 weight += 0.25f;
2676 }
2677}
2678 ##
2679
2680 #SeeAlso rConicTo arcTo addArc quadTo
2681
2682##
2683
Cary Clark682c58d2018-05-16 07:07:07 -04002684#Method void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002685#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002686#In Conic
Cary Clark682c58d2018-05-16 07:07:07 -04002687 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002688 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2689 before adding Conic.
2690
2691 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2692
2693 If w is finite and not one, appends kConic_Verb to Verb_Array;
2694 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2695
2696 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2697 to Point_Array.
2698
2699 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2700 Points p1, p2 to Point_Array.
2701
2702 #Param p1 control Point of added Conic ##
2703 #Param p2 end Point of added Conic ##
2704 #Param w weight of added Conic ##
2705
2706 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002707 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002708 #Description
2709 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002710 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002711 ##
2712void draw(SkCanvas* canvas) {
2713 SkPaint paint;
2714 paint.setAntiAlias(true);
2715 paint.setStyle(SkPaint::kStroke_Style);
2716 SkRect oval = {0, 20, 120, 140};
2717 SkPath path;
2718 for (int i = 0; i < 4; ++i) {
2719 path.moveTo(oval.centerX(), oval.fTop);
2720 path.arcTo(oval, -90, 90 - 20 * i, false);
2721 oval.inset(15, 15);
2722 }
2723 path.offset(100, 0);
2724 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2725 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2726 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2727 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2728 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2729 for (int i = 0; i < 4; ++i) {
2730 path.moveTo(conicPts[i][0]);
2731 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2732 }
2733 canvas->drawPath(path, paint);
2734}
2735 ##
2736
2737 #SeeAlso rConicTo arcTo addArc quadTo
2738
2739##
2740
2741#Method void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2742 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002743#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002744#In Conic
2745#Line # appends Conic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002746
2747 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2748 weighted by w. If Path is empty, or last Verb
2749 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2750
2751 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
Cary Clark682c58d2018-05-16 07:07:07 -04002752 if needed.
2753
Cary Clark73fa9722017-08-29 17:36:51 -04002754 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2755 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2756 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2757 twice to Verb_Array.
2758
2759 In all cases appends Points control and end to Point_Array.
2760 control is Last_Point plus Vector (dx1, dy1).
2761 end is Last_Point plus Vector (dx2, dy2).
2762
Cary Clarkce101242017-09-01 15:51:02 -04002763 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002764
Cary Clark5538c132018-06-14 12:28:14 -04002765 #Param dx1 offset from Last_Point to Conic control on x-axis ##
2766 #Param dy1 offset from Last_Point to Conic control on y-axis ##
2767 #Param dx2 offset from Last_Point to Conic end on x-axis ##
2768 #Param dy2 offset from Last_Point to Conic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002769 #Param w weight of added Conic ##
2770
2771 #Example
2772 #Height 140
2773 void draw(SkCanvas* canvas) {
2774 SkPaint paint;
2775 paint.setAntiAlias(true);
2776 paint.setStyle(SkPaint::kStroke_Style);
2777 SkPath path;
2778 path.moveTo(20, 80);
2779 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2780 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2781 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2782 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2783 canvas->drawPath(path, paint);
2784 }
2785 ##
2786
2787 #SeeAlso conicTo arcTo addArc quadTo
2788
2789##
2790
Cary Clark78de7512018-02-07 07:27:09 -05002791#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002792
2793# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002794#Subtopic Cubic
Cary Clark137b8742018-05-30 09:21:49 -04002795#Alias Cubic ##
2796#Alias Cubics ##
2797#Alias Cubic_Bezier ##
2798#Alias Cubic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002799#Line # curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002800
Cary Clark682c58d2018-05-16 07:07:07 -04002801Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002802Cubic begins at a start Point, curving towards the first control Point;
2803and curves from the end Point towards the second control Point.
2804
2805#Example
2806#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002807void draw(SkCanvas* canvas) {
2808 SkPaint paint;
2809 paint.setAntiAlias(true);
2810 paint.setStyle(SkPaint::kStroke_Style);
2811 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2812 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2813 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2814 paint.setColor(0x7fffffff & colors[i]);
2815 paint.setStrokeWidth(1);
2816 for (unsigned j = 0; j < 3; ++j) {
2817 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2818 }
2819 SkPath path;
2820 path.moveTo(cubicPts[0]);
2821 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2822 paint.setStrokeWidth(3);
2823 paint.setColor(colors[i]);
2824 canvas->drawPath(path, paint);
2825 cubicPts[1].fY += 30;
2826 cubicPts[2].fX += 30;
2827 }
Cary Clark8032b982017-07-28 11:04:54 -04002828}
2829##
Cary Clark73fa9722017-08-29 17:36:51 -04002830
2831#Method void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2832 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002833#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002834#In Cubic
2835#Line # appends Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002836
2837Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2838(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2839(0, 0) before adding Cubic.
2840
2841Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2842then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
2843to Point_Array.
2844
2845#Param x1 first control Point of Cubic in x ##
2846#Param y1 first control Point of Cubic in y ##
2847#Param x2 second control Point of Cubic in x ##
2848#Param y2 second control Point of Cubic in y ##
2849#Param x3 end Point of Cubic in x ##
2850#Param y3 end Point of Cubic in y ##
2851
2852#Example
2853void draw(SkCanvas* canvas) {
2854 SkPaint paint;
2855 paint.setAntiAlias(true);
2856 paint.setStyle(SkPaint::kStroke_Style);
2857 SkPath path;
2858 path.moveTo(0, -10);
2859 for (int i = 0; i < 128; i += 16) {
2860 SkScalar c = i * 0.5f;
2861 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2862 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2863 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2864 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2865 }
2866 path.offset(128, 128);
2867 canvas->drawPath(path, paint);
2868}
2869##
2870
2871#SeeAlso Contour moveTo rCubicTo quadTo
2872
2873##
2874
2875# ------------------------------------------------------------------------------
2876
Cary Clark682c58d2018-05-16 07:07:07 -04002877#Method void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
Cary Clark73fa9722017-08-29 17:36:51 -04002878
Cary Clark4855f782018-02-06 09:41:53 -05002879#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002880#In Cubic
Cary Clark73fa9722017-08-29 17:36:51 -04002881Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2882Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2883(0, 0) before adding Cubic.
2884
2885Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2886then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2887to Point_Array.
2888
2889#Param p1 first control Point of Cubic ##
2890#Param p2 second control Point of Cubic ##
2891#Param p3 end Point of Cubic ##
2892
2893#Example
2894#Height 84
2895 SkPaint paint;
2896 paint.setAntiAlias(true);
2897 paint.setStyle(SkPaint::kStroke_Style);
2898 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2899 SkPath path;
2900 path.moveTo(pts[0]);
2901 path.cubicTo(pts[1], pts[2], pts[3]);
2902 canvas->drawPath(path, paint);
2903##
2904
2905#SeeAlso Contour moveTo rCubicTo quadTo
2906
2907##
2908
2909# ------------------------------------------------------------------------------
2910
2911#Method void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2912 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002913#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002914#In Cubic
2915#Line # appends Cubic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002916
2917 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2918 Vector (dx2, dy2), to Vector (dx3, dy3).
2919 If Path is empty, or last Verb
2920 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2921
2922 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2923 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2924 control and Cubic end to Point_Array.
2925 Cubic control is Last_Point plus Vector (dx1, dy1).
2926 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002927 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002928
Cary Clark5538c132018-06-14 12:28:14 -04002929 #Param x1 offset from Last_Point to first Cubic control on x-axis ##
2930 #Param y1 offset from Last_Point to first Cubic control on y-axis ##
2931 #Param x2 offset from Last_Point to second Cubic control on x-axis ##
2932 #Param y2 offset from Last_Point to second Cubic control on y-axis ##
2933 #Param x3 offset from Last_Point to Cubic end on x-axis ##
2934 #Param y3 offset from Last_Point to Cubic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002935
2936#Example
2937 void draw(SkCanvas* canvas) {
2938 SkPaint paint;
2939 paint.setAntiAlias(true);
2940 paint.setStyle(SkPaint::kStroke_Style);
2941 SkPath path;
2942 path.moveTo(24, 108);
2943 for (int i = 0; i < 16; i++) {
2944 SkScalar sx, sy;
2945 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2946 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2947 }
2948 canvas->drawPath(path, paint);
2949 }
2950##
2951
2952#SeeAlso Contour moveTo cubicTo quadTo
2953
2954##
2955
Cary Clark78de7512018-02-07 07:27:09 -05002956#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002957
2958# ------------------------------------------------------------------------------
2959
Cary Clark08895c42018-02-01 09:37:32 -05002960#Subtopic Arc
2961#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04002962Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
2963by start point and end point, and by radius and tangent lines. Each construction has advantages,
2964and some constructions correspond to Arc drawing in graphics standards.
2965
2966All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
2967Conic describes an Arc of some Oval or Circle.
2968
2969arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
2970describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
Cary Clark682c58d2018-05-16 07:07:07 -04002971which may continue Contour or start a new one. This construction is similar to PostScript and
Cary Clark73fa9722017-08-29 17:36:51 -04002972HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
2973requiring Path.
2974
2975arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
2976describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
2977where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
2978HTML_Canvas arcs.
2979
2980arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04002981 SkScalar x, SkScalar y)
Cary Clark73fa9722017-08-29 17:36:51 -04002982describes Arc as part of Oval with radii (rx, ry), beginning at
2983last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
2984so additional values choose a single solution. This construction is similar to SVG arcs.
2985
2986conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
2987conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
Cary Clark682c58d2018-05-16 07:07:07 -04002988constructions are converted to Conic data when added to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002989
2990#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
2991 do the kind of table shown in the illustration.
2992 example is spaced correctly on fiddle but spacing is too wide on pc
2993##
2994
2995#Example
2996#Height 300
2997#Width 600
2998#Description
2999#List
3000# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
3001# <sup>2</sup> parameter sets force MoveTo ##
Cary Clark5081eed2018-01-22 07:55:48 -05003002# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04003003# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
3004# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3005 Direction sweep, SkScalar x, SkScalar y) ##
3006#List ##
3007#Description ##
3008#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003009###$
Cary Clark73fa9722017-08-29 17:36:51 -04003010struct data {
3011 const char* name;
3012 char super;
3013 int yn[10];
3014};
3015
3016const data dataSet[] = {
3017{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
3018{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
3019{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
3020{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
3021{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
3022{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
3023};
3024
3025#define __degree_symbol__ "\xC2" "\xB0"
3026
3027const char* headers[] = {
3028 "Oval part",
3029 "force moveTo",
3030 "can draw 180" __degree_symbol__,
3031 "can draw 360" __degree_symbol__,
3032 "can draw greater than 360" __degree_symbol__,
3033 "ignored if radius is zero",
3034 "ignored if sweep is zero",
3035 "requires Path",
3036 "describes rotation",
3037 "describes perspective",
3038};
3039
3040const char* yna[] = {
3041 "n/a",
3042 "no",
3043 "yes"
3044};
Cary Clark1a8d7622018-03-05 13:26:16 -05003045$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003046##
3047void draw(SkCanvas* canvas) {
3048 SkPaint lp;
3049 lp.setAntiAlias(true);
3050 SkPaint tp(lp);
3051 SkPaint sp(tp);
3052 SkPaint bp(tp);
3053 bp.setFakeBoldText(true);
3054 sp.setTextSize(10);
3055 lp.setColor(SK_ColorGRAY);
3056 canvas->translate(0, 32);
3057 const int tl = 115;
3058 for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
3059 canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
3060 if (0 == col) {
3061 continue;
3062 }
3063 canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
3064 SkPath path;
3065 path.moveTo(tl - 3 + col * 35, 103);
3066 path.lineTo(tl + 124 + col * 35, -24);
3067 canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
3068 }
3069 for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
3070 if (0 == row) {
3071 canvas->drawLine(tl, 100, tl + 350, 100, lp);
3072 } else {
3073 canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
3074 }
3075 if (row == SK_ARRAY_COUNT(dataSet)) {
3076 break;
3077 }
3078 canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
3079 if (dataSet[row].super) {
3080 SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
3081 canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
3082 }
3083 for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
3084 int val = dataSet[row].yn[col];
3085 canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
3086 if (val > 1) {
3087 char supe = '0' + val - 1;
3088 canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
3089 }
3090 }
3091 }
3092}
3093#Example ##
3094
3095#Example
3096#Height 128
3097#Description
3098#ToDo make this a list or table ##
30991 describes an arc from an oval, a starting angle, and a sweep angle.
31002 is similar to 1, but does not require building a path to draw.
31013 is similar to 1, but always begins new Contour.
31024 describes an arc from a pair of tangent lines and a radius.
31035 describes an arc from Oval center, arc start Point and arc end Point.
31046 describes an arc from a pair of tangent lines and a Conic_Weight.
3105##
3106void draw(SkCanvas* canvas) {
3107 SkRect oval = {8, 8, 56, 56};
3108 SkPaint ovalPaint;
3109 ovalPaint.setAntiAlias(true);
3110 SkPaint textPaint(ovalPaint);
3111 ovalPaint.setStyle(SkPaint::kStroke_Style);
3112 SkPaint arcPaint(ovalPaint);
3113 arcPaint.setStrokeWidth(5);
3114 arcPaint.setColor(SK_ColorBLUE);
3115 canvas->translate(-64, 0);
3116 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3117 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3118 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3119 canvas->drawOval(oval, ovalPaint);
3120 SkPath path;
3121 path.moveTo({56, 32});
3122 switch (arcStyle) {
3123 case '1':
3124 path.arcTo(oval, 0, 90, false);
3125 break;
3126 case '2':
3127 canvas->drawArc(oval, 0, 90, false, arcPaint);
3128 continue;
3129 case '3':
3130 path.addArc(oval, 0, 90);
3131 break;
3132 case '4':
3133 path.arcTo({56, 56}, {32, 56}, 24);
3134 break;
3135 case '5':
3136 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3137 break;
3138 case '6':
3139 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3140 break;
3141 }
3142 canvas->drawPath(path, arcPaint);
3143 }
3144}
3145#Example ##
3146
3147
3148#Method void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05003149#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003150#In Arc
3151#Line # appends Arc ##
Cary Clark80247e52018-07-11 16:18:41 -04003152Appends Arc to Path. Arc added is part of ellipse
Cary Clark73fa9722017-08-29 17:36:51 -04003153bounded by oval, from startAngle through sweepAngle. Both startAngle and
3154sweepAngle are measured in degrees, where zero degrees is aligned with the
3155positive x-axis, and positive sweeps extends Arc clockwise.
3156
3157arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3158is false and Path is not empty. Otherwise, added Contour begins with first point
3159of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3160
3161#Param oval bounds of ellipse containing Arc ##
3162#Param startAngle starting angle of Arc in degrees ##
3163#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3164#Param forceMoveTo true to start a new contour with Arc ##
3165
3166#Example
3167#Height 200
3168#Description
3169arcTo continues a previous contour when forceMoveTo is false and when Path
3170is not empty.
3171##
3172void draw(SkCanvas* canvas) {
3173 SkPaint paint;
3174 SkPath path;
3175 paint.setStyle(SkPaint::kStroke_Style);
3176 paint.setStrokeWidth(4);
3177 path.moveTo(0, 0);
3178 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3179 canvas->drawPath(path, paint);
3180 path.rewind();
3181 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3182 canvas->drawPath(path, paint);
3183 path.rewind();
3184 path.moveTo(0, 0);
3185 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3186 canvas->drawPath(path, paint);
3187}
3188##
3189
3190#SeeAlso addArc SkCanvas::drawArc conicTo
3191
3192##
3193
3194# ------------------------------------------------------------------------------
3195
3196#Method void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003197#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003198#In Arc
Cary Clark80247e52018-07-11 16:18:41 -04003199Appends Arc to Path, after appending Line if needed. Arc is implemented by Conic
Cary Clark73fa9722017-08-29 17:36:51 -04003200weighted to describe part of Circle. Arc is contained by tangent from
3201last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003202is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003203
3204#ToDo allow example to hide source and not be exposed as fiddle ##
3205
3206#Example
3207#Height 226
3208void draw(SkCanvas* canvas) {
3209 SkPaint tangentPaint;
3210 tangentPaint.setAntiAlias(true);
3211 SkPaint textPaint(tangentPaint);
3212 tangentPaint.setStyle(SkPaint::kStroke_Style);
3213 tangentPaint.setColor(SK_ColorGRAY);
3214 SkPaint arcPaint(tangentPaint);
3215 arcPaint.setStrokeWidth(5);
3216 arcPaint.setColor(SK_ColorBLUE);
3217 SkPath path;
3218 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3219 SkScalar radius = 50;
3220 path.moveTo(pts[0]);
3221 path.arcTo(pts[1], pts[2], radius);
3222 canvas->drawLine(pts[0], pts[1], tangentPaint);
3223 canvas->drawLine(pts[1], pts[2], tangentPaint);
3224 SkPoint lastPt;
3225 (void) path.getLastPt(&lastPt);
3226 SkVector radial = pts[2] - pts[1];
3227 radial.setLength(radius);
3228 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3229 canvas->drawCircle(center, radius, tangentPaint);
3230 canvas->drawLine(lastPt, center, tangentPaint);
3231 radial = pts[1] - pts[0];
3232 radial.setLength(radius);
3233 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3234 canvas->drawLine(center, arcStart, tangentPaint);
3235 canvas->drawPath(path, arcPaint);
3236 textPaint.setTextAlign(SkPaint::kRight_Align);
3237 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3238 textPaint.setTextAlign(SkPaint::kLeft_Align);
3239 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3240 textPaint.setTextAlign(SkPaint::kCenter_Align);
3241 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3242 textPaint.setTextAlign(SkPaint::kRight_Align);
3243 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3244 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3245}
3246##
3247
3248If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3249The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3250
3251#Example
3252#Height 128
3253void draw(SkCanvas* canvas) {
3254 SkPaint tangentPaint;
3255 tangentPaint.setAntiAlias(true);
3256 SkPaint textPaint(tangentPaint);
3257 tangentPaint.setStyle(SkPaint::kStroke_Style);
3258 tangentPaint.setColor(SK_ColorGRAY);
3259 SkPaint arcPaint(tangentPaint);
3260 arcPaint.setStrokeWidth(5);
3261 arcPaint.setColor(SK_ColorBLUE);
3262 SkPath path;
3263 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3264 SkScalar radius = 50;
3265 path.moveTo(pts[0]);
3266 path.arcTo(pts[1], pts[2], radius);
3267 canvas->drawLine(pts[0], pts[1], tangentPaint);
3268 canvas->drawLine(pts[1], pts[2], tangentPaint);
3269 SkPoint lastPt;
3270 (void) path.getLastPt(&lastPt);
3271 SkVector radial = pts[2] - pts[1];
3272 radial.setLength(radius);
3273 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3274 canvas->drawLine(lastPt, center, tangentPaint);
3275 radial = pts[1] - pts[0];
3276 radial.setLength(radius);
3277 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3278 canvas->drawLine(center, arcStart, tangentPaint);
3279 canvas->drawPath(path, arcPaint);
3280 textPaint.setTextAlign(SkPaint::kCenter_Align);
3281 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3282 textPaint.setTextAlign(SkPaint::kLeft_Align);
3283 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3284 textPaint.setTextAlign(SkPaint::kCenter_Align);
3285 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3286 textPaint.setTextAlign(SkPaint::kRight_Align);
3287 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3288 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3289}
3290##
3291
3292Arc sweep is always less than 180 degrees. If radius is zero, or if
3293tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3294
3295arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003296arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003297
Cary Clark5538c132018-06-14 12:28:14 -04003298#Param x1 x-axis value common to pair of tangents ##
3299#Param y1 y-axis value common to pair of tangents ##
3300#Param x2 x-axis value end of second tangent ##
3301#Param y2 y-axis value end of second tangent ##
Cary Clark73fa9722017-08-29 17:36:51 -04003302#Param radius distance from Arc to Circle center ##
3303
3304#Example
3305#Description
3306arcTo is represented by Line and circular Conic in Path.
3307##
3308void draw(SkCanvas* canvas) {
3309 SkPath path;
3310 path.moveTo({156, 20});
3311 path.arcTo(200, 20, 170, 50, 50);
3312 SkPath::Iter iter(path, false);
3313 SkPoint p[4];
3314 SkPath::Verb verb;
3315 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3316 switch (verb) {
3317 case SkPath::kMove_Verb:
3318 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3319 break;
3320 case SkPath::kLine_Verb:
3321 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3322 break;
3323 case SkPath::kConic_Verb:
3324 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3325 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3326 break;
3327 default:
3328 SkDebugf("unexpected verb\n");
3329 }
3330 }
3331}
3332#StdOut
3333move to (156,20)
3334line (156,20),(79.2893,20)
3335conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3336##
3337##
3338
Cary Clark682c58d2018-05-16 07:07:07 -04003339#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003340
3341##
3342
3343# ------------------------------------------------------------------------------
3344
Cary Clark682c58d2018-05-16 07:07:07 -04003345#Method void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003346#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003347#In Arc
Cary Clark80247e52018-07-11 16:18:41 -04003348Appends Arc to Path, after appending Line if needed. Arc is implemented by Conic
Cary Clark73fa9722017-08-29 17:36:51 -04003349weighted to describe part of Circle. Arc is contained by tangent from
3350last Path point to p1, and tangent from p1 to p2. Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003351is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003352
3353If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3354The length of Vector from p1 to p2 does not affect Arc.
3355
3356Arc sweep is always less than 180 degrees. If radius is zero, or if
3357tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3358
3359arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003360arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003361
3362#Param p1 Point common to pair of tangents ##
3363#Param p2 end of second tangent ##
3364#Param radius distance from Arc to Circle center ##
3365
3366#Example
3367#Description
3368Because tangent lines are parallel, arcTo appends line from last Path Point to
3369p1, but does not append a circular Conic.
3370##
3371void draw(SkCanvas* canvas) {
3372 SkPath path;
3373 path.moveTo({156, 20});
3374 path.arcTo({200, 20}, {170, 20}, 50);
3375 SkPath::Iter iter(path, false);
3376 SkPoint p[4];
3377 SkPath::Verb verb;
3378 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3379 switch (verb) {
3380 case SkPath::kMove_Verb:
3381 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3382 break;
3383 case SkPath::kLine_Verb:
3384 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3385 break;
3386 case SkPath::kConic_Verb:
3387 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3388 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3389 break;
3390 default:
3391 SkDebugf("unexpected verb\n");
3392 }
3393 }
3394}
3395#StdOut
3396move to (156,20)
3397line (156,20),(200,20)
3398##
3399##
3400
Cary Clark682c58d2018-05-16 07:07:07 -04003401#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003402
3403##
3404
3405# ------------------------------------------------------------------------------
3406
3407#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05003408#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04003409
3410#Code
3411 enum ArcSize {
Cary Clark682c58d2018-05-16 07:07:07 -04003412 kSmall_ArcSize,
3413 kLarge_ArcSize,
Cary Clark73fa9722017-08-29 17:36:51 -04003414 };
3415##
3416
3417Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3418ArcSize and Direction select one of the four Oval parts.
3419
3420#Const kSmall_ArcSize 0
Cary Clark682c58d2018-05-16 07:07:07 -04003421#Line # smaller of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003422##
3423#Const kLarge_ArcSize 1
Cary Clark682c58d2018-05-16 07:07:07 -04003424#Line # larger of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003425##
3426
3427#Example
3428#Height 160
3429#Description
3430Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3431Two routes are large, and two routes are counterclockwise. The one route both large
3432and counterclockwise is blue.
3433##
3434void draw(SkCanvas* canvas) {
3435 SkPaint paint;
3436 paint.setAntiAlias(true);
3437 paint.setStyle(SkPaint::kStroke_Style);
3438 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3439 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3440 SkPath path;
3441 path.moveTo({120, 50});
3442 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3443 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3444 paint.setColor(SK_ColorBLUE);
3445 paint.setStrokeWidth(3);
3446 }
3447 canvas->drawPath(path, paint);
3448 }
3449 }
3450}
3451##
3452
3453#SeeAlso arcTo Direction
3454
3455##
3456
3457# ------------------------------------------------------------------------------
3458
3459#Method void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3460 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003461#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003462#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003463
Cary Clark80247e52018-07-11 16:18:41 -04003464Appends Arc to Path. Arc is implemented by one or more Conics weighted to
Cary Clark154beea2017-10-26 07:58:48 -04003465describe part of Oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
3466curves from last Path Point to (x, y), choosing one of four possible routes:
3467clockwise or counterclockwise, and smaller or larger.
Cary Clark73fa9722017-08-29 17:36:51 -04003468
Cary Clark154beea2017-10-26 07:58:48 -04003469Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if
3470either radii are zero, or if last Path Point equals (x, y). arcTo scales radii
3471(rx, ry) to fit last Path Point and (x, y) if both are greater than zero but
3472too small.
Cary Clark73fa9722017-08-29 17:36:51 -04003473
3474arcTo appends up to four Conic curves.
Cary Clark154beea2017-10-26 07:58:48 -04003475arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value
3476is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise,
3477while kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003478
3479#Param rx radius in x before x-axis rotation ##
3480#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003481#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003482#Param largeArc chooses smaller or larger Arc ##
3483#Param sweep chooses clockwise or counterclockwise Arc ##
3484#Param x end of Arc ##
3485#Param y end of Arc ##
3486
3487#Example
3488#Height 160
3489void draw(SkCanvas* canvas) {
3490 SkPaint paint;
3491 paint.setAntiAlias(true);
3492 paint.setStyle(SkPaint::kStroke_Style);
3493 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3494 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3495 SkPath path;
3496 path.moveTo({120, 50});
3497 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3498 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3499 paint.setColor(SK_ColorBLUE);
3500 paint.setStrokeWidth(3);
3501 }
3502 canvas->drawPath(path, paint);
3503 }
3504 }
3505}
3506##
3507
3508#SeeAlso rArcTo ArcSize Direction
3509
3510##
3511
3512# ------------------------------------------------------------------------------
3513
3514#Method void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04003515 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05003516#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003517#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003518
Cary Clark80247e52018-07-11 16:18:41 -04003519Appends Arc to Path. Arc is implemented by one or more Conic weighted to describe part of Oval
Cary Clark73fa9722017-08-29 17:36:51 -04003520with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last Path Point to
3521(xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise,
3522and smaller or larger.
3523
3524Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either radii are zero,
3525or if last Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
Cary Clarkce101242017-09-01 15:51:02 -04003526xy if both are greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003527
3528arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003529arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3530opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3531kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003532
Cary Clark5538c132018-06-14 12:28:14 -04003533#Param r radii on axes before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003534#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003535#Param largeArc chooses smaller or larger Arc ##
3536#Param sweep chooses clockwise or counterclockwise Arc ##
3537#Param xy end of Arc ##
3538
3539#Example
3540#Height 108
3541void draw(SkCanvas* canvas) {
3542 SkPaint paint;
3543 SkPath path;
3544 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3545 for (auto start : starts) {
3546 path.moveTo(start.fX, start.fY);
3547 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3548 }
3549 canvas->drawPath(path, paint);
3550}
3551##
3552
3553#SeeAlso rArcTo ArcSize Direction
3554
3555##
3556
3557# ------------------------------------------------------------------------------
3558
3559#Method void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3560 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003561#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003562#In Arc
3563#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003564
Cary Clark80247e52018-07-11 16:18:41 -04003565Appends Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003566more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04003567xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
3568
Cary Clark73fa9722017-08-29 17:36:51 -04003569#Formula
3570(x0 + dx, y0 + dy)
3571##
3572, choosing one of four possible routes: clockwise or
3573counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3574is (0, 0).
3575
Cary Clarkce101242017-09-01 15:51:02 -04003576Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3577if either radii are zero, or if last Path Point equals end Point.
3578arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3579greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003580
3581arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003582arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3583opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003584kCW_Direction cast to int is zero.
3585
Cary Clark5538c132018-06-14 12:28:14 -04003586#Param rx radius before x-axis rotation ##
3587#Param ry radius before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003588#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003589#Param largeArc chooses smaller or larger Arc ##
3590#Param sweep chooses clockwise or counterclockwise Arc ##
Cary Clark5538c132018-06-14 12:28:14 -04003591#Param dx x-axis offset end of Arc from last Path Point ##
3592#Param dy y-axis offset end of Arc from last Path Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003593
3594#Example
3595#Height 108
3596void draw(SkCanvas* canvas) {
3597 SkPaint paint;
3598 SkPath path;
3599 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3600 for (auto start : starts) {
3601 path.moveTo(start.fX, start.fY);
3602 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3603 }
3604 canvas->drawPath(path, paint);
3605}
3606##
3607
3608#SeeAlso arcTo ArcSize Direction
3609
3610##
3611
Cary Clark78de7512018-02-07 07:27:09 -05003612#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003613
3614# ------------------------------------------------------------------------------
3615
3616#Method void close()
Cary Clark4855f782018-02-06 09:41:53 -05003617#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003618#Line # makes last Contour a loop ##
Cary Clark80247e52018-07-11 16:18:41 -04003619Appends kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003620with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003621with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
Cary Clark682c58d2018-05-16 07:07:07 -04003622Paint_Stroke_Cap at Contour start and end; closed Contour draws
Cary Clark73fa9722017-08-29 17:36:51 -04003623Paint_Stroke_Join at Contour start and end.
3624
3625close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3626
3627#Example
3628void draw(SkCanvas* canvas) {
3629 SkPaint paint;
3630 paint.setStrokeWidth(15);
3631 paint.setStrokeCap(SkPaint::kRound_Cap);
3632 SkPath path;
3633 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3634 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3635 for (int loop = 0; loop < 2; ++loop) {
3636 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3637 SkPaint::kStrokeAndFill_Style} ) {
3638 paint.setStyle(style);
3639 canvas->drawPath(path, paint);
3640 canvas->translate(85, 0);
3641 }
3642 path.close();
3643 canvas->translate(-255, 128);
3644 }
3645}
3646##
3647
Cary Clark682c58d2018-05-16 07:07:07 -04003648#SeeAlso
Cary Clark73fa9722017-08-29 17:36:51 -04003649
3650##
3651
3652# ------------------------------------------------------------------------------
3653
Cary Clark682c58d2018-05-16 07:07:07 -04003654#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003655#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003656#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003657Returns true if fill is inverted and Path with fill represents area outside
3658of its geometric bounds.
3659
3660#Table
3661#Legend
3662# FillType # is inverse ##
3663##
3664# kWinding_FillType # false ##
3665# kEvenOdd_FillType # false ##
3666# kInverseWinding_FillType # true ##
3667# kInverseEvenOdd_FillType # true ##
3668##
3669
3670#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3671 kInverseWinding_FillType, kInverseEvenOdd_FillType
3672##
3673
3674#Return true if Path fills outside its bounds ##
3675
3676#Example
3677#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003678###$
Cary Clark73fa9722017-08-29 17:36:51 -04003679#define nameValue(fill) { SkPath::fill, #fill }
3680
Cary Clark1a8d7622018-03-05 13:26:16 -05003681$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003682##
3683void draw(SkCanvas* canvas) {
3684 struct {
3685 SkPath::FillType fill;
3686 const char* name;
3687 } fills[] = {
3688 nameValue(kWinding_FillType),
3689 nameValue(kEvenOdd_FillType),
3690 nameValue(kInverseWinding_FillType),
3691 nameValue(kInverseEvenOdd_FillType),
3692 };
3693 for (auto fill: fills ) {
3694 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3695 "true" : "false");
3696 }
3697}
3698#StdOut
3699IsInverseFillType(kWinding_FillType) == false
3700IsInverseFillType(kEvenOdd_FillType) == false
3701IsInverseFillType(kInverseWinding_FillType) == true
3702IsInverseFillType(kInverseEvenOdd_FillType) == true
3703##
3704##
3705
3706#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3707
3708##
3709
3710# ------------------------------------------------------------------------------
3711
Cary Clark682c58d2018-05-16 07:07:07 -04003712#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003713#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003714#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003715Returns equivalent Fill_Type representing Path fill inside its bounds.
3716.
3717
3718#Table
3719#Legend
3720# FillType # inside FillType ##
3721##
3722# kWinding_FillType # kWinding_FillType ##
3723# kEvenOdd_FillType # kEvenOdd_FillType ##
3724# kInverseWinding_FillType # kWinding_FillType ##
3725# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3726##
3727
3728#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3729 kInverseWinding_FillType, kInverseEvenOdd_FillType
3730##
3731
3732#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3733
3734#Example
3735#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003736###$
Cary Clark73fa9722017-08-29 17:36:51 -04003737#define nameValue(fill) { SkPath::fill, #fill }
3738
Cary Clark1a8d7622018-03-05 13:26:16 -05003739$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003740##
3741void draw(SkCanvas* canvas) {
3742 struct {
3743 SkPath::FillType fill;
3744 const char* name;
3745 } fills[] = {
3746 nameValue(kWinding_FillType),
3747 nameValue(kEvenOdd_FillType),
3748 nameValue(kInverseWinding_FillType),
3749 nameValue(kInverseEvenOdd_FillType),
3750 };
3751 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3752 if (fills[i].fill != (SkPath::FillType) i) {
3753 SkDebugf("fills array order does not match FillType enum order");
3754 break;
Cary Clark682c58d2018-05-16 07:07:07 -04003755 }
Cary Clark73fa9722017-08-29 17:36:51 -04003756 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3757 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3758 }
3759}
3760#StdOut
3761ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3762ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3763ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3764ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3765##
3766##
3767
3768#SeeAlso FillType getFillType setFillType IsInverseFillType
3769
3770##
3771
3772# ------------------------------------------------------------------------------
3773
3774#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3775 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05003776#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003777#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04003778
3779Approximates Conic with Quad array. Conic is constructed from start Point p0,
Cary Clark682c58d2018-05-16 07:07:07 -04003780control Point p1, end Point p2, and weight w.
Cary Clark73fa9722017-08-29 17:36:51 -04003781Quad array is stored in pts; this storage is supplied by caller.
3782Maximum Quad count is 2 to the pow2.
Cary Clark682c58d2018-05-16 07:07:07 -04003783Every third point in array shares last Point of previous Quad and first Point of
3784next Quad. Maximum pts storage size is given by:
Cary Clark73fa9722017-08-29 17:36:51 -04003785#Formula
3786(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
3787##
Cary Clark154beea2017-10-26 07:58:48 -04003788.
Cary Clark6fc50412017-09-21 12:31:06 -04003789
Cary Clark154beea2017-10-26 07:58:48 -04003790Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04003791than the number requested.
Cary Clark682c58d2018-05-16 07:07:07 -04003792
Cary Clark73fa9722017-08-29 17:36:51 -04003793Conic_Weight determines the amount of influence Conic control point has on the curve.
3794w less than one represents an elliptical section. w greater than one represents
3795a hyperbolic section. w equal to one represents a parabolic section.
3796
3797Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3798of up to 90 degrees; in this case, set pow2 to one.
3799
3800#Param p0 Conic start Point ##
3801#Param p1 Conic control Point ##
3802#Param p2 Conic end Point ##
3803#Param w Conic weight ##
3804#Param pts storage for Quad array ##
3805#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3806
Cary Clarka523d2d2017-08-30 08:58:10 -04003807#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003808
3809#Example
3810#Description
3811A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3812The middle curve is nearly circular. The top-right curve is parabolic, which can
3813be drawn exactly with a single Quad.
3814##
3815void draw(SkCanvas* canvas) {
3816 SkPaint conicPaint;
3817 conicPaint.setAntiAlias(true);
3818 conicPaint.setStyle(SkPaint::kStroke_Style);
3819 SkPaint quadPaint(conicPaint);
3820 quadPaint.setColor(SK_ColorRED);
3821 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3822 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3823 SkPoint quads[5];
3824 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3825 SkPath path;
3826 path.moveTo(conic[0]);
3827 path.conicTo(conic[1], conic[2], weight);
3828 canvas->drawPath(path, conicPaint);
3829 path.rewind();
3830 path.moveTo(quads[0]);
3831 path.quadTo(quads[1], quads[2]);
3832 path.quadTo(quads[3], quads[4]);
3833 canvas->drawPath(path, quadPaint);
3834 canvas->translate(50, -50);
3835 }
3836}
3837##
3838
3839#SeeAlso Conic Quad
3840
3841##
3842
3843# ------------------------------------------------------------------------------
3844
3845#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003846#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003847#Line # returns if describes Rect ##
Cary Clarkce101242017-09-01 15:51:02 -04003848Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003849If false: rect, isClosed, and direction are unchanged.
3850If true: rect, isClosed, and direction are written to if not nullptr.
3851
3852rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3853that do not alter the area drawn by the returned rect.
3854
3855#Param rect storage for bounds of Rect; may be nullptr ##
3856#Param isClosed storage set to true if Path is closed; may be nullptr ##
3857#Param direction storage set to Rect direction; may be nullptr ##
3858
3859#Return true if Path contains Rect ##
3860
3861#Example
3862#Description
3863After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3864following lineTo does not. addPoly returns true even though rect is not closed, and one
3865side of rect is made up of consecutive line segments.
3866##
3867void draw(SkCanvas* canvas) {
3868 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3869 SkRect rect;
3870 SkPath::Direction direction;
3871 bool isClosed;
Cary Clark682c58d2018-05-16 07:07:07 -04003872 path.isRect(&rect, &isClosed, &direction) ?
Cary Clark73fa9722017-08-29 17:36:51 -04003873 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3874 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3875 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3876 SkDebugf("%s is not rect\n", prefix);
3877 };
3878 SkPath path;
3879 debugster("empty", path);
3880 path.addRect({10, 20, 30, 40});
3881 debugster("addRect", path);
3882 path.moveTo(60, 70);
3883 debugster("moveTo", path);
3884 path.lineTo(60, 70);
3885 debugster("lineTo", path);
3886 path.reset();
3887 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3888 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3889 debugster("addPoly", path);
3890}
3891#StdOut
3892empty is not rect
3893addRect is rect (10, 20, 30, 40); is closed; direction CW
3894moveTo is rect (10, 20, 30, 40); is closed; direction CW
3895lineTo is not rect
3896addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3897##
3898##
3899
3900#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3901
3902##
3903
3904# ------------------------------------------------------------------------------
3905
3906#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003907#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003908#Line # returns if describes Rect pair, one inside the other ##
Cary Clark73fa9722017-08-29 17:36:51 -04003909Returns true if Path is equivalent to nested Rect pair when filled.
3910If false, rect and dirs are unchanged.
3911If true, rect and dirs are written to if not nullptr:
3912setting rect[0] to outer Rect, and rect[1] to inner Rect;
3913setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3914Rect.
3915
3916#Param rect storage for Rect pair; may be nullptr ##
3917#Param dirs storage for Direction pair; may be nullptr ##
3918
3919#Return true if Path contains nested Rect pair ##
3920
3921#Example
3922void draw(SkCanvas* canvas) {
3923 SkPaint paint;
3924 paint.setStyle(SkPaint::kStroke_Style);
3925 paint.setStrokeWidth(5);
3926 SkPath path;
3927 path.addRect({10, 20, 30, 40});
3928 paint.getFillPath(path, &path);
3929 SkRect rects[2];
3930 SkPath::Direction directions[2];
3931 if (path.isNestedFillRects(rects, directions)) {
3932 for (int i = 0; i < 2; ++i) {
3933 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3934 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3935 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3936 }
3937 } else {
3938 SkDebugf("is not nested rectangles\n");
3939 }
3940}
3941#StdOut
3942outer (7.5, 17.5, 32.5, 42.5); direction CW
3943inner (12.5, 22.5, 27.5, 37.5); direction CCW
3944##
3945##
3946
3947#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3948
3949##
3950
3951# ------------------------------------------------------------------------------
3952
3953#Method void addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003954#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003955#Line # adds one Contour containing Rect ##
Cary Clark80247e52018-07-11 16:18:41 -04003956Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -04003957starting with top-left corner of Rect; followed by top-right, bottom-right,
3958and bottom-left if dir is kCW_Direction; or followed by bottom-left,
3959bottom-right, and top-right if dir is kCCW_Direction.
3960
3961#Param rect Rect to add as a closed contour ##
3962#Param dir Direction to wind added contour ##
3963
3964#Example
3965#Description
3966The left Rect dashes starting at the top-left corner, to the right.
3967The right Rect dashes starting at the top-left corner, towards the bottom.
3968##
3969#Height 128
3970void draw(SkCanvas* canvas) {
3971 SkPaint paint;
3972 paint.setStrokeWidth(15);
3973 paint.setStrokeCap(SkPaint::kSquare_Cap);
3974 float intervals[] = { 5, 21.75f };
3975 paint.setStyle(SkPaint::kStroke_Style);
3976 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3977 SkPath path;
3978 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
3979 canvas->drawPath(path, paint);
3980 path.rewind();
3981 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
3982 canvas->drawPath(path, paint);
3983}
3984##
3985
3986#SeeAlso SkCanvas::drawRect Direction
3987
3988##
3989
3990# ------------------------------------------------------------------------------
3991
3992#Method void addRect(const SkRect& rect, Direction dir, unsigned start)
3993
Cary Clark80247e52018-07-11 16:18:41 -04003994Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04003995If dir is kCW_Direction, Rect corners are added clockwise; if dir is
3996kCCW_Direction, Rect corners are added counterclockwise.
3997start determines the first corner added.
3998
3999#Table
4000#Legend
4001# start # first corner ##
4002#Legend ##
4003# 0 # top-left ##
4004# 1 # top-right ##
4005# 2 # bottom-right ##
4006# 3 # bottom-left ##
4007#Table ##
4008
4009#Param rect Rect to add as a closed contour ##
4010#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004011#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04004012
4013#Example
4014#Height 128
4015#Description
4016The arrow is just after the initial corner and points towards the next
4017corner appended to Path.
4018##
4019void draw(SkCanvas* canvas) {
4020 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
4021 const SkRect rect = {10, 10, 54, 54};
4022 SkPaint rectPaint;
4023 rectPaint.setAntiAlias(true);
4024 rectPaint.setStyle(SkPaint::kStroke_Style);
4025 SkPaint arrowPaint(rectPaint);
4026 SkPath arrowPath;
4027 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4028 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4029 SkPath1DPathEffect::kRotate_Style));
4030 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4031 for (unsigned start : { 0, 1, 2, 3 } ) {
4032 SkPath path;
4033 path.addRect(rect, direction, start);
4034 canvas->drawPath(path, rectPaint);
4035 canvas->drawPath(path, arrowPaint);
4036 canvas->translate(64, 0);
4037 }
4038 canvas->translate(-256, 64);
4039 }
4040}
4041##
4042
4043#SeeAlso SkCanvas::drawRect Direction
4044
4045##
4046
4047# ------------------------------------------------------------------------------
4048
4049#Method void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
4050 Direction dir = kCW_Direction)
4051
Cary Clark80247e52018-07-11 16:18:41 -04004052Adds Rect (left, top, right, bottom) to Path,
Cary Clark73fa9722017-08-29 17:36:51 -04004053appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4054starting with top-left corner of Rect; followed by top-right, bottom-right,
4055and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4056bottom-right, and top-right if dir is kCCW_Direction.
4057
Cary Clark5538c132018-06-14 12:28:14 -04004058#Param left smaller x-axis value of Rect ##
4059#Param top smaller y-axis value of Rect ##
4060#Param right larger x-axis value of Rect ##
4061#Param bottom larger y-axis value of Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004062#Param dir Direction to wind added contour ##
4063
4064#Example
4065#Description
4066The left Rect dashes start at the top-left corner, and continue to the right.
4067The right Rect dashes start at the top-left corner, and continue down.
4068##
4069#Height 128
4070void draw(SkCanvas* canvas) {
4071 SkPaint paint;
4072 paint.setStrokeWidth(15);
4073 paint.setStrokeCap(SkPaint::kSquare_Cap);
4074 float intervals[] = { 5, 21.75f };
4075 paint.setStyle(SkPaint::kStroke_Style);
4076 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4077 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4078 SkPath path;
4079 path.addRect(20, 20, 100, 100, direction);
4080 canvas->drawPath(path, paint);
4081 canvas->translate(128, 0);
4082 }
4083}
4084##
4085
4086#SeeAlso SkCanvas::drawRect Direction
4087
4088##
4089
4090# ------------------------------------------------------------------------------
4091
4092#Method void addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004093#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004094#Line # adds one Contour containing Oval ##
Cary Clark80247e52018-07-11 16:18:41 -04004095Adds Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04004096Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4097and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4098clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4099
Cary Clark73fa9722017-08-29 17:36:51 -04004100#Param oval bounds of ellipse added ##
4101#Param dir Direction to wind ellipse ##
4102
4103#Example
4104#Height 120
4105 SkPaint paint;
4106 SkPath oval;
4107 oval.addOval({20, 20, 160, 80});
4108 canvas->drawPath(oval, paint);
4109##
4110
4111#SeeAlso SkCanvas::drawOval Direction Oval
4112
4113##
4114
4115# ------------------------------------------------------------------------------
4116
4117#Method void addOval(const SkRect& oval, Direction dir, unsigned start)
4118
Cary Clark80247e52018-07-11 16:18:41 -04004119Adds Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04004120Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4121and half oval height. Oval begins at start and continues
4122clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4123
4124#Table
4125#Legend
4126# start # Point ##
4127#Legend ##
4128# 0 # oval.centerX(), oval.fTop ##
4129# 1 # oval.fRight, oval.centerY() ##
4130# 2 # oval.centerX(), oval.fBottom ##
4131# 3 # oval.fLeft, oval.centerY() ##
4132#Table ##
4133
4134#Param oval bounds of ellipse added ##
4135#Param dir Direction to wind ellipse ##
4136#Param start index of initial point of ellipse ##
4137
4138#Example
4139#Height 160
4140void draw(SkCanvas* canvas) {
4141 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4142 const SkRect rect = {10, 10, 54, 54};
4143 SkPaint ovalPaint;
4144 ovalPaint.setAntiAlias(true);
4145 SkPaint textPaint(ovalPaint);
4146 textPaint.setTextAlign(SkPaint::kCenter_Align);
4147 ovalPaint.setStyle(SkPaint::kStroke_Style);
4148 SkPaint arrowPaint(ovalPaint);
4149 SkPath arrowPath;
4150 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4151 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4152 SkPath1DPathEffect::kRotate_Style));
4153 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4154 for (unsigned start : { 0, 1, 2, 3 } ) {
4155 SkPath path;
4156 path.addOval(rect, direction, start);
4157 canvas->drawPath(path, ovalPaint);
4158 canvas->drawPath(path, arrowPaint);
4159 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4160 canvas->translate(64, 0);
4161 }
4162 canvas->translate(-256, 72);
4163 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4164 128, 0, textPaint);
4165 }
4166}
4167##
4168
4169#SeeAlso SkCanvas::drawOval Direction Oval
4170
4171##
4172
4173# ------------------------------------------------------------------------------
4174
4175#Method void addCircle(SkScalar x, SkScalar y, SkScalar radius,
4176 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004177#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004178#Line # adds one Contour containing Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04004179
Cary Clark80247e52018-07-11 16:18:41 -04004180Adds Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark682c58d2018-05-16 07:07:07 -04004181four kConic_Verb, and kClose_Verb. Circle begins at:
Cary Clark73fa9722017-08-29 17:36:51 -04004182#Formula
4183(x + radius, y)
4184##
Cary Clark154beea2017-10-26 07:58:48 -04004185, continuing
4186clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04004187
Cary Clark6fc50412017-09-21 12:31:06 -04004188Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004189
4190#Param x center of Circle ##
4191#Param y center of Circle ##
4192#Param radius distance from center to edge ##
4193#Param dir Direction to wind Circle ##
4194
4195#Example
4196void draw(SkCanvas* canvas) {
4197 SkPaint paint;
4198 paint.setAntiAlias(true);
4199 paint.setStyle(SkPaint::kStroke_Style);
4200 paint.setStrokeWidth(10);
4201 for (int size = 10; size < 300; size += 20) {
4202 SkPath path;
4203 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4204 canvas->drawPath(path, paint);
4205 }
4206}
4207##
4208
4209#SeeAlso SkCanvas::drawCircle Direction Circle
4210
4211##
4212
4213# ------------------------------------------------------------------------------
4214
4215#Method void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05004216#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004217#Line # adds one Contour containing Arc ##
Cary Clark80247e52018-07-11 16:18:41 -04004218Appends Arc to Path, as the start of new Contour. Arc added is part of ellipse
Cary Clark73fa9722017-08-29 17:36:51 -04004219bounded by oval, from startAngle through sweepAngle. Both startAngle and
4220sweepAngle are measured in degrees, where zero degrees is aligned with the
4221positive x-axis, and positive sweeps extends Arc clockwise.
4222
Cary Clark682c58d2018-05-16 07:07:07 -04004223If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4224zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
Cary Clark73fa9722017-08-29 17:36:51 -04004225modulo 360, and Arc may or may not draw depending on numeric rounding.
4226
4227#Param oval bounds of ellipse containing Arc ##
4228#Param startAngle starting angle of Arc in degrees ##
4229#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4230
4231#Example
4232#Description
4233The middle row of the left and right columns draw differently from the entries
Cary Clark682c58d2018-05-16 07:07:07 -04004234above and below because sweepAngle is outside of the range of +/-360,
Cary Clark73fa9722017-08-29 17:36:51 -04004235and startAngle modulo 90 is not zero.
4236##
4237void draw(SkCanvas* canvas) {
4238 SkPaint paint;
4239 for (auto start : { 0, 90, 135, 180, 270 } ) {
4240 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4241 SkPath path;
4242 path.addArc({10, 10, 35, 45}, start, sweep);
4243 canvas->drawPath(path, paint);
4244 canvas->translate(252 / 6, 0);
4245 }
4246 canvas->translate(-252, 255 / 5);
4247 }
4248}
4249##
4250
4251#SeeAlso Arc arcTo SkCanvas::drawArc
4252
4253##
4254
4255# ------------------------------------------------------------------------------
4256
4257#Method void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
4258 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004259#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004260#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark73fa9722017-08-29 17:36:51 -04004261
Cary Clark80247e52018-07-11 16:18:41 -04004262Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04004263equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4264dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4265winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4266of the upper-left corner and winds counterclockwise.
4267
4268If either rx or ry is too large, rx and ry are scaled uniformly until the
4269corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4270Rect rect to Path.
4271
4272After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4273
4274#Param rect bounds of Round_Rect ##
Cary Clark5538c132018-06-14 12:28:14 -04004275#Param rx x-axis radius of rounded corners on the Round_Rect ##
4276#Param ry y-axis radius of rounded corners on the Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004277#Param dir Direction to wind Round_Rect ##
4278
4279#Example
4280#Description
4281If either radius is zero, path contains Rect and is drawn red.
4282If sides are only radii, path contains Oval and is drawn blue.
4283All remaining path draws are convex, and are drawn in gray; no
4284paths constructed from addRoundRect are concave, so none are
4285drawn in green.
4286##
4287void draw(SkCanvas* canvas) {
4288 SkPaint paint;
4289 paint.setAntiAlias(true);
4290 for (auto xradius : { 0, 7, 13, 20 } ) {
4291 for (auto yradius : { 0, 9, 18, 40 } ) {
4292 SkPath path;
4293 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4294 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4295 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4296 canvas->drawPath(path, paint);
4297 canvas->translate(64, 0);
4298 }
4299 canvas->translate(-256, 64);
4300 }
4301}
4302##
4303
4304#SeeAlso addRRect SkCanvas::drawRoundRect
4305
4306##
4307
4308# ------------------------------------------------------------------------------
4309
4310#Method void addRoundRect(const SkRect& rect, const SkScalar radii[],
4311 Direction dir = kCW_Direction)
4312
Cary Clark80247e52018-07-11 16:18:41 -04004313Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04004314equal to rect; each corner is 90 degrees of an ellipse with radii from the
4315array.
4316
4317#Table
4318#Legend
4319# radii index # location ##
4320#Legend ##
Cary Clark5538c132018-06-14 12:28:14 -04004321# 0 # x-axis radius of top-left corner ##
4322# 1 # y-axis radius of top-left corner ##
4323# 2 # x-axis radius of top-right corner ##
4324# 3 # y-axis radius of top-right corner ##
4325# 4 # x-axis radius of bottom-right corner ##
4326# 5 # y-axis radius of bottom-right corner ##
4327# 6 # x-axis radius of bottom-left corner ##
4328# 7 # y-axis radius of bottom-left corner ##
Cary Clark73fa9722017-08-29 17:36:51 -04004329#Table ##
4330
Cary Clark682c58d2018-05-16 07:07:07 -04004331If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4332and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
Cary Clark73fa9722017-08-29 17:36:51 -04004333bottom-left of the upper-left corner and winds counterclockwise.
4334
Cary Clark682c58d2018-05-16 07:07:07 -04004335If both radii on any side of rect exceed its length, all radii are scaled
Cary Clark73fa9722017-08-29 17:36:51 -04004336uniformly until the corners fit. If either radius of a corner is less than or
4337equal to zero, both are treated as zero.
4338
4339After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4340
4341#Param rect bounds of Round_Rect ##
4342#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4343#Param dir Direction to wind Round_Rect ##
4344
4345#Example
4346void draw(SkCanvas* canvas) {
4347 SkPaint paint;
4348 paint.setAntiAlias(true);
4349 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4350 SkPath path;
4351 SkMatrix rotate90;
4352 rotate90.setRotate(90, 128, 128);
4353 for (int i = 0; i < 4; ++i) {
4354 path.addRoundRect({10, 10, 110, 110}, radii);
4355 path.transform(rotate90);
4356 }
4357 canvas->drawPath(path, paint);
4358}
4359##
4360
4361#SeeAlso addRRect SkCanvas::drawRoundRect
4362
4363##
4364
4365# ------------------------------------------------------------------------------
4366
4367#Method void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004368#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004369#Line # adds one Contour containing Round_Rect ##
Cary Clark80247e52018-07-11 16:18:41 -04004370Adds rrect to Path, creating a new closed Contour. If
Cary Clark73fa9722017-08-29 17:36:51 -04004371dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4372winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4373of the upper-left corner and winds counterclockwise.
4374
4375After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4376
4377#Param rrect bounds and radii of rounded rectangle ##
4378#Param dir Direction to wind Round_Rect ##
4379
4380#Example
4381void draw(SkCanvas* canvas) {
4382 SkPaint paint;
4383 paint.setAntiAlias(true);
4384 SkRRect rrect;
4385 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4386 rrect.setRectRadii({10, 10, 110, 110}, radii);
4387 SkPath path;
4388 SkMatrix rotate90;
4389 rotate90.setRotate(90, 128, 128);
4390 for (int i = 0; i < 4; ++i) {
4391 path.addRRect(rrect);
4392 path.transform(rotate90);
4393 }
4394 canvas->drawPath(path, paint);
4395}
4396##
4397
4398#SeeAlso addRoundRect SkCanvas::drawRRect
4399
4400##
4401
4402# ------------------------------------------------------------------------------
4403
4404#Method void addRRect(const SkRRect& rrect, Direction dir, unsigned start)
4405
Cary Clark80247e52018-07-11 16:18:41 -04004406Adds rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
Cary Clark73fa9722017-08-29 17:36:51 -04004407winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4408start determines the first point of rrect to add.
4409
4410#Table
4411#Legend
4412# start # location ##
4413#Legend ##
4414# 0 # right of top-left corner ##
4415# 1 # left of top-right corner ##
4416# 2 # bottom of top-right corner ##
4417# 3 # top of bottom-right corner ##
4418# 4 # left of bottom-right corner ##
4419# 5 # right of bottom-left corner ##
4420# 6 # top of bottom-left corner ##
4421# 7 # bottom of top-left corner ##
4422#Table ##
4423
4424After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4425
4426#Param rrect bounds and radii of rounded rectangle ##
4427#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004428#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004429
4430#Example
4431void draw(SkCanvas* canvas) {
4432 SkPaint paint;
4433 paint.setAntiAlias(true);
4434 SkRRect rrect;
4435 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4436 SkPath path;
4437 path.addRRect(rrect);
4438 canvas->drawPath(path, paint);
4439 for (int start = 0; start < 8; ++start) {
4440 SkPath textPath;
4441 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
4442 canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
4443 }
4444}
4445##
4446
Cary Clark682c58d2018-05-16 07:07:07 -04004447#SeeAlso addRoundRect SkCanvas::drawRRect
Cary Clark73fa9722017-08-29 17:36:51 -04004448
4449##
4450
4451# ------------------------------------------------------------------------------
4452
4453#Method void addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05004454#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004455#Line # adds one Contour containing connected lines ##
Cary Clark80247e52018-07-11 16:18:41 -04004456Adds Contour created from Line array, adding (count - 1) Line segments.
Cary Clark6fc50412017-09-21 12:31:06 -04004457Contour added starts at pts[0], then adds a line for every additional Point
4458in pts array. If close is true,appends kClose_Verb to Path, connecting
4459pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004460
4461If count is zero, append kMove_Verb to path.
4462Has no effect if count is less than one.
Cary Clark682c58d2018-05-16 07:07:07 -04004463
Cary Clarka523d2d2017-08-30 08:58:10 -04004464#Param pts array of Line sharing end and start Point ##
4465#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004466#Param close true to add Line connecting Contour end and start ##
4467
4468#Example
4469void draw(SkCanvas* canvas) {
4470 SkPaint paint;
4471 paint.setStrokeWidth(15);
4472 paint.setStrokeCap(SkPaint::kRound_Cap);
4473 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4474 for (bool close : { false, true } ) {
4475 SkPath path;
4476 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4477 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4478 SkPaint::kStrokeAndFill_Style} ) {
4479 paint.setStyle(style);
4480 canvas->drawPath(path, paint);
4481 canvas->translate(85, 0);
4482 }
4483 canvas->translate(-255, 128);
4484 }
4485}
4486##
4487
4488#SeeAlso SkCanvas::drawPoints
4489
4490##
4491
4492# ------------------------------------------------------------------------------
4493
4494#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05004495#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04004496
4497#Code
4498 enum AddPathMode {
Cary Clark682c58d2018-05-16 07:07:07 -04004499 kAppend_AddPathMode,
4500 kExtend_AddPathMode,
Cary Clark73fa9722017-08-29 17:36:51 -04004501 };
4502##
4503
4504AddPathMode chooses how addPath appends. Adding one Path to another can extend
4505the last Contour or start a new Contour.
4506
4507#Const kAppend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004508#Line # appended to destination unaltered ##
Cary Clark73fa9722017-08-29 17:36:51 -04004509 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4510 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4511 starts a new Contour.
4512##
4513#Const kExtend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004514#Line # add line if prior Contour is not closed ##
Cary Clark73fa9722017-08-29 17:36:51 -04004515 If destination is closed or empty, start a new Contour. If destination
4516 is not empty, add Line from Last_Point to added Path first Point. Skip added
4517 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4518##
4519
4520#Example
4521#Description
4522test is built from path, open on the top row, and closed on the bottom row.
4523The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4524The top right composition is made up of one contour; the other three have two.
4525##
4526#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004527 SkPath path, path2;
4528 path.moveTo(20, 20);
4529 path.lineTo(20, 40);
4530 path.lineTo(40, 20);
4531 path2.moveTo(60, 60);
4532 path2.lineTo(80, 60);
4533 path2.lineTo(80, 40);
4534 SkPaint paint;
4535 paint.setStyle(SkPaint::kStroke_Style);
4536 for (int i = 0; i < 2; i++) {
4537 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4538 SkPath test(path);
4539 test.addPath(path2, addPathMode);
4540 canvas->drawPath(test, paint);
4541 canvas->translate(100, 0);
4542 }
4543 canvas->translate(-200, 100);
4544 path.close();
4545 }
Cary Clark73fa9722017-08-29 17:36:51 -04004546##
4547
4548#SeeAlso addPath reverseAddPath
4549
4550##
4551
4552# ------------------------------------------------------------------------------
4553
4554#Method void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
4555 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05004556#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004557#Line # adds contents of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004558
Cary Clark80247e52018-07-11 16:18:41 -04004559Appends src to Path, offset by (dx, dy).
Cary Clark73fa9722017-08-29 17:36:51 -04004560
4561If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4562added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004563Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004564
4565#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clark5538c132018-06-14 12:28:14 -04004566#Param dx offset added to src Point_Array x-axis coordinates ##
4567#Param dy offset added to src Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004568#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4569
4570#Example
4571#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004572 SkPaint paint;
4573 paint.setTextSize(128);
4574 paint.setFakeBoldText(true);
4575 SkPath dest, text;
4576 paint.getTextPath("O", 1, 50, 120, &text);
4577 for (int i = 0; i < 3; i++) {
4578 dest.addPath(text, i * 20, i * 20);
4579 }
4580 Simplify(dest, &dest);
4581 paint.setStyle(SkPaint::kStroke_Style);
4582 paint.setStrokeWidth(3);
4583 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004584##
4585
Cary Clark4855f782018-02-06 09:41:53 -05004586#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004587
4588##
4589
4590# ------------------------------------------------------------------------------
4591
Cary Clark682c58d2018-05-16 07:07:07 -04004592#Method void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
Cary Clark73fa9722017-08-29 17:36:51 -04004593
Cary Clark80247e52018-07-11 16:18:41 -04004594Appends src to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04004595
4596If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4597added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004598Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004599
4600#Param src Path Verbs, Points, and Conic_Weights to add ##
4601#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4602
4603#Example
4604#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004605 SkPaint paint;
4606 paint.setStyle(SkPaint::kStroke_Style);
4607 SkPath dest, path;
4608 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4609 for (int i = 0; i < 2; i++) {
4610 dest.addPath(path, SkPath::kExtend_AddPathMode);
4611 dest.offset(100, 0);
4612 }
Cary Clark73fa9722017-08-29 17:36:51 -04004613 canvas->drawPath(dest, paint);
4614##
4615
4616#SeeAlso AddPathMode reverseAddPath
4617
4618##
4619
4620# ------------------------------------------------------------------------------
4621
4622#Method void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
4623
Cary Clark80247e52018-07-11 16:18:41 -04004624Appends src to Path, transformed by matrix. Transformed curves may have different
Cary Clark73fa9722017-08-29 17:36:51 -04004625Verbs, Points, and Conic_Weights.
4626
4627If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4628added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004629Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004630
4631#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004632#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004633#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4634
4635#Example
4636#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004637 SkPaint paint;
4638 paint.setStyle(SkPaint::kStroke_Style);
4639 SkPath dest, path;
4640 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4641 for (int i = 0; i < 6; i++) {
4642 SkMatrix matrix;
4643 matrix.reset();
4644 matrix.setPerspX(i / 400.f);
4645 dest.addPath(path, matrix);
4646 }
4647 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004648##
4649
Cary Clark4855f782018-02-06 09:41:53 -05004650#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004651
4652##
4653
4654# ------------------------------------------------------------------------------
4655
4656#Method void reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05004657#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004658#Line # adds contents of Path back to front ##
Cary Clark80247e52018-07-11 16:18:41 -04004659Appends src to Path, from back to front.
Cary Clark73fa9722017-08-29 17:36:51 -04004660Reversed src always appends a new Contour to Path.
4661
4662#Param src Path Verbs, Points, and Conic_Weights to add ##
4663
4664#Example
4665#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004666 SkPath path;
4667 path.moveTo(20, 20);
4668 path.lineTo(20, 40);
4669 path.lineTo(40, 20);
4670 SkPaint paint;
4671 paint.setStyle(SkPaint::kStroke_Style);
4672 for (int i = 0; i < 2; i++) {
4673 SkPath path2;
4674 path2.moveTo(60, 60);
4675 path2.lineTo(80, 60);
4676 path2.lineTo(80, 40);
4677 for (int j = 0; j < 2; j++) {
4678 SkPath test(path);
4679 test.reverseAddPath(path2);
4680 canvas->drawPath(test, paint);
4681 canvas->translate(100, 0);
4682 path2.close();
4683 }
4684 canvas->translate(-200, 100);
4685 path.close();
4686 }
Cary Clark73fa9722017-08-29 17:36:51 -04004687##
4688
Cary Clark4855f782018-02-06 09:41:53 -05004689#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04004690
4691##
4692
4693# ------------------------------------------------------------------------------
4694
4695#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004696#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004697#Line # translates Point_Array ##
Cary Clark80247e52018-07-11 16:18:41 -04004698Offsets Point_Array by (dx, dy). Offset Path replaces dst.
Cary Clark73fa9722017-08-29 17:36:51 -04004699If dst is nullptr, Path is replaced by offset data.
4700
Cary Clark5538c132018-06-14 12:28:14 -04004701#Param dx offset added to Point_Array x-axis coordinates ##
4702#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004703#Param dst overwritten, translated copy of Path; may be nullptr ##
4704
4705#Example
4706#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004707 SkPath pattern;
4708 pattern.moveTo(20, 20);
4709 pattern.lineTo(20, 40);
4710 pattern.lineTo(40, 20);
4711 SkPaint paint;
4712 paint.setStyle(SkPaint::kStroke_Style);
4713 for (int i = 0; i < 10; i++) {
4714 SkPath path;
4715 pattern.offset(20 * i, 0, &path);
4716 canvas->drawPath(path, paint);
4717 }
Cary Clark73fa9722017-08-29 17:36:51 -04004718##
4719
4720#SeeAlso addPath transform
4721
4722##
4723
4724# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05004725#Subtopic Transform
4726#Populate
4727#Line # modify all points ##
4728##
Cary Clark73fa9722017-08-29 17:36:51 -04004729
Cary Clark682c58d2018-05-16 07:07:07 -04004730#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05004731#In Transform
Cary Clark80247e52018-07-11 16:18:41 -04004732Offsets Point_Array by (dx, dy). Path is replaced by offset data.
Cary Clark73fa9722017-08-29 17:36:51 -04004733
Cary Clark5538c132018-06-14 12:28:14 -04004734#Param dx offset added to Point_Array x-axis coordinates ##
4735#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004736
4737#Example
4738#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004739 SkPath path;
4740 path.moveTo(20, 20);
4741 path.lineTo(20, 40);
4742 path.lineTo(40, 20);
4743 SkPaint paint;
4744 paint.setStyle(SkPaint::kStroke_Style);
4745 for (int i = 0; i < 10; i++) {
4746 canvas->drawPath(path, paint);
4747 path.offset(20, 0);
4748 }
Cary Clark73fa9722017-08-29 17:36:51 -04004749##
4750
4751#SeeAlso addPath transform SkCanvas::translate()
4752
4753##
4754
4755# ------------------------------------------------------------------------------
4756
4757#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004758#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004759#Line # applies Matrix to Point_Array and Weights ##
Cary Clark80247e52018-07-11 16:18:41 -04004760Transforms Verb_Array, Point_Array, and weight by matrix.
Cary Clark73fa9722017-08-29 17:36:51 -04004761transform may change Verbs and increase their number.
4762Transformed Path replaces dst; if dst is nullptr, original data
Cary Clark682c58d2018-05-16 07:07:07 -04004763is replaced.
Cary Clark73fa9722017-08-29 17:36:51 -04004764
4765#Param matrix Matrix to apply to Path ##
4766#Param dst overwritten, transformed copy of Path; may be nullptr ##
4767
4768#Example
Cary Clark8032b982017-07-28 11:04:54 -04004769#Height 200
4770 SkPath pattern;
4771 pattern.moveTo(100, 100);
4772 pattern.lineTo(100, 20);
4773 pattern.lineTo(20, 100);
4774 SkPaint paint;
4775 paint.setStyle(SkPaint::kStroke_Style);
4776 for (int i = 0; i < 10; i++) {
4777 SkPath path;
4778 SkMatrix matrix;
4779 matrix.setRotate(36 * i, 100, 100);
4780 pattern.transform(matrix, &path);
4781 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004782 }
4783##
4784
4785#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4786
4787##
4788
4789# ------------------------------------------------------------------------------
4790
Cary Clark682c58d2018-05-16 07:07:07 -04004791#Method void transform(const SkMatrix& matrix)
Cary Clark73fa9722017-08-29 17:36:51 -04004792
Cary Clark80247e52018-07-11 16:18:41 -04004793Transforms Verb_Array, Point_Array, and weight by matrix.
Cary Clark73fa9722017-08-29 17:36:51 -04004794transform may change Verbs and increase their number.
4795Path is replaced by transformed data.
4796
4797#Param matrix Matrix to apply to Path ##
4798
4799#Example
Cary Clark8032b982017-07-28 11:04:54 -04004800#Height 200
4801 SkPath path;
4802 path.moveTo(100, 100);
4803 path.quadTo(100, 20, 20, 100);
4804 SkPaint paint;
4805 paint.setStyle(SkPaint::kStroke_Style);
4806 for (int i = 0; i < 10; i++) {
4807 SkMatrix matrix;
4808 matrix.setRotate(36, 100, 100);
4809 path.transform(matrix);
4810 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004811 }
4812##
4813
4814#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4815
4816##
4817
4818# ------------------------------------------------------------------------------
4819
Cary Clark8032b982017-07-28 11:04:54 -04004820#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05004821#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04004822
4823Path is defined cumulatively, often by adding a segment to the end of last
4824Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4825Last_Point can be read and written directly with getLastPt and setLastPt.
4826
Cary Clark73fa9722017-08-29 17:36:51 -04004827#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05004828#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004829#In Last_Point
4830#Line # returns Last_Point ##
Cary Clark682c58d2018-05-16 07:07:07 -04004831 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
Cary Clark73fa9722017-08-29 17:36:51 -04004832 storing (0, 0) if lastPt is not nullptr.
4833
4834 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4835
4836 #Return true if Point_Array contains one or more Points ##
4837
4838 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004839 SkPath path;
4840 path.moveTo(100, 100);
4841 path.quadTo(100, 20, 20, 100);
4842 SkMatrix matrix;
4843 matrix.setRotate(36, 100, 100);
4844 path.transform(matrix);
4845 SkPoint last;
4846 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004847 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4848 #StdOut
4849 last point: 35.2786, 52.9772
Cary Clark682c58d2018-05-16 07:07:07 -04004850 ##
Cary Clark73fa9722017-08-29 17:36:51 -04004851 ##
4852
4853 #SeeAlso setLastPt
4854
4855##
4856
4857#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05004858#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004859#In Last_Point
4860#Line # replaces Last_Point ##
Cary Clark80247e52018-07-11 16:18:41 -04004861 Sets Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
Cary Clark186d08f2018-04-03 08:43:27 -04004862 Verb_Array and append (x, y) to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04004863
Cary Clark5538c132018-06-14 12:28:14 -04004864 #Param x set x-axis value of Last_Point ##
4865 #Param y set y-axis value of Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004866
4867 #Example
4868 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004869 SkPaint paint;
4870 paint.setTextSize(128);
4871 SkPath path;
4872 paint.getTextPath("@", 1, 60, 100, &path);
4873 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004874 canvas->drawPath(path, paint);
4875 ##
4876
4877 #SeeAlso getLastPt
4878
4879##
4880
Cary Clark682c58d2018-05-16 07:07:07 -04004881#Method void setLastPt(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04004882
Cary Clark80247e52018-07-11 16:18:41 -04004883 Sets the last point on the path. If Point_Array is empty, append kMove_Verb to
Cary Clark186d08f2018-04-03 08:43:27 -04004884 Verb_Array and append p to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04004885
4886 #Param p set value of Last_Point ##
4887
4888 #Example
4889 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004890 SkPaint paint;
4891 paint.setTextSize(128);
4892 SkPath path, path2;
4893 paint.getTextPath("A", 1, 60, 100, &path);
4894 paint.getTextPath("Z", 1, 60, 100, &path2);
4895 SkPoint pt, pt2;
4896 path.getLastPt(&pt);
4897 path2.getLastPt(&pt2);
4898 path.setLastPt(pt2);
4899 path2.setLastPt(pt);
4900 canvas->drawPath(path, paint);
4901 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004902 ##
4903
4904 #SeeAlso getLastPt
4905
4906##
4907
4908#Subtopic Last_Point ##
4909
4910# ------------------------------------------------------------------------------
4911
4912#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05004913#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004914
4915#Code
4916 enum SegmentMask {
4917 kLine_SegmentMask = 1 << 0,
4918 kQuad_SegmentMask = 1 << 1,
4919 kConic_SegmentMask = 1 << 2,
4920 kCubic_SegmentMask = 1 << 3,
4921 };
4922##
4923
4924SegmentMask constants correspond to each drawing Verb type in Path; for
4925instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4926
Cary Clark4855f782018-02-06 09:41:53 -05004927#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04004928#Const kLine_SegmentMask 1
Cary Clark682c58d2018-05-16 07:07:07 -04004929#Line # contains one or more Lines ##
Cary Clark73fa9722017-08-29 17:36:51 -04004930Set if Verb_Array contains kLine_Verb.
4931##
4932#Const kQuad_SegmentMask 2
Cary Clark682c58d2018-05-16 07:07:07 -04004933#Line # contains one or more Quads ##
Cary Clark73fa9722017-08-29 17:36:51 -04004934Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4935##
4936#Const kConic_SegmentMask 4
Cary Clark682c58d2018-05-16 07:07:07 -04004937#Line # contains one or more Conics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004938Set if Verb_Array contains kConic_Verb.
4939##
4940#Const kCubic_SegmentMask 8
Cary Clark682c58d2018-05-16 07:07:07 -04004941#Line # contains one or more Cubics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004942Set if Verb_Array contains kCubic_Verb.
4943##
4944
4945#Example
4946#Description
4947When conicTo has a weight of one, Quad is added to Path.
4948##
4949 SkPath path;
4950 path.conicTo(10, 10, 20, 30, 1);
Cary Clark682c58d2018-05-16 07:07:07 -04004951 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004952 SkPath::kConic_SegmentMask ? "set" : "clear");
Cary Clark682c58d2018-05-16 07:07:07 -04004953 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004954 SkPath::kQuad_SegmentMask ? "set" : "clear");
4955#StdOut
4956Path kConic_SegmentMask is clear
4957Path kQuad_SegmentMask is set
4958##
4959##
4960
4961#SeeAlso getSegmentMasks Verb
4962
4963##
4964
4965# ------------------------------------------------------------------------------
4966
Cary Clark682c58d2018-05-16 07:07:07 -04004967#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05004968#In Utility
4969#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004970#Line # returns types in Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004971Returns a mask, where each set bit corresponds to a SegmentMask constant
4972if Path contains one or more Verbs of that type.
4973Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
4974
4975getSegmentMasks() returns a cached result; it is very fast.
4976
4977#Return SegmentMask bits or zero ##
4978
4979#Example
4980SkPath path;
4981path.quadTo(20, 30, 40, 50);
4982path.close();
4983const char* masks[] = { "line", "quad", "conic", "cubic" };
4984int index = 0;
4985for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4986 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4987 if (mask & path.getSegmentMasks()) {
4988 SkDebugf("mask %s set\n", masks[index]);
Cary Clark682c58d2018-05-16 07:07:07 -04004989 }
Cary Clark73fa9722017-08-29 17:36:51 -04004990 ++index;
4991}
4992#StdOut
4993mask quad set
4994##
4995##
4996
4997#SeeAlso getSegmentMasks Verb
4998
4999##
5000
5001# ------------------------------------------------------------------------------
5002
5003#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05005004#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05005005#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04005006Returns true if the point (x, y) is contained by Path, taking into
Cary Clark682c58d2018-05-16 07:07:07 -04005007account FillType.
Cary Clark73fa9722017-08-29 17:36:51 -04005008
5009#Table
5010#Legend
5011# FillType # contains() returns true if Point is enclosed by ##
5012##
5013# kWinding_FillType # a non-zero sum of Contour Directions. ##
5014# kEvenOdd_FillType # an odd number of Contours. ##
5015# kInverseWinding_FillType # a zero sum of Contour Directions. ##
5016# kInverseEvenOdd_FillType # and even number of Contours. ##
Cary Clark682c58d2018-05-16 07:07:07 -04005017##
Cary Clark73fa9722017-08-29 17:36:51 -04005018
Cary Clark5538c132018-06-14 12:28:14 -04005019#Param x x-axis value of containment test ##
5020#Param y y-axis value of containment test ##
Cary Clark73fa9722017-08-29 17:36:51 -04005021
5022#Return true if Point is in Path ##
5023
5024#Example
5025SkPath path;
5026SkPaint paint;
5027paint.setTextSize(256);
5028paint.getTextPath("&", 1, 30, 220, &path);
5029for (int y = 2; y < 256; y += 9) {
5030 for (int x = 2; x < 256; x += 9) {
5031 int coverage = 0;
5032 for (int iy = -4; iy <= 4; iy += 2) {
5033 for (int ix = -4; ix <= 4; ix += 2) {
5034 coverage += path.contains(x + ix, y + iy);
5035 }
5036 }
5037 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5038 canvas->drawCircle(x, y, 8, paint);
5039 }
5040}
5041##
5042
5043#SeeAlso conservativelyContainsRect Fill_Type Op
5044
5045##
5046
5047# ------------------------------------------------------------------------------
5048
5049#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05005050#In Utility
Cary Clark53498e92018-06-28 19:13:56 -04005051#Line # sends text representation to stream ##
Cary Clark154beea2017-10-26 07:58:48 -04005052Writes text representation of Path to stream. If stream is nullptr, writes to
5053standard output. Set forceClose to true to get edges used to fill Path.
5054Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005055of floating point numbers used in Point_Array and Conic_Weights.
5056
Cary Clark224c7002018-06-27 11:00:21 -04005057#Param stream writable WStream receiving Path text representation; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04005058#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005059#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005060
5061#Example
5062 SkPath path;
5063 path.quadTo(20, 30, 40, 50);
5064 for (bool forceClose : { false, true } ) {
5065 for (bool dumpAsHex : { false, true } ) {
5066 path.dump(nullptr, forceClose, dumpAsHex);
5067 SkDebugf("\n");
5068 }
5069 }
5070#StdOut
5071path.setFillType(SkPath::kWinding_FillType);
5072path.moveTo(0, 0);
5073path.quadTo(20, 30, 40, 50);
5074
5075path.setFillType(SkPath::kWinding_FillType);
5076path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5077path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5078
5079path.setFillType(SkPath::kWinding_FillType);
5080path.moveTo(0, 0);
5081path.quadTo(20, 30, 40, 50);
5082path.lineTo(0, 0);
5083path.close();
5084
5085path.setFillType(SkPath::kWinding_FillType);
5086path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5087path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5088path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5089path.close();
5090##
5091##
5092
Cary Clark53498e92018-06-28 19:13:56 -04005093#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
Cary Clark73fa9722017-08-29 17:36:51 -04005094
5095##
5096
5097# ------------------------------------------------------------------------------
5098
5099#Method void dump() const
5100
Cary Clarkce101242017-09-01 15:51:02 -04005101Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005102directly compiled as C++ code. Floating point values are written
5103with limited precision; it may not be possible to reconstruct original Path
5104from output.
5105
5106#Example
5107SkPath path, copy;
5108path.lineTo(6.f / 7, 2.f / 3);
5109path.dump();
5110copy.setFillType(SkPath::kWinding_FillType);
5111copy.moveTo(0, 0);
5112copy.lineTo(0.857143f, 0.666667f);
5113SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5114#StdOut
5115path.setFillType(SkPath::kWinding_FillType);
5116path.moveTo(0, 0);
5117path.lineTo(0.857143f, 0.666667f);
5118path is not equal to copy
5119##
5120##
5121
5122#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5123
5124##
5125
5126# ------------------------------------------------------------------------------
5127
5128#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05005129#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005130#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04005131Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005132directly compiled as C++ code. Floating point values are written
5133in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5134original Path.
5135
Cary Clark682c58d2018-05-16 07:07:07 -04005136Use instead of dump() when submitting
5137#A bug reports against Skia # https://bug.skia.org ##
Cary Clark6fc50412017-09-21 12:31:06 -04005138.
Cary Clark73fa9722017-08-29 17:36:51 -04005139
5140#Example
5141SkPath path, copy;
5142path.lineTo(6.f / 7, 2.f / 3);
5143path.dumpHex();
5144copy.setFillType(SkPath::kWinding_FillType);
5145copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5146copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5147SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5148#StdOut
5149path.setFillType(SkPath::kWinding_FillType);
5150path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5151path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5152path is equal to copy
5153##
5154##
5155
Cary Clark186d08f2018-04-03 08:43:27 -04005156#SeeAlso dump SkRect::dumpHex SkRRect::dumpHex writeToMemory
Cary Clark73fa9722017-08-29 17:36:51 -04005157
5158##
5159
5160# ------------------------------------------------------------------------------
5161
5162#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05005163#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005164#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005165Writes Path to buffer, returning the number of bytes written.
5166Pass nullptr to obtain the storage size.
5167
5168Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5169additionally writes computed information like Convexity and bounds.
5170
5171Use only be used in concert with readFromMemory;
5172the format used for Path in memory is not guaranteed.
5173
5174#Param buffer storage for Path; may be nullptr ##
5175
5176#Return size of storage required for Path; always a multiple of 4 ##
5177
5178#Example
5179void draw(SkCanvas* canvas) {
5180 SkPath path, copy;
5181 path.lineTo(6.f / 7, 2.f / 3);
5182 size_t size = path.writeToMemory(nullptr);
5183 SkTDArray<char> storage;
5184 storage.setCount(size);
5185 path.writeToMemory(storage.begin());
5186 copy.readFromMemory(storage.begin(), size);
5187 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5188}
5189#StdOut
5190path is equal to copy
5191##
5192##
5193
5194#SeeAlso serialize readFromMemory dump dumpHex
5195
5196##
5197
5198#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05005199#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005200#Line # copies data to buffer ##
Cary Clark80247e52018-07-11 16:18:41 -04005201Writes Path to buffer, returning the buffer written to, wrapped in Data.
Cary Clark73fa9722017-08-29 17:36:51 -04005202
5203serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5204additionally writes computed information like Convexity and bounds.
5205
5206serialize() should only be used in concert with readFromMemory.
5207The format used for Path in memory is not guaranteed.
5208
5209#Return Path data wrapped in Data buffer ##
5210
5211#Example
5212void draw(SkCanvas* canvas) {
5213 SkPath path, copy;
5214 path.lineTo(6.f / 7, 2.f / 3);
5215 sk_sp<SkData> data = path.serialize();
5216 copy.readFromMemory(data->data(), data->size());
5217 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5218}
5219#StdOut
5220path is equal to copy
5221##
5222##
5223
5224#SeeAlso writeToMemory readFromMemory dump dumpHex
5225##
5226
5227# ------------------------------------------------------------------------------
5228
5229#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05005230#In Utility
Cary Clark682c58d2018-05-16 07:07:07 -04005231#Line # initializes from buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005232Initializes Path from buffer of size length. Returns zero if the buffer is
Cary Clark682c58d2018-05-16 07:07:07 -04005233data is inconsistent, or the length is too small.
Cary Clark73fa9722017-08-29 17:36:51 -04005234
5235Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5236additionally reads computed information like Convexity and bounds.
5237
5238Used only in concert with writeToMemory;
5239the format used for Path in memory is not guaranteed.
5240
5241#Param buffer storage for Path ##
5242#Param length buffer size in bytes; must be multiple of 4 ##
5243
5244#Return number of bytes read, or zero on failure ##
5245
5246#Example
5247void draw(SkCanvas* canvas) {
5248 SkPath path, copy;
5249 path.lineTo(6.f / 7, 2.f / 3);
5250 size_t size = path.writeToMemory(nullptr);
5251 SkTDArray<char> storage;
5252 storage.setCount(size);
5253 path.writeToMemory(storage.begin());
5254 size_t wrongSize = size - 4;
5255 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5256 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5257 size_t largerSize = size + 4;
5258 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5259 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5260}
5261#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005262length = 32; returned by readFromMemory = 0
Cary Clark06c20f32018-03-20 15:53:27 -04005263length = 40; returned by readFromMemory = 36
Cary Clark73fa9722017-08-29 17:36:51 -04005264##
5265##
5266
5267#SeeAlso writeToMemory
5268
5269##
5270
5271# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05005272#Subtopic Generation_ID
Cary Clark137b8742018-05-30 09:21:49 -04005273#Alias Generation_IDs ##
Cary Clark08895c42018-02-01 09:37:32 -05005274#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04005275Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5276Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5277not necessarily have matching Generation_IDs.
5278
5279Empty Paths have a Generation_ID of one.
5280
5281#Method uint32_t getGenerationID() const
5282
Cary Clarkab2621d2018-01-30 10:08:57 -05005283#In Generation_ID
5284#Line # returns unique ID ##
Cary Clark682c58d2018-05-16 07:07:07 -04005285Returns a non-zero, globally unique value. A different value is returned
Cary Clark73fa9722017-08-29 17:36:51 -04005286if Verb_Array, Point_Array, or Conic_Weight changes.
5287
5288Setting Fill_Type does not change Generation_ID.
5289
5290Each time the path is modified, a different Generation_ID will be returned.
5291
5292#Bug 1762
5293Fill_Type does affect Generation_ID on Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -04005294
5295#Return non-zero, globally unique value ##
5296
5297#Example
5298SkPath path;
5299SkDebugf("empty genID = %u\n", path.getGenerationID());
5300path.lineTo(1, 2);
5301SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5302path.rewind();
5303SkDebugf("empty genID = %u\n", path.getGenerationID());
5304path.lineTo(1, 2);
5305SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5306#StdOut
5307empty genID = 1
53081st lineTo genID = 2
5309empty genID = 1
53102nd lineTo genID = 3
5311##
5312##
5313
5314#SeeAlso operator==(const SkPath& a, const SkPath& b)
5315
5316##
5317
Cary Clark78de7512018-02-07 07:27:09 -05005318#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04005319
5320# ------------------------------------------------------------------------------
5321
5322#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005323#In Property
5324#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005325#Line # returns if data is internally consistent ##
Cary Clark73fa9722017-08-29 17:36:51 -04005326 Returns if Path data is consistent. Corrupt Path data is detected if
5327 internal values are out of range or internal storage does not match
5328 array dimensions.
5329
5330 #Return true if Path data is consistent ##
5331
5332 #NoExample
5333 ##
5334
5335##
5336
5337#Method bool pathRefIsValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005338#Deprecated soon
Cary Clark73fa9722017-08-29 17:36:51 -04005339##
5340
5341# ------------------------------------------------------------------------------
5342
Cary Clark8032b982017-07-28 11:04:54 -04005343#Class Iter
Cary Clark682c58d2018-05-16 07:07:07 -04005344#Line # data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005345
Cary Clark73fa9722017-08-29 17:36:51 -04005346#Code
5347class Iter {
5348public:
5349 Iter();
5350 Iter(const SkPath& path, bool forceClose);
5351 void setPath(const SkPath& path, bool forceClose);
5352 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5353 SkScalar conicWeight() const;
5354 bool isCloseLine() const;
5355 bool isClosedContour() const;
5356};
5357##
5358
Cary Clark137b8742018-05-30 09:21:49 -04005359Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5360Provides options to treat open Contours as closed, and to ignore
5361degenerate data.
5362
Cary Clark8032b982017-07-28 11:04:54 -04005363#Example
5364#Height 128
5365#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005366Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005367path of the glyph.
5368##
Cary Clark73fa9722017-08-29 17:36:51 -04005369void draw(SkCanvas* canvas) {
5370 SkPaint paint;
5371 paint.setAntiAlias(true);
5372 paint.setTextSize(256);
5373 SkPath asterisk, path;
5374 paint.getTextPath("*", 1, 50, 192, &asterisk);
Cary Clark682c58d2018-05-16 07:07:07 -04005375 SkPath::Iter iter(asterisk, true);
Cary Clark73fa9722017-08-29 17:36:51 -04005376 SkPoint start[4], pts[4];
5377 iter.next(start); // skip moveTo
5378 iter.next(start); // first quadTo
5379 path.moveTo((start[0] + start[1]) * 0.5f);
5380 while (SkPath::kClose_Verb != iter.next(pts)) {
5381 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5382 }
5383 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5384 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005385}
5386##
5387
5388#SeeAlso RawIter
5389
5390#Method Iter()
Cary Clark682c58d2018-05-16 07:07:07 -04005391#Line # constructs Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005392Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5393Call setPath to initialize Iter at a later time.
5394
Cary Clark73fa9722017-08-29 17:36:51 -04005395#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005396
5397#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005398void draw(SkCanvas* canvas) {
5399 SkPath::Iter iter;
5400 SkPoint points[4];
5401 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5402 SkPath path;
5403 iter.setPath(path, false);
5404 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005405}
Cary Clark73fa9722017-08-29 17:36:51 -04005406#StdOut
5407iter is done
5408iter is done
5409##
Cary Clark8032b982017-07-28 11:04:54 -04005410##
5411
5412#SeeAlso setPath
5413
5414##
5415
5416#Method Iter(const SkPath& path, bool forceClose)
5417
5418Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5419If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5420open Contour. path is not altered.
5421
Cary Clark73fa9722017-08-29 17:36:51 -04005422#Param path Path to iterate ##
5423#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005424
Cary Clark73fa9722017-08-29 17:36:51 -04005425#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005426
5427#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005428void draw(SkCanvas* canvas) {
5429 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5430 SkDebugf("%s:\n", prefix);
5431 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5432 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5433 SkPath::Verb verb;
5434 do {
5435 SkPoint points[4];
5436 verb = iter.next(points);
5437 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5438 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5439 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5440 }
5441 if (SkPath::kConic_Verb == verb) {
5442 SkDebugf("weight = %g", iter.conicWeight());
5443 }
5444 SkDebugf("\n");
5445 } while (SkPath::kDone_Verb != verb);
5446 SkDebugf("\n");
5447 };
5448
5449 SkPath path;
5450 path.quadTo(10, 20, 30, 40);
5451 SkPath::Iter openIter(path, false);
5452 debugster("open", openIter);
5453 SkPath::Iter closedIter(path, true);
5454 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005455}
5456#StdOut
5457open:
Cary Clark682c58d2018-05-16 07:07:07 -04005458kMove_Verb {0, 0},
5459kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5460kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005461
5462closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005463kMove_Verb {0, 0},
5464kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5465kLine_Verb {30, 40}, {0, 0},
5466kClose_Verb {0, 0},
5467kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005468##
5469##
5470
5471#SeeAlso setPath
5472
5473##
5474
5475#Method void setPath(const SkPath& path, bool forceClose)
5476
5477Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5478If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5479open Contour. path is not altered.
5480
Cary Clark73fa9722017-08-29 17:36:51 -04005481#Param path Path to iterate ##
5482#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005483
5484#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005485void draw(SkCanvas* canvas) {
5486 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5487 SkDebugf("%s:\n", prefix);
5488 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5489 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5490 SkPath::Verb verb;
5491 do {
5492 SkPoint points[4];
5493 verb = iter.next(points);
5494 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5495 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5496 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5497 }
5498 if (SkPath::kConic_Verb == verb) {
5499 SkDebugf("weight = %g", iter.conicWeight());
5500 }
5501 SkDebugf("\n");
5502 } while (SkPath::kDone_Verb != verb);
5503 SkDebugf("\n");
5504 };
5505
5506 SkPath path;
5507 path.quadTo(10, 20, 30, 40);
5508 SkPath::Iter iter(path, false);
5509 debugster("quad open", iter);
5510 SkPath path2;
5511 path2.conicTo(1, 2, 3, 4, .5f);
5512 iter.setPath(path2, true);
5513 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005514}
5515#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005516quad open:
Cary Clark682c58d2018-05-16 07:07:07 -04005517kMove_Verb {0, 0},
5518kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5519kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005520
5521conic closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005522kMove_Verb {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04005523kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005524kLine_Verb {3, 4}, {0, 0},
5525kClose_Verb {0, 0},
5526kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005527##
5528##
5529
5530#SeeAlso Iter(const SkPath& path, bool forceClose)
5531
5532##
5533
Cary Clark682c58d2018-05-16 07:07:07 -04005534#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
Cary Clark8032b982017-07-28 11:04:54 -04005535
Cary Clarka523d2d2017-08-30 08:58:10 -04005536Returns next Verb in Verb_Array, and advances Iter.
5537When Verb_Array is exhausted, returns kDone_Verb.
5538
Cary Clark8032b982017-07-28 11:04:54 -04005539Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005540
Cary Clark8032b982017-07-28 11:04:54 -04005541If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5542only the last in the series; and skip very small Lines, Quads, and Conics; and
5543skip kClose_Verb following kMove_Verb.
5544if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5545Conics with zero lengths.
5546
Cary Clarka523d2d2017-08-30 08:58:10 -04005547 #Param pts storage for Point data describing returned Verb ##
5548 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5549 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005550
Cary Clark73fa9722017-08-29 17:36:51 -04005551 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005552
5553#Example
Cary Clark682c58d2018-05-16 07:07:07 -04005554#Description
Cary Clark8032b982017-07-28 11:04:54 -04005555skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5556followed by the kClose_Verb, the zero length Line and the very small Line.
5557
5558skip degenerate if exact skips the same as skip degenerate, but shows
5559the very small Line.
5560
5561skip none shows all of the Verbs and Points in Path.
5562##
Cary Clark73fa9722017-08-29 17:36:51 -04005563void draw(SkCanvas* canvas) {
5564 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5565 SkPath::Iter iter(path, false);
5566 SkDebugf("%s:\n", prefix);
5567 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5568 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5569 SkPath::Verb verb;
5570 do {
5571 SkPoint points[4];
5572 verb = iter.next(points, degen, exact);
5573 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5574 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5575 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5576 }
5577 SkDebugf("\n");
5578 } while (SkPath::kDone_Verb != verb);
5579 SkDebugf("\n");
5580 };
5581
5582 SkPath path;
5583 path.moveTo(10, 10);
5584 path.moveTo(20, 20);
5585 path.quadTo(10, 20, 30, 40);
5586 path.moveTo(1, 1);
5587 path.close();
5588 path.moveTo(30, 30);
5589 path.lineTo(30, 30);
5590 path.moveTo(30, 30);
5591 path.lineTo(30.00001f, 30);
5592 debugster("skip degenerate", path, true, false);
5593 debugster("skip degenerate if exact", path, true, true);
5594 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005595}
5596#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005597skip degenerate:
Cary Clark682c58d2018-05-16 07:07:07 -04005598kMove_Verb {20, 20},
5599kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5600kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005601
5602skip degenerate if exact:
Cary Clark682c58d2018-05-16 07:07:07 -04005603kMove_Verb {20, 20},
5604kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5605kMove_Verb {30, 30},
5606kLine_Verb {30, 30}, {30.00001, 30},
5607kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005608
5609skip none:
Cary Clark682c58d2018-05-16 07:07:07 -04005610kMove_Verb {10, 10},
5611kMove_Verb {20, 20},
5612kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5613kMove_Verb {1, 1},
5614kClose_Verb {1, 1},
5615kMove_Verb {30, 30},
5616kLine_Verb {30, 30}, {30, 30},
5617kMove_Verb {30, 30},
5618kLine_Verb {30, 30}, {30.00001, 30},
5619kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005620##
5621##
5622
Cary Clark682c58d2018-05-16 07:07:07 -04005623#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
Cary Clark8032b982017-07-28 11:04:54 -04005624
5625##
5626
5627#Method SkScalar conicWeight() const
5628
5629 Returns Conic_Weight if next() returned kConic_Verb.
5630
5631 If next() has not been called, or next() did not return kConic_Verb,
5632 result is undefined.
5633
Cary Clark73fa9722017-08-29 17:36:51 -04005634 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005635
5636 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005637 void draw(SkCanvas* canvas) {
5638 SkPath path;
5639 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005640 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005641 SkPoint p[4];
5642 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5643 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5644 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5645 p[2].fX, p[2].fY);
5646 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005647 }
5648 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005649first verb is move
5650next verb is conic
5651conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005652conic weight: 0.5
5653 ##
5654 ##
5655
5656 #SeeAlso Conic_Weight
5657
5658##
5659
5660#Method bool isCloseLine() const
Cary Clark682c58d2018-05-16 07:07:07 -04005661#Line # returns if Line was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005662 Returns true if last kLine_Verb returned by next() was generated
5663 by kClose_Verb. When true, the end point returned by next() is
5664 also the start point of Contour.
5665
5666 If next() has not been called, or next() did not return kLine_Verb,
5667 result is undefined.
5668
Cary Clark73fa9722017-08-29 17:36:51 -04005669 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005670
5671 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005672void draw(SkCanvas* canvas) {
5673 SkPath path;
5674 path.moveTo(6, 7);
5675 path.conicTo(1, 2, 3, 4, .5f);
5676 path.close();
Cary Clark682c58d2018-05-16 07:07:07 -04005677 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005678 SkPoint p[4];
5679 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5680 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5681 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5682 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5683 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5684 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5685 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005686}
5687 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040056881st verb is move
5689moveTo point: {6,7}
56902nd verb is conic
56913rd verb is line
5692line points: {3,4}, {6,7}
5693line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040056944th verb is close
5695 ##
5696 ##
5697
5698 #SeeAlso close()
5699##
5700
5701#Method bool isClosedContour() const
Cary Clark682c58d2018-05-16 07:07:07 -04005702#Line # returns if Contour has kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005703Returns true if subsequent calls to next() return kClose_Verb before returning
5704kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5705Iter may have been initialized with force close set to true.
5706
Cary Clark73fa9722017-08-29 17:36:51 -04005707#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005708
5709#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005710void draw(SkCanvas* canvas) {
5711 for (bool forceClose : { false, true } ) {
5712 SkPath path;
5713 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005714 SkPath::Iter iter(path, forceClose);
Cary Clark73fa9722017-08-29 17:36:51 -04005715 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5716 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5717 path.close();
5718 iter.setPath(path, forceClose);
5719 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5720 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5721 }
Cary Clark8032b982017-07-28 11:04:54 -04005722}
5723#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005724without close(), forceClose is false: isClosedContour returns false
5725with close(), forceClose is false: isClosedContour returns true
5726without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005727with close(), forceClose is true : isClosedContour returns true
5728##
5729##
5730
5731#SeeAlso Iter(const SkPath& path, bool forceClose)
5732
5733##
Cary Clark73fa9722017-08-29 17:36:51 -04005734
5735#Class Iter ##
5736
Cary Clark8032b982017-07-28 11:04:54 -04005737#Class RawIter
Cary Clark682c58d2018-05-16 07:07:07 -04005738#Line # raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005739
Cary Clark73fa9722017-08-29 17:36:51 -04005740#Code
5741 class RawIter {
5742 public:
5743 RawIter();
5744 RawIter(const SkPath& path);
5745 void setPath(const SkPath& path);
5746 Verb next(SkPoint pts[4]);
5747 Verb peek() const;
5748 SkScalar conicWeight() const;
5749 }
5750##
5751
Cary Clark137b8742018-05-30 09:21:49 -04005752Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5753Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5754
Cary Clark8032b982017-07-28 11:04:54 -04005755 #Method RawIter()
Cary Clark682c58d2018-05-16 07:07:07 -04005756 #Line # constructs empty Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005757
5758 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
Cary Clark78c110e2018-02-09 16:49:09 -05005759 Call setPath to initialize SkPath::Iter at a later time.
Cary Clark8032b982017-07-28 11:04:54 -04005760
Cary Clark73fa9722017-08-29 17:36:51 -04005761 #Return RawIter of empty Path ##
5762
5763 #NoExample
5764 ##
5765 ##
Cary Clark8032b982017-07-28 11:04:54 -04005766
5767 #Method RawIter(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005768 #Line # constructs with Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005769
5770
5771 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5772
Cary Clark73fa9722017-08-29 17:36:51 -04005773 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005774
Cary Clark73fa9722017-08-29 17:36:51 -04005775 #Return RawIter of path ##
5776
5777 #NoExample
5778 ##
5779 ##
Cary Clark8032b982017-07-28 11:04:54 -04005780
5781 #Method void setPath(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005782 #Line # sets Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005783
Cary Clark78c110e2018-02-09 16:49:09 -05005784 Sets SkPath::Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
Cary Clark8032b982017-07-28 11:04:54 -04005785
Cary Clark73fa9722017-08-29 17:36:51 -04005786 #Param path Path to iterate ##
5787
5788 #NoExample
5789 ##
5790 ##
Cary Clark8032b982017-07-28 11:04:54 -04005791
5792 #Method Verb next(SkPoint pts[4])
Cary Clark682c58d2018-05-16 07:07:07 -04005793 #Line # returns next Verb and associated Points ##
Cary Clark8032b982017-07-28 11:04:54 -04005794 Returns next Verb in Verb_Array, and advances RawIter.
5795 When Verb_Array is exhausted, returns kDone_Verb.
5796 Zero to four Points are stored in pts, depending on the returned Verb.
5797
Cary Clarka523d2d2017-08-30 08:58:10 -04005798 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005799
Cary Clark73fa9722017-08-29 17:36:51 -04005800 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005801
5802 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005803 void draw(SkCanvas* canvas) {
5804 SkPath path;
5805 path.moveTo(50, 60);
5806 path.quadTo(10, 20, 30, 40);
5807 path.close();
5808 path.lineTo(30, 30);
5809 path.conicTo(1, 2, 3, 4, .5f);
5810 path.cubicTo(-1, -2, -3, -4, -5, -6);
5811 SkPath::RawIter iter(path);
5812 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5813 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5814 SkPath::Verb verb;
5815 do {
5816 SkPoint points[4];
5817 verb = iter.next(points);
5818 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5819 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5820 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5821 }
5822 if (SkPath::kConic_Verb == verb) {
5823 SkDebugf("weight = %g", iter.conicWeight());
5824 }
5825 SkDebugf("\n");
5826 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005827 }
5828 #StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005829 kMove_Verb {50, 60},
5830 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5831 kClose_Verb {50, 60},
5832 kMove_Verb {50, 60},
5833 kLine_Verb {50, 60}, {30, 30},
Cary Clark73fa9722017-08-29 17:36:51 -04005834 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005835 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
5836 kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005837 ##
5838 ##
5839
5840 #SeeAlso peek()
5841
Cary Clark73fa9722017-08-29 17:36:51 -04005842 ##
Cary Clark8032b982017-07-28 11:04:54 -04005843
5844 #Method Verb peek() const
Cary Clark682c58d2018-05-16 07:07:07 -04005845 #Line # returns next Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005846 Returns next Verb, but does not advance RawIter.
5847
Cary Clark73fa9722017-08-29 17:36:51 -04005848 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005849
5850 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005851 SkPath path;
5852 path.quadTo(10, 20, 30, 40);
5853 path.conicTo(1, 2, 3, 4, .5f);
5854 path.cubicTo(1, 2, 3, 4, .5, 6);
5855 SkPath::RawIter iter(path);
5856 SkPath::Verb verb, peek = iter.peek();
5857 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5858 do {
5859 SkPoint points[4];
5860 verb = iter.next(points);
5861 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5862 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005863 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005864 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5865 #StdOut
5866 #Volatile
5867 peek Move == verb Move
5868 peek Quad == verb Quad
5869 peek Conic == verb Conic
5870 peek Cubic == verb Cubic
5871 peek Done == verb Done
5872 peek Done == verb Done
5873 ##
Cary Clark8032b982017-07-28 11:04:54 -04005874 ##
5875
5876 #Bug 6832
Cary Clark682c58d2018-05-16 07:07:07 -04005877 StdOut is not really volatile, it just produces the wrong result.
Cary Clark8032b982017-07-28 11:04:54 -04005878 A simple fix changes the output of hairlines and needs to be
5879 investigated to see if the change is correct or not.
Cary Clark682c58d2018-05-16 07:07:07 -04005880 see change 21340 (abandoned for now)
Cary Clark8032b982017-07-28 11:04:54 -04005881
5882 #SeeAlso next()
5883
Cary Clark73fa9722017-08-29 17:36:51 -04005884 ##
Cary Clark8032b982017-07-28 11:04:54 -04005885
Cary Clark73fa9722017-08-29 17:36:51 -04005886 #Method SkScalar conicWeight() const
Cary Clark682c58d2018-05-16 07:07:07 -04005887 #Line # returns Conic_Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04005888
Cary Clark8032b982017-07-28 11:04:54 -04005889 Returns Conic_Weight if next() returned kConic_Verb.
5890
5891 If next() has not been called, or next() did not return kConic_Verb,
5892 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04005893
5894 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005895
5896 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005897 void draw(SkCanvas* canvas) {
5898 SkPath path;
5899 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005900 SkPath::RawIter iter(path);
Cary Clark73fa9722017-08-29 17:36:51 -04005901 SkPoint p[4];
5902 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5903 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5904 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5905 p[2].fX, p[2].fY);
5906 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005907 }
5908 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005909 first verb is move
5910 next verb is conic
5911 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005912 conic weight: 0.5
5913 ##
5914 ##
5915
5916 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04005917
5918 ##
5919
5920#Class RawIter ##
5921
5922#Class SkPath ##
5923
5924#Topic Path ##
Cary Clark4855f782018-02-06 09:41:53 -05005925