blob: 0f9608617357d97ab0e9b015716ccda26ffff0c6 [file] [log] [blame]
Cary Clark73fa9722017-08-29 17:36:51 -04001#Topic Path
Cary Clark137b8742018-05-30 09:21:49 -04002#Alias Path_Reference ##
3#Alias Paths ##
Cary Clark73fa9722017-08-29 17:36:51 -04004
Cary Clark73fa9722017-08-29 17:36:51 -04005#Class SkPath
6
Cary Clark61313f32018-10-08 14:57:48 -04007#Code
8#Populate
9##
10
Cary Clark73fa9722017-08-29 17:36:51 -040011Paths contain geometry. Paths may be empty, or contain one or more Verbs that
Cary Clarka560c472017-11-27 10:44:06 -050012outline a figure. Path always starts with a move verb to a Cartesian_Coordinate,
13and may be followed by additional verbs that add lines or curves.
Cary Clark73fa9722017-08-29 17:36:51 -040014Adding a close verb makes the geometry into a continuous loop, a closed contour.
Cary Clarkce101242017-09-01 15:51:02 -040015Paths may contain any number of contours, each beginning with a move verb.
Cary Clark73fa9722017-08-29 17:36:51 -040016
17Path contours may contain only a move verb, or may also contain lines,
Cary Clarkce101242017-09-01 15:51:02 -040018Quadratic_Beziers, Conics, and Cubic_Beziers. Path contours may be open or
Cary Clark73fa9722017-08-29 17:36:51 -040019closed.
20
21When used to draw a filled area, Path describes whether the fill is inside or
22outside the geometry. Path also describes the winding rule used to fill
23overlapping contours.
24
25Internally, Path lazily computes metrics likes bounds and convexity. Call
Cary Clark682c58d2018-05-16 07:07:07 -040026SkPath::updateBoundsCache to make Path thread safe.
27
Cary Clark8032b982017-07-28 11:04:54 -040028#Subtopic Verb
Cary Clark137b8742018-05-30 09:21:49 -040029#Alias Verbs ##
Cary Clark08895c42018-02-01 09:37:32 -050030#Line # line and curve type ##
Cary Clark73fa9722017-08-29 17:36:51 -040031#Enum Verb
Cary Clark08895c42018-02-01 09:37:32 -050032#Line # controls how Path Points are interpreted ##
Cary Clark73fa9722017-08-29 17:36:51 -040033
34#Code
35 enum Verb {
Cary Clark682c58d2018-05-16 07:07:07 -040036 kMove_Verb,
37 kLine_Verb,
38 kQuad_Verb,
39 kConic_Verb,
40 kCubic_Verb,
41 kClose_Verb,
42 kDone_Verb,
Cary Clark73fa9722017-08-29 17:36:51 -040043 };
44##
45
46Verb instructs Path how to interpret one or more Point and optional Conic_Weight;
Cary Clark8032b982017-07-28 11:04:54 -040047manage Contour, and terminate Path.
48
Cary Clark73fa9722017-08-29 17:36:51 -040049#Const kMove_Verb 0
Cary Clark682c58d2018-05-16 07:07:07 -040050#Line # starts new Contour at next Point ##
51 Consecutive kMove_Verb are preserved but all but the last kMove_Verb is
52 ignored. kMove_Verb after other Verbs implicitly closes the previous Contour
53 if SkPaint::kFill_Style is set when drawn; otherwise, stroke is drawn open.
54 kMove_Verb as the last Verb is preserved but ignored.
Cary Clark73fa9722017-08-29 17:36:51 -040055##
56#Const kLine_Verb 1
Cary Clark682c58d2018-05-16 07:07:07 -040057#Line # adds Line from Last_Point to next Point ##
58 Line is a straight segment from Point to Point. Consecutive kLine_Verb
59 extend Contour. kLine_Verb at same position as prior kMove_Verb is
60 preserved, and draws Point if SkPaint::kStroke_Style is set, and
61 SkPaint::Cap is SkPaint::kSquare_Cap or SkPaint::kRound_Cap. kLine_Verb
62 at same position as prior line or curve Verb is preserved but is ignored.
Cary Clark73fa9722017-08-29 17:36:51 -040063##
64#Const kQuad_Verb 2
Cary Clark682c58d2018-05-16 07:07:07 -040065#Line # adds Quad from Last_Point ##
66 Adds Quad from Last_Point, using control Point, and end Point.
Cary Clark73fa9722017-08-29 17:36:51 -040067 Quad is a parabolic section within tangents from Last_Point to control Point,
68 and control Point to end Point.
69##
70#Const kConic_Verb 3
Cary Clark682c58d2018-05-16 07:07:07 -040071#Line # adds Conic from Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -040072 Adds Conic from Last_Point, using control Point, end Point, and Conic_Weight.
Cary Clark682c58d2018-05-16 07:07:07 -040073 Conic is a elliptical, parabolic, or hyperbolic section within tangents
Cary Clark73fa9722017-08-29 17:36:51 -040074 from Last_Point to control Point, and control Point to end Point, constrained
75 by Conic_Weight. Conic_Weight less than one is elliptical; equal to one is
76 parabolic (and identical to Quad); greater than one hyperbolic.
77##
78#Const kCubic_Verb 4
Cary Clark682c58d2018-05-16 07:07:07 -040079#Line # adds Cubic from Last_Point ##
80 Adds Cubic from Last_Point, using two control Points, and end Point.
Cary Clarka560c472017-11-27 10:44:06 -050081 Cubic is a third-order Bezier_Curve section within tangents from Last_Point
82 to first control Point, and from second control Point to end Point.
Cary Clark73fa9722017-08-29 17:36:51 -040083##
84#Const kClose_Verb 5
Cary Clark682c58d2018-05-16 07:07:07 -040085#Line # closes Contour ##
86 Closes Contour, connecting Last_Point to kMove_Verb Point. Consecutive
87 kClose_Verb are preserved but only first has an effect. kClose_Verb after
88 kMove_Verb has no effect.
Cary Clark73fa9722017-08-29 17:36:51 -040089##
90#Const kDone_Verb 6
Cary Clark682c58d2018-05-16 07:07:07 -040091#Line # terminates Path ##
92 Not in Verb_Array, but returned by Path iterator.
Cary Clark8032b982017-07-28 11:04:54 -040093##
94
95Each Verb has zero or more Points stored in Path.
96Path iterator returns complete curve descriptions, duplicating shared Points
97for consecutive entries.
98
99#Table
100#Legend
101# Verb # Allocated Points # Iterated Points # Weights ##
102##
103# kMove_Verb # 1 # 1 # 0 ##
104# kLine_Verb # 1 # 2 # 0 ##
105# kQuad_Verb # 2 # 3 # 0 ##
106# kConic_Verb # 2 # 3 # 1 ##
107# kCubic_Verb # 3 # 4 # 0 ##
108# kClose_Verb # 0 # 1 # 0 ##
109# kDone_Verb # -- # 0 # 0 ##
110##
Cary Clark73fa9722017-08-29 17:36:51 -0400111
112#Example
113void draw(SkCanvas* canvas) {
114 SkPath path;
115 path.lineTo(20, 20);
116 path.quadTo(-10, -10, 30, 30);
117 path.close();
118 path.cubicTo(1, 2, 3, 4, 5, 6);
119 path.conicTo(0, 0, 0, 0, 2);
120 uint8_t verbs[7];
121 int count = path.getVerbs(verbs, (int) SK_ARRAY_COUNT(verbs));
122 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close" };
123 SkDebugf("verb count: %d\nverbs: ", count);
124 for (int i = 0; i < count; ++i) {
125 SkDebugf("k%s_Verb ", verbStr[verbs[i]]);
126 }
127 SkDebugf("\n");
128}
129#StdOut
130verb count: 7
Cary Clark682c58d2018-05-16 07:07:07 -0400131verbs: kMove_Verb kLine_Verb kQuad_Verb kClose_Verb kMove_Verb kCubic_Verb kConic_Verb
Cary Clark73fa9722017-08-29 17:36:51 -0400132##
133##
134
135#Enum Verb ##
136#Subtopic Verb ##
137
138# ------------------------------------------------------------------------------
139#Subtopic Direction
Cary Clark682c58d2018-05-16 07:07:07 -0400140#Line # contour orientation, clockwise or counterclockwise ##
Cary Clark137b8742018-05-30 09:21:49 -0400141#Alias Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400142
143#Enum Direction
Cary Clark08895c42018-02-01 09:37:32 -0500144#Line # sets Contour clockwise or counterclockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400145
146#Code
Mike Klein36743362018-11-06 08:23:30 -0500147 enum Direction : int {
Cary Clark682c58d2018-05-16 07:07:07 -0400148 kCW_Direction,
149 kCCW_Direction,
Cary Clark73fa9722017-08-29 17:36:51 -0400150 };
151##
152
153Direction describes whether Contour is clockwise or counterclockwise.
154When Path contains multiple overlapping Contours, Direction together with
155Fill_Type determines whether overlaps are filled or form holes.
156
157Direction also determines how Contour is measured. For instance, dashing
158measures along Path to determine where to start and stop stroke; Direction
159will change dashed results as it steps clockwise or counterclockwise.
160
Cary Clark682c58d2018-05-16 07:07:07 -0400161Closed Contours like Rect, Round_Rect, Circle, and Oval added with
Cary Clark73fa9722017-08-29 17:36:51 -0400162kCW_Direction travel clockwise; the same added with kCCW_Direction
163travel counterclockwise.
164
165#Const kCW_Direction 0
Cary Clark682c58d2018-05-16 07:07:07 -0400166#Line # contour travels clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400167##
168#Const kCCW_Direction 1
Cary Clark682c58d2018-05-16 07:07:07 -0400169#Line # contour travels counterclockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -0400170##
171
172
173#Example
174#Height 100
175void draw(SkCanvas* canvas) {
176 const SkPoint arrow[] = { {40, -5}, {45, 0}, {40, 5} };
177 const SkRect rect = {10, 10, 90, 90};
178 SkPaint rectPaint;
179 rectPaint.setAntiAlias(true);
180 SkPaint textPaint(rectPaint);
Cary Clark73fa9722017-08-29 17:36:51 -0400181 rectPaint.setStyle(SkPaint::kStroke_Style);
182 SkPaint arrowPaint(rectPaint);
183 SkPath arrowPath;
184 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
185 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 320, 0,
186 SkPath1DPathEffect::kRotate_Style));
187 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
188 canvas->drawRect(rect, rectPaint);
189 for (unsigned start : { 0, 1, 2, 3 } ) {
190 SkPath path;
191 path.addRect(rect, direction, start);
192 canvas->drawPath(path, arrowPaint);
193 }
194 canvas->drawString(SkPath::kCW_Direction == direction ? "CW" : "CCW", rect.centerX(),
195 rect.centerY(), textPaint);
196 canvas->translate(120, 0);
197 }
198}
199##
200
Cary Clark682c58d2018-05-16 07:07:07 -0400201#SeeAlso arcTo rArcTo isRect isNestedFillRects addRect addOval
Cary Clark73fa9722017-08-29 17:36:51 -0400202
203#Enum Direction ##
204#Subtopic Direction ##
205
206# ------------------------------------------------------------------------------
207
208#Method SkPath()
Cary Clark61313f32018-10-08 14:57:48 -0400209#In Constructors
Cary Clarkab2621d2018-01-30 10:08:57 -0500210#Line # constructs with default values ##
Cary Clark09d80c02018-10-31 12:14:03 -0400211#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400212
213#Example
214 SkPath path;
215 SkDebugf("path is " "%s" "empty", path.isEmpty() ? "" : "not ");
216#StdOut
217path is empty
218##
219##
220
221#SeeAlso reset rewind
222
223##
224
225# ------------------------------------------------------------------------------
226
227#Method SkPath(const SkPath& path)
Cary Clark61313f32018-10-08 14:57:48 -0400228#In Constructors
Cary Clarkab2621d2018-01-30 10:08:57 -0500229#Line # makes a shallow copy ##
Cary Clark09d80c02018-10-31 12:14:03 -0400230#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400231
232#Example
233#Description
234 Modifying one path does not effect another, even if they started as copies
235 of each other.
236##
237 SkPath path;
238 path.lineTo(20, 20);
239 SkPath path2(path);
240 path2.close();
241 SkDebugf("path verbs: %d\n", path.countVerbs());
242 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
243 path.reset();
244 SkDebugf("after reset\n" "path verbs: %d\n", path.countVerbs());
245 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
246#StdOut
247path verbs: 2
248path2 verbs: 3
249after reset
250path verbs: 0
251path2 verbs: 3
252##
253##
254
255#SeeAlso operator=(const SkPath& path)
256
257##
258
259# ------------------------------------------------------------------------------
260
261#Method ~SkPath()
262
Cary Clarkab2621d2018-01-30 10:08:57 -0500263#Line # decreases Reference_Count of owned objects ##
Cary Clark09d80c02018-10-31 12:14:03 -0400264#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400265
266#Example
267#Description
Cary Clark09d80c02018-10-31 12:14:03 -0400268delete calls Path destructor, but copy of original in path2 is unaffected.
Cary Clark73fa9722017-08-29 17:36:51 -0400269##
270void draw(SkCanvas* canvas) {
271 SkPath* path = new SkPath();
272 path->lineTo(20, 20);
273 SkPath path2(*path);
274 delete path;
275 SkDebugf("path2 is " "%s" "empty", path2.isEmpty() ? "" : "not ");
276}
277##
278
279#SeeAlso SkPath() SkPath(const SkPath& path) operator=(const SkPath& path)
280
281##
282
283# ------------------------------------------------------------------------------
284
285#Method SkPath& operator=(const SkPath& path)
286
Cary Clarkab2621d2018-01-30 10:08:57 -0500287#Line # makes a shallow copy ##
Cary Clark09d80c02018-10-31 12:14:03 -0400288#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400289
290#Example
291SkPath path1;
292path1.addRect({10, 20, 30, 40});
293SkPath path2 = path1;
294const SkRect& b1 = path1.getBounds();
295SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
296const SkRect& b2 = path2.getBounds();
297SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
298#StdOut
299path1 bounds = 10, 20, 30, 40
300path2 bounds = 10, 20, 30, 40
301#StdOut ##
302##
303
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400304#SeeAlso swap SkPath(const SkPath& path)
Cary Clark73fa9722017-08-29 17:36:51 -0400305
306##
307
308# ------------------------------------------------------------------------------
309
310#Method bool operator==(const SkPath& a, const SkPath& b)
311
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400312#Line # compares Paths for equality ##
Cary Clark09d80c02018-10-31 12:14:03 -0400313#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400314
315#Example
316#Description
317Rewind removes Verb_Array but leaves storage; since storage is not compared,
318Path pair are equivalent.
319##
320void draw(SkCanvas* canvas) {
321 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
322 SkDebugf("%s one %c= two\n", prefix, a == b ? '=' : '!');
323 };
324 SkPath one;
325 SkPath two;
326 debugster("empty", one, two);
327 one.moveTo(0, 0);
328 debugster("moveTo", one, two);
329 one.rewind();
330 debugster("rewind", one, two);
331 one.moveTo(0, 0);
332 one.reset();
333 debugster("reset", one, two);
334}
335#StdOut
336empty one == two
337moveTo one != two
338rewind one == two
339reset one == two
340##
341##
342
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400343#SeeAlso operator!=(const SkPath& a, const SkPath& b) operator=(const SkPath& path)
344
Cary Clark73fa9722017-08-29 17:36:51 -0400345##
346
347# ------------------------------------------------------------------------------
348
Cary Clark682c58d2018-05-16 07:07:07 -0400349#Method bool operator!=(const SkPath& a, const SkPath& b)
Cary Clark73fa9722017-08-29 17:36:51 -0400350
Cary Clarkab2621d2018-01-30 10:08:57 -0500351#Line # compares paths for inequality ##
Cary Clark09d80c02018-10-31 12:14:03 -0400352#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400353
354#Example
355#Description
356Path pair are equal though their convexity is not equal.
357##
358void draw(SkCanvas* canvas) {
359 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
360 SkDebugf("%s one %c= two\n", prefix, a != b ? '!' : '=');
361 };
362 SkPath one;
363 SkPath two;
364 debugster("empty", one, two);
365 one.addRect({10, 20, 30, 40});
366 two.addRect({10, 20, 30, 40});
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400367 debugster("add rect", one, two);
Cary Clark73fa9722017-08-29 17:36:51 -0400368 one.setConvexity(SkPath::kConcave_Convexity);
369 debugster("setConvexity", one, two);
370 SkDebugf("convexity %c=\n", one.getConvexity() == two.getConvexity() ? '=' : '!');
371}
372#StdOut
373empty one == two
Cary Clarkd2ca79c2018-08-10 13:09:13 -0400374add rect one == two
Cary Clark73fa9722017-08-29 17:36:51 -0400375setConvexity one == two
376convexity !=
377##
378##
379
380##
381
382# ------------------------------------------------------------------------------
383
Cary Clark4855f782018-02-06 09:41:53 -0500384#Subtopic Property
Cary Clark4855f782018-02-06 09:41:53 -0500385#Line # metrics and attributes ##
386##
Cary Clark73fa9722017-08-29 17:36:51 -0400387
Cary Clark4855f782018-02-06 09:41:53 -0500388#Method bool isInterpolatable(const SkPath& compare) const
389#In Property
390#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500391#Line # returns if pair contains equal counts of Verb_Array and Weights ##
Cary Clark09d80c02018-10-31 12:14:03 -0400392#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400393
394#Example
395 SkPath path, path2;
396 path.moveTo(20, 20);
397 path.lineTo(40, 40);
398 path.lineTo(20, 20);
399 path.lineTo(40, 40);
400 path.close();
401 path2.addRect({20, 20, 40, 40});
402 SkDebugf("paths are " "%s" "interpolatable", path.isInterpolatable(path2) ? "" : "not ");
403#StdOut
404paths are interpolatable
405##
406##
407
408#SeeAlso isInterpolatable
409
410##
411
412# ------------------------------------------------------------------------------
413
Cary Clark4855f782018-02-06 09:41:53 -0500414#Subtopic Interpolate
Cary Clark4855f782018-02-06 09:41:53 -0500415#Line # weighted average of Path pair ##
416##
Cary Clark73fa9722017-08-29 17:36:51 -0400417
Cary Clark4855f782018-02-06 09:41:53 -0500418#Method bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const
419#In Interpolate
Cary Clarkab2621d2018-01-30 10:08:57 -0500420#Line # interpolates between Path pair ##
Cary Clark80247e52018-07-11 16:18:41 -0400421Interpolates between Paths with Point_Array of equal size.
Cary Clark61dfc3a2018-01-03 08:37:53 -0500422Copy Verb_Array and Weights to out, and set out Point_Array to a weighted
423average of this Point_Array and ending Point_Array, using the formula:
Cary Clark2be81cf2018-09-13 12:04:30 -0400424#Formula # (Path Point * weight) + ending Point * (1 - weight) ##.
Cary Clark73fa9722017-08-29 17:36:51 -0400425
Cary Clark682c58d2018-05-16 07:07:07 -0400426weight is most useful when between zero (ending Point_Array) and
427one (this Point_Array); will work with values outside of this
Cary Clark73fa9722017-08-29 17:36:51 -0400428range.
429
430interpolate() returns false and leaves out unchanged if Point_Array is not
Cary Clark682c58d2018-05-16 07:07:07 -0400431the same size as ending Point_Array. Call isInterpolatable to check Path
Cary Clark73fa9722017-08-29 17:36:51 -0400432compatibility prior to calling interpolate().
433
434#Param ending Point_Array averaged with this Point_Array ##
Cary Clark682c58d2018-05-16 07:07:07 -0400435#Param weight contribution of this Point_Array, and
436 one minus contribution of ending Point_Array
Cary Clark73fa9722017-08-29 17:36:51 -0400437##
438#Param out Path replaced by interpolated averages ##
439
440#Return true if Paths contain same number of Points ##
441
442#Example
443#Height 60
444void draw(SkCanvas* canvas) {
445 SkPaint paint;
446 paint.setAntiAlias(true);
447 paint.setStyle(SkPaint::kStroke_Style);
448 SkPath path, path2;
449 path.moveTo(20, 20);
450 path.lineTo(40, 40);
451 path.lineTo(20, 40);
452 path.lineTo(40, 20);
453 path.close();
454 path2.addRect({20, 20, 40, 40});
455 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
456 SkPath interp;
457 path.interpolate(path2, i, &interp);
458 canvas->drawPath(interp, paint);
459 canvas->translate(30, 0);
460 }
461}
462##
463
464#SeeAlso isInterpolatable
465
466##
467
468# ------------------------------------------------------------------------------
469
Cary Clark682c58d2018-05-16 07:07:07 -0400470#Method bool unique() const
Cary Clark4855f782018-02-06 09:41:53 -0500471#Deprecated soon
472Only valid for Android framework.
Cary Clark73fa9722017-08-29 17:36:51 -0400473##
474
475# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400476#Subtopic Fill_Type
Cary Clark682c58d2018-05-16 07:07:07 -0400477#Line # fill rule, normal and inverted ##
Cary Clark8032b982017-07-28 11:04:54 -0400478
Cary Clark73fa9722017-08-29 17:36:51 -0400479#Enum FillType
Cary Clark08895c42018-02-01 09:37:32 -0500480#Line # sets winding rule and inverse fill ##
Cary Clark73fa9722017-08-29 17:36:51 -0400481
482#Code
483 enum FillType {
Cary Clark682c58d2018-05-16 07:07:07 -0400484 kWinding_FillType,
485 kEvenOdd_FillType,
486 kInverseWinding_FillType,
487 kInverseEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400488 };
489##
Cary Clark8032b982017-07-28 11:04:54 -0400490
Cary Clark682c58d2018-05-16 07:07:07 -0400491Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
Cary Clark8032b982017-07-28 11:04:54 -0400492fills if the sum of Contour edges is not zero, where clockwise edges add one, and
493counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
Cary Clark682c58d2018-05-16 07:07:07 -0400494number of Contour edges is odd. Each Fill_Type has an inverse variant that
Cary Clark8032b982017-07-28 11:04:54 -0400495reverses the rule:
496kInverseWinding_FillType fills where the sum of Contour edges is zero;
497kInverseEvenOdd_FillType fills where the number of Contour edges is even.
498
499#Example
500#Height 100
501#Description
502The top row has two clockwise rectangles. The second row has one clockwise and
503one counterclockwise rectangle. The even-odd variants draw the same. The
504winding variants draw the top rectangle overlap, which has a winding of 2, the
505same as the outer parts of the top rectangles, which have a winding of 1.
506##
Cary Clark73fa9722017-08-29 17:36:51 -0400507void draw(SkCanvas* canvas) {
508 SkPath path;
509 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
510 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
511 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
512 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
513 SkPaint strokePaint;
514 strokePaint.setStyle(SkPaint::kStroke_Style);
515 SkRect clipRect = {0, 0, 51, 100};
516 canvas->drawPath(path, strokePaint);
517 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400518 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400519 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
520 canvas->translate(51, 0);
521 canvas->save();
522 canvas->clipRect(clipRect);
523 path.setFillType(fillType);
524 canvas->drawPath(path, fillPaint);
525 canvas->restore();
526 }
Cary Clark8032b982017-07-28 11:04:54 -0400527}
528##
Cary Clark73fa9722017-08-29 17:36:51 -0400529
530#Const kWinding_FillType 0
Cary Clark682c58d2018-05-16 07:07:07 -0400531#Line # is enclosed by a non-zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400532##
533#Const kEvenOdd_FillType 1
Cary Clark682c58d2018-05-16 07:07:07 -0400534#Line # is enclosed by an odd number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400535##
536#Const kInverseWinding_FillType 2
Cary Clark682c58d2018-05-16 07:07:07 -0400537#Line # is enclosed by a zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400538##
539#Const kInverseEvenOdd_FillType 3
Cary Clark682c58d2018-05-16 07:07:07 -0400540#Line # is enclosed by an even number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400541##
542
543#Example
544#Height 230
545void draw(SkCanvas* canvas) {
546 SkPath path;
547 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
548 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
549 SkPaint strokePaint;
550 strokePaint.setStyle(SkPaint::kStroke_Style);
551 SkRect clipRect = {0, 0, 128, 128};
552 canvas->drawPath(path, strokePaint);
553 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
554 SkPaint textPaint;
555 textPaint.setAntiAlias(true);
Cary Clark73fa9722017-08-29 17:36:51 -0400556 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
557 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
558 textPaint.setTextSize(18);
559 canvas->translate(0, 128);
560 canvas->scale(.5f, .5f);
561 canvas->drawString("inverse", 384, 150, textPaint);
562 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400563 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400564 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
565 canvas->save();
566 canvas->clipRect(clipRect);
567 path.setFillType(fillType);
568 canvas->drawPath(path, fillPaint);
569 canvas->restore();
570 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
571 canvas->translate(128, 0);
572 }
573}
574##
575
576#SeeAlso SkPaint::Style Direction getFillType setFillType
577
578##
579
580# ------------------------------------------------------------------------------
581
Cary Clark682c58d2018-05-16 07:07:07 -0400582#Method FillType getFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400583
Cary Clarkab2621d2018-01-30 10:08:57 -0500584#In Fill_Type
585#Line # returns Fill_Type: winding, even-odd, inverse ##
Cary Clark09d80c02018-10-31 12:14:03 -0400586#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400587
588#Example
589 SkPath path;
590 SkDebugf("default path fill type is %s\n",
591 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
Cary Clark682c58d2018-05-16 07:07:07 -0400592 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
Cary Clark73fa9722017-08-29 17:36:51 -0400593 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
594 "kInverseEvenOdd_FillType");
595#StdOut
596default path fill type is kWinding_FillType
597##
598##
599
600#SeeAlso FillType setFillType isInverseFillType
601
602##
603
604# ------------------------------------------------------------------------------
605
Cary Clark682c58d2018-05-16 07:07:07 -0400606#Method void setFillType(FillType ft)
Cary Clark73fa9722017-08-29 17:36:51 -0400607
Cary Clarkab2621d2018-01-30 10:08:57 -0500608#In Fill_Type
609#Line # sets Fill_Type: winding, even-odd, inverse ##
Cary Clark09d80c02018-10-31 12:14:03 -0400610#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400611
612#Example
613#Description
614If empty Path is set to inverse FillType, it fills all pixels.
615##
616#Height 64
617 SkPath path;
618 path.setFillType(SkPath::kInverseWinding_FillType);
619 SkPaint paint;
620 paint.setColor(SK_ColorBLUE);
621 canvas->drawPath(path, paint);
622##
623
624#SeeAlso FillType getFillType toggleInverseFillType
625
626##
627
628# ------------------------------------------------------------------------------
629
Cary Clark682c58d2018-05-16 07:07:07 -0400630#Method bool isInverseFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400631
Cary Clarkab2621d2018-01-30 10:08:57 -0500632#In Fill_Type
633#Line # returns if Fill_Type fills outside geometry ##
Cary Clark09d80c02018-10-31 12:14:03 -0400634#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400635
636#Example
637 SkPath path;
638 SkDebugf("default path fill type is inverse: %s\n",
639 path.isInverseFillType() ? "true" : "false");
640#StdOut
641default path fill type is inverse: false
642##
643##
644
645#SeeAlso FillType getFillType setFillType toggleInverseFillType
646
647##
648
649# ------------------------------------------------------------------------------
650
Cary Clark682c58d2018-05-16 07:07:07 -0400651#Method void toggleInverseFillType()
Cary Clark73fa9722017-08-29 17:36:51 -0400652
Cary Clarkab2621d2018-01-30 10:08:57 -0500653#In Fill_Type
654#Line # toggles Fill_Type between inside and outside geometry ##
Cary Clark80247e52018-07-11 16:18:41 -0400655Replaces FillType with its inverse. The inverse of FillType describes the area
Cary Clark73fa9722017-08-29 17:36:51 -0400656unmodified by the original FillType.
657
Cary Clark682c58d2018-05-16 07:07:07 -0400658#Table
Cary Clark73fa9722017-08-29 17:36:51 -0400659#Legend
Cary Clark682c58d2018-05-16 07:07:07 -0400660# FillType # toggled FillType ##
Cary Clark73fa9722017-08-29 17:36:51 -0400661##
662# kWinding_FillType # kInverseWinding_FillType ##
663# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
664# kInverseWinding_FillType # kWinding_FillType ##
665# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
666##
667
668#Example
669#Description
670Path drawn normally and through its inverse touches every pixel once.
671##
672#Height 100
673SkPath path;
674SkPaint paint;
675paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -0400676paint.setTextSize(80);
677paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -0400678canvas->drawPath(path, paint);
679path.toggleInverseFillType();
680paint.setColor(SK_ColorGREEN);
681canvas->drawPath(path, paint);
682##
683
684#SeeAlso FillType getFillType setFillType isInverseFillType
685
686##
687
Cary Clark8032b982017-07-28 11:04:54 -0400688#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400689
690# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400691
692#Subtopic Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500693#Line # if Path is concave or convex ##
Cary Clark73fa9722017-08-29 17:36:51 -0400694
695#Enum Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500696#Line # returns if Path is convex or concave ##
Cary Clark73fa9722017-08-29 17:36:51 -0400697
698#Code
Cary Clark884dd7d2017-10-11 10:37:52 -0400699 enum Convexity : uint8_t {
Cary Clark682c58d2018-05-16 07:07:07 -0400700 kUnknown_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400701 kConvex_Convexity,
Cary Clark682c58d2018-05-16 07:07:07 -0400702 kConcave_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400703 };
704##
705
Cary Clark682c58d2018-05-16 07:07:07 -0400706Path is convex if it contains one Contour and Contour loops no more than
707360 degrees, and Contour angles all have same Direction. Convex Path
Cary Clark8032b982017-07-28 11:04:54 -0400708may have better performance and require fewer resources on GPU_Surface.
709
Cary Clark73fa9722017-08-29 17:36:51 -0400710Path is concave when either at least one Direction change is clockwise and
711another is counterclockwise, or the sum of the changes in Direction is not 360
712degrees.
713
Cary Clark682c58d2018-05-16 07:07:07 -0400714Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
Cary Clark73fa9722017-08-29 17:36:51 -0400715if needed by destination Surface.
716
717#Const kUnknown_Convexity 0
Cary Clark682c58d2018-05-16 07:07:07 -0400718#Line # indicates Convexity has not been determined ##
Cary Clark73fa9722017-08-29 17:36:51 -0400719##
720#Const kConvex_Convexity 1
Cary Clark682c58d2018-05-16 07:07:07 -0400721#Line # one Contour made of a simple geometry without indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400722##
723#Const kConcave_Convexity 2
Cary Clark682c58d2018-05-16 07:07:07 -0400724#Line # more than one Contour, or a geometry with indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400725##
726
727#Example
728void draw(SkCanvas* canvas) {
729 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400730 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400731 const char* labels[] = { "unknown", "convex", "concave" };
732 for (SkScalar x : { 40, 100 } ) {
733 SkPath path;
734 quad[0].fX = x;
735 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
736 canvas->drawPath(path, paint);
737 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
738 canvas->translate(100, 100);
739 }
740}
741##
742
743#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
744
745#Enum Convexity ##
746
Cary Clark682c58d2018-05-16 07:07:07 -0400747#Method Convexity getConvexity() const
Cary Clark73fa9722017-08-29 17:36:51 -0400748
Cary Clarkab2621d2018-01-30 10:08:57 -0500749#In Convexity
750#Line # returns geometry convexity, computing if necessary ##
Cary Clark09d80c02018-10-31 12:14:03 -0400751#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400752
753#Example
754void draw(SkCanvas* canvas) {
755 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -0400756 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -0400757 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
758 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
759 SkPath path;
760 debugster("initial", path);
761 path.lineTo(50, 0);
762 debugster("first line", path);
763 path.lineTo(50, 50);
764 debugster("second line", path);
765 path.lineTo(100, 50);
766 debugster("third line", path);
767}
768##
769
770#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
771
772##
773
774# ------------------------------------------------------------------------------
775
Cary Clark682c58d2018-05-16 07:07:07 -0400776#Method Convexity getConvexityOrUnknown() const
Cary Clark73fa9722017-08-29 17:36:51 -0400777
Cary Clarkab2621d2018-01-30 10:08:57 -0500778#In Convexity
779#Line # returns geometry convexity if known ##
Cary Clark09d80c02018-10-31 12:14:03 -0400780#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400781
782#Example
783#Description
784Convexity is unknown unless getConvexity is called without a subsequent call
785that alters the path.
786##
787void draw(SkCanvas* canvas) {
788 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -0400789 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -0400790 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
791 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
792 SkPath path;
793 debugster("initial", path);
794 path.lineTo(50, 0);
795 debugster("first line", path);
796 path.getConvexity();
797 path.lineTo(50, 50);
798 debugster("second line", path);
799 path.lineTo(100, 50);
800 path.getConvexity();
801 debugster("third line", path);
802}
803##
804
805#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
806
807##
808
809# ------------------------------------------------------------------------------
810
811#Method void setConvexity(Convexity convexity)
812
Cary Clarkab2621d2018-01-30 10:08:57 -0500813#In Convexity
814#Line # sets if geometry is convex to avoid future computation ##
Cary Clark09d80c02018-10-31 12:14:03 -0400815#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400816
817#Example
818void draw(SkCanvas* canvas) {
819 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -0400820 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -0400821 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
822 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
Cary Clark682c58d2018-05-16 07:07:07 -0400823 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400824 SkPath path;
825 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
826 debugster("initial", path);
827 path.setConvexity(SkPath::kConcave_Convexity);
828 debugster("after forcing concave", path);
829 path.setConvexity(SkPath::kUnknown_Convexity);
830 debugster("after forcing unknown", path);
831}
832##
833
834#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
835
836##
837
838# ------------------------------------------------------------------------------
839
Cary Clark682c58d2018-05-16 07:07:07 -0400840#Method bool isConvex() const
Cary Clark73fa9722017-08-29 17:36:51 -0400841
Cary Clarkab2621d2018-01-30 10:08:57 -0500842#In Convexity
843#Line # returns if geometry is convex ##
Cary Clark09d80c02018-10-31 12:14:03 -0400844#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400845
846#Example
847#Description
Cary Clark682c58d2018-05-16 07:07:07 -0400848Concave shape is erroneously considered convex after a forced call to
Cary Clark73fa9722017-08-29 17:36:51 -0400849setConvexity.
850##
851void draw(SkCanvas* canvas) {
852 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400853 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400854 for (SkScalar x : { 40, 100 } ) {
855 SkPath path;
856 quad[0].fX = x;
857 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
858 path.setConvexity(SkPath::kConvex_Convexity);
859 canvas->drawPath(path, paint);
860 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
861 canvas->translate(100, 100);
862 }
863}
864##
865
866#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
867
868##
869
Cary Clark73fa9722017-08-29 17:36:51 -0400870#Subtopic Convexity ##
871
872# ------------------------------------------------------------------------------
873
Mike Reed0c3137c2018-02-20 13:57:05 -0500874#Method bool isOval(SkRect* bounds) const
Cary Clark4855f782018-02-06 09:41:53 -0500875#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -0500876#Line # returns if describes Oval ##
Cary Clark09d80c02018-10-31 12:14:03 -0400877#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400878
879#Example
880void draw(SkCanvas* canvas) {
881 SkPaint paint;
882 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -0500883 path.addOval({20, 20, 220, 220});
Cary Clark73fa9722017-08-29 17:36:51 -0400884 SkRect bounds;
Mike Reed0c3137c2018-02-20 13:57:05 -0500885 if (path.isOval(&bounds)) {
886 paint.setColor(0xFF9FBFFF);
887 canvas->drawRect(bounds, paint);
888 }
Cary Clark73fa9722017-08-29 17:36:51 -0400889 paint.setColor(0x3f000000);
890 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -0400891}
892##
893
894#SeeAlso Oval addCircle addOval
895
896##
897
898# ------------------------------------------------------------------------------
899
Mike Reed0c3137c2018-02-20 13:57:05 -0500900#Method bool isRRect(SkRRect* rrect) const
Cary Clark4855f782018-02-06 09:41:53 -0500901#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -0500902#Line # returns if describes Round_Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -0400903#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400904
905#Example
Cary Clarkce101242017-09-01 15:51:02 -0400906#Description
Mike Reed0c3137c2018-02-20 13:57:05 -0500907Draw rounded rectangle and its bounds.
Cary Clarkce101242017-09-01 15:51:02 -0400908##
Cary Clark73fa9722017-08-29 17:36:51 -0400909void draw(SkCanvas* canvas) {
910 SkPaint paint;
911 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -0500912 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50));
Cary Clark73fa9722017-08-29 17:36:51 -0400913 SkRRect rrect;
Mike Reed0c3137c2018-02-20 13:57:05 -0500914 if (path.isRRect(&rrect)) {
915 const SkRect& bounds = rrect.rect();
916 paint.setColor(0xFF9FBFFF);
917 canvas->drawRect(bounds, paint);
918 }
Cary Clark73fa9722017-08-29 17:36:51 -0400919 paint.setColor(0x3f000000);
920 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -0400921}
922##
923
Cary Clark682c58d2018-05-16 07:07:07 -0400924#SeeAlso Round_Rect addRoundRect addRRect
Cary Clark73fa9722017-08-29 17:36:51 -0400925
926##
927
928# ------------------------------------------------------------------------------
929
Cary Clark0251b1b2018-08-15 15:14:55 -0400930#Method SkPath& reset()
Cary Clark61313f32018-10-08 14:57:48 -0400931#In Constructors
Cary Clarkab2621d2018-01-30 10:08:57 -0500932#Line # removes Verb_Array, Point_Array, and Weights; frees memory ##
Cary Clark09d80c02018-10-31 12:14:03 -0400933#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -0400934
Cary Clark73fa9722017-08-29 17:36:51 -0400935#Example
936 SkPath path1, path2;
937 path1.setFillType(SkPath::kInverseWinding_FillType);
938 path1.addRect({10, 20, 30, 40});
939 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
940 path1.reset();
941 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
942##
943
944#SeeAlso rewind()
945
946##
947
948# ------------------------------------------------------------------------------
949
Cary Clark0251b1b2018-08-15 15:14:55 -0400950#Method SkPath& rewind()
Cary Clark61313f32018-10-08 14:57:48 -0400951#In Constructors
Cary Clarkab2621d2018-01-30 10:08:57 -0500952#Line # removes Verb_Array, Point_Array, and Weights, keeping memory ##
Cary Clark09d80c02018-10-31 12:14:03 -0400953#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -0400954
Cary Clark73fa9722017-08-29 17:36:51 -0400955#Example
956#Description
957Although path1 retains its internal storage, it is indistinguishable from
958a newly initialized path.
959##
960 SkPath path1, path2;
961 path1.setFillType(SkPath::kInverseWinding_FillType);
962 path1.addRect({10, 20, 30, 40});
963 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
964 path1.rewind();
965 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
966##
967
968#SeeAlso reset()
969
970##
971
972# ------------------------------------------------------------------------------
973
Cary Clark682c58d2018-05-16 07:07:07 -0400974#Method bool isEmpty() const
Cary Clark4855f782018-02-06 09:41:53 -0500975#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -0500976#Line # returns if verb count is zero ##
Cary Clark09d80c02018-10-31 12:14:03 -0400977#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400978
979#Example
980void draw(SkCanvas* canvas) {
981 auto debugster = [](const char* prefix, const SkPath& path) -> void {
982 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
983 };
984 SkPath path;
985 debugster("initial", path);
986 path.moveTo(0, 0);
987 debugster("after moveTo", path);
988 path.rewind();
989 debugster("after rewind", path);
990 path.lineTo(0, 0);
991 debugster("after lineTo", path);
992 path.reset();
993 debugster("after reset", path);
994}
995#StdOut
996initial path is empty
997after moveTo path is not empty
998after rewind path is empty
999after lineTo path is not empty
1000after reset path is empty
1001##
1002##
1003
1004#SeeAlso SkPath() reset() rewind()
1005
1006##
1007
1008# ------------------------------------------------------------------------------
1009
1010#Method bool isLastContourClosed() const
Cary Clark4855f782018-02-06 09:41:53 -05001011#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001012#Line # returns if final Contour forms a loop ##
Cary Clark09d80c02018-10-31 12:14:03 -04001013#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001014
1015#Example
1016#Description
1017close() has no effect if Path is empty; isLastContourClosed() returns
1018false until Path has geometry followed by close().
1019##
1020void draw(SkCanvas* canvas) {
1021 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1022 SkDebugf("%s last contour is %s" "closed\n", prefix,
1023 path.isLastContourClosed() ? "" : "not ");
1024 };
1025 SkPath path;
1026 debugster("initial", path);
1027 path.close();
1028 debugster("after close", path);
1029 path.lineTo(0, 0);
1030 debugster("after lineTo", path);
1031 path.close();
1032 debugster("after close", path);
1033}
1034#StdOut
1035initial last contour is not closed
1036after close last contour is not closed
1037after lineTo last contour is not closed
1038after close last contour is closed
1039##
1040##
1041
1042#SeeAlso close()
1043
1044##
1045
1046# ------------------------------------------------------------------------------
1047
Cary Clark682c58d2018-05-16 07:07:07 -04001048#Method bool isFinite() const
Cary Clark4855f782018-02-06 09:41:53 -05001049#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001050#Line # returns if all Point values are finite ##
Cary Clark09d80c02018-10-31 12:14:03 -04001051#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001052
1053#Example
1054void draw(SkCanvas* canvas) {
1055 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1056 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1057 };
1058 SkPath path;
1059 debugster("initial", path);
1060 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1061 debugster("after line", path);
1062 SkMatrix matrix;
1063 matrix.setScale(2, 2);
1064 path.transform(matrix);
1065 debugster("after scale", path);
1066}
1067#StdOut
1068initial path is finite
1069after line path is finite
1070after scale path is not finite
1071##
1072##
1073
1074#SeeAlso SkScalar
1075##
1076
1077# ------------------------------------------------------------------------------
1078
Cary Clark682c58d2018-05-16 07:07:07 -04001079#Method bool isVolatile() const
Cary Clark4855f782018-02-06 09:41:53 -05001080#In Property
1081#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001082#Line # returns if Device should not cache ##
Cary Clark09d80c02018-10-31 12:14:03 -04001083#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001084
1085#Example
1086 SkPath path;
1087 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1088#StdOut
1089volatile by default is false
1090##
1091##
1092
1093#SeeAlso setIsVolatile
1094
1095##
1096
1097# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001098#Subtopic Volatile
Cary Clark4855f782018-02-06 09:41:53 -05001099#Line # caching attribute ##
1100##
Cary Clark73fa9722017-08-29 17:36:51 -04001101
Cary Clark682c58d2018-05-16 07:07:07 -04001102#Method void setIsVolatile(bool isVolatile)
Cary Clark4855f782018-02-06 09:41:53 -05001103#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001104#Line # sets if Device should not cache ##
Cary Clark09d80c02018-10-31 12:14:03 -04001105#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001106
1107#Example
1108#Height 50
1109#Width 50
1110 SkPaint paint;
1111 paint.setStyle(SkPaint::kStroke_Style);
1112 SkPath path;
1113 path.setIsVolatile(true);
1114 path.lineTo(40, 40);
1115 canvas->drawPath(path, paint);
1116 path.rewind();
1117 path.moveTo(0, 40);
1118 path.lineTo(40, 0);
1119 canvas->drawPath(path, paint);
1120##
1121
1122#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1123
1124#SeeAlso isVolatile
1125
1126##
1127
1128# ------------------------------------------------------------------------------
1129
Cary Clark682c58d2018-05-16 07:07:07 -04001130#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001131#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001132#Line # returns if Line is very small ##
Cary Clark09d80c02018-10-31 12:14:03 -04001133#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001134
1135#Example
1136#Description
Cary Clarkce101242017-09-01 15:51:02 -04001137As single precision floats, 100 and 100.000001 have the same bit representation,
1138and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001139are not exactly equal, but are nearly equal.
1140##
1141void draw(SkCanvas* canvas) {
1142 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1143 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1144 for (bool exact : { false, true } ) {
1145 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1146 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1147 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1148 ? "" : "not ", exact ? "exactly" : "nearly");
1149 }
1150 }
1151}
1152#StdOut
1153line from (100,100) to (100,100) is degenerate, nearly
1154line from (100,100) to (100,100) is degenerate, exactly
1155line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1156line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1157#StdOut ##
1158##
1159
Cary Clark682c58d2018-05-16 07:07:07 -04001160#SeeAlso IsQuadDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001161##
1162
1163# ------------------------------------------------------------------------------
1164
1165#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001166 const SkPoint& p3, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001167#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001168#Line # returns if Quad is very small ##
Cary Clark09d80c02018-10-31 12:14:03 -04001169#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001170
1171#Example
1172#Description
Cary Clarkce101242017-09-01 15:51:02 -04001173As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001174but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001175the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001176##
1177void draw(SkCanvas* canvas) {
1178 auto debugster = [](const SkPath& path, bool exact) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001179 SkDebugf("quad (%1.8g,%1.8g), (%1.8g,%1.8g), (%1.8g,%1.8g) is %s" "degenerate, %s\n",
Cary Clark73fa9722017-08-29 17:36:51 -04001180 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1181 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1182 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1183 "" : "not ", exact ? "exactly" : "nearly");
1184 };
1185 SkPath path, offset;
1186 path.moveTo({100, 100});
1187 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1188 offset.addPath(path, 1000, 1000);
1189 for (bool exact : { false, true } ) {
1190 debugster(path, exact);
1191 debugster(offset, exact);
1192 }
1193}
1194#StdOut
1195quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1196quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1197quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1198quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1199#StdOut ##
1200##
1201
Cary Clark682c58d2018-05-16 07:07:07 -04001202#SeeAlso IsLineDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001203##
1204
1205# ------------------------------------------------------------------------------
1206
1207#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001208 const SkPoint& p3, const SkPoint& p4, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001209#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001210#Line # returns if Cubic is very small ##
Cary Clark09d80c02018-10-31 12:14:03 -04001211#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001212
1213#Example
1214void draw(SkCanvas* canvas) {
1215 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1216 SkScalar step = 1;
Cary Clark75fd4492018-06-20 12:45:16 -04001217 SkScalar prior, length = 0, degenerate = 0;
Cary Clark73fa9722017-08-29 17:36:51 -04001218 do {
1219 prior = points[0].fX;
1220 step /= 2;
1221 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1222 degenerate = prior;
1223 points[0].fX += step;
1224 } else {
1225 length = prior;
1226 points[0].fX -= step;
1227 }
1228 } while (prior != points[0].fX);
1229 SkDebugf("%1.8g is degenerate\n", degenerate);
1230 SkDebugf("%1.8g is length\n", length);
1231}
1232#StdOut
12330.00024414062 is degenerate
12340.00024414065 is length
1235#StdOut ##
1236##
1237
1238##
1239
1240# ------------------------------------------------------------------------------
1241
1242#Method bool isLine(SkPoint line[2]) const
Cary Clark4855f782018-02-06 09:41:53 -05001243#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001244#Line # returns if describes Line ##
Cary Clark09d80c02018-10-31 12:14:03 -04001245#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001246
1247#Example
1248void draw(SkCanvas* canvas) {
1249 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1250 SkPoint line[2];
1251 if (path.isLine(line)) {
1252 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1253 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1254 } else {
1255 SkDebugf("%s is not line\n", prefix);
1256 }
1257 };
1258 SkPath path;
1259 debugster("empty", path);
1260 path.lineTo(0, 0);
1261 debugster("zero line", path);
1262 path.rewind();
1263 path.moveTo(10, 10);
1264 path.lineTo(20, 20);
1265 debugster("line", path);
1266 path.moveTo(20, 20);
1267 debugster("second move", path);
1268}
1269#StdOut
1270empty is not line
1271zero line is line (0,0) (0,0)
1272line is line (10,10) (20,20)
1273second move is not line
1274##
1275##
1276
1277##
1278
1279# ------------------------------------------------------------------------------
1280
Cary Clark8032b982017-07-28 11:04:54 -04001281#Subtopic Point_Array
Cary Clark08895c42018-02-01 09:37:32 -05001282#Line # end points and control points for lines and curves ##
Cary Clark61dfc3a2018-01-03 08:37:53 -05001283#Substitute SkPoint array
Cary Clark8032b982017-07-28 11:04:54 -04001284
1285Point_Array contains Points satisfying the allocated Points for
1286each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001287and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001288one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1289
1290Point_Array may be read directly from Path with getPoints, or inspected with
1291getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001292
1293#Method int getPoints(SkPoint points[], int max) const
1294
Cary Clarkab2621d2018-01-30 10:08:57 -05001295#In Point_Array
1296#Line # returns Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001297#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001298
1299#Example
1300void draw(SkCanvas* canvas) {
1301 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1302 int count = path.getPoints(points, max);
1303 SkDebugf("%s point count: %d ", prefix, count);
1304 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1305 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1306 }
1307 SkDebugf("\n");
1308 };
1309 SkPath path;
1310 path.lineTo(20, 20);
1311 path.lineTo(-10, -10);
1312 SkPoint points[3];
1313 debugster("no points", path, nullptr, 0);
1314 debugster("zero max", path, points, 0);
1315 debugster("too small", path, points, 2);
1316 debugster("just right", path, points, path.countPoints());
1317}
1318#StdOut
1319no points point count: 3
1320zero max point count: 3
1321too small point count: 3 (0,0) (20,20)
1322just right point count: 3 (0,0) (20,20) (-10,-10)
1323##
1324##
1325
1326#SeeAlso countPoints getPoint
1327##
1328
1329#Method int countPoints() const
1330
Cary Clarkab2621d2018-01-30 10:08:57 -05001331#In Point_Array
1332#Line # returns Point_Array length ##
Cary Clark09d80c02018-10-31 12:14:03 -04001333#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001334
1335#Example
1336void draw(SkCanvas* canvas) {
1337 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1338 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1339 };
1340 SkPath path;
1341 debugster("empty", path);
1342 path.lineTo(0, 0);
1343 debugster("zero line", path);
1344 path.rewind();
1345 path.moveTo(10, 10);
1346 path.lineTo(20, 20);
1347 debugster("line", path);
1348 path.moveTo(20, 20);
1349 debugster("second move", path);
1350}
1351#StdOut
1352empty point count: 0
1353zero line point count: 2
1354line point count: 2
1355second move point count: 3
1356##
1357##
1358
1359#SeeAlso getPoints
1360##
1361
1362#Method SkPoint getPoint(int index) const
1363
Cary Clarkab2621d2018-01-30 10:08:57 -05001364#In Point_Array
1365#Line # returns entry from Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001366#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001367
1368#Example
1369void draw(SkCanvas* canvas) {
Cary Clark73fa9722017-08-29 17:36:51 -04001370 SkPath path;
1371 path.lineTo(20, 20);
1372 path.offset(-10, -10);
1373 for (int i= 0; i < path.countPoints(); ++i) {
1374 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
Cary Clark682c58d2018-05-16 07:07:07 -04001375 }
Cary Clark73fa9722017-08-29 17:36:51 -04001376}
1377#StdOut
1378point 0: (-10,-10)
1379point 1: (10,10)
1380##
1381##
1382
1383#SeeAlso countPoints getPoints
1384##
1385
1386
1387#Subtopic Point_Array ##
1388
1389# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001390#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001391#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001392
1393Verb_Array always starts with kMove_Verb.
1394If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1395the quantity of kMove_Verb equals the Contour count.
1396Verb_Array does not include or count kDone_Verb; it is a convenience
1397returned when iterating through Verb_Array.
1398
Cary Clark682c58d2018-05-16 07:07:07 -04001399Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
Cary Clark8032b982017-07-28 11:04:54 -04001400or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001401
1402#Method int countVerbs() const
1403
Cary Clarkab2621d2018-01-30 10:08:57 -05001404#In Verb_Array
1405#Line # returns Verb_Array length ##
Cary Clark09d80c02018-10-31 12:14:03 -04001406#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001407
1408#Example
1409SkPath path;
1410SkDebugf("empty verb count: %d\n", path.countVerbs());
1411path.addRoundRect({10, 20, 30, 40}, 5, 5);
1412SkDebugf("round rect verb count: %d\n", path.countVerbs());
1413#StdOut
1414empty verb count: 0
1415round rect verb count: 10
1416##
1417##
1418
1419#SeeAlso getVerbs Iter RawIter
1420
1421##
1422
1423#Method int getVerbs(uint8_t verbs[], int max) const
1424
Cary Clarkab2621d2018-01-30 10:08:57 -05001425#In Verb_Array
1426#Line # returns Verb_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001427#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001428
1429#Example
1430void draw(SkCanvas* canvas) {
1431 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1432 int count = path.getVerbs(verbs, max);
1433 SkDebugf("%s verb count: %d ", prefix, count);
1434 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1435 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1436 SkDebugf("%s ", verbStr[verbs[i]]);
1437 }
1438 SkDebugf("\n");
1439 };
1440 SkPath path;
1441 path.lineTo(20, 20);
1442 path.lineTo(-10, -10);
1443 uint8_t verbs[3];
1444 debugster("no verbs", path, nullptr, 0);
1445 debugster("zero max", path, verbs, 0);
1446 debugster("too small", path, verbs, 2);
1447 debugster("just right", path, verbs, path.countVerbs());
1448}
1449#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04001450no verbs verb count: 3
1451zero max verb count: 3
1452too small verb count: 3 move line
1453just right verb count: 3 move line line
Cary Clark73fa9722017-08-29 17:36:51 -04001454##
1455##
1456
1457#SeeAlso countVerbs getPoints Iter RawIter
1458##
Cary Clark8032b982017-07-28 11:04:54 -04001459
1460#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001461
1462# ------------------------------------------------------------------------------
1463
1464#Method void swap(SkPath& other)
Cary Clark61313f32018-10-08 14:57:48 -04001465#In Operators
Cary Clarkab2621d2018-01-30 10:08:57 -05001466#Line # exchanges Path pair ##
Cary Clark09d80c02018-10-31 12:14:03 -04001467#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001468
1469#Example
1470SkPath path1, path2;
1471path1.addRect({10, 20, 30, 40});
1472path1.swap(path2);
1473const SkRect& b1 = path1.getBounds();
1474SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1475const SkRect& b2 = path2.getBounds();
1476SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1477#StdOut
1478path1 bounds = 0, 0, 0, 0
1479path2 bounds = 10, 20, 30, 40
1480#StdOut ##
1481##
1482
1483#SeeAlso operator=(const SkPath& path)
1484
1485##
1486
1487# ------------------------------------------------------------------------------
1488
Cary Clark682c58d2018-05-16 07:07:07 -04001489#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001490#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001491#Line # returns maximum and minimum of Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001492#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001493
1494#Example
1495#Description
1496Bounds of upright Circle can be predicted from center and radius.
1497Bounds of rotated Circle includes control Points outside of filled area.
1498##
1499 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1500 const SkRect& bounds = path.getBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001501 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001502 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1503 };
1504 SkPath path;
1505 debugster("empty", path);
1506 path.addCircle(50, 45, 25);
1507 debugster("circle", path);
1508 SkMatrix matrix;
1509 matrix.setRotate(45, 50, 45);
1510 path.transform(matrix);
1511 debugster("rotated circle", path);
1512#StdOut
1513empty bounds = 0, 0, 0, 0
1514circle bounds = 25, 20, 75, 70
1515rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1516##
1517##
1518
1519#SeeAlso computeTightBounds updateBoundsCache
1520
1521##
1522
1523# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001524#Subtopic Utility
Cary Clark4855f782018-02-06 09:41:53 -05001525#Line # rarely called management functions ##
1526##
Cary Clark73fa9722017-08-29 17:36:51 -04001527
Cary Clark682c58d2018-05-16 07:07:07 -04001528#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001529#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001530#Line # refreshes result of getBounds ##
Cary Clark09d80c02018-10-31 12:14:03 -04001531#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001532
1533#Example
1534 double times[2] = { 0, 0 };
1535 for (int i = 0; i < 10000; ++i) {
1536 SkPath path;
1537 for (int j = 1; j < 100; ++ j) {
1538 path.addCircle(50 + j, 45 + j, 25 + j);
1539 }
1540 if (1 & i) {
1541 path.updateBoundsCache();
1542 }
1543 double start = SkTime::GetNSecs();
1544 (void) path.getBounds();
1545 times[1 & i] += SkTime::GetNSecs() - start;
1546 }
1547 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1548 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1549#StdOut
1550#Volatile
1551uncached avg: 0.18048 ms
1552cached avg: 0.182784 ms
1553##
1554##
1555
1556#SeeAlso getBounds
1557#ToDo the results don't make sense, need to profile to figure this out ##
1558
1559##
1560
1561# ------------------------------------------------------------------------------
1562
1563#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001564#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001565#Line # returns extent of geometry ##
Cary Clark09d80c02018-10-31 12:14:03 -04001566#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001567
1568#Example
1569 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1570 const SkRect& bounds = path.computeTightBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001571 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001572 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1573 };
1574 SkPath path;
1575 debugster("empty", path);
1576 path.addCircle(50, 45, 25);
1577 debugster("circle", path);
1578 SkMatrix matrix;
1579 matrix.setRotate(45, 50, 45);
1580 path.transform(matrix);
1581 debugster("rotated circle", path);
1582#StdOut
1583empty bounds = 0, 0, 0, 0
1584circle bounds = 25, 20, 75, 70
1585rotated circle bounds = 25, 20, 75, 70
1586##
1587##
1588
1589#SeeAlso getBounds
1590
1591##
1592
1593# ------------------------------------------------------------------------------
1594
1595#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05001596#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001597#Line # returns true if Rect may be inside ##
Cary Clark09d80c02018-10-31 12:14:03 -04001598#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001599
1600#Example
1601#Height 140
1602#Description
1603Rect is drawn in blue if it is contained by red Path.
1604##
1605void draw(SkCanvas* canvas) {
1606 SkPath path;
1607 path.addRoundRect({10, 20, 54, 120}, 10, 20);
1608 SkRect tests[] = {
1609 { 10, 40, 54, 80 },
1610 { 25, 20, 39, 120 },
1611 { 15, 25, 49, 115 },
1612 { 13, 27, 51, 113 },
1613 };
1614 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
1615 SkPaint paint;
1616 paint.setColor(SK_ColorRED);
1617 canvas->drawPath(path, paint);
1618 bool rectInPath = path.conservativelyContainsRect(tests[i]);
1619 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
1620 canvas->drawRect(tests[i], paint);
1621 canvas->translate(64, 0);
1622 }
1623}
1624##
1625
1626#SeeAlso contains Op Rect Convexity
1627
1628##
1629
1630# ------------------------------------------------------------------------------
1631
Mike Reed6a388002018-10-16 13:13:09 -04001632#Method void incReserve(int extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05001633#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001634#Line # reserves space for additional data ##
Cary Clark09d80c02018-10-31 12:14:03 -04001635#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001636
1637#Example
1638#Height 192
1639void draw(SkCanvas* canvas) {
1640 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
1641 path->moveTo(size, 0);
1642 for (int i = 1; i < sides; i++) {
1643 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
1644 path->lineTo(c * size, s * size);
1645 }
1646 path->close();
1647 };
1648 SkPath path;
1649 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
1650 for (int sides = 3; sides < 10; ++sides) {
1651 addPoly(sides, sides, &path);
1652 }
1653 SkMatrix matrix;
1654 matrix.setScale(10, 10, -10, -10);
1655 path.transform(matrix);
1656 SkPaint paint;
1657 paint.setStyle(SkPaint::kStroke_Style);
1658 canvas->drawPath(path, paint);
1659}
1660##
1661
1662#SeeAlso Point_Array
1663
1664##
1665
Cary Clark99ebc422018-09-11 15:26:53 -04001666#Method void shrinkToFit()
1667#In Utility
1668#Line # removes unused reserved space ##
Cary Clark09d80c02018-10-31 12:14:03 -04001669#Populate
Cary Clark99ebc422018-09-11 15:26:53 -04001670
1671#NoExample
Florin Malita0e0f1a72018-09-11 16:16:19 -04001672#Height 192
1673void draw(SkCanvas* canvas) {
1674 SkPath skinnyPath;
1675 skinnyPath.lineTo(100, 100);
1676 skinnyPath.shrinkToFit();
1677
1678 SkDebugf("no wasted Path capacity in my house!\n");
1679}
Cary Clark99ebc422018-09-11 15:26:53 -04001680##
Florin Malita0e0f1a72018-09-11 16:16:19 -04001681
Cary Clark99ebc422018-09-11 15:26:53 -04001682#SeeAlso incReserve
Florin Malita0e0f1a72018-09-11 16:16:19 -04001683
Cary Clark99ebc422018-09-11 15:26:53 -04001684##
1685
Cary Clark73fa9722017-08-29 17:36:51 -04001686# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001687#Subtopic Build
Cary Clark4855f782018-02-06 09:41:53 -05001688#Line # adds points and verbs to path ##
1689##
Cary Clark73fa9722017-08-29 17:36:51 -04001690
Cary Clark0251b1b2018-08-15 15:14:55 -04001691#Method SkPath& moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05001692#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001693#Line # starts Contour ##
Cary Clark09d80c02018-10-31 12:14:03 -04001694#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001695
Cary Clark73fa9722017-08-29 17:36:51 -04001696#Example
1697 #Width 140
1698 #Height 100
1699 void draw(SkCanvas* canvas) {
1700 SkRect rect = { 20, 20, 120, 80 };
1701 SkPath path;
1702 path.addRect(rect);
1703 path.moveTo(rect.fLeft, rect.fTop);
1704 path.lineTo(rect.fRight, rect.fBottom);
1705 path.moveTo(rect.fLeft, rect.fBottom);
1706 path.lineTo(rect.fRight, rect.fTop);
1707 SkPaint paint;
1708 paint.setStyle(SkPaint::kStroke_Style);
1709 canvas->drawPath(path, paint);
1710 }
1711##
1712
1713#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
1714
1715##
1716
Cary Clark0251b1b2018-08-15 15:14:55 -04001717#Method SkPath& moveTo(const SkPoint& p)
Cary Clark09d80c02018-10-31 12:14:03 -04001718#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001719
Cary Clark73fa9722017-08-29 17:36:51 -04001720#Example
1721 #Width 128
1722 #Height 128
1723void draw(SkCanvas* canvas) {
Cary Clark682c58d2018-05-16 07:07:07 -04001724 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
Cary Clark73fa9722017-08-29 17:36:51 -04001725 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
1726 SkPath path;
1727 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
1728 path.moveTo(data[i][0]);
1729 path.lineTo(data[i][1]);
1730 path.lineTo(data[i][2]);
1731 }
1732 SkPaint paint;
1733 paint.setStyle(SkPaint::kStroke_Style);
1734 canvas->drawPath(path, paint);
1735}
1736##
1737
1738#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
1739
1740##
1741
Cary Clark0251b1b2018-08-15 15:14:55 -04001742#Method SkPath& rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05001743#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001744#Line # starts Contour relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04001745#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001746
Cary Clark73fa9722017-08-29 17:36:51 -04001747#Example
1748 #Height 100
1749 SkPath path;
1750 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
1751 path.rMoveTo(25, 2);
1752 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
1753 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
1754 path.rLineTo(arrow[i].fX, arrow[i].fY);
1755 }
1756 SkPaint paint;
1757 canvas->drawPath(path, paint);
1758 SkPoint lastPt;
1759 path.getLastPt(&lastPt);
1760 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
1761##
1762
1763#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
1764
1765##
1766
1767# ------------------------------------------------------------------------------
1768
Cary Clark0251b1b2018-08-15 15:14:55 -04001769#Method SkPath& lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05001770#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001771#Line # appends Line ##
Cary Clark09d80c02018-10-31 12:14:03 -04001772#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001773
Cary Clark73fa9722017-08-29 17:36:51 -04001774#Example
1775#Height 100
1776###$
1777void draw(SkCanvas* canvas) {
1778 SkPaint paint;
1779 paint.setAntiAlias(true);
1780 paint.setTextSize(72);
1781 canvas->drawString("#", 120, 80, paint);
1782 paint.setStyle(SkPaint::kStroke_Style);
1783 paint.setStrokeWidth(5);
1784 SkPath path;
1785 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
1786 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
1787 unsigned o = 0;
1788 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
1789 for (unsigned j = 0; j < 2; o++, j++) {
1790 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
1791 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
1792 }
1793 }
1794 canvas->drawPath(path, paint);
1795}
1796$$$#
1797##
1798
1799#SeeAlso Contour moveTo rLineTo addRect
1800
1801##
1802
1803# ------------------------------------------------------------------------------
1804
Cary Clark0251b1b2018-08-15 15:14:55 -04001805#Method SkPath& lineTo(const SkPoint& p)
Cary Clark09d80c02018-10-31 12:14:03 -04001806#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001807
Cary Clark73fa9722017-08-29 17:36:51 -04001808#Example
1809#Height 100
1810 SkPath path;
1811 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
1812 {40, 20}, {40, 80}, {60, 20}, {60, 80},
1813 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
1814 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
1815 path.moveTo(oxo[i]);
1816 path.lineTo(oxo[i + 1]);
1817 }
1818 SkPaint paint;
1819 paint.setStyle(SkPaint::kStroke_Style);
1820 canvas->drawPath(path, paint);
1821##
1822
1823#SeeAlso Contour moveTo rLineTo addRect
1824
1825##
1826
1827# ------------------------------------------------------------------------------
1828
Cary Clark0251b1b2018-08-15 15:14:55 -04001829#Method SkPath& rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05001830#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001831#Line # appends Line relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04001832#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001833
Cary Clark73fa9722017-08-29 17:36:51 -04001834#Example
1835#Height 128
1836void draw(SkCanvas* canvas) {
1837 SkPaint paint;
1838 paint.setAntiAlias(true);
1839 paint.setStyle(SkPaint::kStroke_Style);
1840 SkPath path;
1841 path.moveTo(10, 98);
1842 SkScalar x = 0, y = 0;
1843 for (int i = 10; i < 100; i += 5) {
1844 x += i * ((i & 2) - 1);
1845 y += i * (((i + 1) & 2) - 1);
1846 path.rLineTo(x, y);
Cary Clark682c58d2018-05-16 07:07:07 -04001847
Cary Clark73fa9722017-08-29 17:36:51 -04001848 }
1849 canvas->drawPath(path, paint);
1850}
1851##
1852
1853#SeeAlso Contour moveTo lineTo addRect
1854
1855##
1856
1857# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05001858#Subtopic Quad
Cary Clark137b8742018-05-30 09:21:49 -04001859#Alias Quad ##
1860#Alias Quads ##
1861#Alias Quadratic_Bezier ##
1862#Alias Quadratic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04001863#Line # curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04001864
1865Quad describes a quadratic Bezier, a second-order curve identical to a section
1866of a parabola. Quad begins at a start Point, curves towards a control Point,
1867and then curves to an end Point.
1868
1869#Example
1870#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04001871void draw(SkCanvas* canvas) {
1872 SkPaint paint;
1873 paint.setAntiAlias(true);
1874 paint.setStyle(SkPaint::kStroke_Style);
1875 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
1876 canvas->drawLine(quadPts[0], quadPts[1], paint);
1877 canvas->drawLine(quadPts[1], quadPts[2], paint);
1878 SkPath path;
1879 path.moveTo(quadPts[0]);
1880 path.quadTo(quadPts[1], quadPts[2]);
1881 paint.setStrokeWidth(3);
1882 canvas->drawPath(path, paint);
1883}
Cary Clark8032b982017-07-28 11:04:54 -04001884##
1885
1886Quad is a special case of Conic where Conic_Weight is set to one.
1887
1888Quad is always contained by the triangle connecting its three Points. Quad
1889begins tangent to the line between start Point and control Point, and ends
1890tangent to the line between control Point and end Point.
1891
1892#Example
1893#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04001894void draw(SkCanvas* canvas) {
1895 SkPaint paint;
1896 paint.setAntiAlias(true);
1897 paint.setStyle(SkPaint::kStroke_Style);
1898 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
1899 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
1900 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
1901 paint.setColor(0x7fffffff & colors[i]);
1902 paint.setStrokeWidth(1);
1903 canvas->drawLine(quadPts[0], quadPts[1], paint);
1904 canvas->drawLine(quadPts[1], quadPts[2], paint);
1905 SkPath path;
1906 path.moveTo(quadPts[0]);
1907 path.quadTo(quadPts[1], quadPts[2]);
1908 paint.setStrokeWidth(3);
1909 paint.setColor(colors[i]);
1910 canvas->drawPath(path, paint);
1911 quadPts[1].fY += 30;
1912 }
Cary Clark8032b982017-07-28 11:04:54 -04001913}
1914##
Cary Clark73fa9722017-08-29 17:36:51 -04001915
Cary Clark0251b1b2018-08-15 15:14:55 -04001916#Method SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Cary Clark73fa9722017-08-29 17:36:51 -04001917
Cary Clarkab2621d2018-01-30 10:08:57 -05001918#In Quad
1919#Line # appends Quad ##
Cary Clark09d80c02018-10-31 12:14:03 -04001920#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001921
Cary Clark09d80c02018-10-31 12:14:03 -04001922#Example
Cary Clark73fa9722017-08-29 17:36:51 -04001923 void draw(SkCanvas* canvas) {
1924 SkPaint paint;
1925 paint.setAntiAlias(true);
1926 paint.setStyle(SkPaint::kStroke_Style);
1927 SkPath path;
1928 path.moveTo(0, -10);
1929 for (int i = 0; i < 128; i += 16) {
1930 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
1931 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
1932 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
1933 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
1934 }
1935 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04001936 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001937 }
1938 ##
1939
1940 #SeeAlso Contour moveTo conicTo rQuadTo
1941
1942##
1943
Cary Clark0251b1b2018-08-15 15:14:55 -04001944#Method SkPath& quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05001945#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001946#In Quad
Cary Clark09d80c02018-10-31 12:14:03 -04001947#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001948
Cary Clark09d80c02018-10-31 12:14:03 -04001949#Example
Cary Clark73fa9722017-08-29 17:36:51 -04001950 void draw(SkCanvas* canvas) {
1951 SkPaint paint;
1952 paint.setStyle(SkPaint::kStroke_Style);
1953 paint.setAntiAlias(true);
1954 SkPath path;
1955 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
1956 path.moveTo(pts[1]);
1957 for (int i = 0; i < 3; ++i) {
1958 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
1959 }
1960 canvas->drawPath(path, paint);
1961 }
1962 ##
1963
1964 #SeeAlso Contour moveTo conicTo rQuadTo
1965
1966##
1967
Cary Clark0251b1b2018-08-15 15:14:55 -04001968#Method SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05001969#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001970#In Quad
1971#Line # appends Quad relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04001972#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001973
Cary Clark09d80c02018-10-31 12:14:03 -04001974#Example
Cary Clark73fa9722017-08-29 17:36:51 -04001975 void draw(SkCanvas* canvas) {
1976 SkPaint paint;
1977 paint.setAntiAlias(true);
1978 SkPath path;
1979 path.moveTo(128, 20);
1980 path.rQuadTo(-6, 10, -7, 10);
1981 for (int i = 1; i < 32; i += 4) {
1982 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
1983 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
1984 }
1985 path.quadTo(92, 220, 128, 215);
1986 canvas->drawPath(path, paint);
1987 }
1988 ##
1989
1990 #SeeAlso Contour moveTo conicTo quadTo
1991
1992##
1993
Cary Clark78de7512018-02-07 07:27:09 -05001994#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04001995
1996# ------------------------------------------------------------------------------
1997
Cary Clark78de7512018-02-07 07:27:09 -05001998#Subtopic Conic
Cary Clark08895c42018-02-01 09:37:32 -05001999#Line # conic section defined by three points and a weight ##
Cary Clark137b8742018-05-30 09:21:49 -04002000#Alias Conics ##
Cary Clark8032b982017-07-28 11:04:54 -04002001
2002Conic describes a conical section: a piece of an ellipse, or a piece of a
Cary Clark682c58d2018-05-16 07:07:07 -04002003parabola, or a piece of a hyperbola. Conic begins at a start Point,
Cary Clark8032b982017-07-28 11:04:54 -04002004curves towards a control Point, and then curves to an end Point. The influence
2005of the control Point is determined by Conic_Weight.
2006
Cary Clark73fa9722017-08-29 17:36:51 -04002007Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2008may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002009
2010#Subtopic Weight
Cary Clark137b8742018-05-30 09:21:49 -04002011#Alias Conic_Weights ##
2012#Alias Weights ##
Cary Clark08895c42018-02-01 09:37:32 -05002013#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002014
2015Weight determines both the strength of the control Point and the type of Conic.
Cary Clark682c58d2018-05-16 07:07:07 -04002016Weight varies from zero to infinity. At zero, Weight causes the control Point to
2017have no effect; Conic is identical to a line segment from start Point to end
2018point. If Weight is less than one, Conic follows an elliptical arc.
2019If Weight is exactly one, then Conic is identical to Quad; Conic follows a
2020parabolic arc. If Weight is greater than one, Conic follows a hyperbolic
Cary Clark137b8742018-05-30 09:21:49 -04002021arc. If Weight is infinity, Conic is identical to two line segments, connecting
Cary Clark682c58d2018-05-16 07:07:07 -04002022start Point to control Point, and control Point to end Point.
Cary Clark8032b982017-07-28 11:04:54 -04002023
2024#Example
2025#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002026When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002027##
Cary Clark73fa9722017-08-29 17:36:51 -04002028void draw(SkCanvas* canvas) {
2029 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2030 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2031 SkPath path;
2032 path.conicTo(20, 30, 50, 60, 1);
2033 SkPath::Iter iter(path, false);
2034 SkPath::Verb verb;
2035 do {
2036 SkPoint points[4];
2037 verb = iter.next(points);
2038 SkDebugf("%s ", verbNames[(int) verb]);
2039 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2040 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2041 }
2042 if (SkPath::kConic_Verb == verb) {
2043 SkDebugf("weight = %g", iter.conicWeight());
2044 }
2045 SkDebugf("\n");
2046 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002047}
2048#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002049move {0, 0},
2050quad {0, 0}, {20, 30}, {50, 60},
2051done
Cary Clark8032b982017-07-28 11:04:54 -04002052##
2053##
2054
2055If weight is less than one, Conic is an elliptical segment.
2056
Cary Clark682c58d2018-05-16 07:07:07 -04002057#Example
Cary Clark8032b982017-07-28 11:04:54 -04002058#Description
Cary Clark2be81cf2018-09-13 12:04:30 -04002059A 90 degree circular arc has the weight #Formula # 1 / sqrt(2) ##.
Cary Clark8032b982017-07-28 11:04:54 -04002060##
Cary Clark73fa9722017-08-29 17:36:51 -04002061void draw(SkCanvas* canvas) {
2062 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2063 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2064 SkPath path;
2065 path.arcTo(20, 0, 20, 20, 20);
2066 SkPath::Iter iter(path, false);
2067 SkPath::Verb verb;
2068 do {
2069 SkPoint points[4];
2070 verb = iter.next(points);
2071 SkDebugf("%s ", verbNames[(int) verb]);
2072 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2073 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2074 }
2075 if (SkPath::kConic_Verb == verb) {
2076 SkDebugf("weight = %g", iter.conicWeight());
2077 }
2078 SkDebugf("\n");
2079 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002080}
2081#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002082move {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04002083conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark682c58d2018-05-16 07:07:07 -04002084done
Cary Clark8032b982017-07-28 11:04:54 -04002085##
2086##
2087
Cary Clarkce101242017-09-01 15:51:02 -04002088If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002089a hyperbolic segment can be approximated by straight lines connecting the
2090control Point with the end Points.
2091
2092#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002093void draw(SkCanvas* canvas) {
2094 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2095 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2096 SkPath path;
2097 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2098 SkPath::Iter iter(path, false);
2099 SkPath::Verb verb;
2100 do {
2101 SkPoint points[4];
2102 verb = iter.next(points);
2103 SkDebugf("%s ", verbNames[(int) verb]);
2104 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2105 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2106 }
2107 if (SkPath::kConic_Verb == verb) {
2108 SkDebugf("weight = %g", iter.conicWeight());
2109 }
2110 SkDebugf("\n");
2111 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002112}
2113#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002114move {0, 0},
2115line {0, 0}, {20, 0},
2116line {20, 0}, {20, 20},
2117done
Cary Clark8032b982017-07-28 11:04:54 -04002118##
2119##
2120
2121#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002122
Cary Clark0251b1b2018-08-15 15:14:55 -04002123#Method SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002124 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002125#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002126#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002127#Line # appends Conic ##
Cary Clark09d80c02018-10-31 12:14:03 -04002128#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002129
Cary Clark09d80c02018-10-31 12:14:03 -04002130#Example
Cary Clark8032b982017-07-28 11:04:54 -04002131 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002132 #Description
Cary Clark682c58d2018-05-16 07:07:07 -04002133 As weight increases, curve is pulled towards control point.
Cary Clark73fa9722017-08-29 17:36:51 -04002134 The bottom two curves are elliptical; the next is parabolic; the
2135 top curve is hyperbolic.
2136 ##
2137void draw(SkCanvas* canvas) {
2138 SkPaint paint;
2139 paint.setAntiAlias(true);
2140 paint.setStyle(SkPaint::kStroke_Style);
2141 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2142 canvas->drawLine(conicPts[0], conicPts[1], paint);
2143 canvas->drawLine(conicPts[1], conicPts[2], paint);
2144 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2145 paint.setStrokeWidth(3);
2146 SkScalar weight = 0.5f;
2147 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2148 SkPath path;
2149 path.moveTo(conicPts[0]);
2150 path.conicTo(conicPts[1], conicPts[2], weight);
2151 paint.setColor(colors[i]);
2152 canvas->drawPath(path, paint);
2153 weight += 0.25f;
2154 }
2155}
2156 ##
2157
2158 #SeeAlso rConicTo arcTo addArc quadTo
2159
2160##
2161
Cary Clark0251b1b2018-08-15 15:14:55 -04002162#Method SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002163#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002164#In Conic
Cary Clark09d80c02018-10-31 12:14:03 -04002165#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002166
Cary Clark09d80c02018-10-31 12:14:03 -04002167#Example
Cary Clark8032b982017-07-28 11:04:54 -04002168 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002169 #Description
2170 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002171 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002172 ##
2173void draw(SkCanvas* canvas) {
2174 SkPaint paint;
2175 paint.setAntiAlias(true);
2176 paint.setStyle(SkPaint::kStroke_Style);
2177 SkRect oval = {0, 20, 120, 140};
2178 SkPath path;
2179 for (int i = 0; i < 4; ++i) {
2180 path.moveTo(oval.centerX(), oval.fTop);
2181 path.arcTo(oval, -90, 90 - 20 * i, false);
2182 oval.inset(15, 15);
2183 }
2184 path.offset(100, 0);
2185 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2186 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2187 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2188 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2189 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2190 for (int i = 0; i < 4; ++i) {
2191 path.moveTo(conicPts[i][0]);
2192 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2193 }
2194 canvas->drawPath(path, paint);
2195}
2196 ##
2197
2198 #SeeAlso rConicTo arcTo addArc quadTo
2199
2200##
2201
Cary Clark0251b1b2018-08-15 15:14:55 -04002202#Method SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
Cary Clark73fa9722017-08-29 17:36:51 -04002203 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002204#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002205#In Conic
2206#Line # appends Conic relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04002207#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002208
Cary Clark09d80c02018-10-31 12:14:03 -04002209#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002210 #Height 140
2211 void draw(SkCanvas* canvas) {
2212 SkPaint paint;
2213 paint.setAntiAlias(true);
2214 paint.setStyle(SkPaint::kStroke_Style);
2215 SkPath path;
2216 path.moveTo(20, 80);
2217 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2218 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2219 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2220 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2221 canvas->drawPath(path, paint);
2222 }
2223 ##
2224
2225 #SeeAlso conicTo arcTo addArc quadTo
2226
2227##
2228
Cary Clark78de7512018-02-07 07:27:09 -05002229#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002230
2231# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002232#Subtopic Cubic
Cary Clark137b8742018-05-30 09:21:49 -04002233#Alias Cubic ##
2234#Alias Cubics ##
2235#Alias Cubic_Bezier ##
2236#Alias Cubic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002237#Line # curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002238
Cary Clark682c58d2018-05-16 07:07:07 -04002239Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002240Cubic begins at a start Point, curving towards the first control Point;
2241and curves from the end Point towards the second control Point.
2242
2243#Example
2244#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002245void draw(SkCanvas* canvas) {
2246 SkPaint paint;
2247 paint.setAntiAlias(true);
2248 paint.setStyle(SkPaint::kStroke_Style);
2249 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2250 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2251 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2252 paint.setColor(0x7fffffff & colors[i]);
2253 paint.setStrokeWidth(1);
2254 for (unsigned j = 0; j < 3; ++j) {
2255 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2256 }
2257 SkPath path;
2258 path.moveTo(cubicPts[0]);
2259 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2260 paint.setStrokeWidth(3);
2261 paint.setColor(colors[i]);
2262 canvas->drawPath(path, paint);
2263 cubicPts[1].fY += 30;
2264 cubicPts[2].fX += 30;
2265 }
Cary Clark8032b982017-07-28 11:04:54 -04002266}
2267##
Cary Clark73fa9722017-08-29 17:36:51 -04002268
Cary Clark0251b1b2018-08-15 15:14:55 -04002269#Method SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002270 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002271#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002272#In Cubic
2273#Line # appends Cubic ##
Cary Clark09d80c02018-10-31 12:14:03 -04002274#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002275
Cary Clark73fa9722017-08-29 17:36:51 -04002276#Example
2277void draw(SkCanvas* canvas) {
2278 SkPaint paint;
2279 paint.setAntiAlias(true);
2280 paint.setStyle(SkPaint::kStroke_Style);
2281 SkPath path;
2282 path.moveTo(0, -10);
2283 for (int i = 0; i < 128; i += 16) {
2284 SkScalar c = i * 0.5f;
2285 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2286 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2287 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2288 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2289 }
2290 path.offset(128, 128);
2291 canvas->drawPath(path, paint);
2292}
2293##
2294
2295#SeeAlso Contour moveTo rCubicTo quadTo
2296
2297##
2298
2299# ------------------------------------------------------------------------------
2300
Cary Clark0251b1b2018-08-15 15:14:55 -04002301#Method SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
Cary Clark73fa9722017-08-29 17:36:51 -04002302
Cary Clark4855f782018-02-06 09:41:53 -05002303#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002304#In Cubic
Cary Clark09d80c02018-10-31 12:14:03 -04002305#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002306
Cary Clark73fa9722017-08-29 17:36:51 -04002307#Example
2308#Height 84
2309 SkPaint paint;
2310 paint.setAntiAlias(true);
2311 paint.setStyle(SkPaint::kStroke_Style);
2312 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2313 SkPath path;
2314 path.moveTo(pts[0]);
2315 path.cubicTo(pts[1], pts[2], pts[3]);
2316 canvas->drawPath(path, paint);
2317##
2318
2319#SeeAlso Contour moveTo rCubicTo quadTo
2320
2321##
2322
2323# ------------------------------------------------------------------------------
2324
Cary Clark82456492018-10-31 10:54:50 -04002325#Method SkPath& rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2326 SkScalar dx3, SkScalar dy3)
Cary Clark4855f782018-02-06 09:41:53 -05002327#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002328#In Cubic
2329#Line # appends Cubic relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04002330#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002331
Cary Clark73fa9722017-08-29 17:36:51 -04002332#Example
2333 void draw(SkCanvas* canvas) {
2334 SkPaint paint;
2335 paint.setAntiAlias(true);
2336 paint.setStyle(SkPaint::kStroke_Style);
2337 SkPath path;
2338 path.moveTo(24, 108);
2339 for (int i = 0; i < 16; i++) {
2340 SkScalar sx, sy;
2341 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2342 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2343 }
2344 canvas->drawPath(path, paint);
2345 }
2346##
2347
2348#SeeAlso Contour moveTo cubicTo quadTo
2349
2350##
2351
Cary Clark78de7512018-02-07 07:27:09 -05002352#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002353
2354# ------------------------------------------------------------------------------
2355
Cary Clark08895c42018-02-01 09:37:32 -05002356#Subtopic Arc
2357#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04002358Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
2359by start point and end point, and by radius and tangent lines. Each construction has advantages,
2360and some constructions correspond to Arc drawing in graphics standards.
2361
2362All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
2363Conic describes an Arc of some Oval or Circle.
2364
2365arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
2366describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
Cary Clark682c58d2018-05-16 07:07:07 -04002367which may continue Contour or start a new one. This construction is similar to PostScript and
Cary Clark73fa9722017-08-29 17:36:51 -04002368HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
2369requiring Path.
2370
2371arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
2372describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
2373where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
2374HTML_Canvas arcs.
2375
2376arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04002377 SkScalar x, SkScalar y)
Cary Clark73fa9722017-08-29 17:36:51 -04002378describes Arc as part of Oval with radii (rx, ry), beginning at
2379last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
2380so additional values choose a single solution. This construction is similar to SVG arcs.
2381
2382conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
2383conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
Cary Clark682c58d2018-05-16 07:07:07 -04002384constructions are converted to Conic data when added to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002385
Cary Clark153e76d2018-08-28 11:48:28 -04002386#ToDo example is spaced correctly on fiddle but spacing is too wide on pc
Cary Clark73fa9722017-08-29 17:36:51 -04002387##
2388
Cary Clark153e76d2018-08-28 11:48:28 -04002389#Illustration
2390
Cary Clark73fa9722017-08-29 17:36:51 -04002391#List
2392# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
2393# <sup>2</sup> parameter sets force MoveTo ##
Cary Clark5081eed2018-01-22 07:55:48 -05002394# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04002395# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
2396# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
2397 Direction sweep, SkScalar x, SkScalar y) ##
2398#List ##
Cary Clark73fa9722017-08-29 17:36:51 -04002399
2400#Example
2401#Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002402void draw(SkCanvas* canvas) {
2403 SkRect oval = {8, 8, 56, 56};
2404 SkPaint ovalPaint;
2405 ovalPaint.setAntiAlias(true);
2406 SkPaint textPaint(ovalPaint);
2407 ovalPaint.setStyle(SkPaint::kStroke_Style);
2408 SkPaint arcPaint(ovalPaint);
2409 arcPaint.setStrokeWidth(5);
2410 arcPaint.setColor(SK_ColorBLUE);
2411 canvas->translate(-64, 0);
2412 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
2413 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
2414 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
2415 canvas->drawOval(oval, ovalPaint);
2416 SkPath path;
2417 path.moveTo({56, 32});
2418 switch (arcStyle) {
2419 case '1':
2420 path.arcTo(oval, 0, 90, false);
2421 break;
2422 case '2':
2423 canvas->drawArc(oval, 0, 90, false, arcPaint);
2424 continue;
2425 case '3':
2426 path.addArc(oval, 0, 90);
2427 break;
2428 case '4':
2429 path.arcTo({56, 56}, {32, 56}, 24);
2430 break;
2431 case '5':
2432 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
2433 break;
2434 case '6':
2435 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
2436 break;
2437 }
2438 canvas->drawPath(path, arcPaint);
2439 }
2440}
2441#Example ##
2442
Cary Clark153e76d2018-08-28 11:48:28 -04002443In the example above:
2444#List
2445# 1 describes an arc from an oval, a starting angle, and a sweep angle. ##
2446# 2 is similar to 1, but does not require building a path to draw. ##
2447# 3 is similar to 1, but always begins new Contour. ##
2448# 4 describes an arc from a pair of tangent lines and a radius. ##
2449# 5 describes an arc from Oval center, arc start Point and arc end Point. ##
2450# 6 describes an arc from a pair of tangent lines and a Conic_Weight. ##
2451#List ##
Cary Clark73fa9722017-08-29 17:36:51 -04002452
Cary Clark0251b1b2018-08-15 15:14:55 -04002453#Method SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05002454#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002455#In Arc
2456#Line # appends Arc ##
Cary Clark09d80c02018-10-31 12:14:03 -04002457#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002458
Cary Clark73fa9722017-08-29 17:36:51 -04002459#Example
2460#Height 200
2461#Description
2462arcTo continues a previous contour when forceMoveTo is false and when Path
2463is not empty.
2464##
2465void draw(SkCanvas* canvas) {
2466 SkPaint paint;
2467 SkPath path;
2468 paint.setStyle(SkPaint::kStroke_Style);
2469 paint.setStrokeWidth(4);
2470 path.moveTo(0, 0);
2471 path.arcTo({20, 20, 120, 120}, -90, 90, false);
2472 canvas->drawPath(path, paint);
2473 path.rewind();
2474 path.arcTo({120, 20, 220, 120}, -90, 90, false);
2475 canvas->drawPath(path, paint);
2476 path.rewind();
2477 path.moveTo(0, 0);
2478 path.arcTo({20, 120, 120, 220}, -90, 90, true);
2479 canvas->drawPath(path, paint);
2480}
2481##
2482
2483#SeeAlso addArc SkCanvas::drawArc conicTo
2484
2485##
2486
2487# ------------------------------------------------------------------------------
2488
Cary Clark0251b1b2018-08-15 15:14:55 -04002489#Method SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05002490#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002491#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002492#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002493
2494#Example
2495#Height 226
2496void draw(SkCanvas* canvas) {
2497 SkPaint tangentPaint;
2498 tangentPaint.setAntiAlias(true);
2499 SkPaint textPaint(tangentPaint);
2500 tangentPaint.setStyle(SkPaint::kStroke_Style);
2501 tangentPaint.setColor(SK_ColorGRAY);
2502 SkPaint arcPaint(tangentPaint);
2503 arcPaint.setStrokeWidth(5);
2504 arcPaint.setColor(SK_ColorBLUE);
2505 SkPath path;
2506 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
2507 SkScalar radius = 50;
2508 path.moveTo(pts[0]);
2509 path.arcTo(pts[1], pts[2], radius);
2510 canvas->drawLine(pts[0], pts[1], tangentPaint);
2511 canvas->drawLine(pts[1], pts[2], tangentPaint);
2512 SkPoint lastPt;
2513 (void) path.getLastPt(&lastPt);
2514 SkVector radial = pts[2] - pts[1];
2515 radial.setLength(radius);
2516 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
2517 canvas->drawCircle(center, radius, tangentPaint);
2518 canvas->drawLine(lastPt, center, tangentPaint);
2519 radial = pts[1] - pts[0];
2520 radial.setLength(radius);
2521 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
2522 canvas->drawLine(center, arcStart, tangentPaint);
2523 canvas->drawPath(path, arcPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002524 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002525 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002526 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002527 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
2528 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
2529}
2530##
2531
Cary Clark73fa9722017-08-29 17:36:51 -04002532#Example
2533#Height 128
2534void draw(SkCanvas* canvas) {
2535 SkPaint tangentPaint;
2536 tangentPaint.setAntiAlias(true);
2537 SkPaint textPaint(tangentPaint);
2538 tangentPaint.setStyle(SkPaint::kStroke_Style);
2539 tangentPaint.setColor(SK_ColorGRAY);
2540 SkPaint arcPaint(tangentPaint);
2541 arcPaint.setStrokeWidth(5);
2542 arcPaint.setColor(SK_ColorBLUE);
2543 SkPath path;
2544 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
2545 SkScalar radius = 50;
2546 path.moveTo(pts[0]);
2547 path.arcTo(pts[1], pts[2], radius);
2548 canvas->drawLine(pts[0], pts[1], tangentPaint);
2549 canvas->drawLine(pts[1], pts[2], tangentPaint);
2550 SkPoint lastPt;
2551 (void) path.getLastPt(&lastPt);
2552 SkVector radial = pts[2] - pts[1];
2553 radial.setLength(radius);
2554 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
2555 canvas->drawLine(lastPt, center, tangentPaint);
2556 radial = pts[1] - pts[0];
2557 radial.setLength(radius);
2558 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
2559 canvas->drawLine(center, arcStart, tangentPaint);
2560 canvas->drawPath(path, arcPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002561 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002562 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002563 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002564 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
2565 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
2566}
2567##
2568
Cary Clark73fa9722017-08-29 17:36:51 -04002569#Example
2570#Description
2571arcTo is represented by Line and circular Conic in Path.
2572##
2573void draw(SkCanvas* canvas) {
2574 SkPath path;
2575 path.moveTo({156, 20});
2576 path.arcTo(200, 20, 170, 50, 50);
2577 SkPath::Iter iter(path, false);
2578 SkPoint p[4];
2579 SkPath::Verb verb;
2580 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
2581 switch (verb) {
2582 case SkPath::kMove_Verb:
2583 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
2584 break;
2585 case SkPath::kLine_Verb:
2586 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
2587 break;
2588 case SkPath::kConic_Verb:
2589 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
2590 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
2591 break;
2592 default:
2593 SkDebugf("unexpected verb\n");
2594 }
2595 }
2596}
2597#StdOut
2598move to (156,20)
2599line (156,20),(79.2893,20)
2600conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
2601##
2602##
2603
Cary Clark682c58d2018-05-16 07:07:07 -04002604#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04002605
2606##
2607
2608# ------------------------------------------------------------------------------
2609
Cary Clark0251b1b2018-08-15 15:14:55 -04002610#Method SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05002611#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002612#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002613#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002614
Cary Clark73fa9722017-08-29 17:36:51 -04002615#Example
2616#Description
2617Because tangent lines are parallel, arcTo appends line from last Path Point to
2618p1, but does not append a circular Conic.
2619##
2620void draw(SkCanvas* canvas) {
2621 SkPath path;
2622 path.moveTo({156, 20});
2623 path.arcTo({200, 20}, {170, 20}, 50);
2624 SkPath::Iter iter(path, false);
2625 SkPoint p[4];
2626 SkPath::Verb verb;
2627 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
2628 switch (verb) {
2629 case SkPath::kMove_Verb:
2630 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
2631 break;
2632 case SkPath::kLine_Verb:
2633 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
2634 break;
2635 case SkPath::kConic_Verb:
2636 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
2637 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
2638 break;
2639 default:
2640 SkDebugf("unexpected verb\n");
2641 }
2642 }
2643}
2644#StdOut
2645move to (156,20)
2646line (156,20),(200,20)
2647##
2648##
2649
Cary Clark682c58d2018-05-16 07:07:07 -04002650#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04002651
2652##
2653
2654# ------------------------------------------------------------------------------
2655
2656#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05002657#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04002658
2659#Code
2660 enum ArcSize {
Cary Clark682c58d2018-05-16 07:07:07 -04002661 kSmall_ArcSize,
2662 kLarge_ArcSize,
Cary Clark73fa9722017-08-29 17:36:51 -04002663 };
2664##
2665
2666Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
2667ArcSize and Direction select one of the four Oval parts.
2668
2669#Const kSmall_ArcSize 0
Cary Clark682c58d2018-05-16 07:07:07 -04002670#Line # smaller of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04002671##
2672#Const kLarge_ArcSize 1
Cary Clark682c58d2018-05-16 07:07:07 -04002673#Line # larger of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04002674##
2675
2676#Example
2677#Height 160
2678#Description
2679Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
2680Two routes are large, and two routes are counterclockwise. The one route both large
2681and counterclockwise is blue.
2682##
2683void draw(SkCanvas* canvas) {
2684 SkPaint paint;
2685 paint.setAntiAlias(true);
2686 paint.setStyle(SkPaint::kStroke_Style);
2687 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
2688 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
2689 SkPath path;
2690 path.moveTo({120, 50});
2691 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
2692 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
2693 paint.setColor(SK_ColorBLUE);
2694 paint.setStrokeWidth(3);
2695 }
2696 canvas->drawPath(path, paint);
2697 }
2698 }
2699}
2700##
2701
2702#SeeAlso arcTo Direction
2703
2704##
2705
2706# ------------------------------------------------------------------------------
2707
Cary Clark0251b1b2018-08-15 15:14:55 -04002708#Method SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04002709 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002710#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002711#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002712#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002713
Cary Clark73fa9722017-08-29 17:36:51 -04002714#Example
2715#Height 160
2716void draw(SkCanvas* canvas) {
2717 SkPaint paint;
2718 paint.setAntiAlias(true);
2719 paint.setStyle(SkPaint::kStroke_Style);
2720 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
2721 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
2722 SkPath path;
2723 path.moveTo({120, 50});
2724 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
2725 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
2726 paint.setColor(SK_ColorBLUE);
2727 paint.setStrokeWidth(3);
2728 }
2729 canvas->drawPath(path, paint);
2730 }
2731 }
2732}
2733##
2734
2735#SeeAlso rArcTo ArcSize Direction
2736
2737##
2738
2739# ------------------------------------------------------------------------------
2740
Cary Clark0251b1b2018-08-15 15:14:55 -04002741#Method SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04002742 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05002743#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002744#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002745#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002746
Cary Clark73fa9722017-08-29 17:36:51 -04002747#Example
2748#Height 108
2749void draw(SkCanvas* canvas) {
2750 SkPaint paint;
2751 SkPath path;
2752 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
2753 for (auto start : starts) {
2754 path.moveTo(start.fX, start.fY);
2755 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
2756 }
2757 canvas->drawPath(path, paint);
2758}
2759##
2760
2761#SeeAlso rArcTo ArcSize Direction
2762
2763##
2764
2765# ------------------------------------------------------------------------------
2766
Cary Clark0251b1b2018-08-15 15:14:55 -04002767#Method SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04002768 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002769#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002770#In Arc
2771#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002772
Cary Clark80247e52018-07-11 16:18:41 -04002773Appends Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04002774more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04002775xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
Cary Clark2be81cf2018-09-13 12:04:30 -04002776#Formula # (x0 + dx, y0 + dy) ##, choosing one of four possible routes: clockwise or
Cary Clark73fa9722017-08-29 17:36:51 -04002777counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
2778is (0, 0).
2779
Cary Clarkce101242017-09-01 15:51:02 -04002780Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
2781if either radii are zero, or if last Path Point equals end Point.
2782arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
2783greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04002784
2785arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04002786arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
2787opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04002788kCW_Direction cast to int is zero.
2789
Cary Clark5538c132018-06-14 12:28:14 -04002790#Param rx radius before x-axis rotation ##
2791#Param ry radius before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04002792#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04002793#Param largeArc chooses smaller or larger Arc ##
2794#Param sweep chooses clockwise or counterclockwise Arc ##
Cary Clark5538c132018-06-14 12:28:14 -04002795#Param dx x-axis offset end of Arc from last Path Point ##
2796#Param dy y-axis offset end of Arc from last Path Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002797
Cary Clark0251b1b2018-08-15 15:14:55 -04002798#Return reference to Path ##
2799
Cary Clark73fa9722017-08-29 17:36:51 -04002800#Example
2801#Height 108
2802void draw(SkCanvas* canvas) {
2803 SkPaint paint;
2804 SkPath path;
2805 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
2806 for (auto start : starts) {
2807 path.moveTo(start.fX, start.fY);
2808 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
2809 }
2810 canvas->drawPath(path, paint);
2811}
2812##
2813
2814#SeeAlso arcTo ArcSize Direction
2815
2816##
2817
Cary Clark78de7512018-02-07 07:27:09 -05002818#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04002819
2820# ------------------------------------------------------------------------------
2821
Cary Clark0251b1b2018-08-15 15:14:55 -04002822#Method SkPath& close()
Cary Clark4855f782018-02-06 09:41:53 -05002823#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002824#Line # makes last Contour a loop ##
Cary Clark09d80c02018-10-31 12:14:03 -04002825#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002826
Cary Clark73fa9722017-08-29 17:36:51 -04002827#Example
2828void draw(SkCanvas* canvas) {
2829 SkPaint paint;
2830 paint.setStrokeWidth(15);
2831 paint.setStrokeCap(SkPaint::kRound_Cap);
2832 SkPath path;
2833 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
2834 path.addPoly(points, SK_ARRAY_COUNT(points), false);
2835 for (int loop = 0; loop < 2; ++loop) {
2836 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
2837 SkPaint::kStrokeAndFill_Style} ) {
2838 paint.setStyle(style);
2839 canvas->drawPath(path, paint);
2840 canvas->translate(85, 0);
2841 }
2842 path.close();
2843 canvas->translate(-255, 128);
2844 }
2845}
2846##
2847
Cary Clark682c58d2018-05-16 07:07:07 -04002848#SeeAlso
Cary Clark73fa9722017-08-29 17:36:51 -04002849
2850##
2851
2852# ------------------------------------------------------------------------------
2853
Cary Clark682c58d2018-05-16 07:07:07 -04002854#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05002855#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002856#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04002857Returns true if fill is inverted and Path with fill represents area outside
2858of its geometric bounds.
2859
2860#Table
2861#Legend
2862# FillType # is inverse ##
2863##
2864# kWinding_FillType # false ##
2865# kEvenOdd_FillType # false ##
2866# kInverseWinding_FillType # true ##
2867# kInverseEvenOdd_FillType # true ##
2868##
2869
2870#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
2871 kInverseWinding_FillType, kInverseEvenOdd_FillType
2872##
2873
2874#Return true if Path fills outside its bounds ##
2875
2876#Example
2877#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05002878###$
Cary Clark73fa9722017-08-29 17:36:51 -04002879#define nameValue(fill) { SkPath::fill, #fill }
2880
Cary Clark1a8d7622018-03-05 13:26:16 -05002881$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04002882##
2883void draw(SkCanvas* canvas) {
2884 struct {
2885 SkPath::FillType fill;
2886 const char* name;
2887 } fills[] = {
2888 nameValue(kWinding_FillType),
2889 nameValue(kEvenOdd_FillType),
2890 nameValue(kInverseWinding_FillType),
2891 nameValue(kInverseEvenOdd_FillType),
2892 };
2893 for (auto fill: fills ) {
2894 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
2895 "true" : "false");
2896 }
2897}
2898#StdOut
2899IsInverseFillType(kWinding_FillType) == false
2900IsInverseFillType(kEvenOdd_FillType) == false
2901IsInverseFillType(kInverseWinding_FillType) == true
2902IsInverseFillType(kInverseEvenOdd_FillType) == true
2903##
2904##
2905
2906#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
2907
2908##
2909
2910# ------------------------------------------------------------------------------
2911
Cary Clark682c58d2018-05-16 07:07:07 -04002912#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05002913#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002914#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04002915Returns equivalent Fill_Type representing Path fill inside its bounds.
2916.
2917
2918#Table
2919#Legend
2920# FillType # inside FillType ##
2921##
2922# kWinding_FillType # kWinding_FillType ##
2923# kEvenOdd_FillType # kEvenOdd_FillType ##
2924# kInverseWinding_FillType # kWinding_FillType ##
2925# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
2926##
2927
2928#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
2929 kInverseWinding_FillType, kInverseEvenOdd_FillType
2930##
2931
2932#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
2933
2934#Example
2935#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05002936###$
Cary Clark73fa9722017-08-29 17:36:51 -04002937#define nameValue(fill) { SkPath::fill, #fill }
2938
Cary Clark1a8d7622018-03-05 13:26:16 -05002939$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04002940##
2941void draw(SkCanvas* canvas) {
2942 struct {
2943 SkPath::FillType fill;
2944 const char* name;
2945 } fills[] = {
2946 nameValue(kWinding_FillType),
2947 nameValue(kEvenOdd_FillType),
2948 nameValue(kInverseWinding_FillType),
2949 nameValue(kInverseEvenOdd_FillType),
2950 };
2951 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
2952 if (fills[i].fill != (SkPath::FillType) i) {
2953 SkDebugf("fills array order does not match FillType enum order");
2954 break;
Cary Clark682c58d2018-05-16 07:07:07 -04002955 }
Cary Clark73fa9722017-08-29 17:36:51 -04002956 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
2957 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
2958 }
2959}
2960#StdOut
2961ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
2962ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
2963ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
2964ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
2965##
2966##
2967
2968#SeeAlso FillType getFillType setFillType IsInverseFillType
2969
2970##
2971
2972# ------------------------------------------------------------------------------
2973
2974#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
2975 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05002976#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002977#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04002978
2979Approximates Conic with Quad array. Conic is constructed from start Point p0,
Cary Clark682c58d2018-05-16 07:07:07 -04002980control Point p1, end Point p2, and weight w.
Cary Clark73fa9722017-08-29 17:36:51 -04002981Quad array is stored in pts; this storage is supplied by caller.
2982Maximum Quad count is 2 to the pow2.
Cary Clark682c58d2018-05-16 07:07:07 -04002983Every third point in array shares last Point of previous Quad and first Point of
2984next Quad. Maximum pts storage size is given by:
Cary Clark2be81cf2018-09-13 12:04:30 -04002985#Formula # (1 + 2 * (1 << pow2)) * sizeof(SkPoint) ##.
Cary Clark6fc50412017-09-21 12:31:06 -04002986
Cary Clark154beea2017-10-26 07:58:48 -04002987Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04002988than the number requested.
Cary Clark682c58d2018-05-16 07:07:07 -04002989
Cary Clark73fa9722017-08-29 17:36:51 -04002990Conic_Weight determines the amount of influence Conic control point has on the curve.
2991w less than one represents an elliptical section. w greater than one represents
2992a hyperbolic section. w equal to one represents a parabolic section.
2993
2994Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
2995of up to 90 degrees; in this case, set pow2 to one.
2996
2997#Param p0 Conic start Point ##
2998#Param p1 Conic control Point ##
2999#Param p2 Conic end Point ##
3000#Param w Conic weight ##
3001#Param pts storage for Quad array ##
3002#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3003
Cary Clarka523d2d2017-08-30 08:58:10 -04003004#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003005
3006#Example
3007#Description
3008A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3009The middle curve is nearly circular. The top-right curve is parabolic, which can
3010be drawn exactly with a single Quad.
3011##
3012void draw(SkCanvas* canvas) {
3013 SkPaint conicPaint;
3014 conicPaint.setAntiAlias(true);
3015 conicPaint.setStyle(SkPaint::kStroke_Style);
3016 SkPaint quadPaint(conicPaint);
3017 quadPaint.setColor(SK_ColorRED);
3018 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3019 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3020 SkPoint quads[5];
3021 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3022 SkPath path;
3023 path.moveTo(conic[0]);
3024 path.conicTo(conic[1], conic[2], weight);
3025 canvas->drawPath(path, conicPaint);
3026 path.rewind();
3027 path.moveTo(quads[0]);
3028 path.quadTo(quads[1], quads[2]);
3029 path.quadTo(quads[3], quads[4]);
3030 canvas->drawPath(path, quadPaint);
3031 canvas->translate(50, -50);
3032 }
3033}
3034##
3035
3036#SeeAlso Conic Quad
3037
3038##
3039
3040# ------------------------------------------------------------------------------
3041
3042#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003043#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003044#Line # returns if describes Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -04003045#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003046
3047#Example
3048#Description
3049After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3050following lineTo does not. addPoly returns true even though rect is not closed, and one
3051side of rect is made up of consecutive line segments.
3052##
3053void draw(SkCanvas* canvas) {
3054 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3055 SkRect rect;
3056 SkPath::Direction direction;
3057 bool isClosed;
Cary Clark682c58d2018-05-16 07:07:07 -04003058 path.isRect(&rect, &isClosed, &direction) ?
Cary Clark73fa9722017-08-29 17:36:51 -04003059 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3060 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3061 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3062 SkDebugf("%s is not rect\n", prefix);
3063 };
3064 SkPath path;
3065 debugster("empty", path);
3066 path.addRect({10, 20, 30, 40});
3067 debugster("addRect", path);
3068 path.moveTo(60, 70);
3069 debugster("moveTo", path);
3070 path.lineTo(60, 70);
3071 debugster("lineTo", path);
3072 path.reset();
3073 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3074 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3075 debugster("addPoly", path);
3076}
3077#StdOut
3078empty is not rect
3079addRect is rect (10, 20, 30, 40); is closed; direction CW
3080moveTo is rect (10, 20, 30, 40); is closed; direction CW
3081lineTo is not rect
3082addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3083##
3084##
3085
3086#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3087
3088##
3089
3090# ------------------------------------------------------------------------------
3091
3092#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003093#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003094#Line # returns if describes Rect pair, one inside the other ##
Cary Clark09d80c02018-10-31 12:14:03 -04003095#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003096
3097#Example
3098void draw(SkCanvas* canvas) {
3099 SkPaint paint;
3100 paint.setStyle(SkPaint::kStroke_Style);
3101 paint.setStrokeWidth(5);
3102 SkPath path;
3103 path.addRect({10, 20, 30, 40});
3104 paint.getFillPath(path, &path);
3105 SkRect rects[2];
3106 SkPath::Direction directions[2];
3107 if (path.isNestedFillRects(rects, directions)) {
3108 for (int i = 0; i < 2; ++i) {
3109 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3110 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3111 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3112 }
3113 } else {
3114 SkDebugf("is not nested rectangles\n");
3115 }
3116}
3117#StdOut
3118outer (7.5, 17.5, 32.5, 42.5); direction CW
3119inner (12.5, 22.5, 27.5, 37.5); direction CCW
3120##
3121##
3122
3123#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3124
3125##
3126
3127# ------------------------------------------------------------------------------
3128
Cary Clark0251b1b2018-08-15 15:14:55 -04003129#Method SkPath& addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003130#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003131#Line # adds one Contour containing Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -04003132#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003133
Cary Clark73fa9722017-08-29 17:36:51 -04003134#Example
3135#Description
3136The left Rect dashes starting at the top-left corner, to the right.
3137The right Rect dashes starting at the top-left corner, towards the bottom.
3138##
3139#Height 128
3140void draw(SkCanvas* canvas) {
3141 SkPaint paint;
3142 paint.setStrokeWidth(15);
3143 paint.setStrokeCap(SkPaint::kSquare_Cap);
3144 float intervals[] = { 5, 21.75f };
3145 paint.setStyle(SkPaint::kStroke_Style);
3146 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3147 SkPath path;
3148 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
3149 canvas->drawPath(path, paint);
3150 path.rewind();
3151 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
3152 canvas->drawPath(path, paint);
3153}
3154##
3155
3156#SeeAlso SkCanvas::drawRect Direction
3157
3158##
3159
3160# ------------------------------------------------------------------------------
3161
Cary Clark0251b1b2018-08-15 15:14:55 -04003162#Method SkPath& addRect(const SkRect& rect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04003163
Cary Clark80247e52018-07-11 16:18:41 -04003164Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04003165If dir is kCW_Direction, Rect corners are added clockwise; if dir is
3166kCCW_Direction, Rect corners are added counterclockwise.
3167start determines the first corner added.
3168
3169#Table
3170#Legend
3171# start # first corner ##
3172#Legend ##
3173# 0 # top-left ##
3174# 1 # top-right ##
3175# 2 # bottom-right ##
3176# 3 # bottom-left ##
3177#Table ##
3178
3179#Param rect Rect to add as a closed contour ##
3180#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04003181#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04003182
Cary Clark0251b1b2018-08-15 15:14:55 -04003183#Return reference to Path ##
3184
Cary Clark73fa9722017-08-29 17:36:51 -04003185#Example
3186#Height 128
3187#Description
3188The arrow is just after the initial corner and points towards the next
3189corner appended to Path.
3190##
3191void draw(SkCanvas* canvas) {
3192 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
3193 const SkRect rect = {10, 10, 54, 54};
3194 SkPaint rectPaint;
3195 rectPaint.setAntiAlias(true);
3196 rectPaint.setStyle(SkPaint::kStroke_Style);
3197 SkPaint arrowPaint(rectPaint);
3198 SkPath arrowPath;
3199 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
3200 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
3201 SkPath1DPathEffect::kRotate_Style));
3202 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3203 for (unsigned start : { 0, 1, 2, 3 } ) {
3204 SkPath path;
3205 path.addRect(rect, direction, start);
3206 canvas->drawPath(path, rectPaint);
3207 canvas->drawPath(path, arrowPaint);
3208 canvas->translate(64, 0);
3209 }
3210 canvas->translate(-256, 64);
3211 }
3212}
3213##
3214
3215#SeeAlso SkCanvas::drawRect Direction
3216
3217##
3218
3219# ------------------------------------------------------------------------------
3220
Cary Clark0251b1b2018-08-15 15:14:55 -04003221#Method SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
Cary Clark73fa9722017-08-29 17:36:51 -04003222 Direction dir = kCW_Direction)
Cary Clark09d80c02018-10-31 12:14:03 -04003223#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003224
Cary Clark73fa9722017-08-29 17:36:51 -04003225#Example
3226#Description
3227The left Rect dashes start at the top-left corner, and continue to the right.
3228The right Rect dashes start at the top-left corner, and continue down.
3229##
3230#Height 128
3231void draw(SkCanvas* canvas) {
3232 SkPaint paint;
3233 paint.setStrokeWidth(15);
3234 paint.setStrokeCap(SkPaint::kSquare_Cap);
3235 float intervals[] = { 5, 21.75f };
3236 paint.setStyle(SkPaint::kStroke_Style);
3237 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3238 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3239 SkPath path;
3240 path.addRect(20, 20, 100, 100, direction);
3241 canvas->drawPath(path, paint);
3242 canvas->translate(128, 0);
3243 }
3244}
3245##
3246
3247#SeeAlso SkCanvas::drawRect Direction
3248
3249##
3250
3251# ------------------------------------------------------------------------------
3252
Cary Clark0251b1b2018-08-15 15:14:55 -04003253#Method SkPath& addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003254#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003255#Line # adds one Contour containing Oval ##
Cary Clark09d80c02018-10-31 12:14:03 -04003256#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003257
Cary Clark73fa9722017-08-29 17:36:51 -04003258#Example
3259#Height 120
3260 SkPaint paint;
3261 SkPath oval;
3262 oval.addOval({20, 20, 160, 80});
3263 canvas->drawPath(oval, paint);
3264##
3265
3266#SeeAlso SkCanvas::drawOval Direction Oval
3267
3268##
3269
3270# ------------------------------------------------------------------------------
3271
Cary Clark0251b1b2018-08-15 15:14:55 -04003272#Method SkPath& addOval(const SkRect& oval, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04003273
Cary Clark80247e52018-07-11 16:18:41 -04003274Adds Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04003275Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
3276and half oval height. Oval begins at start and continues
3277clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
3278
3279#Table
3280#Legend
3281# start # Point ##
3282#Legend ##
3283# 0 # oval.centerX(), oval.fTop ##
3284# 1 # oval.fRight, oval.centerY() ##
3285# 2 # oval.centerX(), oval.fBottom ##
3286# 3 # oval.fLeft, oval.centerY() ##
3287#Table ##
3288
3289#Param oval bounds of ellipse added ##
3290#Param dir Direction to wind ellipse ##
3291#Param start index of initial point of ellipse ##
3292
Cary Clark0251b1b2018-08-15 15:14:55 -04003293#Return reference to Path ##
3294
Cary Clark73fa9722017-08-29 17:36:51 -04003295#Example
3296#Height 160
3297void draw(SkCanvas* canvas) {
3298 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
3299 const SkRect rect = {10, 10, 54, 54};
3300 SkPaint ovalPaint;
3301 ovalPaint.setAntiAlias(true);
3302 SkPaint textPaint(ovalPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04003303 ovalPaint.setStyle(SkPaint::kStroke_Style);
3304 SkPaint arrowPaint(ovalPaint);
3305 SkPath arrowPath;
3306 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
3307 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
3308 SkPath1DPathEffect::kRotate_Style));
3309 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3310 for (unsigned start : { 0, 1, 2, 3 } ) {
3311 SkPath path;
3312 path.addOval(rect, direction, start);
3313 canvas->drawPath(path, ovalPaint);
3314 canvas->drawPath(path, arrowPaint);
3315 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
3316 canvas->translate(64, 0);
3317 }
3318 canvas->translate(-256, 72);
3319 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
3320 128, 0, textPaint);
3321 }
3322}
3323##
3324
3325#SeeAlso SkCanvas::drawOval Direction Oval
3326
3327##
3328
3329# ------------------------------------------------------------------------------
3330
Cary Clark0251b1b2018-08-15 15:14:55 -04003331#Method SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
Cary Clark73fa9722017-08-29 17:36:51 -04003332 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003333#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003334#Line # adds one Contour containing Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04003335
Cary Clark80247e52018-07-11 16:18:41 -04003336Adds Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark2be81cf2018-09-13 12:04:30 -04003337four kConic_Verb, and kClose_Verb. Circle begins at: #Formula # (x + radius, y) ##, continuing
Cary Clark154beea2017-10-26 07:58:48 -04003338clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04003339
Cary Clark6fc50412017-09-21 12:31:06 -04003340Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04003341
3342#Param x center of Circle ##
3343#Param y center of Circle ##
3344#Param radius distance from center to edge ##
3345#Param dir Direction to wind Circle ##
3346
Cary Clark0251b1b2018-08-15 15:14:55 -04003347#Return reference to Path ##
3348
Cary Clark73fa9722017-08-29 17:36:51 -04003349#Example
3350void draw(SkCanvas* canvas) {
3351 SkPaint paint;
3352 paint.setAntiAlias(true);
3353 paint.setStyle(SkPaint::kStroke_Style);
3354 paint.setStrokeWidth(10);
3355 for (int size = 10; size < 300; size += 20) {
3356 SkPath path;
3357 path.addCircle(128, 128, size, SkPath::kCW_Direction);
3358 canvas->drawPath(path, paint);
3359 }
3360}
3361##
3362
3363#SeeAlso SkCanvas::drawCircle Direction Circle
3364
3365##
3366
3367# ------------------------------------------------------------------------------
3368
Cary Clark0251b1b2018-08-15 15:14:55 -04003369#Method SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05003370#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003371#Line # adds one Contour containing Arc ##
Cary Clark09d80c02018-10-31 12:14:03 -04003372#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003373
Cary Clark73fa9722017-08-29 17:36:51 -04003374#Example
3375#Description
3376The middle row of the left and right columns draw differently from the entries
Cary Clark682c58d2018-05-16 07:07:07 -04003377above and below because sweepAngle is outside of the range of +/-360,
Cary Clark73fa9722017-08-29 17:36:51 -04003378and startAngle modulo 90 is not zero.
3379##
3380void draw(SkCanvas* canvas) {
3381 SkPaint paint;
3382 for (auto start : { 0, 90, 135, 180, 270 } ) {
3383 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
3384 SkPath path;
3385 path.addArc({10, 10, 35, 45}, start, sweep);
3386 canvas->drawPath(path, paint);
3387 canvas->translate(252 / 6, 0);
3388 }
3389 canvas->translate(-252, 255 / 5);
3390 }
3391}
3392##
3393
3394#SeeAlso Arc arcTo SkCanvas::drawArc
3395
3396##
3397
3398# ------------------------------------------------------------------------------
3399
Cary Clark0251b1b2018-08-15 15:14:55 -04003400#Method SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Cary Clark73fa9722017-08-29 17:36:51 -04003401 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003402#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003403#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark09d80c02018-10-31 12:14:03 -04003404#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003405
Cary Clark73fa9722017-08-29 17:36:51 -04003406#Example
3407#Description
3408If either radius is zero, path contains Rect and is drawn red.
3409If sides are only radii, path contains Oval and is drawn blue.
3410All remaining path draws are convex, and are drawn in gray; no
3411paths constructed from addRoundRect are concave, so none are
3412drawn in green.
3413##
3414void draw(SkCanvas* canvas) {
3415 SkPaint paint;
3416 paint.setAntiAlias(true);
3417 for (auto xradius : { 0, 7, 13, 20 } ) {
3418 for (auto yradius : { 0, 9, 18, 40 } ) {
3419 SkPath path;
3420 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
3421 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
3422 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
3423 canvas->drawPath(path, paint);
3424 canvas->translate(64, 0);
3425 }
3426 canvas->translate(-256, 64);
3427 }
3428}
3429##
3430
3431#SeeAlso addRRect SkCanvas::drawRoundRect
3432
3433##
3434
3435# ------------------------------------------------------------------------------
3436
Cary Clark0251b1b2018-08-15 15:14:55 -04003437#Method SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
Cary Clark73fa9722017-08-29 17:36:51 -04003438 Direction dir = kCW_Direction)
3439
Cary Clark80247e52018-07-11 16:18:41 -04003440Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04003441equal to rect; each corner is 90 degrees of an ellipse with radii from the
3442array.
3443
3444#Table
3445#Legend
3446# radii index # location ##
3447#Legend ##
Cary Clark5538c132018-06-14 12:28:14 -04003448# 0 # x-axis radius of top-left corner ##
3449# 1 # y-axis radius of top-left corner ##
3450# 2 # x-axis radius of top-right corner ##
3451# 3 # y-axis radius of top-right corner ##
3452# 4 # x-axis radius of bottom-right corner ##
3453# 5 # y-axis radius of bottom-right corner ##
3454# 6 # x-axis radius of bottom-left corner ##
3455# 7 # y-axis radius of bottom-left corner ##
Cary Clark73fa9722017-08-29 17:36:51 -04003456#Table ##
3457
Cary Clark682c58d2018-05-16 07:07:07 -04003458If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
3459and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
Cary Clark73fa9722017-08-29 17:36:51 -04003460bottom-left of the upper-left corner and winds counterclockwise.
3461
Cary Clark682c58d2018-05-16 07:07:07 -04003462If both radii on any side of rect exceed its length, all radii are scaled
Cary Clark73fa9722017-08-29 17:36:51 -04003463uniformly until the corners fit. If either radius of a corner is less than or
3464equal to zero, both are treated as zero.
3465
3466After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
3467
3468#Param rect bounds of Round_Rect ##
3469#Param radii array of 8 SkScalar values, a radius pair for each corner ##
3470#Param dir Direction to wind Round_Rect ##
3471
Cary Clark0251b1b2018-08-15 15:14:55 -04003472#Return reference to Path ##
3473
Cary Clark73fa9722017-08-29 17:36:51 -04003474#Example
3475void draw(SkCanvas* canvas) {
3476 SkPaint paint;
3477 paint.setAntiAlias(true);
3478 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
3479 SkPath path;
3480 SkMatrix rotate90;
3481 rotate90.setRotate(90, 128, 128);
3482 for (int i = 0; i < 4; ++i) {
3483 path.addRoundRect({10, 10, 110, 110}, radii);
3484 path.transform(rotate90);
3485 }
3486 canvas->drawPath(path, paint);
3487}
3488##
3489
3490#SeeAlso addRRect SkCanvas::drawRoundRect
3491
3492##
3493
3494# ------------------------------------------------------------------------------
3495
Cary Clark0251b1b2018-08-15 15:14:55 -04003496#Method SkPath& addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003497#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003498#Line # adds one Contour containing Round_Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -04003499#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003500
Cary Clark73fa9722017-08-29 17:36:51 -04003501#Example
3502void draw(SkCanvas* canvas) {
3503 SkPaint paint;
3504 paint.setAntiAlias(true);
3505 SkRRect rrect;
3506 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
3507 rrect.setRectRadii({10, 10, 110, 110}, radii);
3508 SkPath path;
3509 SkMatrix rotate90;
3510 rotate90.setRotate(90, 128, 128);
3511 for (int i = 0; i < 4; ++i) {
3512 path.addRRect(rrect);
3513 path.transform(rotate90);
3514 }
3515 canvas->drawPath(path, paint);
3516}
3517##
3518
3519#SeeAlso addRoundRect SkCanvas::drawRRect
3520
3521##
3522
3523# ------------------------------------------------------------------------------
3524
Cary Clark0251b1b2018-08-15 15:14:55 -04003525#Method SkPath& addRRect(const SkRRect& rrect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04003526
Cary Clark80247e52018-07-11 16:18:41 -04003527Adds rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
Cary Clark73fa9722017-08-29 17:36:51 -04003528winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
3529start determines the first point of rrect to add.
3530
3531#Table
3532#Legend
3533# start # location ##
3534#Legend ##
3535# 0 # right of top-left corner ##
3536# 1 # left of top-right corner ##
3537# 2 # bottom of top-right corner ##
3538# 3 # top of bottom-right corner ##
3539# 4 # left of bottom-right corner ##
3540# 5 # right of bottom-left corner ##
3541# 6 # top of bottom-left corner ##
3542# 7 # bottom of top-left corner ##
3543#Table ##
3544
3545After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
3546
3547#Param rrect bounds and radii of rounded rectangle ##
3548#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04003549#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04003550
Cary Clark0251b1b2018-08-15 15:14:55 -04003551#Return reference to Path ##
3552
Cary Clark73fa9722017-08-29 17:36:51 -04003553#Example
3554void draw(SkCanvas* canvas) {
Mike Reed6a388002018-10-16 13:13:09 -04003555 SkPaint paint;
3556 paint.setAntiAlias(true);
3557 SkRRect rrect;
3558 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
3559 SkPath path;
3560 path.addRRect(rrect);
3561 canvas->drawPath(path, paint);
3562 for (int start = 0; start < 8; ++start) {
3563 SkPath textPath;
3564 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
3565 SkPathMeasure pathMeasure(textPath, false);
3566 SkPoint position;
3567 SkVector tangent;
3568 if (!pathMeasure.getPosTan(0, &position, &tangent)) {
3569 continue;
3570 }
3571 SkRSXform rsxForm = SkRSXform::Make(tangent.fX, tangent.fY,
3572 position.fX + tangent.fY * 5, position.fY - tangent.fX * 5);
3573 canvas->drawTextRSXform(&"01234567"[start], 1, &rsxForm, nullptr, paint);
3574 }
Cary Clark73fa9722017-08-29 17:36:51 -04003575}
3576##
3577
Cary Clark682c58d2018-05-16 07:07:07 -04003578#SeeAlso addRoundRect SkCanvas::drawRRect
Cary Clark73fa9722017-08-29 17:36:51 -04003579
3580##
3581
3582# ------------------------------------------------------------------------------
3583
Cary Clark0251b1b2018-08-15 15:14:55 -04003584#Method SkPath& addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05003585#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003586#Line # adds one Contour containing connected lines ##
Cary Clark09d80c02018-10-31 12:14:03 -04003587#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003588
Cary Clark73fa9722017-08-29 17:36:51 -04003589#Example
3590void draw(SkCanvas* canvas) {
3591 SkPaint paint;
3592 paint.setStrokeWidth(15);
3593 paint.setStrokeCap(SkPaint::kRound_Cap);
3594 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3595 for (bool close : { false, true } ) {
3596 SkPath path;
3597 path.addPoly(points, SK_ARRAY_COUNT(points), close);
3598 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3599 SkPaint::kStrokeAndFill_Style} ) {
3600 paint.setStyle(style);
3601 canvas->drawPath(path, paint);
3602 canvas->translate(85, 0);
3603 }
3604 canvas->translate(-255, 128);
3605 }
3606}
3607##
3608
3609#SeeAlso SkCanvas::drawPoints
3610
3611##
3612
Cary Clark0251b1b2018-08-15 15:14:55 -04003613#Method SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close)
Cary Clark09d80c02018-10-31 12:14:03 -04003614#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003615
3616#Example
3617void draw(SkCanvas* canvas) {
3618 SkPaint paint;
3619 paint.setStrokeWidth(15);
3620 paint.setStrokeCap(SkPaint::kRound_Cap);
3621 for (bool close : { false, true } ) {
3622 SkPath path;
3623 path.addPoly({{20, 20}, {70, 20}, {40, 90}}, close);
3624 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3625 SkPaint::kStrokeAndFill_Style} ) {
3626 paint.setStyle(style);
3627 canvas->drawPath(path, paint);
3628 canvas->translate(85, 0);
3629 }
3630 canvas->translate(-255, 128);
3631 }
3632}
3633##
3634
3635#SeeAlso SkCanvas::drawPoints
3636
3637##
3638
Cary Clark73fa9722017-08-29 17:36:51 -04003639# ------------------------------------------------------------------------------
3640
3641#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05003642#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04003643
3644#Code
3645 enum AddPathMode {
Cary Clark682c58d2018-05-16 07:07:07 -04003646 kAppend_AddPathMode,
3647 kExtend_AddPathMode,
Cary Clark73fa9722017-08-29 17:36:51 -04003648 };
3649##
3650
3651AddPathMode chooses how addPath appends. Adding one Path to another can extend
3652the last Contour or start a new Contour.
3653
3654#Const kAppend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04003655#Line # appended to destination unaltered ##
Cary Clark73fa9722017-08-29 17:36:51 -04003656 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
3657 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
3658 starts a new Contour.
3659##
3660#Const kExtend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04003661#Line # add line if prior Contour is not closed ##
Cary Clark73fa9722017-08-29 17:36:51 -04003662 If destination is closed or empty, start a new Contour. If destination
3663 is not empty, add Line from Last_Point to added Path first Point. Skip added
3664 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
3665##
3666
3667#Example
3668#Description
3669test is built from path, open on the top row, and closed on the bottom row.
3670The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
3671The top right composition is made up of one contour; the other three have two.
3672##
3673#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04003674 SkPath path, path2;
3675 path.moveTo(20, 20);
3676 path.lineTo(20, 40);
3677 path.lineTo(40, 20);
3678 path2.moveTo(60, 60);
3679 path2.lineTo(80, 60);
3680 path2.lineTo(80, 40);
3681 SkPaint paint;
3682 paint.setStyle(SkPaint::kStroke_Style);
3683 for (int i = 0; i < 2; i++) {
3684 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
3685 SkPath test(path);
3686 test.addPath(path2, addPathMode);
3687 canvas->drawPath(test, paint);
3688 canvas->translate(100, 0);
3689 }
3690 canvas->translate(-200, 100);
3691 path.close();
3692 }
Cary Clark73fa9722017-08-29 17:36:51 -04003693##
3694
3695#SeeAlso addPath reverseAddPath
3696
3697##
3698
3699# ------------------------------------------------------------------------------
3700
Cary Clark0251b1b2018-08-15 15:14:55 -04003701#Method SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
Cary Clark73fa9722017-08-29 17:36:51 -04003702 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05003703#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003704#Line # adds contents of Path ##
Cary Clark09d80c02018-10-31 12:14:03 -04003705#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003706
Cary Clark73fa9722017-08-29 17:36:51 -04003707#Example
3708#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04003709 SkPaint paint;
3710 paint.setTextSize(128);
3711 paint.setFakeBoldText(true);
3712 SkPath dest, text;
3713 paint.getTextPath("O", 1, 50, 120, &text);
3714 for (int i = 0; i < 3; i++) {
3715 dest.addPath(text, i * 20, i * 20);
3716 }
3717 Simplify(dest, &dest);
3718 paint.setStyle(SkPaint::kStroke_Style);
3719 paint.setStrokeWidth(3);
3720 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003721##
3722
Cary Clark4855f782018-02-06 09:41:53 -05003723#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04003724
3725##
3726
3727# ------------------------------------------------------------------------------
3728
Cary Clark0251b1b2018-08-15 15:14:55 -04003729#Method SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
Cary Clark09d80c02018-10-31 12:14:03 -04003730#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003731
Cary Clark73fa9722017-08-29 17:36:51 -04003732#Example
3733#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04003734 SkPaint paint;
3735 paint.setStyle(SkPaint::kStroke_Style);
3736 SkPath dest, path;
3737 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
3738 for (int i = 0; i < 2; i++) {
3739 dest.addPath(path, SkPath::kExtend_AddPathMode);
3740 dest.offset(100, 0);
3741 }
Cary Clark73fa9722017-08-29 17:36:51 -04003742 canvas->drawPath(dest, paint);
3743##
3744
3745#SeeAlso AddPathMode reverseAddPath
3746
3747##
3748
3749# ------------------------------------------------------------------------------
3750
Cary Clark0251b1b2018-08-15 15:14:55 -04003751#Method SkPath& addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
Cary Clark09d80c02018-10-31 12:14:03 -04003752#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003753
Cary Clark73fa9722017-08-29 17:36:51 -04003754#Example
3755#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04003756 SkPaint paint;
3757 paint.setStyle(SkPaint::kStroke_Style);
3758 SkPath dest, path;
3759 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
3760 for (int i = 0; i < 6; i++) {
3761 SkMatrix matrix;
3762 matrix.reset();
3763 matrix.setPerspX(i / 400.f);
3764 dest.addPath(path, matrix);
3765 }
3766 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003767##
3768
Cary Clark4855f782018-02-06 09:41:53 -05003769#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04003770
3771##
3772
3773# ------------------------------------------------------------------------------
3774
Cary Clark0251b1b2018-08-15 15:14:55 -04003775#Method SkPath& reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05003776#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003777#Line # adds contents of Path back to front ##
Cary Clark09d80c02018-10-31 12:14:03 -04003778#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003779
Cary Clark73fa9722017-08-29 17:36:51 -04003780#Example
3781#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04003782 SkPath path;
3783 path.moveTo(20, 20);
3784 path.lineTo(20, 40);
3785 path.lineTo(40, 20);
3786 SkPaint paint;
3787 paint.setStyle(SkPaint::kStroke_Style);
3788 for (int i = 0; i < 2; i++) {
3789 SkPath path2;
3790 path2.moveTo(60, 60);
3791 path2.lineTo(80, 60);
3792 path2.lineTo(80, 40);
3793 for (int j = 0; j < 2; j++) {
3794 SkPath test(path);
3795 test.reverseAddPath(path2);
3796 canvas->drawPath(test, paint);
3797 canvas->translate(100, 0);
3798 path2.close();
3799 }
3800 canvas->translate(-200, 100);
3801 path.close();
3802 }
Cary Clark73fa9722017-08-29 17:36:51 -04003803##
3804
Cary Clark4855f782018-02-06 09:41:53 -05003805#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04003806
3807##
3808
3809# ------------------------------------------------------------------------------
3810
3811#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05003812#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05003813#Line # translates Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04003814#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003815
3816#Example
3817#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04003818 SkPath pattern;
3819 pattern.moveTo(20, 20);
3820 pattern.lineTo(20, 40);
3821 pattern.lineTo(40, 20);
3822 SkPaint paint;
3823 paint.setStyle(SkPaint::kStroke_Style);
3824 for (int i = 0; i < 10; i++) {
3825 SkPath path;
3826 pattern.offset(20 * i, 0, &path);
3827 canvas->drawPath(path, paint);
3828 }
Cary Clark73fa9722017-08-29 17:36:51 -04003829##
3830
3831#SeeAlso addPath transform
3832
3833##
3834
3835# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05003836#Subtopic Transform
Cary Clark4855f782018-02-06 09:41:53 -05003837#Line # modify all points ##
3838##
Cary Clark73fa9722017-08-29 17:36:51 -04003839
Cary Clark682c58d2018-05-16 07:07:07 -04003840#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003841#In Transform
Cary Clark09d80c02018-10-31 12:14:03 -04003842#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003843
3844#Example
3845#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04003846 SkPath path;
3847 path.moveTo(20, 20);
3848 path.lineTo(20, 40);
3849 path.lineTo(40, 20);
3850 SkPaint paint;
3851 paint.setStyle(SkPaint::kStroke_Style);
3852 for (int i = 0; i < 10; i++) {
3853 canvas->drawPath(path, paint);
3854 path.offset(20, 0);
3855 }
Cary Clark73fa9722017-08-29 17:36:51 -04003856##
3857
3858#SeeAlso addPath transform SkCanvas::translate()
3859
3860##
3861
3862# ------------------------------------------------------------------------------
3863
3864#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05003865#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05003866#Line # applies Matrix to Point_Array and Weights ##
Cary Clark09d80c02018-10-31 12:14:03 -04003867#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003868
3869#Example
Cary Clark8032b982017-07-28 11:04:54 -04003870#Height 200
3871 SkPath pattern;
3872 pattern.moveTo(100, 100);
3873 pattern.lineTo(100, 20);
3874 pattern.lineTo(20, 100);
3875 SkPaint paint;
3876 paint.setStyle(SkPaint::kStroke_Style);
3877 for (int i = 0; i < 10; i++) {
3878 SkPath path;
3879 SkMatrix matrix;
3880 matrix.setRotate(36 * i, 100, 100);
3881 pattern.transform(matrix, &path);
3882 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003883 }
3884##
3885
3886#SeeAlso addPath offset SkCanvas::concat() SkMatrix
3887
3888##
3889
3890# ------------------------------------------------------------------------------
3891
Cary Clark682c58d2018-05-16 07:07:07 -04003892#Method void transform(const SkMatrix& matrix)
Cary Clark09d80c02018-10-31 12:14:03 -04003893#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003894
3895#Example
Cary Clark8032b982017-07-28 11:04:54 -04003896#Height 200
3897 SkPath path;
3898 path.moveTo(100, 100);
3899 path.quadTo(100, 20, 20, 100);
3900 SkPaint paint;
3901 paint.setStyle(SkPaint::kStroke_Style);
3902 for (int i = 0; i < 10; i++) {
3903 SkMatrix matrix;
3904 matrix.setRotate(36, 100, 100);
3905 path.transform(matrix);
3906 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003907 }
3908##
3909
3910#SeeAlso addPath offset SkCanvas::concat() SkMatrix
3911
3912##
3913
3914# ------------------------------------------------------------------------------
3915
Cary Clark8032b982017-07-28 11:04:54 -04003916#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05003917#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04003918
3919Path is defined cumulatively, often by adding a segment to the end of last
3920Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
3921Last_Point can be read and written directly with getLastPt and setLastPt.
3922
Cary Clark73fa9722017-08-29 17:36:51 -04003923#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05003924#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003925#In Last_Point
3926#Line # returns Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04003927#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003928
Cary Clark09d80c02018-10-31 12:14:03 -04003929#Example
Cary Clark8032b982017-07-28 11:04:54 -04003930 SkPath path;
3931 path.moveTo(100, 100);
3932 path.quadTo(100, 20, 20, 100);
3933 SkMatrix matrix;
3934 matrix.setRotate(36, 100, 100);
3935 path.transform(matrix);
3936 SkPoint last;
3937 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04003938 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
3939 #StdOut
3940 last point: 35.2786, 52.9772
Cary Clark682c58d2018-05-16 07:07:07 -04003941 ##
Cary Clark73fa9722017-08-29 17:36:51 -04003942 ##
3943
3944 #SeeAlso setLastPt
3945
3946##
3947
3948#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003949#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003950#In Last_Point
3951#Line # replaces Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04003952#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003953
Cary Clark09d80c02018-10-31 12:14:03 -04003954#Example
Cary Clark73fa9722017-08-29 17:36:51 -04003955 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04003956 SkPaint paint;
3957 paint.setTextSize(128);
3958 SkPath path;
3959 paint.getTextPath("@", 1, 60, 100, &path);
3960 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04003961 canvas->drawPath(path, paint);
3962 ##
3963
3964 #SeeAlso getLastPt
3965
3966##
3967
Cary Clark682c58d2018-05-16 07:07:07 -04003968#Method void setLastPt(const SkPoint& p)
Cary Clark09d80c02018-10-31 12:14:03 -04003969#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003970
Cary Clark09d80c02018-10-31 12:14:03 -04003971#Example
Cary Clark73fa9722017-08-29 17:36:51 -04003972 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04003973 SkPaint paint;
3974 paint.setTextSize(128);
3975 SkPath path, path2;
3976 paint.getTextPath("A", 1, 60, 100, &path);
3977 paint.getTextPath("Z", 1, 60, 100, &path2);
3978 SkPoint pt, pt2;
3979 path.getLastPt(&pt);
3980 path2.getLastPt(&pt2);
3981 path.setLastPt(pt2);
3982 path2.setLastPt(pt);
3983 canvas->drawPath(path, paint);
3984 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003985 ##
3986
3987 #SeeAlso getLastPt
3988
3989##
3990
3991#Subtopic Last_Point ##
3992
3993# ------------------------------------------------------------------------------
3994
3995#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05003996#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04003997
3998#Code
3999 enum SegmentMask {
4000 kLine_SegmentMask = 1 << 0,
4001 kQuad_SegmentMask = 1 << 1,
4002 kConic_SegmentMask = 1 << 2,
4003 kCubic_SegmentMask = 1 << 3,
4004 };
4005##
4006
4007SegmentMask constants correspond to each drawing Verb type in Path; for
4008instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4009
Cary Clark4855f782018-02-06 09:41:53 -05004010#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04004011#Const kLine_SegmentMask 1
Cary Clark682c58d2018-05-16 07:07:07 -04004012#Line # contains one or more Lines ##
Cary Clark73fa9722017-08-29 17:36:51 -04004013Set if Verb_Array contains kLine_Verb.
4014##
4015#Const kQuad_SegmentMask 2
Cary Clark682c58d2018-05-16 07:07:07 -04004016#Line # contains one or more Quads ##
Cary Clark73fa9722017-08-29 17:36:51 -04004017Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4018##
4019#Const kConic_SegmentMask 4
Cary Clark682c58d2018-05-16 07:07:07 -04004020#Line # contains one or more Conics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004021Set if Verb_Array contains kConic_Verb.
4022##
4023#Const kCubic_SegmentMask 8
Cary Clark682c58d2018-05-16 07:07:07 -04004024#Line # contains one or more Cubics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004025Set if Verb_Array contains kCubic_Verb.
4026##
4027
4028#Example
4029#Description
4030When conicTo has a weight of one, Quad is added to Path.
4031##
4032 SkPath path;
4033 path.conicTo(10, 10, 20, 30, 1);
Cary Clark682c58d2018-05-16 07:07:07 -04004034 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004035 SkPath::kConic_SegmentMask ? "set" : "clear");
Cary Clark682c58d2018-05-16 07:07:07 -04004036 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004037 SkPath::kQuad_SegmentMask ? "set" : "clear");
4038#StdOut
4039Path kConic_SegmentMask is clear
4040Path kQuad_SegmentMask is set
4041##
4042##
4043
4044#SeeAlso getSegmentMasks Verb
4045
4046##
4047
4048# ------------------------------------------------------------------------------
4049
Cary Clark682c58d2018-05-16 07:07:07 -04004050#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05004051#In Utility
4052#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004053#Line # returns types in Verb_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04004054#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004055
4056#Example
4057SkPath path;
4058path.quadTo(20, 30, 40, 50);
4059path.close();
4060const char* masks[] = { "line", "quad", "conic", "cubic" };
4061int index = 0;
4062for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4063 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4064 if (mask & path.getSegmentMasks()) {
4065 SkDebugf("mask %s set\n", masks[index]);
Cary Clark682c58d2018-05-16 07:07:07 -04004066 }
Cary Clark73fa9722017-08-29 17:36:51 -04004067 ++index;
4068}
4069#StdOut
4070mask quad set
4071##
4072##
4073
4074#SeeAlso getSegmentMasks Verb
4075
4076##
4077
4078# ------------------------------------------------------------------------------
4079
4080#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05004081#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004082#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04004083Returns true if the point (x, y) is contained by Path, taking into
Cary Clark682c58d2018-05-16 07:07:07 -04004084account FillType.
Cary Clark73fa9722017-08-29 17:36:51 -04004085
4086#Table
4087#Legend
4088# FillType # contains() returns true if Point is enclosed by ##
4089##
4090# kWinding_FillType # a non-zero sum of Contour Directions. ##
4091# kEvenOdd_FillType # an odd number of Contours. ##
4092# kInverseWinding_FillType # a zero sum of Contour Directions. ##
4093# kInverseEvenOdd_FillType # and even number of Contours. ##
Cary Clark682c58d2018-05-16 07:07:07 -04004094##
Cary Clark73fa9722017-08-29 17:36:51 -04004095
Cary Clark5538c132018-06-14 12:28:14 -04004096#Param x x-axis value of containment test ##
4097#Param y y-axis value of containment test ##
Cary Clark73fa9722017-08-29 17:36:51 -04004098
4099#Return true if Point is in Path ##
4100
4101#Example
4102SkPath path;
4103SkPaint paint;
4104paint.setTextSize(256);
4105paint.getTextPath("&", 1, 30, 220, &path);
4106for (int y = 2; y < 256; y += 9) {
4107 for (int x = 2; x < 256; x += 9) {
4108 int coverage = 0;
4109 for (int iy = -4; iy <= 4; iy += 2) {
4110 for (int ix = -4; ix <= 4; ix += 2) {
4111 coverage += path.contains(x + ix, y + iy);
4112 }
4113 }
4114 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
4115 canvas->drawCircle(x, y, 8, paint);
4116 }
4117}
4118##
4119
4120#SeeAlso conservativelyContainsRect Fill_Type Op
4121
4122##
4123
4124# ------------------------------------------------------------------------------
4125
4126#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05004127#In Utility
Cary Clark53498e92018-06-28 19:13:56 -04004128#Line # sends text representation to stream ##
Cary Clark09d80c02018-10-31 12:14:03 -04004129#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004130
4131#Example
4132 SkPath path;
4133 path.quadTo(20, 30, 40, 50);
4134 for (bool forceClose : { false, true } ) {
4135 for (bool dumpAsHex : { false, true } ) {
4136 path.dump(nullptr, forceClose, dumpAsHex);
4137 SkDebugf("\n");
4138 }
4139 }
4140#StdOut
4141path.setFillType(SkPath::kWinding_FillType);
4142path.moveTo(0, 0);
4143path.quadTo(20, 30, 40, 50);
4144
4145path.setFillType(SkPath::kWinding_FillType);
4146path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4147path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
4148
4149path.setFillType(SkPath::kWinding_FillType);
4150path.moveTo(0, 0);
4151path.quadTo(20, 30, 40, 50);
4152path.lineTo(0, 0);
4153path.close();
4154
4155path.setFillType(SkPath::kWinding_FillType);
4156path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4157path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
4158path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4159path.close();
4160##
4161##
4162
Cary Clark53498e92018-06-28 19:13:56 -04004163#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
Cary Clark73fa9722017-08-29 17:36:51 -04004164
4165##
4166
4167# ------------------------------------------------------------------------------
4168
4169#Method void dump() const
Cary Clark09d80c02018-10-31 12:14:03 -04004170#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004171
4172#Example
4173SkPath path, copy;
4174path.lineTo(6.f / 7, 2.f / 3);
4175path.dump();
4176copy.setFillType(SkPath::kWinding_FillType);
4177copy.moveTo(0, 0);
4178copy.lineTo(0.857143f, 0.666667f);
4179SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4180#StdOut
4181path.setFillType(SkPath::kWinding_FillType);
4182path.moveTo(0, 0);
4183path.lineTo(0.857143f, 0.666667f);
4184path is not equal to copy
4185##
4186##
4187
4188#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
4189
4190##
4191
4192# ------------------------------------------------------------------------------
4193
4194#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05004195#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004196#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04004197Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04004198directly compiled as C++ code. Floating point values are written
4199in hexadecimal to preserve their exact bit pattern. The output reconstructs the
4200original Path.
4201
Cary Clark682c58d2018-05-16 07:07:07 -04004202Use instead of dump() when submitting
4203#A bug reports against Skia # https://bug.skia.org ##
Cary Clark6fc50412017-09-21 12:31:06 -04004204.
Cary Clark73fa9722017-08-29 17:36:51 -04004205
4206#Example
4207SkPath path, copy;
4208path.lineTo(6.f / 7, 2.f / 3);
4209path.dumpHex();
4210copy.setFillType(SkPath::kWinding_FillType);
4211copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4212copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
4213SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4214#StdOut
4215path.setFillType(SkPath::kWinding_FillType);
4216path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4217path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
4218path is equal to copy
4219##
4220##
4221
Cary Clark186d08f2018-04-03 08:43:27 -04004222#SeeAlso dump SkRect::dumpHex SkRRect::dumpHex writeToMemory
Cary Clark73fa9722017-08-29 17:36:51 -04004223
4224##
4225
4226# ------------------------------------------------------------------------------
4227
4228#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05004229#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004230#Line # copies data to buffer ##
Cary Clark09d80c02018-10-31 12:14:03 -04004231#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004232
4233#Example
4234void draw(SkCanvas* canvas) {
4235 SkPath path, copy;
4236 path.lineTo(6.f / 7, 2.f / 3);
4237 size_t size = path.writeToMemory(nullptr);
4238 SkTDArray<char> storage;
4239 storage.setCount(size);
4240 path.writeToMemory(storage.begin());
4241 copy.readFromMemory(storage.begin(), size);
4242 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4243}
4244#StdOut
4245path is equal to copy
4246##
4247##
4248
4249#SeeAlso serialize readFromMemory dump dumpHex
4250
4251##
4252
4253#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05004254#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004255#Line # copies data to buffer ##
Cary Clark09d80c02018-10-31 12:14:03 -04004256#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004257
4258#Example
4259void draw(SkCanvas* canvas) {
4260 SkPath path, copy;
4261 path.lineTo(6.f / 7, 2.f / 3);
4262 sk_sp<SkData> data = path.serialize();
4263 copy.readFromMemory(data->data(), data->size());
4264 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4265}
4266#StdOut
4267path is equal to copy
4268##
4269##
4270
4271#SeeAlso writeToMemory readFromMemory dump dumpHex
4272##
4273
4274# ------------------------------------------------------------------------------
4275
4276#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05004277#In Utility
Cary Clark682c58d2018-05-16 07:07:07 -04004278#Line # initializes from buffer ##
Cary Clark09d80c02018-10-31 12:14:03 -04004279#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004280
4281#Example
4282void draw(SkCanvas* canvas) {
4283 SkPath path, copy;
4284 path.lineTo(6.f / 7, 2.f / 3);
4285 size_t size = path.writeToMemory(nullptr);
4286 SkTDArray<char> storage;
4287 storage.setCount(size);
4288 path.writeToMemory(storage.begin());
4289 size_t wrongSize = size - 4;
4290 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
4291 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
4292 size_t largerSize = size + 4;
4293 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
4294 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
4295}
4296#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04004297length = 32; returned by readFromMemory = 0
Cary Clark06c20f32018-03-20 15:53:27 -04004298length = 40; returned by readFromMemory = 36
Cary Clark73fa9722017-08-29 17:36:51 -04004299##
4300##
4301
4302#SeeAlso writeToMemory
4303
4304##
4305
4306# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05004307#Subtopic Generation_ID
Cary Clark137b8742018-05-30 09:21:49 -04004308#Alias Generation_IDs ##
Cary Clark08895c42018-02-01 09:37:32 -05004309#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04004310Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
4311Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
4312not necessarily have matching Generation_IDs.
4313
4314Empty Paths have a Generation_ID of one.
4315
4316#Method uint32_t getGenerationID() const
4317
Cary Clarkab2621d2018-01-30 10:08:57 -05004318#In Generation_ID
4319#Line # returns unique ID ##
Cary Clark09d80c02018-10-31 12:14:03 -04004320#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004321
4322#Example
4323SkPath path;
4324SkDebugf("empty genID = %u\n", path.getGenerationID());
4325path.lineTo(1, 2);
4326SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
4327path.rewind();
4328SkDebugf("empty genID = %u\n", path.getGenerationID());
4329path.lineTo(1, 2);
4330SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
4331#StdOut
4332empty genID = 1
43331st lineTo genID = 2
4334empty genID = 1
43352nd lineTo genID = 3
4336##
4337##
4338
4339#SeeAlso operator==(const SkPath& a, const SkPath& b)
4340
4341##
4342
Cary Clark78de7512018-02-07 07:27:09 -05004343#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04004344
4345# ------------------------------------------------------------------------------
4346
4347#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05004348#In Property
4349#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004350#Line # returns if data is internally consistent ##
Cary Clark09d80c02018-10-31 12:14:03 -04004351#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004352
Cary Clark09d80c02018-10-31 12:14:03 -04004353#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004354 ##
4355
4356##
4357
4358#Method bool pathRefIsValid() const
Cary Clark4855f782018-02-06 09:41:53 -05004359#Deprecated soon
Cary Clark73fa9722017-08-29 17:36:51 -04004360##
4361
4362# ------------------------------------------------------------------------------
4363
Cary Clark8032b982017-07-28 11:04:54 -04004364#Class Iter
Cary Clark682c58d2018-05-16 07:07:07 -04004365#Line # data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04004366
Cary Clark73fa9722017-08-29 17:36:51 -04004367#Code
Cary Clark61313f32018-10-08 14:57:48 -04004368#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004369##
4370
Cary Clark137b8742018-05-30 09:21:49 -04004371Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
4372Provides options to treat open Contours as closed, and to ignore
4373degenerate data.
4374
Cary Clark8032b982017-07-28 11:04:54 -04004375#Example
4376#Height 128
4377#Description
Cary Clark73fa9722017-08-29 17:36:51 -04004378Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04004379path of the glyph.
4380##
Cary Clark73fa9722017-08-29 17:36:51 -04004381void draw(SkCanvas* canvas) {
4382 SkPaint paint;
4383 paint.setAntiAlias(true);
4384 paint.setTextSize(256);
4385 SkPath asterisk, path;
4386 paint.getTextPath("*", 1, 50, 192, &asterisk);
Cary Clark682c58d2018-05-16 07:07:07 -04004387 SkPath::Iter iter(asterisk, true);
Cary Clark73fa9722017-08-29 17:36:51 -04004388 SkPoint start[4], pts[4];
4389 iter.next(start); // skip moveTo
4390 iter.next(start); // first quadTo
4391 path.moveTo((start[0] + start[1]) * 0.5f);
4392 while (SkPath::kClose_Verb != iter.next(pts)) {
4393 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
4394 }
4395 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
4396 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04004397}
4398##
4399
4400#SeeAlso RawIter
4401
4402#Method Iter()
Cary Clark682c58d2018-05-16 07:07:07 -04004403#Line # constructs Path iterator ##
Cary Clark09d80c02018-10-31 12:14:03 -04004404#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004405
4406#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004407void draw(SkCanvas* canvas) {
4408 SkPath::Iter iter;
4409 SkPoint points[4];
4410 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
4411 SkPath path;
4412 iter.setPath(path, false);
4413 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04004414}
Cary Clark73fa9722017-08-29 17:36:51 -04004415#StdOut
4416iter is done
4417iter is done
4418##
Cary Clark8032b982017-07-28 11:04:54 -04004419##
4420
4421#SeeAlso setPath
4422
4423##
4424
4425#Method Iter(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004426#Line # constructs Path iterator ##
Cary Clark09d80c02018-10-31 12:14:03 -04004427#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004428
4429#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004430void draw(SkCanvas* canvas) {
4431 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
4432 SkDebugf("%s:\n", prefix);
4433 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4434 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4435 SkPath::Verb verb;
4436 do {
4437 SkPoint points[4];
4438 verb = iter.next(points);
4439 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4440 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4441 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
4442 }
4443 if (SkPath::kConic_Verb == verb) {
4444 SkDebugf("weight = %g", iter.conicWeight());
4445 }
4446 SkDebugf("\n");
4447 } while (SkPath::kDone_Verb != verb);
4448 SkDebugf("\n");
4449 };
4450
4451 SkPath path;
4452 path.quadTo(10, 20, 30, 40);
4453 SkPath::Iter openIter(path, false);
4454 debugster("open", openIter);
4455 SkPath::Iter closedIter(path, true);
4456 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04004457}
4458#StdOut
4459open:
Cary Clark682c58d2018-05-16 07:07:07 -04004460kMove_Verb {0, 0},
4461kQuad_Verb {0, 0}, {10, 20}, {30, 40},
4462kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004463
4464closed:
Cary Clark682c58d2018-05-16 07:07:07 -04004465kMove_Verb {0, 0},
4466kQuad_Verb {0, 0}, {10, 20}, {30, 40},
4467kLine_Verb {30, 40}, {0, 0},
4468kClose_Verb {0, 0},
4469kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004470##
4471##
4472
4473#SeeAlso setPath
4474
4475##
4476
4477#Method void setPath(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004478#Line # resets Iter to Path ##
Cary Clark09d80c02018-10-31 12:14:03 -04004479#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004480
4481#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004482void draw(SkCanvas* canvas) {
4483 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
4484 SkDebugf("%s:\n", prefix);
4485 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4486 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4487 SkPath::Verb verb;
4488 do {
4489 SkPoint points[4];
4490 verb = iter.next(points);
4491 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4492 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4493 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
4494 }
4495 if (SkPath::kConic_Verb == verb) {
4496 SkDebugf("weight = %g", iter.conicWeight());
4497 }
4498 SkDebugf("\n");
4499 } while (SkPath::kDone_Verb != verb);
4500 SkDebugf("\n");
4501 };
4502
4503 SkPath path;
4504 path.quadTo(10, 20, 30, 40);
4505 SkPath::Iter iter(path, false);
4506 debugster("quad open", iter);
4507 SkPath path2;
4508 path2.conicTo(1, 2, 3, 4, .5f);
4509 iter.setPath(path2, true);
4510 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04004511}
4512#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004513quad open:
Cary Clark682c58d2018-05-16 07:07:07 -04004514kMove_Verb {0, 0},
4515kQuad_Verb {0, 0}, {10, 20}, {30, 40},
4516kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004517
4518conic closed:
Cary Clark682c58d2018-05-16 07:07:07 -04004519kMove_Verb {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04004520kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04004521kLine_Verb {3, 4}, {0, 0},
4522kClose_Verb {0, 0},
4523kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004524##
4525##
4526
4527#SeeAlso Iter(const SkPath& path, bool forceClose)
4528
4529##
4530
Cary Clark682c58d2018-05-16 07:07:07 -04004531#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004532#Line # returns next Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004533#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004534
4535#Example
Cary Clark682c58d2018-05-16 07:07:07 -04004536#Description
Cary Clark8032b982017-07-28 11:04:54 -04004537skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
4538followed by the kClose_Verb, the zero length Line and the very small Line.
4539
4540skip degenerate if exact skips the same as skip degenerate, but shows
4541the very small Line.
4542
4543skip none shows all of the Verbs and Points in Path.
4544##
Cary Clark73fa9722017-08-29 17:36:51 -04004545void draw(SkCanvas* canvas) {
4546 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
4547 SkPath::Iter iter(path, false);
4548 SkDebugf("%s:\n", prefix);
4549 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4550 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4551 SkPath::Verb verb;
4552 do {
4553 SkPoint points[4];
4554 verb = iter.next(points, degen, exact);
4555 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4556 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4557 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
4558 }
4559 SkDebugf("\n");
4560 } while (SkPath::kDone_Verb != verb);
4561 SkDebugf("\n");
4562 };
4563
4564 SkPath path;
4565 path.moveTo(10, 10);
4566 path.moveTo(20, 20);
4567 path.quadTo(10, 20, 30, 40);
4568 path.moveTo(1, 1);
4569 path.close();
4570 path.moveTo(30, 30);
4571 path.lineTo(30, 30);
4572 path.moveTo(30, 30);
4573 path.lineTo(30.00001f, 30);
4574 debugster("skip degenerate", path, true, false);
4575 debugster("skip degenerate if exact", path, true, true);
4576 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04004577}
4578#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004579skip degenerate:
Cary Clark682c58d2018-05-16 07:07:07 -04004580kMove_Verb {20, 20},
4581kQuad_Verb {20, 20}, {10, 20}, {30, 40},
4582kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004583
4584skip degenerate if exact:
Cary Clark682c58d2018-05-16 07:07:07 -04004585kMove_Verb {20, 20},
4586kQuad_Verb {20, 20}, {10, 20}, {30, 40},
4587kMove_Verb {30, 30},
4588kLine_Verb {30, 30}, {30.00001, 30},
4589kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004590
4591skip none:
Cary Clark682c58d2018-05-16 07:07:07 -04004592kMove_Verb {10, 10},
4593kMove_Verb {20, 20},
4594kQuad_Verb {20, 20}, {10, 20}, {30, 40},
4595kMove_Verb {1, 1},
4596kClose_Verb {1, 1},
4597kMove_Verb {30, 30},
4598kLine_Verb {30, 30}, {30, 30},
4599kMove_Verb {30, 30},
4600kLine_Verb {30, 30}, {30.00001, 30},
4601kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004602##
4603##
4604
Cary Clark682c58d2018-05-16 07:07:07 -04004605#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
Cary Clark8032b982017-07-28 11:04:54 -04004606
4607##
4608
4609#Method SkScalar conicWeight() const
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004610#Line # returns Conic_Weight ##
Cary Clark09d80c02018-10-31 12:14:03 -04004611#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004612
Cary Clark09d80c02018-10-31 12:14:03 -04004613#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004614 void draw(SkCanvas* canvas) {
4615 SkPath path;
4616 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04004617 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04004618 SkPoint p[4];
4619 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
4620 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
4621 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
4622 p[2].fX, p[2].fY);
4623 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04004624 }
4625 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004626first verb is move
4627next verb is conic
4628conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04004629conic weight: 0.5
4630 ##
4631 ##
4632
4633 #SeeAlso Conic_Weight
4634
4635##
4636
4637#Method bool isCloseLine() const
Cary Clark682c58d2018-05-16 07:07:07 -04004638#Line # returns if Line was generated by kClose_Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004639#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004640
Cary Clark09d80c02018-10-31 12:14:03 -04004641#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004642void draw(SkCanvas* canvas) {
4643 SkPath path;
4644 path.moveTo(6, 7);
4645 path.conicTo(1, 2, 3, 4, .5f);
4646 path.close();
Cary Clark682c58d2018-05-16 07:07:07 -04004647 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04004648 SkPoint p[4];
4649 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
4650 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
4651 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
4652 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
4653 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
4654 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
4655 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04004656}
4657 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040046581st verb is move
4659moveTo point: {6,7}
46602nd verb is conic
46613rd verb is line
4662line points: {3,4}, {6,7}
4663line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040046644th verb is close
4665 ##
4666 ##
4667
4668 #SeeAlso close()
4669##
4670
4671#Method bool isClosedContour() const
Cary Clark682c58d2018-05-16 07:07:07 -04004672#Line # returns if Contour has kClose_Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004673#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004674
4675#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004676void draw(SkCanvas* canvas) {
4677 for (bool forceClose : { false, true } ) {
4678 SkPath path;
4679 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04004680 SkPath::Iter iter(path, forceClose);
Cary Clark73fa9722017-08-29 17:36:51 -04004681 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
4682 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
4683 path.close();
4684 iter.setPath(path, forceClose);
4685 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
4686 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
4687 }
Cary Clark8032b982017-07-28 11:04:54 -04004688}
4689#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004690without close(), forceClose is false: isClosedContour returns false
4691with close(), forceClose is false: isClosedContour returns true
4692without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04004693with close(), forceClose is true : isClosedContour returns true
4694##
4695##
4696
4697#SeeAlso Iter(const SkPath& path, bool forceClose)
4698
4699##
Cary Clark73fa9722017-08-29 17:36:51 -04004700
4701#Class Iter ##
4702
Cary Clark8032b982017-07-28 11:04:54 -04004703#Class RawIter
Cary Clark682c58d2018-05-16 07:07:07 -04004704#Line # raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04004705
Cary Clark73fa9722017-08-29 17:36:51 -04004706#Code
Cary Clark61313f32018-10-08 14:57:48 -04004707#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004708##
4709
Cary Clark137b8742018-05-30 09:21:49 -04004710Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
4711Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
4712
Cary Clark61313f32018-10-08 14:57:48 -04004713
Cary Clark8032b982017-07-28 11:04:54 -04004714 #Method RawIter()
Cary Clark682c58d2018-05-16 07:07:07 -04004715 #Line # constructs empty Path iterator ##
Cary Clark09d80c02018-10-31 12:14:03 -04004716#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004717
Cary Clark09d80c02018-10-31 12:14:03 -04004718#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004719 ##
4720 ##
Cary Clark8032b982017-07-28 11:04:54 -04004721
4722 #Method RawIter(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04004723 #Line # constructs with Path to iterate over ##
Cary Clark09d80c02018-10-31 12:14:03 -04004724#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004725
Cary Clark09d80c02018-10-31 12:14:03 -04004726#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004727 ##
4728 ##
Cary Clark8032b982017-07-28 11:04:54 -04004729
4730 #Method void setPath(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04004731 #Line # sets Path to iterate over ##
Cary Clark09d80c02018-10-31 12:14:03 -04004732#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004733
Cary Clark09d80c02018-10-31 12:14:03 -04004734#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004735 ##
4736 ##
Cary Clark8032b982017-07-28 11:04:54 -04004737
4738 #Method Verb next(SkPoint pts[4])
Cary Clark682c58d2018-05-16 07:07:07 -04004739 #Line # returns next Verb and associated Points ##
Cary Clark09d80c02018-10-31 12:14:03 -04004740#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004741
Cary Clark09d80c02018-10-31 12:14:03 -04004742#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004743 void draw(SkCanvas* canvas) {
4744 SkPath path;
4745 path.moveTo(50, 60);
4746 path.quadTo(10, 20, 30, 40);
4747 path.close();
4748 path.lineTo(30, 30);
4749 path.conicTo(1, 2, 3, 4, .5f);
4750 path.cubicTo(-1, -2, -3, -4, -5, -6);
4751 SkPath::RawIter iter(path);
4752 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4753 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4754 SkPath::Verb verb;
4755 do {
4756 SkPoint points[4];
4757 verb = iter.next(points);
4758 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4759 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4760 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
4761 }
4762 if (SkPath::kConic_Verb == verb) {
4763 SkDebugf("weight = %g", iter.conicWeight());
4764 }
4765 SkDebugf("\n");
4766 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04004767 }
4768 #StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04004769 kMove_Verb {50, 60},
4770 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
4771 kClose_Verb {50, 60},
4772 kMove_Verb {50, 60},
4773 kLine_Verb {50, 60}, {30, 30},
Cary Clark73fa9722017-08-29 17:36:51 -04004774 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04004775 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
4776 kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004777 ##
4778 ##
4779
4780 #SeeAlso peek()
4781
Cary Clark73fa9722017-08-29 17:36:51 -04004782 ##
Cary Clark8032b982017-07-28 11:04:54 -04004783
4784 #Method Verb peek() const
Cary Clark682c58d2018-05-16 07:07:07 -04004785 #Line # returns next Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004786 #Populate
Cary Clark8032b982017-07-28 11:04:54 -04004787
4788 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04004789 SkPath path;
4790 path.quadTo(10, 20, 30, 40);
4791 path.conicTo(1, 2, 3, 4, .5f);
4792 path.cubicTo(1, 2, 3, 4, .5, 6);
4793 SkPath::RawIter iter(path);
4794 SkPath::Verb verb, peek = iter.peek();
4795 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4796 do {
4797 SkPoint points[4];
4798 verb = iter.next(points);
4799 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
4800 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04004801 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04004802 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
4803 #StdOut
4804 #Volatile
4805 peek Move == verb Move
4806 peek Quad == verb Quad
4807 peek Conic == verb Conic
4808 peek Cubic == verb Cubic
4809 peek Done == verb Done
4810 peek Done == verb Done
4811 ##
Cary Clark8032b982017-07-28 11:04:54 -04004812 ##
4813
4814 #Bug 6832
Cary Clark09d80c02018-10-31 12:14:03 -04004815 # StdOut is not really volatile, it just produces the wrong result.
4816 # A simple fix changes the output of hairlines and needs to be
4817 # investigated to see if the change is correct or not.
4818 # see change 21340 (abandoned for now)
Cary Clark8032b982017-07-28 11:04:54 -04004819
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004820 #SeeAlso next
Cary Clark8032b982017-07-28 11:04:54 -04004821
Cary Clark73fa9722017-08-29 17:36:51 -04004822 ##
Cary Clark8032b982017-07-28 11:04:54 -04004823
Cary Clark73fa9722017-08-29 17:36:51 -04004824 #Method SkScalar conicWeight() const
Cary Clark682c58d2018-05-16 07:07:07 -04004825 #Line # returns Conic_Weight ##
Cary Clark09d80c02018-10-31 12:14:03 -04004826#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004827
Cary Clark09d80c02018-10-31 12:14:03 -04004828#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004829 void draw(SkCanvas* canvas) {
4830 SkPath path;
4831 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04004832 SkPath::RawIter iter(path);
Cary Clark73fa9722017-08-29 17:36:51 -04004833 SkPoint p[4];
4834 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
4835 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
4836 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
4837 p[2].fX, p[2].fY);
4838 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04004839 }
4840 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004841 first verb is move
4842 next verb is conic
4843 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04004844 conic weight: 0.5
4845 ##
4846 ##
4847
4848 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04004849
4850 ##
4851
4852#Class RawIter ##
4853
4854#Class SkPath ##
4855
4856#Topic Path ##