blob: 869e72e5fdc024bb1b43198525390fd4f3d947e4 [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) {
Cary Clark73fa9722017-08-29 17:36:51 -04001743 SkPath path;
1744 path.lineTo(20, 20);
1745 path.offset(-10, -10);
1746 for (int i= 0; i < path.countPoints(); ++i) {
1747 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
1748 }
1749}
1750#StdOut
1751point 0: (-10,-10)
1752point 1: (10,10)
1753##
1754##
1755
1756#SeeAlso countPoints getPoints
1757##
1758
1759
1760#Subtopic Point_Array ##
1761
1762# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001763#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001764#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001765
1766Verb_Array always starts with kMove_Verb.
1767If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1768the quantity of kMove_Verb equals the Contour count.
1769Verb_Array does not include or count kDone_Verb; it is a convenience
1770returned when iterating through Verb_Array.
1771
1772Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
1773or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001774
1775#Method int countVerbs() const
1776
Cary Clarkab2621d2018-01-30 10:08:57 -05001777#In Verb_Array
1778#Line # returns Verb_Array length ##
Cary Clark73fa9722017-08-29 17:36:51 -04001779Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
1780kCubic_Verb, and kClose_Verb; added to Path.
1781
1782#Return length of Verb_Array ##
1783
1784#Example
1785SkPath path;
1786SkDebugf("empty verb count: %d\n", path.countVerbs());
1787path.addRoundRect({10, 20, 30, 40}, 5, 5);
1788SkDebugf("round rect verb count: %d\n", path.countVerbs());
1789#StdOut
1790empty verb count: 0
1791round rect verb count: 10
1792##
1793##
1794
1795#SeeAlso getVerbs Iter RawIter
1796
1797##
1798
1799#Method int getVerbs(uint8_t verbs[], int max) const
1800
Cary Clarkab2621d2018-01-30 10:08:57 -05001801#In Verb_Array
1802#Line # returns Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001803Returns the number of verbs in the path. Up to max verbs are copied. The
1804verbs are copied as one byte per verb.
1805
1806#Param verbs storage for verbs, may be nullptr ##
1807#Param max maximum number to copy into verbs ##
1808
1809#Return the actual number of verbs in the path ##
1810
1811#Example
1812void draw(SkCanvas* canvas) {
1813 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1814 int count = path.getVerbs(verbs, max);
1815 SkDebugf("%s verb count: %d ", prefix, count);
1816 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1817 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1818 SkDebugf("%s ", verbStr[verbs[i]]);
1819 }
1820 SkDebugf("\n");
1821 };
1822 SkPath path;
1823 path.lineTo(20, 20);
1824 path.lineTo(-10, -10);
1825 uint8_t verbs[3];
1826 debugster("no verbs", path, nullptr, 0);
1827 debugster("zero max", path, verbs, 0);
1828 debugster("too small", path, verbs, 2);
1829 debugster("just right", path, verbs, path.countVerbs());
1830}
1831#StdOut
1832no verbs verb count: 3
1833zero max verb count: 3
1834too small verb count: 3 move line
1835just right verb count: 3 move line line
1836##
1837##
1838
1839#SeeAlso countVerbs getPoints Iter RawIter
1840##
Cary Clark8032b982017-07-28 11:04:54 -04001841
1842#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001843
1844# ------------------------------------------------------------------------------
1845
1846#Method void swap(SkPath& other)
Cary Clark4855f782018-02-06 09:41:53 -05001847#In Operator
Cary Clarkab2621d2018-01-30 10:08:57 -05001848#Line # exchanges Path pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04001849Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1850Cached state is also exchanged. swap() internally exchanges pointers, so
1851it is lightweight and does not allocate memory.
1852
1853swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001854Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001855making assignment as efficient as swap().
1856
1857#Param other Path exchanged by value ##
1858
1859#Example
1860SkPath path1, path2;
1861path1.addRect({10, 20, 30, 40});
1862path1.swap(path2);
1863const SkRect& b1 = path1.getBounds();
1864SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1865const SkRect& b2 = path2.getBounds();
1866SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1867#StdOut
1868path1 bounds = 0, 0, 0, 0
1869path2 bounds = 10, 20, 30, 40
1870#StdOut ##
1871##
1872
1873#SeeAlso operator=(const SkPath& path)
1874
1875##
1876
1877# ------------------------------------------------------------------------------
1878
1879#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001880#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001881#Line # returns maximum and minimum of Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001882Returns minimum and maximum x and y values of Point_Array.
1883Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1884be larger or smaller than area affected when Path is drawn.
1885
1886Rect returned includes all Points added to Path, including Points associated with
1887kMove_Verb that define empty Contours.
1888
1889#Return bounds of all Points in Point_Array ##
1890
1891#Example
1892#Description
1893Bounds of upright Circle can be predicted from center and radius.
1894Bounds of rotated Circle includes control Points outside of filled area.
1895##
1896 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1897 const SkRect& bounds = path.getBounds();
1898 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
1899 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1900 };
1901 SkPath path;
1902 debugster("empty", path);
1903 path.addCircle(50, 45, 25);
1904 debugster("circle", path);
1905 SkMatrix matrix;
1906 matrix.setRotate(45, 50, 45);
1907 path.transform(matrix);
1908 debugster("rotated circle", path);
1909#StdOut
1910empty bounds = 0, 0, 0, 0
1911circle bounds = 25, 20, 75, 70
1912rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1913##
1914##
1915
1916#SeeAlso computeTightBounds updateBoundsCache
1917
1918##
1919
1920# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001921#Subtopic Utility
1922#Populate
1923#Line # rarely called management functions ##
1924##
Cary Clark73fa9722017-08-29 17:36:51 -04001925
1926#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001927#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001928#Line # refreshes result of getBounds ##
Cary Clark73fa9722017-08-29 17:36:51 -04001929Update internal bounds so that subsequent calls to getBounds are instantaneous.
1930Unaltered copies of Path may also access cached bounds through getBounds.
1931
1932For now, identical to calling getBounds and ignoring the returned value.
1933
1934Call to prepare Path subsequently drawn from multiple threads,
1935to avoid a race condition where each draw separately computes the bounds.
1936
1937#Example
1938 double times[2] = { 0, 0 };
1939 for (int i = 0; i < 10000; ++i) {
1940 SkPath path;
1941 for (int j = 1; j < 100; ++ j) {
1942 path.addCircle(50 + j, 45 + j, 25 + j);
1943 }
1944 if (1 & i) {
1945 path.updateBoundsCache();
1946 }
1947 double start = SkTime::GetNSecs();
1948 (void) path.getBounds();
1949 times[1 & i] += SkTime::GetNSecs() - start;
1950 }
1951 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1952 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1953#StdOut
1954#Volatile
1955uncached avg: 0.18048 ms
1956cached avg: 0.182784 ms
1957##
1958##
1959
1960#SeeAlso getBounds
1961#ToDo the results don't make sense, need to profile to figure this out ##
1962
1963##
1964
1965# ------------------------------------------------------------------------------
1966
1967#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001968#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001969#Line # returns extent of geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04001970Returns minimum and maximum x and y values of the lines and curves in Path.
1971Returns (0, 0, 0, 0) if Path contains no points.
1972Returned bounds width and height may be larger or smaller than area affected
1973when Path is drawn.
1974
1975Includes Points associated with kMove_Verb that define empty
1976Contours.
1977
1978Behaves identically to getBounds when Path contains
1979only lines. If Path contains curves, computed bounds includes
1980the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
1981and unlike getBounds, does not cache the result.
1982
1983#Return tight bounds of curves in Path ##
1984
1985#Example
1986 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1987 const SkRect& bounds = path.computeTightBounds();
1988 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
1989 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1990 };
1991 SkPath path;
1992 debugster("empty", path);
1993 path.addCircle(50, 45, 25);
1994 debugster("circle", path);
1995 SkMatrix matrix;
1996 matrix.setRotate(45, 50, 45);
1997 path.transform(matrix);
1998 debugster("rotated circle", path);
1999#StdOut
2000empty bounds = 0, 0, 0, 0
2001circle bounds = 25, 20, 75, 70
2002rotated circle bounds = 25, 20, 75, 70
2003##
2004##
2005
2006#SeeAlso getBounds
2007
2008##
2009
2010# ------------------------------------------------------------------------------
2011
2012#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05002013#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002014#Line # returns true if Rect may be inside ##
Cary Clark73fa9722017-08-29 17:36:51 -04002015Returns true if rect is contained by Path.
2016May return false when rect is contained by Path.
2017
2018For now, only returns true if Path has one Contour and is convex.
2019rect may share points and edges with Path and be contained.
2020Returns true if rect is empty, that is, it has zero width or height; and
2021the Point or Line described by rect is contained by Path.
2022
2023#Param rect Rect, Line, or Point checked for containment ##
2024
2025#Return true if rect is contained ##
2026
2027#Example
2028#Height 140
2029#Description
2030Rect is drawn in blue if it is contained by red Path.
2031##
2032void draw(SkCanvas* canvas) {
2033 SkPath path;
2034 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2035 SkRect tests[] = {
2036 { 10, 40, 54, 80 },
2037 { 25, 20, 39, 120 },
2038 { 15, 25, 49, 115 },
2039 { 13, 27, 51, 113 },
2040 };
2041 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2042 SkPaint paint;
2043 paint.setColor(SK_ColorRED);
2044 canvas->drawPath(path, paint);
2045 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2046 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2047 canvas->drawRect(tests[i], paint);
2048 canvas->translate(64, 0);
2049 }
2050}
2051##
2052
2053#SeeAlso contains Op Rect Convexity
2054
2055##
2056
2057# ------------------------------------------------------------------------------
2058
2059#Method void incReserve(unsigned extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05002060#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002061#Line # reserves space for additional data ##
Cary Clark73fa9722017-08-29 17:36:51 -04002062grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
2063May improve performance and use less memory by
2064reducing the number and size of allocations when creating Path.
2065
Cary Clarkce101242017-09-01 15:51:02 -04002066#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002067
2068#Example
2069#Height 192
2070void draw(SkCanvas* canvas) {
2071 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2072 path->moveTo(size, 0);
2073 for (int i = 1; i < sides; i++) {
2074 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2075 path->lineTo(c * size, s * size);
2076 }
2077 path->close();
2078 };
2079 SkPath path;
2080 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2081 for (int sides = 3; sides < 10; ++sides) {
2082 addPoly(sides, sides, &path);
2083 }
2084 SkMatrix matrix;
2085 matrix.setScale(10, 10, -10, -10);
2086 path.transform(matrix);
2087 SkPaint paint;
2088 paint.setStyle(SkPaint::kStroke_Style);
2089 canvas->drawPath(path, paint);
2090}
2091##
2092
2093#SeeAlso Point_Array
2094
2095##
2096
2097# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05002098#Subtopic Build
2099#Populate
2100#Line # adds points and verbs to path ##
2101##
Cary Clark73fa9722017-08-29 17:36:51 -04002102
2103#Method void moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002104#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002105#Line # starts Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -04002106Adds beginning of Contour at Point (x, y).
2107
2108#Param x x-coordinate of Contour start ##
2109#Param y y-coordinate of Contour start ##
2110
2111#Example
2112 #Width 140
2113 #Height 100
2114 void draw(SkCanvas* canvas) {
2115 SkRect rect = { 20, 20, 120, 80 };
2116 SkPath path;
2117 path.addRect(rect);
2118 path.moveTo(rect.fLeft, rect.fTop);
2119 path.lineTo(rect.fRight, rect.fBottom);
2120 path.moveTo(rect.fLeft, rect.fBottom);
2121 path.lineTo(rect.fRight, rect.fTop);
2122 SkPaint paint;
2123 paint.setStyle(SkPaint::kStroke_Style);
2124 canvas->drawPath(path, paint);
2125 }
2126##
2127
2128#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2129
2130##
2131
2132#Method void moveTo(const SkPoint& p)
2133
2134Adds beginning of Contour at Point p.
2135
2136#Param p contour start ##
2137
2138#Example
2139 #Width 128
2140 #Height 128
2141void draw(SkCanvas* canvas) {
2142 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
2143 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2144 SkPath path;
2145 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2146 path.moveTo(data[i][0]);
2147 path.lineTo(data[i][1]);
2148 path.lineTo(data[i][2]);
2149 }
2150 SkPaint paint;
2151 paint.setStyle(SkPaint::kStroke_Style);
2152 canvas->drawPath(path, paint);
2153}
2154##
2155
2156#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2157
2158##
2159
2160#Method void rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002161#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002162#Line # starts Contour relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002163Adds beginning of Contour relative to Last_Point.
2164If Path is empty, starts Contour at (dx, dy).
2165Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002166Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002167
2168#Param dx offset from Last_Point x to Contour start x ##
2169#Param dy offset from Last_Point y to Contour start y ##
2170
2171#Example
2172 #Height 100
2173 SkPath path;
2174 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2175 path.rMoveTo(25, 2);
2176 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2177 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2178 path.rLineTo(arrow[i].fX, arrow[i].fY);
2179 }
2180 SkPaint paint;
2181 canvas->drawPath(path, paint);
2182 SkPoint lastPt;
2183 path.getLastPt(&lastPt);
2184 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2185##
2186
2187#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2188
2189##
2190
2191# ------------------------------------------------------------------------------
2192
2193#Method void lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002194#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002195#Line # appends Line ##
Cary Clark73fa9722017-08-29 17:36:51 -04002196Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2197kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2198
2199lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2200lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
2201
2202#Param x end of added Line in x ##
2203#Param y end of added Line in y ##
2204
2205#Example
2206#Height 100
2207###$
2208void draw(SkCanvas* canvas) {
2209 SkPaint paint;
2210 paint.setAntiAlias(true);
2211 paint.setTextSize(72);
2212 canvas->drawString("#", 120, 80, paint);
2213 paint.setStyle(SkPaint::kStroke_Style);
2214 paint.setStrokeWidth(5);
2215 SkPath path;
2216 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2217 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2218 unsigned o = 0;
2219 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2220 for (unsigned j = 0; j < 2; o++, j++) {
2221 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2222 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2223 }
2224 }
2225 canvas->drawPath(path, paint);
2226}
2227$$$#
2228##
2229
2230#SeeAlso Contour moveTo rLineTo addRect
2231
2232##
2233
2234# ------------------------------------------------------------------------------
2235
2236#Method void lineTo(const SkPoint& p)
2237
2238Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2239kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2240
2241lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2242lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2243
2244#Param p end Point of added Line ##
2245
2246#Example
2247#Height 100
2248 SkPath path;
2249 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2250 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2251 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2252 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2253 path.moveTo(oxo[i]);
2254 path.lineTo(oxo[i + 1]);
2255 }
2256 SkPaint paint;
2257 paint.setStyle(SkPaint::kStroke_Style);
2258 canvas->drawPath(path, paint);
2259##
2260
2261#SeeAlso Contour moveTo rLineTo addRect
2262
2263##
2264
2265# ------------------------------------------------------------------------------
2266
2267#Method void rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002268#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002269#Line # appends Line relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002270Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2271kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2272
2273Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2274then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2275Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002276Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002277
2278#Param dx offset from Last_Point x to Line end x ##
2279#Param dy offset from Last_Point y to Line end y ##
2280
2281#Example
2282#Height 128
2283void draw(SkCanvas* canvas) {
2284 SkPaint paint;
2285 paint.setAntiAlias(true);
2286 paint.setStyle(SkPaint::kStroke_Style);
2287 SkPath path;
2288 path.moveTo(10, 98);
2289 SkScalar x = 0, y = 0;
2290 for (int i = 10; i < 100; i += 5) {
2291 x += i * ((i & 2) - 1);
2292 y += i * (((i + 1) & 2) - 1);
2293 path.rLineTo(x, y);
2294
2295 }
2296 canvas->drawPath(path, paint);
2297}
2298##
2299
2300#SeeAlso Contour moveTo lineTo addRect
2301
2302##
2303
2304# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002305#Subtopic Quad
Cary Clarkce101242017-09-01 15:51:02 -04002306#Alias Quad
Cary Clark73fa9722017-08-29 17:36:51 -04002307#Alias Quads
Cary Clarkce101242017-09-01 15:51:02 -04002308#Alias Quadratic_Bezier
2309#Alias Quadratic_Beziers
Cary Clark08895c42018-02-01 09:37:32 -05002310#Line # Bezier_Curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002311
2312Quad describes a quadratic Bezier, a second-order curve identical to a section
2313of a parabola. Quad begins at a start Point, curves towards a control Point,
2314and then curves to an end Point.
2315
2316#Example
2317#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002318void draw(SkCanvas* canvas) {
2319 SkPaint paint;
2320 paint.setAntiAlias(true);
2321 paint.setStyle(SkPaint::kStroke_Style);
2322 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2323 canvas->drawLine(quadPts[0], quadPts[1], paint);
2324 canvas->drawLine(quadPts[1], quadPts[2], paint);
2325 SkPath path;
2326 path.moveTo(quadPts[0]);
2327 path.quadTo(quadPts[1], quadPts[2]);
2328 paint.setStrokeWidth(3);
2329 canvas->drawPath(path, paint);
2330}
Cary Clark8032b982017-07-28 11:04:54 -04002331##
2332
2333Quad is a special case of Conic where Conic_Weight is set to one.
2334
2335Quad is always contained by the triangle connecting its three Points. Quad
2336begins tangent to the line between start Point and control Point, and ends
2337tangent to the line between control Point and end Point.
2338
2339#Example
2340#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002341void draw(SkCanvas* canvas) {
2342 SkPaint paint;
2343 paint.setAntiAlias(true);
2344 paint.setStyle(SkPaint::kStroke_Style);
2345 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2346 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2347 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2348 paint.setColor(0x7fffffff & colors[i]);
2349 paint.setStrokeWidth(1);
2350 canvas->drawLine(quadPts[0], quadPts[1], paint);
2351 canvas->drawLine(quadPts[1], quadPts[2], paint);
2352 SkPath path;
2353 path.moveTo(quadPts[0]);
2354 path.quadTo(quadPts[1], quadPts[2]);
2355 paint.setStrokeWidth(3);
2356 paint.setColor(colors[i]);
2357 canvas->drawPath(path, paint);
2358 quadPts[1].fY += 30;
2359 }
Cary Clark8032b982017-07-28 11:04:54 -04002360}
2361##
Cary Clark73fa9722017-08-29 17:36:51 -04002362
2363#Method void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
2364
Cary Clarkab2621d2018-01-30 10:08:57 -05002365#In Quad
2366#Line # appends Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002367 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
2368 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2369 before adding Quad.
2370
2371 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2372 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2373 to Point_Array.
2374
2375 #Param x1 control Point of Quad in x ##
2376 #Param y1 control Point of Quad in y ##
2377 #Param x2 end Point of Quad in x ##
2378 #Param y2 end Point of Quad in y ##
2379
2380 #Example
2381 void draw(SkCanvas* canvas) {
2382 SkPaint paint;
2383 paint.setAntiAlias(true);
2384 paint.setStyle(SkPaint::kStroke_Style);
2385 SkPath path;
2386 path.moveTo(0, -10);
2387 for (int i = 0; i < 128; i += 16) {
2388 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2389 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2390 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2391 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2392 }
2393 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002394 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002395 }
2396 ##
2397
2398 #SeeAlso Contour moveTo conicTo rQuadTo
2399
2400##
2401
2402#Method void quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05002403#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002404#In Quad
Cary Clark73fa9722017-08-29 17:36:51 -04002405 Adds Quad from Last_Point towards Point p1, to Point p2.
2406 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2407 before adding Quad.
2408
2409 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2410 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2411 to Point_Array.
2412
2413 #Param p1 control Point of added Quad ##
2414 #Param p2 end Point of added Quad ##
2415
2416 #Example
2417 void draw(SkCanvas* canvas) {
2418 SkPaint paint;
2419 paint.setStyle(SkPaint::kStroke_Style);
2420 paint.setAntiAlias(true);
2421 SkPath path;
2422 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2423 path.moveTo(pts[1]);
2424 for (int i = 0; i < 3; ++i) {
2425 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2426 }
2427 canvas->drawPath(path, paint);
2428 }
2429 ##
2430
2431 #SeeAlso Contour moveTo conicTo rQuadTo
2432
2433##
2434
2435#Method void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05002436#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002437#In Quad
2438#Line # appends Quad relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002439 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2440 If Path is empty, or last Verb
2441 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2442
2443 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2444 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2445 control and Quad end to Point_Array.
2446 Quad control is Last_Point plus Vector (dx1, dy1).
2447 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002448 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002449
2450 #Param dx1 offset from Last_Point x to Quad control x ##
2451 #Param dy1 offset from Last_Point x to Quad control y ##
2452 #Param dx2 offset from Last_Point x to Quad end x ##
2453 #Param dy2 offset from Last_Point x to Quad end y ##
2454
2455 #Example
2456 void draw(SkCanvas* canvas) {
2457 SkPaint paint;
2458 paint.setAntiAlias(true);
2459 SkPath path;
2460 path.moveTo(128, 20);
2461 path.rQuadTo(-6, 10, -7, 10);
2462 for (int i = 1; i < 32; i += 4) {
2463 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2464 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2465 }
2466 path.quadTo(92, 220, 128, 215);
2467 canvas->drawPath(path, paint);
2468 }
2469 ##
2470
2471 #SeeAlso Contour moveTo conicTo quadTo
2472
2473##
2474
Cary Clark78de7512018-02-07 07:27:09 -05002475#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002476
2477# ------------------------------------------------------------------------------
2478
Cary Clark78de7512018-02-07 07:27:09 -05002479#Subtopic Conic
Cary Clark08895c42018-02-01 09:37:32 -05002480#Line # conic section defined by three points and a weight ##
Cary Clark8032b982017-07-28 11:04:54 -04002481#Alias Conics
2482
2483Conic describes a conical section: a piece of an ellipse, or a piece of a
2484parabola, or a piece of a hyperbola. Conic begins at a start Point,
2485curves towards a control Point, and then curves to an end Point. The influence
2486of the control Point is determined by Conic_Weight.
2487
Cary Clark73fa9722017-08-29 17:36:51 -04002488Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2489may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002490
2491#Subtopic Weight
Cary Clarke0403842017-09-01 19:21:29 +00002492#Alias Conic_Weights
Cary Clarkce101242017-09-01 15:51:02 -04002493#Alias Weights
Cary Clark08895c42018-02-01 09:37:32 -05002494#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002495
2496Weight determines both the strength of the control Point and the type of Conic.
2497If Weight is exactly one, then Conic is identical to Quad; it is always a
2498parabolic segment.
2499
2500
2501
2502#Example
2503#Description
Cary Clark73fa9722017-08-29 17:36:51 -04002504When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002505##
Cary Clark73fa9722017-08-29 17:36:51 -04002506void draw(SkCanvas* canvas) {
2507 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2508 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2509 SkPath path;
2510 path.conicTo(20, 30, 50, 60, 1);
2511 SkPath::Iter iter(path, false);
2512 SkPath::Verb verb;
2513 do {
2514 SkPoint points[4];
2515 verb = iter.next(points);
2516 SkDebugf("%s ", verbNames[(int) verb]);
2517 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2518 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2519 }
2520 if (SkPath::kConic_Verb == verb) {
2521 SkDebugf("weight = %g", iter.conicWeight());
2522 }
2523 SkDebugf("\n");
2524 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002525}
2526#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002527move {0, 0},
2528quad {0, 0}, {20, 30}, {50, 60},
Cary Clark8032b982017-07-28 11:04:54 -04002529done
2530##
2531##
2532
2533If weight is less than one, Conic is an elliptical segment.
2534
2535#Example
2536#Description
2537A 90 degree circular arc has the weight
2538#Formula
25391 / sqrt(2)
2540##
Cary Clark6fc50412017-09-21 12:31:06 -04002541.
Cary Clark8032b982017-07-28 11:04:54 -04002542##
Cary Clark73fa9722017-08-29 17:36:51 -04002543void draw(SkCanvas* canvas) {
2544 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2545 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2546 SkPath path;
2547 path.arcTo(20, 0, 20, 20, 20);
2548 SkPath::Iter iter(path, false);
2549 SkPath::Verb verb;
2550 do {
2551 SkPoint points[4];
2552 verb = iter.next(points);
2553 SkDebugf("%s ", verbNames[(int) verb]);
2554 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2555 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2556 }
2557 if (SkPath::kConic_Verb == verb) {
2558 SkDebugf("weight = %g", iter.conicWeight());
2559 }
2560 SkDebugf("\n");
2561 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002562}
2563#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002564move {0, 0},
2565conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark8032b982017-07-28 11:04:54 -04002566done
2567##
2568##
2569
Cary Clarkce101242017-09-01 15:51:02 -04002570If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002571a hyperbolic segment can be approximated by straight lines connecting the
2572control Point with the end Points.
2573
2574#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002575void draw(SkCanvas* canvas) {
2576 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2577 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2578 SkPath path;
2579 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2580 SkPath::Iter iter(path, false);
2581 SkPath::Verb verb;
2582 do {
2583 SkPoint points[4];
2584 verb = iter.next(points);
2585 SkDebugf("%s ", verbNames[(int) verb]);
2586 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2587 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2588 }
2589 if (SkPath::kConic_Verb == verb) {
2590 SkDebugf("weight = %g", iter.conicWeight());
2591 }
2592 SkDebugf("\n");
2593 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002594}
2595#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002596move {0, 0},
2597line {0, 0}, {20, 0},
2598line {20, 0}, {20, 20},
Cary Clark8032b982017-07-28 11:04:54 -04002599done
2600##
2601##
2602
2603#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002604
2605#Method void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2606 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002607#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002608#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002609#Line # appends Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002610
2611 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
2612 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2613 before adding Conic.
2614
2615 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2616
2617 If w is finite and not one, appends kConic_Verb to Verb_Array;
2618 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2619
2620 If w is one, appends kQuad_Verb to Verb_Array, and
2621 (x1, y1), (x2, y2) to Point_Array.
2622
2623 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2624 (x1, y1), (x2, y2) to Point_Array.
2625
2626 #Param x1 control Point of Conic in x ##
2627 #Param y1 control Point of Conic in y ##
2628 #Param x2 end Point of Conic in x ##
2629 #Param y2 end Point of Conic in y ##
2630 #Param w weight of added Conic ##
2631
2632 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002633 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002634 #Description
2635 As weight increases, curve is pulled towards control point.
2636 The bottom two curves are elliptical; the next is parabolic; the
2637 top curve is hyperbolic.
2638 ##
2639void draw(SkCanvas* canvas) {
2640 SkPaint paint;
2641 paint.setAntiAlias(true);
2642 paint.setStyle(SkPaint::kStroke_Style);
2643 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2644 canvas->drawLine(conicPts[0], conicPts[1], paint);
2645 canvas->drawLine(conicPts[1], conicPts[2], paint);
2646 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2647 paint.setStrokeWidth(3);
2648 SkScalar weight = 0.5f;
2649 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2650 SkPath path;
2651 path.moveTo(conicPts[0]);
2652 path.conicTo(conicPts[1], conicPts[2], weight);
2653 paint.setColor(colors[i]);
2654 canvas->drawPath(path, paint);
2655 weight += 0.25f;
2656 }
2657}
2658 ##
2659
2660 #SeeAlso rConicTo arcTo addArc quadTo
2661
2662##
2663
2664#Method void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002665#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002666#In Conic
Cary Clark73fa9722017-08-29 17:36:51 -04002667 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
2668 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2669 before adding Conic.
2670
2671 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2672
2673 If w is finite and not one, appends kConic_Verb to Verb_Array;
2674 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2675
2676 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2677 to Point_Array.
2678
2679 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2680 Points p1, p2 to Point_Array.
2681
2682 #Param p1 control Point of added Conic ##
2683 #Param p2 end Point of added Conic ##
2684 #Param w weight of added Conic ##
2685
2686 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002687 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002688 #Description
2689 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002690 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002691 ##
2692void draw(SkCanvas* canvas) {
2693 SkPaint paint;
2694 paint.setAntiAlias(true);
2695 paint.setStyle(SkPaint::kStroke_Style);
2696 SkRect oval = {0, 20, 120, 140};
2697 SkPath path;
2698 for (int i = 0; i < 4; ++i) {
2699 path.moveTo(oval.centerX(), oval.fTop);
2700 path.arcTo(oval, -90, 90 - 20 * i, false);
2701 oval.inset(15, 15);
2702 }
2703 path.offset(100, 0);
2704 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2705 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2706 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2707 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2708 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2709 for (int i = 0; i < 4; ++i) {
2710 path.moveTo(conicPts[i][0]);
2711 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2712 }
2713 canvas->drawPath(path, paint);
2714}
2715 ##
2716
2717 #SeeAlso rConicTo arcTo addArc quadTo
2718
2719##
2720
2721#Method void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2722 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002723#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002724#In Conic
2725#Line # appends Conic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002726
2727 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2728 weighted by w. If Path is empty, or last Verb
2729 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2730
2731 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2732 if needed.
2733
2734 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2735 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2736 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2737 twice to Verb_Array.
2738
2739 In all cases appends Points control and end to Point_Array.
2740 control is Last_Point plus Vector (dx1, dy1).
2741 end is Last_Point plus Vector (dx2, dy2).
2742
Cary Clarkce101242017-09-01 15:51:02 -04002743 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002744
2745 #Param dx1 offset from Last_Point x to Conic control x ##
2746 #Param dy1 offset from Last_Point x to Conic control y ##
2747 #Param dx2 offset from Last_Point x to Conic end x ##
2748 #Param dy2 offset from Last_Point x to Conic end y ##
2749 #Param w weight of added Conic ##
2750
2751 #Example
2752 #Height 140
2753 void draw(SkCanvas* canvas) {
2754 SkPaint paint;
2755 paint.setAntiAlias(true);
2756 paint.setStyle(SkPaint::kStroke_Style);
2757 SkPath path;
2758 path.moveTo(20, 80);
2759 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2760 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2761 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2762 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2763 canvas->drawPath(path, paint);
2764 }
2765 ##
2766
2767 #SeeAlso conicTo arcTo addArc quadTo
2768
2769##
2770
Cary Clark78de7512018-02-07 07:27:09 -05002771#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002772
2773# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002774#Subtopic Cubic
Cary Clarkce101242017-09-01 15:51:02 -04002775#Alias Cubic
Cary Clark8032b982017-07-28 11:04:54 -04002776#Alias Cubics
Cary Clarkce101242017-09-01 15:51:02 -04002777#Alias Cubic_Bezier
2778#Alias Cubic_Beziers
Cary Clark08895c42018-02-01 09:37:32 -05002779#Line # Bezier_Curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002780
Cary Clarka560c472017-11-27 10:44:06 -05002781Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002782Cubic begins at a start Point, curving towards the first control Point;
2783and curves from the end Point towards the second control Point.
2784
2785#Example
2786#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002787void draw(SkCanvas* canvas) {
2788 SkPaint paint;
2789 paint.setAntiAlias(true);
2790 paint.setStyle(SkPaint::kStroke_Style);
2791 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2792 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2793 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2794 paint.setColor(0x7fffffff & colors[i]);
2795 paint.setStrokeWidth(1);
2796 for (unsigned j = 0; j < 3; ++j) {
2797 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2798 }
2799 SkPath path;
2800 path.moveTo(cubicPts[0]);
2801 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2802 paint.setStrokeWidth(3);
2803 paint.setColor(colors[i]);
2804 canvas->drawPath(path, paint);
2805 cubicPts[1].fY += 30;
2806 cubicPts[2].fX += 30;
2807 }
Cary Clark8032b982017-07-28 11:04:54 -04002808}
2809##
Cary Clark73fa9722017-08-29 17:36:51 -04002810
2811#Method void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2812 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002813#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002814#In Cubic
2815#Line # appends Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002816
2817Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2818(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2819(0, 0) before adding Cubic.
2820
2821Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2822then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
2823to Point_Array.
2824
2825#Param x1 first control Point of Cubic in x ##
2826#Param y1 first control Point of Cubic in y ##
2827#Param x2 second control Point of Cubic in x ##
2828#Param y2 second control Point of Cubic in y ##
2829#Param x3 end Point of Cubic in x ##
2830#Param y3 end Point of Cubic in y ##
2831
2832#Example
2833void draw(SkCanvas* canvas) {
2834 SkPaint paint;
2835 paint.setAntiAlias(true);
2836 paint.setStyle(SkPaint::kStroke_Style);
2837 SkPath path;
2838 path.moveTo(0, -10);
2839 for (int i = 0; i < 128; i += 16) {
2840 SkScalar c = i * 0.5f;
2841 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2842 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2843 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2844 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2845 }
2846 path.offset(128, 128);
2847 canvas->drawPath(path, paint);
2848}
2849##
2850
2851#SeeAlso Contour moveTo rCubicTo quadTo
2852
2853##
2854
2855# ------------------------------------------------------------------------------
2856
2857#Method void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
2858
Cary Clark4855f782018-02-06 09:41:53 -05002859#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002860#In Cubic
Cary Clark73fa9722017-08-29 17:36:51 -04002861Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2862Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2863(0, 0) before adding Cubic.
2864
2865Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2866then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2867to Point_Array.
2868
2869#Param p1 first control Point of Cubic ##
2870#Param p2 second control Point of Cubic ##
2871#Param p3 end Point of Cubic ##
2872
2873#Example
2874#Height 84
2875 SkPaint paint;
2876 paint.setAntiAlias(true);
2877 paint.setStyle(SkPaint::kStroke_Style);
2878 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2879 SkPath path;
2880 path.moveTo(pts[0]);
2881 path.cubicTo(pts[1], pts[2], pts[3]);
2882 canvas->drawPath(path, paint);
2883##
2884
2885#SeeAlso Contour moveTo rCubicTo quadTo
2886
2887##
2888
2889# ------------------------------------------------------------------------------
2890
2891#Method void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2892 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002893#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002894#In Cubic
2895#Line # appends Cubic relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002896
2897 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2898 Vector (dx2, dy2), to Vector (dx3, dy3).
2899 If Path is empty, or last Verb
2900 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2901
2902 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2903 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2904 control and Cubic end to Point_Array.
2905 Cubic control is Last_Point plus Vector (dx1, dy1).
2906 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002907 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002908
2909 #Param x1 offset from Last_Point x to first Cubic control x ##
2910 #Param y1 offset from Last_Point x to first Cubic control y ##
2911 #Param x2 offset from Last_Point x to second Cubic control x ##
2912 #Param y2 offset from Last_Point x to second Cubic control y ##
2913 #Param x3 offset from Last_Point x to Cubic end x ##
2914 #Param y3 offset from Last_Point x to Cubic end y ##
2915
2916#Example
2917 void draw(SkCanvas* canvas) {
2918 SkPaint paint;
2919 paint.setAntiAlias(true);
2920 paint.setStyle(SkPaint::kStroke_Style);
2921 SkPath path;
2922 path.moveTo(24, 108);
2923 for (int i = 0; i < 16; i++) {
2924 SkScalar sx, sy;
2925 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2926 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2927 }
2928 canvas->drawPath(path, paint);
2929 }
2930##
2931
2932#SeeAlso Contour moveTo cubicTo quadTo
2933
2934##
2935
Cary Clark78de7512018-02-07 07:27:09 -05002936#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002937
2938# ------------------------------------------------------------------------------
2939
Cary Clark08895c42018-02-01 09:37:32 -05002940#Subtopic Arc
2941#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04002942Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
2943by start point and end point, and by radius and tangent lines. Each construction has advantages,
2944and some constructions correspond to Arc drawing in graphics standards.
2945
2946All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
2947Conic describes an Arc of some Oval or Circle.
2948
2949arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
2950describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
2951which may continue Contour or start a new one. This construction is similar to PostScript and
2952HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
2953requiring Path.
2954
2955arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
2956describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
2957where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
2958HTML_Canvas arcs.
2959
2960arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
2961 SkScalar x, SkScalar y)
2962describes Arc as part of Oval with radii (rx, ry), beginning at
2963last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
2964so additional values choose a single solution. This construction is similar to SVG arcs.
2965
2966conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
2967conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
2968constructions are converted to Conic data when added to Path.
2969
2970#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
2971 do the kind of table shown in the illustration.
2972 example is spaced correctly on fiddle but spacing is too wide on pc
2973##
2974
2975#Example
2976#Height 300
2977#Width 600
2978#Description
2979#List
2980# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
2981# <sup>2</sup> parameter sets force MoveTo ##
Cary Clark5081eed2018-01-22 07:55:48 -05002982# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04002983# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
2984# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
2985 Direction sweep, SkScalar x, SkScalar y) ##
2986#List ##
2987#Description ##
2988#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05002989###$
Cary Clark73fa9722017-08-29 17:36:51 -04002990struct data {
2991 const char* name;
2992 char super;
2993 int yn[10];
2994};
2995
2996const data dataSet[] = {
2997{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
2998{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
2999{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
3000{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
3001{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
3002{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
3003};
3004
3005#define __degree_symbol__ "\xC2" "\xB0"
3006
3007const char* headers[] = {
3008 "Oval part",
3009 "force moveTo",
3010 "can draw 180" __degree_symbol__,
3011 "can draw 360" __degree_symbol__,
3012 "can draw greater than 360" __degree_symbol__,
3013 "ignored if radius is zero",
3014 "ignored if sweep is zero",
3015 "requires Path",
3016 "describes rotation",
3017 "describes perspective",
3018};
3019
3020const char* yna[] = {
3021 "n/a",
3022 "no",
3023 "yes"
3024};
Cary Clark1a8d7622018-03-05 13:26:16 -05003025$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003026##
3027void draw(SkCanvas* canvas) {
3028 SkPaint lp;
3029 lp.setAntiAlias(true);
3030 SkPaint tp(lp);
3031 SkPaint sp(tp);
3032 SkPaint bp(tp);
3033 bp.setFakeBoldText(true);
3034 sp.setTextSize(10);
3035 lp.setColor(SK_ColorGRAY);
3036 canvas->translate(0, 32);
3037 const int tl = 115;
3038 for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
3039 canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
3040 if (0 == col) {
3041 continue;
3042 }
3043 canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
3044 SkPath path;
3045 path.moveTo(tl - 3 + col * 35, 103);
3046 path.lineTo(tl + 124 + col * 35, -24);
3047 canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
3048 }
3049 for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
3050 if (0 == row) {
3051 canvas->drawLine(tl, 100, tl + 350, 100, lp);
3052 } else {
3053 canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
3054 }
3055 if (row == SK_ARRAY_COUNT(dataSet)) {
3056 break;
3057 }
3058 canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
3059 if (dataSet[row].super) {
3060 SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
3061 canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
3062 }
3063 for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
3064 int val = dataSet[row].yn[col];
3065 canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
3066 if (val > 1) {
3067 char supe = '0' + val - 1;
3068 canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
3069 }
3070 }
3071 }
3072}
3073#Example ##
3074
3075#Example
3076#Height 128
3077#Description
3078#ToDo make this a list or table ##
30791 describes an arc from an oval, a starting angle, and a sweep angle.
30802 is similar to 1, but does not require building a path to draw.
30813 is similar to 1, but always begins new Contour.
30824 describes an arc from a pair of tangent lines and a radius.
30835 describes an arc from Oval center, arc start Point and arc end Point.
30846 describes an arc from a pair of tangent lines and a Conic_Weight.
3085##
3086void draw(SkCanvas* canvas) {
3087 SkRect oval = {8, 8, 56, 56};
3088 SkPaint ovalPaint;
3089 ovalPaint.setAntiAlias(true);
3090 SkPaint textPaint(ovalPaint);
3091 ovalPaint.setStyle(SkPaint::kStroke_Style);
3092 SkPaint arcPaint(ovalPaint);
3093 arcPaint.setStrokeWidth(5);
3094 arcPaint.setColor(SK_ColorBLUE);
3095 canvas->translate(-64, 0);
3096 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3097 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3098 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3099 canvas->drawOval(oval, ovalPaint);
3100 SkPath path;
3101 path.moveTo({56, 32});
3102 switch (arcStyle) {
3103 case '1':
3104 path.arcTo(oval, 0, 90, false);
3105 break;
3106 case '2':
3107 canvas->drawArc(oval, 0, 90, false, arcPaint);
3108 continue;
3109 case '3':
3110 path.addArc(oval, 0, 90);
3111 break;
3112 case '4':
3113 path.arcTo({56, 56}, {32, 56}, 24);
3114 break;
3115 case '5':
3116 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3117 break;
3118 case '6':
3119 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3120 break;
3121 }
3122 canvas->drawPath(path, arcPaint);
3123 }
3124}
3125#Example ##
3126
3127
3128#Method void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05003129#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003130#In Arc
3131#Line # appends Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003132Append Arc to Path. Arc added is part of ellipse
3133bounded by oval, from startAngle through sweepAngle. Both startAngle and
3134sweepAngle are measured in degrees, where zero degrees is aligned with the
3135positive x-axis, and positive sweeps extends Arc clockwise.
3136
3137arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3138is false and Path is not empty. Otherwise, added Contour begins with first point
3139of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3140
3141#Param oval bounds of ellipse containing Arc ##
3142#Param startAngle starting angle of Arc in degrees ##
3143#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3144#Param forceMoveTo true to start a new contour with Arc ##
3145
3146#Example
3147#Height 200
3148#Description
3149arcTo continues a previous contour when forceMoveTo is false and when Path
3150is not empty.
3151##
3152void draw(SkCanvas* canvas) {
3153 SkPaint paint;
3154 SkPath path;
3155 paint.setStyle(SkPaint::kStroke_Style);
3156 paint.setStrokeWidth(4);
3157 path.moveTo(0, 0);
3158 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3159 canvas->drawPath(path, paint);
3160 path.rewind();
3161 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3162 canvas->drawPath(path, paint);
3163 path.rewind();
3164 path.moveTo(0, 0);
3165 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3166 canvas->drawPath(path, paint);
3167}
3168##
3169
3170#SeeAlso addArc SkCanvas::drawArc conicTo
3171
3172##
3173
3174# ------------------------------------------------------------------------------
3175
3176#Method void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003177#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003178#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003179Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3180weighted to describe part of Circle. Arc is contained by tangent from
3181last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
3182is part of Circle sized to radius, positioned so it touches both tangent lines.
3183
3184#ToDo allow example to hide source and not be exposed as fiddle ##
3185
3186#Example
3187#Height 226
3188void draw(SkCanvas* canvas) {
3189 SkPaint tangentPaint;
3190 tangentPaint.setAntiAlias(true);
3191 SkPaint textPaint(tangentPaint);
3192 tangentPaint.setStyle(SkPaint::kStroke_Style);
3193 tangentPaint.setColor(SK_ColorGRAY);
3194 SkPaint arcPaint(tangentPaint);
3195 arcPaint.setStrokeWidth(5);
3196 arcPaint.setColor(SK_ColorBLUE);
3197 SkPath path;
3198 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3199 SkScalar radius = 50;
3200 path.moveTo(pts[0]);
3201 path.arcTo(pts[1], pts[2], radius);
3202 canvas->drawLine(pts[0], pts[1], tangentPaint);
3203 canvas->drawLine(pts[1], pts[2], tangentPaint);
3204 SkPoint lastPt;
3205 (void) path.getLastPt(&lastPt);
3206 SkVector radial = pts[2] - pts[1];
3207 radial.setLength(radius);
3208 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3209 canvas->drawCircle(center, radius, tangentPaint);
3210 canvas->drawLine(lastPt, center, tangentPaint);
3211 radial = pts[1] - pts[0];
3212 radial.setLength(radius);
3213 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3214 canvas->drawLine(center, arcStart, tangentPaint);
3215 canvas->drawPath(path, arcPaint);
3216 textPaint.setTextAlign(SkPaint::kRight_Align);
3217 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3218 textPaint.setTextAlign(SkPaint::kLeft_Align);
3219 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3220 textPaint.setTextAlign(SkPaint::kCenter_Align);
3221 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3222 textPaint.setTextAlign(SkPaint::kRight_Align);
3223 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3224 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3225}
3226##
3227
3228If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3229The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3230
3231#Example
3232#Height 128
3233void draw(SkCanvas* canvas) {
3234 SkPaint tangentPaint;
3235 tangentPaint.setAntiAlias(true);
3236 SkPaint textPaint(tangentPaint);
3237 tangentPaint.setStyle(SkPaint::kStroke_Style);
3238 tangentPaint.setColor(SK_ColorGRAY);
3239 SkPaint arcPaint(tangentPaint);
3240 arcPaint.setStrokeWidth(5);
3241 arcPaint.setColor(SK_ColorBLUE);
3242 SkPath path;
3243 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3244 SkScalar radius = 50;
3245 path.moveTo(pts[0]);
3246 path.arcTo(pts[1], pts[2], radius);
3247 canvas->drawLine(pts[0], pts[1], tangentPaint);
3248 canvas->drawLine(pts[1], pts[2], tangentPaint);
3249 SkPoint lastPt;
3250 (void) path.getLastPt(&lastPt);
3251 SkVector radial = pts[2] - pts[1];
3252 radial.setLength(radius);
3253 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3254 canvas->drawLine(lastPt, center, tangentPaint);
3255 radial = pts[1] - pts[0];
3256 radial.setLength(radius);
3257 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3258 canvas->drawLine(center, arcStart, tangentPaint);
3259 canvas->drawPath(path, arcPaint);
3260 textPaint.setTextAlign(SkPaint::kCenter_Align);
3261 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3262 textPaint.setTextAlign(SkPaint::kLeft_Align);
3263 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3264 textPaint.setTextAlign(SkPaint::kCenter_Align);
3265 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3266 textPaint.setTextAlign(SkPaint::kRight_Align);
3267 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3268 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3269}
3270##
3271
3272Arc sweep is always less than 180 degrees. If radius is zero, or if
3273tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3274
3275arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003276arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003277
3278#Param x1 x common to pair of tangents ##
3279#Param y1 y common to pair of tangents ##
3280#Param x2 x end of second tangent ##
3281#Param y2 y end of second tangent ##
3282#Param radius distance from Arc to Circle center ##
3283
3284#Example
3285#Description
3286arcTo is represented by Line and circular Conic in Path.
3287##
3288void draw(SkCanvas* canvas) {
3289 SkPath path;
3290 path.moveTo({156, 20});
3291 path.arcTo(200, 20, 170, 50, 50);
3292 SkPath::Iter iter(path, false);
3293 SkPoint p[4];
3294 SkPath::Verb verb;
3295 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3296 switch (verb) {
3297 case SkPath::kMove_Verb:
3298 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3299 break;
3300 case SkPath::kLine_Verb:
3301 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3302 break;
3303 case SkPath::kConic_Verb:
3304 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3305 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3306 break;
3307 default:
3308 SkDebugf("unexpected verb\n");
3309 }
3310 }
3311}
3312#StdOut
3313move to (156,20)
3314line (156,20),(79.2893,20)
3315conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3316##
3317##
3318
3319#SeeAlso conicTo
3320
3321##
3322
3323# ------------------------------------------------------------------------------
3324
3325#Method void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05003326#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003327#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003328Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3329weighted to describe part of Circle. Arc is contained by tangent from
3330last Path point to p1, and tangent from p1 to p2. Arc
3331is part of Circle sized to radius, positioned so it touches both tangent lines.
3332
3333If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3334The length of Vector from p1 to p2 does not affect Arc.
3335
3336Arc sweep is always less than 180 degrees. If radius is zero, or if
3337tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3338
3339arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003340arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003341
3342#Param p1 Point common to pair of tangents ##
3343#Param p2 end of second tangent ##
3344#Param radius distance from Arc to Circle center ##
3345
3346#Example
3347#Description
3348Because tangent lines are parallel, arcTo appends line from last Path Point to
3349p1, but does not append a circular Conic.
3350##
3351void draw(SkCanvas* canvas) {
3352 SkPath path;
3353 path.moveTo({156, 20});
3354 path.arcTo({200, 20}, {170, 20}, 50);
3355 SkPath::Iter iter(path, false);
3356 SkPoint p[4];
3357 SkPath::Verb verb;
3358 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3359 switch (verb) {
3360 case SkPath::kMove_Verb:
3361 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3362 break;
3363 case SkPath::kLine_Verb:
3364 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3365 break;
3366 case SkPath::kConic_Verb:
3367 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3368 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3369 break;
3370 default:
3371 SkDebugf("unexpected verb\n");
3372 }
3373 }
3374}
3375#StdOut
3376move to (156,20)
3377line (156,20),(200,20)
3378##
3379##
3380
3381#SeeAlso conicTo
3382
3383##
3384
3385# ------------------------------------------------------------------------------
3386
3387#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05003388#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04003389
3390#Code
3391 enum ArcSize {
3392 kSmall_ArcSize,
3393 kLarge_ArcSize,
3394 };
3395##
3396
3397Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3398ArcSize and Direction select one of the four Oval parts.
3399
3400#Const kSmall_ArcSize 0
Cary Clark154beea2017-10-26 07:58:48 -04003401smaller of Arc pair
Cary Clark73fa9722017-08-29 17:36:51 -04003402##
3403#Const kLarge_ArcSize 1
Cary Clark154beea2017-10-26 07:58:48 -04003404larger of Arc pair
Cary Clark73fa9722017-08-29 17:36:51 -04003405##
3406
3407#Example
3408#Height 160
3409#Description
3410Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3411Two routes are large, and two routes are counterclockwise. The one route both large
3412and counterclockwise is blue.
3413##
3414void draw(SkCanvas* canvas) {
3415 SkPaint paint;
3416 paint.setAntiAlias(true);
3417 paint.setStyle(SkPaint::kStroke_Style);
3418 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3419 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3420 SkPath path;
3421 path.moveTo({120, 50});
3422 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3423 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3424 paint.setColor(SK_ColorBLUE);
3425 paint.setStrokeWidth(3);
3426 }
3427 canvas->drawPath(path, paint);
3428 }
3429 }
3430}
3431##
3432
3433#SeeAlso arcTo Direction
3434
3435##
3436
3437# ------------------------------------------------------------------------------
3438
3439#Method void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3440 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003441#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003442#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003443
Cary Clark154beea2017-10-26 07:58:48 -04003444Append Arc to Path. Arc is implemented by one or more Conics weighted to
3445describe part of Oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
3446curves from last Path Point to (x, y), choosing one of four possible routes:
3447clockwise or counterclockwise, and smaller or larger.
Cary Clark73fa9722017-08-29 17:36:51 -04003448
Cary Clark154beea2017-10-26 07:58:48 -04003449Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if
3450either radii are zero, or if last Path Point equals (x, y). arcTo scales radii
3451(rx, ry) to fit last Path Point and (x, y) if both are greater than zero but
3452too small.
Cary Clark73fa9722017-08-29 17:36:51 -04003453
3454arcTo appends up to four Conic curves.
Cary Clark154beea2017-10-26 07:58:48 -04003455arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value
3456is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise,
3457while kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003458
3459#Param rx radius in x before x-axis rotation ##
3460#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003461#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003462#Param largeArc chooses smaller or larger Arc ##
3463#Param sweep chooses clockwise or counterclockwise Arc ##
3464#Param x end of Arc ##
3465#Param y end of Arc ##
3466
3467#Example
3468#Height 160
3469void draw(SkCanvas* canvas) {
3470 SkPaint paint;
3471 paint.setAntiAlias(true);
3472 paint.setStyle(SkPaint::kStroke_Style);
3473 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3474 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3475 SkPath path;
3476 path.moveTo({120, 50});
3477 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3478 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3479 paint.setColor(SK_ColorBLUE);
3480 paint.setStrokeWidth(3);
3481 }
3482 canvas->drawPath(path, paint);
3483 }
3484 }
3485}
3486##
3487
3488#SeeAlso rArcTo ArcSize Direction
3489
3490##
3491
3492# ------------------------------------------------------------------------------
3493
3494#Method void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
3495 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05003496#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003497#In Arc
Cary Clark73fa9722017-08-29 17:36:51 -04003498
3499Append Arc to Path. Arc is implemented by one or more Conic weighted to describe part of Oval
3500with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last Path Point to
3501(xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise,
3502and smaller or larger.
3503
3504Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either radii are zero,
3505or if last Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
Cary Clarkce101242017-09-01 15:51:02 -04003506xy if both are greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003507
3508arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003509arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3510opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3511kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003512
3513#Param r radii in x and y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003514#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003515#Param largeArc chooses smaller or larger Arc ##
3516#Param sweep chooses clockwise or counterclockwise Arc ##
3517#Param xy end of Arc ##
3518
3519#Example
3520#Height 108
3521void draw(SkCanvas* canvas) {
3522 SkPaint paint;
3523 SkPath path;
3524 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3525 for (auto start : starts) {
3526 path.moveTo(start.fX, start.fY);
3527 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3528 }
3529 canvas->drawPath(path, paint);
3530}
3531##
3532
3533#SeeAlso rArcTo ArcSize Direction
3534
3535##
3536
3537# ------------------------------------------------------------------------------
3538
3539#Method void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3540 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003541#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003542#In Arc
3543#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04003544
3545Append Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003546more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04003547xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
3548
Cary Clark73fa9722017-08-29 17:36:51 -04003549#Formula
3550(x0 + dx, y0 + dy)
3551##
3552, choosing one of four possible routes: clockwise or
3553counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3554is (0, 0).
3555
Cary Clarkce101242017-09-01 15:51:02 -04003556Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3557if either radii are zero, or if last Path Point equals end Point.
3558arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3559greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003560
3561arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003562arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3563opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003564kCW_Direction cast to int is zero.
3565
3566#Param rx radius in x before x-axis rotation ##
3567#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003568#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003569#Param largeArc chooses smaller or larger Arc ##
3570#Param sweep chooses clockwise or counterclockwise Arc ##
3571#Param dx x offset end of Arc from last Path Point ##
3572#Param dy y offset end of Arc from last Path Point ##
3573
3574#Example
3575#Height 108
3576void draw(SkCanvas* canvas) {
3577 SkPaint paint;
3578 SkPath path;
3579 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3580 for (auto start : starts) {
3581 path.moveTo(start.fX, start.fY);
3582 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3583 }
3584 canvas->drawPath(path, paint);
3585}
3586##
3587
3588#SeeAlso arcTo ArcSize Direction
3589
3590##
3591
Cary Clark78de7512018-02-07 07:27:09 -05003592#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04003593
3594# ------------------------------------------------------------------------------
3595
3596#Method void close()
Cary Clark4855f782018-02-06 09:41:53 -05003597#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003598#Line # makes last Contour a loop ##
Cary Clark73fa9722017-08-29 17:36:51 -04003599Append kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003600with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003601with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
3602Paint_Stroke_Cap at Contour start and end; closed Contour draws
3603Paint_Stroke_Join at Contour start and end.
3604
3605close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3606
3607#Example
3608void draw(SkCanvas* canvas) {
3609 SkPaint paint;
3610 paint.setStrokeWidth(15);
3611 paint.setStrokeCap(SkPaint::kRound_Cap);
3612 SkPath path;
3613 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3614 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3615 for (int loop = 0; loop < 2; ++loop) {
3616 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3617 SkPaint::kStrokeAndFill_Style} ) {
3618 paint.setStyle(style);
3619 canvas->drawPath(path, paint);
3620 canvas->translate(85, 0);
3621 }
3622 path.close();
3623 canvas->translate(-255, 128);
3624 }
3625}
3626##
3627
3628#SeeAlso
3629
3630##
3631
3632# ------------------------------------------------------------------------------
3633
3634#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003635#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003636#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003637Returns true if fill is inverted and Path with fill represents area outside
3638of its geometric bounds.
3639
3640#Table
3641#Legend
3642# FillType # is inverse ##
3643##
3644# kWinding_FillType # false ##
3645# kEvenOdd_FillType # false ##
3646# kInverseWinding_FillType # true ##
3647# kInverseEvenOdd_FillType # true ##
3648##
3649
3650#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3651 kInverseWinding_FillType, kInverseEvenOdd_FillType
3652##
3653
3654#Return true if Path fills outside its bounds ##
3655
3656#Example
3657#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003658###$
Cary Clark73fa9722017-08-29 17:36:51 -04003659#define nameValue(fill) { SkPath::fill, #fill }
3660
Cary Clark1a8d7622018-03-05 13:26:16 -05003661$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003662##
3663void draw(SkCanvas* canvas) {
3664 struct {
3665 SkPath::FillType fill;
3666 const char* name;
3667 } fills[] = {
3668 nameValue(kWinding_FillType),
3669 nameValue(kEvenOdd_FillType),
3670 nameValue(kInverseWinding_FillType),
3671 nameValue(kInverseEvenOdd_FillType),
3672 };
3673 for (auto fill: fills ) {
3674 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3675 "true" : "false");
3676 }
3677}
3678#StdOut
3679IsInverseFillType(kWinding_FillType) == false
3680IsInverseFillType(kEvenOdd_FillType) == false
3681IsInverseFillType(kInverseWinding_FillType) == true
3682IsInverseFillType(kInverseEvenOdd_FillType) == true
3683##
3684##
3685
3686#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3687
3688##
3689
3690# ------------------------------------------------------------------------------
3691
3692#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05003693#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003694#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04003695Returns equivalent Fill_Type representing Path fill inside its bounds.
3696.
3697
3698#Table
3699#Legend
3700# FillType # inside FillType ##
3701##
3702# kWinding_FillType # kWinding_FillType ##
3703# kEvenOdd_FillType # kEvenOdd_FillType ##
3704# kInverseWinding_FillType # kWinding_FillType ##
3705# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3706##
3707
3708#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3709 kInverseWinding_FillType, kInverseEvenOdd_FillType
3710##
3711
3712#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3713
3714#Example
3715#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05003716###$
Cary Clark73fa9722017-08-29 17:36:51 -04003717#define nameValue(fill) { SkPath::fill, #fill }
3718
Cary Clark1a8d7622018-03-05 13:26:16 -05003719$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04003720##
3721void draw(SkCanvas* canvas) {
3722 struct {
3723 SkPath::FillType fill;
3724 const char* name;
3725 } fills[] = {
3726 nameValue(kWinding_FillType),
3727 nameValue(kEvenOdd_FillType),
3728 nameValue(kInverseWinding_FillType),
3729 nameValue(kInverseEvenOdd_FillType),
3730 };
3731 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3732 if (fills[i].fill != (SkPath::FillType) i) {
3733 SkDebugf("fills array order does not match FillType enum order");
3734 break;
3735 }
3736 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3737 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3738 }
3739}
3740#StdOut
3741ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3742ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3743ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3744ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3745##
3746##
3747
3748#SeeAlso FillType getFillType setFillType IsInverseFillType
3749
3750##
3751
3752# ------------------------------------------------------------------------------
3753
3754#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3755 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05003756#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003757#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04003758
3759Approximates Conic with Quad array. Conic is constructed from start Point p0,
3760control Point p1, end Point p2, and weight w.
3761Quad array is stored in pts; this storage is supplied by caller.
3762Maximum Quad count is 2 to the pow2.
3763Every third point in array shares last Point of previous Quad and first Point of
3764next Quad. Maximum pts storage size is given by:
3765#Formula
3766(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
3767##
Cary Clark154beea2017-10-26 07:58:48 -04003768.
Cary Clark6fc50412017-09-21 12:31:06 -04003769
Cary Clark154beea2017-10-26 07:58:48 -04003770Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04003771than the number requested.
3772
3773Conic_Weight determines the amount of influence Conic control point has on the curve.
3774w less than one represents an elliptical section. w greater than one represents
3775a hyperbolic section. w equal to one represents a parabolic section.
3776
3777Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3778of up to 90 degrees; in this case, set pow2 to one.
3779
3780#Param p0 Conic start Point ##
3781#Param p1 Conic control Point ##
3782#Param p2 Conic end Point ##
3783#Param w Conic weight ##
3784#Param pts storage for Quad array ##
3785#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3786
Cary Clarka523d2d2017-08-30 08:58:10 -04003787#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003788
3789#Example
3790#Description
3791A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3792The middle curve is nearly circular. The top-right curve is parabolic, which can
3793be drawn exactly with a single Quad.
3794##
3795void draw(SkCanvas* canvas) {
3796 SkPaint conicPaint;
3797 conicPaint.setAntiAlias(true);
3798 conicPaint.setStyle(SkPaint::kStroke_Style);
3799 SkPaint quadPaint(conicPaint);
3800 quadPaint.setColor(SK_ColorRED);
3801 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3802 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3803 SkPoint quads[5];
3804 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3805 SkPath path;
3806 path.moveTo(conic[0]);
3807 path.conicTo(conic[1], conic[2], weight);
3808 canvas->drawPath(path, conicPaint);
3809 path.rewind();
3810 path.moveTo(quads[0]);
3811 path.quadTo(quads[1], quads[2]);
3812 path.quadTo(quads[3], quads[4]);
3813 canvas->drawPath(path, quadPaint);
3814 canvas->translate(50, -50);
3815 }
3816}
3817##
3818
3819#SeeAlso Conic Quad
3820
3821##
3822
3823# ------------------------------------------------------------------------------
3824
3825#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003826#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003827#Line # returns if describes Rect ##
Cary Clarkce101242017-09-01 15:51:02 -04003828Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003829If false: rect, isClosed, and direction are unchanged.
3830If true: rect, isClosed, and direction are written to if not nullptr.
3831
3832rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3833that do not alter the area drawn by the returned rect.
3834
3835#Param rect storage for bounds of Rect; may be nullptr ##
3836#Param isClosed storage set to true if Path is closed; may be nullptr ##
3837#Param direction storage set to Rect direction; may be nullptr ##
3838
3839#Return true if Path contains Rect ##
3840
3841#Example
3842#Description
3843After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3844following lineTo does not. addPoly returns true even though rect is not closed, and one
3845side of rect is made up of consecutive line segments.
3846##
3847void draw(SkCanvas* canvas) {
3848 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3849 SkRect rect;
3850 SkPath::Direction direction;
3851 bool isClosed;
3852 path.isRect(&rect, &isClosed, &direction) ?
3853 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3854 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3855 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3856 SkDebugf("%s is not rect\n", prefix);
3857 };
3858 SkPath path;
3859 debugster("empty", path);
3860 path.addRect({10, 20, 30, 40});
3861 debugster("addRect", path);
3862 path.moveTo(60, 70);
3863 debugster("moveTo", path);
3864 path.lineTo(60, 70);
3865 debugster("lineTo", path);
3866 path.reset();
3867 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3868 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3869 debugster("addPoly", path);
3870}
3871#StdOut
3872empty is not rect
3873addRect is rect (10, 20, 30, 40); is closed; direction CW
3874moveTo is rect (10, 20, 30, 40); is closed; direction CW
3875lineTo is not rect
3876addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3877##
3878##
3879
3880#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3881
3882##
3883
3884# ------------------------------------------------------------------------------
3885
3886#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003887#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003888#Line # returns if describes Rect pair, one inside the other ##
Cary Clark73fa9722017-08-29 17:36:51 -04003889Returns true if Path is equivalent to nested Rect pair when filled.
3890If false, rect and dirs are unchanged.
3891If true, rect and dirs are written to if not nullptr:
3892setting rect[0] to outer Rect, and rect[1] to inner Rect;
3893setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3894Rect.
3895
3896#Param rect storage for Rect pair; may be nullptr ##
3897#Param dirs storage for Direction pair; may be nullptr ##
3898
3899#Return true if Path contains nested Rect pair ##
3900
3901#Example
3902void draw(SkCanvas* canvas) {
3903 SkPaint paint;
3904 paint.setStyle(SkPaint::kStroke_Style);
3905 paint.setStrokeWidth(5);
3906 SkPath path;
3907 path.addRect({10, 20, 30, 40});
3908 paint.getFillPath(path, &path);
3909 SkRect rects[2];
3910 SkPath::Direction directions[2];
3911 if (path.isNestedFillRects(rects, directions)) {
3912 for (int i = 0; i < 2; ++i) {
3913 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3914 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3915 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3916 }
3917 } else {
3918 SkDebugf("is not nested rectangles\n");
3919 }
3920}
3921#StdOut
3922outer (7.5, 17.5, 32.5, 42.5); direction CW
3923inner (12.5, 22.5, 27.5, 37.5); direction CCW
3924##
3925##
3926
3927#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3928
3929##
3930
3931# ------------------------------------------------------------------------------
3932
3933#Method void addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003934#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003935#Line # adds one Contour containing Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04003936Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
3937starting with top-left corner of Rect; followed by top-right, bottom-right,
3938and bottom-left if dir is kCW_Direction; or followed by bottom-left,
3939bottom-right, and top-right if dir is kCCW_Direction.
3940
3941#Param rect Rect to add as a closed contour ##
3942#Param dir Direction to wind added contour ##
3943
3944#Example
3945#Description
3946The left Rect dashes starting at the top-left corner, to the right.
3947The right Rect dashes starting at the top-left corner, towards the bottom.
3948##
3949#Height 128
3950void draw(SkCanvas* canvas) {
3951 SkPaint paint;
3952 paint.setStrokeWidth(15);
3953 paint.setStrokeCap(SkPaint::kSquare_Cap);
3954 float intervals[] = { 5, 21.75f };
3955 paint.setStyle(SkPaint::kStroke_Style);
3956 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3957 SkPath path;
3958 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
3959 canvas->drawPath(path, paint);
3960 path.rewind();
3961 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
3962 canvas->drawPath(path, paint);
3963}
3964##
3965
3966#SeeAlso SkCanvas::drawRect Direction
3967
3968##
3969
3970# ------------------------------------------------------------------------------
3971
3972#Method void addRect(const SkRect& rect, Direction dir, unsigned start)
3973
3974Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
3975If dir is kCW_Direction, Rect corners are added clockwise; if dir is
3976kCCW_Direction, Rect corners are added counterclockwise.
3977start determines the first corner added.
3978
3979#Table
3980#Legend
3981# start # first corner ##
3982#Legend ##
3983# 0 # top-left ##
3984# 1 # top-right ##
3985# 2 # bottom-right ##
3986# 3 # bottom-left ##
3987#Table ##
3988
3989#Param rect Rect to add as a closed contour ##
3990#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04003991#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04003992
3993#Example
3994#Height 128
3995#Description
3996The arrow is just after the initial corner and points towards the next
3997corner appended to Path.
3998##
3999void draw(SkCanvas* canvas) {
4000 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
4001 const SkRect rect = {10, 10, 54, 54};
4002 SkPaint rectPaint;
4003 rectPaint.setAntiAlias(true);
4004 rectPaint.setStyle(SkPaint::kStroke_Style);
4005 SkPaint arrowPaint(rectPaint);
4006 SkPath arrowPath;
4007 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4008 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4009 SkPath1DPathEffect::kRotate_Style));
4010 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4011 for (unsigned start : { 0, 1, 2, 3 } ) {
4012 SkPath path;
4013 path.addRect(rect, direction, start);
4014 canvas->drawPath(path, rectPaint);
4015 canvas->drawPath(path, arrowPaint);
4016 canvas->translate(64, 0);
4017 }
4018 canvas->translate(-256, 64);
4019 }
4020}
4021##
4022
4023#SeeAlso SkCanvas::drawRect Direction
4024
4025##
4026
4027# ------------------------------------------------------------------------------
4028
4029#Method void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
4030 Direction dir = kCW_Direction)
4031
4032Add Rect (left, top, right, bottom) to Path,
4033appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4034starting with top-left corner of Rect; followed by top-right, bottom-right,
4035and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4036bottom-right, and top-right if dir is kCCW_Direction.
4037
4038#Param left smaller x of Rect ##
4039#Param top smaller y of Rect ##
4040#Param right larger x of Rect ##
4041#Param bottom larger y of Rect ##
4042#Param dir Direction to wind added contour ##
4043
4044#Example
4045#Description
4046The left Rect dashes start at the top-left corner, and continue to the right.
4047The right Rect dashes start at the top-left corner, and continue down.
4048##
4049#Height 128
4050void draw(SkCanvas* canvas) {
4051 SkPaint paint;
4052 paint.setStrokeWidth(15);
4053 paint.setStrokeCap(SkPaint::kSquare_Cap);
4054 float intervals[] = { 5, 21.75f };
4055 paint.setStyle(SkPaint::kStroke_Style);
4056 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4057 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4058 SkPath path;
4059 path.addRect(20, 20, 100, 100, direction);
4060 canvas->drawPath(path, paint);
4061 canvas->translate(128, 0);
4062 }
4063}
4064##
4065
4066#SeeAlso SkCanvas::drawRect Direction
4067
4068##
4069
4070# ------------------------------------------------------------------------------
4071
4072#Method void addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004073#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004074#Line # adds one Contour containing Oval ##
Cary Clark73fa9722017-08-29 17:36:51 -04004075Add Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4076Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4077and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4078clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4079
4080This form is identical to addOval(oval, dir, 1).
4081
4082#Param oval bounds of ellipse added ##
4083#Param dir Direction to wind ellipse ##
4084
4085#Example
4086#Height 120
4087 SkPaint paint;
4088 SkPath oval;
4089 oval.addOval({20, 20, 160, 80});
4090 canvas->drawPath(oval, paint);
4091##
4092
4093#SeeAlso SkCanvas::drawOval Direction Oval
4094
4095##
4096
4097# ------------------------------------------------------------------------------
4098
4099#Method void addOval(const SkRect& oval, Direction dir, unsigned start)
4100
4101Add Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4102Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4103and half oval height. Oval begins at start and continues
4104clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4105
4106#Table
4107#Legend
4108# start # Point ##
4109#Legend ##
4110# 0 # oval.centerX(), oval.fTop ##
4111# 1 # oval.fRight, oval.centerY() ##
4112# 2 # oval.centerX(), oval.fBottom ##
4113# 3 # oval.fLeft, oval.centerY() ##
4114#Table ##
4115
4116#Param oval bounds of ellipse added ##
4117#Param dir Direction to wind ellipse ##
4118#Param start index of initial point of ellipse ##
4119
4120#Example
4121#Height 160
4122void draw(SkCanvas* canvas) {
4123 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4124 const SkRect rect = {10, 10, 54, 54};
4125 SkPaint ovalPaint;
4126 ovalPaint.setAntiAlias(true);
4127 SkPaint textPaint(ovalPaint);
4128 textPaint.setTextAlign(SkPaint::kCenter_Align);
4129 ovalPaint.setStyle(SkPaint::kStroke_Style);
4130 SkPaint arrowPaint(ovalPaint);
4131 SkPath arrowPath;
4132 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4133 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4134 SkPath1DPathEffect::kRotate_Style));
4135 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4136 for (unsigned start : { 0, 1, 2, 3 } ) {
4137 SkPath path;
4138 path.addOval(rect, direction, start);
4139 canvas->drawPath(path, ovalPaint);
4140 canvas->drawPath(path, arrowPaint);
4141 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4142 canvas->translate(64, 0);
4143 }
4144 canvas->translate(-256, 72);
4145 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4146 128, 0, textPaint);
4147 }
4148}
4149##
4150
4151#SeeAlso SkCanvas::drawOval Direction Oval
4152
4153##
4154
4155# ------------------------------------------------------------------------------
4156
4157#Method void addCircle(SkScalar x, SkScalar y, SkScalar radius,
4158 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004159#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004160#Line # adds one Contour containing Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04004161
4162Add Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark154beea2017-10-26 07:58:48 -04004163four kConic_Verb, and kClose_Verb. Circle begins at:
Cary Clark73fa9722017-08-29 17:36:51 -04004164#Formula
4165(x + radius, y)
4166##
Cary Clark154beea2017-10-26 07:58:48 -04004167, continuing
4168clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04004169
Cary Clark6fc50412017-09-21 12:31:06 -04004170Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004171
4172#Param x center of Circle ##
4173#Param y center of Circle ##
4174#Param radius distance from center to edge ##
4175#Param dir Direction to wind Circle ##
4176
4177#Example
4178void draw(SkCanvas* canvas) {
4179 SkPaint paint;
4180 paint.setAntiAlias(true);
4181 paint.setStyle(SkPaint::kStroke_Style);
4182 paint.setStrokeWidth(10);
4183 for (int size = 10; size < 300; size += 20) {
4184 SkPath path;
4185 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4186 canvas->drawPath(path, paint);
4187 }
4188}
4189##
4190
4191#SeeAlso SkCanvas::drawCircle Direction Circle
4192
4193##
4194
4195# ------------------------------------------------------------------------------
4196
4197#Method void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05004198#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004199#Line # adds one Contour containing Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04004200Append Arc to Path, as the start of new Contour. Arc added is part of ellipse
4201bounded by oval, from startAngle through sweepAngle. Both startAngle and
4202sweepAngle are measured in degrees, where zero degrees is aligned with the
4203positive x-axis, and positive sweeps extends Arc clockwise.
4204
4205If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4206zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
4207modulo 360, and Arc may or may not draw depending on numeric rounding.
4208
4209#Param oval bounds of ellipse containing Arc ##
4210#Param startAngle starting angle of Arc in degrees ##
4211#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4212
4213#Example
4214#Description
4215The middle row of the left and right columns draw differently from the entries
4216above and below because sweepAngle is outside of the range of +/-360,
4217and startAngle modulo 90 is not zero.
4218##
4219void draw(SkCanvas* canvas) {
4220 SkPaint paint;
4221 for (auto start : { 0, 90, 135, 180, 270 } ) {
4222 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4223 SkPath path;
4224 path.addArc({10, 10, 35, 45}, start, sweep);
4225 canvas->drawPath(path, paint);
4226 canvas->translate(252 / 6, 0);
4227 }
4228 canvas->translate(-252, 255 / 5);
4229 }
4230}
4231##
4232
4233#SeeAlso Arc arcTo SkCanvas::drawArc
4234
4235##
4236
4237# ------------------------------------------------------------------------------
4238
4239#Method void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
4240 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004241#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004242#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark73fa9722017-08-29 17:36:51 -04004243
4244Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4245equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4246dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4247winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4248of the upper-left corner and winds counterclockwise.
4249
4250If either rx or ry is too large, rx and ry are scaled uniformly until the
4251corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4252Rect rect to Path.
4253
4254After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4255
4256#Param rect bounds of Round_Rect ##
4257#Param rx x-radius of rounded corners on the Round_Rect ##
4258#Param ry y-radius of rounded corners on the Round_Rect ##
4259#Param dir Direction to wind Round_Rect ##
4260
4261#Example
4262#Description
4263If either radius is zero, path contains Rect and is drawn red.
4264If sides are only radii, path contains Oval and is drawn blue.
4265All remaining path draws are convex, and are drawn in gray; no
4266paths constructed from addRoundRect are concave, so none are
4267drawn in green.
4268##
4269void draw(SkCanvas* canvas) {
4270 SkPaint paint;
4271 paint.setAntiAlias(true);
4272 for (auto xradius : { 0, 7, 13, 20 } ) {
4273 for (auto yradius : { 0, 9, 18, 40 } ) {
4274 SkPath path;
4275 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4276 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4277 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4278 canvas->drawPath(path, paint);
4279 canvas->translate(64, 0);
4280 }
4281 canvas->translate(-256, 64);
4282 }
4283}
4284##
4285
4286#SeeAlso addRRect SkCanvas::drawRoundRect
4287
4288##
4289
4290# ------------------------------------------------------------------------------
4291
4292#Method void addRoundRect(const SkRect& rect, const SkScalar radii[],
4293 Direction dir = kCW_Direction)
4294
4295Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4296equal to rect; each corner is 90 degrees of an ellipse with radii from the
4297array.
4298
4299#Table
4300#Legend
4301# radii index # location ##
4302#Legend ##
4303# 0 # x-radius of top-left corner ##
4304# 1 # y-radius of top-left corner ##
4305# 2 # x-radius of top-right corner ##
4306# 3 # y-radius of top-right corner ##
4307# 4 # x-radius of bottom-right corner ##
4308# 5 # y-radius of bottom-right corner ##
4309# 6 # x-radius of bottom-left corner ##
4310# 7 # y-radius of bottom-left corner ##
4311#Table ##
4312
4313If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4314and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
4315bottom-left of the upper-left corner and winds counterclockwise.
4316
4317If both radii on any side of rect exceed its length, all radii are scaled
4318uniformly until the corners fit. If either radius of a corner is less than or
4319equal to zero, both are treated as zero.
4320
4321After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4322
4323#Param rect bounds of Round_Rect ##
4324#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4325#Param dir Direction to wind Round_Rect ##
4326
4327#Example
4328void draw(SkCanvas* canvas) {
4329 SkPaint paint;
4330 paint.setAntiAlias(true);
4331 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4332 SkPath path;
4333 SkMatrix rotate90;
4334 rotate90.setRotate(90, 128, 128);
4335 for (int i = 0; i < 4; ++i) {
4336 path.addRoundRect({10, 10, 110, 110}, radii);
4337 path.transform(rotate90);
4338 }
4339 canvas->drawPath(path, paint);
4340}
4341##
4342
4343#SeeAlso addRRect SkCanvas::drawRoundRect
4344
4345##
4346
4347# ------------------------------------------------------------------------------
4348
4349#Method void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05004350#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004351#Line # adds one Contour containing Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004352Add rrect to Path, creating a new closed Contour. If
4353dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4354winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4355of the upper-left corner and winds counterclockwise.
4356
4357After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4358
4359#Param rrect bounds and radii of rounded rectangle ##
4360#Param dir Direction to wind Round_Rect ##
4361
4362#Example
4363void draw(SkCanvas* canvas) {
4364 SkPaint paint;
4365 paint.setAntiAlias(true);
4366 SkRRect rrect;
4367 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4368 rrect.setRectRadii({10, 10, 110, 110}, radii);
4369 SkPath path;
4370 SkMatrix rotate90;
4371 rotate90.setRotate(90, 128, 128);
4372 for (int i = 0; i < 4; ++i) {
4373 path.addRRect(rrect);
4374 path.transform(rotate90);
4375 }
4376 canvas->drawPath(path, paint);
4377}
4378##
4379
4380#SeeAlso addRoundRect SkCanvas::drawRRect
4381
4382##
4383
4384# ------------------------------------------------------------------------------
4385
4386#Method void addRRect(const SkRRect& rrect, Direction dir, unsigned start)
4387
4388Add rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
4389winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4390start determines the first point of rrect to add.
4391
4392#Table
4393#Legend
4394# start # location ##
4395#Legend ##
4396# 0 # right of top-left corner ##
4397# 1 # left of top-right corner ##
4398# 2 # bottom of top-right corner ##
4399# 3 # top of bottom-right corner ##
4400# 4 # left of bottom-right corner ##
4401# 5 # right of bottom-left corner ##
4402# 6 # top of bottom-left corner ##
4403# 7 # bottom of top-left corner ##
4404#Table ##
4405
4406After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4407
4408#Param rrect bounds and radii of rounded rectangle ##
4409#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004410#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004411
4412#Example
4413void draw(SkCanvas* canvas) {
4414 SkPaint paint;
4415 paint.setAntiAlias(true);
4416 SkRRect rrect;
4417 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4418 SkPath path;
4419 path.addRRect(rrect);
4420 canvas->drawPath(path, paint);
4421 for (int start = 0; start < 8; ++start) {
4422 SkPath textPath;
4423 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
4424 canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
4425 }
4426}
4427##
4428
4429#SeeAlso addRoundRect SkCanvas::drawRRect
4430
4431##
4432
4433# ------------------------------------------------------------------------------
4434
4435#Method void addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05004436#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004437#Line # adds one Contour containing connected lines ##
Cary Clark6fc50412017-09-21 12:31:06 -04004438Add Contour created from Line array, adding (count - 1) Line segments.
4439Contour added starts at pts[0], then adds a line for every additional Point
4440in pts array. If close is true,appends kClose_Verb to Path, connecting
4441pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004442
4443If count is zero, append kMove_Verb to path.
4444Has no effect if count is less than one.
4445
Cary Clarka523d2d2017-08-30 08:58:10 -04004446#Param pts array of Line sharing end and start Point ##
4447#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004448#Param close true to add Line connecting Contour end and start ##
4449
4450#Example
4451void draw(SkCanvas* canvas) {
4452 SkPaint paint;
4453 paint.setStrokeWidth(15);
4454 paint.setStrokeCap(SkPaint::kRound_Cap);
4455 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4456 for (bool close : { false, true } ) {
4457 SkPath path;
4458 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4459 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4460 SkPaint::kStrokeAndFill_Style} ) {
4461 paint.setStyle(style);
4462 canvas->drawPath(path, paint);
4463 canvas->translate(85, 0);
4464 }
4465 canvas->translate(-255, 128);
4466 }
4467}
4468##
4469
4470#SeeAlso SkCanvas::drawPoints
4471
4472##
4473
4474# ------------------------------------------------------------------------------
4475
4476#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05004477#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04004478
4479#Code
4480 enum AddPathMode {
4481 kAppend_AddPathMode,
4482 kExtend_AddPathMode,
4483 };
4484##
4485
4486AddPathMode chooses how addPath appends. Adding one Path to another can extend
4487the last Contour or start a new Contour.
4488
4489#Const kAppend_AddPathMode
4490 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4491 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4492 starts a new Contour.
4493##
4494#Const kExtend_AddPathMode
4495 If destination is closed or empty, start a new Contour. If destination
4496 is not empty, add Line from Last_Point to added Path first Point. Skip added
4497 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4498##
4499
4500#Example
4501#Description
4502test is built from path, open on the top row, and closed on the bottom row.
4503The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4504The top right composition is made up of one contour; the other three have two.
4505##
4506#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004507 SkPath path, path2;
4508 path.moveTo(20, 20);
4509 path.lineTo(20, 40);
4510 path.lineTo(40, 20);
4511 path2.moveTo(60, 60);
4512 path2.lineTo(80, 60);
4513 path2.lineTo(80, 40);
4514 SkPaint paint;
4515 paint.setStyle(SkPaint::kStroke_Style);
4516 for (int i = 0; i < 2; i++) {
4517 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4518 SkPath test(path);
4519 test.addPath(path2, addPathMode);
4520 canvas->drawPath(test, paint);
4521 canvas->translate(100, 0);
4522 }
4523 canvas->translate(-200, 100);
4524 path.close();
4525 }
Cary Clark73fa9722017-08-29 17:36:51 -04004526##
4527
4528#SeeAlso addPath reverseAddPath
4529
4530##
4531
4532# ------------------------------------------------------------------------------
4533
4534#Method void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
4535 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05004536#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004537#Line # adds contents of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004538
4539Append src to Path, offset by (dx, dy).
4540
4541If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4542added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4543Verbs, Points, and Conic_Weights.
4544
4545#Param src Path Verbs, Points, and Conic_Weights to add ##
4546#Param dx offset added to src Point_Array x coordinates ##
4547#Param dy offset added to src Point_Array y coordinates ##
4548#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4549
4550#Example
4551#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004552 SkPaint paint;
4553 paint.setTextSize(128);
4554 paint.setFakeBoldText(true);
4555 SkPath dest, text;
4556 paint.getTextPath("O", 1, 50, 120, &text);
4557 for (int i = 0; i < 3; i++) {
4558 dest.addPath(text, i * 20, i * 20);
4559 }
4560 Simplify(dest, &dest);
4561 paint.setStyle(SkPaint::kStroke_Style);
4562 paint.setStrokeWidth(3);
4563 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004564##
4565
Cary Clark4855f782018-02-06 09:41:53 -05004566#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004567
4568##
4569
4570# ------------------------------------------------------------------------------
4571
4572#Method void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
4573
4574Append src to Path.
4575
4576If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4577added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4578Verbs, Points, and Conic_Weights.
4579
4580#Param src Path Verbs, Points, and Conic_Weights to add ##
4581#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4582
4583#Example
4584#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004585 SkPaint paint;
4586 paint.setStyle(SkPaint::kStroke_Style);
4587 SkPath dest, path;
4588 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4589 for (int i = 0; i < 2; i++) {
4590 dest.addPath(path, SkPath::kExtend_AddPathMode);
4591 dest.offset(100, 0);
4592 }
Cary Clark73fa9722017-08-29 17:36:51 -04004593 canvas->drawPath(dest, paint);
4594##
4595
4596#SeeAlso AddPathMode reverseAddPath
4597
4598##
4599
4600# ------------------------------------------------------------------------------
4601
4602#Method void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
4603
4604Append src to Path, transformed by matrix. Transformed curves may have different
4605Verbs, Points, and Conic_Weights.
4606
4607If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4608added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4609Verbs, Points, and Conic_Weights.
4610
4611#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004612#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004613#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4614
4615#Example
4616#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004617 SkPaint paint;
4618 paint.setStyle(SkPaint::kStroke_Style);
4619 SkPath dest, path;
4620 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4621 for (int i = 0; i < 6; i++) {
4622 SkMatrix matrix;
4623 matrix.reset();
4624 matrix.setPerspX(i / 400.f);
4625 dest.addPath(path, matrix);
4626 }
4627 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004628##
4629
Cary Clark4855f782018-02-06 09:41:53 -05004630#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04004631
4632##
4633
4634# ------------------------------------------------------------------------------
4635
4636#Method void reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05004637#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05004638#Line # adds contents of Path back to front ##
Cary Clark73fa9722017-08-29 17:36:51 -04004639Append src to Path, from back to front.
4640Reversed src always appends a new Contour to Path.
4641
4642#Param src Path Verbs, Points, and Conic_Weights to add ##
4643
4644#Example
4645#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004646 SkPath path;
4647 path.moveTo(20, 20);
4648 path.lineTo(20, 40);
4649 path.lineTo(40, 20);
4650 SkPaint paint;
4651 paint.setStyle(SkPaint::kStroke_Style);
4652 for (int i = 0; i < 2; i++) {
4653 SkPath path2;
4654 path2.moveTo(60, 60);
4655 path2.lineTo(80, 60);
4656 path2.lineTo(80, 40);
4657 for (int j = 0; j < 2; j++) {
4658 SkPath test(path);
4659 test.reverseAddPath(path2);
4660 canvas->drawPath(test, paint);
4661 canvas->translate(100, 0);
4662 path2.close();
4663 }
4664 canvas->translate(-200, 100);
4665 path.close();
4666 }
Cary Clark73fa9722017-08-29 17:36:51 -04004667##
4668
Cary Clark4855f782018-02-06 09:41:53 -05004669#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04004670
4671##
4672
4673# ------------------------------------------------------------------------------
4674
4675#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004676#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004677#Line # translates Point_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004678Offset Point_Array by (dx, dy). Offset Path replaces dst.
4679If dst is nullptr, Path is replaced by offset data.
4680
4681#Param dx offset added to Point_Array x coordinates ##
4682#Param dy offset added to Point_Array y coordinates ##
4683#Param dst overwritten, translated copy of Path; may be nullptr ##
4684
4685#Example
4686#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004687 SkPath pattern;
4688 pattern.moveTo(20, 20);
4689 pattern.lineTo(20, 40);
4690 pattern.lineTo(40, 20);
4691 SkPaint paint;
4692 paint.setStyle(SkPaint::kStroke_Style);
4693 for (int i = 0; i < 10; i++) {
4694 SkPath path;
4695 pattern.offset(20 * i, 0, &path);
4696 canvas->drawPath(path, paint);
4697 }
Cary Clark73fa9722017-08-29 17:36:51 -04004698##
4699
4700#SeeAlso addPath transform
4701
4702##
4703
4704# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05004705#Subtopic Transform
4706#Populate
4707#Line # modify all points ##
4708##
Cary Clark73fa9722017-08-29 17:36:51 -04004709
4710#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05004711#In Transform
Cary Clark73fa9722017-08-29 17:36:51 -04004712Offset Point_Array by (dx, dy). Path is replaced by offset data.
4713
4714#Param dx offset added to Point_Array x coordinates ##
4715#Param dy offset added to Point_Array y coordinates ##
4716
4717#Example
4718#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004719 SkPath path;
4720 path.moveTo(20, 20);
4721 path.lineTo(20, 40);
4722 path.lineTo(40, 20);
4723 SkPaint paint;
4724 paint.setStyle(SkPaint::kStroke_Style);
4725 for (int i = 0; i < 10; i++) {
4726 canvas->drawPath(path, paint);
4727 path.offset(20, 0);
4728 }
Cary Clark73fa9722017-08-29 17:36:51 -04004729##
4730
4731#SeeAlso addPath transform SkCanvas::translate()
4732
4733##
4734
4735# ------------------------------------------------------------------------------
4736
4737#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05004738#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05004739#Line # applies Matrix to Point_Array and Weights ##
Cary Clark73fa9722017-08-29 17:36:51 -04004740Transform Verb_Array, Point_Array, and weight by matrix.
4741transform may change Verbs and increase their number.
4742Transformed Path replaces dst; if dst is nullptr, original data
4743is replaced.
4744
4745#Param matrix Matrix to apply to Path ##
4746#Param dst overwritten, transformed copy of Path; may be nullptr ##
4747
4748#Example
Cary Clark8032b982017-07-28 11:04:54 -04004749#Height 200
4750 SkPath pattern;
4751 pattern.moveTo(100, 100);
4752 pattern.lineTo(100, 20);
4753 pattern.lineTo(20, 100);
4754 SkPaint paint;
4755 paint.setStyle(SkPaint::kStroke_Style);
4756 for (int i = 0; i < 10; i++) {
4757 SkPath path;
4758 SkMatrix matrix;
4759 matrix.setRotate(36 * i, 100, 100);
4760 pattern.transform(matrix, &path);
4761 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004762 }
4763##
4764
4765#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4766
4767##
4768
4769# ------------------------------------------------------------------------------
4770
4771#Method void transform(const SkMatrix& matrix)
4772
4773Transform Verb_Array, Point_Array, and weight by matrix.
4774transform may change Verbs and increase their number.
4775Path is replaced by transformed data.
4776
4777#Param matrix Matrix to apply to Path ##
4778
4779#Example
Cary Clark8032b982017-07-28 11:04:54 -04004780#Height 200
4781 SkPath path;
4782 path.moveTo(100, 100);
4783 path.quadTo(100, 20, 20, 100);
4784 SkPaint paint;
4785 paint.setStyle(SkPaint::kStroke_Style);
4786 for (int i = 0; i < 10; i++) {
4787 SkMatrix matrix;
4788 matrix.setRotate(36, 100, 100);
4789 path.transform(matrix);
4790 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004791 }
4792##
4793
4794#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4795
4796##
4797
4798# ------------------------------------------------------------------------------
4799
Cary Clark8032b982017-07-28 11:04:54 -04004800#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05004801#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04004802
4803Path is defined cumulatively, often by adding a segment to the end of last
4804Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4805Last_Point can be read and written directly with getLastPt and setLastPt.
4806
Cary Clark73fa9722017-08-29 17:36:51 -04004807#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05004808#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004809#In Last_Point
4810#Line # returns Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004811 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
4812 storing (0, 0) if lastPt is not nullptr.
4813
4814 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4815
4816 #Return true if Point_Array contains one or more Points ##
4817
4818 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004819 SkPath path;
4820 path.moveTo(100, 100);
4821 path.quadTo(100, 20, 20, 100);
4822 SkMatrix matrix;
4823 matrix.setRotate(36, 100, 100);
4824 path.transform(matrix);
4825 SkPoint last;
4826 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004827 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4828 #StdOut
4829 last point: 35.2786, 52.9772
4830 ##
4831 ##
4832
4833 #SeeAlso setLastPt
4834
4835##
4836
4837#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05004838#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004839#In Last_Point
4840#Line # replaces Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04004841 Set Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
4842 Verb_Array and (x, y) to Point_Array.
4843
4844 #Param x set x-coordinate of Last_Point ##
4845 #Param y set y-coordinate of Last_Point ##
4846
4847 #Example
4848 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004849 SkPaint paint;
4850 paint.setTextSize(128);
4851 SkPath path;
4852 paint.getTextPath("@", 1, 60, 100, &path);
4853 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004854 canvas->drawPath(path, paint);
4855 ##
4856
4857 #SeeAlso getLastPt
4858
4859##
4860
4861#Method void setLastPt(const SkPoint& p)
4862
4863 Set the last point on the path. If no points have been added, moveTo(p)
4864 is automatically called.
4865
4866 #Param p set value of Last_Point ##
4867
4868 #Example
4869 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004870 SkPaint paint;
4871 paint.setTextSize(128);
4872 SkPath path, path2;
4873 paint.getTextPath("A", 1, 60, 100, &path);
4874 paint.getTextPath("Z", 1, 60, 100, &path2);
4875 SkPoint pt, pt2;
4876 path.getLastPt(&pt);
4877 path2.getLastPt(&pt2);
4878 path.setLastPt(pt2);
4879 path2.setLastPt(pt);
4880 canvas->drawPath(path, paint);
4881 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004882 ##
4883
4884 #SeeAlso getLastPt
4885
4886##
4887
4888#Subtopic Last_Point ##
4889
4890# ------------------------------------------------------------------------------
4891
4892#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05004893#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04004894
4895#Code
4896 enum SegmentMask {
4897 kLine_SegmentMask = 1 << 0,
4898 kQuad_SegmentMask = 1 << 1,
4899 kConic_SegmentMask = 1 << 2,
4900 kCubic_SegmentMask = 1 << 3,
4901 };
4902##
4903
4904SegmentMask constants correspond to each drawing Verb type in Path; for
4905instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4906
Cary Clark4855f782018-02-06 09:41:53 -05004907#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04004908#Const kLine_SegmentMask 1
4909Set if Verb_Array contains kLine_Verb.
4910##
4911#Const kQuad_SegmentMask 2
4912Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4913##
4914#Const kConic_SegmentMask 4
4915Set if Verb_Array contains kConic_Verb.
4916##
4917#Const kCubic_SegmentMask 8
4918Set if Verb_Array contains kCubic_Verb.
4919##
4920
4921#Example
4922#Description
4923When conicTo has a weight of one, Quad is added to Path.
4924##
4925 SkPath path;
4926 path.conicTo(10, 10, 20, 30, 1);
4927 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
4928 SkPath::kConic_SegmentMask ? "set" : "clear");
4929 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
4930 SkPath::kQuad_SegmentMask ? "set" : "clear");
4931#StdOut
4932Path kConic_SegmentMask is clear
4933Path kQuad_SegmentMask is set
4934##
4935##
4936
4937#SeeAlso getSegmentMasks Verb
4938
4939##
4940
4941# ------------------------------------------------------------------------------
4942
4943#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05004944#In Utility
4945#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004946#Line # returns types in Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004947Returns a mask, where each set bit corresponds to a SegmentMask constant
4948if Path contains one or more Verbs of that type.
4949Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
4950
4951getSegmentMasks() returns a cached result; it is very fast.
4952
4953#Return SegmentMask bits or zero ##
4954
4955#Example
4956SkPath path;
4957path.quadTo(20, 30, 40, 50);
4958path.close();
4959const char* masks[] = { "line", "quad", "conic", "cubic" };
4960int index = 0;
4961for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4962 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4963 if (mask & path.getSegmentMasks()) {
4964 SkDebugf("mask %s set\n", masks[index]);
4965 }
4966 ++index;
4967}
4968#StdOut
4969mask quad set
4970##
4971##
4972
4973#SeeAlso getSegmentMasks Verb
4974
4975##
4976
4977# ------------------------------------------------------------------------------
4978
4979#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05004980#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004981#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04004982Returns true if the point (x, y) is contained by Path, taking into
4983account FillType.
4984
4985#Table
4986#Legend
4987# FillType # contains() returns true if Point is enclosed by ##
4988##
4989# kWinding_FillType # a non-zero sum of Contour Directions. ##
4990# kEvenOdd_FillType # an odd number of Contours. ##
4991# kInverseWinding_FillType # a zero sum of Contour Directions. ##
4992# kInverseEvenOdd_FillType # and even number of Contours. ##
4993##
4994
4995#Param x x-coordinate of containment test ##
4996#Param y y-coordinate of containment test ##
4997
4998#Return true if Point is in Path ##
4999
5000#Example
5001SkPath path;
5002SkPaint paint;
5003paint.setTextSize(256);
5004paint.getTextPath("&", 1, 30, 220, &path);
5005for (int y = 2; y < 256; y += 9) {
5006 for (int x = 2; x < 256; x += 9) {
5007 int coverage = 0;
5008 for (int iy = -4; iy <= 4; iy += 2) {
5009 for (int ix = -4; ix <= 4; ix += 2) {
5010 coverage += path.contains(x + ix, y + iy);
5011 }
5012 }
5013 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5014 canvas->drawCircle(x, y, 8, paint);
5015 }
5016}
5017##
5018
5019#SeeAlso conservativelyContainsRect Fill_Type Op
5020
5021##
5022
5023# ------------------------------------------------------------------------------
5024
5025#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05005026#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005027#Line # sends text representation using floats to standard output ##
Cary Clark154beea2017-10-26 07:58:48 -04005028Writes text representation of Path to stream. If stream is nullptr, writes to
5029standard output. Set forceClose to true to get edges used to fill Path.
5030Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005031of floating point numbers used in Point_Array and Conic_Weights.
5032
5033#Param stream writable Stream receiving Path text representation; may be nullptr ##
5034#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005035#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005036
5037#Example
5038 SkPath path;
5039 path.quadTo(20, 30, 40, 50);
5040 for (bool forceClose : { false, true } ) {
5041 for (bool dumpAsHex : { false, true } ) {
5042 path.dump(nullptr, forceClose, dumpAsHex);
5043 SkDebugf("\n");
5044 }
5045 }
5046#StdOut
5047path.setFillType(SkPath::kWinding_FillType);
5048path.moveTo(0, 0);
5049path.quadTo(20, 30, 40, 50);
5050
5051path.setFillType(SkPath::kWinding_FillType);
5052path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5053path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5054
5055path.setFillType(SkPath::kWinding_FillType);
5056path.moveTo(0, 0);
5057path.quadTo(20, 30, 40, 50);
5058path.lineTo(0, 0);
5059path.close();
5060
5061path.setFillType(SkPath::kWinding_FillType);
5062path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5063path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5064path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5065path.close();
5066##
5067##
5068
5069#SeeAlso SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
5070
5071##
5072
5073# ------------------------------------------------------------------------------
5074
5075#Method void dump() const
5076
Cary Clarkce101242017-09-01 15:51:02 -04005077Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005078directly compiled as C++ code. Floating point values are written
5079with limited precision; it may not be possible to reconstruct original Path
5080from output.
5081
5082#Example
5083SkPath path, copy;
5084path.lineTo(6.f / 7, 2.f / 3);
5085path.dump();
5086copy.setFillType(SkPath::kWinding_FillType);
5087copy.moveTo(0, 0);
5088copy.lineTo(0.857143f, 0.666667f);
5089SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5090#StdOut
5091path.setFillType(SkPath::kWinding_FillType);
5092path.moveTo(0, 0);
5093path.lineTo(0.857143f, 0.666667f);
5094path is not equal to copy
5095##
5096##
5097
5098#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5099
5100##
5101
5102# ------------------------------------------------------------------------------
5103
5104#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05005105#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005106#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04005107Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005108directly compiled as C++ code. Floating point values are written
5109in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5110original Path.
5111
Cary Clark6fc50412017-09-21 12:31:06 -04005112Use instead of dump() when submitting
5113#A bug reports against Skia # http://bug.skia.org ##
5114.
Cary Clark73fa9722017-08-29 17:36:51 -04005115
5116#Example
5117SkPath path, copy;
5118path.lineTo(6.f / 7, 2.f / 3);
5119path.dumpHex();
5120copy.setFillType(SkPath::kWinding_FillType);
5121copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5122copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5123SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5124#StdOut
5125path.setFillType(SkPath::kWinding_FillType);
5126path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5127path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5128path is equal to copy
5129##
5130##
5131
5132#SeeAlso dump SkRect::dumpHex() SkRRect::dumpHex() writeToMemory
5133
5134##
5135
5136# ------------------------------------------------------------------------------
5137
5138#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05005139#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005140#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005141Writes Path to buffer, returning the number of bytes written.
5142Pass nullptr to obtain the storage size.
5143
5144Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5145additionally writes computed information like Convexity and bounds.
5146
5147Use only be used in concert with readFromMemory;
5148the format used for Path in memory is not guaranteed.
5149
5150#Param buffer storage for Path; may be nullptr ##
5151
5152#Return size of storage required for Path; always a multiple of 4 ##
5153
5154#Example
5155void draw(SkCanvas* canvas) {
5156 SkPath path, copy;
5157 path.lineTo(6.f / 7, 2.f / 3);
5158 size_t size = path.writeToMemory(nullptr);
5159 SkTDArray<char> storage;
5160 storage.setCount(size);
5161 path.writeToMemory(storage.begin());
5162 copy.readFromMemory(storage.begin(), size);
5163 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5164}
5165#StdOut
5166path is equal to copy
5167##
5168##
5169
5170#SeeAlso serialize readFromMemory dump dumpHex
5171
5172##
5173
5174#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05005175#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005176#Line # copies data to buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005177Write Path to buffer, returning the buffer written to, wrapped in Data.
5178
5179serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5180additionally writes computed information like Convexity and bounds.
5181
5182serialize() should only be used in concert with readFromMemory.
5183The format used for Path in memory is not guaranteed.
5184
5185#Return Path data wrapped in Data buffer ##
5186
5187#Example
5188void draw(SkCanvas* canvas) {
5189 SkPath path, copy;
5190 path.lineTo(6.f / 7, 2.f / 3);
5191 sk_sp<SkData> data = path.serialize();
5192 copy.readFromMemory(data->data(), data->size());
5193 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5194}
5195#StdOut
5196path is equal to copy
5197##
5198##
5199
5200#SeeAlso writeToMemory readFromMemory dump dumpHex
5201##
5202
5203# ------------------------------------------------------------------------------
5204
5205#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05005206#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005207#Line # Initializes from buffer ##
Cary Clark73fa9722017-08-29 17:36:51 -04005208Initializes Path from buffer of size length. Returns zero if the buffer is
5209data is inconsistent, or the length is too small.
5210
5211Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5212additionally reads computed information like Convexity and bounds.
5213
5214Used only in concert with writeToMemory;
5215the format used for Path in memory is not guaranteed.
5216
5217#Param buffer storage for Path ##
5218#Param length buffer size in bytes; must be multiple of 4 ##
5219
5220#Return number of bytes read, or zero on failure ##
5221
5222#Example
5223void draw(SkCanvas* canvas) {
5224 SkPath path, copy;
5225 path.lineTo(6.f / 7, 2.f / 3);
5226 size_t size = path.writeToMemory(nullptr);
5227 SkTDArray<char> storage;
5228 storage.setCount(size);
5229 path.writeToMemory(storage.begin());
5230 size_t wrongSize = size - 4;
5231 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5232 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5233 size_t largerSize = size + 4;
5234 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5235 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5236}
5237#StdOut
Cary Clark06c20f32018-03-20 15:53:27 -04005238length = 32; returned by readFromMemory = 0
5239length = 40; returned by readFromMemory = 36
Cary Clark73fa9722017-08-29 17:36:51 -04005240##
5241##
5242
5243#SeeAlso writeToMemory
5244
5245##
5246
5247# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05005248#Subtopic Generation_ID
Cary Clark73fa9722017-08-29 17:36:51 -04005249#Alias Generation_IDs
Cary Clark08895c42018-02-01 09:37:32 -05005250#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04005251Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5252Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5253not necessarily have matching Generation_IDs.
5254
5255Empty Paths have a Generation_ID of one.
5256
5257#Method uint32_t getGenerationID() const
5258
Cary Clarkab2621d2018-01-30 10:08:57 -05005259#In Generation_ID
5260#Line # returns unique ID ##
Cary Clark73fa9722017-08-29 17:36:51 -04005261Returns a non-zero, globally unique value. A different value is returned
5262if Verb_Array, Point_Array, or Conic_Weight changes.
5263
5264Setting Fill_Type does not change Generation_ID.
5265
5266Each time the path is modified, a different Generation_ID will be returned.
5267
5268#Bug 1762
5269Fill_Type does affect Generation_ID on Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -04005270
5271#Return non-zero, globally unique value ##
5272
5273#Example
5274SkPath path;
5275SkDebugf("empty genID = %u\n", path.getGenerationID());
5276path.lineTo(1, 2);
5277SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5278path.rewind();
5279SkDebugf("empty genID = %u\n", path.getGenerationID());
5280path.lineTo(1, 2);
5281SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5282#StdOut
5283empty genID = 1
52841st lineTo genID = 2
5285empty genID = 1
52862nd lineTo genID = 3
5287##
5288##
5289
5290#SeeAlso operator==(const SkPath& a, const SkPath& b)
5291
5292##
5293
Cary Clark78de7512018-02-07 07:27:09 -05005294#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04005295
5296# ------------------------------------------------------------------------------
5297
5298#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005299#In Property
5300#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05005301#Line # returns if data is internally consistent ##
Cary Clark73fa9722017-08-29 17:36:51 -04005302 Returns if Path data is consistent. Corrupt Path data is detected if
5303 internal values are out of range or internal storage does not match
5304 array dimensions.
5305
5306 #Return true if Path data is consistent ##
5307
5308 #NoExample
5309 ##
5310
5311##
5312
5313#Method bool pathRefIsValid() const
Cary Clark4855f782018-02-06 09:41:53 -05005314#Deprecated soon
Cary Clark73fa9722017-08-29 17:36:51 -04005315##
5316
5317# ------------------------------------------------------------------------------
5318
Cary Clark8032b982017-07-28 11:04:54 -04005319#Class Iter
Cary Clark08895c42018-02-01 09:37:32 -05005320#Line # Path data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005321
5322Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5323Provides options to treat open Contours as closed, and to ignore
5324degenerate data.
5325
Cary Clark73fa9722017-08-29 17:36:51 -04005326#Code
5327class Iter {
5328public:
5329 Iter();
5330 Iter(const SkPath& path, bool forceClose);
5331 void setPath(const SkPath& path, bool forceClose);
5332 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5333 SkScalar conicWeight() const;
5334 bool isCloseLine() const;
5335 bool isClosedContour() const;
5336};
5337##
5338
Cary Clark8032b982017-07-28 11:04:54 -04005339#Example
5340#Height 128
5341#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005342Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005343path of the glyph.
5344##
Cary Clark73fa9722017-08-29 17:36:51 -04005345void draw(SkCanvas* canvas) {
5346 SkPaint paint;
5347 paint.setAntiAlias(true);
5348 paint.setTextSize(256);
5349 SkPath asterisk, path;
5350 paint.getTextPath("*", 1, 50, 192, &asterisk);
5351 SkPath::Iter iter(asterisk, true);
5352 SkPoint start[4], pts[4];
5353 iter.next(start); // skip moveTo
5354 iter.next(start); // first quadTo
5355 path.moveTo((start[0] + start[1]) * 0.5f);
5356 while (SkPath::kClose_Verb != iter.next(pts)) {
5357 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5358 }
5359 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5360 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005361}
5362##
5363
5364#SeeAlso RawIter
5365
5366#Method Iter()
5367
5368Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5369Call setPath to initialize Iter at a later time.
5370
Cary Clark73fa9722017-08-29 17:36:51 -04005371#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005372
5373#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005374void draw(SkCanvas* canvas) {
5375 SkPath::Iter iter;
5376 SkPoint points[4];
5377 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5378 SkPath path;
5379 iter.setPath(path, false);
5380 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005381}
Cary Clark73fa9722017-08-29 17:36:51 -04005382#StdOut
5383iter is done
5384iter is done
5385##
Cary Clark8032b982017-07-28 11:04:54 -04005386##
5387
5388#SeeAlso setPath
5389
5390##
5391
5392#Method Iter(const SkPath& path, bool forceClose)
5393
5394Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5395If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5396open Contour. path is not altered.
5397
Cary Clark73fa9722017-08-29 17:36:51 -04005398#Param path Path to iterate ##
5399#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005400
Cary Clark73fa9722017-08-29 17:36:51 -04005401#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005402
5403#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005404void draw(SkCanvas* canvas) {
5405 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5406 SkDebugf("%s:\n", prefix);
5407 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5408 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5409 SkPath::Verb verb;
5410 do {
5411 SkPoint points[4];
5412 verb = iter.next(points);
5413 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5414 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5415 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5416 }
5417 if (SkPath::kConic_Verb == verb) {
5418 SkDebugf("weight = %g", iter.conicWeight());
5419 }
5420 SkDebugf("\n");
5421 } while (SkPath::kDone_Verb != verb);
5422 SkDebugf("\n");
5423 };
5424
5425 SkPath path;
5426 path.quadTo(10, 20, 30, 40);
5427 SkPath::Iter openIter(path, false);
5428 debugster("open", openIter);
5429 SkPath::Iter closedIter(path, true);
5430 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005431}
5432#StdOut
5433open:
Cary Clark73fa9722017-08-29 17:36:51 -04005434kMove_Verb {0, 0},
5435kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5436kDone_Verb
5437
5438closed:
5439kMove_Verb {0, 0},
5440kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5441kLine_Verb {30, 40}, {0, 0},
5442kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005443kDone_Verb
5444##
5445##
5446
5447#SeeAlso setPath
5448
5449##
5450
5451#Method void setPath(const SkPath& path, bool forceClose)
5452
5453Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5454If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5455open Contour. path is not altered.
5456
Cary Clark73fa9722017-08-29 17:36:51 -04005457#Param path Path to iterate ##
5458#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005459
5460#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005461void draw(SkCanvas* canvas) {
5462 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5463 SkDebugf("%s:\n", prefix);
5464 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5465 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5466 SkPath::Verb verb;
5467 do {
5468 SkPoint points[4];
5469 verb = iter.next(points);
5470 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5471 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5472 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5473 }
5474 if (SkPath::kConic_Verb == verb) {
5475 SkDebugf("weight = %g", iter.conicWeight());
5476 }
5477 SkDebugf("\n");
5478 } while (SkPath::kDone_Verb != verb);
5479 SkDebugf("\n");
5480 };
5481
5482 SkPath path;
5483 path.quadTo(10, 20, 30, 40);
5484 SkPath::Iter iter(path, false);
5485 debugster("quad open", iter);
5486 SkPath path2;
5487 path2.conicTo(1, 2, 3, 4, .5f);
5488 iter.setPath(path2, true);
5489 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005490}
5491#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005492quad open:
5493kMove_Verb {0, 0},
5494kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5495kDone_Verb
5496
5497conic closed:
5498kMove_Verb {0, 0},
5499kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
5500kLine_Verb {3, 4}, {0, 0},
5501kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005502kDone_Verb
5503##
5504##
5505
5506#SeeAlso Iter(const SkPath& path, bool forceClose)
5507
5508##
5509
5510#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
5511
Cary Clarka523d2d2017-08-30 08:58:10 -04005512Returns next Verb in Verb_Array, and advances Iter.
5513When Verb_Array is exhausted, returns kDone_Verb.
5514
Cary Clark8032b982017-07-28 11:04:54 -04005515Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005516
Cary Clark8032b982017-07-28 11:04:54 -04005517If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5518only the last in the series; and skip very small Lines, Quads, and Conics; and
5519skip kClose_Verb following kMove_Verb.
5520if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5521Conics with zero lengths.
5522
Cary Clarka523d2d2017-08-30 08:58:10 -04005523 #Param pts storage for Point data describing returned Verb ##
5524 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5525 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005526
Cary Clark73fa9722017-08-29 17:36:51 -04005527 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005528
5529#Example
5530#Description
5531skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5532followed by the kClose_Verb, the zero length Line and the very small Line.
5533
5534skip degenerate if exact skips the same as skip degenerate, but shows
5535the very small Line.
5536
5537skip none shows all of the Verbs and Points in Path.
5538##
Cary Clark73fa9722017-08-29 17:36:51 -04005539void draw(SkCanvas* canvas) {
5540 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5541 SkPath::Iter iter(path, false);
5542 SkDebugf("%s:\n", prefix);
5543 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5544 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5545 SkPath::Verb verb;
5546 do {
5547 SkPoint points[4];
5548 verb = iter.next(points, degen, exact);
5549 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5550 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5551 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5552 }
5553 SkDebugf("\n");
5554 } while (SkPath::kDone_Verb != verb);
5555 SkDebugf("\n");
5556 };
5557
5558 SkPath path;
5559 path.moveTo(10, 10);
5560 path.moveTo(20, 20);
5561 path.quadTo(10, 20, 30, 40);
5562 path.moveTo(1, 1);
5563 path.close();
5564 path.moveTo(30, 30);
5565 path.lineTo(30, 30);
5566 path.moveTo(30, 30);
5567 path.lineTo(30.00001f, 30);
5568 debugster("skip degenerate", path, true, false);
5569 debugster("skip degenerate if exact", path, true, true);
5570 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005571}
5572#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005573skip degenerate:
5574kMove_Verb {20, 20},
5575kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5576kDone_Verb
5577
5578skip degenerate if exact:
5579kMove_Verb {20, 20},
5580kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5581kMove_Verb {30, 30},
5582kLine_Verb {30, 30}, {30.00001, 30},
5583kDone_Verb
5584
5585skip none:
5586kMove_Verb {10, 10},
5587kMove_Verb {20, 20},
5588kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5589kMove_Verb {1, 1},
5590kClose_Verb {1, 1},
5591kMove_Verb {30, 30},
5592kLine_Verb {30, 30}, {30, 30},
5593kMove_Verb {30, 30},
5594kLine_Verb {30, 30}, {30.00001, 30},
5595kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005596##
5597##
5598
5599#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
5600
5601##
5602
5603#Method SkScalar conicWeight() const
5604
5605 Returns Conic_Weight if next() returned kConic_Verb.
5606
5607 If next() has not been called, or next() did not return kConic_Verb,
5608 result is undefined.
5609
Cary Clark73fa9722017-08-29 17:36:51 -04005610 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005611
5612 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005613 void draw(SkCanvas* canvas) {
5614 SkPath path;
5615 path.conicTo(1, 2, 3, 4, .5f);
5616 SkPath::Iter iter(path, false);
5617 SkPoint p[4];
5618 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5619 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5620 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5621 p[2].fX, p[2].fY);
5622 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005623 }
5624 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005625first verb is move
5626next verb is conic
5627conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005628conic weight: 0.5
5629 ##
5630 ##
5631
5632 #SeeAlso Conic_Weight
5633
5634##
5635
5636#Method bool isCloseLine() const
5637
5638 Returns true if last kLine_Verb returned by next() was generated
5639 by kClose_Verb. When true, the end point returned by next() is
5640 also the start point of Contour.
5641
5642 If next() has not been called, or next() did not return kLine_Verb,
5643 result is undefined.
5644
Cary Clark73fa9722017-08-29 17:36:51 -04005645 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005646
5647 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005648void draw(SkCanvas* canvas) {
5649 SkPath path;
5650 path.moveTo(6, 7);
5651 path.conicTo(1, 2, 3, 4, .5f);
5652 path.close();
5653 SkPath::Iter iter(path, false);
5654 SkPoint p[4];
5655 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5656 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5657 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5658 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5659 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5660 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5661 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005662}
5663 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040056641st verb is move
5665moveTo point: {6,7}
56662nd verb is conic
56673rd verb is line
5668line points: {3,4}, {6,7}
5669line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040056704th verb is close
5671 ##
5672 ##
5673
5674 #SeeAlso close()
5675##
5676
5677#Method bool isClosedContour() const
5678
5679Returns true if subsequent calls to next() return kClose_Verb before returning
5680kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5681Iter may have been initialized with force close set to true.
5682
Cary Clark73fa9722017-08-29 17:36:51 -04005683#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005684
5685#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005686void draw(SkCanvas* canvas) {
5687 for (bool forceClose : { false, true } ) {
5688 SkPath path;
5689 path.conicTo(1, 2, 3, 4, .5f);
5690 SkPath::Iter iter(path, forceClose);
5691 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5692 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5693 path.close();
5694 iter.setPath(path, forceClose);
5695 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5696 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5697 }
Cary Clark8032b982017-07-28 11:04:54 -04005698}
5699#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005700without close(), forceClose is false: isClosedContour returns false
5701with close(), forceClose is false: isClosedContour returns true
5702without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005703with close(), forceClose is true : isClosedContour returns true
5704##
5705##
5706
5707#SeeAlso Iter(const SkPath& path, bool forceClose)
5708
5709##
Cary Clark73fa9722017-08-29 17:36:51 -04005710
5711#Class Iter ##
5712
Cary Clark8032b982017-07-28 11:04:54 -04005713#Class RawIter
Cary Clark08895c42018-02-01 09:37:32 -05005714#Line # Path raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04005715
5716Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5717Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5718
Cary Clark73fa9722017-08-29 17:36:51 -04005719#Code
5720 class RawIter {
5721 public:
5722 RawIter();
5723 RawIter(const SkPath& path);
5724 void setPath(const SkPath& path);
5725 Verb next(SkPoint pts[4]);
5726 Verb peek() const;
5727 SkScalar conicWeight() const;
5728 }
5729##
5730
Cary Clark8032b982017-07-28 11:04:54 -04005731 #Method RawIter()
5732
5733 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
Cary Clark78c110e2018-02-09 16:49:09 -05005734 Call setPath to initialize SkPath::Iter at a later time.
Cary Clark8032b982017-07-28 11:04:54 -04005735
Cary Clark73fa9722017-08-29 17:36:51 -04005736 #Return RawIter of empty Path ##
5737
5738 #NoExample
5739 ##
5740 ##
Cary Clark8032b982017-07-28 11:04:54 -04005741
5742 #Method RawIter(const SkPath& path)
5743
5744
5745 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5746
Cary Clark73fa9722017-08-29 17:36:51 -04005747 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005748
Cary Clark73fa9722017-08-29 17:36:51 -04005749 #Return RawIter of path ##
5750
5751 #NoExample
5752 ##
5753 ##
Cary Clark8032b982017-07-28 11:04:54 -04005754
5755 #Method void setPath(const SkPath& path)
5756
Cary Clark78c110e2018-02-09 16:49:09 -05005757 Sets SkPath::Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
Cary Clark8032b982017-07-28 11:04:54 -04005758
Cary Clark73fa9722017-08-29 17:36:51 -04005759 #Param path Path to iterate ##
5760
5761 #NoExample
5762 ##
5763 ##
Cary Clark8032b982017-07-28 11:04:54 -04005764
5765 #Method Verb next(SkPoint pts[4])
5766
5767 Returns next Verb in Verb_Array, and advances RawIter.
5768 When Verb_Array is exhausted, returns kDone_Verb.
5769 Zero to four Points are stored in pts, depending on the returned Verb.
5770
Cary Clarka523d2d2017-08-30 08:58:10 -04005771 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005772
Cary Clark73fa9722017-08-29 17:36:51 -04005773 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005774
5775 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005776 void draw(SkCanvas* canvas) {
5777 SkPath path;
5778 path.moveTo(50, 60);
5779 path.quadTo(10, 20, 30, 40);
5780 path.close();
5781 path.lineTo(30, 30);
5782 path.conicTo(1, 2, 3, 4, .5f);
5783 path.cubicTo(-1, -2, -3, -4, -5, -6);
5784 SkPath::RawIter iter(path);
5785 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5786 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5787 SkPath::Verb verb;
5788 do {
5789 SkPoint points[4];
5790 verb = iter.next(points);
5791 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5792 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5793 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5794 }
5795 if (SkPath::kConic_Verb == verb) {
5796 SkDebugf("weight = %g", iter.conicWeight());
5797 }
5798 SkDebugf("\n");
5799 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005800 }
5801 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005802 kMove_Verb {50, 60},
5803 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5804 kClose_Verb {50, 60},
5805 kMove_Verb {50, 60},
5806 kLine_Verb {50, 60}, {30, 30},
5807 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
5808 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
Cary Clark8032b982017-07-28 11:04:54 -04005809 kDone_Verb
5810 ##
5811 ##
5812
5813 #SeeAlso peek()
5814
Cary Clark73fa9722017-08-29 17:36:51 -04005815 ##
Cary Clark8032b982017-07-28 11:04:54 -04005816
5817 #Method Verb peek() const
5818
5819 Returns next Verb, but does not advance RawIter.
5820
Cary Clark73fa9722017-08-29 17:36:51 -04005821 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005822
5823 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005824 SkPath path;
5825 path.quadTo(10, 20, 30, 40);
5826 path.conicTo(1, 2, 3, 4, .5f);
5827 path.cubicTo(1, 2, 3, 4, .5, 6);
5828 SkPath::RawIter iter(path);
5829 SkPath::Verb verb, peek = iter.peek();
5830 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5831 do {
5832 SkPoint points[4];
5833 verb = iter.next(points);
5834 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5835 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005836 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005837 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5838 #StdOut
5839 #Volatile
5840 peek Move == verb Move
5841 peek Quad == verb Quad
5842 peek Conic == verb Conic
5843 peek Cubic == verb Cubic
5844 peek Done == verb Done
5845 peek Done == verb Done
5846 ##
Cary Clark8032b982017-07-28 11:04:54 -04005847 ##
5848
5849 #Bug 6832
5850 StdOut isn't really volatile, it just produces the wrong result.
5851 A simple fix changes the output of hairlines and needs to be
5852 investigated to see if the change is correct or not.
5853 https://skia-review.googlesource.com/c/21340/
Cary Clark8032b982017-07-28 11:04:54 -04005854
5855 #SeeAlso next()
5856
Cary Clark73fa9722017-08-29 17:36:51 -04005857 ##
Cary Clark8032b982017-07-28 11:04:54 -04005858
Cary Clark73fa9722017-08-29 17:36:51 -04005859 #Method SkScalar conicWeight() const
5860
Cary Clark8032b982017-07-28 11:04:54 -04005861 Returns Conic_Weight if next() returned kConic_Verb.
5862
5863 If next() has not been called, or next() did not return kConic_Verb,
5864 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04005865
5866 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005867
5868 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005869 void draw(SkCanvas* canvas) {
5870 SkPath path;
5871 path.conicTo(1, 2, 3, 4, .5f);
5872 SkPath::RawIter iter(path);
5873 SkPoint p[4];
5874 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5875 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5876 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5877 p[2].fX, p[2].fY);
5878 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005879 }
5880 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005881 first verb is move
5882 next verb is conic
5883 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005884 conic weight: 0.5
5885 ##
5886 ##
5887
5888 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04005889
5890 ##
5891
5892#Class RawIter ##
5893
5894#Class SkPath ##
5895
5896#Topic Path ##
Cary Clark4855f782018-02-06 09:41:53 -05005897