blob: e38b30da7719d5d04047a20d062bca08c92cab25 [file] [log] [blame]
Cary Clark73fa9722017-08-29 17:36:51 -04001#Topic Path
2#Alias Path_Reference
3#Alias Paths
4
5Path contains Lines and Curves which can be stroked or filled. Contour is
6composed of a series of connected Lines and Curves. Path may contain zero,
7one, or more Contours.
8Each Line and Curve are described by Verb, Points, and optional Conic_Weight.
9
10Each pair of connected Lines and Curves share common Point; for instance, Path
11containing two connected Lines are described the Verb sequence:
12SkPath::kMove_Verb, SkPath::kLine_Verb, SkPath::kLine_Verb; and a Point sequence
13with three entries, sharing
14the middle entry as the end of the first Line and the start of the second Line.
15
16Path components Arc, Rect, Round_Rect, Circle, and Oval are composed of
17Lines and Curves with as many Verbs and Points required
18for an exact description. Once added to Path, these components may lose their
Cary Clarkce101242017-09-01 15:51:02 -040019identity; although Path can be inspected to determine if it describes a single
Cary Clark73fa9722017-08-29 17:36:51 -040020Rect, Oval, Round_Rect, and so on.
21
22#Example
23#Height 192
24#Description
25Path contains three Contours: Line, Circle, and Quad. Line is stroked but
26not filled. Circle is stroked and filled; Circle stroke forms a loop. Quad
27is stroked and filled, but since it is not closed, Quad does not stroke a loop.
28##
29void draw(SkCanvas* canvas) {
30 SkPaint paint;
31 paint.setAntiAlias(true);
32 SkPath path;
33 path.moveTo(124, 108);
34 path.lineTo(172, 24);
35 path.addCircle(50, 50, 30);
36 path.moveTo(36, 148);
37 path.quadTo(66, 188, 120, 136);
38 canvas->drawPath(path, paint);
39 paint.setStyle(SkPaint::kStroke_Style);
40 paint.setColor(SK_ColorBLUE);
41 paint.setStrokeWidth(3);
42 canvas->drawPath(path, paint);
43}
44##
45
46Path contains a Fill_Type which determines whether overlapping Contours
47form fills or holes. Fill_Type also determines whether area inside or outside
48Lines and Curves is filled.
49
50#Example
51#Height 192
52#Description
53Path is drawn filled, then stroked, then stroked and filled.
54##
55void draw(SkCanvas* canvas) {
56 SkPaint paint;
57 paint.setAntiAlias(true);
58 SkPath path;
59 path.moveTo(36, 48);
60 path.quadTo(66, 88, 120, 36);
61 canvas->drawPath(path, paint);
62 paint.setStyle(SkPaint::kStroke_Style);
63 paint.setColor(SK_ColorBLUE);
64 paint.setStrokeWidth(8);
65 canvas->translate(0, 50);
66 canvas->drawPath(path, paint);
67 paint.setStyle(SkPaint::kStrokeAndFill_Style);
68 paint.setColor(SK_ColorRED);
69 canvas->translate(0, 50);
70 canvas->drawPath(path, paint);
71}
72##
73
74Path contents are never shared. Copying Path by value effectively creates
75a new Path independent of the original. Internally, the copy does not duplicate
76its contents until it is edited, to reduce memory use and improve performance.
77
Cary Clark8032b982017-07-28 11:04:54 -040078#Subtopic Subtopics
79#ToDo not all methods are in topics ##
80#ToDo subtopics are not in topics ##
81#Table
82#Legend
83# topics # description ##
84#Legend ##
85#Table ##
86# Contour # A loop of lines and curves. ##
87# Convexity # Whether Path contains simple loop. ##
88# Last_Point # Final Point in Contour. ##
89# Point_Array # All Points in Path. ##
90# Verb # How Points and Contours are defined. ##
91# Verb_Array # All Verbs in Path. ##
92# Verb # How Points and Contours are defined. ##
Cary Clark73fa9722017-08-29 17:36:51 -040093# Conic_Weight # Strength of control Point in Conic. ##
Cary Clark8032b982017-07-28 11:04:54 -040094#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -040095
96
Cary Clark8032b982017-07-28 11:04:54 -040097#Subtopic Contour
98#Alias Contours
99Contour contains one or more Verbs, and as many Points as
100are required to satisfy Verb_Array. First Verb in Path is always
101SkPath::kMove_Verb; each SkPath::kMove_Verb that follows starts a new Contour.
102
103#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400104#Description
105Each SkPath::moveTo starts a new Contour, and content after SkPath::close()
Cary Clarkce101242017-09-01 15:51:02 -0400106also starts a new Contour. Since SkPath::conicTo is not preceded by
Cary Clark73fa9722017-08-29 17:36:51 -0400107SkPath::moveTo, the first Point of the third Contour starts at the last Point
108of the second Contour.
109##
110#Height 192
111 SkPaint paint;
112 paint.setAntiAlias(true);
113 canvas->drawString("1st contour", 150, 100, paint);
114 canvas->drawString("2nd contour", 130, 160, paint);
115 canvas->drawString("3rd contour", 40, 30, paint);
116 paint.setStyle(SkPaint::kStroke_Style);
117 SkPath path;
118 path.moveTo(124, 108);
119 path.lineTo(172, 24);
120 path.moveTo(36, 148);
121 path.quadTo(66, 188, 120, 136);
122 path.close();
123 path.conicTo(70, 20, 110, 40, 0.6f);
124 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -0400125##
126
127If final Verb in Contour is SkPath::kClose_Verb, Line connects Last_Point in
128Contour with first Point. A closed Contour, stroked, draws
129Paint_Stroke_Join at Last_Point and first Point. Without SkPath::kClose_Verb
130as final Verb, Last_Point and first Point are not connected; Contour
131remains open. An open Contour, stroked, draws Paint_Stroke_Cap at
132Last_Point and first Point.
133
134#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400135#Height 160
136#Description
137Path is drawn stroked, with an open Contour and a closed Contour.
138##
139void draw(SkCanvas* canvas) {
140 SkPaint paint;
141 paint.setAntiAlias(true);
142 paint.setStyle(SkPaint::kStroke_Style);
143 paint.setStrokeWidth(8);
144 SkPath path;
145 path.moveTo(36, 48);
146 path.quadTo(66, 88, 120, 36);
147 canvas->drawPath(path, paint);
148 path.close();
149 canvas->translate(0, 50);
150 canvas->drawPath(path, paint);
151}
Cary Clark8032b982017-07-28 11:04:54 -0400152##
153
154#Subtopic Zero_Length
155#Alias Zero_Length_Contour
156Contour length is distance traveled from first Point to Last_Point,
157plus, if Contour is closed, distance from Last_Point to first Point.
158Even if Contour length is zero, stroked Lines are drawn if Paint_Stroke_Cap
159makes them visible.
160
161#Example
Cary Clark73fa9722017-08-29 17:36:51 -0400162#Height 64
163 SkPaint paint;
164 paint.setAntiAlias(true);
165 paint.setStyle(SkPaint::kStroke_Style);
166 paint.setStrokeWidth(8);
167 paint.setStrokeCap(SkPaint::kRound_Cap);
168 SkPath path;
169 path.moveTo(36, 48);
170 path.lineTo(36, 48);
171 canvas->drawPath(path, paint);
172 path.reset();
173 paint.setStrokeCap(SkPaint::kSquare_Cap);
174 path.moveTo(56, 48);
175 path.close();
Cary Clark8032b982017-07-28 11:04:54 -0400176 canvas->drawPath(path, paint);
177##
178
179#Subtopic Zero_Length ##
180
181#Subtopic Contour ##
Cary Clark73fa9722017-08-29 17:36:51 -0400182
183# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400184
Cary Clark73fa9722017-08-29 17:36:51 -0400185#Class SkPath
186
187Paths contain geometry. Paths may be empty, or contain one or more Verbs that
188outline a figure. Path always starts with a move verb to a Cartesian
189coordinate, and may be followed by additional verbs that add lines or curves.
190Adding a close verb makes the geometry into a continuous loop, a closed contour.
Cary Clarkce101242017-09-01 15:51:02 -0400191Paths may contain any number of contours, each beginning with a move verb.
Cary Clark73fa9722017-08-29 17:36:51 -0400192
193Path contours may contain only a move verb, or may also contain lines,
Cary Clarkce101242017-09-01 15:51:02 -0400194Quadratic_Beziers, Conics, and Cubic_Beziers. Path contours may be open or
Cary Clark73fa9722017-08-29 17:36:51 -0400195closed.
196
197When used to draw a filled area, Path describes whether the fill is inside or
198outside the geometry. Path also describes the winding rule used to fill
199overlapping contours.
200
201Internally, Path lazily computes metrics likes bounds and convexity. Call
202SkPath::updateBoundsCache to make Path thread safe.
203
204#Topic Overview
205
Cary Clark8032b982017-07-28 11:04:54 -0400206#Subtopic Constants
207#ToDo incomplete ##
208#Table
209#Legend
210# constants # description ##
211#Legend ##
212# AddPathMode # Sets addPath options. ##
Cary Clarkce101242017-09-01 15:51:02 -0400213# ArcSize # Used by arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, SkScalar x, SkScalar y).##
Cary Clark8032b982017-07-28 11:04:54 -0400214# Convexity # Returns if Path is convex or concave. ##
215# Direction # Sets Contour clockwise or counterclockwise. ##
216# FillType # Sets winding rule and inverse fill. ##
217# SegmentMask
218# Verb # Controls how Path Points are interpreted. ##
219#Table ##
220#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -0400221
Cary Clark8032b982017-07-28 11:04:54 -0400222#Subtopic Classes_and_Structs
223#Table
224#Legend
225# class or struct # description ##
226#Legend ##
227# Iter # Iterates through lines and curves, skipping degenerates. ##
228# RawIter # Iterates through lines and curves, including degenerates. ##
229#Table ##
230#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -0400231
Cary Clark8032b982017-07-28 11:04:54 -0400232#Subtopic Constructors
233#Table
234#Legend
235# # description ##
236#Legend ##
237# SkPath() # Constructs with default values. ##
238# SkPath(const SkPath& path) # Makes a shallow copy. ##
239# ~SkPath() # Decreases Reference_Count of owned objects. ##
240#Table ##
241#Subtopic ##
242
243#Subtopic Operators
244#Table
245#Legend
246# operator # description ##
247#Legend ##
248# operator=(const SkPath& path) # Makes a shallow copy. ##
249# operator==(const SkPath& a, const SkPath& b) # Compares paths for equality. ##
250# operator!=(const SkPath& a, const SkPath& b) # Compares paths for inequality. ##
251#Table ##
252#Subtopic ##
Cary Clark73fa9722017-08-29 17:36:51 -0400253
254#Subtopic Member_Functions
255#Table
256#Legend
257# function # description ##
258#Legend ##
259# ConvertConicToQuads # Approximates Conic with Quad array. ##
260# ConvertToNonInverseFillType # Returns Fill_Type representing inside geometry. ##
261# IsCubicDegenerate # Returns if Cubic is very small. ##
262# IsInverseFillType # Returns if Fill_Type represents outside geometry. ##
263# IsLineDegenerate # Returns if Line is very small. ##
264# IsQuadDegenerate # Returns if Quad is very small. ##
265# addArc # Adds one Contour containing Arc. ##
266# addCircle # Adds one Contour containing Circle. ##
267# addOval # Adds one Contour containing Oval. ##
268# addPath # Adds contents of Path. ##
269# addPoly # Adds one Contour containing connected lines. ##
270# addRRect # Adds one Contour containing Round_Rect. ##
271# addRect # Adds one Contour containing Rect. ##
272# addRoundRect # Adds one Contour containing Round_Rect with common corner radii. ##
273# arcTo # Appends Arc. ##
274# close() # Makes last Contour a loop. ##
275# computeTightBounds # Returns extent of geometry. ##
276# conicTo # Appends Conic. ##
277# conservativelyContainsRect # Returns true if Rect may be inside. ##
278# contains() # Returns if Point is in fill area. ##
279# countPoints # Returns Point_Array length. ##
280# countVerbs # Returns Verb_Array length. ##
281# cubicTo # Appends Cubic. ##
Cary Clarkce101242017-09-01 15:51:02 -0400282# dump() # Sends text representation using floats to standard output. ##
283# dumpHex # Sends text representation using hexadecimal to standard output. ##
Cary Clark73fa9722017-08-29 17:36:51 -0400284# getBounds # Returns maximum and minimum of Point_Array. ##
285# getConvexity # Returns geometry convexity, computing if necessary. ##
286# getConvexityOrUnknown # Returns geometry convexity if known. ##
287# getFillType # Returns Fill_Type: winding, even-odd, inverse. ##
288# getGenerationID # Returns unique ID. ##
289# getLastPt # Returns Last_Point. ##
290# getPoint # Returns entry from Point_Array. ##
291# getPoints # Returns Point_Array. ##
292# getSegmentMasks # Returns types in Verb_Array. ##
293# getVerbs # Returns Verb_Array. ##
294# incReserve # Hint to reserve space for additional data. ##
295# interpolate() # Interpolates between Path pair. ##
296# isConvex # Returns if geometry is convex. ##
297# isEmpty # Returns if verb count is zero. ##
298# isFinite # Returns if all Point values are finite. ##
299# isInterpolatable # Returns if pair contains equal counts of Verb_Array and Weights. ##
300# isInverseFillType # Returns if Fill_Type fills outside geometry. ##
301# isLastContourClosed # Returns if final Contour forms a loop. ##
302# isLine # Returns if describes Line. ##
303# isNestedFillRects # Returns if describes Rect pair, one inside the other. ##
304# isOval # Returns if describes Oval. ##
305# isRRect # Returns if describes Round_Rect. ##
306# isRect # Returns if describes Rect. ##
307# isValid # Returns if data is internally consistent. ##
308# isVolatile # Returns if Device should not cache. ##
309# lineTo # Appends Line. ##
310# moveTo # Starts Contour. ##
311# offset() # Translates Point_Array. ##
312# quadTo # Appends Quad. ##
313# rArcTo # Appends Arc relative to Last_Point. ##
314# rConicTo # Appends Conic relative to Last_Point. ##
315# rCubicTo # Appends Cubic relative to Last_Point. ##
316# rLineTo # Appends Line relative to Last_Point. ##
317# rMoveTo # Starts Contour relative to Last_Point. ##
318# rQuadTo # Appends Quad relative to Last_Point. ##
319# readFromMemory # Initializes from buffer. ##
320# reset() # Removes Verb_Array, Point_Array, and Weights; frees memory. ##
321# reverseAddPath # Adds contents of Path back to front. ##
322# rewind() # Removes Verb_Array, Point_Array, and Weights; leaves memory allocated. ##
323# serialize() # Copies data to buffer. ##
324# setConvexity # Sets if geometry is convex to avoid future computation. ##
325# setFillType # Sets Fill_Type: winding, even-odd, inverse. ##
326# setIsConvex # Deprecated. ##
327# setIsVolatile # Sets if Device should not cache. ##
328# setLastPt # Replaces Last_Point. ##
329# swap() # Exchanges Path pair. ##
330# toggleInverseFillType # Toggles Fill_Type between inside and outside geometry. ##
331# transform() # Applies Matrix to Point_Array and Weights. ##
332# unique() # Returns if data has single owner. ##
333# updateBoundsCache # Refreshes result of getBounds. ##
334# writeToMemory # Copies data to buffer. ##
335#Table ##
336#Subtopic Path_Member_Functions ##
337#Topic Overview ##
338
Cary Clark8032b982017-07-28 11:04:54 -0400339#Subtopic Verb
340#Alias Verbs
341
Cary Clark73fa9722017-08-29 17:36:51 -0400342#Enum Verb
343
344#Code
345 enum Verb {
346 kMove_Verb,
347 kLine_Verb,
348 kQuad_Verb,
349 kConic_Verb,
350 kCubic_Verb,
351 kClose_Verb,
352 kDone_Verb,
353 };
354##
355
356Verb instructs Path how to interpret one or more Point and optional Conic_Weight;
Cary Clark8032b982017-07-28 11:04:54 -0400357manage Contour, and terminate Path.
358
Cary Clark73fa9722017-08-29 17:36:51 -0400359#Const kMove_Verb 0
360 Starts new Contour at next Point.
361##
362#Const kLine_Verb 1
363 Adds Line from Last_Point to next Point.
364 Line is a straight segment from Point to Point.
365##
366#Const kQuad_Verb 2
367 Adds Quad from Last_Point, using control Point, and end Point.
368 Quad is a parabolic section within tangents from Last_Point to control Point,
369 and control Point to end Point.
370##
371#Const kConic_Verb 3
372 Adds Conic from Last_Point, using control Point, end Point, and Conic_Weight.
373 Conic is a elliptical, parabolic, or hyperbolic section within tangents
374 from Last_Point to control Point, and control Point to end Point, constrained
375 by Conic_Weight. Conic_Weight less than one is elliptical; equal to one is
376 parabolic (and identical to Quad); greater than one hyperbolic.
377##
378#Const kCubic_Verb 4
379 Adds Cubic from Last_Point, using two control Points, and end Point.
380 Cubic is a third-order Bezier section within tangents from Last_Point to
381 first control Point, and from second control Point to end Point.
382##
383#Const kClose_Verb 5
384 Closes Contour, connecting Last_Point to kMove_Verb Point.
385##
386#Const kDone_Verb 6
387 Terminates Path. Not in Verb_Array, but returned by Path iterator.
Cary Clark8032b982017-07-28 11:04:54 -0400388##
389
390Each Verb has zero or more Points stored in Path.
391Path iterator returns complete curve descriptions, duplicating shared Points
392for consecutive entries.
393
394#Table
395#Legend
396# Verb # Allocated Points # Iterated Points # Weights ##
397##
398# kMove_Verb # 1 # 1 # 0 ##
399# kLine_Verb # 1 # 2 # 0 ##
400# kQuad_Verb # 2 # 3 # 0 ##
401# kConic_Verb # 2 # 3 # 1 ##
402# kCubic_Verb # 3 # 4 # 0 ##
403# kClose_Verb # 0 # 1 # 0 ##
404# kDone_Verb # -- # 0 # 0 ##
405##
Cary Clark73fa9722017-08-29 17:36:51 -0400406
407#Example
408void draw(SkCanvas* canvas) {
409 SkPath path;
410 path.lineTo(20, 20);
411 path.quadTo(-10, -10, 30, 30);
412 path.close();
413 path.cubicTo(1, 2, 3, 4, 5, 6);
414 path.conicTo(0, 0, 0, 0, 2);
415 uint8_t verbs[7];
416 int count = path.getVerbs(verbs, (int) SK_ARRAY_COUNT(verbs));
417 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close" };
418 SkDebugf("verb count: %d\nverbs: ", count);
419 for (int i = 0; i < count; ++i) {
420 SkDebugf("k%s_Verb ", verbStr[verbs[i]]);
421 }
422 SkDebugf("\n");
423}
424#StdOut
425verb count: 7
426verbs: kMove_Verb kLine_Verb kQuad_Verb kClose_Verb kMove_Verb kCubic_Verb kConic_Verb
427##
428##
429
430#Enum Verb ##
431#Subtopic Verb ##
432
433# ------------------------------------------------------------------------------
434#Subtopic Direction
435#Alias Directions
436
437#Enum Direction
438
439#Code
440 enum Direction {
441 kCW_Direction,
442 kCCW_Direction,
443 };
444##
445
446Direction describes whether Contour is clockwise or counterclockwise.
447When Path contains multiple overlapping Contours, Direction together with
448Fill_Type determines whether overlaps are filled or form holes.
449
450Direction also determines how Contour is measured. For instance, dashing
451measures along Path to determine where to start and stop stroke; Direction
452will change dashed results as it steps clockwise or counterclockwise.
453
454Closed Contours like Rect, Round_Rect, Circle, and Oval added with
455kCW_Direction travel clockwise; the same added with kCCW_Direction
456travel counterclockwise.
457
458#Const kCW_Direction 0
459 Contour travels in a clockwise direction.
460##
461#Const kCCW_Direction 1
462 Contour travels in a counterclockwise direction.
463##
464
465
466#Example
467#Height 100
468void draw(SkCanvas* canvas) {
469 const SkPoint arrow[] = { {40, -5}, {45, 0}, {40, 5} };
470 const SkRect rect = {10, 10, 90, 90};
471 SkPaint rectPaint;
472 rectPaint.setAntiAlias(true);
473 SkPaint textPaint(rectPaint);
474 textPaint.setTextAlign(SkPaint::kCenter_Align);
475 rectPaint.setStyle(SkPaint::kStroke_Style);
476 SkPaint arrowPaint(rectPaint);
477 SkPath arrowPath;
478 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
479 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 320, 0,
480 SkPath1DPathEffect::kRotate_Style));
481 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
482 canvas->drawRect(rect, rectPaint);
483 for (unsigned start : { 0, 1, 2, 3 } ) {
484 SkPath path;
485 path.addRect(rect, direction, start);
486 canvas->drawPath(path, arrowPaint);
487 }
488 canvas->drawString(SkPath::kCW_Direction == direction ? "CW" : "CCW", rect.centerX(),
489 rect.centerY(), textPaint);
490 canvas->translate(120, 0);
491 }
492}
493##
494
495#SeeAlso arcTo rArcTo isRect isNestedFillRects addRect addOval
496
497#Enum Direction ##
498#Subtopic Direction ##
499
500# ------------------------------------------------------------------------------
501
502#Method SkPath()
503
504By default, Path has no Verbs, no Points, and no Weights.
505Fill_Type is set to kWinding_FillType.
506
507#Return empty Path ##
508
509#Example
510 SkPath path;
511 SkDebugf("path is " "%s" "empty", path.isEmpty() ? "" : "not ");
512#StdOut
513path is empty
514##
515##
516
517#SeeAlso reset rewind
518
519##
520
521# ------------------------------------------------------------------------------
522
523#Method SkPath(const SkPath& path)
524
525Copy constructor makes two paths identical by value. Internally, path and
526the returned result share pointer values. The underlying Verb_Array, Point_Array
527and Weights are copied when modified.
528
529Creating a Path copy is very efficient and never allocates memory.
530Paths are always copied by value from the interface; the underlying shared
531pointers are not exposed.
532
533#Param path Path to copy by value ##
534
Cary Clarka523d2d2017-08-30 08:58:10 -0400535#Return copy of Path ##
Cary Clark73fa9722017-08-29 17:36:51 -0400536
537#Example
538#Description
539 Modifying one path does not effect another, even if they started as copies
540 of each other.
541##
542 SkPath path;
543 path.lineTo(20, 20);
544 SkPath path2(path);
545 path2.close();
546 SkDebugf("path verbs: %d\n", path.countVerbs());
547 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
548 path.reset();
549 SkDebugf("after reset\n" "path verbs: %d\n", path.countVerbs());
550 SkDebugf("path2 verbs: %d\n", path2.countVerbs());
551#StdOut
552path verbs: 2
553path2 verbs: 3
554after reset
555path verbs: 0
556path2 verbs: 3
557##
558##
559
560#SeeAlso operator=(const SkPath& path)
561
562##
563
564# ------------------------------------------------------------------------------
565
566#Method ~SkPath()
567
568Releases ownership of any shared data and deletes data if Path is sole owner.
569
570#Example
571#Description
Cary Clarkce101242017-09-01 15:51:02 -0400572delete calls Path Destructor, but copy of original in path2 is unaffected.
Cary Clark73fa9722017-08-29 17:36:51 -0400573##
574void draw(SkCanvas* canvas) {
575 SkPath* path = new SkPath();
576 path->lineTo(20, 20);
577 SkPath path2(*path);
578 delete path;
579 SkDebugf("path2 is " "%s" "empty", path2.isEmpty() ? "" : "not ");
580}
581##
582
583#SeeAlso SkPath() SkPath(const SkPath& path) operator=(const SkPath& path)
584
585##
586
587# ------------------------------------------------------------------------------
588
589#Method SkPath& operator=(const SkPath& path)
590
591Path assignment makes two paths identical by value. Internally, assignment
592shares pointer values. The underlying Verb_Array, Point_Array and Weights
593are copied when modified.
594
595Copying Paths by assignment is very efficient and never allocates memory.
596Paths are always copied by value from the interface; the underlying shared
597pointers are not exposed.
598
Cary Clarkce101242017-09-01 15:51:02 -0400599#Param path Verb_Array, Point_Array, Weights, and Fill_Type to copy ##
Cary Clark73fa9722017-08-29 17:36:51 -0400600
601#Return Path copied by value ##
602
603#Example
604SkPath path1;
605path1.addRect({10, 20, 30, 40});
606SkPath path2 = path1;
607const SkRect& b1 = path1.getBounds();
608SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
609const SkRect& b2 = path2.getBounds();
610SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
611#StdOut
612path1 bounds = 10, 20, 30, 40
613path2 bounds = 10, 20, 30, 40
614#StdOut ##
615##
616
617#SeeAlso swap() SkPath(const SkPath& path)
618
619##
620
621# ------------------------------------------------------------------------------
622
623#Method bool operator==(const SkPath& a, const SkPath& b)
624
625Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
626are equivalent.
627
628#Param a Path to compare ##
629#Param b Path to compare ##
630
631#Return true if Path pair are equivalent ##
632
633#Example
634#Description
635Rewind removes Verb_Array but leaves storage; since storage is not compared,
636Path pair are equivalent.
637##
638void draw(SkCanvas* canvas) {
639 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
640 SkDebugf("%s one %c= two\n", prefix, a == b ? '=' : '!');
641 };
642 SkPath one;
643 SkPath two;
644 debugster("empty", one, two);
645 one.moveTo(0, 0);
646 debugster("moveTo", one, two);
647 one.rewind();
648 debugster("rewind", one, two);
649 one.moveTo(0, 0);
650 one.reset();
651 debugster("reset", one, two);
652}
653#StdOut
654empty one == two
655moveTo one != two
656rewind one == two
657reset one == two
658##
659##
660
661##
662
663# ------------------------------------------------------------------------------
664
665#Method bool operator!=(const SkPath& a, const SkPath& b)
666
667Compares a and b; returns true if Fill_Type, Verb_Array, Point_Array, and Weights
668are not equivalent.
669
670#Param a Path to compare ##
671#Param b Path to compare ##
672
673#Return true if Path pair are not equivalent ##
674
675#Example
676#Description
677Path pair are equal though their convexity is not equal.
678##
679void draw(SkCanvas* canvas) {
680 auto debugster = [](const char* prefix, const SkPath& a, const SkPath& b) -> void {
681 SkDebugf("%s one %c= two\n", prefix, a != b ? '!' : '=');
682 };
683 SkPath one;
684 SkPath two;
685 debugster("empty", one, two);
686 one.addRect({10, 20, 30, 40});
687 two.addRect({10, 20, 30, 40});
688 debugster("addRect", one, two);
689 one.setConvexity(SkPath::kConcave_Convexity);
690 debugster("setConvexity", one, two);
691 SkDebugf("convexity %c=\n", one.getConvexity() == two.getConvexity() ? '=' : '!');
692}
693#StdOut
694empty one == two
695addRect one == two
696setConvexity one == two
697convexity !=
698##
699##
700
701##
702
703# ------------------------------------------------------------------------------
704
705#Method bool isInterpolatable(const SkPath& compare) const
706
707Return true if Paths contain equal Verbs and equal Weights.
708If Paths contain one or more Conics, the Weights must match.
709
710conicTo may add different Verbs depending on Conic_Weight, so it is not
Cary Clarkce101242017-09-01 15:51:02 -0400711trivial to interpolate a pair of Paths containing Conics with different
Cary Clark73fa9722017-08-29 17:36:51 -0400712Conic_Weight values.
713
714#Param compare Path to compare ##
715
716#Return true if Paths Verb_Array and Weights are equivalent ##
717
718#Example
719 SkPath path, path2;
720 path.moveTo(20, 20);
721 path.lineTo(40, 40);
722 path.lineTo(20, 20);
723 path.lineTo(40, 40);
724 path.close();
725 path2.addRect({20, 20, 40, 40});
726 SkDebugf("paths are " "%s" "interpolatable", path.isInterpolatable(path2) ? "" : "not ");
727#StdOut
728paths are interpolatable
729##
730##
731
732#SeeAlso isInterpolatable
733
734##
735
736# ------------------------------------------------------------------------------
737
738#Method bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const
739
740Interpolate between Paths with equal sized Point_Arrays.
741Copy Verb_Array and Weights to out,
742and set out Point_Array to a weighted average of this Point_Array and ending
743Point_Array, using the formula:
744#Formula
745(this->points * weight) + ending->points * (1 - weight)
746##
747
748weight is most useful when between zero (ending Point_Array) and
749one (this Point_Array); will work with values outside of this
750range.
751
752interpolate() returns false and leaves out unchanged if Point_Array is not
753the same size as ending Point_Array. Call isInterpolatable to check Path
754compatibility prior to calling interpolate().
755
756#Param ending Point_Array averaged with this Point_Array ##
757#Param weight contribution of ending Point_Array, and
758 one minus contribution of this Point_Array
759##
760#Param out Path replaced by interpolated averages ##
761
762#Return true if Paths contain same number of Points ##
763
764#Example
765#Height 60
766void draw(SkCanvas* canvas) {
767 SkPaint paint;
768 paint.setAntiAlias(true);
769 paint.setStyle(SkPaint::kStroke_Style);
770 SkPath path, path2;
771 path.moveTo(20, 20);
772 path.lineTo(40, 40);
773 path.lineTo(20, 40);
774 path.lineTo(40, 20);
775 path.close();
776 path2.addRect({20, 20, 40, 40});
777 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
778 SkPath interp;
779 path.interpolate(path2, i, &interp);
780 canvas->drawPath(interp, paint);
781 canvas->translate(30, 0);
782 }
783}
784##
785
786#SeeAlso isInterpolatable
787
788##
789
790# ------------------------------------------------------------------------------
791
792#Method bool unique() const
793
794#Private
795To be deprecated; only valid for Android framework.
796##
797
798#Return true if Path has one owner ##
799
800##
801
802# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400803#Subtopic Fill_Type
804
Cary Clark73fa9722017-08-29 17:36:51 -0400805#Enum FillType
806
807#Code
808 enum FillType {
809 kWinding_FillType,
810 kEvenOdd_FillType,
811 kInverseWinding_FillType,
812 kInverseEvenOdd_FillType,
813 };
814##
Cary Clark8032b982017-07-28 11:04:54 -0400815
816Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
817fills if the sum of Contour edges is not zero, where clockwise edges add one, and
818counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
819number of Contour edges is odd. Each Fill_Type has an inverse variant that
820reverses the rule:
821kInverseWinding_FillType fills where the sum of Contour edges is zero;
822kInverseEvenOdd_FillType fills where the number of Contour edges is even.
823
824#Example
825#Height 100
826#Description
827The top row has two clockwise rectangles. The second row has one clockwise and
828one counterclockwise rectangle. The even-odd variants draw the same. The
829winding variants draw the top rectangle overlap, which has a winding of 2, the
830same as the outer parts of the top rectangles, which have a winding of 1.
831##
Cary Clark73fa9722017-08-29 17:36:51 -0400832void draw(SkCanvas* canvas) {
833 SkPath path;
834 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
835 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
836 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
837 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
838 SkPaint strokePaint;
839 strokePaint.setStyle(SkPaint::kStroke_Style);
840 SkRect clipRect = {0, 0, 51, 100};
841 canvas->drawPath(path, strokePaint);
842 SkPaint fillPaint;
843 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
844 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
845 canvas->translate(51, 0);
846 canvas->save();
847 canvas->clipRect(clipRect);
848 path.setFillType(fillType);
849 canvas->drawPath(path, fillPaint);
850 canvas->restore();
851 }
Cary Clark8032b982017-07-28 11:04:54 -0400852}
853##
Cary Clark73fa9722017-08-29 17:36:51 -0400854
855#Const kWinding_FillType 0
856Specifies fill as area is enclosed by a non-zero sum of Contour Directions.
857##
858#Const kEvenOdd_FillType 1
859Specifies fill as area enclosed by an odd number of Contours.
860##
861#Const kInverseWinding_FillType 2
862Specifies fill as area is enclosed by a zero sum of Contour Directions.
863##
864#Const kInverseEvenOdd_FillType 3
865Specifies fill as area enclosed by an even number of Contours.
866##
867
868#Example
869#Height 230
870void draw(SkCanvas* canvas) {
871 SkPath path;
872 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
873 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
874 SkPaint strokePaint;
875 strokePaint.setStyle(SkPaint::kStroke_Style);
876 SkRect clipRect = {0, 0, 128, 128};
877 canvas->drawPath(path, strokePaint);
878 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
879 SkPaint textPaint;
880 textPaint.setAntiAlias(true);
881 textPaint.setTextAlign(SkPaint::kCenter_Align);
882 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
883 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
884 textPaint.setTextSize(18);
885 canvas->translate(0, 128);
886 canvas->scale(.5f, .5f);
887 canvas->drawString("inverse", 384, 150, textPaint);
888 SkPaint fillPaint;
889 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
890 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
891 canvas->save();
892 canvas->clipRect(clipRect);
893 path.setFillType(fillType);
894 canvas->drawPath(path, fillPaint);
895 canvas->restore();
896 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
897 canvas->translate(128, 0);
898 }
899}
900##
901
902#SeeAlso SkPaint::Style Direction getFillType setFillType
903
904##
905
906# ------------------------------------------------------------------------------
907
908#Method FillType getFillType() const
909
910Returns FillType, the rule used to fill Path. FillType of a new Path is
911kWinding_FillType.
912
913#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
914kInverseEvenOdd_FillType
915##
916
917#Example
918 SkPath path;
919 SkDebugf("default path fill type is %s\n",
920 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
921 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
922 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
923 "kInverseEvenOdd_FillType");
924#StdOut
925default path fill type is kWinding_FillType
926##
927##
928
929#SeeAlso FillType setFillType isInverseFillType
930
931##
932
933# ------------------------------------------------------------------------------
934
935#Method void setFillType(FillType ft)
936
937Sets FillType, the rule used to fill Path. While there is no check
938that ft is legal, values outside of FillType are not supported.
939
940#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
941kInverseEvenOdd_FillType
942##
943
944#Example
945#Description
946If empty Path is set to inverse FillType, it fills all pixels.
947##
948#Height 64
949 SkPath path;
950 path.setFillType(SkPath::kInverseWinding_FillType);
951 SkPaint paint;
952 paint.setColor(SK_ColorBLUE);
953 canvas->drawPath(path, paint);
954##
955
956#SeeAlso FillType getFillType toggleInverseFillType
957
958##
959
960# ------------------------------------------------------------------------------
961
962#Method bool isInverseFillType() const
963
964Returns if FillType describes area outside Path geometry. The inverse fill area
965extends indefinitely.
966
967#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType ##
968
969#Example
970 SkPath path;
971 SkDebugf("default path fill type is inverse: %s\n",
972 path.isInverseFillType() ? "true" : "false");
973#StdOut
974default path fill type is inverse: false
975##
976##
977
978#SeeAlso FillType getFillType setFillType toggleInverseFillType
979
980##
981
982# ------------------------------------------------------------------------------
983
984#Method void toggleInverseFillType()
985
986Replace FillType with its inverse. The inverse of FillType describes the area
987unmodified by the original FillType.
988
989#Table
990#Legend
991# FillType # toggled FillType ##
992##
993# kWinding_FillType # kInverseWinding_FillType ##
994# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
995# kInverseWinding_FillType # kWinding_FillType ##
996# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
997##
998
999#Example
1000#Description
1001Path drawn normally and through its inverse touches every pixel once.
1002##
1003#Height 100
1004SkPath path;
1005SkPaint paint;
1006paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -04001007paint.setTextSize(80);
1008paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -04001009canvas->drawPath(path, paint);
1010path.toggleInverseFillType();
1011paint.setColor(SK_ColorGREEN);
1012canvas->drawPath(path, paint);
1013##
1014
1015#SeeAlso FillType getFillType setFillType isInverseFillType
1016
1017##
1018
Cary Clark8032b982017-07-28 11:04:54 -04001019#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -04001020
1021# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001022
1023#Subtopic Convexity
Cary Clark73fa9722017-08-29 17:36:51 -04001024
1025#Enum Convexity
1026
1027#Code
Cary Clark884dd7d2017-10-11 10:37:52 -04001028 enum Convexity : uint8_t {
Cary Clark73fa9722017-08-29 17:36:51 -04001029 kUnknown_Convexity,
1030 kConvex_Convexity,
1031 kConcave_Convexity,
1032 };
1033##
1034
Cary Clark8032b982017-07-28 11:04:54 -04001035Path is convex if it contains one Contour and Contour loops no more than
1036360 degrees, and Contour angles all have same Direction. Convex Path
1037may have better performance and require fewer resources on GPU_Surface.
1038
Cary Clark73fa9722017-08-29 17:36:51 -04001039Path is concave when either at least one Direction change is clockwise and
1040another is counterclockwise, or the sum of the changes in Direction is not 360
1041degrees.
1042
1043Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
1044if needed by destination Surface.
1045
1046#Const kUnknown_Convexity 0
1047 Indicates Convexity has not been determined.
1048##
1049#Const kConvex_Convexity 1
1050 Path has one Contour made of a simple geometry without indentations.
1051##
1052#Const kConcave_Convexity 2
1053 Path has more than one Contour, or a geometry with indentations.
1054##
1055
1056#Example
1057void draw(SkCanvas* canvas) {
1058 SkPaint paint;
1059 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1060 const char* labels[] = { "unknown", "convex", "concave" };
1061 for (SkScalar x : { 40, 100 } ) {
1062 SkPath path;
1063 quad[0].fX = x;
1064 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1065 canvas->drawPath(path, paint);
1066 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
1067 canvas->translate(100, 100);
1068 }
1069}
1070##
1071
1072#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
1073
1074#Enum Convexity ##
1075
1076#Method Convexity getConvexity() const
1077
1078Computes Convexity if required, and returns stored value.
1079Convexity is computed if stored value is kUnknown_Convexity,
1080or if Path has been altered since Convexity was computed or set.
1081
Cary Clarka523d2d2017-08-30 08:58:10 -04001082#Return computed or stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001083
1084#Example
1085void draw(SkCanvas* canvas) {
1086 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1087 SkDebugf("%s path convexity is %s\n", prefix,
1088 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1089 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1090 SkPath path;
1091 debugster("initial", path);
1092 path.lineTo(50, 0);
1093 debugster("first line", path);
1094 path.lineTo(50, 50);
1095 debugster("second line", path);
1096 path.lineTo(100, 50);
1097 debugster("third line", path);
1098}
1099##
1100
1101#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
1102
1103##
1104
1105# ------------------------------------------------------------------------------
1106
1107#Method Convexity getConvexityOrUnknown() const
1108
1109Returns last computed Convexity, or kUnknown_Convexity if
1110Path has been altered since Convexity was computed or set.
1111
Cary Clarka523d2d2017-08-30 08:58:10 -04001112#Return stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001113
1114#Example
1115#Description
1116Convexity is unknown unless getConvexity is called without a subsequent call
1117that alters the path.
1118##
1119void draw(SkCanvas* canvas) {
1120 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1121 SkDebugf("%s path convexity is %s\n", prefix,
1122 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
1123 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
1124 SkPath path;
1125 debugster("initial", path);
1126 path.lineTo(50, 0);
1127 debugster("first line", path);
1128 path.getConvexity();
1129 path.lineTo(50, 50);
1130 debugster("second line", path);
1131 path.lineTo(100, 50);
1132 path.getConvexity();
1133 debugster("third line", path);
1134}
1135##
1136
1137#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
1138
1139##
1140
1141# ------------------------------------------------------------------------------
1142
1143#Method void setConvexity(Convexity convexity)
1144
1145Stores convexity so that it is later returned by getConvexity or getConvexityOrUnknown.
1146convexity may differ from getConvexity, although setting an incorrect value may
1147cause incorrect or inefficient drawing.
1148
1149If convexity is kUnknown_Convexity: getConvexity will
1150compute Convexity, and getConvexityOrUnknown will return kUnknown_Convexity.
1151
1152If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity
1153and getConvexityOrUnknown will return convexity until the path is
1154altered.
1155
1156#Param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity ##
1157
1158#Example
1159void draw(SkCanvas* canvas) {
1160 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1161 SkDebugf("%s path convexity is %s\n", prefix,
1162 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1163 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1164 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1165 SkPath path;
1166 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1167 debugster("initial", path);
1168 path.setConvexity(SkPath::kConcave_Convexity);
1169 debugster("after forcing concave", path);
1170 path.setConvexity(SkPath::kUnknown_Convexity);
1171 debugster("after forcing unknown", path);
1172}
1173##
1174
1175#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
1176
1177##
1178
1179# ------------------------------------------------------------------------------
1180
1181#Method bool isConvex() const
1182
1183Computes Convexity if required, and returns true if value is kConvex_Convexity.
1184If setConvexity was called with kConvex_Convexity or kConcave_Convexity, and
1185the path has not been altered, Convexity is not recomputed.
1186
1187#Return true if Convexity stored or computed is kConvex_Convexity ##
1188
1189#Example
1190#Description
1191Concave shape is erroneously considered convex after a forced call to
1192setConvexity.
1193##
1194void draw(SkCanvas* canvas) {
1195 SkPaint paint;
1196 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1197 for (SkScalar x : { 40, 100 } ) {
1198 SkPath path;
1199 quad[0].fX = x;
1200 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1201 path.setConvexity(SkPath::kConvex_Convexity);
1202 canvas->drawPath(path, paint);
1203 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
1204 canvas->translate(100, 100);
1205 }
1206}
1207##
1208
1209#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
1210
1211##
1212
1213# ------------------------------------------------------------------------------
1214
1215#Method void setIsConvex(bool isConvex)
1216
1217Deprecated. Use setConvexity.
1218
1219#Deprecated
1220##
1221
1222#NoExample
1223##
1224
1225#SeeAlso Convexity setConvexity getConvexity
1226
1227##
1228
1229#Subtopic Convexity ##
1230
1231# ------------------------------------------------------------------------------
1232
1233#Method bool isOval(SkRect* rect, Direction* dir = nullptr,
1234 unsigned* start = nullptr) const
1235
1236Returns true if constructed by addCircle, addOval; and in some cases,
1237addRoundRect, addRRect. Path constructed with conicTo or rConicTo will not
1238return true though Path draws Oval.
1239
1240rect receives bounds of Oval.
1241dir receives Direction of Oval: kCW_Direction if clockwise, kCCW_Direction if
1242counterclockwise.
1243start receives start of Oval: 0 for top, 1 for right, 2 for bottom, 3 for left.
1244
1245rect, dir, and start are unmodified if Oval is not found.
1246
1247Triggers performance optimizations on some GPU_Surface implementations.
1248
1249#Param rect storage for bounding Rect of Oval; may be nullptr ##
1250#Param dir storage for Direction; may be nullptr ##
1251#Param start storage for start of Oval; may be nullptr ##
1252
1253#Return true if Path was constructed by method that reduces to Oval ##
1254
1255#Example
1256void draw(SkCanvas* canvas) {
1257 SkPaint paint;
1258 SkPath path;
1259 path.addOval({20, 20, 220, 220}, SkPath::kCW_Direction, 1);
1260 SkRect bounds;
1261 SkPath::Direction direction;
1262 unsigned start;
1263 path.isOval(&bounds, &direction, &start);
1264 paint.setColor(0xFF9FBFFF);
1265 canvas->drawRect(bounds, paint);
1266 paint.setColor(0x3f000000);
1267 canvas->drawPath(path, paint);
1268 paint.setColor(SK_ColorBLACK);
1269 canvas->rotate(start * 90, bounds.centerX(), bounds.centerY());
1270 char startText = '0' + start;
1271 paint.setTextSize(20);
1272 canvas->drawText(&startText, 1, bounds.centerX(), bounds.fTop + 20, paint);
1273 paint.setStyle(SkPaint::kStroke_Style);
1274 paint.setStrokeWidth(4);
1275 path.reset();
1276 path.addArc(bounds, -90, SkPath::kCW_Direction == direction ? 90 : -90);
1277 path.rLineTo(20, -20);
1278 canvas->drawPath(path, paint);
1279}
1280##
1281
1282#SeeAlso Oval addCircle addOval
1283
1284##
1285
1286# ------------------------------------------------------------------------------
1287
1288#Method bool isRRect(SkRRect* rrect, Direction* dir = nullptr,
1289 unsigned* start = nullptr) const
1290
1291Returns true if constructed by addRoundRect, addRRect; and if construction
Cary Clarkce101242017-09-01 15:51:02 -04001292is not empty, not Rect, and not Oval. Path constructed with other calls
Cary Clark73fa9722017-08-29 17:36:51 -04001293will not return true though Path draws Round_Rect.
1294
1295rrect receives bounds of Round_Rect.
1296dir receives Direction of Oval: kCW_Direction if clockwise, kCCW_Direction if
1297counterclockwise.
1298start receives start of Round_Rect: 0 for top, 1 for right, 2 for bottom, 3 for left.
1299
1300rrect, dir, and start are unmodified if Round_Rect is not found.
1301
1302Triggers performance optimizations on some GPU_Surface implementations.
1303
1304#Param rrect storage for bounding Rect of Round_Rect; may be nullptr ##
1305#Param dir storage for Direction; may be nullptr ##
1306#Param start storage for start of Round_Rect; may be nullptr ##
1307
Cary Clarkce101242017-09-01 15:51:02 -04001308#Return true if Path contains only Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001309
1310#Example
Cary Clarkce101242017-09-01 15:51:02 -04001311#Description
1312Draw rounded rectangle and its bounds. Draw an arc indicating where the rounded
1313rectangle starts and its direction.
1314##
Cary Clark73fa9722017-08-29 17:36:51 -04001315void draw(SkCanvas* canvas) {
1316 SkPaint paint;
1317 SkPath path;
1318 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50), SkPath::kCCW_Direction, 3);
1319 SkRRect rrect;
1320 SkPath::Direction direction;
1321 unsigned start;
1322 path.isRRect(&rrect, &direction, &start);
1323 const SkRect& bounds = rrect.rect();
1324 paint.setColor(0xFF9FBFFF);
1325 canvas->drawRect(bounds, paint);
1326 paint.setColor(0x3f000000);
1327 canvas->drawPath(path, paint);
1328 paint.setColor(SK_ColorBLACK);
1329 canvas->rotate(start * 90, bounds.centerX(), bounds.centerY());
1330 char startText = '0' + start;
1331 paint.setTextSize(20);
1332 canvas->drawText(&startText, 1, bounds.centerX(), bounds.fTop + 20, paint);
1333 paint.setStyle(SkPaint::kStroke_Style);
1334 paint.setStrokeWidth(4);
1335 path.reset();
1336 path.addArc(bounds, -90, SkPath::kCW_Direction == direction ? 90 : -90);
1337 path.rLineTo(20, -20);
1338 canvas->drawPath(path, paint);
1339}
1340##
1341
1342#SeeAlso Round_Rect addRoundRect addRRect
1343
1344##
1345
1346# ------------------------------------------------------------------------------
1347
1348#Method void reset()
1349
Cary Clarkce101242017-09-01 15:51:02 -04001350Sets Path to its initial state.
Cary Clark73fa9722017-08-29 17:36:51 -04001351Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1352Internal storage associated with Path is released.
1353
1354#Example
1355 SkPath path1, path2;
1356 path1.setFillType(SkPath::kInverseWinding_FillType);
1357 path1.addRect({10, 20, 30, 40});
1358 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1359 path1.reset();
1360 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1361##
1362
1363#SeeAlso rewind()
1364
1365##
1366
1367# ------------------------------------------------------------------------------
1368
1369#Method void rewind()
1370
Cary Clarkce101242017-09-01 15:51:02 -04001371Sets Path to its initial state, preserving internal storage.
Cary Clark73fa9722017-08-29 17:36:51 -04001372Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1373Internal storage associated with Path is retained.
1374
1375Use rewind() instead of reset() if Path storage will be reused and performance
1376is critical.
1377
1378#Example
1379#Description
1380Although path1 retains its internal storage, it is indistinguishable from
1381a newly initialized path.
1382##
1383 SkPath path1, path2;
1384 path1.setFillType(SkPath::kInverseWinding_FillType);
1385 path1.addRect({10, 20, 30, 40});
1386 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1387 path1.rewind();
1388 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1389##
1390
1391#SeeAlso reset()
1392
1393##
1394
1395# ------------------------------------------------------------------------------
1396
1397#Method bool isEmpty() const
1398
1399Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
1400SkPath() constructs empty Path; reset() and (rewind) make Path empty.
1401
1402#Return true if the path contains no Verb array ##
1403
1404#Example
1405void draw(SkCanvas* canvas) {
1406 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1407 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
1408 };
1409 SkPath path;
1410 debugster("initial", path);
1411 path.moveTo(0, 0);
1412 debugster("after moveTo", path);
1413 path.rewind();
1414 debugster("after rewind", path);
1415 path.lineTo(0, 0);
1416 debugster("after lineTo", path);
1417 path.reset();
1418 debugster("after reset", path);
1419}
1420#StdOut
1421initial path is empty
1422after moveTo path is not empty
1423after rewind path is empty
1424after lineTo path is not empty
1425after reset path is empty
1426##
1427##
1428
1429#SeeAlso SkPath() reset() rewind()
1430
1431##
1432
1433# ------------------------------------------------------------------------------
1434
1435#Method bool isLastContourClosed() const
1436
1437Contour is closed if Path Verb array was last modified by close(). When stroked,
1438closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
1439
1440#Return true if the last Contour ends with a kClose_Verb ##
1441
1442#Example
1443#Description
1444close() has no effect if Path is empty; isLastContourClosed() returns
1445false until Path has geometry followed by close().
1446##
1447void draw(SkCanvas* canvas) {
1448 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1449 SkDebugf("%s last contour is %s" "closed\n", prefix,
1450 path.isLastContourClosed() ? "" : "not ");
1451 };
1452 SkPath path;
1453 debugster("initial", path);
1454 path.close();
1455 debugster("after close", path);
1456 path.lineTo(0, 0);
1457 debugster("after lineTo", path);
1458 path.close();
1459 debugster("after close", path);
1460}
1461#StdOut
1462initial last contour is not closed
1463after close last contour is not closed
1464after lineTo last contour is not closed
1465after close last contour is closed
1466##
1467##
1468
1469#SeeAlso close()
1470
1471##
1472
1473# ------------------------------------------------------------------------------
1474
1475#Method bool isFinite() const
1476
1477Returns true for finite Point array values between negative SK_ScalarMax and
1478positive SK_ScalarMax. Returns false for any Point array value of
1479SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
1480
1481#Return true if all Point values are finite ##
1482
1483#Example
1484void draw(SkCanvas* canvas) {
1485 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1486 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1487 };
1488 SkPath path;
1489 debugster("initial", path);
1490 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1491 debugster("after line", path);
1492 SkMatrix matrix;
1493 matrix.setScale(2, 2);
1494 path.transform(matrix);
1495 debugster("after scale", path);
1496}
1497#StdOut
1498initial path is finite
1499after line path is finite
1500after scale path is not finite
1501##
1502##
1503
1504#SeeAlso SkScalar
1505##
1506
1507# ------------------------------------------------------------------------------
1508
1509#Method bool isVolatile() const
1510
1511Returns true if the path is volatile; it will not be altered or discarded
1512by the caller after it is drawn. Paths by default have volatile set false, allowing
1513Surface to attach a cache of data which speeds repeated drawing. If true, Surface
1514may not speed repeated drawing.
1515
1516#Return true if caller will alter Path after drawing ##
1517
1518#Example
1519 SkPath path;
1520 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1521#StdOut
1522volatile by default is false
1523##
1524##
1525
1526#SeeAlso setIsVolatile
1527
1528##
1529
1530# ------------------------------------------------------------------------------
1531
1532#Method void setIsVolatile(bool isVolatile)
1533
1534Specify whether Path is volatile; whether it will be altered or discarded
1535by the caller after it is drawn. Paths by default have volatile set false, allowing
1536Device to attach a cache of data which speeds repeated drawing.
1537
1538Mark temporary paths, discarded or modified after use, as volatile
1539to inform Device that the path need not be cached.
1540
1541Mark animating Path volatile to improve performance.
Cary Clarkce101242017-09-01 15:51:02 -04001542Mark unchanging Path non-volatile to improve repeated rendering.
Cary Clark73fa9722017-08-29 17:36:51 -04001543
1544Raster_Surface Path draws are affected by volatile for some shadows.
1545GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
1546
1547#Param isVolatile true if caller will alter Path after drawing ##
1548
1549#Example
1550#Height 50
1551#Width 50
1552 SkPaint paint;
1553 paint.setStyle(SkPaint::kStroke_Style);
1554 SkPath path;
1555 path.setIsVolatile(true);
1556 path.lineTo(40, 40);
1557 canvas->drawPath(path, paint);
1558 path.rewind();
1559 path.moveTo(0, 40);
1560 path.lineTo(40, 0);
1561 canvas->drawPath(path, paint);
1562##
1563
1564#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1565
1566#SeeAlso isVolatile
1567
1568##
1569
1570# ------------------------------------------------------------------------------
1571
1572#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
1573
1574Test if Line between Point pair is degenerate.
1575Line with no length or that moves a very short distance is degenerate; it is
1576treated as a point.
1577
Cary Clarka523d2d2017-08-30 08:58:10 -04001578exact changes the equality test. If true, returns true only if p1 equals p2.
1579If false, returns true if p1 equals or nearly equals p2.
1580
Cary Clark73fa9722017-08-29 17:36:51 -04001581#Param p1 line start point ##
1582#Param p2 line end point ##
Cary Clarka523d2d2017-08-30 08:58:10 -04001583#Param exact if false, allow nearly equals ##
Cary Clark73fa9722017-08-29 17:36:51 -04001584
1585#Return true if Line is degenerate; its length is effectively zero ##
1586
1587#Example
1588#Description
Cary Clarkce101242017-09-01 15:51:02 -04001589As single precision floats, 100 and 100.000001 have the same bit representation,
1590and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001591are not exactly equal, but are nearly equal.
1592##
1593void draw(SkCanvas* canvas) {
1594 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1595 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1596 for (bool exact : { false, true } ) {
1597 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1598 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1599 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1600 ? "" : "not ", exact ? "exactly" : "nearly");
1601 }
1602 }
1603}
1604#StdOut
1605line from (100,100) to (100,100) is degenerate, nearly
1606line from (100,100) to (100,100) is degenerate, exactly
1607line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1608line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1609#StdOut ##
1610##
1611
1612#SeeAlso IsQuadDegenerate IsCubicDegenerate SkPoint::equalsWithinTolerance
1613##
1614
1615# ------------------------------------------------------------------------------
1616
1617#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
1618 const SkPoint& p3, bool exact)
1619
1620Test if Quad is degenerate.
1621Quad with no length or that moves a very short distance is degenerate; it is
1622treated as a point.
1623
Cary Clarkce101242017-09-01 15:51:02 -04001624#Param p1 Quad start point ##
1625#Param p2 Quad control point ##
1626#Param p3 Quad end point ##
Cary Clark73fa9722017-08-29 17:36:51 -04001627#Param exact if true, returns true only if p1, p2, and p3 are equal;
1628 if false, returns true if p1, p2, and p3 are equal or nearly equal
1629##
1630
1631#Return true if Quad is degenerate; its length is effectively zero ##
1632
1633#Example
1634#Description
Cary Clarkce101242017-09-01 15:51:02 -04001635As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001636but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001637the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001638##
1639void draw(SkCanvas* canvas) {
1640 auto debugster = [](const SkPath& path, bool exact) -> void {
1641 SkDebugf("quad (%1.8g,%1.8g), (%1.8g,%1.8g), (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1642 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1643 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1644 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1645 "" : "not ", exact ? "exactly" : "nearly");
1646 };
1647 SkPath path, offset;
1648 path.moveTo({100, 100});
1649 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1650 offset.addPath(path, 1000, 1000);
1651 for (bool exact : { false, true } ) {
1652 debugster(path, exact);
1653 debugster(offset, exact);
1654 }
1655}
1656#StdOut
1657quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1658quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1659quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1660quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1661#StdOut ##
1662##
1663
1664#SeeAlso IsLineDegenerate IsCubicDegenerate SkPoint::equalsWithinTolerance
1665##
1666
1667# ------------------------------------------------------------------------------
1668
1669#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
1670 const SkPoint& p3, const SkPoint& p4, bool exact)
1671
1672Test if Cubic is degenerate.
1673Cubic with no length or that moves a very short distance is degenerate; it is
1674treated as a point.
1675
Cary Clarkce101242017-09-01 15:51:02 -04001676#Param p1 Cubic start point ##
1677#Param p2 Cubic control point 1 ##
1678#Param p3 Cubic control point 2 ##
1679#Param p4 Cubic end point ##
Cary Clark73fa9722017-08-29 17:36:51 -04001680#Param exact if true, returns true only if p1, p2, p3, and p4 are equal;
1681 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
1682##
1683
1684#Return true if Cubic is degenerate; its length is effectively zero ##
1685
1686#Example
1687void draw(SkCanvas* canvas) {
1688 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1689 SkScalar step = 1;
1690 SkScalar prior, length, degenerate;
1691 do {
1692 prior = points[0].fX;
1693 step /= 2;
1694 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1695 degenerate = prior;
1696 points[0].fX += step;
1697 } else {
1698 length = prior;
1699 points[0].fX -= step;
1700 }
1701 } while (prior != points[0].fX);
1702 SkDebugf("%1.8g is degenerate\n", degenerate);
1703 SkDebugf("%1.8g is length\n", length);
1704}
1705#StdOut
17060.00024414062 is degenerate
17070.00024414065 is length
1708#StdOut ##
1709##
1710
1711##
1712
1713# ------------------------------------------------------------------------------
1714
1715#Method bool isLine(SkPoint line[2]) const
1716
1717Returns true if Path contains only one Line;
1718Path_Verb array has two entries: kMove_Verb, kLine_Verb.
1719If Path contains one Line and line is not nullptr, line is set to
1720Line start point and Line end point.
1721Returns false if Path is not one Line; line is unaltered.
1722
1723#Param line storage for Line. May be nullptr ##
1724
1725#Return true if Path contains exactly one Line ##
1726
1727#Example
1728void draw(SkCanvas* canvas) {
1729 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1730 SkPoint line[2];
1731 if (path.isLine(line)) {
1732 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1733 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1734 } else {
1735 SkDebugf("%s is not line\n", prefix);
1736 }
1737 };
1738 SkPath path;
1739 debugster("empty", path);
1740 path.lineTo(0, 0);
1741 debugster("zero line", path);
1742 path.rewind();
1743 path.moveTo(10, 10);
1744 path.lineTo(20, 20);
1745 debugster("line", path);
1746 path.moveTo(20, 20);
1747 debugster("second move", path);
1748}
1749#StdOut
1750empty is not line
1751zero line is line (0,0) (0,0)
1752line is line (10,10) (20,20)
1753second move is not line
1754##
1755##
1756
1757##
1758
1759# ------------------------------------------------------------------------------
1760
Cary Clark8032b982017-07-28 11:04:54 -04001761#Subtopic Point_Array
1762#Alias Point_Arrays
1763
1764Point_Array contains Points satisfying the allocated Points for
1765each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001766and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001767one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1768
1769Point_Array may be read directly from Path with getPoints, or inspected with
1770getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001771
1772#Method int getPoints(SkPoint points[], int max) const
1773
1774Returns number of points in Path. Up to max points are copied.
1775points may be nullptr; then, max must be zero.
1776If max is greater than number of points, excess points storage is unaltered.
1777
1778#Param points storage for Path Point array. May be nullptr ##
1779#Param max maximum to copy; must be greater than or equal to zero ##
1780
1781#Return Path Point array length ##
1782
1783#Example
1784void draw(SkCanvas* canvas) {
1785 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1786 int count = path.getPoints(points, max);
1787 SkDebugf("%s point count: %d ", prefix, count);
1788 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1789 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1790 }
1791 SkDebugf("\n");
1792 };
1793 SkPath path;
1794 path.lineTo(20, 20);
1795 path.lineTo(-10, -10);
1796 SkPoint points[3];
1797 debugster("no points", path, nullptr, 0);
1798 debugster("zero max", path, points, 0);
1799 debugster("too small", path, points, 2);
1800 debugster("just right", path, points, path.countPoints());
1801}
1802#StdOut
1803no points point count: 3
1804zero max point count: 3
1805too small point count: 3 (0,0) (20,20)
1806just right point count: 3 (0,0) (20,20) (-10,-10)
1807##
1808##
1809
1810#SeeAlso countPoints getPoint
1811##
1812
1813#Method int countPoints() const
1814
1815Returns the number of points in Path.
1816Point count is initially zero.
1817
1818#Return Path Point array length ##
1819
1820#Example
1821void draw(SkCanvas* canvas) {
1822 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1823 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1824 };
1825 SkPath path;
1826 debugster("empty", path);
1827 path.lineTo(0, 0);
1828 debugster("zero line", path);
1829 path.rewind();
1830 path.moveTo(10, 10);
1831 path.lineTo(20, 20);
1832 debugster("line", path);
1833 path.moveTo(20, 20);
1834 debugster("second move", path);
1835}
1836#StdOut
1837empty point count: 0
1838zero line point count: 2
1839line point count: 2
1840second move point count: 3
1841##
1842##
1843
1844#SeeAlso getPoints
1845##
1846
1847#Method SkPoint getPoint(int index) const
1848
1849Returns Point at index in Point_Array. Valid range for index is
18500 to countPoints - 1.
1851Returns (0, 0) if index is out of range.
1852
1853#Param index Point array element selector ##
1854
1855#Return Point array value or (0, 0) ##
1856
1857#Example
1858void draw(SkCanvas* canvas) {
1859 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1860 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1861 };
1862 SkPath path;
1863 path.lineTo(20, 20);
1864 path.offset(-10, -10);
1865 for (int i= 0; i < path.countPoints(); ++i) {
1866 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
1867 }
1868}
1869#StdOut
1870point 0: (-10,-10)
1871point 1: (10,10)
1872##
1873##
1874
1875#SeeAlso countPoints getPoints
1876##
1877
1878
1879#Subtopic Point_Array ##
1880
1881# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001882#Subtopic Verb_Array
1883
1884Verb_Array always starts with kMove_Verb.
1885If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1886the quantity of kMove_Verb equals the Contour count.
1887Verb_Array does not include or count kDone_Verb; it is a convenience
1888returned when iterating through Verb_Array.
1889
1890Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
1891or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001892
1893#Method int countVerbs() const
1894
1895Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
1896kCubic_Verb, and kClose_Verb; added to Path.
1897
1898#Return length of Verb_Array ##
1899
1900#Example
1901SkPath path;
1902SkDebugf("empty verb count: %d\n", path.countVerbs());
1903path.addRoundRect({10, 20, 30, 40}, 5, 5);
1904SkDebugf("round rect verb count: %d\n", path.countVerbs());
1905#StdOut
1906empty verb count: 0
1907round rect verb count: 10
1908##
1909##
1910
1911#SeeAlso getVerbs Iter RawIter
1912
1913##
1914
1915#Method int getVerbs(uint8_t verbs[], int max) const
1916
1917Returns the number of verbs in the path. Up to max verbs are copied. The
1918verbs are copied as one byte per verb.
1919
1920#Param verbs storage for verbs, may be nullptr ##
1921#Param max maximum number to copy into verbs ##
1922
1923#Return the actual number of verbs in the path ##
1924
1925#Example
1926void draw(SkCanvas* canvas) {
1927 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1928 int count = path.getVerbs(verbs, max);
1929 SkDebugf("%s verb count: %d ", prefix, count);
1930 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1931 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1932 SkDebugf("%s ", verbStr[verbs[i]]);
1933 }
1934 SkDebugf("\n");
1935 };
1936 SkPath path;
1937 path.lineTo(20, 20);
1938 path.lineTo(-10, -10);
1939 uint8_t verbs[3];
1940 debugster("no verbs", path, nullptr, 0);
1941 debugster("zero max", path, verbs, 0);
1942 debugster("too small", path, verbs, 2);
1943 debugster("just right", path, verbs, path.countVerbs());
1944}
1945#StdOut
1946no verbs verb count: 3
1947zero max verb count: 3
1948too small verb count: 3 move line
1949just right verb count: 3 move line line
1950##
1951##
1952
1953#SeeAlso countVerbs getPoints Iter RawIter
1954##
Cary Clark8032b982017-07-28 11:04:54 -04001955
1956#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001957
1958# ------------------------------------------------------------------------------
1959
1960#Method void swap(SkPath& other)
1961
1962Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1963Cached state is also exchanged. swap() internally exchanges pointers, so
1964it is lightweight and does not allocate memory.
1965
1966swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001967Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001968making assignment as efficient as swap().
1969
1970#Param other Path exchanged by value ##
1971
1972#Example
1973SkPath path1, path2;
1974path1.addRect({10, 20, 30, 40});
1975path1.swap(path2);
1976const SkRect& b1 = path1.getBounds();
1977SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1978const SkRect& b2 = path2.getBounds();
1979SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1980#StdOut
1981path1 bounds = 0, 0, 0, 0
1982path2 bounds = 10, 20, 30, 40
1983#StdOut ##
1984##
1985
1986#SeeAlso operator=(const SkPath& path)
1987
1988##
1989
1990# ------------------------------------------------------------------------------
1991
1992#Method const SkRect& getBounds() const
1993
1994Returns minimum and maximum x and y values of Point_Array.
1995Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1996be larger or smaller than area affected when Path is drawn.
1997
1998Rect returned includes all Points added to Path, including Points associated with
1999kMove_Verb that define empty Contours.
2000
2001#Return bounds of all Points in Point_Array ##
2002
2003#Example
2004#Description
2005Bounds of upright Circle can be predicted from center and radius.
2006Bounds of rotated Circle includes control Points outside of filled area.
2007##
2008 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2009 const SkRect& bounds = path.getBounds();
2010 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
2011 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2012 };
2013 SkPath path;
2014 debugster("empty", path);
2015 path.addCircle(50, 45, 25);
2016 debugster("circle", path);
2017 SkMatrix matrix;
2018 matrix.setRotate(45, 50, 45);
2019 path.transform(matrix);
2020 debugster("rotated circle", path);
2021#StdOut
2022empty bounds = 0, 0, 0, 0
2023circle bounds = 25, 20, 75, 70
2024rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
2025##
2026##
2027
2028#SeeAlso computeTightBounds updateBoundsCache
2029
2030##
2031
2032# ------------------------------------------------------------------------------
2033
2034#Method void updateBoundsCache() const
2035
2036Update internal bounds so that subsequent calls to getBounds are instantaneous.
2037Unaltered copies of Path may also access cached bounds through getBounds.
2038
2039For now, identical to calling getBounds and ignoring the returned value.
2040
2041Call to prepare Path subsequently drawn from multiple threads,
2042to avoid a race condition where each draw separately computes the bounds.
2043
2044#Example
2045 double times[2] = { 0, 0 };
2046 for (int i = 0; i < 10000; ++i) {
2047 SkPath path;
2048 for (int j = 1; j < 100; ++ j) {
2049 path.addCircle(50 + j, 45 + j, 25 + j);
2050 }
2051 if (1 & i) {
2052 path.updateBoundsCache();
2053 }
2054 double start = SkTime::GetNSecs();
2055 (void) path.getBounds();
2056 times[1 & i] += SkTime::GetNSecs() - start;
2057 }
2058 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
2059 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
2060#StdOut
2061#Volatile
2062uncached avg: 0.18048 ms
2063cached avg: 0.182784 ms
2064##
2065##
2066
2067#SeeAlso getBounds
2068#ToDo the results don't make sense, need to profile to figure this out ##
2069
2070##
2071
2072# ------------------------------------------------------------------------------
2073
2074#Method SkRect computeTightBounds() const
2075
2076Returns minimum and maximum x and y values of the lines and curves in Path.
2077Returns (0, 0, 0, 0) if Path contains no points.
2078Returned bounds width and height may be larger or smaller than area affected
2079when Path is drawn.
2080
2081Includes Points associated with kMove_Verb that define empty
2082Contours.
2083
2084Behaves identically to getBounds when Path contains
2085only lines. If Path contains curves, computed bounds includes
2086the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
2087and unlike getBounds, does not cache the result.
2088
2089#Return tight bounds of curves in Path ##
2090
2091#Example
2092 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2093 const SkRect& bounds = path.computeTightBounds();
2094 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
2095 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2096 };
2097 SkPath path;
2098 debugster("empty", path);
2099 path.addCircle(50, 45, 25);
2100 debugster("circle", path);
2101 SkMatrix matrix;
2102 matrix.setRotate(45, 50, 45);
2103 path.transform(matrix);
2104 debugster("rotated circle", path);
2105#StdOut
2106empty bounds = 0, 0, 0, 0
2107circle bounds = 25, 20, 75, 70
2108rotated circle bounds = 25, 20, 75, 70
2109##
2110##
2111
2112#SeeAlso getBounds
2113
2114##
2115
2116# ------------------------------------------------------------------------------
2117
2118#Method bool conservativelyContainsRect(const SkRect& rect) const
2119
2120Returns true if rect is contained by Path.
2121May return false when rect is contained by Path.
2122
2123For now, only returns true if Path has one Contour and is convex.
2124rect may share points and edges with Path and be contained.
2125Returns true if rect is empty, that is, it has zero width or height; and
2126the Point or Line described by rect is contained by Path.
2127
2128#Param rect Rect, Line, or Point checked for containment ##
2129
2130#Return true if rect is contained ##
2131
2132#Example
2133#Height 140
2134#Description
2135Rect is drawn in blue if it is contained by red Path.
2136##
2137void draw(SkCanvas* canvas) {
2138 SkPath path;
2139 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2140 SkRect tests[] = {
2141 { 10, 40, 54, 80 },
2142 { 25, 20, 39, 120 },
2143 { 15, 25, 49, 115 },
2144 { 13, 27, 51, 113 },
2145 };
2146 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2147 SkPaint paint;
2148 paint.setColor(SK_ColorRED);
2149 canvas->drawPath(path, paint);
2150 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2151 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2152 canvas->drawRect(tests[i], paint);
2153 canvas->translate(64, 0);
2154 }
2155}
2156##
2157
2158#SeeAlso contains Op Rect Convexity
2159
2160##
2161
2162# ------------------------------------------------------------------------------
2163
2164#Method void incReserve(unsigned extraPtCount)
2165
2166grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
2167May improve performance and use less memory by
2168reducing the number and size of allocations when creating Path.
2169
Cary Clarkce101242017-09-01 15:51:02 -04002170#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002171
2172#Example
2173#Height 192
2174void draw(SkCanvas* canvas) {
2175 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2176 path->moveTo(size, 0);
2177 for (int i = 1; i < sides; i++) {
2178 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2179 path->lineTo(c * size, s * size);
2180 }
2181 path->close();
2182 };
2183 SkPath path;
2184 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2185 for (int sides = 3; sides < 10; ++sides) {
2186 addPoly(sides, sides, &path);
2187 }
2188 SkMatrix matrix;
2189 matrix.setScale(10, 10, -10, -10);
2190 path.transform(matrix);
2191 SkPaint paint;
2192 paint.setStyle(SkPaint::kStroke_Style);
2193 canvas->drawPath(path, paint);
2194}
2195##
2196
2197#SeeAlso Point_Array
2198
2199##
2200
2201# ------------------------------------------------------------------------------
2202
2203#Method void moveTo(SkScalar x, SkScalar y)
2204
2205Adds beginning of Contour at Point (x, y).
2206
2207#Param x x-coordinate of Contour start ##
2208#Param y y-coordinate of Contour start ##
2209
2210#Example
2211 #Width 140
2212 #Height 100
2213 void draw(SkCanvas* canvas) {
2214 SkRect rect = { 20, 20, 120, 80 };
2215 SkPath path;
2216 path.addRect(rect);
2217 path.moveTo(rect.fLeft, rect.fTop);
2218 path.lineTo(rect.fRight, rect.fBottom);
2219 path.moveTo(rect.fLeft, rect.fBottom);
2220 path.lineTo(rect.fRight, rect.fTop);
2221 SkPaint paint;
2222 paint.setStyle(SkPaint::kStroke_Style);
2223 canvas->drawPath(path, paint);
2224 }
2225##
2226
2227#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2228
2229##
2230
2231#Method void moveTo(const SkPoint& p)
2232
2233Adds beginning of Contour at Point p.
2234
2235#Param p contour start ##
2236
2237#Example
2238 #Width 128
2239 #Height 128
2240void draw(SkCanvas* canvas) {
2241 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
2242 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2243 SkPath path;
2244 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2245 path.moveTo(data[i][0]);
2246 path.lineTo(data[i][1]);
2247 path.lineTo(data[i][2]);
2248 }
2249 SkPaint paint;
2250 paint.setStyle(SkPaint::kStroke_Style);
2251 canvas->drawPath(path, paint);
2252}
2253##
2254
2255#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2256
2257##
2258
2259#Method void rMoveTo(SkScalar dx, SkScalar dy)
2260
2261Adds beginning of Contour relative to Last_Point.
2262If Path is empty, starts Contour at (dx, dy).
2263Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002264Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002265
2266#Param dx offset from Last_Point x to Contour start x ##
2267#Param dy offset from Last_Point y to Contour start y ##
2268
2269#Example
2270 #Height 100
2271 SkPath path;
2272 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2273 path.rMoveTo(25, 2);
2274 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2275 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2276 path.rLineTo(arrow[i].fX, arrow[i].fY);
2277 }
2278 SkPaint paint;
2279 canvas->drawPath(path, paint);
2280 SkPoint lastPt;
2281 path.getLastPt(&lastPt);
2282 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2283##
2284
2285#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2286
2287##
2288
2289# ------------------------------------------------------------------------------
2290
2291#Method void lineTo(SkScalar x, SkScalar y)
2292
2293Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2294kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2295
2296lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2297lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
2298
2299#Param x end of added Line in x ##
2300#Param y end of added Line in y ##
2301
2302#Example
2303#Height 100
2304###$
2305void draw(SkCanvas* canvas) {
2306 SkPaint paint;
2307 paint.setAntiAlias(true);
2308 paint.setTextSize(72);
2309 canvas->drawString("#", 120, 80, paint);
2310 paint.setStyle(SkPaint::kStroke_Style);
2311 paint.setStrokeWidth(5);
2312 SkPath path;
2313 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2314 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2315 unsigned o = 0;
2316 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2317 for (unsigned j = 0; j < 2; o++, j++) {
2318 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2319 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2320 }
2321 }
2322 canvas->drawPath(path, paint);
2323}
2324$$$#
2325##
2326
2327#SeeAlso Contour moveTo rLineTo addRect
2328
2329##
2330
2331# ------------------------------------------------------------------------------
2332
2333#Method void lineTo(const SkPoint& p)
2334
2335Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2336kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2337
2338lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2339lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2340
2341#Param p end Point of added Line ##
2342
2343#Example
2344#Height 100
2345 SkPath path;
2346 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2347 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2348 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2349 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2350 path.moveTo(oxo[i]);
2351 path.lineTo(oxo[i + 1]);
2352 }
2353 SkPaint paint;
2354 paint.setStyle(SkPaint::kStroke_Style);
2355 canvas->drawPath(path, paint);
2356##
2357
2358#SeeAlso Contour moveTo rLineTo addRect
2359
2360##
2361
2362# ------------------------------------------------------------------------------
2363
2364#Method void rLineTo(SkScalar dx, SkScalar dy)
2365
2366Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2367kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2368
2369Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2370then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2371Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002372Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002373
2374#Param dx offset from Last_Point x to Line end x ##
2375#Param dy offset from Last_Point y to Line end y ##
2376
2377#Example
2378#Height 128
2379void draw(SkCanvas* canvas) {
2380 SkPaint paint;
2381 paint.setAntiAlias(true);
2382 paint.setStyle(SkPaint::kStroke_Style);
2383 SkPath path;
2384 path.moveTo(10, 98);
2385 SkScalar x = 0, y = 0;
2386 for (int i = 10; i < 100; i += 5) {
2387 x += i * ((i & 2) - 1);
2388 y += i * (((i + 1) & 2) - 1);
2389 path.rLineTo(x, y);
2390
2391 }
2392 canvas->drawPath(path, paint);
2393}
2394##
2395
2396#SeeAlso Contour moveTo lineTo addRect
2397
2398##
2399
2400# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04002401#Topic Quad
Cary Clarkce101242017-09-01 15:51:02 -04002402#Alias Quad
Cary Clark73fa9722017-08-29 17:36:51 -04002403#Alias Quads
Cary Clarkce101242017-09-01 15:51:02 -04002404#Alias Quadratic_Bezier
2405#Alias Quadratic_Beziers
Cary Clark8032b982017-07-28 11:04:54 -04002406
2407Quad describes a quadratic Bezier, a second-order curve identical to a section
2408of a parabola. Quad begins at a start Point, curves towards a control Point,
2409and then curves to an end Point.
2410
2411#Example
2412#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002413void draw(SkCanvas* canvas) {
2414 SkPaint paint;
2415 paint.setAntiAlias(true);
2416 paint.setStyle(SkPaint::kStroke_Style);
2417 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2418 canvas->drawLine(quadPts[0], quadPts[1], paint);
2419 canvas->drawLine(quadPts[1], quadPts[2], paint);
2420 SkPath path;
2421 path.moveTo(quadPts[0]);
2422 path.quadTo(quadPts[1], quadPts[2]);
2423 paint.setStrokeWidth(3);
2424 canvas->drawPath(path, paint);
2425}
Cary Clark8032b982017-07-28 11:04:54 -04002426##
2427
2428Quad is a special case of Conic where Conic_Weight is set to one.
2429
2430Quad is always contained by the triangle connecting its three Points. Quad
2431begins tangent to the line between start Point and control Point, and ends
2432tangent to the line between control Point and end Point.
2433
2434#Example
2435#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002436void draw(SkCanvas* canvas) {
2437 SkPaint paint;
2438 paint.setAntiAlias(true);
2439 paint.setStyle(SkPaint::kStroke_Style);
2440 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2441 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2442 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2443 paint.setColor(0x7fffffff & colors[i]);
2444 paint.setStrokeWidth(1);
2445 canvas->drawLine(quadPts[0], quadPts[1], paint);
2446 canvas->drawLine(quadPts[1], quadPts[2], paint);
2447 SkPath path;
2448 path.moveTo(quadPts[0]);
2449 path.quadTo(quadPts[1], quadPts[2]);
2450 paint.setStrokeWidth(3);
2451 paint.setColor(colors[i]);
2452 canvas->drawPath(path, paint);
2453 quadPts[1].fY += 30;
2454 }
Cary Clark8032b982017-07-28 11:04:54 -04002455}
2456##
Cary Clark73fa9722017-08-29 17:36:51 -04002457
2458#Method void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
2459
2460 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
2461 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2462 before adding Quad.
2463
2464 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2465 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2466 to Point_Array.
2467
2468 #Param x1 control Point of Quad in x ##
2469 #Param y1 control Point of Quad in y ##
2470 #Param x2 end Point of Quad in x ##
2471 #Param y2 end Point of Quad in y ##
2472
2473 #Example
2474 void draw(SkCanvas* canvas) {
2475 SkPaint paint;
2476 paint.setAntiAlias(true);
2477 paint.setStyle(SkPaint::kStroke_Style);
2478 SkPath path;
2479 path.moveTo(0, -10);
2480 for (int i = 0; i < 128; i += 16) {
2481 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2482 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2483 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2484 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2485 }
2486 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002487 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002488 }
2489 ##
2490
2491 #SeeAlso Contour moveTo conicTo rQuadTo
2492
2493##
2494
2495#Method void quadTo(const SkPoint& p1, const SkPoint& p2)
2496
2497 Adds Quad from Last_Point towards Point p1, to Point p2.
2498 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2499 before adding Quad.
2500
2501 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2502 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2503 to Point_Array.
2504
2505 #Param p1 control Point of added Quad ##
2506 #Param p2 end Point of added Quad ##
2507
2508 #Example
2509 void draw(SkCanvas* canvas) {
2510 SkPaint paint;
2511 paint.setStyle(SkPaint::kStroke_Style);
2512 paint.setAntiAlias(true);
2513 SkPath path;
2514 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2515 path.moveTo(pts[1]);
2516 for (int i = 0; i < 3; ++i) {
2517 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2518 }
2519 canvas->drawPath(path, paint);
2520 }
2521 ##
2522
2523 #SeeAlso Contour moveTo conicTo rQuadTo
2524
2525##
2526
2527#Method void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
2528
2529 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2530 If Path is empty, or last Verb
2531 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2532
2533 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2534 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2535 control and Quad end to Point_Array.
2536 Quad control is Last_Point plus Vector (dx1, dy1).
2537 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002538 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002539
2540 #Param dx1 offset from Last_Point x to Quad control x ##
2541 #Param dy1 offset from Last_Point x to Quad control y ##
2542 #Param dx2 offset from Last_Point x to Quad end x ##
2543 #Param dy2 offset from Last_Point x to Quad end y ##
2544
2545 #Example
2546 void draw(SkCanvas* canvas) {
2547 SkPaint paint;
2548 paint.setAntiAlias(true);
2549 SkPath path;
2550 path.moveTo(128, 20);
2551 path.rQuadTo(-6, 10, -7, 10);
2552 for (int i = 1; i < 32; i += 4) {
2553 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2554 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2555 }
2556 path.quadTo(92, 220, 128, 215);
2557 canvas->drawPath(path, paint);
2558 }
2559 ##
2560
2561 #SeeAlso Contour moveTo conicTo quadTo
2562
2563##
2564
Cary Clark8032b982017-07-28 11:04:54 -04002565#Topic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002566
2567# ------------------------------------------------------------------------------
2568
Cary Clark8032b982017-07-28 11:04:54 -04002569#Topic Conic
2570#Alias Conics
2571
2572Conic describes a conical section: a piece of an ellipse, or a piece of a
2573parabola, or a piece of a hyperbola. Conic begins at a start Point,
2574curves towards a control Point, and then curves to an end Point. The influence
2575of the control Point is determined by Conic_Weight.
2576
Cary Clark73fa9722017-08-29 17:36:51 -04002577Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2578may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002579
2580#Subtopic Weight
Cary Clarke0403842017-09-01 19:21:29 +00002581#Alias Conic_Weights
Cary Clarkce101242017-09-01 15:51:02 -04002582#Alias Weights
Cary Clark8032b982017-07-28 11:04:54 -04002583
2584Weight determines both the strength of the control Point and the type of Conic.
2585If Weight is exactly one, then Conic is identical to Quad; it is always a
2586parabolic segment.
2587
2588
2589
2590#Example
2591#Description
Cary Clark73fa9722017-08-29 17:36:51 -04002592When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002593##
Cary Clark73fa9722017-08-29 17:36:51 -04002594void draw(SkCanvas* canvas) {
2595 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2596 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2597 SkPath path;
2598 path.conicTo(20, 30, 50, 60, 1);
2599 SkPath::Iter iter(path, false);
2600 SkPath::Verb verb;
2601 do {
2602 SkPoint points[4];
2603 verb = iter.next(points);
2604 SkDebugf("%s ", verbNames[(int) verb]);
2605 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2606 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2607 }
2608 if (SkPath::kConic_Verb == verb) {
2609 SkDebugf("weight = %g", iter.conicWeight());
2610 }
2611 SkDebugf("\n");
2612 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002613}
2614#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002615move {0, 0},
2616quad {0, 0}, {20, 30}, {50, 60},
Cary Clark8032b982017-07-28 11:04:54 -04002617done
2618##
2619##
2620
2621If weight is less than one, Conic is an elliptical segment.
2622
2623#Example
2624#Description
2625A 90 degree circular arc has the weight
2626#Formula
26271 / sqrt(2)
2628##
Cary Clark6fc50412017-09-21 12:31:06 -04002629.
Cary Clark8032b982017-07-28 11:04:54 -04002630##
Cary Clark73fa9722017-08-29 17:36:51 -04002631void draw(SkCanvas* canvas) {
2632 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2633 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2634 SkPath path;
2635 path.arcTo(20, 0, 20, 20, 20);
2636 SkPath::Iter iter(path, false);
2637 SkPath::Verb verb;
2638 do {
2639 SkPoint points[4];
2640 verb = iter.next(points);
2641 SkDebugf("%s ", verbNames[(int) verb]);
2642 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2643 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2644 }
2645 if (SkPath::kConic_Verb == verb) {
2646 SkDebugf("weight = %g", iter.conicWeight());
2647 }
2648 SkDebugf("\n");
2649 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002650}
2651#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002652move {0, 0},
2653conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark8032b982017-07-28 11:04:54 -04002654done
2655##
2656##
2657
Cary Clarkce101242017-09-01 15:51:02 -04002658If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002659a hyperbolic segment can be approximated by straight lines connecting the
2660control Point with the end Points.
2661
2662#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002663void draw(SkCanvas* canvas) {
2664 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2665 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2666 SkPath path;
2667 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2668 SkPath::Iter iter(path, false);
2669 SkPath::Verb verb;
2670 do {
2671 SkPoint points[4];
2672 verb = iter.next(points);
2673 SkDebugf("%s ", verbNames[(int) verb]);
2674 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2675 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2676 }
2677 if (SkPath::kConic_Verb == verb) {
2678 SkDebugf("weight = %g", iter.conicWeight());
2679 }
2680 SkDebugf("\n");
2681 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002682}
2683#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002684move {0, 0},
2685line {0, 0}, {20, 0},
2686line {20, 0}, {20, 20},
Cary Clark8032b982017-07-28 11:04:54 -04002687done
2688##
2689##
2690
2691#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002692
2693#Method void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2694 SkScalar w)
2695
2696 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
2697 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2698 before adding Conic.
2699
2700 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2701
2702 If w is finite and not one, appends kConic_Verb to Verb_Array;
2703 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2704
2705 If w is one, appends kQuad_Verb to Verb_Array, and
2706 (x1, y1), (x2, y2) to Point_Array.
2707
2708 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2709 (x1, y1), (x2, y2) to Point_Array.
2710
2711 #Param x1 control Point of Conic in x ##
2712 #Param y1 control Point of Conic in y ##
2713 #Param x2 end Point of Conic in x ##
2714 #Param y2 end Point of Conic in y ##
2715 #Param w weight of added Conic ##
2716
2717 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002718 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002719 #Description
2720 As weight increases, curve is pulled towards control point.
2721 The bottom two curves are elliptical; the next is parabolic; the
2722 top curve is hyperbolic.
2723 ##
2724void draw(SkCanvas* canvas) {
2725 SkPaint paint;
2726 paint.setAntiAlias(true);
2727 paint.setStyle(SkPaint::kStroke_Style);
2728 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2729 canvas->drawLine(conicPts[0], conicPts[1], paint);
2730 canvas->drawLine(conicPts[1], conicPts[2], paint);
2731 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2732 paint.setStrokeWidth(3);
2733 SkScalar weight = 0.5f;
2734 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2735 SkPath path;
2736 path.moveTo(conicPts[0]);
2737 path.conicTo(conicPts[1], conicPts[2], weight);
2738 paint.setColor(colors[i]);
2739 canvas->drawPath(path, paint);
2740 weight += 0.25f;
2741 }
2742}
2743 ##
2744
2745 #SeeAlso rConicTo arcTo addArc quadTo
2746
2747##
2748
2749#Method void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
2750
2751 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
2752 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2753 before adding Conic.
2754
2755 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2756
2757 If w is finite and not one, appends kConic_Verb to Verb_Array;
2758 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2759
2760 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2761 to Point_Array.
2762
2763 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2764 Points p1, p2 to Point_Array.
2765
2766 #Param p1 control Point of added Conic ##
2767 #Param p2 end Point of added Conic ##
2768 #Param w weight of added Conic ##
2769
2770 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002771 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002772 #Description
2773 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002774 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002775 ##
2776void draw(SkCanvas* canvas) {
2777 SkPaint paint;
2778 paint.setAntiAlias(true);
2779 paint.setStyle(SkPaint::kStroke_Style);
2780 SkRect oval = {0, 20, 120, 140};
2781 SkPath path;
2782 for (int i = 0; i < 4; ++i) {
2783 path.moveTo(oval.centerX(), oval.fTop);
2784 path.arcTo(oval, -90, 90 - 20 * i, false);
2785 oval.inset(15, 15);
2786 }
2787 path.offset(100, 0);
2788 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2789 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2790 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2791 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2792 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2793 for (int i = 0; i < 4; ++i) {
2794 path.moveTo(conicPts[i][0]);
2795 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2796 }
2797 canvas->drawPath(path, paint);
2798}
2799 ##
2800
2801 #SeeAlso rConicTo arcTo addArc quadTo
2802
2803##
2804
2805#Method void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2806 SkScalar w)
2807
2808 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2809 weighted by w. If Path is empty, or last Verb
2810 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2811
2812 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2813 if needed.
2814
2815 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2816 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2817 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2818 twice to Verb_Array.
2819
2820 In all cases appends Points control and end to Point_Array.
2821 control is Last_Point plus Vector (dx1, dy1).
2822 end is Last_Point plus Vector (dx2, dy2).
2823
Cary Clarkce101242017-09-01 15:51:02 -04002824 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002825
2826 #Param dx1 offset from Last_Point x to Conic control x ##
2827 #Param dy1 offset from Last_Point x to Conic control y ##
2828 #Param dx2 offset from Last_Point x to Conic end x ##
2829 #Param dy2 offset from Last_Point x to Conic end y ##
2830 #Param w weight of added Conic ##
2831
2832 #Example
2833 #Height 140
2834 void draw(SkCanvas* canvas) {
2835 SkPaint paint;
2836 paint.setAntiAlias(true);
2837 paint.setStyle(SkPaint::kStroke_Style);
2838 SkPath path;
2839 path.moveTo(20, 80);
2840 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2841 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2842 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2843 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2844 canvas->drawPath(path, paint);
2845 }
2846 ##
2847
2848 #SeeAlso conicTo arcTo addArc quadTo
2849
2850##
2851
2852#Topic Conic ##
2853
2854# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04002855#Topic Cubic
Cary Clarkce101242017-09-01 15:51:02 -04002856#Alias Cubic
Cary Clark8032b982017-07-28 11:04:54 -04002857#Alias Cubics
Cary Clarkce101242017-09-01 15:51:02 -04002858#Alias Cubic_Bezier
2859#Alias Cubic_Beziers
Cary Clark8032b982017-07-28 11:04:54 -04002860
Cary Clarkce101242017-09-01 15:51:02 -04002861Cubic describes a Bezier curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002862Cubic begins at a start Point, curving towards the first control Point;
2863and curves from the end Point towards the second control Point.
2864
2865#Example
2866#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002867void draw(SkCanvas* canvas) {
2868 SkPaint paint;
2869 paint.setAntiAlias(true);
2870 paint.setStyle(SkPaint::kStroke_Style);
2871 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2872 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2873 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2874 paint.setColor(0x7fffffff & colors[i]);
2875 paint.setStrokeWidth(1);
2876 for (unsigned j = 0; j < 3; ++j) {
2877 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2878 }
2879 SkPath path;
2880 path.moveTo(cubicPts[0]);
2881 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2882 paint.setStrokeWidth(3);
2883 paint.setColor(colors[i]);
2884 canvas->drawPath(path, paint);
2885 cubicPts[1].fY += 30;
2886 cubicPts[2].fX += 30;
2887 }
Cary Clark8032b982017-07-28 11:04:54 -04002888}
2889##
Cary Clark73fa9722017-08-29 17:36:51 -04002890
2891#Method void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2892 SkScalar x3, SkScalar y3)
2893
2894Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2895(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2896(0, 0) before adding Cubic.
2897
2898Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2899then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
2900to Point_Array.
2901
2902#Param x1 first control Point of Cubic in x ##
2903#Param y1 first control Point of Cubic in y ##
2904#Param x2 second control Point of Cubic in x ##
2905#Param y2 second control Point of Cubic in y ##
2906#Param x3 end Point of Cubic in x ##
2907#Param y3 end Point of Cubic in y ##
2908
2909#Example
2910void draw(SkCanvas* canvas) {
2911 SkPaint paint;
2912 paint.setAntiAlias(true);
2913 paint.setStyle(SkPaint::kStroke_Style);
2914 SkPath path;
2915 path.moveTo(0, -10);
2916 for (int i = 0; i < 128; i += 16) {
2917 SkScalar c = i * 0.5f;
2918 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2919 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2920 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2921 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2922 }
2923 path.offset(128, 128);
2924 canvas->drawPath(path, paint);
2925}
2926##
2927
2928#SeeAlso Contour moveTo rCubicTo quadTo
2929
2930##
2931
2932# ------------------------------------------------------------------------------
2933
2934#Method void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
2935
2936Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2937Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2938(0, 0) before adding Cubic.
2939
2940Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2941then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2942to Point_Array.
2943
2944#Param p1 first control Point of Cubic ##
2945#Param p2 second control Point of Cubic ##
2946#Param p3 end Point of Cubic ##
2947
2948#Example
2949#Height 84
2950 SkPaint paint;
2951 paint.setAntiAlias(true);
2952 paint.setStyle(SkPaint::kStroke_Style);
2953 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2954 SkPath path;
2955 path.moveTo(pts[0]);
2956 path.cubicTo(pts[1], pts[2], pts[3]);
2957 canvas->drawPath(path, paint);
2958##
2959
2960#SeeAlso Contour moveTo rCubicTo quadTo
2961
2962##
2963
2964# ------------------------------------------------------------------------------
2965
2966#Method void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2967 SkScalar x3, SkScalar y3)
2968
2969 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2970 Vector (dx2, dy2), to Vector (dx3, dy3).
2971 If Path is empty, or last Verb
2972 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2973
2974 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2975 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2976 control and Cubic end to Point_Array.
2977 Cubic control is Last_Point plus Vector (dx1, dy1).
2978 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002979 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002980
2981 #Param x1 offset from Last_Point x to first Cubic control x ##
2982 #Param y1 offset from Last_Point x to first Cubic control y ##
2983 #Param x2 offset from Last_Point x to second Cubic control x ##
2984 #Param y2 offset from Last_Point x to second Cubic control y ##
2985 #Param x3 offset from Last_Point x to Cubic end x ##
2986 #Param y3 offset from Last_Point x to Cubic end y ##
2987
2988#Example
2989 void draw(SkCanvas* canvas) {
2990 SkPaint paint;
2991 paint.setAntiAlias(true);
2992 paint.setStyle(SkPaint::kStroke_Style);
2993 SkPath path;
2994 path.moveTo(24, 108);
2995 for (int i = 0; i < 16; i++) {
2996 SkScalar sx, sy;
2997 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2998 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
2999 }
3000 canvas->drawPath(path, paint);
3001 }
3002##
3003
3004#SeeAlso Contour moveTo cubicTo quadTo
3005
3006##
3007
3008#Topic Cubic ##
3009
3010# ------------------------------------------------------------------------------
3011
3012#Topic Arc
3013
3014Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
3015by start point and end point, and by radius and tangent lines. Each construction has advantages,
3016and some constructions correspond to Arc drawing in graphics standards.
3017
3018All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
3019Conic describes an Arc of some Oval or Circle.
3020
3021arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
3022describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
3023which may continue Contour or start a new one. This construction is similar to PostScript and
3024HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
3025requiring Path.
3026
3027arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
3028describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
3029where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
3030HTML_Canvas arcs.
3031
3032arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
3033 SkScalar x, SkScalar y)
3034describes Arc as part of Oval with radii (rx, ry), beginning at
3035last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
3036so additional values choose a single solution. This construction is similar to SVG arcs.
3037
3038conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
3039conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
3040constructions are converted to Conic data when added to Path.
3041
3042#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
3043 do the kind of table shown in the illustration.
3044 example is spaced correctly on fiddle but spacing is too wide on pc
3045##
3046
3047#Example
3048#Height 300
3049#Width 600
3050#Description
3051#List
3052# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
3053# <sup>2</sup> parameter sets force MoveTo ##
3054# <sup>3</sup> start angle must be multiple of 90 degrees. ##
3055# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
3056# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3057 Direction sweep, SkScalar x, SkScalar y) ##
3058#List ##
3059#Description ##
3060#Function
3061struct data {
3062 const char* name;
3063 char super;
3064 int yn[10];
3065};
3066
3067const data dataSet[] = {
3068{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
3069{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
3070{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
3071{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
3072{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
3073{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
3074};
3075
3076#define __degree_symbol__ "\xC2" "\xB0"
3077
3078const char* headers[] = {
3079 "Oval part",
3080 "force moveTo",
3081 "can draw 180" __degree_symbol__,
3082 "can draw 360" __degree_symbol__,
3083 "can draw greater than 360" __degree_symbol__,
3084 "ignored if radius is zero",
3085 "ignored if sweep is zero",
3086 "requires Path",
3087 "describes rotation",
3088 "describes perspective",
3089};
3090
3091const char* yna[] = {
3092 "n/a",
3093 "no",
3094 "yes"
3095};
3096
3097##
3098void draw(SkCanvas* canvas) {
3099 SkPaint lp;
3100 lp.setAntiAlias(true);
3101 SkPaint tp(lp);
3102 SkPaint sp(tp);
3103 SkPaint bp(tp);
3104 bp.setFakeBoldText(true);
3105 sp.setTextSize(10);
3106 lp.setColor(SK_ColorGRAY);
3107 canvas->translate(0, 32);
3108 const int tl = 115;
3109 for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
3110 canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
3111 if (0 == col) {
3112 continue;
3113 }
3114 canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
3115 SkPath path;
3116 path.moveTo(tl - 3 + col * 35, 103);
3117 path.lineTo(tl + 124 + col * 35, -24);
3118 canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
3119 }
3120 for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
3121 if (0 == row) {
3122 canvas->drawLine(tl, 100, tl + 350, 100, lp);
3123 } else {
3124 canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
3125 }
3126 if (row == SK_ARRAY_COUNT(dataSet)) {
3127 break;
3128 }
3129 canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
3130 if (dataSet[row].super) {
3131 SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
3132 canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
3133 }
3134 for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
3135 int val = dataSet[row].yn[col];
3136 canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
3137 if (val > 1) {
3138 char supe = '0' + val - 1;
3139 canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
3140 }
3141 }
3142 }
3143}
3144#Example ##
3145
3146#Example
3147#Height 128
3148#Description
3149#ToDo make this a list or table ##
31501 describes an arc from an oval, a starting angle, and a sweep angle.
31512 is similar to 1, but does not require building a path to draw.
31523 is similar to 1, but always begins new Contour.
31534 describes an arc from a pair of tangent lines and a radius.
31545 describes an arc from Oval center, arc start Point and arc end Point.
31556 describes an arc from a pair of tangent lines and a Conic_Weight.
3156##
3157void draw(SkCanvas* canvas) {
3158 SkRect oval = {8, 8, 56, 56};
3159 SkPaint ovalPaint;
3160 ovalPaint.setAntiAlias(true);
3161 SkPaint textPaint(ovalPaint);
3162 ovalPaint.setStyle(SkPaint::kStroke_Style);
3163 SkPaint arcPaint(ovalPaint);
3164 arcPaint.setStrokeWidth(5);
3165 arcPaint.setColor(SK_ColorBLUE);
3166 canvas->translate(-64, 0);
3167 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3168 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3169 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3170 canvas->drawOval(oval, ovalPaint);
3171 SkPath path;
3172 path.moveTo({56, 32});
3173 switch (arcStyle) {
3174 case '1':
3175 path.arcTo(oval, 0, 90, false);
3176 break;
3177 case '2':
3178 canvas->drawArc(oval, 0, 90, false, arcPaint);
3179 continue;
3180 case '3':
3181 path.addArc(oval, 0, 90);
3182 break;
3183 case '4':
3184 path.arcTo({56, 56}, {32, 56}, 24);
3185 break;
3186 case '5':
3187 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3188 break;
3189 case '6':
3190 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3191 break;
3192 }
3193 canvas->drawPath(path, arcPaint);
3194 }
3195}
3196#Example ##
3197
3198
3199#Method void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
3200
3201Append Arc to Path. Arc added is part of ellipse
3202bounded by oval, from startAngle through sweepAngle. Both startAngle and
3203sweepAngle are measured in degrees, where zero degrees is aligned with the
3204positive x-axis, and positive sweeps extends Arc clockwise.
3205
3206arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3207is false and Path is not empty. Otherwise, added Contour begins with first point
3208of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3209
3210#Param oval bounds of ellipse containing Arc ##
3211#Param startAngle starting angle of Arc in degrees ##
3212#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3213#Param forceMoveTo true to start a new contour with Arc ##
3214
3215#Example
3216#Height 200
3217#Description
3218arcTo continues a previous contour when forceMoveTo is false and when Path
3219is not empty.
3220##
3221void draw(SkCanvas* canvas) {
3222 SkPaint paint;
3223 SkPath path;
3224 paint.setStyle(SkPaint::kStroke_Style);
3225 paint.setStrokeWidth(4);
3226 path.moveTo(0, 0);
3227 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3228 canvas->drawPath(path, paint);
3229 path.rewind();
3230 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3231 canvas->drawPath(path, paint);
3232 path.rewind();
3233 path.moveTo(0, 0);
3234 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3235 canvas->drawPath(path, paint);
3236}
3237##
3238
3239#SeeAlso addArc SkCanvas::drawArc conicTo
3240
3241##
3242
3243# ------------------------------------------------------------------------------
3244
3245#Method void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
3246
3247Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3248weighted to describe part of Circle. Arc is contained by tangent from
3249last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
3250is part of Circle sized to radius, positioned so it touches both tangent lines.
3251
3252#ToDo allow example to hide source and not be exposed as fiddle ##
3253
3254#Example
3255#Height 226
3256void draw(SkCanvas* canvas) {
3257 SkPaint tangentPaint;
3258 tangentPaint.setAntiAlias(true);
3259 SkPaint textPaint(tangentPaint);
3260 tangentPaint.setStyle(SkPaint::kStroke_Style);
3261 tangentPaint.setColor(SK_ColorGRAY);
3262 SkPaint arcPaint(tangentPaint);
3263 arcPaint.setStrokeWidth(5);
3264 arcPaint.setColor(SK_ColorBLUE);
3265 SkPath path;
3266 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3267 SkScalar radius = 50;
3268 path.moveTo(pts[0]);
3269 path.arcTo(pts[1], pts[2], radius);
3270 canvas->drawLine(pts[0], pts[1], tangentPaint);
3271 canvas->drawLine(pts[1], pts[2], tangentPaint);
3272 SkPoint lastPt;
3273 (void) path.getLastPt(&lastPt);
3274 SkVector radial = pts[2] - pts[1];
3275 radial.setLength(radius);
3276 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3277 canvas->drawCircle(center, radius, tangentPaint);
3278 canvas->drawLine(lastPt, center, tangentPaint);
3279 radial = pts[1] - pts[0];
3280 radial.setLength(radius);
3281 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3282 canvas->drawLine(center, arcStart, tangentPaint);
3283 canvas->drawPath(path, arcPaint);
3284 textPaint.setTextAlign(SkPaint::kRight_Align);
3285 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3286 textPaint.setTextAlign(SkPaint::kLeft_Align);
3287 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3288 textPaint.setTextAlign(SkPaint::kCenter_Align);
3289 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3290 textPaint.setTextAlign(SkPaint::kRight_Align);
3291 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3292 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3293}
3294##
3295
3296If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3297The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3298
3299#Example
3300#Height 128
3301void draw(SkCanvas* canvas) {
3302 SkPaint tangentPaint;
3303 tangentPaint.setAntiAlias(true);
3304 SkPaint textPaint(tangentPaint);
3305 tangentPaint.setStyle(SkPaint::kStroke_Style);
3306 tangentPaint.setColor(SK_ColorGRAY);
3307 SkPaint arcPaint(tangentPaint);
3308 arcPaint.setStrokeWidth(5);
3309 arcPaint.setColor(SK_ColorBLUE);
3310 SkPath path;
3311 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3312 SkScalar radius = 50;
3313 path.moveTo(pts[0]);
3314 path.arcTo(pts[1], pts[2], radius);
3315 canvas->drawLine(pts[0], pts[1], tangentPaint);
3316 canvas->drawLine(pts[1], pts[2], tangentPaint);
3317 SkPoint lastPt;
3318 (void) path.getLastPt(&lastPt);
3319 SkVector radial = pts[2] - pts[1];
3320 radial.setLength(radius);
3321 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3322 canvas->drawLine(lastPt, center, tangentPaint);
3323 radial = pts[1] - pts[0];
3324 radial.setLength(radius);
3325 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3326 canvas->drawLine(center, arcStart, tangentPaint);
3327 canvas->drawPath(path, arcPaint);
3328 textPaint.setTextAlign(SkPaint::kCenter_Align);
3329 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3330 textPaint.setTextAlign(SkPaint::kLeft_Align);
3331 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3332 textPaint.setTextAlign(SkPaint::kCenter_Align);
3333 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3334 textPaint.setTextAlign(SkPaint::kRight_Align);
3335 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3336 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3337}
3338##
3339
3340Arc sweep is always less than 180 degrees. If radius is zero, or if
3341tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3342
3343arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003344arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003345
3346#Param x1 x common to pair of tangents ##
3347#Param y1 y common to pair of tangents ##
3348#Param x2 x end of second tangent ##
3349#Param y2 y end of second tangent ##
3350#Param radius distance from Arc to Circle center ##
3351
3352#Example
3353#Description
3354arcTo is represented by Line and circular Conic in Path.
3355##
3356void draw(SkCanvas* canvas) {
3357 SkPath path;
3358 path.moveTo({156, 20});
3359 path.arcTo(200, 20, 170, 50, 50);
3360 SkPath::Iter iter(path, false);
3361 SkPoint p[4];
3362 SkPath::Verb verb;
3363 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3364 switch (verb) {
3365 case SkPath::kMove_Verb:
3366 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3367 break;
3368 case SkPath::kLine_Verb:
3369 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3370 break;
3371 case SkPath::kConic_Verb:
3372 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3373 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3374 break;
3375 default:
3376 SkDebugf("unexpected verb\n");
3377 }
3378 }
3379}
3380#StdOut
3381move to (156,20)
3382line (156,20),(79.2893,20)
3383conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3384##
3385##
3386
3387#SeeAlso conicTo
3388
3389##
3390
3391# ------------------------------------------------------------------------------
3392
3393#Method void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
3394
3395Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3396weighted to describe part of Circle. Arc is contained by tangent from
3397last Path point to p1, and tangent from p1 to p2. Arc
3398is part of Circle sized to radius, positioned so it touches both tangent lines.
3399
3400If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3401The length of Vector from p1 to p2 does not affect Arc.
3402
3403Arc sweep is always less than 180 degrees. If radius is zero, or if
3404tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3405
3406arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003407arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003408
3409#Param p1 Point common to pair of tangents ##
3410#Param p2 end of second tangent ##
3411#Param radius distance from Arc to Circle center ##
3412
3413#Example
3414#Description
3415Because tangent lines are parallel, arcTo appends line from last Path Point to
3416p1, but does not append a circular Conic.
3417##
3418void draw(SkCanvas* canvas) {
3419 SkPath path;
3420 path.moveTo({156, 20});
3421 path.arcTo({200, 20}, {170, 20}, 50);
3422 SkPath::Iter iter(path, false);
3423 SkPoint p[4];
3424 SkPath::Verb verb;
3425 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3426 switch (verb) {
3427 case SkPath::kMove_Verb:
3428 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3429 break;
3430 case SkPath::kLine_Verb:
3431 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3432 break;
3433 case SkPath::kConic_Verb:
3434 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3435 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3436 break;
3437 default:
3438 SkDebugf("unexpected verb\n");
3439 }
3440 }
3441}
3442#StdOut
3443move to (156,20)
3444line (156,20),(200,20)
3445##
3446##
3447
3448#SeeAlso conicTo
3449
3450##
3451
3452# ------------------------------------------------------------------------------
3453
3454#Enum ArcSize
3455
3456#Code
3457 enum ArcSize {
3458 kSmall_ArcSize,
3459 kLarge_ArcSize,
3460 };
3461##
3462
3463Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3464ArcSize and Direction select one of the four Oval parts.
3465
3466#Const kSmall_ArcSize 0
3467Smaller of Arc pair.
3468##
3469#Const kLarge_ArcSize 1
3470Larger of Arc pair.
3471##
3472
3473#Example
3474#Height 160
3475#Description
3476Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3477Two routes are large, and two routes are counterclockwise. The one route both large
3478and counterclockwise is blue.
3479##
3480void draw(SkCanvas* canvas) {
3481 SkPaint paint;
3482 paint.setAntiAlias(true);
3483 paint.setStyle(SkPaint::kStroke_Style);
3484 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3485 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3486 SkPath path;
3487 path.moveTo({120, 50});
3488 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3489 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3490 paint.setColor(SK_ColorBLUE);
3491 paint.setStrokeWidth(3);
3492 }
3493 canvas->drawPath(path, paint);
3494 }
3495 }
3496}
3497##
3498
3499#SeeAlso arcTo Direction
3500
3501##
3502
3503# ------------------------------------------------------------------------------
3504
3505#Method void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3506 Direction sweep, SkScalar x, SkScalar y)
3507
Cary Clarkce101242017-09-01 15:51:02 -04003508Append Arc to Path. Arc is implemented by one or more Conics weighted to describe part of Oval
Cary Clark73fa9722017-08-29 17:36:51 -04003509with radii (rx, ry) rotated by xAxisRotate degrees. Arc curves from last Path Point to (x, y),
3510choosing one of four possible routes: clockwise or counterclockwise, and smaller or larger.
3511
3512Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if either radii are zero,
3513or if last Path Point equals (x, y). arcTo scales radii (rx, ry) to fit last Path Point and
3514(x, y) if both are greater than zero but too small.
3515
3516arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003517arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3518opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while kCW_Direction
Cary Clark73fa9722017-08-29 17:36:51 -04003519cast to int is zero.
3520
3521#Param rx radius in x before x-axis rotation ##
3522#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003523#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003524#Param largeArc chooses smaller or larger Arc ##
3525#Param sweep chooses clockwise or counterclockwise Arc ##
3526#Param x end of Arc ##
3527#Param y end of Arc ##
3528
3529#Example
3530#Height 160
3531void draw(SkCanvas* canvas) {
3532 SkPaint paint;
3533 paint.setAntiAlias(true);
3534 paint.setStyle(SkPaint::kStroke_Style);
3535 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3536 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3537 SkPath path;
3538 path.moveTo({120, 50});
3539 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3540 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3541 paint.setColor(SK_ColorBLUE);
3542 paint.setStrokeWidth(3);
3543 }
3544 canvas->drawPath(path, paint);
3545 }
3546 }
3547}
3548##
3549
3550#SeeAlso rArcTo ArcSize Direction
3551
3552##
3553
3554# ------------------------------------------------------------------------------
3555
3556#Method void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
3557 const SkPoint xy)
3558
3559Append Arc to Path. Arc is implemented by one or more Conic weighted to describe part of Oval
3560with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last Path Point to
3561(xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise,
3562and smaller or larger.
3563
3564Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either radii are zero,
3565or if last Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
Cary Clarkce101242017-09-01 15:51:02 -04003566xy if both are greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003567
3568arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003569arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3570opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3571kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003572
3573#Param r radii in x and y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003574#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003575#Param largeArc chooses smaller or larger Arc ##
3576#Param sweep chooses clockwise or counterclockwise Arc ##
3577#Param xy end of Arc ##
3578
3579#Example
3580#Height 108
3581void draw(SkCanvas* canvas) {
3582 SkPaint paint;
3583 SkPath path;
3584 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3585 for (auto start : starts) {
3586 path.moveTo(start.fX, start.fY);
3587 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3588 }
3589 canvas->drawPath(path, paint);
3590}
3591##
3592
3593#SeeAlso rArcTo ArcSize Direction
3594
3595##
3596
3597# ------------------------------------------------------------------------------
3598
3599#Method void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3600 Direction sweep, SkScalar dx, SkScalar dy)
3601
3602Append Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003603more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
3604xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point
Cary Clark73fa9722017-08-29 17:36:51 -04003605#Formula
3606(x0 + dx, y0 + dy)
3607##
3608, choosing one of four possible routes: clockwise or
3609counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3610is (0, 0).
3611
Cary Clarkce101242017-09-01 15:51:02 -04003612Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3613if either radii are zero, or if last Path Point equals end Point.
3614arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3615greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003616
3617arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003618arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3619opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003620kCW_Direction cast to int is zero.
3621
3622#Param rx radius in x before x-axis rotation ##
3623#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003624#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003625#Param largeArc chooses smaller or larger Arc ##
3626#Param sweep chooses clockwise or counterclockwise Arc ##
3627#Param dx x offset end of Arc from last Path Point ##
3628#Param dy y offset end of Arc from last Path Point ##
3629
3630#Example
3631#Height 108
3632void draw(SkCanvas* canvas) {
3633 SkPaint paint;
3634 SkPath path;
3635 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3636 for (auto start : starts) {
3637 path.moveTo(start.fX, start.fY);
3638 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3639 }
3640 canvas->drawPath(path, paint);
3641}
3642##
3643
3644#SeeAlso arcTo ArcSize Direction
3645
3646##
3647
3648#Topic Arc ##
3649
3650# ------------------------------------------------------------------------------
3651
3652#Method void close()
3653
3654Append kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003655with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003656with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
3657Paint_Stroke_Cap at Contour start and end; closed Contour draws
3658Paint_Stroke_Join at Contour start and end.
3659
3660close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3661
3662#Example
3663void draw(SkCanvas* canvas) {
3664 SkPaint paint;
3665 paint.setStrokeWidth(15);
3666 paint.setStrokeCap(SkPaint::kRound_Cap);
3667 SkPath path;
3668 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3669 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3670 for (int loop = 0; loop < 2; ++loop) {
3671 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3672 SkPaint::kStrokeAndFill_Style} ) {
3673 paint.setStyle(style);
3674 canvas->drawPath(path, paint);
3675 canvas->translate(85, 0);
3676 }
3677 path.close();
3678 canvas->translate(-255, 128);
3679 }
3680}
3681##
3682
3683#SeeAlso
3684
3685##
3686
3687# ------------------------------------------------------------------------------
3688
3689#Method static bool IsInverseFillType(FillType fill)
3690
3691Returns true if fill is inverted and Path with fill represents area outside
3692of its geometric bounds.
3693
3694#Table
3695#Legend
3696# FillType # is inverse ##
3697##
3698# kWinding_FillType # false ##
3699# kEvenOdd_FillType # false ##
3700# kInverseWinding_FillType # true ##
3701# kInverseEvenOdd_FillType # true ##
3702##
3703
3704#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3705 kInverseWinding_FillType, kInverseEvenOdd_FillType
3706##
3707
3708#Return true if Path fills outside its bounds ##
3709
3710#Example
3711#Function
3712#define nameValue(fill) { SkPath::fill, #fill }
3713
3714##
3715void draw(SkCanvas* canvas) {
3716 struct {
3717 SkPath::FillType fill;
3718 const char* name;
3719 } fills[] = {
3720 nameValue(kWinding_FillType),
3721 nameValue(kEvenOdd_FillType),
3722 nameValue(kInverseWinding_FillType),
3723 nameValue(kInverseEvenOdd_FillType),
3724 };
3725 for (auto fill: fills ) {
3726 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3727 "true" : "false");
3728 }
3729}
3730#StdOut
3731IsInverseFillType(kWinding_FillType) == false
3732IsInverseFillType(kEvenOdd_FillType) == false
3733IsInverseFillType(kInverseWinding_FillType) == true
3734IsInverseFillType(kInverseEvenOdd_FillType) == true
3735##
3736##
3737
3738#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3739
3740##
3741
3742# ------------------------------------------------------------------------------
3743
3744#Method static FillType ConvertToNonInverseFillType(FillType fill)
3745
3746Returns equivalent Fill_Type representing Path fill inside its bounds.
3747.
3748
3749#Table
3750#Legend
3751# FillType # inside FillType ##
3752##
3753# kWinding_FillType # kWinding_FillType ##
3754# kEvenOdd_FillType # kEvenOdd_FillType ##
3755# kInverseWinding_FillType # kWinding_FillType ##
3756# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3757##
3758
3759#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3760 kInverseWinding_FillType, kInverseEvenOdd_FillType
3761##
3762
3763#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3764
3765#Example
3766#Function
3767#define nameValue(fill) { SkPath::fill, #fill }
3768
3769##
3770void draw(SkCanvas* canvas) {
3771 struct {
3772 SkPath::FillType fill;
3773 const char* name;
3774 } fills[] = {
3775 nameValue(kWinding_FillType),
3776 nameValue(kEvenOdd_FillType),
3777 nameValue(kInverseWinding_FillType),
3778 nameValue(kInverseEvenOdd_FillType),
3779 };
3780 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3781 if (fills[i].fill != (SkPath::FillType) i) {
3782 SkDebugf("fills array order does not match FillType enum order");
3783 break;
3784 }
3785 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3786 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3787 }
3788}
3789#StdOut
3790ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3791ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3792ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3793ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3794##
3795##
3796
3797#SeeAlso FillType getFillType setFillType IsInverseFillType
3798
3799##
3800
3801# ------------------------------------------------------------------------------
3802
3803#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3804 SkScalar w, SkPoint pts[], int pow2)
3805
3806Approximates Conic with Quad array. Conic is constructed from start Point p0,
3807control Point p1, end Point p2, and weight w.
3808Quad array is stored in pts; this storage is supplied by caller.
3809Maximum Quad count is 2 to the pow2.
3810Every third point in array shares last Point of previous Quad and first Point of
3811next Quad. Maximum pts storage size is given by:
3812#Formula
3813(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
3814##
Cary Clark6fc50412017-09-21 12:31:06 -04003815
Cary Clark73fa9722017-08-29 17:36:51 -04003816ConvertConicToQuads returns Quad count used the approximation, which may be smaller
3817than the number requested.
3818
3819Conic_Weight determines the amount of influence Conic control point has on the curve.
3820w less than one represents an elliptical section. w greater than one represents
3821a hyperbolic section. w equal to one represents a parabolic section.
3822
3823Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3824of up to 90 degrees; in this case, set pow2 to one.
3825
3826#Param p0 Conic start Point ##
3827#Param p1 Conic control Point ##
3828#Param p2 Conic end Point ##
3829#Param w Conic weight ##
3830#Param pts storage for Quad array ##
3831#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3832
Cary Clarka523d2d2017-08-30 08:58:10 -04003833#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003834
3835#Example
3836#Description
3837A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3838The middle curve is nearly circular. The top-right curve is parabolic, which can
3839be drawn exactly with a single Quad.
3840##
3841void draw(SkCanvas* canvas) {
3842 SkPaint conicPaint;
3843 conicPaint.setAntiAlias(true);
3844 conicPaint.setStyle(SkPaint::kStroke_Style);
3845 SkPaint quadPaint(conicPaint);
3846 quadPaint.setColor(SK_ColorRED);
3847 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3848 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3849 SkPoint quads[5];
3850 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3851 SkPath path;
3852 path.moveTo(conic[0]);
3853 path.conicTo(conic[1], conic[2], weight);
3854 canvas->drawPath(path, conicPaint);
3855 path.rewind();
3856 path.moveTo(quads[0]);
3857 path.quadTo(quads[1], quads[2]);
3858 path.quadTo(quads[3], quads[4]);
3859 canvas->drawPath(path, quadPaint);
3860 canvas->translate(50, -50);
3861 }
3862}
3863##
3864
3865#SeeAlso Conic Quad
3866
3867##
3868
3869# ------------------------------------------------------------------------------
3870
3871#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
3872
Cary Clarkce101242017-09-01 15:51:02 -04003873Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003874If false: rect, isClosed, and direction are unchanged.
3875If true: rect, isClosed, and direction are written to if not nullptr.
3876
3877rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3878that do not alter the area drawn by the returned rect.
3879
3880#Param rect storage for bounds of Rect; may be nullptr ##
3881#Param isClosed storage set to true if Path is closed; may be nullptr ##
3882#Param direction storage set to Rect direction; may be nullptr ##
3883
3884#Return true if Path contains Rect ##
3885
3886#Example
3887#Description
3888After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3889following lineTo does not. addPoly returns true even though rect is not closed, and one
3890side of rect is made up of consecutive line segments.
3891##
3892void draw(SkCanvas* canvas) {
3893 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3894 SkRect rect;
3895 SkPath::Direction direction;
3896 bool isClosed;
3897 path.isRect(&rect, &isClosed, &direction) ?
3898 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3899 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3900 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3901 SkDebugf("%s is not rect\n", prefix);
3902 };
3903 SkPath path;
3904 debugster("empty", path);
3905 path.addRect({10, 20, 30, 40});
3906 debugster("addRect", path);
3907 path.moveTo(60, 70);
3908 debugster("moveTo", path);
3909 path.lineTo(60, 70);
3910 debugster("lineTo", path);
3911 path.reset();
3912 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3913 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3914 debugster("addPoly", path);
3915}
3916#StdOut
3917empty is not rect
3918addRect is rect (10, 20, 30, 40); is closed; direction CW
3919moveTo is rect (10, 20, 30, 40); is closed; direction CW
3920lineTo is not rect
3921addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3922##
3923##
3924
3925#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3926
3927##
3928
3929# ------------------------------------------------------------------------------
3930
3931#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
3932
3933Returns true if Path is equivalent to nested Rect pair when filled.
3934If false, rect and dirs are unchanged.
3935If true, rect and dirs are written to if not nullptr:
3936setting rect[0] to outer Rect, and rect[1] to inner Rect;
3937setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3938Rect.
3939
3940#Param rect storage for Rect pair; may be nullptr ##
3941#Param dirs storage for Direction pair; may be nullptr ##
3942
3943#Return true if Path contains nested Rect pair ##
3944
3945#Example
3946void draw(SkCanvas* canvas) {
3947 SkPaint paint;
3948 paint.setStyle(SkPaint::kStroke_Style);
3949 paint.setStrokeWidth(5);
3950 SkPath path;
3951 path.addRect({10, 20, 30, 40});
3952 paint.getFillPath(path, &path);
3953 SkRect rects[2];
3954 SkPath::Direction directions[2];
3955 if (path.isNestedFillRects(rects, directions)) {
3956 for (int i = 0; i < 2; ++i) {
3957 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3958 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3959 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3960 }
3961 } else {
3962 SkDebugf("is not nested rectangles\n");
3963 }
3964}
3965#StdOut
3966outer (7.5, 17.5, 32.5, 42.5); direction CW
3967inner (12.5, 22.5, 27.5, 37.5); direction CCW
3968##
3969##
3970
3971#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3972
3973##
3974
3975# ------------------------------------------------------------------------------
3976
3977#Method void addRect(const SkRect& rect, Direction dir = kCW_Direction)
3978
3979Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
3980starting with top-left corner of Rect; followed by top-right, bottom-right,
3981and bottom-left if dir is kCW_Direction; or followed by bottom-left,
3982bottom-right, and top-right if dir is kCCW_Direction.
3983
3984#Param rect Rect to add as a closed contour ##
3985#Param dir Direction to wind added contour ##
3986
3987#Example
3988#Description
3989The left Rect dashes starting at the top-left corner, to the right.
3990The right Rect dashes starting at the top-left corner, towards the bottom.
3991##
3992#Height 128
3993void draw(SkCanvas* canvas) {
3994 SkPaint paint;
3995 paint.setStrokeWidth(15);
3996 paint.setStrokeCap(SkPaint::kSquare_Cap);
3997 float intervals[] = { 5, 21.75f };
3998 paint.setStyle(SkPaint::kStroke_Style);
3999 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4000 SkPath path;
4001 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
4002 canvas->drawPath(path, paint);
4003 path.rewind();
4004 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
4005 canvas->drawPath(path, paint);
4006}
4007##
4008
4009#SeeAlso SkCanvas::drawRect Direction
4010
4011##
4012
4013# ------------------------------------------------------------------------------
4014
4015#Method void addRect(const SkRect& rect, Direction dir, unsigned start)
4016
4017Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
4018If dir is kCW_Direction, Rect corners are added clockwise; if dir is
4019kCCW_Direction, Rect corners are added counterclockwise.
4020start determines the first corner added.
4021
4022#Table
4023#Legend
4024# start # first corner ##
4025#Legend ##
4026# 0 # top-left ##
4027# 1 # top-right ##
4028# 2 # bottom-right ##
4029# 3 # bottom-left ##
4030#Table ##
4031
4032#Param rect Rect to add as a closed contour ##
4033#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004034#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04004035
4036#Example
4037#Height 128
4038#Description
4039The arrow is just after the initial corner and points towards the next
4040corner appended to Path.
4041##
4042void draw(SkCanvas* canvas) {
4043 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
4044 const SkRect rect = {10, 10, 54, 54};
4045 SkPaint rectPaint;
4046 rectPaint.setAntiAlias(true);
4047 rectPaint.setStyle(SkPaint::kStroke_Style);
4048 SkPaint arrowPaint(rectPaint);
4049 SkPath arrowPath;
4050 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4051 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4052 SkPath1DPathEffect::kRotate_Style));
4053 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4054 for (unsigned start : { 0, 1, 2, 3 } ) {
4055 SkPath path;
4056 path.addRect(rect, direction, start);
4057 canvas->drawPath(path, rectPaint);
4058 canvas->drawPath(path, arrowPaint);
4059 canvas->translate(64, 0);
4060 }
4061 canvas->translate(-256, 64);
4062 }
4063}
4064##
4065
4066#SeeAlso SkCanvas::drawRect Direction
4067
4068##
4069
4070# ------------------------------------------------------------------------------
4071
4072#Method void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
4073 Direction dir = kCW_Direction)
4074
4075Add Rect (left, top, right, bottom) to Path,
4076appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4077starting with top-left corner of Rect; followed by top-right, bottom-right,
4078and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4079bottom-right, and top-right if dir is kCCW_Direction.
4080
4081#Param left smaller x of Rect ##
4082#Param top smaller y of Rect ##
4083#Param right larger x of Rect ##
4084#Param bottom larger y of Rect ##
4085#Param dir Direction to wind added contour ##
4086
4087#Example
4088#Description
4089The left Rect dashes start at the top-left corner, and continue to the right.
4090The right Rect dashes start at the top-left corner, and continue down.
4091##
4092#Height 128
4093void draw(SkCanvas* canvas) {
4094 SkPaint paint;
4095 paint.setStrokeWidth(15);
4096 paint.setStrokeCap(SkPaint::kSquare_Cap);
4097 float intervals[] = { 5, 21.75f };
4098 paint.setStyle(SkPaint::kStroke_Style);
4099 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4100 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4101 SkPath path;
4102 path.addRect(20, 20, 100, 100, direction);
4103 canvas->drawPath(path, paint);
4104 canvas->translate(128, 0);
4105 }
4106}
4107##
4108
4109#SeeAlso SkCanvas::drawRect Direction
4110
4111##
4112
4113# ------------------------------------------------------------------------------
4114
4115#Method void addOval(const SkRect& oval, Direction dir = kCW_Direction)
4116
4117Add Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4118Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4119and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4120clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4121
4122This form is identical to addOval(oval, dir, 1).
4123
4124#Param oval bounds of ellipse added ##
4125#Param dir Direction to wind ellipse ##
4126
4127#Example
4128#Height 120
4129 SkPaint paint;
4130 SkPath oval;
4131 oval.addOval({20, 20, 160, 80});
4132 canvas->drawPath(oval, paint);
4133##
4134
4135#SeeAlso SkCanvas::drawOval Direction Oval
4136
4137##
4138
4139# ------------------------------------------------------------------------------
4140
4141#Method void addOval(const SkRect& oval, Direction dir, unsigned start)
4142
4143Add Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4144Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4145and half oval height. Oval begins at start and continues
4146clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4147
4148#Table
4149#Legend
4150# start # Point ##
4151#Legend ##
4152# 0 # oval.centerX(), oval.fTop ##
4153# 1 # oval.fRight, oval.centerY() ##
4154# 2 # oval.centerX(), oval.fBottom ##
4155# 3 # oval.fLeft, oval.centerY() ##
4156#Table ##
4157
4158#Param oval bounds of ellipse added ##
4159#Param dir Direction to wind ellipse ##
4160#Param start index of initial point of ellipse ##
4161
4162#Example
4163#Height 160
4164void draw(SkCanvas* canvas) {
4165 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4166 const SkRect rect = {10, 10, 54, 54};
4167 SkPaint ovalPaint;
4168 ovalPaint.setAntiAlias(true);
4169 SkPaint textPaint(ovalPaint);
4170 textPaint.setTextAlign(SkPaint::kCenter_Align);
4171 ovalPaint.setStyle(SkPaint::kStroke_Style);
4172 SkPaint arrowPaint(ovalPaint);
4173 SkPath arrowPath;
4174 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4175 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4176 SkPath1DPathEffect::kRotate_Style));
4177 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4178 for (unsigned start : { 0, 1, 2, 3 } ) {
4179 SkPath path;
4180 path.addOval(rect, direction, start);
4181 canvas->drawPath(path, ovalPaint);
4182 canvas->drawPath(path, arrowPaint);
4183 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4184 canvas->translate(64, 0);
4185 }
4186 canvas->translate(-256, 72);
4187 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4188 128, 0, textPaint);
4189 }
4190}
4191##
4192
4193#SeeAlso SkCanvas::drawOval Direction Oval
4194
4195##
4196
4197# ------------------------------------------------------------------------------
4198
4199#Method void addCircle(SkScalar x, SkScalar y, SkScalar radius,
4200 Direction dir = kCW_Direction)
4201
4202Add Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
4203four kConic_Verb, and kClose_Verb. Circle begins at
4204#Formula
4205(x + radius, y)
4206##
Cary Clark6fc50412017-09-21 12:31:06 -04004207, continuing clockwise if dir is kCW_Direction, and counterclockwise if dir is
Cary Clark73fa9722017-08-29 17:36:51 -04004208kCCW_Direction.
4209
Cary Clark6fc50412017-09-21 12:31:06 -04004210Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004211
4212#Param x center of Circle ##
4213#Param y center of Circle ##
4214#Param radius distance from center to edge ##
4215#Param dir Direction to wind Circle ##
4216
4217#Example
4218void draw(SkCanvas* canvas) {
4219 SkPaint paint;
4220 paint.setAntiAlias(true);
4221 paint.setStyle(SkPaint::kStroke_Style);
4222 paint.setStrokeWidth(10);
4223 for (int size = 10; size < 300; size += 20) {
4224 SkPath path;
4225 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4226 canvas->drawPath(path, paint);
4227 }
4228}
4229##
4230
4231#SeeAlso SkCanvas::drawCircle Direction Circle
4232
4233##
4234
4235# ------------------------------------------------------------------------------
4236
4237#Method void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
4238
4239Append Arc to Path, as the start of new Contour. Arc added is part of ellipse
4240bounded by oval, from startAngle through sweepAngle. Both startAngle and
4241sweepAngle are measured in degrees, where zero degrees is aligned with the
4242positive x-axis, and positive sweeps extends Arc clockwise.
4243
4244If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4245zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
4246modulo 360, and Arc may or may not draw depending on numeric rounding.
4247
4248#Param oval bounds of ellipse containing Arc ##
4249#Param startAngle starting angle of Arc in degrees ##
4250#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4251
4252#Example
4253#Description
4254The middle row of the left and right columns draw differently from the entries
4255above and below because sweepAngle is outside of the range of +/-360,
4256and startAngle modulo 90 is not zero.
4257##
4258void draw(SkCanvas* canvas) {
4259 SkPaint paint;
4260 for (auto start : { 0, 90, 135, 180, 270 } ) {
4261 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4262 SkPath path;
4263 path.addArc({10, 10, 35, 45}, start, sweep);
4264 canvas->drawPath(path, paint);
4265 canvas->translate(252 / 6, 0);
4266 }
4267 canvas->translate(-252, 255 / 5);
4268 }
4269}
4270##
4271
4272#SeeAlso Arc arcTo SkCanvas::drawArc
4273
4274##
4275
4276# ------------------------------------------------------------------------------
4277
4278#Method void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
4279 Direction dir = kCW_Direction)
4280
4281Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4282equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4283dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4284winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4285of the upper-left corner and winds counterclockwise.
4286
4287If either rx or ry is too large, rx and ry are scaled uniformly until the
4288corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4289Rect rect to Path.
4290
4291After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4292
4293#Param rect bounds of Round_Rect ##
4294#Param rx x-radius of rounded corners on the Round_Rect ##
4295#Param ry y-radius of rounded corners on the Round_Rect ##
4296#Param dir Direction to wind Round_Rect ##
4297
4298#Example
4299#Description
4300If either radius is zero, path contains Rect and is drawn red.
4301If sides are only radii, path contains Oval and is drawn blue.
4302All remaining path draws are convex, and are drawn in gray; no
4303paths constructed from addRoundRect are concave, so none are
4304drawn in green.
4305##
4306void draw(SkCanvas* canvas) {
4307 SkPaint paint;
4308 paint.setAntiAlias(true);
4309 for (auto xradius : { 0, 7, 13, 20 } ) {
4310 for (auto yradius : { 0, 9, 18, 40 } ) {
4311 SkPath path;
4312 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4313 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4314 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4315 canvas->drawPath(path, paint);
4316 canvas->translate(64, 0);
4317 }
4318 canvas->translate(-256, 64);
4319 }
4320}
4321##
4322
4323#SeeAlso addRRect SkCanvas::drawRoundRect
4324
4325##
4326
4327# ------------------------------------------------------------------------------
4328
4329#Method void addRoundRect(const SkRect& rect, const SkScalar radii[],
4330 Direction dir = kCW_Direction)
4331
4332Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4333equal to rect; each corner is 90 degrees of an ellipse with radii from the
4334array.
4335
4336#Table
4337#Legend
4338# radii index # location ##
4339#Legend ##
4340# 0 # x-radius of top-left corner ##
4341# 1 # y-radius of top-left corner ##
4342# 2 # x-radius of top-right corner ##
4343# 3 # y-radius of top-right corner ##
4344# 4 # x-radius of bottom-right corner ##
4345# 5 # y-radius of bottom-right corner ##
4346# 6 # x-radius of bottom-left corner ##
4347# 7 # y-radius of bottom-left corner ##
4348#Table ##
4349
4350If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4351and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
4352bottom-left of the upper-left corner and winds counterclockwise.
4353
4354If both radii on any side of rect exceed its length, all radii are scaled
4355uniformly until the corners fit. If either radius of a corner is less than or
4356equal to zero, both are treated as zero.
4357
4358After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4359
4360#Param rect bounds of Round_Rect ##
4361#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4362#Param dir Direction to wind Round_Rect ##
4363
4364#Example
4365void draw(SkCanvas* canvas) {
4366 SkPaint paint;
4367 paint.setAntiAlias(true);
4368 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4369 SkPath path;
4370 SkMatrix rotate90;
4371 rotate90.setRotate(90, 128, 128);
4372 for (int i = 0; i < 4; ++i) {
4373 path.addRoundRect({10, 10, 110, 110}, radii);
4374 path.transform(rotate90);
4375 }
4376 canvas->drawPath(path, paint);
4377}
4378##
4379
4380#SeeAlso addRRect SkCanvas::drawRoundRect
4381
4382##
4383
4384# ------------------------------------------------------------------------------
4385
4386#Method void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
4387
4388Add rrect to Path, creating a new closed Contour. If
4389dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4390winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4391of the upper-left corner and winds counterclockwise.
4392
4393After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4394
4395#Param rrect bounds and radii of rounded rectangle ##
4396#Param dir Direction to wind Round_Rect ##
4397
4398#Example
4399void draw(SkCanvas* canvas) {
4400 SkPaint paint;
4401 paint.setAntiAlias(true);
4402 SkRRect rrect;
4403 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4404 rrect.setRectRadii({10, 10, 110, 110}, radii);
4405 SkPath path;
4406 SkMatrix rotate90;
4407 rotate90.setRotate(90, 128, 128);
4408 for (int i = 0; i < 4; ++i) {
4409 path.addRRect(rrect);
4410 path.transform(rotate90);
4411 }
4412 canvas->drawPath(path, paint);
4413}
4414##
4415
4416#SeeAlso addRoundRect SkCanvas::drawRRect
4417
4418##
4419
4420# ------------------------------------------------------------------------------
4421
4422#Method void addRRect(const SkRRect& rrect, Direction dir, unsigned start)
4423
4424Add rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
4425winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4426start determines the first point of rrect to add.
4427
4428#Table
4429#Legend
4430# start # location ##
4431#Legend ##
4432# 0 # right of top-left corner ##
4433# 1 # left of top-right corner ##
4434# 2 # bottom of top-right corner ##
4435# 3 # top of bottom-right corner ##
4436# 4 # left of bottom-right corner ##
4437# 5 # right of bottom-left corner ##
4438# 6 # top of bottom-left corner ##
4439# 7 # bottom of top-left corner ##
4440#Table ##
4441
4442After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4443
4444#Param rrect bounds and radii of rounded rectangle ##
4445#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004446#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004447
4448#Example
4449void draw(SkCanvas* canvas) {
4450 SkPaint paint;
4451 paint.setAntiAlias(true);
4452 SkRRect rrect;
4453 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4454 SkPath path;
4455 path.addRRect(rrect);
4456 canvas->drawPath(path, paint);
4457 for (int start = 0; start < 8; ++start) {
4458 SkPath textPath;
4459 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
4460 canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
4461 }
4462}
4463##
4464
4465#SeeAlso addRoundRect SkCanvas::drawRRect
4466
4467##
4468
4469# ------------------------------------------------------------------------------
4470
4471#Method void addPoly(const SkPoint pts[], int count, bool close)
4472
Cary Clark6fc50412017-09-21 12:31:06 -04004473Add Contour created from Line array, adding (count - 1) Line segments.
4474Contour added starts at pts[0], then adds a line for every additional Point
4475in pts array. If close is true,appends kClose_Verb to Path, connecting
4476pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004477
4478If count is zero, append kMove_Verb to path.
4479Has no effect if count is less than one.
4480
Cary Clarka523d2d2017-08-30 08:58:10 -04004481#Param pts array of Line sharing end and start Point ##
4482#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004483#Param close true to add Line connecting Contour end and start ##
4484
4485#Example
4486void draw(SkCanvas* canvas) {
4487 SkPaint paint;
4488 paint.setStrokeWidth(15);
4489 paint.setStrokeCap(SkPaint::kRound_Cap);
4490 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4491 for (bool close : { false, true } ) {
4492 SkPath path;
4493 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4494 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4495 SkPaint::kStrokeAndFill_Style} ) {
4496 paint.setStyle(style);
4497 canvas->drawPath(path, paint);
4498 canvas->translate(85, 0);
4499 }
4500 canvas->translate(-255, 128);
4501 }
4502}
4503##
4504
4505#SeeAlso SkCanvas::drawPoints
4506
4507##
4508
4509# ------------------------------------------------------------------------------
4510
4511#Enum AddPathMode
4512
4513#Code
4514 enum AddPathMode {
4515 kAppend_AddPathMode,
4516 kExtend_AddPathMode,
4517 };
4518##
4519
4520AddPathMode chooses how addPath appends. Adding one Path to another can extend
4521the last Contour or start a new Contour.
4522
4523#Const kAppend_AddPathMode
4524 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4525 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4526 starts a new Contour.
4527##
4528#Const kExtend_AddPathMode
4529 If destination is closed or empty, start a new Contour. If destination
4530 is not empty, add Line from Last_Point to added Path first Point. Skip added
4531 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4532##
4533
4534#Example
4535#Description
4536test is built from path, open on the top row, and closed on the bottom row.
4537The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4538The top right composition is made up of one contour; the other three have two.
4539##
4540#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004541 SkPath path, path2;
4542 path.moveTo(20, 20);
4543 path.lineTo(20, 40);
4544 path.lineTo(40, 20);
4545 path2.moveTo(60, 60);
4546 path2.lineTo(80, 60);
4547 path2.lineTo(80, 40);
4548 SkPaint paint;
4549 paint.setStyle(SkPaint::kStroke_Style);
4550 for (int i = 0; i < 2; i++) {
4551 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4552 SkPath test(path);
4553 test.addPath(path2, addPathMode);
4554 canvas->drawPath(test, paint);
4555 canvas->translate(100, 0);
4556 }
4557 canvas->translate(-200, 100);
4558 path.close();
4559 }
Cary Clark73fa9722017-08-29 17:36:51 -04004560##
4561
4562#SeeAlso addPath reverseAddPath
4563
4564##
4565
4566# ------------------------------------------------------------------------------
4567
4568#Method void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
4569 AddPathMode mode = kAppend_AddPathMode)
4570
4571Append src to Path, offset by (dx, dy).
4572
4573If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4574added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4575Verbs, Points, and Conic_Weights.
4576
4577#Param src Path Verbs, Points, and Conic_Weights to add ##
4578#Param dx offset added to src Point_Array x coordinates ##
4579#Param dy offset added to src Point_Array y coordinates ##
4580#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4581
4582#Example
4583#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004584 SkPaint paint;
4585 paint.setTextSize(128);
4586 paint.setFakeBoldText(true);
4587 SkPath dest, text;
4588 paint.getTextPath("O", 1, 50, 120, &text);
4589 for (int i = 0; i < 3; i++) {
4590 dest.addPath(text, i * 20, i * 20);
4591 }
4592 Simplify(dest, &dest);
4593 paint.setStyle(SkPaint::kStroke_Style);
4594 paint.setStrokeWidth(3);
4595 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004596##
4597
4598#SeeAlso AddPathMode offset() reverseAddPath
4599
4600##
4601
4602# ------------------------------------------------------------------------------
4603
4604#Method void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
4605
4606Append src to Path.
4607
4608If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4609added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4610Verbs, Points, and Conic_Weights.
4611
4612#Param src Path Verbs, Points, and Conic_Weights to add ##
4613#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4614
4615#Example
4616#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004617 SkPaint paint;
4618 paint.setStyle(SkPaint::kStroke_Style);
4619 SkPath dest, path;
4620 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4621 for (int i = 0; i < 2; i++) {
4622 dest.addPath(path, SkPath::kExtend_AddPathMode);
4623 dest.offset(100, 0);
4624 }
Cary Clark73fa9722017-08-29 17:36:51 -04004625 canvas->drawPath(dest, paint);
4626##
4627
4628#SeeAlso AddPathMode reverseAddPath
4629
4630##
4631
4632# ------------------------------------------------------------------------------
4633
4634#Method void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
4635
4636Append src to Path, transformed by matrix. Transformed curves may have different
4637Verbs, Points, and Conic_Weights.
4638
4639If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4640added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4641Verbs, Points, and Conic_Weights.
4642
4643#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004644#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004645#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4646
4647#Example
4648#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004649 SkPaint paint;
4650 paint.setStyle(SkPaint::kStroke_Style);
4651 SkPath dest, path;
4652 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4653 for (int i = 0; i < 6; i++) {
4654 SkMatrix matrix;
4655 matrix.reset();
4656 matrix.setPerspX(i / 400.f);
4657 dest.addPath(path, matrix);
4658 }
4659 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004660##
4661
4662#SeeAlso AddPathMode transform() offset() reverseAddPath
4663
4664##
4665
4666# ------------------------------------------------------------------------------
4667
4668#Method void reverseAddPath(const SkPath& src)
4669
4670Append src to Path, from back to front.
4671Reversed src always appends a new Contour to Path.
4672
4673#Param src Path Verbs, Points, and Conic_Weights to add ##
4674
4675#Example
4676#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004677 SkPath path;
4678 path.moveTo(20, 20);
4679 path.lineTo(20, 40);
4680 path.lineTo(40, 20);
4681 SkPaint paint;
4682 paint.setStyle(SkPaint::kStroke_Style);
4683 for (int i = 0; i < 2; i++) {
4684 SkPath path2;
4685 path2.moveTo(60, 60);
4686 path2.lineTo(80, 60);
4687 path2.lineTo(80, 40);
4688 for (int j = 0; j < 2; j++) {
4689 SkPath test(path);
4690 test.reverseAddPath(path2);
4691 canvas->drawPath(test, paint);
4692 canvas->translate(100, 0);
4693 path2.close();
4694 }
4695 canvas->translate(-200, 100);
4696 path.close();
4697 }
Cary Clark73fa9722017-08-29 17:36:51 -04004698##
4699
4700#SeeAlso AddPathMode transform() offset() addPath
4701
4702##
4703
4704# ------------------------------------------------------------------------------
4705
4706#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
4707
4708Offset Point_Array by (dx, dy). Offset Path replaces dst.
4709If dst is nullptr, Path is replaced by offset data.
4710
4711#Param dx offset added to Point_Array x coordinates ##
4712#Param dy offset added to Point_Array y coordinates ##
4713#Param dst overwritten, translated copy of Path; may be nullptr ##
4714
4715#Example
4716#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004717 SkPath pattern;
4718 pattern.moveTo(20, 20);
4719 pattern.lineTo(20, 40);
4720 pattern.lineTo(40, 20);
4721 SkPaint paint;
4722 paint.setStyle(SkPaint::kStroke_Style);
4723 for (int i = 0; i < 10; i++) {
4724 SkPath path;
4725 pattern.offset(20 * i, 0, &path);
4726 canvas->drawPath(path, paint);
4727 }
Cary Clark73fa9722017-08-29 17:36:51 -04004728##
4729
4730#SeeAlso addPath transform
4731
4732##
4733
4734# ------------------------------------------------------------------------------
4735
4736#Method void offset(SkScalar dx, SkScalar dy)
4737
4738Offset Point_Array by (dx, dy). Path is replaced by offset data.
4739
4740#Param dx offset added to Point_Array x coordinates ##
4741#Param dy offset added to Point_Array y coordinates ##
4742
4743#Example
4744#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004745 SkPath path;
4746 path.moveTo(20, 20);
4747 path.lineTo(20, 40);
4748 path.lineTo(40, 20);
4749 SkPaint paint;
4750 paint.setStyle(SkPaint::kStroke_Style);
4751 for (int i = 0; i < 10; i++) {
4752 canvas->drawPath(path, paint);
4753 path.offset(20, 0);
4754 }
Cary Clark73fa9722017-08-29 17:36:51 -04004755##
4756
4757#SeeAlso addPath transform SkCanvas::translate()
4758
4759##
4760
4761# ------------------------------------------------------------------------------
4762
4763#Method void transform(const SkMatrix& matrix, SkPath* dst) const
4764
4765Transform Verb_Array, Point_Array, and weight by matrix.
4766transform may change Verbs and increase their number.
4767Transformed Path replaces dst; if dst is nullptr, original data
4768is replaced.
4769
4770#Param matrix Matrix to apply to Path ##
4771#Param dst overwritten, transformed copy of Path; may be nullptr ##
4772
4773#Example
Cary Clark8032b982017-07-28 11:04:54 -04004774#Height 200
4775 SkPath pattern;
4776 pattern.moveTo(100, 100);
4777 pattern.lineTo(100, 20);
4778 pattern.lineTo(20, 100);
4779 SkPaint paint;
4780 paint.setStyle(SkPaint::kStroke_Style);
4781 for (int i = 0; i < 10; i++) {
4782 SkPath path;
4783 SkMatrix matrix;
4784 matrix.setRotate(36 * i, 100, 100);
4785 pattern.transform(matrix, &path);
4786 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004787 }
4788##
4789
4790#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4791
4792##
4793
4794# ------------------------------------------------------------------------------
4795
4796#Method void transform(const SkMatrix& matrix)
4797
4798Transform Verb_Array, Point_Array, and weight by matrix.
4799transform may change Verbs and increase their number.
4800Path is replaced by transformed data.
4801
4802#Param matrix Matrix to apply to Path ##
4803
4804#Example
Cary Clark8032b982017-07-28 11:04:54 -04004805#Height 200
4806 SkPath path;
4807 path.moveTo(100, 100);
4808 path.quadTo(100, 20, 20, 100);
4809 SkPaint paint;
4810 paint.setStyle(SkPaint::kStroke_Style);
4811 for (int i = 0; i < 10; i++) {
4812 SkMatrix matrix;
4813 matrix.setRotate(36, 100, 100);
4814 path.transform(matrix);
4815 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004816 }
4817##
4818
4819#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4820
4821##
4822
4823# ------------------------------------------------------------------------------
4824
Cary Clark8032b982017-07-28 11:04:54 -04004825#Subtopic Last_Point
4826
4827Path is defined cumulatively, often by adding a segment to the end of last
4828Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4829Last_Point can be read and written directly with getLastPt and setLastPt.
4830
Cary Clark73fa9722017-08-29 17:36:51 -04004831#Method bool getLastPt(SkPoint* lastPt) const
4832
4833 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
4834 storing (0, 0) if lastPt is not nullptr.
4835
4836 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4837
4838 #Return true if Point_Array contains one or more Points ##
4839
4840 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004841 SkPath path;
4842 path.moveTo(100, 100);
4843 path.quadTo(100, 20, 20, 100);
4844 SkMatrix matrix;
4845 matrix.setRotate(36, 100, 100);
4846 path.transform(matrix);
4847 SkPoint last;
4848 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004849 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4850 #StdOut
4851 last point: 35.2786, 52.9772
4852 ##
4853 ##
4854
4855 #SeeAlso setLastPt
4856
4857##
4858
4859#Method void setLastPt(SkScalar x, SkScalar y)
4860
4861 Set Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
4862 Verb_Array and (x, y) to Point_Array.
4863
4864 #Param x set x-coordinate of Last_Point ##
4865 #Param y set y-coordinate of Last_Point ##
4866
4867 #Example
4868 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004869 SkPaint paint;
4870 paint.setTextSize(128);
4871 SkPath path;
4872 paint.getTextPath("@", 1, 60, 100, &path);
4873 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004874 canvas->drawPath(path, paint);
4875 ##
4876
4877 #SeeAlso getLastPt
4878
4879##
4880
4881#Method void setLastPt(const SkPoint& p)
4882
4883 Set the last point on the path. If no points have been added, moveTo(p)
4884 is automatically called.
4885
4886 #Param p set value of Last_Point ##
4887
4888 #Example
4889 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004890 SkPaint paint;
4891 paint.setTextSize(128);
4892 SkPath path, path2;
4893 paint.getTextPath("A", 1, 60, 100, &path);
4894 paint.getTextPath("Z", 1, 60, 100, &path2);
4895 SkPoint pt, pt2;
4896 path.getLastPt(&pt);
4897 path2.getLastPt(&pt2);
4898 path.setLastPt(pt2);
4899 path2.setLastPt(pt);
4900 canvas->drawPath(path, paint);
4901 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004902 ##
4903
4904 #SeeAlso getLastPt
4905
4906##
4907
4908#Subtopic Last_Point ##
4909
4910# ------------------------------------------------------------------------------
4911
4912#Enum SegmentMask
4913
4914#Code
4915 enum SegmentMask {
4916 kLine_SegmentMask = 1 << 0,
4917 kQuad_SegmentMask = 1 << 1,
4918 kConic_SegmentMask = 1 << 2,
4919 kCubic_SegmentMask = 1 << 3,
4920 };
4921##
4922
4923SegmentMask constants correspond to each drawing Verb type in Path; for
4924instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4925
4926#Bug 6785 ##
4927#Const kLine_SegmentMask 1
4928Set if Verb_Array contains kLine_Verb.
4929##
4930#Const kQuad_SegmentMask 2
4931Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4932##
4933#Const kConic_SegmentMask 4
4934Set if Verb_Array contains kConic_Verb.
4935##
4936#Const kCubic_SegmentMask 8
4937Set if Verb_Array contains kCubic_Verb.
4938##
4939
4940#Example
4941#Description
4942When conicTo has a weight of one, Quad is added to Path.
4943##
4944 SkPath path;
4945 path.conicTo(10, 10, 20, 30, 1);
4946 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
4947 SkPath::kConic_SegmentMask ? "set" : "clear");
4948 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
4949 SkPath::kQuad_SegmentMask ? "set" : "clear");
4950#StdOut
4951Path kConic_SegmentMask is clear
4952Path kQuad_SegmentMask is set
4953##
4954##
4955
4956#SeeAlso getSegmentMasks Verb
4957
4958##
4959
4960# ------------------------------------------------------------------------------
4961
4962#Method uint32_t getSegmentMasks() const
4963
4964Returns a mask, where each set bit corresponds to a SegmentMask constant
4965if Path contains one or more Verbs of that type.
4966Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
4967
4968getSegmentMasks() returns a cached result; it is very fast.
4969
4970#Return SegmentMask bits or zero ##
4971
4972#Example
4973SkPath path;
4974path.quadTo(20, 30, 40, 50);
4975path.close();
4976const char* masks[] = { "line", "quad", "conic", "cubic" };
4977int index = 0;
4978for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4979 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4980 if (mask & path.getSegmentMasks()) {
4981 SkDebugf("mask %s set\n", masks[index]);
4982 }
4983 ++index;
4984}
4985#StdOut
4986mask quad set
4987##
4988##
4989
4990#SeeAlso getSegmentMasks Verb
4991
4992##
4993
4994# ------------------------------------------------------------------------------
4995
4996#Method bool contains(SkScalar x, SkScalar y) const
4997
4998Returns true if the point (x, y) is contained by Path, taking into
4999account FillType.
5000
5001#Table
5002#Legend
5003# FillType # contains() returns true if Point is enclosed by ##
5004##
5005# kWinding_FillType # a non-zero sum of Contour Directions. ##
5006# kEvenOdd_FillType # an odd number of Contours. ##
5007# kInverseWinding_FillType # a zero sum of Contour Directions. ##
5008# kInverseEvenOdd_FillType # and even number of Contours. ##
5009##
5010
5011#Param x x-coordinate of containment test ##
5012#Param y y-coordinate of containment test ##
5013
5014#Return true if Point is in Path ##
5015
5016#Example
5017SkPath path;
5018SkPaint paint;
5019paint.setTextSize(256);
5020paint.getTextPath("&", 1, 30, 220, &path);
5021for (int y = 2; y < 256; y += 9) {
5022 for (int x = 2; x < 256; x += 9) {
5023 int coverage = 0;
5024 for (int iy = -4; iy <= 4; iy += 2) {
5025 for (int ix = -4; ix <= 4; ix += 2) {
5026 coverage += path.contains(x + ix, y + iy);
5027 }
5028 }
5029 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5030 canvas->drawCircle(x, y, 8, paint);
5031 }
5032}
5033##
5034
5035#SeeAlso conservativelyContainsRect Fill_Type Op
5036
5037##
5038
5039# ------------------------------------------------------------------------------
5040
5041#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
5042
5043Writes text representation of Path to stream. If stream is nullptr, dump() writes to
Cary Clarkce101242017-09-01 15:51:02 -04005044standard output. Set forceClose to true to get
Cary Clark7fc1d122017-10-09 14:07:42 -04005045edges used to fill Path. Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005046of floating point numbers used in Point_Array and Conic_Weights.
5047
5048#Param stream writable Stream receiving Path text representation; may be nullptr ##
5049#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005050#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005051
5052#Example
5053 SkPath path;
5054 path.quadTo(20, 30, 40, 50);
5055 for (bool forceClose : { false, true } ) {
5056 for (bool dumpAsHex : { false, true } ) {
5057 path.dump(nullptr, forceClose, dumpAsHex);
5058 SkDebugf("\n");
5059 }
5060 }
5061#StdOut
5062path.setFillType(SkPath::kWinding_FillType);
5063path.moveTo(0, 0);
5064path.quadTo(20, 30, 40, 50);
5065
5066path.setFillType(SkPath::kWinding_FillType);
5067path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5068path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5069
5070path.setFillType(SkPath::kWinding_FillType);
5071path.moveTo(0, 0);
5072path.quadTo(20, 30, 40, 50);
5073path.lineTo(0, 0);
5074path.close();
5075
5076path.setFillType(SkPath::kWinding_FillType);
5077path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5078path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5079path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5080path.close();
5081##
5082##
5083
5084#SeeAlso SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
5085
5086##
5087
5088# ------------------------------------------------------------------------------
5089
5090#Method void dump() const
5091
Cary Clarkce101242017-09-01 15:51:02 -04005092Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005093directly compiled as C++ code. Floating point values are written
5094with limited precision; it may not be possible to reconstruct original Path
5095from output.
5096
5097#Example
5098SkPath path, copy;
5099path.lineTo(6.f / 7, 2.f / 3);
5100path.dump();
5101copy.setFillType(SkPath::kWinding_FillType);
5102copy.moveTo(0, 0);
5103copy.lineTo(0.857143f, 0.666667f);
5104SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5105#StdOut
5106path.setFillType(SkPath::kWinding_FillType);
5107path.moveTo(0, 0);
5108path.lineTo(0.857143f, 0.666667f);
5109path is not equal to copy
5110##
5111##
5112
5113#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5114
5115##
5116
5117# ------------------------------------------------------------------------------
5118
5119#Method void dumpHex() const
5120
Cary Clarkce101242017-09-01 15:51:02 -04005121Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005122directly compiled as C++ code. Floating point values are written
5123in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5124original Path.
5125
Cary Clark6fc50412017-09-21 12:31:06 -04005126Use instead of dump() when submitting
5127#A bug reports against Skia # http://bug.skia.org ##
5128.
Cary Clark73fa9722017-08-29 17:36:51 -04005129
5130#Example
5131SkPath path, copy;
5132path.lineTo(6.f / 7, 2.f / 3);
5133path.dumpHex();
5134copy.setFillType(SkPath::kWinding_FillType);
5135copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5136copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5137SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5138#StdOut
5139path.setFillType(SkPath::kWinding_FillType);
5140path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5141path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5142path is equal to copy
5143##
5144##
5145
5146#SeeAlso dump SkRect::dumpHex() SkRRect::dumpHex() writeToMemory
5147
5148##
5149
5150# ------------------------------------------------------------------------------
5151
5152#Method size_t writeToMemory(void* buffer) const
5153
5154Writes Path to buffer, returning the number of bytes written.
5155Pass nullptr to obtain the storage size.
5156
5157Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5158additionally writes computed information like Convexity and bounds.
5159
5160Use only be used in concert with readFromMemory;
5161the format used for Path in memory is not guaranteed.
5162
5163#Param buffer storage for Path; may be nullptr ##
5164
5165#Return size of storage required for Path; always a multiple of 4 ##
5166
5167#Example
5168void draw(SkCanvas* canvas) {
5169 SkPath path, copy;
5170 path.lineTo(6.f / 7, 2.f / 3);
5171 size_t size = path.writeToMemory(nullptr);
5172 SkTDArray<char> storage;
5173 storage.setCount(size);
5174 path.writeToMemory(storage.begin());
5175 copy.readFromMemory(storage.begin(), size);
5176 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5177}
5178#StdOut
5179path is equal to copy
5180##
5181##
5182
5183#SeeAlso serialize readFromMemory dump dumpHex
5184
5185##
5186
5187#Method sk_sp<SkData> serialize() const
5188
5189Write Path to buffer, returning the buffer written to, wrapped in Data.
5190
5191serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5192additionally writes computed information like Convexity and bounds.
5193
5194serialize() should only be used in concert with readFromMemory.
5195The format used for Path in memory is not guaranteed.
5196
5197#Return Path data wrapped in Data buffer ##
5198
5199#Example
5200void draw(SkCanvas* canvas) {
5201 SkPath path, copy;
5202 path.lineTo(6.f / 7, 2.f / 3);
5203 sk_sp<SkData> data = path.serialize();
5204 copy.readFromMemory(data->data(), data->size());
5205 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5206}
5207#StdOut
5208path is equal to copy
5209##
5210##
5211
5212#SeeAlso writeToMemory readFromMemory dump dumpHex
5213##
5214
5215# ------------------------------------------------------------------------------
5216
5217#Method size_t readFromMemory(const void* buffer, size_t length)
5218
5219Initializes Path from buffer of size length. Returns zero if the buffer is
5220data is inconsistent, or the length is too small.
5221
5222Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5223additionally reads computed information like Convexity and bounds.
5224
5225Used only in concert with writeToMemory;
5226the format used for Path in memory is not guaranteed.
5227
5228#Param buffer storage for Path ##
5229#Param length buffer size in bytes; must be multiple of 4 ##
5230
5231#Return number of bytes read, or zero on failure ##
5232
5233#Example
5234void draw(SkCanvas* canvas) {
5235 SkPath path, copy;
5236 path.lineTo(6.f / 7, 2.f / 3);
5237 size_t size = path.writeToMemory(nullptr);
5238 SkTDArray<char> storage;
5239 storage.setCount(size);
5240 path.writeToMemory(storage.begin());
5241 size_t wrongSize = size - 4;
5242 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5243 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5244 size_t largerSize = size + 4;
5245 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5246 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5247}
5248#StdOut
5249length = 60; returned by readFromMemory = 0
5250length = 68; returned by readFromMemory = 64
5251##
5252##
5253
5254#SeeAlso writeToMemory
5255
5256##
5257
5258# ------------------------------------------------------------------------------
5259#Topic Generation_ID
5260#Alias Generation_IDs
5261
5262Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5263Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5264not necessarily have matching Generation_IDs.
5265
5266Empty Paths have a Generation_ID of one.
5267
5268#Method uint32_t getGenerationID() const
5269
5270Returns a non-zero, globally unique value. A different value is returned
5271if Verb_Array, Point_Array, or Conic_Weight changes.
5272
5273Setting Fill_Type does not change Generation_ID.
5274
5275Each time the path is modified, a different Generation_ID will be returned.
5276
5277#Bug 1762
5278Fill_Type does affect Generation_ID on Android framework.
5279##
5280
5281#Return non-zero, globally unique value ##
5282
5283#Example
5284SkPath path;
5285SkDebugf("empty genID = %u\n", path.getGenerationID());
5286path.lineTo(1, 2);
5287SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5288path.rewind();
5289SkDebugf("empty genID = %u\n", path.getGenerationID());
5290path.lineTo(1, 2);
5291SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5292#StdOut
5293empty genID = 1
52941st lineTo genID = 2
5295empty genID = 1
52962nd lineTo genID = 3
5297##
5298##
5299
5300#SeeAlso operator==(const SkPath& a, const SkPath& b)
5301
5302##
5303
5304#Topic ##
5305
5306# ------------------------------------------------------------------------------
5307
5308#Method bool isValid() const
5309
5310 Returns if Path data is consistent. Corrupt Path data is detected if
5311 internal values are out of range or internal storage does not match
5312 array dimensions.
5313
5314 #Return true if Path data is consistent ##
5315
5316 #NoExample
5317 ##
5318
5319##
5320
5321#Method bool pathRefIsValid() const
5322
5323 Returns if Path data is consistent.
5324
5325 #Deprecated
5326 To be deprecated soon.
5327 ##
5328
5329 #Return true if Path data is consistent ##
5330
5331 #NoExample
5332 ##
5333##
5334
5335# ------------------------------------------------------------------------------
5336
Cary Clark8032b982017-07-28 11:04:54 -04005337#Class Iter
5338
5339Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5340Provides options to treat open Contours as closed, and to ignore
5341degenerate data.
5342
Cary Clark73fa9722017-08-29 17:36:51 -04005343#Code
5344class Iter {
5345public:
5346 Iter();
5347 Iter(const SkPath& path, bool forceClose);
5348 void setPath(const SkPath& path, bool forceClose);
5349 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5350 SkScalar conicWeight() const;
5351 bool isCloseLine() const;
5352 bool isClosedContour() const;
5353};
5354##
5355
Cary Clark8032b982017-07-28 11:04:54 -04005356#Example
5357#Height 128
5358#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005359Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005360path of the glyph.
5361##
Cary Clark73fa9722017-08-29 17:36:51 -04005362void draw(SkCanvas* canvas) {
5363 SkPaint paint;
5364 paint.setAntiAlias(true);
5365 paint.setTextSize(256);
5366 SkPath asterisk, path;
5367 paint.getTextPath("*", 1, 50, 192, &asterisk);
5368 SkPath::Iter iter(asterisk, true);
5369 SkPoint start[4], pts[4];
5370 iter.next(start); // skip moveTo
5371 iter.next(start); // first quadTo
5372 path.moveTo((start[0] + start[1]) * 0.5f);
5373 while (SkPath::kClose_Verb != iter.next(pts)) {
5374 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5375 }
5376 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5377 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005378}
5379##
5380
5381#SeeAlso RawIter
5382
5383#Method Iter()
5384
5385Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5386Call setPath to initialize Iter at a later time.
5387
Cary Clark73fa9722017-08-29 17:36:51 -04005388#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005389
5390#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005391void draw(SkCanvas* canvas) {
5392 SkPath::Iter iter;
5393 SkPoint points[4];
5394 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5395 SkPath path;
5396 iter.setPath(path, false);
5397 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005398}
Cary Clark73fa9722017-08-29 17:36:51 -04005399#StdOut
5400iter is done
5401iter is done
5402##
Cary Clark8032b982017-07-28 11:04:54 -04005403##
5404
5405#SeeAlso setPath
5406
5407##
5408
5409#Method Iter(const SkPath& path, bool forceClose)
5410
5411Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5412If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5413open Contour. path is not altered.
5414
Cary Clark73fa9722017-08-29 17:36:51 -04005415#Param path Path to iterate ##
5416#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005417
Cary Clark73fa9722017-08-29 17:36:51 -04005418#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005419
5420#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005421void draw(SkCanvas* canvas) {
5422 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5423 SkDebugf("%s:\n", prefix);
5424 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5425 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5426 SkPath::Verb verb;
5427 do {
5428 SkPoint points[4];
5429 verb = iter.next(points);
5430 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5431 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5432 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5433 }
5434 if (SkPath::kConic_Verb == verb) {
5435 SkDebugf("weight = %g", iter.conicWeight());
5436 }
5437 SkDebugf("\n");
5438 } while (SkPath::kDone_Verb != verb);
5439 SkDebugf("\n");
5440 };
5441
5442 SkPath path;
5443 path.quadTo(10, 20, 30, 40);
5444 SkPath::Iter openIter(path, false);
5445 debugster("open", openIter);
5446 SkPath::Iter closedIter(path, true);
5447 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005448}
5449#StdOut
5450open:
Cary Clark73fa9722017-08-29 17:36:51 -04005451kMove_Verb {0, 0},
5452kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5453kDone_Verb
5454
5455closed:
5456kMove_Verb {0, 0},
5457kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5458kLine_Verb {30, 40}, {0, 0},
5459kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005460kDone_Verb
5461##
5462##
5463
5464#SeeAlso setPath
5465
5466##
5467
5468#Method void setPath(const SkPath& path, bool forceClose)
5469
5470Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5471If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5472open Contour. path is not altered.
5473
Cary Clark73fa9722017-08-29 17:36:51 -04005474#Param path Path to iterate ##
5475#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005476
5477#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005478void draw(SkCanvas* canvas) {
5479 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5480 SkDebugf("%s:\n", prefix);
5481 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5482 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5483 SkPath::Verb verb;
5484 do {
5485 SkPoint points[4];
5486 verb = iter.next(points);
5487 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5488 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5489 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5490 }
5491 if (SkPath::kConic_Verb == verb) {
5492 SkDebugf("weight = %g", iter.conicWeight());
5493 }
5494 SkDebugf("\n");
5495 } while (SkPath::kDone_Verb != verb);
5496 SkDebugf("\n");
5497 };
5498
5499 SkPath path;
5500 path.quadTo(10, 20, 30, 40);
5501 SkPath::Iter iter(path, false);
5502 debugster("quad open", iter);
5503 SkPath path2;
5504 path2.conicTo(1, 2, 3, 4, .5f);
5505 iter.setPath(path2, true);
5506 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005507}
5508#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005509quad open:
5510kMove_Verb {0, 0},
5511kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5512kDone_Verb
5513
5514conic closed:
5515kMove_Verb {0, 0},
5516kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
5517kLine_Verb {3, 4}, {0, 0},
5518kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005519kDone_Verb
5520##
5521##
5522
5523#SeeAlso Iter(const SkPath& path, bool forceClose)
5524
5525##
5526
5527#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
5528
Cary Clarka523d2d2017-08-30 08:58:10 -04005529Returns next Verb in Verb_Array, and advances Iter.
5530When Verb_Array is exhausted, returns kDone_Verb.
5531
Cary Clark8032b982017-07-28 11:04:54 -04005532Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005533
Cary Clark8032b982017-07-28 11:04:54 -04005534If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5535only the last in the series; and skip very small Lines, Quads, and Conics; and
5536skip kClose_Verb following kMove_Verb.
5537if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5538Conics with zero lengths.
5539
Cary Clarka523d2d2017-08-30 08:58:10 -04005540 #Param pts storage for Point data describing returned Verb ##
5541 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5542 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005543
Cary Clark73fa9722017-08-29 17:36:51 -04005544 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005545
5546#Example
5547#Description
5548skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5549followed by the kClose_Verb, the zero length Line and the very small Line.
5550
5551skip degenerate if exact skips the same as skip degenerate, but shows
5552the very small Line.
5553
5554skip none shows all of the Verbs and Points in Path.
5555##
Cary Clark73fa9722017-08-29 17:36:51 -04005556void draw(SkCanvas* canvas) {
5557 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5558 SkPath::Iter iter(path, false);
5559 SkDebugf("%s:\n", prefix);
5560 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5561 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5562 SkPath::Verb verb;
5563 do {
5564 SkPoint points[4];
5565 verb = iter.next(points, degen, exact);
5566 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5567 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5568 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5569 }
5570 SkDebugf("\n");
5571 } while (SkPath::kDone_Verb != verb);
5572 SkDebugf("\n");
5573 };
5574
5575 SkPath path;
5576 path.moveTo(10, 10);
5577 path.moveTo(20, 20);
5578 path.quadTo(10, 20, 30, 40);
5579 path.moveTo(1, 1);
5580 path.close();
5581 path.moveTo(30, 30);
5582 path.lineTo(30, 30);
5583 path.moveTo(30, 30);
5584 path.lineTo(30.00001f, 30);
5585 debugster("skip degenerate", path, true, false);
5586 debugster("skip degenerate if exact", path, true, true);
5587 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005588}
5589#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005590skip degenerate:
5591kMove_Verb {20, 20},
5592kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5593kDone_Verb
5594
5595skip degenerate if exact:
5596kMove_Verb {20, 20},
5597kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5598kMove_Verb {30, 30},
5599kLine_Verb {30, 30}, {30.00001, 30},
5600kDone_Verb
5601
5602skip none:
5603kMove_Verb {10, 10},
5604kMove_Verb {20, 20},
5605kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5606kMove_Verb {1, 1},
5607kClose_Verb {1, 1},
5608kMove_Verb {30, 30},
5609kLine_Verb {30, 30}, {30, 30},
5610kMove_Verb {30, 30},
5611kLine_Verb {30, 30}, {30.00001, 30},
5612kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005613##
5614##
5615
5616#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
5617
5618##
5619
5620#Method SkScalar conicWeight() const
5621
5622 Returns Conic_Weight if next() returned kConic_Verb.
5623
5624 If next() has not been called, or next() did not return kConic_Verb,
5625 result is undefined.
5626
Cary Clark73fa9722017-08-29 17:36:51 -04005627 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005628
5629 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005630 void draw(SkCanvas* canvas) {
5631 SkPath path;
5632 path.conicTo(1, 2, 3, 4, .5f);
5633 SkPath::Iter iter(path, false);
5634 SkPoint p[4];
5635 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5636 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5637 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5638 p[2].fX, p[2].fY);
5639 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005640 }
5641 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005642first verb is move
5643next verb is conic
5644conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005645conic weight: 0.5
5646 ##
5647 ##
5648
5649 #SeeAlso Conic_Weight
5650
5651##
5652
5653#Method bool isCloseLine() const
5654
5655 Returns true if last kLine_Verb returned by next() was generated
5656 by kClose_Verb. When true, the end point returned by next() is
5657 also the start point of Contour.
5658
5659 If next() has not been called, or next() did not return kLine_Verb,
5660 result is undefined.
5661
Cary Clark73fa9722017-08-29 17:36:51 -04005662 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005663
5664 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005665void draw(SkCanvas* canvas) {
5666 SkPath path;
5667 path.moveTo(6, 7);
5668 path.conicTo(1, 2, 3, 4, .5f);
5669 path.close();
5670 SkPath::Iter iter(path, false);
5671 SkPoint p[4];
5672 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5673 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5674 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5675 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5676 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5677 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5678 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005679}
5680 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040056811st verb is move
5682moveTo point: {6,7}
56832nd verb is conic
56843rd verb is line
5685line points: {3,4}, {6,7}
5686line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040056874th verb is close
5688 ##
5689 ##
5690
5691 #SeeAlso close()
5692##
5693
5694#Method bool isClosedContour() const
5695
5696Returns true if subsequent calls to next() return kClose_Verb before returning
5697kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5698Iter may have been initialized with force close set to true.
5699
Cary Clark73fa9722017-08-29 17:36:51 -04005700#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005701
5702#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005703void draw(SkCanvas* canvas) {
5704 for (bool forceClose : { false, true } ) {
5705 SkPath path;
5706 path.conicTo(1, 2, 3, 4, .5f);
5707 SkPath::Iter iter(path, forceClose);
5708 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5709 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5710 path.close();
5711 iter.setPath(path, forceClose);
5712 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5713 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5714 }
Cary Clark8032b982017-07-28 11:04:54 -04005715}
5716#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005717without close(), forceClose is false: isClosedContour returns false
5718with close(), forceClose is false: isClosedContour returns true
5719without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005720with close(), forceClose is true : isClosedContour returns true
5721##
5722##
5723
5724#SeeAlso Iter(const SkPath& path, bool forceClose)
5725
5726##
Cary Clark73fa9722017-08-29 17:36:51 -04005727
5728#Class Iter ##
5729
Cary Clark8032b982017-07-28 11:04:54 -04005730#Class RawIter
5731
5732Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5733Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5734
Cary Clark73fa9722017-08-29 17:36:51 -04005735#Code
5736 class RawIter {
5737 public:
5738 RawIter();
5739 RawIter(const SkPath& path);
5740 void setPath(const SkPath& path);
5741 Verb next(SkPoint pts[4]);
5742 Verb peek() const;
5743 SkScalar conicWeight() const;
5744 }
5745##
5746
Cary Clark8032b982017-07-28 11:04:54 -04005747 #Method RawIter()
5748
5749 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
5750 Call setPath to initialize Iter at a later time.
5751
Cary Clark73fa9722017-08-29 17:36:51 -04005752 #Return RawIter of empty Path ##
5753
5754 #NoExample
5755 ##
5756 ##
Cary Clark8032b982017-07-28 11:04:54 -04005757
5758 #Method RawIter(const SkPath& path)
5759
5760
5761 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5762
Cary Clark73fa9722017-08-29 17:36:51 -04005763 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005764
Cary Clark73fa9722017-08-29 17:36:51 -04005765 #Return RawIter of path ##
5766
5767 #NoExample
5768 ##
5769 ##
Cary Clark8032b982017-07-28 11:04:54 -04005770
5771 #Method void setPath(const SkPath& path)
5772
5773 Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5774
Cary Clark73fa9722017-08-29 17:36:51 -04005775 #Param path Path to iterate ##
5776
5777 #NoExample
5778 ##
5779 ##
Cary Clark8032b982017-07-28 11:04:54 -04005780
5781 #Method Verb next(SkPoint pts[4])
5782
5783 Returns next Verb in Verb_Array, and advances RawIter.
5784 When Verb_Array is exhausted, returns kDone_Verb.
5785 Zero to four Points are stored in pts, depending on the returned Verb.
5786
Cary Clarka523d2d2017-08-30 08:58:10 -04005787 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005788
Cary Clark73fa9722017-08-29 17:36:51 -04005789 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005790
5791 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005792 void draw(SkCanvas* canvas) {
5793 SkPath path;
5794 path.moveTo(50, 60);
5795 path.quadTo(10, 20, 30, 40);
5796 path.close();
5797 path.lineTo(30, 30);
5798 path.conicTo(1, 2, 3, 4, .5f);
5799 path.cubicTo(-1, -2, -3, -4, -5, -6);
5800 SkPath::RawIter iter(path);
5801 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5802 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5803 SkPath::Verb verb;
5804 do {
5805 SkPoint points[4];
5806 verb = iter.next(points);
5807 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5808 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5809 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5810 }
5811 if (SkPath::kConic_Verb == verb) {
5812 SkDebugf("weight = %g", iter.conicWeight());
5813 }
5814 SkDebugf("\n");
5815 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005816 }
5817 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005818 kMove_Verb {50, 60},
5819 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5820 kClose_Verb {50, 60},
5821 kMove_Verb {50, 60},
5822 kLine_Verb {50, 60}, {30, 30},
5823 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
5824 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
Cary Clark8032b982017-07-28 11:04:54 -04005825 kDone_Verb
5826 ##
5827 ##
5828
5829 #SeeAlso peek()
5830
Cary Clark73fa9722017-08-29 17:36:51 -04005831 ##
Cary Clark8032b982017-07-28 11:04:54 -04005832
5833 #Method Verb peek() const
5834
5835 Returns next Verb, but does not advance RawIter.
5836
Cary Clark73fa9722017-08-29 17:36:51 -04005837 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005838
5839 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005840 SkPath path;
5841 path.quadTo(10, 20, 30, 40);
5842 path.conicTo(1, 2, 3, 4, .5f);
5843 path.cubicTo(1, 2, 3, 4, .5, 6);
5844 SkPath::RawIter iter(path);
5845 SkPath::Verb verb, peek = iter.peek();
5846 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5847 do {
5848 SkPoint points[4];
5849 verb = iter.next(points);
5850 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5851 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005852 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005853 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5854 #StdOut
5855 #Volatile
5856 peek Move == verb Move
5857 peek Quad == verb Quad
5858 peek Conic == verb Conic
5859 peek Cubic == verb Cubic
5860 peek Done == verb Done
5861 peek Done == verb Done
5862 ##
Cary Clark8032b982017-07-28 11:04:54 -04005863 ##
5864
5865 #Bug 6832
5866 StdOut isn't really volatile, it just produces the wrong result.
5867 A simple fix changes the output of hairlines and needs to be
5868 investigated to see if the change is correct or not.
5869 https://skia-review.googlesource.com/c/21340/
5870 ##
5871
5872 #SeeAlso next()
5873
Cary Clark73fa9722017-08-29 17:36:51 -04005874 ##
Cary Clark8032b982017-07-28 11:04:54 -04005875
Cary Clark73fa9722017-08-29 17:36:51 -04005876 #Method SkScalar conicWeight() const
5877
Cary Clark8032b982017-07-28 11:04:54 -04005878 Returns Conic_Weight if next() returned kConic_Verb.
5879
5880 If next() has not been called, or next() did not return kConic_Verb,
5881 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04005882
5883 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005884
5885 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005886 void draw(SkCanvas* canvas) {
5887 SkPath path;
5888 path.conicTo(1, 2, 3, 4, .5f);
5889 SkPath::RawIter iter(path);
5890 SkPoint p[4];
5891 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5892 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5893 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5894 p[2].fX, p[2].fY);
5895 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005896 }
5897 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005898 first verb is move
5899 next verb is conic
5900 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005901 conic weight: 0.5
5902 ##
5903 ##
5904
5905 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04005906
5907 ##
5908
5909#Class RawIter ##
5910
5911#Class SkPath ##
5912
5913#Topic Path ##