blob: deb1a046f5c9207d40a4d4b8035af19a38d8440b [file] [log] [blame]
Cary Clark73fa9722017-08-29 17:36:51 -04001#Topic Path
Cary Clark137b8742018-05-30 09:21:49 -04002#Alias Path_Reference ##
3#Alias Paths ##
Cary Clark73fa9722017-08-29 17:36:51 -04004
Cary Clark682c58d2018-05-16 07:07:07 -04005Path contains Lines and Curves which can be stroked or filled. Contour is
6composed of a series of connected Lines and Curves. Path may contain zero,
Cary Clark73fa9722017-08-29 17:36:51 -04007one, or more Contours.
8Each Line and Curve are described by Verb, Points, and optional Conic_Weight.
9
10Each pair of connected Lines and Curves share common Point; for instance, Path
Cary Clark682c58d2018-05-16 07:07:07 -040011containing two connected Lines are described the Verb sequence:
Cary Clark73fa9722017-08-29 17:36:51 -040012SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb; and a Point sequence
13with three entries, sharing
14the middle entry as the end of the first Line and the start of the second Line.
15
16Path components Arc, Rect, Round_Rect, Circle, and Oval are composed of
17Lines and Curves with as many Verbs and Points required
18for an exact description. Once added to Path, these components may lose their
Cary Clarkce101242017-09-01 15:51:02 -040019identity; although Path can be inspected to determine if it describes a single
Cary Clark73fa9722017-08-29 17:36:51 -040020Rect, Oval, Round_Rect, and so on.
21
22#Example
23#Height 192
24#Description
25Path contains three Contours: Line, Circle, and Quad. Line is stroked but
26not filled. Circle is stroked and filled; Circle stroke forms a loop. Quad
27is stroked and filled, but since it is not closed, Quad does not stroke a loop.
28##
29void draw(SkCanvas* canvas) {
30 SkPaint paint;
31 paint.setAntiAlias(true);
32 SkPath path;
33 path.moveTo(124, 108);
34 path.lineTo(172, 24);
35 path.addCircle(50, 50, 30);
36 path.moveTo(36, 148);
37 path.quadTo(66, 188, 120, 136);
38 canvas->drawPath(path, paint);
39 paint.setStyle(SkPaint::kStroke_Style);
40 paint.setColor(SK_ColorBLUE);
41 paint.setStrokeWidth(3);
42 canvas->drawPath(path, paint);
43}
44##
45
46Path contains a Fill_Type which determines whether overlapping Contours
47form fills or holes. Fill_Type also determines whether area inside or outside
48Lines and Curves is filled.
49
50#Example
51#Height 192
52#Description
53Path is drawn filled, then stroked, then stroked and filled.
54##
55void draw(SkCanvas* canvas) {
56 SkPaint paint;
57 paint.setAntiAlias(true);
58 SkPath path;
59 path.moveTo(36, 48);
60 path.quadTo(66, 88, 120, 36);
61 canvas->drawPath(path, paint);
62 paint.setStyle(SkPaint::kStroke_Style);
63 paint.setColor(SK_ColorBLUE);
64 paint.setStrokeWidth(8);
65 canvas->translate(0, 50);
66 canvas->drawPath(path, paint);
67 paint.setStyle(SkPaint::kStrokeAndFill_Style);
68 paint.setColor(SK_ColorRED);
69 canvas->translate(0, 50);
70 canvas->drawPath(path, paint);
71}
72##
73
74Path contents are never shared. Copying Path by value effectively creates
75a new Path independent of the original. Internally, the copy does not duplicate
76its contents until it is edited, to reduce memory use and improve performance.
77
Cary Clark8032b982017-07-28 11:04:54 -040078#Subtopic Contour
Cary Clark137b8742018-05-30 09:21:49 -040079#Alias Contours ##
Cary Clark08895c42018-02-01 09:37:32 -050080#Line # loop of lines and curves ##
81
Cary Clark8032b982017-07-28 11:04:54 -040082Contour contains one or more Verbs, and as many Points as
83are required to satisfy Verb_Array. First Verb in Path is always
84SkPath::kMove_Verb; each SkPath::kMove_Verb that follows starts a new Contour.
85
86#Example
Cary Clark682c58d2018-05-16 07:07:07 -040087#Description
Cary Clark73fa9722017-08-29 17:36:51 -040088Each SkPath::moveTo starts a new Contour, and content after SkPath::close()
Cary Clark682c58d2018-05-16 07:07:07 -040089also starts a new Contour. Since SkPath::conicTo is not preceded by
Cary Clark73fa9722017-08-29 17:36:51 -040090SkPath::moveTo, the first Point of the third Contour starts at the last Point
91of the second Contour.
92##
93#Height 192
94 SkPaint paint;
95 paint.setAntiAlias(true);
96 canvas->drawString("1st contour", 150, 100, paint);
97 canvas->drawString("2nd contour", 130, 160, paint);
98 canvas->drawString("3rd contour", 40, 30, paint);
99 paint.setStyle(SkPaint::kStroke_Style);
100 SkPath path;
101 path.moveTo(124, 108);
102 path.lineTo(172, 24);
103 path.moveTo(36, 148);
104 path.quadTo(66, 188, 120, 136);
105 path.close();
106 path.conicTo(70, 20, 110, 40, 0.6f);
107 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -0400108##
109
110If final Verb in Contour is SkPath::kClose_Verb, Line connects Last_Point in
Cary Clark682c58d2018-05-16 07:07:07 -0400111Contour with first Point. A closed Contour, stroked, draws
Cary Clark8032b982017-07-28 11:04:54 -0400112Paint_Stroke_Join at Last_Point and first Point. Without SkPath::kClose_Verb
113as final Verb, Last_Point and first Point are not connected; Contour
Cary Clark682c58d2018-05-16 07:07:07 -0400114remains open. An open Contour, stroked, draws Paint_Stroke_Cap at
Cary Clark8032b982017-07-28 11:04:54 -0400115Last_Point and first Point.
116
117#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400118#Height 160
119#Description
120Path is drawn stroked, with an open Contour and a closed Contour.
121##
122void draw(SkCanvas* canvas) {
123 SkPaint paint;
124 paint.setAntiAlias(true);
125 paint.setStyle(SkPaint::kStroke_Style);
126 paint.setStrokeWidth(8);
127 SkPath path;
128 path.moveTo(36, 48);
129 path.quadTo(66, 88, 120, 36);
130 canvas->drawPath(path, paint);
131 path.close();
132 canvas->translate(0, 50);
133 canvas->drawPath(path, paint);
134}
Cary Clark8032b982017-07-28 11:04:54 -0400135##
136
137#Subtopic Zero_Length
Cary Clark137b8742018-05-30 09:21:49 -0400138#Alias Zero_Length_Contour ##
Cary Clark08895c42018-02-01 09:37:32 -0500139#Line # consideration when contour has no length ##
Cary Clark8032b982017-07-28 11:04:54 -0400140Contour length is distance traveled from first Point to Last_Point,
141plus, if Contour is closed, distance from Last_Point to first Point.
142Even if Contour length is zero, stroked Lines are drawn if Paint_Stroke_Cap
143makes them visible.
144
145#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400146#Height 64
147 SkPaint paint;
148 paint.setAntiAlias(true);
149 paint.setStyle(SkPaint::kStroke_Style);
150 paint.setStrokeWidth(8);
151 paint.setStrokeCap(SkPaint::kRound_Cap);
152 SkPath path;
153 path.moveTo(36, 48);
154 path.lineTo(36, 48);
155 canvas->drawPath(path, paint);
156 path.reset();
157 paint.setStrokeCap(SkPaint::kSquare_Cap);
158 path.moveTo(56, 48);
159 path.close();
Cary Clark8032b982017-07-28 11:04:54 -0400160 canvas->drawPath(path, paint);
161##
162
163#Subtopic Zero_Length ##
164
165#Subtopic Contour ##
Cary Clark682c58d2018-05-16 07:07:07 -0400166
Cary Clark73fa9722017-08-29 17:36:51 -0400167# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400168
Cary Clark73fa9722017-08-29 17:36:51 -0400169#Class SkPath
170
171Paths contain geometry. Paths may be empty, or contain one or more Verbs that
Cary Clarka560c472017-11-27 10:44:06 -0500172outline a figure. Path always starts with a move verb to a Cartesian_Coordinate,
173and may be followed by additional verbs that add lines or curves.
Cary Clark73fa9722017-08-29 17:36:51 -0400174Adding a close verb makes the geometry into a continuous loop, a closed contour.
Cary Clarkce101242017-09-01 15:51:02 -0400175Paths may contain any number of contours, each beginning with a move verb.
Cary Clark73fa9722017-08-29 17:36:51 -0400176
177Path contours may contain only a move verb, or may also contain lines,
Cary Clarkce101242017-09-01 15:51:02 -0400178Quadratic_Beziers, Conics, and Cubic_Beziers. Path contours may be open or
Cary Clark73fa9722017-08-29 17:36:51 -0400179closed.
180
181When used to draw a filled area, Path describes whether the fill is inside or
182outside the geometry. Path also describes the winding rule used to fill
183overlapping contours.
184
185Internally, Path lazily computes metrics likes bounds and convexity. Call
Cary Clark682c58d2018-05-16 07:07:07 -0400186SkPath::updateBoundsCache to make Path thread safe.
187
188#Subtopic Overview
189#Populate
190##
Cary Clark73fa9722017-08-29 17:36:51 -0400191
Cary Clark4855f782018-02-06 09:41:53 -0500192#Subtopic Related_Function
Cary Clark08895c42018-02-01 09:37:32 -0500193#Populate
194##
Cary Clark5081eed2018-01-22 07:55:48 -0500195
Cary Clark4855f782018-02-06 09:41:53 -0500196#Subtopic Constant
Cary Clark08895c42018-02-01 09:37:32 -0500197#Populate
198##
Cary Clark73fa9722017-08-29 17:36:51 -0400199
Cary Clark682c58d2018-05-16 07:07:07 -0400200#Subtopic Class
Cary Clark08895c42018-02-01 09:37:32 -0500201#Populate
202##
Cary Clark73fa9722017-08-29 17:36:51 -0400203
Cary Clark4855f782018-02-06 09:41:53 -0500204#Subtopic Constructor
Cary Clark08895c42018-02-01 09:37:32 -0500205#Populate
206##
Cary Clark8032b982017-07-28 11:04:54 -0400207
Cary Clark4855f782018-02-06 09:41:53 -0500208#Subtopic Operator
Cary Clark08895c42018-02-01 09:37:32 -0500209#Populate
210##
Cary Clark73fa9722017-08-29 17:36:51 -0400211
Cary Clark4855f782018-02-06 09:41:53 -0500212#Subtopic Member_Function
Cary Clark08895c42018-02-01 09:37:32 -0500213#Populate
214##
Cary Clark73fa9722017-08-29 17:36:51 -0400215
Cary Clark8032b982017-07-28 11:04:54 -0400216#Subtopic Verb
Cary Clark137b8742018-05-30 09:21:49 -0400217#Alias Verbs ##
Cary Clark08895c42018-02-01 09:37:32 -0500218#Line # line and curve type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400219#Enum Verb
Cary Clark08895c42018-02-01 09:37:32 -0500220#Line # controls how Path Points are interpreted ##
Cary Clark73fa9722017-08-29 17:36:51 -0400221
222#Code
223 enum Verb {
Cary Clark682c58d2018-05-16 07:07:07 -0400224 kMove_Verb,
225 kLine_Verb,
226 kQuad_Verb,
227 kConic_Verb,
228 kCubic_Verb,
229 kClose_Verb,
230 kDone_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -0400231 };
232##
233
234Verb instructs Path how to interpret one or more Point and optional Conic_Weight;
Cary Clark8032b982017-07-28 11:04:54 -0400235manage Contour, and terminate Path.
236
Cary Clark73fa9722017-08-29 17:36:51 -0400237#Const kMove_Verb 0
Cary Clark682c58d2018-05-16 07:07:07 -0400238#Line # starts new Contour at next Point ##
239 Consecutive kMove_Verb are preserved but all but the last kMove_Verb is
240 ignored. kMove_Verb after other Verbs implicitly closes the previous Contour
241 if SkPaint::kFill_Style is set when drawn; otherwise, stroke is drawn open.
242 kMove_Verb as the last Verb is preserved but ignored.
Cary Clark73fa9722017-08-29 17:36:51 -0400243##
244#Const kLine_Verb 1
Cary Clark682c58d2018-05-16 07:07:07 -0400245#Line # adds Line from Last_Point to next Point ##
246 Line is a straight segment from Point to Point. Consecutive kLine_Verb
247 extend Contour. kLine_Verb at same position as prior kMove_Verb is
248 preserved, and draws Point if SkPaint::kStroke_Style is set, and
249 SkPaint::Cap is SkPaint::kSquare_Cap or SkPaint::kRound_Cap. kLine_Verb
250 at same position as prior line or curve Verb is preserved but is ignored.
Cary Clark73fa9722017-08-29 17:36:51 -0400251##
252#Const kQuad_Verb 2
Cary Clark682c58d2018-05-16 07:07:07 -0400253#Line # adds Quad from Last_Point ##
254 Adds Quad from Last_Point, using control Point, and end Point.
Cary Clark73fa9722017-08-29 17:36:51 -0400255 Quad is a parabolic section within tangents from Last_Point to control Point,
256 and control Point to end Point.
257##
258#Const kConic_Verb 3
Cary Clark682c58d2018-05-16 07:07:07 -0400259#Line # adds Conic from Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -0400260 Adds Conic from Last_Point, using control Point, end Point, and Conic_Weight.
Cary Clark682c58d2018-05-16 07:07:07 -0400261 Conic is a elliptical, parabolic, or hyperbolic section within tangents
Cary Clark73fa9722017-08-29 17:36:51 -0400262 from Last_Point to control Point, and control Point to end Point, constrained
263 by Conic_Weight. Conic_Weight less than one is elliptical; equal to one is
264 parabolic (and identical to Quad); greater than one hyperbolic.
265##
266#Const kCubic_Verb 4
Cary Clark682c58d2018-05-16 07:07:07 -0400267#Line # adds Cubic from Last_Point ##
268 Adds Cubic from Last_Point, using two control Points, and end Point.
Cary Clarka560c472017-11-27 10:44:06 -0500269 Cubic is a third-order Bezier_Curve section within tangents from Last_Point
270 to first control Point, and from second control Point to end Point.
Cary Clark73fa9722017-08-29 17:36:51 -0400271##
272#Const kClose_Verb 5
Cary Clark682c58d2018-05-16 07:07:07 -0400273#Line # closes Contour ##
274 Closes Contour, connecting Last_Point to kMove_Verb Point. Consecutive
275 kClose_Verb are preserved but only first has an effect. kClose_Verb after
276 kMove_Verb has no effect.
Cary Clark73fa9722017-08-29 17:36:51 -0400277##
278#Const kDone_Verb 6
Cary Clark682c58d2018-05-16 07:07:07 -0400279#Line # terminates Path ##
280 Not in Verb_Array, but returned by Path iterator.
Cary Clark8032b982017-07-28 11:04:54 -0400281##
282
283Each Verb has zero or more Points stored in Path.
284Path iterator returns complete curve descriptions, duplicating shared Points
285for consecutive entries.
286
287#Table
288#Legend
289# Verb # Allocated Points # Iterated Points # Weights ##
290##
291# kMove_Verb # 1 # 1 # 0 ##
292# kLine_Verb # 1 # 2 # 0 ##
293# kQuad_Verb # 2 # 3 # 0 ##
294# kConic_Verb # 2 # 3 # 1 ##
295# kCubic_Verb # 3 # 4 # 0 ##
296# kClose_Verb # 0 # 1 # 0 ##
297# kDone_Verb # -- # 0 # 0 ##
298##
Cary Clark73fa9722017-08-29 17:36:51 -0400299
300#Example
301void draw(SkCanvas* canvas) {
302 SkPath path;
303 path.lineTo(20, 20);
304 path.quadTo(-10, -10, 30, 30);
305 path.close();
306 path.cubicTo(1, 2, 3, 4, 5, 6);
307 path.conicTo(0, 0, 0, 0, 2);
308 uint8_t verbs[7];
309 int count = path.getVerbs(verbs, (int) SK_ARRAY_COUNT(verbs));
310 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close" };
311 SkDebugf("verb count: %d\nverbs: ", count);
312 for (int i = 0; i < count; ++i) {
313 SkDebugf("k%s_Verb ", verbStr[verbs[i]]);
314 }
315 SkDebugf("\n");
316}
317#StdOut
318verb count: 7
Cary Clark682c58d2018-05-16 07:07:07 -0400319verbs: kMove_Verb kLine_Verb kQuad_Verb kClose_Verb kMove_Verb kCubic_Verb kConic_Verb
Cary Clark73fa9722017-08-29 17:36:51 -0400320##
321##
322
323#Enum Verb ##
324#Subtopic Verb ##
325
326# ------------------------------------------------------------------------------
327#Subtopic Direction
Cary Clark682c58d2018-05-16 07:07:07 -0400328#Line # contour orientation, clockwise or counterclockwise ##
Cary Clark137b8742018-05-30 09:21:49 -0400329#Alias Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400330
331#Enum Direction
Cary Clark08895c42018-02-01 09:37:32 -0500332#Line # sets Contour clockwise or counterclockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400333
334#Code
335 enum Direction {
Cary Clark682c58d2018-05-16 07:07:07 -0400336 kCW_Direction,
337 kCCW_Direction,
Cary Clark73fa9722017-08-29 17:36:51 -0400338 };
339##
340
341Direction describes whether Contour is clockwise or counterclockwise.
342When Path contains multiple overlapping Contours, Direction together with
343Fill_Type determines whether overlaps are filled or form holes.
344
345Direction also determines how Contour is measured. For instance, dashing
346measures along Path to determine where to start and stop stroke; Direction
347will change dashed results as it steps clockwise or counterclockwise.
348
Cary Clark682c58d2018-05-16 07:07:07 -0400349Closed Contours like Rect, Round_Rect, Circle, and Oval added with
Cary Clark73fa9722017-08-29 17:36:51 -0400350kCW_Direction travel clockwise; the same added with kCCW_Direction
351travel counterclockwise.
352
353#Const kCW_Direction 0
Cary Clark682c58d2018-05-16 07:07:07 -0400354#Line # contour travels clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400355##
356#Const kCCW_Direction 1
Cary Clark682c58d2018-05-16 07:07:07 -0400357#Line # contour travels counterclockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400358##
359
360
361#Example
362#Height 100
363void draw(SkCanvas* canvas) {
364 const SkPoint arrow[] = { {40, -5}, {45, 0}, {40, 5} };
365 const SkRect rect = {10, 10, 90, 90};
366 SkPaint rectPaint;
367 rectPaint.setAntiAlias(true);
368 SkPaint textPaint(rectPaint);
369 textPaint.setTextAlign(SkPaint::kCenter_Align);
370 rectPaint.setStyle(SkPaint::kStroke_Style);
371 SkPaint arrowPaint(rectPaint);
372 SkPath arrowPath;
373 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
374 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 320, 0,
375 SkPath1DPathEffect::kRotate_Style));
376 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
377 canvas->drawRect(rect, rectPaint);
378 for (unsigned start : { 0, 1, 2, 3 } ) {
379 SkPath path;
380 path.addRect(rect, direction, start);
381 canvas->drawPath(path, arrowPaint);
382 }
383 canvas->drawString(SkPath::kCW_Direction == direction ? "CW" : "CCW", rect.centerX(),
384 rect.centerY(), textPaint);
385 canvas->translate(120, 0);
386 }
387}
388##
389
Cary Clark682c58d2018-05-16 07:07:07 -0400390#SeeAlso arcTo rArcTo isRect isNestedFillRects addRect addOval
Cary Clark73fa9722017-08-29 17:36:51 -0400391
392#Enum Direction ##
393#Subtopic Direction ##
394
395# ------------------------------------------------------------------------------
396
397#Method SkPath()
398
Cary Clarkab2621d2018-01-30 10:08:57 -0500399#Line # constructs with default values ##
Cary Clark73fa9722017-08-29 17:36:51 -0400400By default, Path has no Verbs, no Points, and no Weights.
401Fill_Type is set to kWinding_FillType.
402
403#Return empty Path ##
404
405#Example
406 SkPath path;
407 SkDebugf("path is " "%s" "empty", path.isEmpty() ? "" : "not ");
408#StdOut
409path is empty
410##
411##
412
413#SeeAlso reset rewind
414
415##
416
417# ------------------------------------------------------------------------------
418
419#Method SkPath(const SkPath& path)
420
Cary Clarkab2621d2018-01-30 10:08:57 -0500421#Line # makes a shallow copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400422Copy constructor makes two paths identical by value. Internally, path and
423the returned result share pointer values. The underlying Verb_Array, Point_Array
424and Weights are copied when modified.
425
426Creating a Path copy is very efficient and never allocates memory.
427Paths are always copied by value from the interface; the underlying shared
428pointers are not exposed.
429
430#Param path Path to copy by value ##
431
Cary Clarka523d2d2017-08-30 08:58:10 -0400432#Return copy of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -0400433
434#Example
435#Description
436 Modifying one path does not effect another, even if they started as copies
437 of each other.
438##
439 SkPath path;
440 path.lineTo(20, 20);
441 SkPath path2(path);
442 path2.close();
443 SkDebugf("path verbs: %d\n", path.countVerbs());
444 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
445 path.reset();
446 SkDebugf("after reset\n" "path verbs: %d\n", path.countVerbs());
447 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
448#StdOut
449path verbs: 2
450path2 verbs: 3
451after reset
452path verbs: 0
453path2 verbs: 3
454##
455##
456
457#SeeAlso operator=(const SkPath& path)
458
459##
460
461# ------------------------------------------------------------------------------
462
463#Method ~SkPath()
464
Cary Clarkab2621d2018-01-30 10:08:57 -0500465#Line # decreases Reference_Count of owned objects ##
Cary Clark73fa9722017-08-29 17:36:51 -0400466Releases ownership of any shared data and deletes data if Path is sole owner.
467
468#Example
469#Description
Cary Clarkce101242017-09-01 15:51:02 -0400470delete calls Path Destructor, but copy of original in path2 is unaffected.
Cary Clark73fa9722017-08-29 17:36:51 -0400471##
472void draw(SkCanvas* canvas) {
473 SkPath* path = new SkPath();
474 path->lineTo(20, 20);
475 SkPath path2(*path);
476 delete path;
477 SkDebugf("path2 is " "%s" "empty", path2.isEmpty() ? "" : "not ");
478}
479##
480
481#SeeAlso SkPath() SkPath(const SkPath& path) operator=(const SkPath& path)
482
483##
484
485# ------------------------------------------------------------------------------
486
487#Method SkPath& operator=(const SkPath& path)
488
Cary Clarkab2621d2018-01-30 10:08:57 -0500489#Line # makes a shallow copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400490Path assignment makes two paths identical by value. Internally, assignment
491shares pointer values. The underlying Verb_Array, Point_Array and Weights
492are copied when modified.
493
494Copying Paths by assignment is very efficient and never allocates memory.
495Paths are always copied by value from the interface; the underlying shared
496pointers are not exposed.
497
Cary Clarkce101242017-09-01 15:51:02 -0400498#Param path Verb_Array, Point_Array, Weights, and Fill_Type to copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400499
500#Return Path copied by value ##
501
502#Example
503SkPath path1;
504path1.addRect({10, 20, 30, 40});
505SkPath path2 = path1;
506const SkRect& b1 = path1.getBounds();
507SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
508const SkRect& b2 = path2.getBounds();
509SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
510#StdOut
511path1 bounds = 10, 20, 30, 40
512path2 bounds = 10, 20, 30, 40
513#StdOut ##
514##
515
516#SeeAlso swap() SkPath(const SkPath& path)
517
518##
519
520# ------------------------------------------------------------------------------
521
522#Method bool operator==(const SkPath& a, const SkPath& b)
523
Cary Clarkab2621d2018-01-30 10:08:57 -0500524#Line # compares paths for equality ##
Cary Clark73fa9722017-08-29 17:36:51 -0400525Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
526are equivalent.
527
528#Param a Path to compare ##
529#Param b Path to compare ##
530
531#Return true if Path pair are equivalent ##
532
533#Example
534#Description
535Rewind removes Verb_Array but leaves storage; since storage is not compared,
536Path pair are equivalent.
537##
538void draw(SkCanvas* canvas) {
539 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
540 SkDebugf("%s one %c= two\n", prefix, a == b ? '=' : '!');
541 };
542 SkPath one;
543 SkPath two;
544 debugster("empty", one, two);
545 one.moveTo(0, 0);
546 debugster("moveTo", one, two);
547 one.rewind();
548 debugster("rewind", one, two);
549 one.moveTo(0, 0);
550 one.reset();
551 debugster("reset", one, two);
552}
553#StdOut
554empty one == two
555moveTo one != two
556rewind one == two
557reset one == two
558##
559##
560
561##
562
563# ------------------------------------------------------------------------------
564
Cary Clark682c58d2018-05-16 07:07:07 -0400565#Method bool operator!=(const SkPath& a, const SkPath& b)
Cary Clark73fa9722017-08-29 17:36:51 -0400566
Cary Clarkab2621d2018-01-30 10:08:57 -0500567#Line # compares paths for inequality ##
Cary Clark73fa9722017-08-29 17:36:51 -0400568Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
569are not equivalent.
570
571#Param a Path to compare ##
572#Param b Path to compare ##
573
574#Return true if Path pair are not equivalent ##
575
576#Example
577#Description
578Path pair are equal though their convexity is not equal.
579##
580void draw(SkCanvas* canvas) {
581 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
582 SkDebugf("%s one %c= two\n", prefix, a != b ? '!' : '=');
583 };
584 SkPath one;
585 SkPath two;
586 debugster("empty", one, two);
587 one.addRect({10, 20, 30, 40});
588 two.addRect({10, 20, 30, 40});
589 debugster("addRect", one, two);
590 one.setConvexity(SkPath::kConcave_Convexity);
591 debugster("setConvexity", one, two);
592 SkDebugf("convexity %c=\n", one.getConvexity() == two.getConvexity() ? '=' : '!');
593}
594#StdOut
595empty one == two
596addRect one == two
597setConvexity one == two
598convexity !=
599##
600##
601
602##
603
604# ------------------------------------------------------------------------------
605
Cary Clark4855f782018-02-06 09:41:53 -0500606#Subtopic Property
607#Populate
608#Line # metrics and attributes ##
609##
Cary Clark73fa9722017-08-29 17:36:51 -0400610
Cary Clark4855f782018-02-06 09:41:53 -0500611#Method bool isInterpolatable(const SkPath& compare) const
612#In Property
613#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500614#Line # returns if pair contains equal counts of Verb_Array and Weights ##
Cary Clark73fa9722017-08-29 17:36:51 -0400615Return true if Paths contain equal Verbs and equal Weights.
616If Paths contain one or more Conics, the Weights must match.
617
618conicTo may add different Verbs depending on Conic_Weight, so it is not
Cary Clarkce101242017-09-01 15:51:02 -0400619trivial to interpolate a pair of Paths containing Conics with different
Cary Clark682c58d2018-05-16 07:07:07 -0400620Conic_Weight values.
Cary Clark73fa9722017-08-29 17:36:51 -0400621
622#Param compare Path to compare ##
623
624#Return true if Paths Verb_Array and Weights are equivalent ##
625
626#Example
627 SkPath path, path2;
628 path.moveTo(20, 20);
629 path.lineTo(40, 40);
630 path.lineTo(20, 20);
631 path.lineTo(40, 40);
632 path.close();
633 path2.addRect({20, 20, 40, 40});
634 SkDebugf("paths are " "%s" "interpolatable", path.isInterpolatable(path2) ? "" : "not ");
635#StdOut
636paths are interpolatable
637##
638##
639
640#SeeAlso isInterpolatable
641
642##
643
644# ------------------------------------------------------------------------------
645
Cary Clark4855f782018-02-06 09:41:53 -0500646#Subtopic Interpolate
647#Populate
648#Line # weighted average of Path pair ##
649##
Cary Clark73fa9722017-08-29 17:36:51 -0400650
Cary Clark4855f782018-02-06 09:41:53 -0500651#Method bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const
652#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500653#Line # interpolates between Path pair ##
Cary Clark61dfc3a2018-01-03 08:37:53 -0500654Interpolate between Paths with Point_Array of equal size.
655Copy Verb_Array and Weights to out, and set out Point_Array to a weighted
656average of this Point_Array and ending Point_Array, using the formula:
Cary Clark73fa9722017-08-29 17:36:51 -0400657#Formula
Cary Clarkac47b882018-01-11 10:35:44 -0500658(Path Point * weight) + ending Point * (1 - weight)
Cary Clark73fa9722017-08-29 17:36:51 -0400659##
Cary Clark154beea2017-10-26 07:58:48 -0400660.
Cary Clark73fa9722017-08-29 17:36:51 -0400661
Cary Clark682c58d2018-05-16 07:07:07 -0400662weight is most useful when between zero (ending Point_Array) and
663one (this Point_Array); will work with values outside of this
Cary Clark73fa9722017-08-29 17:36:51 -0400664range.
665
666interpolate() returns false and leaves out unchanged if Point_Array is not
Cary Clark682c58d2018-05-16 07:07:07 -0400667the same size as ending Point_Array. Call isInterpolatable to check Path
Cary Clark73fa9722017-08-29 17:36:51 -0400668compatibility prior to calling interpolate().
669
670#Param ending Point_Array averaged with this Point_Array ##
Cary Clark682c58d2018-05-16 07:07:07 -0400671#Param weight contribution of this Point_Array, and
672 one minus contribution of ending Point_Array
Cary Clark73fa9722017-08-29 17:36:51 -0400673##
674#Param out Path replaced by interpolated averages ##
675
676#Return true if Paths contain same number of Points ##
677
678#Example
679#Height 60
680void draw(SkCanvas* canvas) {
681 SkPaint paint;
682 paint.setAntiAlias(true);
683 paint.setStyle(SkPaint::kStroke_Style);
684 SkPath path, path2;
685 path.moveTo(20, 20);
686 path.lineTo(40, 40);
687 path.lineTo(20, 40);
688 path.lineTo(40, 20);
689 path.close();
690 path2.addRect({20, 20, 40, 40});
691 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
692 SkPath interp;
693 path.interpolate(path2, i, &interp);
694 canvas->drawPath(interp, paint);
695 canvas->translate(30, 0);
696 }
697}
698##
699
700#SeeAlso isInterpolatable
701
702##
703
704# ------------------------------------------------------------------------------
705
Cary Clark682c58d2018-05-16 07:07:07 -0400706#Method bool unique() const
Cary Clark4855f782018-02-06 09:41:53 -0500707#Deprecated soon
708Only valid for Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -0400709##
710
711# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400712#Subtopic Fill_Type
Cary Clark682c58d2018-05-16 07:07:07 -0400713#Line # fill rule, normal and inverted ##
Cary Clark8032b982017-07-28 11:04:54 -0400714
Cary Clark73fa9722017-08-29 17:36:51 -0400715#Enum FillType
Cary Clark08895c42018-02-01 09:37:32 -0500716#Line # sets winding rule and inverse fill ##
Cary Clark73fa9722017-08-29 17:36:51 -0400717
718#Code
719 enum FillType {
Cary Clark682c58d2018-05-16 07:07:07 -0400720 kWinding_FillType,
721 kEvenOdd_FillType,
722 kInverseWinding_FillType,
723 kInverseEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400724 };
725##
Cary Clark8032b982017-07-28 11:04:54 -0400726
Cary Clark682c58d2018-05-16 07:07:07 -0400727Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
Cary Clark8032b982017-07-28 11:04:54 -0400728fills if the sum of Contour edges is not zero, where clockwise edges add one, and
729counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
Cary Clark682c58d2018-05-16 07:07:07 -0400730number of Contour edges is odd. Each Fill_Type has an inverse variant that
Cary Clark8032b982017-07-28 11:04:54 -0400731reverses the rule:
732kInverseWinding_FillType fills where the sum of Contour edges is zero;
733kInverseEvenOdd_FillType fills where the number of Contour edges is even.
734
735#Example
736#Height 100
737#Description
738The top row has two clockwise rectangles. The second row has one clockwise and
739one counterclockwise rectangle. The even-odd variants draw the same. The
740winding variants draw the top rectangle overlap, which has a winding of 2, the
741same as the outer parts of the top rectangles, which have a winding of 1.
742##
Cary Clark73fa9722017-08-29 17:36:51 -0400743void draw(SkCanvas* canvas) {
744 SkPath path;
745 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
746 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
747 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
748 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
749 SkPaint strokePaint;
750 strokePaint.setStyle(SkPaint::kStroke_Style);
751 SkRect clipRect = {0, 0, 51, 100};
752 canvas->drawPath(path, strokePaint);
753 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400754 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400755 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
756 canvas->translate(51, 0);
757 canvas->save();
758 canvas->clipRect(clipRect);
759 path.setFillType(fillType);
760 canvas->drawPath(path, fillPaint);
761 canvas->restore();
762 }
Cary Clark8032b982017-07-28 11:04:54 -0400763}
764##
Cary Clark73fa9722017-08-29 17:36:51 -0400765
766#Const kWinding_FillType 0
Cary Clark682c58d2018-05-16 07:07:07 -0400767#Line # is enclosed by a non-zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400768##
769#Const kEvenOdd_FillType 1
Cary Clark682c58d2018-05-16 07:07:07 -0400770#Line # is enclosed by an odd number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400771##
772#Const kInverseWinding_FillType 2
Cary Clark682c58d2018-05-16 07:07:07 -0400773#Line # is enclosed by a zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400774##
775#Const kInverseEvenOdd_FillType 3
Cary Clark682c58d2018-05-16 07:07:07 -0400776#Line # is enclosed by an even number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400777##
778
779#Example
780#Height 230
781void draw(SkCanvas* canvas) {
782 SkPath path;
783 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
784 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
785 SkPaint strokePaint;
786 strokePaint.setStyle(SkPaint::kStroke_Style);
787 SkRect clipRect = {0, 0, 128, 128};
788 canvas->drawPath(path, strokePaint);
789 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
790 SkPaint textPaint;
791 textPaint.setAntiAlias(true);
792 textPaint.setTextAlign(SkPaint::kCenter_Align);
793 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
794 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
795 textPaint.setTextSize(18);
796 canvas->translate(0, 128);
797 canvas->scale(.5f, .5f);
798 canvas->drawString("inverse", 384, 150, textPaint);
799 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400800 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400801 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
802 canvas->save();
803 canvas->clipRect(clipRect);
804 path.setFillType(fillType);
805 canvas->drawPath(path, fillPaint);
806 canvas->restore();
807 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
808 canvas->translate(128, 0);
809 }
810}
811##
812
813#SeeAlso SkPaint::Style Direction getFillType setFillType
814
815##
816
817# ------------------------------------------------------------------------------
818
Cary Clark682c58d2018-05-16 07:07:07 -0400819#Method FillType getFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400820
Cary Clarkab2621d2018-01-30 10:08:57 -0500821#In Fill_Type
822#Line # returns Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400823Returns FillType, the rule used to fill Path. FillType of a new Path is
824kWinding_FillType.
825
Cary Clark682c58d2018-05-16 07:07:07 -0400826#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
827kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400828##
829
830#Example
831 SkPath path;
832 SkDebugf("default path fill type is %s\n",
833 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
Cary Clark682c58d2018-05-16 07:07:07 -0400834 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
Cary Clark73fa9722017-08-29 17:36:51 -0400835 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
836 "kInverseEvenOdd_FillType");
837#StdOut
838default path fill type is kWinding_FillType
839##
840##
841
842#SeeAlso FillType setFillType isInverseFillType
843
844##
845
846# ------------------------------------------------------------------------------
847
Cary Clark682c58d2018-05-16 07:07:07 -0400848#Method void setFillType(FillType ft)
Cary Clark73fa9722017-08-29 17:36:51 -0400849
Cary Clarkab2621d2018-01-30 10:08:57 -0500850#In Fill_Type
851#Line # sets Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400852Sets FillType, the rule used to fill Path. While there is no check
853that ft is legal, values outside of FillType are not supported.
854
Cary Clark682c58d2018-05-16 07:07:07 -0400855#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
856kInverseEvenOdd_FillType
Cary Clark73fa9722017-08-29 17:36:51 -0400857##
858
859#Example
860#Description
861If empty Path is set to inverse FillType, it fills all pixels.
862##
863#Height 64
864 SkPath path;
865 path.setFillType(SkPath::kInverseWinding_FillType);
866 SkPaint paint;
867 paint.setColor(SK_ColorBLUE);
868 canvas->drawPath(path, paint);
869##
870
871#SeeAlso FillType getFillType toggleInverseFillType
872
873##
874
875# ------------------------------------------------------------------------------
876
Cary Clark682c58d2018-05-16 07:07:07 -0400877#Method bool isInverseFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400878
Cary Clarkab2621d2018-01-30 10:08:57 -0500879#In Fill_Type
880#Line # returns if Fill_Type fills outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -0400881Returns if FillType describes area outside Path geometry. The inverse fill area
882extends indefinitely.
883
884#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType ##
885
886#Example
887 SkPath path;
888 SkDebugf("default path fill type is inverse: %s\n",
889 path.isInverseFillType() ? "true" : "false");
890#StdOut
891default path fill type is inverse: false
892##
893##
894
895#SeeAlso FillType getFillType setFillType toggleInverseFillType
896
897##
898
899# ------------------------------------------------------------------------------
900
Cary Clark682c58d2018-05-16 07:07:07 -0400901#Method void toggleInverseFillType()
Cary Clark73fa9722017-08-29 17:36:51 -0400902
Cary Clarkab2621d2018-01-30 10:08:57 -0500903#In Fill_Type
904#Line # toggles Fill_Type between inside and outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -0400905Replace FillType with its inverse. The inverse of FillType describes the area
906unmodified by the original FillType.
907
Cary Clark682c58d2018-05-16 07:07:07 -0400908#Table
Cary Clark73fa9722017-08-29 17:36:51 -0400909#Legend
Cary Clark682c58d2018-05-16 07:07:07 -0400910# FillType # toggled FillType ##
Cary Clark73fa9722017-08-29 17:36:51 -0400911##
912# kWinding_FillType # kInverseWinding_FillType ##
913# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
914# kInverseWinding_FillType # kWinding_FillType ##
915# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
916##
917
918#Example
919#Description
920Path drawn normally and through its inverse touches every pixel once.
921##
922#Height 100
923SkPath path;
924SkPaint paint;
925paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -0400926paint.setTextSize(80);
927paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -0400928canvas->drawPath(path, paint);
929path.toggleInverseFillType();
930paint.setColor(SK_ColorGREEN);
931canvas->drawPath(path, paint);
932##
933
934#SeeAlso FillType getFillType setFillType isInverseFillType
935
936##
937
Cary Clark8032b982017-07-28 11:04:54 -0400938#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400939
940# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400941
942#Subtopic Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500943#Line # if Path is concave or convex ##
Cary Clark73fa9722017-08-29 17:36:51 -0400944
945#Enum Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500946#Line # returns if Path is convex or concave ##
Cary Clark73fa9722017-08-29 17:36:51 -0400947
948#Code
Cary Clark884dd7d2017-10-11 10:37:52 -0400949 enum Convexity : uint8_t {
Cary Clark682c58d2018-05-16 07:07:07 -0400950 kUnknown_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400951 kConvex_Convexity,
Cary Clark682c58d2018-05-16 07:07:07 -0400952 kConcave_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400953 };
954##
955
Cary Clark682c58d2018-05-16 07:07:07 -0400956Path is convex if it contains one Contour and Contour loops no more than
957360 degrees, and Contour angles all have same Direction. Convex Path
Cary Clark8032b982017-07-28 11:04:54 -0400958may have better performance and require fewer resources on GPU_Surface.
959
Cary Clark73fa9722017-08-29 17:36:51 -0400960Path is concave when either at least one Direction change is clockwise and
961another is counterclockwise, or the sum of the changes in Direction is not 360
962degrees.
963
Cary Clark682c58d2018-05-16 07:07:07 -0400964Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
Cary Clark73fa9722017-08-29 17:36:51 -0400965if needed by destination Surface.
966
967#Const kUnknown_Convexity 0
Cary Clark682c58d2018-05-16 07:07:07 -0400968#Line # indicates Convexity has not been determined ##
Cary Clark73fa9722017-08-29 17:36:51 -0400969##
970#Const kConvex_Convexity 1
Cary Clark682c58d2018-05-16 07:07:07 -0400971#Line # one Contour made of a simple geometry without indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400972##
973#Const kConcave_Convexity 2
Cary Clark682c58d2018-05-16 07:07:07 -0400974#Line # more than one Contour, or a geometry with indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400975##
976
977#Example
978void draw(SkCanvas* canvas) {
979 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400980 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400981 const char* labels[] = { "unknown", "convex", "concave" };
982 for (SkScalar x : { 40, 100 } ) {
983 SkPath path;
984 quad[0].fX = x;
985 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
986 canvas->drawPath(path, paint);
987 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
988 canvas->translate(100, 100);
989 }
990}
991##
992
993#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
994
995#Enum Convexity ##
996
Cary Clark682c58d2018-05-16 07:07:07 -0400997#Method Convexity getConvexity() const
Cary Clark73fa9722017-08-29 17:36:51 -0400998
Cary Clarkab2621d2018-01-30 10:08:57 -0500999#In Convexity
1000#Line # returns geometry convexity, computing if necessary ##
Cary Clark682c58d2018-05-16 07:07:07 -04001001Computes Convexity if required, and returns stored value.
Cary Clark73fa9722017-08-29 17:36:51 -04001002Convexity is computed if stored value is kUnknown_Convexity,
1003or if Path has been altered since Convexity was computed or set.
1004
Cary Clarka523d2d2017-08-30 08:58:10 -04001005#Return computed or stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001006
1007#Example
1008void draw(SkCanvas* canvas) {
1009 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001010 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001011 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1012 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1013 SkPath path;
1014 debugster("initial", path);
1015 path.lineTo(50, 0);
1016 debugster("first line", path);
1017 path.lineTo(50, 50);
1018 debugster("second line", path);
1019 path.lineTo(100, 50);
1020 debugster("third line", path);
1021}
1022##
1023
1024#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
1025
1026##
1027
1028# ------------------------------------------------------------------------------
1029
Cary Clark682c58d2018-05-16 07:07:07 -04001030#Method Convexity getConvexityOrUnknown() const
Cary Clark73fa9722017-08-29 17:36:51 -04001031
Cary Clarkab2621d2018-01-30 10:08:57 -05001032#In Convexity
1033#Line # returns geometry convexity if known ##
Cary Clark682c58d2018-05-16 07:07:07 -04001034Returns last computed Convexity, or kUnknown_Convexity if
Cary Clark73fa9722017-08-29 17:36:51 -04001035Path has been altered since Convexity was computed or set.
1036
Cary Clarka523d2d2017-08-30 08:58:10 -04001037#Return stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001038
1039#Example
1040#Description
1041Convexity is unknown unless getConvexity is called without a subsequent call
1042that alters the path.
1043##
1044void draw(SkCanvas* canvas) {
1045 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001046 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001047 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
1048 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
1049 SkPath path;
1050 debugster("initial", path);
1051 path.lineTo(50, 0);
1052 debugster("first line", path);
1053 path.getConvexity();
1054 path.lineTo(50, 50);
1055 debugster("second line", path);
1056 path.lineTo(100, 50);
1057 path.getConvexity();
1058 debugster("third line", path);
1059}
1060##
1061
1062#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
1063
1064##
1065
1066# ------------------------------------------------------------------------------
1067
1068#Method void setConvexity(Convexity convexity)
1069
Cary Clarkab2621d2018-01-30 10:08:57 -05001070#In Convexity
1071#Line # sets if geometry is convex to avoid future computation ##
Cary Clark73fa9722017-08-29 17:36:51 -04001072Stores convexity so that it is later returned by getConvexity or getConvexityOrUnknown.
1073convexity may differ from getConvexity, although setting an incorrect value may
1074cause incorrect or inefficient drawing.
1075
1076If convexity is kUnknown_Convexity: getConvexity will
1077compute Convexity, and getConvexityOrUnknown will return kUnknown_Convexity.
1078
1079If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity
1080and getConvexityOrUnknown will return convexity until the path is
1081altered.
1082
1083#Param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity ##
1084
1085#Example
1086void draw(SkCanvas* canvas) {
1087 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001088 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001089 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1090 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
Cary Clark682c58d2018-05-16 07:07:07 -04001091 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001092 SkPath path;
1093 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1094 debugster("initial", path);
1095 path.setConvexity(SkPath::kConcave_Convexity);
1096 debugster("after forcing concave", path);
1097 path.setConvexity(SkPath::kUnknown_Convexity);
1098 debugster("after forcing unknown", path);
1099}
1100##
1101
1102#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
1103
1104##
1105
1106# ------------------------------------------------------------------------------
1107
Cary Clark682c58d2018-05-16 07:07:07 -04001108#Method bool isConvex() const
Cary Clark73fa9722017-08-29 17:36:51 -04001109
Cary Clarkab2621d2018-01-30 10:08:57 -05001110#In Convexity
1111#Line # returns if geometry is convex ##
Cary Clark73fa9722017-08-29 17:36:51 -04001112Computes Convexity if required, and returns true if value is kConvex_Convexity.
1113If setConvexity was called with kConvex_Convexity or kConcave_Convexity, and
1114the path has not been altered, Convexity is not recomputed.
1115
1116#Return true if Convexity stored or computed is kConvex_Convexity ##
1117
1118#Example
1119#Description
Cary Clark682c58d2018-05-16 07:07:07 -04001120Concave shape is erroneously considered convex after a forced call to
Cary Clark73fa9722017-08-29 17:36:51 -04001121setConvexity.
1122##
1123void draw(SkCanvas* canvas) {
1124 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -04001125 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -04001126 for (SkScalar x : { 40, 100 } ) {
1127 SkPath path;
1128 quad[0].fX = x;
1129 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1130 path.setConvexity(SkPath::kConvex_Convexity);
1131 canvas->drawPath(path, paint);
1132 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
1133 canvas->translate(100, 100);
1134 }
1135}
1136##
1137
1138#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
1139
1140##
1141
Cary Clark73fa9722017-08-29 17:36:51 -04001142#Subtopic Convexity ##
1143
1144# ------------------------------------------------------------------------------
1145
Mike Reed0c3137c2018-02-20 13:57:05 -05001146#Method bool isOval(SkRect* bounds) const
Cary Clark4855f782018-02-06 09:41:53 -05001147#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001148#Line # returns if describes Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04001149
Mike Reed0c3137c2018-02-20 13:57:05 -05001150Returns true if this path is recognized as an oval or circle.
Cary Clark73fa9722017-08-29 17:36:51 -04001151
Mike Reed0c3137c2018-02-20 13:57:05 -05001152bounds receives bounds of Oval.
Cary Clark73fa9722017-08-29 17:36:51 -04001153
Mike Reed0c3137c2018-02-20 13:57:05 -05001154bounds is unmodified if Oval is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001155
Mike Reed0c3137c2018-02-20 13:57:05 -05001156#Param bounds storage for bounding Rect of Oval; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001157
Mike Reed0c3137c2018-02-20 13:57:05 -05001158#Return true if Path is recognized as an oval or circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04001159
1160#Example
1161void draw(SkCanvas* canvas) {
1162 SkPaint paint;
1163 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001164 path.addOval({20, 20, 220, 220});
Cary Clark73fa9722017-08-29 17:36:51 -04001165 SkRect bounds;
Mike Reed0c3137c2018-02-20 13:57:05 -05001166 if (path.isOval(&bounds)) {
1167 paint.setColor(0xFF9FBFFF);
1168 canvas->drawRect(bounds, paint);
1169 }
Cary Clark73fa9722017-08-29 17:36:51 -04001170 paint.setColor(0x3f000000);
1171 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001172}
1173##
1174
1175#SeeAlso Oval addCircle addOval
1176
1177##
1178
1179# ------------------------------------------------------------------------------
1180
Mike Reed0c3137c2018-02-20 13:57:05 -05001181#Method bool isRRect(SkRRect* rrect) const
Cary Clark4855f782018-02-06 09:41:53 -05001182#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001183#Line # returns if describes Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001184
Mike Reed0c3137c2018-02-20 13:57:05 -05001185Returns true if this path is recognized as a SkRRect (but not an oval/circle or rect).
Cary Clark73fa9722017-08-29 17:36:51 -04001186
1187rrect receives bounds of Round_Rect.
Cary Clark73fa9722017-08-29 17:36:51 -04001188
Mike Reed0c3137c2018-02-20 13:57:05 -05001189rrect is unmodified if Round_Rect is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001190
1191#Param rrect storage for bounding Rect of Round_Rect; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001192
Cary Clarkce101242017-09-01 15:51:02 -04001193#Return true if Path contains only Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001194
1195#Example
Cary Clarkce101242017-09-01 15:51:02 -04001196#Description
Mike Reed0c3137c2018-02-20 13:57:05 -05001197Draw rounded rectangle and its bounds.
Cary Clarkce101242017-09-01 15:51:02 -04001198##
Cary Clark73fa9722017-08-29 17:36:51 -04001199void draw(SkCanvas* canvas) {
1200 SkPaint paint;
1201 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001202 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50));
Cary Clark73fa9722017-08-29 17:36:51 -04001203 SkRRect rrect;
Mike Reed0c3137c2018-02-20 13:57:05 -05001204 if (path.isRRect(&rrect)) {
1205 const SkRect& bounds = rrect.rect();
1206 paint.setColor(0xFF9FBFFF);
1207 canvas->drawRect(bounds, paint);
1208 }
Cary Clark73fa9722017-08-29 17:36:51 -04001209 paint.setColor(0x3f000000);
1210 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001211}
1212##
1213
Cary Clark682c58d2018-05-16 07:07:07 -04001214#SeeAlso Round_Rect addRoundRect addRRect
Cary Clark73fa9722017-08-29 17:36:51 -04001215
1216##
1217
1218# ------------------------------------------------------------------------------
1219
1220#Method void reset()
Cary Clark4855f782018-02-06 09:41:53 -05001221#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001222#Line # removes Verb_Array, Point_Array, and Weights; frees memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001223Sets Path to its initial state.
Cary Clark73fa9722017-08-29 17:36:51 -04001224Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1225Internal storage associated with Path is released.
1226
1227#Example
1228 SkPath path1, path2;
1229 path1.setFillType(SkPath::kInverseWinding_FillType);
1230 path1.addRect({10, 20, 30, 40});
1231 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1232 path1.reset();
1233 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1234##
1235
1236#SeeAlso rewind()
1237
1238##
1239
1240# ------------------------------------------------------------------------------
1241
1242#Method void rewind()
Cary Clark4855f782018-02-06 09:41:53 -05001243#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001244#Line # removes Verb_Array, Point_Array, and Weights, keeping memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001245Sets Path to its initial state, preserving internal storage.
Cary Clark73fa9722017-08-29 17:36:51 -04001246Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1247Internal storage associated with Path is retained.
1248
1249Use rewind() instead of reset() if Path storage will be reused and performance
Cary Clark682c58d2018-05-16 07:07:07 -04001250is critical.
Cary Clark73fa9722017-08-29 17:36:51 -04001251
1252#Example
1253#Description
1254Although path1 retains its internal storage, it is indistinguishable from
1255a newly initialized path.
1256##
1257 SkPath path1, path2;
1258 path1.setFillType(SkPath::kInverseWinding_FillType);
1259 path1.addRect({10, 20, 30, 40});
1260 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1261 path1.rewind();
1262 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1263##
1264
1265#SeeAlso reset()
1266
1267##
1268
1269# ------------------------------------------------------------------------------
1270
Cary Clark682c58d2018-05-16 07:07:07 -04001271#Method bool isEmpty() const
Cary Clark4855f782018-02-06 09:41:53 -05001272#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001273#Line # returns if verb count is zero ##
Cary Clark73fa9722017-08-29 17:36:51 -04001274Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
Cary Clark682c58d2018-05-16 07:07:07 -04001275SkPath() constructs empty Path; reset() and (rewind) make Path empty.
Cary Clark73fa9722017-08-29 17:36:51 -04001276
1277#Return true if the path contains no Verb array ##
1278
1279#Example
1280void draw(SkCanvas* canvas) {
1281 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1282 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
1283 };
1284 SkPath path;
1285 debugster("initial", path);
1286 path.moveTo(0, 0);
1287 debugster("after moveTo", path);
1288 path.rewind();
1289 debugster("after rewind", path);
1290 path.lineTo(0, 0);
1291 debugster("after lineTo", path);
1292 path.reset();
1293 debugster("after reset", path);
1294}
1295#StdOut
1296initial path is empty
1297after moveTo path is not empty
1298after rewind path is empty
1299after lineTo path is not empty
1300after reset path is empty
1301##
1302##
1303
1304#SeeAlso SkPath() reset() rewind()
1305
1306##
1307
1308# ------------------------------------------------------------------------------
1309
1310#Method bool isLastContourClosed() const
Cary Clark4855f782018-02-06 09:41:53 -05001311#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001312#Line # returns if final Contour forms a loop ##
Cary Clark73fa9722017-08-29 17:36:51 -04001313Contour is closed if Path Verb array was last modified by close(). When stroked,
Cary Clark682c58d2018-05-16 07:07:07 -04001314closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
Cary Clark73fa9722017-08-29 17:36:51 -04001315
1316#Return true if the last Contour ends with a kClose_Verb ##
1317
1318#Example
1319#Description
1320close() has no effect if Path is empty; isLastContourClosed() returns
1321false until Path has geometry followed by close().
1322##
1323void draw(SkCanvas* canvas) {
1324 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1325 SkDebugf("%s last contour is %s" "closed\n", prefix,
1326 path.isLastContourClosed() ? "" : "not ");
1327 };
1328 SkPath path;
1329 debugster("initial", path);
1330 path.close();
1331 debugster("after close", path);
1332 path.lineTo(0, 0);
1333 debugster("after lineTo", path);
1334 path.close();
1335 debugster("after close", path);
1336}
1337#StdOut
1338initial last contour is not closed
1339after close last contour is not closed
1340after lineTo last contour is not closed
1341after close last contour is closed
1342##
1343##
1344
1345#SeeAlso close()
1346
1347##
1348
1349# ------------------------------------------------------------------------------
1350
Cary Clark682c58d2018-05-16 07:07:07 -04001351#Method bool isFinite() const
Cary Clark4855f782018-02-06 09:41:53 -05001352#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001353#Line # returns if all Point values are finite ##
Cary Clark73fa9722017-08-29 17:36:51 -04001354Returns true for finite Point array values between negative SK_ScalarMax and
1355positive SK_ScalarMax. Returns false for any Point array value of
1356SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
1357
1358#Return true if all Point values are finite ##
1359
1360#Example
1361void draw(SkCanvas* canvas) {
1362 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1363 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1364 };
1365 SkPath path;
1366 debugster("initial", path);
1367 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1368 debugster("after line", path);
1369 SkMatrix matrix;
1370 matrix.setScale(2, 2);
1371 path.transform(matrix);
1372 debugster("after scale", path);
1373}
1374#StdOut
1375initial path is finite
1376after line path is finite
1377after scale path is not finite
1378##
1379##
1380
1381#SeeAlso SkScalar
1382##
1383
1384# ------------------------------------------------------------------------------
1385
Cary Clark682c58d2018-05-16 07:07:07 -04001386#Method bool isVolatile() const
Cary Clark4855f782018-02-06 09:41:53 -05001387#In Property
1388#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001389#Line # returns if Device should not cache ##
Cary Clark73fa9722017-08-29 17:36:51 -04001390Returns true if the path is volatile; it will not be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001391by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001392Surface to attach a cache of data which speeds repeated drawing. If true, Surface
1393may not speed repeated drawing.
1394
1395#Return true if caller will alter Path after drawing ##
1396
1397#Example
1398 SkPath path;
1399 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1400#StdOut
1401volatile by default is false
1402##
1403##
1404
1405#SeeAlso setIsVolatile
1406
1407##
1408
1409# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001410#Subtopic Volatile
1411#Populate
1412#Line # caching attribute ##
1413##
Cary Clark73fa9722017-08-29 17:36:51 -04001414
Cary Clark682c58d2018-05-16 07:07:07 -04001415#Method void setIsVolatile(bool isVolatile)
Cary Clark4855f782018-02-06 09:41:53 -05001416#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001417#Line # sets if Device should not cache ##
Cary Clark73fa9722017-08-29 17:36:51 -04001418Specify whether Path is volatile; whether it will be altered or discarded
Cary Clark682c58d2018-05-16 07:07:07 -04001419by the caller after it is drawn. Paths by default have volatile set false, allowing
Cary Clark73fa9722017-08-29 17:36:51 -04001420Device to attach a cache of data which speeds repeated drawing.
1421
1422Mark temporary paths, discarded or modified after use, as volatile
1423to inform Device that the path need not be cached.
1424
1425Mark animating Path volatile to improve performance.
Cary Clarkce101242017-09-01 15:51:02 -04001426Mark unchanging Path non-volatile to improve repeated rendering.
Cary Clark73fa9722017-08-29 17:36:51 -04001427
1428Raster_Surface Path draws are affected by volatile for some shadows.
1429GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
1430
1431#Param isVolatile true if caller will alter Path after drawing ##
1432
1433#Example
1434#Height 50
1435#Width 50
1436 SkPaint paint;
1437 paint.setStyle(SkPaint::kStroke_Style);
1438 SkPath path;
1439 path.setIsVolatile(true);
1440 path.lineTo(40, 40);
1441 canvas->drawPath(path, paint);
1442 path.rewind();
1443 path.moveTo(0, 40);
1444 path.lineTo(40, 0);
1445 canvas->drawPath(path, paint);
1446##
1447
1448#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1449
1450#SeeAlso isVolatile
1451
1452##
1453
1454# ------------------------------------------------------------------------------
1455
Cary Clark682c58d2018-05-16 07:07:07 -04001456#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001457#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001458#Line # returns if Line is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001459Test if Line between Point pair is degenerate.
1460Line with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001461treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001462
Cary Clarka523d2d2017-08-30 08:58:10 -04001463exact changes the equality test. If true, returns true only if p1 equals p2.
1464If false, returns true if p1 equals or nearly equals p2.
1465
Cary Clark73fa9722017-08-29 17:36:51 -04001466#Param p1 line start point ##
1467#Param p2 line end point ##
Cary Clarka523d2d2017-08-30 08:58:10 -04001468#Param exact if false, allow nearly equals ##
Cary Clark73fa9722017-08-29 17:36:51 -04001469
1470#Return true if Line is degenerate; its length is effectively zero ##
1471
1472#Example
1473#Description
Cary Clarkce101242017-09-01 15:51:02 -04001474As single precision floats, 100 and 100.000001 have the same bit representation,
1475and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001476are not exactly equal, but are nearly equal.
1477##
1478void draw(SkCanvas* canvas) {
1479 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1480 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1481 for (bool exact : { false, true } ) {
1482 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1483 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1484 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1485 ? "" : "not ", exact ? "exactly" : "nearly");
1486 }
1487 }
1488}
1489#StdOut
1490line from (100,100) to (100,100) is degenerate, nearly
1491line from (100,100) to (100,100) is degenerate, exactly
1492line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1493line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1494#StdOut ##
1495##
1496
Cary Clark682c58d2018-05-16 07:07:07 -04001497#SeeAlso IsQuadDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001498##
1499
1500# ------------------------------------------------------------------------------
1501
1502#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001503 const SkPoint& p3, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001504#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001505#Line # returns if Quad is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001506
1507Test if Quad is degenerate.
1508Quad with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001509treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001510
Cary Clarkce101242017-09-01 15:51:02 -04001511#Param p1 Quad start point ##
1512#Param p2 Quad control point ##
1513#Param p3 Quad end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001514#Param exact if true, returns true only if p1, p2, and p3 are equal;
1515 if false, returns true if p1, p2, and p3 are equal or nearly equal
Cary Clark73fa9722017-08-29 17:36:51 -04001516##
1517
1518#Return true if Quad is degenerate; its length is effectively zero ##
1519
1520#Example
1521#Description
Cary Clarkce101242017-09-01 15:51:02 -04001522As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001523but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001524the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001525##
1526void draw(SkCanvas* canvas) {
1527 auto debugster = [](const SkPath& path, bool exact) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001528 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 -04001529 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1530 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1531 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1532 "" : "not ", exact ? "exactly" : "nearly");
1533 };
1534 SkPath path, offset;
1535 path.moveTo({100, 100});
1536 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1537 offset.addPath(path, 1000, 1000);
1538 for (bool exact : { false, true } ) {
1539 debugster(path, exact);
1540 debugster(offset, exact);
1541 }
1542}
1543#StdOut
1544quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1545quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1546quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1547quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1548#StdOut ##
1549##
1550
Cary Clark682c58d2018-05-16 07:07:07 -04001551#SeeAlso IsLineDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001552##
1553
1554# ------------------------------------------------------------------------------
1555
1556#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001557 const SkPoint& p3, const SkPoint& p4, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001558#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001559#Line # returns if Cubic is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001560
1561Test if Cubic is degenerate.
1562Cubic with no length or that moves a very short distance is degenerate; it is
Cary Clark682c58d2018-05-16 07:07:07 -04001563treated as a point.
Cary Clark73fa9722017-08-29 17:36:51 -04001564
Cary Clarkce101242017-09-01 15:51:02 -04001565#Param p1 Cubic start point ##
1566#Param p2 Cubic control point 1 ##
1567#Param p3 Cubic control point 2 ##
1568#Param p4 Cubic end point ##
Cary Clark682c58d2018-05-16 07:07:07 -04001569#Param exact if true, returns true only if p1, p2, p3, and p4 are equal;
Cary Clark73fa9722017-08-29 17:36:51 -04001570 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
1571##
1572
1573#Return true if Cubic is degenerate; its length is effectively zero ##
1574
1575#Example
1576void draw(SkCanvas* canvas) {
1577 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1578 SkScalar step = 1;
1579 SkScalar prior, length, degenerate;
1580 do {
1581 prior = points[0].fX;
1582 step /= 2;
1583 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1584 degenerate = prior;
1585 points[0].fX += step;
1586 } else {
1587 length = prior;
1588 points[0].fX -= step;
1589 }
1590 } while (prior != points[0].fX);
1591 SkDebugf("%1.8g is degenerate\n", degenerate);
1592 SkDebugf("%1.8g is length\n", length);
1593}
1594#StdOut
15950.00024414062 is degenerate
15960.00024414065 is length
1597#StdOut ##
1598##
1599
1600##
1601
1602# ------------------------------------------------------------------------------
1603
1604#Method bool isLine(SkPoint line[2]) const
Cary Clark4855f782018-02-06 09:41:53 -05001605#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001606#Line # returns if describes Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04001607Returns true if Path contains only one Line;
Cary Clark682c58d2018-05-16 07:07:07 -04001608Path_Verb array has two entries: kMove_Verb, kLine_Verb.
1609If Path contains one Line and line is not nullptr, line is set to
Cary Clark73fa9722017-08-29 17:36:51 -04001610Line start point and Line end point.
1611Returns false if Path is not one Line; line is unaltered.
1612
1613#Param line storage for Line. May be nullptr ##
1614
1615#Return true if Path contains exactly one Line ##
1616
1617#Example
1618void draw(SkCanvas* canvas) {
1619 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1620 SkPoint line[2];
1621 if (path.isLine(line)) {
1622 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1623 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1624 } else {
1625 SkDebugf("%s is not line\n", prefix);
1626 }
1627 };
1628 SkPath path;
1629 debugster("empty", path);
1630 path.lineTo(0, 0);
1631 debugster("zero line", path);
1632 path.rewind();
1633 path.moveTo(10, 10);
1634 path.lineTo(20, 20);
1635 debugster("line", path);
1636 path.moveTo(20, 20);
1637 debugster("second move", path);
1638}
1639#StdOut
1640empty is not line
1641zero line is line (0,0) (0,0)
1642line is line (10,10) (20,20)
1643second move is not line
1644##
1645##
1646
1647##
1648
1649# ------------------------------------------------------------------------------
1650
Cary Clark8032b982017-07-28 11:04:54 -04001651#Subtopic Point_Array
Cary Clark08895c42018-02-01 09:37:32 -05001652#Line # end points and control points for lines and curves ##
Cary Clark61dfc3a2018-01-03 08:37:53 -05001653#Substitute SkPoint array
Cary Clark8032b982017-07-28 11:04:54 -04001654
1655Point_Array contains Points satisfying the allocated Points for
1656each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001657and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001658one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1659
1660Point_Array may be read directly from Path with getPoints, or inspected with
1661getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001662
1663#Method int getPoints(SkPoint points[], int max) const
1664
Cary Clarkab2621d2018-01-30 10:08:57 -05001665#In Point_Array
1666#Line # returns Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001667Returns number of points in Path. Up to max points are copied.
1668points may be nullptr; then, max must be zero.
Cary Clark682c58d2018-05-16 07:07:07 -04001669If max is greater than number of points, excess points storage is unaltered.
Cary Clark73fa9722017-08-29 17:36:51 -04001670
1671#Param points storage for Path Point array. May be nullptr ##
1672#Param max maximum to copy; must be greater than or equal to zero ##
1673
1674#Return Path Point array length ##
1675
1676#Example
1677void draw(SkCanvas* canvas) {
1678 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1679 int count = path.getPoints(points, max);
1680 SkDebugf("%s point count: %d ", prefix, count);
1681 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1682 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1683 }
1684 SkDebugf("\n");
1685 };
1686 SkPath path;
1687 path.lineTo(20, 20);
1688 path.lineTo(-10, -10);
1689 SkPoint points[3];
1690 debugster("no points", path, nullptr, 0);
1691 debugster("zero max", path, points, 0);
1692 debugster("too small", path, points, 2);
1693 debugster("just right", path, points, path.countPoints());
1694}
1695#StdOut
1696no points point count: 3
1697zero max point count: 3
1698too small point count: 3 (0,0) (20,20)
1699just right point count: 3 (0,0) (20,20) (-10,-10)
1700##
1701##
1702
1703#SeeAlso countPoints getPoint
1704##
1705
1706#Method int countPoints() const
1707
Cary Clarkab2621d2018-01-30 10:08:57 -05001708#In Point_Array
1709#Line # returns Point_Array length ##
Cary Clark73fa9722017-08-29 17:36:51 -04001710Returns the number of points in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001711Point count is initially zero.
Cary Clark73fa9722017-08-29 17:36:51 -04001712
1713#Return Path Point array length ##
1714
1715#Example
1716void draw(SkCanvas* canvas) {
1717 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1718 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1719 };
1720 SkPath path;
1721 debugster("empty", path);
1722 path.lineTo(0, 0);
1723 debugster("zero line", path);
1724 path.rewind();
1725 path.moveTo(10, 10);
1726 path.lineTo(20, 20);
1727 debugster("line", path);
1728 path.moveTo(20, 20);
1729 debugster("second move", path);
1730}
1731#StdOut
1732empty point count: 0
1733zero line point count: 2
1734line point count: 2
1735second move point count: 3
1736##
1737##
1738
1739#SeeAlso getPoints
1740##
1741
1742#Method SkPoint getPoint(int index) const
1743
Cary Clarkab2621d2018-01-30 10:08:57 -05001744#In Point_Array
1745#Line # returns entry from Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001746Returns Point at index in Point_Array. Valid range for index is
17470 to countPoints - 1.
Cary Clark682c58d2018-05-16 07:07:07 -04001748Returns (0, 0) if index is out of range.
Cary Clark73fa9722017-08-29 17:36:51 -04001749
1750#Param index Point array element selector ##
1751
1752#Return Point array value or (0, 0) ##
1753
1754#Example
1755void draw(SkCanvas* canvas) {
Cary Clark73fa9722017-08-29 17:36:51 -04001756 SkPath path;
1757 path.lineTo(20, 20);
1758 path.offset(-10, -10);
1759 for (int i= 0; i < path.countPoints(); ++i) {
1760 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
Cary Clark682c58d2018-05-16 07:07:07 -04001761 }
Cary Clark73fa9722017-08-29 17:36:51 -04001762}
1763#StdOut
1764point 0: (-10,-10)
1765point 1: (10,10)
1766##
1767##
1768
1769#SeeAlso countPoints getPoints
1770##
1771
1772
1773#Subtopic Point_Array ##
1774
1775# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001776#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001777#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001778
1779Verb_Array always starts with kMove_Verb.
1780If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1781the quantity of kMove_Verb equals the Contour count.
1782Verb_Array does not include or count kDone_Verb; it is a convenience
1783returned when iterating through Verb_Array.
1784
Cary Clark682c58d2018-05-16 07:07:07 -04001785Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
Cary Clark8032b982017-07-28 11:04:54 -04001786or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001787
1788#Method int countVerbs() const
1789
Cary Clarkab2621d2018-01-30 10:08:57 -05001790#In Verb_Array
1791#Line # returns Verb_Array length ##
Cary Clark682c58d2018-05-16 07:07:07 -04001792Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -04001793kCubic_Verb, and kClose_Verb; added to Path.
1794
1795#Return length of Verb_Array ##
1796
1797#Example
1798SkPath path;
1799SkDebugf("empty verb count: %d\n", path.countVerbs());
1800path.addRoundRect({10, 20, 30, 40}, 5, 5);
1801SkDebugf("round rect verb count: %d\n", path.countVerbs());
1802#StdOut
1803empty verb count: 0
1804round rect verb count: 10
1805##
1806##
1807
1808#SeeAlso getVerbs Iter RawIter
1809
1810##
1811
1812#Method int getVerbs(uint8_t verbs[], int max) const
1813
Cary Clarkab2621d2018-01-30 10:08:57 -05001814#In Verb_Array
1815#Line # returns Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001816Returns the number of verbs in the path. Up to max verbs are copied. The
1817verbs are copied as one byte per verb.
1818
1819#Param verbs storage for verbs, may be nullptr ##
1820#Param max maximum number to copy into verbs ##
1821
1822#Return the actual number of verbs in the path ##
1823
1824#Example
1825void draw(SkCanvas* canvas) {
1826 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1827 int count = path.getVerbs(verbs, max);
1828 SkDebugf("%s verb count: %d ", prefix, count);
1829 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1830 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1831 SkDebugf("%s ", verbStr[verbs[i]]);
1832 }
1833 SkDebugf("\n");
1834 };
1835 SkPath path;
1836 path.lineTo(20, 20);
1837 path.lineTo(-10, -10);
1838 uint8_t verbs[3];
1839 debugster("no verbs", path, nullptr, 0);
1840 debugster("zero max", path, verbs, 0);
1841 debugster("too small", path, verbs, 2);
1842 debugster("just right", path, verbs, path.countVerbs());
1843}
1844#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04001845no verbs verb count: 3
1846zero max verb count: 3
1847too small verb count: 3 move line
1848just right verb count: 3 move line line
Cary Clark73fa9722017-08-29 17:36:51 -04001849##
1850##
1851
1852#SeeAlso countVerbs getPoints Iter RawIter
1853##
Cary Clark8032b982017-07-28 11:04:54 -04001854
1855#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001856
1857# ------------------------------------------------------------------------------
1858
1859#Method void swap(SkPath& other)
Cary Clark4855f782018-02-06 09:41:53 -05001860#In Operator
Cary Clarkab2621d2018-01-30 10:08:57 -05001861#Line # exchanges Path pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04001862Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1863Cached state is also exchanged. swap() internally exchanges pointers, so
1864it is lightweight and does not allocate memory.
1865
1866swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001867Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001868making assignment as efficient as swap().
1869
1870#Param other Path exchanged by value ##
1871
1872#Example
1873SkPath path1, path2;
1874path1.addRect({10, 20, 30, 40});
1875path1.swap(path2);
1876const SkRect& b1 = path1.getBounds();
1877SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1878const SkRect& b2 = path2.getBounds();
1879SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1880#StdOut
1881path1 bounds = 0, 0, 0, 0
1882path2 bounds = 10, 20, 30, 40
1883#StdOut ##
1884##
1885
1886#SeeAlso operator=(const SkPath& path)
1887
1888##
1889
1890# ------------------------------------------------------------------------------
1891
Cary Clark682c58d2018-05-16 07:07:07 -04001892#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001893#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001894#Line # returns maximum and minimum of Point_Array ##
Cary Clark5538c132018-06-14 12:28:14 -04001895Returns minimum and maximum axes values of Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04001896Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1897be larger or smaller than area affected when Path is drawn.
1898
1899Rect returned includes all Points added to Path, including Points associated with
1900kMove_Verb that define empty Contours.
1901
1902#Return bounds of all Points in Point_Array ##
1903
1904#Example
1905#Description
1906Bounds of upright Circle can be predicted from center and radius.
1907Bounds of rotated Circle includes control Points outside of filled area.
1908##
1909 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1910 const SkRect& bounds = path.getBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001911 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001912 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1913 };
1914 SkPath path;
1915 debugster("empty", path);
1916 path.addCircle(50, 45, 25);
1917 debugster("circle", path);
1918 SkMatrix matrix;
1919 matrix.setRotate(45, 50, 45);
1920 path.transform(matrix);
1921 debugster("rotated circle", path);
1922#StdOut
1923empty bounds = 0, 0, 0, 0
1924circle bounds = 25, 20, 75, 70
1925rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1926##
1927##
1928
1929#SeeAlso computeTightBounds updateBoundsCache
1930
1931##
1932
1933# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001934#Subtopic Utility
1935#Populate
1936#Line # rarely called management functions ##
1937##
Cary Clark73fa9722017-08-29 17:36:51 -04001938
Cary Clark682c58d2018-05-16 07:07:07 -04001939#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001940#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001941#Line # refreshes result of getBounds ##
Cary Clark73fa9722017-08-29 17:36:51 -04001942Update internal bounds so that subsequent calls to getBounds are instantaneous.
1943Unaltered copies of Path may also access cached bounds through getBounds.
1944
1945For now, identical to calling getBounds and ignoring the returned value.
1946
Cary Clark682c58d2018-05-16 07:07:07 -04001947Call to prepare Path subsequently drawn from multiple threads,
Cary Clark73fa9722017-08-29 17:36:51 -04001948to avoid a race condition where each draw separately computes the bounds.
1949
1950#Example
1951 double times[2] = { 0, 0 };
1952 for (int i = 0; i < 10000; ++i) {
1953 SkPath path;
1954 for (int j = 1; j < 100; ++ j) {
1955 path.addCircle(50 + j, 45 + j, 25 + j);
1956 }
1957 if (1 & i) {
1958 path.updateBoundsCache();
1959 }
1960 double start = SkTime::GetNSecs();
1961 (void) path.getBounds();
1962 times[1 & i] += SkTime::GetNSecs() - start;
1963 }
1964 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1965 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1966#StdOut
1967#Volatile
1968uncached avg: 0.18048 ms
1969cached avg: 0.182784 ms
1970##
1971##
1972
1973#SeeAlso getBounds
1974#ToDo the results don't make sense, need to profile to figure this out ##
1975
1976##
1977
1978# ------------------------------------------------------------------------------
1979
1980#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001981#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001982#Line # returns extent of geometry ##
Cary Clark5538c132018-06-14 12:28:14 -04001983Returns minimum and maximum axes values of the lines and curves in Path.
Cary Clark682c58d2018-05-16 07:07:07 -04001984Returns (0, 0, 0, 0) if Path contains no points.
1985Returned bounds width and height may be larger or smaller than area affected
Cary Clark73fa9722017-08-29 17:36:51 -04001986when Path is drawn.
1987
1988Includes Points associated with kMove_Verb that define empty
1989Contours.
1990
1991Behaves identically to getBounds when Path contains
1992only lines. If Path contains curves, computed bounds includes
1993the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
1994and unlike getBounds, does not cache the result.
1995
1996#Return tight bounds of curves in Path ##
1997
1998#Example
1999 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2000 const SkRect& bounds = path.computeTightBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04002001 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04002002 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2003 };
2004 SkPath path;
2005 debugster("empty", path);
2006 path.addCircle(50, 45, 25);
2007 debugster("circle", path);
2008 SkMatrix matrix;
2009 matrix.setRotate(45, 50, 45);
2010 path.transform(matrix);
2011 debugster("rotated circle", path);
2012#StdOut
2013empty bounds = 0, 0, 0, 0
2014circle bounds = 25, 20, 75, 70
2015rotated circle bounds = 25, 20, 75, 70
2016##
2017##
2018
2019#SeeAlso getBounds
2020
2021##
2022
2023# ------------------------------------------------------------------------------
2024
2025#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05002026#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002027#Line # returns true if Rect may be inside ##
Cary Clark682c58d2018-05-16 07:07:07 -04002028Returns true if rect is contained by Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002029May return false when rect is contained by Path.
2030
2031For now, only returns true if Path has one Contour and is convex.
2032rect may share points and edges with Path and be contained.
2033Returns true if rect is empty, that is, it has zero width or height; and
2034the Point or Line described by rect is contained by Path.
2035
2036#Param rect Rect, Line, or Point checked for containment ##
2037
2038#Return true if rect is contained ##
2039
2040#Example
2041#Height 140
2042#Description
2043Rect is drawn in blue if it is contained by red Path.
2044##
2045void draw(SkCanvas* canvas) {
2046 SkPath path;
2047 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2048 SkRect tests[] = {
2049 { 10, 40, 54, 80 },
2050 { 25, 20, 39, 120 },
2051 { 15, 25, 49, 115 },
2052 { 13, 27, 51, 113 },
2053 };
2054 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2055 SkPaint paint;
2056 paint.setColor(SK_ColorRED);
2057 canvas->drawPath(path, paint);
2058 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2059 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2060 canvas->drawRect(tests[i], paint);
2061 canvas->translate(64, 0);
2062 }
2063}
2064##
2065
2066#SeeAlso contains Op Rect Convexity
2067
2068##
2069
2070# ------------------------------------------------------------------------------
2071
2072#Method void incReserve(unsigned extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05002073#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002074#Line # reserves space for additional data ##
Cary Clark73fa9722017-08-29 17:36:51 -04002075grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
2076May improve performance and use less memory by
2077reducing the number and size of allocations when creating Path.
2078
Cary Clarkce101242017-09-01 15:51:02 -04002079#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002080
2081#Example
2082#Height 192
2083void draw(SkCanvas* canvas) {
2084 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2085 path->moveTo(size, 0);
2086 for (int i = 1; i < sides; i++) {
2087 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2088 path->lineTo(c * size, s * size);
2089 }
2090 path->close();
2091 };
2092 SkPath path;
2093 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2094 for (int sides = 3; sides < 10; ++sides) {
2095 addPoly(sides, sides, &path);
2096 }
2097 SkMatrix matrix;
2098 matrix.setScale(10, 10, -10, -10);
2099 path.transform(matrix);
2100 SkPaint paint;
2101 paint.setStyle(SkPaint::kStroke_Style);
2102 canvas->drawPath(path, paint);
2103}
2104##
2105
2106#SeeAlso Point_Array
2107
2108##
2109
2110# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05002111#Subtopic Build
2112#Populate
2113#Line # adds points and verbs to path ##
2114##
Cary Clark73fa9722017-08-29 17:36:51 -04002115
2116#Method void moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002117#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002118#Line # starts Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -04002119Adds beginning of Contour at Point (x, y).
2120
Cary Clark5538c132018-06-14 12:28:14 -04002121#Param x x-axis value of Contour start ##
2122#Param y y-axis value of Contour start ##
Cary Clark73fa9722017-08-29 17:36:51 -04002123
2124#Example
2125 #Width 140
2126 #Height 100
2127 void draw(SkCanvas* canvas) {
2128 SkRect rect = { 20, 20, 120, 80 };
2129 SkPath path;
2130 path.addRect(rect);
2131 path.moveTo(rect.fLeft, rect.fTop);
2132 path.lineTo(rect.fRight, rect.fBottom);
2133 path.moveTo(rect.fLeft, rect.fBottom);
2134 path.lineTo(rect.fRight, rect.fTop);
2135 SkPaint paint;
2136 paint.setStyle(SkPaint::kStroke_Style);
2137 canvas->drawPath(path, paint);
2138 }
2139##
2140
2141#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2142
2143##
2144
Cary Clark682c58d2018-05-16 07:07:07 -04002145#Method void moveTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002146
2147Adds beginning of Contour at Point p.
2148
2149#Param p contour start ##
2150
2151#Example
2152 #Width 128
2153 #Height 128
2154void draw(SkCanvas* canvas) {
Cary Clark682c58d2018-05-16 07:07:07 -04002155 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
Cary Clark73fa9722017-08-29 17:36:51 -04002156 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2157 SkPath path;
2158 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2159 path.moveTo(data[i][0]);
2160 path.lineTo(data[i][1]);
2161 path.lineTo(data[i][2]);
2162 }
2163 SkPaint paint;
2164 paint.setStyle(SkPaint::kStroke_Style);
2165 canvas->drawPath(path, paint);
2166}
2167##
2168
2169#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2170
2171##
2172
2173#Method void rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002174#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002175#Line # starts Contour relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002176Adds beginning of Contour relative to Last_Point.
2177If Path is empty, starts Contour at (dx, dy).
Cary Clark682c58d2018-05-16 07:07:07 -04002178Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002179Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002180
Cary Clark5538c132018-06-14 12:28:14 -04002181#Param dx offset from Last_Point to Contour start on x-axis ##
2182#Param dy offset from Last_Point to Contour start on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002183
2184#Example
2185 #Height 100
2186 SkPath path;
2187 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2188 path.rMoveTo(25, 2);
2189 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2190 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2191 path.rLineTo(arrow[i].fX, arrow[i].fY);
2192 }
2193 SkPaint paint;
2194 canvas->drawPath(path, paint);
2195 SkPoint lastPt;
2196 path.getLastPt(&lastPt);
2197 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2198##
2199
2200#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2201
2202##
2203
2204# ------------------------------------------------------------------------------
2205
2206#Method void lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002207#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002208#Line # appends Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04002209Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2210kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2211
2212lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2213lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
Cary Clark682c58d2018-05-16 07:07:07 -04002214
Cary Clark73fa9722017-08-29 17:36:51 -04002215#Param x end of added Line in x ##
2216#Param y end of added Line in y ##
2217
2218#Example
2219#Height 100
2220###$
2221void draw(SkCanvas* canvas) {
2222 SkPaint paint;
2223 paint.setAntiAlias(true);
2224 paint.setTextSize(72);
2225 canvas->drawString("#", 120, 80, paint);
2226 paint.setStyle(SkPaint::kStroke_Style);
2227 paint.setStrokeWidth(5);
2228 SkPath path;
2229 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2230 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2231 unsigned o = 0;
2232 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2233 for (unsigned j = 0; j < 2; o++, j++) {
2234 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2235 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2236 }
2237 }
2238 canvas->drawPath(path, paint);
2239}
2240$$$#
2241##
2242
2243#SeeAlso Contour moveTo rLineTo addRect
2244
2245##
2246
2247# ------------------------------------------------------------------------------
2248
Cary Clark682c58d2018-05-16 07:07:07 -04002249#Method void lineTo(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04002250
2251Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2252kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2253
2254lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2255lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2256
2257#Param p end Point of added Line ##
2258
2259#Example
2260#Height 100
2261 SkPath path;
2262 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2263 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2264 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2265 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2266 path.moveTo(oxo[i]);
2267 path.lineTo(oxo[i + 1]);
2268 }
2269 SkPaint paint;
2270 paint.setStyle(SkPaint::kStroke_Style);
2271 canvas->drawPath(path, paint);
2272##
2273
2274#SeeAlso Contour moveTo rLineTo addRect
2275
2276##
2277
2278# ------------------------------------------------------------------------------
2279
2280#Method void rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002281#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002282#Line # appends Line relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002283Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2284kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2285
2286Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2287then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2288Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002289Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002290
Cary Clark5538c132018-06-14 12:28:14 -04002291#Param dx offset from Last_Point to Line end on x-axis ##
2292#Param dy offset from Last_Point to Line end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002293
2294#Example
2295#Height 128
2296void draw(SkCanvas* canvas) {
2297 SkPaint paint;
2298 paint.setAntiAlias(true);
2299 paint.setStyle(SkPaint::kStroke_Style);
2300 SkPath path;
2301 path.moveTo(10, 98);
2302 SkScalar x = 0, y = 0;
2303 for (int i = 10; i < 100; i += 5) {
2304 x += i * ((i & 2) - 1);
2305 y += i * (((i + 1) & 2) - 1);
2306 path.rLineTo(x, y);
Cary Clark682c58d2018-05-16 07:07:07 -04002307
Cary Clark73fa9722017-08-29 17:36:51 -04002308 }
2309 canvas->drawPath(path, paint);
2310}
2311##
2312
2313#SeeAlso Contour moveTo lineTo addRect
2314
2315##
2316
2317# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002318#Subtopic Quad
Cary Clark137b8742018-05-30 09:21:49 -04002319#Alias Quad ##
2320#Alias Quads ##
2321#Alias Quadratic_Bezier ##
2322#Alias Quadratic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002323#Line # curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002324
2325Quad describes a quadratic Bezier, a second-order curve identical to a section
2326of a parabola. Quad begins at a start Point, curves towards a control Point,
2327and then curves to an end Point.
2328
2329#Example
2330#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002331void draw(SkCanvas* canvas) {
2332 SkPaint paint;
2333 paint.setAntiAlias(true);
2334 paint.setStyle(SkPaint::kStroke_Style);
2335 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2336 canvas->drawLine(quadPts[0], quadPts[1], paint);
2337 canvas->drawLine(quadPts[1], quadPts[2], paint);
2338 SkPath path;
2339 path.moveTo(quadPts[0]);
2340 path.quadTo(quadPts[1], quadPts[2]);
2341 paint.setStrokeWidth(3);
2342 canvas->drawPath(path, paint);
2343}
Cary Clark8032b982017-07-28 11:04:54 -04002344##
2345
2346Quad is a special case of Conic where Conic_Weight is set to one.
2347
2348Quad is always contained by the triangle connecting its three Points. Quad
2349begins tangent to the line between start Point and control Point, and ends
2350tangent to the line between control Point and end Point.
2351
2352#Example
2353#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002354void draw(SkCanvas* canvas) {
2355 SkPaint paint;
2356 paint.setAntiAlias(true);
2357 paint.setStyle(SkPaint::kStroke_Style);
2358 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2359 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2360 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2361 paint.setColor(0x7fffffff & colors[i]);
2362 paint.setStrokeWidth(1);
2363 canvas->drawLine(quadPts[0], quadPts[1], paint);
2364 canvas->drawLine(quadPts[1], quadPts[2], paint);
2365 SkPath path;
2366 path.moveTo(quadPts[0]);
2367 path.quadTo(quadPts[1], quadPts[2]);
2368 paint.setStrokeWidth(3);
2369 paint.setColor(colors[i]);
2370 canvas->drawPath(path, paint);
2371 quadPts[1].fY += 30;
2372 }
Cary Clark8032b982017-07-28 11:04:54 -04002373}
2374##
Cary Clark73fa9722017-08-29 17:36:51 -04002375
2376#Method void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
2377
Cary Clarkab2621d2018-01-30 10:08:57 -05002378#In Quad
2379#Line # appends Quad ##
Cary Clark682c58d2018-05-16 07:07:07 -04002380 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
Cary Clark73fa9722017-08-29 17:36:51 -04002381 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2382 before adding Quad.
2383
2384 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2385 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2386 to Point_Array.
2387
2388 #Param x1 control Point of Quad in x ##
2389 #Param y1 control Point of Quad in y ##
2390 #Param x2 end Point of Quad in x ##
2391 #Param y2 end Point of Quad in y ##
2392
2393 #Example
2394 void draw(SkCanvas* canvas) {
2395 SkPaint paint;
2396 paint.setAntiAlias(true);
2397 paint.setStyle(SkPaint::kStroke_Style);
2398 SkPath path;
2399 path.moveTo(0, -10);
2400 for (int i = 0; i < 128; i += 16) {
2401 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2402 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2403 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2404 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2405 }
2406 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002407 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002408 }
2409 ##
2410
2411 #SeeAlso Contour moveTo conicTo rQuadTo
2412
2413##
2414
Cary Clark682c58d2018-05-16 07:07:07 -04002415#Method void quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05002416#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002417#In Quad
Cary Clark682c58d2018-05-16 07:07:07 -04002418 Adds Quad from Last_Point towards Point p1, to Point p2.
Cary Clark73fa9722017-08-29 17:36:51 -04002419 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2420 before adding Quad.
2421
2422 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2423 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2424 to Point_Array.
2425
2426 #Param p1 control Point of added Quad ##
2427 #Param p2 end Point of added Quad ##
2428
2429 #Example
2430 void draw(SkCanvas* canvas) {
2431 SkPaint paint;
2432 paint.setStyle(SkPaint::kStroke_Style);
2433 paint.setAntiAlias(true);
2434 SkPath path;
2435 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2436 path.moveTo(pts[1]);
2437 for (int i = 0; i < 3; ++i) {
2438 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2439 }
2440 canvas->drawPath(path, paint);
2441 }
2442 ##
2443
2444 #SeeAlso Contour moveTo conicTo rQuadTo
2445
2446##
2447
2448#Method void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05002449#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002450#In Quad
2451#Line # appends Quad relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002452 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2453 If Path is empty, or last Verb
2454 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2455
2456 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2457 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2458 control and Quad end to Point_Array.
2459 Quad control is Last_Point plus Vector (dx1, dy1).
2460 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002461 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002462
Cary Clark5538c132018-06-14 12:28:14 -04002463 #Param dx1 offset from Last_Point to Quad control on x-axis ##
2464 #Param dy1 offset from Last_Point to Quad control on y-axis ##
2465 #Param dx2 offset from Last_Point to Quad end on x-axis ##
2466 #Param dy2 offset from Last_Point to Quad end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002467
2468 #Example
2469 void draw(SkCanvas* canvas) {
2470 SkPaint paint;
2471 paint.setAntiAlias(true);
2472 SkPath path;
2473 path.moveTo(128, 20);
2474 path.rQuadTo(-6, 10, -7, 10);
2475 for (int i = 1; i < 32; i += 4) {
2476 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2477 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2478 }
2479 path.quadTo(92, 220, 128, 215);
2480 canvas->drawPath(path, paint);
2481 }
2482 ##
2483
2484 #SeeAlso Contour moveTo conicTo quadTo
2485
2486##
2487
Cary Clark78de7512018-02-07 07:27:09 -05002488#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002489
2490# ------------------------------------------------------------------------------
2491
Cary Clark78de7512018-02-07 07:27:09 -05002492#Subtopic Conic
Cary Clark08895c42018-02-01 09:37:32 -05002493#Line # conic section defined by three points and a weight ##
Cary Clark137b8742018-05-30 09:21:49 -04002494#Alias Conics ##
Cary Clark8032b982017-07-28 11:04:54 -04002495
2496Conic describes a conical section: a piece of an ellipse, or a piece of a
Cary Clark682c58d2018-05-16 07:07:07 -04002497parabola, or a piece of a hyperbola. Conic begins at a start Point,
Cary Clark8032b982017-07-28 11:04:54 -04002498curves towards a control Point, and then curves to an end Point. The influence
2499of the control Point is determined by Conic_Weight.
2500
Cary Clark73fa9722017-08-29 17:36:51 -04002501Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2502may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002503
2504#Subtopic Weight
Cary Clark137b8742018-05-30 09:21:49 -04002505#Alias Conic_Weights ##
2506#Alias Weights ##
Cary Clark08895c42018-02-01 09:37:32 -05002507#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002508
2509Weight determines both the strength of the control Point and the type of Conic.
Cary Clark682c58d2018-05-16 07:07:07 -04002510Weight varies from zero to infinity. At zero, Weight causes the control Point to
2511have no effect; Conic is identical to a line segment from start Point to end
2512point. If Weight is less than one, Conic follows an elliptical arc.
2513If Weight is exactly one, then Conic is identical to Quad; Conic follows a
2514parabolic arc. If Weight is greater than one, Conic follows a hyperbolic
Cary Clark137b8742018-05-30 09:21:49 -04002515arc. If Weight is infinity, Conic is identical to two line segments, connecting
Cary Clark682c58d2018-05-16 07:07:07 -04002516start Point to control Point, and control Point to end Point.
Cary Clark8032b982017-07-28 11:04:54 -04002517
2518#Example
2519#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002520When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002521##
Cary Clark73fa9722017-08-29 17:36:51 -04002522void draw(SkCanvas* canvas) {
2523 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2524 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2525 SkPath path;
2526 path.conicTo(20, 30, 50, 60, 1);
2527 SkPath::Iter iter(path, false);
2528 SkPath::Verb verb;
2529 do {
2530 SkPoint points[4];
2531 verb = iter.next(points);
2532 SkDebugf("%s ", verbNames[(int) verb]);
2533 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2534 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2535 }
2536 if (SkPath::kConic_Verb == verb) {
2537 SkDebugf("weight = %g", iter.conicWeight());
2538 }
2539 SkDebugf("\n");
2540 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002541}
2542#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002543move {0, 0},
2544quad {0, 0}, {20, 30}, {50, 60},
2545done
Cary Clark8032b982017-07-28 11:04:54 -04002546##
2547##
2548
2549If weight is less than one, Conic is an elliptical segment.
2550
Cary Clark682c58d2018-05-16 07:07:07 -04002551#Example
Cary Clark8032b982017-07-28 11:04:54 -04002552#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002553A 90 degree circular arc has the weight
Cary Clark8032b982017-07-28 11:04:54 -04002554#Formula
25551 / sqrt(2)
2556##
Cary Clark6fc50412017-09-21 12:31:06 -04002557.
Cary Clark8032b982017-07-28 11:04:54 -04002558##
Cary Clark73fa9722017-08-29 17:36:51 -04002559void draw(SkCanvas* canvas) {
2560 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2561 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2562 SkPath path;
2563 path.arcTo(20, 0, 20, 20, 20);
2564 SkPath::Iter iter(path, false);
2565 SkPath::Verb verb;
2566 do {
2567 SkPoint points[4];
2568 verb = iter.next(points);
2569 SkDebugf("%s ", verbNames[(int) verb]);
2570 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2571 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2572 }
2573 if (SkPath::kConic_Verb == verb) {
2574 SkDebugf("weight = %g", iter.conicWeight());
2575 }
2576 SkDebugf("\n");
2577 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002578}
2579#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002580move {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04002581conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark682c58d2018-05-16 07:07:07 -04002582done
Cary Clark8032b982017-07-28 11:04:54 -04002583##
2584##
2585
Cary Clarkce101242017-09-01 15:51:02 -04002586If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002587a hyperbolic segment can be approximated by straight lines connecting the
2588control Point with the end Points.
2589
2590#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002591void draw(SkCanvas* canvas) {
2592 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2593 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2594 SkPath path;
2595 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2596 SkPath::Iter iter(path, false);
2597 SkPath::Verb verb;
2598 do {
2599 SkPoint points[4];
2600 verb = iter.next(points);
2601 SkDebugf("%s ", verbNames[(int) verb]);
2602 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2603 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2604 }
2605 if (SkPath::kConic_Verb == verb) {
2606 SkDebugf("weight = %g", iter.conicWeight());
2607 }
2608 SkDebugf("\n");
2609 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002610}
2611#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002612move {0, 0},
2613line {0, 0}, {20, 0},
2614line {20, 0}, {20, 20},
2615done
Cary Clark8032b982017-07-28 11:04:54 -04002616##
2617##
2618
2619#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002620
2621#Method void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2622 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002623#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002624#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002625#Line # appends Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002626
Cary Clark682c58d2018-05-16 07:07:07 -04002627 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002628 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2629 before adding Conic.
2630
2631 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2632
2633 If w is finite and not one, appends kConic_Verb to Verb_Array;
2634 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2635
2636 If w is one, appends kQuad_Verb to Verb_Array, and
2637 (x1, y1), (x2, y2) to Point_Array.
2638
2639 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2640 (x1, y1), (x2, y2) to Point_Array.
2641
2642 #Param x1 control Point of Conic in x ##
2643 #Param y1 control Point of Conic in y ##
2644 #Param x2 end Point of Conic in x ##
2645 #Param y2 end Point of Conic in y ##
2646 #Param w weight of added Conic ##
2647
2648 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002649 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002650 #Description
Cary Clark682c58d2018-05-16 07:07:07 -04002651 As weight increases, curve is pulled towards control point.
Cary Clark73fa9722017-08-29 17:36:51 -04002652 The bottom two curves are elliptical; the next is parabolic; the
2653 top curve is hyperbolic.
2654 ##
2655void draw(SkCanvas* canvas) {
2656 SkPaint paint;
2657 paint.setAntiAlias(true);
2658 paint.setStyle(SkPaint::kStroke_Style);
2659 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2660 canvas->drawLine(conicPts[0], conicPts[1], paint);
2661 canvas->drawLine(conicPts[1], conicPts[2], paint);
2662 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2663 paint.setStrokeWidth(3);
2664 SkScalar weight = 0.5f;
2665 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2666 SkPath path;
2667 path.moveTo(conicPts[0]);
2668 path.conicTo(conicPts[1], conicPts[2], weight);
2669 paint.setColor(colors[i]);
2670 canvas->drawPath(path, paint);
2671 weight += 0.25f;
2672 }
2673}
2674 ##
2675
2676 #SeeAlso rConicTo arcTo addArc quadTo
2677
2678##
2679
Cary Clark682c58d2018-05-16 07:07:07 -04002680#Method void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002681#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002682#In Conic
Cary Clark682c58d2018-05-16 07:07:07 -04002683 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
Cary Clark73fa9722017-08-29 17:36:51 -04002684 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2685 before adding Conic.
2686
2687 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2688
2689 If w is finite and not one, appends kConic_Verb to Verb_Array;
2690 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2691
2692 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2693 to Point_Array.
2694
2695 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2696 Points p1, p2 to Point_Array.
2697
2698 #Param p1 control Point of added Conic ##
2699 #Param p2 end Point of added Conic ##
2700 #Param w weight of added Conic ##
2701
2702 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002703 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002704 #Description
2705 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002706 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002707 ##
2708void draw(SkCanvas* canvas) {
2709 SkPaint paint;
2710 paint.setAntiAlias(true);
2711 paint.setStyle(SkPaint::kStroke_Style);
2712 SkRect oval = {0, 20, 120, 140};
2713 SkPath path;
2714 for (int i = 0; i < 4; ++i) {
2715 path.moveTo(oval.centerX(), oval.fTop);
2716 path.arcTo(oval, -90, 90 - 20 * i, false);
2717 oval.inset(15, 15);
2718 }
2719 path.offset(100, 0);
2720 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2721 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2722 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2723 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2724 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2725 for (int i = 0; i < 4; ++i) {
2726 path.moveTo(conicPts[i][0]);
2727 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2728 }
2729 canvas->drawPath(path, paint);
2730}
2731 ##
2732
2733 #SeeAlso rConicTo arcTo addArc quadTo
2734
2735##
2736
2737#Method void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2738 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002739#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002740#In Conic
2741#Line # appends Conic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002742
2743 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2744 weighted by w. If Path is empty, or last Verb
2745 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2746
2747 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
Cary Clark682c58d2018-05-16 07:07:07 -04002748 if needed.
2749
Cary Clark73fa9722017-08-29 17:36:51 -04002750 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2751 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2752 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2753 twice to Verb_Array.
2754
2755 In all cases appends Points control and end to Point_Array.
2756 control is Last_Point plus Vector (dx1, dy1).
2757 end is Last_Point plus Vector (dx2, dy2).
2758
Cary Clarkce101242017-09-01 15:51:02 -04002759 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002760
Cary Clark5538c132018-06-14 12:28:14 -04002761 #Param dx1 offset from Last_Point to Conic control on x-axis ##
2762 #Param dy1 offset from Last_Point to Conic control on y-axis ##
2763 #Param dx2 offset from Last_Point to Conic end on x-axis ##
2764 #Param dy2 offset from Last_Point to Conic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002765 #Param w weight of added Conic ##
2766
2767 #Example
2768 #Height 140
2769 void draw(SkCanvas* canvas) {
2770 SkPaint paint;
2771 paint.setAntiAlias(true);
2772 paint.setStyle(SkPaint::kStroke_Style);
2773 SkPath path;
2774 path.moveTo(20, 80);
2775 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2776 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2777 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2778 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2779 canvas->drawPath(path, paint);
2780 }
2781 ##
2782
2783 #SeeAlso conicTo arcTo addArc quadTo
2784
2785##
2786
Cary Clark78de7512018-02-07 07:27:09 -05002787#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002788
2789# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002790#Subtopic Cubic
Cary Clark137b8742018-05-30 09:21:49 -04002791#Alias Cubic ##
2792#Alias Cubics ##
2793#Alias Cubic_Bezier ##
2794#Alias Cubic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002795#Line # curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002796
Cary Clark682c58d2018-05-16 07:07:07 -04002797Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002798Cubic begins at a start Point, curving towards the first control Point;
2799and curves from the end Point towards the second control Point.
2800
2801#Example
2802#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002803void draw(SkCanvas* canvas) {
2804 SkPaint paint;
2805 paint.setAntiAlias(true);
2806 paint.setStyle(SkPaint::kStroke_Style);
2807 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2808 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2809 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2810 paint.setColor(0x7fffffff & colors[i]);
2811 paint.setStrokeWidth(1);
2812 for (unsigned j = 0; j < 3; ++j) {
2813 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2814 }
2815 SkPath path;
2816 path.moveTo(cubicPts[0]);
2817 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2818 paint.setStrokeWidth(3);
2819 paint.setColor(colors[i]);
2820 canvas->drawPath(path, paint);
2821 cubicPts[1].fY += 30;
2822 cubicPts[2].fX += 30;
2823 }
Cary Clark8032b982017-07-28 11:04:54 -04002824}
2825##
Cary Clark73fa9722017-08-29 17:36:51 -04002826
2827#Method void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2828 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002829#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002830#In Cubic
2831#Line # appends Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002832
2833Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2834(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2835(0, 0) before adding Cubic.
2836
2837Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2838then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
2839to Point_Array.
2840
2841#Param x1 first control Point of Cubic in x ##
2842#Param y1 first control Point of Cubic in y ##
2843#Param x2 second control Point of Cubic in x ##
2844#Param y2 second control Point of Cubic in y ##
2845#Param x3 end Point of Cubic in x ##
2846#Param y3 end Point of Cubic in y ##
2847
2848#Example
2849void draw(SkCanvas* canvas) {
2850 SkPaint paint;
2851 paint.setAntiAlias(true);
2852 paint.setStyle(SkPaint::kStroke_Style);
2853 SkPath path;
2854 path.moveTo(0, -10);
2855 for (int i = 0; i < 128; i += 16) {
2856 SkScalar c = i * 0.5f;
2857 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2858 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2859 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2860 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2861 }
2862 path.offset(128, 128);
2863 canvas->drawPath(path, paint);
2864}
2865##
2866
2867#SeeAlso Contour moveTo rCubicTo quadTo
2868
2869##
2870
2871# ------------------------------------------------------------------------------
2872
Cary Clark682c58d2018-05-16 07:07:07 -04002873#Method void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
Cary Clark73fa9722017-08-29 17:36:51 -04002874
Cary Clark4855f782018-02-06 09:41:53 -05002875#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002876#In Cubic
Cary Clark73fa9722017-08-29 17:36:51 -04002877Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2878Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2879(0, 0) before adding Cubic.
2880
2881Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2882then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2883to Point_Array.
2884
2885#Param p1 first control Point of Cubic ##
2886#Param p2 second control Point of Cubic ##
2887#Param p3 end Point of Cubic ##
2888
2889#Example
2890#Height 84
2891 SkPaint paint;
2892 paint.setAntiAlias(true);
2893 paint.setStyle(SkPaint::kStroke_Style);
2894 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2895 SkPath path;
2896 path.moveTo(pts[0]);
2897 path.cubicTo(pts[1], pts[2], pts[3]);
2898 canvas->drawPath(path, paint);
2899##
2900
2901#SeeAlso Contour moveTo rCubicTo quadTo
2902
2903##
2904
2905# ------------------------------------------------------------------------------
2906
2907#Method void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2908 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002909#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002910#In Cubic
2911#Line # appends Cubic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002912
2913 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2914 Vector (dx2, dy2), to Vector (dx3, dy3).
2915 If Path is empty, or last Verb
2916 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2917
2918 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2919 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2920 control and Cubic end to Point_Array.
2921 Cubic control is Last_Point plus Vector (dx1, dy1).
2922 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002923 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002924
Cary Clark5538c132018-06-14 12:28:14 -04002925 #Param x1 offset from Last_Point to first Cubic control on x-axis ##
2926 #Param y1 offset from Last_Point to first Cubic control on y-axis ##
2927 #Param x2 offset from Last_Point to second Cubic control on x-axis ##
2928 #Param y2 offset from Last_Point to second Cubic control on y-axis ##
2929 #Param x3 offset from Last_Point to Cubic end on x-axis ##
2930 #Param y3 offset from Last_Point to Cubic end on y-axis ##
Cary Clark73fa9722017-08-29 17:36:51 -04002931
2932#Example
2933 void draw(SkCanvas* canvas) {
2934 SkPaint paint;
2935 paint.setAntiAlias(true);
2936 paint.setStyle(SkPaint::kStroke_Style);
2937 SkPath path;
2938 path.moveTo(24, 108);
2939 for (int i = 0; i < 16; i++) {
2940 SkScalar sx, sy;
2941 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2942 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2943 }
2944 canvas->drawPath(path, paint);
2945 }
2946##
2947
2948#SeeAlso Contour moveTo cubicTo quadTo
2949
2950##
2951
Cary Clark78de7512018-02-07 07:27:09 -05002952#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002953
2954# ------------------------------------------------------------------------------
2955
Cary Clark08895c42018-02-01 09:37:32 -05002956#Subtopic Arc
2957#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04002958Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
2959by start point and end point, and by radius and tangent lines. Each construction has advantages,
2960and some constructions correspond to Arc drawing in graphics standards.
2961
2962All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
2963Conic describes an Arc of some Oval or Circle.
2964
2965arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
2966describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
Cary Clark682c58d2018-05-16 07:07:07 -04002967which may continue Contour or start a new one. This construction is similar to PostScript and
Cary Clark73fa9722017-08-29 17:36:51 -04002968HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
2969requiring Path.
2970
2971arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
2972describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
2973where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
2974HTML_Canvas arcs.
2975
2976arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04002977 SkScalar x, SkScalar y)
Cary Clark73fa9722017-08-29 17:36:51 -04002978describes Arc as part of Oval with radii (rx, ry), beginning at
2979last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
2980so additional values choose a single solution. This construction is similar to SVG arcs.
2981
2982conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
2983conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
Cary Clark682c58d2018-05-16 07:07:07 -04002984constructions are converted to Conic data when added to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002985
2986#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
2987 do the kind of table shown in the illustration.
2988 example is spaced correctly on fiddle but spacing is too wide on pc
2989##
2990
2991#Example
2992#Height 300
2993#Width 600
2994#Description
2995#List
2996# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
2997# <sup>2</sup> parameter sets force MoveTo ##
Cary Clark5081eed2018-01-22 07:55:48 -05002998# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04002999# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
3000# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3001 Direction sweep, SkScalar x, SkScalar y) ##
3002#List ##
3003#Description ##
3004#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003005###$
Cary Clark73fa9722017-08-29 17:36:51 -04003006struct data {
3007 const char* name;
3008 char super;
3009 int yn[10];
3010};
3011
3012const data dataSet[] = {
3013{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
3014{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
3015{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
3016{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
3017{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
3018{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
3019};
3020
3021#define __degree_symbol__ "\xC2" "\xB0"
3022
3023const char* headers[] = {
3024 "Oval part",
3025 "force moveTo",
3026 "can draw 180" __degree_symbol__,
3027 "can draw 360" __degree_symbol__,
3028 "can draw greater than 360" __degree_symbol__,
3029 "ignored if radius is zero",
3030 "ignored if sweep is zero",
3031 "requires Path",
3032 "describes rotation",
3033 "describes perspective",
3034};
3035
3036const char* yna[] = {
3037 "n/a",
3038 "no",
3039 "yes"
3040};
Cary Clark1a8d7622018-03-05 13:26:16 -05003041$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003042##
3043void draw(SkCanvas* canvas) {
3044 SkPaint lp;
3045 lp.setAntiAlias(true);
3046 SkPaint tp(lp);
3047 SkPaint sp(tp);
3048 SkPaint bp(tp);
3049 bp.setFakeBoldText(true);
3050 sp.setTextSize(10);
3051 lp.setColor(SK_ColorGRAY);
3052 canvas->translate(0, 32);
3053 const int tl = 115;
3054 for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
3055 canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
3056 if (0 == col) {
3057 continue;
3058 }
3059 canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
3060 SkPath path;
3061 path.moveTo(tl - 3 + col * 35, 103);
3062 path.lineTo(tl + 124 + col * 35, -24);
3063 canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
3064 }
3065 for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
3066 if (0 == row) {
3067 canvas->drawLine(tl, 100, tl + 350, 100, lp);
3068 } else {
3069 canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
3070 }
3071 if (row == SK_ARRAY_COUNT(dataSet)) {
3072 break;
3073 }
3074 canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
3075 if (dataSet[row].super) {
3076 SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
3077 canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
3078 }
3079 for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
3080 int val = dataSet[row].yn[col];
3081 canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
3082 if (val > 1) {
3083 char supe = '0' + val - 1;
3084 canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
3085 }
3086 }
3087 }
3088}
3089#Example ##
3090
3091#Example
3092#Height 128
3093#Description
3094#ToDo make this a list or table ##
30951 describes an arc from an oval, a starting angle, and a sweep angle.
30962 is similar to 1, but does not require building a path to draw.
30973 is similar to 1, but always begins new Contour.
30984 describes an arc from a pair of tangent lines and a radius.
30995 describes an arc from Oval center, arc start Point and arc end Point.
31006 describes an arc from a pair of tangent lines and a Conic_Weight.
3101##
3102void draw(SkCanvas* canvas) {
3103 SkRect oval = {8, 8, 56, 56};
3104 SkPaint ovalPaint;
3105 ovalPaint.setAntiAlias(true);
3106 SkPaint textPaint(ovalPaint);
3107 ovalPaint.setStyle(SkPaint::kStroke_Style);
3108 SkPaint arcPaint(ovalPaint);
3109 arcPaint.setStrokeWidth(5);
3110 arcPaint.setColor(SK_ColorBLUE);
3111 canvas->translate(-64, 0);
3112 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3113 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3114 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3115 canvas->drawOval(oval, ovalPaint);
3116 SkPath path;
3117 path.moveTo({56, 32});
3118 switch (arcStyle) {
3119 case '1':
3120 path.arcTo(oval, 0, 90, false);
3121 break;
3122 case '2':
3123 canvas->drawArc(oval, 0, 90, false, arcPaint);
3124 continue;
3125 case '3':
3126 path.addArc(oval, 0, 90);
3127 break;
3128 case '4':
3129 path.arcTo({56, 56}, {32, 56}, 24);
3130 break;
3131 case '5':
3132 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3133 break;
3134 case '6':
3135 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3136 break;
3137 }
3138 canvas->drawPath(path, arcPaint);
3139 }
3140}
3141#Example ##
3142
3143
3144#Method void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05003145#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003146#In Arc
3147#Line # appends Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003148Append Arc to Path. Arc added is part of ellipse
3149bounded by oval, from startAngle through sweepAngle. Both startAngle and
3150sweepAngle are measured in degrees, where zero degrees is aligned with the
3151positive x-axis, and positive sweeps extends Arc clockwise.
3152
3153arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3154is false and Path is not empty. Otherwise, added Contour begins with first point
3155of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3156
3157#Param oval bounds of ellipse containing Arc ##
3158#Param startAngle starting angle of Arc in degrees ##
3159#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3160#Param forceMoveTo true to start a new contour with Arc ##
3161
3162#Example
3163#Height 200
3164#Description
3165arcTo continues a previous contour when forceMoveTo is false and when Path
3166is not empty.
3167##
3168void draw(SkCanvas* canvas) {
3169 SkPaint paint;
3170 SkPath path;
3171 paint.setStyle(SkPaint::kStroke_Style);
3172 paint.setStrokeWidth(4);
3173 path.moveTo(0, 0);
3174 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3175 canvas->drawPath(path, paint);
3176 path.rewind();
3177 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3178 canvas->drawPath(path, paint);
3179 path.rewind();
3180 path.moveTo(0, 0);
3181 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3182 canvas->drawPath(path, paint);
3183}
3184##
3185
3186#SeeAlso addArc SkCanvas::drawArc conicTo
3187
3188##
3189
3190# ------------------------------------------------------------------------------
3191
3192#Method void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003193#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003194#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003195Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3196weighted to describe part of Circle. Arc is contained by tangent from
3197last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003198is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003199
3200#ToDo allow example to hide source and not be exposed as fiddle ##
3201
3202#Example
3203#Height 226
3204void draw(SkCanvas* canvas) {
3205 SkPaint tangentPaint;
3206 tangentPaint.setAntiAlias(true);
3207 SkPaint textPaint(tangentPaint);
3208 tangentPaint.setStyle(SkPaint::kStroke_Style);
3209 tangentPaint.setColor(SK_ColorGRAY);
3210 SkPaint arcPaint(tangentPaint);
3211 arcPaint.setStrokeWidth(5);
3212 arcPaint.setColor(SK_ColorBLUE);
3213 SkPath path;
3214 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3215 SkScalar radius = 50;
3216 path.moveTo(pts[0]);
3217 path.arcTo(pts[1], pts[2], radius);
3218 canvas->drawLine(pts[0], pts[1], tangentPaint);
3219 canvas->drawLine(pts[1], pts[2], tangentPaint);
3220 SkPoint lastPt;
3221 (void) path.getLastPt(&lastPt);
3222 SkVector radial = pts[2] - pts[1];
3223 radial.setLength(radius);
3224 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3225 canvas->drawCircle(center, radius, tangentPaint);
3226 canvas->drawLine(lastPt, center, tangentPaint);
3227 radial = pts[1] - pts[0];
3228 radial.setLength(radius);
3229 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3230 canvas->drawLine(center, arcStart, tangentPaint);
3231 canvas->drawPath(path, arcPaint);
3232 textPaint.setTextAlign(SkPaint::kRight_Align);
3233 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3234 textPaint.setTextAlign(SkPaint::kLeft_Align);
3235 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3236 textPaint.setTextAlign(SkPaint::kCenter_Align);
3237 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3238 textPaint.setTextAlign(SkPaint::kRight_Align);
3239 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3240 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3241}
3242##
3243
3244If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3245The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3246
3247#Example
3248#Height 128
3249void draw(SkCanvas* canvas) {
3250 SkPaint tangentPaint;
3251 tangentPaint.setAntiAlias(true);
3252 SkPaint textPaint(tangentPaint);
3253 tangentPaint.setStyle(SkPaint::kStroke_Style);
3254 tangentPaint.setColor(SK_ColorGRAY);
3255 SkPaint arcPaint(tangentPaint);
3256 arcPaint.setStrokeWidth(5);
3257 arcPaint.setColor(SK_ColorBLUE);
3258 SkPath path;
3259 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3260 SkScalar radius = 50;
3261 path.moveTo(pts[0]);
3262 path.arcTo(pts[1], pts[2], radius);
3263 canvas->drawLine(pts[0], pts[1], tangentPaint);
3264 canvas->drawLine(pts[1], pts[2], tangentPaint);
3265 SkPoint lastPt;
3266 (void) path.getLastPt(&lastPt);
3267 SkVector radial = pts[2] - pts[1];
3268 radial.setLength(radius);
3269 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3270 canvas->drawLine(lastPt, center, tangentPaint);
3271 radial = pts[1] - pts[0];
3272 radial.setLength(radius);
3273 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3274 canvas->drawLine(center, arcStart, tangentPaint);
3275 canvas->drawPath(path, arcPaint);
3276 textPaint.setTextAlign(SkPaint::kCenter_Align);
3277 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3278 textPaint.setTextAlign(SkPaint::kLeft_Align);
3279 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3280 textPaint.setTextAlign(SkPaint::kCenter_Align);
3281 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3282 textPaint.setTextAlign(SkPaint::kRight_Align);
3283 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3284 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3285}
3286##
3287
3288Arc sweep is always less than 180 degrees. If radius is zero, or if
3289tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3290
3291arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003292arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003293
Cary Clark5538c132018-06-14 12:28:14 -04003294#Param x1 x-axis value common to pair of tangents ##
3295#Param y1 y-axis value common to pair of tangents ##
3296#Param x2 x-axis value end of second tangent ##
3297#Param y2 y-axis value end of second tangent ##
Cary Clark73fa9722017-08-29 17:36:51 -04003298#Param radius distance from Arc to Circle center ##
3299
3300#Example
3301#Description
3302arcTo is represented by Line and circular Conic in Path.
3303##
3304void draw(SkCanvas* canvas) {
3305 SkPath path;
3306 path.moveTo({156, 20});
3307 path.arcTo(200, 20, 170, 50, 50);
3308 SkPath::Iter iter(path, false);
3309 SkPoint p[4];
3310 SkPath::Verb verb;
3311 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3312 switch (verb) {
3313 case SkPath::kMove_Verb:
3314 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3315 break;
3316 case SkPath::kLine_Verb:
3317 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3318 break;
3319 case SkPath::kConic_Verb:
3320 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3321 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3322 break;
3323 default:
3324 SkDebugf("unexpected verb\n");
3325 }
3326 }
3327}
3328#StdOut
3329move to (156,20)
3330line (156,20),(79.2893,20)
3331conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3332##
3333##
3334
Cary Clark682c58d2018-05-16 07:07:07 -04003335#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003336
3337##
3338
3339# ------------------------------------------------------------------------------
3340
Cary Clark682c58d2018-05-16 07:07:07 -04003341#Method void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003342#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003343#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003344Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3345weighted to describe part of Circle. Arc is contained by tangent from
3346last Path point to p1, and tangent from p1 to p2. Arc
Cary Clark682c58d2018-05-16 07:07:07 -04003347is part of Circle sized to radius, positioned so it touches both tangent lines.
Cary Clark73fa9722017-08-29 17:36:51 -04003348
3349If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3350The length of Vector from p1 to p2 does not affect Arc.
3351
3352Arc sweep is always less than 180 degrees. If radius is zero, or if
3353tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3354
3355arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003356arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003357
3358#Param p1 Point common to pair of tangents ##
3359#Param p2 end of second tangent ##
3360#Param radius distance from Arc to Circle center ##
3361
3362#Example
3363#Description
3364Because tangent lines are parallel, arcTo appends line from last Path Point to
3365p1, but does not append a circular Conic.
3366##
3367void draw(SkCanvas* canvas) {
3368 SkPath path;
3369 path.moveTo({156, 20});
3370 path.arcTo({200, 20}, {170, 20}, 50);
3371 SkPath::Iter iter(path, false);
3372 SkPoint p[4];
3373 SkPath::Verb verb;
3374 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3375 switch (verb) {
3376 case SkPath::kMove_Verb:
3377 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3378 break;
3379 case SkPath::kLine_Verb:
3380 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3381 break;
3382 case SkPath::kConic_Verb:
3383 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3384 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3385 break;
3386 default:
3387 SkDebugf("unexpected verb\n");
3388 }
3389 }
3390}
3391#StdOut
3392move to (156,20)
3393line (156,20),(200,20)
3394##
3395##
3396
Cary Clark682c58d2018-05-16 07:07:07 -04003397#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04003398
3399##
3400
3401# ------------------------------------------------------------------------------
3402
3403#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05003404#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04003405
3406#Code
3407 enum ArcSize {
Cary Clark682c58d2018-05-16 07:07:07 -04003408 kSmall_ArcSize,
3409 kLarge_ArcSize,
Cary Clark73fa9722017-08-29 17:36:51 -04003410 };
3411##
3412
3413Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3414ArcSize and Direction select one of the four Oval parts.
3415
3416#Const kSmall_ArcSize 0
Cary Clark682c58d2018-05-16 07:07:07 -04003417#Line # smaller of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003418##
3419#Const kLarge_ArcSize 1
Cary Clark682c58d2018-05-16 07:07:07 -04003420#Line # larger of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04003421##
3422
3423#Example
3424#Height 160
3425#Description
3426Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3427Two routes are large, and two routes are counterclockwise. The one route both large
3428and counterclockwise is blue.
3429##
3430void draw(SkCanvas* canvas) {
3431 SkPaint paint;
3432 paint.setAntiAlias(true);
3433 paint.setStyle(SkPaint::kStroke_Style);
3434 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3435 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3436 SkPath path;
3437 path.moveTo({120, 50});
3438 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3439 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3440 paint.setColor(SK_ColorBLUE);
3441 paint.setStrokeWidth(3);
3442 }
3443 canvas->drawPath(path, paint);
3444 }
3445 }
3446}
3447##
3448
3449#SeeAlso arcTo Direction
3450
3451##
3452
3453# ------------------------------------------------------------------------------
3454
3455#Method void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3456 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003457#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003458#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003459
Cary Clark154beea2017-10-26 07:58:48 -04003460Append Arc to Path. Arc is implemented by one or more Conics weighted to
3461describe part of Oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
3462curves from last Path Point to (x, y), choosing one of four possible routes:
3463clockwise or counterclockwise, and smaller or larger.
Cary Clark73fa9722017-08-29 17:36:51 -04003464
Cary Clark154beea2017-10-26 07:58:48 -04003465Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if
3466either radii are zero, or if last Path Point equals (x, y). arcTo scales radii
3467(rx, ry) to fit last Path Point and (x, y) if both are greater than zero but
3468too small.
Cary Clark73fa9722017-08-29 17:36:51 -04003469
3470arcTo appends up to four Conic curves.
Cary Clark154beea2017-10-26 07:58:48 -04003471arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value
3472is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise,
3473while kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003474
3475#Param rx radius in x before x-axis rotation ##
3476#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003477#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003478#Param largeArc chooses smaller or larger Arc ##
3479#Param sweep chooses clockwise or counterclockwise Arc ##
3480#Param x end of Arc ##
3481#Param y end of Arc ##
3482
3483#Example
3484#Height 160
3485void draw(SkCanvas* canvas) {
3486 SkPaint paint;
3487 paint.setAntiAlias(true);
3488 paint.setStyle(SkPaint::kStroke_Style);
3489 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3490 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3491 SkPath path;
3492 path.moveTo({120, 50});
3493 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3494 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3495 paint.setColor(SK_ColorBLUE);
3496 paint.setStrokeWidth(3);
3497 }
3498 canvas->drawPath(path, paint);
3499 }
3500 }
3501}
3502##
3503
3504#SeeAlso rArcTo ArcSize Direction
3505
3506##
3507
3508# ------------------------------------------------------------------------------
3509
3510#Method void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04003511 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05003512#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003513#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003514
3515Append Arc to Path. Arc is implemented by one or more Conic weighted to describe part of Oval
3516with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last Path Point to
3517(xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise,
3518and smaller or larger.
3519
3520Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either radii are zero,
3521or if last Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
Cary Clarkce101242017-09-01 15:51:02 -04003522xy if both are greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003523
3524arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003525arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3526opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3527kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003528
Cary Clark5538c132018-06-14 12:28:14 -04003529#Param r radii on axes before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003530#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003531#Param largeArc chooses smaller or larger Arc ##
3532#Param sweep chooses clockwise or counterclockwise Arc ##
3533#Param xy end of Arc ##
3534
3535#Example
3536#Height 108
3537void draw(SkCanvas* canvas) {
3538 SkPaint paint;
3539 SkPath path;
3540 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3541 for (auto start : starts) {
3542 path.moveTo(start.fX, start.fY);
3543 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3544 }
3545 canvas->drawPath(path, paint);
3546}
3547##
3548
3549#SeeAlso rArcTo ArcSize Direction
3550
3551##
3552
3553# ------------------------------------------------------------------------------
3554
3555#Method void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3556 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003557#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003558#In Arc
3559#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003560
Cary Clark682c58d2018-05-16 07:07:07 -04003561Append Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003562more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04003563xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
3564
Cary Clark73fa9722017-08-29 17:36:51 -04003565#Formula
3566(x0 + dx, y0 + dy)
3567##
3568, choosing one of four possible routes: clockwise or
3569counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3570is (0, 0).
3571
Cary Clarkce101242017-09-01 15:51:02 -04003572Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3573if either radii are zero, or if last Path Point equals end Point.
3574arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3575greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003576
3577arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003578arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3579opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003580kCW_Direction cast to int is zero.
3581
Cary Clark5538c132018-06-14 12:28:14 -04003582#Param rx radius before x-axis rotation ##
3583#Param ry radius before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003584#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003585#Param largeArc chooses smaller or larger Arc ##
3586#Param sweep chooses clockwise or counterclockwise Arc ##
Cary Clark5538c132018-06-14 12:28:14 -04003587#Param dx x-axis offset end of Arc from last Path Point ##
3588#Param dy y-axis offset end of Arc from last Path Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003589
3590#Example
3591#Height 108
3592void draw(SkCanvas* canvas) {
3593 SkPaint paint;
3594 SkPath path;
3595 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3596 for (auto start : starts) {
3597 path.moveTo(start.fX, start.fY);
3598 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3599 }
3600 canvas->drawPath(path, paint);
3601}
3602##
3603
3604#SeeAlso arcTo ArcSize Direction
3605
3606##
3607
Cary Clark78de7512018-02-07 07:27:09 -05003608#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003609
3610# ------------------------------------------------------------------------------
3611
3612#Method void close()
Cary Clark4855f782018-02-06 09:41:53 -05003613#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003614#Line # makes last Contour a loop ##
Cary Clark73fa9722017-08-29 17:36:51 -04003615Append kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003616with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003617with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
Cary Clark682c58d2018-05-16 07:07:07 -04003618Paint_Stroke_Cap at Contour start and end; closed Contour draws
Cary Clark73fa9722017-08-29 17:36:51 -04003619Paint_Stroke_Join at Contour start and end.
3620
3621close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3622
3623#Example
3624void draw(SkCanvas* canvas) {
3625 SkPaint paint;
3626 paint.setStrokeWidth(15);
3627 paint.setStrokeCap(SkPaint::kRound_Cap);
3628 SkPath path;
3629 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3630 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3631 for (int loop = 0; loop < 2; ++loop) {
3632 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3633 SkPaint::kStrokeAndFill_Style} ) {
3634 paint.setStyle(style);
3635 canvas->drawPath(path, paint);
3636 canvas->translate(85, 0);
3637 }
3638 path.close();
3639 canvas->translate(-255, 128);
3640 }
3641}
3642##
3643
Cary Clark682c58d2018-05-16 07:07:07 -04003644#SeeAlso
Cary Clark73fa9722017-08-29 17:36:51 -04003645
3646##
3647
3648# ------------------------------------------------------------------------------
3649
Cary Clark682c58d2018-05-16 07:07:07 -04003650#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003651#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003652#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003653Returns true if fill is inverted and Path with fill represents area outside
3654of its geometric bounds.
3655
3656#Table
3657#Legend
3658# FillType # is inverse ##
3659##
3660# kWinding_FillType # false ##
3661# kEvenOdd_FillType # false ##
3662# kInverseWinding_FillType # true ##
3663# kInverseEvenOdd_FillType # true ##
3664##
3665
3666#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3667 kInverseWinding_FillType, kInverseEvenOdd_FillType
3668##
3669
3670#Return true if Path fills outside its bounds ##
3671
3672#Example
3673#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003674###$
Cary Clark73fa9722017-08-29 17:36:51 -04003675#define nameValue(fill) { SkPath::fill, #fill }
3676
Cary Clark1a8d7622018-03-05 13:26:16 -05003677$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003678##
3679void draw(SkCanvas* canvas) {
3680 struct {
3681 SkPath::FillType fill;
3682 const char* name;
3683 } fills[] = {
3684 nameValue(kWinding_FillType),
3685 nameValue(kEvenOdd_FillType),
3686 nameValue(kInverseWinding_FillType),
3687 nameValue(kInverseEvenOdd_FillType),
3688 };
3689 for (auto fill: fills ) {
3690 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3691 "true" : "false");
3692 }
3693}
3694#StdOut
3695IsInverseFillType(kWinding_FillType) == false
3696IsInverseFillType(kEvenOdd_FillType) == false
3697IsInverseFillType(kInverseWinding_FillType) == true
3698IsInverseFillType(kInverseEvenOdd_FillType) == true
3699##
3700##
3701
3702#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3703
3704##
3705
3706# ------------------------------------------------------------------------------
3707
Cary Clark682c58d2018-05-16 07:07:07 -04003708#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003709#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003710#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003711Returns equivalent Fill_Type representing Path fill inside its bounds.
3712.
3713
3714#Table
3715#Legend
3716# FillType # inside FillType ##
3717##
3718# kWinding_FillType # kWinding_FillType ##
3719# kEvenOdd_FillType # kEvenOdd_FillType ##
3720# kInverseWinding_FillType # kWinding_FillType ##
3721# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3722##
3723
3724#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3725 kInverseWinding_FillType, kInverseEvenOdd_FillType
3726##
3727
3728#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3729
3730#Example
3731#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003732###$
Cary Clark73fa9722017-08-29 17:36:51 -04003733#define nameValue(fill) { SkPath::fill, #fill }
3734
Cary Clark1a8d7622018-03-05 13:26:16 -05003735$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003736##
3737void draw(SkCanvas* canvas) {
3738 struct {
3739 SkPath::FillType fill;
3740 const char* name;
3741 } fills[] = {
3742 nameValue(kWinding_FillType),
3743 nameValue(kEvenOdd_FillType),
3744 nameValue(kInverseWinding_FillType),
3745 nameValue(kInverseEvenOdd_FillType),
3746 };
3747 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3748 if (fills[i].fill != (SkPath::FillType) i) {
3749 SkDebugf("fills array order does not match FillType enum order");
3750 break;
Cary Clark682c58d2018-05-16 07:07:07 -04003751 }
Cary Clark73fa9722017-08-29 17:36:51 -04003752 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3753 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3754 }
3755}
3756#StdOut
3757ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3758ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3759ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3760ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3761##
3762##
3763
3764#SeeAlso FillType getFillType setFillType IsInverseFillType
3765
3766##
3767
3768# ------------------------------------------------------------------------------
3769
3770#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3771 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05003772#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003773#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04003774
3775Approximates Conic with Quad array. Conic is constructed from start Point p0,
Cary Clark682c58d2018-05-16 07:07:07 -04003776control Point p1, end Point p2, and weight w.
Cary Clark73fa9722017-08-29 17:36:51 -04003777Quad array is stored in pts; this storage is supplied by caller.
3778Maximum Quad count is 2 to the pow2.
Cary Clark682c58d2018-05-16 07:07:07 -04003779Every third point in array shares last Point of previous Quad and first Point of
3780next Quad. Maximum pts storage size is given by:
Cary Clark73fa9722017-08-29 17:36:51 -04003781#Formula
3782(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
3783##
Cary Clark154beea2017-10-26 07:58:48 -04003784.
Cary Clark6fc50412017-09-21 12:31:06 -04003785
Cary Clark154beea2017-10-26 07:58:48 -04003786Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04003787than the number requested.
Cary Clark682c58d2018-05-16 07:07:07 -04003788
Cary Clark73fa9722017-08-29 17:36:51 -04003789Conic_Weight determines the amount of influence Conic control point has on the curve.
3790w less than one represents an elliptical section. w greater than one represents
3791a hyperbolic section. w equal to one represents a parabolic section.
3792
3793Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3794of up to 90 degrees; in this case, set pow2 to one.
3795
3796#Param p0 Conic start Point ##
3797#Param p1 Conic control Point ##
3798#Param p2 Conic end Point ##
3799#Param w Conic weight ##
3800#Param pts storage for Quad array ##
3801#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3802
Cary Clarka523d2d2017-08-30 08:58:10 -04003803#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003804
3805#Example
3806#Description
3807A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3808The middle curve is nearly circular. The top-right curve is parabolic, which can
3809be drawn exactly with a single Quad.
3810##
3811void draw(SkCanvas* canvas) {
3812 SkPaint conicPaint;
3813 conicPaint.setAntiAlias(true);
3814 conicPaint.setStyle(SkPaint::kStroke_Style);
3815 SkPaint quadPaint(conicPaint);
3816 quadPaint.setColor(SK_ColorRED);
3817 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3818 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3819 SkPoint quads[5];
3820 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3821 SkPath path;
3822 path.moveTo(conic[0]);
3823 path.conicTo(conic[1], conic[2], weight);
3824 canvas->drawPath(path, conicPaint);
3825 path.rewind();
3826 path.moveTo(quads[0]);
3827 path.quadTo(quads[1], quads[2]);
3828 path.quadTo(quads[3], quads[4]);
3829 canvas->drawPath(path, quadPaint);
3830 canvas->translate(50, -50);
3831 }
3832}
3833##
3834
3835#SeeAlso Conic Quad
3836
3837##
3838
3839# ------------------------------------------------------------------------------
3840
3841#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003842#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003843#Line # returns if describes Rect ##
Cary Clarkce101242017-09-01 15:51:02 -04003844Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003845If false: rect, isClosed, and direction are unchanged.
3846If true: rect, isClosed, and direction are written to if not nullptr.
3847
3848rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3849that do not alter the area drawn by the returned rect.
3850
3851#Param rect storage for bounds of Rect; may be nullptr ##
3852#Param isClosed storage set to true if Path is closed; may be nullptr ##
3853#Param direction storage set to Rect direction; may be nullptr ##
3854
3855#Return true if Path contains Rect ##
3856
3857#Example
3858#Description
3859After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3860following lineTo does not. addPoly returns true even though rect is not closed, and one
3861side of rect is made up of consecutive line segments.
3862##
3863void draw(SkCanvas* canvas) {
3864 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3865 SkRect rect;
3866 SkPath::Direction direction;
3867 bool isClosed;
Cary Clark682c58d2018-05-16 07:07:07 -04003868 path.isRect(&rect, &isClosed, &direction) ?
Cary Clark73fa9722017-08-29 17:36:51 -04003869 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3870 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3871 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3872 SkDebugf("%s is not rect\n", prefix);
3873 };
3874 SkPath path;
3875 debugster("empty", path);
3876 path.addRect({10, 20, 30, 40});
3877 debugster("addRect", path);
3878 path.moveTo(60, 70);
3879 debugster("moveTo", path);
3880 path.lineTo(60, 70);
3881 debugster("lineTo", path);
3882 path.reset();
3883 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3884 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3885 debugster("addPoly", path);
3886}
3887#StdOut
3888empty is not rect
3889addRect is rect (10, 20, 30, 40); is closed; direction CW
3890moveTo is rect (10, 20, 30, 40); is closed; direction CW
3891lineTo is not rect
3892addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3893##
3894##
3895
3896#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3897
3898##
3899
3900# ------------------------------------------------------------------------------
3901
3902#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003903#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003904#Line # returns if describes Rect pair, one inside the other ##
Cary Clark73fa9722017-08-29 17:36:51 -04003905Returns true if Path is equivalent to nested Rect pair when filled.
3906If false, rect and dirs are unchanged.
3907If true, rect and dirs are written to if not nullptr:
3908setting rect[0] to outer Rect, and rect[1] to inner Rect;
3909setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3910Rect.
3911
3912#Param rect storage for Rect pair; may be nullptr ##
3913#Param dirs storage for Direction pair; may be nullptr ##
3914
3915#Return true if Path contains nested Rect pair ##
3916
3917#Example
3918void draw(SkCanvas* canvas) {
3919 SkPaint paint;
3920 paint.setStyle(SkPaint::kStroke_Style);
3921 paint.setStrokeWidth(5);
3922 SkPath path;
3923 path.addRect({10, 20, 30, 40});
3924 paint.getFillPath(path, &path);
3925 SkRect rects[2];
3926 SkPath::Direction directions[2];
3927 if (path.isNestedFillRects(rects, directions)) {
3928 for (int i = 0; i < 2; ++i) {
3929 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3930 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3931 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3932 }
3933 } else {
3934 SkDebugf("is not nested rectangles\n");
3935 }
3936}
3937#StdOut
3938outer (7.5, 17.5, 32.5, 42.5); direction CW
3939inner (12.5, 22.5, 27.5, 37.5); direction CCW
3940##
3941##
3942
3943#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3944
3945##
3946
3947# ------------------------------------------------------------------------------
3948
3949#Method void addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003950#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003951#Line # adds one Contour containing Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04003952Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
3953starting with top-left corner of Rect; followed by top-right, bottom-right,
3954and bottom-left if dir is kCW_Direction; or followed by bottom-left,
3955bottom-right, and top-right if dir is kCCW_Direction.
3956
3957#Param rect Rect to add as a closed contour ##
3958#Param dir Direction to wind added contour ##
3959
3960#Example
3961#Description
3962The left Rect dashes starting at the top-left corner, to the right.
3963The right Rect dashes starting at the top-left corner, towards the bottom.
3964##
3965#Height 128
3966void draw(SkCanvas* canvas) {
3967 SkPaint paint;
3968 paint.setStrokeWidth(15);
3969 paint.setStrokeCap(SkPaint::kSquare_Cap);
3970 float intervals[] = { 5, 21.75f };
3971 paint.setStyle(SkPaint::kStroke_Style);
3972 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3973 SkPath path;
3974 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
3975 canvas->drawPath(path, paint);
3976 path.rewind();
3977 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
3978 canvas->drawPath(path, paint);
3979}
3980##
3981
3982#SeeAlso SkCanvas::drawRect Direction
3983
3984##
3985
3986# ------------------------------------------------------------------------------
3987
3988#Method void addRect(const SkRect& rect, Direction dir, unsigned start)
3989
3990Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
3991If dir is kCW_Direction, Rect corners are added clockwise; if dir is
3992kCCW_Direction, Rect corners are added counterclockwise.
3993start determines the first corner added.
3994
3995#Table
3996#Legend
3997# start # first corner ##
3998#Legend ##
3999# 0 # top-left ##
4000# 1 # top-right ##
4001# 2 # bottom-right ##
4002# 3 # bottom-left ##
4003#Table ##
4004
4005#Param rect Rect to add as a closed contour ##
4006#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004007#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04004008
4009#Example
4010#Height 128
4011#Description
4012The arrow is just after the initial corner and points towards the next
4013corner appended to Path.
4014##
4015void draw(SkCanvas* canvas) {
4016 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
4017 const SkRect rect = {10, 10, 54, 54};
4018 SkPaint rectPaint;
4019 rectPaint.setAntiAlias(true);
4020 rectPaint.setStyle(SkPaint::kStroke_Style);
4021 SkPaint arrowPaint(rectPaint);
4022 SkPath arrowPath;
4023 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4024 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4025 SkPath1DPathEffect::kRotate_Style));
4026 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4027 for (unsigned start : { 0, 1, 2, 3 } ) {
4028 SkPath path;
4029 path.addRect(rect, direction, start);
4030 canvas->drawPath(path, rectPaint);
4031 canvas->drawPath(path, arrowPaint);
4032 canvas->translate(64, 0);
4033 }
4034 canvas->translate(-256, 64);
4035 }
4036}
4037##
4038
4039#SeeAlso SkCanvas::drawRect Direction
4040
4041##
4042
4043# ------------------------------------------------------------------------------
4044
4045#Method void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
4046 Direction dir = kCW_Direction)
4047
4048Add Rect (left, top, right, bottom) to Path,
4049appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4050starting with top-left corner of Rect; followed by top-right, bottom-right,
4051and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4052bottom-right, and top-right if dir is kCCW_Direction.
4053
Cary Clark5538c132018-06-14 12:28:14 -04004054#Param left smaller x-axis value of Rect ##
4055#Param top smaller y-axis value of Rect ##
4056#Param right larger x-axis value of Rect ##
4057#Param bottom larger y-axis value of Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004058#Param dir Direction to wind added contour ##
4059
4060#Example
4061#Description
4062The left Rect dashes start at the top-left corner, and continue to the right.
4063The right Rect dashes start at the top-left corner, and continue down.
4064##
4065#Height 128
4066void draw(SkCanvas* canvas) {
4067 SkPaint paint;
4068 paint.setStrokeWidth(15);
4069 paint.setStrokeCap(SkPaint::kSquare_Cap);
4070 float intervals[] = { 5, 21.75f };
4071 paint.setStyle(SkPaint::kStroke_Style);
4072 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4073 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4074 SkPath path;
4075 path.addRect(20, 20, 100, 100, direction);
4076 canvas->drawPath(path, paint);
4077 canvas->translate(128, 0);
4078 }
4079}
4080##
4081
4082#SeeAlso SkCanvas::drawRect Direction
4083
4084##
4085
4086# ------------------------------------------------------------------------------
4087
4088#Method void addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004089#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004090#Line # adds one Contour containing Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04004091Add Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4092Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4093and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4094clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4095
Cary Clark73fa9722017-08-29 17:36:51 -04004096#Param oval bounds of ellipse added ##
4097#Param dir Direction to wind ellipse ##
4098
4099#Example
4100#Height 120
4101 SkPaint paint;
4102 SkPath oval;
4103 oval.addOval({20, 20, 160, 80});
4104 canvas->drawPath(oval, paint);
4105##
4106
4107#SeeAlso SkCanvas::drawOval Direction Oval
4108
4109##
4110
4111# ------------------------------------------------------------------------------
4112
4113#Method void addOval(const SkRect& oval, Direction dir, unsigned start)
4114
4115Add Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4116Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4117and half oval height. Oval begins at start and continues
4118clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4119
4120#Table
4121#Legend
4122# start # Point ##
4123#Legend ##
4124# 0 # oval.centerX(), oval.fTop ##
4125# 1 # oval.fRight, oval.centerY() ##
4126# 2 # oval.centerX(), oval.fBottom ##
4127# 3 # oval.fLeft, oval.centerY() ##
4128#Table ##
4129
4130#Param oval bounds of ellipse added ##
4131#Param dir Direction to wind ellipse ##
4132#Param start index of initial point of ellipse ##
4133
4134#Example
4135#Height 160
4136void draw(SkCanvas* canvas) {
4137 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4138 const SkRect rect = {10, 10, 54, 54};
4139 SkPaint ovalPaint;
4140 ovalPaint.setAntiAlias(true);
4141 SkPaint textPaint(ovalPaint);
4142 textPaint.setTextAlign(SkPaint::kCenter_Align);
4143 ovalPaint.setStyle(SkPaint::kStroke_Style);
4144 SkPaint arrowPaint(ovalPaint);
4145 SkPath arrowPath;
4146 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4147 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4148 SkPath1DPathEffect::kRotate_Style));
4149 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4150 for (unsigned start : { 0, 1, 2, 3 } ) {
4151 SkPath path;
4152 path.addOval(rect, direction, start);
4153 canvas->drawPath(path, ovalPaint);
4154 canvas->drawPath(path, arrowPaint);
4155 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4156 canvas->translate(64, 0);
4157 }
4158 canvas->translate(-256, 72);
4159 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4160 128, 0, textPaint);
4161 }
4162}
4163##
4164
4165#SeeAlso SkCanvas::drawOval Direction Oval
4166
4167##
4168
4169# ------------------------------------------------------------------------------
4170
4171#Method void addCircle(SkScalar x, SkScalar y, SkScalar radius,
4172 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004173#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004174#Line # adds one Contour containing Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04004175
4176Add Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark682c58d2018-05-16 07:07:07 -04004177four kConic_Verb, and kClose_Verb. Circle begins at:
Cary Clark73fa9722017-08-29 17:36:51 -04004178#Formula
4179(x + radius, y)
4180##
Cary Clark154beea2017-10-26 07:58:48 -04004181, continuing
4182clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04004183
Cary Clark6fc50412017-09-21 12:31:06 -04004184Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004185
4186#Param x center of Circle ##
4187#Param y center of Circle ##
4188#Param radius distance from center to edge ##
4189#Param dir Direction to wind Circle ##
4190
4191#Example
4192void draw(SkCanvas* canvas) {
4193 SkPaint paint;
4194 paint.setAntiAlias(true);
4195 paint.setStyle(SkPaint::kStroke_Style);
4196 paint.setStrokeWidth(10);
4197 for (int size = 10; size < 300; size += 20) {
4198 SkPath path;
4199 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4200 canvas->drawPath(path, paint);
4201 }
4202}
4203##
4204
4205#SeeAlso SkCanvas::drawCircle Direction Circle
4206
4207##
4208
4209# ------------------------------------------------------------------------------
4210
4211#Method void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05004212#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004213#Line # adds one Contour containing Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04004214Append Arc to Path, as the start of new Contour. Arc added is part of ellipse
4215bounded by oval, from startAngle through sweepAngle. Both startAngle and
4216sweepAngle are measured in degrees, where zero degrees is aligned with the
4217positive x-axis, and positive sweeps extends Arc clockwise.
4218
Cary Clark682c58d2018-05-16 07:07:07 -04004219If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4220zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
Cary Clark73fa9722017-08-29 17:36:51 -04004221modulo 360, and Arc may or may not draw depending on numeric rounding.
4222
4223#Param oval bounds of ellipse containing Arc ##
4224#Param startAngle starting angle of Arc in degrees ##
4225#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4226
4227#Example
4228#Description
4229The middle row of the left and right columns draw differently from the entries
Cary Clark682c58d2018-05-16 07:07:07 -04004230above and below because sweepAngle is outside of the range of +/-360,
Cary Clark73fa9722017-08-29 17:36:51 -04004231and startAngle modulo 90 is not zero.
4232##
4233void draw(SkCanvas* canvas) {
4234 SkPaint paint;
4235 for (auto start : { 0, 90, 135, 180, 270 } ) {
4236 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4237 SkPath path;
4238 path.addArc({10, 10, 35, 45}, start, sweep);
4239 canvas->drawPath(path, paint);
4240 canvas->translate(252 / 6, 0);
4241 }
4242 canvas->translate(-252, 255 / 5);
4243 }
4244}
4245##
4246
4247#SeeAlso Arc arcTo SkCanvas::drawArc
4248
4249##
4250
4251# ------------------------------------------------------------------------------
4252
4253#Method void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
4254 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004255#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004256#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark73fa9722017-08-29 17:36:51 -04004257
4258Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4259equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4260dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4261winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4262of the upper-left corner and winds counterclockwise.
4263
4264If either rx or ry is too large, rx and ry are scaled uniformly until the
4265corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4266Rect rect to Path.
4267
4268After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4269
4270#Param rect bounds of Round_Rect ##
Cary Clark5538c132018-06-14 12:28:14 -04004271#Param rx x-axis radius of rounded corners on the Round_Rect ##
4272#Param ry y-axis radius of rounded corners on the Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004273#Param dir Direction to wind Round_Rect ##
4274
4275#Example
4276#Description
4277If either radius is zero, path contains Rect and is drawn red.
4278If sides are only radii, path contains Oval and is drawn blue.
4279All remaining path draws are convex, and are drawn in gray; no
4280paths constructed from addRoundRect are concave, so none are
4281drawn in green.
4282##
4283void draw(SkCanvas* canvas) {
4284 SkPaint paint;
4285 paint.setAntiAlias(true);
4286 for (auto xradius : { 0, 7, 13, 20 } ) {
4287 for (auto yradius : { 0, 9, 18, 40 } ) {
4288 SkPath path;
4289 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4290 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4291 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4292 canvas->drawPath(path, paint);
4293 canvas->translate(64, 0);
4294 }
4295 canvas->translate(-256, 64);
4296 }
4297}
4298##
4299
4300#SeeAlso addRRect SkCanvas::drawRoundRect
4301
4302##
4303
4304# ------------------------------------------------------------------------------
4305
4306#Method void addRoundRect(const SkRect& rect, const SkScalar radii[],
4307 Direction dir = kCW_Direction)
4308
4309Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4310equal to rect; each corner is 90 degrees of an ellipse with radii from the
4311array.
4312
4313#Table
4314#Legend
4315# radii index # location ##
4316#Legend ##
Cary Clark5538c132018-06-14 12:28:14 -04004317# 0 # x-axis radius of top-left corner ##
4318# 1 # y-axis radius of top-left corner ##
4319# 2 # x-axis radius of top-right corner ##
4320# 3 # y-axis radius of top-right corner ##
4321# 4 # x-axis radius of bottom-right corner ##
4322# 5 # y-axis radius of bottom-right corner ##
4323# 6 # x-axis radius of bottom-left corner ##
4324# 7 # y-axis radius of bottom-left corner ##
Cary Clark73fa9722017-08-29 17:36:51 -04004325#Table ##
4326
Cary Clark682c58d2018-05-16 07:07:07 -04004327If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4328and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
Cary Clark73fa9722017-08-29 17:36:51 -04004329bottom-left of the upper-left corner and winds counterclockwise.
4330
Cary Clark682c58d2018-05-16 07:07:07 -04004331If both radii on any side of rect exceed its length, all radii are scaled
Cary Clark73fa9722017-08-29 17:36:51 -04004332uniformly until the corners fit. If either radius of a corner is less than or
4333equal to zero, both are treated as zero.
4334
4335After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4336
4337#Param rect bounds of Round_Rect ##
4338#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4339#Param dir Direction to wind Round_Rect ##
4340
4341#Example
4342void draw(SkCanvas* canvas) {
4343 SkPaint paint;
4344 paint.setAntiAlias(true);
4345 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4346 SkPath path;
4347 SkMatrix rotate90;
4348 rotate90.setRotate(90, 128, 128);
4349 for (int i = 0; i < 4; ++i) {
4350 path.addRoundRect({10, 10, 110, 110}, radii);
4351 path.transform(rotate90);
4352 }
4353 canvas->drawPath(path, paint);
4354}
4355##
4356
4357#SeeAlso addRRect SkCanvas::drawRoundRect
4358
4359##
4360
4361# ------------------------------------------------------------------------------
4362
4363#Method void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004364#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004365#Line # adds one Contour containing Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004366Add rrect to Path, creating a new closed Contour. If
4367dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4368winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4369of the upper-left corner and winds counterclockwise.
4370
4371After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4372
4373#Param rrect bounds and radii of rounded rectangle ##
4374#Param dir Direction to wind Round_Rect ##
4375
4376#Example
4377void draw(SkCanvas* canvas) {
4378 SkPaint paint;
4379 paint.setAntiAlias(true);
4380 SkRRect rrect;
4381 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4382 rrect.setRectRadii({10, 10, 110, 110}, radii);
4383 SkPath path;
4384 SkMatrix rotate90;
4385 rotate90.setRotate(90, 128, 128);
4386 for (int i = 0; i < 4; ++i) {
4387 path.addRRect(rrect);
4388 path.transform(rotate90);
4389 }
4390 canvas->drawPath(path, paint);
4391}
4392##
4393
4394#SeeAlso addRoundRect SkCanvas::drawRRect
4395
4396##
4397
4398# ------------------------------------------------------------------------------
4399
4400#Method void addRRect(const SkRRect& rrect, Direction dir, unsigned start)
4401
4402Add rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
4403winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4404start determines the first point of rrect to add.
4405
4406#Table
4407#Legend
4408# start # location ##
4409#Legend ##
4410# 0 # right of top-left corner ##
4411# 1 # left of top-right corner ##
4412# 2 # bottom of top-right corner ##
4413# 3 # top of bottom-right corner ##
4414# 4 # left of bottom-right corner ##
4415# 5 # right of bottom-left corner ##
4416# 6 # top of bottom-left corner ##
4417# 7 # bottom of top-left corner ##
4418#Table ##
4419
4420After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4421
4422#Param rrect bounds and radii of rounded rectangle ##
4423#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004424#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004425
4426#Example
4427void draw(SkCanvas* canvas) {
4428 SkPaint paint;
4429 paint.setAntiAlias(true);
4430 SkRRect rrect;
4431 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4432 SkPath path;
4433 path.addRRect(rrect);
4434 canvas->drawPath(path, paint);
4435 for (int start = 0; start < 8; ++start) {
4436 SkPath textPath;
4437 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
4438 canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
4439 }
4440}
4441##
4442
Cary Clark682c58d2018-05-16 07:07:07 -04004443#SeeAlso addRoundRect SkCanvas::drawRRect
Cary Clark73fa9722017-08-29 17:36:51 -04004444
4445##
4446
4447# ------------------------------------------------------------------------------
4448
4449#Method void addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05004450#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004451#Line # adds one Contour containing connected lines ##
Cary Clark6fc50412017-09-21 12:31:06 -04004452Add Contour created from Line array, adding (count - 1) Line segments.
4453Contour added starts at pts[0], then adds a line for every additional Point
4454in pts array. If close is true,appends kClose_Verb to Path, connecting
4455pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004456
4457If count is zero, append kMove_Verb to path.
4458Has no effect if count is less than one.
Cary Clark682c58d2018-05-16 07:07:07 -04004459
Cary Clarka523d2d2017-08-30 08:58:10 -04004460#Param pts array of Line sharing end and start Point ##
4461#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004462#Param close true to add Line connecting Contour end and start ##
4463
4464#Example
4465void draw(SkCanvas* canvas) {
4466 SkPaint paint;
4467 paint.setStrokeWidth(15);
4468 paint.setStrokeCap(SkPaint::kRound_Cap);
4469 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4470 for (bool close : { false, true } ) {
4471 SkPath path;
4472 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4473 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4474 SkPaint::kStrokeAndFill_Style} ) {
4475 paint.setStyle(style);
4476 canvas->drawPath(path, paint);
4477 canvas->translate(85, 0);
4478 }
4479 canvas->translate(-255, 128);
4480 }
4481}
4482##
4483
4484#SeeAlso SkCanvas::drawPoints
4485
4486##
4487
4488# ------------------------------------------------------------------------------
4489
4490#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05004491#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04004492
4493#Code
4494 enum AddPathMode {
Cary Clark682c58d2018-05-16 07:07:07 -04004495 kAppend_AddPathMode,
4496 kExtend_AddPathMode,
Cary Clark73fa9722017-08-29 17:36:51 -04004497 };
4498##
4499
4500AddPathMode chooses how addPath appends. Adding one Path to another can extend
4501the last Contour or start a new Contour.
4502
4503#Const kAppend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004504#Line # appended to destination unaltered ##
Cary Clark73fa9722017-08-29 17:36:51 -04004505 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4506 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4507 starts a new Contour.
4508##
4509#Const kExtend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04004510#Line # add line if prior Contour is not closed ##
Cary Clark73fa9722017-08-29 17:36:51 -04004511 If destination is closed or empty, start a new Contour. If destination
4512 is not empty, add Line from Last_Point to added Path first Point. Skip added
4513 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4514##
4515
4516#Example
4517#Description
4518test is built from path, open on the top row, and closed on the bottom row.
4519The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4520The top right composition is made up of one contour; the other three have two.
4521##
4522#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004523 SkPath path, path2;
4524 path.moveTo(20, 20);
4525 path.lineTo(20, 40);
4526 path.lineTo(40, 20);
4527 path2.moveTo(60, 60);
4528 path2.lineTo(80, 60);
4529 path2.lineTo(80, 40);
4530 SkPaint paint;
4531 paint.setStyle(SkPaint::kStroke_Style);
4532 for (int i = 0; i < 2; i++) {
4533 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4534 SkPath test(path);
4535 test.addPath(path2, addPathMode);
4536 canvas->drawPath(test, paint);
4537 canvas->translate(100, 0);
4538 }
4539 canvas->translate(-200, 100);
4540 path.close();
4541 }
Cary Clark73fa9722017-08-29 17:36:51 -04004542##
4543
4544#SeeAlso addPath reverseAddPath
4545
4546##
4547
4548# ------------------------------------------------------------------------------
4549
4550#Method void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
4551 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05004552#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004553#Line # adds contents of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004554
Cary Clark682c58d2018-05-16 07:07:07 -04004555Append src to Path, offset by (dx, dy).
Cary Clark73fa9722017-08-29 17:36:51 -04004556
4557If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4558added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004559Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004560
4561#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clark5538c132018-06-14 12:28:14 -04004562#Param dx offset added to src Point_Array x-axis coordinates ##
4563#Param dy offset added to src Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004564#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4565
4566#Example
4567#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004568 SkPaint paint;
4569 paint.setTextSize(128);
4570 paint.setFakeBoldText(true);
4571 SkPath dest, text;
4572 paint.getTextPath("O", 1, 50, 120, &text);
4573 for (int i = 0; i < 3; i++) {
4574 dest.addPath(text, i * 20, i * 20);
4575 }
4576 Simplify(dest, &dest);
4577 paint.setStyle(SkPaint::kStroke_Style);
4578 paint.setStrokeWidth(3);
4579 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004580##
4581
Cary Clark4855f782018-02-06 09:41:53 -05004582#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004583
4584##
4585
4586# ------------------------------------------------------------------------------
4587
Cary Clark682c58d2018-05-16 07:07:07 -04004588#Method void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
Cary Clark73fa9722017-08-29 17:36:51 -04004589
4590Append src to Path.
4591
4592If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4593added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004594Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004595
4596#Param src Path Verbs, Points, and Conic_Weights to add ##
4597#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4598
4599#Example
4600#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004601 SkPaint paint;
4602 paint.setStyle(SkPaint::kStroke_Style);
4603 SkPath dest, path;
4604 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4605 for (int i = 0; i < 2; i++) {
4606 dest.addPath(path, SkPath::kExtend_AddPathMode);
4607 dest.offset(100, 0);
4608 }
Cary Clark73fa9722017-08-29 17:36:51 -04004609 canvas->drawPath(dest, paint);
4610##
4611
4612#SeeAlso AddPathMode reverseAddPath
4613
4614##
4615
4616# ------------------------------------------------------------------------------
4617
4618#Method void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
4619
4620Append src to Path, transformed by matrix. Transformed curves may have different
4621Verbs, Points, and Conic_Weights.
4622
4623If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4624added unaltered. If mode is kExtend_AddPathMode, add Line before appending
Cary Clark682c58d2018-05-16 07:07:07 -04004625Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04004626
4627#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004628#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004629#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4630
4631#Example
4632#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004633 SkPaint paint;
4634 paint.setStyle(SkPaint::kStroke_Style);
4635 SkPath dest, path;
4636 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4637 for (int i = 0; i < 6; i++) {
4638 SkMatrix matrix;
4639 matrix.reset();
4640 matrix.setPerspX(i / 400.f);
4641 dest.addPath(path, matrix);
4642 }
4643 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004644##
4645
Cary Clark4855f782018-02-06 09:41:53 -05004646#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004647
4648##
4649
4650# ------------------------------------------------------------------------------
4651
4652#Method void reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05004653#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004654#Line # adds contents of Path back to front ##
Cary Clark682c58d2018-05-16 07:07:07 -04004655Append src to Path, from back to front.
Cary Clark73fa9722017-08-29 17:36:51 -04004656Reversed src always appends a new Contour to Path.
4657
4658#Param src Path Verbs, Points, and Conic_Weights to add ##
4659
4660#Example
4661#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004662 SkPath path;
4663 path.moveTo(20, 20);
4664 path.lineTo(20, 40);
4665 path.lineTo(40, 20);
4666 SkPaint paint;
4667 paint.setStyle(SkPaint::kStroke_Style);
4668 for (int i = 0; i < 2; i++) {
4669 SkPath path2;
4670 path2.moveTo(60, 60);
4671 path2.lineTo(80, 60);
4672 path2.lineTo(80, 40);
4673 for (int j = 0; j < 2; j++) {
4674 SkPath test(path);
4675 test.reverseAddPath(path2);
4676 canvas->drawPath(test, paint);
4677 canvas->translate(100, 0);
4678 path2.close();
4679 }
4680 canvas->translate(-200, 100);
4681 path.close();
4682 }
Cary Clark73fa9722017-08-29 17:36:51 -04004683##
4684
Cary Clark4855f782018-02-06 09:41:53 -05004685#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04004686
4687##
4688
4689# ------------------------------------------------------------------------------
4690
4691#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004692#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004693#Line # translates Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004694Offset Point_Array by (dx, dy). Offset Path replaces dst.
4695If dst is nullptr, Path is replaced by offset data.
4696
Cary Clark5538c132018-06-14 12:28:14 -04004697#Param dx offset added to Point_Array x-axis coordinates ##
4698#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004699#Param dst overwritten, translated copy of Path; may be nullptr ##
4700
4701#Example
4702#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004703 SkPath pattern;
4704 pattern.moveTo(20, 20);
4705 pattern.lineTo(20, 40);
4706 pattern.lineTo(40, 20);
4707 SkPaint paint;
4708 paint.setStyle(SkPaint::kStroke_Style);
4709 for (int i = 0; i < 10; i++) {
4710 SkPath path;
4711 pattern.offset(20 * i, 0, &path);
4712 canvas->drawPath(path, paint);
4713 }
Cary Clark73fa9722017-08-29 17:36:51 -04004714##
4715
4716#SeeAlso addPath transform
4717
4718##
4719
4720# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05004721#Subtopic Transform
4722#Populate
4723#Line # modify all points ##
4724##
Cary Clark73fa9722017-08-29 17:36:51 -04004725
Cary Clark682c58d2018-05-16 07:07:07 -04004726#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05004727#In Transform
Cary Clark73fa9722017-08-29 17:36:51 -04004728Offset Point_Array by (dx, dy). Path is replaced by offset data.
4729
Cary Clark5538c132018-06-14 12:28:14 -04004730#Param dx offset added to Point_Array x-axis coordinates ##
4731#Param dy offset added to Point_Array y-axis coordinates ##
Cary Clark73fa9722017-08-29 17:36:51 -04004732
4733#Example
4734#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004735 SkPath path;
4736 path.moveTo(20, 20);
4737 path.lineTo(20, 40);
4738 path.lineTo(40, 20);
4739 SkPaint paint;
4740 paint.setStyle(SkPaint::kStroke_Style);
4741 for (int i = 0; i < 10; i++) {
4742 canvas->drawPath(path, paint);
4743 path.offset(20, 0);
4744 }
Cary Clark73fa9722017-08-29 17:36:51 -04004745##
4746
4747#SeeAlso addPath transform SkCanvas::translate()
4748
4749##
4750
4751# ------------------------------------------------------------------------------
4752
4753#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004754#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004755#Line # applies Matrix to Point_Array and Weights ##
Cary Clark73fa9722017-08-29 17:36:51 -04004756Transform Verb_Array, Point_Array, and weight by matrix.
4757transform may change Verbs and increase their number.
4758Transformed Path replaces dst; if dst is nullptr, original data
Cary Clark682c58d2018-05-16 07:07:07 -04004759is replaced.
Cary Clark73fa9722017-08-29 17:36:51 -04004760
4761#Param matrix Matrix to apply to Path ##
4762#Param dst overwritten, transformed copy of Path; may be nullptr ##
4763
4764#Example
Cary Clark8032b982017-07-28 11:04:54 -04004765#Height 200
4766 SkPath pattern;
4767 pattern.moveTo(100, 100);
4768 pattern.lineTo(100, 20);
4769 pattern.lineTo(20, 100);
4770 SkPaint paint;
4771 paint.setStyle(SkPaint::kStroke_Style);
4772 for (int i = 0; i < 10; i++) {
4773 SkPath path;
4774 SkMatrix matrix;
4775 matrix.setRotate(36 * i, 100, 100);
4776 pattern.transform(matrix, &path);
4777 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004778 }
4779##
4780
4781#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4782
4783##
4784
4785# ------------------------------------------------------------------------------
4786
Cary Clark682c58d2018-05-16 07:07:07 -04004787#Method void transform(const SkMatrix& matrix)
Cary Clark73fa9722017-08-29 17:36:51 -04004788
4789Transform Verb_Array, Point_Array, and weight by matrix.
4790transform may change Verbs and increase their number.
4791Path is replaced by transformed data.
4792
4793#Param matrix Matrix to apply to Path ##
4794
4795#Example
Cary Clark8032b982017-07-28 11:04:54 -04004796#Height 200
4797 SkPath path;
4798 path.moveTo(100, 100);
4799 path.quadTo(100, 20, 20, 100);
4800 SkPaint paint;
4801 paint.setStyle(SkPaint::kStroke_Style);
4802 for (int i = 0; i < 10; i++) {
4803 SkMatrix matrix;
4804 matrix.setRotate(36, 100, 100);
4805 path.transform(matrix);
4806 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004807 }
4808##
4809
4810#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4811
4812##
4813
4814# ------------------------------------------------------------------------------
4815
Cary Clark8032b982017-07-28 11:04:54 -04004816#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05004817#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04004818
4819Path is defined cumulatively, often by adding a segment to the end of last
4820Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4821Last_Point can be read and written directly with getLastPt and setLastPt.
4822
Cary Clark73fa9722017-08-29 17:36:51 -04004823#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05004824#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004825#In Last_Point
4826#Line # returns Last_Point ##
Cary Clark682c58d2018-05-16 07:07:07 -04004827 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
Cary Clark73fa9722017-08-29 17:36:51 -04004828 storing (0, 0) if lastPt is not nullptr.
4829
4830 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4831
4832 #Return true if Point_Array contains one or more Points ##
4833
4834 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004835 SkPath path;
4836 path.moveTo(100, 100);
4837 path.quadTo(100, 20, 20, 100);
4838 SkMatrix matrix;
4839 matrix.setRotate(36, 100, 100);
4840 path.transform(matrix);
4841 SkPoint last;
4842 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004843 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4844 #StdOut
4845 last point: 35.2786, 52.9772
Cary Clark682c58d2018-05-16 07:07:07 -04004846 ##
Cary Clark73fa9722017-08-29 17:36:51 -04004847 ##
4848
4849 #SeeAlso setLastPt
4850
4851##
4852
4853#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05004854#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004855#In Last_Point
4856#Line # replaces Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004857 Set Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
Cary Clark186d08f2018-04-03 08:43:27 -04004858 Verb_Array and append (x, y) to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04004859
Cary Clark5538c132018-06-14 12:28:14 -04004860 #Param x set x-axis value of Last_Point ##
4861 #Param y set y-axis value of Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004862
4863 #Example
4864 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004865 SkPaint paint;
4866 paint.setTextSize(128);
4867 SkPath path;
4868 paint.getTextPath("@", 1, 60, 100, &path);
4869 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004870 canvas->drawPath(path, paint);
4871 ##
4872
4873 #SeeAlso getLastPt
4874
4875##
4876
Cary Clark682c58d2018-05-16 07:07:07 -04004877#Method void setLastPt(const SkPoint& p)
Cary Clark73fa9722017-08-29 17:36:51 -04004878
Cary Clark186d08f2018-04-03 08:43:27 -04004879 Set the last point on the path. If Point_Array is empty, append kMove_Verb to
4880 Verb_Array and append p to Point_Array.
Cary Clark73fa9722017-08-29 17:36:51 -04004881
4882 #Param p set value of Last_Point ##
4883
4884 #Example
4885 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004886 SkPaint paint;
4887 paint.setTextSize(128);
4888 SkPath path, path2;
4889 paint.getTextPath("A", 1, 60, 100, &path);
4890 paint.getTextPath("Z", 1, 60, 100, &path2);
4891 SkPoint pt, pt2;
4892 path.getLastPt(&pt);
4893 path2.getLastPt(&pt2);
4894 path.setLastPt(pt2);
4895 path2.setLastPt(pt);
4896 canvas->drawPath(path, paint);
4897 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004898 ##
4899
4900 #SeeAlso getLastPt
4901
4902##
4903
4904#Subtopic Last_Point ##
4905
4906# ------------------------------------------------------------------------------
4907
4908#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05004909#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004910
4911#Code
4912 enum SegmentMask {
4913 kLine_SegmentMask = 1 << 0,
4914 kQuad_SegmentMask = 1 << 1,
4915 kConic_SegmentMask = 1 << 2,
4916 kCubic_SegmentMask = 1 << 3,
4917 };
4918##
4919
4920SegmentMask constants correspond to each drawing Verb type in Path; for
4921instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4922
Cary Clark4855f782018-02-06 09:41:53 -05004923#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04004924#Const kLine_SegmentMask 1
Cary Clark682c58d2018-05-16 07:07:07 -04004925#Line # contains one or more Lines ##
Cary Clark73fa9722017-08-29 17:36:51 -04004926Set if Verb_Array contains kLine_Verb.
4927##
4928#Const kQuad_SegmentMask 2
Cary Clark682c58d2018-05-16 07:07:07 -04004929#Line # contains one or more Quads ##
Cary Clark73fa9722017-08-29 17:36:51 -04004930Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4931##
4932#Const kConic_SegmentMask 4
Cary Clark682c58d2018-05-16 07:07:07 -04004933#Line # contains one or more Conics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004934Set if Verb_Array contains kConic_Verb.
4935##
4936#Const kCubic_SegmentMask 8
Cary Clark682c58d2018-05-16 07:07:07 -04004937#Line # contains one or more Cubics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004938Set if Verb_Array contains kCubic_Verb.
4939##
4940
4941#Example
4942#Description
4943When conicTo has a weight of one, Quad is added to Path.
4944##
4945 SkPath path;
4946 path.conicTo(10, 10, 20, 30, 1);
Cary Clark682c58d2018-05-16 07:07:07 -04004947 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004948 SkPath::kConic_SegmentMask ? "set" : "clear");
Cary Clark682c58d2018-05-16 07:07:07 -04004949 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004950 SkPath::kQuad_SegmentMask ? "set" : "clear");
4951#StdOut
4952Path kConic_SegmentMask is clear
4953Path kQuad_SegmentMask is set
4954##
4955##
4956
4957#SeeAlso getSegmentMasks Verb
4958
4959##
4960
4961# ------------------------------------------------------------------------------
4962
Cary Clark682c58d2018-05-16 07:07:07 -04004963#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05004964#In Utility
4965#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004966#Line # returns types in Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004967Returns a mask, where each set bit corresponds to a SegmentMask constant
4968if Path contains one or more Verbs of that type.
4969Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
4970
4971getSegmentMasks() returns a cached result; it is very fast.
4972
4973#Return SegmentMask bits or zero ##
4974
4975#Example
4976SkPath path;
4977path.quadTo(20, 30, 40, 50);
4978path.close();
4979const char* masks[] = { "line", "quad", "conic", "cubic" };
4980int index = 0;
4981for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4982 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4983 if (mask & path.getSegmentMasks()) {
4984 SkDebugf("mask %s set\n", masks[index]);
Cary Clark682c58d2018-05-16 07:07:07 -04004985 }
Cary Clark73fa9722017-08-29 17:36:51 -04004986 ++index;
4987}
4988#StdOut
4989mask quad set
4990##
4991##
4992
4993#SeeAlso getSegmentMasks Verb
4994
4995##
4996
4997# ------------------------------------------------------------------------------
4998
4999#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05005000#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05005001#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04005002Returns true if the point (x, y) is contained by Path, taking into
Cary Clark682c58d2018-05-16 07:07:07 -04005003account FillType.
Cary Clark73fa9722017-08-29 17:36:51 -04005004
5005#Table
5006#Legend
5007# FillType # contains() returns true if Point is enclosed by ##
5008##
5009# kWinding_FillType # a non-zero sum of Contour Directions. ##
5010# kEvenOdd_FillType # an odd number of Contours. ##
5011# kInverseWinding_FillType # a zero sum of Contour Directions. ##
5012# kInverseEvenOdd_FillType # and even number of Contours. ##
Cary Clark682c58d2018-05-16 07:07:07 -04005013##
Cary Clark73fa9722017-08-29 17:36:51 -04005014
Cary Clark5538c132018-06-14 12:28:14 -04005015#Param x x-axis value of containment test ##
5016#Param y y-axis value of containment test ##
Cary Clark73fa9722017-08-29 17:36:51 -04005017
5018#Return true if Point is in Path ##
5019
5020#Example
5021SkPath path;
5022SkPaint paint;
5023paint.setTextSize(256);
5024paint.getTextPath("&", 1, 30, 220, &path);
5025for (int y = 2; y < 256; y += 9) {
5026 for (int x = 2; x < 256; x += 9) {
5027 int coverage = 0;
5028 for (int iy = -4; iy <= 4; iy += 2) {
5029 for (int ix = -4; ix <= 4; ix += 2) {
5030 coverage += path.contains(x + ix, y + iy);
5031 }
5032 }
5033 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5034 canvas->drawCircle(x, y, 8, paint);
5035 }
5036}
5037##
5038
5039#SeeAlso conservativelyContainsRect Fill_Type Op
5040
5041##
5042
5043# ------------------------------------------------------------------------------
5044
5045#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05005046#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005047#Line # sends text representation using floats to standard output ##
Cary Clark154beea2017-10-26 07:58:48 -04005048Writes text representation of Path to stream. If stream is nullptr, writes to
5049standard output. Set forceClose to true to get edges used to fill Path.
5050Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005051of floating point numbers used in Point_Array and Conic_Weights.
5052
5053#Param stream writable Stream receiving Path text representation; may be nullptr ##
5054#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005055#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005056
5057#Example
5058 SkPath path;
5059 path.quadTo(20, 30, 40, 50);
5060 for (bool forceClose : { false, true } ) {
5061 for (bool dumpAsHex : { false, true } ) {
5062 path.dump(nullptr, forceClose, dumpAsHex);
5063 SkDebugf("\n");
5064 }
5065 }
5066#StdOut
5067path.setFillType(SkPath::kWinding_FillType);
5068path.moveTo(0, 0);
5069path.quadTo(20, 30, 40, 50);
5070
5071path.setFillType(SkPath::kWinding_FillType);
5072path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5073path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5074
5075path.setFillType(SkPath::kWinding_FillType);
5076path.moveTo(0, 0);
5077path.quadTo(20, 30, 40, 50);
5078path.lineTo(0, 0);
5079path.close();
5080
5081path.setFillType(SkPath::kWinding_FillType);
5082path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5083path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5084path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5085path.close();
5086##
5087##
5088
5089#SeeAlso SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
5090
5091##
5092
5093# ------------------------------------------------------------------------------
5094
5095#Method void dump() const
5096
Cary Clarkce101242017-09-01 15:51:02 -04005097Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005098directly compiled as C++ code. Floating point values are written
5099with limited precision; it may not be possible to reconstruct original Path
5100from output.
5101
5102#Example
5103SkPath path, copy;
5104path.lineTo(6.f / 7, 2.f / 3);
5105path.dump();
5106copy.setFillType(SkPath::kWinding_FillType);
5107copy.moveTo(0, 0);
5108copy.lineTo(0.857143f, 0.666667f);
5109SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5110#StdOut
5111path.setFillType(SkPath::kWinding_FillType);
5112path.moveTo(0, 0);
5113path.lineTo(0.857143f, 0.666667f);
5114path is not equal to copy
5115##
5116##
5117
5118#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5119
5120##
5121
5122# ------------------------------------------------------------------------------
5123
5124#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05005125#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005126#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04005127Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005128directly compiled as C++ code. Floating point values are written
5129in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5130original Path.
5131
Cary Clark682c58d2018-05-16 07:07:07 -04005132Use instead of dump() when submitting
5133#A bug reports against Skia # https://bug.skia.org ##
Cary Clark6fc50412017-09-21 12:31:06 -04005134.
Cary Clark73fa9722017-08-29 17:36:51 -04005135
5136#Example
5137SkPath path, copy;
5138path.lineTo(6.f / 7, 2.f / 3);
5139path.dumpHex();
5140copy.setFillType(SkPath::kWinding_FillType);
5141copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5142copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5143SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5144#StdOut
5145path.setFillType(SkPath::kWinding_FillType);
5146path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5147path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5148path is equal to copy
5149##
5150##
5151
Cary Clark186d08f2018-04-03 08:43:27 -04005152#SeeAlso dump SkRect::dumpHex SkRRect::dumpHex writeToMemory
Cary Clark73fa9722017-08-29 17:36:51 -04005153
5154##
5155
5156# ------------------------------------------------------------------------------
5157
5158#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05005159#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005160#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005161Writes Path to buffer, returning the number of bytes written.
5162Pass nullptr to obtain the storage size.
5163
5164Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5165additionally writes computed information like Convexity and bounds.
5166
5167Use only be used in concert with readFromMemory;
5168the format used for Path in memory is not guaranteed.
5169
5170#Param buffer storage for Path; may be nullptr ##
5171
5172#Return size of storage required for Path; always a multiple of 4 ##
5173
5174#Example
5175void draw(SkCanvas* canvas) {
5176 SkPath path, copy;
5177 path.lineTo(6.f / 7, 2.f / 3);
5178 size_t size = path.writeToMemory(nullptr);
5179 SkTDArray<char> storage;
5180 storage.setCount(size);
5181 path.writeToMemory(storage.begin());
5182 copy.readFromMemory(storage.begin(), size);
5183 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5184}
5185#StdOut
5186path is equal to copy
5187##
5188##
5189
5190#SeeAlso serialize readFromMemory dump dumpHex
5191
5192##
5193
5194#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05005195#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005196#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005197Write Path to buffer, returning the buffer written to, wrapped in Data.
5198
5199serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5200additionally writes computed information like Convexity and bounds.
5201
5202serialize() should only be used in concert with readFromMemory.
5203The format used for Path in memory is not guaranteed.
5204
5205#Return Path data wrapped in Data buffer ##
5206
5207#Example
5208void draw(SkCanvas* canvas) {
5209 SkPath path, copy;
5210 path.lineTo(6.f / 7, 2.f / 3);
5211 sk_sp<SkData> data = path.serialize();
5212 copy.readFromMemory(data->data(), data->size());
5213 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5214}
5215#StdOut
5216path is equal to copy
5217##
5218##
5219
5220#SeeAlso writeToMemory readFromMemory dump dumpHex
5221##
5222
5223# ------------------------------------------------------------------------------
5224
5225#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05005226#In Utility
Cary Clark682c58d2018-05-16 07:07:07 -04005227#Line # initializes from buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005228Initializes Path from buffer of size length. Returns zero if the buffer is
Cary Clark682c58d2018-05-16 07:07:07 -04005229data is inconsistent, or the length is too small.
Cary Clark73fa9722017-08-29 17:36:51 -04005230
5231Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5232additionally reads computed information like Convexity and bounds.
5233
5234Used only in concert with writeToMemory;
5235the format used for Path in memory is not guaranteed.
5236
5237#Param buffer storage for Path ##
5238#Param length buffer size in bytes; must be multiple of 4 ##
5239
5240#Return number of bytes read, or zero on failure ##
5241
5242#Example
5243void draw(SkCanvas* canvas) {
5244 SkPath path, copy;
5245 path.lineTo(6.f / 7, 2.f / 3);
5246 size_t size = path.writeToMemory(nullptr);
5247 SkTDArray<char> storage;
5248 storage.setCount(size);
5249 path.writeToMemory(storage.begin());
5250 size_t wrongSize = size - 4;
5251 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5252 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5253 size_t largerSize = size + 4;
5254 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5255 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5256}
5257#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005258length = 32; returned by readFromMemory = 0
Cary Clark06c20f32018-03-20 15:53:27 -04005259length = 40; returned by readFromMemory = 36
Cary Clark73fa9722017-08-29 17:36:51 -04005260##
5261##
5262
5263#SeeAlso writeToMemory
5264
5265##
5266
5267# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05005268#Subtopic Generation_ID
Cary Clark137b8742018-05-30 09:21:49 -04005269#Alias Generation_IDs ##
Cary Clark08895c42018-02-01 09:37:32 -05005270#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04005271Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5272Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5273not necessarily have matching Generation_IDs.
5274
5275Empty Paths have a Generation_ID of one.
5276
5277#Method uint32_t getGenerationID() const
5278
Cary Clarkab2621d2018-01-30 10:08:57 -05005279#In Generation_ID
5280#Line # returns unique ID ##
Cary Clark682c58d2018-05-16 07:07:07 -04005281Returns a non-zero, globally unique value. A different value is returned
Cary Clark73fa9722017-08-29 17:36:51 -04005282if Verb_Array, Point_Array, or Conic_Weight changes.
5283
5284Setting Fill_Type does not change Generation_ID.
5285
5286Each time the path is modified, a different Generation_ID will be returned.
5287
5288#Bug 1762
5289Fill_Type does affect Generation_ID on Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -04005290
5291#Return non-zero, globally unique value ##
5292
5293#Example
5294SkPath path;
5295SkDebugf("empty genID = %u\n", path.getGenerationID());
5296path.lineTo(1, 2);
5297SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5298path.rewind();
5299SkDebugf("empty genID = %u\n", path.getGenerationID());
5300path.lineTo(1, 2);
5301SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5302#StdOut
5303empty genID = 1
53041st lineTo genID = 2
5305empty genID = 1
53062nd lineTo genID = 3
5307##
5308##
5309
5310#SeeAlso operator==(const SkPath& a, const SkPath& b)
5311
5312##
5313
Cary Clark78de7512018-02-07 07:27:09 -05005314#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04005315
5316# ------------------------------------------------------------------------------
5317
5318#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005319#In Property
5320#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005321#Line # returns if data is internally consistent ##
Cary Clark73fa9722017-08-29 17:36:51 -04005322 Returns if Path data is consistent. Corrupt Path data is detected if
5323 internal values are out of range or internal storage does not match
5324 array dimensions.
5325
5326 #Return true if Path data is consistent ##
5327
5328 #NoExample
5329 ##
5330
5331##
5332
5333#Method bool pathRefIsValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005334#Deprecated soon
Cary Clark73fa9722017-08-29 17:36:51 -04005335##
5336
5337# ------------------------------------------------------------------------------
5338
Cary Clark8032b982017-07-28 11:04:54 -04005339#Class Iter
Cary Clark682c58d2018-05-16 07:07:07 -04005340#Line # data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005341
Cary Clark73fa9722017-08-29 17:36:51 -04005342#Code
5343class Iter {
5344public:
5345 Iter();
5346 Iter(const SkPath& path, bool forceClose);
5347 void setPath(const SkPath& path, bool forceClose);
5348 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5349 SkScalar conicWeight() const;
5350 bool isCloseLine() const;
5351 bool isClosedContour() const;
5352};
5353##
5354
Cary Clark137b8742018-05-30 09:21:49 -04005355Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5356Provides options to treat open Contours as closed, and to ignore
5357degenerate data.
5358
Cary Clark8032b982017-07-28 11:04:54 -04005359#Example
5360#Height 128
5361#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005362Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005363path of the glyph.
5364##
Cary Clark73fa9722017-08-29 17:36:51 -04005365void draw(SkCanvas* canvas) {
5366 SkPaint paint;
5367 paint.setAntiAlias(true);
5368 paint.setTextSize(256);
5369 SkPath asterisk, path;
5370 paint.getTextPath("*", 1, 50, 192, &asterisk);
Cary Clark682c58d2018-05-16 07:07:07 -04005371 SkPath::Iter iter(asterisk, true);
Cary Clark73fa9722017-08-29 17:36:51 -04005372 SkPoint start[4], pts[4];
5373 iter.next(start); // skip moveTo
5374 iter.next(start); // first quadTo
5375 path.moveTo((start[0] + start[1]) * 0.5f);
5376 while (SkPath::kClose_Verb != iter.next(pts)) {
5377 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5378 }
5379 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5380 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005381}
5382##
5383
5384#SeeAlso RawIter
5385
5386#Method Iter()
Cary Clark682c58d2018-05-16 07:07:07 -04005387#Line # constructs Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005388Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5389Call setPath to initialize Iter at a later time.
5390
Cary Clark73fa9722017-08-29 17:36:51 -04005391#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005392
5393#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005394void draw(SkCanvas* canvas) {
5395 SkPath::Iter iter;
5396 SkPoint points[4];
5397 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5398 SkPath path;
5399 iter.setPath(path, false);
5400 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005401}
Cary Clark73fa9722017-08-29 17:36:51 -04005402#StdOut
5403iter is done
5404iter is done
5405##
Cary Clark8032b982017-07-28 11:04:54 -04005406##
5407
5408#SeeAlso setPath
5409
5410##
5411
5412#Method Iter(const SkPath& path, bool forceClose)
5413
5414Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5415If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5416open Contour. path is not altered.
5417
Cary Clark73fa9722017-08-29 17:36:51 -04005418#Param path Path to iterate ##
5419#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005420
Cary Clark73fa9722017-08-29 17:36:51 -04005421#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005422
5423#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005424void draw(SkCanvas* canvas) {
5425 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5426 SkDebugf("%s:\n", prefix);
5427 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5428 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5429 SkPath::Verb verb;
5430 do {
5431 SkPoint points[4];
5432 verb = iter.next(points);
5433 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5434 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5435 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5436 }
5437 if (SkPath::kConic_Verb == verb) {
5438 SkDebugf("weight = %g", iter.conicWeight());
5439 }
5440 SkDebugf("\n");
5441 } while (SkPath::kDone_Verb != verb);
5442 SkDebugf("\n");
5443 };
5444
5445 SkPath path;
5446 path.quadTo(10, 20, 30, 40);
5447 SkPath::Iter openIter(path, false);
5448 debugster("open", openIter);
5449 SkPath::Iter closedIter(path, true);
5450 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005451}
5452#StdOut
5453open:
Cary Clark682c58d2018-05-16 07:07:07 -04005454kMove_Verb {0, 0},
5455kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5456kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005457
5458closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005459kMove_Verb {0, 0},
5460kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5461kLine_Verb {30, 40}, {0, 0},
5462kClose_Verb {0, 0},
5463kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005464##
5465##
5466
5467#SeeAlso setPath
5468
5469##
5470
5471#Method void setPath(const SkPath& path, bool forceClose)
5472
5473Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5474If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5475open Contour. path is not altered.
5476
Cary Clark73fa9722017-08-29 17:36:51 -04005477#Param path Path to iterate ##
5478#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005479
5480#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005481void draw(SkCanvas* canvas) {
5482 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5483 SkDebugf("%s:\n", prefix);
5484 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5485 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5486 SkPath::Verb verb;
5487 do {
5488 SkPoint points[4];
5489 verb = iter.next(points);
5490 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5491 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5492 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5493 }
5494 if (SkPath::kConic_Verb == verb) {
5495 SkDebugf("weight = %g", iter.conicWeight());
5496 }
5497 SkDebugf("\n");
5498 } while (SkPath::kDone_Verb != verb);
5499 SkDebugf("\n");
5500 };
5501
5502 SkPath path;
5503 path.quadTo(10, 20, 30, 40);
5504 SkPath::Iter iter(path, false);
5505 debugster("quad open", iter);
5506 SkPath path2;
5507 path2.conicTo(1, 2, 3, 4, .5f);
5508 iter.setPath(path2, true);
5509 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005510}
5511#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005512quad open:
Cary Clark682c58d2018-05-16 07:07:07 -04005513kMove_Verb {0, 0},
5514kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5515kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005516
5517conic closed:
Cary Clark682c58d2018-05-16 07:07:07 -04005518kMove_Verb {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04005519kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005520kLine_Verb {3, 4}, {0, 0},
5521kClose_Verb {0, 0},
5522kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005523##
5524##
5525
5526#SeeAlso Iter(const SkPath& path, bool forceClose)
5527
5528##
5529
Cary Clark682c58d2018-05-16 07:07:07 -04005530#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
Cary Clark8032b982017-07-28 11:04:54 -04005531
Cary Clarka523d2d2017-08-30 08:58:10 -04005532Returns next Verb in Verb_Array, and advances Iter.
5533When Verb_Array is exhausted, returns kDone_Verb.
5534
Cary Clark8032b982017-07-28 11:04:54 -04005535Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005536
Cary Clark8032b982017-07-28 11:04:54 -04005537If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5538only the last in the series; and skip very small Lines, Quads, and Conics; and
5539skip kClose_Verb following kMove_Verb.
5540if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5541Conics with zero lengths.
5542
Cary Clarka523d2d2017-08-30 08:58:10 -04005543 #Param pts storage for Point data describing returned Verb ##
5544 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5545 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005546
Cary Clark73fa9722017-08-29 17:36:51 -04005547 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005548
5549#Example
Cary Clark682c58d2018-05-16 07:07:07 -04005550#Description
Cary Clark8032b982017-07-28 11:04:54 -04005551skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5552followed by the kClose_Verb, the zero length Line and the very small Line.
5553
5554skip degenerate if exact skips the same as skip degenerate, but shows
5555the very small Line.
5556
5557skip none shows all of the Verbs and Points in Path.
5558##
Cary Clark73fa9722017-08-29 17:36:51 -04005559void draw(SkCanvas* canvas) {
5560 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5561 SkPath::Iter iter(path, false);
5562 SkDebugf("%s:\n", prefix);
5563 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5564 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5565 SkPath::Verb verb;
5566 do {
5567 SkPoint points[4];
5568 verb = iter.next(points, degen, exact);
5569 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5570 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5571 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5572 }
5573 SkDebugf("\n");
5574 } while (SkPath::kDone_Verb != verb);
5575 SkDebugf("\n");
5576 };
5577
5578 SkPath path;
5579 path.moveTo(10, 10);
5580 path.moveTo(20, 20);
5581 path.quadTo(10, 20, 30, 40);
5582 path.moveTo(1, 1);
5583 path.close();
5584 path.moveTo(30, 30);
5585 path.lineTo(30, 30);
5586 path.moveTo(30, 30);
5587 path.lineTo(30.00001f, 30);
5588 debugster("skip degenerate", path, true, false);
5589 debugster("skip degenerate if exact", path, true, true);
5590 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005591}
5592#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005593skip degenerate:
Cary Clark682c58d2018-05-16 07:07:07 -04005594kMove_Verb {20, 20},
5595kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5596kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005597
5598skip degenerate if exact:
Cary Clark682c58d2018-05-16 07:07:07 -04005599kMove_Verb {20, 20},
5600kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5601kMove_Verb {30, 30},
5602kLine_Verb {30, 30}, {30.00001, 30},
5603kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04005604
5605skip none:
Cary Clark682c58d2018-05-16 07:07:07 -04005606kMove_Verb {10, 10},
5607kMove_Verb {20, 20},
5608kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5609kMove_Verb {1, 1},
5610kClose_Verb {1, 1},
5611kMove_Verb {30, 30},
5612kLine_Verb {30, 30}, {30, 30},
5613kMove_Verb {30, 30},
5614kLine_Verb {30, 30}, {30.00001, 30},
5615kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005616##
5617##
5618
Cary Clark682c58d2018-05-16 07:07:07 -04005619#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
Cary Clark8032b982017-07-28 11:04:54 -04005620
5621##
5622
5623#Method SkScalar conicWeight() const
5624
5625 Returns Conic_Weight if next() returned kConic_Verb.
5626
5627 If next() has not been called, or next() did not return kConic_Verb,
5628 result is undefined.
5629
Cary Clark73fa9722017-08-29 17:36:51 -04005630 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005631
5632 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005633 void draw(SkCanvas* canvas) {
5634 SkPath path;
5635 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005636 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005637 SkPoint p[4];
5638 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5639 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5640 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5641 p[2].fX, p[2].fY);
5642 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005643 }
5644 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005645first verb is move
5646next verb is conic
5647conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005648conic weight: 0.5
5649 ##
5650 ##
5651
5652 #SeeAlso Conic_Weight
5653
5654##
5655
5656#Method bool isCloseLine() const
Cary Clark682c58d2018-05-16 07:07:07 -04005657#Line # returns if Line was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005658 Returns true if last kLine_Verb returned by next() was generated
5659 by kClose_Verb. When true, the end point returned by next() is
5660 also the start point of Contour.
5661
5662 If next() has not been called, or next() did not return kLine_Verb,
5663 result is undefined.
5664
Cary Clark73fa9722017-08-29 17:36:51 -04005665 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005666
5667 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005668void draw(SkCanvas* canvas) {
5669 SkPath path;
5670 path.moveTo(6, 7);
5671 path.conicTo(1, 2, 3, 4, .5f);
5672 path.close();
Cary Clark682c58d2018-05-16 07:07:07 -04005673 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04005674 SkPoint p[4];
5675 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5676 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5677 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5678 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5679 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5680 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5681 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005682}
5683 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040056841st verb is move
5685moveTo point: {6,7}
56862nd verb is conic
56873rd verb is line
5688line points: {3,4}, {6,7}
5689line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040056904th verb is close
5691 ##
5692 ##
5693
5694 #SeeAlso close()
5695##
5696
5697#Method bool isClosedContour() const
Cary Clark682c58d2018-05-16 07:07:07 -04005698#Line # returns if Contour has kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005699Returns true if subsequent calls to next() return kClose_Verb before returning
5700kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5701Iter may have been initialized with force close set to true.
5702
Cary Clark73fa9722017-08-29 17:36:51 -04005703#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005704
5705#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005706void draw(SkCanvas* canvas) {
5707 for (bool forceClose : { false, true } ) {
5708 SkPath path;
5709 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005710 SkPath::Iter iter(path, forceClose);
Cary Clark73fa9722017-08-29 17:36:51 -04005711 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5712 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5713 path.close();
5714 iter.setPath(path, forceClose);
5715 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5716 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5717 }
Cary Clark8032b982017-07-28 11:04:54 -04005718}
5719#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005720without close(), forceClose is false: isClosedContour returns false
5721with close(), forceClose is false: isClosedContour returns true
5722without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005723with close(), forceClose is true : isClosedContour returns true
5724##
5725##
5726
5727#SeeAlso Iter(const SkPath& path, bool forceClose)
5728
5729##
Cary Clark73fa9722017-08-29 17:36:51 -04005730
5731#Class Iter ##
5732
Cary Clark8032b982017-07-28 11:04:54 -04005733#Class RawIter
Cary Clark682c58d2018-05-16 07:07:07 -04005734#Line # raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005735
Cary Clark73fa9722017-08-29 17:36:51 -04005736#Code
5737 class RawIter {
5738 public:
5739 RawIter();
5740 RawIter(const SkPath& path);
5741 void setPath(const SkPath& path);
5742 Verb next(SkPoint pts[4]);
5743 Verb peek() const;
5744 SkScalar conicWeight() const;
5745 }
5746##
5747
Cary Clark137b8742018-05-30 09:21:49 -04005748Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5749Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5750
Cary Clark8032b982017-07-28 11:04:54 -04005751 #Method RawIter()
Cary Clark682c58d2018-05-16 07:07:07 -04005752 #Line # constructs empty Path iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005753
5754 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
Cary Clark78c110e2018-02-09 16:49:09 -05005755 Call setPath to initialize SkPath::Iter at a later time.
Cary Clark8032b982017-07-28 11:04:54 -04005756
Cary Clark73fa9722017-08-29 17:36:51 -04005757 #Return RawIter of empty Path ##
5758
5759 #NoExample
5760 ##
5761 ##
Cary Clark8032b982017-07-28 11:04:54 -04005762
5763 #Method RawIter(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005764 #Line # constructs with Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005765
5766
5767 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5768
Cary Clark73fa9722017-08-29 17:36:51 -04005769 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005770
Cary Clark73fa9722017-08-29 17:36:51 -04005771 #Return RawIter of path ##
5772
5773 #NoExample
5774 ##
5775 ##
Cary Clark8032b982017-07-28 11:04:54 -04005776
5777 #Method void setPath(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04005778 #Line # sets Path to iterate over ##
Cary Clark8032b982017-07-28 11:04:54 -04005779
Cary Clark78c110e2018-02-09 16:49:09 -05005780 Sets SkPath::Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
Cary Clark8032b982017-07-28 11:04:54 -04005781
Cary Clark73fa9722017-08-29 17:36:51 -04005782 #Param path Path to iterate ##
5783
5784 #NoExample
5785 ##
5786 ##
Cary Clark8032b982017-07-28 11:04:54 -04005787
5788 #Method Verb next(SkPoint pts[4])
Cary Clark682c58d2018-05-16 07:07:07 -04005789 #Line # returns next Verb and associated Points ##
Cary Clark8032b982017-07-28 11:04:54 -04005790 Returns next Verb in Verb_Array, and advances RawIter.
5791 When Verb_Array is exhausted, returns kDone_Verb.
5792 Zero to four Points are stored in pts, depending on the returned Verb.
5793
Cary Clarka523d2d2017-08-30 08:58:10 -04005794 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005795
Cary Clark73fa9722017-08-29 17:36:51 -04005796 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005797
5798 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005799 void draw(SkCanvas* canvas) {
5800 SkPath path;
5801 path.moveTo(50, 60);
5802 path.quadTo(10, 20, 30, 40);
5803 path.close();
5804 path.lineTo(30, 30);
5805 path.conicTo(1, 2, 3, 4, .5f);
5806 path.cubicTo(-1, -2, -3, -4, -5, -6);
5807 SkPath::RawIter iter(path);
5808 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5809 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5810 SkPath::Verb verb;
5811 do {
5812 SkPoint points[4];
5813 verb = iter.next(points);
5814 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5815 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5816 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5817 }
5818 if (SkPath::kConic_Verb == verb) {
5819 SkDebugf("weight = %g", iter.conicWeight());
5820 }
5821 SkDebugf("\n");
5822 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005823 }
5824 #StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04005825 kMove_Verb {50, 60},
5826 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5827 kClose_Verb {50, 60},
5828 kMove_Verb {50, 60},
5829 kLine_Verb {50, 60}, {30, 30},
Cary Clark73fa9722017-08-29 17:36:51 -04005830 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04005831 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
5832 kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005833 ##
5834 ##
5835
5836 #SeeAlso peek()
5837
Cary Clark73fa9722017-08-29 17:36:51 -04005838 ##
Cary Clark8032b982017-07-28 11:04:54 -04005839
5840 #Method Verb peek() const
Cary Clark682c58d2018-05-16 07:07:07 -04005841 #Line # returns next Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005842 Returns next Verb, but does not advance RawIter.
5843
Cary Clark73fa9722017-08-29 17:36:51 -04005844 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005845
5846 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005847 SkPath path;
5848 path.quadTo(10, 20, 30, 40);
5849 path.conicTo(1, 2, 3, 4, .5f);
5850 path.cubicTo(1, 2, 3, 4, .5, 6);
5851 SkPath::RawIter iter(path);
5852 SkPath::Verb verb, peek = iter.peek();
5853 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5854 do {
5855 SkPoint points[4];
5856 verb = iter.next(points);
5857 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5858 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005859 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005860 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5861 #StdOut
5862 #Volatile
5863 peek Move == verb Move
5864 peek Quad == verb Quad
5865 peek Conic == verb Conic
5866 peek Cubic == verb Cubic
5867 peek Done == verb Done
5868 peek Done == verb Done
5869 ##
Cary Clark8032b982017-07-28 11:04:54 -04005870 ##
5871
5872 #Bug 6832
Cary Clark682c58d2018-05-16 07:07:07 -04005873 StdOut is not really volatile, it just produces the wrong result.
Cary Clark8032b982017-07-28 11:04:54 -04005874 A simple fix changes the output of hairlines and needs to be
5875 investigated to see if the change is correct or not.
Cary Clark682c58d2018-05-16 07:07:07 -04005876 see change 21340 (abandoned for now)
Cary Clark8032b982017-07-28 11:04:54 -04005877
5878 #SeeAlso next()
5879
Cary Clark73fa9722017-08-29 17:36:51 -04005880 ##
Cary Clark8032b982017-07-28 11:04:54 -04005881
Cary Clark73fa9722017-08-29 17:36:51 -04005882 #Method SkScalar conicWeight() const
Cary Clark682c58d2018-05-16 07:07:07 -04005883 #Line # returns Conic_Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04005884
Cary Clark8032b982017-07-28 11:04:54 -04005885 Returns Conic_Weight if next() returned kConic_Verb.
5886
5887 If next() has not been called, or next() did not return kConic_Verb,
5888 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04005889
5890 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005891
5892 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005893 void draw(SkCanvas* canvas) {
5894 SkPath path;
5895 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04005896 SkPath::RawIter iter(path);
Cary Clark73fa9722017-08-29 17:36:51 -04005897 SkPoint p[4];
5898 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5899 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5900 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5901 p[2].fX, p[2].fY);
5902 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005903 }
5904 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005905 first verb is move
5906 next verb is conic
5907 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005908 conic weight: 0.5
5909 ##
5910 ##
5911
5912 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04005913
5914 ##
5915
5916#Class RawIter ##
5917
5918#Class SkPath ##
5919
5920#Topic Path ##
Cary Clark4855f782018-02-06 09:41:53 -05005921