blob: fdb755e9f7e55c3518ba95b2435a6b8857d0e806 [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()
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400398#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -0500399#Line # constructs with default values ##
Cary Clarkd2ca79c2018-08-10 13:09:13 -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)
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400420#In Constructor
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
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400518#SeeAlso swap SkPath(const SkPath& path)
Cary Clark73fa9722017-08-29 17:36:51 -0400519
520##
521
522# ------------------------------------------------------------------------------
523
524#Method bool operator==(const SkPath& a, const SkPath& b)
525
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400526#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
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400563#SeeAlso operator!=(const SkPath& a, const SkPath& b) operator=(const SkPath& path)
564
Cary Clark73fa9722017-08-29 17:36:51 -0400565##
566
567# ------------------------------------------------------------------------------
568
Cary Clark682c58d2018-05-16 07:07:07 -0400569#Method bool operator!=(const SkPath& a, const SkPath& b)
Cary Clark73fa9722017-08-29 17:36:51 -0400570
Cary Clarkab2621d2018-01-30 10:08:57 -0500571#Line # compares paths for inequality ##
Cary Clark73fa9722017-08-29 17:36:51 -0400572Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
573are not equivalent.
574
575#Param a Path to compare ##
576#Param b Path to compare ##
577
578#Return true if Path pair are not equivalent ##
579
580#Example
581#Description
582Path pair are equal though their convexity is not equal.
583##
584void draw(SkCanvas* canvas) {
585 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
586 SkDebugf("%s one %c= two\n", prefix, a != b ? '!' : '=');
587 };
588 SkPath one;
589 SkPath two;
590 debugster("empty", one, two);
591 one.addRect({10, 20, 30, 40});
592 two.addRect({10, 20, 30, 40});
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400593 debugster("add rect", one, two);
Cary Clark73fa9722017-08-29 17:36:51 -0400594 one.setConvexity(SkPath::kConcave_Convexity);
595 debugster("setConvexity", one, two);
596 SkDebugf("convexity %c=\n", one.getConvexity() == two.getConvexity() ? '=' : '!');
597}
598#StdOut
599empty one == two
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400600add rect one == two
Cary Clark73fa9722017-08-29 17:36:51 -0400601setConvexity one == two
602convexity !=
603##
604##
605
606##
607
608# ------------------------------------------------------------------------------
609
Cary Clark4855f782018-02-06 09:41:53 -0500610#Subtopic Property
611#Populate
612#Line # metrics and attributes ##
613##
Cary Clark73fa9722017-08-29 17:36:51 -0400614
Cary Clark4855f782018-02-06 09:41:53 -0500615#Method bool isInterpolatable(const SkPath& compare) const
616#In Property
617#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500618#Line # returns if pair contains equal counts of Verb_Array and Weights ##
Cary Clark80247e52018-07-11 16:18:41 -0400619Returns true if Paths contain equal Verbs and equal Weights.
Cary Clark73fa9722017-08-29 17:36:51 -0400620If Paths contain one or more Conics, the Weights must match.
621
622conicTo may add different Verbs depending on Conic_Weight, so it is not
Cary Clarkce101242017-09-01 15:51:02 -0400623trivial to interpolate a pair of Paths containing Conics with different
Cary Clark682c58d2018-05-16 07:07:07 -0400624Conic_Weight values.
Cary Clark73fa9722017-08-29 17:36:51 -0400625
626#Param compare Path to compare ##
627
628#Return true if Paths Verb_Array and Weights are equivalent ##
629
630#Example
631 SkPath path, path2;
632 path.moveTo(20, 20);
633 path.lineTo(40, 40);
634 path.lineTo(20, 20);
635 path.lineTo(40, 40);
636 path.close();
637 path2.addRect({20, 20, 40, 40});
638 SkDebugf("paths are " "%s" "interpolatable", path.isInterpolatable(path2) ? "" : "not ");
639#StdOut
640paths are interpolatable
641##
642##
643
644#SeeAlso isInterpolatable
645
646##
647
648# ------------------------------------------------------------------------------
649
Cary Clark4855f782018-02-06 09:41:53 -0500650#Subtopic Interpolate
651#Populate
652#Line # weighted average of Path pair ##
653##
Cary Clark73fa9722017-08-29 17:36:51 -0400654
Cary Clark4855f782018-02-06 09:41:53 -0500655#Method bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const
656#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500657#Line # interpolates between Path pair ##
Cary Clark80247e52018-07-11 16:18:41 -0400658Interpolates between Paths with Point_Array of equal size.
Cary Clark61dfc3a2018-01-03 08:37:53 -0500659Copy Verb_Array and Weights to out, and set out Point_Array to a weighted
660average of this Point_Array and ending Point_Array, using the formula:
Cary Clark2be81cf2018-09-13 12:04:30 -0400661#Formula # (Path Point * weight) + ending Point * (1 - weight) ##.
Cary Clark73fa9722017-08-29 17:36:51 -0400662
Cary Clark682c58d2018-05-16 07:07:07 -0400663weight is most useful when between zero (ending Point_Array) and
664one (this Point_Array); will work with values outside of this
Cary Clark73fa9722017-08-29 17:36:51 -0400665range.
666
667interpolate() returns false and leaves out unchanged if Point_Array is not
Cary Clark682c58d2018-05-16 07:07:07 -0400668the same size as ending Point_Array. Call isInterpolatable to check Path
Cary Clark73fa9722017-08-29 17:36:51 -0400669compatibility prior to calling interpolate().
670
671#Param ending Point_Array averaged with this Point_Array ##
Cary Clark682c58d2018-05-16 07:07:07 -0400672#Param weight contribution of this Point_Array, and
673 one minus contribution of ending Point_Array
Cary Clark73fa9722017-08-29 17:36:51 -0400674##
675#Param out Path replaced by interpolated averages ##
676
677#Return true if Paths contain same number of Points ##
678
679#Example
680#Height 60
681void draw(SkCanvas* canvas) {
682 SkPaint paint;
683 paint.setAntiAlias(true);
684 paint.setStyle(SkPaint::kStroke_Style);
685 SkPath path, path2;
686 path.moveTo(20, 20);
687 path.lineTo(40, 40);
688 path.lineTo(20, 40);
689 path.lineTo(40, 20);
690 path.close();
691 path2.addRect({20, 20, 40, 40});
692 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
693 SkPath interp;
694 path.interpolate(path2, i, &interp);
695 canvas->drawPath(interp, paint);
696 canvas->translate(30, 0);
697 }
698}
699##
700
701#SeeAlso isInterpolatable
702
703##
704
705# ------------------------------------------------------------------------------
706
Cary Clark682c58d2018-05-16 07:07:07 -0400707#Method bool unique() const
Cary Clark4855f782018-02-06 09:41:53 -0500708#Deprecated soon
709Only valid for Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -0400710##
711
712# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400713#Subtopic Fill_Type
Cary Clark682c58d2018-05-16 07:07:07 -0400714#Line # fill rule, normal and inverted ##
Cary Clark8032b982017-07-28 11:04:54 -0400715
Cary Clark73fa9722017-08-29 17:36:51 -0400716#Enum FillType
Cary Clark08895c42018-02-01 09:37:32 -0500717#Line # sets winding rule and inverse fill ##
Cary Clark73fa9722017-08-29 17:36:51 -0400718
719#Code
720 enum FillType {
Cary Clark682c58d2018-05-16 07:07:07 -0400721 kWinding_FillType,
722 kEvenOdd_FillType,
723 kInverseWinding_FillType,
724 kInverseEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400725 };
726##
Cary Clark8032b982017-07-28 11:04:54 -0400727
Cary Clark682c58d2018-05-16 07:07:07 -0400728Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
Cary Clark8032b982017-07-28 11:04:54 -0400729fills if the sum of Contour edges is not zero, where clockwise edges add one, and
730counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
Cary Clark682c58d2018-05-16 07:07:07 -0400731number of Contour edges is odd. Each Fill_Type has an inverse variant that
Cary Clark8032b982017-07-28 11:04:54 -0400732reverses the rule:
733kInverseWinding_FillType fills where the sum of Contour edges is zero;
734kInverseEvenOdd_FillType fills where the number of Contour edges is even.
735
736#Example
737#Height 100
738#Description
739The top row has two clockwise rectangles. The second row has one clockwise and
740one counterclockwise rectangle. The even-odd variants draw the same. The
741winding variants draw the top rectangle overlap, which has a winding of 2, the
742same as the outer parts of the top rectangles, which have a winding of 1.
743##
Cary Clark73fa9722017-08-29 17:36:51 -0400744void draw(SkCanvas* canvas) {
745 SkPath path;
746 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
747 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
748 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
749 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
750 SkPaint strokePaint;
751 strokePaint.setStyle(SkPaint::kStroke_Style);
752 SkRect clipRect = {0, 0, 51, 100};
753 canvas->drawPath(path, strokePaint);
754 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400755 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400756 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
757 canvas->translate(51, 0);
758 canvas->save();
759 canvas->clipRect(clipRect);
760 path.setFillType(fillType);
761 canvas->drawPath(path, fillPaint);
762 canvas->restore();
763 }
Cary Clark8032b982017-07-28 11:04:54 -0400764}
765##
Cary Clark73fa9722017-08-29 17:36:51 -0400766
767#Const kWinding_FillType 0
Cary Clark682c58d2018-05-16 07:07:07 -0400768#Line # is enclosed by a non-zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400769##
770#Const kEvenOdd_FillType 1
Cary Clark682c58d2018-05-16 07:07:07 -0400771#Line # is enclosed by an odd number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400772##
773#Const kInverseWinding_FillType 2
Cary Clark682c58d2018-05-16 07:07:07 -0400774#Line # is enclosed by a zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400775##
776#Const kInverseEvenOdd_FillType 3
Cary Clark682c58d2018-05-16 07:07:07 -0400777#Line # is enclosed by an even number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400778##
779
780#Example
781#Height 230
782void draw(SkCanvas* canvas) {
783 SkPath path;
784 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
785 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
786 SkPaint strokePaint;
787 strokePaint.setStyle(SkPaint::kStroke_Style);
788 SkRect clipRect = {0, 0, 128, 128};
789 canvas->drawPath(path, strokePaint);
790 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
791 SkPaint textPaint;
792 textPaint.setAntiAlias(true);
793 textPaint.setTextAlign(SkPaint::kCenter_Align);
794 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
795 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
796 textPaint.setTextSize(18);
797 canvas->translate(0, 128);
798 canvas->scale(.5f, .5f);
799 canvas->drawString("inverse", 384, 150, textPaint);
800 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400801 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400802 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
803 canvas->save();
804 canvas->clipRect(clipRect);
805 path.setFillType(fillType);
806 canvas->drawPath(path, fillPaint);
807 canvas->restore();
808 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
809 canvas->translate(128, 0);
810 }
811}
812##
813
814#SeeAlso SkPaint::Style Direction getFillType setFillType
815
816##
817
818# ------------------------------------------------------------------------------
819
Cary Clark682c58d2018-05-16 07:07:07 -0400820#Method FillType getFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400821
Cary Clarkab2621d2018-01-30 10:08:57 -0500822#In Fill_Type
823#Line # returns Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400824Returns FillType, the rule used to fill Path. FillType of a new Path is
825kWinding_FillType.
826
Cary Clark682c58d2018-05-16 07:07:07 -0400827#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
828kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400829##
830
831#Example
832 SkPath path;
833 SkDebugf("default path fill type is %s\n",
834 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
Cary Clark682c58d2018-05-16 07:07:07 -0400835 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
Cary Clark73fa9722017-08-29 17:36:51 -0400836 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
837 "kInverseEvenOdd_FillType");
838#StdOut
839default path fill type is kWinding_FillType
840##
841##
842
843#SeeAlso FillType setFillType isInverseFillType
844
845##
846
847# ------------------------------------------------------------------------------
848
Cary Clark682c58d2018-05-16 07:07:07 -0400849#Method void setFillType(FillType ft)
Cary Clark73fa9722017-08-29 17:36:51 -0400850
Cary Clarkab2621d2018-01-30 10:08:57 -0500851#In Fill_Type
852#Line # sets Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400853Sets FillType, the rule used to fill Path. While there is no check
854that ft is legal, values outside of FillType are not supported.
855
Cary Clark682c58d2018-05-16 07:07:07 -0400856#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
857kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400858##
859
860#Example
861#Description
862If empty Path is set to inverse FillType, it fills all pixels.
863##
864#Height 64
865 SkPath path;
866 path.setFillType(SkPath::kInverseWinding_FillType);
867 SkPaint paint;
868 paint.setColor(SK_ColorBLUE);
869 canvas->drawPath(path, paint);
870##
871
872#SeeAlso FillType getFillType toggleInverseFillType
873
874##
875
876# ------------------------------------------------------------------------------
877
Cary Clark682c58d2018-05-16 07:07:07 -0400878#Method bool isInverseFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400879
Cary Clarkab2621d2018-01-30 10:08:57 -0500880#In Fill_Type
881#Line # returns if Fill_Type fills outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -0400882Returns if FillType describes area outside Path geometry. The inverse fill area
883extends indefinitely.
884
885#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType ##
886
887#Example
888 SkPath path;
889 SkDebugf("default path fill type is inverse: %s\n",
890 path.isInverseFillType() ? "true" : "false");
891#StdOut
892default path fill type is inverse: false
893##
894##
895
896#SeeAlso FillType getFillType setFillType toggleInverseFillType
897
898##
899
900# ------------------------------------------------------------------------------
901
Cary Clark682c58d2018-05-16 07:07:07 -0400902#Method void toggleInverseFillType()
Cary Clark73fa9722017-08-29 17:36:51 -0400903
Cary Clarkab2621d2018-01-30 10:08:57 -0500904#In Fill_Type
905#Line # toggles Fill_Type between inside and outside geometry ##
Cary Clark80247e52018-07-11 16:18:41 -0400906Replaces FillType with its inverse. The inverse of FillType describes the area
Cary Clark73fa9722017-08-29 17:36:51 -0400907unmodified by the original FillType.
908
Cary Clark682c58d2018-05-16 07:07:07 -0400909#Table
Cary Clark73fa9722017-08-29 17:36:51 -0400910#Legend
Cary Clark682c58d2018-05-16 07:07:07 -0400911# FillType # toggled FillType ##
Cary Clark73fa9722017-08-29 17:36:51 -0400912##
913# kWinding_FillType # kInverseWinding_FillType ##
914# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
915# kInverseWinding_FillType # kWinding_FillType ##
916# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
917##
918
919#Example
920#Description
921Path drawn normally and through its inverse touches every pixel once.
922##
923#Height 100
924SkPath path;
925SkPaint paint;
926paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -0400927paint.setTextSize(80);
928paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -0400929canvas->drawPath(path, paint);
930path.toggleInverseFillType();
931paint.setColor(SK_ColorGREEN);
932canvas->drawPath(path, paint);
933##
934
935#SeeAlso FillType getFillType setFillType isInverseFillType
936
937##
938
Cary Clark8032b982017-07-28 11:04:54 -0400939#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400940
941# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400942
943#Subtopic Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500944#Line # if Path is concave or convex ##
Cary Clark73fa9722017-08-29 17:36:51 -0400945
946#Enum Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500947#Line # returns if Path is convex or concave ##
Cary Clark73fa9722017-08-29 17:36:51 -0400948
949#Code
Cary Clark884dd7d2017-10-11 10:37:52 -0400950 enum Convexity : uint8_t {
Cary Clark682c58d2018-05-16 07:07:07 -0400951 kUnknown_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400952 kConvex_Convexity,
Cary Clark682c58d2018-05-16 07:07:07 -0400953 kConcave_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400954 };
955##
956
Cary Clark682c58d2018-05-16 07:07:07 -0400957Path is convex if it contains one Contour and Contour loops no more than
958360 degrees, and Contour angles all have same Direction. Convex Path
Cary Clark8032b982017-07-28 11:04:54 -0400959may have better performance and require fewer resources on GPU_Surface.
960
Cary Clark73fa9722017-08-29 17:36:51 -0400961Path is concave when either at least one Direction change is clockwise and
962another is counterclockwise, or the sum of the changes in Direction is not 360
963degrees.
964
Cary Clark682c58d2018-05-16 07:07:07 -0400965Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
Cary Clark73fa9722017-08-29 17:36:51 -0400966if needed by destination Surface.
967
968#Const kUnknown_Convexity 0
Cary Clark682c58d2018-05-16 07:07:07 -0400969#Line # indicates Convexity has not been determined ##
Cary Clark73fa9722017-08-29 17:36:51 -0400970##
971#Const kConvex_Convexity 1
Cary Clark682c58d2018-05-16 07:07:07 -0400972#Line # one Contour made of a simple geometry without indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400973##
974#Const kConcave_Convexity 2
Cary Clark682c58d2018-05-16 07:07:07 -0400975#Line # more than one Contour, or a geometry with indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400976##
977
978#Example
979void draw(SkCanvas* canvas) {
980 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400981 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400982 const char* labels[] = { "unknown", "convex", "concave" };
983 for (SkScalar x : { 40, 100 } ) {
984 SkPath path;
985 quad[0].fX = x;
986 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
987 canvas->drawPath(path, paint);
988 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
989 canvas->translate(100, 100);
990 }
991}
992##
993
994#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
995
996#Enum Convexity ##
997
Cary Clark682c58d2018-05-16 07:07:07 -0400998#Method Convexity getConvexity() const
Cary Clark73fa9722017-08-29 17:36:51 -0400999
Cary Clarkab2621d2018-01-30 10:08:57 -05001000#In Convexity
1001#Line # returns geometry convexity, computing if necessary ##
Cary Clark682c58d2018-05-16 07:07:07 -04001002Computes Convexity if required, and returns stored value.
Cary Clark73fa9722017-08-29 17:36:51 -04001003Convexity is computed if stored value is kUnknown_Convexity,
1004or if Path has been altered since Convexity was computed or set.
1005
Cary Clarka523d2d2017-08-30 08:58:10 -04001006#Return computed or stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001007
1008#Example
1009void draw(SkCanvas* canvas) {
1010 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001011 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001012 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1013 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1014 SkPath path;
1015 debugster("initial", path);
1016 path.lineTo(50, 0);
1017 debugster("first line", path);
1018 path.lineTo(50, 50);
1019 debugster("second line", path);
1020 path.lineTo(100, 50);
1021 debugster("third line", path);
1022}
1023##
1024
1025#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
1026
1027##
1028
1029# ------------------------------------------------------------------------------
1030
Cary Clark682c58d2018-05-16 07:07:07 -04001031#Method Convexity getConvexityOrUnknown() const
Cary Clark73fa9722017-08-29 17:36:51 -04001032
Cary Clarkab2621d2018-01-30 10:08:57 -05001033#In Convexity
1034#Line # returns geometry convexity if known ##
Cary Clark682c58d2018-05-16 07:07:07 -04001035Returns last computed Convexity, or kUnknown_Convexity if
Cary Clark73fa9722017-08-29 17:36:51 -04001036Path has been altered since Convexity was computed or set.
1037
Cary Clarka523d2d2017-08-30 08:58:10 -04001038#Return stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001039
1040#Example
1041#Description
1042Convexity is unknown unless getConvexity is called without a subsequent call
1043that alters the path.
1044##
1045void draw(SkCanvas* canvas) {
1046 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001047 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001048 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
1049 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
1050 SkPath path;
1051 debugster("initial", path);
1052 path.lineTo(50, 0);
1053 debugster("first line", path);
1054 path.getConvexity();
1055 path.lineTo(50, 50);
1056 debugster("second line", path);
1057 path.lineTo(100, 50);
1058 path.getConvexity();
1059 debugster("third line", path);
1060}
1061##
1062
1063#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
1064
1065##
1066
1067# ------------------------------------------------------------------------------
1068
1069#Method void setConvexity(Convexity convexity)
1070
Cary Clarkab2621d2018-01-30 10:08:57 -05001071#In Convexity
1072#Line # sets if geometry is convex to avoid future computation ##
Cary Clark73fa9722017-08-29 17:36:51 -04001073Stores convexity so that it is later returned by getConvexity or getConvexityOrUnknown.
1074convexity may differ from getConvexity, although setting an incorrect value may
1075cause incorrect or inefficient drawing.
1076
1077If convexity is kUnknown_Convexity: getConvexity will
1078compute Convexity, and getConvexityOrUnknown will return kUnknown_Convexity.
1079
1080If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity
1081and getConvexityOrUnknown will return convexity until the path is
1082altered.
1083
1084#Param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity ##
1085
1086#Example
1087void draw(SkCanvas* canvas) {
1088 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001089 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001090 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1091 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
Cary Clark682c58d2018-05-16 07:07:07 -04001092 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001093 SkPath path;
1094 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1095 debugster("initial", path);
1096 path.setConvexity(SkPath::kConcave_Convexity);
1097 debugster("after forcing concave", path);
1098 path.setConvexity(SkPath::kUnknown_Convexity);
1099 debugster("after forcing unknown", path);
1100}
1101##
1102
1103#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
1104
1105##
1106
1107# ------------------------------------------------------------------------------
1108
Cary Clark682c58d2018-05-16 07:07:07 -04001109#Method bool isConvex() const
Cary Clark73fa9722017-08-29 17:36:51 -04001110
Cary Clarkab2621d2018-01-30 10:08:57 -05001111#In Convexity
1112#Line # returns if geometry is convex ##
Cary Clark73fa9722017-08-29 17:36:51 -04001113Computes Convexity if required, and returns true if value is kConvex_Convexity.
1114If setConvexity was called with kConvex_Convexity or kConcave_Convexity, and
1115the path has not been altered, Convexity is not recomputed.
1116
1117#Return true if Convexity stored or computed is kConvex_Convexity ##
1118
1119#Example
1120#Description
Cary Clark682c58d2018-05-16 07:07:07 -04001121Concave shape is erroneously considered convex after a forced call to
Cary Clark73fa9722017-08-29 17:36:51 -04001122setConvexity.
1123##
1124void draw(SkCanvas* canvas) {
1125 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -04001126 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001127 for (SkScalar x : { 40, 100 } ) {
1128 SkPath path;
1129 quad[0].fX = x;
1130 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1131 path.setConvexity(SkPath::kConvex_Convexity);
1132 canvas->drawPath(path, paint);
1133 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
1134 canvas->translate(100, 100);
1135 }
1136}
1137##
1138
1139#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
1140
1141##
1142
Cary Clark73fa9722017-08-29 17:36:51 -04001143#Subtopic Convexity ##
1144
1145# ------------------------------------------------------------------------------
1146
Mike Reed0c3137c2018-02-20 13:57:05 -05001147#Method bool isOval(SkRect* bounds) const
Cary Clark4855f782018-02-06 09:41:53 -05001148#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001149#Line # returns if describes Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04001150
Mike Reed0c3137c2018-02-20 13:57:05 -05001151Returns true if this path is recognized as an oval or circle.
Cary Clark73fa9722017-08-29 17:36:51 -04001152
Mike Reed0c3137c2018-02-20 13:57:05 -05001153bounds receives bounds of Oval.
Cary Clark73fa9722017-08-29 17:36:51 -04001154
Mike Reed0c3137c2018-02-20 13:57:05 -05001155bounds is unmodified if Oval is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001156
Mike Reed0c3137c2018-02-20 13:57:05 -05001157#Param bounds storage for bounding Rect of Oval; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001158
Mike Reed0c3137c2018-02-20 13:57:05 -05001159#Return true if Path is recognized as an oval or circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04001160
1161#Example
1162void draw(SkCanvas* canvas) {
1163 SkPaint paint;
1164 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001165 path.addOval({20, 20, 220, 220});
Cary Clark73fa9722017-08-29 17:36:51 -04001166 SkRect bounds;
Mike Reed0c3137c2018-02-20 13:57:05 -05001167 if (path.isOval(&bounds)) {
1168 paint.setColor(0xFF9FBFFF);
1169 canvas->drawRect(bounds, paint);
1170 }
Cary Clark73fa9722017-08-29 17:36:51 -04001171 paint.setColor(0x3f000000);
1172 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001173}
1174##
1175
1176#SeeAlso Oval addCircle addOval
1177
1178##
1179
1180# ------------------------------------------------------------------------------
1181
Mike Reed0c3137c2018-02-20 13:57:05 -05001182#Method bool isRRect(SkRRect* rrect) const
Cary Clark4855f782018-02-06 09:41:53 -05001183#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001184#Line # returns if describes Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001185
Mike Reed0c3137c2018-02-20 13:57:05 -05001186Returns true if this path is recognized as a SkRRect (but not an oval/circle or rect).
Cary Clark73fa9722017-08-29 17:36:51 -04001187
1188rrect receives bounds of Round_Rect.
Cary Clark73fa9722017-08-29 17:36:51 -04001189
Mike Reed0c3137c2018-02-20 13:57:05 -05001190rrect is unmodified if Round_Rect is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001191
1192#Param rrect storage for bounding Rect of Round_Rect; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001193
Cary Clarkce101242017-09-01 15:51:02 -04001194#Return true if Path contains only Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001195
1196#Example
Cary Clarkce101242017-09-01 15:51:02 -04001197#Description
Mike Reed0c3137c2018-02-20 13:57:05 -05001198Draw rounded rectangle and its bounds.
Cary Clarkce101242017-09-01 15:51:02 -04001199##
Cary Clark73fa9722017-08-29 17:36:51 -04001200void draw(SkCanvas* canvas) {
1201 SkPaint paint;
1202 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001203 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50));
Cary Clark73fa9722017-08-29 17:36:51 -04001204 SkRRect rrect;
Mike Reed0c3137c2018-02-20 13:57:05 -05001205 if (path.isRRect(&rrect)) {
1206 const SkRect& bounds = rrect.rect();
1207 paint.setColor(0xFF9FBFFF);
1208 canvas->drawRect(bounds, paint);
1209 }
Cary Clark73fa9722017-08-29 17:36:51 -04001210 paint.setColor(0x3f000000);
1211 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001212}
1213##
1214
Cary Clark682c58d2018-05-16 07:07:07 -04001215#SeeAlso Round_Rect addRoundRect addRRect
Cary Clark73fa9722017-08-29 17:36:51 -04001216
1217##
1218
1219# ------------------------------------------------------------------------------
1220
Cary Clark0251b1b2018-08-15 15:14:55 -04001221#Method SkPath& reset()
Cary Clark4855f782018-02-06 09:41:53 -05001222#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001223#Line # removes Verb_Array, Point_Array, and Weights; frees memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001224Sets Path to its initial state.
Cary Clark73fa9722017-08-29 17:36:51 -04001225Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1226Internal storage associated with Path is released.
1227
Cary Clark0251b1b2018-08-15 15:14:55 -04001228#Return reference to Path ##
1229
Cary Clark73fa9722017-08-29 17:36:51 -04001230#Example
1231 SkPath path1, path2;
1232 path1.setFillType(SkPath::kInverseWinding_FillType);
1233 path1.addRect({10, 20, 30, 40});
1234 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1235 path1.reset();
1236 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1237##
1238
1239#SeeAlso rewind()
1240
1241##
1242
1243# ------------------------------------------------------------------------------
1244
Cary Clark0251b1b2018-08-15 15:14:55 -04001245#Method SkPath& rewind()
Cary Clark4855f782018-02-06 09:41:53 -05001246#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001247#Line # removes Verb_Array, Point_Array, and Weights, keeping memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001248Sets Path to its initial state, preserving internal storage.
Cary Clark73fa9722017-08-29 17:36:51 -04001249Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1250Internal storage associated with Path is retained.
1251
1252Use rewind() instead of reset() if Path storage will be reused and performance
Cary Clark682c58d2018-05-16 07:07:07 -04001253is critical.
Cary Clark73fa9722017-08-29 17:36:51 -04001254
Cary Clark0251b1b2018-08-15 15:14:55 -04001255#Return reference to Path ##
1256
Cary Clark73fa9722017-08-29 17:36:51 -04001257#Example
1258#Description
1259Although path1 retains its internal storage, it is indistinguishable from
1260a newly initialized path.
1261##
1262 SkPath path1, path2;
1263 path1.setFillType(SkPath::kInverseWinding_FillType);
1264 path1.addRect({10, 20, 30, 40});
1265 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1266 path1.rewind();
1267 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1268##
1269
1270#SeeAlso reset()
1271
1272##
1273
1274# ------------------------------------------------------------------------------
1275
Cary Clark682c58d2018-05-16 07:07:07 -04001276#Method bool isEmpty() const
Cary Clark4855f782018-02-06 09:41:53 -05001277#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001278#Line # returns if verb count is zero ##
Cary Clark80247e52018-07-11 16:18:41 -04001279Returns if Path is empty.
Cary Clark73fa9722017-08-29 17:36:51 -04001280Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
Cary Clarkd2ca79c2018-08-10 13:09:13 -04001281SkPath() constructs empty Path; reset() and rewind() make Path empty.
Cary Clark73fa9722017-08-29 17:36:51 -04001282
1283#Return true if the path contains no Verb array ##
1284
1285#Example
1286void draw(SkCanvas* canvas) {
1287 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1288 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
1289 };
1290 SkPath path;
1291 debugster("initial", path);
1292 path.moveTo(0, 0);
1293 debugster("after moveTo", path);
1294 path.rewind();
1295 debugster("after rewind", path);
1296 path.lineTo(0, 0);
1297 debugster("after lineTo", path);
1298 path.reset();
1299 debugster("after reset", path);
1300}
1301#StdOut
1302initial path is empty
1303after moveTo path is not empty
1304after rewind path is empty
1305after lineTo path is not empty
1306after reset path is empty
1307##
1308##
1309
1310#SeeAlso SkPath() reset() rewind()
1311
1312##
1313
1314# ------------------------------------------------------------------------------
1315
1316#Method bool isLastContourClosed() const
Cary Clark4855f782018-02-06 09:41:53 -05001317#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001318#Line # returns if final Contour forms a loop ##
Cary Clark80247e52018-07-11 16:18:41 -04001319Returns if Contour is closed.
Cary Clark73fa9722017-08-29 17:36:51 -04001320Contour is closed if Path Verb array was last modified by close(). When stroked,
Cary Clark682c58d2018-05-16 07:07:07 -04001321closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
Cary Clark73fa9722017-08-29 17:36:51 -04001322
1323#Return true if the last Contour ends with a kClose_Verb ##
1324
1325#Example
1326#Description
1327close() has no effect if Path is empty; isLastContourClosed() returns
1328false until Path has geometry followed by close().
1329##
1330void draw(SkCanvas* canvas) {
1331 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1332 SkDebugf("%s last contour is %s" "closed\n", prefix,
1333 path.isLastContourClosed() ? "" : "not ");
1334 };
1335 SkPath path;
1336 debugster("initial", path);
1337 path.close();
1338 debugster("after close", path);
1339 path.lineTo(0, 0);
1340 debugster("after lineTo", path);
1341 path.close();
1342 debugster("after close", path);
1343}
1344#StdOut
1345initial last contour is not closed
1346after close last contour is not closed
1347after lineTo last contour is not closed
1348after close last contour is closed
1349##
1350##
1351
1352#SeeAlso close()
1353
1354##
1355
1356# ------------------------------------------------------------------------------
1357
Cary Clark682c58d2018-05-16 07:07:07 -04001358#Method bool isFinite() const
Cary Clark4855f782018-02-06 09:41:53 -05001359#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001360#Line # returns if all Point values are finite ##
Cary Clark73fa9722017-08-29 17:36:51 -04001361Returns true for finite Point array values between negative SK_ScalarMax and
1362positive SK_ScalarMax. Returns false for any Point array value of
1363SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
1364
1365#Return true if all Point values are finite ##
1366
1367#Example
1368void draw(SkCanvas* canvas) {
1369 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1370 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1371 };
1372 SkPath path;
1373 debugster("initial", path);
1374 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1375 debugster("after line", path);
1376 SkMatrix matrix;
1377 matrix.setScale(2, 2);
1378 path.transform(matrix);
1379 debugster("after scale", path);
1380}
1381#StdOut
1382initial path is finite
1383after line path is finite
1384after scale path is not finite
1385##
1386##
1387
1388#SeeAlso SkScalar
1389##
1390
1391# ------------------------------------------------------------------------------
1392
Cary Clark682c58d2018-05-16 07:07:07 -04001393#Method bool isVolatile() const
Cary Clark4855f782018-02-06 09:41:53 -05001394#In Property
1395#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001396#Line # returns if Device should not cache ##
Cary Clark73fa9722017-08-29 17:36:51 -04001397Returns true if the path is volatile; it will not be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001398by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001399Surface to attach a cache of data which speeds repeated drawing. If true, Surface
1400may not speed repeated drawing.
1401
1402#Return true if caller will alter Path after drawing ##
1403
1404#Example
1405 SkPath path;
1406 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1407#StdOut
1408volatile by default is false
1409##
1410##
1411
1412#SeeAlso setIsVolatile
1413
1414##
1415
1416# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001417#Subtopic Volatile
1418#Populate
1419#Line # caching attribute ##
1420##
Cary Clark73fa9722017-08-29 17:36:51 -04001421
Cary Clark682c58d2018-05-16 07:07:07 -04001422#Method void setIsVolatile(bool isVolatile)
Cary Clark4855f782018-02-06 09:41:53 -05001423#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001424#Line # sets if Device should not cache ##
Cary Clark80247e52018-07-11 16:18:41 -04001425Specifies whether Path is volatile; whether it will be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001426by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001427Device to attach a cache of data which speeds repeated drawing.
1428
1429Mark temporary paths, discarded or modified after use, as volatile
1430to inform Device that the path need not be cached.
1431
1432Mark animating Path volatile to improve performance.
Cary Clarkce101242017-09-01 15:51:02 -04001433Mark unchanging Path non-volatile to improve repeated rendering.
Cary Clark73fa9722017-08-29 17:36:51 -04001434
1435Raster_Surface Path draws are affected by volatile for some shadows.
1436GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
1437
1438#Param isVolatile true if caller will alter Path after drawing ##
1439
1440#Example
1441#Height 50
1442#Width 50
1443 SkPaint paint;
1444 paint.setStyle(SkPaint::kStroke_Style);
1445 SkPath path;
1446 path.setIsVolatile(true);
1447 path.lineTo(40, 40);
1448 canvas->drawPath(path, paint);
1449 path.rewind();
1450 path.moveTo(0, 40);
1451 path.lineTo(40, 0);
1452 canvas->drawPath(path, paint);
1453##
1454
1455#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1456
1457#SeeAlso isVolatile
1458
1459##
1460
1461# ------------------------------------------------------------------------------
1462
Cary Clark682c58d2018-05-16 07:07:07 -04001463#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001464#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001465#Line # returns if Line is very small ##
Cary Clark80247e52018-07-11 16:18:41 -04001466Tests if Line between Point pair is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001467Line with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001468treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001469
Cary Clarka523d2d2017-08-30 08:58:10 -04001470exact changes the equality test. If true, returns true only if p1 equals p2.
1471If false, returns true if p1 equals or nearly equals p2.
1472
Cary Clark73fa9722017-08-29 17:36:51 -04001473#Param p1 line start point ##
1474#Param p2 line end point ##
Cary Clarka523d2d2017-08-30 08:58:10 -04001475#Param exact if false, allow nearly equals ##
Cary Clark73fa9722017-08-29 17:36:51 -04001476
1477#Return true if Line is degenerate; its length is effectively zero ##
1478
1479#Example
1480#Description
Cary Clarkce101242017-09-01 15:51:02 -04001481As single precision floats, 100 and 100.000001 have the same bit representation,
1482and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001483are not exactly equal, but are nearly equal.
1484##
1485void draw(SkCanvas* canvas) {
1486 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1487 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1488 for (bool exact : { false, true } ) {
1489 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1490 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1491 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1492 ? "" : "not ", exact ? "exactly" : "nearly");
1493 }
1494 }
1495}
1496#StdOut
1497line from (100,100) to (100,100) is degenerate, nearly
1498line from (100,100) to (100,100) is degenerate, exactly
1499line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1500line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1501#StdOut ##
1502##
1503
Cary Clark682c58d2018-05-16 07:07:07 -04001504#SeeAlso IsQuadDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001505##
1506
1507# ------------------------------------------------------------------------------
1508
1509#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001510 const SkPoint& p3, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001511#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001512#Line # returns if Quad is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001513
Cary Clark80247e52018-07-11 16:18:41 -04001514Tests if Quad is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001515Quad with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001516treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001517
Cary Clarkce101242017-09-01 15:51:02 -04001518#Param p1 Quad start point ##
1519#Param p2 Quad control point ##
1520#Param p3 Quad end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001521#Param exact if true, returns true only if p1, p2, and p3 are equal;
1522 if false, returns true if p1, p2, and p3 are equal or nearly equal
Cary Clark73fa9722017-08-29 17:36:51 -04001523##
1524
1525#Return true if Quad is degenerate; its length is effectively zero ##
1526
1527#Example
1528#Description
Cary Clarkce101242017-09-01 15:51:02 -04001529As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001530but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001531the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001532##
1533void draw(SkCanvas* canvas) {
1534 auto debugster = [](const SkPath& path, bool exact) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001535 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 -04001536 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1537 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1538 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1539 "" : "not ", exact ? "exactly" : "nearly");
1540 };
1541 SkPath path, offset;
1542 path.moveTo({100, 100});
1543 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1544 offset.addPath(path, 1000, 1000);
1545 for (bool exact : { false, true } ) {
1546 debugster(path, exact);
1547 debugster(offset, exact);
1548 }
1549}
1550#StdOut
1551quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1552quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1553quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1554quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1555#StdOut ##
1556##
1557
Cary Clark682c58d2018-05-16 07:07:07 -04001558#SeeAlso IsLineDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001559##
1560
1561# ------------------------------------------------------------------------------
1562
1563#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001564 const SkPoint& p3, const SkPoint& p4, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001565#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001566#Line # returns if Cubic is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001567
Cary Clark80247e52018-07-11 16:18:41 -04001568Tests if Cubic is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001569Cubic with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001570treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001571
Cary Clarkce101242017-09-01 15:51:02 -04001572#Param p1 Cubic start point ##
1573#Param p2 Cubic control point 1 ##
1574#Param p3 Cubic control point 2 ##
1575#Param p4 Cubic end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001576#Param exact if true, returns true only if p1, p2, p3, and p4 are equal;
Cary Clark73fa9722017-08-29 17:36:51 -04001577 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
1578##
1579
1580#Return true if Cubic is degenerate; its length is effectively zero ##
1581
1582#Example
1583void draw(SkCanvas* canvas) {
1584 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1585 SkScalar step = 1;
Cary Clark75fd4492018-06-20 12:45:16 -04001586 SkScalar prior, length = 0, degenerate = 0;
Cary Clark73fa9722017-08-29 17:36:51 -04001587 do {
1588 prior = points[0].fX;
1589 step /= 2;
1590 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1591 degenerate = prior;
1592 points[0].fX += step;
1593 } else {
1594 length = prior;
1595 points[0].fX -= step;
1596 }
1597 } while (prior != points[0].fX);
1598 SkDebugf("%1.8g is degenerate\n", degenerate);
1599 SkDebugf("%1.8g is length\n", length);
1600}
1601#StdOut
16020.00024414062 is degenerate
16030.00024414065 is length
1604#StdOut ##
1605##
1606
1607##
1608
1609# ------------------------------------------------------------------------------
1610
1611#Method bool isLine(SkPoint line[2]) const
Cary Clark4855f782018-02-06 09:41:53 -05001612#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001613#Line # returns if describes Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04001614Returns true if Path contains only one Line;
Cary Clark682c58d2018-05-16 07:07:07 -04001615Path_Verb array has two entries: kMove_Verb, kLine_Verb.
1616If Path contains one Line and line is not nullptr, line is set to
Cary Clark73fa9722017-08-29 17:36:51 -04001617Line start point and Line end point.
1618Returns false if Path is not one Line; line is unaltered.
1619
1620#Param line storage for Line. May be nullptr ##
1621
1622#Return true if Path contains exactly one Line ##
1623
1624#Example
1625void draw(SkCanvas* canvas) {
1626 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1627 SkPoint line[2];
1628 if (path.isLine(line)) {
1629 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1630 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1631 } else {
1632 SkDebugf("%s is not line\n", prefix);
1633 }
1634 };
1635 SkPath path;
1636 debugster("empty", path);
1637 path.lineTo(0, 0);
1638 debugster("zero line", path);
1639 path.rewind();
1640 path.moveTo(10, 10);
1641 path.lineTo(20, 20);
1642 debugster("line", path);
1643 path.moveTo(20, 20);
1644 debugster("second move", path);
1645}
1646#StdOut
1647empty is not line
1648zero line is line (0,0) (0,0)
1649line is line (10,10) (20,20)
1650second move is not line
1651##
1652##
1653
1654##
1655
1656# ------------------------------------------------------------------------------
1657
Cary Clark8032b982017-07-28 11:04:54 -04001658#Subtopic Point_Array
Cary Clark08895c42018-02-01 09:37:32 -05001659#Line # end points and control points for lines and curves ##
Cary Clark61dfc3a2018-01-03 08:37:53 -05001660#Substitute SkPoint array
Cary Clark8032b982017-07-28 11:04:54 -04001661
1662Point_Array contains Points satisfying the allocated Points for
1663each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001664and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001665one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1666
1667Point_Array may be read directly from Path with getPoints, or inspected with
1668getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001669
1670#Method int getPoints(SkPoint points[], int max) const
1671
Cary Clarkab2621d2018-01-30 10:08:57 -05001672#In Point_Array
1673#Line # returns Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001674Returns number of points in Path. Up to max points are copied.
1675points may be nullptr; then, max must be zero.
Cary Clark682c58d2018-05-16 07:07:07 -04001676If max is greater than number of points, excess points storage is unaltered.
Cary Clark73fa9722017-08-29 17:36:51 -04001677
1678#Param points storage for Path Point array. May be nullptr ##
1679#Param max maximum to copy; must be greater than or equal to zero ##
1680
1681#Return Path Point array length ##
1682
1683#Example
1684void draw(SkCanvas* canvas) {
1685 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1686 int count = path.getPoints(points, max);
1687 SkDebugf("%s point count: %d ", prefix, count);
1688 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1689 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1690 }
1691 SkDebugf("\n");
1692 };
1693 SkPath path;
1694 path.lineTo(20, 20);
1695 path.lineTo(-10, -10);
1696 SkPoint points[3];
1697 debugster("no points", path, nullptr, 0);
1698 debugster("zero max", path, points, 0);
1699 debugster("too small", path, points, 2);
1700 debugster("just right", path, points, path.countPoints());
1701}
1702#StdOut
1703no points point count: 3
1704zero max point count: 3
1705too small point count: 3 (0,0) (20,20)
1706just right point count: 3 (0,0) (20,20) (-10,-10)
1707##
1708##
1709
1710#SeeAlso countPoints getPoint
1711##
1712
1713#Method int countPoints() const
1714
Cary Clarkab2621d2018-01-30 10:08:57 -05001715#In Point_Array
1716#Line # returns Point_Array length ##
Cary Clark73fa9722017-08-29 17:36:51 -04001717Returns the number of points in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001718Point count is initially zero.
Cary Clark73fa9722017-08-29 17:36:51 -04001719
1720#Return Path Point array length ##
1721
1722#Example
1723void draw(SkCanvas* canvas) {
1724 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1725 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1726 };
1727 SkPath path;
1728 debugster("empty", path);
1729 path.lineTo(0, 0);
1730 debugster("zero line", path);
1731 path.rewind();
1732 path.moveTo(10, 10);
1733 path.lineTo(20, 20);
1734 debugster("line", path);
1735 path.moveTo(20, 20);
1736 debugster("second move", path);
1737}
1738#StdOut
1739empty point count: 0
1740zero line point count: 2
1741line point count: 2
1742second move point count: 3
1743##
1744##
1745
1746#SeeAlso getPoints
1747##
1748
1749#Method SkPoint getPoint(int index) const
1750
Cary Clarkab2621d2018-01-30 10:08:57 -05001751#In Point_Array
1752#Line # returns entry from Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001753Returns Point at index in Point_Array. Valid range for index is
17540 to countPoints - 1.
Cary Clark682c58d2018-05-16 07:07:07 -04001755Returns (0, 0) if index is out of range.
Cary Clark73fa9722017-08-29 17:36:51 -04001756
1757#Param index Point array element selector ##
1758
1759#Return Point array value or (0, 0) ##
1760
1761#Example
1762void draw(SkCanvas* canvas) {
Cary Clark73fa9722017-08-29 17:36:51 -04001763 SkPath path;
1764 path.lineTo(20, 20);
1765 path.offset(-10, -10);
1766 for (int i= 0; i < path.countPoints(); ++i) {
1767 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
Cary Clark682c58d2018-05-16 07:07:07 -04001768 }
Cary Clark73fa9722017-08-29 17:36:51 -04001769}
1770#StdOut
1771point 0: (-10,-10)
1772point 1: (10,10)
1773##
1774##
1775
1776#SeeAlso countPoints getPoints
1777##
1778
1779
1780#Subtopic Point_Array ##
1781
1782# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001783#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001784#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001785
1786Verb_Array always starts with kMove_Verb.
1787If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1788the quantity of kMove_Verb equals the Contour count.
1789Verb_Array does not include or count kDone_Verb; it is a convenience
1790returned when iterating through Verb_Array.
1791
Cary Clark682c58d2018-05-16 07:07:07 -04001792Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
Cary Clark8032b982017-07-28 11:04:54 -04001793or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001794
1795#Method int countVerbs() const
1796
Cary Clarkab2621d2018-01-30 10:08:57 -05001797#In Verb_Array
1798#Line # returns Verb_Array length ##
Cary Clark682c58d2018-05-16 07:07:07 -04001799Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -04001800kCubic_Verb, and kClose_Verb; added to Path.
1801
1802#Return length of Verb_Array ##
1803
1804#Example
1805SkPath path;
1806SkDebugf("empty verb count: %d\n", path.countVerbs());
1807path.addRoundRect({10, 20, 30, 40}, 5, 5);
1808SkDebugf("round rect verb count: %d\n", path.countVerbs());
1809#StdOut
1810empty verb count: 0
1811round rect verb count: 10
1812##
1813##
1814
1815#SeeAlso getVerbs Iter RawIter
1816
1817##
1818
1819#Method int getVerbs(uint8_t verbs[], int max) const
1820
Cary Clarkab2621d2018-01-30 10:08:57 -05001821#In Verb_Array
1822#Line # returns Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001823Returns the number of verbs in the path. Up to max verbs are copied. The
1824verbs are copied as one byte per verb.
1825
1826#Param verbs storage for verbs, may be nullptr ##
1827#Param max maximum number to copy into verbs ##
1828
1829#Return the actual number of verbs in the path ##
1830
1831#Example
1832void draw(SkCanvas* canvas) {
1833 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1834 int count = path.getVerbs(verbs, max);
1835 SkDebugf("%s verb count: %d ", prefix, count);
1836 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1837 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1838 SkDebugf("%s ", verbStr[verbs[i]]);
1839 }
1840 SkDebugf("\n");
1841 };
1842 SkPath path;
1843 path.lineTo(20, 20);
1844 path.lineTo(-10, -10);
1845 uint8_t verbs[3];
1846 debugster("no verbs", path, nullptr, 0);
1847 debugster("zero max", path, verbs, 0);
1848 debugster("too small", path, verbs, 2);
1849 debugster("just right", path, verbs, path.countVerbs());
1850}
1851#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04001852no verbs verb count: 3
1853zero max verb count: 3
1854too small verb count: 3 move line
1855just right verb count: 3 move line line
Cary Clark73fa9722017-08-29 17:36:51 -04001856##
1857##
1858
1859#SeeAlso countVerbs getPoints Iter RawIter
1860##
Cary Clark8032b982017-07-28 11:04:54 -04001861
1862#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001863
1864# ------------------------------------------------------------------------------
1865
1866#Method void swap(SkPath& other)
Cary Clark4855f782018-02-06 09:41:53 -05001867#In Operator
Cary Clarkab2621d2018-01-30 10:08:57 -05001868#Line # exchanges Path pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04001869Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1870Cached state is also exchanged. swap() internally exchanges pointers, so
1871it is lightweight and does not allocate memory.
1872
1873swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001874Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001875making assignment as efficient as swap().
1876
1877#Param other Path exchanged by value ##
1878
1879#Example
1880SkPath path1, path2;
1881path1.addRect({10, 20, 30, 40});
1882path1.swap(path2);
1883const SkRect& b1 = path1.getBounds();
1884SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1885const SkRect& b2 = path2.getBounds();
1886SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1887#StdOut
1888path1 bounds = 0, 0, 0, 0
1889path2 bounds = 10, 20, 30, 40
1890#StdOut ##
1891##
1892
1893#SeeAlso operator=(const SkPath& path)
1894
1895##
1896
1897# ------------------------------------------------------------------------------
1898
Cary Clark682c58d2018-05-16 07:07:07 -04001899#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001900#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001901#Line # returns maximum and minimum of Point_Array ##
Cary Clark5538c132018-06-14 12:28:14 -04001902Returns minimum and maximum axes values of Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04001903Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1904be larger or smaller than area affected when Path is drawn.
1905
1906Rect returned includes all Points added to Path, including Points associated with
1907kMove_Verb that define empty Contours.
1908
1909#Return bounds of all Points in Point_Array ##
1910
1911#Example
1912#Description
1913Bounds of upright Circle can be predicted from center and radius.
1914Bounds of rotated Circle includes control Points outside of filled area.
1915##
1916 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1917 const SkRect& bounds = path.getBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001918 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001919 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1920 };
1921 SkPath path;
1922 debugster("empty", path);
1923 path.addCircle(50, 45, 25);
1924 debugster("circle", path);
1925 SkMatrix matrix;
1926 matrix.setRotate(45, 50, 45);
1927 path.transform(matrix);
1928 debugster("rotated circle", path);
1929#StdOut
1930empty bounds = 0, 0, 0, 0
1931circle bounds = 25, 20, 75, 70
1932rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1933##
1934##
1935
1936#SeeAlso computeTightBounds updateBoundsCache
1937
1938##
1939
1940# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001941#Subtopic Utility
1942#Populate
1943#Line # rarely called management functions ##
1944##
Cary Clark73fa9722017-08-29 17:36:51 -04001945
Cary Clark682c58d2018-05-16 07:07:07 -04001946#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001947#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001948#Line # refreshes result of getBounds ##
Cary Clark80247e52018-07-11 16:18:41 -04001949Updates internal bounds so that subsequent calls to getBounds are instantaneous.
Cary Clark73fa9722017-08-29 17:36:51 -04001950Unaltered copies of Path may also access cached bounds through getBounds.
1951
1952For now, identical to calling getBounds and ignoring the returned value.
1953
Cary Clark682c58d2018-05-16 07:07:07 -04001954Call to prepare Path subsequently drawn from multiple threads,
Cary Clark73fa9722017-08-29 17:36:51 -04001955to avoid a race condition where each draw separately computes the bounds.
1956
1957#Example
1958 double times[2] = { 0, 0 };
1959 for (int i = 0; i < 10000; ++i) {
1960 SkPath path;
1961 for (int j = 1; j < 100; ++ j) {
1962 path.addCircle(50 + j, 45 + j, 25 + j);
1963 }
1964 if (1 & i) {
1965 path.updateBoundsCache();
1966 }
1967 double start = SkTime::GetNSecs();
1968 (void) path.getBounds();
1969 times[1 & i] += SkTime::GetNSecs() - start;
1970 }
1971 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1972 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1973#StdOut
1974#Volatile
1975uncached avg: 0.18048 ms
1976cached avg: 0.182784 ms
1977##
1978##
1979
1980#SeeAlso getBounds
1981#ToDo the results don't make sense, need to profile to figure this out ##
1982
1983##
1984
1985# ------------------------------------------------------------------------------
1986
1987#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001988#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001989#Line # returns extent of geometry ##
Cary Clark5538c132018-06-14 12:28:14 -04001990Returns minimum and maximum axes values of the lines and curves in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001991Returns (0, 0, 0, 0) if Path contains no points.
1992Returned bounds width and height may be larger or smaller than area affected
Cary Clark73fa9722017-08-29 17:36:51 -04001993when Path is drawn.
1994
1995Includes Points associated with kMove_Verb that define empty
1996Contours.
1997
1998Behaves identically to getBounds when Path contains
1999only lines. If Path contains curves, computed bounds includes
2000the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
2001and unlike getBounds, does not cache the result.
2002
2003#Return tight bounds of curves in Path ##
2004
2005#Example
2006 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2007 const SkRect& bounds = path.computeTightBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04002008 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04002009 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2010 };
2011 SkPath path;
2012 debugster("empty", path);
2013 path.addCircle(50, 45, 25);
2014 debugster("circle", path);
2015 SkMatrix matrix;
2016 matrix.setRotate(45, 50, 45);
2017 path.transform(matrix);
2018 debugster("rotated circle", path);
2019#StdOut
2020empty bounds = 0, 0, 0, 0
2021circle bounds = 25, 20, 75, 70
2022rotated circle bounds = 25, 20, 75, 70
2023##
2024##
2025
2026#SeeAlso getBounds
2027
2028##
2029
2030# ------------------------------------------------------------------------------
2031
2032#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05002033#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002034#Line # returns true if Rect may be inside ##
Cary Clark682c58d2018-05-16 07:07:07 -04002035Returns true if rect is contained by Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002036May return false when rect is contained by Path.
2037
2038For now, only returns true if Path has one Contour and is convex.
2039rect may share points and edges with Path and be contained.
2040Returns true if rect is empty, that is, it has zero width or height; and
2041the Point or Line described by rect is contained by Path.
2042
2043#Param rect Rect, Line, or Point checked for containment ##
2044
2045#Return true if rect is contained ##
2046
2047#Example
2048#Height 140
2049#Description
2050Rect is drawn in blue if it is contained by red Path.
2051##
2052void draw(SkCanvas* canvas) {
2053 SkPath path;
2054 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2055 SkRect tests[] = {
2056 { 10, 40, 54, 80 },
2057 { 25, 20, 39, 120 },
2058 { 15, 25, 49, 115 },
2059 { 13, 27, 51, 113 },
2060 };
2061 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2062 SkPaint paint;
2063 paint.setColor(SK_ColorRED);
2064 canvas->drawPath(path, paint);
2065 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2066 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2067 canvas->drawRect(tests[i], paint);
2068 canvas->translate(64, 0);
2069 }
2070}
2071##
2072
2073#SeeAlso contains Op Rect Convexity
2074
2075##
2076
2077# ------------------------------------------------------------------------------
2078
2079#Method void incReserve(unsigned extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05002080#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002081#Line # reserves space for additional data ##
Cary Clark80247e52018-07-11 16:18:41 -04002082Grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
Cary Clark73fa9722017-08-29 17:36:51 -04002083May improve performance and use less memory by
2084reducing the number and size of allocations when creating Path.
2085
Cary Clarkce101242017-09-01 15:51:02 -04002086#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002087
2088#Example
2089#Height 192
2090void draw(SkCanvas* canvas) {
2091 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2092 path->moveTo(size, 0);
2093 for (int i = 1; i < sides; i++) {
2094 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2095 path->lineTo(c * size, s * size);
2096 }
2097 path->close();
2098 };
2099 SkPath path;
2100 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2101 for (int sides = 3; sides < 10; ++sides) {
2102 addPoly(sides, sides, &path);
2103 }
2104 SkMatrix matrix;
2105 matrix.setScale(10, 10, -10, -10);
2106 path.transform(matrix);
2107 SkPaint paint;
2108 paint.setStyle(SkPaint::kStroke_Style);
2109 canvas->drawPath(path, paint);
2110}
2111##
2112
2113#SeeAlso Point_Array
2114
2115##
2116
Cary Clark99ebc422018-09-11 15:26:53 -04002117#Method void shrinkToFit()
2118#In Utility
2119#Line # removes unused reserved space ##
Florin Malita0e0f1a72018-09-11 16:16:19 -04002120Shrinks Path Verb_Array and Point_Array storage to discard unused capacity.
2121May reduce the heap overhead for Paths known to be fully constructed.
Cary Clark99ebc422018-09-11 15:26:53 -04002122
2123#NoExample
Florin Malita0e0f1a72018-09-11 16:16:19 -04002124#Height 192
2125void draw(SkCanvas* canvas) {
2126 SkPath skinnyPath;
2127 skinnyPath.lineTo(100, 100);
2128 skinnyPath.shrinkToFit();
2129
2130 SkDebugf("no wasted Path capacity in my house!\n");
2131}
Cary Clark99ebc422018-09-11 15:26:53 -04002132##
Florin Malita0e0f1a72018-09-11 16:16:19 -04002133
Cary Clark99ebc422018-09-11 15:26:53 -04002134#SeeAlso incReserve
Florin Malita0e0f1a72018-09-11 16:16:19 -04002135
Cary Clark99ebc422018-09-11 15:26:53 -04002136##
2137
Cary Clark73fa9722017-08-29 17:36:51 -04002138# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05002139#Subtopic Build
2140#Populate
2141#Line # adds points and verbs to path ##
2142##
Cary Clark73fa9722017-08-29 17:36:51 -04002143
Cary Clark0251b1b2018-08-15 15:14:55 -04002144#Method SkPath& moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002145#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002146#Line # starts Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -04002147Adds beginning of Contour at Point (x, y).
2148
Cary Clark5538c132018-06-14 12:28:14 -04002149#Param x x-axis value of Contour start ##
2150#Param y y-axis value of Contour start ##
Cary Clark73fa9722017-08-29 17:36:51 -04002151
Cary Clark0251b1b2018-08-15 15:14:55 -04002152#Return reference to Path ##
2153
Cary Clark73fa9722017-08-29 17:36:51 -04002154#Example
2155 #Width 140
2156 #Height 100
2157 void draw(SkCanvas* canvas) {
2158 SkRect rect = { 20, 20, 120, 80 };
2159 SkPath path;
2160 path.addRect(rect);
2161 path.moveTo(rect.fLeft, rect.fTop);
2162 path.lineTo(rect.fRight, rect.fBottom);
2163 path.moveTo(rect.fLeft, rect.fBottom);
2164 path.lineTo(rect.fRight, rect.fTop);
2165 SkPaint paint;
2166 paint.setStyle(SkPaint::kStroke_Style);
2167 canvas->drawPath(path, paint);
2168 }
2169##
2170
2171#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2172
2173##
2174
Cary Clark0251b1b2018-08-15 15:14:55 -04002175#Method SkPath& moveTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002176
2177Adds beginning of Contour at Point p.
2178
2179#Param p contour start ##
2180
Cary Clark0251b1b2018-08-15 15:14:55 -04002181#Return reference to Path ##
2182
Cary Clark73fa9722017-08-29 17:36:51 -04002183#Example
2184 #Width 128
2185 #Height 128
2186void draw(SkCanvas* canvas) {
Cary Clark682c58d2018-05-16 07:07:07 -04002187 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
Cary Clark73fa9722017-08-29 17:36:51 -04002188 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2189 SkPath path;
2190 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2191 path.moveTo(data[i][0]);
2192 path.lineTo(data[i][1]);
2193 path.lineTo(data[i][2]);
2194 }
2195 SkPaint paint;
2196 paint.setStyle(SkPaint::kStroke_Style);
2197 canvas->drawPath(path, paint);
2198}
2199##
2200
2201#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2202
2203##
2204
Cary Clark0251b1b2018-08-15 15:14:55 -04002205#Method SkPath& rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002206#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002207#Line # starts Contour relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002208Adds beginning of Contour relative to Last_Point.
2209If Path is empty, starts Contour at (dx, dy).
Cary Clark682c58d2018-05-16 07:07:07 -04002210Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002211Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002212
Cary Clark5538c132018-06-14 12:28:14 -04002213#Param dx offset from Last_Point to Contour start on x-axis ##
2214#Param dy offset from Last_Point to Contour start on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002215
Cary Clark0251b1b2018-08-15 15:14:55 -04002216#Return reference to Path ##
2217
Cary Clark73fa9722017-08-29 17:36:51 -04002218#Example
2219 #Height 100
2220 SkPath path;
2221 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2222 path.rMoveTo(25, 2);
2223 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2224 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2225 path.rLineTo(arrow[i].fX, arrow[i].fY);
2226 }
2227 SkPaint paint;
2228 canvas->drawPath(path, paint);
2229 SkPoint lastPt;
2230 path.getLastPt(&lastPt);
2231 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2232##
2233
2234#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2235
2236##
2237
2238# ------------------------------------------------------------------------------
2239
Cary Clark0251b1b2018-08-15 15:14:55 -04002240#Method SkPath& lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002241#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002242#Line # appends Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04002243Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2244kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2245
2246lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2247lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
Cary Clark682c58d2018-05-16 07:07:07 -04002248
Cary Clark73fa9722017-08-29 17:36:51 -04002249#Param x end of added Line in x ##
2250#Param y end of added Line in y ##
2251
Cary Clark0251b1b2018-08-15 15:14:55 -04002252#Return reference to Path ##
2253
Cary Clark73fa9722017-08-29 17:36:51 -04002254#Example
2255#Height 100
2256###$
2257void draw(SkCanvas* canvas) {
2258 SkPaint paint;
2259 paint.setAntiAlias(true);
2260 paint.setTextSize(72);
2261 canvas->drawString("#", 120, 80, paint);
2262 paint.setStyle(SkPaint::kStroke_Style);
2263 paint.setStrokeWidth(5);
2264 SkPath path;
2265 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2266 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2267 unsigned o = 0;
2268 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2269 for (unsigned j = 0; j < 2; o++, j++) {
2270 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2271 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2272 }
2273 }
2274 canvas->drawPath(path, paint);
2275}
2276$$$#
2277##
2278
2279#SeeAlso Contour moveTo rLineTo addRect
2280
2281##
2282
2283# ------------------------------------------------------------------------------
2284
Cary Clark0251b1b2018-08-15 15:14:55 -04002285#Method SkPath& lineTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002286
2287Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2288kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2289
2290lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2291lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2292
2293#Param p end Point of added Line ##
2294
Cary Clark0251b1b2018-08-15 15:14:55 -04002295#Return reference to Path ##
2296
Cary Clark73fa9722017-08-29 17:36:51 -04002297#Example
2298#Height 100
2299 SkPath path;
2300 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2301 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2302 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2303 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2304 path.moveTo(oxo[i]);
2305 path.lineTo(oxo[i + 1]);
2306 }
2307 SkPaint paint;
2308 paint.setStyle(SkPaint::kStroke_Style);
2309 canvas->drawPath(path, paint);
2310##
2311
2312#SeeAlso Contour moveTo rLineTo addRect
2313
2314##
2315
2316# ------------------------------------------------------------------------------
2317
Cary Clark0251b1b2018-08-15 15:14:55 -04002318#Method SkPath& rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002319#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002320#Line # appends Line relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002321Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2322kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2323
2324Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2325then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2326Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002327Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002328
Cary Clark5538c132018-06-14 12:28:14 -04002329#Param dx offset from Last_Point to Line end on x-axis ##
2330#Param dy offset from Last_Point to Line end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002331
Cary Clark0251b1b2018-08-15 15:14:55 -04002332#Return reference to Path ##
2333
Cary Clark73fa9722017-08-29 17:36:51 -04002334#Example
2335#Height 128
2336void draw(SkCanvas* canvas) {
2337 SkPaint paint;
2338 paint.setAntiAlias(true);
2339 paint.setStyle(SkPaint::kStroke_Style);
2340 SkPath path;
2341 path.moveTo(10, 98);
2342 SkScalar x = 0, y = 0;
2343 for (int i = 10; i < 100; i += 5) {
2344 x += i * ((i & 2) - 1);
2345 y += i * (((i + 1) & 2) - 1);
2346 path.rLineTo(x, y);
Cary Clark682c58d2018-05-16 07:07:07 -04002347
Cary Clark73fa9722017-08-29 17:36:51 -04002348 }
2349 canvas->drawPath(path, paint);
2350}
2351##
2352
2353#SeeAlso Contour moveTo lineTo addRect
2354
2355##
2356
2357# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002358#Subtopic Quad
Cary Clark137b8742018-05-30 09:21:49 -04002359#Alias Quad ##
2360#Alias Quads ##
2361#Alias Quadratic_Bezier ##
2362#Alias Quadratic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002363#Line # curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002364
2365Quad describes a quadratic Bezier, a second-order curve identical to a section
2366of a parabola. Quad begins at a start Point, curves towards a control Point,
2367and then curves to an end Point.
2368
2369#Example
2370#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002371void draw(SkCanvas* canvas) {
2372 SkPaint paint;
2373 paint.setAntiAlias(true);
2374 paint.setStyle(SkPaint::kStroke_Style);
2375 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2376 canvas->drawLine(quadPts[0], quadPts[1], paint);
2377 canvas->drawLine(quadPts[1], quadPts[2], paint);
2378 SkPath path;
2379 path.moveTo(quadPts[0]);
2380 path.quadTo(quadPts[1], quadPts[2]);
2381 paint.setStrokeWidth(3);
2382 canvas->drawPath(path, paint);
2383}
Cary Clark8032b982017-07-28 11:04:54 -04002384##
2385
2386Quad is a special case of Conic where Conic_Weight is set to one.
2387
2388Quad is always contained by the triangle connecting its three Points. Quad
2389begins tangent to the line between start Point and control Point, and ends
2390tangent to the line between control Point and end Point.
2391
2392#Example
2393#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002394void draw(SkCanvas* canvas) {
2395 SkPaint paint;
2396 paint.setAntiAlias(true);
2397 paint.setStyle(SkPaint::kStroke_Style);
2398 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2399 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2400 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2401 paint.setColor(0x7fffffff & colors[i]);
2402 paint.setStrokeWidth(1);
2403 canvas->drawLine(quadPts[0], quadPts[1], paint);
2404 canvas->drawLine(quadPts[1], quadPts[2], paint);
2405 SkPath path;
2406 path.moveTo(quadPts[0]);
2407 path.quadTo(quadPts[1], quadPts[2]);
2408 paint.setStrokeWidth(3);
2409 paint.setColor(colors[i]);
2410 canvas->drawPath(path, paint);
2411 quadPts[1].fY += 30;
2412 }
Cary Clark8032b982017-07-28 11:04:54 -04002413}
2414##
Cary Clark73fa9722017-08-29 17:36:51 -04002415
Cary Clark0251b1b2018-08-15 15:14:55 -04002416#Method SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Cary Clark73fa9722017-08-29 17:36:51 -04002417
Cary Clarkab2621d2018-01-30 10:08:57 -05002418#In Quad
2419#Line # appends Quad ##
Cary Clark682c58d2018-05-16 07:07:07 -04002420 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
Cary Clark73fa9722017-08-29 17:36:51 -04002421 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2422 before adding Quad.
2423
2424 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2425 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2426 to Point_Array.
2427
2428 #Param x1 control Point of Quad in x ##
2429 #Param y1 control Point of Quad in y ##
2430 #Param x2 end Point of Quad in x ##
2431 #Param y2 end Point of Quad in y ##
2432
Cary Clark0251b1b2018-08-15 15:14:55 -04002433 #Return reference to Path ##
2434
Cary Clark73fa9722017-08-29 17:36:51 -04002435 #Example
2436 void draw(SkCanvas* canvas) {
2437 SkPaint paint;
2438 paint.setAntiAlias(true);
2439 paint.setStyle(SkPaint::kStroke_Style);
2440 SkPath path;
2441 path.moveTo(0, -10);
2442 for (int i = 0; i < 128; i += 16) {
2443 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2444 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2445 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2446 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2447 }
2448 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002449 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002450 }
2451 ##
2452
2453 #SeeAlso Contour moveTo conicTo rQuadTo
2454
2455##
2456
Cary Clark0251b1b2018-08-15 15:14:55 -04002457#Method SkPath& quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05002458#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002459#In Quad
Cary Clark682c58d2018-05-16 07:07:07 -04002460 Adds Quad from Last_Point towards Point p1, to Point p2.
Cary Clark73fa9722017-08-29 17:36:51 -04002461 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2462 before adding Quad.
2463
2464 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2465 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2466 to Point_Array.
2467
2468 #Param p1 control Point of added Quad ##
2469 #Param p2 end Point of added Quad ##
2470
Cary Clark0251b1b2018-08-15 15:14:55 -04002471 #Return reference to Path ##
2472
Cary Clark73fa9722017-08-29 17:36:51 -04002473 #Example
2474 void draw(SkCanvas* canvas) {
2475 SkPaint paint;
2476 paint.setStyle(SkPaint::kStroke_Style);
2477 paint.setAntiAlias(true);
2478 SkPath path;
2479 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2480 path.moveTo(pts[1]);
2481 for (int i = 0; i < 3; ++i) {
2482 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2483 }
2484 canvas->drawPath(path, paint);
2485 }
2486 ##
2487
2488 #SeeAlso Contour moveTo conicTo rQuadTo
2489
2490##
2491
Cary Clark0251b1b2018-08-15 15:14:55 -04002492#Method SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05002493#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002494#In Quad
2495#Line # appends Quad relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002496 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2497 If Path is empty, or last Verb
2498 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2499
2500 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2501 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2502 control and Quad end to Point_Array.
2503 Quad control is Last_Point plus Vector (dx1, dy1).
2504 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002505 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002506
Cary Clark5538c132018-06-14 12:28:14 -04002507 #Param dx1 offset from Last_Point to Quad control on x-axis ##
2508 #Param dy1 offset from Last_Point to Quad control on y-axis ##
2509 #Param dx2 offset from Last_Point to Quad end on x-axis ##
2510 #Param dy2 offset from Last_Point to Quad end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002511
Cary Clark0251b1b2018-08-15 15:14:55 -04002512 #Return reference to Path ##
2513
Cary Clark73fa9722017-08-29 17:36:51 -04002514 #Example
2515 void draw(SkCanvas* canvas) {
2516 SkPaint paint;
2517 paint.setAntiAlias(true);
2518 SkPath path;
2519 path.moveTo(128, 20);
2520 path.rQuadTo(-6, 10, -7, 10);
2521 for (int i = 1; i < 32; i += 4) {
2522 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2523 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2524 }
2525 path.quadTo(92, 220, 128, 215);
2526 canvas->drawPath(path, paint);
2527 }
2528 ##
2529
2530 #SeeAlso Contour moveTo conicTo quadTo
2531
2532##
2533
Cary Clark78de7512018-02-07 07:27:09 -05002534#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002535
2536# ------------------------------------------------------------------------------
2537
Cary Clark78de7512018-02-07 07:27:09 -05002538#Subtopic Conic
Cary Clark08895c42018-02-01 09:37:32 -05002539#Line # conic section defined by three points and a weight ##
Cary Clark137b8742018-05-30 09:21:49 -04002540#Alias Conics ##
Cary Clark8032b982017-07-28 11:04:54 -04002541
2542Conic describes a conical section: a piece of an ellipse, or a piece of a
Cary Clark682c58d2018-05-16 07:07:07 -04002543parabola, or a piece of a hyperbola. Conic begins at a start Point,
Cary Clark8032b982017-07-28 11:04:54 -04002544curves towards a control Point, and then curves to an end Point. The influence
2545of the control Point is determined by Conic_Weight.
2546
Cary Clark73fa9722017-08-29 17:36:51 -04002547Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2548may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002549
2550#Subtopic Weight
Cary Clark137b8742018-05-30 09:21:49 -04002551#Alias Conic_Weights ##
2552#Alias Weights ##
Cary Clark08895c42018-02-01 09:37:32 -05002553#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002554
2555Weight determines both the strength of the control Point and the type of Conic.
Cary Clark682c58d2018-05-16 07:07:07 -04002556Weight varies from zero to infinity. At zero, Weight causes the control Point to
2557have no effect; Conic is identical to a line segment from start Point to end
2558point. If Weight is less than one, Conic follows an elliptical arc.
2559If Weight is exactly one, then Conic is identical to Quad; Conic follows a
2560parabolic arc. If Weight is greater than one, Conic follows a hyperbolic
Cary Clark137b8742018-05-30 09:21:49 -04002561arc. If Weight is infinity, Conic is identical to two line segments, connecting
Cary Clark682c58d2018-05-16 07:07:07 -04002562start Point to control Point, and control Point to end Point.
Cary Clark8032b982017-07-28 11:04:54 -04002563
2564#Example
2565#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002566When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002567##
Cary Clark73fa9722017-08-29 17:36:51 -04002568void draw(SkCanvas* canvas) {
2569 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2570 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2571 SkPath path;
2572 path.conicTo(20, 30, 50, 60, 1);
2573 SkPath::Iter iter(path, false);
2574 SkPath::Verb verb;
2575 do {
2576 SkPoint points[4];
2577 verb = iter.next(points);
2578 SkDebugf("%s ", verbNames[(int) verb]);
2579 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2580 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2581 }
2582 if (SkPath::kConic_Verb == verb) {
2583 SkDebugf("weight = %g", iter.conicWeight());
2584 }
2585 SkDebugf("\n");
2586 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002587}
2588#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002589move {0, 0},
2590quad {0, 0}, {20, 30}, {50, 60},
2591done
Cary Clark8032b982017-07-28 11:04:54 -04002592##
2593##
2594
2595If weight is less than one, Conic is an elliptical segment.
2596
Cary Clark682c58d2018-05-16 07:07:07 -04002597#Example
Cary Clark8032b982017-07-28 11:04:54 -04002598#Description
Cary Clark2be81cf2018-09-13 12:04:30 -04002599A 90 degree circular arc has the weight #Formula # 1 / sqrt(2) ##.
Cary Clark8032b982017-07-28 11:04:54 -04002600##
Cary Clark73fa9722017-08-29 17:36:51 -04002601void draw(SkCanvas* canvas) {
2602 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2603 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2604 SkPath path;
2605 path.arcTo(20, 0, 20, 20, 20);
2606 SkPath::Iter iter(path, false);
2607 SkPath::Verb verb;
2608 do {
2609 SkPoint points[4];
2610 verb = iter.next(points);
2611 SkDebugf("%s ", verbNames[(int) verb]);
2612 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2613 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2614 }
2615 if (SkPath::kConic_Verb == verb) {
2616 SkDebugf("weight = %g", iter.conicWeight());
2617 }
2618 SkDebugf("\n");
2619 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002620}
2621#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002622move {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04002623conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark682c58d2018-05-16 07:07:07 -04002624done
Cary Clark8032b982017-07-28 11:04:54 -04002625##
2626##
2627
Cary Clarkce101242017-09-01 15:51:02 -04002628If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002629a hyperbolic segment can be approximated by straight lines connecting the
2630control Point with the end Points.
2631
2632#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002633void draw(SkCanvas* canvas) {
2634 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2635 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2636 SkPath path;
2637 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2638 SkPath::Iter iter(path, false);
2639 SkPath::Verb verb;
2640 do {
2641 SkPoint points[4];
2642 verb = iter.next(points);
2643 SkDebugf("%s ", verbNames[(int) verb]);
2644 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2645 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2646 }
2647 if (SkPath::kConic_Verb == verb) {
2648 SkDebugf("weight = %g", iter.conicWeight());
2649 }
2650 SkDebugf("\n");
2651 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002652}
2653#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002654move {0, 0},
2655line {0, 0}, {20, 0},
2656line {20, 0}, {20, 20},
2657done
Cary Clark8032b982017-07-28 11:04:54 -04002658##
2659##
2660
2661#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002662
Cary Clark0251b1b2018-08-15 15:14:55 -04002663#Method SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002664 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002665#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002666#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002667#Line # appends Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002668
Cary Clark682c58d2018-05-16 07:07:07 -04002669 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002670 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2671 before adding Conic.
2672
2673 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2674
2675 If w is finite and not one, appends kConic_Verb to Verb_Array;
2676 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2677
2678 If w is one, appends kQuad_Verb to Verb_Array, and
2679 (x1, y1), (x2, y2) to Point_Array.
2680
2681 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2682 (x1, y1), (x2, y2) to Point_Array.
2683
2684 #Param x1 control Point of Conic in x ##
2685 #Param y1 control Point of Conic in y ##
2686 #Param x2 end Point of Conic in x ##
2687 #Param y2 end Point of Conic in y ##
2688 #Param w weight of added Conic ##
2689
Cary Clark0251b1b2018-08-15 15:14:55 -04002690 #Return reference to Path ##
2691
Cary Clark73fa9722017-08-29 17:36:51 -04002692 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002693 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002694 #Description
Cary Clark682c58d2018-05-16 07:07:07 -04002695 As weight increases, curve is pulled towards control point.
Cary Clark73fa9722017-08-29 17:36:51 -04002696 The bottom two curves are elliptical; the next is parabolic; the
2697 top curve is hyperbolic.
2698 ##
2699void draw(SkCanvas* canvas) {
2700 SkPaint paint;
2701 paint.setAntiAlias(true);
2702 paint.setStyle(SkPaint::kStroke_Style);
2703 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2704 canvas->drawLine(conicPts[0], conicPts[1], paint);
2705 canvas->drawLine(conicPts[1], conicPts[2], paint);
2706 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2707 paint.setStrokeWidth(3);
2708 SkScalar weight = 0.5f;
2709 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2710 SkPath path;
2711 path.moveTo(conicPts[0]);
2712 path.conicTo(conicPts[1], conicPts[2], weight);
2713 paint.setColor(colors[i]);
2714 canvas->drawPath(path, paint);
2715 weight += 0.25f;
2716 }
2717}
2718 ##
2719
2720 #SeeAlso rConicTo arcTo addArc quadTo
2721
2722##
2723
Cary Clark0251b1b2018-08-15 15:14:55 -04002724#Method SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002725#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002726#In Conic
Cary Clark682c58d2018-05-16 07:07:07 -04002727 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002728 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2729 before adding Conic.
2730
2731 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2732
2733 If w is finite and not one, appends kConic_Verb to Verb_Array;
2734 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2735
2736 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2737 to Point_Array.
2738
2739 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2740 Points p1, p2 to Point_Array.
2741
2742 #Param p1 control Point of added Conic ##
2743 #Param p2 end Point of added Conic ##
2744 #Param w weight of added Conic ##
2745
Cary Clark0251b1b2018-08-15 15:14:55 -04002746 #Return reference to Path ##
2747
Cary Clark73fa9722017-08-29 17:36:51 -04002748 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002749 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002750 #Description
2751 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002752 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002753 ##
2754void draw(SkCanvas* canvas) {
2755 SkPaint paint;
2756 paint.setAntiAlias(true);
2757 paint.setStyle(SkPaint::kStroke_Style);
2758 SkRect oval = {0, 20, 120, 140};
2759 SkPath path;
2760 for (int i = 0; i < 4; ++i) {
2761 path.moveTo(oval.centerX(), oval.fTop);
2762 path.arcTo(oval, -90, 90 - 20 * i, false);
2763 oval.inset(15, 15);
2764 }
2765 path.offset(100, 0);
2766 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2767 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2768 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2769 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2770 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2771 for (int i = 0; i < 4; ++i) {
2772 path.moveTo(conicPts[i][0]);
2773 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2774 }
2775 canvas->drawPath(path, paint);
2776}
2777 ##
2778
2779 #SeeAlso rConicTo arcTo addArc quadTo
2780
2781##
2782
Cary Clark0251b1b2018-08-15 15:14:55 -04002783#Method SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
Cary Clark73fa9722017-08-29 17:36:51 -04002784 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002785#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002786#In Conic
2787#Line # appends Conic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002788
2789 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2790 weighted by w. If Path is empty, or last Verb
2791 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2792
2793 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
Cary Clark682c58d2018-05-16 07:07:07 -04002794 if needed.
2795
Cary Clark73fa9722017-08-29 17:36:51 -04002796 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2797 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2798 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2799 twice to Verb_Array.
2800
2801 In all cases appends Points control and end to Point_Array.
2802 control is Last_Point plus Vector (dx1, dy1).
2803 end is Last_Point plus Vector (dx2, dy2).
2804
Cary Clarkce101242017-09-01 15:51:02 -04002805 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002806
Cary Clark5538c132018-06-14 12:28:14 -04002807 #Param dx1 offset from Last_Point to Conic control on x-axis ##
2808 #Param dy1 offset from Last_Point to Conic control on y-axis ##
2809 #Param dx2 offset from Last_Point to Conic end on x-axis ##
2810 #Param dy2 offset from Last_Point to Conic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002811 #Param w weight of added Conic ##
2812
Cary Clark0251b1b2018-08-15 15:14:55 -04002813 #Return reference to Path ##
2814
Cary Clark73fa9722017-08-29 17:36:51 -04002815 #Example
2816 #Height 140
2817 void draw(SkCanvas* canvas) {
2818 SkPaint paint;
2819 paint.setAntiAlias(true);
2820 paint.setStyle(SkPaint::kStroke_Style);
2821 SkPath path;
2822 path.moveTo(20, 80);
2823 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2824 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2825 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2826 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2827 canvas->drawPath(path, paint);
2828 }
2829 ##
2830
2831 #SeeAlso conicTo arcTo addArc quadTo
2832
2833##
2834
Cary Clark78de7512018-02-07 07:27:09 -05002835#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002836
2837# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002838#Subtopic Cubic
Cary Clark137b8742018-05-30 09:21:49 -04002839#Alias Cubic ##
2840#Alias Cubics ##
2841#Alias Cubic_Bezier ##
2842#Alias Cubic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002843#Line # curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002844
Cary Clark682c58d2018-05-16 07:07:07 -04002845Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002846Cubic begins at a start Point, curving towards the first control Point;
2847and curves from the end Point towards the second control Point.
2848
2849#Example
2850#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002851void draw(SkCanvas* canvas) {
2852 SkPaint paint;
2853 paint.setAntiAlias(true);
2854 paint.setStyle(SkPaint::kStroke_Style);
2855 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2856 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2857 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2858 paint.setColor(0x7fffffff & colors[i]);
2859 paint.setStrokeWidth(1);
2860 for (unsigned j = 0; j < 3; ++j) {
2861 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2862 }
2863 SkPath path;
2864 path.moveTo(cubicPts[0]);
2865 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2866 paint.setStrokeWidth(3);
2867 paint.setColor(colors[i]);
2868 canvas->drawPath(path, paint);
2869 cubicPts[1].fY += 30;
2870 cubicPts[2].fX += 30;
2871 }
Cary Clark8032b982017-07-28 11:04:54 -04002872}
2873##
Cary Clark73fa9722017-08-29 17:36:51 -04002874
Cary Clark0251b1b2018-08-15 15:14:55 -04002875#Method SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002876 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002877#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002878#In Cubic
2879#Line # appends Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002880
2881Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2882(x3, y3). 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 (x1, y1), (x2, y2), (x3, y3)
2887to Point_Array.
2888
2889#Param x1 first control Point of Cubic in x ##
2890#Param y1 first control Point of Cubic in y ##
2891#Param x2 second control Point of Cubic in x ##
2892#Param y2 second control Point of Cubic in y ##
2893#Param x3 end Point of Cubic in x ##
2894#Param y3 end Point of Cubic in y ##
2895
Cary Clark0251b1b2018-08-15 15:14:55 -04002896#Return reference to Path ##
2897
Cary Clark73fa9722017-08-29 17:36:51 -04002898#Example
2899void draw(SkCanvas* canvas) {
2900 SkPaint paint;
2901 paint.setAntiAlias(true);
2902 paint.setStyle(SkPaint::kStroke_Style);
2903 SkPath path;
2904 path.moveTo(0, -10);
2905 for (int i = 0; i < 128; i += 16) {
2906 SkScalar c = i * 0.5f;
2907 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2908 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2909 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2910 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2911 }
2912 path.offset(128, 128);
2913 canvas->drawPath(path, paint);
2914}
2915##
2916
2917#SeeAlso Contour moveTo rCubicTo quadTo
2918
2919##
2920
2921# ------------------------------------------------------------------------------
2922
Cary Clark0251b1b2018-08-15 15:14:55 -04002923#Method SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
Cary Clark73fa9722017-08-29 17:36:51 -04002924
Cary Clark4855f782018-02-06 09:41:53 -05002925#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002926#In Cubic
Cary Clark73fa9722017-08-29 17:36:51 -04002927Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2928Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2929(0, 0) before adding Cubic.
2930
2931Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2932then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2933to Point_Array.
2934
2935#Param p1 first control Point of Cubic ##
2936#Param p2 second control Point of Cubic ##
2937#Param p3 end Point of Cubic ##
2938
Cary Clark0251b1b2018-08-15 15:14:55 -04002939#Return reference to Path ##
2940
Cary Clark73fa9722017-08-29 17:36:51 -04002941#Example
2942#Height 84
2943 SkPaint paint;
2944 paint.setAntiAlias(true);
2945 paint.setStyle(SkPaint::kStroke_Style);
2946 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2947 SkPath path;
2948 path.moveTo(pts[0]);
2949 path.cubicTo(pts[1], pts[2], pts[3]);
2950 canvas->drawPath(path, paint);
2951##
2952
2953#SeeAlso Contour moveTo rCubicTo quadTo
2954
2955##
2956
2957# ------------------------------------------------------------------------------
2958
Cary Clark0251b1b2018-08-15 15:14:55 -04002959#Method SkPath& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002960 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002961#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002962#In Cubic
2963#Line # appends Cubic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002964
2965 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2966 Vector (dx2, dy2), to Vector (dx3, dy3).
2967 If Path is empty, or last Verb
2968 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2969
2970 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2971 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2972 control and Cubic end to Point_Array.
2973 Cubic control is Last_Point plus Vector (dx1, dy1).
2974 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002975 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002976
Cary Clark5538c132018-06-14 12:28:14 -04002977 #Param x1 offset from Last_Point to first Cubic control on x-axis ##
2978 #Param y1 offset from Last_Point to first Cubic control on y-axis ##
2979 #Param x2 offset from Last_Point to second Cubic control on x-axis ##
2980 #Param y2 offset from Last_Point to second Cubic control on y-axis ##
2981 #Param x3 offset from Last_Point to Cubic end on x-axis ##
2982 #Param y3 offset from Last_Point to Cubic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002983
Cary Clark0251b1b2018-08-15 15:14:55 -04002984 #Return reference to Path ##
2985
Cary Clark73fa9722017-08-29 17:36:51 -04002986#Example
2987 void draw(SkCanvas* canvas) {
2988 SkPaint paint;
2989 paint.setAntiAlias(true);
2990 paint.setStyle(SkPaint::kStroke_Style);
2991 SkPath path;
2992 path.moveTo(24, 108);
2993 for (int i = 0; i < 16; i++) {
2994 SkScalar sx, sy;
2995 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2996 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2997 }
2998 canvas->drawPath(path, paint);
2999 }
3000##
3001
3002#SeeAlso Contour moveTo cubicTo quadTo
3003
3004##
3005
Cary Clark78de7512018-02-07 07:27:09 -05003006#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04003007
3008# ------------------------------------------------------------------------------
3009
Cary Clark08895c42018-02-01 09:37:32 -05003010#Subtopic Arc
3011#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04003012Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
3013by start point and end point, and by radius and tangent lines. Each construction has advantages,
3014and some constructions correspond to Arc drawing in graphics standards.
3015
3016All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
3017Conic describes an Arc of some Oval or Circle.
3018
3019arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
3020describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
Cary Clark682c58d2018-05-16 07:07:07 -04003021which may continue Contour or start a new one. This construction is similar to PostScript and
Cary Clark73fa9722017-08-29 17:36:51 -04003022HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
3023requiring Path.
3024
3025arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
3026describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
3027where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
3028HTML_Canvas arcs.
3029
3030arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04003031 SkScalar x, SkScalar y)
Cary Clark73fa9722017-08-29 17:36:51 -04003032describes Arc as part of Oval with radii (rx, ry), beginning at
3033last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
3034so additional values choose a single solution. This construction is similar to SVG arcs.
3035
3036conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
3037conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
Cary Clark682c58d2018-05-16 07:07:07 -04003038constructions are converted to Conic data when added to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04003039
Cary Clark153e76d2018-08-28 11:48:28 -04003040#ToDo example is spaced correctly on fiddle but spacing is too wide on pc
Cary Clark73fa9722017-08-29 17:36:51 -04003041##
3042
Cary Clark153e76d2018-08-28 11:48:28 -04003043#Illustration
3044
Cary Clark73fa9722017-08-29 17:36:51 -04003045#List
3046# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
3047# <sup>2</sup> parameter sets force MoveTo ##
Cary Clark5081eed2018-01-22 07:55:48 -05003048# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04003049# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
3050# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3051 Direction sweep, SkScalar x, SkScalar y) ##
3052#List ##
Cary Clark73fa9722017-08-29 17:36:51 -04003053
3054#Example
3055#Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04003056void draw(SkCanvas* canvas) {
3057 SkRect oval = {8, 8, 56, 56};
3058 SkPaint ovalPaint;
3059 ovalPaint.setAntiAlias(true);
3060 SkPaint textPaint(ovalPaint);
3061 ovalPaint.setStyle(SkPaint::kStroke_Style);
3062 SkPaint arcPaint(ovalPaint);
3063 arcPaint.setStrokeWidth(5);
3064 arcPaint.setColor(SK_ColorBLUE);
3065 canvas->translate(-64, 0);
3066 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3067 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3068 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3069 canvas->drawOval(oval, ovalPaint);
3070 SkPath path;
3071 path.moveTo({56, 32});
3072 switch (arcStyle) {
3073 case '1':
3074 path.arcTo(oval, 0, 90, false);
3075 break;
3076 case '2':
3077 canvas->drawArc(oval, 0, 90, false, arcPaint);
3078 continue;
3079 case '3':
3080 path.addArc(oval, 0, 90);
3081 break;
3082 case '4':
3083 path.arcTo({56, 56}, {32, 56}, 24);
3084 break;
3085 case '5':
3086 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3087 break;
3088 case '6':
3089 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3090 break;
3091 }
3092 canvas->drawPath(path, arcPaint);
3093 }
3094}
3095#Example ##
3096
Cary Clark153e76d2018-08-28 11:48:28 -04003097In the example above:
3098#List
3099# 1 describes an arc from an oval, a starting angle, and a sweep angle. ##
3100# 2 is similar to 1, but does not require building a path to draw. ##
3101# 3 is similar to 1, but always begins new Contour. ##
3102# 4 describes an arc from a pair of tangent lines and a radius. ##
3103# 5 describes an arc from Oval center, arc start Point and arc end Point. ##
3104# 6 describes an arc from a pair of tangent lines and a Conic_Weight. ##
3105#List ##
Cary Clark73fa9722017-08-29 17:36:51 -04003106
Cary Clark0251b1b2018-08-15 15:14:55 -04003107#Method SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05003108#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003109#In Arc
3110#Line # appends Arc ##
Cary Clark80247e52018-07-11 16:18:41 -04003111Appends Arc to Path. Arc added is part of ellipse
Cary Clark73fa9722017-08-29 17:36:51 -04003112bounded by oval, from startAngle through sweepAngle. Both startAngle and
3113sweepAngle are measured in degrees, where zero degrees is aligned with the
3114positive x-axis, and positive sweeps extends Arc clockwise.
3115
3116arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3117is false and Path is not empty. Otherwise, added Contour begins with first point
3118of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3119
3120#Param oval bounds of ellipse containing Arc ##
3121#Param startAngle starting angle of Arc in degrees ##
3122#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3123#Param forceMoveTo true to start a new contour with Arc ##
3124
Cary Clark0251b1b2018-08-15 15:14:55 -04003125#Return reference to Path ##
3126
Cary Clark73fa9722017-08-29 17:36:51 -04003127#Example
3128#Height 200
3129#Description
3130arcTo continues a previous contour when forceMoveTo is false and when Path
3131is not empty.
3132##
3133void draw(SkCanvas* canvas) {
3134 SkPaint paint;
3135 SkPath path;
3136 paint.setStyle(SkPaint::kStroke_Style);
3137 paint.setStrokeWidth(4);
3138 path.moveTo(0, 0);
3139 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3140 canvas->drawPath(path, paint);
3141 path.rewind();
3142 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3143 canvas->drawPath(path, paint);
3144 path.rewind();
3145 path.moveTo(0, 0);
3146 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3147 canvas->drawPath(path, paint);
3148}
3149##
3150
3151#SeeAlso addArc SkCanvas::drawArc conicTo
3152
3153##
3154
3155# ------------------------------------------------------------------------------
3156
Cary Clark0251b1b2018-08-15 15:14:55 -04003157#Method SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003158#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003159#In Arc
Cary Clark80247e52018-07-11 16:18:41 -04003160Appends Arc to Path, after appending Line if needed. Arc is implemented by Conic
Cary Clark73fa9722017-08-29 17:36:51 -04003161weighted to describe part of Circle. Arc is contained by tangent from
3162last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003163is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003164
3165#ToDo allow example to hide source and not be exposed as fiddle ##
3166
3167#Example
3168#Height 226
3169void draw(SkCanvas* canvas) {
3170 SkPaint tangentPaint;
3171 tangentPaint.setAntiAlias(true);
3172 SkPaint textPaint(tangentPaint);
3173 tangentPaint.setStyle(SkPaint::kStroke_Style);
3174 tangentPaint.setColor(SK_ColorGRAY);
3175 SkPaint arcPaint(tangentPaint);
3176 arcPaint.setStrokeWidth(5);
3177 arcPaint.setColor(SK_ColorBLUE);
3178 SkPath path;
3179 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3180 SkScalar radius = 50;
3181 path.moveTo(pts[0]);
3182 path.arcTo(pts[1], pts[2], radius);
3183 canvas->drawLine(pts[0], pts[1], tangentPaint);
3184 canvas->drawLine(pts[1], pts[2], tangentPaint);
3185 SkPoint lastPt;
3186 (void) path.getLastPt(&lastPt);
3187 SkVector radial = pts[2] - pts[1];
3188 radial.setLength(radius);
3189 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3190 canvas->drawCircle(center, radius, tangentPaint);
3191 canvas->drawLine(lastPt, center, tangentPaint);
3192 radial = pts[1] - pts[0];
3193 radial.setLength(radius);
3194 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3195 canvas->drawLine(center, arcStart, tangentPaint);
3196 canvas->drawPath(path, arcPaint);
3197 textPaint.setTextAlign(SkPaint::kRight_Align);
3198 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3199 textPaint.setTextAlign(SkPaint::kLeft_Align);
3200 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3201 textPaint.setTextAlign(SkPaint::kCenter_Align);
3202 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3203 textPaint.setTextAlign(SkPaint::kRight_Align);
3204 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3205 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3206}
3207##
3208
3209If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3210The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3211
3212#Example
3213#Height 128
3214void draw(SkCanvas* canvas) {
3215 SkPaint tangentPaint;
3216 tangentPaint.setAntiAlias(true);
3217 SkPaint textPaint(tangentPaint);
3218 tangentPaint.setStyle(SkPaint::kStroke_Style);
3219 tangentPaint.setColor(SK_ColorGRAY);
3220 SkPaint arcPaint(tangentPaint);
3221 arcPaint.setStrokeWidth(5);
3222 arcPaint.setColor(SK_ColorBLUE);
3223 SkPath path;
3224 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3225 SkScalar radius = 50;
3226 path.moveTo(pts[0]);
3227 path.arcTo(pts[1], pts[2], radius);
3228 canvas->drawLine(pts[0], pts[1], tangentPaint);
3229 canvas->drawLine(pts[1], pts[2], tangentPaint);
3230 SkPoint lastPt;
3231 (void) path.getLastPt(&lastPt);
3232 SkVector radial = pts[2] - pts[1];
3233 radial.setLength(radius);
3234 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3235 canvas->drawLine(lastPt, center, tangentPaint);
3236 radial = pts[1] - pts[0];
3237 radial.setLength(radius);
3238 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3239 canvas->drawLine(center, arcStart, tangentPaint);
3240 canvas->drawPath(path, arcPaint);
3241 textPaint.setTextAlign(SkPaint::kCenter_Align);
3242 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3243 textPaint.setTextAlign(SkPaint::kLeft_Align);
3244 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3245 textPaint.setTextAlign(SkPaint::kCenter_Align);
3246 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3247 textPaint.setTextAlign(SkPaint::kRight_Align);
3248 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3249 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3250}
3251##
3252
3253Arc sweep is always less than 180 degrees. If radius is zero, or if
3254tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3255
3256arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003257arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003258
Cary Clark5538c132018-06-14 12:28:14 -04003259#Param x1 x-axis value common to pair of tangents ##
3260#Param y1 y-axis value common to pair of tangents ##
3261#Param x2 x-axis value end of second tangent ##
3262#Param y2 y-axis value end of second tangent ##
Cary Clark73fa9722017-08-29 17:36:51 -04003263#Param radius distance from Arc to Circle center ##
3264
Cary Clark0251b1b2018-08-15 15:14:55 -04003265#Return reference to Path ##
3266
Cary Clark73fa9722017-08-29 17:36:51 -04003267#Example
3268#Description
3269arcTo is represented by Line and circular Conic in Path.
3270##
3271void draw(SkCanvas* canvas) {
3272 SkPath path;
3273 path.moveTo({156, 20});
3274 path.arcTo(200, 20, 170, 50, 50);
3275 SkPath::Iter iter(path, false);
3276 SkPoint p[4];
3277 SkPath::Verb verb;
3278 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3279 switch (verb) {
3280 case SkPath::kMove_Verb:
3281 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3282 break;
3283 case SkPath::kLine_Verb:
3284 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3285 break;
3286 case SkPath::kConic_Verb:
3287 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3288 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3289 break;
3290 default:
3291 SkDebugf("unexpected verb\n");
3292 }
3293 }
3294}
3295#StdOut
3296move to (156,20)
3297line (156,20),(79.2893,20)
3298conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3299##
3300##
3301
Cary Clark682c58d2018-05-16 07:07:07 -04003302#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003303
3304##
3305
3306# ------------------------------------------------------------------------------
3307
Cary Clark0251b1b2018-08-15 15:14:55 -04003308#Method SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003309#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003310#In Arc
Cary Clark80247e52018-07-11 16:18:41 -04003311Appends Arc to Path, after appending Line if needed. Arc is implemented by Conic
Cary Clark73fa9722017-08-29 17:36:51 -04003312weighted to describe part of Circle. Arc is contained by tangent from
3313last Path point to p1, and tangent from p1 to p2. Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003314is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003315
3316If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3317The length of Vector from p1 to p2 does not affect Arc.
3318
3319Arc sweep is always less than 180 degrees. If radius is zero, or if
3320tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3321
3322arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003323arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003324
3325#Param p1 Point common to pair of tangents ##
3326#Param p2 end of second tangent ##
3327#Param radius distance from Arc to Circle center ##
3328
Cary Clark0251b1b2018-08-15 15:14:55 -04003329#Return reference to Path ##
3330
Cary Clark73fa9722017-08-29 17:36:51 -04003331#Example
3332#Description
3333Because tangent lines are parallel, arcTo appends line from last Path Point to
3334p1, but does not append a circular Conic.
3335##
3336void draw(SkCanvas* canvas) {
3337 SkPath path;
3338 path.moveTo({156, 20});
3339 path.arcTo({200, 20}, {170, 20}, 50);
3340 SkPath::Iter iter(path, false);
3341 SkPoint p[4];
3342 SkPath::Verb verb;
3343 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3344 switch (verb) {
3345 case SkPath::kMove_Verb:
3346 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3347 break;
3348 case SkPath::kLine_Verb:
3349 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3350 break;
3351 case SkPath::kConic_Verb:
3352 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3353 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3354 break;
3355 default:
3356 SkDebugf("unexpected verb\n");
3357 }
3358 }
3359}
3360#StdOut
3361move to (156,20)
3362line (156,20),(200,20)
3363##
3364##
3365
Cary Clark682c58d2018-05-16 07:07:07 -04003366#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003367
3368##
3369
3370# ------------------------------------------------------------------------------
3371
3372#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05003373#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04003374
3375#Code
3376 enum ArcSize {
Cary Clark682c58d2018-05-16 07:07:07 -04003377 kSmall_ArcSize,
3378 kLarge_ArcSize,
Cary Clark73fa9722017-08-29 17:36:51 -04003379 };
3380##
3381
3382Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3383ArcSize and Direction select one of the four Oval parts.
3384
3385#Const kSmall_ArcSize 0
Cary Clark682c58d2018-05-16 07:07:07 -04003386#Line # smaller of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003387##
3388#Const kLarge_ArcSize 1
Cary Clark682c58d2018-05-16 07:07:07 -04003389#Line # larger of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003390##
3391
3392#Example
3393#Height 160
3394#Description
3395Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3396Two routes are large, and two routes are counterclockwise. The one route both large
3397and counterclockwise is blue.
3398##
3399void draw(SkCanvas* canvas) {
3400 SkPaint paint;
3401 paint.setAntiAlias(true);
3402 paint.setStyle(SkPaint::kStroke_Style);
3403 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3404 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3405 SkPath path;
3406 path.moveTo({120, 50});
3407 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3408 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3409 paint.setColor(SK_ColorBLUE);
3410 paint.setStrokeWidth(3);
3411 }
3412 canvas->drawPath(path, paint);
3413 }
3414 }
3415}
3416##
3417
3418#SeeAlso arcTo Direction
3419
3420##
3421
3422# ------------------------------------------------------------------------------
3423
Cary Clark0251b1b2018-08-15 15:14:55 -04003424#Method SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04003425 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003426#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003427#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003428
Cary Clark80247e52018-07-11 16:18:41 -04003429Appends Arc to Path. Arc is implemented by one or more Conics weighted to
Cary Clark154beea2017-10-26 07:58:48 -04003430describe part of Oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
3431curves from last Path Point to (x, y), choosing one of four possible routes:
3432clockwise or counterclockwise, and smaller or larger.
Cary Clark73fa9722017-08-29 17:36:51 -04003433
Cary Clark154beea2017-10-26 07:58:48 -04003434Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if
3435either radii are zero, or if last Path Point equals (x, y). arcTo scales radii
3436(rx, ry) to fit last Path Point and (x, y) if both are greater than zero but
3437too small.
Cary Clark73fa9722017-08-29 17:36:51 -04003438
3439arcTo appends up to four Conic curves.
Cary Clark154beea2017-10-26 07:58:48 -04003440arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value
3441is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise,
3442while kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003443
3444#Param rx radius in x before x-axis rotation ##
3445#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003446#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003447#Param largeArc chooses smaller or larger Arc ##
3448#Param sweep chooses clockwise or counterclockwise Arc ##
3449#Param x end of Arc ##
3450#Param y end of Arc ##
3451
Cary Clark0251b1b2018-08-15 15:14:55 -04003452#Return reference to Path ##
3453
Cary Clark73fa9722017-08-29 17:36:51 -04003454#Example
3455#Height 160
3456void draw(SkCanvas* canvas) {
3457 SkPaint paint;
3458 paint.setAntiAlias(true);
3459 paint.setStyle(SkPaint::kStroke_Style);
3460 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3461 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3462 SkPath path;
3463 path.moveTo({120, 50});
3464 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3465 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3466 paint.setColor(SK_ColorBLUE);
3467 paint.setStrokeWidth(3);
3468 }
3469 canvas->drawPath(path, paint);
3470 }
3471 }
3472}
3473##
3474
3475#SeeAlso rArcTo ArcSize Direction
3476
3477##
3478
3479# ------------------------------------------------------------------------------
3480
Cary Clark0251b1b2018-08-15 15:14:55 -04003481#Method SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04003482 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05003483#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003484#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003485
Cary Clark2be81cf2018-09-13 12:04:30 -04003486Appends Arc to Path. Arc is implemented by one or more Conic weighted to describe
3487part of Oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves
3488from last Path Point to (xy.fX, xy.fY), choosing one of four possible routes:
3489clockwise or counterclockwise,
Cary Clark73fa9722017-08-29 17:36:51 -04003490and smaller or larger.
3491
Cary Clark2be81cf2018-09-13 12:04:30 -04003492Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either
3493radii are zero, or if last Path Point equals (x, y). arcTo scales radii r to fit
3494last Path Point and xy if both are greater than zero but too small to describe
3495an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003496
3497arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003498arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3499opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3500kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003501
Cary Clark5538c132018-06-14 12:28:14 -04003502#Param r radii on axes before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003503#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003504#Param largeArc chooses smaller or larger Arc ##
3505#Param sweep chooses clockwise or counterclockwise Arc ##
3506#Param xy end of Arc ##
3507
Cary Clark0251b1b2018-08-15 15:14:55 -04003508#Return reference to Path ##
3509
Cary Clark73fa9722017-08-29 17:36:51 -04003510#Example
3511#Height 108
3512void draw(SkCanvas* canvas) {
3513 SkPaint paint;
3514 SkPath path;
3515 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3516 for (auto start : starts) {
3517 path.moveTo(start.fX, start.fY);
3518 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3519 }
3520 canvas->drawPath(path, paint);
3521}
3522##
3523
3524#SeeAlso rArcTo ArcSize Direction
3525
3526##
3527
3528# ------------------------------------------------------------------------------
3529
Cary Clark0251b1b2018-08-15 15:14:55 -04003530#Method SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04003531 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003532#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003533#In Arc
3534#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003535
Cary Clark80247e52018-07-11 16:18:41 -04003536Appends Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003537more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04003538xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
Cary Clark2be81cf2018-09-13 12:04:30 -04003539#Formula # (x0 + dx, y0 + dy) ##, choosing one of four possible routes: clockwise or
Cary Clark73fa9722017-08-29 17:36:51 -04003540counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3541is (0, 0).
3542
Cary Clarkce101242017-09-01 15:51:02 -04003543Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3544if either radii are zero, or if last Path Point equals end Point.
3545arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3546greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003547
3548arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003549arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3550opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003551kCW_Direction cast to int is zero.
3552
Cary Clark5538c132018-06-14 12:28:14 -04003553#Param rx radius before x-axis rotation ##
3554#Param ry radius before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003555#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003556#Param largeArc chooses smaller or larger Arc ##
3557#Param sweep chooses clockwise or counterclockwise Arc ##
Cary Clark5538c132018-06-14 12:28:14 -04003558#Param dx x-axis offset end of Arc from last Path Point ##
3559#Param dy y-axis offset end of Arc from last Path Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003560
Cary Clark0251b1b2018-08-15 15:14:55 -04003561#Return reference to Path ##
3562
Cary Clark73fa9722017-08-29 17:36:51 -04003563#Example
3564#Height 108
3565void draw(SkCanvas* canvas) {
3566 SkPaint paint;
3567 SkPath path;
3568 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3569 for (auto start : starts) {
3570 path.moveTo(start.fX, start.fY);
3571 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3572 }
3573 canvas->drawPath(path, paint);
3574}
3575##
3576
3577#SeeAlso arcTo ArcSize Direction
3578
3579##
3580
Cary Clark78de7512018-02-07 07:27:09 -05003581#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003582
3583# ------------------------------------------------------------------------------
3584
Cary Clark0251b1b2018-08-15 15:14:55 -04003585#Method SkPath& close()
Cary Clark4855f782018-02-06 09:41:53 -05003586#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003587#Line # makes last Contour a loop ##
Cary Clark80247e52018-07-11 16:18:41 -04003588Appends kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003589with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003590with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
Cary Clark682c58d2018-05-16 07:07:07 -04003591Paint_Stroke_Cap at Contour start and end; closed Contour draws
Cary Clark73fa9722017-08-29 17:36:51 -04003592Paint_Stroke_Join at Contour start and end.
3593
3594close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3595
Cary Clark0251b1b2018-08-15 15:14:55 -04003596#Return reference to Path ##
3597
Cary Clark73fa9722017-08-29 17:36:51 -04003598#Example
3599void draw(SkCanvas* canvas) {
3600 SkPaint paint;
3601 paint.setStrokeWidth(15);
3602 paint.setStrokeCap(SkPaint::kRound_Cap);
3603 SkPath path;
3604 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3605 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3606 for (int loop = 0; loop < 2; ++loop) {
3607 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3608 SkPaint::kStrokeAndFill_Style} ) {
3609 paint.setStyle(style);
3610 canvas->drawPath(path, paint);
3611 canvas->translate(85, 0);
3612 }
3613 path.close();
3614 canvas->translate(-255, 128);
3615 }
3616}
3617##
3618
Cary Clark682c58d2018-05-16 07:07:07 -04003619#SeeAlso
Cary Clark73fa9722017-08-29 17:36:51 -04003620
3621##
3622
3623# ------------------------------------------------------------------------------
3624
Cary Clark682c58d2018-05-16 07:07:07 -04003625#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003626#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003627#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003628Returns true if fill is inverted and Path with fill represents area outside
3629of its geometric bounds.
3630
3631#Table
3632#Legend
3633# FillType # is inverse ##
3634##
3635# kWinding_FillType # false ##
3636# kEvenOdd_FillType # false ##
3637# kInverseWinding_FillType # true ##
3638# kInverseEvenOdd_FillType # true ##
3639##
3640
3641#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3642 kInverseWinding_FillType, kInverseEvenOdd_FillType
3643##
3644
3645#Return true if Path fills outside its bounds ##
3646
3647#Example
3648#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003649###$
Cary Clark73fa9722017-08-29 17:36:51 -04003650#define nameValue(fill) { SkPath::fill, #fill }
3651
Cary Clark1a8d7622018-03-05 13:26:16 -05003652$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003653##
3654void draw(SkCanvas* canvas) {
3655 struct {
3656 SkPath::FillType fill;
3657 const char* name;
3658 } fills[] = {
3659 nameValue(kWinding_FillType),
3660 nameValue(kEvenOdd_FillType),
3661 nameValue(kInverseWinding_FillType),
3662 nameValue(kInverseEvenOdd_FillType),
3663 };
3664 for (auto fill: fills ) {
3665 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3666 "true" : "false");
3667 }
3668}
3669#StdOut
3670IsInverseFillType(kWinding_FillType) == false
3671IsInverseFillType(kEvenOdd_FillType) == false
3672IsInverseFillType(kInverseWinding_FillType) == true
3673IsInverseFillType(kInverseEvenOdd_FillType) == true
3674##
3675##
3676
3677#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3678
3679##
3680
3681# ------------------------------------------------------------------------------
3682
Cary Clark682c58d2018-05-16 07:07:07 -04003683#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003684#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003685#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003686Returns equivalent Fill_Type representing Path fill inside its bounds.
3687.
3688
3689#Table
3690#Legend
3691# FillType # inside FillType ##
3692##
3693# kWinding_FillType # kWinding_FillType ##
3694# kEvenOdd_FillType # kEvenOdd_FillType ##
3695# kInverseWinding_FillType # kWinding_FillType ##
3696# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3697##
3698
3699#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3700 kInverseWinding_FillType, kInverseEvenOdd_FillType
3701##
3702
3703#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3704
3705#Example
3706#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003707###$
Cary Clark73fa9722017-08-29 17:36:51 -04003708#define nameValue(fill) { SkPath::fill, #fill }
3709
Cary Clark1a8d7622018-03-05 13:26:16 -05003710$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003711##
3712void draw(SkCanvas* canvas) {
3713 struct {
3714 SkPath::FillType fill;
3715 const char* name;
3716 } fills[] = {
3717 nameValue(kWinding_FillType),
3718 nameValue(kEvenOdd_FillType),
3719 nameValue(kInverseWinding_FillType),
3720 nameValue(kInverseEvenOdd_FillType),
3721 };
3722 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3723 if (fills[i].fill != (SkPath::FillType) i) {
3724 SkDebugf("fills array order does not match FillType enum order");
3725 break;
Cary Clark682c58d2018-05-16 07:07:07 -04003726 }
Cary Clark73fa9722017-08-29 17:36:51 -04003727 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3728 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3729 }
3730}
3731#StdOut
3732ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3733ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3734ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3735ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3736##
3737##
3738
3739#SeeAlso FillType getFillType setFillType IsInverseFillType
3740
3741##
3742
3743# ------------------------------------------------------------------------------
3744
3745#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3746 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05003747#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003748#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04003749
3750Approximates Conic with Quad array. Conic is constructed from start Point p0,
Cary Clark682c58d2018-05-16 07:07:07 -04003751control Point p1, end Point p2, and weight w.
Cary Clark73fa9722017-08-29 17:36:51 -04003752Quad array is stored in pts; this storage is supplied by caller.
3753Maximum Quad count is 2 to the pow2.
Cary Clark682c58d2018-05-16 07:07:07 -04003754Every third point in array shares last Point of previous Quad and first Point of
3755next Quad. Maximum pts storage size is given by:
Cary Clark2be81cf2018-09-13 12:04:30 -04003756#Formula # (1 + 2 * (1 << pow2)) * sizeof(SkPoint) ##.
Cary Clark6fc50412017-09-21 12:31:06 -04003757
Cary Clark154beea2017-10-26 07:58:48 -04003758Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04003759than the number requested.
Cary Clark682c58d2018-05-16 07:07:07 -04003760
Cary Clark73fa9722017-08-29 17:36:51 -04003761Conic_Weight determines the amount of influence Conic control point has on the curve.
3762w less than one represents an elliptical section. w greater than one represents
3763a hyperbolic section. w equal to one represents a parabolic section.
3764
3765Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3766of up to 90 degrees; in this case, set pow2 to one.
3767
3768#Param p0 Conic start Point ##
3769#Param p1 Conic control Point ##
3770#Param p2 Conic end Point ##
3771#Param w Conic weight ##
3772#Param pts storage for Quad array ##
3773#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3774
Cary Clarka523d2d2017-08-30 08:58:10 -04003775#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003776
3777#Example
3778#Description
3779A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3780The middle curve is nearly circular. The top-right curve is parabolic, which can
3781be drawn exactly with a single Quad.
3782##
3783void draw(SkCanvas* canvas) {
3784 SkPaint conicPaint;
3785 conicPaint.setAntiAlias(true);
3786 conicPaint.setStyle(SkPaint::kStroke_Style);
3787 SkPaint quadPaint(conicPaint);
3788 quadPaint.setColor(SK_ColorRED);
3789 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3790 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3791 SkPoint quads[5];
3792 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3793 SkPath path;
3794 path.moveTo(conic[0]);
3795 path.conicTo(conic[1], conic[2], weight);
3796 canvas->drawPath(path, conicPaint);
3797 path.rewind();
3798 path.moveTo(quads[0]);
3799 path.quadTo(quads[1], quads[2]);
3800 path.quadTo(quads[3], quads[4]);
3801 canvas->drawPath(path, quadPaint);
3802 canvas->translate(50, -50);
3803 }
3804}
3805##
3806
3807#SeeAlso Conic Quad
3808
3809##
3810
3811# ------------------------------------------------------------------------------
3812
3813#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003814#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003815#Line # returns if describes Rect ##
Cary Clarkce101242017-09-01 15:51:02 -04003816Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003817If false: rect, isClosed, and direction are unchanged.
3818If true: rect, isClosed, and direction are written to if not nullptr.
3819
3820rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3821that do not alter the area drawn by the returned rect.
3822
3823#Param rect storage for bounds of Rect; may be nullptr ##
3824#Param isClosed storage set to true if Path is closed; may be nullptr ##
3825#Param direction storage set to Rect direction; may be nullptr ##
3826
3827#Return true if Path contains Rect ##
3828
3829#Example
3830#Description
3831After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3832following lineTo does not. addPoly returns true even though rect is not closed, and one
3833side of rect is made up of consecutive line segments.
3834##
3835void draw(SkCanvas* canvas) {
3836 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3837 SkRect rect;
3838 SkPath::Direction direction;
3839 bool isClosed;
Cary Clark682c58d2018-05-16 07:07:07 -04003840 path.isRect(&rect, &isClosed, &direction) ?
Cary Clark73fa9722017-08-29 17:36:51 -04003841 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3842 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3843 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3844 SkDebugf("%s is not rect\n", prefix);
3845 };
3846 SkPath path;
3847 debugster("empty", path);
3848 path.addRect({10, 20, 30, 40});
3849 debugster("addRect", path);
3850 path.moveTo(60, 70);
3851 debugster("moveTo", path);
3852 path.lineTo(60, 70);
3853 debugster("lineTo", path);
3854 path.reset();
3855 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3856 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3857 debugster("addPoly", path);
3858}
3859#StdOut
3860empty is not rect
3861addRect is rect (10, 20, 30, 40); is closed; direction CW
3862moveTo is rect (10, 20, 30, 40); is closed; direction CW
3863lineTo is not rect
3864addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3865##
3866##
3867
3868#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3869
3870##
3871
3872# ------------------------------------------------------------------------------
3873
3874#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003875#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003876#Line # returns if describes Rect pair, one inside the other ##
Cary Clark73fa9722017-08-29 17:36:51 -04003877Returns true if Path is equivalent to nested Rect pair when filled.
3878If false, rect and dirs are unchanged.
3879If true, rect and dirs are written to if not nullptr:
3880setting rect[0] to outer Rect, and rect[1] to inner Rect;
3881setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3882Rect.
3883
3884#Param rect storage for Rect pair; may be nullptr ##
3885#Param dirs storage for Direction pair; may be nullptr ##
3886
3887#Return true if Path contains nested Rect pair ##
3888
3889#Example
3890void draw(SkCanvas* canvas) {
3891 SkPaint paint;
3892 paint.setStyle(SkPaint::kStroke_Style);
3893 paint.setStrokeWidth(5);
3894 SkPath path;
3895 path.addRect({10, 20, 30, 40});
3896 paint.getFillPath(path, &path);
3897 SkRect rects[2];
3898 SkPath::Direction directions[2];
3899 if (path.isNestedFillRects(rects, directions)) {
3900 for (int i = 0; i < 2; ++i) {
3901 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3902 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3903 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3904 }
3905 } else {
3906 SkDebugf("is not nested rectangles\n");
3907 }
3908}
3909#StdOut
3910outer (7.5, 17.5, 32.5, 42.5); direction CW
3911inner (12.5, 22.5, 27.5, 37.5); direction CCW
3912##
3913##
3914
3915#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3916
3917##
3918
3919# ------------------------------------------------------------------------------
3920
Cary Clark0251b1b2018-08-15 15:14:55 -04003921#Method SkPath& addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003922#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003923#Line # adds one Contour containing Rect ##
Cary Clark80247e52018-07-11 16:18:41 -04003924Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -04003925starting with top-left corner of Rect; followed by top-right, bottom-right,
3926and bottom-left if dir is kCW_Direction; or followed by bottom-left,
3927bottom-right, and top-right if dir is kCCW_Direction.
3928
3929#Param rect Rect to add as a closed contour ##
3930#Param dir Direction to wind added contour ##
3931
Cary Clark0251b1b2018-08-15 15:14:55 -04003932#Return reference to Path ##
3933
Cary Clark73fa9722017-08-29 17:36:51 -04003934#Example
3935#Description
3936The left Rect dashes starting at the top-left corner, to the right.
3937The right Rect dashes starting at the top-left corner, towards the bottom.
3938##
3939#Height 128
3940void draw(SkCanvas* canvas) {
3941 SkPaint paint;
3942 paint.setStrokeWidth(15);
3943 paint.setStrokeCap(SkPaint::kSquare_Cap);
3944 float intervals[] = { 5, 21.75f };
3945 paint.setStyle(SkPaint::kStroke_Style);
3946 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3947 SkPath path;
3948 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
3949 canvas->drawPath(path, paint);
3950 path.rewind();
3951 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
3952 canvas->drawPath(path, paint);
3953}
3954##
3955
3956#SeeAlso SkCanvas::drawRect Direction
3957
3958##
3959
3960# ------------------------------------------------------------------------------
3961
Cary Clark0251b1b2018-08-15 15:14:55 -04003962#Method SkPath& addRect(const SkRect& rect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04003963
Cary Clark80247e52018-07-11 16:18:41 -04003964Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04003965If dir is kCW_Direction, Rect corners are added clockwise; if dir is
3966kCCW_Direction, Rect corners are added counterclockwise.
3967start determines the first corner added.
3968
3969#Table
3970#Legend
3971# start # first corner ##
3972#Legend ##
3973# 0 # top-left ##
3974# 1 # top-right ##
3975# 2 # bottom-right ##
3976# 3 # bottom-left ##
3977#Table ##
3978
3979#Param rect Rect to add as a closed contour ##
3980#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04003981#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04003982
Cary Clark0251b1b2018-08-15 15:14:55 -04003983#Return reference to Path ##
3984
Cary Clark73fa9722017-08-29 17:36:51 -04003985#Example
3986#Height 128
3987#Description
3988The arrow is just after the initial corner and points towards the next
3989corner appended to Path.
3990##
3991void draw(SkCanvas* canvas) {
3992 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
3993 const SkRect rect = {10, 10, 54, 54};
3994 SkPaint rectPaint;
3995 rectPaint.setAntiAlias(true);
3996 rectPaint.setStyle(SkPaint::kStroke_Style);
3997 SkPaint arrowPaint(rectPaint);
3998 SkPath arrowPath;
3999 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4000 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4001 SkPath1DPathEffect::kRotate_Style));
4002 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4003 for (unsigned start : { 0, 1, 2, 3 } ) {
4004 SkPath path;
4005 path.addRect(rect, direction, start);
4006 canvas->drawPath(path, rectPaint);
4007 canvas->drawPath(path, arrowPaint);
4008 canvas->translate(64, 0);
4009 }
4010 canvas->translate(-256, 64);
4011 }
4012}
4013##
4014
4015#SeeAlso SkCanvas::drawRect Direction
4016
4017##
4018
4019# ------------------------------------------------------------------------------
4020
Cary Clark0251b1b2018-08-15 15:14:55 -04004021#Method SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
Cary Clark73fa9722017-08-29 17:36:51 -04004022 Direction dir = kCW_Direction)
4023
Cary Clark80247e52018-07-11 16:18:41 -04004024Adds Rect (left, top, right, bottom) to Path,
Cary Clark73fa9722017-08-29 17:36:51 -04004025appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4026starting with top-left corner of Rect; followed by top-right, bottom-right,
4027and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4028bottom-right, and top-right if dir is kCCW_Direction.
4029
Cary Clark5538c132018-06-14 12:28:14 -04004030#Param left smaller x-axis value of Rect ##
4031#Param top smaller y-axis value of Rect ##
4032#Param right larger x-axis value of Rect ##
4033#Param bottom larger y-axis value of Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004034#Param dir Direction to wind added contour ##
4035
Cary Clark0251b1b2018-08-15 15:14:55 -04004036#Return reference to Path ##
4037
Cary Clark73fa9722017-08-29 17:36:51 -04004038#Example
4039#Description
4040The left Rect dashes start at the top-left corner, and continue to the right.
4041The right Rect dashes start at the top-left corner, and continue down.
4042##
4043#Height 128
4044void draw(SkCanvas* canvas) {
4045 SkPaint paint;
4046 paint.setStrokeWidth(15);
4047 paint.setStrokeCap(SkPaint::kSquare_Cap);
4048 float intervals[] = { 5, 21.75f };
4049 paint.setStyle(SkPaint::kStroke_Style);
4050 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4051 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4052 SkPath path;
4053 path.addRect(20, 20, 100, 100, direction);
4054 canvas->drawPath(path, paint);
4055 canvas->translate(128, 0);
4056 }
4057}
4058##
4059
4060#SeeAlso SkCanvas::drawRect Direction
4061
4062##
4063
4064# ------------------------------------------------------------------------------
4065
Cary Clark0251b1b2018-08-15 15:14:55 -04004066#Method SkPath& addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004067#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004068#Line # adds one Contour containing Oval ##
Cary Clark80247e52018-07-11 16:18:41 -04004069Adds Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04004070Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4071and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4072clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4073
Cary Clark73fa9722017-08-29 17:36:51 -04004074#Param oval bounds of ellipse added ##
4075#Param dir Direction to wind ellipse ##
4076
Cary Clark0251b1b2018-08-15 15:14:55 -04004077#Return reference to Path ##
4078
Cary Clark73fa9722017-08-29 17:36:51 -04004079#Example
4080#Height 120
4081 SkPaint paint;
4082 SkPath oval;
4083 oval.addOval({20, 20, 160, 80});
4084 canvas->drawPath(oval, paint);
4085##
4086
4087#SeeAlso SkCanvas::drawOval Direction Oval
4088
4089##
4090
4091# ------------------------------------------------------------------------------
4092
Cary Clark0251b1b2018-08-15 15:14:55 -04004093#Method SkPath& addOval(const SkRect& oval, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04004094
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 start and continues
4098clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4099
4100#Table
4101#Legend
4102# start # Point ##
4103#Legend ##
4104# 0 # oval.centerX(), oval.fTop ##
4105# 1 # oval.fRight, oval.centerY() ##
4106# 2 # oval.centerX(), oval.fBottom ##
4107# 3 # oval.fLeft, oval.centerY() ##
4108#Table ##
4109
4110#Param oval bounds of ellipse added ##
4111#Param dir Direction to wind ellipse ##
4112#Param start index of initial point of ellipse ##
4113
Cary Clark0251b1b2018-08-15 15:14:55 -04004114#Return reference to Path ##
4115
Cary Clark73fa9722017-08-29 17:36:51 -04004116#Example
4117#Height 160
4118void draw(SkCanvas* canvas) {
4119 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4120 const SkRect rect = {10, 10, 54, 54};
4121 SkPaint ovalPaint;
4122 ovalPaint.setAntiAlias(true);
4123 SkPaint textPaint(ovalPaint);
4124 textPaint.setTextAlign(SkPaint::kCenter_Align);
4125 ovalPaint.setStyle(SkPaint::kStroke_Style);
4126 SkPaint arrowPaint(ovalPaint);
4127 SkPath arrowPath;
4128 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4129 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4130 SkPath1DPathEffect::kRotate_Style));
4131 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4132 for (unsigned start : { 0, 1, 2, 3 } ) {
4133 SkPath path;
4134 path.addOval(rect, direction, start);
4135 canvas->drawPath(path, ovalPaint);
4136 canvas->drawPath(path, arrowPaint);
4137 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4138 canvas->translate(64, 0);
4139 }
4140 canvas->translate(-256, 72);
4141 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4142 128, 0, textPaint);
4143 }
4144}
4145##
4146
4147#SeeAlso SkCanvas::drawOval Direction Oval
4148
4149##
4150
4151# ------------------------------------------------------------------------------
4152
Cary Clark0251b1b2018-08-15 15:14:55 -04004153#Method SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
Cary Clark73fa9722017-08-29 17:36:51 -04004154 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004155#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004156#Line # adds one Contour containing Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04004157
Cary Clark80247e52018-07-11 16:18:41 -04004158Adds Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark2be81cf2018-09-13 12:04:30 -04004159four kConic_Verb, and kClose_Verb. Circle begins at: #Formula # (x + radius, y) ##, continuing
Cary Clark154beea2017-10-26 07:58:48 -04004160clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04004161
Cary Clark6fc50412017-09-21 12:31:06 -04004162Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004163
4164#Param x center of Circle ##
4165#Param y center of Circle ##
4166#Param radius distance from center to edge ##
4167#Param dir Direction to wind Circle ##
4168
Cary Clark0251b1b2018-08-15 15:14:55 -04004169#Return reference to Path ##
4170
Cary Clark73fa9722017-08-29 17:36:51 -04004171#Example
4172void draw(SkCanvas* canvas) {
4173 SkPaint paint;
4174 paint.setAntiAlias(true);
4175 paint.setStyle(SkPaint::kStroke_Style);
4176 paint.setStrokeWidth(10);
4177 for (int size = 10; size < 300; size += 20) {
4178 SkPath path;
4179 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4180 canvas->drawPath(path, paint);
4181 }
4182}
4183##
4184
4185#SeeAlso SkCanvas::drawCircle Direction Circle
4186
4187##
4188
4189# ------------------------------------------------------------------------------
4190
Cary Clark0251b1b2018-08-15 15:14:55 -04004191#Method SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05004192#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004193#Line # adds one Contour containing Arc ##
Cary Clark80247e52018-07-11 16:18:41 -04004194Appends Arc to Path, as the start of new Contour. Arc added is part of ellipse
Cary Clark73fa9722017-08-29 17:36:51 -04004195bounded by oval, from startAngle through sweepAngle. Both startAngle and
4196sweepAngle are measured in degrees, where zero degrees is aligned with the
4197positive x-axis, and positive sweeps extends Arc clockwise.
4198
Cary Clark682c58d2018-05-16 07:07:07 -04004199If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4200zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
Cary Clark73fa9722017-08-29 17:36:51 -04004201modulo 360, and Arc may or may not draw depending on numeric rounding.
4202
4203#Param oval bounds of ellipse containing Arc ##
4204#Param startAngle starting angle of Arc in degrees ##
4205#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4206
Cary Clark0251b1b2018-08-15 15:14:55 -04004207#Return reference to Path ##
4208
Cary Clark73fa9722017-08-29 17:36:51 -04004209#Example
4210#Description
4211The middle row of the left and right columns draw differently from the entries
Cary Clark682c58d2018-05-16 07:07:07 -04004212above and below because sweepAngle is outside of the range of +/-360,
Cary Clark73fa9722017-08-29 17:36:51 -04004213and startAngle modulo 90 is not zero.
4214##
4215void draw(SkCanvas* canvas) {
4216 SkPaint paint;
4217 for (auto start : { 0, 90, 135, 180, 270 } ) {
4218 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4219 SkPath path;
4220 path.addArc({10, 10, 35, 45}, start, sweep);
4221 canvas->drawPath(path, paint);
4222 canvas->translate(252 / 6, 0);
4223 }
4224 canvas->translate(-252, 255 / 5);
4225 }
4226}
4227##
4228
4229#SeeAlso Arc arcTo SkCanvas::drawArc
4230
4231##
4232
4233# ------------------------------------------------------------------------------
4234
Cary Clark0251b1b2018-08-15 15:14:55 -04004235#Method SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Cary Clark73fa9722017-08-29 17:36:51 -04004236 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004237#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004238#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark73fa9722017-08-29 17:36:51 -04004239
Cary Clark80247e52018-07-11 16:18:41 -04004240Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04004241equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4242dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4243winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4244of the upper-left corner and winds counterclockwise.
4245
4246If either rx or ry is too large, rx and ry are scaled uniformly until the
4247corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4248Rect rect to Path.
4249
4250After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4251
4252#Param rect bounds of Round_Rect ##
Cary Clark5538c132018-06-14 12:28:14 -04004253#Param rx x-axis radius of rounded corners on the Round_Rect ##
4254#Param ry y-axis radius of rounded corners on the Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004255#Param dir Direction to wind Round_Rect ##
4256
Cary Clark0251b1b2018-08-15 15:14:55 -04004257#Return reference to Path ##
4258
Cary Clark73fa9722017-08-29 17:36:51 -04004259#Example
4260#Description
4261If either radius is zero, path contains Rect and is drawn red.
4262If sides are only radii, path contains Oval and is drawn blue.
4263All remaining path draws are convex, and are drawn in gray; no
4264paths constructed from addRoundRect are concave, so none are
4265drawn in green.
4266##
4267void draw(SkCanvas* canvas) {
4268 SkPaint paint;
4269 paint.setAntiAlias(true);
4270 for (auto xradius : { 0, 7, 13, 20 } ) {
4271 for (auto yradius : { 0, 9, 18, 40 } ) {
4272 SkPath path;
4273 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4274 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4275 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4276 canvas->drawPath(path, paint);
4277 canvas->translate(64, 0);
4278 }
4279 canvas->translate(-256, 64);
4280 }
4281}
4282##
4283
4284#SeeAlso addRRect SkCanvas::drawRoundRect
4285
4286##
4287
4288# ------------------------------------------------------------------------------
4289
Cary Clark0251b1b2018-08-15 15:14:55 -04004290#Method SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
Cary Clark73fa9722017-08-29 17:36:51 -04004291 Direction dir = kCW_Direction)
4292
Cary Clark80247e52018-07-11 16:18:41 -04004293Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04004294equal to rect; each corner is 90 degrees of an ellipse with radii from the
4295array.
4296
4297#Table
4298#Legend
4299# radii index # location ##
4300#Legend ##
Cary Clark5538c132018-06-14 12:28:14 -04004301# 0 # x-axis radius of top-left corner ##
4302# 1 # y-axis radius of top-left corner ##
4303# 2 # x-axis radius of top-right corner ##
4304# 3 # y-axis radius of top-right corner ##
4305# 4 # x-axis radius of bottom-right corner ##
4306# 5 # y-axis radius of bottom-right corner ##
4307# 6 # x-axis radius of bottom-left corner ##
4308# 7 # y-axis radius of bottom-left corner ##
Cary Clark73fa9722017-08-29 17:36:51 -04004309#Table ##
4310
Cary Clark682c58d2018-05-16 07:07:07 -04004311If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4312and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
Cary Clark73fa9722017-08-29 17:36:51 -04004313bottom-left of the upper-left corner and winds counterclockwise.
4314
Cary Clark682c58d2018-05-16 07:07:07 -04004315If both radii on any side of rect exceed its length, all radii are scaled
Cary Clark73fa9722017-08-29 17:36:51 -04004316uniformly until the corners fit. If either radius of a corner is less than or
4317equal to zero, both are treated as zero.
4318
4319After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4320
4321#Param rect bounds of Round_Rect ##
4322#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4323#Param dir Direction to wind Round_Rect ##
4324
Cary Clark0251b1b2018-08-15 15:14:55 -04004325#Return reference to Path ##
4326
Cary Clark73fa9722017-08-29 17:36:51 -04004327#Example
4328void draw(SkCanvas* canvas) {
4329 SkPaint paint;
4330 paint.setAntiAlias(true);
4331 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4332 SkPath path;
4333 SkMatrix rotate90;
4334 rotate90.setRotate(90, 128, 128);
4335 for (int i = 0; i < 4; ++i) {
4336 path.addRoundRect({10, 10, 110, 110}, radii);
4337 path.transform(rotate90);
4338 }
4339 canvas->drawPath(path, paint);
4340}
4341##
4342
4343#SeeAlso addRRect SkCanvas::drawRoundRect
4344
4345##
4346
4347# ------------------------------------------------------------------------------
4348
Cary Clark0251b1b2018-08-15 15:14:55 -04004349#Method SkPath& addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004350#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004351#Line # adds one Contour containing Round_Rect ##
Cary Clark80247e52018-07-11 16:18:41 -04004352Adds rrect to Path, creating a new closed Contour. If
Cary Clark73fa9722017-08-29 17:36:51 -04004353dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4354winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4355of the upper-left corner and winds counterclockwise.
4356
4357After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4358
4359#Param rrect bounds and radii of rounded rectangle ##
4360#Param dir Direction to wind Round_Rect ##
4361
Cary Clark0251b1b2018-08-15 15:14:55 -04004362#Return reference to Path ##
4363
Cary Clark73fa9722017-08-29 17:36:51 -04004364#Example
4365void draw(SkCanvas* canvas) {
4366 SkPaint paint;
4367 paint.setAntiAlias(true);
4368 SkRRect rrect;
4369 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4370 rrect.setRectRadii({10, 10, 110, 110}, radii);
4371 SkPath path;
4372 SkMatrix rotate90;
4373 rotate90.setRotate(90, 128, 128);
4374 for (int i = 0; i < 4; ++i) {
4375 path.addRRect(rrect);
4376 path.transform(rotate90);
4377 }
4378 canvas->drawPath(path, paint);
4379}
4380##
4381
4382#SeeAlso addRoundRect SkCanvas::drawRRect
4383
4384##
4385
4386# ------------------------------------------------------------------------------
4387
Cary Clark0251b1b2018-08-15 15:14:55 -04004388#Method SkPath& addRRect(const SkRRect& rrect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04004389
Cary Clark80247e52018-07-11 16:18:41 -04004390Adds rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
Cary Clark73fa9722017-08-29 17:36:51 -04004391winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4392start determines the first point of rrect to add.
4393
4394#Table
4395#Legend
4396# start # location ##
4397#Legend ##
4398# 0 # right of top-left corner ##
4399# 1 # left of top-right corner ##
4400# 2 # bottom of top-right corner ##
4401# 3 # top of bottom-right corner ##
4402# 4 # left of bottom-right corner ##
4403# 5 # right of bottom-left corner ##
4404# 6 # top of bottom-left corner ##
4405# 7 # bottom of top-left corner ##
4406#Table ##
4407
4408After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4409
4410#Param rrect bounds and radii of rounded rectangle ##
4411#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004412#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004413
Cary Clark0251b1b2018-08-15 15:14:55 -04004414#Return reference to Path ##
4415
Cary Clark73fa9722017-08-29 17:36:51 -04004416#Example
Cary Clark153e76d2018-08-28 11:48:28 -04004417###$
4418$Function
4419#include "SkTextOnPath.h"
4420$$
4421
Cary Clark73fa9722017-08-29 17:36:51 -04004422void draw(SkCanvas* canvas) {
4423 SkPaint paint;
4424 paint.setAntiAlias(true);
4425 SkRRect rrect;
4426 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4427 SkPath path;
4428 path.addRRect(rrect);
4429 canvas->drawPath(path, paint);
4430 for (int start = 0; start < 8; ++start) {
4431 SkPath textPath;
4432 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
Cary Clark153e76d2018-08-28 11:48:28 -04004433 SkMatrix matrix;
4434 matrix.setTranslate(0, -5);
4435 SkDrawTextOnPath(&"01234567"[start], 1, paint, textPath, &matrix, canvas);
Cary Clark73fa9722017-08-29 17:36:51 -04004436 }
4437}
Cary Clark153e76d2018-08-28 11:48:28 -04004438$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04004439##
4440
Cary Clark682c58d2018-05-16 07:07:07 -04004441#SeeAlso addRoundRect SkCanvas::drawRRect
Cary Clark73fa9722017-08-29 17:36:51 -04004442
4443##
4444
4445# ------------------------------------------------------------------------------
4446
Cary Clark0251b1b2018-08-15 15:14:55 -04004447#Method SkPath& addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05004448#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004449#Line # adds one Contour containing connected lines ##
Cary Clark80247e52018-07-11 16:18:41 -04004450Adds Contour created from Line array, adding (count - 1) Line segments.
Cary Clark6fc50412017-09-21 12:31:06 -04004451Contour added starts at pts[0], then adds a line for every additional Point
Cary Clark0251b1b2018-08-15 15:14:55 -04004452in pts array. If close is true, appends kClose_Verb to Path, connecting
Cary Clark6fc50412017-09-21 12:31:06 -04004453pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004454
4455If count is zero, append kMove_Verb to path.
4456Has no effect if count is less than one.
Cary Clark682c58d2018-05-16 07:07:07 -04004457
Cary Clarka523d2d2017-08-30 08:58:10 -04004458#Param pts array of Line sharing end and start Point ##
4459#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004460#Param close true to add Line connecting Contour end and start ##
4461
Cary Clark0251b1b2018-08-15 15:14:55 -04004462#Return reference to Path ##
4463
Cary Clark73fa9722017-08-29 17:36:51 -04004464#Example
4465void draw(SkCanvas* canvas) {
4466 SkPaint paint;
4467 paint.setStrokeWidth(15);
4468 paint.setStrokeCap(SkPaint::kRound_Cap);
4469 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4470 for (bool close : { false, true } ) {
4471 SkPath path;
4472 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4473 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4474 SkPaint::kStrokeAndFill_Style} ) {
4475 paint.setStyle(style);
4476 canvas->drawPath(path, paint);
4477 canvas->translate(85, 0);
4478 }
4479 canvas->translate(-255, 128);
4480 }
4481}
4482##
4483
4484#SeeAlso SkCanvas::drawPoints
4485
4486##
4487
Cary Clark0251b1b2018-08-15 15:14:55 -04004488#Method SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close)
4489
4490Adds Contour created from list. Contour added starts at list[0], then adds a line
4491for every additional Point in list. If close is true, appends kClose_Verb to Path,
4492connecting last and first Point in list.
4493
4494If list is empty, append kMove_Verb to path.
4495
4496#Param list array of Points ##
4497#Param close true to add Line connecting Contour end and start ##
4498
4499#Return reference to Path ##
4500
4501#Example
4502void draw(SkCanvas* canvas) {
4503 SkPaint paint;
4504 paint.setStrokeWidth(15);
4505 paint.setStrokeCap(SkPaint::kRound_Cap);
4506 for (bool close : { false, true } ) {
4507 SkPath path;
4508 path.addPoly({{20, 20}, {70, 20}, {40, 90}}, close);
4509 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4510 SkPaint::kStrokeAndFill_Style} ) {
4511 paint.setStyle(style);
4512 canvas->drawPath(path, paint);
4513 canvas->translate(85, 0);
4514 }
4515 canvas->translate(-255, 128);
4516 }
4517}
4518##
4519
4520#SeeAlso SkCanvas::drawPoints
4521
4522##
4523
Cary Clark73fa9722017-08-29 17:36:51 -04004524# ------------------------------------------------------------------------------
4525
4526#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05004527#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04004528
4529#Code
4530 enum AddPathMode {
Cary Clark682c58d2018-05-16 07:07:07 -04004531 kAppend_AddPathMode,
4532 kExtend_AddPathMode,
Cary Clark73fa9722017-08-29 17:36:51 -04004533 };
4534##
4535
4536AddPathMode chooses how addPath appends. Adding one Path to another can extend
4537the last Contour or start a new Contour.
4538
4539#Const kAppend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004540#Line # appended to destination unaltered ##
Cary Clark73fa9722017-08-29 17:36:51 -04004541 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4542 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4543 starts a new Contour.
4544##
4545#Const kExtend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004546#Line # add line if prior Contour is not closed ##
Cary Clark73fa9722017-08-29 17:36:51 -04004547 If destination is closed or empty, start a new Contour. If destination
4548 is not empty, add Line from Last_Point to added Path first Point. Skip added
4549 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4550##
4551
4552#Example
4553#Description
4554test is built from path, open on the top row, and closed on the bottom row.
4555The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4556The top right composition is made up of one contour; the other three have two.
4557##
4558#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004559 SkPath path, path2;
4560 path.moveTo(20, 20);
4561 path.lineTo(20, 40);
4562 path.lineTo(40, 20);
4563 path2.moveTo(60, 60);
4564 path2.lineTo(80, 60);
4565 path2.lineTo(80, 40);
4566 SkPaint paint;
4567 paint.setStyle(SkPaint::kStroke_Style);
4568 for (int i = 0; i < 2; i++) {
4569 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4570 SkPath test(path);
4571 test.addPath(path2, addPathMode);
4572 canvas->drawPath(test, paint);
4573 canvas->translate(100, 0);
4574 }
4575 canvas->translate(-200, 100);
4576 path.close();
4577 }
Cary Clark73fa9722017-08-29 17:36:51 -04004578##
4579
4580#SeeAlso addPath reverseAddPath
4581
4582##
4583
4584# ------------------------------------------------------------------------------
4585
Cary Clark0251b1b2018-08-15 15:14:55 -04004586#Method SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
Cary Clark73fa9722017-08-29 17:36:51 -04004587 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05004588#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004589#Line # adds contents of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004590
Cary Clark80247e52018-07-11 16:18:41 -04004591Appends src to Path, offset by (dx, dy).
Cary Clark73fa9722017-08-29 17:36:51 -04004592
4593If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4594added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004595Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004596
4597#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clark5538c132018-06-14 12:28:14 -04004598#Param dx offset added to src Point_Array x-axis coordinates ##
4599#Param dy offset added to src Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004600#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4601
Cary Clark0251b1b2018-08-15 15:14:55 -04004602#Return reference to Path ##
4603
Cary Clark73fa9722017-08-29 17:36:51 -04004604#Example
4605#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004606 SkPaint paint;
4607 paint.setTextSize(128);
4608 paint.setFakeBoldText(true);
4609 SkPath dest, text;
4610 paint.getTextPath("O", 1, 50, 120, &text);
4611 for (int i = 0; i < 3; i++) {
4612 dest.addPath(text, i * 20, i * 20);
4613 }
4614 Simplify(dest, &dest);
4615 paint.setStyle(SkPaint::kStroke_Style);
4616 paint.setStrokeWidth(3);
4617 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004618##
4619
Cary Clark4855f782018-02-06 09:41:53 -05004620#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004621
4622##
4623
4624# ------------------------------------------------------------------------------
4625
Cary Clark0251b1b2018-08-15 15:14:55 -04004626#Method SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
Cary Clark73fa9722017-08-29 17:36:51 -04004627
Cary Clark80247e52018-07-11 16:18:41 -04004628Appends src to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04004629
4630If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4631added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004632Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004633
4634#Param src Path Verbs, Points, and Conic_Weights to add ##
4635#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4636
Cary Clark0251b1b2018-08-15 15:14:55 -04004637#Return reference to Path ##
4638
Cary Clark73fa9722017-08-29 17:36:51 -04004639#Example
4640#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004641 SkPaint paint;
4642 paint.setStyle(SkPaint::kStroke_Style);
4643 SkPath dest, path;
4644 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4645 for (int i = 0; i < 2; i++) {
4646 dest.addPath(path, SkPath::kExtend_AddPathMode);
4647 dest.offset(100, 0);
4648 }
Cary Clark73fa9722017-08-29 17:36:51 -04004649 canvas->drawPath(dest, paint);
4650##
4651
4652#SeeAlso AddPathMode reverseAddPath
4653
4654##
4655
4656# ------------------------------------------------------------------------------
4657
Cary Clark0251b1b2018-08-15 15:14:55 -04004658#Method SkPath& addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
Cary Clark73fa9722017-08-29 17:36:51 -04004659
Cary Clark80247e52018-07-11 16:18:41 -04004660Appends src to Path, transformed by matrix. Transformed curves may have different
Cary Clark73fa9722017-08-29 17:36:51 -04004661Verbs, Points, and Conic_Weights.
4662
4663If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4664added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004665Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004666
4667#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004668#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004669#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4670
Cary Clark0251b1b2018-08-15 15:14:55 -04004671#Return reference to Path ##
4672
Cary Clark73fa9722017-08-29 17:36:51 -04004673#Example
4674#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004675 SkPaint paint;
4676 paint.setStyle(SkPaint::kStroke_Style);
4677 SkPath dest, path;
4678 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4679 for (int i = 0; i < 6; i++) {
4680 SkMatrix matrix;
4681 matrix.reset();
4682 matrix.setPerspX(i / 400.f);
4683 dest.addPath(path, matrix);
4684 }
4685 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004686##
4687
Cary Clark4855f782018-02-06 09:41:53 -05004688#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004689
4690##
4691
4692# ------------------------------------------------------------------------------
4693
Cary Clark0251b1b2018-08-15 15:14:55 -04004694#Method SkPath& reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05004695#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004696#Line # adds contents of Path back to front ##
Cary Clark80247e52018-07-11 16:18:41 -04004697Appends src to Path, from back to front.
Cary Clark73fa9722017-08-29 17:36:51 -04004698Reversed src always appends a new Contour to Path.
4699
4700#Param src Path Verbs, Points, and Conic_Weights to add ##
4701
Cary Clark0251b1b2018-08-15 15:14:55 -04004702#Return reference to Path ##
4703
Cary Clark73fa9722017-08-29 17:36:51 -04004704#Example
4705#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004706 SkPath path;
4707 path.moveTo(20, 20);
4708 path.lineTo(20, 40);
4709 path.lineTo(40, 20);
4710 SkPaint paint;
4711 paint.setStyle(SkPaint::kStroke_Style);
4712 for (int i = 0; i < 2; i++) {
4713 SkPath path2;
4714 path2.moveTo(60, 60);
4715 path2.lineTo(80, 60);
4716 path2.lineTo(80, 40);
4717 for (int j = 0; j < 2; j++) {
4718 SkPath test(path);
4719 test.reverseAddPath(path2);
4720 canvas->drawPath(test, paint);
4721 canvas->translate(100, 0);
4722 path2.close();
4723 }
4724 canvas->translate(-200, 100);
4725 path.close();
4726 }
Cary Clark73fa9722017-08-29 17:36:51 -04004727##
4728
Cary Clark4855f782018-02-06 09:41:53 -05004729#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04004730
4731##
4732
4733# ------------------------------------------------------------------------------
4734
4735#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004736#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004737#Line # translates Point_Array ##
Cary Clark80247e52018-07-11 16:18:41 -04004738Offsets Point_Array by (dx, dy). Offset Path replaces dst.
Cary Clark73fa9722017-08-29 17:36:51 -04004739If dst is nullptr, Path is replaced by offset data.
4740
Cary Clark5538c132018-06-14 12:28:14 -04004741#Param dx offset added to Point_Array x-axis coordinates ##
4742#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004743#Param dst overwritten, translated copy of Path; may be nullptr ##
4744
4745#Example
4746#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004747 SkPath pattern;
4748 pattern.moveTo(20, 20);
4749 pattern.lineTo(20, 40);
4750 pattern.lineTo(40, 20);
4751 SkPaint paint;
4752 paint.setStyle(SkPaint::kStroke_Style);
4753 for (int i = 0; i < 10; i++) {
4754 SkPath path;
4755 pattern.offset(20 * i, 0, &path);
4756 canvas->drawPath(path, paint);
4757 }
Cary Clark73fa9722017-08-29 17:36:51 -04004758##
4759
4760#SeeAlso addPath transform
4761
4762##
4763
4764# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05004765#Subtopic Transform
4766#Populate
4767#Line # modify all points ##
4768##
Cary Clark73fa9722017-08-29 17:36:51 -04004769
Cary Clark682c58d2018-05-16 07:07:07 -04004770#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05004771#In Transform
Cary Clark80247e52018-07-11 16:18:41 -04004772Offsets Point_Array by (dx, dy). Path is replaced by offset data.
Cary Clark73fa9722017-08-29 17:36:51 -04004773
Cary Clark5538c132018-06-14 12:28:14 -04004774#Param dx offset added to Point_Array x-axis coordinates ##
4775#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004776
4777#Example
4778#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004779 SkPath path;
4780 path.moveTo(20, 20);
4781 path.lineTo(20, 40);
4782 path.lineTo(40, 20);
4783 SkPaint paint;
4784 paint.setStyle(SkPaint::kStroke_Style);
4785 for (int i = 0; i < 10; i++) {
4786 canvas->drawPath(path, paint);
4787 path.offset(20, 0);
4788 }
Cary Clark73fa9722017-08-29 17:36:51 -04004789##
4790
4791#SeeAlso addPath transform SkCanvas::translate()
4792
4793##
4794
4795# ------------------------------------------------------------------------------
4796
4797#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004798#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004799#Line # applies Matrix to Point_Array and Weights ##
Cary Clark80247e52018-07-11 16:18:41 -04004800Transforms Verb_Array, Point_Array, and weight by matrix.
Cary Clark73fa9722017-08-29 17:36:51 -04004801transform may change Verbs and increase their number.
4802Transformed Path replaces dst; if dst is nullptr, original data
Cary Clark682c58d2018-05-16 07:07:07 -04004803is replaced.
Cary Clark73fa9722017-08-29 17:36:51 -04004804
4805#Param matrix Matrix to apply to Path ##
4806#Param dst overwritten, transformed copy of Path; may be nullptr ##
4807
4808#Example
Cary Clark8032b982017-07-28 11:04:54 -04004809#Height 200
4810 SkPath pattern;
4811 pattern.moveTo(100, 100);
4812 pattern.lineTo(100, 20);
4813 pattern.lineTo(20, 100);
4814 SkPaint paint;
4815 paint.setStyle(SkPaint::kStroke_Style);
4816 for (int i = 0; i < 10; i++) {
4817 SkPath path;
4818 SkMatrix matrix;
4819 matrix.setRotate(36 * i, 100, 100);
4820 pattern.transform(matrix, &path);
4821 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004822 }
4823##
4824
4825#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4826
4827##
4828
4829# ------------------------------------------------------------------------------
4830
Cary Clark682c58d2018-05-16 07:07:07 -04004831#Method void transform(const SkMatrix& matrix)
Cary Clark73fa9722017-08-29 17:36:51 -04004832
Cary Clark80247e52018-07-11 16:18:41 -04004833Transforms Verb_Array, Point_Array, and weight by matrix.
Cary Clark73fa9722017-08-29 17:36:51 -04004834transform may change Verbs and increase their number.
4835Path is replaced by transformed data.
4836
4837#Param matrix Matrix to apply to Path ##
4838
4839#Example
Cary Clark8032b982017-07-28 11:04:54 -04004840#Height 200
4841 SkPath path;
4842 path.moveTo(100, 100);
4843 path.quadTo(100, 20, 20, 100);
4844 SkPaint paint;
4845 paint.setStyle(SkPaint::kStroke_Style);
4846 for (int i = 0; i < 10; i++) {
4847 SkMatrix matrix;
4848 matrix.setRotate(36, 100, 100);
4849 path.transform(matrix);
4850 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004851 }
4852##
4853
4854#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4855
4856##
4857
4858# ------------------------------------------------------------------------------
4859
Cary Clark8032b982017-07-28 11:04:54 -04004860#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05004861#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04004862
4863Path is defined cumulatively, often by adding a segment to the end of last
4864Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4865Last_Point can be read and written directly with getLastPt and setLastPt.
4866
Cary Clark73fa9722017-08-29 17:36:51 -04004867#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05004868#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004869#In Last_Point
4870#Line # returns Last_Point ##
Cary Clark682c58d2018-05-16 07:07:07 -04004871 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
Cary Clark73fa9722017-08-29 17:36:51 -04004872 storing (0, 0) if lastPt is not nullptr.
4873
4874 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4875
4876 #Return true if Point_Array contains one or more Points ##
4877
4878 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004879 SkPath path;
4880 path.moveTo(100, 100);
4881 path.quadTo(100, 20, 20, 100);
4882 SkMatrix matrix;
4883 matrix.setRotate(36, 100, 100);
4884 path.transform(matrix);
4885 SkPoint last;
4886 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004887 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4888 #StdOut
4889 last point: 35.2786, 52.9772
Cary Clark682c58d2018-05-16 07:07:07 -04004890 ##
Cary Clark73fa9722017-08-29 17:36:51 -04004891 ##
4892
4893 #SeeAlso setLastPt
4894
4895##
4896
4897#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05004898#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004899#In Last_Point
4900#Line # replaces Last_Point ##
Cary Clark80247e52018-07-11 16:18:41 -04004901 Sets Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
Cary Clark186d08f2018-04-03 08:43:27 -04004902 Verb_Array and append (x, y) to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04004903
Cary Clark5538c132018-06-14 12:28:14 -04004904 #Param x set x-axis value of Last_Point ##
4905 #Param y set y-axis value of Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004906
4907 #Example
4908 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004909 SkPaint paint;
4910 paint.setTextSize(128);
4911 SkPath path;
4912 paint.getTextPath("@", 1, 60, 100, &path);
4913 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004914 canvas->drawPath(path, paint);
4915 ##
4916
4917 #SeeAlso getLastPt
4918
4919##
4920
Cary Clark682c58d2018-05-16 07:07:07 -04004921#Method void setLastPt(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04004922
Cary Clark80247e52018-07-11 16:18:41 -04004923 Sets the last point on the path. If Point_Array is empty, append kMove_Verb to
Cary Clark186d08f2018-04-03 08:43:27 -04004924 Verb_Array and append p to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04004925
4926 #Param p set value of Last_Point ##
4927
4928 #Example
4929 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004930 SkPaint paint;
4931 paint.setTextSize(128);
4932 SkPath path, path2;
4933 paint.getTextPath("A", 1, 60, 100, &path);
4934 paint.getTextPath("Z", 1, 60, 100, &path2);
4935 SkPoint pt, pt2;
4936 path.getLastPt(&pt);
4937 path2.getLastPt(&pt2);
4938 path.setLastPt(pt2);
4939 path2.setLastPt(pt);
4940 canvas->drawPath(path, paint);
4941 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004942 ##
4943
4944 #SeeAlso getLastPt
4945
4946##
4947
4948#Subtopic Last_Point ##
4949
4950# ------------------------------------------------------------------------------
4951
4952#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05004953#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004954
4955#Code
4956 enum SegmentMask {
4957 kLine_SegmentMask = 1 << 0,
4958 kQuad_SegmentMask = 1 << 1,
4959 kConic_SegmentMask = 1 << 2,
4960 kCubic_SegmentMask = 1 << 3,
4961 };
4962##
4963
4964SegmentMask constants correspond to each drawing Verb type in Path; for
4965instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4966
Cary Clark4855f782018-02-06 09:41:53 -05004967#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04004968#Const kLine_SegmentMask 1
Cary Clark682c58d2018-05-16 07:07:07 -04004969#Line # contains one or more Lines ##
Cary Clark73fa9722017-08-29 17:36:51 -04004970Set if Verb_Array contains kLine_Verb.
4971##
4972#Const kQuad_SegmentMask 2
Cary Clark682c58d2018-05-16 07:07:07 -04004973#Line # contains one or more Quads ##
Cary Clark73fa9722017-08-29 17:36:51 -04004974Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4975##
4976#Const kConic_SegmentMask 4
Cary Clark682c58d2018-05-16 07:07:07 -04004977#Line # contains one or more Conics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004978Set if Verb_Array contains kConic_Verb.
4979##
4980#Const kCubic_SegmentMask 8
Cary Clark682c58d2018-05-16 07:07:07 -04004981#Line # contains one or more Cubics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004982Set if Verb_Array contains kCubic_Verb.
4983##
4984
4985#Example
4986#Description
4987When conicTo has a weight of one, Quad is added to Path.
4988##
4989 SkPath path;
4990 path.conicTo(10, 10, 20, 30, 1);
Cary Clark682c58d2018-05-16 07:07:07 -04004991 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004992 SkPath::kConic_SegmentMask ? "set" : "clear");
Cary Clark682c58d2018-05-16 07:07:07 -04004993 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004994 SkPath::kQuad_SegmentMask ? "set" : "clear");
4995#StdOut
4996Path kConic_SegmentMask is clear
4997Path kQuad_SegmentMask is set
4998##
4999##
5000
5001#SeeAlso getSegmentMasks Verb
5002
5003##
5004
5005# ------------------------------------------------------------------------------
5006
Cary Clark682c58d2018-05-16 07:07:07 -04005007#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05005008#In Utility
5009#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05005010#Line # returns types in Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04005011Returns a mask, where each set bit corresponds to a SegmentMask constant
5012if Path contains one or more Verbs of that type.
5013Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
5014
5015getSegmentMasks() returns a cached result; it is very fast.
5016
5017#Return SegmentMask bits or zero ##
5018
5019#Example
5020SkPath path;
5021path.quadTo(20, 30, 40, 50);
5022path.close();
5023const char* masks[] = { "line", "quad", "conic", "cubic" };
5024int index = 0;
5025for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
5026 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
5027 if (mask & path.getSegmentMasks()) {
5028 SkDebugf("mask %s set\n", masks[index]);
Cary Clark682c58d2018-05-16 07:07:07 -04005029 }
Cary Clark73fa9722017-08-29 17:36:51 -04005030 ++index;
5031}
5032#StdOut
5033mask quad set
5034##
5035##
5036
5037#SeeAlso getSegmentMasks Verb
5038
5039##
5040
5041# ------------------------------------------------------------------------------
5042
5043#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05005044#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05005045#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04005046Returns true if the point (x, y) is contained by Path, taking into
Cary Clark682c58d2018-05-16 07:07:07 -04005047account FillType.
Cary Clark73fa9722017-08-29 17:36:51 -04005048
5049#Table
5050#Legend
5051# FillType # contains() returns true if Point is enclosed by ##
5052##
5053# kWinding_FillType # a non-zero sum of Contour Directions. ##
5054# kEvenOdd_FillType # an odd number of Contours. ##
5055# kInverseWinding_FillType # a zero sum of Contour Directions. ##
5056# kInverseEvenOdd_FillType # and even number of Contours. ##
Cary Clark682c58d2018-05-16 07:07:07 -04005057##
Cary Clark73fa9722017-08-29 17:36:51 -04005058
Cary Clark5538c132018-06-14 12:28:14 -04005059#Param x x-axis value of containment test ##
5060#Param y y-axis value of containment test ##
Cary Clark73fa9722017-08-29 17:36:51 -04005061
5062#Return true if Point is in Path ##
5063
5064#Example
5065SkPath path;
5066SkPaint paint;
5067paint.setTextSize(256);
5068paint.getTextPath("&", 1, 30, 220, &path);
5069for (int y = 2; y < 256; y += 9) {
5070 for (int x = 2; x < 256; x += 9) {
5071 int coverage = 0;
5072 for (int iy = -4; iy <= 4; iy += 2) {
5073 for (int ix = -4; ix <= 4; ix += 2) {
5074 coverage += path.contains(x + ix, y + iy);
5075 }
5076 }
5077 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5078 canvas->drawCircle(x, y, 8, paint);
5079 }
5080}
5081##
5082
5083#SeeAlso conservativelyContainsRect Fill_Type Op
5084
5085##
5086
5087# ------------------------------------------------------------------------------
5088
5089#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05005090#In Utility
Cary Clark53498e92018-06-28 19:13:56 -04005091#Line # sends text representation to stream ##
Cary Clark154beea2017-10-26 07:58:48 -04005092Writes text representation of Path to stream. If stream is nullptr, writes to
5093standard output. Set forceClose to true to get edges used to fill Path.
5094Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005095of floating point numbers used in Point_Array and Conic_Weights.
5096
Cary Clark224c7002018-06-27 11:00:21 -04005097#Param stream writable WStream receiving Path text representation; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04005098#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005099#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005100
5101#Example
5102 SkPath path;
5103 path.quadTo(20, 30, 40, 50);
5104 for (bool forceClose : { false, true } ) {
5105 for (bool dumpAsHex : { false, true } ) {
5106 path.dump(nullptr, forceClose, dumpAsHex);
5107 SkDebugf("\n");
5108 }
5109 }
5110#StdOut
5111path.setFillType(SkPath::kWinding_FillType);
5112path.moveTo(0, 0);
5113path.quadTo(20, 30, 40, 50);
5114
5115path.setFillType(SkPath::kWinding_FillType);
5116path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5117path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5118
5119path.setFillType(SkPath::kWinding_FillType);
5120path.moveTo(0, 0);
5121path.quadTo(20, 30, 40, 50);
5122path.lineTo(0, 0);
5123path.close();
5124
5125path.setFillType(SkPath::kWinding_FillType);
5126path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5127path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5128path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5129path.close();
5130##
5131##
5132
Cary Clark53498e92018-06-28 19:13:56 -04005133#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
Cary Clark73fa9722017-08-29 17:36:51 -04005134
5135##
5136
5137# ------------------------------------------------------------------------------
5138
5139#Method void dump() const
5140
Cary Clarkce101242017-09-01 15:51:02 -04005141Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005142directly compiled as C++ code. Floating point values are written
5143with limited precision; it may not be possible to reconstruct original Path
5144from output.
5145
5146#Example
5147SkPath path, copy;
5148path.lineTo(6.f / 7, 2.f / 3);
5149path.dump();
5150copy.setFillType(SkPath::kWinding_FillType);
5151copy.moveTo(0, 0);
5152copy.lineTo(0.857143f, 0.666667f);
5153SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5154#StdOut
5155path.setFillType(SkPath::kWinding_FillType);
5156path.moveTo(0, 0);
5157path.lineTo(0.857143f, 0.666667f);
5158path is not equal to copy
5159##
5160##
5161
5162#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5163
5164##
5165
5166# ------------------------------------------------------------------------------
5167
5168#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05005169#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005170#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04005171Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005172directly compiled as C++ code. Floating point values are written
5173in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5174original Path.
5175
Cary Clark682c58d2018-05-16 07:07:07 -04005176Use instead of dump() when submitting
5177#A bug reports against Skia # https://bug.skia.org ##
Cary Clark6fc50412017-09-21 12:31:06 -04005178.
Cary Clark73fa9722017-08-29 17:36:51 -04005179
5180#Example
5181SkPath path, copy;
5182path.lineTo(6.f / 7, 2.f / 3);
5183path.dumpHex();
5184copy.setFillType(SkPath::kWinding_FillType);
5185copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5186copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5187SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5188#StdOut
5189path.setFillType(SkPath::kWinding_FillType);
5190path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5191path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5192path is equal to copy
5193##
5194##
5195
Cary Clark186d08f2018-04-03 08:43:27 -04005196#SeeAlso dump SkRect::dumpHex SkRRect::dumpHex writeToMemory
Cary Clark73fa9722017-08-29 17:36:51 -04005197
5198##
5199
5200# ------------------------------------------------------------------------------
5201
5202#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05005203#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005204#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005205Writes Path to buffer, returning the number of bytes written.
5206Pass nullptr to obtain the storage size.
5207
5208Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5209additionally writes computed information like Convexity and bounds.
5210
5211Use only be used in concert with readFromMemory;
5212the format used for Path in memory is not guaranteed.
5213
5214#Param buffer storage for Path; may be nullptr ##
5215
5216#Return size of storage required for Path; always a multiple of 4 ##
5217
5218#Example
5219void draw(SkCanvas* canvas) {
5220 SkPath path, copy;
5221 path.lineTo(6.f / 7, 2.f / 3);
5222 size_t size = path.writeToMemory(nullptr);
5223 SkTDArray<char> storage;
5224 storage.setCount(size);
5225 path.writeToMemory(storage.begin());
5226 copy.readFromMemory(storage.begin(), size);
5227 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5228}
5229#StdOut
5230path is equal to copy
5231##
5232##
5233
5234#SeeAlso serialize readFromMemory dump dumpHex
5235
5236##
5237
5238#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05005239#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005240#Line # copies data to buffer ##
Cary Clark80247e52018-07-11 16:18:41 -04005241Writes Path to buffer, returning the buffer written to, wrapped in Data.
Cary Clark73fa9722017-08-29 17:36:51 -04005242
5243serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5244additionally writes computed information like Convexity and bounds.
5245
5246serialize() should only be used in concert with readFromMemory.
5247The format used for Path in memory is not guaranteed.
5248
5249#Return Path data wrapped in Data buffer ##
5250
5251#Example
5252void draw(SkCanvas* canvas) {
5253 SkPath path, copy;
5254 path.lineTo(6.f / 7, 2.f / 3);
5255 sk_sp<SkData> data = path.serialize();
5256 copy.readFromMemory(data->data(), data->size());
5257 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5258}
5259#StdOut
5260path is equal to copy
5261##
5262##
5263
5264#SeeAlso writeToMemory readFromMemory dump dumpHex
5265##
5266
5267# ------------------------------------------------------------------------------
5268
5269#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05005270#In Utility
Cary Clark682c58d2018-05-16 07:07:07 -04005271#Line # initializes from buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005272Initializes Path from buffer of size length. Returns zero if the buffer is
Cary Clark682c58d2018-05-16 07:07:07 -04005273data is inconsistent, or the length is too small.
Cary Clark73fa9722017-08-29 17:36:51 -04005274
5275Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5276additionally reads computed information like Convexity and bounds.
5277
5278Used only in concert with writeToMemory;
5279the format used for Path in memory is not guaranteed.
5280
5281#Param buffer storage for Path ##
5282#Param length buffer size in bytes; must be multiple of 4 ##
5283
5284#Return number of bytes read, or zero on failure ##
5285
5286#Example
5287void draw(SkCanvas* canvas) {
5288 SkPath path, copy;
5289 path.lineTo(6.f / 7, 2.f / 3);
5290 size_t size = path.writeToMemory(nullptr);
5291 SkTDArray<char> storage;
5292 storage.setCount(size);
5293 path.writeToMemory(storage.begin());
5294 size_t wrongSize = size - 4;
5295 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5296 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5297 size_t largerSize = size + 4;
5298 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5299 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5300}
5301#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005302length = 32; returned by readFromMemory = 0
Cary Clark06c20f32018-03-20 15:53:27 -04005303length = 40; returned by readFromMemory = 36
Cary Clark73fa9722017-08-29 17:36:51 -04005304##
5305##
5306
5307#SeeAlso writeToMemory
5308
5309##
5310
5311# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05005312#Subtopic Generation_ID
Cary Clark137b8742018-05-30 09:21:49 -04005313#Alias Generation_IDs ##
Cary Clark08895c42018-02-01 09:37:32 -05005314#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04005315Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5316Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5317not necessarily have matching Generation_IDs.
5318
5319Empty Paths have a Generation_ID of one.
5320
5321#Method uint32_t getGenerationID() const
5322
Cary Clarkab2621d2018-01-30 10:08:57 -05005323#In Generation_ID
5324#Line # returns unique ID ##
Cary Clark682c58d2018-05-16 07:07:07 -04005325Returns a non-zero, globally unique value. A different value is returned
Cary Clark73fa9722017-08-29 17:36:51 -04005326if Verb_Array, Point_Array, or Conic_Weight changes.
5327
5328Setting Fill_Type does not change Generation_ID.
5329
5330Each time the path is modified, a different Generation_ID will be returned.
5331
5332#Bug 1762
5333Fill_Type does affect Generation_ID on Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -04005334
5335#Return non-zero, globally unique value ##
5336
5337#Example
5338SkPath path;
5339SkDebugf("empty genID = %u\n", path.getGenerationID());
5340path.lineTo(1, 2);
5341SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5342path.rewind();
5343SkDebugf("empty genID = %u\n", path.getGenerationID());
5344path.lineTo(1, 2);
5345SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5346#StdOut
5347empty genID = 1
53481st lineTo genID = 2
5349empty genID = 1
53502nd lineTo genID = 3
5351##
5352##
5353
5354#SeeAlso operator==(const SkPath& a, const SkPath& b)
5355
5356##
5357
Cary Clark78de7512018-02-07 07:27:09 -05005358#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04005359
5360# ------------------------------------------------------------------------------
5361
5362#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005363#In Property
5364#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005365#Line # returns if data is internally consistent ##
Cary Clark73fa9722017-08-29 17:36:51 -04005366 Returns if Path data is consistent. Corrupt Path data is detected if
5367 internal values are out of range or internal storage does not match
5368 array dimensions.
5369
5370 #Return true if Path data is consistent ##
5371
5372 #NoExample
5373 ##
5374
5375##
5376
5377#Method bool pathRefIsValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005378#Deprecated soon
Cary Clark73fa9722017-08-29 17:36:51 -04005379##
5380
5381# ------------------------------------------------------------------------------
5382
Cary Clark8032b982017-07-28 11:04:54 -04005383#Class Iter
Cary Clark682c58d2018-05-16 07:07:07 -04005384#Line # data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005385
Cary Clark73fa9722017-08-29 17:36:51 -04005386#Code
5387class Iter {
5388public:
5389 Iter();
5390 Iter(const SkPath& path, bool forceClose);
5391 void setPath(const SkPath& path, bool forceClose);
5392 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5393 SkScalar conicWeight() const;
5394 bool isCloseLine() const;
5395 bool isClosedContour() const;
5396};
5397##
5398
Cary Clark137b8742018-05-30 09:21:49 -04005399Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5400Provides options to treat open Contours as closed, and to ignore
5401degenerate data.
5402
Cary Clark8032b982017-07-28 11:04:54 -04005403#Example
5404#Height 128
5405#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005406Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005407path of the glyph.
5408##
Cary Clark73fa9722017-08-29 17:36:51 -04005409void draw(SkCanvas* canvas) {
5410 SkPaint paint;
5411 paint.setAntiAlias(true);
5412 paint.setTextSize(256);
5413 SkPath asterisk, path;
5414 paint.getTextPath("*", 1, 50, 192, &asterisk);
Cary Clark682c58d2018-05-16 07:07:07 -04005415 SkPath::Iter iter(asterisk, true);
Cary Clark73fa9722017-08-29 17:36:51 -04005416 SkPoint start[4], pts[4];
5417 iter.next(start); // skip moveTo
5418 iter.next(start); // first quadTo
5419 path.moveTo((start[0] + start[1]) * 0.5f);
5420 while (SkPath::kClose_Verb != iter.next(pts)) {
5421 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5422 }
5423 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5424 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005425}
5426##
5427
5428#SeeAlso RawIter
5429
5430#Method Iter()
Cary Clark682c58d2018-05-16 07:07:07 -04005431#Line # constructs Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005432Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5433Call setPath to initialize Iter at a later time.
5434
Cary Clark73fa9722017-08-29 17:36:51 -04005435#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005436
5437#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005438void draw(SkCanvas* canvas) {
5439 SkPath::Iter iter;
5440 SkPoint points[4];
5441 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5442 SkPath path;
5443 iter.setPath(path, false);
5444 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005445}
Cary Clark73fa9722017-08-29 17:36:51 -04005446#StdOut
5447iter is done
5448iter is done
5449##
Cary Clark8032b982017-07-28 11:04:54 -04005450##
5451
5452#SeeAlso setPath
5453
5454##
5455
5456#Method Iter(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005457#Line # constructs Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005458
5459Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5460If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5461open Contour. path is not altered.
5462
Cary Clark73fa9722017-08-29 17:36:51 -04005463#Param path Path to iterate ##
5464#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005465
Cary Clark73fa9722017-08-29 17:36:51 -04005466#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005467
5468#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005469void draw(SkCanvas* canvas) {
5470 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5471 SkDebugf("%s:\n", prefix);
5472 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5473 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5474 SkPath::Verb verb;
5475 do {
5476 SkPoint points[4];
5477 verb = iter.next(points);
5478 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5479 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5480 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5481 }
5482 if (SkPath::kConic_Verb == verb) {
5483 SkDebugf("weight = %g", iter.conicWeight());
5484 }
5485 SkDebugf("\n");
5486 } while (SkPath::kDone_Verb != verb);
5487 SkDebugf("\n");
5488 };
5489
5490 SkPath path;
5491 path.quadTo(10, 20, 30, 40);
5492 SkPath::Iter openIter(path, false);
5493 debugster("open", openIter);
5494 SkPath::Iter closedIter(path, true);
5495 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005496}
5497#StdOut
5498open:
Cary Clark682c58d2018-05-16 07:07:07 -04005499kMove_Verb {0, 0},
5500kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5501kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005502
5503closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005504kMove_Verb {0, 0},
5505kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5506kLine_Verb {30, 40}, {0, 0},
5507kClose_Verb {0, 0},
5508kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005509##
5510##
5511
5512#SeeAlso setPath
5513
5514##
5515
5516#Method void setPath(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005517#Line # resets Iter to Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005518Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5519If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5520open Contour. path is not altered.
5521
Cary Clark73fa9722017-08-29 17:36:51 -04005522#Param path Path to iterate ##
5523#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005524
5525#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005526void draw(SkCanvas* canvas) {
5527 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5528 SkDebugf("%s:\n", prefix);
5529 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5530 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5531 SkPath::Verb verb;
5532 do {
5533 SkPoint points[4];
5534 verb = iter.next(points);
5535 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5536 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5537 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5538 }
5539 if (SkPath::kConic_Verb == verb) {
5540 SkDebugf("weight = %g", iter.conicWeight());
5541 }
5542 SkDebugf("\n");
5543 } while (SkPath::kDone_Verb != verb);
5544 SkDebugf("\n");
5545 };
5546
5547 SkPath path;
5548 path.quadTo(10, 20, 30, 40);
5549 SkPath::Iter iter(path, false);
5550 debugster("quad open", iter);
5551 SkPath path2;
5552 path2.conicTo(1, 2, 3, 4, .5f);
5553 iter.setPath(path2, true);
5554 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005555}
5556#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005557quad open:
Cary Clark682c58d2018-05-16 07:07:07 -04005558kMove_Verb {0, 0},
5559kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5560kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005561
5562conic closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005563kMove_Verb {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04005564kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005565kLine_Verb {3, 4}, {0, 0},
5566kClose_Verb {0, 0},
5567kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005568##
5569##
5570
5571#SeeAlso Iter(const SkPath& path, bool forceClose)
5572
5573##
5574
Cary Clark682c58d2018-05-16 07:07:07 -04005575#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005576#Line # returns next Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005577
Cary Clarka523d2d2017-08-30 08:58:10 -04005578Returns next Verb in Verb_Array, and advances Iter.
5579When Verb_Array is exhausted, returns kDone_Verb.
5580
Cary Clark8032b982017-07-28 11:04:54 -04005581Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005582
Cary Clark8032b982017-07-28 11:04:54 -04005583If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5584only the last in the series; and skip very small Lines, Quads, and Conics; and
5585skip kClose_Verb following kMove_Verb.
5586if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5587Conics with zero lengths.
5588
Cary Clarka523d2d2017-08-30 08:58:10 -04005589 #Param pts storage for Point data describing returned Verb ##
5590 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5591 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005592
Cary Clark73fa9722017-08-29 17:36:51 -04005593 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005594
5595#Example
Cary Clark682c58d2018-05-16 07:07:07 -04005596#Description
Cary Clark8032b982017-07-28 11:04:54 -04005597skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5598followed by the kClose_Verb, the zero length Line and the very small Line.
5599
5600skip degenerate if exact skips the same as skip degenerate, but shows
5601the very small Line.
5602
5603skip none shows all of the Verbs and Points in Path.
5604##
Cary Clark73fa9722017-08-29 17:36:51 -04005605void draw(SkCanvas* canvas) {
5606 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5607 SkPath::Iter iter(path, false);
5608 SkDebugf("%s:\n", prefix);
5609 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5610 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5611 SkPath::Verb verb;
5612 do {
5613 SkPoint points[4];
5614 verb = iter.next(points, degen, exact);
5615 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5616 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5617 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5618 }
5619 SkDebugf("\n");
5620 } while (SkPath::kDone_Verb != verb);
5621 SkDebugf("\n");
5622 };
5623
5624 SkPath path;
5625 path.moveTo(10, 10);
5626 path.moveTo(20, 20);
5627 path.quadTo(10, 20, 30, 40);
5628 path.moveTo(1, 1);
5629 path.close();
5630 path.moveTo(30, 30);
5631 path.lineTo(30, 30);
5632 path.moveTo(30, 30);
5633 path.lineTo(30.00001f, 30);
5634 debugster("skip degenerate", path, true, false);
5635 debugster("skip degenerate if exact", path, true, true);
5636 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005637}
5638#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005639skip degenerate:
Cary Clark682c58d2018-05-16 07:07:07 -04005640kMove_Verb {20, 20},
5641kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5642kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005643
5644skip degenerate if exact:
Cary Clark682c58d2018-05-16 07:07:07 -04005645kMove_Verb {20, 20},
5646kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5647kMove_Verb {30, 30},
5648kLine_Verb {30, 30}, {30.00001, 30},
5649kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005650
5651skip none:
Cary Clark682c58d2018-05-16 07:07:07 -04005652kMove_Verb {10, 10},
5653kMove_Verb {20, 20},
5654kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5655kMove_Verb {1, 1},
5656kClose_Verb {1, 1},
5657kMove_Verb {30, 30},
5658kLine_Verb {30, 30}, {30, 30},
5659kMove_Verb {30, 30},
5660kLine_Verb {30, 30}, {30.00001, 30},
5661kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005662##
5663##
5664
Cary Clark682c58d2018-05-16 07:07:07 -04005665#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
Cary Clark8032b982017-07-28 11:04:54 -04005666
5667##
5668
5669#Method SkScalar conicWeight() const
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005670#Line # returns Conic_Weight ##
Cary Clark8032b982017-07-28 11:04:54 -04005671 Returns Conic_Weight if next() returned kConic_Verb.
5672
5673 If next() has not been called, or next() did not return kConic_Verb,
5674 result is undefined.
5675
Cary Clark73fa9722017-08-29 17:36:51 -04005676 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005677
5678 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005679 void draw(SkCanvas* canvas) {
5680 SkPath path;
5681 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005682 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005683 SkPoint p[4];
5684 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5685 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5686 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5687 p[2].fX, p[2].fY);
5688 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005689 }
5690 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005691first verb is move
5692next verb is conic
5693conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005694conic weight: 0.5
5695 ##
5696 ##
5697
5698 #SeeAlso Conic_Weight
5699
5700##
5701
5702#Method bool isCloseLine() const
Cary Clark682c58d2018-05-16 07:07:07 -04005703#Line # returns if Line was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005704 Returns true if last kLine_Verb returned by next() was generated
5705 by kClose_Verb. When true, the end point returned by next() is
5706 also the start point of Contour.
5707
5708 If next() has not been called, or next() did not return kLine_Verb,
5709 result is undefined.
5710
Cary Clark73fa9722017-08-29 17:36:51 -04005711 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005712
5713 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005714void draw(SkCanvas* canvas) {
5715 SkPath path;
5716 path.moveTo(6, 7);
5717 path.conicTo(1, 2, 3, 4, .5f);
5718 path.close();
Cary Clark682c58d2018-05-16 07:07:07 -04005719 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005720 SkPoint p[4];
5721 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5722 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5723 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5724 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5725 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5726 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5727 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005728}
5729 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040057301st verb is move
5731moveTo point: {6,7}
57322nd verb is conic
57333rd verb is line
5734line points: {3,4}, {6,7}
5735line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040057364th verb is close
5737 ##
5738 ##
5739
5740 #SeeAlso close()
5741##
5742
5743#Method bool isClosedContour() const
Cary Clark682c58d2018-05-16 07:07:07 -04005744#Line # returns if Contour has kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005745Returns true if subsequent calls to next() return kClose_Verb before returning
5746kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5747Iter may have been initialized with force close set to true.
5748
Cary Clark73fa9722017-08-29 17:36:51 -04005749#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005750
5751#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005752void draw(SkCanvas* canvas) {
5753 for (bool forceClose : { false, true } ) {
5754 SkPath path;
5755 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005756 SkPath::Iter iter(path, forceClose);
Cary Clark73fa9722017-08-29 17:36:51 -04005757 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5758 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5759 path.close();
5760 iter.setPath(path, forceClose);
5761 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5762 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5763 }
Cary Clark8032b982017-07-28 11:04:54 -04005764}
5765#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005766without close(), forceClose is false: isClosedContour returns false
5767with close(), forceClose is false: isClosedContour returns true
5768without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005769with close(), forceClose is true : isClosedContour returns true
5770##
5771##
5772
5773#SeeAlso Iter(const SkPath& path, bool forceClose)
5774
5775##
Cary Clark73fa9722017-08-29 17:36:51 -04005776
5777#Class Iter ##
5778
Cary Clark8032b982017-07-28 11:04:54 -04005779#Class RawIter
Cary Clark682c58d2018-05-16 07:07:07 -04005780#Line # raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005781
Cary Clark73fa9722017-08-29 17:36:51 -04005782#Code
5783 class RawIter {
5784 public:
5785 RawIter();
5786 RawIter(const SkPath& path);
5787 void setPath(const SkPath& path);
5788 Verb next(SkPoint pts[4]);
5789 Verb peek() const;
5790 SkScalar conicWeight() const;
5791 }
5792##
5793
Cary Clark137b8742018-05-30 09:21:49 -04005794Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5795Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5796
Cary Clark8032b982017-07-28 11:04:54 -04005797 #Method RawIter()
Cary Clark682c58d2018-05-16 07:07:07 -04005798 #Line # constructs empty Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005799
5800 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
Cary Clark78c110e2018-02-09 16:49:09 -05005801 Call setPath to initialize SkPath::Iter at a later time.
Cary Clark8032b982017-07-28 11:04:54 -04005802
Cary Clark73fa9722017-08-29 17:36:51 -04005803 #Return RawIter of empty Path ##
5804
5805 #NoExample
5806 ##
5807 ##
Cary Clark8032b982017-07-28 11:04:54 -04005808
5809 #Method RawIter(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005810 #Line # constructs with Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005811
5812
5813 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5814
Cary Clark73fa9722017-08-29 17:36:51 -04005815 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005816
Cary Clark73fa9722017-08-29 17:36:51 -04005817 #Return RawIter of path ##
5818
5819 #NoExample
5820 ##
5821 ##
Cary Clark8032b982017-07-28 11:04:54 -04005822
5823 #Method void setPath(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005824 #Line # sets Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005825
Cary Clark78c110e2018-02-09 16:49:09 -05005826 Sets SkPath::Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
Cary Clark8032b982017-07-28 11:04:54 -04005827
Cary Clark73fa9722017-08-29 17:36:51 -04005828 #Param path Path to iterate ##
5829
5830 #NoExample
5831 ##
5832 ##
Cary Clark8032b982017-07-28 11:04:54 -04005833
5834 #Method Verb next(SkPoint pts[4])
Cary Clark682c58d2018-05-16 07:07:07 -04005835 #Line # returns next Verb and associated Points ##
Cary Clark8032b982017-07-28 11:04:54 -04005836 Returns next Verb in Verb_Array, and advances RawIter.
5837 When Verb_Array is exhausted, returns kDone_Verb.
5838 Zero to four Points are stored in pts, depending on the returned Verb.
5839
Cary Clarka523d2d2017-08-30 08:58:10 -04005840 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005841
Cary Clark73fa9722017-08-29 17:36:51 -04005842 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005843
5844 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005845 void draw(SkCanvas* canvas) {
5846 SkPath path;
5847 path.moveTo(50, 60);
5848 path.quadTo(10, 20, 30, 40);
5849 path.close();
5850 path.lineTo(30, 30);
5851 path.conicTo(1, 2, 3, 4, .5f);
5852 path.cubicTo(-1, -2, -3, -4, -5, -6);
5853 SkPath::RawIter iter(path);
5854 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5855 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5856 SkPath::Verb verb;
5857 do {
5858 SkPoint points[4];
5859 verb = iter.next(points);
5860 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5861 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5862 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5863 }
5864 if (SkPath::kConic_Verb == verb) {
5865 SkDebugf("weight = %g", iter.conicWeight());
5866 }
5867 SkDebugf("\n");
5868 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005869 }
5870 #StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005871 kMove_Verb {50, 60},
5872 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5873 kClose_Verb {50, 60},
5874 kMove_Verb {50, 60},
5875 kLine_Verb {50, 60}, {30, 30},
Cary Clark73fa9722017-08-29 17:36:51 -04005876 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005877 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
5878 kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005879 ##
5880 ##
5881
5882 #SeeAlso peek()
5883
Cary Clark73fa9722017-08-29 17:36:51 -04005884 ##
Cary Clark8032b982017-07-28 11:04:54 -04005885
5886 #Method Verb peek() const
Cary Clark682c58d2018-05-16 07:07:07 -04005887 #Line # returns next Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005888 Returns next Verb, but does not advance RawIter.
5889
Cary Clark73fa9722017-08-29 17:36:51 -04005890 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005891
5892 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005893 SkPath path;
5894 path.quadTo(10, 20, 30, 40);
5895 path.conicTo(1, 2, 3, 4, .5f);
5896 path.cubicTo(1, 2, 3, 4, .5, 6);
5897 SkPath::RawIter iter(path);
5898 SkPath::Verb verb, peek = iter.peek();
5899 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5900 do {
5901 SkPoint points[4];
5902 verb = iter.next(points);
5903 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5904 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005905 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005906 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5907 #StdOut
5908 #Volatile
5909 peek Move == verb Move
5910 peek Quad == verb Quad
5911 peek Conic == verb Conic
5912 peek Cubic == verb Cubic
5913 peek Done == verb Done
5914 peek Done == verb Done
5915 ##
Cary Clark8032b982017-07-28 11:04:54 -04005916 ##
5917
5918 #Bug 6832
Cary Clark682c58d2018-05-16 07:07:07 -04005919 StdOut is not really volatile, it just produces the wrong result.
Cary Clark8032b982017-07-28 11:04:54 -04005920 A simple fix changes the output of hairlines and needs to be
5921 investigated to see if the change is correct or not.
Cary Clark682c58d2018-05-16 07:07:07 -04005922 see change 21340 (abandoned for now)
Cary Clark8032b982017-07-28 11:04:54 -04005923
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005924 #SeeAlso next
Cary Clark8032b982017-07-28 11:04:54 -04005925
Cary Clark73fa9722017-08-29 17:36:51 -04005926 ##
Cary Clark8032b982017-07-28 11:04:54 -04005927
Cary Clark73fa9722017-08-29 17:36:51 -04005928 #Method SkScalar conicWeight() const
Cary Clark682c58d2018-05-16 07:07:07 -04005929 #Line # returns Conic_Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04005930
Cary Clark8032b982017-07-28 11:04:54 -04005931 Returns Conic_Weight if next() returned kConic_Verb.
5932
5933 If next() has not been called, or next() did not return kConic_Verb,
5934 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04005935
5936 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005937
5938 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005939 void draw(SkCanvas* canvas) {
5940 SkPath path;
5941 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005942 SkPath::RawIter iter(path);
Cary Clark73fa9722017-08-29 17:36:51 -04005943 SkPoint p[4];
5944 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5945 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5946 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5947 p[2].fX, p[2].fY);
5948 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005949 }
5950 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005951 first verb is move
5952 next verb is conic
5953 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005954 conic weight: 0.5
5955 ##
5956 ##
5957
5958 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04005959
5960 ##
5961
5962#Class RawIter ##
5963
5964#Class SkPath ##
5965
5966#Topic Path ##
Cary Clark4855f782018-02-06 09:41:53 -05005967