blob: b41fe22ecfbf540c96e9a35f2a5413758b69fbcf [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 Clark73fa9722017-08-29 17:36:51 -0400661#Formula
Cary Clarkac47b882018-01-11 10:35:44 -0500662(Path Point * weight) + ending Point * (1 - weight)
Cary Clark73fa9722017-08-29 17:36:51 -0400663##
Cary Clark154beea2017-10-26 07:58:48 -0400664.
Cary Clark73fa9722017-08-29 17:36:51 -0400665
Cary Clark682c58d2018-05-16 07:07:07 -0400666weight is most useful when between zero (ending Point_Array) and
667one (this Point_Array); will work with values outside of this
Cary Clark73fa9722017-08-29 17:36:51 -0400668range.
669
670interpolate() returns false and leaves out unchanged if Point_Array is not
Cary Clark682c58d2018-05-16 07:07:07 -0400671the same size as ending Point_Array. Call isInterpolatable to check Path
Cary Clark73fa9722017-08-29 17:36:51 -0400672compatibility prior to calling interpolate().
673
674#Param ending Point_Array averaged with this Point_Array ##
Cary Clark682c58d2018-05-16 07:07:07 -0400675#Param weight contribution of this Point_Array, and
676 one minus contribution of ending Point_Array
Cary Clark73fa9722017-08-29 17:36:51 -0400677##
678#Param out Path replaced by interpolated averages ##
679
680#Return true if Paths contain same number of Points ##
681
682#Example
683#Height 60
684void draw(SkCanvas* canvas) {
685 SkPaint paint;
686 paint.setAntiAlias(true);
687 paint.setStyle(SkPaint::kStroke_Style);
688 SkPath path, path2;
689 path.moveTo(20, 20);
690 path.lineTo(40, 40);
691 path.lineTo(20, 40);
692 path.lineTo(40, 20);
693 path.close();
694 path2.addRect({20, 20, 40, 40});
695 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
696 SkPath interp;
697 path.interpolate(path2, i, &interp);
698 canvas->drawPath(interp, paint);
699 canvas->translate(30, 0);
700 }
701}
702##
703
704#SeeAlso isInterpolatable
705
706##
707
708# ------------------------------------------------------------------------------
709
Cary Clark682c58d2018-05-16 07:07:07 -0400710#Method bool unique() const
Cary Clark4855f782018-02-06 09:41:53 -0500711#Deprecated soon
712Only valid for Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -0400713##
714
715# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400716#Subtopic Fill_Type
Cary Clark682c58d2018-05-16 07:07:07 -0400717#Line # fill rule, normal and inverted ##
Cary Clark8032b982017-07-28 11:04:54 -0400718
Cary Clark73fa9722017-08-29 17:36:51 -0400719#Enum FillType
Cary Clark08895c42018-02-01 09:37:32 -0500720#Line # sets winding rule and inverse fill ##
Cary Clark73fa9722017-08-29 17:36:51 -0400721
722#Code
723 enum FillType {
Cary Clark682c58d2018-05-16 07:07:07 -0400724 kWinding_FillType,
725 kEvenOdd_FillType,
726 kInverseWinding_FillType,
727 kInverseEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400728 };
729##
Cary Clark8032b982017-07-28 11:04:54 -0400730
Cary Clark682c58d2018-05-16 07:07:07 -0400731Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
Cary Clark8032b982017-07-28 11:04:54 -0400732fills if the sum of Contour edges is not zero, where clockwise edges add one, and
733counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
Cary Clark682c58d2018-05-16 07:07:07 -0400734number of Contour edges is odd. Each Fill_Type has an inverse variant that
Cary Clark8032b982017-07-28 11:04:54 -0400735reverses the rule:
736kInverseWinding_FillType fills where the sum of Contour edges is zero;
737kInverseEvenOdd_FillType fills where the number of Contour edges is even.
738
739#Example
740#Height 100
741#Description
742The top row has two clockwise rectangles. The second row has one clockwise and
743one counterclockwise rectangle. The even-odd variants draw the same. The
744winding variants draw the top rectangle overlap, which has a winding of 2, the
745same as the outer parts of the top rectangles, which have a winding of 1.
746##
Cary Clark73fa9722017-08-29 17:36:51 -0400747void draw(SkCanvas* canvas) {
748 SkPath path;
749 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
750 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
751 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
752 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
753 SkPaint strokePaint;
754 strokePaint.setStyle(SkPaint::kStroke_Style);
755 SkRect clipRect = {0, 0, 51, 100};
756 canvas->drawPath(path, strokePaint);
757 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400758 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400759 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
760 canvas->translate(51, 0);
761 canvas->save();
762 canvas->clipRect(clipRect);
763 path.setFillType(fillType);
764 canvas->drawPath(path, fillPaint);
765 canvas->restore();
766 }
Cary Clark8032b982017-07-28 11:04:54 -0400767}
768##
Cary Clark73fa9722017-08-29 17:36:51 -0400769
770#Const kWinding_FillType 0
Cary Clark682c58d2018-05-16 07:07:07 -0400771#Line # is enclosed by a non-zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400772##
773#Const kEvenOdd_FillType 1
Cary Clark682c58d2018-05-16 07:07:07 -0400774#Line # is enclosed by an odd number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400775##
776#Const kInverseWinding_FillType 2
Cary Clark682c58d2018-05-16 07:07:07 -0400777#Line # is enclosed by a zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400778##
779#Const kInverseEvenOdd_FillType 3
Cary Clark682c58d2018-05-16 07:07:07 -0400780#Line # is enclosed by an even number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400781##
782
783#Example
784#Height 230
785void draw(SkCanvas* canvas) {
786 SkPath path;
787 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
788 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
789 SkPaint strokePaint;
790 strokePaint.setStyle(SkPaint::kStroke_Style);
791 SkRect clipRect = {0, 0, 128, 128};
792 canvas->drawPath(path, strokePaint);
793 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
794 SkPaint textPaint;
795 textPaint.setAntiAlias(true);
796 textPaint.setTextAlign(SkPaint::kCenter_Align);
797 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
798 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
799 textPaint.setTextSize(18);
800 canvas->translate(0, 128);
801 canvas->scale(.5f, .5f);
802 canvas->drawString("inverse", 384, 150, textPaint);
803 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400804 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400805 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
806 canvas->save();
807 canvas->clipRect(clipRect);
808 path.setFillType(fillType);
809 canvas->drawPath(path, fillPaint);
810 canvas->restore();
811 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
812 canvas->translate(128, 0);
813 }
814}
815##
816
817#SeeAlso SkPaint::Style Direction getFillType setFillType
818
819##
820
821# ------------------------------------------------------------------------------
822
Cary Clark682c58d2018-05-16 07:07:07 -0400823#Method FillType getFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400824
Cary Clarkab2621d2018-01-30 10:08:57 -0500825#In Fill_Type
826#Line # returns Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400827Returns FillType, the rule used to fill Path. FillType of a new Path is
828kWinding_FillType.
829
Cary Clark682c58d2018-05-16 07:07:07 -0400830#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
831kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400832##
833
834#Example
835 SkPath path;
836 SkDebugf("default path fill type is %s\n",
837 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
Cary Clark682c58d2018-05-16 07:07:07 -0400838 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
Cary Clark73fa9722017-08-29 17:36:51 -0400839 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
840 "kInverseEvenOdd_FillType");
841#StdOut
842default path fill type is kWinding_FillType
843##
844##
845
846#SeeAlso FillType setFillType isInverseFillType
847
848##
849
850# ------------------------------------------------------------------------------
851
Cary Clark682c58d2018-05-16 07:07:07 -0400852#Method void setFillType(FillType ft)
Cary Clark73fa9722017-08-29 17:36:51 -0400853
Cary Clarkab2621d2018-01-30 10:08:57 -0500854#In Fill_Type
855#Line # sets Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400856Sets FillType, the rule used to fill Path. While there is no check
857that ft is legal, values outside of FillType are not supported.
858
Cary Clark682c58d2018-05-16 07:07:07 -0400859#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
860kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400861##
862
863#Example
864#Description
865If empty Path is set to inverse FillType, it fills all pixels.
866##
867#Height 64
868 SkPath path;
869 path.setFillType(SkPath::kInverseWinding_FillType);
870 SkPaint paint;
871 paint.setColor(SK_ColorBLUE);
872 canvas->drawPath(path, paint);
873##
874
875#SeeAlso FillType getFillType toggleInverseFillType
876
877##
878
879# ------------------------------------------------------------------------------
880
Cary Clark682c58d2018-05-16 07:07:07 -0400881#Method bool isInverseFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400882
Cary Clarkab2621d2018-01-30 10:08:57 -0500883#In Fill_Type
884#Line # returns if Fill_Type fills outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -0400885Returns if FillType describes area outside Path geometry. The inverse fill area
886extends indefinitely.
887
888#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType ##
889
890#Example
891 SkPath path;
892 SkDebugf("default path fill type is inverse: %s\n",
893 path.isInverseFillType() ? "true" : "false");
894#StdOut
895default path fill type is inverse: false
896##
897##
898
899#SeeAlso FillType getFillType setFillType toggleInverseFillType
900
901##
902
903# ------------------------------------------------------------------------------
904
Cary Clark682c58d2018-05-16 07:07:07 -0400905#Method void toggleInverseFillType()
Cary Clark73fa9722017-08-29 17:36:51 -0400906
Cary Clarkab2621d2018-01-30 10:08:57 -0500907#In Fill_Type
908#Line # toggles Fill_Type between inside and outside geometry ##
Cary Clark80247e52018-07-11 16:18:41 -0400909Replaces FillType with its inverse. The inverse of FillType describes the area
Cary Clark73fa9722017-08-29 17:36:51 -0400910unmodified by the original FillType.
911
Cary Clark682c58d2018-05-16 07:07:07 -0400912#Table
Cary Clark73fa9722017-08-29 17:36:51 -0400913#Legend
Cary Clark682c58d2018-05-16 07:07:07 -0400914# FillType # toggled FillType ##
Cary Clark73fa9722017-08-29 17:36:51 -0400915##
916# kWinding_FillType # kInverseWinding_FillType ##
917# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
918# kInverseWinding_FillType # kWinding_FillType ##
919# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
920##
921
922#Example
923#Description
924Path drawn normally and through its inverse touches every pixel once.
925##
926#Height 100
927SkPath path;
928SkPaint paint;
929paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -0400930paint.setTextSize(80);
931paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -0400932canvas->drawPath(path, paint);
933path.toggleInverseFillType();
934paint.setColor(SK_ColorGREEN);
935canvas->drawPath(path, paint);
936##
937
938#SeeAlso FillType getFillType setFillType isInverseFillType
939
940##
941
Cary Clark8032b982017-07-28 11:04:54 -0400942#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400943
944# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400945
946#Subtopic Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500947#Line # if Path is concave or convex ##
Cary Clark73fa9722017-08-29 17:36:51 -0400948
949#Enum Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500950#Line # returns if Path is convex or concave ##
Cary Clark73fa9722017-08-29 17:36:51 -0400951
952#Code
Cary Clark884dd7d2017-10-11 10:37:52 -0400953 enum Convexity : uint8_t {
Cary Clark682c58d2018-05-16 07:07:07 -0400954 kUnknown_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400955 kConvex_Convexity,
Cary Clark682c58d2018-05-16 07:07:07 -0400956 kConcave_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400957 };
958##
959
Cary Clark682c58d2018-05-16 07:07:07 -0400960Path is convex if it contains one Contour and Contour loops no more than
961360 degrees, and Contour angles all have same Direction. Convex Path
Cary Clark8032b982017-07-28 11:04:54 -0400962may have better performance and require fewer resources on GPU_Surface.
963
Cary Clark73fa9722017-08-29 17:36:51 -0400964Path is concave when either at least one Direction change is clockwise and
965another is counterclockwise, or the sum of the changes in Direction is not 360
966degrees.
967
Cary Clark682c58d2018-05-16 07:07:07 -0400968Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
Cary Clark73fa9722017-08-29 17:36:51 -0400969if needed by destination Surface.
970
971#Const kUnknown_Convexity 0
Cary Clark682c58d2018-05-16 07:07:07 -0400972#Line # indicates Convexity has not been determined ##
Cary Clark73fa9722017-08-29 17:36:51 -0400973##
974#Const kConvex_Convexity 1
Cary Clark682c58d2018-05-16 07:07:07 -0400975#Line # one Contour made of a simple geometry without indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400976##
977#Const kConcave_Convexity 2
Cary Clark682c58d2018-05-16 07:07:07 -0400978#Line # more than one Contour, or a geometry with indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400979##
980
981#Example
982void draw(SkCanvas* canvas) {
983 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400984 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400985 const char* labels[] = { "unknown", "convex", "concave" };
986 for (SkScalar x : { 40, 100 } ) {
987 SkPath path;
988 quad[0].fX = x;
989 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
990 canvas->drawPath(path, paint);
991 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
992 canvas->translate(100, 100);
993 }
994}
995##
996
997#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
998
999#Enum Convexity ##
1000
Cary Clark682c58d2018-05-16 07:07:07 -04001001#Method Convexity getConvexity() const
Cary Clark73fa9722017-08-29 17:36:51 -04001002
Cary Clarkab2621d2018-01-30 10:08:57 -05001003#In Convexity
1004#Line # returns geometry convexity, computing if necessary ##
Cary Clark682c58d2018-05-16 07:07:07 -04001005Computes Convexity if required, and returns stored value.
Cary Clark73fa9722017-08-29 17:36:51 -04001006Convexity is computed if stored value is kUnknown_Convexity,
1007or if Path has been altered since Convexity was computed or set.
1008
Cary Clarka523d2d2017-08-30 08:58:10 -04001009#Return computed or stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001010
1011#Example
1012void draw(SkCanvas* canvas) {
1013 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001014 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001015 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1016 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1017 SkPath path;
1018 debugster("initial", path);
1019 path.lineTo(50, 0);
1020 debugster("first line", path);
1021 path.lineTo(50, 50);
1022 debugster("second line", path);
1023 path.lineTo(100, 50);
1024 debugster("third line", path);
1025}
1026##
1027
1028#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
1029
1030##
1031
1032# ------------------------------------------------------------------------------
1033
Cary Clark682c58d2018-05-16 07:07:07 -04001034#Method Convexity getConvexityOrUnknown() const
Cary Clark73fa9722017-08-29 17:36:51 -04001035
Cary Clarkab2621d2018-01-30 10:08:57 -05001036#In Convexity
1037#Line # returns geometry convexity if known ##
Cary Clark682c58d2018-05-16 07:07:07 -04001038Returns last computed Convexity, or kUnknown_Convexity if
Cary Clark73fa9722017-08-29 17:36:51 -04001039Path has been altered since Convexity was computed or set.
1040
Cary Clarka523d2d2017-08-30 08:58:10 -04001041#Return stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001042
1043#Example
1044#Description
1045Convexity is unknown unless getConvexity is called without a subsequent call
1046that alters the path.
1047##
1048void draw(SkCanvas* canvas) {
1049 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001050 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001051 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
1052 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
1053 SkPath path;
1054 debugster("initial", path);
1055 path.lineTo(50, 0);
1056 debugster("first line", path);
1057 path.getConvexity();
1058 path.lineTo(50, 50);
1059 debugster("second line", path);
1060 path.lineTo(100, 50);
1061 path.getConvexity();
1062 debugster("third line", path);
1063}
1064##
1065
1066#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
1067
1068##
1069
1070# ------------------------------------------------------------------------------
1071
1072#Method void setConvexity(Convexity convexity)
1073
Cary Clarkab2621d2018-01-30 10:08:57 -05001074#In Convexity
1075#Line # sets if geometry is convex to avoid future computation ##
Cary Clark73fa9722017-08-29 17:36:51 -04001076Stores convexity so that it is later returned by getConvexity or getConvexityOrUnknown.
1077convexity may differ from getConvexity, although setting an incorrect value may
1078cause incorrect or inefficient drawing.
1079
1080If convexity is kUnknown_Convexity: getConvexity will
1081compute Convexity, and getConvexityOrUnknown will return kUnknown_Convexity.
1082
1083If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity
1084and getConvexityOrUnknown will return convexity until the path is
1085altered.
1086
1087#Param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity ##
1088
1089#Example
1090void draw(SkCanvas* canvas) {
1091 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001092 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001093 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1094 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
Cary Clark682c58d2018-05-16 07:07:07 -04001095 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001096 SkPath path;
1097 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1098 debugster("initial", path);
1099 path.setConvexity(SkPath::kConcave_Convexity);
1100 debugster("after forcing concave", path);
1101 path.setConvexity(SkPath::kUnknown_Convexity);
1102 debugster("after forcing unknown", path);
1103}
1104##
1105
1106#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
1107
1108##
1109
1110# ------------------------------------------------------------------------------
1111
Cary Clark682c58d2018-05-16 07:07:07 -04001112#Method bool isConvex() const
Cary Clark73fa9722017-08-29 17:36:51 -04001113
Cary Clarkab2621d2018-01-30 10:08:57 -05001114#In Convexity
1115#Line # returns if geometry is convex ##
Cary Clark73fa9722017-08-29 17:36:51 -04001116Computes Convexity if required, and returns true if value is kConvex_Convexity.
1117If setConvexity was called with kConvex_Convexity or kConcave_Convexity, and
1118the path has not been altered, Convexity is not recomputed.
1119
1120#Return true if Convexity stored or computed is kConvex_Convexity ##
1121
1122#Example
1123#Description
Cary Clark682c58d2018-05-16 07:07:07 -04001124Concave shape is erroneously considered convex after a forced call to
Cary Clark73fa9722017-08-29 17:36:51 -04001125setConvexity.
1126##
1127void draw(SkCanvas* canvas) {
1128 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -04001129 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001130 for (SkScalar x : { 40, 100 } ) {
1131 SkPath path;
1132 quad[0].fX = x;
1133 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1134 path.setConvexity(SkPath::kConvex_Convexity);
1135 canvas->drawPath(path, paint);
1136 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
1137 canvas->translate(100, 100);
1138 }
1139}
1140##
1141
1142#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
1143
1144##
1145
Cary Clark73fa9722017-08-29 17:36:51 -04001146#Subtopic Convexity ##
1147
1148# ------------------------------------------------------------------------------
1149
Mike Reed0c3137c2018-02-20 13:57:05 -05001150#Method bool isOval(SkRect* bounds) const
Cary Clark4855f782018-02-06 09:41:53 -05001151#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001152#Line # returns if describes Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04001153
Mike Reed0c3137c2018-02-20 13:57:05 -05001154Returns true if this path is recognized as an oval or circle.
Cary Clark73fa9722017-08-29 17:36:51 -04001155
Mike Reed0c3137c2018-02-20 13:57:05 -05001156bounds receives bounds of Oval.
Cary Clark73fa9722017-08-29 17:36:51 -04001157
Mike Reed0c3137c2018-02-20 13:57:05 -05001158bounds is unmodified if Oval is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001159
Mike Reed0c3137c2018-02-20 13:57:05 -05001160#Param bounds storage for bounding Rect of Oval; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001161
Mike Reed0c3137c2018-02-20 13:57:05 -05001162#Return true if Path is recognized as an oval or circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04001163
1164#Example
1165void draw(SkCanvas* canvas) {
1166 SkPaint paint;
1167 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001168 path.addOval({20, 20, 220, 220});
Cary Clark73fa9722017-08-29 17:36:51 -04001169 SkRect bounds;
Mike Reed0c3137c2018-02-20 13:57:05 -05001170 if (path.isOval(&bounds)) {
1171 paint.setColor(0xFF9FBFFF);
1172 canvas->drawRect(bounds, paint);
1173 }
Cary Clark73fa9722017-08-29 17:36:51 -04001174 paint.setColor(0x3f000000);
1175 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001176}
1177##
1178
1179#SeeAlso Oval addCircle addOval
1180
1181##
1182
1183# ------------------------------------------------------------------------------
1184
Mike Reed0c3137c2018-02-20 13:57:05 -05001185#Method bool isRRect(SkRRect* rrect) const
Cary Clark4855f782018-02-06 09:41:53 -05001186#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001187#Line # returns if describes Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001188
Mike Reed0c3137c2018-02-20 13:57:05 -05001189Returns true if this path is recognized as a SkRRect (but not an oval/circle or rect).
Cary Clark73fa9722017-08-29 17:36:51 -04001190
1191rrect receives bounds of Round_Rect.
Cary Clark73fa9722017-08-29 17:36:51 -04001192
Mike Reed0c3137c2018-02-20 13:57:05 -05001193rrect is unmodified if Round_Rect is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001194
1195#Param rrect storage for bounding Rect of Round_Rect; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001196
Cary Clarkce101242017-09-01 15:51:02 -04001197#Return true if Path contains only Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001198
1199#Example
Cary Clarkce101242017-09-01 15:51:02 -04001200#Description
Mike Reed0c3137c2018-02-20 13:57:05 -05001201Draw rounded rectangle and its bounds.
Cary Clarkce101242017-09-01 15:51:02 -04001202##
Cary Clark73fa9722017-08-29 17:36:51 -04001203void draw(SkCanvas* canvas) {
1204 SkPaint paint;
1205 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001206 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50));
Cary Clark73fa9722017-08-29 17:36:51 -04001207 SkRRect rrect;
Mike Reed0c3137c2018-02-20 13:57:05 -05001208 if (path.isRRect(&rrect)) {
1209 const SkRect& bounds = rrect.rect();
1210 paint.setColor(0xFF9FBFFF);
1211 canvas->drawRect(bounds, paint);
1212 }
Cary Clark73fa9722017-08-29 17:36:51 -04001213 paint.setColor(0x3f000000);
1214 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001215}
1216##
1217
Cary Clark682c58d2018-05-16 07:07:07 -04001218#SeeAlso Round_Rect addRoundRect addRRect
Cary Clark73fa9722017-08-29 17:36:51 -04001219
1220##
1221
1222# ------------------------------------------------------------------------------
1223
Cary Clark0251b1b2018-08-15 15:14:55 -04001224#Method SkPath& reset()
Cary Clark4855f782018-02-06 09:41:53 -05001225#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001226#Line # removes Verb_Array, Point_Array, and Weights; frees memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001227Sets Path to its initial state.
Cary Clark73fa9722017-08-29 17:36:51 -04001228Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1229Internal storage associated with Path is released.
1230
Cary Clark0251b1b2018-08-15 15:14:55 -04001231#Return reference to Path ##
1232
Cary Clark73fa9722017-08-29 17:36:51 -04001233#Example
1234 SkPath path1, path2;
1235 path1.setFillType(SkPath::kInverseWinding_FillType);
1236 path1.addRect({10, 20, 30, 40});
1237 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1238 path1.reset();
1239 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1240##
1241
1242#SeeAlso rewind()
1243
1244##
1245
1246# ------------------------------------------------------------------------------
1247
Cary Clark0251b1b2018-08-15 15:14:55 -04001248#Method SkPath& rewind()
Cary Clark4855f782018-02-06 09:41:53 -05001249#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001250#Line # removes Verb_Array, Point_Array, and Weights, keeping memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001251Sets Path to its initial state, preserving internal storage.
Cary Clark73fa9722017-08-29 17:36:51 -04001252Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1253Internal storage associated with Path is retained.
1254
1255Use rewind() instead of reset() if Path storage will be reused and performance
Cary Clark682c58d2018-05-16 07:07:07 -04001256is critical.
Cary Clark73fa9722017-08-29 17:36:51 -04001257
Cary Clark0251b1b2018-08-15 15:14:55 -04001258#Return reference to Path ##
1259
Cary Clark73fa9722017-08-29 17:36:51 -04001260#Example
1261#Description
1262Although path1 retains its internal storage, it is indistinguishable from
1263a newly initialized path.
1264##
1265 SkPath path1, path2;
1266 path1.setFillType(SkPath::kInverseWinding_FillType);
1267 path1.addRect({10, 20, 30, 40});
1268 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1269 path1.rewind();
1270 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1271##
1272
1273#SeeAlso reset()
1274
1275##
1276
1277# ------------------------------------------------------------------------------
1278
Cary Clark682c58d2018-05-16 07:07:07 -04001279#Method bool isEmpty() const
Cary Clark4855f782018-02-06 09:41:53 -05001280#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001281#Line # returns if verb count is zero ##
Cary Clark80247e52018-07-11 16:18:41 -04001282Returns if Path is empty.
Cary Clark73fa9722017-08-29 17:36:51 -04001283Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
Cary Clarkd2ca79c2018-08-10 13:09:13 -04001284SkPath() constructs empty Path; reset() and rewind() make Path empty.
Cary Clark73fa9722017-08-29 17:36:51 -04001285
1286#Return true if the path contains no Verb array ##
1287
1288#Example
1289void draw(SkCanvas* canvas) {
1290 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1291 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
1292 };
1293 SkPath path;
1294 debugster("initial", path);
1295 path.moveTo(0, 0);
1296 debugster("after moveTo", path);
1297 path.rewind();
1298 debugster("after rewind", path);
1299 path.lineTo(0, 0);
1300 debugster("after lineTo", path);
1301 path.reset();
1302 debugster("after reset", path);
1303}
1304#StdOut
1305initial path is empty
1306after moveTo path is not empty
1307after rewind path is empty
1308after lineTo path is not empty
1309after reset path is empty
1310##
1311##
1312
1313#SeeAlso SkPath() reset() rewind()
1314
1315##
1316
1317# ------------------------------------------------------------------------------
1318
1319#Method bool isLastContourClosed() const
Cary Clark4855f782018-02-06 09:41:53 -05001320#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001321#Line # returns if final Contour forms a loop ##
Cary Clark80247e52018-07-11 16:18:41 -04001322Returns if Contour is closed.
Cary Clark73fa9722017-08-29 17:36:51 -04001323Contour is closed if Path Verb array was last modified by close(). When stroked,
Cary Clark682c58d2018-05-16 07:07:07 -04001324closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
Cary Clark73fa9722017-08-29 17:36:51 -04001325
1326#Return true if the last Contour ends with a kClose_Verb ##
1327
1328#Example
1329#Description
1330close() has no effect if Path is empty; isLastContourClosed() returns
1331false until Path has geometry followed by close().
1332##
1333void draw(SkCanvas* canvas) {
1334 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1335 SkDebugf("%s last contour is %s" "closed\n", prefix,
1336 path.isLastContourClosed() ? "" : "not ");
1337 };
1338 SkPath path;
1339 debugster("initial", path);
1340 path.close();
1341 debugster("after close", path);
1342 path.lineTo(0, 0);
1343 debugster("after lineTo", path);
1344 path.close();
1345 debugster("after close", path);
1346}
1347#StdOut
1348initial last contour is not closed
1349after close last contour is not closed
1350after lineTo last contour is not closed
1351after close last contour is closed
1352##
1353##
1354
1355#SeeAlso close()
1356
1357##
1358
1359# ------------------------------------------------------------------------------
1360
Cary Clark682c58d2018-05-16 07:07:07 -04001361#Method bool isFinite() const
Cary Clark4855f782018-02-06 09:41:53 -05001362#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001363#Line # returns if all Point values are finite ##
Cary Clark73fa9722017-08-29 17:36:51 -04001364Returns true for finite Point array values between negative SK_ScalarMax and
1365positive SK_ScalarMax. Returns false for any Point array value of
1366SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
1367
1368#Return true if all Point values are finite ##
1369
1370#Example
1371void draw(SkCanvas* canvas) {
1372 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1373 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1374 };
1375 SkPath path;
1376 debugster("initial", path);
1377 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1378 debugster("after line", path);
1379 SkMatrix matrix;
1380 matrix.setScale(2, 2);
1381 path.transform(matrix);
1382 debugster("after scale", path);
1383}
1384#StdOut
1385initial path is finite
1386after line path is finite
1387after scale path is not finite
1388##
1389##
1390
1391#SeeAlso SkScalar
1392##
1393
1394# ------------------------------------------------------------------------------
1395
Cary Clark682c58d2018-05-16 07:07:07 -04001396#Method bool isVolatile() const
Cary Clark4855f782018-02-06 09:41:53 -05001397#In Property
1398#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001399#Line # returns if Device should not cache ##
Cary Clark73fa9722017-08-29 17:36:51 -04001400Returns true if the path is volatile; it will not be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001401by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001402Surface to attach a cache of data which speeds repeated drawing. If true, Surface
1403may not speed repeated drawing.
1404
1405#Return true if caller will alter Path after drawing ##
1406
1407#Example
1408 SkPath path;
1409 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1410#StdOut
1411volatile by default is false
1412##
1413##
1414
1415#SeeAlso setIsVolatile
1416
1417##
1418
1419# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001420#Subtopic Volatile
1421#Populate
1422#Line # caching attribute ##
1423##
Cary Clark73fa9722017-08-29 17:36:51 -04001424
Cary Clark682c58d2018-05-16 07:07:07 -04001425#Method void setIsVolatile(bool isVolatile)
Cary Clark4855f782018-02-06 09:41:53 -05001426#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001427#Line # sets if Device should not cache ##
Cary Clark80247e52018-07-11 16:18:41 -04001428Specifies whether Path is volatile; whether it will be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001429by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001430Device to attach a cache of data which speeds repeated drawing.
1431
1432Mark temporary paths, discarded or modified after use, as volatile
1433to inform Device that the path need not be cached.
1434
1435Mark animating Path volatile to improve performance.
Cary Clarkce101242017-09-01 15:51:02 -04001436Mark unchanging Path non-volatile to improve repeated rendering.
Cary Clark73fa9722017-08-29 17:36:51 -04001437
1438Raster_Surface Path draws are affected by volatile for some shadows.
1439GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
1440
1441#Param isVolatile true if caller will alter Path after drawing ##
1442
1443#Example
1444#Height 50
1445#Width 50
1446 SkPaint paint;
1447 paint.setStyle(SkPaint::kStroke_Style);
1448 SkPath path;
1449 path.setIsVolatile(true);
1450 path.lineTo(40, 40);
1451 canvas->drawPath(path, paint);
1452 path.rewind();
1453 path.moveTo(0, 40);
1454 path.lineTo(40, 0);
1455 canvas->drawPath(path, paint);
1456##
1457
1458#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1459
1460#SeeAlso isVolatile
1461
1462##
1463
1464# ------------------------------------------------------------------------------
1465
Cary Clark682c58d2018-05-16 07:07:07 -04001466#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001467#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001468#Line # returns if Line is very small ##
Cary Clark80247e52018-07-11 16:18:41 -04001469Tests if Line between Point pair is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001470Line with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001471treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001472
Cary Clarka523d2d2017-08-30 08:58:10 -04001473exact changes the equality test. If true, returns true only if p1 equals p2.
1474If false, returns true if p1 equals or nearly equals p2.
1475
Cary Clark73fa9722017-08-29 17:36:51 -04001476#Param p1 line start point ##
1477#Param p2 line end point ##
Cary Clarka523d2d2017-08-30 08:58:10 -04001478#Param exact if false, allow nearly equals ##
Cary Clark73fa9722017-08-29 17:36:51 -04001479
1480#Return true if Line is degenerate; its length is effectively zero ##
1481
1482#Example
1483#Description
Cary Clarkce101242017-09-01 15:51:02 -04001484As single precision floats, 100 and 100.000001 have the same bit representation,
1485and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001486are not exactly equal, but are nearly equal.
1487##
1488void draw(SkCanvas* canvas) {
1489 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1490 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1491 for (bool exact : { false, true } ) {
1492 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1493 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1494 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1495 ? "" : "not ", exact ? "exactly" : "nearly");
1496 }
1497 }
1498}
1499#StdOut
1500line from (100,100) to (100,100) is degenerate, nearly
1501line from (100,100) to (100,100) is degenerate, exactly
1502line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1503line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1504#StdOut ##
1505##
1506
Cary Clark682c58d2018-05-16 07:07:07 -04001507#SeeAlso IsQuadDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001508##
1509
1510# ------------------------------------------------------------------------------
1511
1512#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001513 const SkPoint& p3, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001514#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001515#Line # returns if Quad is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001516
Cary Clark80247e52018-07-11 16:18:41 -04001517Tests if Quad is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001518Quad with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001519treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001520
Cary Clarkce101242017-09-01 15:51:02 -04001521#Param p1 Quad start point ##
1522#Param p2 Quad control point ##
1523#Param p3 Quad end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001524#Param exact if true, returns true only if p1, p2, and p3 are equal;
1525 if false, returns true if p1, p2, and p3 are equal or nearly equal
Cary Clark73fa9722017-08-29 17:36:51 -04001526##
1527
1528#Return true if Quad is degenerate; its length is effectively zero ##
1529
1530#Example
1531#Description
Cary Clarkce101242017-09-01 15:51:02 -04001532As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001533but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001534the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001535##
1536void draw(SkCanvas* canvas) {
1537 auto debugster = [](const SkPath& path, bool exact) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001538 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 -04001539 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1540 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1541 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1542 "" : "not ", exact ? "exactly" : "nearly");
1543 };
1544 SkPath path, offset;
1545 path.moveTo({100, 100});
1546 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1547 offset.addPath(path, 1000, 1000);
1548 for (bool exact : { false, true } ) {
1549 debugster(path, exact);
1550 debugster(offset, exact);
1551 }
1552}
1553#StdOut
1554quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1555quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1556quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1557quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1558#StdOut ##
1559##
1560
Cary Clark682c58d2018-05-16 07:07:07 -04001561#SeeAlso IsLineDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001562##
1563
1564# ------------------------------------------------------------------------------
1565
1566#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001567 const SkPoint& p3, const SkPoint& p4, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001568#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001569#Line # returns if Cubic is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001570
Cary Clark80247e52018-07-11 16:18:41 -04001571Tests if Cubic is degenerate.
Cary Clark73fa9722017-08-29 17:36:51 -04001572Cubic with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001573treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001574
Cary Clarkce101242017-09-01 15:51:02 -04001575#Param p1 Cubic start point ##
1576#Param p2 Cubic control point 1 ##
1577#Param p3 Cubic control point 2 ##
1578#Param p4 Cubic end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001579#Param exact if true, returns true only if p1, p2, p3, and p4 are equal;
Cary Clark73fa9722017-08-29 17:36:51 -04001580 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
1581##
1582
1583#Return true if Cubic is degenerate; its length is effectively zero ##
1584
1585#Example
1586void draw(SkCanvas* canvas) {
1587 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1588 SkScalar step = 1;
Cary Clark75fd4492018-06-20 12:45:16 -04001589 SkScalar prior, length = 0, degenerate = 0;
Cary Clark73fa9722017-08-29 17:36:51 -04001590 do {
1591 prior = points[0].fX;
1592 step /= 2;
1593 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1594 degenerate = prior;
1595 points[0].fX += step;
1596 } else {
1597 length = prior;
1598 points[0].fX -= step;
1599 }
1600 } while (prior != points[0].fX);
1601 SkDebugf("%1.8g is degenerate\n", degenerate);
1602 SkDebugf("%1.8g is length\n", length);
1603}
1604#StdOut
16050.00024414062 is degenerate
16060.00024414065 is length
1607#StdOut ##
1608##
1609
1610##
1611
1612# ------------------------------------------------------------------------------
1613
1614#Method bool isLine(SkPoint line[2]) const
Cary Clark4855f782018-02-06 09:41:53 -05001615#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001616#Line # returns if describes Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04001617Returns true if Path contains only one Line;
Cary Clark682c58d2018-05-16 07:07:07 -04001618Path_Verb array has two entries: kMove_Verb, kLine_Verb.
1619If Path contains one Line and line is not nullptr, line is set to
Cary Clark73fa9722017-08-29 17:36:51 -04001620Line start point and Line end point.
1621Returns false if Path is not one Line; line is unaltered.
1622
1623#Param line storage for Line. May be nullptr ##
1624
1625#Return true if Path contains exactly one Line ##
1626
1627#Example
1628void draw(SkCanvas* canvas) {
1629 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1630 SkPoint line[2];
1631 if (path.isLine(line)) {
1632 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1633 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1634 } else {
1635 SkDebugf("%s is not line\n", prefix);
1636 }
1637 };
1638 SkPath path;
1639 debugster("empty", path);
1640 path.lineTo(0, 0);
1641 debugster("zero line", path);
1642 path.rewind();
1643 path.moveTo(10, 10);
1644 path.lineTo(20, 20);
1645 debugster("line", path);
1646 path.moveTo(20, 20);
1647 debugster("second move", path);
1648}
1649#StdOut
1650empty is not line
1651zero line is line (0,0) (0,0)
1652line is line (10,10) (20,20)
1653second move is not line
1654##
1655##
1656
1657##
1658
1659# ------------------------------------------------------------------------------
1660
Cary Clark8032b982017-07-28 11:04:54 -04001661#Subtopic Point_Array
Cary Clark08895c42018-02-01 09:37:32 -05001662#Line # end points and control points for lines and curves ##
Cary Clark61dfc3a2018-01-03 08:37:53 -05001663#Substitute SkPoint array
Cary Clark8032b982017-07-28 11:04:54 -04001664
1665Point_Array contains Points satisfying the allocated Points for
1666each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001667and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001668one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1669
1670Point_Array may be read directly from Path with getPoints, or inspected with
1671getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001672
1673#Method int getPoints(SkPoint points[], int max) const
1674
Cary Clarkab2621d2018-01-30 10:08:57 -05001675#In Point_Array
1676#Line # returns Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001677Returns number of points in Path. Up to max points are copied.
1678points may be nullptr; then, max must be zero.
Cary Clark682c58d2018-05-16 07:07:07 -04001679If max is greater than number of points, excess points storage is unaltered.
Cary Clark73fa9722017-08-29 17:36:51 -04001680
1681#Param points storage for Path Point array. May be nullptr ##
1682#Param max maximum to copy; must be greater than or equal to zero ##
1683
1684#Return Path Point array length ##
1685
1686#Example
1687void draw(SkCanvas* canvas) {
1688 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1689 int count = path.getPoints(points, max);
1690 SkDebugf("%s point count: %d ", prefix, count);
1691 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1692 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1693 }
1694 SkDebugf("\n");
1695 };
1696 SkPath path;
1697 path.lineTo(20, 20);
1698 path.lineTo(-10, -10);
1699 SkPoint points[3];
1700 debugster("no points", path, nullptr, 0);
1701 debugster("zero max", path, points, 0);
1702 debugster("too small", path, points, 2);
1703 debugster("just right", path, points, path.countPoints());
1704}
1705#StdOut
1706no points point count: 3
1707zero max point count: 3
1708too small point count: 3 (0,0) (20,20)
1709just right point count: 3 (0,0) (20,20) (-10,-10)
1710##
1711##
1712
1713#SeeAlso countPoints getPoint
1714##
1715
1716#Method int countPoints() const
1717
Cary Clarkab2621d2018-01-30 10:08:57 -05001718#In Point_Array
1719#Line # returns Point_Array length ##
Cary Clark73fa9722017-08-29 17:36:51 -04001720Returns the number of points in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001721Point count is initially zero.
Cary Clark73fa9722017-08-29 17:36:51 -04001722
1723#Return Path Point array length ##
1724
1725#Example
1726void draw(SkCanvas* canvas) {
1727 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1728 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1729 };
1730 SkPath path;
1731 debugster("empty", path);
1732 path.lineTo(0, 0);
1733 debugster("zero line", path);
1734 path.rewind();
1735 path.moveTo(10, 10);
1736 path.lineTo(20, 20);
1737 debugster("line", path);
1738 path.moveTo(20, 20);
1739 debugster("second move", path);
1740}
1741#StdOut
1742empty point count: 0
1743zero line point count: 2
1744line point count: 2
1745second move point count: 3
1746##
1747##
1748
1749#SeeAlso getPoints
1750##
1751
1752#Method SkPoint getPoint(int index) const
1753
Cary Clarkab2621d2018-01-30 10:08:57 -05001754#In Point_Array
1755#Line # returns entry from Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001756Returns Point at index in Point_Array. Valid range for index is
17570 to countPoints - 1.
Cary Clark682c58d2018-05-16 07:07:07 -04001758Returns (0, 0) if index is out of range.
Cary Clark73fa9722017-08-29 17:36:51 -04001759
1760#Param index Point array element selector ##
1761
1762#Return Point array value or (0, 0) ##
1763
1764#Example
1765void draw(SkCanvas* canvas) {
Cary Clark73fa9722017-08-29 17:36:51 -04001766 SkPath path;
1767 path.lineTo(20, 20);
1768 path.offset(-10, -10);
1769 for (int i= 0; i < path.countPoints(); ++i) {
1770 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
Cary Clark682c58d2018-05-16 07:07:07 -04001771 }
Cary Clark73fa9722017-08-29 17:36:51 -04001772}
1773#StdOut
1774point 0: (-10,-10)
1775point 1: (10,10)
1776##
1777##
1778
1779#SeeAlso countPoints getPoints
1780##
1781
1782
1783#Subtopic Point_Array ##
1784
1785# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001786#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001787#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001788
1789Verb_Array always starts with kMove_Verb.
1790If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1791the quantity of kMove_Verb equals the Contour count.
1792Verb_Array does not include or count kDone_Verb; it is a convenience
1793returned when iterating through Verb_Array.
1794
Cary Clark682c58d2018-05-16 07:07:07 -04001795Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
Cary Clark8032b982017-07-28 11:04:54 -04001796or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001797
1798#Method int countVerbs() const
1799
Cary Clarkab2621d2018-01-30 10:08:57 -05001800#In Verb_Array
1801#Line # returns Verb_Array length ##
Cary Clark682c58d2018-05-16 07:07:07 -04001802Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -04001803kCubic_Verb, and kClose_Verb; added to Path.
1804
1805#Return length of Verb_Array ##
1806
1807#Example
1808SkPath path;
1809SkDebugf("empty verb count: %d\n", path.countVerbs());
1810path.addRoundRect({10, 20, 30, 40}, 5, 5);
1811SkDebugf("round rect verb count: %d\n", path.countVerbs());
1812#StdOut
1813empty verb count: 0
1814round rect verb count: 10
1815##
1816##
1817
1818#SeeAlso getVerbs Iter RawIter
1819
1820##
1821
1822#Method int getVerbs(uint8_t verbs[], int max) const
1823
Cary Clarkab2621d2018-01-30 10:08:57 -05001824#In Verb_Array
1825#Line # returns Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001826Returns the number of verbs in the path. Up to max verbs are copied. The
1827verbs are copied as one byte per verb.
1828
1829#Param verbs storage for verbs, may be nullptr ##
1830#Param max maximum number to copy into verbs ##
1831
1832#Return the actual number of verbs in the path ##
1833
1834#Example
1835void draw(SkCanvas* canvas) {
1836 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1837 int count = path.getVerbs(verbs, max);
1838 SkDebugf("%s verb count: %d ", prefix, count);
1839 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1840 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1841 SkDebugf("%s ", verbStr[verbs[i]]);
1842 }
1843 SkDebugf("\n");
1844 };
1845 SkPath path;
1846 path.lineTo(20, 20);
1847 path.lineTo(-10, -10);
1848 uint8_t verbs[3];
1849 debugster("no verbs", path, nullptr, 0);
1850 debugster("zero max", path, verbs, 0);
1851 debugster("too small", path, verbs, 2);
1852 debugster("just right", path, verbs, path.countVerbs());
1853}
1854#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04001855no verbs verb count: 3
1856zero max verb count: 3
1857too small verb count: 3 move line
1858just right verb count: 3 move line line
Cary Clark73fa9722017-08-29 17:36:51 -04001859##
1860##
1861
1862#SeeAlso countVerbs getPoints Iter RawIter
1863##
Cary Clark8032b982017-07-28 11:04:54 -04001864
1865#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001866
1867# ------------------------------------------------------------------------------
1868
1869#Method void swap(SkPath& other)
Cary Clark4855f782018-02-06 09:41:53 -05001870#In Operator
Cary Clarkab2621d2018-01-30 10:08:57 -05001871#Line # exchanges Path pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04001872Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1873Cached state is also exchanged. swap() internally exchanges pointers, so
1874it is lightweight and does not allocate memory.
1875
1876swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001877Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001878making assignment as efficient as swap().
1879
1880#Param other Path exchanged by value ##
1881
1882#Example
1883SkPath path1, path2;
1884path1.addRect({10, 20, 30, 40});
1885path1.swap(path2);
1886const SkRect& b1 = path1.getBounds();
1887SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1888const SkRect& b2 = path2.getBounds();
1889SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1890#StdOut
1891path1 bounds = 0, 0, 0, 0
1892path2 bounds = 10, 20, 30, 40
1893#StdOut ##
1894##
1895
1896#SeeAlso operator=(const SkPath& path)
1897
1898##
1899
1900# ------------------------------------------------------------------------------
1901
Cary Clark682c58d2018-05-16 07:07:07 -04001902#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001903#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001904#Line # returns maximum and minimum of Point_Array ##
Cary Clark5538c132018-06-14 12:28:14 -04001905Returns minimum and maximum axes values of Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04001906Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1907be larger or smaller than area affected when Path is drawn.
1908
1909Rect returned includes all Points added to Path, including Points associated with
1910kMove_Verb that define empty Contours.
1911
1912#Return bounds of all Points in Point_Array ##
1913
1914#Example
1915#Description
1916Bounds of upright Circle can be predicted from center and radius.
1917Bounds of rotated Circle includes control Points outside of filled area.
1918##
1919 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1920 const SkRect& bounds = path.getBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001921 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001922 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1923 };
1924 SkPath path;
1925 debugster("empty", path);
1926 path.addCircle(50, 45, 25);
1927 debugster("circle", path);
1928 SkMatrix matrix;
1929 matrix.setRotate(45, 50, 45);
1930 path.transform(matrix);
1931 debugster("rotated circle", path);
1932#StdOut
1933empty bounds = 0, 0, 0, 0
1934circle bounds = 25, 20, 75, 70
1935rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1936##
1937##
1938
1939#SeeAlso computeTightBounds updateBoundsCache
1940
1941##
1942
1943# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001944#Subtopic Utility
1945#Populate
1946#Line # rarely called management functions ##
1947##
Cary Clark73fa9722017-08-29 17:36:51 -04001948
Cary Clark682c58d2018-05-16 07:07:07 -04001949#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001950#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001951#Line # refreshes result of getBounds ##
Cary Clark80247e52018-07-11 16:18:41 -04001952Updates internal bounds so that subsequent calls to getBounds are instantaneous.
Cary Clark73fa9722017-08-29 17:36:51 -04001953Unaltered copies of Path may also access cached bounds through getBounds.
1954
1955For now, identical to calling getBounds and ignoring the returned value.
1956
Cary Clark682c58d2018-05-16 07:07:07 -04001957Call to prepare Path subsequently drawn from multiple threads,
Cary Clark73fa9722017-08-29 17:36:51 -04001958to avoid a race condition where each draw separately computes the bounds.
1959
1960#Example
1961 double times[2] = { 0, 0 };
1962 for (int i = 0; i < 10000; ++i) {
1963 SkPath path;
1964 for (int j = 1; j < 100; ++ j) {
1965 path.addCircle(50 + j, 45 + j, 25 + j);
1966 }
1967 if (1 & i) {
1968 path.updateBoundsCache();
1969 }
1970 double start = SkTime::GetNSecs();
1971 (void) path.getBounds();
1972 times[1 & i] += SkTime::GetNSecs() - start;
1973 }
1974 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1975 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1976#StdOut
1977#Volatile
1978uncached avg: 0.18048 ms
1979cached avg: 0.182784 ms
1980##
1981##
1982
1983#SeeAlso getBounds
1984#ToDo the results don't make sense, need to profile to figure this out ##
1985
1986##
1987
1988# ------------------------------------------------------------------------------
1989
1990#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001991#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001992#Line # returns extent of geometry ##
Cary Clark5538c132018-06-14 12:28:14 -04001993Returns minimum and maximum axes values of the lines and curves in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001994Returns (0, 0, 0, 0) if Path contains no points.
1995Returned bounds width and height may be larger or smaller than area affected
Cary Clark73fa9722017-08-29 17:36:51 -04001996when Path is drawn.
1997
1998Includes Points associated with kMove_Verb that define empty
1999Contours.
2000
2001Behaves identically to getBounds when Path contains
2002only lines. If Path contains curves, computed bounds includes
2003the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
2004and unlike getBounds, does not cache the result.
2005
2006#Return tight bounds of curves in Path ##
2007
2008#Example
2009 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2010 const SkRect& bounds = path.computeTightBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04002011 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04002012 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2013 };
2014 SkPath path;
2015 debugster("empty", path);
2016 path.addCircle(50, 45, 25);
2017 debugster("circle", path);
2018 SkMatrix matrix;
2019 matrix.setRotate(45, 50, 45);
2020 path.transform(matrix);
2021 debugster("rotated circle", path);
2022#StdOut
2023empty bounds = 0, 0, 0, 0
2024circle bounds = 25, 20, 75, 70
2025rotated circle bounds = 25, 20, 75, 70
2026##
2027##
2028
2029#SeeAlso getBounds
2030
2031##
2032
2033# ------------------------------------------------------------------------------
2034
2035#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05002036#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002037#Line # returns true if Rect may be inside ##
Cary Clark682c58d2018-05-16 07:07:07 -04002038Returns true if rect is contained by Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002039May return false when rect is contained by Path.
2040
2041For now, only returns true if Path has one Contour and is convex.
2042rect may share points and edges with Path and be contained.
2043Returns true if rect is empty, that is, it has zero width or height; and
2044the Point or Line described by rect is contained by Path.
2045
2046#Param rect Rect, Line, or Point checked for containment ##
2047
2048#Return true if rect is contained ##
2049
2050#Example
2051#Height 140
2052#Description
2053Rect is drawn in blue if it is contained by red Path.
2054##
2055void draw(SkCanvas* canvas) {
2056 SkPath path;
2057 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2058 SkRect tests[] = {
2059 { 10, 40, 54, 80 },
2060 { 25, 20, 39, 120 },
2061 { 15, 25, 49, 115 },
2062 { 13, 27, 51, 113 },
2063 };
2064 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2065 SkPaint paint;
2066 paint.setColor(SK_ColorRED);
2067 canvas->drawPath(path, paint);
2068 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2069 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2070 canvas->drawRect(tests[i], paint);
2071 canvas->translate(64, 0);
2072 }
2073}
2074##
2075
2076#SeeAlso contains Op Rect Convexity
2077
2078##
2079
2080# ------------------------------------------------------------------------------
2081
2082#Method void incReserve(unsigned extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05002083#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002084#Line # reserves space for additional data ##
Cary Clark80247e52018-07-11 16:18:41 -04002085Grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
Cary Clark73fa9722017-08-29 17:36:51 -04002086May improve performance and use less memory by
2087reducing the number and size of allocations when creating Path.
2088
Cary Clarkce101242017-09-01 15:51:02 -04002089#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002090
2091#Example
2092#Height 192
2093void draw(SkCanvas* canvas) {
2094 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2095 path->moveTo(size, 0);
2096 for (int i = 1; i < sides; i++) {
2097 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2098 path->lineTo(c * size, s * size);
2099 }
2100 path->close();
2101 };
2102 SkPath path;
2103 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2104 for (int sides = 3; sides < 10; ++sides) {
2105 addPoly(sides, sides, &path);
2106 }
2107 SkMatrix matrix;
2108 matrix.setScale(10, 10, -10, -10);
2109 path.transform(matrix);
2110 SkPaint paint;
2111 paint.setStyle(SkPaint::kStroke_Style);
2112 canvas->drawPath(path, paint);
2113}
2114##
2115
2116#SeeAlso Point_Array
2117
2118##
2119
2120# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05002121#Subtopic Build
2122#Populate
2123#Line # adds points and verbs to path ##
2124##
Cary Clark73fa9722017-08-29 17:36:51 -04002125
Cary Clark0251b1b2018-08-15 15:14:55 -04002126#Method SkPath& moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002127#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002128#Line # starts Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -04002129Adds beginning of Contour at Point (x, y).
2130
Cary Clark5538c132018-06-14 12:28:14 -04002131#Param x x-axis value of Contour start ##
2132#Param y y-axis value of Contour start ##
Cary Clark73fa9722017-08-29 17:36:51 -04002133
Cary Clark0251b1b2018-08-15 15:14:55 -04002134#Return reference to Path ##
2135
Cary Clark73fa9722017-08-29 17:36:51 -04002136#Example
2137 #Width 140
2138 #Height 100
2139 void draw(SkCanvas* canvas) {
2140 SkRect rect = { 20, 20, 120, 80 };
2141 SkPath path;
2142 path.addRect(rect);
2143 path.moveTo(rect.fLeft, rect.fTop);
2144 path.lineTo(rect.fRight, rect.fBottom);
2145 path.moveTo(rect.fLeft, rect.fBottom);
2146 path.lineTo(rect.fRight, rect.fTop);
2147 SkPaint paint;
2148 paint.setStyle(SkPaint::kStroke_Style);
2149 canvas->drawPath(path, paint);
2150 }
2151##
2152
2153#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2154
2155##
2156
Cary Clark0251b1b2018-08-15 15:14:55 -04002157#Method SkPath& moveTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002158
2159Adds beginning of Contour at Point p.
2160
2161#Param p contour start ##
2162
Cary Clark0251b1b2018-08-15 15:14:55 -04002163#Return reference to Path ##
2164
Cary Clark73fa9722017-08-29 17:36:51 -04002165#Example
2166 #Width 128
2167 #Height 128
2168void draw(SkCanvas* canvas) {
Cary Clark682c58d2018-05-16 07:07:07 -04002169 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
Cary Clark73fa9722017-08-29 17:36:51 -04002170 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2171 SkPath path;
2172 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2173 path.moveTo(data[i][0]);
2174 path.lineTo(data[i][1]);
2175 path.lineTo(data[i][2]);
2176 }
2177 SkPaint paint;
2178 paint.setStyle(SkPaint::kStroke_Style);
2179 canvas->drawPath(path, paint);
2180}
2181##
2182
2183#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2184
2185##
2186
Cary Clark0251b1b2018-08-15 15:14:55 -04002187#Method SkPath& rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002188#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002189#Line # starts Contour relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002190Adds beginning of Contour relative to Last_Point.
2191If Path is empty, starts Contour at (dx, dy).
Cary Clark682c58d2018-05-16 07:07:07 -04002192Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002193Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002194
Cary Clark5538c132018-06-14 12:28:14 -04002195#Param dx offset from Last_Point to Contour start on x-axis ##
2196#Param dy offset from Last_Point to Contour start on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002197
Cary Clark0251b1b2018-08-15 15:14:55 -04002198#Return reference to Path ##
2199
Cary Clark73fa9722017-08-29 17:36:51 -04002200#Example
2201 #Height 100
2202 SkPath path;
2203 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2204 path.rMoveTo(25, 2);
2205 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2206 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2207 path.rLineTo(arrow[i].fX, arrow[i].fY);
2208 }
2209 SkPaint paint;
2210 canvas->drawPath(path, paint);
2211 SkPoint lastPt;
2212 path.getLastPt(&lastPt);
2213 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2214##
2215
2216#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2217
2218##
2219
2220# ------------------------------------------------------------------------------
2221
Cary Clark0251b1b2018-08-15 15:14:55 -04002222#Method SkPath& lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002223#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002224#Line # appends Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04002225Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2226kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2227
2228lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2229lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
Cary Clark682c58d2018-05-16 07:07:07 -04002230
Cary Clark73fa9722017-08-29 17:36:51 -04002231#Param x end of added Line in x ##
2232#Param y end of added Line in y ##
2233
Cary Clark0251b1b2018-08-15 15:14:55 -04002234#Return reference to Path ##
2235
Cary Clark73fa9722017-08-29 17:36:51 -04002236#Example
2237#Height 100
2238###$
2239void draw(SkCanvas* canvas) {
2240 SkPaint paint;
2241 paint.setAntiAlias(true);
2242 paint.setTextSize(72);
2243 canvas->drawString("#", 120, 80, paint);
2244 paint.setStyle(SkPaint::kStroke_Style);
2245 paint.setStrokeWidth(5);
2246 SkPath path;
2247 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2248 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2249 unsigned o = 0;
2250 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2251 for (unsigned j = 0; j < 2; o++, j++) {
2252 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2253 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2254 }
2255 }
2256 canvas->drawPath(path, paint);
2257}
2258$$$#
2259##
2260
2261#SeeAlso Contour moveTo rLineTo addRect
2262
2263##
2264
2265# ------------------------------------------------------------------------------
2266
Cary Clark0251b1b2018-08-15 15:14:55 -04002267#Method SkPath& lineTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002268
2269Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2270kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2271
2272lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2273lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2274
2275#Param p end Point of added Line ##
2276
Cary Clark0251b1b2018-08-15 15:14:55 -04002277#Return reference to Path ##
2278
Cary Clark73fa9722017-08-29 17:36:51 -04002279#Example
2280#Height 100
2281 SkPath path;
2282 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2283 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2284 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2285 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2286 path.moveTo(oxo[i]);
2287 path.lineTo(oxo[i + 1]);
2288 }
2289 SkPaint paint;
2290 paint.setStyle(SkPaint::kStroke_Style);
2291 canvas->drawPath(path, paint);
2292##
2293
2294#SeeAlso Contour moveTo rLineTo addRect
2295
2296##
2297
2298# ------------------------------------------------------------------------------
2299
Cary Clark0251b1b2018-08-15 15:14:55 -04002300#Method SkPath& rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002301#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002302#Line # appends Line relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002303Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2304kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2305
2306Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2307then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2308Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002309Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002310
Cary Clark5538c132018-06-14 12:28:14 -04002311#Param dx offset from Last_Point to Line end on x-axis ##
2312#Param dy offset from Last_Point to Line end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002313
Cary Clark0251b1b2018-08-15 15:14:55 -04002314#Return reference to Path ##
2315
Cary Clark73fa9722017-08-29 17:36:51 -04002316#Example
2317#Height 128
2318void draw(SkCanvas* canvas) {
2319 SkPaint paint;
2320 paint.setAntiAlias(true);
2321 paint.setStyle(SkPaint::kStroke_Style);
2322 SkPath path;
2323 path.moveTo(10, 98);
2324 SkScalar x = 0, y = 0;
2325 for (int i = 10; i < 100; i += 5) {
2326 x += i * ((i & 2) - 1);
2327 y += i * (((i + 1) & 2) - 1);
2328 path.rLineTo(x, y);
Cary Clark682c58d2018-05-16 07:07:07 -04002329
Cary Clark73fa9722017-08-29 17:36:51 -04002330 }
2331 canvas->drawPath(path, paint);
2332}
2333##
2334
2335#SeeAlso Contour moveTo lineTo addRect
2336
2337##
2338
2339# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002340#Subtopic Quad
Cary Clark137b8742018-05-30 09:21:49 -04002341#Alias Quad ##
2342#Alias Quads ##
2343#Alias Quadratic_Bezier ##
2344#Alias Quadratic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002345#Line # curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002346
2347Quad describes a quadratic Bezier, a second-order curve identical to a section
2348of a parabola. Quad begins at a start Point, curves towards a control Point,
2349and then curves to an end Point.
2350
2351#Example
2352#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002353void draw(SkCanvas* canvas) {
2354 SkPaint paint;
2355 paint.setAntiAlias(true);
2356 paint.setStyle(SkPaint::kStroke_Style);
2357 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2358 canvas->drawLine(quadPts[0], quadPts[1], paint);
2359 canvas->drawLine(quadPts[1], quadPts[2], paint);
2360 SkPath path;
2361 path.moveTo(quadPts[0]);
2362 path.quadTo(quadPts[1], quadPts[2]);
2363 paint.setStrokeWidth(3);
2364 canvas->drawPath(path, paint);
2365}
Cary Clark8032b982017-07-28 11:04:54 -04002366##
2367
2368Quad is a special case of Conic where Conic_Weight is set to one.
2369
2370Quad is always contained by the triangle connecting its three Points. Quad
2371begins tangent to the line between start Point and control Point, and ends
2372tangent to the line between control Point and end Point.
2373
2374#Example
2375#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002376void draw(SkCanvas* canvas) {
2377 SkPaint paint;
2378 paint.setAntiAlias(true);
2379 paint.setStyle(SkPaint::kStroke_Style);
2380 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2381 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2382 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2383 paint.setColor(0x7fffffff & colors[i]);
2384 paint.setStrokeWidth(1);
2385 canvas->drawLine(quadPts[0], quadPts[1], paint);
2386 canvas->drawLine(quadPts[1], quadPts[2], paint);
2387 SkPath path;
2388 path.moveTo(quadPts[0]);
2389 path.quadTo(quadPts[1], quadPts[2]);
2390 paint.setStrokeWidth(3);
2391 paint.setColor(colors[i]);
2392 canvas->drawPath(path, paint);
2393 quadPts[1].fY += 30;
2394 }
Cary Clark8032b982017-07-28 11:04:54 -04002395}
2396##
Cary Clark73fa9722017-08-29 17:36:51 -04002397
Cary Clark0251b1b2018-08-15 15:14:55 -04002398#Method SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Cary Clark73fa9722017-08-29 17:36:51 -04002399
Cary Clarkab2621d2018-01-30 10:08:57 -05002400#In Quad
2401#Line # appends Quad ##
Cary Clark682c58d2018-05-16 07:07:07 -04002402 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
Cary Clark73fa9722017-08-29 17:36:51 -04002403 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2404 before adding Quad.
2405
2406 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2407 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2408 to Point_Array.
2409
2410 #Param x1 control Point of Quad in x ##
2411 #Param y1 control Point of Quad in y ##
2412 #Param x2 end Point of Quad in x ##
2413 #Param y2 end Point of Quad in y ##
2414
Cary Clark0251b1b2018-08-15 15:14:55 -04002415 #Return reference to Path ##
2416
Cary Clark73fa9722017-08-29 17:36:51 -04002417 #Example
2418 void draw(SkCanvas* canvas) {
2419 SkPaint paint;
2420 paint.setAntiAlias(true);
2421 paint.setStyle(SkPaint::kStroke_Style);
2422 SkPath path;
2423 path.moveTo(0, -10);
2424 for (int i = 0; i < 128; i += 16) {
2425 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2426 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2427 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2428 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2429 }
2430 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002431 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002432 }
2433 ##
2434
2435 #SeeAlso Contour moveTo conicTo rQuadTo
2436
2437##
2438
Cary Clark0251b1b2018-08-15 15:14:55 -04002439#Method SkPath& quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05002440#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002441#In Quad
Cary Clark682c58d2018-05-16 07:07:07 -04002442 Adds Quad from Last_Point towards Point p1, to Point p2.
Cary Clark73fa9722017-08-29 17:36:51 -04002443 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2444 before adding Quad.
2445
2446 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2447 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2448 to Point_Array.
2449
2450 #Param p1 control Point of added Quad ##
2451 #Param p2 end Point of added Quad ##
2452
Cary Clark0251b1b2018-08-15 15:14:55 -04002453 #Return reference to Path ##
2454
Cary Clark73fa9722017-08-29 17:36:51 -04002455 #Example
2456 void draw(SkCanvas* canvas) {
2457 SkPaint paint;
2458 paint.setStyle(SkPaint::kStroke_Style);
2459 paint.setAntiAlias(true);
2460 SkPath path;
2461 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2462 path.moveTo(pts[1]);
2463 for (int i = 0; i < 3; ++i) {
2464 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2465 }
2466 canvas->drawPath(path, paint);
2467 }
2468 ##
2469
2470 #SeeAlso Contour moveTo conicTo rQuadTo
2471
2472##
2473
Cary Clark0251b1b2018-08-15 15:14:55 -04002474#Method SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05002475#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002476#In Quad
2477#Line # appends Quad relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002478 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2479 If Path is empty, or last Verb
2480 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2481
2482 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2483 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2484 control and Quad end to Point_Array.
2485 Quad control is Last_Point plus Vector (dx1, dy1).
2486 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002487 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002488
Cary Clark5538c132018-06-14 12:28:14 -04002489 #Param dx1 offset from Last_Point to Quad control on x-axis ##
2490 #Param dy1 offset from Last_Point to Quad control on y-axis ##
2491 #Param dx2 offset from Last_Point to Quad end on x-axis ##
2492 #Param dy2 offset from Last_Point to Quad end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002493
Cary Clark0251b1b2018-08-15 15:14:55 -04002494 #Return reference to Path ##
2495
Cary Clark73fa9722017-08-29 17:36:51 -04002496 #Example
2497 void draw(SkCanvas* canvas) {
2498 SkPaint paint;
2499 paint.setAntiAlias(true);
2500 SkPath path;
2501 path.moveTo(128, 20);
2502 path.rQuadTo(-6, 10, -7, 10);
2503 for (int i = 1; i < 32; i += 4) {
2504 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2505 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2506 }
2507 path.quadTo(92, 220, 128, 215);
2508 canvas->drawPath(path, paint);
2509 }
2510 ##
2511
2512 #SeeAlso Contour moveTo conicTo quadTo
2513
2514##
2515
Cary Clark78de7512018-02-07 07:27:09 -05002516#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002517
2518# ------------------------------------------------------------------------------
2519
Cary Clark78de7512018-02-07 07:27:09 -05002520#Subtopic Conic
Cary Clark08895c42018-02-01 09:37:32 -05002521#Line # conic section defined by three points and a weight ##
Cary Clark137b8742018-05-30 09:21:49 -04002522#Alias Conics ##
Cary Clark8032b982017-07-28 11:04:54 -04002523
2524Conic describes a conical section: a piece of an ellipse, or a piece of a
Cary Clark682c58d2018-05-16 07:07:07 -04002525parabola, or a piece of a hyperbola. Conic begins at a start Point,
Cary Clark8032b982017-07-28 11:04:54 -04002526curves towards a control Point, and then curves to an end Point. The influence
2527of the control Point is determined by Conic_Weight.
2528
Cary Clark73fa9722017-08-29 17:36:51 -04002529Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2530may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002531
2532#Subtopic Weight
Cary Clark137b8742018-05-30 09:21:49 -04002533#Alias Conic_Weights ##
2534#Alias Weights ##
Cary Clark08895c42018-02-01 09:37:32 -05002535#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002536
2537Weight determines both the strength of the control Point and the type of Conic.
Cary Clark682c58d2018-05-16 07:07:07 -04002538Weight varies from zero to infinity. At zero, Weight causes the control Point to
2539have no effect; Conic is identical to a line segment from start Point to end
2540point. If Weight is less than one, Conic follows an elliptical arc.
2541If Weight is exactly one, then Conic is identical to Quad; Conic follows a
2542parabolic arc. If Weight is greater than one, Conic follows a hyperbolic
Cary Clark137b8742018-05-30 09:21:49 -04002543arc. If Weight is infinity, Conic is identical to two line segments, connecting
Cary Clark682c58d2018-05-16 07:07:07 -04002544start Point to control Point, and control Point to end Point.
Cary Clark8032b982017-07-28 11:04:54 -04002545
2546#Example
2547#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002548When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002549##
Cary Clark73fa9722017-08-29 17:36:51 -04002550void draw(SkCanvas* canvas) {
2551 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2552 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2553 SkPath path;
2554 path.conicTo(20, 30, 50, 60, 1);
2555 SkPath::Iter iter(path, false);
2556 SkPath::Verb verb;
2557 do {
2558 SkPoint points[4];
2559 verb = iter.next(points);
2560 SkDebugf("%s ", verbNames[(int) verb]);
2561 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2562 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2563 }
2564 if (SkPath::kConic_Verb == verb) {
2565 SkDebugf("weight = %g", iter.conicWeight());
2566 }
2567 SkDebugf("\n");
2568 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002569}
2570#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002571move {0, 0},
2572quad {0, 0}, {20, 30}, {50, 60},
2573done
Cary Clark8032b982017-07-28 11:04:54 -04002574##
2575##
2576
2577If weight is less than one, Conic is an elliptical segment.
2578
Cary Clark682c58d2018-05-16 07:07:07 -04002579#Example
Cary Clark8032b982017-07-28 11:04:54 -04002580#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002581A 90 degree circular arc has the weight
Cary Clark8032b982017-07-28 11:04:54 -04002582#Formula
25831 / sqrt(2)
2584##
Cary Clark6fc50412017-09-21 12:31:06 -04002585.
Cary Clark8032b982017-07-28 11:04:54 -04002586##
Cary Clark73fa9722017-08-29 17:36:51 -04002587void draw(SkCanvas* canvas) {
2588 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2589 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2590 SkPath path;
2591 path.arcTo(20, 0, 20, 20, 20);
2592 SkPath::Iter iter(path, false);
2593 SkPath::Verb verb;
2594 do {
2595 SkPoint points[4];
2596 verb = iter.next(points);
2597 SkDebugf("%s ", verbNames[(int) verb]);
2598 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2599 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2600 }
2601 if (SkPath::kConic_Verb == verb) {
2602 SkDebugf("weight = %g", iter.conicWeight());
2603 }
2604 SkDebugf("\n");
2605 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002606}
2607#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002608move {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04002609conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark682c58d2018-05-16 07:07:07 -04002610done
Cary Clark8032b982017-07-28 11:04:54 -04002611##
2612##
2613
Cary Clarkce101242017-09-01 15:51:02 -04002614If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002615a hyperbolic segment can be approximated by straight lines connecting the
2616control Point with the end Points.
2617
2618#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002619void draw(SkCanvas* canvas) {
2620 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2621 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2622 SkPath path;
2623 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2624 SkPath::Iter iter(path, false);
2625 SkPath::Verb verb;
2626 do {
2627 SkPoint points[4];
2628 verb = iter.next(points);
2629 SkDebugf("%s ", verbNames[(int) verb]);
2630 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2631 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2632 }
2633 if (SkPath::kConic_Verb == verb) {
2634 SkDebugf("weight = %g", iter.conicWeight());
2635 }
2636 SkDebugf("\n");
2637 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002638}
2639#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002640move {0, 0},
2641line {0, 0}, {20, 0},
2642line {20, 0}, {20, 20},
2643done
Cary Clark8032b982017-07-28 11:04:54 -04002644##
2645##
2646
2647#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002648
Cary Clark0251b1b2018-08-15 15:14:55 -04002649#Method SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002650 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002651#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002652#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002653#Line # appends Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002654
Cary Clark682c58d2018-05-16 07:07:07 -04002655 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002656 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2657 before adding Conic.
2658
2659 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2660
2661 If w is finite and not one, appends kConic_Verb to Verb_Array;
2662 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2663
2664 If w is one, appends kQuad_Verb to Verb_Array, and
2665 (x1, y1), (x2, y2) to Point_Array.
2666
2667 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2668 (x1, y1), (x2, y2) to Point_Array.
2669
2670 #Param x1 control Point of Conic in x ##
2671 #Param y1 control Point of Conic in y ##
2672 #Param x2 end Point of Conic in x ##
2673 #Param y2 end Point of Conic in y ##
2674 #Param w weight of added Conic ##
2675
Cary Clark0251b1b2018-08-15 15:14:55 -04002676 #Return reference to Path ##
2677
Cary Clark73fa9722017-08-29 17:36:51 -04002678 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002679 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002680 #Description
Cary Clark682c58d2018-05-16 07:07:07 -04002681 As weight increases, curve is pulled towards control point.
Cary Clark73fa9722017-08-29 17:36:51 -04002682 The bottom two curves are elliptical; the next is parabolic; the
2683 top curve is hyperbolic.
2684 ##
2685void draw(SkCanvas* canvas) {
2686 SkPaint paint;
2687 paint.setAntiAlias(true);
2688 paint.setStyle(SkPaint::kStroke_Style);
2689 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2690 canvas->drawLine(conicPts[0], conicPts[1], paint);
2691 canvas->drawLine(conicPts[1], conicPts[2], paint);
2692 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2693 paint.setStrokeWidth(3);
2694 SkScalar weight = 0.5f;
2695 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2696 SkPath path;
2697 path.moveTo(conicPts[0]);
2698 path.conicTo(conicPts[1], conicPts[2], weight);
2699 paint.setColor(colors[i]);
2700 canvas->drawPath(path, paint);
2701 weight += 0.25f;
2702 }
2703}
2704 ##
2705
2706 #SeeAlso rConicTo arcTo addArc quadTo
2707
2708##
2709
Cary Clark0251b1b2018-08-15 15:14:55 -04002710#Method SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002711#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002712#In Conic
Cary Clark682c58d2018-05-16 07:07:07 -04002713 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002714 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2715 before adding Conic.
2716
2717 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2718
2719 If w is finite and not one, appends kConic_Verb to Verb_Array;
2720 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2721
2722 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2723 to Point_Array.
2724
2725 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2726 Points p1, p2 to Point_Array.
2727
2728 #Param p1 control Point of added Conic ##
2729 #Param p2 end Point of added Conic ##
2730 #Param w weight of added Conic ##
2731
Cary Clark0251b1b2018-08-15 15:14:55 -04002732 #Return reference to Path ##
2733
Cary Clark73fa9722017-08-29 17:36:51 -04002734 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002735 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002736 #Description
2737 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002738 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002739 ##
2740void draw(SkCanvas* canvas) {
2741 SkPaint paint;
2742 paint.setAntiAlias(true);
2743 paint.setStyle(SkPaint::kStroke_Style);
2744 SkRect oval = {0, 20, 120, 140};
2745 SkPath path;
2746 for (int i = 0; i < 4; ++i) {
2747 path.moveTo(oval.centerX(), oval.fTop);
2748 path.arcTo(oval, -90, 90 - 20 * i, false);
2749 oval.inset(15, 15);
2750 }
2751 path.offset(100, 0);
2752 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2753 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2754 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2755 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2756 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2757 for (int i = 0; i < 4; ++i) {
2758 path.moveTo(conicPts[i][0]);
2759 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2760 }
2761 canvas->drawPath(path, paint);
2762}
2763 ##
2764
2765 #SeeAlso rConicTo arcTo addArc quadTo
2766
2767##
2768
Cary Clark0251b1b2018-08-15 15:14:55 -04002769#Method SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
Cary Clark73fa9722017-08-29 17:36:51 -04002770 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002771#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002772#In Conic
2773#Line # appends Conic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002774
2775 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2776 weighted by w. If Path is empty, or last Verb
2777 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2778
2779 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
Cary Clark682c58d2018-05-16 07:07:07 -04002780 if needed.
2781
Cary Clark73fa9722017-08-29 17:36:51 -04002782 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2783 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2784 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2785 twice to Verb_Array.
2786
2787 In all cases appends Points control and end to Point_Array.
2788 control is Last_Point plus Vector (dx1, dy1).
2789 end is Last_Point plus Vector (dx2, dy2).
2790
Cary Clarkce101242017-09-01 15:51:02 -04002791 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002792
Cary Clark5538c132018-06-14 12:28:14 -04002793 #Param dx1 offset from Last_Point to Conic control on x-axis ##
2794 #Param dy1 offset from Last_Point to Conic control on y-axis ##
2795 #Param dx2 offset from Last_Point to Conic end on x-axis ##
2796 #Param dy2 offset from Last_Point to Conic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002797 #Param w weight of added Conic ##
2798
Cary Clark0251b1b2018-08-15 15:14:55 -04002799 #Return reference to Path ##
2800
Cary Clark73fa9722017-08-29 17:36:51 -04002801 #Example
2802 #Height 140
2803 void draw(SkCanvas* canvas) {
2804 SkPaint paint;
2805 paint.setAntiAlias(true);
2806 paint.setStyle(SkPaint::kStroke_Style);
2807 SkPath path;
2808 path.moveTo(20, 80);
2809 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2810 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2811 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2812 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2813 canvas->drawPath(path, paint);
2814 }
2815 ##
2816
2817 #SeeAlso conicTo arcTo addArc quadTo
2818
2819##
2820
Cary Clark78de7512018-02-07 07:27:09 -05002821#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002822
2823# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002824#Subtopic Cubic
Cary Clark137b8742018-05-30 09:21:49 -04002825#Alias Cubic ##
2826#Alias Cubics ##
2827#Alias Cubic_Bezier ##
2828#Alias Cubic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002829#Line # curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002830
Cary Clark682c58d2018-05-16 07:07:07 -04002831Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002832Cubic begins at a start Point, curving towards the first control Point;
2833and curves from the end Point towards the second control Point.
2834
2835#Example
2836#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002837void draw(SkCanvas* canvas) {
2838 SkPaint paint;
2839 paint.setAntiAlias(true);
2840 paint.setStyle(SkPaint::kStroke_Style);
2841 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2842 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2843 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2844 paint.setColor(0x7fffffff & colors[i]);
2845 paint.setStrokeWidth(1);
2846 for (unsigned j = 0; j < 3; ++j) {
2847 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2848 }
2849 SkPath path;
2850 path.moveTo(cubicPts[0]);
2851 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2852 paint.setStrokeWidth(3);
2853 paint.setColor(colors[i]);
2854 canvas->drawPath(path, paint);
2855 cubicPts[1].fY += 30;
2856 cubicPts[2].fX += 30;
2857 }
Cary Clark8032b982017-07-28 11:04:54 -04002858}
2859##
Cary Clark73fa9722017-08-29 17:36:51 -04002860
Cary Clark0251b1b2018-08-15 15:14:55 -04002861#Method SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002862 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002863#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002864#In Cubic
2865#Line # appends Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002866
2867Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2868(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2869(0, 0) before adding Cubic.
2870
2871Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2872then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
2873to Point_Array.
2874
2875#Param x1 first control Point of Cubic in x ##
2876#Param y1 first control Point of Cubic in y ##
2877#Param x2 second control Point of Cubic in x ##
2878#Param y2 second control Point of Cubic in y ##
2879#Param x3 end Point of Cubic in x ##
2880#Param y3 end Point of Cubic in y ##
2881
Cary Clark0251b1b2018-08-15 15:14:55 -04002882#Return reference to Path ##
2883
Cary Clark73fa9722017-08-29 17:36:51 -04002884#Example
2885void draw(SkCanvas* canvas) {
2886 SkPaint paint;
2887 paint.setAntiAlias(true);
2888 paint.setStyle(SkPaint::kStroke_Style);
2889 SkPath path;
2890 path.moveTo(0, -10);
2891 for (int i = 0; i < 128; i += 16) {
2892 SkScalar c = i * 0.5f;
2893 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2894 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2895 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2896 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2897 }
2898 path.offset(128, 128);
2899 canvas->drawPath(path, paint);
2900}
2901##
2902
2903#SeeAlso Contour moveTo rCubicTo quadTo
2904
2905##
2906
2907# ------------------------------------------------------------------------------
2908
Cary Clark0251b1b2018-08-15 15:14:55 -04002909#Method SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
Cary Clark73fa9722017-08-29 17:36:51 -04002910
Cary Clark4855f782018-02-06 09:41:53 -05002911#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002912#In Cubic
Cary Clark73fa9722017-08-29 17:36:51 -04002913Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2914Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2915(0, 0) before adding Cubic.
2916
2917Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2918then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2919to Point_Array.
2920
2921#Param p1 first control Point of Cubic ##
2922#Param p2 second control Point of Cubic ##
2923#Param p3 end Point of Cubic ##
2924
Cary Clark0251b1b2018-08-15 15:14:55 -04002925#Return reference to Path ##
2926
Cary Clark73fa9722017-08-29 17:36:51 -04002927#Example
2928#Height 84
2929 SkPaint paint;
2930 paint.setAntiAlias(true);
2931 paint.setStyle(SkPaint::kStroke_Style);
2932 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2933 SkPath path;
2934 path.moveTo(pts[0]);
2935 path.cubicTo(pts[1], pts[2], pts[3]);
2936 canvas->drawPath(path, paint);
2937##
2938
2939#SeeAlso Contour moveTo rCubicTo quadTo
2940
2941##
2942
2943# ------------------------------------------------------------------------------
2944
Cary Clark0251b1b2018-08-15 15:14:55 -04002945#Method SkPath& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002946 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002947#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002948#In Cubic
2949#Line # appends Cubic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002950
2951 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2952 Vector (dx2, dy2), to Vector (dx3, dy3).
2953 If Path is empty, or last Verb
2954 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2955
2956 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2957 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2958 control and Cubic end to Point_Array.
2959 Cubic control is Last_Point plus Vector (dx1, dy1).
2960 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002961 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002962
Cary Clark5538c132018-06-14 12:28:14 -04002963 #Param x1 offset from Last_Point to first Cubic control on x-axis ##
2964 #Param y1 offset from Last_Point to first Cubic control on y-axis ##
2965 #Param x2 offset from Last_Point to second Cubic control on x-axis ##
2966 #Param y2 offset from Last_Point to second Cubic control on y-axis ##
2967 #Param x3 offset from Last_Point to Cubic end on x-axis ##
2968 #Param y3 offset from Last_Point to Cubic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002969
Cary Clark0251b1b2018-08-15 15:14:55 -04002970 #Return reference to Path ##
2971
Cary Clark73fa9722017-08-29 17:36:51 -04002972#Example
2973 void draw(SkCanvas* canvas) {
2974 SkPaint paint;
2975 paint.setAntiAlias(true);
2976 paint.setStyle(SkPaint::kStroke_Style);
2977 SkPath path;
2978 path.moveTo(24, 108);
2979 for (int i = 0; i < 16; i++) {
2980 SkScalar sx, sy;
2981 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2982 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2983 }
2984 canvas->drawPath(path, paint);
2985 }
2986##
2987
2988#SeeAlso Contour moveTo cubicTo quadTo
2989
2990##
2991
Cary Clark78de7512018-02-07 07:27:09 -05002992#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002993
2994# ------------------------------------------------------------------------------
2995
Cary Clark08895c42018-02-01 09:37:32 -05002996#Subtopic Arc
2997#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04002998Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
2999by start point and end point, and by radius and tangent lines. Each construction has advantages,
3000and some constructions correspond to Arc drawing in graphics standards.
3001
3002All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
3003Conic describes an Arc of some Oval or Circle.
3004
3005arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
3006describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
Cary Clark682c58d2018-05-16 07:07:07 -04003007which may continue Contour or start a new one. This construction is similar to PostScript and
Cary Clark73fa9722017-08-29 17:36:51 -04003008HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
3009requiring Path.
3010
3011arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
3012describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
3013where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
3014HTML_Canvas arcs.
3015
3016arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04003017 SkScalar x, SkScalar y)
Cary Clark73fa9722017-08-29 17:36:51 -04003018describes Arc as part of Oval with radii (rx, ry), beginning at
3019last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
3020so additional values choose a single solution. This construction is similar to SVG arcs.
3021
3022conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
3023conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
Cary Clark682c58d2018-05-16 07:07:07 -04003024constructions are converted to Conic data when added to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04003025
3026#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
3027 do the kind of table shown in the illustration.
3028 example is spaced correctly on fiddle but spacing is too wide on pc
3029##
3030
3031#Example
3032#Height 300
3033#Width 600
3034#Description
3035#List
3036# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
3037# <sup>2</sup> parameter sets force MoveTo ##
Cary Clark5081eed2018-01-22 07:55:48 -05003038# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04003039# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
3040# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3041 Direction sweep, SkScalar x, SkScalar y) ##
3042#List ##
3043#Description ##
3044#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003045###$
Cary Clark73fa9722017-08-29 17:36:51 -04003046struct data {
3047 const char* name;
3048 char super;
3049 int yn[10];
3050};
3051
3052const data dataSet[] = {
3053{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
3054{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
3055{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
3056{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
3057{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
3058{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
3059};
3060
3061#define __degree_symbol__ "\xC2" "\xB0"
3062
3063const char* headers[] = {
3064 "Oval part",
3065 "force moveTo",
3066 "can draw 180" __degree_symbol__,
3067 "can draw 360" __degree_symbol__,
3068 "can draw greater than 360" __degree_symbol__,
3069 "ignored if radius is zero",
3070 "ignored if sweep is zero",
3071 "requires Path",
3072 "describes rotation",
3073 "describes perspective",
3074};
3075
3076const char* yna[] = {
3077 "n/a",
3078 "no",
3079 "yes"
3080};
Cary Clark1a8d7622018-03-05 13:26:16 -05003081$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003082##
3083void draw(SkCanvas* canvas) {
3084 SkPaint lp;
3085 lp.setAntiAlias(true);
3086 SkPaint tp(lp);
3087 SkPaint sp(tp);
3088 SkPaint bp(tp);
3089 bp.setFakeBoldText(true);
3090 sp.setTextSize(10);
3091 lp.setColor(SK_ColorGRAY);
3092 canvas->translate(0, 32);
3093 const int tl = 115;
3094 for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
3095 canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
3096 if (0 == col) {
3097 continue;
3098 }
3099 canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
3100 SkPath path;
3101 path.moveTo(tl - 3 + col * 35, 103);
3102 path.lineTo(tl + 124 + col * 35, -24);
3103 canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
3104 }
3105 for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
3106 if (0 == row) {
3107 canvas->drawLine(tl, 100, tl + 350, 100, lp);
3108 } else {
3109 canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
3110 }
3111 if (row == SK_ARRAY_COUNT(dataSet)) {
3112 break;
3113 }
3114 canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
3115 if (dataSet[row].super) {
3116 SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
3117 canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
3118 }
3119 for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
3120 int val = dataSet[row].yn[col];
3121 canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
3122 if (val > 1) {
3123 char supe = '0' + val - 1;
3124 canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
3125 }
3126 }
3127 }
3128}
3129#Example ##
3130
3131#Example
3132#Height 128
3133#Description
3134#ToDo make this a list or table ##
31351 describes an arc from an oval, a starting angle, and a sweep angle.
31362 is similar to 1, but does not require building a path to draw.
31373 is similar to 1, but always begins new Contour.
31384 describes an arc from a pair of tangent lines and a radius.
31395 describes an arc from Oval center, arc start Point and arc end Point.
31406 describes an arc from a pair of tangent lines and a Conic_Weight.
3141##
3142void draw(SkCanvas* canvas) {
3143 SkRect oval = {8, 8, 56, 56};
3144 SkPaint ovalPaint;
3145 ovalPaint.setAntiAlias(true);
3146 SkPaint textPaint(ovalPaint);
3147 ovalPaint.setStyle(SkPaint::kStroke_Style);
3148 SkPaint arcPaint(ovalPaint);
3149 arcPaint.setStrokeWidth(5);
3150 arcPaint.setColor(SK_ColorBLUE);
3151 canvas->translate(-64, 0);
3152 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3153 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3154 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3155 canvas->drawOval(oval, ovalPaint);
3156 SkPath path;
3157 path.moveTo({56, 32});
3158 switch (arcStyle) {
3159 case '1':
3160 path.arcTo(oval, 0, 90, false);
3161 break;
3162 case '2':
3163 canvas->drawArc(oval, 0, 90, false, arcPaint);
3164 continue;
3165 case '3':
3166 path.addArc(oval, 0, 90);
3167 break;
3168 case '4':
3169 path.arcTo({56, 56}, {32, 56}, 24);
3170 break;
3171 case '5':
3172 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3173 break;
3174 case '6':
3175 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3176 break;
3177 }
3178 canvas->drawPath(path, arcPaint);
3179 }
3180}
3181#Example ##
3182
3183
Cary Clark0251b1b2018-08-15 15:14:55 -04003184#Method SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05003185#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003186#In Arc
3187#Line # appends Arc ##
Cary Clark80247e52018-07-11 16:18:41 -04003188Appends Arc to Path. Arc added is part of ellipse
Cary Clark73fa9722017-08-29 17:36:51 -04003189bounded by oval, from startAngle through sweepAngle. Both startAngle and
3190sweepAngle are measured in degrees, where zero degrees is aligned with the
3191positive x-axis, and positive sweeps extends Arc clockwise.
3192
3193arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3194is false and Path is not empty. Otherwise, added Contour begins with first point
3195of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3196
3197#Param oval bounds of ellipse containing Arc ##
3198#Param startAngle starting angle of Arc in degrees ##
3199#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3200#Param forceMoveTo true to start a new contour with Arc ##
3201
Cary Clark0251b1b2018-08-15 15:14:55 -04003202#Return reference to Path ##
3203
Cary Clark73fa9722017-08-29 17:36:51 -04003204#Example
3205#Height 200
3206#Description
3207arcTo continues a previous contour when forceMoveTo is false and when Path
3208is not empty.
3209##
3210void draw(SkCanvas* canvas) {
3211 SkPaint paint;
3212 SkPath path;
3213 paint.setStyle(SkPaint::kStroke_Style);
3214 paint.setStrokeWidth(4);
3215 path.moveTo(0, 0);
3216 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3217 canvas->drawPath(path, paint);
3218 path.rewind();
3219 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3220 canvas->drawPath(path, paint);
3221 path.rewind();
3222 path.moveTo(0, 0);
3223 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3224 canvas->drawPath(path, paint);
3225}
3226##
3227
3228#SeeAlso addArc SkCanvas::drawArc conicTo
3229
3230##
3231
3232# ------------------------------------------------------------------------------
3233
Cary Clark0251b1b2018-08-15 15:14:55 -04003234#Method SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003235#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003236#In Arc
Cary Clark80247e52018-07-11 16:18:41 -04003237Appends Arc to Path, after appending Line if needed. Arc is implemented by Conic
Cary Clark73fa9722017-08-29 17:36:51 -04003238weighted to describe part of Circle. Arc is contained by tangent from
3239last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003240is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003241
3242#ToDo allow example to hide source and not be exposed as fiddle ##
3243
3244#Example
3245#Height 226
3246void draw(SkCanvas* canvas) {
3247 SkPaint tangentPaint;
3248 tangentPaint.setAntiAlias(true);
3249 SkPaint textPaint(tangentPaint);
3250 tangentPaint.setStyle(SkPaint::kStroke_Style);
3251 tangentPaint.setColor(SK_ColorGRAY);
3252 SkPaint arcPaint(tangentPaint);
3253 arcPaint.setStrokeWidth(5);
3254 arcPaint.setColor(SK_ColorBLUE);
3255 SkPath path;
3256 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3257 SkScalar radius = 50;
3258 path.moveTo(pts[0]);
3259 path.arcTo(pts[1], pts[2], radius);
3260 canvas->drawLine(pts[0], pts[1], tangentPaint);
3261 canvas->drawLine(pts[1], pts[2], tangentPaint);
3262 SkPoint lastPt;
3263 (void) path.getLastPt(&lastPt);
3264 SkVector radial = pts[2] - pts[1];
3265 radial.setLength(radius);
3266 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3267 canvas->drawCircle(center, radius, tangentPaint);
3268 canvas->drawLine(lastPt, center, tangentPaint);
3269 radial = pts[1] - pts[0];
3270 radial.setLength(radius);
3271 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3272 canvas->drawLine(center, arcStart, tangentPaint);
3273 canvas->drawPath(path, arcPaint);
3274 textPaint.setTextAlign(SkPaint::kRight_Align);
3275 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3276 textPaint.setTextAlign(SkPaint::kLeft_Align);
3277 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3278 textPaint.setTextAlign(SkPaint::kCenter_Align);
3279 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3280 textPaint.setTextAlign(SkPaint::kRight_Align);
3281 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3282 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3283}
3284##
3285
3286If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3287The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3288
3289#Example
3290#Height 128
3291void draw(SkCanvas* canvas) {
3292 SkPaint tangentPaint;
3293 tangentPaint.setAntiAlias(true);
3294 SkPaint textPaint(tangentPaint);
3295 tangentPaint.setStyle(SkPaint::kStroke_Style);
3296 tangentPaint.setColor(SK_ColorGRAY);
3297 SkPaint arcPaint(tangentPaint);
3298 arcPaint.setStrokeWidth(5);
3299 arcPaint.setColor(SK_ColorBLUE);
3300 SkPath path;
3301 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3302 SkScalar radius = 50;
3303 path.moveTo(pts[0]);
3304 path.arcTo(pts[1], pts[2], radius);
3305 canvas->drawLine(pts[0], pts[1], tangentPaint);
3306 canvas->drawLine(pts[1], pts[2], tangentPaint);
3307 SkPoint lastPt;
3308 (void) path.getLastPt(&lastPt);
3309 SkVector radial = pts[2] - pts[1];
3310 radial.setLength(radius);
3311 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3312 canvas->drawLine(lastPt, center, tangentPaint);
3313 radial = pts[1] - pts[0];
3314 radial.setLength(radius);
3315 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3316 canvas->drawLine(center, arcStart, tangentPaint);
3317 canvas->drawPath(path, arcPaint);
3318 textPaint.setTextAlign(SkPaint::kCenter_Align);
3319 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3320 textPaint.setTextAlign(SkPaint::kLeft_Align);
3321 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3322 textPaint.setTextAlign(SkPaint::kCenter_Align);
3323 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3324 textPaint.setTextAlign(SkPaint::kRight_Align);
3325 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3326 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3327}
3328##
3329
3330Arc sweep is always less than 180 degrees. If radius is zero, or if
3331tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3332
3333arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003334arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003335
Cary Clark5538c132018-06-14 12:28:14 -04003336#Param x1 x-axis value common to pair of tangents ##
3337#Param y1 y-axis value common to pair of tangents ##
3338#Param x2 x-axis value end of second tangent ##
3339#Param y2 y-axis value end of second tangent ##
Cary Clark73fa9722017-08-29 17:36:51 -04003340#Param radius distance from Arc to Circle center ##
3341
Cary Clark0251b1b2018-08-15 15:14:55 -04003342#Return reference to Path ##
3343
Cary Clark73fa9722017-08-29 17:36:51 -04003344#Example
3345#Description
3346arcTo is represented by Line and circular Conic in Path.
3347##
3348void draw(SkCanvas* canvas) {
3349 SkPath path;
3350 path.moveTo({156, 20});
3351 path.arcTo(200, 20, 170, 50, 50);
3352 SkPath::Iter iter(path, false);
3353 SkPoint p[4];
3354 SkPath::Verb verb;
3355 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3356 switch (verb) {
3357 case SkPath::kMove_Verb:
3358 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3359 break;
3360 case SkPath::kLine_Verb:
3361 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3362 break;
3363 case SkPath::kConic_Verb:
3364 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3365 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3366 break;
3367 default:
3368 SkDebugf("unexpected verb\n");
3369 }
3370 }
3371}
3372#StdOut
3373move to (156,20)
3374line (156,20),(79.2893,20)
3375conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3376##
3377##
3378
Cary Clark682c58d2018-05-16 07:07:07 -04003379#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003380
3381##
3382
3383# ------------------------------------------------------------------------------
3384
Cary Clark0251b1b2018-08-15 15:14:55 -04003385#Method SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003386#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003387#In Arc
Cary Clark80247e52018-07-11 16:18:41 -04003388Appends Arc to Path, after appending Line if needed. Arc is implemented by Conic
Cary Clark73fa9722017-08-29 17:36:51 -04003389weighted to describe part of Circle. Arc is contained by tangent from
3390last Path point to p1, and tangent from p1 to p2. Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003391is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003392
3393If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3394The length of Vector from p1 to p2 does not affect Arc.
3395
3396Arc sweep is always less than 180 degrees. If radius is zero, or if
3397tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3398
3399arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003400arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003401
3402#Param p1 Point common to pair of tangents ##
3403#Param p2 end of second tangent ##
3404#Param radius distance from Arc to Circle center ##
3405
Cary Clark0251b1b2018-08-15 15:14:55 -04003406#Return reference to Path ##
3407
Cary Clark73fa9722017-08-29 17:36:51 -04003408#Example
3409#Description
3410Because tangent lines are parallel, arcTo appends line from last Path Point to
3411p1, but does not append a circular Conic.
3412##
3413void draw(SkCanvas* canvas) {
3414 SkPath path;
3415 path.moveTo({156, 20});
3416 path.arcTo({200, 20}, {170, 20}, 50);
3417 SkPath::Iter iter(path, false);
3418 SkPoint p[4];
3419 SkPath::Verb verb;
3420 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3421 switch (verb) {
3422 case SkPath::kMove_Verb:
3423 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3424 break;
3425 case SkPath::kLine_Verb:
3426 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3427 break;
3428 case SkPath::kConic_Verb:
3429 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3430 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3431 break;
3432 default:
3433 SkDebugf("unexpected verb\n");
3434 }
3435 }
3436}
3437#StdOut
3438move to (156,20)
3439line (156,20),(200,20)
3440##
3441##
3442
Cary Clark682c58d2018-05-16 07:07:07 -04003443#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003444
3445##
3446
3447# ------------------------------------------------------------------------------
3448
3449#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05003450#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04003451
3452#Code
3453 enum ArcSize {
Cary Clark682c58d2018-05-16 07:07:07 -04003454 kSmall_ArcSize,
3455 kLarge_ArcSize,
Cary Clark73fa9722017-08-29 17:36:51 -04003456 };
3457##
3458
3459Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3460ArcSize and Direction select one of the four Oval parts.
3461
3462#Const kSmall_ArcSize 0
Cary Clark682c58d2018-05-16 07:07:07 -04003463#Line # smaller of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003464##
3465#Const kLarge_ArcSize 1
Cary Clark682c58d2018-05-16 07:07:07 -04003466#Line # larger of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003467##
3468
3469#Example
3470#Height 160
3471#Description
3472Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3473Two routes are large, and two routes are counterclockwise. The one route both large
3474and counterclockwise is blue.
3475##
3476void draw(SkCanvas* canvas) {
3477 SkPaint paint;
3478 paint.setAntiAlias(true);
3479 paint.setStyle(SkPaint::kStroke_Style);
3480 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3481 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3482 SkPath path;
3483 path.moveTo({120, 50});
3484 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3485 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3486 paint.setColor(SK_ColorBLUE);
3487 paint.setStrokeWidth(3);
3488 }
3489 canvas->drawPath(path, paint);
3490 }
3491 }
3492}
3493##
3494
3495#SeeAlso arcTo Direction
3496
3497##
3498
3499# ------------------------------------------------------------------------------
3500
Cary Clark0251b1b2018-08-15 15:14:55 -04003501#Method SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04003502 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003503#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003504#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003505
Cary Clark80247e52018-07-11 16:18:41 -04003506Appends Arc to Path. Arc is implemented by one or more Conics weighted to
Cary Clark154beea2017-10-26 07:58:48 -04003507describe part of Oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
3508curves from last Path Point to (x, y), choosing one of four possible routes:
3509clockwise or counterclockwise, and smaller or larger.
Cary Clark73fa9722017-08-29 17:36:51 -04003510
Cary Clark154beea2017-10-26 07:58:48 -04003511Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if
3512either radii are zero, or if last Path Point equals (x, y). arcTo scales radii
3513(rx, ry) to fit last Path Point and (x, y) if both are greater than zero but
3514too small.
Cary Clark73fa9722017-08-29 17:36:51 -04003515
3516arcTo appends up to four Conic curves.
Cary Clark154beea2017-10-26 07:58:48 -04003517arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value
3518is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise,
3519while kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003520
3521#Param rx radius in x before x-axis rotation ##
3522#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003523#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003524#Param largeArc chooses smaller or larger Arc ##
3525#Param sweep chooses clockwise or counterclockwise Arc ##
3526#Param x end of Arc ##
3527#Param y end of Arc ##
3528
Cary Clark0251b1b2018-08-15 15:14:55 -04003529#Return reference to Path ##
3530
Cary Clark73fa9722017-08-29 17:36:51 -04003531#Example
3532#Height 160
3533void draw(SkCanvas* canvas) {
3534 SkPaint paint;
3535 paint.setAntiAlias(true);
3536 paint.setStyle(SkPaint::kStroke_Style);
3537 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3538 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3539 SkPath path;
3540 path.moveTo({120, 50});
3541 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3542 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3543 paint.setColor(SK_ColorBLUE);
3544 paint.setStrokeWidth(3);
3545 }
3546 canvas->drawPath(path, paint);
3547 }
3548 }
3549}
3550##
3551
3552#SeeAlso rArcTo ArcSize Direction
3553
3554##
3555
3556# ------------------------------------------------------------------------------
3557
Cary Clark0251b1b2018-08-15 15:14:55 -04003558#Method SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04003559 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05003560#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003561#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003562
Cary Clark80247e52018-07-11 16:18:41 -04003563Appends Arc to Path. Arc is implemented by one or more Conic weighted to describe part of Oval
Cary Clark73fa9722017-08-29 17:36:51 -04003564with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last Path Point to
3565(xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise,
3566and smaller or larger.
3567
3568Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either radii are zero,
3569or if last Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
Cary Clarkce101242017-09-01 15:51:02 -04003570xy if both are greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003571
3572arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003573arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3574opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3575kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003576
Cary Clark5538c132018-06-14 12:28:14 -04003577#Param r radii on axes before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003578#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003579#Param largeArc chooses smaller or larger Arc ##
3580#Param sweep chooses clockwise or counterclockwise Arc ##
3581#Param xy end of Arc ##
3582
Cary Clark0251b1b2018-08-15 15:14:55 -04003583#Return reference to Path ##
3584
Cary Clark73fa9722017-08-29 17:36:51 -04003585#Example
3586#Height 108
3587void draw(SkCanvas* canvas) {
3588 SkPaint paint;
3589 SkPath path;
3590 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3591 for (auto start : starts) {
3592 path.moveTo(start.fX, start.fY);
3593 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3594 }
3595 canvas->drawPath(path, paint);
3596}
3597##
3598
3599#SeeAlso rArcTo ArcSize Direction
3600
3601##
3602
3603# ------------------------------------------------------------------------------
3604
Cary Clark0251b1b2018-08-15 15:14:55 -04003605#Method SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04003606 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003607#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003608#In Arc
3609#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003610
Cary Clark80247e52018-07-11 16:18:41 -04003611Appends Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003612more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04003613xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
3614
Cary Clark73fa9722017-08-29 17:36:51 -04003615#Formula
3616(x0 + dx, y0 + dy)
3617##
3618, choosing one of four possible routes: clockwise or
3619counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3620is (0, 0).
3621
Cary Clarkce101242017-09-01 15:51:02 -04003622Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3623if either radii are zero, or if last Path Point equals end Point.
3624arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3625greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003626
3627arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003628arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3629opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003630kCW_Direction cast to int is zero.
3631
Cary Clark5538c132018-06-14 12:28:14 -04003632#Param rx radius before x-axis rotation ##
3633#Param ry radius before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003634#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003635#Param largeArc chooses smaller or larger Arc ##
3636#Param sweep chooses clockwise or counterclockwise Arc ##
Cary Clark5538c132018-06-14 12:28:14 -04003637#Param dx x-axis offset end of Arc from last Path Point ##
3638#Param dy y-axis offset end of Arc from last Path Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003639
Cary Clark0251b1b2018-08-15 15:14:55 -04003640#Return reference to Path ##
3641
Cary Clark73fa9722017-08-29 17:36:51 -04003642#Example
3643#Height 108
3644void draw(SkCanvas* canvas) {
3645 SkPaint paint;
3646 SkPath path;
3647 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3648 for (auto start : starts) {
3649 path.moveTo(start.fX, start.fY);
3650 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3651 }
3652 canvas->drawPath(path, paint);
3653}
3654##
3655
3656#SeeAlso arcTo ArcSize Direction
3657
3658##
3659
Cary Clark78de7512018-02-07 07:27:09 -05003660#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003661
3662# ------------------------------------------------------------------------------
3663
Cary Clark0251b1b2018-08-15 15:14:55 -04003664#Method SkPath& close()
Cary Clark4855f782018-02-06 09:41:53 -05003665#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003666#Line # makes last Contour a loop ##
Cary Clark80247e52018-07-11 16:18:41 -04003667Appends kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003668with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003669with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
Cary Clark682c58d2018-05-16 07:07:07 -04003670Paint_Stroke_Cap at Contour start and end; closed Contour draws
Cary Clark73fa9722017-08-29 17:36:51 -04003671Paint_Stroke_Join at Contour start and end.
3672
3673close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3674
Cary Clark0251b1b2018-08-15 15:14:55 -04003675#Return reference to Path ##
3676
Cary Clark73fa9722017-08-29 17:36:51 -04003677#Example
3678void draw(SkCanvas* canvas) {
3679 SkPaint paint;
3680 paint.setStrokeWidth(15);
3681 paint.setStrokeCap(SkPaint::kRound_Cap);
3682 SkPath path;
3683 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3684 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3685 for (int loop = 0; loop < 2; ++loop) {
3686 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3687 SkPaint::kStrokeAndFill_Style} ) {
3688 paint.setStyle(style);
3689 canvas->drawPath(path, paint);
3690 canvas->translate(85, 0);
3691 }
3692 path.close();
3693 canvas->translate(-255, 128);
3694 }
3695}
3696##
3697
Cary Clark682c58d2018-05-16 07:07:07 -04003698#SeeAlso
Cary Clark73fa9722017-08-29 17:36:51 -04003699
3700##
3701
3702# ------------------------------------------------------------------------------
3703
Cary Clark682c58d2018-05-16 07:07:07 -04003704#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003705#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003706#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003707Returns true if fill is inverted and Path with fill represents area outside
3708of its geometric bounds.
3709
3710#Table
3711#Legend
3712# FillType # is inverse ##
3713##
3714# kWinding_FillType # false ##
3715# kEvenOdd_FillType # false ##
3716# kInverseWinding_FillType # true ##
3717# kInverseEvenOdd_FillType # true ##
3718##
3719
3720#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3721 kInverseWinding_FillType, kInverseEvenOdd_FillType
3722##
3723
3724#Return true if Path fills outside its bounds ##
3725
3726#Example
3727#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003728###$
Cary Clark73fa9722017-08-29 17:36:51 -04003729#define nameValue(fill) { SkPath::fill, #fill }
3730
Cary Clark1a8d7622018-03-05 13:26:16 -05003731$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003732##
3733void draw(SkCanvas* canvas) {
3734 struct {
3735 SkPath::FillType fill;
3736 const char* name;
3737 } fills[] = {
3738 nameValue(kWinding_FillType),
3739 nameValue(kEvenOdd_FillType),
3740 nameValue(kInverseWinding_FillType),
3741 nameValue(kInverseEvenOdd_FillType),
3742 };
3743 for (auto fill: fills ) {
3744 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3745 "true" : "false");
3746 }
3747}
3748#StdOut
3749IsInverseFillType(kWinding_FillType) == false
3750IsInverseFillType(kEvenOdd_FillType) == false
3751IsInverseFillType(kInverseWinding_FillType) == true
3752IsInverseFillType(kInverseEvenOdd_FillType) == true
3753##
3754##
3755
3756#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3757
3758##
3759
3760# ------------------------------------------------------------------------------
3761
Cary Clark682c58d2018-05-16 07:07:07 -04003762#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003763#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003764#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003765Returns equivalent Fill_Type representing Path fill inside its bounds.
3766.
3767
3768#Table
3769#Legend
3770# FillType # inside FillType ##
3771##
3772# kWinding_FillType # kWinding_FillType ##
3773# kEvenOdd_FillType # kEvenOdd_FillType ##
3774# kInverseWinding_FillType # kWinding_FillType ##
3775# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3776##
3777
3778#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3779 kInverseWinding_FillType, kInverseEvenOdd_FillType
3780##
3781
3782#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3783
3784#Example
3785#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003786###$
Cary Clark73fa9722017-08-29 17:36:51 -04003787#define nameValue(fill) { SkPath::fill, #fill }
3788
Cary Clark1a8d7622018-03-05 13:26:16 -05003789$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003790##
3791void draw(SkCanvas* canvas) {
3792 struct {
3793 SkPath::FillType fill;
3794 const char* name;
3795 } fills[] = {
3796 nameValue(kWinding_FillType),
3797 nameValue(kEvenOdd_FillType),
3798 nameValue(kInverseWinding_FillType),
3799 nameValue(kInverseEvenOdd_FillType),
3800 };
3801 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3802 if (fills[i].fill != (SkPath::FillType) i) {
3803 SkDebugf("fills array order does not match FillType enum order");
3804 break;
Cary Clark682c58d2018-05-16 07:07:07 -04003805 }
Cary Clark73fa9722017-08-29 17:36:51 -04003806 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3807 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3808 }
3809}
3810#StdOut
3811ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3812ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3813ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3814ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3815##
3816##
3817
3818#SeeAlso FillType getFillType setFillType IsInverseFillType
3819
3820##
3821
3822# ------------------------------------------------------------------------------
3823
3824#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3825 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05003826#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003827#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04003828
3829Approximates Conic with Quad array. Conic is constructed from start Point p0,
Cary Clark682c58d2018-05-16 07:07:07 -04003830control Point p1, end Point p2, and weight w.
Cary Clark73fa9722017-08-29 17:36:51 -04003831Quad array is stored in pts; this storage is supplied by caller.
3832Maximum Quad count is 2 to the pow2.
Cary Clark682c58d2018-05-16 07:07:07 -04003833Every third point in array shares last Point of previous Quad and first Point of
3834next Quad. Maximum pts storage size is given by:
Cary Clark73fa9722017-08-29 17:36:51 -04003835#Formula
3836(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
3837##
Cary Clark154beea2017-10-26 07:58:48 -04003838.
Cary Clark6fc50412017-09-21 12:31:06 -04003839
Cary Clark154beea2017-10-26 07:58:48 -04003840Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04003841than the number requested.
Cary Clark682c58d2018-05-16 07:07:07 -04003842
Cary Clark73fa9722017-08-29 17:36:51 -04003843Conic_Weight determines the amount of influence Conic control point has on the curve.
3844w less than one represents an elliptical section. w greater than one represents
3845a hyperbolic section. w equal to one represents a parabolic section.
3846
3847Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3848of up to 90 degrees; in this case, set pow2 to one.
3849
3850#Param p0 Conic start Point ##
3851#Param p1 Conic control Point ##
3852#Param p2 Conic end Point ##
3853#Param w Conic weight ##
3854#Param pts storage for Quad array ##
3855#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3856
Cary Clarka523d2d2017-08-30 08:58:10 -04003857#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003858
3859#Example
3860#Description
3861A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3862The middle curve is nearly circular. The top-right curve is parabolic, which can
3863be drawn exactly with a single Quad.
3864##
3865void draw(SkCanvas* canvas) {
3866 SkPaint conicPaint;
3867 conicPaint.setAntiAlias(true);
3868 conicPaint.setStyle(SkPaint::kStroke_Style);
3869 SkPaint quadPaint(conicPaint);
3870 quadPaint.setColor(SK_ColorRED);
3871 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3872 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3873 SkPoint quads[5];
3874 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3875 SkPath path;
3876 path.moveTo(conic[0]);
3877 path.conicTo(conic[1], conic[2], weight);
3878 canvas->drawPath(path, conicPaint);
3879 path.rewind();
3880 path.moveTo(quads[0]);
3881 path.quadTo(quads[1], quads[2]);
3882 path.quadTo(quads[3], quads[4]);
3883 canvas->drawPath(path, quadPaint);
3884 canvas->translate(50, -50);
3885 }
3886}
3887##
3888
3889#SeeAlso Conic Quad
3890
3891##
3892
3893# ------------------------------------------------------------------------------
3894
3895#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003896#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003897#Line # returns if describes Rect ##
Cary Clarkce101242017-09-01 15:51:02 -04003898Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003899If false: rect, isClosed, and direction are unchanged.
3900If true: rect, isClosed, and direction are written to if not nullptr.
3901
3902rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3903that do not alter the area drawn by the returned rect.
3904
3905#Param rect storage for bounds of Rect; may be nullptr ##
3906#Param isClosed storage set to true if Path is closed; may be nullptr ##
3907#Param direction storage set to Rect direction; may be nullptr ##
3908
3909#Return true if Path contains Rect ##
3910
3911#Example
3912#Description
3913After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3914following lineTo does not. addPoly returns true even though rect is not closed, and one
3915side of rect is made up of consecutive line segments.
3916##
3917void draw(SkCanvas* canvas) {
3918 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3919 SkRect rect;
3920 SkPath::Direction direction;
3921 bool isClosed;
Cary Clark682c58d2018-05-16 07:07:07 -04003922 path.isRect(&rect, &isClosed, &direction) ?
Cary Clark73fa9722017-08-29 17:36:51 -04003923 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3924 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3925 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3926 SkDebugf("%s is not rect\n", prefix);
3927 };
3928 SkPath path;
3929 debugster("empty", path);
3930 path.addRect({10, 20, 30, 40});
3931 debugster("addRect", path);
3932 path.moveTo(60, 70);
3933 debugster("moveTo", path);
3934 path.lineTo(60, 70);
3935 debugster("lineTo", path);
3936 path.reset();
3937 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3938 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3939 debugster("addPoly", path);
3940}
3941#StdOut
3942empty is not rect
3943addRect is rect (10, 20, 30, 40); is closed; direction CW
3944moveTo is rect (10, 20, 30, 40); is closed; direction CW
3945lineTo is not rect
3946addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3947##
3948##
3949
3950#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3951
3952##
3953
3954# ------------------------------------------------------------------------------
3955
3956#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003957#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003958#Line # returns if describes Rect pair, one inside the other ##
Cary Clark73fa9722017-08-29 17:36:51 -04003959Returns true if Path is equivalent to nested Rect pair when filled.
3960If false, rect and dirs are unchanged.
3961If true, rect and dirs are written to if not nullptr:
3962setting rect[0] to outer Rect, and rect[1] to inner Rect;
3963setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3964Rect.
3965
3966#Param rect storage for Rect pair; may be nullptr ##
3967#Param dirs storage for Direction pair; may be nullptr ##
3968
3969#Return true if Path contains nested Rect pair ##
3970
3971#Example
3972void draw(SkCanvas* canvas) {
3973 SkPaint paint;
3974 paint.setStyle(SkPaint::kStroke_Style);
3975 paint.setStrokeWidth(5);
3976 SkPath path;
3977 path.addRect({10, 20, 30, 40});
3978 paint.getFillPath(path, &path);
3979 SkRect rects[2];
3980 SkPath::Direction directions[2];
3981 if (path.isNestedFillRects(rects, directions)) {
3982 for (int i = 0; i < 2; ++i) {
3983 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3984 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3985 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3986 }
3987 } else {
3988 SkDebugf("is not nested rectangles\n");
3989 }
3990}
3991#StdOut
3992outer (7.5, 17.5, 32.5, 42.5); direction CW
3993inner (12.5, 22.5, 27.5, 37.5); direction CCW
3994##
3995##
3996
3997#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3998
3999##
4000
4001# ------------------------------------------------------------------------------
4002
Cary Clark0251b1b2018-08-15 15:14:55 -04004003#Method SkPath& addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004004#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004005#Line # adds one Contour containing Rect ##
Cary Clark80247e52018-07-11 16:18:41 -04004006Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -04004007starting with top-left corner of Rect; followed by top-right, bottom-right,
4008and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4009bottom-right, and top-right if dir is kCCW_Direction.
4010
4011#Param rect Rect to add as a closed contour ##
4012#Param dir Direction to wind added contour ##
4013
Cary Clark0251b1b2018-08-15 15:14:55 -04004014#Return reference to Path ##
4015
Cary Clark73fa9722017-08-29 17:36:51 -04004016#Example
4017#Description
4018The left Rect dashes starting at the top-left corner, to the right.
4019The right Rect dashes starting at the top-left corner, towards the bottom.
4020##
4021#Height 128
4022void draw(SkCanvas* canvas) {
4023 SkPaint paint;
4024 paint.setStrokeWidth(15);
4025 paint.setStrokeCap(SkPaint::kSquare_Cap);
4026 float intervals[] = { 5, 21.75f };
4027 paint.setStyle(SkPaint::kStroke_Style);
4028 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4029 SkPath path;
4030 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
4031 canvas->drawPath(path, paint);
4032 path.rewind();
4033 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
4034 canvas->drawPath(path, paint);
4035}
4036##
4037
4038#SeeAlso SkCanvas::drawRect Direction
4039
4040##
4041
4042# ------------------------------------------------------------------------------
4043
Cary Clark0251b1b2018-08-15 15:14:55 -04004044#Method SkPath& addRect(const SkRect& rect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04004045
Cary Clark80247e52018-07-11 16:18:41 -04004046Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04004047If dir is kCW_Direction, Rect corners are added clockwise; if dir is
4048kCCW_Direction, Rect corners are added counterclockwise.
4049start determines the first corner added.
4050
4051#Table
4052#Legend
4053# start # first corner ##
4054#Legend ##
4055# 0 # top-left ##
4056# 1 # top-right ##
4057# 2 # bottom-right ##
4058# 3 # bottom-left ##
4059#Table ##
4060
4061#Param rect Rect to add as a closed contour ##
4062#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004063#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04004064
Cary Clark0251b1b2018-08-15 15:14:55 -04004065#Return reference to Path ##
4066
Cary Clark73fa9722017-08-29 17:36:51 -04004067#Example
4068#Height 128
4069#Description
4070The arrow is just after the initial corner and points towards the next
4071corner appended to Path.
4072##
4073void draw(SkCanvas* canvas) {
4074 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
4075 const SkRect rect = {10, 10, 54, 54};
4076 SkPaint rectPaint;
4077 rectPaint.setAntiAlias(true);
4078 rectPaint.setStyle(SkPaint::kStroke_Style);
4079 SkPaint arrowPaint(rectPaint);
4080 SkPath arrowPath;
4081 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4082 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4083 SkPath1DPathEffect::kRotate_Style));
4084 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4085 for (unsigned start : { 0, 1, 2, 3 } ) {
4086 SkPath path;
4087 path.addRect(rect, direction, start);
4088 canvas->drawPath(path, rectPaint);
4089 canvas->drawPath(path, arrowPaint);
4090 canvas->translate(64, 0);
4091 }
4092 canvas->translate(-256, 64);
4093 }
4094}
4095##
4096
4097#SeeAlso SkCanvas::drawRect Direction
4098
4099##
4100
4101# ------------------------------------------------------------------------------
4102
Cary Clark0251b1b2018-08-15 15:14:55 -04004103#Method SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
Cary Clark73fa9722017-08-29 17:36:51 -04004104 Direction dir = kCW_Direction)
4105
Cary Clark80247e52018-07-11 16:18:41 -04004106Adds Rect (left, top, right, bottom) to Path,
Cary Clark73fa9722017-08-29 17:36:51 -04004107appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4108starting with top-left corner of Rect; followed by top-right, bottom-right,
4109and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4110bottom-right, and top-right if dir is kCCW_Direction.
4111
Cary Clark5538c132018-06-14 12:28:14 -04004112#Param left smaller x-axis value of Rect ##
4113#Param top smaller y-axis value of Rect ##
4114#Param right larger x-axis value of Rect ##
4115#Param bottom larger y-axis value of Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004116#Param dir Direction to wind added contour ##
4117
Cary Clark0251b1b2018-08-15 15:14:55 -04004118#Return reference to Path ##
4119
Cary Clark73fa9722017-08-29 17:36:51 -04004120#Example
4121#Description
4122The left Rect dashes start at the top-left corner, and continue to the right.
4123The right Rect dashes start at the top-left corner, and continue down.
4124##
4125#Height 128
4126void draw(SkCanvas* canvas) {
4127 SkPaint paint;
4128 paint.setStrokeWidth(15);
4129 paint.setStrokeCap(SkPaint::kSquare_Cap);
4130 float intervals[] = { 5, 21.75f };
4131 paint.setStyle(SkPaint::kStroke_Style);
4132 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4133 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4134 SkPath path;
4135 path.addRect(20, 20, 100, 100, direction);
4136 canvas->drawPath(path, paint);
4137 canvas->translate(128, 0);
4138 }
4139}
4140##
4141
4142#SeeAlso SkCanvas::drawRect Direction
4143
4144##
4145
4146# ------------------------------------------------------------------------------
4147
Cary Clark0251b1b2018-08-15 15:14:55 -04004148#Method SkPath& addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004149#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004150#Line # adds one Contour containing Oval ##
Cary Clark80247e52018-07-11 16:18:41 -04004151Adds Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04004152Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4153and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4154clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4155
Cary Clark73fa9722017-08-29 17:36:51 -04004156#Param oval bounds of ellipse added ##
4157#Param dir Direction to wind ellipse ##
4158
Cary Clark0251b1b2018-08-15 15:14:55 -04004159#Return reference to Path ##
4160
Cary Clark73fa9722017-08-29 17:36:51 -04004161#Example
4162#Height 120
4163 SkPaint paint;
4164 SkPath oval;
4165 oval.addOval({20, 20, 160, 80});
4166 canvas->drawPath(oval, paint);
4167##
4168
4169#SeeAlso SkCanvas::drawOval Direction Oval
4170
4171##
4172
4173# ------------------------------------------------------------------------------
4174
Cary Clark0251b1b2018-08-15 15:14:55 -04004175#Method SkPath& addOval(const SkRect& oval, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04004176
Cary Clark80247e52018-07-11 16:18:41 -04004177Adds Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04004178Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4179and half oval height. Oval begins at start and continues
4180clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4181
4182#Table
4183#Legend
4184# start # Point ##
4185#Legend ##
4186# 0 # oval.centerX(), oval.fTop ##
4187# 1 # oval.fRight, oval.centerY() ##
4188# 2 # oval.centerX(), oval.fBottom ##
4189# 3 # oval.fLeft, oval.centerY() ##
4190#Table ##
4191
4192#Param oval bounds of ellipse added ##
4193#Param dir Direction to wind ellipse ##
4194#Param start index of initial point of ellipse ##
4195
Cary Clark0251b1b2018-08-15 15:14:55 -04004196#Return reference to Path ##
4197
Cary Clark73fa9722017-08-29 17:36:51 -04004198#Example
4199#Height 160
4200void draw(SkCanvas* canvas) {
4201 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4202 const SkRect rect = {10, 10, 54, 54};
4203 SkPaint ovalPaint;
4204 ovalPaint.setAntiAlias(true);
4205 SkPaint textPaint(ovalPaint);
4206 textPaint.setTextAlign(SkPaint::kCenter_Align);
4207 ovalPaint.setStyle(SkPaint::kStroke_Style);
4208 SkPaint arrowPaint(ovalPaint);
4209 SkPath arrowPath;
4210 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4211 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4212 SkPath1DPathEffect::kRotate_Style));
4213 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4214 for (unsigned start : { 0, 1, 2, 3 } ) {
4215 SkPath path;
4216 path.addOval(rect, direction, start);
4217 canvas->drawPath(path, ovalPaint);
4218 canvas->drawPath(path, arrowPaint);
4219 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4220 canvas->translate(64, 0);
4221 }
4222 canvas->translate(-256, 72);
4223 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4224 128, 0, textPaint);
4225 }
4226}
4227##
4228
4229#SeeAlso SkCanvas::drawOval Direction Oval
4230
4231##
4232
4233# ------------------------------------------------------------------------------
4234
Cary Clark0251b1b2018-08-15 15:14:55 -04004235#Method SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
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 Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04004239
Cary Clark80247e52018-07-11 16:18:41 -04004240Adds Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark682c58d2018-05-16 07:07:07 -04004241four kConic_Verb, and kClose_Verb. Circle begins at:
Cary Clark73fa9722017-08-29 17:36:51 -04004242#Formula
4243(x + radius, y)
4244##
Cary Clark154beea2017-10-26 07:58:48 -04004245, continuing
4246clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04004247
Cary Clark6fc50412017-09-21 12:31:06 -04004248Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004249
4250#Param x center of Circle ##
4251#Param y center of Circle ##
4252#Param radius distance from center to edge ##
4253#Param dir Direction to wind Circle ##
4254
Cary Clark0251b1b2018-08-15 15:14:55 -04004255#Return reference to Path ##
4256
Cary Clark73fa9722017-08-29 17:36:51 -04004257#Example
4258void draw(SkCanvas* canvas) {
4259 SkPaint paint;
4260 paint.setAntiAlias(true);
4261 paint.setStyle(SkPaint::kStroke_Style);
4262 paint.setStrokeWidth(10);
4263 for (int size = 10; size < 300; size += 20) {
4264 SkPath path;
4265 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4266 canvas->drawPath(path, paint);
4267 }
4268}
4269##
4270
4271#SeeAlso SkCanvas::drawCircle Direction Circle
4272
4273##
4274
4275# ------------------------------------------------------------------------------
4276
Cary Clark0251b1b2018-08-15 15:14:55 -04004277#Method SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05004278#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004279#Line # adds one Contour containing Arc ##
Cary Clark80247e52018-07-11 16:18:41 -04004280Appends Arc to Path, as the start of new Contour. Arc added is part of ellipse
Cary Clark73fa9722017-08-29 17:36:51 -04004281bounded by oval, from startAngle through sweepAngle. Both startAngle and
4282sweepAngle are measured in degrees, where zero degrees is aligned with the
4283positive x-axis, and positive sweeps extends Arc clockwise.
4284
Cary Clark682c58d2018-05-16 07:07:07 -04004285If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4286zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
Cary Clark73fa9722017-08-29 17:36:51 -04004287modulo 360, and Arc may or may not draw depending on numeric rounding.
4288
4289#Param oval bounds of ellipse containing Arc ##
4290#Param startAngle starting angle of Arc in degrees ##
4291#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4292
Cary Clark0251b1b2018-08-15 15:14:55 -04004293#Return reference to Path ##
4294
Cary Clark73fa9722017-08-29 17:36:51 -04004295#Example
4296#Description
4297The middle row of the left and right columns draw differently from the entries
Cary Clark682c58d2018-05-16 07:07:07 -04004298above and below because sweepAngle is outside of the range of +/-360,
Cary Clark73fa9722017-08-29 17:36:51 -04004299and startAngle modulo 90 is not zero.
4300##
4301void draw(SkCanvas* canvas) {
4302 SkPaint paint;
4303 for (auto start : { 0, 90, 135, 180, 270 } ) {
4304 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4305 SkPath path;
4306 path.addArc({10, 10, 35, 45}, start, sweep);
4307 canvas->drawPath(path, paint);
4308 canvas->translate(252 / 6, 0);
4309 }
4310 canvas->translate(-252, 255 / 5);
4311 }
4312}
4313##
4314
4315#SeeAlso Arc arcTo SkCanvas::drawArc
4316
4317##
4318
4319# ------------------------------------------------------------------------------
4320
Cary Clark0251b1b2018-08-15 15:14:55 -04004321#Method SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Cary Clark73fa9722017-08-29 17:36:51 -04004322 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004323#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004324#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark73fa9722017-08-29 17:36:51 -04004325
Cary Clark80247e52018-07-11 16:18:41 -04004326Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04004327equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4328dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4329winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4330of the upper-left corner and winds counterclockwise.
4331
4332If either rx or ry is too large, rx and ry are scaled uniformly until the
4333corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4334Rect rect to Path.
4335
4336After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4337
4338#Param rect bounds of Round_Rect ##
Cary Clark5538c132018-06-14 12:28:14 -04004339#Param rx x-axis radius of rounded corners on the Round_Rect ##
4340#Param ry y-axis radius of rounded corners on the Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004341#Param dir Direction to wind Round_Rect ##
4342
Cary Clark0251b1b2018-08-15 15:14:55 -04004343#Return reference to Path ##
4344
Cary Clark73fa9722017-08-29 17:36:51 -04004345#Example
4346#Description
4347If either radius is zero, path contains Rect and is drawn red.
4348If sides are only radii, path contains Oval and is drawn blue.
4349All remaining path draws are convex, and are drawn in gray; no
4350paths constructed from addRoundRect are concave, so none are
4351drawn in green.
4352##
4353void draw(SkCanvas* canvas) {
4354 SkPaint paint;
4355 paint.setAntiAlias(true);
4356 for (auto xradius : { 0, 7, 13, 20 } ) {
4357 for (auto yradius : { 0, 9, 18, 40 } ) {
4358 SkPath path;
4359 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4360 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4361 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4362 canvas->drawPath(path, paint);
4363 canvas->translate(64, 0);
4364 }
4365 canvas->translate(-256, 64);
4366 }
4367}
4368##
4369
4370#SeeAlso addRRect SkCanvas::drawRoundRect
4371
4372##
4373
4374# ------------------------------------------------------------------------------
4375
Cary Clark0251b1b2018-08-15 15:14:55 -04004376#Method SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
Cary Clark73fa9722017-08-29 17:36:51 -04004377 Direction dir = kCW_Direction)
4378
Cary Clark80247e52018-07-11 16:18:41 -04004379Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04004380equal to rect; each corner is 90 degrees of an ellipse with radii from the
4381array.
4382
4383#Table
4384#Legend
4385# radii index # location ##
4386#Legend ##
Cary Clark5538c132018-06-14 12:28:14 -04004387# 0 # x-axis radius of top-left corner ##
4388# 1 # y-axis radius of top-left corner ##
4389# 2 # x-axis radius of top-right corner ##
4390# 3 # y-axis radius of top-right corner ##
4391# 4 # x-axis radius of bottom-right corner ##
4392# 5 # y-axis radius of bottom-right corner ##
4393# 6 # x-axis radius of bottom-left corner ##
4394# 7 # y-axis radius of bottom-left corner ##
Cary Clark73fa9722017-08-29 17:36:51 -04004395#Table ##
4396
Cary Clark682c58d2018-05-16 07:07:07 -04004397If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4398and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
Cary Clark73fa9722017-08-29 17:36:51 -04004399bottom-left of the upper-left corner and winds counterclockwise.
4400
Cary Clark682c58d2018-05-16 07:07:07 -04004401If both radii on any side of rect exceed its length, all radii are scaled
Cary Clark73fa9722017-08-29 17:36:51 -04004402uniformly until the corners fit. If either radius of a corner is less than or
4403equal to zero, both are treated as zero.
4404
4405After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4406
4407#Param rect bounds of Round_Rect ##
4408#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4409#Param dir Direction to wind Round_Rect ##
4410
Cary Clark0251b1b2018-08-15 15:14:55 -04004411#Return reference to Path ##
4412
Cary Clark73fa9722017-08-29 17:36:51 -04004413#Example
4414void draw(SkCanvas* canvas) {
4415 SkPaint paint;
4416 paint.setAntiAlias(true);
4417 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4418 SkPath path;
4419 SkMatrix rotate90;
4420 rotate90.setRotate(90, 128, 128);
4421 for (int i = 0; i < 4; ++i) {
4422 path.addRoundRect({10, 10, 110, 110}, radii);
4423 path.transform(rotate90);
4424 }
4425 canvas->drawPath(path, paint);
4426}
4427##
4428
4429#SeeAlso addRRect SkCanvas::drawRoundRect
4430
4431##
4432
4433# ------------------------------------------------------------------------------
4434
Cary Clark0251b1b2018-08-15 15:14:55 -04004435#Method SkPath& addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004436#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004437#Line # adds one Contour containing Round_Rect ##
Cary Clark80247e52018-07-11 16:18:41 -04004438Adds rrect to Path, creating a new closed Contour. If
Cary Clark73fa9722017-08-29 17:36:51 -04004439dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4440winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4441of the upper-left corner and winds counterclockwise.
4442
4443After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4444
4445#Param rrect bounds and radii of rounded rectangle ##
4446#Param dir Direction to wind Round_Rect ##
4447
Cary Clark0251b1b2018-08-15 15:14:55 -04004448#Return reference to Path ##
4449
Cary Clark73fa9722017-08-29 17:36:51 -04004450#Example
4451void draw(SkCanvas* canvas) {
4452 SkPaint paint;
4453 paint.setAntiAlias(true);
4454 SkRRect rrect;
4455 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4456 rrect.setRectRadii({10, 10, 110, 110}, radii);
4457 SkPath path;
4458 SkMatrix rotate90;
4459 rotate90.setRotate(90, 128, 128);
4460 for (int i = 0; i < 4; ++i) {
4461 path.addRRect(rrect);
4462 path.transform(rotate90);
4463 }
4464 canvas->drawPath(path, paint);
4465}
4466##
4467
4468#SeeAlso addRoundRect SkCanvas::drawRRect
4469
4470##
4471
4472# ------------------------------------------------------------------------------
4473
Cary Clark0251b1b2018-08-15 15:14:55 -04004474#Method SkPath& addRRect(const SkRRect& rrect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04004475
Cary Clark80247e52018-07-11 16:18:41 -04004476Adds rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
Cary Clark73fa9722017-08-29 17:36:51 -04004477winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4478start determines the first point of rrect to add.
4479
4480#Table
4481#Legend
4482# start # location ##
4483#Legend ##
4484# 0 # right of top-left corner ##
4485# 1 # left of top-right corner ##
4486# 2 # bottom of top-right corner ##
4487# 3 # top of bottom-right corner ##
4488# 4 # left of bottom-right corner ##
4489# 5 # right of bottom-left corner ##
4490# 6 # top of bottom-left corner ##
4491# 7 # bottom of top-left corner ##
4492#Table ##
4493
4494After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4495
4496#Param rrect bounds and radii of rounded rectangle ##
4497#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004498#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004499
Cary Clark0251b1b2018-08-15 15:14:55 -04004500#Return reference to Path ##
4501
Cary Clark73fa9722017-08-29 17:36:51 -04004502#Example
4503void draw(SkCanvas* canvas) {
4504 SkPaint paint;
4505 paint.setAntiAlias(true);
4506 SkRRect rrect;
4507 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4508 SkPath path;
4509 path.addRRect(rrect);
4510 canvas->drawPath(path, paint);
4511 for (int start = 0; start < 8; ++start) {
4512 SkPath textPath;
4513 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
4514 canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
4515 }
4516}
4517##
4518
Cary Clark682c58d2018-05-16 07:07:07 -04004519#SeeAlso addRoundRect SkCanvas::drawRRect
Cary Clark73fa9722017-08-29 17:36:51 -04004520
4521##
4522
4523# ------------------------------------------------------------------------------
4524
Cary Clark0251b1b2018-08-15 15:14:55 -04004525#Method SkPath& addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05004526#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004527#Line # adds one Contour containing connected lines ##
Cary Clark80247e52018-07-11 16:18:41 -04004528Adds Contour created from Line array, adding (count - 1) Line segments.
Cary Clark6fc50412017-09-21 12:31:06 -04004529Contour added starts at pts[0], then adds a line for every additional Point
Cary Clark0251b1b2018-08-15 15:14:55 -04004530in pts array. If close is true, appends kClose_Verb to Path, connecting
Cary Clark6fc50412017-09-21 12:31:06 -04004531pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004532
4533If count is zero, append kMove_Verb to path.
4534Has no effect if count is less than one.
Cary Clark682c58d2018-05-16 07:07:07 -04004535
Cary Clarka523d2d2017-08-30 08:58:10 -04004536#Param pts array of Line sharing end and start Point ##
4537#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004538#Param close true to add Line connecting Contour end and start ##
4539
Cary Clark0251b1b2018-08-15 15:14:55 -04004540#Return reference to Path ##
4541
Cary Clark73fa9722017-08-29 17:36:51 -04004542#Example
4543void draw(SkCanvas* canvas) {
4544 SkPaint paint;
4545 paint.setStrokeWidth(15);
4546 paint.setStrokeCap(SkPaint::kRound_Cap);
4547 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4548 for (bool close : { false, true } ) {
4549 SkPath path;
4550 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4551 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4552 SkPaint::kStrokeAndFill_Style} ) {
4553 paint.setStyle(style);
4554 canvas->drawPath(path, paint);
4555 canvas->translate(85, 0);
4556 }
4557 canvas->translate(-255, 128);
4558 }
4559}
4560##
4561
4562#SeeAlso SkCanvas::drawPoints
4563
4564##
4565
Cary Clark0251b1b2018-08-15 15:14:55 -04004566#Method SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close)
4567
4568Adds Contour created from list. Contour added starts at list[0], then adds a line
4569for every additional Point in list. If close is true, appends kClose_Verb to Path,
4570connecting last and first Point in list.
4571
4572If list is empty, append kMove_Verb to path.
4573
4574#Param list array of Points ##
4575#Param close true to add Line connecting Contour end and start ##
4576
4577#Return reference to Path ##
4578
4579#Example
4580void draw(SkCanvas* canvas) {
4581 SkPaint paint;
4582 paint.setStrokeWidth(15);
4583 paint.setStrokeCap(SkPaint::kRound_Cap);
4584 for (bool close : { false, true } ) {
4585 SkPath path;
4586 path.addPoly({{20, 20}, {70, 20}, {40, 90}}, close);
4587 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4588 SkPaint::kStrokeAndFill_Style} ) {
4589 paint.setStyle(style);
4590 canvas->drawPath(path, paint);
4591 canvas->translate(85, 0);
4592 }
4593 canvas->translate(-255, 128);
4594 }
4595}
4596##
4597
4598#SeeAlso SkCanvas::drawPoints
4599
4600##
4601
Cary Clark73fa9722017-08-29 17:36:51 -04004602# ------------------------------------------------------------------------------
4603
4604#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05004605#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04004606
4607#Code
4608 enum AddPathMode {
Cary Clark682c58d2018-05-16 07:07:07 -04004609 kAppend_AddPathMode,
4610 kExtend_AddPathMode,
Cary Clark73fa9722017-08-29 17:36:51 -04004611 };
4612##
4613
4614AddPathMode chooses how addPath appends. Adding one Path to another can extend
4615the last Contour or start a new Contour.
4616
4617#Const kAppend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004618#Line # appended to destination unaltered ##
Cary Clark73fa9722017-08-29 17:36:51 -04004619 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4620 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4621 starts a new Contour.
4622##
4623#Const kExtend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004624#Line # add line if prior Contour is not closed ##
Cary Clark73fa9722017-08-29 17:36:51 -04004625 If destination is closed or empty, start a new Contour. If destination
4626 is not empty, add Line from Last_Point to added Path first Point. Skip added
4627 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4628##
4629
4630#Example
4631#Description
4632test is built from path, open on the top row, and closed on the bottom row.
4633The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4634The top right composition is made up of one contour; the other three have two.
4635##
4636#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004637 SkPath path, path2;
4638 path.moveTo(20, 20);
4639 path.lineTo(20, 40);
4640 path.lineTo(40, 20);
4641 path2.moveTo(60, 60);
4642 path2.lineTo(80, 60);
4643 path2.lineTo(80, 40);
4644 SkPaint paint;
4645 paint.setStyle(SkPaint::kStroke_Style);
4646 for (int i = 0; i < 2; i++) {
4647 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4648 SkPath test(path);
4649 test.addPath(path2, addPathMode);
4650 canvas->drawPath(test, paint);
4651 canvas->translate(100, 0);
4652 }
4653 canvas->translate(-200, 100);
4654 path.close();
4655 }
Cary Clark73fa9722017-08-29 17:36:51 -04004656##
4657
4658#SeeAlso addPath reverseAddPath
4659
4660##
4661
4662# ------------------------------------------------------------------------------
4663
Cary Clark0251b1b2018-08-15 15:14:55 -04004664#Method SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
Cary Clark73fa9722017-08-29 17:36:51 -04004665 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05004666#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004667#Line # adds contents of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004668
Cary Clark80247e52018-07-11 16:18:41 -04004669Appends src to Path, offset by (dx, dy).
Cary Clark73fa9722017-08-29 17:36:51 -04004670
4671If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4672added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004673Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004674
4675#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clark5538c132018-06-14 12:28:14 -04004676#Param dx offset added to src Point_Array x-axis coordinates ##
4677#Param dy offset added to src Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004678#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4679
Cary Clark0251b1b2018-08-15 15:14:55 -04004680#Return reference to Path ##
4681
Cary Clark73fa9722017-08-29 17:36:51 -04004682#Example
4683#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004684 SkPaint paint;
4685 paint.setTextSize(128);
4686 paint.setFakeBoldText(true);
4687 SkPath dest, text;
4688 paint.getTextPath("O", 1, 50, 120, &text);
4689 for (int i = 0; i < 3; i++) {
4690 dest.addPath(text, i * 20, i * 20);
4691 }
4692 Simplify(dest, &dest);
4693 paint.setStyle(SkPaint::kStroke_Style);
4694 paint.setStrokeWidth(3);
4695 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004696##
4697
Cary Clark4855f782018-02-06 09:41:53 -05004698#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004699
4700##
4701
4702# ------------------------------------------------------------------------------
4703
Cary Clark0251b1b2018-08-15 15:14:55 -04004704#Method SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
Cary Clark73fa9722017-08-29 17:36:51 -04004705
Cary Clark80247e52018-07-11 16:18:41 -04004706Appends src to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04004707
4708If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4709added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004710Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004711
4712#Param src Path Verbs, Points, and Conic_Weights to add ##
4713#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4714
Cary Clark0251b1b2018-08-15 15:14:55 -04004715#Return reference to Path ##
4716
Cary Clark73fa9722017-08-29 17:36:51 -04004717#Example
4718#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004719 SkPaint paint;
4720 paint.setStyle(SkPaint::kStroke_Style);
4721 SkPath dest, path;
4722 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4723 for (int i = 0; i < 2; i++) {
4724 dest.addPath(path, SkPath::kExtend_AddPathMode);
4725 dest.offset(100, 0);
4726 }
Cary Clark73fa9722017-08-29 17:36:51 -04004727 canvas->drawPath(dest, paint);
4728##
4729
4730#SeeAlso AddPathMode reverseAddPath
4731
4732##
4733
4734# ------------------------------------------------------------------------------
4735
Cary Clark0251b1b2018-08-15 15:14:55 -04004736#Method SkPath& addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
Cary Clark73fa9722017-08-29 17:36:51 -04004737
Cary Clark80247e52018-07-11 16:18:41 -04004738Appends src to Path, transformed by matrix. Transformed curves may have different
Cary Clark73fa9722017-08-29 17:36:51 -04004739Verbs, Points, and Conic_Weights.
4740
4741If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4742added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004743Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004744
4745#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004746#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004747#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4748
Cary Clark0251b1b2018-08-15 15:14:55 -04004749#Return reference to Path ##
4750
Cary Clark73fa9722017-08-29 17:36:51 -04004751#Example
4752#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004753 SkPaint paint;
4754 paint.setStyle(SkPaint::kStroke_Style);
4755 SkPath dest, path;
4756 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4757 for (int i = 0; i < 6; i++) {
4758 SkMatrix matrix;
4759 matrix.reset();
4760 matrix.setPerspX(i / 400.f);
4761 dest.addPath(path, matrix);
4762 }
4763 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004764##
4765
Cary Clark4855f782018-02-06 09:41:53 -05004766#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004767
4768##
4769
4770# ------------------------------------------------------------------------------
4771
Cary Clark0251b1b2018-08-15 15:14:55 -04004772#Method SkPath& reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05004773#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004774#Line # adds contents of Path back to front ##
Cary Clark80247e52018-07-11 16:18:41 -04004775Appends src to Path, from back to front.
Cary Clark73fa9722017-08-29 17:36:51 -04004776Reversed src always appends a new Contour to Path.
4777
4778#Param src Path Verbs, Points, and Conic_Weights to add ##
4779
Cary Clark0251b1b2018-08-15 15:14:55 -04004780#Return reference to Path ##
4781
Cary Clark73fa9722017-08-29 17:36:51 -04004782#Example
4783#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004784 SkPath path;
4785 path.moveTo(20, 20);
4786 path.lineTo(20, 40);
4787 path.lineTo(40, 20);
4788 SkPaint paint;
4789 paint.setStyle(SkPaint::kStroke_Style);
4790 for (int i = 0; i < 2; i++) {
4791 SkPath path2;
4792 path2.moveTo(60, 60);
4793 path2.lineTo(80, 60);
4794 path2.lineTo(80, 40);
4795 for (int j = 0; j < 2; j++) {
4796 SkPath test(path);
4797 test.reverseAddPath(path2);
4798 canvas->drawPath(test, paint);
4799 canvas->translate(100, 0);
4800 path2.close();
4801 }
4802 canvas->translate(-200, 100);
4803 path.close();
4804 }
Cary Clark73fa9722017-08-29 17:36:51 -04004805##
4806
Cary Clark4855f782018-02-06 09:41:53 -05004807#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04004808
4809##
4810
4811# ------------------------------------------------------------------------------
4812
4813#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004814#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004815#Line # translates Point_Array ##
Cary Clark80247e52018-07-11 16:18:41 -04004816Offsets Point_Array by (dx, dy). Offset Path replaces dst.
Cary Clark73fa9722017-08-29 17:36:51 -04004817If dst is nullptr, Path is replaced by offset data.
4818
Cary Clark5538c132018-06-14 12:28:14 -04004819#Param dx offset added to Point_Array x-axis coordinates ##
4820#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004821#Param dst overwritten, translated copy of Path; may be nullptr ##
4822
4823#Example
4824#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004825 SkPath pattern;
4826 pattern.moveTo(20, 20);
4827 pattern.lineTo(20, 40);
4828 pattern.lineTo(40, 20);
4829 SkPaint paint;
4830 paint.setStyle(SkPaint::kStroke_Style);
4831 for (int i = 0; i < 10; i++) {
4832 SkPath path;
4833 pattern.offset(20 * i, 0, &path);
4834 canvas->drawPath(path, paint);
4835 }
Cary Clark73fa9722017-08-29 17:36:51 -04004836##
4837
4838#SeeAlso addPath transform
4839
4840##
4841
4842# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05004843#Subtopic Transform
4844#Populate
4845#Line # modify all points ##
4846##
Cary Clark73fa9722017-08-29 17:36:51 -04004847
Cary Clark682c58d2018-05-16 07:07:07 -04004848#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05004849#In Transform
Cary Clark80247e52018-07-11 16:18:41 -04004850Offsets Point_Array by (dx, dy). Path is replaced by offset data.
Cary Clark73fa9722017-08-29 17:36:51 -04004851
Cary Clark5538c132018-06-14 12:28:14 -04004852#Param dx offset added to Point_Array x-axis coordinates ##
4853#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004854
4855#Example
4856#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004857 SkPath path;
4858 path.moveTo(20, 20);
4859 path.lineTo(20, 40);
4860 path.lineTo(40, 20);
4861 SkPaint paint;
4862 paint.setStyle(SkPaint::kStroke_Style);
4863 for (int i = 0; i < 10; i++) {
4864 canvas->drawPath(path, paint);
4865 path.offset(20, 0);
4866 }
Cary Clark73fa9722017-08-29 17:36:51 -04004867##
4868
4869#SeeAlso addPath transform SkCanvas::translate()
4870
4871##
4872
4873# ------------------------------------------------------------------------------
4874
4875#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004876#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004877#Line # applies Matrix to Point_Array and Weights ##
Cary Clark80247e52018-07-11 16:18:41 -04004878Transforms Verb_Array, Point_Array, and weight by matrix.
Cary Clark73fa9722017-08-29 17:36:51 -04004879transform may change Verbs and increase their number.
4880Transformed Path replaces dst; if dst is nullptr, original data
Cary Clark682c58d2018-05-16 07:07:07 -04004881is replaced.
Cary Clark73fa9722017-08-29 17:36:51 -04004882
4883#Param matrix Matrix to apply to Path ##
4884#Param dst overwritten, transformed copy of Path; may be nullptr ##
4885
4886#Example
Cary Clark8032b982017-07-28 11:04:54 -04004887#Height 200
4888 SkPath pattern;
4889 pattern.moveTo(100, 100);
4890 pattern.lineTo(100, 20);
4891 pattern.lineTo(20, 100);
4892 SkPaint paint;
4893 paint.setStyle(SkPaint::kStroke_Style);
4894 for (int i = 0; i < 10; i++) {
4895 SkPath path;
4896 SkMatrix matrix;
4897 matrix.setRotate(36 * i, 100, 100);
4898 pattern.transform(matrix, &path);
4899 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004900 }
4901##
4902
4903#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4904
4905##
4906
4907# ------------------------------------------------------------------------------
4908
Cary Clark682c58d2018-05-16 07:07:07 -04004909#Method void transform(const SkMatrix& matrix)
Cary Clark73fa9722017-08-29 17:36:51 -04004910
Cary Clark80247e52018-07-11 16:18:41 -04004911Transforms Verb_Array, Point_Array, and weight by matrix.
Cary Clark73fa9722017-08-29 17:36:51 -04004912transform may change Verbs and increase their number.
4913Path is replaced by transformed data.
4914
4915#Param matrix Matrix to apply to Path ##
4916
4917#Example
Cary Clark8032b982017-07-28 11:04:54 -04004918#Height 200
4919 SkPath path;
4920 path.moveTo(100, 100);
4921 path.quadTo(100, 20, 20, 100);
4922 SkPaint paint;
4923 paint.setStyle(SkPaint::kStroke_Style);
4924 for (int i = 0; i < 10; i++) {
4925 SkMatrix matrix;
4926 matrix.setRotate(36, 100, 100);
4927 path.transform(matrix);
4928 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004929 }
4930##
4931
4932#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4933
4934##
4935
4936# ------------------------------------------------------------------------------
4937
Cary Clark8032b982017-07-28 11:04:54 -04004938#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05004939#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04004940
4941Path is defined cumulatively, often by adding a segment to the end of last
4942Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4943Last_Point can be read and written directly with getLastPt and setLastPt.
4944
Cary Clark73fa9722017-08-29 17:36:51 -04004945#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05004946#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004947#In Last_Point
4948#Line # returns Last_Point ##
Cary Clark682c58d2018-05-16 07:07:07 -04004949 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
Cary Clark73fa9722017-08-29 17:36:51 -04004950 storing (0, 0) if lastPt is not nullptr.
4951
4952 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4953
4954 #Return true if Point_Array contains one or more Points ##
4955
4956 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004957 SkPath path;
4958 path.moveTo(100, 100);
4959 path.quadTo(100, 20, 20, 100);
4960 SkMatrix matrix;
4961 matrix.setRotate(36, 100, 100);
4962 path.transform(matrix);
4963 SkPoint last;
4964 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004965 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4966 #StdOut
4967 last point: 35.2786, 52.9772
Cary Clark682c58d2018-05-16 07:07:07 -04004968 ##
Cary Clark73fa9722017-08-29 17:36:51 -04004969 ##
4970
4971 #SeeAlso setLastPt
4972
4973##
4974
4975#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05004976#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004977#In Last_Point
4978#Line # replaces Last_Point ##
Cary Clark80247e52018-07-11 16:18:41 -04004979 Sets Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
Cary Clark186d08f2018-04-03 08:43:27 -04004980 Verb_Array and append (x, y) to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04004981
Cary Clark5538c132018-06-14 12:28:14 -04004982 #Param x set x-axis value of Last_Point ##
4983 #Param y set y-axis value of Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004984
4985 #Example
4986 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004987 SkPaint paint;
4988 paint.setTextSize(128);
4989 SkPath path;
4990 paint.getTextPath("@", 1, 60, 100, &path);
4991 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004992 canvas->drawPath(path, paint);
4993 ##
4994
4995 #SeeAlso getLastPt
4996
4997##
4998
Cary Clark682c58d2018-05-16 07:07:07 -04004999#Method void setLastPt(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04005000
Cary Clark80247e52018-07-11 16:18:41 -04005001 Sets the last point on the path. If Point_Array is empty, append kMove_Verb to
Cary Clark186d08f2018-04-03 08:43:27 -04005002 Verb_Array and append p to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04005003
5004 #Param p set value of Last_Point ##
5005
5006 #Example
5007 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04005008 SkPaint paint;
5009 paint.setTextSize(128);
5010 SkPath path, path2;
5011 paint.getTextPath("A", 1, 60, 100, &path);
5012 paint.getTextPath("Z", 1, 60, 100, &path2);
5013 SkPoint pt, pt2;
5014 path.getLastPt(&pt);
5015 path2.getLastPt(&pt2);
5016 path.setLastPt(pt2);
5017 path2.setLastPt(pt);
5018 canvas->drawPath(path, paint);
5019 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04005020 ##
5021
5022 #SeeAlso getLastPt
5023
5024##
5025
5026#Subtopic Last_Point ##
5027
5028# ------------------------------------------------------------------------------
5029
5030#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05005031#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04005032
5033#Code
5034 enum SegmentMask {
5035 kLine_SegmentMask = 1 << 0,
5036 kQuad_SegmentMask = 1 << 1,
5037 kConic_SegmentMask = 1 << 2,
5038 kCubic_SegmentMask = 1 << 3,
5039 };
5040##
5041
5042SegmentMask constants correspond to each drawing Verb type in Path; for
5043instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
5044
Cary Clark4855f782018-02-06 09:41:53 -05005045#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04005046#Const kLine_SegmentMask 1
Cary Clark682c58d2018-05-16 07:07:07 -04005047#Line # contains one or more Lines ##
Cary Clark73fa9722017-08-29 17:36:51 -04005048Set if Verb_Array contains kLine_Verb.
5049##
5050#Const kQuad_SegmentMask 2
Cary Clark682c58d2018-05-16 07:07:07 -04005051#Line # contains one or more Quads ##
Cary Clark73fa9722017-08-29 17:36:51 -04005052Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
5053##
5054#Const kConic_SegmentMask 4
Cary Clark682c58d2018-05-16 07:07:07 -04005055#Line # contains one or more Conics ##
Cary Clark73fa9722017-08-29 17:36:51 -04005056Set if Verb_Array contains kConic_Verb.
5057##
5058#Const kCubic_SegmentMask 8
Cary Clark682c58d2018-05-16 07:07:07 -04005059#Line # contains one or more Cubics ##
Cary Clark73fa9722017-08-29 17:36:51 -04005060Set if Verb_Array contains kCubic_Verb.
5061##
5062
5063#Example
5064#Description
5065When conicTo has a weight of one, Quad is added to Path.
5066##
5067 SkPath path;
5068 path.conicTo(10, 10, 20, 30, 1);
Cary Clark682c58d2018-05-16 07:07:07 -04005069 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04005070 SkPath::kConic_SegmentMask ? "set" : "clear");
Cary Clark682c58d2018-05-16 07:07:07 -04005071 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04005072 SkPath::kQuad_SegmentMask ? "set" : "clear");
5073#StdOut
5074Path kConic_SegmentMask is clear
5075Path kQuad_SegmentMask is set
5076##
5077##
5078
5079#SeeAlso getSegmentMasks Verb
5080
5081##
5082
5083# ------------------------------------------------------------------------------
5084
Cary Clark682c58d2018-05-16 07:07:07 -04005085#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05005086#In Utility
5087#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05005088#Line # returns types in Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04005089Returns a mask, where each set bit corresponds to a SegmentMask constant
5090if Path contains one or more Verbs of that type.
5091Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
5092
5093getSegmentMasks() returns a cached result; it is very fast.
5094
5095#Return SegmentMask bits or zero ##
5096
5097#Example
5098SkPath path;
5099path.quadTo(20, 30, 40, 50);
5100path.close();
5101const char* masks[] = { "line", "quad", "conic", "cubic" };
5102int index = 0;
5103for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
5104 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
5105 if (mask & path.getSegmentMasks()) {
5106 SkDebugf("mask %s set\n", masks[index]);
Cary Clark682c58d2018-05-16 07:07:07 -04005107 }
Cary Clark73fa9722017-08-29 17:36:51 -04005108 ++index;
5109}
5110#StdOut
5111mask quad set
5112##
5113##
5114
5115#SeeAlso getSegmentMasks Verb
5116
5117##
5118
5119# ------------------------------------------------------------------------------
5120
5121#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05005122#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05005123#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04005124Returns true if the point (x, y) is contained by Path, taking into
Cary Clark682c58d2018-05-16 07:07:07 -04005125account FillType.
Cary Clark73fa9722017-08-29 17:36:51 -04005126
5127#Table
5128#Legend
5129# FillType # contains() returns true if Point is enclosed by ##
5130##
5131# kWinding_FillType # a non-zero sum of Contour Directions. ##
5132# kEvenOdd_FillType # an odd number of Contours. ##
5133# kInverseWinding_FillType # a zero sum of Contour Directions. ##
5134# kInverseEvenOdd_FillType # and even number of Contours. ##
Cary Clark682c58d2018-05-16 07:07:07 -04005135##
Cary Clark73fa9722017-08-29 17:36:51 -04005136
Cary Clark5538c132018-06-14 12:28:14 -04005137#Param x x-axis value of containment test ##
5138#Param y y-axis value of containment test ##
Cary Clark73fa9722017-08-29 17:36:51 -04005139
5140#Return true if Point is in Path ##
5141
5142#Example
5143SkPath path;
5144SkPaint paint;
5145paint.setTextSize(256);
5146paint.getTextPath("&", 1, 30, 220, &path);
5147for (int y = 2; y < 256; y += 9) {
5148 for (int x = 2; x < 256; x += 9) {
5149 int coverage = 0;
5150 for (int iy = -4; iy <= 4; iy += 2) {
5151 for (int ix = -4; ix <= 4; ix += 2) {
5152 coverage += path.contains(x + ix, y + iy);
5153 }
5154 }
5155 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5156 canvas->drawCircle(x, y, 8, paint);
5157 }
5158}
5159##
5160
5161#SeeAlso conservativelyContainsRect Fill_Type Op
5162
5163##
5164
5165# ------------------------------------------------------------------------------
5166
5167#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05005168#In Utility
Cary Clark53498e92018-06-28 19:13:56 -04005169#Line # sends text representation to stream ##
Cary Clark154beea2017-10-26 07:58:48 -04005170Writes text representation of Path to stream. If stream is nullptr, writes to
5171standard output. Set forceClose to true to get edges used to fill Path.
5172Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005173of floating point numbers used in Point_Array and Conic_Weights.
5174
Cary Clark224c7002018-06-27 11:00:21 -04005175#Param stream writable WStream receiving Path text representation; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04005176#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005177#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005178
5179#Example
5180 SkPath path;
5181 path.quadTo(20, 30, 40, 50);
5182 for (bool forceClose : { false, true } ) {
5183 for (bool dumpAsHex : { false, true } ) {
5184 path.dump(nullptr, forceClose, dumpAsHex);
5185 SkDebugf("\n");
5186 }
5187 }
5188#StdOut
5189path.setFillType(SkPath::kWinding_FillType);
5190path.moveTo(0, 0);
5191path.quadTo(20, 30, 40, 50);
5192
5193path.setFillType(SkPath::kWinding_FillType);
5194path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5195path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5196
5197path.setFillType(SkPath::kWinding_FillType);
5198path.moveTo(0, 0);
5199path.quadTo(20, 30, 40, 50);
5200path.lineTo(0, 0);
5201path.close();
5202
5203path.setFillType(SkPath::kWinding_FillType);
5204path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5205path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5206path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5207path.close();
5208##
5209##
5210
Cary Clark53498e92018-06-28 19:13:56 -04005211#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
Cary Clark73fa9722017-08-29 17:36:51 -04005212
5213##
5214
5215# ------------------------------------------------------------------------------
5216
5217#Method void dump() const
5218
Cary Clarkce101242017-09-01 15:51:02 -04005219Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005220directly compiled as C++ code. Floating point values are written
5221with limited precision; it may not be possible to reconstruct original Path
5222from output.
5223
5224#Example
5225SkPath path, copy;
5226path.lineTo(6.f / 7, 2.f / 3);
5227path.dump();
5228copy.setFillType(SkPath::kWinding_FillType);
5229copy.moveTo(0, 0);
5230copy.lineTo(0.857143f, 0.666667f);
5231SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5232#StdOut
5233path.setFillType(SkPath::kWinding_FillType);
5234path.moveTo(0, 0);
5235path.lineTo(0.857143f, 0.666667f);
5236path is not equal to copy
5237##
5238##
5239
5240#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5241
5242##
5243
5244# ------------------------------------------------------------------------------
5245
5246#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05005247#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005248#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04005249Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005250directly compiled as C++ code. Floating point values are written
5251in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5252original Path.
5253
Cary Clark682c58d2018-05-16 07:07:07 -04005254Use instead of dump() when submitting
5255#A bug reports against Skia # https://bug.skia.org ##
Cary Clark6fc50412017-09-21 12:31:06 -04005256.
Cary Clark73fa9722017-08-29 17:36:51 -04005257
5258#Example
5259SkPath path, copy;
5260path.lineTo(6.f / 7, 2.f / 3);
5261path.dumpHex();
5262copy.setFillType(SkPath::kWinding_FillType);
5263copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5264copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5265SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5266#StdOut
5267path.setFillType(SkPath::kWinding_FillType);
5268path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5269path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5270path is equal to copy
5271##
5272##
5273
Cary Clark186d08f2018-04-03 08:43:27 -04005274#SeeAlso dump SkRect::dumpHex SkRRect::dumpHex writeToMemory
Cary Clark73fa9722017-08-29 17:36:51 -04005275
5276##
5277
5278# ------------------------------------------------------------------------------
5279
5280#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05005281#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005282#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005283Writes Path to buffer, returning the number of bytes written.
5284Pass nullptr to obtain the storage size.
5285
5286Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5287additionally writes computed information like Convexity and bounds.
5288
5289Use only be used in concert with readFromMemory;
5290the format used for Path in memory is not guaranteed.
5291
5292#Param buffer storage for Path; may be nullptr ##
5293
5294#Return size of storage required for Path; always a multiple of 4 ##
5295
5296#Example
5297void draw(SkCanvas* canvas) {
5298 SkPath path, copy;
5299 path.lineTo(6.f / 7, 2.f / 3);
5300 size_t size = path.writeToMemory(nullptr);
5301 SkTDArray<char> storage;
5302 storage.setCount(size);
5303 path.writeToMemory(storage.begin());
5304 copy.readFromMemory(storage.begin(), size);
5305 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5306}
5307#StdOut
5308path is equal to copy
5309##
5310##
5311
5312#SeeAlso serialize readFromMemory dump dumpHex
5313
5314##
5315
5316#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05005317#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005318#Line # copies data to buffer ##
Cary Clark80247e52018-07-11 16:18:41 -04005319Writes Path to buffer, returning the buffer written to, wrapped in Data.
Cary Clark73fa9722017-08-29 17:36:51 -04005320
5321serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5322additionally writes computed information like Convexity and bounds.
5323
5324serialize() should only be used in concert with readFromMemory.
5325The format used for Path in memory is not guaranteed.
5326
5327#Return Path data wrapped in Data buffer ##
5328
5329#Example
5330void draw(SkCanvas* canvas) {
5331 SkPath path, copy;
5332 path.lineTo(6.f / 7, 2.f / 3);
5333 sk_sp<SkData> data = path.serialize();
5334 copy.readFromMemory(data->data(), data->size());
5335 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5336}
5337#StdOut
5338path is equal to copy
5339##
5340##
5341
5342#SeeAlso writeToMemory readFromMemory dump dumpHex
5343##
5344
5345# ------------------------------------------------------------------------------
5346
5347#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05005348#In Utility
Cary Clark682c58d2018-05-16 07:07:07 -04005349#Line # initializes from buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005350Initializes Path from buffer of size length. Returns zero if the buffer is
Cary Clark682c58d2018-05-16 07:07:07 -04005351data is inconsistent, or the length is too small.
Cary Clark73fa9722017-08-29 17:36:51 -04005352
5353Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5354additionally reads computed information like Convexity and bounds.
5355
5356Used only in concert with writeToMemory;
5357the format used for Path in memory is not guaranteed.
5358
5359#Param buffer storage for Path ##
5360#Param length buffer size in bytes; must be multiple of 4 ##
5361
5362#Return number of bytes read, or zero on failure ##
5363
5364#Example
5365void draw(SkCanvas* canvas) {
5366 SkPath path, copy;
5367 path.lineTo(6.f / 7, 2.f / 3);
5368 size_t size = path.writeToMemory(nullptr);
5369 SkTDArray<char> storage;
5370 storage.setCount(size);
5371 path.writeToMemory(storage.begin());
5372 size_t wrongSize = size - 4;
5373 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5374 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5375 size_t largerSize = size + 4;
5376 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5377 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5378}
5379#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005380length = 32; returned by readFromMemory = 0
Cary Clark06c20f32018-03-20 15:53:27 -04005381length = 40; returned by readFromMemory = 36
Cary Clark73fa9722017-08-29 17:36:51 -04005382##
5383##
5384
5385#SeeAlso writeToMemory
5386
5387##
5388
5389# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05005390#Subtopic Generation_ID
Cary Clark137b8742018-05-30 09:21:49 -04005391#Alias Generation_IDs ##
Cary Clark08895c42018-02-01 09:37:32 -05005392#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04005393Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5394Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5395not necessarily have matching Generation_IDs.
5396
5397Empty Paths have a Generation_ID of one.
5398
5399#Method uint32_t getGenerationID() const
5400
Cary Clarkab2621d2018-01-30 10:08:57 -05005401#In Generation_ID
5402#Line # returns unique ID ##
Cary Clark682c58d2018-05-16 07:07:07 -04005403Returns a non-zero, globally unique value. A different value is returned
Cary Clark73fa9722017-08-29 17:36:51 -04005404if Verb_Array, Point_Array, or Conic_Weight changes.
5405
5406Setting Fill_Type does not change Generation_ID.
5407
5408Each time the path is modified, a different Generation_ID will be returned.
5409
5410#Bug 1762
5411Fill_Type does affect Generation_ID on Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -04005412
5413#Return non-zero, globally unique value ##
5414
5415#Example
5416SkPath path;
5417SkDebugf("empty genID = %u\n", path.getGenerationID());
5418path.lineTo(1, 2);
5419SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5420path.rewind();
5421SkDebugf("empty genID = %u\n", path.getGenerationID());
5422path.lineTo(1, 2);
5423SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5424#StdOut
5425empty genID = 1
54261st lineTo genID = 2
5427empty genID = 1
54282nd lineTo genID = 3
5429##
5430##
5431
5432#SeeAlso operator==(const SkPath& a, const SkPath& b)
5433
5434##
5435
Cary Clark78de7512018-02-07 07:27:09 -05005436#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04005437
5438# ------------------------------------------------------------------------------
5439
5440#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005441#In Property
5442#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005443#Line # returns if data is internally consistent ##
Cary Clark73fa9722017-08-29 17:36:51 -04005444 Returns if Path data is consistent. Corrupt Path data is detected if
5445 internal values are out of range or internal storage does not match
5446 array dimensions.
5447
5448 #Return true if Path data is consistent ##
5449
5450 #NoExample
5451 ##
5452
5453##
5454
5455#Method bool pathRefIsValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005456#Deprecated soon
Cary Clark73fa9722017-08-29 17:36:51 -04005457##
5458
5459# ------------------------------------------------------------------------------
5460
Cary Clark8032b982017-07-28 11:04:54 -04005461#Class Iter
Cary Clark682c58d2018-05-16 07:07:07 -04005462#Line # data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005463
Cary Clark73fa9722017-08-29 17:36:51 -04005464#Code
5465class Iter {
5466public:
5467 Iter();
5468 Iter(const SkPath& path, bool forceClose);
5469 void setPath(const SkPath& path, bool forceClose);
5470 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5471 SkScalar conicWeight() const;
5472 bool isCloseLine() const;
5473 bool isClosedContour() const;
5474};
5475##
5476
Cary Clark137b8742018-05-30 09:21:49 -04005477Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5478Provides options to treat open Contours as closed, and to ignore
5479degenerate data.
5480
Cary Clark8032b982017-07-28 11:04:54 -04005481#Example
5482#Height 128
5483#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005484Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005485path of the glyph.
5486##
Cary Clark73fa9722017-08-29 17:36:51 -04005487void draw(SkCanvas* canvas) {
5488 SkPaint paint;
5489 paint.setAntiAlias(true);
5490 paint.setTextSize(256);
5491 SkPath asterisk, path;
5492 paint.getTextPath("*", 1, 50, 192, &asterisk);
Cary Clark682c58d2018-05-16 07:07:07 -04005493 SkPath::Iter iter(asterisk, true);
Cary Clark73fa9722017-08-29 17:36:51 -04005494 SkPoint start[4], pts[4];
5495 iter.next(start); // skip moveTo
5496 iter.next(start); // first quadTo
5497 path.moveTo((start[0] + start[1]) * 0.5f);
5498 while (SkPath::kClose_Verb != iter.next(pts)) {
5499 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5500 }
5501 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5502 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005503}
5504##
5505
5506#SeeAlso RawIter
5507
5508#Method Iter()
Cary Clark682c58d2018-05-16 07:07:07 -04005509#Line # constructs Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005510Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5511Call setPath to initialize Iter at a later time.
5512
Cary Clark73fa9722017-08-29 17:36:51 -04005513#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005514
5515#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005516void draw(SkCanvas* canvas) {
5517 SkPath::Iter iter;
5518 SkPoint points[4];
5519 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5520 SkPath path;
5521 iter.setPath(path, false);
5522 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005523}
Cary Clark73fa9722017-08-29 17:36:51 -04005524#StdOut
5525iter is done
5526iter is done
5527##
Cary Clark8032b982017-07-28 11:04:54 -04005528##
5529
5530#SeeAlso setPath
5531
5532##
5533
5534#Method Iter(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005535#Line # constructs Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005536
5537Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5538If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5539open Contour. path is not altered.
5540
Cary Clark73fa9722017-08-29 17:36:51 -04005541#Param path Path to iterate ##
5542#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005543
Cary Clark73fa9722017-08-29 17:36:51 -04005544#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005545
5546#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005547void draw(SkCanvas* canvas) {
5548 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5549 SkDebugf("%s:\n", prefix);
5550 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5551 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5552 SkPath::Verb verb;
5553 do {
5554 SkPoint points[4];
5555 verb = iter.next(points);
5556 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5557 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5558 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5559 }
5560 if (SkPath::kConic_Verb == verb) {
5561 SkDebugf("weight = %g", iter.conicWeight());
5562 }
5563 SkDebugf("\n");
5564 } while (SkPath::kDone_Verb != verb);
5565 SkDebugf("\n");
5566 };
5567
5568 SkPath path;
5569 path.quadTo(10, 20, 30, 40);
5570 SkPath::Iter openIter(path, false);
5571 debugster("open", openIter);
5572 SkPath::Iter closedIter(path, true);
5573 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005574}
5575#StdOut
5576open:
Cary Clark682c58d2018-05-16 07:07:07 -04005577kMove_Verb {0, 0},
5578kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5579kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005580
5581closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005582kMove_Verb {0, 0},
5583kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5584kLine_Verb {30, 40}, {0, 0},
5585kClose_Verb {0, 0},
5586kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005587##
5588##
5589
5590#SeeAlso setPath
5591
5592##
5593
5594#Method void setPath(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005595#Line # resets Iter to Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005596Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5597If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5598open Contour. path is not altered.
5599
Cary Clark73fa9722017-08-29 17:36:51 -04005600#Param path Path to iterate ##
5601#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005602
5603#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005604void draw(SkCanvas* canvas) {
5605 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5606 SkDebugf("%s:\n", prefix);
5607 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5608 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5609 SkPath::Verb verb;
5610 do {
5611 SkPoint points[4];
5612 verb = iter.next(points);
5613 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5614 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5615 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5616 }
5617 if (SkPath::kConic_Verb == verb) {
5618 SkDebugf("weight = %g", iter.conicWeight());
5619 }
5620 SkDebugf("\n");
5621 } while (SkPath::kDone_Verb != verb);
5622 SkDebugf("\n");
5623 };
5624
5625 SkPath path;
5626 path.quadTo(10, 20, 30, 40);
5627 SkPath::Iter iter(path, false);
5628 debugster("quad open", iter);
5629 SkPath path2;
5630 path2.conicTo(1, 2, 3, 4, .5f);
5631 iter.setPath(path2, true);
5632 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005633}
5634#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005635quad open:
Cary Clark682c58d2018-05-16 07:07:07 -04005636kMove_Verb {0, 0},
5637kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5638kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005639
5640conic closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005641kMove_Verb {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04005642kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005643kLine_Verb {3, 4}, {0, 0},
5644kClose_Verb {0, 0},
5645kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005646##
5647##
5648
5649#SeeAlso Iter(const SkPath& path, bool forceClose)
5650
5651##
5652
Cary Clark682c58d2018-05-16 07:07:07 -04005653#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005654#Line # returns next Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005655
Cary Clarka523d2d2017-08-30 08:58:10 -04005656Returns next Verb in Verb_Array, and advances Iter.
5657When Verb_Array is exhausted, returns kDone_Verb.
5658
Cary Clark8032b982017-07-28 11:04:54 -04005659Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005660
Cary Clark8032b982017-07-28 11:04:54 -04005661If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5662only the last in the series; and skip very small Lines, Quads, and Conics; and
5663skip kClose_Verb following kMove_Verb.
5664if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5665Conics with zero lengths.
5666
Cary Clarka523d2d2017-08-30 08:58:10 -04005667 #Param pts storage for Point data describing returned Verb ##
5668 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5669 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005670
Cary Clark73fa9722017-08-29 17:36:51 -04005671 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005672
5673#Example
Cary Clark682c58d2018-05-16 07:07:07 -04005674#Description
Cary Clark8032b982017-07-28 11:04:54 -04005675skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5676followed by the kClose_Verb, the zero length Line and the very small Line.
5677
5678skip degenerate if exact skips the same as skip degenerate, but shows
5679the very small Line.
5680
5681skip none shows all of the Verbs and Points in Path.
5682##
Cary Clark73fa9722017-08-29 17:36:51 -04005683void draw(SkCanvas* canvas) {
5684 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5685 SkPath::Iter iter(path, false);
5686 SkDebugf("%s:\n", prefix);
5687 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5688 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5689 SkPath::Verb verb;
5690 do {
5691 SkPoint points[4];
5692 verb = iter.next(points, degen, exact);
5693 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5694 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5695 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5696 }
5697 SkDebugf("\n");
5698 } while (SkPath::kDone_Verb != verb);
5699 SkDebugf("\n");
5700 };
5701
5702 SkPath path;
5703 path.moveTo(10, 10);
5704 path.moveTo(20, 20);
5705 path.quadTo(10, 20, 30, 40);
5706 path.moveTo(1, 1);
5707 path.close();
5708 path.moveTo(30, 30);
5709 path.lineTo(30, 30);
5710 path.moveTo(30, 30);
5711 path.lineTo(30.00001f, 30);
5712 debugster("skip degenerate", path, true, false);
5713 debugster("skip degenerate if exact", path, true, true);
5714 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005715}
5716#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005717skip degenerate:
Cary Clark682c58d2018-05-16 07:07:07 -04005718kMove_Verb {20, 20},
5719kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5720kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005721
5722skip degenerate if exact:
Cary Clark682c58d2018-05-16 07:07:07 -04005723kMove_Verb {20, 20},
5724kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5725kMove_Verb {30, 30},
5726kLine_Verb {30, 30}, {30.00001, 30},
5727kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005728
5729skip none:
Cary Clark682c58d2018-05-16 07:07:07 -04005730kMove_Verb {10, 10},
5731kMove_Verb {20, 20},
5732kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5733kMove_Verb {1, 1},
5734kClose_Verb {1, 1},
5735kMove_Verb {30, 30},
5736kLine_Verb {30, 30}, {30, 30},
5737kMove_Verb {30, 30},
5738kLine_Verb {30, 30}, {30.00001, 30},
5739kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005740##
5741##
5742
Cary Clark682c58d2018-05-16 07:07:07 -04005743#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
Cary Clark8032b982017-07-28 11:04:54 -04005744
5745##
5746
5747#Method SkScalar conicWeight() const
Cary Clarkd2ca79c2018-08-10 13:09:13 -04005748#Line # returns Conic_Weight ##
Cary Clark8032b982017-07-28 11:04:54 -04005749 Returns Conic_Weight if next() returned kConic_Verb.
5750
5751 If next() has not been called, or next() did not return kConic_Verb,
5752 result is undefined.
5753
Cary Clark73fa9722017-08-29 17:36:51 -04005754 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005755
5756 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005757 void draw(SkCanvas* canvas) {
5758 SkPath path;
5759 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005760 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005761 SkPoint p[4];
5762 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5763 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5764 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5765 p[2].fX, p[2].fY);
5766 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005767 }
5768 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005769first verb is move
5770next verb is conic
5771conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005772conic weight: 0.5
5773 ##
5774 ##
5775
5776 #SeeAlso Conic_Weight
5777
5778##
5779
5780#Method bool isCloseLine() const
Cary Clark682c58d2018-05-16 07:07:07 -04005781#Line # returns if Line was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005782 Returns true if last kLine_Verb returned by next() was generated
5783 by kClose_Verb. When true, the end point returned by next() is
5784 also the start point of Contour.
5785
5786 If next() has not been called, or next() did not return kLine_Verb,
5787 result is undefined.
5788
Cary Clark73fa9722017-08-29 17:36:51 -04005789 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005790
5791 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005792void draw(SkCanvas* canvas) {
5793 SkPath path;
5794 path.moveTo(6, 7);
5795 path.conicTo(1, 2, 3, 4, .5f);
5796 path.close();
Cary Clark682c58d2018-05-16 07:07:07 -04005797 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005798 SkPoint p[4];
5799 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5800 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5801 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5802 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5803 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5804 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5805 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005806}
5807 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040058081st verb is move
5809moveTo point: {6,7}
58102nd verb is conic
58113rd verb is line
5812line points: {3,4}, {6,7}
5813line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040058144th verb is close
5815 ##
5816 ##
5817
5818 #SeeAlso close()
5819##
5820
5821#Method bool isClosedContour() const
Cary Clark682c58d2018-05-16 07:07:07 -04005822#Line # returns if Contour has kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005823Returns true if subsequent calls to next() return kClose_Verb before returning
5824kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5825Iter may have been initialized with force close set to true.
5826
Cary Clark73fa9722017-08-29 17:36:51 -04005827#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005828
5829#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005830void draw(SkCanvas* canvas) {
5831 for (bool forceClose : { false, true } ) {
5832 SkPath path;
5833 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005834 SkPath::Iter iter(path, forceClose);
Cary Clark73fa9722017-08-29 17:36:51 -04005835 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5836 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5837 path.close();
5838 iter.setPath(path, forceClose);
5839 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5840 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5841 }
Cary Clark8032b982017-07-28 11:04:54 -04005842}
5843#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005844without close(), forceClose is false: isClosedContour returns false
5845with close(), forceClose is false: isClosedContour returns true
5846without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005847with close(), forceClose is true : isClosedContour returns true
5848##
5849##
5850
5851#SeeAlso Iter(const SkPath& path, bool forceClose)
5852
5853##
Cary Clark73fa9722017-08-29 17:36:51 -04005854
5855#Class Iter ##
5856
Cary Clark8032b982017-07-28 11:04:54 -04005857#Class RawIter
Cary Clark682c58d2018-05-16 07:07:07 -04005858#Line # raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005859
Cary Clark73fa9722017-08-29 17:36:51 -04005860#Code
5861 class RawIter {
5862 public:
5863 RawIter();
5864 RawIter(const SkPath& path);
5865 void setPath(const SkPath& path);
5866 Verb next(SkPoint pts[4]);
5867 Verb peek() const;
5868 SkScalar conicWeight() const;
5869 }
5870##
5871
Cary Clark137b8742018-05-30 09:21:49 -04005872Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5873Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5874
Cary Clark8032b982017-07-28 11:04:54 -04005875 #Method RawIter()
Cary Clark682c58d2018-05-16 07:07:07 -04005876 #Line # constructs empty Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005877
5878 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
Cary Clark78c110e2018-02-09 16:49:09 -05005879 Call setPath to initialize SkPath::Iter at a later time.
Cary Clark8032b982017-07-28 11:04:54 -04005880
Cary Clark73fa9722017-08-29 17:36:51 -04005881 #Return RawIter of empty Path ##
5882
5883 #NoExample
5884 ##
5885 ##
Cary Clark8032b982017-07-28 11:04:54 -04005886
5887 #Method RawIter(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005888 #Line # constructs with Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005889
5890
5891 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5892
Cary Clark73fa9722017-08-29 17:36:51 -04005893 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005894
Cary Clark73fa9722017-08-29 17:36:51 -04005895 #Return RawIter of path ##
5896
5897 #NoExample
5898 ##
5899 ##
Cary Clark8032b982017-07-28 11:04:54 -04005900
5901 #Method void setPath(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005902 #Line # sets Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005903
Cary Clark78c110e2018-02-09 16:49:09 -05005904 Sets SkPath::Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
Cary Clark8032b982017-07-28 11:04:54 -04005905
Cary Clark73fa9722017-08-29 17:36:51 -04005906 #Param path Path to iterate ##
5907
5908 #NoExample
5909 ##
5910 ##
Cary Clark8032b982017-07-28 11:04:54 -04005911
5912 #Method Verb next(SkPoint pts[4])
Cary Clark682c58d2018-05-16 07:07:07 -04005913 #Line # returns next Verb and associated Points ##
Cary Clark8032b982017-07-28 11:04:54 -04005914 Returns next Verb in Verb_Array, and advances RawIter.
5915 When Verb_Array is exhausted, returns kDone_Verb.
5916 Zero to four Points are stored in pts, depending on the returned Verb.
5917
Cary Clarka523d2d2017-08-30 08:58:10 -04005918 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005919
Cary Clark73fa9722017-08-29 17:36:51 -04005920 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005921
5922 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005923 void draw(SkCanvas* canvas) {
5924 SkPath path;
5925 path.moveTo(50, 60);
5926 path.quadTo(10, 20, 30, 40);
5927 path.close();
5928 path.lineTo(30, 30);
5929 path.conicTo(1, 2, 3, 4, .5f);
5930 path.cubicTo(-1, -2, -3, -4, -5, -6);
5931 SkPath::RawIter iter(path);
5932 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5933 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5934 SkPath::Verb verb;
5935 do {
5936 SkPoint points[4];
5937 verb = iter.next(points);
5938 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5939 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5940 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5941 }
5942 if (SkPath::kConic_Verb == verb) {
5943 SkDebugf("weight = %g", iter.conicWeight());
5944 }
5945 SkDebugf("\n");
5946 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005947 }
5948 #StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005949 kMove_Verb {50, 60},
5950 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5951 kClose_Verb {50, 60},
5952 kMove_Verb {50, 60},
5953 kLine_Verb {50, 60}, {30, 30},
Cary Clark73fa9722017-08-29 17:36:51 -04005954 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005955 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
5956 kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005957 ##
5958 ##
5959
5960 #SeeAlso peek()
5961
Cary Clark73fa9722017-08-29 17:36:51 -04005962 ##
Cary Clark8032b982017-07-28 11:04:54 -04005963
5964 #Method Verb peek() const
Cary Clark682c58d2018-05-16 07:07:07 -04005965 #Line # returns next Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005966 Returns next Verb, but does not advance RawIter.
5967
Cary Clark73fa9722017-08-29 17:36:51 -04005968 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005969
5970 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005971 SkPath path;
5972 path.quadTo(10, 20, 30, 40);
5973 path.conicTo(1, 2, 3, 4, .5f);
5974 path.cubicTo(1, 2, 3, 4, .5, 6);
5975 SkPath::RawIter iter(path);
5976 SkPath::Verb verb, peek = iter.peek();
5977 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5978 do {
5979 SkPoint points[4];
5980 verb = iter.next(points);
5981 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5982 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005983 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005984 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5985 #StdOut
5986 #Volatile
5987 peek Move == verb Move
5988 peek Quad == verb Quad
5989 peek Conic == verb Conic
5990 peek Cubic == verb Cubic
5991 peek Done == verb Done
5992 peek Done == verb Done
5993 ##
Cary Clark8032b982017-07-28 11:04:54 -04005994 ##
5995
5996 #Bug 6832
Cary Clark682c58d2018-05-16 07:07:07 -04005997 StdOut is not really volatile, it just produces the wrong result.
Cary Clark8032b982017-07-28 11:04:54 -04005998 A simple fix changes the output of hairlines and needs to be
5999 investigated to see if the change is correct or not.
Cary Clark682c58d2018-05-16 07:07:07 -04006000 see change 21340 (abandoned for now)
Cary Clark8032b982017-07-28 11:04:54 -04006001
Cary Clarkd2ca79c2018-08-10 13:09:13 -04006002 #SeeAlso next
Cary Clark8032b982017-07-28 11:04:54 -04006003
Cary Clark73fa9722017-08-29 17:36:51 -04006004 ##
Cary Clark8032b982017-07-28 11:04:54 -04006005
Cary Clark73fa9722017-08-29 17:36:51 -04006006 #Method SkScalar conicWeight() const
Cary Clark682c58d2018-05-16 07:07:07 -04006007 #Line # returns Conic_Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04006008
Cary Clark8032b982017-07-28 11:04:54 -04006009 Returns Conic_Weight if next() returned kConic_Verb.
6010
6011 If next() has not been called, or next() did not return kConic_Verb,
6012 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04006013
6014 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04006015
6016 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04006017 void draw(SkCanvas* canvas) {
6018 SkPath path;
6019 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04006020 SkPath::RawIter iter(path);
Cary Clark73fa9722017-08-29 17:36:51 -04006021 SkPoint p[4];
6022 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
6023 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
6024 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
6025 p[2].fX, p[2].fY);
6026 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04006027 }
6028 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04006029 first verb is move
6030 next verb is conic
6031 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04006032 conic weight: 0.5
6033 ##
6034 ##
6035
6036 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04006037
6038 ##
6039
6040#Class RawIter ##
6041
6042#Class SkPath ##
6043
6044#Topic Path ##
Cary Clark4855f782018-02-06 09:41:53 -05006045