blob: 03a51d6428ba2f8a300552c76bb24197e3ef8e88 [file] [log] [blame]
Cary Clark73fa9722017-08-29 17:36:51 -04001#Topic Path
2#Alias Path_Reference
3#Alias Paths
4
Cary Clark08895c42018-02-01 09:37:32 -05005#Subtopic Overview
Cary Clark4855f782018-02-06 09:41:53 -05006 #Subtopic Subtopic
Cary Clark08895c42018-02-01 09:37:32 -05007 #Populate
8 ##
9##
10
Cary Clark73fa9722017-08-29 17:36:51 -040011Path contains Lines and Curves which can be stroked or filled. Contour is
12composed of a series of connected Lines and Curves. Path may contain zero,
13one, or more Contours.
14Each Line and Curve are described by Verb, Points, and optional Conic_Weight.
15
16Each pair of connected Lines and Curves share common Point; for instance, Path
17containing two connected Lines are described the Verb sequence:
18SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb; and a Point sequence
19with three entries, sharing
20the middle entry as the end of the first Line and the start of the second Line.
21
22Path components Arc, Rect, Round_Rect, Circle, and Oval are composed of
23Lines and Curves with as many Verbs and Points required
24for an exact description. Once added to Path, these components may lose their
Cary Clarkce101242017-09-01 15:51:02 -040025identity; although Path can be inspected to determine if it describes a single
Cary Clark73fa9722017-08-29 17:36:51 -040026Rect, Oval, Round_Rect, and so on.
27
28#Example
29#Height 192
30#Description
31Path contains three Contours: Line, Circle, and Quad. Line is stroked but
32not filled. Circle is stroked and filled; Circle stroke forms a loop. Quad
33is stroked and filled, but since it is not closed, Quad does not stroke a loop.
34##
35void draw(SkCanvas* canvas) {
36 SkPaint paint;
37 paint.setAntiAlias(true);
38 SkPath path;
39 path.moveTo(124, 108);
40 path.lineTo(172, 24);
41 path.addCircle(50, 50, 30);
42 path.moveTo(36, 148);
43 path.quadTo(66, 188, 120, 136);
44 canvas->drawPath(path, paint);
45 paint.setStyle(SkPaint::kStroke_Style);
46 paint.setColor(SK_ColorBLUE);
47 paint.setStrokeWidth(3);
48 canvas->drawPath(path, paint);
49}
50##
51
52Path contains a Fill_Type which determines whether overlapping Contours
53form fills or holes. Fill_Type also determines whether area inside or outside
54Lines and Curves is filled.
55
56#Example
57#Height 192
58#Description
59Path is drawn filled, then stroked, then stroked and filled.
60##
61void draw(SkCanvas* canvas) {
62 SkPaint paint;
63 paint.setAntiAlias(true);
64 SkPath path;
65 path.moveTo(36, 48);
66 path.quadTo(66, 88, 120, 36);
67 canvas->drawPath(path, paint);
68 paint.setStyle(SkPaint::kStroke_Style);
69 paint.setColor(SK_ColorBLUE);
70 paint.setStrokeWidth(8);
71 canvas->translate(0, 50);
72 canvas->drawPath(path, paint);
73 paint.setStyle(SkPaint::kStrokeAndFill_Style);
74 paint.setColor(SK_ColorRED);
75 canvas->translate(0, 50);
76 canvas->drawPath(path, paint);
77}
78##
79
80Path contents are never shared. Copying Path by value effectively creates
81a new Path independent of the original. Internally, the copy does not duplicate
82its contents until it is edited, to reduce memory use and improve performance.
83
Cary Clark8032b982017-07-28 11:04:54 -040084#Subtopic Contour
85#Alias Contours
Cary Clark08895c42018-02-01 09:37:32 -050086#Line # loop of lines and curves ##
87
Cary Clark8032b982017-07-28 11:04:54 -040088Contour contains one or more Verbs, and as many Points as
89are required to satisfy Verb_Array. First Verb in Path is always
90SkPath::kMove_Verb; each SkPath::kMove_Verb that follows starts a new Contour.
91
92#Example
Cary Clark73fa9722017-08-29 17:36:51 -040093#Description
94Each SkPath::moveTo starts a new Contour, and content after SkPath::close()
Cary Clarkce101242017-09-01 15:51:02 -040095also starts a new Contour. Since SkPath::conicTo is not preceded by
Cary Clark73fa9722017-08-29 17:36:51 -040096SkPath::moveTo, the first Point of the third Contour starts at the last Point
97of the second Contour.
98##
99#Height 192
100 SkPaint paint;
101 paint.setAntiAlias(true);
102 canvas->drawString("1st contour", 150, 100, paint);
103 canvas->drawString("2nd contour", 130, 160, paint);
104 canvas->drawString("3rd contour", 40, 30, paint);
105 paint.setStyle(SkPaint::kStroke_Style);
106 SkPath path;
107 path.moveTo(124, 108);
108 path.lineTo(172, 24);
109 path.moveTo(36, 148);
110 path.quadTo(66, 188, 120, 136);
111 path.close();
112 path.conicTo(70, 20, 110, 40, 0.6f);
113 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -0400114##
115
116If final Verb in Contour is SkPath::kClose_Verb, Line connects Last_Point in
117Contour with first Point. A closed Contour, stroked, draws
118Paint_Stroke_Join at Last_Point and first Point. Without SkPath::kClose_Verb
119as final Verb, Last_Point and first Point are not connected; Contour
120remains open. An open Contour, stroked, draws Paint_Stroke_Cap at
121Last_Point and first Point.
122
123#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400124#Height 160
125#Description
126Path is drawn stroked, with an open Contour and a closed Contour.
127##
128void draw(SkCanvas* canvas) {
129 SkPaint paint;
130 paint.setAntiAlias(true);
131 paint.setStyle(SkPaint::kStroke_Style);
132 paint.setStrokeWidth(8);
133 SkPath path;
134 path.moveTo(36, 48);
135 path.quadTo(66, 88, 120, 36);
136 canvas->drawPath(path, paint);
137 path.close();
138 canvas->translate(0, 50);
139 canvas->drawPath(path, paint);
140}
Cary Clark8032b982017-07-28 11:04:54 -0400141##
142
143#Subtopic Zero_Length
144#Alias Zero_Length_Contour
Cary Clark08895c42018-02-01 09:37:32 -0500145#Line # consideration when contour has no length ##
Cary Clark8032b982017-07-28 11:04:54 -0400146Contour length is distance traveled from first Point to Last_Point,
147plus, if Contour is closed, distance from Last_Point to first Point.
148Even if Contour length is zero, stroked Lines are drawn if Paint_Stroke_Cap
149makes them visible.
150
151#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400152#Height 64
153 SkPaint paint;
154 paint.setAntiAlias(true);
155 paint.setStyle(SkPaint::kStroke_Style);
156 paint.setStrokeWidth(8);
157 paint.setStrokeCap(SkPaint::kRound_Cap);
158 SkPath path;
159 path.moveTo(36, 48);
160 path.lineTo(36, 48);
161 canvas->drawPath(path, paint);
162 path.reset();
163 paint.setStrokeCap(SkPaint::kSquare_Cap);
164 path.moveTo(56, 48);
165 path.close();
Cary Clark8032b982017-07-28 11:04:54 -0400166 canvas->drawPath(path, paint);
167##
168
169#Subtopic Zero_Length ##
170
171#Subtopic Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -0400172
173# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400174
Cary Clark73fa9722017-08-29 17:36:51 -0400175#Class SkPath
176
177Paths contain geometry. Paths may be empty, or contain one or more Verbs that
Cary Clarka560c472017-11-27 10:44:06 -0500178outline a figure. Path always starts with a move verb to a Cartesian_Coordinate,
179and may be followed by additional verbs that add lines or curves.
Cary Clark73fa9722017-08-29 17:36:51 -0400180Adding a close verb makes the geometry into a continuous loop, a closed contour.
Cary Clarkce101242017-09-01 15:51:02 -0400181Paths may contain any number of contours, each beginning with a move verb.
Cary Clark73fa9722017-08-29 17:36:51 -0400182
183Path contours may contain only a move verb, or may also contain lines,
Cary Clarkce101242017-09-01 15:51:02 -0400184Quadratic_Beziers, Conics, and Cubic_Beziers. Path contours may be open or
Cary Clark73fa9722017-08-29 17:36:51 -0400185closed.
186
187When used to draw a filled area, Path describes whether the fill is inside or
188outside the geometry. Path also describes the winding rule used to fill
189overlapping contours.
190
191Internally, Path lazily computes metrics likes bounds and convexity. Call
192SkPath::updateBoundsCache to make Path thread safe.
193
Cary Clark4855f782018-02-06 09:41:53 -0500194#Subtopic Related_Function
Cary Clark08895c42018-02-01 09:37:32 -0500195#Populate
196##
Cary Clark5081eed2018-01-22 07:55:48 -0500197
Cary Clark4855f782018-02-06 09:41:53 -0500198#Subtopic Constant
Cary Clark08895c42018-02-01 09:37:32 -0500199#Populate
200##
Cary Clark73fa9722017-08-29 17:36:51 -0400201
Cary Clark4855f782018-02-06 09:41:53 -0500202#Subtopic Class_or_Struct
Cary Clark08895c42018-02-01 09:37:32 -0500203#Populate
204##
Cary Clark73fa9722017-08-29 17:36:51 -0400205
Cary Clark4855f782018-02-06 09:41:53 -0500206#Subtopic Constructor
Cary Clark08895c42018-02-01 09:37:32 -0500207#Populate
208##
Cary Clark8032b982017-07-28 11:04:54 -0400209
Cary Clark4855f782018-02-06 09:41:53 -0500210#Subtopic Operator
Cary Clark08895c42018-02-01 09:37:32 -0500211#Populate
212##
Cary Clark73fa9722017-08-29 17:36:51 -0400213
Cary Clark4855f782018-02-06 09:41:53 -0500214#Subtopic Member_Function
Cary Clark08895c42018-02-01 09:37:32 -0500215#Populate
216##
Cary Clark73fa9722017-08-29 17:36:51 -0400217
Cary Clark8032b982017-07-28 11:04:54 -0400218#Subtopic Verb
219#Alias Verbs
Cary Clark08895c42018-02-01 09:37:32 -0500220#Line # line and curve type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400221#Enum Verb
Cary Clark08895c42018-02-01 09:37:32 -0500222#Line # controls how Path Points are interpreted ##
Cary Clark73fa9722017-08-29 17:36:51 -0400223
224#Code
225 enum Verb {
226 kMove_Verb,
227 kLine_Verb,
228 kQuad_Verb,
229 kConic_Verb,
230 kCubic_Verb,
231 kClose_Verb,
232 kDone_Verb,
233 };
234##
235
236Verb instructs Path how to interpret one or more Point and optional Conic_Weight;
Cary Clark8032b982017-07-28 11:04:54 -0400237manage Contour, and terminate Path.
238
Cary Clark73fa9722017-08-29 17:36:51 -0400239#Const kMove_Verb 0
240 Starts new Contour at next Point.
241##
242#Const kLine_Verb 1
243 Adds Line from Last_Point to next Point.
244 Line is a straight segment from Point to Point.
245##
246#Const kQuad_Verb 2
247 Adds Quad from Last_Point, using control Point, and end Point.
248 Quad is a parabolic section within tangents from Last_Point to control Point,
249 and control Point to end Point.
250##
251#Const kConic_Verb 3
252 Adds Conic from Last_Point, using control Point, end Point, and Conic_Weight.
253 Conic is a elliptical, parabolic, or hyperbolic section within tangents
254 from Last_Point to control Point, and control Point to end Point, constrained
255 by Conic_Weight. Conic_Weight less than one is elliptical; equal to one is
256 parabolic (and identical to Quad); greater than one hyperbolic.
257##
258#Const kCubic_Verb 4
259 Adds Cubic from Last_Point, using two control Points, and end Point.
Cary Clarka560c472017-11-27 10:44:06 -0500260 Cubic is a third-order Bezier_Curve section within tangents from Last_Point
261 to first control Point, and from second control Point to end Point.
Cary Clark73fa9722017-08-29 17:36:51 -0400262##
263#Const kClose_Verb 5
264 Closes Contour, connecting Last_Point to kMove_Verb Point.
265##
266#Const kDone_Verb 6
267 Terminates Path. Not in Verb_Array, but returned by Path iterator.
Cary Clark8032b982017-07-28 11:04:54 -0400268##
269
270Each Verb has zero or more Points stored in Path.
271Path iterator returns complete curve descriptions, duplicating shared Points
272for consecutive entries.
273
274#Table
275#Legend
276# Verb # Allocated Points # Iterated Points # Weights ##
277##
278# kMove_Verb # 1 # 1 # 0 ##
279# kLine_Verb # 1 # 2 # 0 ##
280# kQuad_Verb # 2 # 3 # 0 ##
281# kConic_Verb # 2 # 3 # 1 ##
282# kCubic_Verb # 3 # 4 # 0 ##
283# kClose_Verb # 0 # 1 # 0 ##
284# kDone_Verb # -- # 0 # 0 ##
285##
Cary Clark73fa9722017-08-29 17:36:51 -0400286
287#Example
288void draw(SkCanvas* canvas) {
289 SkPath path;
290 path.lineTo(20, 20);
291 path.quadTo(-10, -10, 30, 30);
292 path.close();
293 path.cubicTo(1, 2, 3, 4, 5, 6);
294 path.conicTo(0, 0, 0, 0, 2);
295 uint8_t verbs[7];
296 int count = path.getVerbs(verbs, (int) SK_ARRAY_COUNT(verbs));
297 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close" };
298 SkDebugf("verb count: %d\nverbs: ", count);
299 for (int i = 0; i < count; ++i) {
300 SkDebugf("k%s_Verb ", verbStr[verbs[i]]);
301 }
302 SkDebugf("\n");
303}
304#StdOut
305verb count: 7
306verbs: kMove_Verb kLine_Verb kQuad_Verb kClose_Verb kMove_Verb kCubic_Verb kConic_Verb
307##
308##
309
310#Enum Verb ##
311#Subtopic Verb ##
312
313# ------------------------------------------------------------------------------
314#Subtopic Direction
Cary Clark08895c42018-02-01 09:37:32 -0500315#Line # Path contour orientation ##
Cary Clark73fa9722017-08-29 17:36:51 -0400316#Alias Directions
317
318#Enum Direction
Cary Clark08895c42018-02-01 09:37:32 -0500319#Line # sets Contour clockwise or counterclockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400320
321#Code
322 enum Direction {
323 kCW_Direction,
324 kCCW_Direction,
325 };
326##
327
328Direction describes whether Contour is clockwise or counterclockwise.
329When Path contains multiple overlapping Contours, Direction together with
330Fill_Type determines whether overlaps are filled or form holes.
331
332Direction also determines how Contour is measured. For instance, dashing
333measures along Path to determine where to start and stop stroke; Direction
334will change dashed results as it steps clockwise or counterclockwise.
335
336Closed Contours like Rect, Round_Rect, Circle, and Oval added with
337kCW_Direction travel clockwise; the same added with kCCW_Direction
338travel counterclockwise.
339
340#Const kCW_Direction 0
Cary Clark154beea2017-10-26 07:58:48 -0400341 Contour travels in a clockwise direction
Cary Clark73fa9722017-08-29 17:36:51 -0400342##
343#Const kCCW_Direction 1
Cary Clark154beea2017-10-26 07:58:48 -0400344 Contour travels in a counterclockwise direction
Cary Clark73fa9722017-08-29 17:36:51 -0400345##
346
347
348#Example
349#Height 100
350void draw(SkCanvas* canvas) {
351 const SkPoint arrow[] = { {40, -5}, {45, 0}, {40, 5} };
352 const SkRect rect = {10, 10, 90, 90};
353 SkPaint rectPaint;
354 rectPaint.setAntiAlias(true);
355 SkPaint textPaint(rectPaint);
356 textPaint.setTextAlign(SkPaint::kCenter_Align);
357 rectPaint.setStyle(SkPaint::kStroke_Style);
358 SkPaint arrowPaint(rectPaint);
359 SkPath arrowPath;
360 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
361 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 320, 0,
362 SkPath1DPathEffect::kRotate_Style));
363 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
364 canvas->drawRect(rect, rectPaint);
365 for (unsigned start : { 0, 1, 2, 3 } ) {
366 SkPath path;
367 path.addRect(rect, direction, start);
368 canvas->drawPath(path, arrowPaint);
369 }
370 canvas->drawString(SkPath::kCW_Direction == direction ? "CW" : "CCW", rect.centerX(),
371 rect.centerY(), textPaint);
372 canvas->translate(120, 0);
373 }
374}
375##
376
377#SeeAlso arcTo rArcTo isRect isNestedFillRects addRect addOval
378
379#Enum Direction ##
380#Subtopic Direction ##
381
382# ------------------------------------------------------------------------------
383
384#Method SkPath()
385
Cary Clarkab2621d2018-01-30 10:08:57 -0500386#Line # constructs with default values ##
Cary Clark73fa9722017-08-29 17:36:51 -0400387By default, Path has no Verbs, no Points, and no Weights.
388Fill_Type is set to kWinding_FillType.
389
390#Return empty Path ##
391
392#Example
393 SkPath path;
394 SkDebugf("path is " "%s" "empty", path.isEmpty() ? "" : "not ");
395#StdOut
396path is empty
397##
398##
399
400#SeeAlso reset rewind
401
402##
403
404# ------------------------------------------------------------------------------
405
406#Method SkPath(const SkPath& path)
407
Cary Clarkab2621d2018-01-30 10:08:57 -0500408#Line # makes a shallow copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400409Copy constructor makes two paths identical by value. Internally, path and
410the returned result share pointer values. The underlying Verb_Array, Point_Array
411and Weights are copied when modified.
412
413Creating a Path copy is very efficient and never allocates memory.
414Paths are always copied by value from the interface; the underlying shared
415pointers are not exposed.
416
417#Param path Path to copy by value ##
418
Cary Clarka523d2d2017-08-30 08:58:10 -0400419#Return copy of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -0400420
421#Example
422#Description
423 Modifying one path does not effect another, even if they started as copies
424 of each other.
425##
426 SkPath path;
427 path.lineTo(20, 20);
428 SkPath path2(path);
429 path2.close();
430 SkDebugf("path verbs: %d\n", path.countVerbs());
431 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
432 path.reset();
433 SkDebugf("after reset\n" "path verbs: %d\n", path.countVerbs());
434 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
435#StdOut
436path verbs: 2
437path2 verbs: 3
438after reset
439path verbs: 0
440path2 verbs: 3
441##
442##
443
444#SeeAlso operator=(const SkPath& path)
445
446##
447
448# ------------------------------------------------------------------------------
449
450#Method ~SkPath()
451
Cary Clarkab2621d2018-01-30 10:08:57 -0500452#Line # decreases Reference_Count of owned objects ##
Cary Clark73fa9722017-08-29 17:36:51 -0400453Releases ownership of any shared data and deletes data if Path is sole owner.
454
455#Example
456#Description
Cary Clarkce101242017-09-01 15:51:02 -0400457delete calls Path Destructor, but copy of original in path2 is unaffected.
Cary Clark73fa9722017-08-29 17:36:51 -0400458##
459void draw(SkCanvas* canvas) {
460 SkPath* path = new SkPath();
461 path->lineTo(20, 20);
462 SkPath path2(*path);
463 delete path;
464 SkDebugf("path2 is " "%s" "empty", path2.isEmpty() ? "" : "not ");
465}
466##
467
468#SeeAlso SkPath() SkPath(const SkPath& path) operator=(const SkPath& path)
469
470##
471
472# ------------------------------------------------------------------------------
473
474#Method SkPath& operator=(const SkPath& path)
475
Cary Clarkab2621d2018-01-30 10:08:57 -0500476#Line # makes a shallow copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400477Path assignment makes two paths identical by value. Internally, assignment
478shares pointer values. The underlying Verb_Array, Point_Array and Weights
479are copied when modified.
480
481Copying Paths by assignment is very efficient and never allocates memory.
482Paths are always copied by value from the interface; the underlying shared
483pointers are not exposed.
484
Cary Clarkce101242017-09-01 15:51:02 -0400485#Param path Verb_Array, Point_Array, Weights, and Fill_Type to copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400486
487#Return Path copied by value ##
488
489#Example
490SkPath path1;
491path1.addRect({10, 20, 30, 40});
492SkPath path2 = path1;
493const SkRect& b1 = path1.getBounds();
494SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
495const SkRect& b2 = path2.getBounds();
496SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
497#StdOut
498path1 bounds = 10, 20, 30, 40
499path2 bounds = 10, 20, 30, 40
500#StdOut ##
501##
502
503#SeeAlso swap() SkPath(const SkPath& path)
504
505##
506
507# ------------------------------------------------------------------------------
508
509#Method bool operator==(const SkPath& a, const SkPath& b)
510
Cary Clarkab2621d2018-01-30 10:08:57 -0500511#Line # compares paths for equality ##
Cary Clark73fa9722017-08-29 17:36:51 -0400512Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
513are equivalent.
514
515#Param a Path to compare ##
516#Param b Path to compare ##
517
518#Return true if Path pair are equivalent ##
519
520#Example
521#Description
522Rewind removes Verb_Array but leaves storage; since storage is not compared,
523Path pair are equivalent.
524##
525void draw(SkCanvas* canvas) {
526 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
527 SkDebugf("%s one %c= two\n", prefix, a == b ? '=' : '!');
528 };
529 SkPath one;
530 SkPath two;
531 debugster("empty", one, two);
532 one.moveTo(0, 0);
533 debugster("moveTo", one, two);
534 one.rewind();
535 debugster("rewind", one, two);
536 one.moveTo(0, 0);
537 one.reset();
538 debugster("reset", one, two);
539}
540#StdOut
541empty one == two
542moveTo one != two
543rewind one == two
544reset one == two
545##
546##
547
548##
549
550# ------------------------------------------------------------------------------
551
552#Method bool operator!=(const SkPath& a, const SkPath& b)
553
Cary Clarkab2621d2018-01-30 10:08:57 -0500554#Line # compares paths for inequality ##
Cary Clark73fa9722017-08-29 17:36:51 -0400555Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
556are not equivalent.
557
558#Param a Path to compare ##
559#Param b Path to compare ##
560
561#Return true if Path pair are not equivalent ##
562
563#Example
564#Description
565Path pair are equal though their convexity is not equal.
566##
567void draw(SkCanvas* canvas) {
568 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
569 SkDebugf("%s one %c= two\n", prefix, a != b ? '!' : '=');
570 };
571 SkPath one;
572 SkPath two;
573 debugster("empty", one, two);
574 one.addRect({10, 20, 30, 40});
575 two.addRect({10, 20, 30, 40});
576 debugster("addRect", one, two);
577 one.setConvexity(SkPath::kConcave_Convexity);
578 debugster("setConvexity", one, two);
579 SkDebugf("convexity %c=\n", one.getConvexity() == two.getConvexity() ? '=' : '!');
580}
581#StdOut
582empty one == two
583addRect one == two
584setConvexity one == two
585convexity !=
586##
587##
588
589##
590
591# ------------------------------------------------------------------------------
592
Cary Clark4855f782018-02-06 09:41:53 -0500593#Subtopic Property
594#Populate
595#Line # metrics and attributes ##
596##
Cary Clark73fa9722017-08-29 17:36:51 -0400597
Cary Clark4855f782018-02-06 09:41:53 -0500598#Method bool isInterpolatable(const SkPath& compare) const
599#In Property
600#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500601#Line # returns if pair contains equal counts of Verb_Array and Weights ##
Cary Clark73fa9722017-08-29 17:36:51 -0400602Return true if Paths contain equal Verbs and equal Weights.
603If Paths contain one or more Conics, the Weights must match.
604
605conicTo may add different Verbs depending on Conic_Weight, so it is not
Cary Clarkce101242017-09-01 15:51:02 -0400606trivial to interpolate a pair of Paths containing Conics with different
Cary Clark73fa9722017-08-29 17:36:51 -0400607Conic_Weight values.
608
609#Param compare Path to compare ##
610
611#Return true if Paths Verb_Array and Weights are equivalent ##
612
613#Example
614 SkPath path, path2;
615 path.moveTo(20, 20);
616 path.lineTo(40, 40);
617 path.lineTo(20, 20);
618 path.lineTo(40, 40);
619 path.close();
620 path2.addRect({20, 20, 40, 40});
621 SkDebugf("paths are " "%s" "interpolatable", path.isInterpolatable(path2) ? "" : "not ");
622#StdOut
623paths are interpolatable
624##
625##
626
627#SeeAlso isInterpolatable
628
629##
630
631# ------------------------------------------------------------------------------
632
Cary Clark4855f782018-02-06 09:41:53 -0500633#Subtopic Interpolate
634#Populate
635#Line # weighted average of Path pair ##
636##
Cary Clark73fa9722017-08-29 17:36:51 -0400637
Cary Clark4855f782018-02-06 09:41:53 -0500638#Method bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const
639#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500640#Line # interpolates between Path pair ##
Cary Clark61dfc3a2018-01-03 08:37:53 -0500641Interpolate between Paths with Point_Array of equal size.
642Copy Verb_Array and Weights to out, and set out Point_Array to a weighted
643average of this Point_Array and ending Point_Array, using the formula:
Cary Clark73fa9722017-08-29 17:36:51 -0400644#Formula
Cary Clarkac47b882018-01-11 10:35:44 -0500645(Path Point * weight) + ending Point * (1 - weight)
Cary Clark73fa9722017-08-29 17:36:51 -0400646##
Cary Clark154beea2017-10-26 07:58:48 -0400647.
Cary Clark73fa9722017-08-29 17:36:51 -0400648
649weight is most useful when between zero (ending Point_Array) and
650one (this Point_Array); will work with values outside of this
651range.
652
653interpolate() returns false and leaves out unchanged if Point_Array is not
654the same size as ending Point_Array. Call isInterpolatable to check Path
655compatibility prior to calling interpolate().
656
657#Param ending Point_Array averaged with this Point_Array ##
Cary Clark61dfc3a2018-01-03 08:37:53 -0500658#Param weight contribution of this Point_Array, and
659 one minus contribution of ending Point_Array
Cary Clark73fa9722017-08-29 17:36:51 -0400660##
661#Param out Path replaced by interpolated averages ##
662
663#Return true if Paths contain same number of Points ##
664
665#Example
666#Height 60
667void draw(SkCanvas* canvas) {
668 SkPaint paint;
669 paint.setAntiAlias(true);
670 paint.setStyle(SkPaint::kStroke_Style);
671 SkPath path, path2;
672 path.moveTo(20, 20);
673 path.lineTo(40, 40);
674 path.lineTo(20, 40);
675 path.lineTo(40, 20);
676 path.close();
677 path2.addRect({20, 20, 40, 40});
678 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
679 SkPath interp;
680 path.interpolate(path2, i, &interp);
681 canvas->drawPath(interp, paint);
682 canvas->translate(30, 0);
683 }
684}
685##
686
687#SeeAlso isInterpolatable
688
689##
690
691# ------------------------------------------------------------------------------
692
693#Method bool unique() const
Cary Clark4855f782018-02-06 09:41:53 -0500694#Deprecated soon
695Only valid for Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -0400696##
697
698# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400699#Subtopic Fill_Type
Cary Clark08895c42018-02-01 09:37:32 -0500700#Line # Path fill rule, normal and inverted ##
Cary Clark8032b982017-07-28 11:04:54 -0400701
Cary Clark73fa9722017-08-29 17:36:51 -0400702#Enum FillType
Cary Clark08895c42018-02-01 09:37:32 -0500703#Line # sets winding rule and inverse fill ##
Cary Clark73fa9722017-08-29 17:36:51 -0400704
705#Code
706 enum FillType {
707 kWinding_FillType,
708 kEvenOdd_FillType,
709 kInverseWinding_FillType,
710 kInverseEvenOdd_FillType,
711 };
712##
Cary Clark8032b982017-07-28 11:04:54 -0400713
714Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
715fills if the sum of Contour edges is not zero, where clockwise edges add one, and
716counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
717number of Contour edges is odd. Each Fill_Type has an inverse variant that
718reverses the rule:
719kInverseWinding_FillType fills where the sum of Contour edges is zero;
720kInverseEvenOdd_FillType fills where the number of Contour edges is even.
721
722#Example
723#Height 100
724#Description
725The top row has two clockwise rectangles. The second row has one clockwise and
726one counterclockwise rectangle. The even-odd variants draw the same. The
727winding variants draw the top rectangle overlap, which has a winding of 2, the
728same as the outer parts of the top rectangles, which have a winding of 1.
729##
Cary Clark73fa9722017-08-29 17:36:51 -0400730void draw(SkCanvas* canvas) {
731 SkPath path;
732 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
733 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
734 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
735 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
736 SkPaint strokePaint;
737 strokePaint.setStyle(SkPaint::kStroke_Style);
738 SkRect clipRect = {0, 0, 51, 100};
739 canvas->drawPath(path, strokePaint);
740 SkPaint fillPaint;
741 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
742 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
743 canvas->translate(51, 0);
744 canvas->save();
745 canvas->clipRect(clipRect);
746 path.setFillType(fillType);
747 canvas->drawPath(path, fillPaint);
748 canvas->restore();
749 }
Cary Clark8032b982017-07-28 11:04:54 -0400750}
751##
Cary Clark73fa9722017-08-29 17:36:51 -0400752
753#Const kWinding_FillType 0
754Specifies fill as area is enclosed by a non-zero sum of Contour Directions.
755##
756#Const kEvenOdd_FillType 1
757Specifies fill as area enclosed by an odd number of Contours.
758##
759#Const kInverseWinding_FillType 2
760Specifies fill as area is enclosed by a zero sum of Contour Directions.
761##
762#Const kInverseEvenOdd_FillType 3
763Specifies fill as area enclosed by an even number of Contours.
764##
765
766#Example
767#Height 230
768void draw(SkCanvas* canvas) {
769 SkPath path;
770 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
771 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
772 SkPaint strokePaint;
773 strokePaint.setStyle(SkPaint::kStroke_Style);
774 SkRect clipRect = {0, 0, 128, 128};
775 canvas->drawPath(path, strokePaint);
776 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
777 SkPaint textPaint;
778 textPaint.setAntiAlias(true);
779 textPaint.setTextAlign(SkPaint::kCenter_Align);
780 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
781 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
782 textPaint.setTextSize(18);
783 canvas->translate(0, 128);
784 canvas->scale(.5f, .5f);
785 canvas->drawString("inverse", 384, 150, textPaint);
786 SkPaint fillPaint;
787 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
788 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
789 canvas->save();
790 canvas->clipRect(clipRect);
791 path.setFillType(fillType);
792 canvas->drawPath(path, fillPaint);
793 canvas->restore();
794 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
795 canvas->translate(128, 0);
796 }
797}
798##
799
800#SeeAlso SkPaint::Style Direction getFillType setFillType
801
802##
803
804# ------------------------------------------------------------------------------
805
806#Method FillType getFillType() const
807
Cary Clarkab2621d2018-01-30 10:08:57 -0500808#In Fill_Type
809#Line # returns Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400810Returns FillType, the rule used to fill Path. FillType of a new Path is
811kWinding_FillType.
812
813#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
814kInverseEvenOdd_FillType
815##
816
817#Example
818 SkPath path;
819 SkDebugf("default path fill type is %s\n",
820 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
821 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
822 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
823 "kInverseEvenOdd_FillType");
824#StdOut
825default path fill type is kWinding_FillType
826##
827##
828
829#SeeAlso FillType setFillType isInverseFillType
830
831##
832
833# ------------------------------------------------------------------------------
834
835#Method void setFillType(FillType ft)
836
Cary Clarkab2621d2018-01-30 10:08:57 -0500837#In Fill_Type
838#Line # sets Fill_Type: winding, even-odd, inverse ##
Cary Clark73fa9722017-08-29 17:36:51 -0400839Sets FillType, the rule used to fill Path. While there is no check
840that ft is legal, values outside of FillType are not supported.
841
842#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
843kInverseEvenOdd_FillType
844##
845
846#Example
847#Description
848If empty Path is set to inverse FillType, it fills all pixels.
849##
850#Height 64
851 SkPath path;
852 path.setFillType(SkPath::kInverseWinding_FillType);
853 SkPaint paint;
854 paint.setColor(SK_ColorBLUE);
855 canvas->drawPath(path, paint);
856##
857
858#SeeAlso FillType getFillType toggleInverseFillType
859
860##
861
862# ------------------------------------------------------------------------------
863
864#Method bool isInverseFillType() const
865
Cary Clarkab2621d2018-01-30 10:08:57 -0500866#In Fill_Type
867#Line # returns if Fill_Type fills outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -0400868Returns if FillType describes area outside Path geometry. The inverse fill area
869extends indefinitely.
870
871#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType ##
872
873#Example
874 SkPath path;
875 SkDebugf("default path fill type is inverse: %s\n",
876 path.isInverseFillType() ? "true" : "false");
877#StdOut
878default path fill type is inverse: false
879##
880##
881
882#SeeAlso FillType getFillType setFillType toggleInverseFillType
883
884##
885
886# ------------------------------------------------------------------------------
887
888#Method void toggleInverseFillType()
889
Cary Clarkab2621d2018-01-30 10:08:57 -0500890#In Fill_Type
891#Line # toggles Fill_Type between inside and outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -0400892Replace FillType with its inverse. The inverse of FillType describes the area
893unmodified by the original FillType.
894
895#Table
896#Legend
897# FillType # toggled FillType ##
898##
899# kWinding_FillType # kInverseWinding_FillType ##
900# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
901# kInverseWinding_FillType # kWinding_FillType ##
902# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
903##
904
905#Example
906#Description
907Path drawn normally and through its inverse touches every pixel once.
908##
909#Height 100
910SkPath path;
911SkPaint paint;
912paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -0400913paint.setTextSize(80);
914paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -0400915canvas->drawPath(path, paint);
916path.toggleInverseFillType();
917paint.setColor(SK_ColorGREEN);
918canvas->drawPath(path, paint);
919##
920
921#SeeAlso FillType getFillType setFillType isInverseFillType
922
923##
924
Cary Clark8032b982017-07-28 11:04:54 -0400925#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400926
927# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400928
929#Subtopic Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500930#Line # if Path is concave or convex ##
Cary Clark73fa9722017-08-29 17:36:51 -0400931
932#Enum Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500933#Line # returns if Path is convex or concave ##
Cary Clark73fa9722017-08-29 17:36:51 -0400934
935#Code
Cary Clark884dd7d2017-10-11 10:37:52 -0400936 enum Convexity : uint8_t {
Cary Clark73fa9722017-08-29 17:36:51 -0400937 kUnknown_Convexity,
938 kConvex_Convexity,
939 kConcave_Convexity,
940 };
941##
942
Cary Clark8032b982017-07-28 11:04:54 -0400943Path is convex if it contains one Contour and Contour loops no more than
944360 degrees, and Contour angles all have same Direction. Convex Path
945may have better performance and require fewer resources on GPU_Surface.
946
Cary Clark73fa9722017-08-29 17:36:51 -0400947Path is concave when either at least one Direction change is clockwise and
948another is counterclockwise, or the sum of the changes in Direction is not 360
949degrees.
950
951Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
952if needed by destination Surface.
953
954#Const kUnknown_Convexity 0
955 Indicates Convexity has not been determined.
956##
957#Const kConvex_Convexity 1
958 Path has one Contour made of a simple geometry without indentations.
959##
960#Const kConcave_Convexity 2
961 Path has more than one Contour, or a geometry with indentations.
962##
963
964#Example
965void draw(SkCanvas* canvas) {
966 SkPaint paint;
967 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
968 const char* labels[] = { "unknown", "convex", "concave" };
969 for (SkScalar x : { 40, 100 } ) {
970 SkPath path;
971 quad[0].fX = x;
972 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
973 canvas->drawPath(path, paint);
974 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
975 canvas->translate(100, 100);
976 }
977}
978##
979
980#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
981
982#Enum Convexity ##
983
984#Method Convexity getConvexity() const
985
Cary Clarkab2621d2018-01-30 10:08:57 -0500986#In Convexity
987#Line # returns geometry convexity, computing if necessary ##
Cary Clark73fa9722017-08-29 17:36:51 -0400988Computes Convexity if required, and returns stored value.
989Convexity is computed if stored value is kUnknown_Convexity,
990or if Path has been altered since Convexity was computed or set.
991
Cary Clarka523d2d2017-08-30 08:58:10 -0400992#Return computed or stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -0400993
994#Example
995void draw(SkCanvas* canvas) {
996 auto debugster = [](const char* prefix, const SkPath& path) -> void {
997 SkDebugf("%s path convexity is %s\n", prefix,
998 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
999 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1000 SkPath path;
1001 debugster("initial", path);
1002 path.lineTo(50, 0);
1003 debugster("first line", path);
1004 path.lineTo(50, 50);
1005 debugster("second line", path);
1006 path.lineTo(100, 50);
1007 debugster("third line", path);
1008}
1009##
1010
1011#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
1012
1013##
1014
1015# ------------------------------------------------------------------------------
1016
1017#Method Convexity getConvexityOrUnknown() const
1018
Cary Clarkab2621d2018-01-30 10:08:57 -05001019#In Convexity
1020#Line # returns geometry convexity if known ##
Cary Clark73fa9722017-08-29 17:36:51 -04001021Returns last computed Convexity, or kUnknown_Convexity if
1022Path has been altered since Convexity was computed or set.
1023
Cary Clarka523d2d2017-08-30 08:58:10 -04001024#Return stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001025
1026#Example
1027#Description
1028Convexity is unknown unless getConvexity is called without a subsequent call
1029that alters the path.
1030##
1031void draw(SkCanvas* canvas) {
1032 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1033 SkDebugf("%s path convexity is %s\n", prefix,
1034 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
1035 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
1036 SkPath path;
1037 debugster("initial", path);
1038 path.lineTo(50, 0);
1039 debugster("first line", path);
1040 path.getConvexity();
1041 path.lineTo(50, 50);
1042 debugster("second line", path);
1043 path.lineTo(100, 50);
1044 path.getConvexity();
1045 debugster("third line", path);
1046}
1047##
1048
1049#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
1050
1051##
1052
1053# ------------------------------------------------------------------------------
1054
1055#Method void setConvexity(Convexity convexity)
1056
Cary Clarkab2621d2018-01-30 10:08:57 -05001057#In Convexity
1058#Line # sets if geometry is convex to avoid future computation ##
Cary Clark73fa9722017-08-29 17:36:51 -04001059Stores convexity so that it is later returned by getConvexity or getConvexityOrUnknown.
1060convexity may differ from getConvexity, although setting an incorrect value may
1061cause incorrect or inefficient drawing.
1062
1063If convexity is kUnknown_Convexity: getConvexity will
1064compute Convexity, and getConvexityOrUnknown will return kUnknown_Convexity.
1065
1066If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity
1067and getConvexityOrUnknown will return convexity until the path is
1068altered.
1069
1070#Param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity ##
1071
1072#Example
1073void draw(SkCanvas* canvas) {
1074 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1075 SkDebugf("%s path convexity is %s\n", prefix,
1076 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1077 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1078 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1079 SkPath path;
1080 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1081 debugster("initial", path);
1082 path.setConvexity(SkPath::kConcave_Convexity);
1083 debugster("after forcing concave", path);
1084 path.setConvexity(SkPath::kUnknown_Convexity);
1085 debugster("after forcing unknown", path);
1086}
1087##
1088
1089#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
1090
1091##
1092
1093# ------------------------------------------------------------------------------
1094
1095#Method bool isConvex() const
1096
Cary Clarkab2621d2018-01-30 10:08:57 -05001097#In Convexity
1098#Line # returns if geometry is convex ##
Cary Clark73fa9722017-08-29 17:36:51 -04001099Computes Convexity if required, and returns true if value is kConvex_Convexity.
1100If setConvexity was called with kConvex_Convexity or kConcave_Convexity, and
1101the path has not been altered, Convexity is not recomputed.
1102
1103#Return true if Convexity stored or computed is kConvex_Convexity ##
1104
1105#Example
1106#Description
1107Concave shape is erroneously considered convex after a forced call to
1108setConvexity.
1109##
1110void draw(SkCanvas* canvas) {
1111 SkPaint paint;
1112 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1113 for (SkScalar x : { 40, 100 } ) {
1114 SkPath path;
1115 quad[0].fX = x;
1116 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1117 path.setConvexity(SkPath::kConvex_Convexity);
1118 canvas->drawPath(path, paint);
1119 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
1120 canvas->translate(100, 100);
1121 }
1122}
1123##
1124
1125#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
1126
1127##
1128
Cary Clark73fa9722017-08-29 17:36:51 -04001129#Subtopic Convexity ##
1130
1131# ------------------------------------------------------------------------------
1132
Mike Reed0c3137c2018-02-20 13:57:05 -05001133#Method bool isOval(SkRect* bounds) const
Cary Clark4855f782018-02-06 09:41:53 -05001134#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001135#Line # returns if describes Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04001136
Mike Reed0c3137c2018-02-20 13:57:05 -05001137Returns true if this path is recognized as an oval or circle.
Cary Clark73fa9722017-08-29 17:36:51 -04001138
Mike Reed0c3137c2018-02-20 13:57:05 -05001139bounds receives bounds of Oval.
Cary Clark73fa9722017-08-29 17:36:51 -04001140
Mike Reed0c3137c2018-02-20 13:57:05 -05001141bounds is unmodified if Oval is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001142
Mike Reed0c3137c2018-02-20 13:57:05 -05001143#Param bounds storage for bounding Rect of Oval; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001144
Mike Reed0c3137c2018-02-20 13:57:05 -05001145#Return true if Path is recognized as an oval or circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04001146
1147#Example
1148void draw(SkCanvas* canvas) {
1149 SkPaint paint;
1150 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001151 path.addOval({20, 20, 220, 220});
Cary Clark73fa9722017-08-29 17:36:51 -04001152 SkRect bounds;
Mike Reed0c3137c2018-02-20 13:57:05 -05001153 if (path.isOval(&bounds)) {
1154 paint.setColor(0xFF9FBFFF);
1155 canvas->drawRect(bounds, paint);
1156 }
Cary Clark73fa9722017-08-29 17:36:51 -04001157 paint.setColor(0x3f000000);
1158 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001159}
1160##
1161
1162#SeeAlso Oval addCircle addOval
1163
1164##
1165
1166# ------------------------------------------------------------------------------
1167
Mike Reed0c3137c2018-02-20 13:57:05 -05001168#Method bool isRRect(SkRRect* rrect) const
Cary Clark4855f782018-02-06 09:41:53 -05001169#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001170#Line # returns if describes Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001171
Mike Reed0c3137c2018-02-20 13:57:05 -05001172Returns true if this path is recognized as a SkRRect (but not an oval/circle or rect).
Cary Clark73fa9722017-08-29 17:36:51 -04001173
1174rrect receives bounds of Round_Rect.
Cary Clark73fa9722017-08-29 17:36:51 -04001175
Mike Reed0c3137c2018-02-20 13:57:05 -05001176rrect is unmodified if Round_Rect is not found.
Cary Clark73fa9722017-08-29 17:36:51 -04001177
1178#Param rrect storage for bounding Rect of Round_Rect; may be nullptr ##
Cary Clark73fa9722017-08-29 17:36:51 -04001179
Cary Clarkce101242017-09-01 15:51:02 -04001180#Return true if Path contains only Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001181
1182#Example
Cary Clarkce101242017-09-01 15:51:02 -04001183#Description
Mike Reed0c3137c2018-02-20 13:57:05 -05001184Draw rounded rectangle and its bounds.
Cary Clarkce101242017-09-01 15:51:02 -04001185##
Cary Clark73fa9722017-08-29 17:36:51 -04001186void draw(SkCanvas* canvas) {
1187 SkPaint paint;
1188 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -05001189 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50));
Cary Clark73fa9722017-08-29 17:36:51 -04001190 SkRRect rrect;
Mike Reed0c3137c2018-02-20 13:57:05 -05001191 if (path.isRRect(&rrect)) {
1192 const SkRect& bounds = rrect.rect();
1193 paint.setColor(0xFF9FBFFF);
1194 canvas->drawRect(bounds, paint);
1195 }
Cary Clark73fa9722017-08-29 17:36:51 -04001196 paint.setColor(0x3f000000);
1197 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001198}
1199##
1200
1201#SeeAlso Round_Rect addRoundRect addRRect
1202
1203##
1204
1205# ------------------------------------------------------------------------------
1206
1207#Method void reset()
Cary Clark4855f782018-02-06 09:41:53 -05001208#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001209#Line # removes Verb_Array, Point_Array, and Weights; frees memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001210Sets Path to its initial state.
Cary Clark73fa9722017-08-29 17:36:51 -04001211Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1212Internal storage associated with Path is released.
1213
1214#Example
1215 SkPath path1, path2;
1216 path1.setFillType(SkPath::kInverseWinding_FillType);
1217 path1.addRect({10, 20, 30, 40});
1218 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1219 path1.reset();
1220 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1221##
1222
1223#SeeAlso rewind()
1224
1225##
1226
1227# ------------------------------------------------------------------------------
1228
1229#Method void rewind()
Cary Clark4855f782018-02-06 09:41:53 -05001230#In Constructor
Cary Clarkab2621d2018-01-30 10:08:57 -05001231#Line # removes Verb_Array, Point_Array, and Weights, keeping memory ##
Cary Clarkce101242017-09-01 15:51:02 -04001232Sets Path to its initial state, preserving internal storage.
Cary Clark73fa9722017-08-29 17:36:51 -04001233Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1234Internal storage associated with Path is retained.
1235
1236Use rewind() instead of reset() if Path storage will be reused and performance
1237is critical.
1238
1239#Example
1240#Description
1241Although path1 retains its internal storage, it is indistinguishable from
1242a newly initialized path.
1243##
1244 SkPath path1, path2;
1245 path1.setFillType(SkPath::kInverseWinding_FillType);
1246 path1.addRect({10, 20, 30, 40});
1247 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1248 path1.rewind();
1249 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1250##
1251
1252#SeeAlso reset()
1253
1254##
1255
1256# ------------------------------------------------------------------------------
1257
1258#Method bool isEmpty() const
Cary Clark4855f782018-02-06 09:41:53 -05001259#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001260#Line # returns if verb count is zero ##
Cary Clark73fa9722017-08-29 17:36:51 -04001261Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
1262SkPath() constructs empty Path; reset() and (rewind) make Path empty.
1263
1264#Return true if the path contains no Verb array ##
1265
1266#Example
1267void draw(SkCanvas* canvas) {
1268 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1269 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
1270 };
1271 SkPath path;
1272 debugster("initial", path);
1273 path.moveTo(0, 0);
1274 debugster("after moveTo", path);
1275 path.rewind();
1276 debugster("after rewind", path);
1277 path.lineTo(0, 0);
1278 debugster("after lineTo", path);
1279 path.reset();
1280 debugster("after reset", path);
1281}
1282#StdOut
1283initial path is empty
1284after moveTo path is not empty
1285after rewind path is empty
1286after lineTo path is not empty
1287after reset path is empty
1288##
1289##
1290
1291#SeeAlso SkPath() reset() rewind()
1292
1293##
1294
1295# ------------------------------------------------------------------------------
1296
1297#Method bool isLastContourClosed() const
Cary Clark4855f782018-02-06 09:41:53 -05001298#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001299#Line # returns if final Contour forms a loop ##
Cary Clark73fa9722017-08-29 17:36:51 -04001300Contour is closed if Path Verb array was last modified by close(). When stroked,
1301closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
1302
1303#Return true if the last Contour ends with a kClose_Verb ##
1304
1305#Example
1306#Description
1307close() has no effect if Path is empty; isLastContourClosed() returns
1308false until Path has geometry followed by close().
1309##
1310void draw(SkCanvas* canvas) {
1311 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1312 SkDebugf("%s last contour is %s" "closed\n", prefix,
1313 path.isLastContourClosed() ? "" : "not ");
1314 };
1315 SkPath path;
1316 debugster("initial", path);
1317 path.close();
1318 debugster("after close", path);
1319 path.lineTo(0, 0);
1320 debugster("after lineTo", path);
1321 path.close();
1322 debugster("after close", path);
1323}
1324#StdOut
1325initial last contour is not closed
1326after close last contour is not closed
1327after lineTo last contour is not closed
1328after close last contour is closed
1329##
1330##
1331
1332#SeeAlso close()
1333
1334##
1335
1336# ------------------------------------------------------------------------------
1337
1338#Method bool isFinite() const
Cary Clark4855f782018-02-06 09:41:53 -05001339#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001340#Line # returns if all Point values are finite ##
Cary Clark73fa9722017-08-29 17:36:51 -04001341Returns true for finite Point array values between negative SK_ScalarMax and
1342positive SK_ScalarMax. Returns false for any Point array value of
1343SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
1344
1345#Return true if all Point values are finite ##
1346
1347#Example
1348void draw(SkCanvas* canvas) {
1349 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1350 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1351 };
1352 SkPath path;
1353 debugster("initial", path);
1354 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1355 debugster("after line", path);
1356 SkMatrix matrix;
1357 matrix.setScale(2, 2);
1358 path.transform(matrix);
1359 debugster("after scale", path);
1360}
1361#StdOut
1362initial path is finite
1363after line path is finite
1364after scale path is not finite
1365##
1366##
1367
1368#SeeAlso SkScalar
1369##
1370
1371# ------------------------------------------------------------------------------
1372
1373#Method bool isVolatile() const
Cary Clark4855f782018-02-06 09:41:53 -05001374#In Property
1375#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001376#Line # returns if Device should not cache ##
Cary Clark73fa9722017-08-29 17:36:51 -04001377Returns true if the path is volatile; it will not be altered or discarded
1378by the caller after it is drawn. Paths by default have volatile set false, allowing
1379Surface to attach a cache of data which speeds repeated drawing. If true, Surface
1380may not speed repeated drawing.
1381
1382#Return true if caller will alter Path after drawing ##
1383
1384#Example
1385 SkPath path;
1386 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1387#StdOut
1388volatile by default is false
1389##
1390##
1391
1392#SeeAlso setIsVolatile
1393
1394##
1395
1396# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001397#Subtopic Volatile
1398#Populate
1399#Line # caching attribute ##
1400##
Cary Clark73fa9722017-08-29 17:36:51 -04001401
1402#Method void setIsVolatile(bool isVolatile)
Cary Clark4855f782018-02-06 09:41:53 -05001403#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001404#Line # sets if Device should not cache ##
Cary Clark73fa9722017-08-29 17:36:51 -04001405Specify whether Path is volatile; whether it will be altered or discarded
1406by the caller after it is drawn. Paths by default have volatile set false, allowing
1407Device to attach a cache of data which speeds repeated drawing.
1408
1409Mark temporary paths, discarded or modified after use, as volatile
1410to inform Device that the path need not be cached.
1411
1412Mark animating Path volatile to improve performance.
Cary Clarkce101242017-09-01 15:51:02 -04001413Mark unchanging Path non-volatile to improve repeated rendering.
Cary Clark73fa9722017-08-29 17:36:51 -04001414
1415Raster_Surface Path draws are affected by volatile for some shadows.
1416GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
1417
1418#Param isVolatile true if caller will alter Path after drawing ##
1419
1420#Example
1421#Height 50
1422#Width 50
1423 SkPaint paint;
1424 paint.setStyle(SkPaint::kStroke_Style);
1425 SkPath path;
1426 path.setIsVolatile(true);
1427 path.lineTo(40, 40);
1428 canvas->drawPath(path, paint);
1429 path.rewind();
1430 path.moveTo(0, 40);
1431 path.lineTo(40, 0);
1432 canvas->drawPath(path, paint);
1433##
1434
1435#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1436
1437#SeeAlso isVolatile
1438
1439##
1440
1441# ------------------------------------------------------------------------------
1442
1443#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001444#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001445#Line # returns if Line is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001446Test if Line between Point pair is degenerate.
1447Line with no length or that moves a very short distance is degenerate; it is
1448treated as a point.
1449
Cary Clarka523d2d2017-08-30 08:58:10 -04001450exact changes the equality test. If true, returns true only if p1 equals p2.
1451If false, returns true if p1 equals or nearly equals p2.
1452
Cary Clark73fa9722017-08-29 17:36:51 -04001453#Param p1 line start point ##
1454#Param p2 line end point ##
Cary Clarka523d2d2017-08-30 08:58:10 -04001455#Param exact if false, allow nearly equals ##
Cary Clark73fa9722017-08-29 17:36:51 -04001456
1457#Return true if Line is degenerate; its length is effectively zero ##
1458
1459#Example
1460#Description
Cary Clarkce101242017-09-01 15:51:02 -04001461As single precision floats, 100 and 100.000001 have the same bit representation,
1462and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001463are not exactly equal, but are nearly equal.
1464##
1465void draw(SkCanvas* canvas) {
1466 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1467 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1468 for (bool exact : { false, true } ) {
1469 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1470 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1471 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1472 ? "" : "not ", exact ? "exactly" : "nearly");
1473 }
1474 }
1475}
1476#StdOut
1477line from (100,100) to (100,100) is degenerate, nearly
1478line from (100,100) to (100,100) is degenerate, exactly
1479line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1480line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1481#StdOut ##
1482##
1483
Cary Clarka560c472017-11-27 10:44:06 -05001484#SeeAlso IsQuadDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001485##
1486
1487# ------------------------------------------------------------------------------
1488
1489#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
1490 const SkPoint& p3, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001491#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001492#Line # returns if Quad is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001493
1494Test if Quad is degenerate.
1495Quad with no length or that moves a very short distance is degenerate; it is
1496treated as a point.
1497
Cary Clarkce101242017-09-01 15:51:02 -04001498#Param p1 Quad start point ##
1499#Param p2 Quad control point ##
1500#Param p3 Quad end point ##
Cary Clark73fa9722017-08-29 17:36:51 -04001501#Param exact if true, returns true only if p1, p2, and p3 are equal;
1502 if false, returns true if p1, p2, and p3 are equal or nearly equal
1503##
1504
1505#Return true if Quad is degenerate; its length is effectively zero ##
1506
1507#Example
1508#Description
Cary Clarkce101242017-09-01 15:51:02 -04001509As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001510but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001511the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001512##
1513void draw(SkCanvas* canvas) {
1514 auto debugster = [](const SkPath& path, bool exact) -> void {
1515 SkDebugf("quad (%1.8g,%1.8g), (%1.8g,%1.8g), (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1516 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1517 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1518 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1519 "" : "not ", exact ? "exactly" : "nearly");
1520 };
1521 SkPath path, offset;
1522 path.moveTo({100, 100});
1523 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1524 offset.addPath(path, 1000, 1000);
1525 for (bool exact : { false, true } ) {
1526 debugster(path, exact);
1527 debugster(offset, exact);
1528 }
1529}
1530#StdOut
1531quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1532quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1533quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1534quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1535#StdOut ##
1536##
1537
Cary Clarka560c472017-11-27 10:44:06 -05001538#SeeAlso IsLineDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001539##
1540
1541# ------------------------------------------------------------------------------
1542
1543#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
1544 const SkPoint& p3, const SkPoint& p4, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001545#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001546#Line # returns if Cubic is very small ##
Cary Clark73fa9722017-08-29 17:36:51 -04001547
1548Test if Cubic is degenerate.
1549Cubic with no length or that moves a very short distance is degenerate; it is
1550treated as a point.
1551
Cary Clarkce101242017-09-01 15:51:02 -04001552#Param p1 Cubic start point ##
1553#Param p2 Cubic control point 1 ##
1554#Param p3 Cubic control point 2 ##
1555#Param p4 Cubic end point ##
Cary Clark73fa9722017-08-29 17:36:51 -04001556#Param exact if true, returns true only if p1, p2, p3, and p4 are equal;
1557 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
1558##
1559
1560#Return true if Cubic is degenerate; its length is effectively zero ##
1561
1562#Example
1563void draw(SkCanvas* canvas) {
1564 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1565 SkScalar step = 1;
1566 SkScalar prior, length, degenerate;
1567 do {
1568 prior = points[0].fX;
1569 step /= 2;
1570 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1571 degenerate = prior;
1572 points[0].fX += step;
1573 } else {
1574 length = prior;
1575 points[0].fX -= step;
1576 }
1577 } while (prior != points[0].fX);
1578 SkDebugf("%1.8g is degenerate\n", degenerate);
1579 SkDebugf("%1.8g is length\n", length);
1580}
1581#StdOut
15820.00024414062 is degenerate
15830.00024414065 is length
1584#StdOut ##
1585##
1586
1587##
1588
1589# ------------------------------------------------------------------------------
1590
1591#Method bool isLine(SkPoint line[2]) const
Cary Clark4855f782018-02-06 09:41:53 -05001592#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001593#Line # returns if describes Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04001594Returns true if Path contains only one Line;
1595Path_Verb array has two entries: kMove_Verb, kLine_Verb.
1596If Path contains one Line and line is not nullptr, line is set to
1597Line start point and Line end point.
1598Returns false if Path is not one Line; line is unaltered.
1599
1600#Param line storage for Line. May be nullptr ##
1601
1602#Return true if Path contains exactly one Line ##
1603
1604#Example
1605void draw(SkCanvas* canvas) {
1606 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1607 SkPoint line[2];
1608 if (path.isLine(line)) {
1609 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1610 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1611 } else {
1612 SkDebugf("%s is not line\n", prefix);
1613 }
1614 };
1615 SkPath path;
1616 debugster("empty", path);
1617 path.lineTo(0, 0);
1618 debugster("zero line", path);
1619 path.rewind();
1620 path.moveTo(10, 10);
1621 path.lineTo(20, 20);
1622 debugster("line", path);
1623 path.moveTo(20, 20);
1624 debugster("second move", path);
1625}
1626#StdOut
1627empty is not line
1628zero line is line (0,0) (0,0)
1629line is line (10,10) (20,20)
1630second move is not line
1631##
1632##
1633
1634##
1635
1636# ------------------------------------------------------------------------------
1637
Cary Clark8032b982017-07-28 11:04:54 -04001638#Subtopic Point_Array
Cary Clark08895c42018-02-01 09:37:32 -05001639#Line # end points and control points for lines and curves ##
Cary Clark61dfc3a2018-01-03 08:37:53 -05001640#Substitute SkPoint array
Cary Clark8032b982017-07-28 11:04:54 -04001641
1642Point_Array contains Points satisfying the allocated Points for
1643each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001644and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001645one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1646
1647Point_Array may be read directly from Path with getPoints, or inspected with
1648getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001649
1650#Method int getPoints(SkPoint points[], int max) const
1651
Cary Clarkab2621d2018-01-30 10:08:57 -05001652#In Point_Array
1653#Line # returns Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001654Returns number of points in Path. Up to max points are copied.
1655points may be nullptr; then, max must be zero.
1656If max is greater than number of points, excess points storage is unaltered.
1657
1658#Param points storage for Path Point array. May be nullptr ##
1659#Param max maximum to copy; must be greater than or equal to zero ##
1660
1661#Return Path Point array length ##
1662
1663#Example
1664void draw(SkCanvas* canvas) {
1665 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1666 int count = path.getPoints(points, max);
1667 SkDebugf("%s point count: %d ", prefix, count);
1668 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1669 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1670 }
1671 SkDebugf("\n");
1672 };
1673 SkPath path;
1674 path.lineTo(20, 20);
1675 path.lineTo(-10, -10);
1676 SkPoint points[3];
1677 debugster("no points", path, nullptr, 0);
1678 debugster("zero max", path, points, 0);
1679 debugster("too small", path, points, 2);
1680 debugster("just right", path, points, path.countPoints());
1681}
1682#StdOut
1683no points point count: 3
1684zero max point count: 3
1685too small point count: 3 (0,0) (20,20)
1686just right point count: 3 (0,0) (20,20) (-10,-10)
1687##
1688##
1689
1690#SeeAlso countPoints getPoint
1691##
1692
1693#Method int countPoints() const
1694
Cary Clarkab2621d2018-01-30 10:08:57 -05001695#In Point_Array
1696#Line # returns Point_Array length ##
Cary Clark73fa9722017-08-29 17:36:51 -04001697Returns the number of points in Path.
1698Point count is initially zero.
1699
1700#Return Path Point array length ##
1701
1702#Example
1703void draw(SkCanvas* canvas) {
1704 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1705 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1706 };
1707 SkPath path;
1708 debugster("empty", path);
1709 path.lineTo(0, 0);
1710 debugster("zero line", path);
1711 path.rewind();
1712 path.moveTo(10, 10);
1713 path.lineTo(20, 20);
1714 debugster("line", path);
1715 path.moveTo(20, 20);
1716 debugster("second move", path);
1717}
1718#StdOut
1719empty point count: 0
1720zero line point count: 2
1721line point count: 2
1722second move point count: 3
1723##
1724##
1725
1726#SeeAlso getPoints
1727##
1728
1729#Method SkPoint getPoint(int index) const
1730
Cary Clarkab2621d2018-01-30 10:08:57 -05001731#In Point_Array
1732#Line # returns entry from Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001733Returns Point at index in Point_Array. Valid range for index is
17340 to countPoints - 1.
1735Returns (0, 0) if index is out of range.
1736
1737#Param index Point array element selector ##
1738
1739#Return Point array value or (0, 0) ##
1740
1741#Example
1742void draw(SkCanvas* canvas) {
1743 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1744 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1745 };
1746 SkPath path;
1747 path.lineTo(20, 20);
1748 path.offset(-10, -10);
1749 for (int i= 0; i < path.countPoints(); ++i) {
1750 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
1751 }
1752}
1753#StdOut
1754point 0: (-10,-10)
1755point 1: (10,10)
1756##
1757##
1758
1759#SeeAlso countPoints getPoints
1760##
1761
1762
1763#Subtopic Point_Array ##
1764
1765# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001766#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001767#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001768
1769Verb_Array always starts with kMove_Verb.
1770If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1771the quantity of kMove_Verb equals the Contour count.
1772Verb_Array does not include or count kDone_Verb; it is a convenience
1773returned when iterating through Verb_Array.
1774
1775Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
1776or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001777
1778#Method int countVerbs() const
1779
Cary Clarkab2621d2018-01-30 10:08:57 -05001780#In Verb_Array
1781#Line # returns Verb_Array length ##
Cary Clark73fa9722017-08-29 17:36:51 -04001782Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
1783kCubic_Verb, and kClose_Verb; added to Path.
1784
1785#Return length of Verb_Array ##
1786
1787#Example
1788SkPath path;
1789SkDebugf("empty verb count: %d\n", path.countVerbs());
1790path.addRoundRect({10, 20, 30, 40}, 5, 5);
1791SkDebugf("round rect verb count: %d\n", path.countVerbs());
1792#StdOut
1793empty verb count: 0
1794round rect verb count: 10
1795##
1796##
1797
1798#SeeAlso getVerbs Iter RawIter
1799
1800##
1801
1802#Method int getVerbs(uint8_t verbs[], int max) const
1803
Cary Clarkab2621d2018-01-30 10:08:57 -05001804#In Verb_Array
1805#Line # returns Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001806Returns the number of verbs in the path. Up to max verbs are copied. The
1807verbs are copied as one byte per verb.
1808
1809#Param verbs storage for verbs, may be nullptr ##
1810#Param max maximum number to copy into verbs ##
1811
1812#Return the actual number of verbs in the path ##
1813
1814#Example
1815void draw(SkCanvas* canvas) {
1816 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1817 int count = path.getVerbs(verbs, max);
1818 SkDebugf("%s verb count: %d ", prefix, count);
1819 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1820 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1821 SkDebugf("%s ", verbStr[verbs[i]]);
1822 }
1823 SkDebugf("\n");
1824 };
1825 SkPath path;
1826 path.lineTo(20, 20);
1827 path.lineTo(-10, -10);
1828 uint8_t verbs[3];
1829 debugster("no verbs", path, nullptr, 0);
1830 debugster("zero max", path, verbs, 0);
1831 debugster("too small", path, verbs, 2);
1832 debugster("just right", path, verbs, path.countVerbs());
1833}
1834#StdOut
1835no verbs verb count: 3
1836zero max verb count: 3
1837too small verb count: 3 move line
1838just right verb count: 3 move line line
1839##
1840##
1841
1842#SeeAlso countVerbs getPoints Iter RawIter
1843##
Cary Clark8032b982017-07-28 11:04:54 -04001844
1845#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001846
1847# ------------------------------------------------------------------------------
1848
1849#Method void swap(SkPath& other)
Cary Clark4855f782018-02-06 09:41:53 -05001850#In Operator
Cary Clarkab2621d2018-01-30 10:08:57 -05001851#Line # exchanges Path pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04001852Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1853Cached state is also exchanged. swap() internally exchanges pointers, so
1854it is lightweight and does not allocate memory.
1855
1856swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001857Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001858making assignment as efficient as swap().
1859
1860#Param other Path exchanged by value ##
1861
1862#Example
1863SkPath path1, path2;
1864path1.addRect({10, 20, 30, 40});
1865path1.swap(path2);
1866const SkRect& b1 = path1.getBounds();
1867SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1868const SkRect& b2 = path2.getBounds();
1869SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1870#StdOut
1871path1 bounds = 0, 0, 0, 0
1872path2 bounds = 10, 20, 30, 40
1873#StdOut ##
1874##
1875
1876#SeeAlso operator=(const SkPath& path)
1877
1878##
1879
1880# ------------------------------------------------------------------------------
1881
1882#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001883#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001884#Line # returns maximum and minimum of Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001885Returns minimum and maximum x and y values of Point_Array.
1886Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1887be larger or smaller than area affected when Path is drawn.
1888
1889Rect returned includes all Points added to Path, including Points associated with
1890kMove_Verb that define empty Contours.
1891
1892#Return bounds of all Points in Point_Array ##
1893
1894#Example
1895#Description
1896Bounds of upright Circle can be predicted from center and radius.
1897Bounds of rotated Circle includes control Points outside of filled area.
1898##
1899 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1900 const SkRect& bounds = path.getBounds();
1901 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
1902 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1903 };
1904 SkPath path;
1905 debugster("empty", path);
1906 path.addCircle(50, 45, 25);
1907 debugster("circle", path);
1908 SkMatrix matrix;
1909 matrix.setRotate(45, 50, 45);
1910 path.transform(matrix);
1911 debugster("rotated circle", path);
1912#StdOut
1913empty bounds = 0, 0, 0, 0
1914circle bounds = 25, 20, 75, 70
1915rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1916##
1917##
1918
1919#SeeAlso computeTightBounds updateBoundsCache
1920
1921##
1922
1923# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001924#Subtopic Utility
1925#Populate
1926#Line # rarely called management functions ##
1927##
Cary Clark73fa9722017-08-29 17:36:51 -04001928
1929#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001930#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001931#Line # refreshes result of getBounds ##
Cary Clark73fa9722017-08-29 17:36:51 -04001932Update internal bounds so that subsequent calls to getBounds are instantaneous.
1933Unaltered copies of Path may also access cached bounds through getBounds.
1934
1935For now, identical to calling getBounds and ignoring the returned value.
1936
1937Call to prepare Path subsequently drawn from multiple threads,
1938to avoid a race condition where each draw separately computes the bounds.
1939
1940#Example
1941 double times[2] = { 0, 0 };
1942 for (int i = 0; i < 10000; ++i) {
1943 SkPath path;
1944 for (int j = 1; j < 100; ++ j) {
1945 path.addCircle(50 + j, 45 + j, 25 + j);
1946 }
1947 if (1 & i) {
1948 path.updateBoundsCache();
1949 }
1950 double start = SkTime::GetNSecs();
1951 (void) path.getBounds();
1952 times[1 & i] += SkTime::GetNSecs() - start;
1953 }
1954 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1955 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1956#StdOut
1957#Volatile
1958uncached avg: 0.18048 ms
1959cached avg: 0.182784 ms
1960##
1961##
1962
1963#SeeAlso getBounds
1964#ToDo the results don't make sense, need to profile to figure this out ##
1965
1966##
1967
1968# ------------------------------------------------------------------------------
1969
1970#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001971#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001972#Line # returns extent of geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04001973Returns minimum and maximum x and y values of the lines and curves in Path.
1974Returns (0, 0, 0, 0) if Path contains no points.
1975Returned bounds width and height may be larger or smaller than area affected
1976when Path is drawn.
1977
1978Includes Points associated with kMove_Verb that define empty
1979Contours.
1980
1981Behaves identically to getBounds when Path contains
1982only lines. If Path contains curves, computed bounds includes
1983the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
1984and unlike getBounds, does not cache the result.
1985
1986#Return tight bounds of curves in Path ##
1987
1988#Example
1989 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1990 const SkRect& bounds = path.computeTightBounds();
1991 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
1992 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1993 };
1994 SkPath path;
1995 debugster("empty", path);
1996 path.addCircle(50, 45, 25);
1997 debugster("circle", path);
1998 SkMatrix matrix;
1999 matrix.setRotate(45, 50, 45);
2000 path.transform(matrix);
2001 debugster("rotated circle", path);
2002#StdOut
2003empty bounds = 0, 0, 0, 0
2004circle bounds = 25, 20, 75, 70
2005rotated circle bounds = 25, 20, 75, 70
2006##
2007##
2008
2009#SeeAlso getBounds
2010
2011##
2012
2013# ------------------------------------------------------------------------------
2014
2015#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05002016#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002017#Line # returns true if Rect may be inside ##
Cary Clark73fa9722017-08-29 17:36:51 -04002018Returns true if rect is contained by Path.
2019May return false when rect is contained by Path.
2020
2021For now, only returns true if Path has one Contour and is convex.
2022rect may share points and edges with Path and be contained.
2023Returns true if rect is empty, that is, it has zero width or height; and
2024the Point or Line described by rect is contained by Path.
2025
2026#Param rect Rect, Line, or Point checked for containment ##
2027
2028#Return true if rect is contained ##
2029
2030#Example
2031#Height 140
2032#Description
2033Rect is drawn in blue if it is contained by red Path.
2034##
2035void draw(SkCanvas* canvas) {
2036 SkPath path;
2037 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2038 SkRect tests[] = {
2039 { 10, 40, 54, 80 },
2040 { 25, 20, 39, 120 },
2041 { 15, 25, 49, 115 },
2042 { 13, 27, 51, 113 },
2043 };
2044 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2045 SkPaint paint;
2046 paint.setColor(SK_ColorRED);
2047 canvas->drawPath(path, paint);
2048 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2049 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2050 canvas->drawRect(tests[i], paint);
2051 canvas->translate(64, 0);
2052 }
2053}
2054##
2055
2056#SeeAlso contains Op Rect Convexity
2057
2058##
2059
2060# ------------------------------------------------------------------------------
2061
2062#Method void incReserve(unsigned extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05002063#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002064#Line # reserves space for additional data ##
Cary Clark73fa9722017-08-29 17:36:51 -04002065grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
2066May improve performance and use less memory by
2067reducing the number and size of allocations when creating Path.
2068
Cary Clarkce101242017-09-01 15:51:02 -04002069#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002070
2071#Example
2072#Height 192
2073void draw(SkCanvas* canvas) {
2074 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2075 path->moveTo(size, 0);
2076 for (int i = 1; i < sides; i++) {
2077 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2078 path->lineTo(c * size, s * size);
2079 }
2080 path->close();
2081 };
2082 SkPath path;
2083 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2084 for (int sides = 3; sides < 10; ++sides) {
2085 addPoly(sides, sides, &path);
2086 }
2087 SkMatrix matrix;
2088 matrix.setScale(10, 10, -10, -10);
2089 path.transform(matrix);
2090 SkPaint paint;
2091 paint.setStyle(SkPaint::kStroke_Style);
2092 canvas->drawPath(path, paint);
2093}
2094##
2095
2096#SeeAlso Point_Array
2097
2098##
2099
2100# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05002101#Subtopic Build
2102#Populate
2103#Line # adds points and verbs to path ##
2104##
Cary Clark73fa9722017-08-29 17:36:51 -04002105
2106#Method void moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002107#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002108#Line # starts Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -04002109Adds beginning of Contour at Point (x, y).
2110
2111#Param x x-coordinate of Contour start ##
2112#Param y y-coordinate of Contour start ##
2113
2114#Example
2115 #Width 140
2116 #Height 100
2117 void draw(SkCanvas* canvas) {
2118 SkRect rect = { 20, 20, 120, 80 };
2119 SkPath path;
2120 path.addRect(rect);
2121 path.moveTo(rect.fLeft, rect.fTop);
2122 path.lineTo(rect.fRight, rect.fBottom);
2123 path.moveTo(rect.fLeft, rect.fBottom);
2124 path.lineTo(rect.fRight, rect.fTop);
2125 SkPaint paint;
2126 paint.setStyle(SkPaint::kStroke_Style);
2127 canvas->drawPath(path, paint);
2128 }
2129##
2130
2131#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2132
2133##
2134
2135#Method void moveTo(const SkPoint& p)
2136
2137Adds beginning of Contour at Point p.
2138
2139#Param p contour start ##
2140
2141#Example
2142 #Width 128
2143 #Height 128
2144void draw(SkCanvas* canvas) {
2145 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
2146 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2147 SkPath path;
2148 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2149 path.moveTo(data[i][0]);
2150 path.lineTo(data[i][1]);
2151 path.lineTo(data[i][2]);
2152 }
2153 SkPaint paint;
2154 paint.setStyle(SkPaint::kStroke_Style);
2155 canvas->drawPath(path, paint);
2156}
2157##
2158
2159#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2160
2161##
2162
2163#Method void rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002164#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002165#Line # starts Contour relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002166Adds beginning of Contour relative to Last_Point.
2167If Path is empty, starts Contour at (dx, dy).
2168Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002169Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002170
2171#Param dx offset from Last_Point x to Contour start x ##
2172#Param dy offset from Last_Point y to Contour start y ##
2173
2174#Example
2175 #Height 100
2176 SkPath path;
2177 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2178 path.rMoveTo(25, 2);
2179 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2180 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2181 path.rLineTo(arrow[i].fX, arrow[i].fY);
2182 }
2183 SkPaint paint;
2184 canvas->drawPath(path, paint);
2185 SkPoint lastPt;
2186 path.getLastPt(&lastPt);
2187 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2188##
2189
2190#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2191
2192##
2193
2194# ------------------------------------------------------------------------------
2195
2196#Method void lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002197#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002198#Line # appends Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04002199Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2200kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2201
2202lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2203lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
2204
2205#Param x end of added Line in x ##
2206#Param y end of added Line in y ##
2207
2208#Example
2209#Height 100
2210###$
2211void draw(SkCanvas* canvas) {
2212 SkPaint paint;
2213 paint.setAntiAlias(true);
2214 paint.setTextSize(72);
2215 canvas->drawString("#", 120, 80, paint);
2216 paint.setStyle(SkPaint::kStroke_Style);
2217 paint.setStrokeWidth(5);
2218 SkPath path;
2219 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2220 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2221 unsigned o = 0;
2222 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2223 for (unsigned j = 0; j < 2; o++, j++) {
2224 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2225 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2226 }
2227 }
2228 canvas->drawPath(path, paint);
2229}
2230$$$#
2231##
2232
2233#SeeAlso Contour moveTo rLineTo addRect
2234
2235##
2236
2237# ------------------------------------------------------------------------------
2238
2239#Method void lineTo(const SkPoint& p)
2240
2241Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2242kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2243
2244lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2245lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2246
2247#Param p end Point of added Line ##
2248
2249#Example
2250#Height 100
2251 SkPath path;
2252 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2253 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2254 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2255 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2256 path.moveTo(oxo[i]);
2257 path.lineTo(oxo[i + 1]);
2258 }
2259 SkPaint paint;
2260 paint.setStyle(SkPaint::kStroke_Style);
2261 canvas->drawPath(path, paint);
2262##
2263
2264#SeeAlso Contour moveTo rLineTo addRect
2265
2266##
2267
2268# ------------------------------------------------------------------------------
2269
2270#Method void rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002271#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002272#Line # appends Line relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002273Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2274kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2275
2276Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2277then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2278Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002279Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002280
2281#Param dx offset from Last_Point x to Line end x ##
2282#Param dy offset from Last_Point y to Line end y ##
2283
2284#Example
2285#Height 128
2286void draw(SkCanvas* canvas) {
2287 SkPaint paint;
2288 paint.setAntiAlias(true);
2289 paint.setStyle(SkPaint::kStroke_Style);
2290 SkPath path;
2291 path.moveTo(10, 98);
2292 SkScalar x = 0, y = 0;
2293 for (int i = 10; i < 100; i += 5) {
2294 x += i * ((i & 2) - 1);
2295 y += i * (((i + 1) & 2) - 1);
2296 path.rLineTo(x, y);
2297
2298 }
2299 canvas->drawPath(path, paint);
2300}
2301##
2302
2303#SeeAlso Contour moveTo lineTo addRect
2304
2305##
2306
2307# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002308#Subtopic Quad
Cary Clarkce101242017-09-01 15:51:02 -04002309#Alias Quad
Cary Clark73fa9722017-08-29 17:36:51 -04002310#Alias Quads
Cary Clarkce101242017-09-01 15:51:02 -04002311#Alias Quadratic_Bezier
2312#Alias Quadratic_Beziers
Cary Clark08895c42018-02-01 09:37:32 -05002313#Line # Bezier_Curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002314
2315Quad describes a quadratic Bezier, a second-order curve identical to a section
2316of a parabola. Quad begins at a start Point, curves towards a control Point,
2317and then curves to an end Point.
2318
2319#Example
2320#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002321void draw(SkCanvas* canvas) {
2322 SkPaint paint;
2323 paint.setAntiAlias(true);
2324 paint.setStyle(SkPaint::kStroke_Style);
2325 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2326 canvas->drawLine(quadPts[0], quadPts[1], paint);
2327 canvas->drawLine(quadPts[1], quadPts[2], paint);
2328 SkPath path;
2329 path.moveTo(quadPts[0]);
2330 path.quadTo(quadPts[1], quadPts[2]);
2331 paint.setStrokeWidth(3);
2332 canvas->drawPath(path, paint);
2333}
Cary Clark8032b982017-07-28 11:04:54 -04002334##
2335
2336Quad is a special case of Conic where Conic_Weight is set to one.
2337
2338Quad is always contained by the triangle connecting its three Points. Quad
2339begins tangent to the line between start Point and control Point, and ends
2340tangent to the line between control Point and end Point.
2341
2342#Example
2343#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002344void draw(SkCanvas* canvas) {
2345 SkPaint paint;
2346 paint.setAntiAlias(true);
2347 paint.setStyle(SkPaint::kStroke_Style);
2348 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2349 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2350 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2351 paint.setColor(0x7fffffff & colors[i]);
2352 paint.setStrokeWidth(1);
2353 canvas->drawLine(quadPts[0], quadPts[1], paint);
2354 canvas->drawLine(quadPts[1], quadPts[2], paint);
2355 SkPath path;
2356 path.moveTo(quadPts[0]);
2357 path.quadTo(quadPts[1], quadPts[2]);
2358 paint.setStrokeWidth(3);
2359 paint.setColor(colors[i]);
2360 canvas->drawPath(path, paint);
2361 quadPts[1].fY += 30;
2362 }
Cary Clark8032b982017-07-28 11:04:54 -04002363}
2364##
Cary Clark73fa9722017-08-29 17:36:51 -04002365
2366#Method void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
2367
Cary Clarkab2621d2018-01-30 10:08:57 -05002368#In Quad
2369#Line # appends Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002370 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
2371 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2372 before adding Quad.
2373
2374 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2375 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2376 to Point_Array.
2377
2378 #Param x1 control Point of Quad in x ##
2379 #Param y1 control Point of Quad in y ##
2380 #Param x2 end Point of Quad in x ##
2381 #Param y2 end Point of Quad in y ##
2382
2383 #Example
2384 void draw(SkCanvas* canvas) {
2385 SkPaint paint;
2386 paint.setAntiAlias(true);
2387 paint.setStyle(SkPaint::kStroke_Style);
2388 SkPath path;
2389 path.moveTo(0, -10);
2390 for (int i = 0; i < 128; i += 16) {
2391 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2392 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2393 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2394 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2395 }
2396 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002397 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002398 }
2399 ##
2400
2401 #SeeAlso Contour moveTo conicTo rQuadTo
2402
2403##
2404
2405#Method void quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05002406#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002407#In Quad
Cary Clark73fa9722017-08-29 17:36:51 -04002408 Adds Quad from Last_Point towards Point p1, to Point p2.
2409 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2410 before adding Quad.
2411
2412 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2413 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2414 to Point_Array.
2415
2416 #Param p1 control Point of added Quad ##
2417 #Param p2 end Point of added Quad ##
2418
2419 #Example
2420 void draw(SkCanvas* canvas) {
2421 SkPaint paint;
2422 paint.setStyle(SkPaint::kStroke_Style);
2423 paint.setAntiAlias(true);
2424 SkPath path;
2425 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2426 path.moveTo(pts[1]);
2427 for (int i = 0; i < 3; ++i) {
2428 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2429 }
2430 canvas->drawPath(path, paint);
2431 }
2432 ##
2433
2434 #SeeAlso Contour moveTo conicTo rQuadTo
2435
2436##
2437
2438#Method void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05002439#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002440#In Quad
2441#Line # appends Quad relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002442 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2443 If Path is empty, or last Verb
2444 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2445
2446 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2447 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2448 control and Quad end to Point_Array.
2449 Quad control is Last_Point plus Vector (dx1, dy1).
2450 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002451 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002452
2453 #Param dx1 offset from Last_Point x to Quad control x ##
2454 #Param dy1 offset from Last_Point x to Quad control y ##
2455 #Param dx2 offset from Last_Point x to Quad end x ##
2456 #Param dy2 offset from Last_Point x to Quad end y ##
2457
2458 #Example
2459 void draw(SkCanvas* canvas) {
2460 SkPaint paint;
2461 paint.setAntiAlias(true);
2462 SkPath path;
2463 path.moveTo(128, 20);
2464 path.rQuadTo(-6, 10, -7, 10);
2465 for (int i = 1; i < 32; i += 4) {
2466 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2467 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2468 }
2469 path.quadTo(92, 220, 128, 215);
2470 canvas->drawPath(path, paint);
2471 }
2472 ##
2473
2474 #SeeAlso Contour moveTo conicTo quadTo
2475
2476##
2477
Cary Clark78de7512018-02-07 07:27:09 -05002478#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002479
2480# ------------------------------------------------------------------------------
2481
Cary Clark78de7512018-02-07 07:27:09 -05002482#Subtopic Conic
Cary Clark08895c42018-02-01 09:37:32 -05002483#Line # conic section defined by three points and a weight ##
Cary Clark8032b982017-07-28 11:04:54 -04002484#Alias Conics
2485
2486Conic describes a conical section: a piece of an ellipse, or a piece of a
2487parabola, or a piece of a hyperbola. Conic begins at a start Point,
2488curves towards a control Point, and then curves to an end Point. The influence
2489of the control Point is determined by Conic_Weight.
2490
Cary Clark73fa9722017-08-29 17:36:51 -04002491Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2492may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002493
2494#Subtopic Weight
Cary Clarke0403842017-09-01 19:21:29 +00002495#Alias Conic_Weights
Cary Clarkce101242017-09-01 15:51:02 -04002496#Alias Weights
Cary Clark08895c42018-02-01 09:37:32 -05002497#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002498
2499Weight determines both the strength of the control Point and the type of Conic.
2500If Weight is exactly one, then Conic is identical to Quad; it is always a
2501parabolic segment.
2502
2503
2504
2505#Example
2506#Description
Cary Clark73fa9722017-08-29 17:36:51 -04002507When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002508##
Cary Clark73fa9722017-08-29 17:36:51 -04002509void draw(SkCanvas* canvas) {
2510 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2511 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2512 SkPath path;
2513 path.conicTo(20, 30, 50, 60, 1);
2514 SkPath::Iter iter(path, false);
2515 SkPath::Verb verb;
2516 do {
2517 SkPoint points[4];
2518 verb = iter.next(points);
2519 SkDebugf("%s ", verbNames[(int) verb]);
2520 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2521 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2522 }
2523 if (SkPath::kConic_Verb == verb) {
2524 SkDebugf("weight = %g", iter.conicWeight());
2525 }
2526 SkDebugf("\n");
2527 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002528}
2529#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002530move {0, 0},
2531quad {0, 0}, {20, 30}, {50, 60},
Cary Clark8032b982017-07-28 11:04:54 -04002532done
2533##
2534##
2535
2536If weight is less than one, Conic is an elliptical segment.
2537
2538#Example
2539#Description
2540A 90 degree circular arc has the weight
2541#Formula
25421 / sqrt(2)
2543##
Cary Clark6fc50412017-09-21 12:31:06 -04002544.
Cary Clark8032b982017-07-28 11:04:54 -04002545##
Cary Clark73fa9722017-08-29 17:36:51 -04002546void draw(SkCanvas* canvas) {
2547 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2548 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2549 SkPath path;
2550 path.arcTo(20, 0, 20, 20, 20);
2551 SkPath::Iter iter(path, false);
2552 SkPath::Verb verb;
2553 do {
2554 SkPoint points[4];
2555 verb = iter.next(points);
2556 SkDebugf("%s ", verbNames[(int) verb]);
2557 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2558 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2559 }
2560 if (SkPath::kConic_Verb == verb) {
2561 SkDebugf("weight = %g", iter.conicWeight());
2562 }
2563 SkDebugf("\n");
2564 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002565}
2566#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002567move {0, 0},
2568conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark8032b982017-07-28 11:04:54 -04002569done
2570##
2571##
2572
Cary Clarkce101242017-09-01 15:51:02 -04002573If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002574a hyperbolic segment can be approximated by straight lines connecting the
2575control Point with the end Points.
2576
2577#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002578void draw(SkCanvas* canvas) {
2579 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2580 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2581 SkPath path;
2582 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2583 SkPath::Iter iter(path, false);
2584 SkPath::Verb verb;
2585 do {
2586 SkPoint points[4];
2587 verb = iter.next(points);
2588 SkDebugf("%s ", verbNames[(int) verb]);
2589 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2590 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2591 }
2592 if (SkPath::kConic_Verb == verb) {
2593 SkDebugf("weight = %g", iter.conicWeight());
2594 }
2595 SkDebugf("\n");
2596 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002597}
2598#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002599move {0, 0},
2600line {0, 0}, {20, 0},
2601line {20, 0}, {20, 20},
Cary Clark8032b982017-07-28 11:04:54 -04002602done
2603##
2604##
2605
2606#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002607
2608#Method void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2609 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002610#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002611#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002612#Line # appends Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002613
2614 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
2615 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2616 before adding Conic.
2617
2618 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2619
2620 If w is finite and not one, appends kConic_Verb to Verb_Array;
2621 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2622
2623 If w is one, appends kQuad_Verb to Verb_Array, and
2624 (x1, y1), (x2, y2) to Point_Array.
2625
2626 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2627 (x1, y1), (x2, y2) to Point_Array.
2628
2629 #Param x1 control Point of Conic in x ##
2630 #Param y1 control Point of Conic in y ##
2631 #Param x2 end Point of Conic in x ##
2632 #Param y2 end Point of Conic in y ##
2633 #Param w weight of added Conic ##
2634
2635 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002636 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002637 #Description
2638 As weight increases, curve is pulled towards control point.
2639 The bottom two curves are elliptical; the next is parabolic; the
2640 top curve is hyperbolic.
2641 ##
2642void draw(SkCanvas* canvas) {
2643 SkPaint paint;
2644 paint.setAntiAlias(true);
2645 paint.setStyle(SkPaint::kStroke_Style);
2646 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2647 canvas->drawLine(conicPts[0], conicPts[1], paint);
2648 canvas->drawLine(conicPts[1], conicPts[2], paint);
2649 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2650 paint.setStrokeWidth(3);
2651 SkScalar weight = 0.5f;
2652 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2653 SkPath path;
2654 path.moveTo(conicPts[0]);
2655 path.conicTo(conicPts[1], conicPts[2], weight);
2656 paint.setColor(colors[i]);
2657 canvas->drawPath(path, paint);
2658 weight += 0.25f;
2659 }
2660}
2661 ##
2662
2663 #SeeAlso rConicTo arcTo addArc quadTo
2664
2665##
2666
2667#Method void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002668#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002669#In Conic
Cary Clark73fa9722017-08-29 17:36:51 -04002670 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
2671 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2672 before adding Conic.
2673
2674 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2675
2676 If w is finite and not one, appends kConic_Verb to Verb_Array;
2677 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2678
2679 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2680 to Point_Array.
2681
2682 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2683 Points p1, p2 to Point_Array.
2684
2685 #Param p1 control Point of added Conic ##
2686 #Param p2 end Point of added Conic ##
2687 #Param w weight of added Conic ##
2688
2689 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002690 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002691 #Description
2692 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002693 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002694 ##
2695void draw(SkCanvas* canvas) {
2696 SkPaint paint;
2697 paint.setAntiAlias(true);
2698 paint.setStyle(SkPaint::kStroke_Style);
2699 SkRect oval = {0, 20, 120, 140};
2700 SkPath path;
2701 for (int i = 0; i < 4; ++i) {
2702 path.moveTo(oval.centerX(), oval.fTop);
2703 path.arcTo(oval, -90, 90 - 20 * i, false);
2704 oval.inset(15, 15);
2705 }
2706 path.offset(100, 0);
2707 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2708 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2709 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2710 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2711 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2712 for (int i = 0; i < 4; ++i) {
2713 path.moveTo(conicPts[i][0]);
2714 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2715 }
2716 canvas->drawPath(path, paint);
2717}
2718 ##
2719
2720 #SeeAlso rConicTo arcTo addArc quadTo
2721
2722##
2723
2724#Method void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2725 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002726#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002727#In Conic
2728#Line # appends Conic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002729
2730 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2731 weighted by w. If Path is empty, or last Verb
2732 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2733
2734 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2735 if needed.
2736
2737 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2738 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2739 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2740 twice to Verb_Array.
2741
2742 In all cases appends Points control and end to Point_Array.
2743 control is Last_Point plus Vector (dx1, dy1).
2744 end is Last_Point plus Vector (dx2, dy2).
2745
Cary Clarkce101242017-09-01 15:51:02 -04002746 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002747
2748 #Param dx1 offset from Last_Point x to Conic control x ##
2749 #Param dy1 offset from Last_Point x to Conic control y ##
2750 #Param dx2 offset from Last_Point x to Conic end x ##
2751 #Param dy2 offset from Last_Point x to Conic end y ##
2752 #Param w weight of added Conic ##
2753
2754 #Example
2755 #Height 140
2756 void draw(SkCanvas* canvas) {
2757 SkPaint paint;
2758 paint.setAntiAlias(true);
2759 paint.setStyle(SkPaint::kStroke_Style);
2760 SkPath path;
2761 path.moveTo(20, 80);
2762 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2763 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2764 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2765 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2766 canvas->drawPath(path, paint);
2767 }
2768 ##
2769
2770 #SeeAlso conicTo arcTo addArc quadTo
2771
2772##
2773
Cary Clark78de7512018-02-07 07:27:09 -05002774#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002775
2776# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002777#Subtopic Cubic
Cary Clarkce101242017-09-01 15:51:02 -04002778#Alias Cubic
Cary Clark8032b982017-07-28 11:04:54 -04002779#Alias Cubics
Cary Clarkce101242017-09-01 15:51:02 -04002780#Alias Cubic_Bezier
2781#Alias Cubic_Beziers
Cary Clark08895c42018-02-01 09:37:32 -05002782#Line # Bezier_Curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002783
Cary Clarka560c472017-11-27 10:44:06 -05002784Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002785Cubic begins at a start Point, curving towards the first control Point;
2786and curves from the end Point towards the second control Point.
2787
2788#Example
2789#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002790void draw(SkCanvas* canvas) {
2791 SkPaint paint;
2792 paint.setAntiAlias(true);
2793 paint.setStyle(SkPaint::kStroke_Style);
2794 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2795 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2796 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2797 paint.setColor(0x7fffffff & colors[i]);
2798 paint.setStrokeWidth(1);
2799 for (unsigned j = 0; j < 3; ++j) {
2800 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2801 }
2802 SkPath path;
2803 path.moveTo(cubicPts[0]);
2804 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2805 paint.setStrokeWidth(3);
2806 paint.setColor(colors[i]);
2807 canvas->drawPath(path, paint);
2808 cubicPts[1].fY += 30;
2809 cubicPts[2].fX += 30;
2810 }
Cary Clark8032b982017-07-28 11:04:54 -04002811}
2812##
Cary Clark73fa9722017-08-29 17:36:51 -04002813
2814#Method void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2815 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002816#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002817#In Cubic
2818#Line # appends Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002819
2820Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2821(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2822(0, 0) before adding Cubic.
2823
2824Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2825then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
2826to Point_Array.
2827
2828#Param x1 first control Point of Cubic in x ##
2829#Param y1 first control Point of Cubic in y ##
2830#Param x2 second control Point of Cubic in x ##
2831#Param y2 second control Point of Cubic in y ##
2832#Param x3 end Point of Cubic in x ##
2833#Param y3 end Point of Cubic in y ##
2834
2835#Example
2836void draw(SkCanvas* canvas) {
2837 SkPaint paint;
2838 paint.setAntiAlias(true);
2839 paint.setStyle(SkPaint::kStroke_Style);
2840 SkPath path;
2841 path.moveTo(0, -10);
2842 for (int i = 0; i < 128; i += 16) {
2843 SkScalar c = i * 0.5f;
2844 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2845 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2846 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2847 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2848 }
2849 path.offset(128, 128);
2850 canvas->drawPath(path, paint);
2851}
2852##
2853
2854#SeeAlso Contour moveTo rCubicTo quadTo
2855
2856##
2857
2858# ------------------------------------------------------------------------------
2859
2860#Method void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
2861
Cary Clark4855f782018-02-06 09:41:53 -05002862#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002863#In Cubic
Cary Clark73fa9722017-08-29 17:36:51 -04002864Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2865Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2866(0, 0) before adding Cubic.
2867
2868Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2869then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2870to Point_Array.
2871
2872#Param p1 first control Point of Cubic ##
2873#Param p2 second control Point of Cubic ##
2874#Param p3 end Point of Cubic ##
2875
2876#Example
2877#Height 84
2878 SkPaint paint;
2879 paint.setAntiAlias(true);
2880 paint.setStyle(SkPaint::kStroke_Style);
2881 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2882 SkPath path;
2883 path.moveTo(pts[0]);
2884 path.cubicTo(pts[1], pts[2], pts[3]);
2885 canvas->drawPath(path, paint);
2886##
2887
2888#SeeAlso Contour moveTo rCubicTo quadTo
2889
2890##
2891
2892# ------------------------------------------------------------------------------
2893
2894#Method void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2895 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002896#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002897#In Cubic
2898#Line # appends Cubic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002899
2900 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2901 Vector (dx2, dy2), to Vector (dx3, dy3).
2902 If Path is empty, or last Verb
2903 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2904
2905 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2906 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2907 control and Cubic end to Point_Array.
2908 Cubic control is Last_Point plus Vector (dx1, dy1).
2909 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002910 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002911
2912 #Param x1 offset from Last_Point x to first Cubic control x ##
2913 #Param y1 offset from Last_Point x to first Cubic control y ##
2914 #Param x2 offset from Last_Point x to second Cubic control x ##
2915 #Param y2 offset from Last_Point x to second Cubic control y ##
2916 #Param x3 offset from Last_Point x to Cubic end x ##
2917 #Param y3 offset from Last_Point x to Cubic end y ##
2918
2919#Example
2920 void draw(SkCanvas* canvas) {
2921 SkPaint paint;
2922 paint.setAntiAlias(true);
2923 paint.setStyle(SkPaint::kStroke_Style);
2924 SkPath path;
2925 path.moveTo(24, 108);
2926 for (int i = 0; i < 16; i++) {
2927 SkScalar sx, sy;
2928 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2929 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2930 }
2931 canvas->drawPath(path, paint);
2932 }
2933##
2934
2935#SeeAlso Contour moveTo cubicTo quadTo
2936
2937##
2938
Cary Clark78de7512018-02-07 07:27:09 -05002939#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002940
2941# ------------------------------------------------------------------------------
2942
Cary Clark08895c42018-02-01 09:37:32 -05002943#Subtopic Arc
2944#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04002945Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
2946by start point and end point, and by radius and tangent lines. Each construction has advantages,
2947and some constructions correspond to Arc drawing in graphics standards.
2948
2949All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
2950Conic describes an Arc of some Oval or Circle.
2951
2952arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
2953describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
2954which may continue Contour or start a new one. This construction is similar to PostScript and
2955HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
2956requiring Path.
2957
2958arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
2959describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
2960where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
2961HTML_Canvas arcs.
2962
2963arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
2964 SkScalar x, SkScalar y)
2965describes Arc as part of Oval with radii (rx, ry), beginning at
2966last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
2967so additional values choose a single solution. This construction is similar to SVG arcs.
2968
2969conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
2970conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
2971constructions are converted to Conic data when added to Path.
2972
2973#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
2974 do the kind of table shown in the illustration.
2975 example is spaced correctly on fiddle but spacing is too wide on pc
2976##
2977
2978#Example
2979#Height 300
2980#Width 600
2981#Description
2982#List
2983# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
2984# <sup>2</sup> parameter sets force MoveTo ##
Cary Clark5081eed2018-01-22 07:55:48 -05002985# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04002986# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
2987# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
2988 Direction sweep, SkScalar x, SkScalar y) ##
2989#List ##
2990#Description ##
2991#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05002992###$
Cary Clark73fa9722017-08-29 17:36:51 -04002993struct data {
2994 const char* name;
2995 char super;
2996 int yn[10];
2997};
2998
2999const data dataSet[] = {
3000{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
3001{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
3002{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
3003{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
3004{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
3005{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
3006};
3007
3008#define __degree_symbol__ "\xC2" "\xB0"
3009
3010const char* headers[] = {
3011 "Oval part",
3012 "force moveTo",
3013 "can draw 180" __degree_symbol__,
3014 "can draw 360" __degree_symbol__,
3015 "can draw greater than 360" __degree_symbol__,
3016 "ignored if radius is zero",
3017 "ignored if sweep is zero",
3018 "requires Path",
3019 "describes rotation",
3020 "describes perspective",
3021};
3022
3023const char* yna[] = {
3024 "n/a",
3025 "no",
3026 "yes"
3027};
Cary Clark1a8d7622018-03-05 13:26:16 -05003028$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003029##
3030void draw(SkCanvas* canvas) {
3031 SkPaint lp;
3032 lp.setAntiAlias(true);
3033 SkPaint tp(lp);
3034 SkPaint sp(tp);
3035 SkPaint bp(tp);
3036 bp.setFakeBoldText(true);
3037 sp.setTextSize(10);
3038 lp.setColor(SK_ColorGRAY);
3039 canvas->translate(0, 32);
3040 const int tl = 115;
3041 for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
3042 canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
3043 if (0 == col) {
3044 continue;
3045 }
3046 canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
3047 SkPath path;
3048 path.moveTo(tl - 3 + col * 35, 103);
3049 path.lineTo(tl + 124 + col * 35, -24);
3050 canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
3051 }
3052 for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
3053 if (0 == row) {
3054 canvas->drawLine(tl, 100, tl + 350, 100, lp);
3055 } else {
3056 canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
3057 }
3058 if (row == SK_ARRAY_COUNT(dataSet)) {
3059 break;
3060 }
3061 canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
3062 if (dataSet[row].super) {
3063 SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
3064 canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
3065 }
3066 for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
3067 int val = dataSet[row].yn[col];
3068 canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
3069 if (val > 1) {
3070 char supe = '0' + val - 1;
3071 canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
3072 }
3073 }
3074 }
3075}
3076#Example ##
3077
3078#Example
3079#Height 128
3080#Description
3081#ToDo make this a list or table ##
30821 describes an arc from an oval, a starting angle, and a sweep angle.
30832 is similar to 1, but does not require building a path to draw.
30843 is similar to 1, but always begins new Contour.
30854 describes an arc from a pair of tangent lines and a radius.
30865 describes an arc from Oval center, arc start Point and arc end Point.
30876 describes an arc from a pair of tangent lines and a Conic_Weight.
3088##
3089void draw(SkCanvas* canvas) {
3090 SkRect oval = {8, 8, 56, 56};
3091 SkPaint ovalPaint;
3092 ovalPaint.setAntiAlias(true);
3093 SkPaint textPaint(ovalPaint);
3094 ovalPaint.setStyle(SkPaint::kStroke_Style);
3095 SkPaint arcPaint(ovalPaint);
3096 arcPaint.setStrokeWidth(5);
3097 arcPaint.setColor(SK_ColorBLUE);
3098 canvas->translate(-64, 0);
3099 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3100 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3101 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3102 canvas->drawOval(oval, ovalPaint);
3103 SkPath path;
3104 path.moveTo({56, 32});
3105 switch (arcStyle) {
3106 case '1':
3107 path.arcTo(oval, 0, 90, false);
3108 break;
3109 case '2':
3110 canvas->drawArc(oval, 0, 90, false, arcPaint);
3111 continue;
3112 case '3':
3113 path.addArc(oval, 0, 90);
3114 break;
3115 case '4':
3116 path.arcTo({56, 56}, {32, 56}, 24);
3117 break;
3118 case '5':
3119 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3120 break;
3121 case '6':
3122 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3123 break;
3124 }
3125 canvas->drawPath(path, arcPaint);
3126 }
3127}
3128#Example ##
3129
3130
3131#Method void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05003132#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003133#In Arc
3134#Line # appends Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003135Append Arc to Path. Arc added is part of ellipse
3136bounded by oval, from startAngle through sweepAngle. Both startAngle and
3137sweepAngle are measured in degrees, where zero degrees is aligned with the
3138positive x-axis, and positive sweeps extends Arc clockwise.
3139
3140arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3141is false and Path is not empty. Otherwise, added Contour begins with first point
3142of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3143
3144#Param oval bounds of ellipse containing Arc ##
3145#Param startAngle starting angle of Arc in degrees ##
3146#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3147#Param forceMoveTo true to start a new contour with Arc ##
3148
3149#Example
3150#Height 200
3151#Description
3152arcTo continues a previous contour when forceMoveTo is false and when Path
3153is not empty.
3154##
3155void draw(SkCanvas* canvas) {
3156 SkPaint paint;
3157 SkPath path;
3158 paint.setStyle(SkPaint::kStroke_Style);
3159 paint.setStrokeWidth(4);
3160 path.moveTo(0, 0);
3161 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3162 canvas->drawPath(path, paint);
3163 path.rewind();
3164 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3165 canvas->drawPath(path, paint);
3166 path.rewind();
3167 path.moveTo(0, 0);
3168 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3169 canvas->drawPath(path, paint);
3170}
3171##
3172
3173#SeeAlso addArc SkCanvas::drawArc conicTo
3174
3175##
3176
3177# ------------------------------------------------------------------------------
3178
3179#Method void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003180#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003181#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003182Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3183weighted to describe part of Circle. Arc is contained by tangent from
3184last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
3185is part of Circle sized to radius, positioned so it touches both tangent lines.
3186
3187#ToDo allow example to hide source and not be exposed as fiddle ##
3188
3189#Example
3190#Height 226
3191void draw(SkCanvas* canvas) {
3192 SkPaint tangentPaint;
3193 tangentPaint.setAntiAlias(true);
3194 SkPaint textPaint(tangentPaint);
3195 tangentPaint.setStyle(SkPaint::kStroke_Style);
3196 tangentPaint.setColor(SK_ColorGRAY);
3197 SkPaint arcPaint(tangentPaint);
3198 arcPaint.setStrokeWidth(5);
3199 arcPaint.setColor(SK_ColorBLUE);
3200 SkPath path;
3201 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3202 SkScalar radius = 50;
3203 path.moveTo(pts[0]);
3204 path.arcTo(pts[1], pts[2], radius);
3205 canvas->drawLine(pts[0], pts[1], tangentPaint);
3206 canvas->drawLine(pts[1], pts[2], tangentPaint);
3207 SkPoint lastPt;
3208 (void) path.getLastPt(&lastPt);
3209 SkVector radial = pts[2] - pts[1];
3210 radial.setLength(radius);
3211 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3212 canvas->drawCircle(center, radius, tangentPaint);
3213 canvas->drawLine(lastPt, center, tangentPaint);
3214 radial = pts[1] - pts[0];
3215 radial.setLength(radius);
3216 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3217 canvas->drawLine(center, arcStart, tangentPaint);
3218 canvas->drawPath(path, arcPaint);
3219 textPaint.setTextAlign(SkPaint::kRight_Align);
3220 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3221 textPaint.setTextAlign(SkPaint::kLeft_Align);
3222 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3223 textPaint.setTextAlign(SkPaint::kCenter_Align);
3224 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3225 textPaint.setTextAlign(SkPaint::kRight_Align);
3226 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3227 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3228}
3229##
3230
3231If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3232The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3233
3234#Example
3235#Height 128
3236void draw(SkCanvas* canvas) {
3237 SkPaint tangentPaint;
3238 tangentPaint.setAntiAlias(true);
3239 SkPaint textPaint(tangentPaint);
3240 tangentPaint.setStyle(SkPaint::kStroke_Style);
3241 tangentPaint.setColor(SK_ColorGRAY);
3242 SkPaint arcPaint(tangentPaint);
3243 arcPaint.setStrokeWidth(5);
3244 arcPaint.setColor(SK_ColorBLUE);
3245 SkPath path;
3246 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3247 SkScalar radius = 50;
3248 path.moveTo(pts[0]);
3249 path.arcTo(pts[1], pts[2], radius);
3250 canvas->drawLine(pts[0], pts[1], tangentPaint);
3251 canvas->drawLine(pts[1], pts[2], tangentPaint);
3252 SkPoint lastPt;
3253 (void) path.getLastPt(&lastPt);
3254 SkVector radial = pts[2] - pts[1];
3255 radial.setLength(radius);
3256 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3257 canvas->drawLine(lastPt, center, tangentPaint);
3258 radial = pts[1] - pts[0];
3259 radial.setLength(radius);
3260 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3261 canvas->drawLine(center, arcStart, tangentPaint);
3262 canvas->drawPath(path, arcPaint);
3263 textPaint.setTextAlign(SkPaint::kCenter_Align);
3264 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3265 textPaint.setTextAlign(SkPaint::kLeft_Align);
3266 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3267 textPaint.setTextAlign(SkPaint::kCenter_Align);
3268 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3269 textPaint.setTextAlign(SkPaint::kRight_Align);
3270 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3271 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3272}
3273##
3274
3275Arc sweep is always less than 180 degrees. If radius is zero, or if
3276tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3277
3278arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003279arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003280
3281#Param x1 x common to pair of tangents ##
3282#Param y1 y common to pair of tangents ##
3283#Param x2 x end of second tangent ##
3284#Param y2 y end of second tangent ##
3285#Param radius distance from Arc to Circle center ##
3286
3287#Example
3288#Description
3289arcTo is represented by Line and circular Conic in Path.
3290##
3291void draw(SkCanvas* canvas) {
3292 SkPath path;
3293 path.moveTo({156, 20});
3294 path.arcTo(200, 20, 170, 50, 50);
3295 SkPath::Iter iter(path, false);
3296 SkPoint p[4];
3297 SkPath::Verb verb;
3298 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3299 switch (verb) {
3300 case SkPath::kMove_Verb:
3301 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3302 break;
3303 case SkPath::kLine_Verb:
3304 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3305 break;
3306 case SkPath::kConic_Verb:
3307 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3308 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3309 break;
3310 default:
3311 SkDebugf("unexpected verb\n");
3312 }
3313 }
3314}
3315#StdOut
3316move to (156,20)
3317line (156,20),(79.2893,20)
3318conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3319##
3320##
3321
3322#SeeAlso conicTo
3323
3324##
3325
3326# ------------------------------------------------------------------------------
3327
3328#Method void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003329#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003330#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003331Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3332weighted to describe part of Circle. Arc is contained by tangent from
3333last Path point to p1, and tangent from p1 to p2. Arc
3334is part of Circle sized to radius, positioned so it touches both tangent lines.
3335
3336If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3337The length of Vector from p1 to p2 does not affect Arc.
3338
3339Arc sweep is always less than 180 degrees. If radius is zero, or if
3340tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3341
3342arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003343arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003344
3345#Param p1 Point common to pair of tangents ##
3346#Param p2 end of second tangent ##
3347#Param radius distance from Arc to Circle center ##
3348
3349#Example
3350#Description
3351Because tangent lines are parallel, arcTo appends line from last Path Point to
3352p1, but does not append a circular Conic.
3353##
3354void draw(SkCanvas* canvas) {
3355 SkPath path;
3356 path.moveTo({156, 20});
3357 path.arcTo({200, 20}, {170, 20}, 50);
3358 SkPath::Iter iter(path, false);
3359 SkPoint p[4];
3360 SkPath::Verb verb;
3361 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3362 switch (verb) {
3363 case SkPath::kMove_Verb:
3364 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3365 break;
3366 case SkPath::kLine_Verb:
3367 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3368 break;
3369 case SkPath::kConic_Verb:
3370 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3371 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3372 break;
3373 default:
3374 SkDebugf("unexpected verb\n");
3375 }
3376 }
3377}
3378#StdOut
3379move to (156,20)
3380line (156,20),(200,20)
3381##
3382##
3383
3384#SeeAlso conicTo
3385
3386##
3387
3388# ------------------------------------------------------------------------------
3389
3390#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05003391#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04003392
3393#Code
3394 enum ArcSize {
3395 kSmall_ArcSize,
3396 kLarge_ArcSize,
3397 };
3398##
3399
3400Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3401ArcSize and Direction select one of the four Oval parts.
3402
3403#Const kSmall_ArcSize 0
Cary Clark154beea2017-10-26 07:58:48 -04003404smaller of Arc pair
Cary Clark73fa9722017-08-29 17:36:51 -04003405##
3406#Const kLarge_ArcSize 1
Cary Clark154beea2017-10-26 07:58:48 -04003407larger of Arc pair
Cary Clark73fa9722017-08-29 17:36:51 -04003408##
3409
3410#Example
3411#Height 160
3412#Description
3413Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3414Two routes are large, and two routes are counterclockwise. The one route both large
3415and counterclockwise is blue.
3416##
3417void draw(SkCanvas* canvas) {
3418 SkPaint paint;
3419 paint.setAntiAlias(true);
3420 paint.setStyle(SkPaint::kStroke_Style);
3421 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3422 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3423 SkPath path;
3424 path.moveTo({120, 50});
3425 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3426 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3427 paint.setColor(SK_ColorBLUE);
3428 paint.setStrokeWidth(3);
3429 }
3430 canvas->drawPath(path, paint);
3431 }
3432 }
3433}
3434##
3435
3436#SeeAlso arcTo Direction
3437
3438##
3439
3440# ------------------------------------------------------------------------------
3441
3442#Method void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3443 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003444#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003445#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003446
Cary Clark154beea2017-10-26 07:58:48 -04003447Append Arc to Path. Arc is implemented by one or more Conics weighted to
3448describe part of Oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
3449curves from last Path Point to (x, y), choosing one of four possible routes:
3450clockwise or counterclockwise, and smaller or larger.
Cary Clark73fa9722017-08-29 17:36:51 -04003451
Cary Clark154beea2017-10-26 07:58:48 -04003452Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if
3453either radii are zero, or if last Path Point equals (x, y). arcTo scales radii
3454(rx, ry) to fit last Path Point and (x, y) if both are greater than zero but
3455too small.
Cary Clark73fa9722017-08-29 17:36:51 -04003456
3457arcTo appends up to four Conic curves.
Cary Clark154beea2017-10-26 07:58:48 -04003458arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value
3459is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise,
3460while kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003461
3462#Param rx radius in x before x-axis rotation ##
3463#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003464#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003465#Param largeArc chooses smaller or larger Arc ##
3466#Param sweep chooses clockwise or counterclockwise Arc ##
3467#Param x end of Arc ##
3468#Param y end of Arc ##
3469
3470#Example
3471#Height 160
3472void draw(SkCanvas* canvas) {
3473 SkPaint paint;
3474 paint.setAntiAlias(true);
3475 paint.setStyle(SkPaint::kStroke_Style);
3476 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3477 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3478 SkPath path;
3479 path.moveTo({120, 50});
3480 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3481 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3482 paint.setColor(SK_ColorBLUE);
3483 paint.setStrokeWidth(3);
3484 }
3485 canvas->drawPath(path, paint);
3486 }
3487 }
3488}
3489##
3490
3491#SeeAlso rArcTo ArcSize Direction
3492
3493##
3494
3495# ------------------------------------------------------------------------------
3496
3497#Method void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
3498 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05003499#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003500#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003501
3502Append Arc to Path. Arc is implemented by one or more Conic weighted to describe part of Oval
3503with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last Path Point to
3504(xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise,
3505and smaller or larger.
3506
3507Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either radii are zero,
3508or if last Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
Cary Clarkce101242017-09-01 15:51:02 -04003509xy if both are greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003510
3511arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003512arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3513opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3514kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003515
3516#Param r radii in x and y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003517#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003518#Param largeArc chooses smaller or larger Arc ##
3519#Param sweep chooses clockwise or counterclockwise Arc ##
3520#Param xy end of Arc ##
3521
3522#Example
3523#Height 108
3524void draw(SkCanvas* canvas) {
3525 SkPaint paint;
3526 SkPath path;
3527 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3528 for (auto start : starts) {
3529 path.moveTo(start.fX, start.fY);
3530 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3531 }
3532 canvas->drawPath(path, paint);
3533}
3534##
3535
3536#SeeAlso rArcTo ArcSize Direction
3537
3538##
3539
3540# ------------------------------------------------------------------------------
3541
3542#Method void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3543 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003544#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003545#In Arc
3546#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003547
3548Append Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003549more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04003550xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
3551
Cary Clark73fa9722017-08-29 17:36:51 -04003552#Formula
3553(x0 + dx, y0 + dy)
3554##
3555, choosing one of four possible routes: clockwise or
3556counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3557is (0, 0).
3558
Cary Clarkce101242017-09-01 15:51:02 -04003559Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3560if either radii are zero, or if last Path Point equals end Point.
3561arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3562greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003563
3564arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003565arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3566opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003567kCW_Direction cast to int is zero.
3568
3569#Param rx radius in x before x-axis rotation ##
3570#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003571#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003572#Param largeArc chooses smaller or larger Arc ##
3573#Param sweep chooses clockwise or counterclockwise Arc ##
3574#Param dx x offset end of Arc from last Path Point ##
3575#Param dy y offset end of Arc from last Path Point ##
3576
3577#Example
3578#Height 108
3579void draw(SkCanvas* canvas) {
3580 SkPaint paint;
3581 SkPath path;
3582 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3583 for (auto start : starts) {
3584 path.moveTo(start.fX, start.fY);
3585 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3586 }
3587 canvas->drawPath(path, paint);
3588}
3589##
3590
3591#SeeAlso arcTo ArcSize Direction
3592
3593##
3594
Cary Clark78de7512018-02-07 07:27:09 -05003595#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003596
3597# ------------------------------------------------------------------------------
3598
3599#Method void close()
Cary Clark4855f782018-02-06 09:41:53 -05003600#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003601#Line # makes last Contour a loop ##
Cary Clark73fa9722017-08-29 17:36:51 -04003602Append kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003603with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003604with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
3605Paint_Stroke_Cap at Contour start and end; closed Contour draws
3606Paint_Stroke_Join at Contour start and end.
3607
3608close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3609
3610#Example
3611void draw(SkCanvas* canvas) {
3612 SkPaint paint;
3613 paint.setStrokeWidth(15);
3614 paint.setStrokeCap(SkPaint::kRound_Cap);
3615 SkPath path;
3616 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3617 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3618 for (int loop = 0; loop < 2; ++loop) {
3619 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3620 SkPaint::kStrokeAndFill_Style} ) {
3621 paint.setStyle(style);
3622 canvas->drawPath(path, paint);
3623 canvas->translate(85, 0);
3624 }
3625 path.close();
3626 canvas->translate(-255, 128);
3627 }
3628}
3629##
3630
3631#SeeAlso
3632
3633##
3634
3635# ------------------------------------------------------------------------------
3636
3637#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003638#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003639#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003640Returns true if fill is inverted and Path with fill represents area outside
3641of its geometric bounds.
3642
3643#Table
3644#Legend
3645# FillType # is inverse ##
3646##
3647# kWinding_FillType # false ##
3648# kEvenOdd_FillType # false ##
3649# kInverseWinding_FillType # true ##
3650# kInverseEvenOdd_FillType # true ##
3651##
3652
3653#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3654 kInverseWinding_FillType, kInverseEvenOdd_FillType
3655##
3656
3657#Return true if Path fills outside its bounds ##
3658
3659#Example
3660#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003661###$
Cary Clark73fa9722017-08-29 17:36:51 -04003662#define nameValue(fill) { SkPath::fill, #fill }
3663
Cary Clark1a8d7622018-03-05 13:26:16 -05003664$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003665##
3666void draw(SkCanvas* canvas) {
3667 struct {
3668 SkPath::FillType fill;
3669 const char* name;
3670 } fills[] = {
3671 nameValue(kWinding_FillType),
3672 nameValue(kEvenOdd_FillType),
3673 nameValue(kInverseWinding_FillType),
3674 nameValue(kInverseEvenOdd_FillType),
3675 };
3676 for (auto fill: fills ) {
3677 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3678 "true" : "false");
3679 }
3680}
3681#StdOut
3682IsInverseFillType(kWinding_FillType) == false
3683IsInverseFillType(kEvenOdd_FillType) == false
3684IsInverseFillType(kInverseWinding_FillType) == true
3685IsInverseFillType(kInverseEvenOdd_FillType) == true
3686##
3687##
3688
3689#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3690
3691##
3692
3693# ------------------------------------------------------------------------------
3694
3695#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003696#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003697#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003698Returns equivalent Fill_Type representing Path fill inside its bounds.
3699.
3700
3701#Table
3702#Legend
3703# FillType # inside FillType ##
3704##
3705# kWinding_FillType # kWinding_FillType ##
3706# kEvenOdd_FillType # kEvenOdd_FillType ##
3707# kInverseWinding_FillType # kWinding_FillType ##
3708# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3709##
3710
3711#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3712 kInverseWinding_FillType, kInverseEvenOdd_FillType
3713##
3714
3715#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3716
3717#Example
3718#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003719###$
Cary Clark73fa9722017-08-29 17:36:51 -04003720#define nameValue(fill) { SkPath::fill, #fill }
3721
Cary Clark1a8d7622018-03-05 13:26:16 -05003722$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003723##
3724void draw(SkCanvas* canvas) {
3725 struct {
3726 SkPath::FillType fill;
3727 const char* name;
3728 } fills[] = {
3729 nameValue(kWinding_FillType),
3730 nameValue(kEvenOdd_FillType),
3731 nameValue(kInverseWinding_FillType),
3732 nameValue(kInverseEvenOdd_FillType),
3733 };
3734 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3735 if (fills[i].fill != (SkPath::FillType) i) {
3736 SkDebugf("fills array order does not match FillType enum order");
3737 break;
3738 }
3739 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3740 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3741 }
3742}
3743#StdOut
3744ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3745ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3746ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3747ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3748##
3749##
3750
3751#SeeAlso FillType getFillType setFillType IsInverseFillType
3752
3753##
3754
3755# ------------------------------------------------------------------------------
3756
3757#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3758 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05003759#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003760#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04003761
3762Approximates Conic with Quad array. Conic is constructed from start Point p0,
3763control Point p1, end Point p2, and weight w.
3764Quad array is stored in pts; this storage is supplied by caller.
3765Maximum Quad count is 2 to the pow2.
3766Every third point in array shares last Point of previous Quad and first Point of
3767next Quad. Maximum pts storage size is given by:
3768#Formula
3769(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
3770##
Cary Clark154beea2017-10-26 07:58:48 -04003771.
Cary Clark6fc50412017-09-21 12:31:06 -04003772
Cary Clark154beea2017-10-26 07:58:48 -04003773Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04003774than the number requested.
3775
3776Conic_Weight determines the amount of influence Conic control point has on the curve.
3777w less than one represents an elliptical section. w greater than one represents
3778a hyperbolic section. w equal to one represents a parabolic section.
3779
3780Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3781of up to 90 degrees; in this case, set pow2 to one.
3782
3783#Param p0 Conic start Point ##
3784#Param p1 Conic control Point ##
3785#Param p2 Conic end Point ##
3786#Param w Conic weight ##
3787#Param pts storage for Quad array ##
3788#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3789
Cary Clarka523d2d2017-08-30 08:58:10 -04003790#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003791
3792#Example
3793#Description
3794A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3795The middle curve is nearly circular. The top-right curve is parabolic, which can
3796be drawn exactly with a single Quad.
3797##
3798void draw(SkCanvas* canvas) {
3799 SkPaint conicPaint;
3800 conicPaint.setAntiAlias(true);
3801 conicPaint.setStyle(SkPaint::kStroke_Style);
3802 SkPaint quadPaint(conicPaint);
3803 quadPaint.setColor(SK_ColorRED);
3804 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3805 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3806 SkPoint quads[5];
3807 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3808 SkPath path;
3809 path.moveTo(conic[0]);
3810 path.conicTo(conic[1], conic[2], weight);
3811 canvas->drawPath(path, conicPaint);
3812 path.rewind();
3813 path.moveTo(quads[0]);
3814 path.quadTo(quads[1], quads[2]);
3815 path.quadTo(quads[3], quads[4]);
3816 canvas->drawPath(path, quadPaint);
3817 canvas->translate(50, -50);
3818 }
3819}
3820##
3821
3822#SeeAlso Conic Quad
3823
3824##
3825
3826# ------------------------------------------------------------------------------
3827
3828#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003829#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003830#Line # returns if describes Rect ##
Cary Clarkce101242017-09-01 15:51:02 -04003831Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003832If false: rect, isClosed, and direction are unchanged.
3833If true: rect, isClosed, and direction are written to if not nullptr.
3834
3835rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3836that do not alter the area drawn by the returned rect.
3837
3838#Param rect storage for bounds of Rect; may be nullptr ##
3839#Param isClosed storage set to true if Path is closed; may be nullptr ##
3840#Param direction storage set to Rect direction; may be nullptr ##
3841
3842#Return true if Path contains Rect ##
3843
3844#Example
3845#Description
3846After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3847following lineTo does not. addPoly returns true even though rect is not closed, and one
3848side of rect is made up of consecutive line segments.
3849##
3850void draw(SkCanvas* canvas) {
3851 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3852 SkRect rect;
3853 SkPath::Direction direction;
3854 bool isClosed;
3855 path.isRect(&rect, &isClosed, &direction) ?
3856 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3857 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3858 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3859 SkDebugf("%s is not rect\n", prefix);
3860 };
3861 SkPath path;
3862 debugster("empty", path);
3863 path.addRect({10, 20, 30, 40});
3864 debugster("addRect", path);
3865 path.moveTo(60, 70);
3866 debugster("moveTo", path);
3867 path.lineTo(60, 70);
3868 debugster("lineTo", path);
3869 path.reset();
3870 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3871 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3872 debugster("addPoly", path);
3873}
3874#StdOut
3875empty is not rect
3876addRect is rect (10, 20, 30, 40); is closed; direction CW
3877moveTo is rect (10, 20, 30, 40); is closed; direction CW
3878lineTo is not rect
3879addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3880##
3881##
3882
3883#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3884
3885##
3886
3887# ------------------------------------------------------------------------------
3888
3889#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003890#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003891#Line # returns if describes Rect pair, one inside the other ##
Cary Clark73fa9722017-08-29 17:36:51 -04003892Returns true if Path is equivalent to nested Rect pair when filled.
3893If false, rect and dirs are unchanged.
3894If true, rect and dirs are written to if not nullptr:
3895setting rect[0] to outer Rect, and rect[1] to inner Rect;
3896setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3897Rect.
3898
3899#Param rect storage for Rect pair; may be nullptr ##
3900#Param dirs storage for Direction pair; may be nullptr ##
3901
3902#Return true if Path contains nested Rect pair ##
3903
3904#Example
3905void draw(SkCanvas* canvas) {
3906 SkPaint paint;
3907 paint.setStyle(SkPaint::kStroke_Style);
3908 paint.setStrokeWidth(5);
3909 SkPath path;
3910 path.addRect({10, 20, 30, 40});
3911 paint.getFillPath(path, &path);
3912 SkRect rects[2];
3913 SkPath::Direction directions[2];
3914 if (path.isNestedFillRects(rects, directions)) {
3915 for (int i = 0; i < 2; ++i) {
3916 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3917 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3918 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3919 }
3920 } else {
3921 SkDebugf("is not nested rectangles\n");
3922 }
3923}
3924#StdOut
3925outer (7.5, 17.5, 32.5, 42.5); direction CW
3926inner (12.5, 22.5, 27.5, 37.5); direction CCW
3927##
3928##
3929
3930#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3931
3932##
3933
3934# ------------------------------------------------------------------------------
3935
3936#Method void addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003937#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003938#Line # adds one Contour containing Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04003939Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
3940starting with top-left corner of Rect; followed by top-right, bottom-right,
3941and bottom-left if dir is kCW_Direction; or followed by bottom-left,
3942bottom-right, and top-right if dir is kCCW_Direction.
3943
3944#Param rect Rect to add as a closed contour ##
3945#Param dir Direction to wind added contour ##
3946
3947#Example
3948#Description
3949The left Rect dashes starting at the top-left corner, to the right.
3950The right Rect dashes starting at the top-left corner, towards the bottom.
3951##
3952#Height 128
3953void draw(SkCanvas* canvas) {
3954 SkPaint paint;
3955 paint.setStrokeWidth(15);
3956 paint.setStrokeCap(SkPaint::kSquare_Cap);
3957 float intervals[] = { 5, 21.75f };
3958 paint.setStyle(SkPaint::kStroke_Style);
3959 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3960 SkPath path;
3961 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
3962 canvas->drawPath(path, paint);
3963 path.rewind();
3964 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
3965 canvas->drawPath(path, paint);
3966}
3967##
3968
3969#SeeAlso SkCanvas::drawRect Direction
3970
3971##
3972
3973# ------------------------------------------------------------------------------
3974
3975#Method void addRect(const SkRect& rect, Direction dir, unsigned start)
3976
3977Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
3978If dir is kCW_Direction, Rect corners are added clockwise; if dir is
3979kCCW_Direction, Rect corners are added counterclockwise.
3980start determines the first corner added.
3981
3982#Table
3983#Legend
3984# start # first corner ##
3985#Legend ##
3986# 0 # top-left ##
3987# 1 # top-right ##
3988# 2 # bottom-right ##
3989# 3 # bottom-left ##
3990#Table ##
3991
3992#Param rect Rect to add as a closed contour ##
3993#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04003994#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04003995
3996#Example
3997#Height 128
3998#Description
3999The arrow is just after the initial corner and points towards the next
4000corner appended to Path.
4001##
4002void draw(SkCanvas* canvas) {
4003 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
4004 const SkRect rect = {10, 10, 54, 54};
4005 SkPaint rectPaint;
4006 rectPaint.setAntiAlias(true);
4007 rectPaint.setStyle(SkPaint::kStroke_Style);
4008 SkPaint arrowPaint(rectPaint);
4009 SkPath arrowPath;
4010 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4011 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4012 SkPath1DPathEffect::kRotate_Style));
4013 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4014 for (unsigned start : { 0, 1, 2, 3 } ) {
4015 SkPath path;
4016 path.addRect(rect, direction, start);
4017 canvas->drawPath(path, rectPaint);
4018 canvas->drawPath(path, arrowPaint);
4019 canvas->translate(64, 0);
4020 }
4021 canvas->translate(-256, 64);
4022 }
4023}
4024##
4025
4026#SeeAlso SkCanvas::drawRect Direction
4027
4028##
4029
4030# ------------------------------------------------------------------------------
4031
4032#Method void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
4033 Direction dir = kCW_Direction)
4034
4035Add Rect (left, top, right, bottom) to Path,
4036appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4037starting with top-left corner of Rect; followed by top-right, bottom-right,
4038and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4039bottom-right, and top-right if dir is kCCW_Direction.
4040
4041#Param left smaller x of Rect ##
4042#Param top smaller y of Rect ##
4043#Param right larger x of Rect ##
4044#Param bottom larger y of Rect ##
4045#Param dir Direction to wind added contour ##
4046
4047#Example
4048#Description
4049The left Rect dashes start at the top-left corner, and continue to the right.
4050The right Rect dashes start at the top-left corner, and continue down.
4051##
4052#Height 128
4053void draw(SkCanvas* canvas) {
4054 SkPaint paint;
4055 paint.setStrokeWidth(15);
4056 paint.setStrokeCap(SkPaint::kSquare_Cap);
4057 float intervals[] = { 5, 21.75f };
4058 paint.setStyle(SkPaint::kStroke_Style);
4059 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4060 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4061 SkPath path;
4062 path.addRect(20, 20, 100, 100, direction);
4063 canvas->drawPath(path, paint);
4064 canvas->translate(128, 0);
4065 }
4066}
4067##
4068
4069#SeeAlso SkCanvas::drawRect Direction
4070
4071##
4072
4073# ------------------------------------------------------------------------------
4074
4075#Method void addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004076#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004077#Line # adds one Contour containing Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04004078Add Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4079Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4080and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4081clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4082
4083This form is identical to addOval(oval, dir, 1).
4084
4085#Param oval bounds of ellipse added ##
4086#Param dir Direction to wind ellipse ##
4087
4088#Example
4089#Height 120
4090 SkPaint paint;
4091 SkPath oval;
4092 oval.addOval({20, 20, 160, 80});
4093 canvas->drawPath(oval, paint);
4094##
4095
4096#SeeAlso SkCanvas::drawOval Direction Oval
4097
4098##
4099
4100# ------------------------------------------------------------------------------
4101
4102#Method void addOval(const SkRect& oval, Direction dir, unsigned start)
4103
4104Add Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4105Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4106and half oval height. Oval begins at start and continues
4107clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4108
4109#Table
4110#Legend
4111# start # Point ##
4112#Legend ##
4113# 0 # oval.centerX(), oval.fTop ##
4114# 1 # oval.fRight, oval.centerY() ##
4115# 2 # oval.centerX(), oval.fBottom ##
4116# 3 # oval.fLeft, oval.centerY() ##
4117#Table ##
4118
4119#Param oval bounds of ellipse added ##
4120#Param dir Direction to wind ellipse ##
4121#Param start index of initial point of ellipse ##
4122
4123#Example
4124#Height 160
4125void draw(SkCanvas* canvas) {
4126 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4127 const SkRect rect = {10, 10, 54, 54};
4128 SkPaint ovalPaint;
4129 ovalPaint.setAntiAlias(true);
4130 SkPaint textPaint(ovalPaint);
4131 textPaint.setTextAlign(SkPaint::kCenter_Align);
4132 ovalPaint.setStyle(SkPaint::kStroke_Style);
4133 SkPaint arrowPaint(ovalPaint);
4134 SkPath arrowPath;
4135 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4136 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4137 SkPath1DPathEffect::kRotate_Style));
4138 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4139 for (unsigned start : { 0, 1, 2, 3 } ) {
4140 SkPath path;
4141 path.addOval(rect, direction, start);
4142 canvas->drawPath(path, ovalPaint);
4143 canvas->drawPath(path, arrowPaint);
4144 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4145 canvas->translate(64, 0);
4146 }
4147 canvas->translate(-256, 72);
4148 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4149 128, 0, textPaint);
4150 }
4151}
4152##
4153
4154#SeeAlso SkCanvas::drawOval Direction Oval
4155
4156##
4157
4158# ------------------------------------------------------------------------------
4159
4160#Method void addCircle(SkScalar x, SkScalar y, SkScalar radius,
4161 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004162#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004163#Line # adds one Contour containing Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04004164
4165Add Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark154beea2017-10-26 07:58:48 -04004166four kConic_Verb, and kClose_Verb. Circle begins at:
Cary Clark73fa9722017-08-29 17:36:51 -04004167#Formula
4168(x + radius, y)
4169##
Cary Clark154beea2017-10-26 07:58:48 -04004170, continuing
4171clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04004172
Cary Clark6fc50412017-09-21 12:31:06 -04004173Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004174
4175#Param x center of Circle ##
4176#Param y center of Circle ##
4177#Param radius distance from center to edge ##
4178#Param dir Direction to wind Circle ##
4179
4180#Example
4181void draw(SkCanvas* canvas) {
4182 SkPaint paint;
4183 paint.setAntiAlias(true);
4184 paint.setStyle(SkPaint::kStroke_Style);
4185 paint.setStrokeWidth(10);
4186 for (int size = 10; size < 300; size += 20) {
4187 SkPath path;
4188 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4189 canvas->drawPath(path, paint);
4190 }
4191}
4192##
4193
4194#SeeAlso SkCanvas::drawCircle Direction Circle
4195
4196##
4197
4198# ------------------------------------------------------------------------------
4199
4200#Method void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05004201#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004202#Line # adds one Contour containing Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04004203Append Arc to Path, as the start of new Contour. Arc added is part of ellipse
4204bounded by oval, from startAngle through sweepAngle. Both startAngle and
4205sweepAngle are measured in degrees, where zero degrees is aligned with the
4206positive x-axis, and positive sweeps extends Arc clockwise.
4207
4208If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4209zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
4210modulo 360, and Arc may or may not draw depending on numeric rounding.
4211
4212#Param oval bounds of ellipse containing Arc ##
4213#Param startAngle starting angle of Arc in degrees ##
4214#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4215
4216#Example
4217#Description
4218The middle row of the left and right columns draw differently from the entries
4219above and below because sweepAngle is outside of the range of +/-360,
4220and startAngle modulo 90 is not zero.
4221##
4222void draw(SkCanvas* canvas) {
4223 SkPaint paint;
4224 for (auto start : { 0, 90, 135, 180, 270 } ) {
4225 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4226 SkPath path;
4227 path.addArc({10, 10, 35, 45}, start, sweep);
4228 canvas->drawPath(path, paint);
4229 canvas->translate(252 / 6, 0);
4230 }
4231 canvas->translate(-252, 255 / 5);
4232 }
4233}
4234##
4235
4236#SeeAlso Arc arcTo SkCanvas::drawArc
4237
4238##
4239
4240# ------------------------------------------------------------------------------
4241
4242#Method void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
4243 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004244#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004245#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark73fa9722017-08-29 17:36:51 -04004246
4247Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4248equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4249dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4250winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4251of the upper-left corner and winds counterclockwise.
4252
4253If either rx or ry is too large, rx and ry are scaled uniformly until the
4254corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4255Rect rect to Path.
4256
4257After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4258
4259#Param rect bounds of Round_Rect ##
4260#Param rx x-radius of rounded corners on the Round_Rect ##
4261#Param ry y-radius of rounded corners on the Round_Rect ##
4262#Param dir Direction to wind Round_Rect ##
4263
4264#Example
4265#Description
4266If either radius is zero, path contains Rect and is drawn red.
4267If sides are only radii, path contains Oval and is drawn blue.
4268All remaining path draws are convex, and are drawn in gray; no
4269paths constructed from addRoundRect are concave, so none are
4270drawn in green.
4271##
4272void draw(SkCanvas* canvas) {
4273 SkPaint paint;
4274 paint.setAntiAlias(true);
4275 for (auto xradius : { 0, 7, 13, 20 } ) {
4276 for (auto yradius : { 0, 9, 18, 40 } ) {
4277 SkPath path;
4278 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4279 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4280 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4281 canvas->drawPath(path, paint);
4282 canvas->translate(64, 0);
4283 }
4284 canvas->translate(-256, 64);
4285 }
4286}
4287##
4288
4289#SeeAlso addRRect SkCanvas::drawRoundRect
4290
4291##
4292
4293# ------------------------------------------------------------------------------
4294
4295#Method void addRoundRect(const SkRect& rect, const SkScalar radii[],
4296 Direction dir = kCW_Direction)
4297
4298Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4299equal to rect; each corner is 90 degrees of an ellipse with radii from the
4300array.
4301
4302#Table
4303#Legend
4304# radii index # location ##
4305#Legend ##
4306# 0 # x-radius of top-left corner ##
4307# 1 # y-radius of top-left corner ##
4308# 2 # x-radius of top-right corner ##
4309# 3 # y-radius of top-right corner ##
4310# 4 # x-radius of bottom-right corner ##
4311# 5 # y-radius of bottom-right corner ##
4312# 6 # x-radius of bottom-left corner ##
4313# 7 # y-radius of bottom-left corner ##
4314#Table ##
4315
4316If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4317and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
4318bottom-left of the upper-left corner and winds counterclockwise.
4319
4320If both radii on any side of rect exceed its length, all radii are scaled
4321uniformly until the corners fit. If either radius of a corner is less than or
4322equal to zero, both are treated as zero.
4323
4324After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4325
4326#Param rect bounds of Round_Rect ##
4327#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4328#Param dir Direction to wind Round_Rect ##
4329
4330#Example
4331void draw(SkCanvas* canvas) {
4332 SkPaint paint;
4333 paint.setAntiAlias(true);
4334 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4335 SkPath path;
4336 SkMatrix rotate90;
4337 rotate90.setRotate(90, 128, 128);
4338 for (int i = 0; i < 4; ++i) {
4339 path.addRoundRect({10, 10, 110, 110}, radii);
4340 path.transform(rotate90);
4341 }
4342 canvas->drawPath(path, paint);
4343}
4344##
4345
4346#SeeAlso addRRect SkCanvas::drawRoundRect
4347
4348##
4349
4350# ------------------------------------------------------------------------------
4351
4352#Method void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004353#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004354#Line # adds one Contour containing Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004355Add rrect to Path, creating a new closed Contour. If
4356dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4357winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4358of the upper-left corner and winds counterclockwise.
4359
4360After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4361
4362#Param rrect bounds and radii of rounded rectangle ##
4363#Param dir Direction to wind Round_Rect ##
4364
4365#Example
4366void draw(SkCanvas* canvas) {
4367 SkPaint paint;
4368 paint.setAntiAlias(true);
4369 SkRRect rrect;
4370 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4371 rrect.setRectRadii({10, 10, 110, 110}, radii);
4372 SkPath path;
4373 SkMatrix rotate90;
4374 rotate90.setRotate(90, 128, 128);
4375 for (int i = 0; i < 4; ++i) {
4376 path.addRRect(rrect);
4377 path.transform(rotate90);
4378 }
4379 canvas->drawPath(path, paint);
4380}
4381##
4382
4383#SeeAlso addRoundRect SkCanvas::drawRRect
4384
4385##
4386
4387# ------------------------------------------------------------------------------
4388
4389#Method void addRRect(const SkRRect& rrect, Direction dir, unsigned start)
4390
4391Add rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
4392winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4393start determines the first point of rrect to add.
4394
4395#Table
4396#Legend
4397# start # location ##
4398#Legend ##
4399# 0 # right of top-left corner ##
4400# 1 # left of top-right corner ##
4401# 2 # bottom of top-right corner ##
4402# 3 # top of bottom-right corner ##
4403# 4 # left of bottom-right corner ##
4404# 5 # right of bottom-left corner ##
4405# 6 # top of bottom-left corner ##
4406# 7 # bottom of top-left corner ##
4407#Table ##
4408
4409After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4410
4411#Param rrect bounds and radii of rounded rectangle ##
4412#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004413#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004414
4415#Example
4416void draw(SkCanvas* canvas) {
4417 SkPaint paint;
4418 paint.setAntiAlias(true);
4419 SkRRect rrect;
4420 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4421 SkPath path;
4422 path.addRRect(rrect);
4423 canvas->drawPath(path, paint);
4424 for (int start = 0; start < 8; ++start) {
4425 SkPath textPath;
4426 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
4427 canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
4428 }
4429}
4430##
4431
4432#SeeAlso addRoundRect SkCanvas::drawRRect
4433
4434##
4435
4436# ------------------------------------------------------------------------------
4437
4438#Method void addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05004439#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004440#Line # adds one Contour containing connected lines ##
Cary Clark6fc50412017-09-21 12:31:06 -04004441Add Contour created from Line array, adding (count - 1) Line segments.
4442Contour added starts at pts[0], then adds a line for every additional Point
4443in pts array. If close is true,appends kClose_Verb to Path, connecting
4444pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004445
4446If count is zero, append kMove_Verb to path.
4447Has no effect if count is less than one.
4448
Cary Clarka523d2d2017-08-30 08:58:10 -04004449#Param pts array of Line sharing end and start Point ##
4450#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004451#Param close true to add Line connecting Contour end and start ##
4452
4453#Example
4454void draw(SkCanvas* canvas) {
4455 SkPaint paint;
4456 paint.setStrokeWidth(15);
4457 paint.setStrokeCap(SkPaint::kRound_Cap);
4458 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4459 for (bool close : { false, true } ) {
4460 SkPath path;
4461 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4462 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4463 SkPaint::kStrokeAndFill_Style} ) {
4464 paint.setStyle(style);
4465 canvas->drawPath(path, paint);
4466 canvas->translate(85, 0);
4467 }
4468 canvas->translate(-255, 128);
4469 }
4470}
4471##
4472
4473#SeeAlso SkCanvas::drawPoints
4474
4475##
4476
4477# ------------------------------------------------------------------------------
4478
4479#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05004480#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04004481
4482#Code
4483 enum AddPathMode {
4484 kAppend_AddPathMode,
4485 kExtend_AddPathMode,
4486 };
4487##
4488
4489AddPathMode chooses how addPath appends. Adding one Path to another can extend
4490the last Contour or start a new Contour.
4491
4492#Const kAppend_AddPathMode
4493 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4494 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4495 starts a new Contour.
4496##
4497#Const kExtend_AddPathMode
4498 If destination is closed or empty, start a new Contour. If destination
4499 is not empty, add Line from Last_Point to added Path first Point. Skip added
4500 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4501##
4502
4503#Example
4504#Description
4505test is built from path, open on the top row, and closed on the bottom row.
4506The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4507The top right composition is made up of one contour; the other three have two.
4508##
4509#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004510 SkPath path, path2;
4511 path.moveTo(20, 20);
4512 path.lineTo(20, 40);
4513 path.lineTo(40, 20);
4514 path2.moveTo(60, 60);
4515 path2.lineTo(80, 60);
4516 path2.lineTo(80, 40);
4517 SkPaint paint;
4518 paint.setStyle(SkPaint::kStroke_Style);
4519 for (int i = 0; i < 2; i++) {
4520 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4521 SkPath test(path);
4522 test.addPath(path2, addPathMode);
4523 canvas->drawPath(test, paint);
4524 canvas->translate(100, 0);
4525 }
4526 canvas->translate(-200, 100);
4527 path.close();
4528 }
Cary Clark73fa9722017-08-29 17:36:51 -04004529##
4530
4531#SeeAlso addPath reverseAddPath
4532
4533##
4534
4535# ------------------------------------------------------------------------------
4536
4537#Method void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
4538 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05004539#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004540#Line # adds contents of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004541
4542Append src to Path, offset by (dx, dy).
4543
4544If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4545added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4546Verbs, Points, and Conic_Weights.
4547
4548#Param src Path Verbs, Points, and Conic_Weights to add ##
4549#Param dx offset added to src Point_Array x coordinates ##
4550#Param dy offset added to src Point_Array y coordinates ##
4551#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4552
4553#Example
4554#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004555 SkPaint paint;
4556 paint.setTextSize(128);
4557 paint.setFakeBoldText(true);
4558 SkPath dest, text;
4559 paint.getTextPath("O", 1, 50, 120, &text);
4560 for (int i = 0; i < 3; i++) {
4561 dest.addPath(text, i * 20, i * 20);
4562 }
4563 Simplify(dest, &dest);
4564 paint.setStyle(SkPaint::kStroke_Style);
4565 paint.setStrokeWidth(3);
4566 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004567##
4568
Cary Clark4855f782018-02-06 09:41:53 -05004569#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004570
4571##
4572
4573# ------------------------------------------------------------------------------
4574
4575#Method void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
4576
4577Append src to Path.
4578
4579If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4580added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4581Verbs, Points, and Conic_Weights.
4582
4583#Param src Path Verbs, Points, and Conic_Weights to add ##
4584#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4585
4586#Example
4587#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004588 SkPaint paint;
4589 paint.setStyle(SkPaint::kStroke_Style);
4590 SkPath dest, path;
4591 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4592 for (int i = 0; i < 2; i++) {
4593 dest.addPath(path, SkPath::kExtend_AddPathMode);
4594 dest.offset(100, 0);
4595 }
Cary Clark73fa9722017-08-29 17:36:51 -04004596 canvas->drawPath(dest, paint);
4597##
4598
4599#SeeAlso AddPathMode reverseAddPath
4600
4601##
4602
4603# ------------------------------------------------------------------------------
4604
4605#Method void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
4606
4607Append src to Path, transformed by matrix. Transformed curves may have different
4608Verbs, Points, and Conic_Weights.
4609
4610If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4611added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4612Verbs, Points, and Conic_Weights.
4613
4614#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004615#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004616#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4617
4618#Example
4619#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004620 SkPaint paint;
4621 paint.setStyle(SkPaint::kStroke_Style);
4622 SkPath dest, path;
4623 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4624 for (int i = 0; i < 6; i++) {
4625 SkMatrix matrix;
4626 matrix.reset();
4627 matrix.setPerspX(i / 400.f);
4628 dest.addPath(path, matrix);
4629 }
4630 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004631##
4632
Cary Clark4855f782018-02-06 09:41:53 -05004633#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004634
4635##
4636
4637# ------------------------------------------------------------------------------
4638
4639#Method void reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05004640#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004641#Line # adds contents of Path back to front ##
Cary Clark73fa9722017-08-29 17:36:51 -04004642Append src to Path, from back to front.
4643Reversed src always appends a new Contour to Path.
4644
4645#Param src Path Verbs, Points, and Conic_Weights to add ##
4646
4647#Example
4648#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004649 SkPath path;
4650 path.moveTo(20, 20);
4651 path.lineTo(20, 40);
4652 path.lineTo(40, 20);
4653 SkPaint paint;
4654 paint.setStyle(SkPaint::kStroke_Style);
4655 for (int i = 0; i < 2; i++) {
4656 SkPath path2;
4657 path2.moveTo(60, 60);
4658 path2.lineTo(80, 60);
4659 path2.lineTo(80, 40);
4660 for (int j = 0; j < 2; j++) {
4661 SkPath test(path);
4662 test.reverseAddPath(path2);
4663 canvas->drawPath(test, paint);
4664 canvas->translate(100, 0);
4665 path2.close();
4666 }
4667 canvas->translate(-200, 100);
4668 path.close();
4669 }
Cary Clark73fa9722017-08-29 17:36:51 -04004670##
4671
Cary Clark4855f782018-02-06 09:41:53 -05004672#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04004673
4674##
4675
4676# ------------------------------------------------------------------------------
4677
4678#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004679#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004680#Line # translates Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004681Offset Point_Array by (dx, dy). Offset Path replaces dst.
4682If dst is nullptr, Path is replaced by offset data.
4683
4684#Param dx offset added to Point_Array x coordinates ##
4685#Param dy offset added to Point_Array y coordinates ##
4686#Param dst overwritten, translated copy of Path; may be nullptr ##
4687
4688#Example
4689#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004690 SkPath pattern;
4691 pattern.moveTo(20, 20);
4692 pattern.lineTo(20, 40);
4693 pattern.lineTo(40, 20);
4694 SkPaint paint;
4695 paint.setStyle(SkPaint::kStroke_Style);
4696 for (int i = 0; i < 10; i++) {
4697 SkPath path;
4698 pattern.offset(20 * i, 0, &path);
4699 canvas->drawPath(path, paint);
4700 }
Cary Clark73fa9722017-08-29 17:36:51 -04004701##
4702
4703#SeeAlso addPath transform
4704
4705##
4706
4707# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05004708#Subtopic Transform
4709#Populate
4710#Line # modify all points ##
4711##
Cary Clark73fa9722017-08-29 17:36:51 -04004712
4713#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05004714#In Transform
Cary Clark73fa9722017-08-29 17:36:51 -04004715Offset Point_Array by (dx, dy). Path is replaced by offset data.
4716
4717#Param dx offset added to Point_Array x coordinates ##
4718#Param dy offset added to Point_Array y coordinates ##
4719
4720#Example
4721#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004722 SkPath path;
4723 path.moveTo(20, 20);
4724 path.lineTo(20, 40);
4725 path.lineTo(40, 20);
4726 SkPaint paint;
4727 paint.setStyle(SkPaint::kStroke_Style);
4728 for (int i = 0; i < 10; i++) {
4729 canvas->drawPath(path, paint);
4730 path.offset(20, 0);
4731 }
Cary Clark73fa9722017-08-29 17:36:51 -04004732##
4733
4734#SeeAlso addPath transform SkCanvas::translate()
4735
4736##
4737
4738# ------------------------------------------------------------------------------
4739
4740#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004741#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004742#Line # applies Matrix to Point_Array and Weights ##
Cary Clark73fa9722017-08-29 17:36:51 -04004743Transform Verb_Array, Point_Array, and weight by matrix.
4744transform may change Verbs and increase their number.
4745Transformed Path replaces dst; if dst is nullptr, original data
4746is replaced.
4747
4748#Param matrix Matrix to apply to Path ##
4749#Param dst overwritten, transformed copy of Path; may be nullptr ##
4750
4751#Example
Cary Clark8032b982017-07-28 11:04:54 -04004752#Height 200
4753 SkPath pattern;
4754 pattern.moveTo(100, 100);
4755 pattern.lineTo(100, 20);
4756 pattern.lineTo(20, 100);
4757 SkPaint paint;
4758 paint.setStyle(SkPaint::kStroke_Style);
4759 for (int i = 0; i < 10; i++) {
4760 SkPath path;
4761 SkMatrix matrix;
4762 matrix.setRotate(36 * i, 100, 100);
4763 pattern.transform(matrix, &path);
4764 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004765 }
4766##
4767
4768#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4769
4770##
4771
4772# ------------------------------------------------------------------------------
4773
4774#Method void transform(const SkMatrix& matrix)
4775
4776Transform Verb_Array, Point_Array, and weight by matrix.
4777transform may change Verbs and increase their number.
4778Path is replaced by transformed data.
4779
4780#Param matrix Matrix to apply to Path ##
4781
4782#Example
Cary Clark8032b982017-07-28 11:04:54 -04004783#Height 200
4784 SkPath path;
4785 path.moveTo(100, 100);
4786 path.quadTo(100, 20, 20, 100);
4787 SkPaint paint;
4788 paint.setStyle(SkPaint::kStroke_Style);
4789 for (int i = 0; i < 10; i++) {
4790 SkMatrix matrix;
4791 matrix.setRotate(36, 100, 100);
4792 path.transform(matrix);
4793 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004794 }
4795##
4796
4797#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4798
4799##
4800
4801# ------------------------------------------------------------------------------
4802
Cary Clark8032b982017-07-28 11:04:54 -04004803#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05004804#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04004805
4806Path is defined cumulatively, often by adding a segment to the end of last
4807Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4808Last_Point can be read and written directly with getLastPt and setLastPt.
4809
Cary Clark73fa9722017-08-29 17:36:51 -04004810#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05004811#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004812#In Last_Point
4813#Line # returns Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004814 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
4815 storing (0, 0) if lastPt is not nullptr.
4816
4817 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4818
4819 #Return true if Point_Array contains one or more Points ##
4820
4821 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004822 SkPath path;
4823 path.moveTo(100, 100);
4824 path.quadTo(100, 20, 20, 100);
4825 SkMatrix matrix;
4826 matrix.setRotate(36, 100, 100);
4827 path.transform(matrix);
4828 SkPoint last;
4829 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004830 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4831 #StdOut
4832 last point: 35.2786, 52.9772
4833 ##
4834 ##
4835
4836 #SeeAlso setLastPt
4837
4838##
4839
4840#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05004841#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004842#In Last_Point
4843#Line # replaces Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004844 Set Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
4845 Verb_Array and (x, y) to Point_Array.
4846
4847 #Param x set x-coordinate of Last_Point ##
4848 #Param y set y-coordinate of Last_Point ##
4849
4850 #Example
4851 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004852 SkPaint paint;
4853 paint.setTextSize(128);
4854 SkPath path;
4855 paint.getTextPath("@", 1, 60, 100, &path);
4856 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004857 canvas->drawPath(path, paint);
4858 ##
4859
4860 #SeeAlso getLastPt
4861
4862##
4863
4864#Method void setLastPt(const SkPoint& p)
4865
4866 Set the last point on the path. If no points have been added, moveTo(p)
4867 is automatically called.
4868
4869 #Param p set value of Last_Point ##
4870
4871 #Example
4872 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004873 SkPaint paint;
4874 paint.setTextSize(128);
4875 SkPath path, path2;
4876 paint.getTextPath("A", 1, 60, 100, &path);
4877 paint.getTextPath("Z", 1, 60, 100, &path2);
4878 SkPoint pt, pt2;
4879 path.getLastPt(&pt);
4880 path2.getLastPt(&pt2);
4881 path.setLastPt(pt2);
4882 path2.setLastPt(pt);
4883 canvas->drawPath(path, paint);
4884 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004885 ##
4886
4887 #SeeAlso getLastPt
4888
4889##
4890
4891#Subtopic Last_Point ##
4892
4893# ------------------------------------------------------------------------------
4894
4895#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05004896#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004897
4898#Code
4899 enum SegmentMask {
4900 kLine_SegmentMask = 1 << 0,
4901 kQuad_SegmentMask = 1 << 1,
4902 kConic_SegmentMask = 1 << 2,
4903 kCubic_SegmentMask = 1 << 3,
4904 };
4905##
4906
4907SegmentMask constants correspond to each drawing Verb type in Path; for
4908instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4909
Cary Clark4855f782018-02-06 09:41:53 -05004910#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04004911#Const kLine_SegmentMask 1
4912Set if Verb_Array contains kLine_Verb.
4913##
4914#Const kQuad_SegmentMask 2
4915Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4916##
4917#Const kConic_SegmentMask 4
4918Set if Verb_Array contains kConic_Verb.
4919##
4920#Const kCubic_SegmentMask 8
4921Set if Verb_Array contains kCubic_Verb.
4922##
4923
4924#Example
4925#Description
4926When conicTo has a weight of one, Quad is added to Path.
4927##
4928 SkPath path;
4929 path.conicTo(10, 10, 20, 30, 1);
4930 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
4931 SkPath::kConic_SegmentMask ? "set" : "clear");
4932 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
4933 SkPath::kQuad_SegmentMask ? "set" : "clear");
4934#StdOut
4935Path kConic_SegmentMask is clear
4936Path kQuad_SegmentMask is set
4937##
4938##
4939
4940#SeeAlso getSegmentMasks Verb
4941
4942##
4943
4944# ------------------------------------------------------------------------------
4945
4946#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05004947#In Utility
4948#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004949#Line # returns types in Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004950Returns a mask, where each set bit corresponds to a SegmentMask constant
4951if Path contains one or more Verbs of that type.
4952Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
4953
4954getSegmentMasks() returns a cached result; it is very fast.
4955
4956#Return SegmentMask bits or zero ##
4957
4958#Example
4959SkPath path;
4960path.quadTo(20, 30, 40, 50);
4961path.close();
4962const char* masks[] = { "line", "quad", "conic", "cubic" };
4963int index = 0;
4964for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4965 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4966 if (mask & path.getSegmentMasks()) {
4967 SkDebugf("mask %s set\n", masks[index]);
4968 }
4969 ++index;
4970}
4971#StdOut
4972mask quad set
4973##
4974##
4975
4976#SeeAlso getSegmentMasks Verb
4977
4978##
4979
4980# ------------------------------------------------------------------------------
4981
4982#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05004983#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004984#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04004985Returns true if the point (x, y) is contained by Path, taking into
4986account FillType.
4987
4988#Table
4989#Legend
4990# FillType # contains() returns true if Point is enclosed by ##
4991##
4992# kWinding_FillType # a non-zero sum of Contour Directions. ##
4993# kEvenOdd_FillType # an odd number of Contours. ##
4994# kInverseWinding_FillType # a zero sum of Contour Directions. ##
4995# kInverseEvenOdd_FillType # and even number of Contours. ##
4996##
4997
4998#Param x x-coordinate of containment test ##
4999#Param y y-coordinate of containment test ##
5000
5001#Return true if Point is in Path ##
5002
5003#Example
5004SkPath path;
5005SkPaint paint;
5006paint.setTextSize(256);
5007paint.getTextPath("&", 1, 30, 220, &path);
5008for (int y = 2; y < 256; y += 9) {
5009 for (int x = 2; x < 256; x += 9) {
5010 int coverage = 0;
5011 for (int iy = -4; iy <= 4; iy += 2) {
5012 for (int ix = -4; ix <= 4; ix += 2) {
5013 coverage += path.contains(x + ix, y + iy);
5014 }
5015 }
5016 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5017 canvas->drawCircle(x, y, 8, paint);
5018 }
5019}
5020##
5021
5022#SeeAlso conservativelyContainsRect Fill_Type Op
5023
5024##
5025
5026# ------------------------------------------------------------------------------
5027
5028#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05005029#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005030#Line # sends text representation using floats to standard output ##
Cary Clark154beea2017-10-26 07:58:48 -04005031Writes text representation of Path to stream. If stream is nullptr, writes to
5032standard output. Set forceClose to true to get edges used to fill Path.
5033Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005034of floating point numbers used in Point_Array and Conic_Weights.
5035
5036#Param stream writable Stream receiving Path text representation; may be nullptr ##
5037#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005038#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005039
5040#Example
5041 SkPath path;
5042 path.quadTo(20, 30, 40, 50);
5043 for (bool forceClose : { false, true } ) {
5044 for (bool dumpAsHex : { false, true } ) {
5045 path.dump(nullptr, forceClose, dumpAsHex);
5046 SkDebugf("\n");
5047 }
5048 }
5049#StdOut
5050path.setFillType(SkPath::kWinding_FillType);
5051path.moveTo(0, 0);
5052path.quadTo(20, 30, 40, 50);
5053
5054path.setFillType(SkPath::kWinding_FillType);
5055path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5056path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5057
5058path.setFillType(SkPath::kWinding_FillType);
5059path.moveTo(0, 0);
5060path.quadTo(20, 30, 40, 50);
5061path.lineTo(0, 0);
5062path.close();
5063
5064path.setFillType(SkPath::kWinding_FillType);
5065path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5066path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5067path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5068path.close();
5069##
5070##
5071
5072#SeeAlso SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
5073
5074##
5075
5076# ------------------------------------------------------------------------------
5077
5078#Method void dump() const
5079
Cary Clarkce101242017-09-01 15:51:02 -04005080Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005081directly compiled as C++ code. Floating point values are written
5082with limited precision; it may not be possible to reconstruct original Path
5083from output.
5084
5085#Example
5086SkPath path, copy;
5087path.lineTo(6.f / 7, 2.f / 3);
5088path.dump();
5089copy.setFillType(SkPath::kWinding_FillType);
5090copy.moveTo(0, 0);
5091copy.lineTo(0.857143f, 0.666667f);
5092SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5093#StdOut
5094path.setFillType(SkPath::kWinding_FillType);
5095path.moveTo(0, 0);
5096path.lineTo(0.857143f, 0.666667f);
5097path is not equal to copy
5098##
5099##
5100
5101#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5102
5103##
5104
5105# ------------------------------------------------------------------------------
5106
5107#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05005108#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005109#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04005110Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005111directly compiled as C++ code. Floating point values are written
5112in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5113original Path.
5114
Cary Clark6fc50412017-09-21 12:31:06 -04005115Use instead of dump() when submitting
5116#A bug reports against Skia # http://bug.skia.org ##
5117.
Cary Clark73fa9722017-08-29 17:36:51 -04005118
5119#Example
5120SkPath path, copy;
5121path.lineTo(6.f / 7, 2.f / 3);
5122path.dumpHex();
5123copy.setFillType(SkPath::kWinding_FillType);
5124copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5125copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5126SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5127#StdOut
5128path.setFillType(SkPath::kWinding_FillType);
5129path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5130path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5131path is equal to copy
5132##
5133##
5134
5135#SeeAlso dump SkRect::dumpHex() SkRRect::dumpHex() writeToMemory
5136
5137##
5138
5139# ------------------------------------------------------------------------------
5140
5141#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05005142#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005143#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005144Writes Path to buffer, returning the number of bytes written.
5145Pass nullptr to obtain the storage size.
5146
5147Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5148additionally writes computed information like Convexity and bounds.
5149
5150Use only be used in concert with readFromMemory;
5151the format used for Path in memory is not guaranteed.
5152
5153#Param buffer storage for Path; may be nullptr ##
5154
5155#Return size of storage required for Path; always a multiple of 4 ##
5156
5157#Example
5158void draw(SkCanvas* canvas) {
5159 SkPath path, copy;
5160 path.lineTo(6.f / 7, 2.f / 3);
5161 size_t size = path.writeToMemory(nullptr);
5162 SkTDArray<char> storage;
5163 storage.setCount(size);
5164 path.writeToMemory(storage.begin());
5165 copy.readFromMemory(storage.begin(), size);
5166 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5167}
5168#StdOut
5169path is equal to copy
5170##
5171##
5172
5173#SeeAlso serialize readFromMemory dump dumpHex
5174
5175##
5176
5177#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05005178#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005179#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005180Write Path to buffer, returning the buffer written to, wrapped in Data.
5181
5182serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5183additionally writes computed information like Convexity and bounds.
5184
5185serialize() should only be used in concert with readFromMemory.
5186The format used for Path in memory is not guaranteed.
5187
5188#Return Path data wrapped in Data buffer ##
5189
5190#Example
5191void draw(SkCanvas* canvas) {
5192 SkPath path, copy;
5193 path.lineTo(6.f / 7, 2.f / 3);
5194 sk_sp<SkData> data = path.serialize();
5195 copy.readFromMemory(data->data(), data->size());
5196 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5197}
5198#StdOut
5199path is equal to copy
5200##
5201##
5202
5203#SeeAlso writeToMemory readFromMemory dump dumpHex
5204##
5205
5206# ------------------------------------------------------------------------------
5207
5208#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05005209#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005210#Line # Initializes from buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005211Initializes Path from buffer of size length. Returns zero if the buffer is
5212data is inconsistent, or the length is too small.
5213
5214Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5215additionally reads computed information like Convexity and bounds.
5216
5217Used only in concert with writeToMemory;
5218the format used for Path in memory is not guaranteed.
5219
5220#Param buffer storage for Path ##
5221#Param length buffer size in bytes; must be multiple of 4 ##
5222
5223#Return number of bytes read, or zero on failure ##
5224
5225#Example
5226void draw(SkCanvas* canvas) {
5227 SkPath path, copy;
5228 path.lineTo(6.f / 7, 2.f / 3);
5229 size_t size = path.writeToMemory(nullptr);
5230 SkTDArray<char> storage;
5231 storage.setCount(size);
5232 path.writeToMemory(storage.begin());
5233 size_t wrongSize = size - 4;
5234 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5235 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5236 size_t largerSize = size + 4;
5237 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5238 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5239}
5240#StdOut
5241length = 60; returned by readFromMemory = 0
5242length = 68; returned by readFromMemory = 64
5243##
5244##
5245
5246#SeeAlso writeToMemory
5247
5248##
5249
5250# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05005251#Subtopic Generation_ID
Cary Clark73fa9722017-08-29 17:36:51 -04005252#Alias Generation_IDs
Cary Clark08895c42018-02-01 09:37:32 -05005253#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04005254Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5255Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5256not necessarily have matching Generation_IDs.
5257
5258Empty Paths have a Generation_ID of one.
5259
5260#Method uint32_t getGenerationID() const
5261
Cary Clarkab2621d2018-01-30 10:08:57 -05005262#In Generation_ID
5263#Line # returns unique ID ##
Cary Clark73fa9722017-08-29 17:36:51 -04005264Returns a non-zero, globally unique value. A different value is returned
5265if Verb_Array, Point_Array, or Conic_Weight changes.
5266
5267Setting Fill_Type does not change Generation_ID.
5268
5269Each time the path is modified, a different Generation_ID will be returned.
5270
5271#Bug 1762
5272Fill_Type does affect Generation_ID on Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -04005273
5274#Return non-zero, globally unique value ##
5275
5276#Example
5277SkPath path;
5278SkDebugf("empty genID = %u\n", path.getGenerationID());
5279path.lineTo(1, 2);
5280SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5281path.rewind();
5282SkDebugf("empty genID = %u\n", path.getGenerationID());
5283path.lineTo(1, 2);
5284SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5285#StdOut
5286empty genID = 1
52871st lineTo genID = 2
5288empty genID = 1
52892nd lineTo genID = 3
5290##
5291##
5292
5293#SeeAlso operator==(const SkPath& a, const SkPath& b)
5294
5295##
5296
Cary Clark78de7512018-02-07 07:27:09 -05005297#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04005298
5299# ------------------------------------------------------------------------------
5300
5301#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005302#In Property
5303#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005304#Line # returns if data is internally consistent ##
Cary Clark73fa9722017-08-29 17:36:51 -04005305 Returns if Path data is consistent. Corrupt Path data is detected if
5306 internal values are out of range or internal storage does not match
5307 array dimensions.
5308
5309 #Return true if Path data is consistent ##
5310
5311 #NoExample
5312 ##
5313
5314##
5315
5316#Method bool pathRefIsValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005317#Deprecated soon
Cary Clark73fa9722017-08-29 17:36:51 -04005318##
5319
5320# ------------------------------------------------------------------------------
5321
Cary Clark8032b982017-07-28 11:04:54 -04005322#Class Iter
Cary Clark08895c42018-02-01 09:37:32 -05005323#Line # Path data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005324
5325Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5326Provides options to treat open Contours as closed, and to ignore
5327degenerate data.
5328
Cary Clark73fa9722017-08-29 17:36:51 -04005329#Code
5330class Iter {
5331public:
5332 Iter();
5333 Iter(const SkPath& path, bool forceClose);
5334 void setPath(const SkPath& path, bool forceClose);
5335 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5336 SkScalar conicWeight() const;
5337 bool isCloseLine() const;
5338 bool isClosedContour() const;
5339};
5340##
5341
Cary Clark8032b982017-07-28 11:04:54 -04005342#Example
5343#Height 128
5344#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005345Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005346path of the glyph.
5347##
Cary Clark73fa9722017-08-29 17:36:51 -04005348void draw(SkCanvas* canvas) {
5349 SkPaint paint;
5350 paint.setAntiAlias(true);
5351 paint.setTextSize(256);
5352 SkPath asterisk, path;
5353 paint.getTextPath("*", 1, 50, 192, &asterisk);
5354 SkPath::Iter iter(asterisk, true);
5355 SkPoint start[4], pts[4];
5356 iter.next(start); // skip moveTo
5357 iter.next(start); // first quadTo
5358 path.moveTo((start[0] + start[1]) * 0.5f);
5359 while (SkPath::kClose_Verb != iter.next(pts)) {
5360 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5361 }
5362 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5363 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005364}
5365##
5366
5367#SeeAlso RawIter
5368
5369#Method Iter()
5370
5371Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5372Call setPath to initialize Iter at a later time.
5373
Cary Clark73fa9722017-08-29 17:36:51 -04005374#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005375
5376#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005377void draw(SkCanvas* canvas) {
5378 SkPath::Iter iter;
5379 SkPoint points[4];
5380 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5381 SkPath path;
5382 iter.setPath(path, false);
5383 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005384}
Cary Clark73fa9722017-08-29 17:36:51 -04005385#StdOut
5386iter is done
5387iter is done
5388##
Cary Clark8032b982017-07-28 11:04:54 -04005389##
5390
5391#SeeAlso setPath
5392
5393##
5394
5395#Method Iter(const SkPath& path, bool forceClose)
5396
5397Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5398If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5399open Contour. path is not altered.
5400
Cary Clark73fa9722017-08-29 17:36:51 -04005401#Param path Path to iterate ##
5402#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005403
Cary Clark73fa9722017-08-29 17:36:51 -04005404#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005405
5406#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005407void draw(SkCanvas* canvas) {
5408 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5409 SkDebugf("%s:\n", prefix);
5410 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5411 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5412 SkPath::Verb verb;
5413 do {
5414 SkPoint points[4];
5415 verb = iter.next(points);
5416 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5417 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5418 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5419 }
5420 if (SkPath::kConic_Verb == verb) {
5421 SkDebugf("weight = %g", iter.conicWeight());
5422 }
5423 SkDebugf("\n");
5424 } while (SkPath::kDone_Verb != verb);
5425 SkDebugf("\n");
5426 };
5427
5428 SkPath path;
5429 path.quadTo(10, 20, 30, 40);
5430 SkPath::Iter openIter(path, false);
5431 debugster("open", openIter);
5432 SkPath::Iter closedIter(path, true);
5433 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005434}
5435#StdOut
5436open:
Cary Clark73fa9722017-08-29 17:36:51 -04005437kMove_Verb {0, 0},
5438kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5439kDone_Verb
5440
5441closed:
5442kMove_Verb {0, 0},
5443kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5444kLine_Verb {30, 40}, {0, 0},
5445kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005446kDone_Verb
5447##
5448##
5449
5450#SeeAlso setPath
5451
5452##
5453
5454#Method void setPath(const SkPath& path, bool forceClose)
5455
5456Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5457If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5458open Contour. path is not altered.
5459
Cary Clark73fa9722017-08-29 17:36:51 -04005460#Param path Path to iterate ##
5461#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005462
5463#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005464void draw(SkCanvas* canvas) {
5465 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5466 SkDebugf("%s:\n", prefix);
5467 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5468 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5469 SkPath::Verb verb;
5470 do {
5471 SkPoint points[4];
5472 verb = iter.next(points);
5473 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5474 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5475 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5476 }
5477 if (SkPath::kConic_Verb == verb) {
5478 SkDebugf("weight = %g", iter.conicWeight());
5479 }
5480 SkDebugf("\n");
5481 } while (SkPath::kDone_Verb != verb);
5482 SkDebugf("\n");
5483 };
5484
5485 SkPath path;
5486 path.quadTo(10, 20, 30, 40);
5487 SkPath::Iter iter(path, false);
5488 debugster("quad open", iter);
5489 SkPath path2;
5490 path2.conicTo(1, 2, 3, 4, .5f);
5491 iter.setPath(path2, true);
5492 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005493}
5494#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005495quad open:
5496kMove_Verb {0, 0},
5497kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5498kDone_Verb
5499
5500conic closed:
5501kMove_Verb {0, 0},
5502kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
5503kLine_Verb {3, 4}, {0, 0},
5504kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005505kDone_Verb
5506##
5507##
5508
5509#SeeAlso Iter(const SkPath& path, bool forceClose)
5510
5511##
5512
5513#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
5514
Cary Clarka523d2d2017-08-30 08:58:10 -04005515Returns next Verb in Verb_Array, and advances Iter.
5516When Verb_Array is exhausted, returns kDone_Verb.
5517
Cary Clark8032b982017-07-28 11:04:54 -04005518Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005519
Cary Clark8032b982017-07-28 11:04:54 -04005520If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5521only the last in the series; and skip very small Lines, Quads, and Conics; and
5522skip kClose_Verb following kMove_Verb.
5523if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5524Conics with zero lengths.
5525
Cary Clarka523d2d2017-08-30 08:58:10 -04005526 #Param pts storage for Point data describing returned Verb ##
5527 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5528 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005529
Cary Clark73fa9722017-08-29 17:36:51 -04005530 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005531
5532#Example
5533#Description
5534skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5535followed by the kClose_Verb, the zero length Line and the very small Line.
5536
5537skip degenerate if exact skips the same as skip degenerate, but shows
5538the very small Line.
5539
5540skip none shows all of the Verbs and Points in Path.
5541##
Cary Clark73fa9722017-08-29 17:36:51 -04005542void draw(SkCanvas* canvas) {
5543 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5544 SkPath::Iter iter(path, false);
5545 SkDebugf("%s:\n", prefix);
5546 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5547 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5548 SkPath::Verb verb;
5549 do {
5550 SkPoint points[4];
5551 verb = iter.next(points, degen, exact);
5552 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5553 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5554 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5555 }
5556 SkDebugf("\n");
5557 } while (SkPath::kDone_Verb != verb);
5558 SkDebugf("\n");
5559 };
5560
5561 SkPath path;
5562 path.moveTo(10, 10);
5563 path.moveTo(20, 20);
5564 path.quadTo(10, 20, 30, 40);
5565 path.moveTo(1, 1);
5566 path.close();
5567 path.moveTo(30, 30);
5568 path.lineTo(30, 30);
5569 path.moveTo(30, 30);
5570 path.lineTo(30.00001f, 30);
5571 debugster("skip degenerate", path, true, false);
5572 debugster("skip degenerate if exact", path, true, true);
5573 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005574}
5575#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005576skip degenerate:
5577kMove_Verb {20, 20},
5578kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5579kDone_Verb
5580
5581skip degenerate if exact:
5582kMove_Verb {20, 20},
5583kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5584kMove_Verb {30, 30},
5585kLine_Verb {30, 30}, {30.00001, 30},
5586kDone_Verb
5587
5588skip none:
5589kMove_Verb {10, 10},
5590kMove_Verb {20, 20},
5591kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5592kMove_Verb {1, 1},
5593kClose_Verb {1, 1},
5594kMove_Verb {30, 30},
5595kLine_Verb {30, 30}, {30, 30},
5596kMove_Verb {30, 30},
5597kLine_Verb {30, 30}, {30.00001, 30},
5598kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005599##
5600##
5601
5602#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
5603
5604##
5605
5606#Method SkScalar conicWeight() const
5607
5608 Returns Conic_Weight if next() returned kConic_Verb.
5609
5610 If next() has not been called, or next() did not return kConic_Verb,
5611 result is undefined.
5612
Cary Clark73fa9722017-08-29 17:36:51 -04005613 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005614
5615 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005616 void draw(SkCanvas* canvas) {
5617 SkPath path;
5618 path.conicTo(1, 2, 3, 4, .5f);
5619 SkPath::Iter iter(path, false);
5620 SkPoint p[4];
5621 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5622 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5623 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5624 p[2].fX, p[2].fY);
5625 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005626 }
5627 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005628first verb is move
5629next verb is conic
5630conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005631conic weight: 0.5
5632 ##
5633 ##
5634
5635 #SeeAlso Conic_Weight
5636
5637##
5638
5639#Method bool isCloseLine() const
5640
5641 Returns true if last kLine_Verb returned by next() was generated
5642 by kClose_Verb. When true, the end point returned by next() is
5643 also the start point of Contour.
5644
5645 If next() has not been called, or next() did not return kLine_Verb,
5646 result is undefined.
5647
Cary Clark73fa9722017-08-29 17:36:51 -04005648 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005649
5650 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005651void draw(SkCanvas* canvas) {
5652 SkPath path;
5653 path.moveTo(6, 7);
5654 path.conicTo(1, 2, 3, 4, .5f);
5655 path.close();
5656 SkPath::Iter iter(path, false);
5657 SkPoint p[4];
5658 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5659 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5660 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5661 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5662 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5663 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5664 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005665}
5666 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040056671st verb is move
5668moveTo point: {6,7}
56692nd verb is conic
56703rd verb is line
5671line points: {3,4}, {6,7}
5672line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040056734th verb is close
5674 ##
5675 ##
5676
5677 #SeeAlso close()
5678##
5679
5680#Method bool isClosedContour() const
5681
5682Returns true if subsequent calls to next() return kClose_Verb before returning
5683kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5684Iter may have been initialized with force close set to true.
5685
Cary Clark73fa9722017-08-29 17:36:51 -04005686#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005687
5688#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005689void draw(SkCanvas* canvas) {
5690 for (bool forceClose : { false, true } ) {
5691 SkPath path;
5692 path.conicTo(1, 2, 3, 4, .5f);
5693 SkPath::Iter iter(path, forceClose);
5694 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5695 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5696 path.close();
5697 iter.setPath(path, forceClose);
5698 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5699 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5700 }
Cary Clark8032b982017-07-28 11:04:54 -04005701}
5702#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005703without close(), forceClose is false: isClosedContour returns false
5704with close(), forceClose is false: isClosedContour returns true
5705without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005706with close(), forceClose is true : isClosedContour returns true
5707##
5708##
5709
5710#SeeAlso Iter(const SkPath& path, bool forceClose)
5711
5712##
Cary Clark73fa9722017-08-29 17:36:51 -04005713
5714#Class Iter ##
5715
Cary Clark8032b982017-07-28 11:04:54 -04005716#Class RawIter
Cary Clark08895c42018-02-01 09:37:32 -05005717#Line # Path raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005718
5719Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5720Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5721
Cary Clark73fa9722017-08-29 17:36:51 -04005722#Code
5723 class RawIter {
5724 public:
5725 RawIter();
5726 RawIter(const SkPath& path);
5727 void setPath(const SkPath& path);
5728 Verb next(SkPoint pts[4]);
5729 Verb peek() const;
5730 SkScalar conicWeight() const;
5731 }
5732##
5733
Cary Clark8032b982017-07-28 11:04:54 -04005734 #Method RawIter()
5735
5736 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
Cary Clark78c110e2018-02-09 16:49:09 -05005737 Call setPath to initialize SkPath::Iter at a later time.
Cary Clark8032b982017-07-28 11:04:54 -04005738
Cary Clark73fa9722017-08-29 17:36:51 -04005739 #Return RawIter of empty Path ##
5740
5741 #NoExample
5742 ##
5743 ##
Cary Clark8032b982017-07-28 11:04:54 -04005744
5745 #Method RawIter(const SkPath& path)
5746
5747
5748 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5749
Cary Clark73fa9722017-08-29 17:36:51 -04005750 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005751
Cary Clark73fa9722017-08-29 17:36:51 -04005752 #Return RawIter of path ##
5753
5754 #NoExample
5755 ##
5756 ##
Cary Clark8032b982017-07-28 11:04:54 -04005757
5758 #Method void setPath(const SkPath& path)
5759
Cary Clark78c110e2018-02-09 16:49:09 -05005760 Sets SkPath::Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
Cary Clark8032b982017-07-28 11:04:54 -04005761
Cary Clark73fa9722017-08-29 17:36:51 -04005762 #Param path Path to iterate ##
5763
5764 #NoExample
5765 ##
5766 ##
Cary Clark8032b982017-07-28 11:04:54 -04005767
5768 #Method Verb next(SkPoint pts[4])
5769
5770 Returns next Verb in Verb_Array, and advances RawIter.
5771 When Verb_Array is exhausted, returns kDone_Verb.
5772 Zero to four Points are stored in pts, depending on the returned Verb.
5773
Cary Clarka523d2d2017-08-30 08:58:10 -04005774 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005775
Cary Clark73fa9722017-08-29 17:36:51 -04005776 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005777
5778 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005779 void draw(SkCanvas* canvas) {
5780 SkPath path;
5781 path.moveTo(50, 60);
5782 path.quadTo(10, 20, 30, 40);
5783 path.close();
5784 path.lineTo(30, 30);
5785 path.conicTo(1, 2, 3, 4, .5f);
5786 path.cubicTo(-1, -2, -3, -4, -5, -6);
5787 SkPath::RawIter iter(path);
5788 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5789 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5790 SkPath::Verb verb;
5791 do {
5792 SkPoint points[4];
5793 verb = iter.next(points);
5794 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5795 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5796 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5797 }
5798 if (SkPath::kConic_Verb == verb) {
5799 SkDebugf("weight = %g", iter.conicWeight());
5800 }
5801 SkDebugf("\n");
5802 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005803 }
5804 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005805 kMove_Verb {50, 60},
5806 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5807 kClose_Verb {50, 60},
5808 kMove_Verb {50, 60},
5809 kLine_Verb {50, 60}, {30, 30},
5810 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
5811 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
Cary Clark8032b982017-07-28 11:04:54 -04005812 kDone_Verb
5813 ##
5814 ##
5815
5816 #SeeAlso peek()
5817
Cary Clark73fa9722017-08-29 17:36:51 -04005818 ##
Cary Clark8032b982017-07-28 11:04:54 -04005819
5820 #Method Verb peek() const
5821
5822 Returns next Verb, but does not advance RawIter.
5823
Cary Clark73fa9722017-08-29 17:36:51 -04005824 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005825
5826 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005827 SkPath path;
5828 path.quadTo(10, 20, 30, 40);
5829 path.conicTo(1, 2, 3, 4, .5f);
5830 path.cubicTo(1, 2, 3, 4, .5, 6);
5831 SkPath::RawIter iter(path);
5832 SkPath::Verb verb, peek = iter.peek();
5833 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5834 do {
5835 SkPoint points[4];
5836 verb = iter.next(points);
5837 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5838 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005839 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005840 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5841 #StdOut
5842 #Volatile
5843 peek Move == verb Move
5844 peek Quad == verb Quad
5845 peek Conic == verb Conic
5846 peek Cubic == verb Cubic
5847 peek Done == verb Done
5848 peek Done == verb Done
5849 ##
Cary Clark8032b982017-07-28 11:04:54 -04005850 ##
5851
5852 #Bug 6832
5853 StdOut isn't really volatile, it just produces the wrong result.
5854 A simple fix changes the output of hairlines and needs to be
5855 investigated to see if the change is correct or not.
5856 https://skia-review.googlesource.com/c/21340/
Cary Clark8032b982017-07-28 11:04:54 -04005857
5858 #SeeAlso next()
5859
Cary Clark73fa9722017-08-29 17:36:51 -04005860 ##
Cary Clark8032b982017-07-28 11:04:54 -04005861
Cary Clark73fa9722017-08-29 17:36:51 -04005862 #Method SkScalar conicWeight() const
5863
Cary Clark8032b982017-07-28 11:04:54 -04005864 Returns Conic_Weight if next() returned kConic_Verb.
5865
5866 If next() has not been called, or next() did not return kConic_Verb,
5867 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04005868
5869 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005870
5871 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005872 void draw(SkCanvas* canvas) {
5873 SkPath path;
5874 path.conicTo(1, 2, 3, 4, .5f);
5875 SkPath::RawIter iter(path);
5876 SkPoint p[4];
5877 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5878 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5879 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5880 p[2].fX, p[2].fY);
5881 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005882 }
5883 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005884 first verb is move
5885 next verb is conic
5886 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005887 conic weight: 0.5
5888 ##
5889 ##
5890
5891 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04005892
5893 ##
5894
5895#Class RawIter ##
5896
5897#Class SkPath ##
5898
5899#Topic Path ##
Cary Clark4855f782018-02-06 09:41:53 -05005900