blob: 11d0b5308a17dd90b5cadfabea671488b9bb92d7 [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
Cary Clark77b3f3a2018-11-07 14:59:03 -0500317rewind() removes Verb_Array but leaves storage; since storage is not compared,
Cary Clark73fa9722017-08-29 17:36:51 -0400318Path 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# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400469#Subtopic Fill_Type
Cary Clark682c58d2018-05-16 07:07:07 -0400470#Line # fill rule, normal and inverted ##
Cary Clark8032b982017-07-28 11:04:54 -0400471
Cary Clark73fa9722017-08-29 17:36:51 -0400472#Enum FillType
Cary Clark08895c42018-02-01 09:37:32 -0500473#Line # sets winding rule and inverse fill ##
Cary Clark73fa9722017-08-29 17:36:51 -0400474
475#Code
476 enum FillType {
Cary Clark682c58d2018-05-16 07:07:07 -0400477 kWinding_FillType,
478 kEvenOdd_FillType,
479 kInverseWinding_FillType,
480 kInverseEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400481 };
482##
Cary Clark8032b982017-07-28 11:04:54 -0400483
Cary Clark682c58d2018-05-16 07:07:07 -0400484Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
Cary Clark8032b982017-07-28 11:04:54 -0400485fills if the sum of Contour edges is not zero, where clockwise edges add one, and
486counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
Cary Clark682c58d2018-05-16 07:07:07 -0400487number of Contour edges is odd. Each Fill_Type has an inverse variant that
Cary Clark8032b982017-07-28 11:04:54 -0400488reverses the rule:
489kInverseWinding_FillType fills where the sum of Contour edges is zero;
490kInverseEvenOdd_FillType fills where the number of Contour edges is even.
491
492#Example
493#Height 100
494#Description
495The top row has two clockwise rectangles. The second row has one clockwise and
496one counterclockwise rectangle. The even-odd variants draw the same. The
497winding variants draw the top rectangle overlap, which has a winding of 2, the
498same as the outer parts of the top rectangles, which have a winding of 1.
499##
Cary Clark73fa9722017-08-29 17:36:51 -0400500void draw(SkCanvas* canvas) {
501 SkPath path;
502 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
503 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
504 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
505 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
506 SkPaint strokePaint;
507 strokePaint.setStyle(SkPaint::kStroke_Style);
508 SkRect clipRect = {0, 0, 51, 100};
509 canvas->drawPath(path, strokePaint);
510 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400511 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400512 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
513 canvas->translate(51, 0);
514 canvas->save();
515 canvas->clipRect(clipRect);
516 path.setFillType(fillType);
517 canvas->drawPath(path, fillPaint);
518 canvas->restore();
519 }
Cary Clark8032b982017-07-28 11:04:54 -0400520}
521##
Cary Clark73fa9722017-08-29 17:36:51 -0400522
523#Const kWinding_FillType 0
Cary Clark682c58d2018-05-16 07:07:07 -0400524#Line # is enclosed by a non-zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400525##
526#Const kEvenOdd_FillType 1
Cary Clark682c58d2018-05-16 07:07:07 -0400527#Line # is enclosed by an odd number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400528##
529#Const kInverseWinding_FillType 2
Cary Clark682c58d2018-05-16 07:07:07 -0400530#Line # is enclosed by a zero sum of Contour Directions ##
Cary Clark73fa9722017-08-29 17:36:51 -0400531##
532#Const kInverseEvenOdd_FillType 3
Cary Clark682c58d2018-05-16 07:07:07 -0400533#Line # is enclosed by an even number of Contours ##
Cary Clark73fa9722017-08-29 17:36:51 -0400534##
535
536#Example
537#Height 230
538void draw(SkCanvas* canvas) {
539 SkPath path;
540 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
541 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
542 SkPaint strokePaint;
543 strokePaint.setStyle(SkPaint::kStroke_Style);
544 SkRect clipRect = {0, 0, 128, 128};
545 canvas->drawPath(path, strokePaint);
546 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
547 SkPaint textPaint;
548 textPaint.setAntiAlias(true);
Cary Clark73fa9722017-08-29 17:36:51 -0400549 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
550 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
551 textPaint.setTextSize(18);
552 canvas->translate(0, 128);
553 canvas->scale(.5f, .5f);
554 canvas->drawString("inverse", 384, 150, textPaint);
555 SkPaint fillPaint;
Cary Clark682c58d2018-05-16 07:07:07 -0400556 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
Cary Clark73fa9722017-08-29 17:36:51 -0400557 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
558 canvas->save();
559 canvas->clipRect(clipRect);
560 path.setFillType(fillType);
561 canvas->drawPath(path, fillPaint);
562 canvas->restore();
563 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
564 canvas->translate(128, 0);
565 }
566}
567##
568
569#SeeAlso SkPaint::Style Direction getFillType setFillType
570
571##
572
573# ------------------------------------------------------------------------------
574
Cary Clark682c58d2018-05-16 07:07:07 -0400575#Method FillType getFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400576
Cary Clarkab2621d2018-01-30 10:08:57 -0500577#In Fill_Type
578#Line # returns Fill_Type: winding, even-odd, inverse ##
Cary Clark09d80c02018-10-31 12:14:03 -0400579#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400580
581#Example
582 SkPath path;
583 SkDebugf("default path fill type is %s\n",
584 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
Cary Clark682c58d2018-05-16 07:07:07 -0400585 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
Cary Clark73fa9722017-08-29 17:36:51 -0400586 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
587 "kInverseEvenOdd_FillType");
588#StdOut
589default path fill type is kWinding_FillType
590##
591##
592
593#SeeAlso FillType setFillType isInverseFillType
594
595##
596
597# ------------------------------------------------------------------------------
598
Cary Clark682c58d2018-05-16 07:07:07 -0400599#Method void setFillType(FillType ft)
Cary Clark73fa9722017-08-29 17:36:51 -0400600
Cary Clarkab2621d2018-01-30 10:08:57 -0500601#In Fill_Type
602#Line # sets Fill_Type: winding, even-odd, inverse ##
Cary Clark09d80c02018-10-31 12:14:03 -0400603#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400604
605#Example
606#Description
607If empty Path is set to inverse FillType, it fills all pixels.
608##
609#Height 64
610 SkPath path;
611 path.setFillType(SkPath::kInverseWinding_FillType);
612 SkPaint paint;
613 paint.setColor(SK_ColorBLUE);
614 canvas->drawPath(path, paint);
615##
616
617#SeeAlso FillType getFillType toggleInverseFillType
618
619##
620
621# ------------------------------------------------------------------------------
622
Cary Clark682c58d2018-05-16 07:07:07 -0400623#Method bool isInverseFillType() const
Cary Clark73fa9722017-08-29 17:36:51 -0400624
Cary Clarkab2621d2018-01-30 10:08:57 -0500625#In Fill_Type
626#Line # returns if Fill_Type fills outside geometry ##
Cary Clark09d80c02018-10-31 12:14:03 -0400627#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400628
629#Example
630 SkPath path;
631 SkDebugf("default path fill type is inverse: %s\n",
632 path.isInverseFillType() ? "true" : "false");
633#StdOut
634default path fill type is inverse: false
635##
636##
637
638#SeeAlso FillType getFillType setFillType toggleInverseFillType
639
640##
641
642# ------------------------------------------------------------------------------
643
Cary Clark682c58d2018-05-16 07:07:07 -0400644#Method void toggleInverseFillType()
Cary Clark73fa9722017-08-29 17:36:51 -0400645
Cary Clarkab2621d2018-01-30 10:08:57 -0500646#In Fill_Type
647#Line # toggles Fill_Type between inside and outside geometry ##
Cary Clark80247e52018-07-11 16:18:41 -0400648Replaces FillType with its inverse. The inverse of FillType describes the area
Cary Clark73fa9722017-08-29 17:36:51 -0400649unmodified by the original FillType.
650
Cary Clark682c58d2018-05-16 07:07:07 -0400651#Table
Cary Clark73fa9722017-08-29 17:36:51 -0400652#Legend
Cary Clark682c58d2018-05-16 07:07:07 -0400653# FillType # toggled FillType ##
Cary Clark73fa9722017-08-29 17:36:51 -0400654##
655# kWinding_FillType # kInverseWinding_FillType ##
656# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
657# kInverseWinding_FillType # kWinding_FillType ##
658# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
659##
660
661#Example
662#Description
663Path drawn normally and through its inverse touches every pixel once.
664##
665#Height 100
666SkPath path;
667SkPaint paint;
668paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -0400669paint.setTextSize(80);
670paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -0400671canvas->drawPath(path, paint);
672path.toggleInverseFillType();
673paint.setColor(SK_ColorGREEN);
674canvas->drawPath(path, paint);
675##
676
677#SeeAlso FillType getFillType setFillType isInverseFillType
678
679##
680
Cary Clark8032b982017-07-28 11:04:54 -0400681#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -0400682
683# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400684
685#Subtopic Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500686#Line # if Path is concave or convex ##
Cary Clark73fa9722017-08-29 17:36:51 -0400687
688#Enum Convexity
Cary Clark08895c42018-02-01 09:37:32 -0500689#Line # returns if Path is convex or concave ##
Cary Clark73fa9722017-08-29 17:36:51 -0400690
691#Code
Cary Clark884dd7d2017-10-11 10:37:52 -0400692 enum Convexity : uint8_t {
Cary Clark682c58d2018-05-16 07:07:07 -0400693 kUnknown_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400694 kConvex_Convexity,
Cary Clark682c58d2018-05-16 07:07:07 -0400695 kConcave_Convexity,
Cary Clark73fa9722017-08-29 17:36:51 -0400696 };
697##
698
Cary Clark682c58d2018-05-16 07:07:07 -0400699Path is convex if it contains one Contour and Contour loops no more than
700360 degrees, and Contour angles all have same Direction. Convex Path
Cary Clark8032b982017-07-28 11:04:54 -0400701may have better performance and require fewer resources on GPU_Surface.
702
Cary Clark73fa9722017-08-29 17:36:51 -0400703Path is concave when either at least one Direction change is clockwise and
704another is counterclockwise, or the sum of the changes in Direction is not 360
705degrees.
706
Cary Clark682c58d2018-05-16 07:07:07 -0400707Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
Cary Clark73fa9722017-08-29 17:36:51 -0400708if needed by destination Surface.
709
710#Const kUnknown_Convexity 0
Cary Clark682c58d2018-05-16 07:07:07 -0400711#Line # indicates Convexity has not been determined ##
Cary Clark73fa9722017-08-29 17:36:51 -0400712##
713#Const kConvex_Convexity 1
Cary Clark682c58d2018-05-16 07:07:07 -0400714#Line # one Contour made of a simple geometry without indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400715##
716#Const kConcave_Convexity 2
Cary Clark682c58d2018-05-16 07:07:07 -0400717#Line # more than one Contour, or a geometry with indentations ##
Cary Clark73fa9722017-08-29 17:36:51 -0400718##
719
720#Example
721void draw(SkCanvas* canvas) {
722 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400723 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400724 const char* labels[] = { "unknown", "convex", "concave" };
725 for (SkScalar x : { 40, 100 } ) {
726 SkPath path;
727 quad[0].fX = x;
728 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
729 canvas->drawPath(path, paint);
730 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
731 canvas->translate(100, 100);
732 }
733}
734##
735
736#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
737
738#Enum Convexity ##
739
Cary Clark682c58d2018-05-16 07:07:07 -0400740#Method Convexity getConvexity() const
Cary Clark73fa9722017-08-29 17:36:51 -0400741
Cary Clarkab2621d2018-01-30 10:08:57 -0500742#In Convexity
743#Line # returns geometry convexity, computing if necessary ##
Cary Clark09d80c02018-10-31 12:14:03 -0400744#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400745
746#Example
747void draw(SkCanvas* canvas) {
748 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -0400749 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -0400750 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
751 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
752 SkPath path;
753 debugster("initial", path);
754 path.lineTo(50, 0);
755 debugster("first line", path);
756 path.lineTo(50, 50);
757 debugster("second line", path);
758 path.lineTo(100, 50);
759 debugster("third line", path);
760}
761##
762
763#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
764
765##
766
767# ------------------------------------------------------------------------------
768
Cary Clark682c58d2018-05-16 07:07:07 -0400769#Method Convexity getConvexityOrUnknown() const
Cary Clark73fa9722017-08-29 17:36:51 -0400770
Cary Clarkab2621d2018-01-30 10:08:57 -0500771#In Convexity
772#Line # returns geometry convexity if known ##
Cary Clark09d80c02018-10-31 12:14:03 -0400773#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400774
775#Example
776#Description
777Convexity is unknown unless getConvexity is called without a subsequent call
778that alters the path.
779##
780void draw(SkCanvas* canvas) {
781 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -0400782 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -0400783 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
784 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
785 SkPath path;
786 debugster("initial", path);
787 path.lineTo(50, 0);
788 debugster("first line", path);
789 path.getConvexity();
790 path.lineTo(50, 50);
791 debugster("second line", path);
792 path.lineTo(100, 50);
793 path.getConvexity();
794 debugster("third line", path);
795}
796##
797
798#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
799
800##
801
802# ------------------------------------------------------------------------------
803
804#Method void setConvexity(Convexity convexity)
805
Cary Clarkab2621d2018-01-30 10:08:57 -0500806#In Convexity
807#Line # sets if geometry is convex to avoid future computation ##
Cary Clark09d80c02018-10-31 12:14:03 -0400808#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400809
810#Example
811void draw(SkCanvas* canvas) {
812 auto debugster = [](const char* prefix, const SkPath& path) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -0400813 SkDebugf("%s path convexity is %s\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -0400814 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
815 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
Cary Clark682c58d2018-05-16 07:07:07 -0400816 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400817 SkPath path;
818 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
819 debugster("initial", path);
820 path.setConvexity(SkPath::kConcave_Convexity);
821 debugster("after forcing concave", path);
822 path.setConvexity(SkPath::kUnknown_Convexity);
823 debugster("after forcing unknown", path);
824}
825##
826
827#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
828
829##
830
831# ------------------------------------------------------------------------------
832
Cary Clark682c58d2018-05-16 07:07:07 -0400833#Method bool isConvex() const
Cary Clark73fa9722017-08-29 17:36:51 -0400834
Cary Clarkab2621d2018-01-30 10:08:57 -0500835#In Convexity
836#Line # returns if geometry is convex ##
Cary Clark09d80c02018-10-31 12:14:03 -0400837#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400838
839#Example
840#Description
Cary Clark682c58d2018-05-16 07:07:07 -0400841Concave shape is erroneously considered convex after a forced call to
Cary Clark73fa9722017-08-29 17:36:51 -0400842setConvexity.
843##
844void draw(SkCanvas* canvas) {
845 SkPaint paint;
Cary Clark682c58d2018-05-16 07:07:07 -0400846 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
Cary Clark73fa9722017-08-29 17:36:51 -0400847 for (SkScalar x : { 40, 100 } ) {
848 SkPath path;
849 quad[0].fX = x;
850 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
851 path.setConvexity(SkPath::kConvex_Convexity);
852 canvas->drawPath(path, paint);
853 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
854 canvas->translate(100, 100);
855 }
856}
857##
858
859#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
860
861##
862
Cary Clark73fa9722017-08-29 17:36:51 -0400863#Subtopic Convexity ##
864
865# ------------------------------------------------------------------------------
866
Mike Reed0c3137c2018-02-20 13:57:05 -0500867#Method bool isOval(SkRect* bounds) const
Cary Clark4855f782018-02-06 09:41:53 -0500868#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -0500869#Line # returns if describes Oval ##
Cary Clark09d80c02018-10-31 12:14:03 -0400870#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400871
872#Example
873void draw(SkCanvas* canvas) {
874 SkPaint paint;
875 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -0500876 path.addOval({20, 20, 220, 220});
Cary Clark73fa9722017-08-29 17:36:51 -0400877 SkRect bounds;
Mike Reed0c3137c2018-02-20 13:57:05 -0500878 if (path.isOval(&bounds)) {
879 paint.setColor(0xFF9FBFFF);
880 canvas->drawRect(bounds, paint);
881 }
Cary Clark73fa9722017-08-29 17:36:51 -0400882 paint.setColor(0x3f000000);
883 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -0400884}
885##
886
887#SeeAlso Oval addCircle addOval
888
889##
890
891# ------------------------------------------------------------------------------
892
Mike Reed0c3137c2018-02-20 13:57:05 -0500893#Method bool isRRect(SkRRect* rrect) const
Cary Clark4855f782018-02-06 09:41:53 -0500894#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -0500895#Line # returns if describes Round_Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -0400896#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400897
898#Example
Cary Clarkce101242017-09-01 15:51:02 -0400899#Description
Mike Reed0c3137c2018-02-20 13:57:05 -0500900Draw rounded rectangle and its bounds.
Cary Clarkce101242017-09-01 15:51:02 -0400901##
Cary Clark73fa9722017-08-29 17:36:51 -0400902void draw(SkCanvas* canvas) {
903 SkPaint paint;
904 SkPath path;
Mike Reed0c3137c2018-02-20 13:57:05 -0500905 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50));
Cary Clark73fa9722017-08-29 17:36:51 -0400906 SkRRect rrect;
Mike Reed0c3137c2018-02-20 13:57:05 -0500907 if (path.isRRect(&rrect)) {
908 const SkRect& bounds = rrect.rect();
909 paint.setColor(0xFF9FBFFF);
910 canvas->drawRect(bounds, paint);
911 }
Cary Clark73fa9722017-08-29 17:36:51 -0400912 paint.setColor(0x3f000000);
913 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -0400914}
915##
916
Cary Clark682c58d2018-05-16 07:07:07 -0400917#SeeAlso Round_Rect addRoundRect addRRect
Cary Clark73fa9722017-08-29 17:36:51 -0400918
919##
920
921# ------------------------------------------------------------------------------
922
Cary Clark0251b1b2018-08-15 15:14:55 -0400923#Method SkPath& reset()
Cary Clark61313f32018-10-08 14:57:48 -0400924#In Constructors
Cary Clarkab2621d2018-01-30 10:08:57 -0500925#Line # removes Verb_Array, Point_Array, and Weights; frees memory ##
Cary Clark09d80c02018-10-31 12:14:03 -0400926#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -0400927
Cary Clark73fa9722017-08-29 17:36:51 -0400928#Example
929 SkPath path1, path2;
930 path1.setFillType(SkPath::kInverseWinding_FillType);
931 path1.addRect({10, 20, 30, 40});
932 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
933 path1.reset();
934 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
935##
936
937#SeeAlso rewind()
938
939##
940
941# ------------------------------------------------------------------------------
942
Cary Clark0251b1b2018-08-15 15:14:55 -0400943#Method SkPath& rewind()
Cary Clark61313f32018-10-08 14:57:48 -0400944#In Constructors
Cary Clarkab2621d2018-01-30 10:08:57 -0500945#Line # removes Verb_Array, Point_Array, and Weights, keeping memory ##
Cary Clark09d80c02018-10-31 12:14:03 -0400946#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -0400947
Cary Clark73fa9722017-08-29 17:36:51 -0400948#Example
949#Description
950Although path1 retains its internal storage, it is indistinguishable from
951a newly initialized path.
952##
953 SkPath path1, path2;
954 path1.setFillType(SkPath::kInverseWinding_FillType);
955 path1.addRect({10, 20, 30, 40});
956 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
957 path1.rewind();
958 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
959##
960
961#SeeAlso reset()
962
963##
964
965# ------------------------------------------------------------------------------
966
Cary Clark682c58d2018-05-16 07:07:07 -0400967#Method bool isEmpty() const
Cary Clark4855f782018-02-06 09:41:53 -0500968#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -0500969#Line # returns if verb count is zero ##
Cary Clark09d80c02018-10-31 12:14:03 -0400970#Populate
Cary Clark73fa9722017-08-29 17:36:51 -0400971
972#Example
973void draw(SkCanvas* canvas) {
974 auto debugster = [](const char* prefix, const SkPath& path) -> void {
975 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
976 };
977 SkPath path;
978 debugster("initial", path);
979 path.moveTo(0, 0);
980 debugster("after moveTo", path);
981 path.rewind();
982 debugster("after rewind", path);
983 path.lineTo(0, 0);
984 debugster("after lineTo", path);
985 path.reset();
986 debugster("after reset", path);
987}
988#StdOut
989initial path is empty
990after moveTo path is not empty
991after rewind path is empty
992after lineTo path is not empty
993after reset path is empty
994##
995##
996
997#SeeAlso SkPath() reset() rewind()
998
999##
1000
1001# ------------------------------------------------------------------------------
1002
1003#Method bool isLastContourClosed() const
Cary Clark4855f782018-02-06 09:41:53 -05001004#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001005#Line # returns if final Contour forms a loop ##
Cary Clark09d80c02018-10-31 12:14:03 -04001006#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001007
1008#Example
1009#Description
1010close() has no effect if Path is empty; isLastContourClosed() returns
1011false until Path has geometry followed by close().
1012##
1013void draw(SkCanvas* canvas) {
1014 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1015 SkDebugf("%s last contour is %s" "closed\n", prefix,
1016 path.isLastContourClosed() ? "" : "not ");
1017 };
1018 SkPath path;
1019 debugster("initial", path);
1020 path.close();
1021 debugster("after close", path);
1022 path.lineTo(0, 0);
1023 debugster("after lineTo", path);
1024 path.close();
1025 debugster("after close", path);
1026}
1027#StdOut
1028initial last contour is not closed
1029after close last contour is not closed
1030after lineTo last contour is not closed
1031after close last contour is closed
1032##
1033##
1034
1035#SeeAlso close()
1036
1037##
1038
1039# ------------------------------------------------------------------------------
1040
Cary Clark682c58d2018-05-16 07:07:07 -04001041#Method bool isFinite() const
Cary Clark4855f782018-02-06 09:41:53 -05001042#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001043#Line # returns if all Point values are finite ##
Cary Clark09d80c02018-10-31 12:14:03 -04001044#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001045
1046#Example
1047void draw(SkCanvas* canvas) {
1048 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1049 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1050 };
1051 SkPath path;
1052 debugster("initial", path);
1053 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1054 debugster("after line", path);
1055 SkMatrix matrix;
1056 matrix.setScale(2, 2);
1057 path.transform(matrix);
1058 debugster("after scale", path);
1059}
1060#StdOut
1061initial path is finite
1062after line path is finite
1063after scale path is not finite
1064##
1065##
1066
1067#SeeAlso SkScalar
1068##
1069
1070# ------------------------------------------------------------------------------
1071
Cary Clark682c58d2018-05-16 07:07:07 -04001072#Method bool isVolatile() const
Cary Clark4855f782018-02-06 09:41:53 -05001073#In Property
1074#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001075#Line # returns if Device should not cache ##
Cary Clark09d80c02018-10-31 12:14:03 -04001076#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001077
1078#Example
1079 SkPath path;
1080 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1081#StdOut
1082volatile by default is false
1083##
1084##
1085
1086#SeeAlso setIsVolatile
1087
1088##
1089
1090# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001091#Subtopic Volatile
Cary Clark4855f782018-02-06 09:41:53 -05001092#Line # caching attribute ##
1093##
Cary Clark73fa9722017-08-29 17:36:51 -04001094
Cary Clark682c58d2018-05-16 07:07:07 -04001095#Method void setIsVolatile(bool isVolatile)
Cary Clark4855f782018-02-06 09:41:53 -05001096#In Volatile
Cary Clarkab2621d2018-01-30 10:08:57 -05001097#Line # sets if Device should not cache ##
Cary Clark09d80c02018-10-31 12:14:03 -04001098#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001099
1100#Example
1101#Height 50
1102#Width 50
1103 SkPaint paint;
1104 paint.setStyle(SkPaint::kStroke_Style);
1105 SkPath path;
1106 path.setIsVolatile(true);
1107 path.lineTo(40, 40);
1108 canvas->drawPath(path, paint);
1109 path.rewind();
1110 path.moveTo(0, 40);
1111 path.lineTo(40, 0);
1112 canvas->drawPath(path, paint);
1113##
1114
1115#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1116
1117#SeeAlso isVolatile
1118
1119##
1120
1121# ------------------------------------------------------------------------------
1122
Cary Clark682c58d2018-05-16 07:07:07 -04001123#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001124#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001125#Line # returns if Line is very small ##
Cary Clark09d80c02018-10-31 12:14:03 -04001126#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001127
1128#Example
1129#Description
Cary Clarkce101242017-09-01 15:51:02 -04001130As single precision floats, 100 and 100.000001 have the same bit representation,
1131and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001132are not exactly equal, but are nearly equal.
1133##
1134void draw(SkCanvas* canvas) {
1135 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1136 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1137 for (bool exact : { false, true } ) {
1138 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1139 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1140 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1141 ? "" : "not ", exact ? "exactly" : "nearly");
1142 }
1143 }
1144}
1145#StdOut
1146line from (100,100) to (100,100) is degenerate, nearly
1147line from (100,100) to (100,100) is degenerate, exactly
1148line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1149line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1150#StdOut ##
1151##
1152
Cary Clark682c58d2018-05-16 07:07:07 -04001153#SeeAlso IsQuadDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001154##
1155
1156# ------------------------------------------------------------------------------
1157
1158#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001159 const SkPoint& p3, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001160#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001161#Line # returns if Quad is very small ##
Cary Clark09d80c02018-10-31 12:14:03 -04001162#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001163
1164#Example
1165#Description
Cary Clarkce101242017-09-01 15:51:02 -04001166As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001167but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001168the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001169##
1170void draw(SkCanvas* canvas) {
1171 auto debugster = [](const SkPath& path, bool exact) -> void {
Cary Clark682c58d2018-05-16 07:07:07 -04001172 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 -04001173 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1174 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1175 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1176 "" : "not ", exact ? "exactly" : "nearly");
1177 };
1178 SkPath path, offset;
1179 path.moveTo({100, 100});
1180 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1181 offset.addPath(path, 1000, 1000);
1182 for (bool exact : { false, true } ) {
1183 debugster(path, exact);
1184 debugster(offset, exact);
1185 }
1186}
1187#StdOut
1188quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1189quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1190quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1191quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1192#StdOut ##
1193##
1194
Cary Clark682c58d2018-05-16 07:07:07 -04001195#SeeAlso IsLineDegenerate IsCubicDegenerate
Cary Clark73fa9722017-08-29 17:36:51 -04001196##
1197
1198# ------------------------------------------------------------------------------
1199
1200#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
Cary Clark682c58d2018-05-16 07:07:07 -04001201 const SkPoint& p3, const SkPoint& p4, bool exact)
Cary Clark4855f782018-02-06 09:41:53 -05001202#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001203#Line # returns if Cubic is very small ##
Cary Clark09d80c02018-10-31 12:14:03 -04001204#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001205
1206#Example
1207void draw(SkCanvas* canvas) {
1208 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1209 SkScalar step = 1;
Cary Clark75fd4492018-06-20 12:45:16 -04001210 SkScalar prior, length = 0, degenerate = 0;
Cary Clark73fa9722017-08-29 17:36:51 -04001211 do {
1212 prior = points[0].fX;
1213 step /= 2;
1214 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1215 degenerate = prior;
1216 points[0].fX += step;
1217 } else {
1218 length = prior;
1219 points[0].fX -= step;
1220 }
1221 } while (prior != points[0].fX);
1222 SkDebugf("%1.8g is degenerate\n", degenerate);
1223 SkDebugf("%1.8g is length\n", length);
1224}
1225#StdOut
12260.00024414062 is degenerate
12270.00024414065 is length
1228#StdOut ##
1229##
1230
1231##
1232
1233# ------------------------------------------------------------------------------
1234
1235#Method bool isLine(SkPoint line[2]) const
Cary Clark4855f782018-02-06 09:41:53 -05001236#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001237#Line # returns if describes Line ##
Cary Clark09d80c02018-10-31 12:14:03 -04001238#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001239
1240#Example
1241void draw(SkCanvas* canvas) {
1242 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1243 SkPoint line[2];
1244 if (path.isLine(line)) {
1245 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1246 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1247 } else {
1248 SkDebugf("%s is not line\n", prefix);
1249 }
1250 };
1251 SkPath path;
1252 debugster("empty", path);
1253 path.lineTo(0, 0);
1254 debugster("zero line", path);
1255 path.rewind();
1256 path.moveTo(10, 10);
1257 path.lineTo(20, 20);
1258 debugster("line", path);
1259 path.moveTo(20, 20);
1260 debugster("second move", path);
1261}
1262#StdOut
1263empty is not line
1264zero line is line (0,0) (0,0)
1265line is line (10,10) (20,20)
1266second move is not line
1267##
1268##
1269
1270##
1271
1272# ------------------------------------------------------------------------------
1273
Cary Clark8032b982017-07-28 11:04:54 -04001274#Subtopic Point_Array
Cary Clark08895c42018-02-01 09:37:32 -05001275#Line # end points and control points for lines and curves ##
Cary Clark61dfc3a2018-01-03 08:37:53 -05001276#Substitute SkPoint array
Cary Clark8032b982017-07-28 11:04:54 -04001277
1278Point_Array contains Points satisfying the allocated Points for
1279each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clark77b3f3a2018-11-07 14:59:03 -05001280and Quad is described by Verb_Array: kMove_Verb, kLine_Verb, kQuad_Verb; and
Cary Clark8032b982017-07-28 11:04:54 -04001281one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1282
1283Point_Array may be read directly from Path with getPoints, or inspected with
1284getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001285
1286#Method int getPoints(SkPoint points[], int max) const
1287
Cary Clarkab2621d2018-01-30 10:08:57 -05001288#In Point_Array
1289#Line # returns Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001290#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001291
1292#Example
1293void draw(SkCanvas* canvas) {
1294 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1295 int count = path.getPoints(points, max);
1296 SkDebugf("%s point count: %d ", prefix, count);
1297 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1298 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1299 }
1300 SkDebugf("\n");
1301 };
1302 SkPath path;
1303 path.lineTo(20, 20);
1304 path.lineTo(-10, -10);
1305 SkPoint points[3];
1306 debugster("no points", path, nullptr, 0);
1307 debugster("zero max", path, points, 0);
1308 debugster("too small", path, points, 2);
1309 debugster("just right", path, points, path.countPoints());
1310}
1311#StdOut
1312no points point count: 3
1313zero max point count: 3
1314too small point count: 3 (0,0) (20,20)
1315just right point count: 3 (0,0) (20,20) (-10,-10)
1316##
1317##
1318
1319#SeeAlso countPoints getPoint
1320##
1321
1322#Method int countPoints() const
1323
Cary Clarkab2621d2018-01-30 10:08:57 -05001324#In Point_Array
1325#Line # returns Point_Array length ##
Cary Clark09d80c02018-10-31 12:14:03 -04001326#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001327
1328#Example
1329void draw(SkCanvas* canvas) {
1330 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1331 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1332 };
1333 SkPath path;
1334 debugster("empty", path);
1335 path.lineTo(0, 0);
1336 debugster("zero line", path);
1337 path.rewind();
1338 path.moveTo(10, 10);
1339 path.lineTo(20, 20);
1340 debugster("line", path);
1341 path.moveTo(20, 20);
1342 debugster("second move", path);
1343}
1344#StdOut
1345empty point count: 0
1346zero line point count: 2
1347line point count: 2
1348second move point count: 3
1349##
1350##
1351
1352#SeeAlso getPoints
1353##
1354
1355#Method SkPoint getPoint(int index) const
1356
Cary Clarkab2621d2018-01-30 10:08:57 -05001357#In Point_Array
1358#Line # returns entry from Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001359#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001360
1361#Example
1362void draw(SkCanvas* canvas) {
Cary Clark73fa9722017-08-29 17:36:51 -04001363 SkPath path;
1364 path.lineTo(20, 20);
1365 path.offset(-10, -10);
1366 for (int i= 0; i < path.countPoints(); ++i) {
1367 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
Cary Clark682c58d2018-05-16 07:07:07 -04001368 }
Cary Clark73fa9722017-08-29 17:36:51 -04001369}
1370#StdOut
1371point 0: (-10,-10)
1372point 1: (10,10)
1373##
1374##
1375
1376#SeeAlso countPoints getPoints
1377##
1378
1379
1380#Subtopic Point_Array ##
1381
1382# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001383#Subtopic Verb_Array
Cary Clark08895c42018-02-01 09:37:32 -05001384#Line # line and curve type for points ##
Cary Clark8032b982017-07-28 11:04:54 -04001385
1386Verb_Array always starts with kMove_Verb.
1387If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1388the quantity of kMove_Verb equals the Contour count.
1389Verb_Array does not include or count kDone_Verb; it is a convenience
1390returned when iterating through Verb_Array.
1391
Cary Clark682c58d2018-05-16 07:07:07 -04001392Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
Cary Clark8032b982017-07-28 11:04:54 -04001393or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001394
1395#Method int countVerbs() const
1396
Cary Clarkab2621d2018-01-30 10:08:57 -05001397#In Verb_Array
1398#Line # returns Verb_Array length ##
Cary Clark09d80c02018-10-31 12:14:03 -04001399#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001400
1401#Example
1402SkPath path;
1403SkDebugf("empty verb count: %d\n", path.countVerbs());
1404path.addRoundRect({10, 20, 30, 40}, 5, 5);
1405SkDebugf("round rect verb count: %d\n", path.countVerbs());
1406#StdOut
1407empty verb count: 0
1408round rect verb count: 10
1409##
1410##
1411
1412#SeeAlso getVerbs Iter RawIter
1413
1414##
1415
1416#Method int getVerbs(uint8_t verbs[], int max) const
1417
Cary Clarkab2621d2018-01-30 10:08:57 -05001418#In Verb_Array
1419#Line # returns Verb_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001420#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001421
1422#Example
1423void draw(SkCanvas* canvas) {
1424 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1425 int count = path.getVerbs(verbs, max);
1426 SkDebugf("%s verb count: %d ", prefix, count);
1427 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1428 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1429 SkDebugf("%s ", verbStr[verbs[i]]);
1430 }
1431 SkDebugf("\n");
1432 };
1433 SkPath path;
1434 path.lineTo(20, 20);
1435 path.lineTo(-10, -10);
1436 uint8_t verbs[3];
1437 debugster("no verbs", path, nullptr, 0);
1438 debugster("zero max", path, verbs, 0);
1439 debugster("too small", path, verbs, 2);
1440 debugster("just right", path, verbs, path.countVerbs());
1441}
1442#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04001443no verbs verb count: 3
1444zero max verb count: 3
1445too small verb count: 3 move line
1446just right verb count: 3 move line line
Cary Clark73fa9722017-08-29 17:36:51 -04001447##
1448##
1449
1450#SeeAlso countVerbs getPoints Iter RawIter
1451##
Cary Clark8032b982017-07-28 11:04:54 -04001452
1453#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001454
1455# ------------------------------------------------------------------------------
1456
1457#Method void swap(SkPath& other)
Cary Clark61313f32018-10-08 14:57:48 -04001458#In Operators
Cary Clarkab2621d2018-01-30 10:08:57 -05001459#Line # exchanges Path pair ##
Cary Clark09d80c02018-10-31 12:14:03 -04001460#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001461
1462#Example
1463SkPath path1, path2;
1464path1.addRect({10, 20, 30, 40});
1465path1.swap(path2);
1466const SkRect& b1 = path1.getBounds();
1467SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1468const SkRect& b2 = path2.getBounds();
1469SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1470#StdOut
1471path1 bounds = 0, 0, 0, 0
1472path2 bounds = 10, 20, 30, 40
1473#StdOut ##
1474##
1475
1476#SeeAlso operator=(const SkPath& path)
1477
1478##
1479
1480# ------------------------------------------------------------------------------
1481
Cary Clark682c58d2018-05-16 07:07:07 -04001482#Method const SkRect& getBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001483#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001484#Line # returns maximum and minimum of Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04001485#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001486
1487#Example
1488#Description
1489Bounds of upright Circle can be predicted from center and radius.
1490Bounds of rotated Circle includes control Points outside of filled area.
1491##
1492 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1493 const SkRect& bounds = path.getBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001494 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001495 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1496 };
1497 SkPath path;
1498 debugster("empty", path);
1499 path.addCircle(50, 45, 25);
1500 debugster("circle", path);
1501 SkMatrix matrix;
1502 matrix.setRotate(45, 50, 45);
1503 path.transform(matrix);
1504 debugster("rotated circle", path);
1505#StdOut
1506empty bounds = 0, 0, 0, 0
1507circle bounds = 25, 20, 75, 70
1508rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
1509##
1510##
1511
1512#SeeAlso computeTightBounds updateBoundsCache
1513
1514##
1515
1516# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001517#Subtopic Utility
Cary Clark4855f782018-02-06 09:41:53 -05001518#Line # rarely called management functions ##
1519##
Cary Clark73fa9722017-08-29 17:36:51 -04001520
Cary Clark682c58d2018-05-16 07:07:07 -04001521#Method void updateBoundsCache() const
Cary Clark4855f782018-02-06 09:41:53 -05001522#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001523#Line # refreshes result of getBounds ##
Cary Clark09d80c02018-10-31 12:14:03 -04001524#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001525
1526#Example
1527 double times[2] = { 0, 0 };
1528 for (int i = 0; i < 10000; ++i) {
1529 SkPath path;
1530 for (int j = 1; j < 100; ++ j) {
1531 path.addCircle(50 + j, 45 + j, 25 + j);
1532 }
1533 if (1 & i) {
1534 path.updateBoundsCache();
1535 }
1536 double start = SkTime::GetNSecs();
1537 (void) path.getBounds();
1538 times[1 & i] += SkTime::GetNSecs() - start;
1539 }
1540 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
1541 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
1542#StdOut
1543#Volatile
1544uncached avg: 0.18048 ms
1545cached avg: 0.182784 ms
1546##
1547##
1548
1549#SeeAlso getBounds
1550#ToDo the results don't make sense, need to profile to figure this out ##
1551
1552##
1553
1554# ------------------------------------------------------------------------------
1555
1556#Method SkRect computeTightBounds() const
Cary Clark4855f782018-02-06 09:41:53 -05001557#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001558#Line # returns extent of geometry ##
Cary Clark09d80c02018-10-31 12:14:03 -04001559#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001560
1561#Example
1562 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1563 const SkRect& bounds = path.computeTightBounds();
Cary Clark682c58d2018-05-16 07:07:07 -04001564 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
Cary Clark73fa9722017-08-29 17:36:51 -04001565 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
1566 };
1567 SkPath path;
1568 debugster("empty", path);
1569 path.addCircle(50, 45, 25);
1570 debugster("circle", path);
1571 SkMatrix matrix;
1572 matrix.setRotate(45, 50, 45);
1573 path.transform(matrix);
1574 debugster("rotated circle", path);
1575#StdOut
1576empty bounds = 0, 0, 0, 0
1577circle bounds = 25, 20, 75, 70
1578rotated circle bounds = 25, 20, 75, 70
1579##
1580##
1581
1582#SeeAlso getBounds
1583
1584##
1585
1586# ------------------------------------------------------------------------------
1587
1588#Method bool conservativelyContainsRect(const SkRect& rect) const
Cary Clark4855f782018-02-06 09:41:53 -05001589#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05001590#Line # returns true if Rect may be inside ##
Cary Clark09d80c02018-10-31 12:14:03 -04001591#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001592
1593#Example
1594#Height 140
1595#Description
1596Rect is drawn in blue if it is contained by red Path.
1597##
1598void draw(SkCanvas* canvas) {
1599 SkPath path;
1600 path.addRoundRect({10, 20, 54, 120}, 10, 20);
1601 SkRect tests[] = {
1602 { 10, 40, 54, 80 },
1603 { 25, 20, 39, 120 },
1604 { 15, 25, 49, 115 },
1605 { 13, 27, 51, 113 },
1606 };
1607 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
1608 SkPaint paint;
1609 paint.setColor(SK_ColorRED);
1610 canvas->drawPath(path, paint);
1611 bool rectInPath = path.conservativelyContainsRect(tests[i]);
1612 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
1613 canvas->drawRect(tests[i], paint);
1614 canvas->translate(64, 0);
1615 }
1616}
1617##
1618
1619#SeeAlso contains Op Rect Convexity
1620
1621##
1622
1623# ------------------------------------------------------------------------------
1624
Mike Reed6a388002018-10-16 13:13:09 -04001625#Method void incReserve(int extraPtCount)
Cary Clark4855f782018-02-06 09:41:53 -05001626#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05001627#Line # reserves space for additional data ##
Cary Clark09d80c02018-10-31 12:14:03 -04001628#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001629
1630#Example
1631#Height 192
1632void draw(SkCanvas* canvas) {
1633 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
1634 path->moveTo(size, 0);
1635 for (int i = 1; i < sides; i++) {
1636 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
1637 path->lineTo(c * size, s * size);
1638 }
1639 path->close();
1640 };
1641 SkPath path;
1642 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
1643 for (int sides = 3; sides < 10; ++sides) {
1644 addPoly(sides, sides, &path);
1645 }
1646 SkMatrix matrix;
1647 matrix.setScale(10, 10, -10, -10);
1648 path.transform(matrix);
1649 SkPaint paint;
1650 paint.setStyle(SkPaint::kStroke_Style);
1651 canvas->drawPath(path, paint);
1652}
1653##
1654
1655#SeeAlso Point_Array
1656
1657##
1658
Cary Clark99ebc422018-09-11 15:26:53 -04001659#Method void shrinkToFit()
1660#In Utility
1661#Line # removes unused reserved space ##
Cary Clark09d80c02018-10-31 12:14:03 -04001662#Populate
Cary Clark99ebc422018-09-11 15:26:53 -04001663
1664#NoExample
Florin Malita0e0f1a72018-09-11 16:16:19 -04001665#Height 192
1666void draw(SkCanvas* canvas) {
1667 SkPath skinnyPath;
1668 skinnyPath.lineTo(100, 100);
1669 skinnyPath.shrinkToFit();
1670
1671 SkDebugf("no wasted Path capacity in my house!\n");
1672}
Cary Clark99ebc422018-09-11 15:26:53 -04001673##
Florin Malita0e0f1a72018-09-11 16:16:19 -04001674
Cary Clark99ebc422018-09-11 15:26:53 -04001675#SeeAlso incReserve
Florin Malita0e0f1a72018-09-11 16:16:19 -04001676
Cary Clark99ebc422018-09-11 15:26:53 -04001677##
1678
Cary Clark73fa9722017-08-29 17:36:51 -04001679# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05001680#Subtopic Build
Cary Clark4855f782018-02-06 09:41:53 -05001681#Line # adds points and verbs to path ##
1682##
Cary Clark73fa9722017-08-29 17:36:51 -04001683
Cary Clark0251b1b2018-08-15 15:14:55 -04001684#Method SkPath& moveTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05001685#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001686#Line # starts Contour ##
Cary Clark09d80c02018-10-31 12:14:03 -04001687#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001688
Cary Clark73fa9722017-08-29 17:36:51 -04001689#Example
1690 #Width 140
1691 #Height 100
1692 void draw(SkCanvas* canvas) {
1693 SkRect rect = { 20, 20, 120, 80 };
1694 SkPath path;
1695 path.addRect(rect);
1696 path.moveTo(rect.fLeft, rect.fTop);
1697 path.lineTo(rect.fRight, rect.fBottom);
1698 path.moveTo(rect.fLeft, rect.fBottom);
1699 path.lineTo(rect.fRight, rect.fTop);
1700 SkPaint paint;
1701 paint.setStyle(SkPaint::kStroke_Style);
1702 canvas->drawPath(path, paint);
1703 }
1704##
1705
1706#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
1707
1708##
1709
Cary Clark0251b1b2018-08-15 15:14:55 -04001710#Method SkPath& moveTo(const SkPoint& p)
Cary Clark09d80c02018-10-31 12:14:03 -04001711#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001712
Cary Clark73fa9722017-08-29 17:36:51 -04001713#Example
1714 #Width 128
1715 #Height 128
1716void draw(SkCanvas* canvas) {
Cary Clark682c58d2018-05-16 07:07:07 -04001717 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
Cary Clark73fa9722017-08-29 17:36:51 -04001718 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
1719 SkPath path;
1720 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
1721 path.moveTo(data[i][0]);
1722 path.lineTo(data[i][1]);
1723 path.lineTo(data[i][2]);
1724 }
1725 SkPaint paint;
1726 paint.setStyle(SkPaint::kStroke_Style);
1727 canvas->drawPath(path, paint);
1728}
1729##
1730
1731#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
1732
1733##
1734
Cary Clark0251b1b2018-08-15 15:14:55 -04001735#Method SkPath& rMoveTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05001736#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001737#Line # starts Contour relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04001738#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001739
Cary Clark73fa9722017-08-29 17:36:51 -04001740#Example
1741 #Height 100
1742 SkPath path;
1743 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
1744 path.rMoveTo(25, 2);
1745 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
1746 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
1747 path.rLineTo(arrow[i].fX, arrow[i].fY);
1748 }
1749 SkPaint paint;
1750 canvas->drawPath(path, paint);
1751 SkPoint lastPt;
1752 path.getLastPt(&lastPt);
1753 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
1754##
1755
1756#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
1757
1758##
1759
1760# ------------------------------------------------------------------------------
1761
Cary Clark0251b1b2018-08-15 15:14:55 -04001762#Method SkPath& lineTo(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05001763#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001764#Line # appends Line ##
Cary Clark09d80c02018-10-31 12:14:03 -04001765#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001766
Cary Clark73fa9722017-08-29 17:36:51 -04001767#Example
1768#Height 100
1769###$
1770void draw(SkCanvas* canvas) {
1771 SkPaint paint;
1772 paint.setAntiAlias(true);
1773 paint.setTextSize(72);
1774 canvas->drawString("#", 120, 80, paint);
1775 paint.setStyle(SkPaint::kStroke_Style);
1776 paint.setStrokeWidth(5);
1777 SkPath path;
1778 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
1779 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
1780 unsigned o = 0;
1781 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
1782 for (unsigned j = 0; j < 2; o++, j++) {
1783 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
1784 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
1785 }
1786 }
1787 canvas->drawPath(path, paint);
1788}
1789$$$#
1790##
1791
1792#SeeAlso Contour moveTo rLineTo addRect
1793
1794##
1795
1796# ------------------------------------------------------------------------------
1797
Cary Clark0251b1b2018-08-15 15:14:55 -04001798#Method SkPath& lineTo(const SkPoint& p)
Cary Clark09d80c02018-10-31 12:14:03 -04001799#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001800
Cary Clark73fa9722017-08-29 17:36:51 -04001801#Example
1802#Height 100
1803 SkPath path;
1804 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
1805 {40, 20}, {40, 80}, {60, 20}, {60, 80},
1806 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
1807 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
1808 path.moveTo(oxo[i]);
1809 path.lineTo(oxo[i + 1]);
1810 }
1811 SkPaint paint;
1812 paint.setStyle(SkPaint::kStroke_Style);
1813 canvas->drawPath(path, paint);
1814##
1815
1816#SeeAlso Contour moveTo rLineTo addRect
1817
1818##
1819
1820# ------------------------------------------------------------------------------
1821
Cary Clark0251b1b2018-08-15 15:14:55 -04001822#Method SkPath& rLineTo(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05001823#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001824#Line # appends Line relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04001825#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04001826
Cary Clark73fa9722017-08-29 17:36:51 -04001827#Example
1828#Height 128
1829void draw(SkCanvas* canvas) {
1830 SkPaint paint;
1831 paint.setAntiAlias(true);
1832 paint.setStyle(SkPaint::kStroke_Style);
1833 SkPath path;
1834 path.moveTo(10, 98);
1835 SkScalar x = 0, y = 0;
1836 for (int i = 10; i < 100; i += 5) {
1837 x += i * ((i & 2) - 1);
1838 y += i * (((i + 1) & 2) - 1);
1839 path.rLineTo(x, y);
Cary Clark682c58d2018-05-16 07:07:07 -04001840
Cary Clark73fa9722017-08-29 17:36:51 -04001841 }
1842 canvas->drawPath(path, paint);
1843}
1844##
1845
1846#SeeAlso Contour moveTo lineTo addRect
1847
1848##
1849
1850# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05001851#Subtopic Quad
Cary Clark137b8742018-05-30 09:21:49 -04001852#Alias Quad ##
1853#Alias Quads ##
1854#Alias Quadratic_Bezier ##
1855#Alias Quadratic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04001856#Line # curve described by second-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04001857
Cary Clark77b3f3a2018-11-07 14:59:03 -05001858Quad describes a Quadratic_Bezier, a second-order curve identical to a section
Cary Clark8032b982017-07-28 11:04:54 -04001859of a parabola. Quad begins at a start Point, curves towards a control Point,
1860and then curves to an end Point.
1861
1862#Example
1863#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04001864void draw(SkCanvas* canvas) {
1865 SkPaint paint;
1866 paint.setAntiAlias(true);
1867 paint.setStyle(SkPaint::kStroke_Style);
1868 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
1869 canvas->drawLine(quadPts[0], quadPts[1], paint);
1870 canvas->drawLine(quadPts[1], quadPts[2], paint);
1871 SkPath path;
1872 path.moveTo(quadPts[0]);
1873 path.quadTo(quadPts[1], quadPts[2]);
1874 paint.setStrokeWidth(3);
1875 canvas->drawPath(path, paint);
1876}
Cary Clark8032b982017-07-28 11:04:54 -04001877##
1878
1879Quad is a special case of Conic where Conic_Weight is set to one.
1880
1881Quad is always contained by the triangle connecting its three Points. Quad
1882begins tangent to the line between start Point and control Point, and ends
1883tangent to the line between control Point and end Point.
1884
1885#Example
1886#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04001887void draw(SkCanvas* canvas) {
1888 SkPaint paint;
1889 paint.setAntiAlias(true);
1890 paint.setStyle(SkPaint::kStroke_Style);
1891 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
1892 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
1893 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
1894 paint.setColor(0x7fffffff & colors[i]);
1895 paint.setStrokeWidth(1);
1896 canvas->drawLine(quadPts[0], quadPts[1], paint);
1897 canvas->drawLine(quadPts[1], quadPts[2], paint);
1898 SkPath path;
1899 path.moveTo(quadPts[0]);
1900 path.quadTo(quadPts[1], quadPts[2]);
1901 paint.setStrokeWidth(3);
1902 paint.setColor(colors[i]);
1903 canvas->drawPath(path, paint);
1904 quadPts[1].fY += 30;
1905 }
Cary Clark8032b982017-07-28 11:04:54 -04001906}
1907##
Cary Clark73fa9722017-08-29 17:36:51 -04001908
Cary Clark0251b1b2018-08-15 15:14:55 -04001909#Method SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Cary Clark73fa9722017-08-29 17:36:51 -04001910
Cary Clarkab2621d2018-01-30 10:08:57 -05001911#In Quad
1912#Line # appends Quad ##
Cary Clark09d80c02018-10-31 12:14:03 -04001913#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001914
Cary Clark09d80c02018-10-31 12:14:03 -04001915#Example
Cary Clark73fa9722017-08-29 17:36:51 -04001916 void draw(SkCanvas* canvas) {
1917 SkPaint paint;
1918 paint.setAntiAlias(true);
1919 paint.setStyle(SkPaint::kStroke_Style);
1920 SkPath path;
1921 path.moveTo(0, -10);
1922 for (int i = 0; i < 128; i += 16) {
1923 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
1924 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
1925 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
1926 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
1927 }
1928 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04001929 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04001930 }
1931 ##
1932
1933 #SeeAlso Contour moveTo conicTo rQuadTo
1934
1935##
1936
Cary Clark0251b1b2018-08-15 15:14:55 -04001937#Method SkPath& quadTo(const SkPoint& p1, const SkPoint& p2)
Cary Clark4855f782018-02-06 09:41:53 -05001938#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001939#In Quad
Cary Clark09d80c02018-10-31 12:14:03 -04001940#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001941
Cary Clark09d80c02018-10-31 12:14:03 -04001942#Example
Cary Clark73fa9722017-08-29 17:36:51 -04001943 void draw(SkCanvas* canvas) {
1944 SkPaint paint;
1945 paint.setStyle(SkPaint::kStroke_Style);
1946 paint.setAntiAlias(true);
1947 SkPath path;
1948 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
1949 path.moveTo(pts[1]);
1950 for (int i = 0; i < 3; ++i) {
1951 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
1952 }
1953 canvas->drawPath(path, paint);
1954 }
1955 ##
1956
1957 #SeeAlso Contour moveTo conicTo rQuadTo
1958
1959##
1960
Cary Clark0251b1b2018-08-15 15:14:55 -04001961#Method SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
Cary Clark4855f782018-02-06 09:41:53 -05001962#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05001963#In Quad
1964#Line # appends Quad relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04001965#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04001966
Cary Clark09d80c02018-10-31 12:14:03 -04001967#Example
Cary Clark73fa9722017-08-29 17:36:51 -04001968 void draw(SkCanvas* canvas) {
1969 SkPaint paint;
1970 paint.setAntiAlias(true);
1971 SkPath path;
1972 path.moveTo(128, 20);
1973 path.rQuadTo(-6, 10, -7, 10);
1974 for (int i = 1; i < 32; i += 4) {
1975 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
1976 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
1977 }
1978 path.quadTo(92, 220, 128, 215);
1979 canvas->drawPath(path, paint);
1980 }
1981 ##
1982
1983 #SeeAlso Contour moveTo conicTo quadTo
1984
1985##
1986
Cary Clark78de7512018-02-07 07:27:09 -05001987#Subtopic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04001988
1989# ------------------------------------------------------------------------------
1990
Cary Clark78de7512018-02-07 07:27:09 -05001991#Subtopic Conic
Cary Clark77b3f3a2018-11-07 14:59:03 -05001992#Alias Conic ##
Cary Clark137b8742018-05-30 09:21:49 -04001993#Alias Conics ##
Cary Clark77b3f3a2018-11-07 14:59:03 -05001994#Line # conic section defined by three points and a weight ##
Cary Clark8032b982017-07-28 11:04:54 -04001995
1996Conic describes a conical section: a piece of an ellipse, or a piece of a
Cary Clark682c58d2018-05-16 07:07:07 -04001997parabola, or a piece of a hyperbola. Conic begins at a start Point,
Cary Clark8032b982017-07-28 11:04:54 -04001998curves towards a control Point, and then curves to an end Point. The influence
1999of the control Point is determined by Conic_Weight.
2000
Cary Clark73fa9722017-08-29 17:36:51 -04002001Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2002may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002003
2004#Subtopic Weight
Cary Clark137b8742018-05-30 09:21:49 -04002005#Alias Conic_Weights ##
2006#Alias Weights ##
Cary Clark08895c42018-02-01 09:37:32 -05002007#Line # strength of Conic control Point ##
Cary Clark8032b982017-07-28 11:04:54 -04002008
2009Weight determines both the strength of the control Point and the type of Conic.
Cary Clark682c58d2018-05-16 07:07:07 -04002010Weight varies from zero to infinity. At zero, Weight causes the control Point to
2011have no effect; Conic is identical to a line segment from start Point to end
2012point. If Weight is less than one, Conic follows an elliptical arc.
2013If Weight is exactly one, then Conic is identical to Quad; Conic follows a
2014parabolic arc. If Weight is greater than one, Conic follows a hyperbolic
Cary Clark137b8742018-05-30 09:21:49 -04002015arc. If Weight is infinity, Conic is identical to two line segments, connecting
Cary Clark682c58d2018-05-16 07:07:07 -04002016start Point to control Point, and control Point to end Point.
Cary Clark8032b982017-07-28 11:04:54 -04002017
2018#Example
2019#Description
Cary Clark682c58d2018-05-16 07:07:07 -04002020When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002021##
Cary Clark73fa9722017-08-29 17:36:51 -04002022void draw(SkCanvas* canvas) {
2023 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2024 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2025 SkPath path;
2026 path.conicTo(20, 30, 50, 60, 1);
2027 SkPath::Iter iter(path, false);
2028 SkPath::Verb verb;
2029 do {
2030 SkPoint points[4];
2031 verb = iter.next(points);
2032 SkDebugf("%s ", verbNames[(int) verb]);
2033 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2034 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2035 }
2036 if (SkPath::kConic_Verb == verb) {
2037 SkDebugf("weight = %g", iter.conicWeight());
2038 }
2039 SkDebugf("\n");
2040 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002041}
2042#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002043move {0, 0},
2044quad {0, 0}, {20, 30}, {50, 60},
2045done
Cary Clark8032b982017-07-28 11:04:54 -04002046##
2047##
2048
2049If weight is less than one, Conic is an elliptical segment.
2050
Cary Clark682c58d2018-05-16 07:07:07 -04002051#Example
Cary Clark8032b982017-07-28 11:04:54 -04002052#Description
Cary Clark2be81cf2018-09-13 12:04:30 -04002053A 90 degree circular arc has the weight #Formula # 1 / sqrt(2) ##.
Cary Clark8032b982017-07-28 11:04:54 -04002054##
Cary Clark73fa9722017-08-29 17:36:51 -04002055void draw(SkCanvas* canvas) {
2056 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2057 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2058 SkPath path;
2059 path.arcTo(20, 0, 20, 20, 20);
2060 SkPath::Iter iter(path, false);
2061 SkPath::Verb verb;
2062 do {
2063 SkPoint points[4];
2064 verb = iter.next(points);
2065 SkDebugf("%s ", verbNames[(int) verb]);
2066 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2067 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2068 }
2069 if (SkPath::kConic_Verb == verb) {
2070 SkDebugf("weight = %g", iter.conicWeight());
2071 }
2072 SkDebugf("\n");
2073 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002074}
2075#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002076move {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04002077conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark682c58d2018-05-16 07:07:07 -04002078done
Cary Clark8032b982017-07-28 11:04:54 -04002079##
2080##
2081
Cary Clarkce101242017-09-01 15:51:02 -04002082If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002083a hyperbolic segment can be approximated by straight lines connecting the
2084control Point with the end Points.
2085
2086#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002087void draw(SkCanvas* canvas) {
2088 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2089 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2090 SkPath path;
2091 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2092 SkPath::Iter iter(path, false);
2093 SkPath::Verb verb;
2094 do {
2095 SkPoint points[4];
2096 verb = iter.next(points);
2097 SkDebugf("%s ", verbNames[(int) verb]);
2098 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2099 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2100 }
2101 if (SkPath::kConic_Verb == verb) {
2102 SkDebugf("weight = %g", iter.conicWeight());
2103 }
2104 SkDebugf("\n");
2105 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002106}
2107#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04002108move {0, 0},
2109line {0, 0}, {20, 0},
2110line {20, 0}, {20, 20},
2111done
Cary Clark8032b982017-07-28 11:04:54 -04002112##
2113##
2114
2115#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002116
Cary Clark0251b1b2018-08-15 15:14:55 -04002117#Method SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002118 SkScalar w)
Cary Clarkab2621d2018-01-30 10:08:57 -05002119#In Conic
Cary Clark4855f782018-02-06 09:41:53 -05002120#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002121#Line # appends Conic ##
Cary Clark09d80c02018-10-31 12:14:03 -04002122#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002123
Cary Clark09d80c02018-10-31 12:14:03 -04002124#Example
Cary Clark8032b982017-07-28 11:04:54 -04002125 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002126 #Description
Cary Clark682c58d2018-05-16 07:07:07 -04002127 As weight increases, curve is pulled towards control point.
Cary Clark73fa9722017-08-29 17:36:51 -04002128 The bottom two curves are elliptical; the next is parabolic; the
2129 top curve is hyperbolic.
2130 ##
2131void draw(SkCanvas* canvas) {
2132 SkPaint paint;
2133 paint.setAntiAlias(true);
2134 paint.setStyle(SkPaint::kStroke_Style);
2135 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2136 canvas->drawLine(conicPts[0], conicPts[1], paint);
2137 canvas->drawLine(conicPts[1], conicPts[2], paint);
2138 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2139 paint.setStrokeWidth(3);
2140 SkScalar weight = 0.5f;
2141 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2142 SkPath path;
2143 path.moveTo(conicPts[0]);
2144 path.conicTo(conicPts[1], conicPts[2], weight);
2145 paint.setColor(colors[i]);
2146 canvas->drawPath(path, paint);
2147 weight += 0.25f;
2148 }
2149}
2150 ##
2151
2152 #SeeAlso rConicTo arcTo addArc quadTo
2153
2154##
2155
Cary Clark0251b1b2018-08-15 15:14:55 -04002156#Method SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002157#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002158#In Conic
Cary Clark09d80c02018-10-31 12:14:03 -04002159#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002160
Cary Clark09d80c02018-10-31 12:14:03 -04002161#Example
Cary Clark8032b982017-07-28 11:04:54 -04002162 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002163 #Description
2164 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002165 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002166 ##
2167void draw(SkCanvas* canvas) {
2168 SkPaint paint;
2169 paint.setAntiAlias(true);
2170 paint.setStyle(SkPaint::kStroke_Style);
2171 SkRect oval = {0, 20, 120, 140};
2172 SkPath path;
2173 for (int i = 0; i < 4; ++i) {
2174 path.moveTo(oval.centerX(), oval.fTop);
2175 path.arcTo(oval, -90, 90 - 20 * i, false);
2176 oval.inset(15, 15);
2177 }
2178 path.offset(100, 0);
2179 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2180 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2181 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2182 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2183 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2184 for (int i = 0; i < 4; ++i) {
2185 path.moveTo(conicPts[i][0]);
2186 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2187 }
2188 canvas->drawPath(path, paint);
2189}
2190 ##
2191
2192 #SeeAlso rConicTo arcTo addArc quadTo
2193
2194##
2195
Cary Clark0251b1b2018-08-15 15:14:55 -04002196#Method SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
Cary Clark73fa9722017-08-29 17:36:51 -04002197 SkScalar w)
Cary Clark4855f782018-02-06 09:41:53 -05002198#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002199#In Conic
2200#Line # appends Conic relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04002201#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002202
Cary Clark09d80c02018-10-31 12:14:03 -04002203#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002204 #Height 140
2205 void draw(SkCanvas* canvas) {
2206 SkPaint paint;
2207 paint.setAntiAlias(true);
2208 paint.setStyle(SkPaint::kStroke_Style);
2209 SkPath path;
2210 path.moveTo(20, 80);
2211 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2212 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2213 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2214 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2215 canvas->drawPath(path, paint);
2216 }
2217 ##
2218
2219 #SeeAlso conicTo arcTo addArc quadTo
2220
2221##
2222
Cary Clark78de7512018-02-07 07:27:09 -05002223#Subtopic Conic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002224
2225# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05002226#Subtopic Cubic
Cary Clark137b8742018-05-30 09:21:49 -04002227#Alias Cubic ##
2228#Alias Cubics ##
2229#Alias Cubic_Bezier ##
2230#Alias Cubic_Beziers ##
Cary Clark682c58d2018-05-16 07:07:07 -04002231#Line # curve described by third-order polynomial ##
Cary Clark8032b982017-07-28 11:04:54 -04002232
Cary Clark682c58d2018-05-16 07:07:07 -04002233Cubic describes a Bezier_Curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002234Cubic begins at a start Point, curving towards the first control Point;
2235and curves from the end Point towards the second control Point.
2236
2237#Example
2238#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002239void draw(SkCanvas* canvas) {
2240 SkPaint paint;
2241 paint.setAntiAlias(true);
2242 paint.setStyle(SkPaint::kStroke_Style);
2243 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2244 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2245 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2246 paint.setColor(0x7fffffff & colors[i]);
2247 paint.setStrokeWidth(1);
2248 for (unsigned j = 0; j < 3; ++j) {
2249 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2250 }
2251 SkPath path;
2252 path.moveTo(cubicPts[0]);
2253 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2254 paint.setStrokeWidth(3);
2255 paint.setColor(colors[i]);
2256 canvas->drawPath(path, paint);
2257 cubicPts[1].fY += 30;
2258 cubicPts[2].fX += 30;
2259 }
Cary Clark8032b982017-07-28 11:04:54 -04002260}
2261##
Cary Clark73fa9722017-08-29 17:36:51 -04002262
Cary Clark0251b1b2018-08-15 15:14:55 -04002263#Method SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
Cary Clark73fa9722017-08-29 17:36:51 -04002264 SkScalar x3, SkScalar y3)
Cary Clark4855f782018-02-06 09:41:53 -05002265#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002266#In Cubic
2267#Line # appends Cubic ##
Cary Clark09d80c02018-10-31 12:14:03 -04002268#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002269
Cary Clark73fa9722017-08-29 17:36:51 -04002270#Example
2271void draw(SkCanvas* canvas) {
2272 SkPaint paint;
2273 paint.setAntiAlias(true);
2274 paint.setStyle(SkPaint::kStroke_Style);
2275 SkPath path;
2276 path.moveTo(0, -10);
2277 for (int i = 0; i < 128; i += 16) {
2278 SkScalar c = i * 0.5f;
2279 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2280 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2281 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2282 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2283 }
2284 path.offset(128, 128);
2285 canvas->drawPath(path, paint);
2286}
2287##
2288
2289#SeeAlso Contour moveTo rCubicTo quadTo
2290
2291##
2292
2293# ------------------------------------------------------------------------------
2294
Cary Clark0251b1b2018-08-15 15:14:55 -04002295#Method SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
Cary Clark73fa9722017-08-29 17:36:51 -04002296
Cary Clark4855f782018-02-06 09:41:53 -05002297#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002298#In Cubic
Cary Clark09d80c02018-10-31 12:14:03 -04002299#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002300
Cary Clark73fa9722017-08-29 17:36:51 -04002301#Example
2302#Height 84
2303 SkPaint paint;
2304 paint.setAntiAlias(true);
2305 paint.setStyle(SkPaint::kStroke_Style);
2306 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2307 SkPath path;
2308 path.moveTo(pts[0]);
2309 path.cubicTo(pts[1], pts[2], pts[3]);
2310 canvas->drawPath(path, paint);
2311##
2312
2313#SeeAlso Contour moveTo rCubicTo quadTo
2314
2315##
2316
2317# ------------------------------------------------------------------------------
2318
Cary Clark82456492018-10-31 10:54:50 -04002319#Method SkPath& rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2320 SkScalar dx3, SkScalar dy3)
Cary Clark4855f782018-02-06 09:41:53 -05002321#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002322#In Cubic
2323#Line # appends Cubic relative to Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04002324#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002325
Cary Clark73fa9722017-08-29 17:36:51 -04002326#Example
2327 void draw(SkCanvas* canvas) {
2328 SkPaint paint;
2329 paint.setAntiAlias(true);
2330 paint.setStyle(SkPaint::kStroke_Style);
2331 SkPath path;
2332 path.moveTo(24, 108);
2333 for (int i = 0; i < 16; i++) {
2334 SkScalar sx, sy;
2335 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2336 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2337 }
2338 canvas->drawPath(path, paint);
2339 }
2340##
2341
2342#SeeAlso Contour moveTo cubicTo quadTo
2343
2344##
2345
Cary Clark78de7512018-02-07 07:27:09 -05002346#Subtopic Cubic ##
Cary Clark73fa9722017-08-29 17:36:51 -04002347
2348# ------------------------------------------------------------------------------
2349
Cary Clark08895c42018-02-01 09:37:32 -05002350#Subtopic Arc
2351#Line # part of Oval or Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04002352Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
2353by start point and end point, and by radius and tangent lines. Each construction has advantages,
2354and some constructions correspond to Arc drawing in graphics standards.
2355
2356All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
2357Conic describes an Arc of some Oval or Circle.
2358
2359arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
2360describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
Cary Clark682c58d2018-05-16 07:07:07 -04002361which may continue Contour or start a new one. This construction is similar to PostScript and
Cary Clark77b3f3a2018-11-07 14:59:03 -05002362HTML_Canvas arcs. Variation addArc always starts new Contour. SkCanvas::drawArc draws without
Cary Clark73fa9722017-08-29 17:36:51 -04002363requiring Path.
2364
2365arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark77b3f3a2018-11-07 14:59:03 -05002366describes Arc as tangent to the line segment from last Point added to Path to (x1, y1); and tangent
2367to the line segment from (x1, y1) to (x2, y2). This construction is similar to PostScript and
Cary Clark73fa9722017-08-29 17:36:51 -04002368HTML_Canvas arcs.
2369
2370arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04002371 SkScalar x, SkScalar y)
Cary Clark73fa9722017-08-29 17:36:51 -04002372describes Arc as part of Oval with radii (rx, ry), beginning at
2373last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
2374so additional values choose a single solution. This construction is similar to SVG arcs.
2375
2376conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
2377conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
Cary Clark682c58d2018-05-16 07:07:07 -04002378constructions are converted to Conic data when added to Path.
Cary Clark73fa9722017-08-29 17:36:51 -04002379
Cary Clark153e76d2018-08-28 11:48:28 -04002380#ToDo example is spaced correctly on fiddle but spacing is too wide on pc
Cary Clark73fa9722017-08-29 17:36:51 -04002381##
2382
Cary Clark153e76d2018-08-28 11:48:28 -04002383#Illustration
2384
Cary Clark73fa9722017-08-29 17:36:51 -04002385#List
2386# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
Cary Clark77b3f3a2018-11-07 14:59:03 -05002387# <sup>2</sup> parameter adds move to first point ##
Cary Clark5081eed2018-01-22 07:55:48 -05002388# <sup>3</sup> start angle must be multiple of 90 degrees ##
Cary Clark73fa9722017-08-29 17:36:51 -04002389# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
2390# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
2391 Direction sweep, SkScalar x, SkScalar y) ##
2392#List ##
Cary Clark73fa9722017-08-29 17:36:51 -04002393
2394#Example
2395#Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002396void draw(SkCanvas* canvas) {
2397 SkRect oval = {8, 8, 56, 56};
2398 SkPaint ovalPaint;
2399 ovalPaint.setAntiAlias(true);
2400 SkPaint textPaint(ovalPaint);
2401 ovalPaint.setStyle(SkPaint::kStroke_Style);
2402 SkPaint arcPaint(ovalPaint);
2403 arcPaint.setStrokeWidth(5);
2404 arcPaint.setColor(SK_ColorBLUE);
2405 canvas->translate(-64, 0);
2406 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
2407 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
2408 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
2409 canvas->drawOval(oval, ovalPaint);
2410 SkPath path;
2411 path.moveTo({56, 32});
2412 switch (arcStyle) {
2413 case '1':
2414 path.arcTo(oval, 0, 90, false);
2415 break;
2416 case '2':
2417 canvas->drawArc(oval, 0, 90, false, arcPaint);
2418 continue;
2419 case '3':
2420 path.addArc(oval, 0, 90);
2421 break;
2422 case '4':
2423 path.arcTo({56, 56}, {32, 56}, 24);
2424 break;
2425 case '5':
2426 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
2427 break;
2428 case '6':
2429 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
2430 break;
2431 }
2432 canvas->drawPath(path, arcPaint);
2433 }
2434}
2435#Example ##
2436
Cary Clark153e76d2018-08-28 11:48:28 -04002437In the example above:
2438#List
2439# 1 describes an arc from an oval, a starting angle, and a sweep angle. ##
2440# 2 is similar to 1, but does not require building a path to draw. ##
2441# 3 is similar to 1, but always begins new Contour. ##
2442# 4 describes an arc from a pair of tangent lines and a radius. ##
2443# 5 describes an arc from Oval center, arc start Point and arc end Point. ##
2444# 6 describes an arc from a pair of tangent lines and a Conic_Weight. ##
2445#List ##
Cary Clark73fa9722017-08-29 17:36:51 -04002446
Cary Clark0251b1b2018-08-15 15:14:55 -04002447#Method SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
Cary Clark4855f782018-02-06 09:41:53 -05002448#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002449#In Arc
2450#Line # appends Arc ##
Cary Clark09d80c02018-10-31 12:14:03 -04002451#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002452
Cary Clark73fa9722017-08-29 17:36:51 -04002453#Example
2454#Height 200
2455#Description
2456arcTo continues a previous contour when forceMoveTo is false and when Path
2457is not empty.
2458##
2459void draw(SkCanvas* canvas) {
2460 SkPaint paint;
2461 SkPath path;
2462 paint.setStyle(SkPaint::kStroke_Style);
2463 paint.setStrokeWidth(4);
2464 path.moveTo(0, 0);
2465 path.arcTo({20, 20, 120, 120}, -90, 90, false);
2466 canvas->drawPath(path, paint);
2467 path.rewind();
2468 path.arcTo({120, 20, 220, 120}, -90, 90, false);
2469 canvas->drawPath(path, paint);
2470 path.rewind();
2471 path.moveTo(0, 0);
2472 path.arcTo({20, 120, 120, 220}, -90, 90, true);
2473 canvas->drawPath(path, paint);
2474}
2475##
2476
2477#SeeAlso addArc SkCanvas::drawArc conicTo
2478
2479##
2480
2481# ------------------------------------------------------------------------------
2482
Cary Clark0251b1b2018-08-15 15:14:55 -04002483#Method SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05002484#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002485#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002486#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04002487
2488#Example
2489#Height 226
2490void draw(SkCanvas* canvas) {
2491 SkPaint tangentPaint;
2492 tangentPaint.setAntiAlias(true);
2493 SkPaint textPaint(tangentPaint);
2494 tangentPaint.setStyle(SkPaint::kStroke_Style);
2495 tangentPaint.setColor(SK_ColorGRAY);
2496 SkPaint arcPaint(tangentPaint);
2497 arcPaint.setStrokeWidth(5);
2498 arcPaint.setColor(SK_ColorBLUE);
2499 SkPath path;
2500 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
2501 SkScalar radius = 50;
2502 path.moveTo(pts[0]);
2503 path.arcTo(pts[1], pts[2], radius);
2504 canvas->drawLine(pts[0], pts[1], tangentPaint);
2505 canvas->drawLine(pts[1], pts[2], tangentPaint);
2506 SkPoint lastPt;
2507 (void) path.getLastPt(&lastPt);
2508 SkVector radial = pts[2] - pts[1];
2509 radial.setLength(radius);
2510 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
2511 canvas->drawCircle(center, radius, tangentPaint);
2512 canvas->drawLine(lastPt, center, tangentPaint);
2513 radial = pts[1] - pts[0];
2514 radial.setLength(radius);
2515 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
2516 canvas->drawLine(center, arcStart, tangentPaint);
2517 canvas->drawPath(path, arcPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002518 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002519 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002520 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002521 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
2522 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
2523}
2524##
2525
Cary Clark73fa9722017-08-29 17:36:51 -04002526#Example
2527#Height 128
2528void draw(SkCanvas* canvas) {
2529 SkPaint tangentPaint;
2530 tangentPaint.setAntiAlias(true);
2531 SkPaint textPaint(tangentPaint);
2532 tangentPaint.setStyle(SkPaint::kStroke_Style);
2533 tangentPaint.setColor(SK_ColorGRAY);
2534 SkPaint arcPaint(tangentPaint);
2535 arcPaint.setStrokeWidth(5);
2536 arcPaint.setColor(SK_ColorBLUE);
2537 SkPath path;
2538 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
2539 SkScalar radius = 50;
2540 path.moveTo(pts[0]);
2541 path.arcTo(pts[1], pts[2], radius);
2542 canvas->drawLine(pts[0], pts[1], tangentPaint);
2543 canvas->drawLine(pts[1], pts[2], tangentPaint);
2544 SkPoint lastPt;
2545 (void) path.getLastPt(&lastPt);
2546 SkVector radial = pts[2] - pts[1];
2547 radial.setLength(radius);
2548 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
2549 canvas->drawLine(lastPt, center, tangentPaint);
2550 radial = pts[1] - pts[0];
2551 radial.setLength(radius);
2552 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
2553 canvas->drawLine(center, arcStart, tangentPaint);
2554 canvas->drawPath(path, arcPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002555 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002556 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002557 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04002558 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
2559 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
2560}
2561##
2562
Cary Clark73fa9722017-08-29 17:36:51 -04002563#Example
2564#Description
2565arcTo is represented by Line and circular Conic in Path.
2566##
2567void draw(SkCanvas* canvas) {
2568 SkPath path;
2569 path.moveTo({156, 20});
2570 path.arcTo(200, 20, 170, 50, 50);
2571 SkPath::Iter iter(path, false);
2572 SkPoint p[4];
2573 SkPath::Verb verb;
2574 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
2575 switch (verb) {
2576 case SkPath::kMove_Verb:
2577 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
2578 break;
2579 case SkPath::kLine_Verb:
2580 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
2581 break;
2582 case SkPath::kConic_Verb:
2583 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
2584 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
2585 break;
2586 default:
2587 SkDebugf("unexpected verb\n");
2588 }
2589 }
2590}
2591#StdOut
2592move to (156,20)
2593line (156,20),(79.2893,20)
2594conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
2595##
2596##
2597
Cary Clark682c58d2018-05-16 07:07:07 -04002598#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04002599
2600##
2601
2602# ------------------------------------------------------------------------------
2603
Cary Clark0251b1b2018-08-15 15:14:55 -04002604#Method SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
Cary Clark4855f782018-02-06 09:41:53 -05002605#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002606#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002607#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002608
Cary Clark73fa9722017-08-29 17:36:51 -04002609#Example
2610#Description
2611Because tangent lines are parallel, arcTo appends line from last Path Point to
2612p1, but does not append a circular Conic.
2613##
2614void draw(SkCanvas* canvas) {
2615 SkPath path;
2616 path.moveTo({156, 20});
2617 path.arcTo({200, 20}, {170, 20}, 50);
2618 SkPath::Iter iter(path, false);
2619 SkPoint p[4];
2620 SkPath::Verb verb;
2621 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
2622 switch (verb) {
2623 case SkPath::kMove_Verb:
2624 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
2625 break;
2626 case SkPath::kLine_Verb:
2627 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
2628 break;
2629 case SkPath::kConic_Verb:
2630 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
2631 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
2632 break;
2633 default:
2634 SkDebugf("unexpected verb\n");
2635 }
2636 }
2637}
2638#StdOut
2639move to (156,20)
2640line (156,20),(200,20)
2641##
2642##
2643
Cary Clark682c58d2018-05-16 07:07:07 -04002644#SeeAlso conicTo
Cary Clark73fa9722017-08-29 17:36:51 -04002645
2646##
2647
2648# ------------------------------------------------------------------------------
2649
2650#Enum ArcSize
Cary Clark08895c42018-02-01 09:37:32 -05002651#Line # used by arcTo variation ##
Cary Clark73fa9722017-08-29 17:36:51 -04002652
2653#Code
2654 enum ArcSize {
Cary Clark682c58d2018-05-16 07:07:07 -04002655 kSmall_ArcSize,
2656 kLarge_ArcSize,
Cary Clark73fa9722017-08-29 17:36:51 -04002657 };
2658##
2659
Cary Clark77b3f3a2018-11-07 14:59:03 -05002660Four axis-aligned Ovals with the same height and width intersect a pair of Points.
2661ArcSize and Direction select one of the four Ovals, by choosing the larger or smaller
2662arc between the Points; and by choosing the arc Direction, clockwise
2663or counterclockwise.
Cary Clark73fa9722017-08-29 17:36:51 -04002664
2665#Const kSmall_ArcSize 0
Cary Clark682c58d2018-05-16 07:07:07 -04002666#Line # smaller of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04002667##
2668#Const kLarge_ArcSize 1
Cary Clark682c58d2018-05-16 07:07:07 -04002669#Line # larger of Arc pair ##
Cary Clark73fa9722017-08-29 17:36:51 -04002670##
2671
2672#Example
2673#Height 160
2674#Description
2675Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
2676Two routes are large, and two routes are counterclockwise. The one route both large
2677and counterclockwise is blue.
2678##
2679void draw(SkCanvas* canvas) {
2680 SkPaint paint;
2681 paint.setAntiAlias(true);
2682 paint.setStyle(SkPaint::kStroke_Style);
2683 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
2684 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
2685 SkPath path;
2686 path.moveTo({120, 50});
2687 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
2688 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
2689 paint.setColor(SK_ColorBLUE);
2690 paint.setStrokeWidth(3);
2691 }
2692 canvas->drawPath(path, paint);
2693 }
2694 }
2695}
2696##
2697
2698#SeeAlso arcTo Direction
2699
2700##
2701
2702# ------------------------------------------------------------------------------
2703
Cary Clark0251b1b2018-08-15 15:14:55 -04002704#Method SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04002705 Direction sweep, SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05002706#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002707#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002708#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002709
Cary Clark73fa9722017-08-29 17:36:51 -04002710#Example
2711#Height 160
2712void draw(SkCanvas* canvas) {
2713 SkPaint paint;
2714 paint.setAntiAlias(true);
2715 paint.setStyle(SkPaint::kStroke_Style);
2716 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
2717 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
2718 SkPath path;
2719 path.moveTo({120, 50});
2720 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
2721 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
2722 paint.setColor(SK_ColorBLUE);
2723 paint.setStrokeWidth(3);
2724 }
2725 canvas->drawPath(path, paint);
2726 }
2727 }
2728}
2729##
2730
2731#SeeAlso rArcTo ArcSize Direction
2732
2733##
2734
2735# ------------------------------------------------------------------------------
2736
Cary Clark0251b1b2018-08-15 15:14:55 -04002737#Method SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
Cary Clark682c58d2018-05-16 07:07:07 -04002738 const SkPoint xy)
Cary Clark4855f782018-02-06 09:41:53 -05002739#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002740#In Arc
Cary Clark09d80c02018-10-31 12:14:03 -04002741#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002742
Cary Clark73fa9722017-08-29 17:36:51 -04002743#Example
2744#Height 108
2745void draw(SkCanvas* canvas) {
2746 SkPaint paint;
2747 SkPath path;
2748 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
2749 for (auto start : starts) {
2750 path.moveTo(start.fX, start.fY);
2751 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
2752 }
2753 canvas->drawPath(path, paint);
2754}
2755##
2756
2757#SeeAlso rArcTo ArcSize Direction
2758
2759##
2760
2761# ------------------------------------------------------------------------------
2762
Cary Clark0251b1b2018-08-15 15:14:55 -04002763#Method SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Cary Clark73fa9722017-08-29 17:36:51 -04002764 Direction sweep, SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05002765#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002766#In Arc
2767#Line # appends Arc relative to Last_Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002768
Cary Clark80247e52018-07-11 16:18:41 -04002769Appends Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04002770more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark77b3f3a2018-11-07 14:59:03 -05002771xAxisRotate degrees. Arc curves from last Path Point to relative end Point
2772(dx, dy), choosing one of four possible routes: clockwise or
Cary Clark73fa9722017-08-29 17:36:51 -04002773counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
2774is (0, 0).
2775
Cary Clarkce101242017-09-01 15:51:02 -04002776Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
2777if either radii are zero, or if last Path Point equals end Point.
2778arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
2779greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04002780
2781arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04002782arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
2783opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04002784kCW_Direction cast to int is zero.
2785
Cary Clark5538c132018-06-14 12:28:14 -04002786#Param rx radius before x-axis rotation ##
2787#Param ry radius before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04002788#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04002789#Param largeArc chooses smaller or larger Arc ##
2790#Param sweep chooses clockwise or counterclockwise Arc ##
Cary Clark5538c132018-06-14 12:28:14 -04002791#Param dx x-axis offset end of Arc from last Path Point ##
2792#Param dy y-axis offset end of Arc from last Path Point ##
Cary Clark73fa9722017-08-29 17:36:51 -04002793
Cary Clark0251b1b2018-08-15 15:14:55 -04002794#Return reference to Path ##
2795
Cary Clark73fa9722017-08-29 17:36:51 -04002796#Example
2797#Height 108
2798void draw(SkCanvas* canvas) {
2799 SkPaint paint;
2800 SkPath path;
2801 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
2802 for (auto start : starts) {
2803 path.moveTo(start.fX, start.fY);
2804 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
2805 }
2806 canvas->drawPath(path, paint);
2807}
2808##
2809
2810#SeeAlso arcTo ArcSize Direction
2811
2812##
2813
Cary Clark78de7512018-02-07 07:27:09 -05002814#Subtopic Arc ##
Cary Clark73fa9722017-08-29 17:36:51 -04002815
2816# ------------------------------------------------------------------------------
2817
Cary Clark0251b1b2018-08-15 15:14:55 -04002818#Method SkPath& close()
Cary Clark4855f782018-02-06 09:41:53 -05002819#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05002820#Line # makes last Contour a loop ##
Cary Clark09d80c02018-10-31 12:14:03 -04002821#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04002822
Cary Clark73fa9722017-08-29 17:36:51 -04002823#Example
2824void draw(SkCanvas* canvas) {
2825 SkPaint paint;
2826 paint.setStrokeWidth(15);
2827 paint.setStrokeCap(SkPaint::kRound_Cap);
2828 SkPath path;
2829 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
2830 path.addPoly(points, SK_ARRAY_COUNT(points), false);
2831 for (int loop = 0; loop < 2; ++loop) {
2832 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
2833 SkPaint::kStrokeAndFill_Style} ) {
2834 paint.setStyle(style);
2835 canvas->drawPath(path, paint);
2836 canvas->translate(85, 0);
2837 }
2838 path.close();
2839 canvas->translate(-255, 128);
2840 }
2841}
2842##
2843
Cary Clark682c58d2018-05-16 07:07:07 -04002844#SeeAlso
Cary Clark73fa9722017-08-29 17:36:51 -04002845
2846##
2847
2848# ------------------------------------------------------------------------------
2849
Cary Clark682c58d2018-05-16 07:07:07 -04002850#Method static bool IsInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05002851#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05002852#Line # returns if Fill_Type represents outside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04002853Returns true if fill is inverted and Path with fill represents area outside
2854of its geometric bounds.
2855
2856#Table
2857#Legend
2858# FillType # is inverse ##
2859##
2860# kWinding_FillType # false ##
2861# kEvenOdd_FillType # false ##
2862# kInverseWinding_FillType # true ##
2863# kInverseEvenOdd_FillType # true ##
2864##
2865
2866#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
2867 kInverseWinding_FillType, kInverseEvenOdd_FillType
2868##
2869
2870#Return true if Path fills outside its bounds ##
2871
2872#Example
2873#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05002874###$
Cary Clark73fa9722017-08-29 17:36:51 -04002875#define nameValue(fill) { SkPath::fill, #fill }
2876
Cary Clark1a8d7622018-03-05 13:26:16 -05002877$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04002878##
2879void draw(SkCanvas* canvas) {
2880 struct {
2881 SkPath::FillType fill;
2882 const char* name;
2883 } fills[] = {
2884 nameValue(kWinding_FillType),
2885 nameValue(kEvenOdd_FillType),
2886 nameValue(kInverseWinding_FillType),
2887 nameValue(kInverseEvenOdd_FillType),
2888 };
2889 for (auto fill: fills ) {
2890 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
2891 "true" : "false");
2892 }
2893}
2894#StdOut
2895IsInverseFillType(kWinding_FillType) == false
2896IsInverseFillType(kEvenOdd_FillType) == false
2897IsInverseFillType(kInverseWinding_FillType) == true
2898IsInverseFillType(kInverseEvenOdd_FillType) == true
2899##
2900##
2901
2902#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
2903
2904##
2905
2906# ------------------------------------------------------------------------------
2907
Cary Clark682c58d2018-05-16 07:07:07 -04002908#Method static FillType ConvertToNonInverseFillType(FillType fill)
Cary Clark4855f782018-02-06 09:41:53 -05002909#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002910#Line # returns Fill_Type representing inside geometry ##
Cary Clark73fa9722017-08-29 17:36:51 -04002911Returns equivalent Fill_Type representing Path fill inside its bounds.
Cary Clark73fa9722017-08-29 17:36:51 -04002912
2913#Table
2914#Legend
2915# FillType # inside FillType ##
2916##
2917# kWinding_FillType # kWinding_FillType ##
2918# kEvenOdd_FillType # kEvenOdd_FillType ##
2919# kInverseWinding_FillType # kWinding_FillType ##
2920# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
2921##
2922
2923#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
2924 kInverseWinding_FillType, kInverseEvenOdd_FillType
2925##
2926
2927#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
2928
2929#Example
2930#Function
Cary Clark1a8d7622018-03-05 13:26:16 -05002931###$
Cary Clark73fa9722017-08-29 17:36:51 -04002932#define nameValue(fill) { SkPath::fill, #fill }
2933
Cary Clark1a8d7622018-03-05 13:26:16 -05002934$$$#
Cary Clark73fa9722017-08-29 17:36:51 -04002935##
2936void draw(SkCanvas* canvas) {
2937 struct {
2938 SkPath::FillType fill;
2939 const char* name;
2940 } fills[] = {
2941 nameValue(kWinding_FillType),
2942 nameValue(kEvenOdd_FillType),
2943 nameValue(kInverseWinding_FillType),
2944 nameValue(kInverseEvenOdd_FillType),
2945 };
2946 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
2947 if (fills[i].fill != (SkPath::FillType) i) {
2948 SkDebugf("fills array order does not match FillType enum order");
2949 break;
Cary Clark682c58d2018-05-16 07:07:07 -04002950 }
Cary Clark73fa9722017-08-29 17:36:51 -04002951 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
2952 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
2953 }
2954}
2955#StdOut
2956ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
2957ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
2958ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
2959ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
2960##
2961##
2962
2963#SeeAlso FillType getFillType setFillType IsInverseFillType
2964
2965##
2966
2967# ------------------------------------------------------------------------------
2968
2969#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
2970 SkScalar w, SkPoint pts[], int pow2)
Cary Clark4855f782018-02-06 09:41:53 -05002971#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05002972#Line # approximates Conic with Quad array ##
Cary Clark73fa9722017-08-29 17:36:51 -04002973
2974Approximates Conic with Quad array. Conic is constructed from start Point p0,
Cary Clark682c58d2018-05-16 07:07:07 -04002975control Point p1, end Point p2, and weight w.
Cary Clark73fa9722017-08-29 17:36:51 -04002976Quad array is stored in pts; this storage is supplied by caller.
2977Maximum Quad count is 2 to the pow2.
Cary Clark682c58d2018-05-16 07:07:07 -04002978Every third point in array shares last Point of previous Quad and first Point of
2979next Quad. Maximum pts storage size is given by:
Cary Clark2be81cf2018-09-13 12:04:30 -04002980#Formula # (1 + 2 * (1 << pow2)) * sizeof(SkPoint) ##.
Cary Clark6fc50412017-09-21 12:31:06 -04002981
Cary Clark154beea2017-10-26 07:58:48 -04002982Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04002983than the number requested.
Cary Clark682c58d2018-05-16 07:07:07 -04002984
Cary Clark73fa9722017-08-29 17:36:51 -04002985Conic_Weight determines the amount of influence Conic control point has on the curve.
2986w less than one represents an elliptical section. w greater than one represents
2987a hyperbolic section. w equal to one represents a parabolic section.
2988
2989Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
2990of up to 90 degrees; in this case, set pow2 to one.
2991
2992#Param p0 Conic start Point ##
2993#Param p1 Conic control Point ##
2994#Param p2 Conic end Point ##
2995#Param w Conic weight ##
2996#Param pts storage for Quad array ##
2997#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
2998
Cary Clarka523d2d2017-08-30 08:58:10 -04002999#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003000
3001#Example
3002#Description
3003A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3004The middle curve is nearly circular. The top-right curve is parabolic, which can
3005be drawn exactly with a single Quad.
3006##
3007void draw(SkCanvas* canvas) {
3008 SkPaint conicPaint;
3009 conicPaint.setAntiAlias(true);
3010 conicPaint.setStyle(SkPaint::kStroke_Style);
3011 SkPaint quadPaint(conicPaint);
3012 quadPaint.setColor(SK_ColorRED);
3013 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3014 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3015 SkPoint quads[5];
3016 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3017 SkPath path;
3018 path.moveTo(conic[0]);
3019 path.conicTo(conic[1], conic[2], weight);
3020 canvas->drawPath(path, conicPaint);
3021 path.rewind();
3022 path.moveTo(quads[0]);
3023 path.quadTo(quads[1], quads[2]);
3024 path.quadTo(quads[3], quads[4]);
3025 canvas->drawPath(path, quadPaint);
3026 canvas->translate(50, -50);
3027 }
3028}
3029##
3030
3031#SeeAlso Conic Quad
3032
3033##
3034
3035# ------------------------------------------------------------------------------
3036
3037#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003038#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003039#Line # returns if describes Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -04003040#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003041
3042#Example
3043#Description
3044After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3045following lineTo does not. addPoly returns true even though rect is not closed, and one
3046side of rect is made up of consecutive line segments.
3047##
3048void draw(SkCanvas* canvas) {
3049 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3050 SkRect rect;
3051 SkPath::Direction direction;
3052 bool isClosed;
Cary Clark682c58d2018-05-16 07:07:07 -04003053 path.isRect(&rect, &isClosed, &direction) ?
Cary Clark73fa9722017-08-29 17:36:51 -04003054 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3055 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3056 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3057 SkDebugf("%s is not rect\n", prefix);
3058 };
3059 SkPath path;
3060 debugster("empty", path);
3061 path.addRect({10, 20, 30, 40});
3062 debugster("addRect", path);
3063 path.moveTo(60, 70);
3064 debugster("moveTo", path);
3065 path.lineTo(60, 70);
3066 debugster("lineTo", path);
3067 path.reset();
3068 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3069 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3070 debugster("addPoly", path);
3071}
3072#StdOut
3073empty is not rect
3074addRect is rect (10, 20, 30, 40); is closed; direction CW
3075moveTo is rect (10, 20, 30, 40); is closed; direction CW
3076lineTo is not rect
3077addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3078##
3079##
3080
3081#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3082
3083##
3084
3085# ------------------------------------------------------------------------------
3086
3087#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
Cary Clark4855f782018-02-06 09:41:53 -05003088#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003089#Line # returns if describes Rect pair, one inside the other ##
Cary Clark09d80c02018-10-31 12:14:03 -04003090#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003091
3092#Example
3093void draw(SkCanvas* canvas) {
3094 SkPaint paint;
3095 paint.setStyle(SkPaint::kStroke_Style);
3096 paint.setStrokeWidth(5);
3097 SkPath path;
3098 path.addRect({10, 20, 30, 40});
3099 paint.getFillPath(path, &path);
3100 SkRect rects[2];
3101 SkPath::Direction directions[2];
3102 if (path.isNestedFillRects(rects, directions)) {
3103 for (int i = 0; i < 2; ++i) {
3104 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3105 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3106 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3107 }
3108 } else {
3109 SkDebugf("is not nested rectangles\n");
3110 }
3111}
3112#StdOut
3113outer (7.5, 17.5, 32.5, 42.5); direction CW
3114inner (12.5, 22.5, 27.5, 37.5); direction CCW
3115##
3116##
3117
3118#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3119
3120##
3121
3122# ------------------------------------------------------------------------------
3123
Cary Clark0251b1b2018-08-15 15:14:55 -04003124#Method SkPath& addRect(const SkRect& rect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003125#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003126#Line # adds one Contour containing Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -04003127#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003128
Cary Clark73fa9722017-08-29 17:36:51 -04003129#Example
3130#Description
3131The left Rect dashes starting at the top-left corner, to the right.
3132The right Rect dashes starting at the top-left corner, towards the bottom.
3133##
3134#Height 128
3135void draw(SkCanvas* canvas) {
3136 SkPaint paint;
3137 paint.setStrokeWidth(15);
3138 paint.setStrokeCap(SkPaint::kSquare_Cap);
3139 float intervals[] = { 5, 21.75f };
3140 paint.setStyle(SkPaint::kStroke_Style);
3141 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3142 SkPath path;
3143 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
3144 canvas->drawPath(path, paint);
3145 path.rewind();
3146 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
3147 canvas->drawPath(path, paint);
3148}
3149##
3150
3151#SeeAlso SkCanvas::drawRect Direction
3152
3153##
3154
3155# ------------------------------------------------------------------------------
3156
Cary Clark0251b1b2018-08-15 15:14:55 -04003157#Method SkPath& addRect(const SkRect& rect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04003158
Cary Clark80247e52018-07-11 16:18:41 -04003159Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04003160If dir is kCW_Direction, Rect corners are added clockwise; if dir is
3161kCCW_Direction, Rect corners are added counterclockwise.
3162start determines the first corner added.
3163
3164#Table
3165#Legend
3166# start # first corner ##
3167#Legend ##
3168# 0 # top-left ##
3169# 1 # top-right ##
3170# 2 # bottom-right ##
3171# 3 # bottom-left ##
3172#Table ##
3173
3174#Param rect Rect to add as a closed contour ##
3175#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04003176#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04003177
Cary Clark0251b1b2018-08-15 15:14:55 -04003178#Return reference to Path ##
3179
Cary Clark73fa9722017-08-29 17:36:51 -04003180#Example
3181#Height 128
3182#Description
3183The arrow is just after the initial corner and points towards the next
3184corner appended to Path.
3185##
3186void draw(SkCanvas* canvas) {
3187 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
3188 const SkRect rect = {10, 10, 54, 54};
3189 SkPaint rectPaint;
3190 rectPaint.setAntiAlias(true);
3191 rectPaint.setStyle(SkPaint::kStroke_Style);
3192 SkPaint arrowPaint(rectPaint);
3193 SkPath arrowPath;
3194 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
3195 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
3196 SkPath1DPathEffect::kRotate_Style));
3197 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3198 for (unsigned start : { 0, 1, 2, 3 } ) {
3199 SkPath path;
3200 path.addRect(rect, direction, start);
3201 canvas->drawPath(path, rectPaint);
3202 canvas->drawPath(path, arrowPaint);
3203 canvas->translate(64, 0);
3204 }
3205 canvas->translate(-256, 64);
3206 }
3207}
3208##
3209
3210#SeeAlso SkCanvas::drawRect Direction
3211
3212##
3213
3214# ------------------------------------------------------------------------------
3215
Cary Clark0251b1b2018-08-15 15:14:55 -04003216#Method SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
Cary Clark73fa9722017-08-29 17:36:51 -04003217 Direction dir = kCW_Direction)
Cary Clark09d80c02018-10-31 12:14:03 -04003218#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003219
Cary Clark73fa9722017-08-29 17:36:51 -04003220#Example
3221#Description
3222The left Rect dashes start at the top-left corner, and continue to the right.
3223The right Rect dashes start at the top-left corner, and continue down.
3224##
3225#Height 128
3226void draw(SkCanvas* canvas) {
3227 SkPaint paint;
3228 paint.setStrokeWidth(15);
3229 paint.setStrokeCap(SkPaint::kSquare_Cap);
3230 float intervals[] = { 5, 21.75f };
3231 paint.setStyle(SkPaint::kStroke_Style);
3232 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
3233 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3234 SkPath path;
3235 path.addRect(20, 20, 100, 100, direction);
3236 canvas->drawPath(path, paint);
3237 canvas->translate(128, 0);
3238 }
3239}
3240##
3241
3242#SeeAlso SkCanvas::drawRect Direction
3243
3244##
3245
3246# ------------------------------------------------------------------------------
3247
Cary Clark0251b1b2018-08-15 15:14:55 -04003248#Method SkPath& addOval(const SkRect& oval, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003249#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003250#Line # adds one Contour containing Oval ##
Cary Clark09d80c02018-10-31 12:14:03 -04003251#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003252
Cary Clark73fa9722017-08-29 17:36:51 -04003253#Example
3254#Height 120
3255 SkPaint paint;
3256 SkPath oval;
3257 oval.addOval({20, 20, 160, 80});
3258 canvas->drawPath(oval, paint);
3259##
3260
3261#SeeAlso SkCanvas::drawOval Direction Oval
3262
3263##
3264
3265# ------------------------------------------------------------------------------
3266
Cary Clark0251b1b2018-08-15 15:14:55 -04003267#Method SkPath& addOval(const SkRect& oval, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04003268
Cary Clark80247e52018-07-11 16:18:41 -04003269Adds Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Cary Clark73fa9722017-08-29 17:36:51 -04003270Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
3271and half oval height. Oval begins at start and continues
3272clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
3273
3274#Table
3275#Legend
3276# start # Point ##
3277#Legend ##
3278# 0 # oval.centerX(), oval.fTop ##
3279# 1 # oval.fRight, oval.centerY() ##
3280# 2 # oval.centerX(), oval.fBottom ##
3281# 3 # oval.fLeft, oval.centerY() ##
3282#Table ##
3283
3284#Param oval bounds of ellipse added ##
3285#Param dir Direction to wind ellipse ##
3286#Param start index of initial point of ellipse ##
3287
Cary Clark0251b1b2018-08-15 15:14:55 -04003288#Return reference to Path ##
3289
Cary Clark73fa9722017-08-29 17:36:51 -04003290#Example
3291#Height 160
3292void draw(SkCanvas* canvas) {
3293 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
3294 const SkRect rect = {10, 10, 54, 54};
3295 SkPaint ovalPaint;
3296 ovalPaint.setAntiAlias(true);
3297 SkPaint textPaint(ovalPaint);
Cary Clark73fa9722017-08-29 17:36:51 -04003298 ovalPaint.setStyle(SkPaint::kStroke_Style);
3299 SkPaint arrowPaint(ovalPaint);
3300 SkPath arrowPath;
3301 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
3302 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
3303 SkPath1DPathEffect::kRotate_Style));
3304 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3305 for (unsigned start : { 0, 1, 2, 3 } ) {
3306 SkPath path;
3307 path.addOval(rect, direction, start);
3308 canvas->drawPath(path, ovalPaint);
3309 canvas->drawPath(path, arrowPaint);
3310 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
3311 canvas->translate(64, 0);
3312 }
3313 canvas->translate(-256, 72);
3314 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
3315 128, 0, textPaint);
3316 }
3317}
3318##
3319
3320#SeeAlso SkCanvas::drawOval Direction Oval
3321
3322##
3323
3324# ------------------------------------------------------------------------------
3325
Cary Clark0251b1b2018-08-15 15:14:55 -04003326#Method SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
Cary Clark73fa9722017-08-29 17:36:51 -04003327 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003328#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003329#Line # adds one Contour containing Circle ##
Cary Clark73fa9722017-08-29 17:36:51 -04003330
Cary Clark80247e52018-07-11 16:18:41 -04003331Adds Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark2be81cf2018-09-13 12:04:30 -04003332four kConic_Verb, and kClose_Verb. Circle begins at: #Formula # (x + radius, y) ##, continuing
Cary Clark154beea2017-10-26 07:58:48 -04003333clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04003334
Cary Clark6fc50412017-09-21 12:31:06 -04003335Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04003336
3337#Param x center of Circle ##
3338#Param y center of Circle ##
3339#Param radius distance from center to edge ##
3340#Param dir Direction to wind Circle ##
3341
Cary Clark0251b1b2018-08-15 15:14:55 -04003342#Return reference to Path ##
3343
Cary Clark73fa9722017-08-29 17:36:51 -04003344#Example
3345void draw(SkCanvas* canvas) {
3346 SkPaint paint;
3347 paint.setAntiAlias(true);
3348 paint.setStyle(SkPaint::kStroke_Style);
3349 paint.setStrokeWidth(10);
3350 for (int size = 10; size < 300; size += 20) {
3351 SkPath path;
3352 path.addCircle(128, 128, size, SkPath::kCW_Direction);
3353 canvas->drawPath(path, paint);
3354 }
3355}
3356##
3357
3358#SeeAlso SkCanvas::drawCircle Direction Circle
3359
3360##
3361
3362# ------------------------------------------------------------------------------
3363
Cary Clark0251b1b2018-08-15 15:14:55 -04003364#Method SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
Cary Clark4855f782018-02-06 09:41:53 -05003365#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003366#Line # adds one Contour containing Arc ##
Cary Clark09d80c02018-10-31 12:14:03 -04003367#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003368
Cary Clark73fa9722017-08-29 17:36:51 -04003369#Example
3370#Description
3371The middle row of the left and right columns draw differently from the entries
Cary Clark682c58d2018-05-16 07:07:07 -04003372above and below because sweepAngle is outside of the range of +/-360,
Cary Clark73fa9722017-08-29 17:36:51 -04003373and startAngle modulo 90 is not zero.
3374##
3375void draw(SkCanvas* canvas) {
3376 SkPaint paint;
3377 for (auto start : { 0, 90, 135, 180, 270 } ) {
3378 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
3379 SkPath path;
3380 path.addArc({10, 10, 35, 45}, start, sweep);
3381 canvas->drawPath(path, paint);
3382 canvas->translate(252 / 6, 0);
3383 }
3384 canvas->translate(-252, 255 / 5);
3385 }
3386}
3387##
3388
3389#SeeAlso Arc arcTo SkCanvas::drawArc
3390
3391##
3392
3393# ------------------------------------------------------------------------------
3394
Cary Clark0251b1b2018-08-15 15:14:55 -04003395#Method SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Cary Clark73fa9722017-08-29 17:36:51 -04003396 Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003397#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003398#Line # adds one Contour containing Round_Rect with common corner radii ##
Cary Clark09d80c02018-10-31 12:14:03 -04003399#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003400
Cary Clark73fa9722017-08-29 17:36:51 -04003401#Example
3402#Description
3403If either radius is zero, path contains Rect and is drawn red.
3404If sides are only radii, path contains Oval and is drawn blue.
3405All remaining path draws are convex, and are drawn in gray; no
3406paths constructed from addRoundRect are concave, so none are
3407drawn in green.
3408##
3409void draw(SkCanvas* canvas) {
3410 SkPaint paint;
3411 paint.setAntiAlias(true);
3412 for (auto xradius : { 0, 7, 13, 20 } ) {
3413 for (auto yradius : { 0, 9, 18, 40 } ) {
3414 SkPath path;
3415 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
3416 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
3417 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
3418 canvas->drawPath(path, paint);
3419 canvas->translate(64, 0);
3420 }
3421 canvas->translate(-256, 64);
3422 }
3423}
3424##
3425
3426#SeeAlso addRRect SkCanvas::drawRoundRect
3427
3428##
3429
3430# ------------------------------------------------------------------------------
3431
Cary Clark0251b1b2018-08-15 15:14:55 -04003432#Method SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
Cary Clark73fa9722017-08-29 17:36:51 -04003433 Direction dir = kCW_Direction)
3434
Cary Clark80247e52018-07-11 16:18:41 -04003435Appends Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
Cary Clark73fa9722017-08-29 17:36:51 -04003436equal to rect; each corner is 90 degrees of an ellipse with radii from the
3437array.
3438
3439#Table
3440#Legend
3441# radii index # location ##
3442#Legend ##
Cary Clark5538c132018-06-14 12:28:14 -04003443# 0 # x-axis radius of top-left corner ##
3444# 1 # y-axis radius of top-left corner ##
3445# 2 # x-axis radius of top-right corner ##
3446# 3 # y-axis radius of top-right corner ##
3447# 4 # x-axis radius of bottom-right corner ##
3448# 5 # y-axis radius of bottom-right corner ##
3449# 6 # x-axis radius of bottom-left corner ##
3450# 7 # y-axis radius of bottom-left corner ##
Cary Clark73fa9722017-08-29 17:36:51 -04003451#Table ##
3452
Cary Clark682c58d2018-05-16 07:07:07 -04003453If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
3454and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
Cary Clark73fa9722017-08-29 17:36:51 -04003455bottom-left of the upper-left corner and winds counterclockwise.
3456
Cary Clark682c58d2018-05-16 07:07:07 -04003457If both radii on any side of rect exceed its length, all radii are scaled
Cary Clark73fa9722017-08-29 17:36:51 -04003458uniformly until the corners fit. If either radius of a corner is less than or
3459equal to zero, both are treated as zero.
3460
Cary Clark77b3f3a2018-11-07 14:59:03 -05003461After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
Cary Clark73fa9722017-08-29 17:36:51 -04003462
3463#Param rect bounds of Round_Rect ##
3464#Param radii array of 8 SkScalar values, a radius pair for each corner ##
3465#Param dir Direction to wind Round_Rect ##
3466
Cary Clark0251b1b2018-08-15 15:14:55 -04003467#Return reference to Path ##
3468
Cary Clark73fa9722017-08-29 17:36:51 -04003469#Example
3470void draw(SkCanvas* canvas) {
3471 SkPaint paint;
3472 paint.setAntiAlias(true);
3473 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
3474 SkPath path;
3475 SkMatrix rotate90;
3476 rotate90.setRotate(90, 128, 128);
3477 for (int i = 0; i < 4; ++i) {
3478 path.addRoundRect({10, 10, 110, 110}, radii);
3479 path.transform(rotate90);
3480 }
3481 canvas->drawPath(path, paint);
3482}
3483##
3484
3485#SeeAlso addRRect SkCanvas::drawRoundRect
3486
3487##
3488
3489# ------------------------------------------------------------------------------
3490
Cary Clark0251b1b2018-08-15 15:14:55 -04003491#Method SkPath& addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
Cary Clark4855f782018-02-06 09:41:53 -05003492#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003493#Line # adds one Contour containing Round_Rect ##
Cary Clark09d80c02018-10-31 12:14:03 -04003494#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003495
Cary Clark73fa9722017-08-29 17:36:51 -04003496#Example
3497void draw(SkCanvas* canvas) {
3498 SkPaint paint;
3499 paint.setAntiAlias(true);
3500 SkRRect rrect;
3501 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
3502 rrect.setRectRadii({10, 10, 110, 110}, radii);
3503 SkPath path;
3504 SkMatrix rotate90;
3505 rotate90.setRotate(90, 128, 128);
3506 for (int i = 0; i < 4; ++i) {
3507 path.addRRect(rrect);
3508 path.transform(rotate90);
3509 }
3510 canvas->drawPath(path, paint);
3511}
3512##
3513
3514#SeeAlso addRoundRect SkCanvas::drawRRect
3515
3516##
3517
3518# ------------------------------------------------------------------------------
3519
Cary Clark0251b1b2018-08-15 15:14:55 -04003520#Method SkPath& addRRect(const SkRRect& rrect, Direction dir, unsigned start)
Cary Clark73fa9722017-08-29 17:36:51 -04003521
Cary Clark80247e52018-07-11 16:18:41 -04003522Adds rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
Cary Clark73fa9722017-08-29 17:36:51 -04003523winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
3524start determines the first point of rrect to add.
3525
3526#Table
3527#Legend
3528# start # location ##
3529#Legend ##
3530# 0 # right of top-left corner ##
3531# 1 # left of top-right corner ##
3532# 2 # bottom of top-right corner ##
3533# 3 # top of bottom-right corner ##
3534# 4 # left of bottom-right corner ##
3535# 5 # right of bottom-left corner ##
3536# 6 # top of bottom-left corner ##
3537# 7 # bottom of top-left corner ##
3538#Table ##
3539
3540After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
3541
3542#Param rrect bounds and radii of rounded rectangle ##
3543#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04003544#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04003545
Cary Clark0251b1b2018-08-15 15:14:55 -04003546#Return reference to Path ##
3547
Cary Clark73fa9722017-08-29 17:36:51 -04003548#Example
3549void draw(SkCanvas* canvas) {
Mike Reed6a388002018-10-16 13:13:09 -04003550 SkPaint paint;
3551 paint.setAntiAlias(true);
3552 SkRRect rrect;
3553 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
3554 SkPath path;
3555 path.addRRect(rrect);
3556 canvas->drawPath(path, paint);
3557 for (int start = 0; start < 8; ++start) {
3558 SkPath textPath;
3559 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
3560 SkPathMeasure pathMeasure(textPath, false);
3561 SkPoint position;
3562 SkVector tangent;
3563 if (!pathMeasure.getPosTan(0, &position, &tangent)) {
3564 continue;
3565 }
3566 SkRSXform rsxForm = SkRSXform::Make(tangent.fX, tangent.fY,
3567 position.fX + tangent.fY * 5, position.fY - tangent.fX * 5);
3568 canvas->drawTextRSXform(&"01234567"[start], 1, &rsxForm, nullptr, paint);
3569 }
Cary Clark73fa9722017-08-29 17:36:51 -04003570}
3571##
3572
Cary Clark682c58d2018-05-16 07:07:07 -04003573#SeeAlso addRoundRect SkCanvas::drawRRect
Cary Clark73fa9722017-08-29 17:36:51 -04003574
3575##
3576
3577# ------------------------------------------------------------------------------
3578
Cary Clark0251b1b2018-08-15 15:14:55 -04003579#Method SkPath& addPoly(const SkPoint pts[], int count, bool close)
Cary Clark4855f782018-02-06 09:41:53 -05003580#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003581#Line # adds one Contour containing connected lines ##
Cary Clark09d80c02018-10-31 12:14:03 -04003582#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003583
Cary Clark73fa9722017-08-29 17:36:51 -04003584#Example
3585void draw(SkCanvas* canvas) {
3586 SkPaint paint;
3587 paint.setStrokeWidth(15);
3588 paint.setStrokeCap(SkPaint::kRound_Cap);
3589 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3590 for (bool close : { false, true } ) {
3591 SkPath path;
3592 path.addPoly(points, SK_ARRAY_COUNT(points), close);
3593 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3594 SkPaint::kStrokeAndFill_Style} ) {
3595 paint.setStyle(style);
3596 canvas->drawPath(path, paint);
3597 canvas->translate(85, 0);
3598 }
3599 canvas->translate(-255, 128);
3600 }
3601}
3602##
3603
3604#SeeAlso SkCanvas::drawPoints
3605
3606##
3607
Cary Clark0251b1b2018-08-15 15:14:55 -04003608#Method SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close)
Cary Clark09d80c02018-10-31 12:14:03 -04003609#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003610
3611#Example
3612void draw(SkCanvas* canvas) {
3613 SkPaint paint;
3614 paint.setStrokeWidth(15);
3615 paint.setStrokeCap(SkPaint::kRound_Cap);
3616 for (bool close : { false, true } ) {
3617 SkPath path;
3618 path.addPoly({{20, 20}, {70, 20}, {40, 90}}, close);
3619 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3620 SkPaint::kStrokeAndFill_Style} ) {
3621 paint.setStyle(style);
3622 canvas->drawPath(path, paint);
3623 canvas->translate(85, 0);
3624 }
3625 canvas->translate(-255, 128);
3626 }
3627}
3628##
3629
3630#SeeAlso SkCanvas::drawPoints
3631
3632##
3633
Cary Clark73fa9722017-08-29 17:36:51 -04003634# ------------------------------------------------------------------------------
3635
3636#Enum AddPathMode
Cary Clark08895c42018-02-01 09:37:32 -05003637#Line # sets addPath options ##
Cary Clark73fa9722017-08-29 17:36:51 -04003638
3639#Code
3640 enum AddPathMode {
Cary Clark682c58d2018-05-16 07:07:07 -04003641 kAppend_AddPathMode,
3642 kExtend_AddPathMode,
Cary Clark73fa9722017-08-29 17:36:51 -04003643 };
3644##
3645
3646AddPathMode chooses how addPath appends. Adding one Path to another can extend
3647the last Contour or start a new Contour.
3648
3649#Const kAppend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04003650#Line # appended to destination unaltered ##
Cary Clark73fa9722017-08-29 17:36:51 -04003651 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
3652 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
3653 starts a new Contour.
3654##
3655#Const kExtend_AddPathMode
Cary Clark682c58d2018-05-16 07:07:07 -04003656#Line # add line if prior Contour is not closed ##
Cary Clark73fa9722017-08-29 17:36:51 -04003657 If destination is closed or empty, start a new Contour. If destination
3658 is not empty, add Line from Last_Point to added Path first Point. Skip added
Cary Clark77b3f3a2018-11-07 14:59:03 -05003659 Path initial kMove_Verb, then append remaining Verbs, Points, and Conic_Weights.
Cary Clark73fa9722017-08-29 17:36:51 -04003660##
3661
3662#Example
3663#Description
3664test is built from path, open on the top row, and closed on the bottom row.
3665The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
3666The top right composition is made up of one contour; the other three have two.
3667##
3668#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04003669 SkPath path, path2;
3670 path.moveTo(20, 20);
3671 path.lineTo(20, 40);
3672 path.lineTo(40, 20);
3673 path2.moveTo(60, 60);
3674 path2.lineTo(80, 60);
3675 path2.lineTo(80, 40);
3676 SkPaint paint;
3677 paint.setStyle(SkPaint::kStroke_Style);
3678 for (int i = 0; i < 2; i++) {
3679 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
3680 SkPath test(path);
3681 test.addPath(path2, addPathMode);
3682 canvas->drawPath(test, paint);
3683 canvas->translate(100, 0);
3684 }
3685 canvas->translate(-200, 100);
3686 path.close();
3687 }
Cary Clark73fa9722017-08-29 17:36:51 -04003688##
3689
3690#SeeAlso addPath reverseAddPath
3691
3692##
3693
3694# ------------------------------------------------------------------------------
3695
Cary Clark0251b1b2018-08-15 15:14:55 -04003696#Method SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
Cary Clark73fa9722017-08-29 17:36:51 -04003697 AddPathMode mode = kAppend_AddPathMode)
Cary Clark4855f782018-02-06 09:41:53 -05003698#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003699#Line # adds contents of Path ##
Cary Clark09d80c02018-10-31 12:14:03 -04003700#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003701
Cary Clark73fa9722017-08-29 17:36:51 -04003702#Example
3703#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04003704 SkPaint paint;
3705 paint.setTextSize(128);
3706 paint.setFakeBoldText(true);
3707 SkPath dest, text;
3708 paint.getTextPath("O", 1, 50, 120, &text);
3709 for (int i = 0; i < 3; i++) {
3710 dest.addPath(text, i * 20, i * 20);
3711 }
3712 Simplify(dest, &dest);
3713 paint.setStyle(SkPaint::kStroke_Style);
3714 paint.setStrokeWidth(3);
3715 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003716##
3717
Cary Clark4855f782018-02-06 09:41:53 -05003718#SeeAlso AddPathMode offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04003719
3720##
3721
3722# ------------------------------------------------------------------------------
3723
Cary Clark0251b1b2018-08-15 15:14:55 -04003724#Method SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
Cary Clark09d80c02018-10-31 12:14:03 -04003725#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003726
Cary Clark73fa9722017-08-29 17:36:51 -04003727#Example
3728#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04003729 SkPaint paint;
3730 paint.setStyle(SkPaint::kStroke_Style);
3731 SkPath dest, path;
3732 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
3733 for (int i = 0; i < 2; i++) {
3734 dest.addPath(path, SkPath::kExtend_AddPathMode);
3735 dest.offset(100, 0);
3736 }
Cary Clark73fa9722017-08-29 17:36:51 -04003737 canvas->drawPath(dest, paint);
3738##
3739
3740#SeeAlso AddPathMode reverseAddPath
3741
3742##
3743
3744# ------------------------------------------------------------------------------
3745
Cary Clark0251b1b2018-08-15 15:14:55 -04003746#Method SkPath& addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
Cary Clark09d80c02018-10-31 12:14:03 -04003747#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003748
Cary Clark73fa9722017-08-29 17:36:51 -04003749#Example
3750#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04003751 SkPaint paint;
3752 paint.setStyle(SkPaint::kStroke_Style);
3753 SkPath dest, path;
3754 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
3755 for (int i = 0; i < 6; i++) {
3756 SkMatrix matrix;
3757 matrix.reset();
3758 matrix.setPerspX(i / 400.f);
3759 dest.addPath(path, matrix);
3760 }
3761 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003762##
3763
Cary Clark4855f782018-02-06 09:41:53 -05003764#SeeAlso AddPathMode transform offset reverseAddPath
Cary Clark73fa9722017-08-29 17:36:51 -04003765
3766##
3767
3768# ------------------------------------------------------------------------------
3769
Cary Clark0251b1b2018-08-15 15:14:55 -04003770#Method SkPath& reverseAddPath(const SkPath& src)
Cary Clark4855f782018-02-06 09:41:53 -05003771#In Build
Cary Clarkab2621d2018-01-30 10:08:57 -05003772#Line # adds contents of Path back to front ##
Cary Clark09d80c02018-10-31 12:14:03 -04003773#Populate
Cary Clark0251b1b2018-08-15 15:14:55 -04003774
Cary Clark73fa9722017-08-29 17:36:51 -04003775#Example
3776#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04003777 SkPath path;
3778 path.moveTo(20, 20);
3779 path.lineTo(20, 40);
3780 path.lineTo(40, 20);
3781 SkPaint paint;
3782 paint.setStyle(SkPaint::kStroke_Style);
3783 for (int i = 0; i < 2; i++) {
3784 SkPath path2;
3785 path2.moveTo(60, 60);
3786 path2.lineTo(80, 60);
3787 path2.lineTo(80, 40);
3788 for (int j = 0; j < 2; j++) {
3789 SkPath test(path);
3790 test.reverseAddPath(path2);
3791 canvas->drawPath(test, paint);
3792 canvas->translate(100, 0);
3793 path2.close();
3794 }
3795 canvas->translate(-200, 100);
3796 path.close();
3797 }
Cary Clark73fa9722017-08-29 17:36:51 -04003798##
3799
Cary Clark4855f782018-02-06 09:41:53 -05003800#SeeAlso AddPathMode transform offset addPath
Cary Clark73fa9722017-08-29 17:36:51 -04003801
3802##
3803
3804# ------------------------------------------------------------------------------
3805
3806#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05003807#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05003808#Line # translates Point_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04003809#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003810
3811#Example
3812#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04003813 SkPath pattern;
3814 pattern.moveTo(20, 20);
3815 pattern.lineTo(20, 40);
3816 pattern.lineTo(40, 20);
3817 SkPaint paint;
3818 paint.setStyle(SkPaint::kStroke_Style);
3819 for (int i = 0; i < 10; i++) {
3820 SkPath path;
3821 pattern.offset(20 * i, 0, &path);
3822 canvas->drawPath(path, paint);
3823 }
Cary Clark73fa9722017-08-29 17:36:51 -04003824##
3825
3826#SeeAlso addPath transform
3827
3828##
3829
3830# ------------------------------------------------------------------------------
Cary Clark4855f782018-02-06 09:41:53 -05003831#Subtopic Transform
Cary Clark4855f782018-02-06 09:41:53 -05003832#Line # modify all points ##
3833##
Cary Clark73fa9722017-08-29 17:36:51 -04003834
Cary Clark682c58d2018-05-16 07:07:07 -04003835#Method void offset(SkScalar dx, SkScalar dy)
Cary Clark4855f782018-02-06 09:41:53 -05003836#In Transform
Cary Clark09d80c02018-10-31 12:14:03 -04003837#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003838
3839#Example
3840#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04003841 SkPath path;
3842 path.moveTo(20, 20);
3843 path.lineTo(20, 40);
3844 path.lineTo(40, 20);
3845 SkPaint paint;
3846 paint.setStyle(SkPaint::kStroke_Style);
3847 for (int i = 0; i < 10; i++) {
3848 canvas->drawPath(path, paint);
3849 path.offset(20, 0);
3850 }
Cary Clark73fa9722017-08-29 17:36:51 -04003851##
3852
3853#SeeAlso addPath transform SkCanvas::translate()
3854
3855##
3856
3857# ------------------------------------------------------------------------------
3858
3859#Method void transform(const SkMatrix& matrix, SkPath* dst) const
Cary Clark4855f782018-02-06 09:41:53 -05003860#In Transform
Cary Clarkab2621d2018-01-30 10:08:57 -05003861#Line # applies Matrix to Point_Array and Weights ##
Cary Clark09d80c02018-10-31 12:14:03 -04003862#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003863
3864#Example
Cary Clark8032b982017-07-28 11:04:54 -04003865#Height 200
3866 SkPath pattern;
3867 pattern.moveTo(100, 100);
3868 pattern.lineTo(100, 20);
3869 pattern.lineTo(20, 100);
3870 SkPaint paint;
3871 paint.setStyle(SkPaint::kStroke_Style);
3872 for (int i = 0; i < 10; i++) {
3873 SkPath path;
3874 SkMatrix matrix;
3875 matrix.setRotate(36 * i, 100, 100);
3876 pattern.transform(matrix, &path);
3877 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003878 }
3879##
3880
3881#SeeAlso addPath offset SkCanvas::concat() SkMatrix
3882
3883##
3884
3885# ------------------------------------------------------------------------------
3886
Cary Clark682c58d2018-05-16 07:07:07 -04003887#Method void transform(const SkMatrix& matrix)
Cary Clark09d80c02018-10-31 12:14:03 -04003888#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003889
3890#Example
Cary Clark8032b982017-07-28 11:04:54 -04003891#Height 200
3892 SkPath path;
3893 path.moveTo(100, 100);
3894 path.quadTo(100, 20, 20, 100);
3895 SkPaint paint;
3896 paint.setStyle(SkPaint::kStroke_Style);
3897 for (int i = 0; i < 10; i++) {
3898 SkMatrix matrix;
3899 matrix.setRotate(36, 100, 100);
3900 path.transform(matrix);
3901 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003902 }
3903##
3904
3905#SeeAlso addPath offset SkCanvas::concat() SkMatrix
3906
3907##
3908
3909# ------------------------------------------------------------------------------
3910
Cary Clark8032b982017-07-28 11:04:54 -04003911#Subtopic Last_Point
Cary Clark08895c42018-02-01 09:37:32 -05003912#Line # final Point in Contour ##
Cary Clark8032b982017-07-28 11:04:54 -04003913
3914Path is defined cumulatively, often by adding a segment to the end of last
3915Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
3916Last_Point can be read and written directly with getLastPt and setLastPt.
3917
Cary Clark73fa9722017-08-29 17:36:51 -04003918#Method bool getLastPt(SkPoint* lastPt) const
Cary Clark4855f782018-02-06 09:41:53 -05003919#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05003920#In Last_Point
3921#Line # returns Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04003922#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003923
Cary Clark09d80c02018-10-31 12:14:03 -04003924#Example
Cary Clark8032b982017-07-28 11:04:54 -04003925 SkPath path;
3926 path.moveTo(100, 100);
3927 path.quadTo(100, 20, 20, 100);
3928 SkMatrix matrix;
3929 matrix.setRotate(36, 100, 100);
3930 path.transform(matrix);
3931 SkPoint last;
3932 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04003933 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
3934 #StdOut
3935 last point: 35.2786, 52.9772
Cary Clark682c58d2018-05-16 07:07:07 -04003936 ##
Cary Clark73fa9722017-08-29 17:36:51 -04003937 ##
3938
3939 #SeeAlso setLastPt
3940
3941##
3942
3943#Method void setLastPt(SkScalar x, SkScalar y)
Cary Clark4855f782018-02-06 09:41:53 -05003944#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05003945#In Last_Point
3946#Line # replaces Last_Point ##
Cary Clark09d80c02018-10-31 12:14:03 -04003947#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003948
Cary Clark09d80c02018-10-31 12:14:03 -04003949#Example
Cary Clark73fa9722017-08-29 17:36:51 -04003950 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04003951 SkPaint paint;
3952 paint.setTextSize(128);
3953 SkPath path;
3954 paint.getTextPath("@", 1, 60, 100, &path);
3955 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04003956 canvas->drawPath(path, paint);
3957 ##
3958
3959 #SeeAlso getLastPt
3960
3961##
3962
Cary Clark682c58d2018-05-16 07:07:07 -04003963#Method void setLastPt(const SkPoint& p)
Cary Clark09d80c02018-10-31 12:14:03 -04003964#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04003965
Cary Clark09d80c02018-10-31 12:14:03 -04003966#Example
Cary Clark73fa9722017-08-29 17:36:51 -04003967 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04003968 SkPaint paint;
3969 paint.setTextSize(128);
3970 SkPath path, path2;
3971 paint.getTextPath("A", 1, 60, 100, &path);
3972 paint.getTextPath("Z", 1, 60, 100, &path2);
3973 SkPoint pt, pt2;
3974 path.getLastPt(&pt);
3975 path2.getLastPt(&pt2);
3976 path.setLastPt(pt2);
3977 path2.setLastPt(pt);
3978 canvas->drawPath(path, paint);
3979 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04003980 ##
3981
3982 #SeeAlso getLastPt
3983
3984##
3985
3986#Subtopic Last_Point ##
3987
3988# ------------------------------------------------------------------------------
3989
3990#Enum SegmentMask
Cary Clark08895c42018-02-01 09:37:32 -05003991#Line # returns Verb types in Path ##
Cary Clark73fa9722017-08-29 17:36:51 -04003992
3993#Code
3994 enum SegmentMask {
3995 kLine_SegmentMask = 1 << 0,
3996 kQuad_SegmentMask = 1 << 1,
3997 kConic_SegmentMask = 1 << 2,
3998 kCubic_SegmentMask = 1 << 3,
3999 };
4000##
4001
4002SegmentMask constants correspond to each drawing Verb type in Path; for
4003instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4004
Cary Clark4855f782018-02-06 09:41:53 -05004005#Bug 6785
Cary Clark73fa9722017-08-29 17:36:51 -04004006#Const kLine_SegmentMask 1
Cary Clark682c58d2018-05-16 07:07:07 -04004007#Line # contains one or more Lines ##
Cary Clark73fa9722017-08-29 17:36:51 -04004008Set if Verb_Array contains kLine_Verb.
4009##
4010#Const kQuad_SegmentMask 2
Cary Clark682c58d2018-05-16 07:07:07 -04004011#Line # contains one or more Quads ##
Cary Clark73fa9722017-08-29 17:36:51 -04004012Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4013##
4014#Const kConic_SegmentMask 4
Cary Clark682c58d2018-05-16 07:07:07 -04004015#Line # contains one or more Conics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004016Set if Verb_Array contains kConic_Verb.
4017##
4018#Const kCubic_SegmentMask 8
Cary Clark682c58d2018-05-16 07:07:07 -04004019#Line # contains one or more Cubics ##
Cary Clark73fa9722017-08-29 17:36:51 -04004020Set if Verb_Array contains kCubic_Verb.
4021##
4022
4023#Example
4024#Description
4025When conicTo has a weight of one, Quad is added to Path.
4026##
4027 SkPath path;
4028 path.conicTo(10, 10, 20, 30, 1);
Cary Clark682c58d2018-05-16 07:07:07 -04004029 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004030 SkPath::kConic_SegmentMask ? "set" : "clear");
Cary Clark682c58d2018-05-16 07:07:07 -04004031 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
Cary Clark73fa9722017-08-29 17:36:51 -04004032 SkPath::kQuad_SegmentMask ? "set" : "clear");
4033#StdOut
4034Path kConic_SegmentMask is clear
4035Path kQuad_SegmentMask is set
4036##
4037##
4038
4039#SeeAlso getSegmentMasks Verb
4040
4041##
4042
4043# ------------------------------------------------------------------------------
4044
Cary Clark682c58d2018-05-16 07:07:07 -04004045#Method uint32_t getSegmentMasks() const
Cary Clark4855f782018-02-06 09:41:53 -05004046#In Utility
4047#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004048#Line # returns types in Verb_Array ##
Cary Clark09d80c02018-10-31 12:14:03 -04004049#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004050
4051#Example
4052SkPath path;
4053path.quadTo(20, 30, 40, 50);
4054path.close();
4055const char* masks[] = { "line", "quad", "conic", "cubic" };
4056int index = 0;
4057for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4058 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4059 if (mask & path.getSegmentMasks()) {
4060 SkDebugf("mask %s set\n", masks[index]);
Cary Clark682c58d2018-05-16 07:07:07 -04004061 }
Cary Clark73fa9722017-08-29 17:36:51 -04004062 ++index;
4063}
4064#StdOut
4065mask quad set
4066##
4067##
4068
4069#SeeAlso getSegmentMasks Verb
4070
4071##
4072
4073# ------------------------------------------------------------------------------
4074
4075#Method bool contains(SkScalar x, SkScalar y) const
Cary Clark4855f782018-02-06 09:41:53 -05004076#In Property
Cary Clarkab2621d2018-01-30 10:08:57 -05004077#Line # returns if Point is in fill area ##
Cary Clark73fa9722017-08-29 17:36:51 -04004078Returns true if the point (x, y) is contained by Path, taking into
Cary Clark682c58d2018-05-16 07:07:07 -04004079account FillType.
Cary Clark73fa9722017-08-29 17:36:51 -04004080
4081#Table
4082#Legend
4083# FillType # contains() returns true if Point is enclosed by ##
4084##
4085# kWinding_FillType # a non-zero sum of Contour Directions. ##
4086# kEvenOdd_FillType # an odd number of Contours. ##
4087# kInverseWinding_FillType # a zero sum of Contour Directions. ##
4088# kInverseEvenOdd_FillType # and even number of Contours. ##
Cary Clark682c58d2018-05-16 07:07:07 -04004089##
Cary Clark73fa9722017-08-29 17:36:51 -04004090
Cary Clark5538c132018-06-14 12:28:14 -04004091#Param x x-axis value of containment test ##
4092#Param y y-axis value of containment test ##
Cary Clark73fa9722017-08-29 17:36:51 -04004093
4094#Return true if Point is in Path ##
4095
4096#Example
4097SkPath path;
4098SkPaint paint;
4099paint.setTextSize(256);
4100paint.getTextPath("&", 1, 30, 220, &path);
4101for (int y = 2; y < 256; y += 9) {
4102 for (int x = 2; x < 256; x += 9) {
4103 int coverage = 0;
4104 for (int iy = -4; iy <= 4; iy += 2) {
4105 for (int ix = -4; ix <= 4; ix += 2) {
4106 coverage += path.contains(x + ix, y + iy);
4107 }
4108 }
4109 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
4110 canvas->drawCircle(x, y, 8, paint);
4111 }
4112}
4113##
4114
4115#SeeAlso conservativelyContainsRect Fill_Type Op
4116
4117##
4118
4119# ------------------------------------------------------------------------------
4120
4121#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
Cary Clark4855f782018-02-06 09:41:53 -05004122#In Utility
Cary Clark53498e92018-06-28 19:13:56 -04004123#Line # sends text representation to stream ##
Cary Clark09d80c02018-10-31 12:14:03 -04004124#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004125
4126#Example
4127 SkPath path;
4128 path.quadTo(20, 30, 40, 50);
4129 for (bool forceClose : { false, true } ) {
4130 for (bool dumpAsHex : { false, true } ) {
4131 path.dump(nullptr, forceClose, dumpAsHex);
4132 SkDebugf("\n");
4133 }
4134 }
4135#StdOut
4136path.setFillType(SkPath::kWinding_FillType);
4137path.moveTo(0, 0);
4138path.quadTo(20, 30, 40, 50);
4139
4140path.setFillType(SkPath::kWinding_FillType);
4141path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4142path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
4143
4144path.setFillType(SkPath::kWinding_FillType);
4145path.moveTo(0, 0);
4146path.quadTo(20, 30, 40, 50);
4147path.lineTo(0, 0);
4148path.close();
4149
4150path.setFillType(SkPath::kWinding_FillType);
4151path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4152path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
4153path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4154path.close();
4155##
4156##
4157
Cary Clark53498e92018-06-28 19:13:56 -04004158#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
Cary Clark73fa9722017-08-29 17:36:51 -04004159
4160##
4161
4162# ------------------------------------------------------------------------------
4163
4164#Method void dump() const
Cary Clark09d80c02018-10-31 12:14:03 -04004165#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004166
4167#Example
4168SkPath path, copy;
4169path.lineTo(6.f / 7, 2.f / 3);
4170path.dump();
4171copy.setFillType(SkPath::kWinding_FillType);
4172copy.moveTo(0, 0);
4173copy.lineTo(0.857143f, 0.666667f);
4174SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4175#StdOut
4176path.setFillType(SkPath::kWinding_FillType);
4177path.moveTo(0, 0);
4178path.lineTo(0.857143f, 0.666667f);
4179path is not equal to copy
4180##
4181##
4182
4183#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
4184
4185##
4186
4187# ------------------------------------------------------------------------------
4188
4189#Method void dumpHex() const
Cary Clark4855f782018-02-06 09:41:53 -05004190#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004191#Line # sends text representation using hexadecimal to standard output ##
Cary Clarkce101242017-09-01 15:51:02 -04004192Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04004193directly compiled as C++ code. Floating point values are written
4194in hexadecimal to preserve their exact bit pattern. The output reconstructs the
4195original Path.
4196
Cary Clark682c58d2018-05-16 07:07:07 -04004197Use instead of dump() when submitting
4198#A bug reports against Skia # https://bug.skia.org ##
Cary Clark6fc50412017-09-21 12:31:06 -04004199.
Cary Clark73fa9722017-08-29 17:36:51 -04004200
4201#Example
4202SkPath path, copy;
4203path.lineTo(6.f / 7, 2.f / 3);
4204path.dumpHex();
4205copy.setFillType(SkPath::kWinding_FillType);
4206copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4207copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
4208SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4209#StdOut
4210path.setFillType(SkPath::kWinding_FillType);
4211path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
4212path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
4213path is equal to copy
4214##
4215##
4216
Cary Clark186d08f2018-04-03 08:43:27 -04004217#SeeAlso dump SkRect::dumpHex SkRRect::dumpHex writeToMemory
Cary Clark73fa9722017-08-29 17:36:51 -04004218
4219##
4220
4221# ------------------------------------------------------------------------------
4222
4223#Method size_t writeToMemory(void* buffer) const
Cary Clark4855f782018-02-06 09:41:53 -05004224#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004225#Line # copies data to buffer ##
Cary Clark09d80c02018-10-31 12:14:03 -04004226#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004227
4228#Example
4229void draw(SkCanvas* canvas) {
4230 SkPath path, copy;
4231 path.lineTo(6.f / 7, 2.f / 3);
4232 size_t size = path.writeToMemory(nullptr);
4233 SkTDArray<char> storage;
4234 storage.setCount(size);
4235 path.writeToMemory(storage.begin());
4236 copy.readFromMemory(storage.begin(), size);
4237 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4238}
4239#StdOut
4240path is equal to copy
4241##
4242##
4243
4244#SeeAlso serialize readFromMemory dump dumpHex
4245
4246##
4247
4248#Method sk_sp<SkData> serialize() const
Cary Clark4855f782018-02-06 09:41:53 -05004249#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004250#Line # copies data to buffer ##
Cary Clark09d80c02018-10-31 12:14:03 -04004251#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004252
4253#Example
4254void draw(SkCanvas* canvas) {
4255 SkPath path, copy;
4256 path.lineTo(6.f / 7, 2.f / 3);
4257 sk_sp<SkData> data = path.serialize();
4258 copy.readFromMemory(data->data(), data->size());
4259 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
4260}
4261#StdOut
4262path is equal to copy
4263##
4264##
4265
4266#SeeAlso writeToMemory readFromMemory dump dumpHex
4267##
4268
4269# ------------------------------------------------------------------------------
4270
4271#Method size_t readFromMemory(const void* buffer, size_t length)
Cary Clark4855f782018-02-06 09:41:53 -05004272#In Utility
Cary Clark682c58d2018-05-16 07:07:07 -04004273#Line # initializes from buffer ##
Cary Clark09d80c02018-10-31 12:14:03 -04004274#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004275
4276#Example
4277void draw(SkCanvas* canvas) {
4278 SkPath path, copy;
4279 path.lineTo(6.f / 7, 2.f / 3);
4280 size_t size = path.writeToMemory(nullptr);
4281 SkTDArray<char> storage;
4282 storage.setCount(size);
4283 path.writeToMemory(storage.begin());
4284 size_t wrongSize = size - 4;
4285 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
4286 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
4287 size_t largerSize = size + 4;
4288 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
4289 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
4290}
4291#StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04004292length = 32; returned by readFromMemory = 0
Cary Clark06c20f32018-03-20 15:53:27 -04004293length = 40; returned by readFromMemory = 36
Cary Clark73fa9722017-08-29 17:36:51 -04004294##
4295##
4296
4297#SeeAlso writeToMemory
4298
4299##
4300
4301# ------------------------------------------------------------------------------
Cary Clark78de7512018-02-07 07:27:09 -05004302#Subtopic Generation_ID
Cary Clark137b8742018-05-30 09:21:49 -04004303#Alias Generation_IDs ##
Cary Clark08895c42018-02-01 09:37:32 -05004304#Line # value reflecting contents change ##
Cary Clark73fa9722017-08-29 17:36:51 -04004305Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
4306Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
4307not necessarily have matching Generation_IDs.
4308
4309Empty Paths have a Generation_ID of one.
4310
4311#Method uint32_t getGenerationID() const
4312
Cary Clarkab2621d2018-01-30 10:08:57 -05004313#In Generation_ID
4314#Line # returns unique ID ##
Cary Clark09d80c02018-10-31 12:14:03 -04004315#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004316
4317#Example
4318SkPath path;
4319SkDebugf("empty genID = %u\n", path.getGenerationID());
4320path.lineTo(1, 2);
4321SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
4322path.rewind();
4323SkDebugf("empty genID = %u\n", path.getGenerationID());
4324path.lineTo(1, 2);
4325SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
4326#StdOut
4327empty genID = 1
43281st lineTo genID = 2
4329empty genID = 1
43302nd lineTo genID = 3
4331##
4332##
4333
4334#SeeAlso operator==(const SkPath& a, const SkPath& b)
4335
4336##
4337
Cary Clark78de7512018-02-07 07:27:09 -05004338#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -04004339
4340# ------------------------------------------------------------------------------
4341
4342#Method bool isValid() const
Cary Clark4855f782018-02-06 09:41:53 -05004343#In Property
4344#In Utility
Cary Clarkab2621d2018-01-30 10:08:57 -05004345#Line # returns if data is internally consistent ##
Cary Clark09d80c02018-10-31 12:14:03 -04004346#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004347
Cary Clark09d80c02018-10-31 12:14:03 -04004348#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004349 ##
4350
4351##
4352
Cary Clark73fa9722017-08-29 17:36:51 -04004353# ------------------------------------------------------------------------------
4354
Cary Clark8032b982017-07-28 11:04:54 -04004355#Class Iter
Cary Clark682c58d2018-05-16 07:07:07 -04004356#Line # data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04004357
Cary Clark73fa9722017-08-29 17:36:51 -04004358#Code
Cary Clark61313f32018-10-08 14:57:48 -04004359#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004360##
4361
Cary Clark137b8742018-05-30 09:21:49 -04004362Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
4363Provides options to treat open Contours as closed, and to ignore
4364degenerate data.
4365
Cary Clark8032b982017-07-28 11:04:54 -04004366#Example
4367#Height 128
4368#Description
Cary Clark73fa9722017-08-29 17:36:51 -04004369Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04004370path of the glyph.
4371##
Cary Clark73fa9722017-08-29 17:36:51 -04004372void draw(SkCanvas* canvas) {
4373 SkPaint paint;
4374 paint.setAntiAlias(true);
4375 paint.setTextSize(256);
4376 SkPath asterisk, path;
4377 paint.getTextPath("*", 1, 50, 192, &asterisk);
Cary Clark682c58d2018-05-16 07:07:07 -04004378 SkPath::Iter iter(asterisk, true);
Cary Clark73fa9722017-08-29 17:36:51 -04004379 SkPoint start[4], pts[4];
4380 iter.next(start); // skip moveTo
4381 iter.next(start); // first quadTo
4382 path.moveTo((start[0] + start[1]) * 0.5f);
4383 while (SkPath::kClose_Verb != iter.next(pts)) {
4384 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
4385 }
4386 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
4387 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04004388}
4389##
4390
4391#SeeAlso RawIter
4392
4393#Method Iter()
Cary Clark682c58d2018-05-16 07:07:07 -04004394#Line # constructs Path iterator ##
Cary Clark09d80c02018-10-31 12:14:03 -04004395#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004396
4397#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004398void draw(SkCanvas* canvas) {
4399 SkPath::Iter iter;
4400 SkPoint points[4];
4401 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
4402 SkPath path;
4403 iter.setPath(path, false);
4404 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04004405}
Cary Clark73fa9722017-08-29 17:36:51 -04004406#StdOut
4407iter is done
4408iter is done
4409##
Cary Clark8032b982017-07-28 11:04:54 -04004410##
4411
4412#SeeAlso setPath
4413
4414##
4415
4416#Method Iter(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004417#Line # constructs Path iterator ##
Cary Clark09d80c02018-10-31 12:14:03 -04004418#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004419
4420#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004421void draw(SkCanvas* canvas) {
4422 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
4423 SkDebugf("%s:\n", prefix);
4424 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4425 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4426 SkPath::Verb verb;
4427 do {
4428 SkPoint points[4];
4429 verb = iter.next(points);
4430 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4431 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4432 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
4433 }
4434 if (SkPath::kConic_Verb == verb) {
4435 SkDebugf("weight = %g", iter.conicWeight());
4436 }
4437 SkDebugf("\n");
4438 } while (SkPath::kDone_Verb != verb);
4439 SkDebugf("\n");
4440 };
4441
4442 SkPath path;
4443 path.quadTo(10, 20, 30, 40);
4444 SkPath::Iter openIter(path, false);
4445 debugster("open", openIter);
4446 SkPath::Iter closedIter(path, true);
4447 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04004448}
4449#StdOut
4450open:
Cary Clark682c58d2018-05-16 07:07:07 -04004451kMove_Verb {0, 0},
4452kQuad_Verb {0, 0}, {10, 20}, {30, 40},
4453kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004454
4455closed:
Cary Clark682c58d2018-05-16 07:07:07 -04004456kMove_Verb {0, 0},
4457kQuad_Verb {0, 0}, {10, 20}, {30, 40},
4458kLine_Verb {30, 40}, {0, 0},
4459kClose_Verb {0, 0},
4460kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004461##
4462##
4463
4464#SeeAlso setPath
4465
4466##
4467
4468#Method void setPath(const SkPath& path, bool forceClose)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004469#Line # resets Iter to Path ##
Cary Clark09d80c02018-10-31 12:14:03 -04004470#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004471
4472#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004473void draw(SkCanvas* canvas) {
4474 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
4475 SkDebugf("%s:\n", prefix);
4476 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4477 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4478 SkPath::Verb verb;
4479 do {
4480 SkPoint points[4];
4481 verb = iter.next(points);
4482 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4483 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4484 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
4485 }
4486 if (SkPath::kConic_Verb == verb) {
4487 SkDebugf("weight = %g", iter.conicWeight());
4488 }
4489 SkDebugf("\n");
4490 } while (SkPath::kDone_Verb != verb);
4491 SkDebugf("\n");
4492 };
4493
4494 SkPath path;
4495 path.quadTo(10, 20, 30, 40);
4496 SkPath::Iter iter(path, false);
4497 debugster("quad open", iter);
4498 SkPath path2;
4499 path2.conicTo(1, 2, 3, 4, .5f);
4500 iter.setPath(path2, true);
4501 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04004502}
4503#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004504quad open:
Cary Clark682c58d2018-05-16 07:07:07 -04004505kMove_Verb {0, 0},
4506kQuad_Verb {0, 0}, {10, 20}, {30, 40},
4507kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004508
4509conic closed:
Cary Clark682c58d2018-05-16 07:07:07 -04004510kMove_Verb {0, 0},
Cary Clark73fa9722017-08-29 17:36:51 -04004511kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04004512kLine_Verb {3, 4}, {0, 0},
4513kClose_Verb {0, 0},
4514kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004515##
4516##
4517
4518#SeeAlso Iter(const SkPath& path, bool forceClose)
4519
4520##
4521
Cary Clark682c58d2018-05-16 07:07:07 -04004522#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004523#Line # returns next Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004524#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004525
4526#Example
Cary Clark682c58d2018-05-16 07:07:07 -04004527#Description
Cary Clark8032b982017-07-28 11:04:54 -04004528skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
4529followed by the kClose_Verb, the zero length Line and the very small Line.
4530
4531skip degenerate if exact skips the same as skip degenerate, but shows
4532the very small Line.
4533
4534skip none shows all of the Verbs and Points in Path.
4535##
Cary Clark73fa9722017-08-29 17:36:51 -04004536void draw(SkCanvas* canvas) {
4537 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
4538 SkPath::Iter iter(path, false);
4539 SkDebugf("%s:\n", prefix);
4540 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4541 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4542 SkPath::Verb verb;
4543 do {
4544 SkPoint points[4];
4545 verb = iter.next(points, degen, exact);
4546 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4547 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4548 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
4549 }
4550 SkDebugf("\n");
4551 } while (SkPath::kDone_Verb != verb);
4552 SkDebugf("\n");
4553 };
4554
4555 SkPath path;
4556 path.moveTo(10, 10);
4557 path.moveTo(20, 20);
4558 path.quadTo(10, 20, 30, 40);
4559 path.moveTo(1, 1);
4560 path.close();
4561 path.moveTo(30, 30);
4562 path.lineTo(30, 30);
4563 path.moveTo(30, 30);
4564 path.lineTo(30.00001f, 30);
4565 debugster("skip degenerate", path, true, false);
4566 debugster("skip degenerate if exact", path, true, true);
4567 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04004568}
4569#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004570skip degenerate:
Cary Clark682c58d2018-05-16 07:07:07 -04004571kMove_Verb {20, 20},
4572kQuad_Verb {20, 20}, {10, 20}, {30, 40},
4573kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004574
4575skip degenerate if exact:
Cary Clark682c58d2018-05-16 07:07:07 -04004576kMove_Verb {20, 20},
4577kQuad_Verb {20, 20}, {10, 20}, {30, 40},
4578kMove_Verb {30, 30},
4579kLine_Verb {30, 30}, {30.00001, 30},
4580kDone_Verb
Cary Clark73fa9722017-08-29 17:36:51 -04004581
4582skip none:
Cary Clark682c58d2018-05-16 07:07:07 -04004583kMove_Verb {10, 10},
4584kMove_Verb {20, 20},
4585kQuad_Verb {20, 20}, {10, 20}, {30, 40},
4586kMove_Verb {1, 1},
4587kClose_Verb {1, 1},
4588kMove_Verb {30, 30},
4589kLine_Verb {30, 30}, {30, 30},
4590kMove_Verb {30, 30},
4591kLine_Verb {30, 30}, {30.00001, 30},
4592kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004593##
4594##
4595
Cary Clark682c58d2018-05-16 07:07:07 -04004596#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
Cary Clark8032b982017-07-28 11:04:54 -04004597
4598##
4599
4600#Method SkScalar conicWeight() const
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004601#Line # returns Conic_Weight ##
Cary Clark09d80c02018-10-31 12:14:03 -04004602#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004603
Cary Clark09d80c02018-10-31 12:14:03 -04004604#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004605 void draw(SkCanvas* canvas) {
4606 SkPath path;
4607 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04004608 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04004609 SkPoint p[4];
4610 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
4611 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
4612 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
4613 p[2].fX, p[2].fY);
4614 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04004615 }
4616 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004617first verb is move
4618next verb is conic
4619conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04004620conic weight: 0.5
4621 ##
4622 ##
4623
4624 #SeeAlso Conic_Weight
4625
4626##
4627
4628#Method bool isCloseLine() const
Cary Clark682c58d2018-05-16 07:07:07 -04004629#Line # returns if Line was generated by kClose_Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004630#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004631
Cary Clark09d80c02018-10-31 12:14:03 -04004632#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004633void draw(SkCanvas* canvas) {
4634 SkPath path;
4635 path.moveTo(6, 7);
4636 path.conicTo(1, 2, 3, 4, .5f);
4637 path.close();
Cary Clark682c58d2018-05-16 07:07:07 -04004638 SkPath::Iter iter(path, false);
Cary Clark73fa9722017-08-29 17:36:51 -04004639 SkPoint p[4];
4640 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
4641 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
4642 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
4643 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
4644 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
4645 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
4646 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04004647}
4648 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040046491st verb is move
4650moveTo point: {6,7}
46512nd verb is conic
46523rd verb is line
4653line points: {3,4}, {6,7}
4654line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040046554th verb is close
4656 ##
4657 ##
4658
4659 #SeeAlso close()
4660##
4661
4662#Method bool isClosedContour() const
Cary Clark682c58d2018-05-16 07:07:07 -04004663#Line # returns if Contour has kClose_Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004664#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004665
4666#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004667void draw(SkCanvas* canvas) {
4668 for (bool forceClose : { false, true } ) {
4669 SkPath path;
4670 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04004671 SkPath::Iter iter(path, forceClose);
Cary Clark73fa9722017-08-29 17:36:51 -04004672 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
4673 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
4674 path.close();
4675 iter.setPath(path, forceClose);
4676 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
4677 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
4678 }
Cary Clark8032b982017-07-28 11:04:54 -04004679}
4680#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004681without close(), forceClose is false: isClosedContour returns false
4682with close(), forceClose is false: isClosedContour returns true
4683without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04004684with close(), forceClose is true : isClosedContour returns true
4685##
4686##
4687
4688#SeeAlso Iter(const SkPath& path, bool forceClose)
4689
4690##
Cary Clark73fa9722017-08-29 17:36:51 -04004691
4692#Class Iter ##
4693
Cary Clark8032b982017-07-28 11:04:54 -04004694#Class RawIter
Cary Clark682c58d2018-05-16 07:07:07 -04004695#Line # raw data iterator ##
Cary Clark8032b982017-07-28 11:04:54 -04004696
Cary Clark73fa9722017-08-29 17:36:51 -04004697#Code
Cary Clark61313f32018-10-08 14:57:48 -04004698#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004699##
4700
Cary Clark137b8742018-05-30 09:21:49 -04004701Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
4702Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
4703
Cary Clark61313f32018-10-08 14:57:48 -04004704
Cary Clark8032b982017-07-28 11:04:54 -04004705 #Method RawIter()
Cary Clark682c58d2018-05-16 07:07:07 -04004706 #Line # constructs empty Path iterator ##
Cary Clark09d80c02018-10-31 12:14:03 -04004707#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004708
Cary Clark09d80c02018-10-31 12:14:03 -04004709#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004710 ##
4711 ##
Cary Clark8032b982017-07-28 11:04:54 -04004712
4713 #Method RawIter(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04004714 #Line # constructs with Path to iterate over ##
Cary Clark09d80c02018-10-31 12:14:03 -04004715#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004716
Cary Clark09d80c02018-10-31 12:14:03 -04004717#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004718 ##
4719 ##
Cary Clark8032b982017-07-28 11:04:54 -04004720
4721 #Method void setPath(const SkPath& path)
Cary Clark682c58d2018-05-16 07:07:07 -04004722 #Line # sets Path to iterate over ##
Cary Clark09d80c02018-10-31 12:14:03 -04004723#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004724
Cary Clark09d80c02018-10-31 12:14:03 -04004725#NoExample
Cary Clark73fa9722017-08-29 17:36:51 -04004726 ##
4727 ##
Cary Clark8032b982017-07-28 11:04:54 -04004728
4729 #Method Verb next(SkPoint pts[4])
Cary Clark682c58d2018-05-16 07:07:07 -04004730 #Line # returns next Verb and associated Points ##
Cary Clark09d80c02018-10-31 12:14:03 -04004731#Populate
Cary Clark8032b982017-07-28 11:04:54 -04004732
Cary Clark09d80c02018-10-31 12:14:03 -04004733#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004734 void draw(SkCanvas* canvas) {
4735 SkPath path;
4736 path.moveTo(50, 60);
4737 path.quadTo(10, 20, 30, 40);
4738 path.close();
4739 path.lineTo(30, 30);
4740 path.conicTo(1, 2, 3, 4, .5f);
4741 path.cubicTo(-1, -2, -3, -4, -5, -6);
4742 SkPath::RawIter iter(path);
4743 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4744 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
4745 SkPath::Verb verb;
4746 do {
4747 SkPoint points[4];
4748 verb = iter.next(points);
4749 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
4750 for (int i = 0; i < pointCount[(int) verb]; ++i) {
4751 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
4752 }
4753 if (SkPath::kConic_Verb == verb) {
4754 SkDebugf("weight = %g", iter.conicWeight());
4755 }
4756 SkDebugf("\n");
4757 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04004758 }
4759 #StdOut
Cary Clark682c58d2018-05-16 07:07:07 -04004760 kMove_Verb {50, 60},
4761 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
4762 kClose_Verb {50, 60},
4763 kMove_Verb {50, 60},
4764 kLine_Verb {50, 60}, {30, 30},
Cary Clark73fa9722017-08-29 17:36:51 -04004765 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
Cary Clark682c58d2018-05-16 07:07:07 -04004766 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
4767 kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04004768 ##
4769 ##
4770
4771 #SeeAlso peek()
4772
Cary Clark73fa9722017-08-29 17:36:51 -04004773 ##
Cary Clark8032b982017-07-28 11:04:54 -04004774
4775 #Method Verb peek() const
Cary Clark682c58d2018-05-16 07:07:07 -04004776 #Line # returns next Verb ##
Cary Clark09d80c02018-10-31 12:14:03 -04004777 #Populate
Cary Clark8032b982017-07-28 11:04:54 -04004778
4779 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04004780 SkPath path;
4781 path.quadTo(10, 20, 30, 40);
4782 path.conicTo(1, 2, 3, 4, .5f);
4783 path.cubicTo(1, 2, 3, 4, .5, 6);
4784 SkPath::RawIter iter(path);
4785 SkPath::Verb verb, peek = iter.peek();
4786 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
4787 do {
4788 SkPoint points[4];
4789 verb = iter.next(points);
4790 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
4791 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04004792 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04004793 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
4794 #StdOut
4795 #Volatile
4796 peek Move == verb Move
4797 peek Quad == verb Quad
4798 peek Conic == verb Conic
4799 peek Cubic == verb Cubic
4800 peek Done == verb Done
4801 peek Done == verb Done
4802 ##
Cary Clark8032b982017-07-28 11:04:54 -04004803 ##
4804
4805 #Bug 6832
Cary Clark09d80c02018-10-31 12:14:03 -04004806 # StdOut is not really volatile, it just produces the wrong result.
4807 # A simple fix changes the output of hairlines and needs to be
4808 # investigated to see if the change is correct or not.
4809 # see change 21340 (abandoned for now)
Cary Clark8032b982017-07-28 11:04:54 -04004810
Cary Clarkd2ca79c2018-08-10 13:09:13 -04004811 #SeeAlso next
Cary Clark8032b982017-07-28 11:04:54 -04004812
Cary Clark73fa9722017-08-29 17:36:51 -04004813 ##
Cary Clark8032b982017-07-28 11:04:54 -04004814
Cary Clark73fa9722017-08-29 17:36:51 -04004815 #Method SkScalar conicWeight() const
Cary Clark682c58d2018-05-16 07:07:07 -04004816 #Line # returns Conic_Weight ##
Cary Clark09d80c02018-10-31 12:14:03 -04004817#Populate
Cary Clark73fa9722017-08-29 17:36:51 -04004818
Cary Clark09d80c02018-10-31 12:14:03 -04004819#Example
Cary Clark73fa9722017-08-29 17:36:51 -04004820 void draw(SkCanvas* canvas) {
4821 SkPath path;
4822 path.conicTo(1, 2, 3, 4, .5f);
Cary Clark682c58d2018-05-16 07:07:07 -04004823 SkPath::RawIter iter(path);
Cary Clark73fa9722017-08-29 17:36:51 -04004824 SkPoint p[4];
4825 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
4826 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
4827 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
4828 p[2].fX, p[2].fY);
4829 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04004830 }
4831 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04004832 first verb is move
4833 next verb is conic
4834 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04004835 conic weight: 0.5
4836 ##
4837 ##
4838
4839 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04004840
4841 ##
4842
4843#Class RawIter ##
4844
4845#Class SkPath ##
4846
4847#Topic Path ##