blob: 9caad2d4813ac709e0fc9cc622cb4672b4be70b5 [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
Cary Clark154beea2017-10-26 07:58:48 -0400459 Contour travels in a clockwise direction
Cary Clark73fa9722017-08-29 17:36:51 -0400460##
461#Const kCCW_Direction 1
Cary Clark154beea2017-10-26 07:58:48 -0400462 Contour travels in a counterclockwise direction
Cary Clark73fa9722017-08-29 17:36:51 -0400463##
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##
Cary Clark154beea2017-10-26 07:58:48 -0400747.
Cary Clark73fa9722017-08-29 17:36:51 -0400748
749weight is most useful when between zero (ending Point_Array) and
750one (this Point_Array); will work with values outside of this
751range.
752
753interpolate() returns false and leaves out unchanged if Point_Array is not
754the same size as ending Point_Array. Call isInterpolatable to check Path
755compatibility prior to calling interpolate().
756
757#Param ending Point_Array averaged with this Point_Array ##
758#Param weight contribution of ending Point_Array, and
759 one minus contribution of this Point_Array
760##
761#Param out Path replaced by interpolated averages ##
762
763#Return true if Paths contain same number of Points ##
764
765#Example
766#Height 60
767void draw(SkCanvas* canvas) {
768 SkPaint paint;
769 paint.setAntiAlias(true);
770 paint.setStyle(SkPaint::kStroke_Style);
771 SkPath path, path2;
772 path.moveTo(20, 20);
773 path.lineTo(40, 40);
774 path.lineTo(20, 40);
775 path.lineTo(40, 20);
776 path.close();
777 path2.addRect({20, 20, 40, 40});
778 for (SkScalar i = 0; i <= 1; i += 1.f / 6) {
779 SkPath interp;
780 path.interpolate(path2, i, &interp);
781 canvas->drawPath(interp, paint);
782 canvas->translate(30, 0);
783 }
784}
785##
786
787#SeeAlso isInterpolatable
788
789##
790
791# ------------------------------------------------------------------------------
792
793#Method bool unique() const
794
795#Private
796To be deprecated; only valid for Android framework.
797##
798
799#Return true if Path has one owner ##
800
801##
802
803# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -0400804#Subtopic Fill_Type
805
Cary Clark73fa9722017-08-29 17:36:51 -0400806#Enum FillType
807
808#Code
809 enum FillType {
810 kWinding_FillType,
811 kEvenOdd_FillType,
812 kInverseWinding_FillType,
813 kInverseEvenOdd_FillType,
814 };
815##
Cary Clark8032b982017-07-28 11:04:54 -0400816
817Fill_Type selects the rule used to fill Path. Path set to kWinding_FillType
818fills if the sum of Contour edges is not zero, where clockwise edges add one, and
819counterclockwise edges subtract one. Path set to kEvenOdd_FillType fills if the
820number of Contour edges is odd. Each Fill_Type has an inverse variant that
821reverses the rule:
822kInverseWinding_FillType fills where the sum of Contour edges is zero;
823kInverseEvenOdd_FillType fills where the number of Contour edges is even.
824
825#Example
826#Height 100
827#Description
828The top row has two clockwise rectangles. The second row has one clockwise and
829one counterclockwise rectangle. The even-odd variants draw the same. The
830winding variants draw the top rectangle overlap, which has a winding of 2, the
831same as the outer parts of the top rectangles, which have a winding of 1.
832##
Cary Clark73fa9722017-08-29 17:36:51 -0400833void draw(SkCanvas* canvas) {
834 SkPath path;
835 path.addRect({10, 10, 30, 30}, SkPath::kCW_Direction);
836 path.addRect({20, 20, 40, 40}, SkPath::kCW_Direction);
837 path.addRect({10, 60, 30, 80}, SkPath::kCW_Direction);
838 path.addRect({20, 70, 40, 90}, SkPath::kCCW_Direction);
839 SkPaint strokePaint;
840 strokePaint.setStyle(SkPaint::kStroke_Style);
841 SkRect clipRect = {0, 0, 51, 100};
842 canvas->drawPath(path, strokePaint);
843 SkPaint fillPaint;
844 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
845 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
846 canvas->translate(51, 0);
847 canvas->save();
848 canvas->clipRect(clipRect);
849 path.setFillType(fillType);
850 canvas->drawPath(path, fillPaint);
851 canvas->restore();
852 }
Cary Clark8032b982017-07-28 11:04:54 -0400853}
854##
Cary Clark73fa9722017-08-29 17:36:51 -0400855
856#Const kWinding_FillType 0
857Specifies fill as area is enclosed by a non-zero sum of Contour Directions.
858##
859#Const kEvenOdd_FillType 1
860Specifies fill as area enclosed by an odd number of Contours.
861##
862#Const kInverseWinding_FillType 2
863Specifies fill as area is enclosed by a zero sum of Contour Directions.
864##
865#Const kInverseEvenOdd_FillType 3
866Specifies fill as area enclosed by an even number of Contours.
867##
868
869#Example
870#Height 230
871void draw(SkCanvas* canvas) {
872 SkPath path;
873 path.addRect({20, 10, 80, 70}, SkPath::kCW_Direction);
874 path.addRect({40, 30, 100, 90}, SkPath::kCW_Direction);
875 SkPaint strokePaint;
876 strokePaint.setStyle(SkPaint::kStroke_Style);
877 SkRect clipRect = {0, 0, 128, 128};
878 canvas->drawPath(path, strokePaint);
879 canvas->drawLine({0, 50}, {120, 50}, strokePaint);
880 SkPaint textPaint;
881 textPaint.setAntiAlias(true);
882 textPaint.setTextAlign(SkPaint::kCenter_Align);
883 SkScalar textHPos[] = { 10, 30, 60, 90, 110 };
884 canvas->drawPosTextH("01210", 5, textHPos, 48, textPaint);
885 textPaint.setTextSize(18);
886 canvas->translate(0, 128);
887 canvas->scale(.5f, .5f);
888 canvas->drawString("inverse", 384, 150, textPaint);
889 SkPaint fillPaint;
890 for (auto fillType : { SkPath::kWinding_FillType, SkPath::kEvenOdd_FillType,
891 SkPath::kInverseWinding_FillType, SkPath::kInverseEvenOdd_FillType } ) {
892 canvas->save();
893 canvas->clipRect(clipRect);
894 path.setFillType(fillType);
895 canvas->drawPath(path, fillPaint);
896 canvas->restore();
897 canvas->drawString(fillType & 1 ? "even-odd" : "winding", 64, 170, textPaint);
898 canvas->translate(128, 0);
899 }
900}
901##
902
903#SeeAlso SkPaint::Style Direction getFillType setFillType
904
905##
906
907# ------------------------------------------------------------------------------
908
909#Method FillType getFillType() const
910
911Returns FillType, the rule used to fill Path. FillType of a new Path is
912kWinding_FillType.
913
914#Return one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
915kInverseEvenOdd_FillType
916##
917
918#Example
919 SkPath path;
920 SkDebugf("default path fill type is %s\n",
921 path.getFillType() == SkPath::kWinding_FillType ? "kWinding_FillType" :
922 path.getFillType() == SkPath::kEvenOdd_FillType ? "kEvenOdd_FillType" :
923 path.getFillType() == SkPath::kInverseWinding_FillType ? "kInverseWinding_FillType" :
924 "kInverseEvenOdd_FillType");
925#StdOut
926default path fill type is kWinding_FillType
927##
928##
929
930#SeeAlso FillType setFillType isInverseFillType
931
932##
933
934# ------------------------------------------------------------------------------
935
936#Method void setFillType(FillType ft)
937
938Sets FillType, the rule used to fill Path. While there is no check
939that ft is legal, values outside of FillType are not supported.
940
941#Param ft one of: kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType,
942kInverseEvenOdd_FillType
943##
944
945#Example
946#Description
947If empty Path is set to inverse FillType, it fills all pixels.
948##
949#Height 64
950 SkPath path;
951 path.setFillType(SkPath::kInverseWinding_FillType);
952 SkPaint paint;
953 paint.setColor(SK_ColorBLUE);
954 canvas->drawPath(path, paint);
955##
956
957#SeeAlso FillType getFillType toggleInverseFillType
958
959##
960
961# ------------------------------------------------------------------------------
962
963#Method bool isInverseFillType() const
964
965Returns if FillType describes area outside Path geometry. The inverse fill area
966extends indefinitely.
967
968#Return true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType ##
969
970#Example
971 SkPath path;
972 SkDebugf("default path fill type is inverse: %s\n",
973 path.isInverseFillType() ? "true" : "false");
974#StdOut
975default path fill type is inverse: false
976##
977##
978
979#SeeAlso FillType getFillType setFillType toggleInverseFillType
980
981##
982
983# ------------------------------------------------------------------------------
984
985#Method void toggleInverseFillType()
986
987Replace FillType with its inverse. The inverse of FillType describes the area
988unmodified by the original FillType.
989
990#Table
991#Legend
992# FillType # toggled FillType ##
993##
994# kWinding_FillType # kInverseWinding_FillType ##
995# kEvenOdd_FillType # kInverseEvenOdd_FillType ##
996# kInverseWinding_FillType # kWinding_FillType ##
997# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
998##
999
1000#Example
1001#Description
1002Path drawn normally and through its inverse touches every pixel once.
1003##
1004#Height 100
1005SkPath path;
1006SkPaint paint;
1007paint.setColor(SK_ColorRED);
Cary Clark8032b982017-07-28 11:04:54 -04001008paint.setTextSize(80);
1009paint.getTextPath("ABC", 3, 20, 80, &path);
Cary Clark73fa9722017-08-29 17:36:51 -04001010canvas->drawPath(path, paint);
1011path.toggleInverseFillType();
1012paint.setColor(SK_ColorGREEN);
1013canvas->drawPath(path, paint);
1014##
1015
1016#SeeAlso FillType getFillType setFillType isInverseFillType
1017
1018##
1019
Cary Clark8032b982017-07-28 11:04:54 -04001020#Subtopic Fill_Type ##
Cary Clark73fa9722017-08-29 17:36:51 -04001021
1022# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001023
1024#Subtopic Convexity
Cary Clark73fa9722017-08-29 17:36:51 -04001025
1026#Enum Convexity
1027
1028#Code
Cary Clark884dd7d2017-10-11 10:37:52 -04001029 enum Convexity : uint8_t {
Cary Clark73fa9722017-08-29 17:36:51 -04001030 kUnknown_Convexity,
1031 kConvex_Convexity,
1032 kConcave_Convexity,
1033 };
1034##
1035
Cary Clark8032b982017-07-28 11:04:54 -04001036Path is convex if it contains one Contour and Contour loops no more than
1037360 degrees, and Contour angles all have same Direction. Convex Path
1038may have better performance and require fewer resources on GPU_Surface.
1039
Cary Clark73fa9722017-08-29 17:36:51 -04001040Path is concave when either at least one Direction change is clockwise and
1041another is counterclockwise, or the sum of the changes in Direction is not 360
1042degrees.
1043
1044Initially Path Convexity is kUnknown_Convexity. Path Convexity is computed
1045if needed by destination Surface.
1046
1047#Const kUnknown_Convexity 0
1048 Indicates Convexity has not been determined.
1049##
1050#Const kConvex_Convexity 1
1051 Path has one Contour made of a simple geometry without indentations.
1052##
1053#Const kConcave_Convexity 2
1054 Path has more than one Contour, or a geometry with indentations.
1055##
1056
1057#Example
1058void draw(SkCanvas* canvas) {
1059 SkPaint paint;
1060 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1061 const char* labels[] = { "unknown", "convex", "concave" };
1062 for (SkScalar x : { 40, 100 } ) {
1063 SkPath path;
1064 quad[0].fX = x;
1065 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1066 canvas->drawPath(path, paint);
1067 canvas->drawString(labels[(int) path.getConvexity()], 30, 100, paint);
1068 canvas->translate(100, 100);
1069 }
1070}
1071##
1072
1073#SeeAlso Contour Direction getConvexity getConvexityOrUnknown setConvexity isConvex
1074
1075#Enum Convexity ##
1076
1077#Method Convexity getConvexity() const
1078
1079Computes Convexity if required, and returns stored value.
1080Convexity is computed if stored value is kUnknown_Convexity,
1081or if Path has been altered since Convexity was computed or set.
1082
Cary Clarka523d2d2017-08-30 08:58:10 -04001083#Return computed or stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001084
1085#Example
1086void draw(SkCanvas* canvas) {
1087 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1088 SkDebugf("%s path convexity is %s\n", prefix,
1089 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1090 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1091 SkPath path;
1092 debugster("initial", path);
1093 path.lineTo(50, 0);
1094 debugster("first line", path);
1095 path.lineTo(50, 50);
1096 debugster("second line", path);
1097 path.lineTo(100, 50);
1098 debugster("third line", path);
1099}
1100##
1101
1102#SeeAlso Convexity Contour Direction getConvexityOrUnknown setConvexity isConvex
1103
1104##
1105
1106# ------------------------------------------------------------------------------
1107
1108#Method Convexity getConvexityOrUnknown() const
1109
1110Returns last computed Convexity, or kUnknown_Convexity if
1111Path has been altered since Convexity was computed or set.
1112
Cary Clarka523d2d2017-08-30 08:58:10 -04001113#Return stored Convexity ##
Cary Clark73fa9722017-08-29 17:36:51 -04001114
1115#Example
1116#Description
1117Convexity is unknown unless getConvexity is called without a subsequent call
1118that alters the path.
1119##
1120void draw(SkCanvas* canvas) {
1121 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1122 SkDebugf("%s path convexity is %s\n", prefix,
1123 SkPath::kUnknown_Convexity == path.getConvexityOrUnknown() ? "unknown" :
1124 SkPath::kConvex_Convexity == path.getConvexityOrUnknown() ? "convex" : "concave"); };
1125 SkPath path;
1126 debugster("initial", path);
1127 path.lineTo(50, 0);
1128 debugster("first line", path);
1129 path.getConvexity();
1130 path.lineTo(50, 50);
1131 debugster("second line", path);
1132 path.lineTo(100, 50);
1133 path.getConvexity();
1134 debugster("third line", path);
1135}
1136##
1137
1138#SeeAlso Convexity Contour Direction getConvexity setConvexity isConvex
1139
1140##
1141
1142# ------------------------------------------------------------------------------
1143
1144#Method void setConvexity(Convexity convexity)
1145
1146Stores convexity so that it is later returned by getConvexity or getConvexityOrUnknown.
1147convexity may differ from getConvexity, although setting an incorrect value may
1148cause incorrect or inefficient drawing.
1149
1150If convexity is kUnknown_Convexity: getConvexity will
1151compute Convexity, and getConvexityOrUnknown will return kUnknown_Convexity.
1152
1153If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity
1154and getConvexityOrUnknown will return convexity until the path is
1155altered.
1156
1157#Param convexity one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity ##
1158
1159#Example
1160void draw(SkCanvas* canvas) {
1161 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1162 SkDebugf("%s path convexity is %s\n", prefix,
1163 SkPath::kUnknown_Convexity == path.getConvexity() ? "unknown" :
1164 SkPath::kConvex_Convexity == path.getConvexity() ? "convex" : "concave"); };
1165 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1166 SkPath path;
1167 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1168 debugster("initial", path);
1169 path.setConvexity(SkPath::kConcave_Convexity);
1170 debugster("after forcing concave", path);
1171 path.setConvexity(SkPath::kUnknown_Convexity);
1172 debugster("after forcing unknown", path);
1173}
1174##
1175
1176#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown isConvex
1177
1178##
1179
1180# ------------------------------------------------------------------------------
1181
1182#Method bool isConvex() const
1183
1184Computes Convexity if required, and returns true if value is kConvex_Convexity.
1185If setConvexity was called with kConvex_Convexity or kConcave_Convexity, and
1186the path has not been altered, Convexity is not recomputed.
1187
1188#Return true if Convexity stored or computed is kConvex_Convexity ##
1189
1190#Example
1191#Description
1192Concave shape is erroneously considered convex after a forced call to
1193setConvexity.
1194##
1195void draw(SkCanvas* canvas) {
1196 SkPaint paint;
1197 SkPoint quad[] = {{70, 70}, {20, 20}, {120, 20}, {120, 120}};
1198 for (SkScalar x : { 40, 100 } ) {
1199 SkPath path;
1200 quad[0].fX = x;
1201 path.addPoly(quad, SK_ARRAY_COUNT(quad), true);
1202 path.setConvexity(SkPath::kConvex_Convexity);
1203 canvas->drawPath(path, paint);
1204 canvas->drawString(path.isConvex() ? "convex" : "not convex", 30, 100, paint);
1205 canvas->translate(100, 100);
1206 }
1207}
1208##
1209
1210#SeeAlso Convexity Contour Direction getConvexity getConvexityOrUnknown setConvexity
1211
1212##
1213
1214# ------------------------------------------------------------------------------
1215
1216#Method void setIsConvex(bool isConvex)
1217
1218Deprecated. Use setConvexity.
1219
1220#Deprecated
1221##
1222
1223#NoExample
1224##
1225
1226#SeeAlso Convexity setConvexity getConvexity
1227
1228##
1229
1230#Subtopic Convexity ##
1231
1232# ------------------------------------------------------------------------------
1233
1234#Method bool isOval(SkRect* rect, Direction* dir = nullptr,
1235 unsigned* start = nullptr) const
1236
1237Returns true if constructed by addCircle, addOval; and in some cases,
1238addRoundRect, addRRect. Path constructed with conicTo or rConicTo will not
1239return true though Path draws Oval.
1240
1241rect receives bounds of Oval.
1242dir receives Direction of Oval: kCW_Direction if clockwise, kCCW_Direction if
1243counterclockwise.
1244start receives start of Oval: 0 for top, 1 for right, 2 for bottom, 3 for left.
1245
1246rect, dir, and start are unmodified if Oval is not found.
1247
1248Triggers performance optimizations on some GPU_Surface implementations.
1249
1250#Param rect storage for bounding Rect of Oval; may be nullptr ##
1251#Param dir storage for Direction; may be nullptr ##
1252#Param start storage for start of Oval; may be nullptr ##
1253
1254#Return true if Path was constructed by method that reduces to Oval ##
1255
1256#Example
1257void draw(SkCanvas* canvas) {
1258 SkPaint paint;
1259 SkPath path;
1260 path.addOval({20, 20, 220, 220}, SkPath::kCW_Direction, 1);
1261 SkRect bounds;
1262 SkPath::Direction direction;
1263 unsigned start;
1264 path.isOval(&bounds, &direction, &start);
1265 paint.setColor(0xFF9FBFFF);
1266 canvas->drawRect(bounds, paint);
1267 paint.setColor(0x3f000000);
1268 canvas->drawPath(path, paint);
1269 paint.setColor(SK_ColorBLACK);
1270 canvas->rotate(start * 90, bounds.centerX(), bounds.centerY());
1271 char startText = '0' + start;
1272 paint.setTextSize(20);
1273 canvas->drawText(&startText, 1, bounds.centerX(), bounds.fTop + 20, paint);
1274 paint.setStyle(SkPaint::kStroke_Style);
1275 paint.setStrokeWidth(4);
1276 path.reset();
1277 path.addArc(bounds, -90, SkPath::kCW_Direction == direction ? 90 : -90);
1278 path.rLineTo(20, -20);
1279 canvas->drawPath(path, paint);
1280}
1281##
1282
1283#SeeAlso Oval addCircle addOval
1284
1285##
1286
1287# ------------------------------------------------------------------------------
1288
1289#Method bool isRRect(SkRRect* rrect, Direction* dir = nullptr,
1290 unsigned* start = nullptr) const
1291
1292Returns true if constructed by addRoundRect, addRRect; and if construction
Cary Clarkce101242017-09-01 15:51:02 -04001293is not empty, not Rect, and not Oval. Path constructed with other calls
Cary Clark73fa9722017-08-29 17:36:51 -04001294will not return true though Path draws Round_Rect.
1295
1296rrect receives bounds of Round_Rect.
1297dir receives Direction of Oval: kCW_Direction if clockwise, kCCW_Direction if
1298counterclockwise.
1299start receives start of Round_Rect: 0 for top, 1 for right, 2 for bottom, 3 for left.
1300
1301rrect, dir, and start are unmodified if Round_Rect is not found.
1302
1303Triggers performance optimizations on some GPU_Surface implementations.
1304
1305#Param rrect storage for bounding Rect of Round_Rect; may be nullptr ##
1306#Param dir storage for Direction; may be nullptr ##
1307#Param start storage for start of Round_Rect; may be nullptr ##
1308
Cary Clarkce101242017-09-01 15:51:02 -04001309#Return true if Path contains only Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04001310
1311#Example
Cary Clarkce101242017-09-01 15:51:02 -04001312#Description
1313Draw rounded rectangle and its bounds. Draw an arc indicating where the rounded
1314rectangle starts and its direction.
1315##
Cary Clark73fa9722017-08-29 17:36:51 -04001316void draw(SkCanvas* canvas) {
1317 SkPaint paint;
1318 SkPath path;
1319 path.addRRect(SkRRect::MakeRectXY({20, 20, 220, 220}, 30, 50), SkPath::kCCW_Direction, 3);
1320 SkRRect rrect;
1321 SkPath::Direction direction;
1322 unsigned start;
1323 path.isRRect(&rrect, &direction, &start);
1324 const SkRect& bounds = rrect.rect();
1325 paint.setColor(0xFF9FBFFF);
1326 canvas->drawRect(bounds, paint);
1327 paint.setColor(0x3f000000);
1328 canvas->drawPath(path, paint);
1329 paint.setColor(SK_ColorBLACK);
1330 canvas->rotate(start * 90, bounds.centerX(), bounds.centerY());
1331 char startText = '0' + start;
1332 paint.setTextSize(20);
1333 canvas->drawText(&startText, 1, bounds.centerX(), bounds.fTop + 20, paint);
1334 paint.setStyle(SkPaint::kStroke_Style);
1335 paint.setStrokeWidth(4);
1336 path.reset();
1337 path.addArc(bounds, -90, SkPath::kCW_Direction == direction ? 90 : -90);
1338 path.rLineTo(20, -20);
1339 canvas->drawPath(path, paint);
1340}
1341##
1342
1343#SeeAlso Round_Rect addRoundRect addRRect
1344
1345##
1346
1347# ------------------------------------------------------------------------------
1348
1349#Method void reset()
1350
Cary Clarkce101242017-09-01 15:51:02 -04001351Sets Path to its initial state.
Cary Clark73fa9722017-08-29 17:36:51 -04001352Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1353Internal storage associated with Path is released.
1354
1355#Example
1356 SkPath path1, path2;
1357 path1.setFillType(SkPath::kInverseWinding_FillType);
1358 path1.addRect({10, 20, 30, 40});
1359 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1360 path1.reset();
1361 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1362##
1363
1364#SeeAlso rewind()
1365
1366##
1367
1368# ------------------------------------------------------------------------------
1369
1370#Method void rewind()
1371
Cary Clarkce101242017-09-01 15:51:02 -04001372Sets Path to its initial state, preserving internal storage.
Cary Clark73fa9722017-08-29 17:36:51 -04001373Removes Verb_Array, Point_Array, and Weights, and sets FillType to kWinding_FillType.
1374Internal storage associated with Path is retained.
1375
1376Use rewind() instead of reset() if Path storage will be reused and performance
1377is critical.
1378
1379#Example
1380#Description
1381Although path1 retains its internal storage, it is indistinguishable from
1382a newly initialized path.
1383##
1384 SkPath path1, path2;
1385 path1.setFillType(SkPath::kInverseWinding_FillType);
1386 path1.addRect({10, 20, 30, 40});
1387 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1388 path1.rewind();
1389 SkDebugf("path1 %c= path2\n", path1 == path2 ? '=' : '!');
1390##
1391
1392#SeeAlso reset()
1393
1394##
1395
1396# ------------------------------------------------------------------------------
1397
1398#Method bool isEmpty() const
1399
1400Empty Path may have FillType but has no SkPoint, Verb, or Conic_Weight.
1401SkPath() constructs empty Path; reset() and (rewind) make Path empty.
1402
1403#Return true if the path contains no Verb array ##
1404
1405#Example
1406void draw(SkCanvas* canvas) {
1407 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1408 SkDebugf("%s path is %s" "empty\n", prefix, path.isEmpty() ? "" : "not ");
1409 };
1410 SkPath path;
1411 debugster("initial", path);
1412 path.moveTo(0, 0);
1413 debugster("after moveTo", path);
1414 path.rewind();
1415 debugster("after rewind", path);
1416 path.lineTo(0, 0);
1417 debugster("after lineTo", path);
1418 path.reset();
1419 debugster("after reset", path);
1420}
1421#StdOut
1422initial path is empty
1423after moveTo path is not empty
1424after rewind path is empty
1425after lineTo path is not empty
1426after reset path is empty
1427##
1428##
1429
1430#SeeAlso SkPath() reset() rewind()
1431
1432##
1433
1434# ------------------------------------------------------------------------------
1435
1436#Method bool isLastContourClosed() const
1437
1438Contour is closed if Path Verb array was last modified by close(). When stroked,
1439closed Contour draws Paint_Stroke_Join instead of Paint_Stroke_Cap at first and last Point.
1440
1441#Return true if the last Contour ends with a kClose_Verb ##
1442
1443#Example
1444#Description
1445close() has no effect if Path is empty; isLastContourClosed() returns
1446false until Path has geometry followed by close().
1447##
1448void draw(SkCanvas* canvas) {
1449 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1450 SkDebugf("%s last contour is %s" "closed\n", prefix,
1451 path.isLastContourClosed() ? "" : "not ");
1452 };
1453 SkPath path;
1454 debugster("initial", path);
1455 path.close();
1456 debugster("after close", path);
1457 path.lineTo(0, 0);
1458 debugster("after lineTo", path);
1459 path.close();
1460 debugster("after close", path);
1461}
1462#StdOut
1463initial last contour is not closed
1464after close last contour is not closed
1465after lineTo last contour is not closed
1466after close last contour is closed
1467##
1468##
1469
1470#SeeAlso close()
1471
1472##
1473
1474# ------------------------------------------------------------------------------
1475
1476#Method bool isFinite() const
1477
1478Returns true for finite Point array values between negative SK_ScalarMax and
1479positive SK_ScalarMax. Returns false for any Point array value of
1480SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
1481
1482#Return true if all Point values are finite ##
1483
1484#Example
1485void draw(SkCanvas* canvas) {
1486 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1487 SkDebugf("%s path is %s" "finite\n", prefix, path.isFinite() ? "" : "not ");
1488 };
1489 SkPath path;
1490 debugster("initial", path);
1491 path.lineTo(SK_ScalarMax, SK_ScalarMax);
1492 debugster("after line", path);
1493 SkMatrix matrix;
1494 matrix.setScale(2, 2);
1495 path.transform(matrix);
1496 debugster("after scale", path);
1497}
1498#StdOut
1499initial path is finite
1500after line path is finite
1501after scale path is not finite
1502##
1503##
1504
1505#SeeAlso SkScalar
1506##
1507
1508# ------------------------------------------------------------------------------
1509
1510#Method bool isVolatile() const
1511
1512Returns true if the path is volatile; it will not be altered or discarded
1513by the caller after it is drawn. Paths by default have volatile set false, allowing
1514Surface to attach a cache of data which speeds repeated drawing. If true, Surface
1515may not speed repeated drawing.
1516
1517#Return true if caller will alter Path after drawing ##
1518
1519#Example
1520 SkPath path;
1521 SkDebugf("volatile by default is %s\n", path.isVolatile() ? "true" : "false");
1522#StdOut
1523volatile by default is false
1524##
1525##
1526
1527#SeeAlso setIsVolatile
1528
1529##
1530
1531# ------------------------------------------------------------------------------
1532
1533#Method void setIsVolatile(bool isVolatile)
1534
1535Specify whether Path is volatile; whether it will be altered or discarded
1536by the caller after it is drawn. Paths by default have volatile set false, allowing
1537Device to attach a cache of data which speeds repeated drawing.
1538
1539Mark temporary paths, discarded or modified after use, as volatile
1540to inform Device that the path need not be cached.
1541
1542Mark animating Path volatile to improve performance.
Cary Clarkce101242017-09-01 15:51:02 -04001543Mark unchanging Path non-volatile to improve repeated rendering.
Cary Clark73fa9722017-08-29 17:36:51 -04001544
1545Raster_Surface Path draws are affected by volatile for some shadows.
1546GPU_Surface Path draws are affected by volatile for some shadows and concave geometries.
1547
1548#Param isVolatile true if caller will alter Path after drawing ##
1549
1550#Example
1551#Height 50
1552#Width 50
1553 SkPaint paint;
1554 paint.setStyle(SkPaint::kStroke_Style);
1555 SkPath path;
1556 path.setIsVolatile(true);
1557 path.lineTo(40, 40);
1558 canvas->drawPath(path, paint);
1559 path.rewind();
1560 path.moveTo(0, 40);
1561 path.lineTo(40, 0);
1562 canvas->drawPath(path, paint);
1563##
1564
1565#ToDo tie example to bench to show how volatile affects speed or dm to show resource usage ##
1566
1567#SeeAlso isVolatile
1568
1569##
1570
1571# ------------------------------------------------------------------------------
1572
1573#Method static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact)
1574
1575Test if Line between Point pair is degenerate.
1576Line with no length or that moves a very short distance is degenerate; it is
1577treated as a point.
1578
Cary Clarka523d2d2017-08-30 08:58:10 -04001579exact changes the equality test. If true, returns true only if p1 equals p2.
1580If false, returns true if p1 equals or nearly equals p2.
1581
Cary Clark73fa9722017-08-29 17:36:51 -04001582#Param p1 line start point ##
1583#Param p2 line end point ##
Cary Clarka523d2d2017-08-30 08:58:10 -04001584#Param exact if false, allow nearly equals ##
Cary Clark73fa9722017-08-29 17:36:51 -04001585
1586#Return true if Line is degenerate; its length is effectively zero ##
1587
1588#Example
1589#Description
Cary Clarkce101242017-09-01 15:51:02 -04001590As single precision floats, 100 and 100.000001 have the same bit representation,
1591and are exactly equal. 100 and 100.0001 have different bit representations, and
Cary Clark73fa9722017-08-29 17:36:51 -04001592are not exactly equal, but are nearly equal.
1593##
1594void draw(SkCanvas* canvas) {
1595 SkPoint points[] = { {100, 100}, {100.000001f, 100.000001f}, {100.0001f, 100.0001f} };
1596 for (size_t i = 0; i < SK_ARRAY_COUNT(points) - 1; ++i) {
1597 for (bool exact : { false, true } ) {
1598 SkDebugf("line from (%1.8g,%1.8g) to (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1599 points[i].fX, points[i].fY, points[i + 1].fX, points[i + 1].fY,
1600 SkPath::IsLineDegenerate(points[i], points[i + 1], exact)
1601 ? "" : "not ", exact ? "exactly" : "nearly");
1602 }
1603 }
1604}
1605#StdOut
1606line from (100,100) to (100,100) is degenerate, nearly
1607line from (100,100) to (100,100) is degenerate, exactly
1608line from (100,100) to (100.0001,100.0001) is degenerate, nearly
1609line from (100,100) to (100.0001,100.0001) is not degenerate, exactly
1610#StdOut ##
1611##
1612
1613#SeeAlso IsQuadDegenerate IsCubicDegenerate SkPoint::equalsWithinTolerance
1614##
1615
1616# ------------------------------------------------------------------------------
1617
1618#Method static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
1619 const SkPoint& p3, bool exact)
1620
1621Test if Quad is degenerate.
1622Quad with no length or that moves a very short distance is degenerate; it is
1623treated as a point.
1624
Cary Clarkce101242017-09-01 15:51:02 -04001625#Param p1 Quad start point ##
1626#Param p2 Quad control point ##
1627#Param p3 Quad end point ##
Cary Clark73fa9722017-08-29 17:36:51 -04001628#Param exact if true, returns true only if p1, p2, and p3 are equal;
1629 if false, returns true if p1, p2, and p3 are equal or nearly equal
1630##
1631
1632#Return true if Quad is degenerate; its length is effectively zero ##
1633
1634#Example
1635#Description
Cary Clarkce101242017-09-01 15:51:02 -04001636As single precision floats: 100, 100.00001, and 100.00002 have different bit representations
Cary Clark73fa9722017-08-29 17:36:51 -04001637but nearly the same value. Translating all three by 1000 gives them the same bit representation;
Cary Clarkce101242017-09-01 15:51:02 -04001638the fractional portion of the number can not be represented by the float and is lost.
Cary Clark73fa9722017-08-29 17:36:51 -04001639##
1640void draw(SkCanvas* canvas) {
1641 auto debugster = [](const SkPath& path, bool exact) -> void {
1642 SkDebugf("quad (%1.8g,%1.8g), (%1.8g,%1.8g), (%1.8g,%1.8g) is %s" "degenerate, %s\n",
1643 path.getPoint(0).fX, path.getPoint(0).fY, path.getPoint(1).fX,
1644 path.getPoint(1).fY, path.getPoint(2).fX, path.getPoint(2).fY,
1645 SkPath::IsQuadDegenerate(path.getPoint(0), path.getPoint(1), path.getPoint(2), exact) ?
1646 "" : "not ", exact ? "exactly" : "nearly");
1647 };
1648 SkPath path, offset;
1649 path.moveTo({100, 100});
1650 path.quadTo({100.00001f, 100.00001f}, {100.00002f, 100.00002f});
1651 offset.addPath(path, 1000, 1000);
1652 for (bool exact : { false, true } ) {
1653 debugster(path, exact);
1654 debugster(offset, exact);
1655 }
1656}
1657#StdOut
1658quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is degenerate, nearly
1659quad (1100,1100), (1100,1100), (1100,1100) is degenerate, nearly
1660quad (100,100), (100.00001,100.00001), (100.00002,100.00002) is not degenerate, exactly
1661quad (1100,1100), (1100,1100), (1100,1100) is degenerate, exactly
1662#StdOut ##
1663##
1664
1665#SeeAlso IsLineDegenerate IsCubicDegenerate SkPoint::equalsWithinTolerance
1666##
1667
1668# ------------------------------------------------------------------------------
1669
1670#Method static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
1671 const SkPoint& p3, const SkPoint& p4, bool exact)
1672
1673Test if Cubic is degenerate.
1674Cubic with no length or that moves a very short distance is degenerate; it is
1675treated as a point.
1676
Cary Clarkce101242017-09-01 15:51:02 -04001677#Param p1 Cubic start point ##
1678#Param p2 Cubic control point 1 ##
1679#Param p3 Cubic control point 2 ##
1680#Param p4 Cubic end point ##
Cary Clark73fa9722017-08-29 17:36:51 -04001681#Param exact if true, returns true only if p1, p2, p3, and p4 are equal;
1682 if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
1683##
1684
1685#Return true if Cubic is degenerate; its length is effectively zero ##
1686
1687#Example
1688void draw(SkCanvas* canvas) {
1689 SkPoint points[] = {{1, 0}, {0, 0}, {0, 0}, {0, 0}};
1690 SkScalar step = 1;
1691 SkScalar prior, length, degenerate;
1692 do {
1693 prior = points[0].fX;
1694 step /= 2;
1695 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3], false)) {
1696 degenerate = prior;
1697 points[0].fX += step;
1698 } else {
1699 length = prior;
1700 points[0].fX -= step;
1701 }
1702 } while (prior != points[0].fX);
1703 SkDebugf("%1.8g is degenerate\n", degenerate);
1704 SkDebugf("%1.8g is length\n", length);
1705}
1706#StdOut
17070.00024414062 is degenerate
17080.00024414065 is length
1709#StdOut ##
1710##
1711
1712##
1713
1714# ------------------------------------------------------------------------------
1715
1716#Method bool isLine(SkPoint line[2]) const
1717
1718Returns true if Path contains only one Line;
1719Path_Verb array has two entries: kMove_Verb, kLine_Verb.
1720If Path contains one Line and line is not nullptr, line is set to
1721Line start point and Line end point.
1722Returns false if Path is not one Line; line is unaltered.
1723
1724#Param line storage for Line. May be nullptr ##
1725
1726#Return true if Path contains exactly one Line ##
1727
1728#Example
1729void draw(SkCanvas* canvas) {
1730 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1731 SkPoint line[2];
1732 if (path.isLine(line)) {
1733 SkDebugf("%s is line (%1.8g,%1.8g) (%1.8g,%1.8g)\n", prefix,
1734 line[0].fX, line[0].fY, line[1].fX, line[1].fY);
1735 } else {
1736 SkDebugf("%s is not line\n", prefix);
1737 }
1738 };
1739 SkPath path;
1740 debugster("empty", path);
1741 path.lineTo(0, 0);
1742 debugster("zero line", path);
1743 path.rewind();
1744 path.moveTo(10, 10);
1745 path.lineTo(20, 20);
1746 debugster("line", path);
1747 path.moveTo(20, 20);
1748 debugster("second move", path);
1749}
1750#StdOut
1751empty is not line
1752zero line is line (0,0) (0,0)
1753line is line (10,10) (20,20)
1754second move is not line
1755##
1756##
1757
1758##
1759
1760# ------------------------------------------------------------------------------
1761
Cary Clark8032b982017-07-28 11:04:54 -04001762#Subtopic Point_Array
1763#Alias Point_Arrays
1764
1765Point_Array contains Points satisfying the allocated Points for
1766each Verb in Verb_Array. For instance, Path containing one Contour with Line
Cary Clarkce101242017-09-01 15:51:02 -04001767and Quad is described by Verb_Array: Verb::kMoveTo, Verb::kLineTo, Verb::kQuadTo; and
Cary Clark8032b982017-07-28 11:04:54 -04001768one Point for move, one Point for Line, two Points for Quad; totaling four Points.
1769
1770Point_Array may be read directly from Path with getPoints, or inspected with
1771getPoint, with Iter, or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001772
1773#Method int getPoints(SkPoint points[], int max) const
1774
1775Returns number of points in Path. Up to max points are copied.
1776points may be nullptr; then, max must be zero.
1777If max is greater than number of points, excess points storage is unaltered.
1778
1779#Param points storage for Path Point array. May be nullptr ##
1780#Param max maximum to copy; must be greater than or equal to zero ##
1781
1782#Return Path Point array length ##
1783
1784#Example
1785void draw(SkCanvas* canvas) {
1786 auto debugster = [](const char* prefix, const SkPath& path, SkPoint* points, int max) -> void {
1787 int count = path.getPoints(points, max);
1788 SkDebugf("%s point count: %d ", prefix, count);
1789 for (int i = 0; i < SkTMin(count, max) && points; ++i) {
1790 SkDebugf("(%1.8g,%1.8g) ", points[i].fX, points[i].fY);
1791 }
1792 SkDebugf("\n");
1793 };
1794 SkPath path;
1795 path.lineTo(20, 20);
1796 path.lineTo(-10, -10);
1797 SkPoint points[3];
1798 debugster("no points", path, nullptr, 0);
1799 debugster("zero max", path, points, 0);
1800 debugster("too small", path, points, 2);
1801 debugster("just right", path, points, path.countPoints());
1802}
1803#StdOut
1804no points point count: 3
1805zero max point count: 3
1806too small point count: 3 (0,0) (20,20)
1807just right point count: 3 (0,0) (20,20) (-10,-10)
1808##
1809##
1810
1811#SeeAlso countPoints getPoint
1812##
1813
1814#Method int countPoints() const
1815
1816Returns the number of points in Path.
1817Point count is initially zero.
1818
1819#Return Path Point array length ##
1820
1821#Example
1822void draw(SkCanvas* canvas) {
1823 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1824 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1825 };
1826 SkPath path;
1827 debugster("empty", path);
1828 path.lineTo(0, 0);
1829 debugster("zero line", path);
1830 path.rewind();
1831 path.moveTo(10, 10);
1832 path.lineTo(20, 20);
1833 debugster("line", path);
1834 path.moveTo(20, 20);
1835 debugster("second move", path);
1836}
1837#StdOut
1838empty point count: 0
1839zero line point count: 2
1840line point count: 2
1841second move point count: 3
1842##
1843##
1844
1845#SeeAlso getPoints
1846##
1847
1848#Method SkPoint getPoint(int index) const
1849
1850Returns Point at index in Point_Array. Valid range for index is
18510 to countPoints - 1.
1852Returns (0, 0) if index is out of range.
1853
1854#Param index Point array element selector ##
1855
1856#Return Point array value or (0, 0) ##
1857
1858#Example
1859void draw(SkCanvas* canvas) {
1860 auto debugster = [](const char* prefix, const SkPath& path) -> void {
1861 SkDebugf("%s point count: %d\n", prefix, path.countPoints());
1862 };
1863 SkPath path;
1864 path.lineTo(20, 20);
1865 path.offset(-10, -10);
1866 for (int i= 0; i < path.countPoints(); ++i) {
1867 SkDebugf("point %d: (%1.8g,%1.8g)\n", i, path.getPoint(i).fX, path.getPoint(i).fY);
1868 }
1869}
1870#StdOut
1871point 0: (-10,-10)
1872point 1: (10,10)
1873##
1874##
1875
1876#SeeAlso countPoints getPoints
1877##
1878
1879
1880#Subtopic Point_Array ##
1881
1882# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04001883#Subtopic Verb_Array
1884
1885Verb_Array always starts with kMove_Verb.
1886If kClose_Verb is not the last entry, it is always followed by kMove_Verb;
1887the quantity of kMove_Verb equals the Contour count.
1888Verb_Array does not include or count kDone_Verb; it is a convenience
1889returned when iterating through Verb_Array.
1890
1891Verb_Array may be read directly from Path with getVerbs, or inspected with Iter,
1892or with RawIter.
Cary Clark73fa9722017-08-29 17:36:51 -04001893
1894#Method int countVerbs() const
1895
1896Returns the number of Verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
1897kCubic_Verb, and kClose_Verb; added to Path.
1898
1899#Return length of Verb_Array ##
1900
1901#Example
1902SkPath path;
1903SkDebugf("empty verb count: %d\n", path.countVerbs());
1904path.addRoundRect({10, 20, 30, 40}, 5, 5);
1905SkDebugf("round rect verb count: %d\n", path.countVerbs());
1906#StdOut
1907empty verb count: 0
1908round rect verb count: 10
1909##
1910##
1911
1912#SeeAlso getVerbs Iter RawIter
1913
1914##
1915
1916#Method int getVerbs(uint8_t verbs[], int max) const
1917
1918Returns the number of verbs in the path. Up to max verbs are copied. The
1919verbs are copied as one byte per verb.
1920
1921#Param verbs storage for verbs, may be nullptr ##
1922#Param max maximum number to copy into verbs ##
1923
1924#Return the actual number of verbs in the path ##
1925
1926#Example
1927void draw(SkCanvas* canvas) {
1928 auto debugster = [](const char* prefix, const SkPath& path, uint8_t* verbs, int max) -> void {
1929 int count = path.getVerbs(verbs, max);
1930 SkDebugf("%s verb count: %d ", prefix, count);
1931 const char* verbStr[] = { "move", "line", "quad", "conic", "cubic", "close" };
1932 for (int i = 0; i < SkTMin(count, max) && verbs; ++i) {
1933 SkDebugf("%s ", verbStr[verbs[i]]);
1934 }
1935 SkDebugf("\n");
1936 };
1937 SkPath path;
1938 path.lineTo(20, 20);
1939 path.lineTo(-10, -10);
1940 uint8_t verbs[3];
1941 debugster("no verbs", path, nullptr, 0);
1942 debugster("zero max", path, verbs, 0);
1943 debugster("too small", path, verbs, 2);
1944 debugster("just right", path, verbs, path.countVerbs());
1945}
1946#StdOut
1947no verbs verb count: 3
1948zero max verb count: 3
1949too small verb count: 3 move line
1950just right verb count: 3 move line line
1951##
1952##
1953
1954#SeeAlso countVerbs getPoints Iter RawIter
1955##
Cary Clark8032b982017-07-28 11:04:54 -04001956
1957#Subtopic Verb_Array ##
Cary Clark73fa9722017-08-29 17:36:51 -04001958
1959# ------------------------------------------------------------------------------
1960
1961#Method void swap(SkPath& other)
1962
1963Exchanges the Verb_Array, Point_Array, Weights, and Fill_Type with other.
1964Cached state is also exchanged. swap() internally exchanges pointers, so
1965it is lightweight and does not allocate memory.
1966
1967swap() usage has largely been replaced by operator=(const SkPath& path).
Cary Clarkce101242017-09-01 15:51:02 -04001968Paths do not copy their content on assignment until they are written to,
Cary Clark73fa9722017-08-29 17:36:51 -04001969making assignment as efficient as swap().
1970
1971#Param other Path exchanged by value ##
1972
1973#Example
1974SkPath path1, path2;
1975path1.addRect({10, 20, 30, 40});
1976path1.swap(path2);
1977const SkRect& b1 = path1.getBounds();
1978SkDebugf("path1 bounds = %g, %g, %g, %g\n", b1.fLeft, b1.fTop, b1.fRight, b1.fBottom);
1979const SkRect& b2 = path2.getBounds();
1980SkDebugf("path2 bounds = %g, %g, %g, %g\n", b2.fLeft, b2.fTop, b2.fRight, b2.fBottom);
1981#StdOut
1982path1 bounds = 0, 0, 0, 0
1983path2 bounds = 10, 20, 30, 40
1984#StdOut ##
1985##
1986
1987#SeeAlso operator=(const SkPath& path)
1988
1989##
1990
1991# ------------------------------------------------------------------------------
1992
1993#Method const SkRect& getBounds() const
1994
1995Returns minimum and maximum x and y values of Point_Array.
1996Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
1997be larger or smaller than area affected when Path is drawn.
1998
1999Rect returned includes all Points added to Path, including Points associated with
2000kMove_Verb that define empty Contours.
2001
2002#Return bounds of all Points in Point_Array ##
2003
2004#Example
2005#Description
2006Bounds of upright Circle can be predicted from center and radius.
2007Bounds of rotated Circle includes control Points outside of filled area.
2008##
2009 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2010 const SkRect& bounds = path.getBounds();
2011 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
2012 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2013 };
2014 SkPath path;
2015 debugster("empty", path);
2016 path.addCircle(50, 45, 25);
2017 debugster("circle", path);
2018 SkMatrix matrix;
2019 matrix.setRotate(45, 50, 45);
2020 path.transform(matrix);
2021 debugster("rotated circle", path);
2022#StdOut
2023empty bounds = 0, 0, 0, 0
2024circle bounds = 25, 20, 75, 70
2025rotated circle bounds = 14.6447, 9.64466, 85.3553, 80.3553
2026##
2027##
2028
2029#SeeAlso computeTightBounds updateBoundsCache
2030
2031##
2032
2033# ------------------------------------------------------------------------------
2034
2035#Method void updateBoundsCache() const
2036
2037Update internal bounds so that subsequent calls to getBounds are instantaneous.
2038Unaltered copies of Path may also access cached bounds through getBounds.
2039
2040For now, identical to calling getBounds and ignoring the returned value.
2041
2042Call to prepare Path subsequently drawn from multiple threads,
2043to avoid a race condition where each draw separately computes the bounds.
2044
2045#Example
2046 double times[2] = { 0, 0 };
2047 for (int i = 0; i < 10000; ++i) {
2048 SkPath path;
2049 for (int j = 1; j < 100; ++ j) {
2050 path.addCircle(50 + j, 45 + j, 25 + j);
2051 }
2052 if (1 & i) {
2053 path.updateBoundsCache();
2054 }
2055 double start = SkTime::GetNSecs();
2056 (void) path.getBounds();
2057 times[1 & i] += SkTime::GetNSecs() - start;
2058 }
2059 SkDebugf("uncached avg: %g ms\n", times[0] * 1e-6);
2060 SkDebugf("cached avg: %g ms\n", times[1] * 1e-6);
2061#StdOut
2062#Volatile
2063uncached avg: 0.18048 ms
2064cached avg: 0.182784 ms
2065##
2066##
2067
2068#SeeAlso getBounds
2069#ToDo the results don't make sense, need to profile to figure this out ##
2070
2071##
2072
2073# ------------------------------------------------------------------------------
2074
2075#Method SkRect computeTightBounds() const
2076
2077Returns minimum and maximum x and y values of the lines and curves in Path.
2078Returns (0, 0, 0, 0) if Path contains no points.
2079Returned bounds width and height may be larger or smaller than area affected
2080when Path is drawn.
2081
2082Includes Points associated with kMove_Verb that define empty
2083Contours.
2084
2085Behaves identically to getBounds when Path contains
2086only lines. If Path contains curves, computed bounds includes
2087the maximum extent of the Quad, Conic, or Cubic; is slower than getBounds;
2088and unlike getBounds, does not cache the result.
2089
2090#Return tight bounds of curves in Path ##
2091
2092#Example
2093 auto debugster = [](const char* prefix, const SkPath& path) -> void {
2094 const SkRect& bounds = path.computeTightBounds();
2095 SkDebugf("%s bounds = %g, %g, %g, %g\n", prefix,
2096 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
2097 };
2098 SkPath path;
2099 debugster("empty", path);
2100 path.addCircle(50, 45, 25);
2101 debugster("circle", path);
2102 SkMatrix matrix;
2103 matrix.setRotate(45, 50, 45);
2104 path.transform(matrix);
2105 debugster("rotated circle", path);
2106#StdOut
2107empty bounds = 0, 0, 0, 0
2108circle bounds = 25, 20, 75, 70
2109rotated circle bounds = 25, 20, 75, 70
2110##
2111##
2112
2113#SeeAlso getBounds
2114
2115##
2116
2117# ------------------------------------------------------------------------------
2118
2119#Method bool conservativelyContainsRect(const SkRect& rect) const
2120
2121Returns true if rect is contained by Path.
2122May return false when rect is contained by Path.
2123
2124For now, only returns true if Path has one Contour and is convex.
2125rect may share points and edges with Path and be contained.
2126Returns true if rect is empty, that is, it has zero width or height; and
2127the Point or Line described by rect is contained by Path.
2128
2129#Param rect Rect, Line, or Point checked for containment ##
2130
2131#Return true if rect is contained ##
2132
2133#Example
2134#Height 140
2135#Description
2136Rect is drawn in blue if it is contained by red Path.
2137##
2138void draw(SkCanvas* canvas) {
2139 SkPath path;
2140 path.addRoundRect({10, 20, 54, 120}, 10, 20);
2141 SkRect tests[] = {
2142 { 10, 40, 54, 80 },
2143 { 25, 20, 39, 120 },
2144 { 15, 25, 49, 115 },
2145 { 13, 27, 51, 113 },
2146 };
2147 for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
2148 SkPaint paint;
2149 paint.setColor(SK_ColorRED);
2150 canvas->drawPath(path, paint);
2151 bool rectInPath = path.conservativelyContainsRect(tests[i]);
2152 paint.setColor(rectInPath ? SK_ColorBLUE : SK_ColorBLACK);
2153 canvas->drawRect(tests[i], paint);
2154 canvas->translate(64, 0);
2155 }
2156}
2157##
2158
2159#SeeAlso contains Op Rect Convexity
2160
2161##
2162
2163# ------------------------------------------------------------------------------
2164
2165#Method void incReserve(unsigned extraPtCount)
2166
2167grows Path Verb_Array and Point_Array to contain extraPtCount additional Points.
2168May improve performance and use less memory by
2169reducing the number and size of allocations when creating Path.
2170
Cary Clarkce101242017-09-01 15:51:02 -04002171#Param extraPtCount number of additional Points to allocate ##
Cary Clark73fa9722017-08-29 17:36:51 -04002172
2173#Example
2174#Height 192
2175void draw(SkCanvas* canvas) {
2176 auto addPoly = [](int sides, SkScalar size, SkPath* path) -> void {
2177 path->moveTo(size, 0);
2178 for (int i = 1; i < sides; i++) {
2179 SkScalar c, s = SkScalarSinCos(SK_ScalarPI * 2 * i / sides, &c);
2180 path->lineTo(c * size, s * size);
2181 }
2182 path->close();
2183 };
2184 SkPath path;
2185 path.incReserve(3 + 4 + 5 + 6 + 7 + 8 + 9);
2186 for (int sides = 3; sides < 10; ++sides) {
2187 addPoly(sides, sides, &path);
2188 }
2189 SkMatrix matrix;
2190 matrix.setScale(10, 10, -10, -10);
2191 path.transform(matrix);
2192 SkPaint paint;
2193 paint.setStyle(SkPaint::kStroke_Style);
2194 canvas->drawPath(path, paint);
2195}
2196##
2197
2198#SeeAlso Point_Array
2199
2200##
2201
2202# ------------------------------------------------------------------------------
2203
2204#Method void moveTo(SkScalar x, SkScalar y)
2205
2206Adds beginning of Contour at Point (x, y).
2207
2208#Param x x-coordinate of Contour start ##
2209#Param y y-coordinate of Contour start ##
2210
2211#Example
2212 #Width 140
2213 #Height 100
2214 void draw(SkCanvas* canvas) {
2215 SkRect rect = { 20, 20, 120, 80 };
2216 SkPath path;
2217 path.addRect(rect);
2218 path.moveTo(rect.fLeft, rect.fTop);
2219 path.lineTo(rect.fRight, rect.fBottom);
2220 path.moveTo(rect.fLeft, rect.fBottom);
2221 path.lineTo(rect.fRight, rect.fTop);
2222 SkPaint paint;
2223 paint.setStyle(SkPaint::kStroke_Style);
2224 canvas->drawPath(path, paint);
2225 }
2226##
2227
2228#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2229
2230##
2231
2232#Method void moveTo(const SkPoint& p)
2233
2234Adds beginning of Contour at Point p.
2235
2236#Param p contour start ##
2237
2238#Example
2239 #Width 128
2240 #Height 128
2241void draw(SkCanvas* canvas) {
2242 SkPoint data[][3] = {{{30,40},{60,60},{90,30}}, {{30,120},{60,100},{90,120}},
2243 {{60,100},{60,40},{70,30}}, {{60,40},{50,20},{70,30}}};
2244 SkPath path;
2245 for (unsigned i = 0; i < SK_ARRAY_COUNT(data); ++i) {
2246 path.moveTo(data[i][0]);
2247 path.lineTo(data[i][1]);
2248 path.lineTo(data[i][2]);
2249 }
2250 SkPaint paint;
2251 paint.setStyle(SkPaint::kStroke_Style);
2252 canvas->drawPath(path, paint);
2253}
2254##
2255
2256#SeeAlso Contour lineTo rMoveTo quadTo conicTo cubicTo close()
2257
2258##
2259
2260#Method void rMoveTo(SkScalar dx, SkScalar dy)
2261
2262Adds beginning of Contour relative to Last_Point.
2263If Path is empty, starts Contour at (dx, dy).
2264Otherwise, start Contour at Last_Point offset by (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002265Function name stands for "relative move to".
Cary Clark73fa9722017-08-29 17:36:51 -04002266
2267#Param dx offset from Last_Point x to Contour start x ##
2268#Param dy offset from Last_Point y to Contour start y ##
2269
2270#Example
2271 #Height 100
2272 SkPath path;
2273 path.addRect({20, 20, 80, 80}, SkPath::kCW_Direction, 2);
2274 path.rMoveTo(25, 2);
2275 SkVector arrow[] = {{0, -4}, {-20, 0}, {0, -3}, {-5, 5}, {5, 5}, {0, -3}, {20, 0}};
2276 for (unsigned i = 0; i < SK_ARRAY_COUNT(arrow); ++i) {
2277 path.rLineTo(arrow[i].fX, arrow[i].fY);
2278 }
2279 SkPaint paint;
2280 canvas->drawPath(path, paint);
2281 SkPoint lastPt;
2282 path.getLastPt(&lastPt);
2283 canvas->drawString("start", lastPt.fX, lastPt.fY, paint);
2284##
2285
2286#SeeAlso Contour lineTo moveTo quadTo conicTo cubicTo close()
2287
2288##
2289
2290# ------------------------------------------------------------------------------
2291
2292#Method void lineTo(SkScalar x, SkScalar y)
2293
2294Adds Line from Last_Point to (x, y). If Path is empty, or last Verb is
2295kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2296
2297lineTo appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2298lineTo then appends kLine_Verb to Verb_Array and (x, y) to Point_Array.
2299
2300#Param x end of added Line in x ##
2301#Param y end of added Line in y ##
2302
2303#Example
2304#Height 100
2305###$
2306void draw(SkCanvas* canvas) {
2307 SkPaint paint;
2308 paint.setAntiAlias(true);
2309 paint.setTextSize(72);
2310 canvas->drawString("#", 120, 80, paint);
2311 paint.setStyle(SkPaint::kStroke_Style);
2312 paint.setStrokeWidth(5);
2313 SkPath path;
2314 SkPoint hash[] = {{58, 28}, {43, 80}, {37, 45}, {85, 45}};
2315 SkVector offsets[] = {{0, 0}, {17, 0}, {0, 0}, {-5, 17}};
2316 unsigned o = 0;
2317 for (unsigned i = 0; i < SK_ARRAY_COUNT(hash); i += 2) {
2318 for (unsigned j = 0; j < 2; o++, j++) {
2319 path.moveTo(hash[i].fX + offsets[o].fX, hash[i].fY + offsets[o].fY);
2320 path.lineTo(hash[i + 1].fX + offsets[o].fX, hash[i + 1].fY + offsets[o].fY);
2321 }
2322 }
2323 canvas->drawPath(path, paint);
2324}
2325$$$#
2326##
2327
2328#SeeAlso Contour moveTo rLineTo addRect
2329
2330##
2331
2332# ------------------------------------------------------------------------------
2333
2334#Method void lineTo(const SkPoint& p)
2335
2336Adds Line from Last_Point to Point p. If Path is empty, or last Verb is
2337kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2338
2339lineTo first appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2340lineTo then appends kLine_Verb to Verb_Array and Point p to Point_Array.
2341
2342#Param p end Point of added Line ##
2343
2344#Example
2345#Height 100
2346 SkPath path;
2347 SkVector oxo[] = {{25, 25}, {35, 35}, {25, 35}, {35, 25},
2348 {40, 20}, {40, 80}, {60, 20}, {60, 80},
2349 {20, 40}, {80, 40}, {20, 60}, {80, 60}};
2350 for (unsigned i = 0; i < SK_ARRAY_COUNT(oxo); i += 2) {
2351 path.moveTo(oxo[i]);
2352 path.lineTo(oxo[i + 1]);
2353 }
2354 SkPaint paint;
2355 paint.setStyle(SkPaint::kStroke_Style);
2356 canvas->drawPath(path, paint);
2357##
2358
2359#SeeAlso Contour moveTo rLineTo addRect
2360
2361##
2362
2363# ------------------------------------------------------------------------------
2364
2365#Method void rLineTo(SkScalar dx, SkScalar dy)
2366
2367Adds Line from Last_Point to Vector (dx, dy). If Path is empty, or last Verb is
2368kClose_Verb, Last_Point is set to (0, 0) before adding Line.
2369
2370Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2371then appends kLine_Verb to Verb_Array and Line end to Point_Array.
2372Line end is Last_Point plus Vector (dx, dy).
Cary Clarkce101242017-09-01 15:51:02 -04002373Function name stands for "relative line to".
Cary Clark73fa9722017-08-29 17:36:51 -04002374
2375#Param dx offset from Last_Point x to Line end x ##
2376#Param dy offset from Last_Point y to Line end y ##
2377
2378#Example
2379#Height 128
2380void draw(SkCanvas* canvas) {
2381 SkPaint paint;
2382 paint.setAntiAlias(true);
2383 paint.setStyle(SkPaint::kStroke_Style);
2384 SkPath path;
2385 path.moveTo(10, 98);
2386 SkScalar x = 0, y = 0;
2387 for (int i = 10; i < 100; i += 5) {
2388 x += i * ((i & 2) - 1);
2389 y += i * (((i + 1) & 2) - 1);
2390 path.rLineTo(x, y);
2391
2392 }
2393 canvas->drawPath(path, paint);
2394}
2395##
2396
2397#SeeAlso Contour moveTo lineTo addRect
2398
2399##
2400
2401# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04002402#Topic Quad
Cary Clarkce101242017-09-01 15:51:02 -04002403#Alias Quad
Cary Clark73fa9722017-08-29 17:36:51 -04002404#Alias Quads
Cary Clarkce101242017-09-01 15:51:02 -04002405#Alias Quadratic_Bezier
2406#Alias Quadratic_Beziers
Cary Clark8032b982017-07-28 11:04:54 -04002407
2408Quad describes a quadratic Bezier, a second-order curve identical to a section
2409of a parabola. Quad begins at a start Point, curves towards a control Point,
2410and then curves to an end Point.
2411
2412#Example
2413#Height 110
Cary Clark73fa9722017-08-29 17:36:51 -04002414void draw(SkCanvas* canvas) {
2415 SkPaint paint;
2416 paint.setAntiAlias(true);
2417 paint.setStyle(SkPaint::kStroke_Style);
2418 SkPoint quadPts[] = {{20, 90}, {120, 10}, {220, 90}};
2419 canvas->drawLine(quadPts[0], quadPts[1], paint);
2420 canvas->drawLine(quadPts[1], quadPts[2], paint);
2421 SkPath path;
2422 path.moveTo(quadPts[0]);
2423 path.quadTo(quadPts[1], quadPts[2]);
2424 paint.setStrokeWidth(3);
2425 canvas->drawPath(path, paint);
2426}
Cary Clark8032b982017-07-28 11:04:54 -04002427##
2428
2429Quad is a special case of Conic where Conic_Weight is set to one.
2430
2431Quad is always contained by the triangle connecting its three Points. Quad
2432begins tangent to the line between start Point and control Point, and ends
2433tangent to the line between control Point and end Point.
2434
2435#Example
2436#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002437void draw(SkCanvas* canvas) {
2438 SkPaint paint;
2439 paint.setAntiAlias(true);
2440 paint.setStyle(SkPaint::kStroke_Style);
2441 SkPoint quadPts[] = {{20, 150}, {120, 10}, {220, 150}};
2442 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2443 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2444 paint.setColor(0x7fffffff & colors[i]);
2445 paint.setStrokeWidth(1);
2446 canvas->drawLine(quadPts[0], quadPts[1], paint);
2447 canvas->drawLine(quadPts[1], quadPts[2], paint);
2448 SkPath path;
2449 path.moveTo(quadPts[0]);
2450 path.quadTo(quadPts[1], quadPts[2]);
2451 paint.setStrokeWidth(3);
2452 paint.setColor(colors[i]);
2453 canvas->drawPath(path, paint);
2454 quadPts[1].fY += 30;
2455 }
Cary Clark8032b982017-07-28 11:04:54 -04002456}
2457##
Cary Clark73fa9722017-08-29 17:36:51 -04002458
2459#Method void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
2460
2461 Adds Quad from Last_Point towards (x1, y1), to (x2, y2).
2462 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2463 before adding Quad.
2464
2465 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2466 then appends kQuad_Verb to Verb_Array; and (x1, y1), (x2, y2)
2467 to Point_Array.
2468
2469 #Param x1 control Point of Quad in x ##
2470 #Param y1 control Point of Quad in y ##
2471 #Param x2 end Point of Quad in x ##
2472 #Param y2 end Point of Quad in y ##
2473
2474 #Example
2475 void draw(SkCanvas* canvas) {
2476 SkPaint paint;
2477 paint.setAntiAlias(true);
2478 paint.setStyle(SkPaint::kStroke_Style);
2479 SkPath path;
2480 path.moveTo(0, -10);
2481 for (int i = 0; i < 128; i += 16) {
2482 path.quadTo( 10 + i, -10 - i, 10 + i, 0);
2483 path.quadTo( 14 + i, 14 + i, 0, 14 + i);
2484 path.quadTo(-18 - i, 18 + i, -18 - i, 0);
2485 path.quadTo(-22 - i, -22 - i, 0, -22 - i);
2486 }
2487 path.offset(128, 128);
Cary Clark8032b982017-07-28 11:04:54 -04002488 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04002489 }
2490 ##
2491
2492 #SeeAlso Contour moveTo conicTo rQuadTo
2493
2494##
2495
2496#Method void quadTo(const SkPoint& p1, const SkPoint& p2)
2497
2498 Adds Quad from Last_Point towards Point p1, to Point p2.
2499 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2500 before adding Quad.
2501
2502 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2503 then appends kQuad_Verb to Verb_Array; and Points p1, p2
2504 to Point_Array.
2505
2506 #Param p1 control Point of added Quad ##
2507 #Param p2 end Point of added Quad ##
2508
2509 #Example
2510 void draw(SkCanvas* canvas) {
2511 SkPaint paint;
2512 paint.setStyle(SkPaint::kStroke_Style);
2513 paint.setAntiAlias(true);
2514 SkPath path;
2515 SkPoint pts[] = {{128, 10}, {10, 214}, {236, 214}};
2516 path.moveTo(pts[1]);
2517 for (int i = 0; i < 3; ++i) {
2518 path.quadTo(pts[i % 3], pts[(i + 2) % 3]);
2519 }
2520 canvas->drawPath(path, paint);
2521 }
2522 ##
2523
2524 #SeeAlso Contour moveTo conicTo rQuadTo
2525
2526##
2527
2528#Method void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
2529
2530 Adds Quad from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2).
2531 If Path is empty, or last Verb
2532 is kClose_Verb, Last_Point is set to (0, 0) before adding Quad.
2533
2534 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2535 if needed; then appends kQuad_Verb to Verb_Array; and appends Quad
2536 control and Quad end to Point_Array.
2537 Quad control is Last_Point plus Vector (dx1, dy1).
2538 Quad end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002539 Function name stands for "relative quad to".
Cary Clark73fa9722017-08-29 17:36:51 -04002540
2541 #Param dx1 offset from Last_Point x to Quad control x ##
2542 #Param dy1 offset from Last_Point x to Quad control y ##
2543 #Param dx2 offset from Last_Point x to Quad end x ##
2544 #Param dy2 offset from Last_Point x to Quad end y ##
2545
2546 #Example
2547 void draw(SkCanvas* canvas) {
2548 SkPaint paint;
2549 paint.setAntiAlias(true);
2550 SkPath path;
2551 path.moveTo(128, 20);
2552 path.rQuadTo(-6, 10, -7, 10);
2553 for (int i = 1; i < 32; i += 4) {
2554 path.rQuadTo(10 + i, 10 + i, 10 + i * 4, 10);
2555 path.rQuadTo(-10 - i, 10 + i, -10 - (i + 2) * 4, 10);
2556 }
2557 path.quadTo(92, 220, 128, 215);
2558 canvas->drawPath(path, paint);
2559 }
2560 ##
2561
2562 #SeeAlso Contour moveTo conicTo quadTo
2563
2564##
2565
Cary Clark8032b982017-07-28 11:04:54 -04002566#Topic Quad ##
Cary Clark73fa9722017-08-29 17:36:51 -04002567
2568# ------------------------------------------------------------------------------
2569
Cary Clark8032b982017-07-28 11:04:54 -04002570#Topic Conic
2571#Alias Conics
2572
2573Conic describes a conical section: a piece of an ellipse, or a piece of a
2574parabola, or a piece of a hyperbola. Conic begins at a start Point,
2575curves towards a control Point, and then curves to an end Point. The influence
2576of the control Point is determined by Conic_Weight.
2577
Cary Clark73fa9722017-08-29 17:36:51 -04002578Each Conic in Path adds two Points and one Conic_Weight. Conic_Weights in Path
2579may be inspected with Iter, or with RawIter.
Cary Clark8032b982017-07-28 11:04:54 -04002580
2581#Subtopic Weight
Cary Clarke0403842017-09-01 19:21:29 +00002582#Alias Conic_Weights
Cary Clarkce101242017-09-01 15:51:02 -04002583#Alias Weights
Cary Clark8032b982017-07-28 11:04:54 -04002584
2585Weight determines both the strength of the control Point and the type of Conic.
2586If Weight is exactly one, then Conic is identical to Quad; it is always a
2587parabolic segment.
2588
2589
2590
2591#Example
2592#Description
Cary Clark73fa9722017-08-29 17:36:51 -04002593When Conic_Weight is one, Quad is added to path; the two are identical.
Cary Clark8032b982017-07-28 11:04:54 -04002594##
Cary Clark73fa9722017-08-29 17:36:51 -04002595void draw(SkCanvas* canvas) {
2596 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2597 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2598 SkPath path;
2599 path.conicTo(20, 30, 50, 60, 1);
2600 SkPath::Iter iter(path, false);
2601 SkPath::Verb verb;
2602 do {
2603 SkPoint points[4];
2604 verb = iter.next(points);
2605 SkDebugf("%s ", verbNames[(int) verb]);
2606 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2607 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2608 }
2609 if (SkPath::kConic_Verb == verb) {
2610 SkDebugf("weight = %g", iter.conicWeight());
2611 }
2612 SkDebugf("\n");
2613 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002614}
2615#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002616move {0, 0},
2617quad {0, 0}, {20, 30}, {50, 60},
Cary Clark8032b982017-07-28 11:04:54 -04002618done
2619##
2620##
2621
2622If weight is less than one, Conic is an elliptical segment.
2623
2624#Example
2625#Description
2626A 90 degree circular arc has the weight
2627#Formula
26281 / sqrt(2)
2629##
Cary Clark6fc50412017-09-21 12:31:06 -04002630.
Cary Clark8032b982017-07-28 11:04:54 -04002631##
Cary Clark73fa9722017-08-29 17:36:51 -04002632void draw(SkCanvas* canvas) {
2633 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2634 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2635 SkPath path;
2636 path.arcTo(20, 0, 20, 20, 20);
2637 SkPath::Iter iter(path, false);
2638 SkPath::Verb verb;
2639 do {
2640 SkPoint points[4];
2641 verb = iter.next(points);
2642 SkDebugf("%s ", verbNames[(int) verb]);
2643 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2644 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2645 }
2646 if (SkPath::kConic_Verb == verb) {
2647 SkDebugf("weight = %g", iter.conicWeight());
2648 }
2649 SkDebugf("\n");
2650 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002651}
2652#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002653move {0, 0},
2654conic {0, 0}, {20, 0}, {20, 20}, weight = 0.707107
Cary Clark8032b982017-07-28 11:04:54 -04002655done
2656##
2657##
2658
Cary Clarkce101242017-09-01 15:51:02 -04002659If weight is greater than one, Conic is a hyperbolic segment. As weight gets large,
Cary Clark8032b982017-07-28 11:04:54 -04002660a hyperbolic segment can be approximated by straight lines connecting the
2661control Point with the end Points.
2662
2663#Example
Cary Clark73fa9722017-08-29 17:36:51 -04002664void draw(SkCanvas* canvas) {
2665 const char* verbNames[] = { "move", "line", "quad", "conic", "cubic", "close", "done" };
2666 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
2667 SkPath path;
2668 path.conicTo(20, 0, 20, 20, SK_ScalarInfinity);
2669 SkPath::Iter iter(path, false);
2670 SkPath::Verb verb;
2671 do {
2672 SkPoint points[4];
2673 verb = iter.next(points);
2674 SkDebugf("%s ", verbNames[(int) verb]);
2675 for (int i = 0; i < pointCount[(int) verb]; ++i) {
2676 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
2677 }
2678 if (SkPath::kConic_Verb == verb) {
2679 SkDebugf("weight = %g", iter.conicWeight());
2680 }
2681 SkDebugf("\n");
2682 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04002683}
2684#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04002685move {0, 0},
2686line {0, 0}, {20, 0},
2687line {20, 0}, {20, 20},
Cary Clark8032b982017-07-28 11:04:54 -04002688done
2689##
2690##
2691
2692#Subtopic Weight ##
Cary Clark73fa9722017-08-29 17:36:51 -04002693
2694#Method void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2695 SkScalar w)
2696
2697 Adds Conic from Last_Point towards (x1, y1), to (x2, y2), weighted by w.
2698 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2699 before adding Conic.
2700
2701 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2702
2703 If w is finite and not one, appends kConic_Verb to Verb_Array;
2704 and (x1, y1), (x2, y2) to Point_Array; and w to Conic_Weights.
2705
2706 If w is one, appends kQuad_Verb to Verb_Array, and
2707 (x1, y1), (x2, y2) to Point_Array.
2708
2709 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2710 (x1, y1), (x2, y2) to Point_Array.
2711
2712 #Param x1 control Point of Conic in x ##
2713 #Param y1 control Point of Conic in y ##
2714 #Param x2 end Point of Conic in x ##
2715 #Param y2 end Point of Conic in y ##
2716 #Param w weight of added Conic ##
2717
2718 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002719 #Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002720 #Description
2721 As weight increases, curve is pulled towards control point.
2722 The bottom two curves are elliptical; the next is parabolic; the
2723 top curve is hyperbolic.
2724 ##
2725void draw(SkCanvas* canvas) {
2726 SkPaint paint;
2727 paint.setAntiAlias(true);
2728 paint.setStyle(SkPaint::kStroke_Style);
2729 SkPoint conicPts[] = {{20, 150}, {120, 10}, {220, 150}};
2730 canvas->drawLine(conicPts[0], conicPts[1], paint);
2731 canvas->drawLine(conicPts[1], conicPts[2], paint);
2732 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2733 paint.setStrokeWidth(3);
2734 SkScalar weight = 0.5f;
2735 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2736 SkPath path;
2737 path.moveTo(conicPts[0]);
2738 path.conicTo(conicPts[1], conicPts[2], weight);
2739 paint.setColor(colors[i]);
2740 canvas->drawPath(path, paint);
2741 weight += 0.25f;
2742 }
2743}
2744 ##
2745
2746 #SeeAlso rConicTo arcTo addArc quadTo
2747
2748##
2749
2750#Method void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w)
2751
2752 Adds Conic from Last_Point towards Point p1, to Point p2, weighted by w.
2753 If Path is empty, or last Verb is kClose_Verb, Last_Point is set to (0, 0)
2754 before adding Conic.
2755
2756 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed.
2757
2758 If w is finite and not one, appends kConic_Verb to Verb_Array;
2759 and Points p1, p2 to Point_Array; and w to Conic_Weights.
2760
2761 If w is one, appends kQuad_Verb to Verb_Array, and Points p1, p2
2762 to Point_Array.
2763
2764 If w is not finite, appends kLine_Verb twice to Verb_Array, and
2765 Points p1, p2 to Point_Array.
2766
2767 #Param p1 control Point of added Conic ##
2768 #Param p2 end Point of added Conic ##
2769 #Param w weight of added Conic ##
2770
2771 #Example
Cary Clark8032b982017-07-28 11:04:54 -04002772 #Height 128
Cary Clark73fa9722017-08-29 17:36:51 -04002773 #Description
2774 Conics and arcs use identical representations. As the arc sweep increases
Cary Clarkce101242017-09-01 15:51:02 -04002775 the Conic_Weight also increases, but remains smaller than one.
Cary Clark73fa9722017-08-29 17:36:51 -04002776 ##
2777void draw(SkCanvas* canvas) {
2778 SkPaint paint;
2779 paint.setAntiAlias(true);
2780 paint.setStyle(SkPaint::kStroke_Style);
2781 SkRect oval = {0, 20, 120, 140};
2782 SkPath path;
2783 for (int i = 0; i < 4; ++i) {
2784 path.moveTo(oval.centerX(), oval.fTop);
2785 path.arcTo(oval, -90, 90 - 20 * i, false);
2786 oval.inset(15, 15);
2787 }
2788 path.offset(100, 0);
2789 SkScalar conicWeights[] = { 0.707107f, 0.819152f, 0.906308f, 0.965926f };
2790 SkPoint conicPts[][3] = { { {40, 20}, {100, 20}, {100, 80} },
2791 { {40, 35}, {71.509f, 35}, {82.286f, 64.6091f} },
2792 { {40, 50}, {53.9892f, 50}, {62.981f, 60.7164f} },
2793 { {40, 65}, {44.0192f, 65}, {47.5f, 67.0096f} } };
2794 for (int i = 0; i < 4; ++i) {
2795 path.moveTo(conicPts[i][0]);
2796 path.conicTo(conicPts[i][1], conicPts[i][2], conicWeights[i]);
2797 }
2798 canvas->drawPath(path, paint);
2799}
2800 ##
2801
2802 #SeeAlso rConicTo arcTo addArc quadTo
2803
2804##
2805
2806#Method void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
2807 SkScalar w)
2808
2809 Adds Conic from Last_Point towards Vector (dx1, dy1), to Vector (dx2, dy2),
2810 weighted by w. If Path is empty, or last Verb
2811 is kClose_Verb, Last_Point is set to (0, 0) before adding Conic.
2812
2813 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2814 if needed.
2815
2816 If w is finite and not one, next appends kConic_Verb to Verb_Array,
2817 and w is recorded as Conic_Weight; otherwise, if w is one, appends
2818 kQuad_Verb to Verb_Array; or if w is not finite, appends kLine_Verb
2819 twice to Verb_Array.
2820
2821 In all cases appends Points control and end to Point_Array.
2822 control is Last_Point plus Vector (dx1, dy1).
2823 end is Last_Point plus Vector (dx2, dy2).
2824
Cary Clarkce101242017-09-01 15:51:02 -04002825 Function name stands for "relative conic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002826
2827 #Param dx1 offset from Last_Point x to Conic control x ##
2828 #Param dy1 offset from Last_Point x to Conic control y ##
2829 #Param dx2 offset from Last_Point x to Conic end x ##
2830 #Param dy2 offset from Last_Point x to Conic end y ##
2831 #Param w weight of added Conic ##
2832
2833 #Example
2834 #Height 140
2835 void draw(SkCanvas* canvas) {
2836 SkPaint paint;
2837 paint.setAntiAlias(true);
2838 paint.setStyle(SkPaint::kStroke_Style);
2839 SkPath path;
2840 path.moveTo(20, 80);
2841 path.rConicTo( 60, 0, 60, 60, 0.707107f);
2842 path.rConicTo( 0, -60, 60, -60, 0.707107f);
2843 path.rConicTo(-60, 0, -60, -60, 0.707107f);
2844 path.rConicTo( 0, 60, -60, 60, 0.707107f);
2845 canvas->drawPath(path, paint);
2846 }
2847 ##
2848
2849 #SeeAlso conicTo arcTo addArc quadTo
2850
2851##
2852
2853#Topic Conic ##
2854
2855# ------------------------------------------------------------------------------
Cary Clark8032b982017-07-28 11:04:54 -04002856#Topic Cubic
Cary Clarkce101242017-09-01 15:51:02 -04002857#Alias Cubic
Cary Clark8032b982017-07-28 11:04:54 -04002858#Alias Cubics
Cary Clarkce101242017-09-01 15:51:02 -04002859#Alias Cubic_Bezier
2860#Alias Cubic_Beziers
Cary Clark8032b982017-07-28 11:04:54 -04002861
Cary Clarkce101242017-09-01 15:51:02 -04002862Cubic describes a Bezier curve segment described by a third-order polynomial.
Cary Clark8032b982017-07-28 11:04:54 -04002863Cubic begins at a start Point, curving towards the first control Point;
2864and curves from the end Point towards the second control Point.
2865
2866#Example
2867#Height 160
Cary Clark73fa9722017-08-29 17:36:51 -04002868void draw(SkCanvas* canvas) {
2869 SkPaint paint;
2870 paint.setAntiAlias(true);
2871 paint.setStyle(SkPaint::kStroke_Style);
2872 SkPoint cubicPts[] = {{20, 150}, {90, 10}, {160, 150}, {230, 10}};
2873 SkColor colors[] = { 0xff88ff00, 0xff0088bb, 0xff6600cc, 0xffbb3377 };
2874 for (unsigned i = 0; i < SK_ARRAY_COUNT(colors); ++i) {
2875 paint.setColor(0x7fffffff & colors[i]);
2876 paint.setStrokeWidth(1);
2877 for (unsigned j = 0; j < 3; ++j) {
2878 canvas->drawLine(cubicPts[j], cubicPts[j + 1], paint);
2879 }
2880 SkPath path;
2881 path.moveTo(cubicPts[0]);
2882 path.cubicTo(cubicPts[1], cubicPts[2], cubicPts[3]);
2883 paint.setStrokeWidth(3);
2884 paint.setColor(colors[i]);
2885 canvas->drawPath(path, paint);
2886 cubicPts[1].fY += 30;
2887 cubicPts[2].fX += 30;
2888 }
Cary Clark8032b982017-07-28 11:04:54 -04002889}
2890##
Cary Clark73fa9722017-08-29 17:36:51 -04002891
2892#Method void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2893 SkScalar x3, SkScalar y3)
2894
2895Adds Cubic from Last_Point towards (x1, y1), then towards (x2, y2), ending at
2896(x3, y3). If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2897(0, 0) before adding Cubic.
2898
2899Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2900then appends kCubic_Verb to Verb_Array; and (x1, y1), (x2, y2), (x3, y3)
2901to Point_Array.
2902
2903#Param x1 first control Point of Cubic in x ##
2904#Param y1 first control Point of Cubic in y ##
2905#Param x2 second control Point of Cubic in x ##
2906#Param y2 second control Point of Cubic in y ##
2907#Param x3 end Point of Cubic in x ##
2908#Param y3 end Point of Cubic in y ##
2909
2910#Example
2911void draw(SkCanvas* canvas) {
2912 SkPaint paint;
2913 paint.setAntiAlias(true);
2914 paint.setStyle(SkPaint::kStroke_Style);
2915 SkPath path;
2916 path.moveTo(0, -10);
2917 for (int i = 0; i < 128; i += 16) {
2918 SkScalar c = i * 0.5f;
2919 path.cubicTo( 10 + c, -10 - i, 10 + i, -10 - c, 10 + i, 0);
2920 path.cubicTo( 14 + i, 14 + c, 14 + c, 14 + i, 0, 14 + i);
2921 path.cubicTo(-18 - c, 18 + i, -18 - i, 18 + c, -18 - i, 0);
2922 path.cubicTo(-22 - i, -22 - c, -22 - c, -22 - i, 0, -22 - i);
2923 }
2924 path.offset(128, 128);
2925 canvas->drawPath(path, paint);
2926}
2927##
2928
2929#SeeAlso Contour moveTo rCubicTo quadTo
2930
2931##
2932
2933# ------------------------------------------------------------------------------
2934
2935#Method void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
2936
2937Adds Cubic from Last_Point towards Point p1, then towards Point p2, ending at
2938Point p3. If Path is empty, or last Verb is kClose_Verb, Last_Point is set to
2939(0, 0) before adding Cubic.
2940
2941Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array, if needed;
2942then appends kCubic_Verb to Verb_Array; and Points p1, p2, p3
2943to Point_Array.
2944
2945#Param p1 first control Point of Cubic ##
2946#Param p2 second control Point of Cubic ##
2947#Param p3 end Point of Cubic ##
2948
2949#Example
2950#Height 84
2951 SkPaint paint;
2952 paint.setAntiAlias(true);
2953 paint.setStyle(SkPaint::kStroke_Style);
2954 SkPoint pts[] = { {20, 20}, {300, 80}, {-140, 90}, {220, 10} };
2955 SkPath path;
2956 path.moveTo(pts[0]);
2957 path.cubicTo(pts[1], pts[2], pts[3]);
2958 canvas->drawPath(path, paint);
2959##
2960
2961#SeeAlso Contour moveTo rCubicTo quadTo
2962
2963##
2964
2965# ------------------------------------------------------------------------------
2966
2967#Method void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
2968 SkScalar x3, SkScalar y3)
2969
2970 Adds Cubic from Last_Point towards Vector (dx1, dy1), then towards
2971 Vector (dx2, dy2), to Vector (dx3, dy3).
2972 If Path is empty, or last Verb
2973 is kClose_Verb, Last_Point is set to (0, 0) before adding Cubic.
2974
2975 Appends kMove_Verb to Verb_Array and (0, 0) to Point_Array,
2976 if needed; then appends kCubic_Verb to Verb_Array; and appends Cubic
2977 control and Cubic end to Point_Array.
2978 Cubic control is Last_Point plus Vector (dx1, dy1).
2979 Cubic end is Last_Point plus Vector (dx2, dy2).
Cary Clarkce101242017-09-01 15:51:02 -04002980 Function name stands for "relative cubic to".
Cary Clark73fa9722017-08-29 17:36:51 -04002981
2982 #Param x1 offset from Last_Point x to first Cubic control x ##
2983 #Param y1 offset from Last_Point x to first Cubic control y ##
2984 #Param x2 offset from Last_Point x to second Cubic control x ##
2985 #Param y2 offset from Last_Point x to second Cubic control y ##
2986 #Param x3 offset from Last_Point x to Cubic end x ##
2987 #Param y3 offset from Last_Point x to Cubic end y ##
2988
2989#Example
2990 void draw(SkCanvas* canvas) {
2991 SkPaint paint;
2992 paint.setAntiAlias(true);
2993 paint.setStyle(SkPaint::kStroke_Style);
2994 SkPath path;
2995 path.moveTo(24, 108);
2996 for (int i = 0; i < 16; i++) {
2997 SkScalar sx, sy;
2998 sx = SkScalarSinCos(i * SK_ScalarPI / 8, &sy);
2999 path.rCubicTo(40 * sx, 4 * sy, 4 * sx, 40 * sy, 40 * sx, 40 * sy);
3000 }
3001 canvas->drawPath(path, paint);
3002 }
3003##
3004
3005#SeeAlso Contour moveTo cubicTo quadTo
3006
3007##
3008
3009#Topic Cubic ##
3010
3011# ------------------------------------------------------------------------------
3012
3013#Topic Arc
3014
3015Arc can be constructed in a number of ways. Arc may be described by part of Oval and angles,
3016by start point and end point, and by radius and tangent lines. Each construction has advantages,
3017and some constructions correspond to Arc drawing in graphics standards.
3018
3019All Arc draws are implemented by one or more Conic draws. When Conic_Weight is less than one,
3020Conic describes an Arc of some Oval or Circle.
3021
3022arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
3023describes Arc as a piece of Oval, beginning at start angle, sweeping clockwise or counterclockwise,
3024which may continue Contour or start a new one. This construction is similar to PostScript and
3025HTML_Canvas arcs. Variation addArc always starts new Contour. Canvas::drawArc draws without
3026requiring Path.
3027
3028arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
3029describes Arc as tangent to the line (x0, y0), (x1, y1) and tangent to the line (x1, y1), (x2, y2)
3030where (x0, y0) is the last Point added to Path. This construction is similar to PostScript and
3031HTML_Canvas arcs.
3032
3033arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
3034 SkScalar x, SkScalar y)
3035describes Arc as part of Oval with radii (rx, ry), beginning at
3036last Point added to Path and ending at (x, y). More than one Arc satisfies this criteria,
3037so additional values choose a single solution. This construction is similar to SVG arcs.
3038
3039conicTo describes Arc of less than 180 degrees as a pair of tangent lines and Conic_Weight.
3040conicTo can represent any Arc with a sweep less than 180 degrees at any rotation. All arcTo
3041constructions are converted to Conic data when added to Path.
3042
3043#ToDo allow example to hide source and not be exposed as fiddle since markdown / html can't
3044 do the kind of table shown in the illustration.
3045 example is spaced correctly on fiddle but spacing is too wide on pc
3046##
3047
3048#Example
3049#Height 300
3050#Width 600
3051#Description
3052#List
3053# <sup>1</sup> arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo) ##
3054# <sup>2</sup> parameter sets force MoveTo ##
3055# <sup>3</sup> start angle must be multiple of 90 degrees. ##
3056# <sup>4</sup> arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) ##
3057# <sup>5</sup> arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3058 Direction sweep, SkScalar x, SkScalar y) ##
3059#List ##
3060#Description ##
3061#Function
3062struct data {
3063 const char* name;
3064 char super;
3065 int yn[10];
3066};
3067
3068const data dataSet[] = {
3069{ "arcTo sweep", '1', {1, 3, 1, 0, 0, 0, 0, 1, 0, 0 }},
3070{ "drawArc", 0, {1, -1, 1, 1, 1, 1, 1, 0, 0, 0 }},
3071{ "addArc", 0, {1, 1, 1, 4, 0, 1, 1, 1, 0, 0 }},
3072{ "arcTo tangents", '4', {0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }},
3073{ "arcTo radii", '5', {1, 0, 1, 0, 0, 0, 0, 1, 1, 0 }},
3074{ "conicTo", 0, {1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }}
3075};
3076
3077#define __degree_symbol__ "\xC2" "\xB0"
3078
3079const char* headers[] = {
3080 "Oval part",
3081 "force moveTo",
3082 "can draw 180" __degree_symbol__,
3083 "can draw 360" __degree_symbol__,
3084 "can draw greater than 360" __degree_symbol__,
3085 "ignored if radius is zero",
3086 "ignored if sweep is zero",
3087 "requires Path",
3088 "describes rotation",
3089 "describes perspective",
3090};
3091
3092const char* yna[] = {
3093 "n/a",
3094 "no",
3095 "yes"
3096};
3097
3098##
3099void draw(SkCanvas* canvas) {
3100 SkPaint lp;
3101 lp.setAntiAlias(true);
3102 SkPaint tp(lp);
3103 SkPaint sp(tp);
3104 SkPaint bp(tp);
3105 bp.setFakeBoldText(true);
3106 sp.setTextSize(10);
3107 lp.setColor(SK_ColorGRAY);
3108 canvas->translate(0, 32);
3109 const int tl = 115;
3110 for (unsigned col = 0; col <= SK_ARRAY_COUNT(headers); ++col) {
3111 canvas->drawLine(tl + col * 35, 100, tl + col * 35, 250, lp);
3112 if (0 == col) {
3113 continue;
3114 }
3115 canvas->drawLine(tl + col * 35, 100, tl + 100 + col * 35, 0, lp);
3116 SkPath path;
3117 path.moveTo(tl - 3 + col * 35, 103);
3118 path.lineTo(tl + 124 + col * 35, -24);
3119 canvas->drawTextOnPathHV(headers[col -1], strlen(headers[col -1]), path, 0, -9, bp);
3120 }
3121 for (unsigned row = 0; row <= SK_ARRAY_COUNT(dataSet); ++row) {
3122 if (0 == row) {
3123 canvas->drawLine(tl, 100, tl + 350, 100, lp);
3124 } else {
3125 canvas->drawLine(5, 100 + row * 25, tl + 350, 100 + row * 25, lp);
3126 }
3127 if (row == SK_ARRAY_COUNT(dataSet)) {
3128 break;
3129 }
3130 canvas->drawString(dataSet[row].name, 5, 117 + row * 25, bp);
3131 if (dataSet[row].super) {
3132 SkScalar width = bp.measureText(dataSet[row].name, strlen(dataSet[row].name));
3133 canvas->drawText(&dataSet[row].super, 1, 8 + width, 112 + row * 25, sp);
3134 }
3135 for (unsigned col = 0; col < SK_ARRAY_COUNT(headers); ++col) {
3136 int val = dataSet[row].yn[col];
3137 canvas->drawString(yna[SkTMin(2, val + 1)], tl + 5 + col * 35, 117 + row * 25, tp);
3138 if (val > 1) {
3139 char supe = '0' + val - 1;
3140 canvas->drawText(&supe, 1, tl + 25 + col * 35, 112 + row * 25, sp);
3141 }
3142 }
3143 }
3144}
3145#Example ##
3146
3147#Example
3148#Height 128
3149#Description
3150#ToDo make this a list or table ##
31511 describes an arc from an oval, a starting angle, and a sweep angle.
31522 is similar to 1, but does not require building a path to draw.
31533 is similar to 1, but always begins new Contour.
31544 describes an arc from a pair of tangent lines and a radius.
31555 describes an arc from Oval center, arc start Point and arc end Point.
31566 describes an arc from a pair of tangent lines and a Conic_Weight.
3157##
3158void draw(SkCanvas* canvas) {
3159 SkRect oval = {8, 8, 56, 56};
3160 SkPaint ovalPaint;
3161 ovalPaint.setAntiAlias(true);
3162 SkPaint textPaint(ovalPaint);
3163 ovalPaint.setStyle(SkPaint::kStroke_Style);
3164 SkPaint arcPaint(ovalPaint);
3165 arcPaint.setStrokeWidth(5);
3166 arcPaint.setColor(SK_ColorBLUE);
3167 canvas->translate(-64, 0);
3168 for (char arcStyle = '1'; arcStyle <= '6'; ++arcStyle) {
3169 '4' == arcStyle ? canvas->translate(-96, 55) : canvas->translate(64, 0);
3170 canvas->drawText(&arcStyle, 1, 30, 36, textPaint);
3171 canvas->drawOval(oval, ovalPaint);
3172 SkPath path;
3173 path.moveTo({56, 32});
3174 switch (arcStyle) {
3175 case '1':
3176 path.arcTo(oval, 0, 90, false);
3177 break;
3178 case '2':
3179 canvas->drawArc(oval, 0, 90, false, arcPaint);
3180 continue;
3181 case '3':
3182 path.addArc(oval, 0, 90);
3183 break;
3184 case '4':
3185 path.arcTo({56, 56}, {32, 56}, 24);
3186 break;
3187 case '5':
3188 path.arcTo({24, 24}, 0, SkPath::kSmall_ArcSize, SkPath::kCW_Direction, {32, 56});
3189 break;
3190 case '6':
3191 path.conicTo({56, 56}, {32, 56}, SK_ScalarRoot2Over2);
3192 break;
3193 }
3194 canvas->drawPath(path, arcPaint);
3195 }
3196}
3197#Example ##
3198
3199
3200#Method void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
3201
3202Append Arc to Path. Arc added is part of ellipse
3203bounded by oval, from startAngle through sweepAngle. Both startAngle and
3204sweepAngle are measured in degrees, where zero degrees is aligned with the
3205positive x-axis, and positive sweeps extends Arc clockwise.
3206
3207arcTo adds Line connecting Path last Point to initial Arc Point if forceMoveTo
3208is false and Path is not empty. Otherwise, added Contour begins with first point
3209of Arc. Angles greater than -360 and less than 360 are treated modulo 360.
3210
3211#Param oval bounds of ellipse containing Arc ##
3212#Param startAngle starting angle of Arc in degrees ##
3213#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
3214#Param forceMoveTo true to start a new contour with Arc ##
3215
3216#Example
3217#Height 200
3218#Description
3219arcTo continues a previous contour when forceMoveTo is false and when Path
3220is not empty.
3221##
3222void draw(SkCanvas* canvas) {
3223 SkPaint paint;
3224 SkPath path;
3225 paint.setStyle(SkPaint::kStroke_Style);
3226 paint.setStrokeWidth(4);
3227 path.moveTo(0, 0);
3228 path.arcTo({20, 20, 120, 120}, -90, 90, false);
3229 canvas->drawPath(path, paint);
3230 path.rewind();
3231 path.arcTo({120, 20, 220, 120}, -90, 90, false);
3232 canvas->drawPath(path, paint);
3233 path.rewind();
3234 path.moveTo(0, 0);
3235 path.arcTo({20, 120, 120, 220}, -90, 90, true);
3236 canvas->drawPath(path, paint);
3237}
3238##
3239
3240#SeeAlso addArc SkCanvas::drawArc conicTo
3241
3242##
3243
3244# ------------------------------------------------------------------------------
3245
3246#Method void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius)
3247
3248Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3249weighted to describe part of Circle. Arc is contained by tangent from
3250last Path point (x0, y0) to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
3251is part of Circle sized to radius, positioned so it touches both tangent lines.
3252
3253#ToDo allow example to hide source and not be exposed as fiddle ##
3254
3255#Example
3256#Height 226
3257void draw(SkCanvas* canvas) {
3258 SkPaint tangentPaint;
3259 tangentPaint.setAntiAlias(true);
3260 SkPaint textPaint(tangentPaint);
3261 tangentPaint.setStyle(SkPaint::kStroke_Style);
3262 tangentPaint.setColor(SK_ColorGRAY);
3263 SkPaint arcPaint(tangentPaint);
3264 arcPaint.setStrokeWidth(5);
3265 arcPaint.setColor(SK_ColorBLUE);
3266 SkPath path;
3267 SkPoint pts[] = { {56, 20}, {200, 20}, {90, 190} };
3268 SkScalar radius = 50;
3269 path.moveTo(pts[0]);
3270 path.arcTo(pts[1], pts[2], radius);
3271 canvas->drawLine(pts[0], pts[1], tangentPaint);
3272 canvas->drawLine(pts[1], pts[2], tangentPaint);
3273 SkPoint lastPt;
3274 (void) path.getLastPt(&lastPt);
3275 SkVector radial = pts[2] - pts[1];
3276 radial.setLength(radius);
3277 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3278 canvas->drawCircle(center, radius, tangentPaint);
3279 canvas->drawLine(lastPt, center, tangentPaint);
3280 radial = pts[1] - pts[0];
3281 radial.setLength(radius);
3282 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3283 canvas->drawLine(center, arcStart, tangentPaint);
3284 canvas->drawPath(path, arcPaint);
3285 textPaint.setTextAlign(SkPaint::kRight_Align);
3286 canvas->drawString("(x0, y0)", pts[0].fX - 5, pts[0].fY, textPaint);
3287 textPaint.setTextAlign(SkPaint::kLeft_Align);
3288 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3289 textPaint.setTextAlign(SkPaint::kCenter_Align);
3290 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3291 textPaint.setTextAlign(SkPaint::kRight_Align);
3292 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3293 canvas->drawString("radius", center.fX - 3, center.fY - 16, textPaint);
3294}
3295##
3296
3297If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3298The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
3299
3300#Example
3301#Height 128
3302void draw(SkCanvas* canvas) {
3303 SkPaint tangentPaint;
3304 tangentPaint.setAntiAlias(true);
3305 SkPaint textPaint(tangentPaint);
3306 tangentPaint.setStyle(SkPaint::kStroke_Style);
3307 tangentPaint.setColor(SK_ColorGRAY);
3308 SkPaint arcPaint(tangentPaint);
3309 arcPaint.setStrokeWidth(5);
3310 arcPaint.setColor(SK_ColorBLUE);
3311 SkPath path;
3312 SkPoint pts[] = { {156, 20}, {200, 20}, {170, 50} };
3313 SkScalar radius = 50;
3314 path.moveTo(pts[0]);
3315 path.arcTo(pts[1], pts[2], radius);
3316 canvas->drawLine(pts[0], pts[1], tangentPaint);
3317 canvas->drawLine(pts[1], pts[2], tangentPaint);
3318 SkPoint lastPt;
3319 (void) path.getLastPt(&lastPt);
3320 SkVector radial = pts[2] - pts[1];
3321 radial.setLength(radius);
3322 SkPoint center = { lastPt.fX - radial.fY, lastPt.fY + radial.fX };
3323 canvas->drawLine(lastPt, center, tangentPaint);
3324 radial = pts[1] - pts[0];
3325 radial.setLength(radius);
3326 SkPoint arcStart = { center.fX + radial.fY, center.fY - radial.fX };
3327 canvas->drawLine(center, arcStart, tangentPaint);
3328 canvas->drawPath(path, arcPaint);
3329 textPaint.setTextAlign(SkPaint::kCenter_Align);
3330 canvas->drawString("(x0, y0)", pts[0].fX, pts[0].fY - 7, textPaint);
3331 textPaint.setTextAlign(SkPaint::kLeft_Align);
3332 canvas->drawString("(x1, y1)", pts[1].fX + 5, pts[1].fY, textPaint);
3333 textPaint.setTextAlign(SkPaint::kCenter_Align);
3334 canvas->drawString("(x2, y2)", pts[2].fX, pts[2].fY + 15, textPaint);
3335 textPaint.setTextAlign(SkPaint::kRight_Align);
3336 canvas->drawString("radius", center.fX + 15, center.fY + 25, textPaint);
3337 canvas->drawString("radius", center.fX - 5, center.fY - 20, textPaint);
3338}
3339##
3340
3341Arc sweep is always less than 180 degrees. If radius is zero, or if
3342tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
3343
3344arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003345arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003346
3347#Param x1 x common to pair of tangents ##
3348#Param y1 y common to pair of tangents ##
3349#Param x2 x end of second tangent ##
3350#Param y2 y end of second tangent ##
3351#Param radius distance from Arc to Circle center ##
3352
3353#Example
3354#Description
3355arcTo is represented by Line and circular Conic in Path.
3356##
3357void draw(SkCanvas* canvas) {
3358 SkPath path;
3359 path.moveTo({156, 20});
3360 path.arcTo(200, 20, 170, 50, 50);
3361 SkPath::Iter iter(path, false);
3362 SkPoint p[4];
3363 SkPath::Verb verb;
3364 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3365 switch (verb) {
3366 case SkPath::kMove_Verb:
3367 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3368 break;
3369 case SkPath::kLine_Verb:
3370 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3371 break;
3372 case SkPath::kConic_Verb:
3373 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3374 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3375 break;
3376 default:
3377 SkDebugf("unexpected verb\n");
3378 }
3379 }
3380}
3381#StdOut
3382move to (156,20)
3383line (156,20),(79.2893,20)
3384conic (79.2893,20),(200,20),(114.645,105.355) weight 0.382683
3385##
3386##
3387
3388#SeeAlso conicTo
3389
3390##
3391
3392# ------------------------------------------------------------------------------
3393
3394#Method void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius)
3395
3396Append Arc to Path, after appending Line if needed. Arc is implemented by Conic
3397weighted to describe part of Circle. Arc is contained by tangent from
3398last Path point to p1, and tangent from p1 to p2. Arc
3399is part of Circle sized to radius, positioned so it touches both tangent lines.
3400
3401If last Path Point does not start Arc, arcTo appends connecting Line to Path.
3402The length of Vector from p1 to p2 does not affect Arc.
3403
3404Arc sweep is always less than 180 degrees. If radius is zero, or if
3405tangents are nearly parallel, arcTo appends Line from last Path Point to p1.
3406
3407arcTo appends at most one Line and one Conic.
Cary Clarkce101242017-09-01 15:51:02 -04003408arcTo implements the functionality of PostScript_Arct and HTML_Canvas_ArcTo.
Cary Clark73fa9722017-08-29 17:36:51 -04003409
3410#Param p1 Point common to pair of tangents ##
3411#Param p2 end of second tangent ##
3412#Param radius distance from Arc to Circle center ##
3413
3414#Example
3415#Description
3416Because tangent lines are parallel, arcTo appends line from last Path Point to
3417p1, but does not append a circular Conic.
3418##
3419void draw(SkCanvas* canvas) {
3420 SkPath path;
3421 path.moveTo({156, 20});
3422 path.arcTo({200, 20}, {170, 20}, 50);
3423 SkPath::Iter iter(path, false);
3424 SkPoint p[4];
3425 SkPath::Verb verb;
3426 while (SkPath::kDone_Verb != (verb = iter.next(p))) {
3427 switch (verb) {
3428 case SkPath::kMove_Verb:
3429 SkDebugf("move to (%g,%g)\n", p[0].fX, p[0].fY);
3430 break;
3431 case SkPath::kLine_Verb:
3432 SkDebugf("line (%g,%g),(%g,%g)\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
3433 break;
3434 case SkPath::kConic_Verb:
3435 SkDebugf("conic (%g,%g),(%g,%g),(%g,%g) weight %g\n",
3436 p[0].fX, p[0].fY, p[1].fX, p[1].fY, p[2].fX, p[2].fY, iter.conicWeight());
3437 break;
3438 default:
3439 SkDebugf("unexpected verb\n");
3440 }
3441 }
3442}
3443#StdOut
3444move to (156,20)
3445line (156,20),(200,20)
3446##
3447##
3448
3449#SeeAlso conicTo
3450
3451##
3452
3453# ------------------------------------------------------------------------------
3454
3455#Enum ArcSize
3456
3457#Code
3458 enum ArcSize {
3459 kSmall_ArcSize,
3460 kLarge_ArcSize,
3461 };
3462##
3463
3464Four Oval parts with radii (rx, ry) start at last Path Point and ends at (x, y).
3465ArcSize and Direction select one of the four Oval parts.
3466
3467#Const kSmall_ArcSize 0
Cary Clark154beea2017-10-26 07:58:48 -04003468smaller of Arc pair
Cary Clark73fa9722017-08-29 17:36:51 -04003469##
3470#Const kLarge_ArcSize 1
Cary Clark154beea2017-10-26 07:58:48 -04003471larger of Arc pair
Cary Clark73fa9722017-08-29 17:36:51 -04003472##
3473
3474#Example
3475#Height 160
3476#Description
3477Arc begins at top of Oval pair and ends at bottom. Arc can take four routes to get there.
3478Two routes are large, and two routes are counterclockwise. The one route both large
3479and counterclockwise is blue.
3480##
3481void draw(SkCanvas* canvas) {
3482 SkPaint paint;
3483 paint.setAntiAlias(true);
3484 paint.setStyle(SkPaint::kStroke_Style);
3485 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3486 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3487 SkPath path;
3488 path.moveTo({120, 50});
3489 path.arcTo(70, 40, 30, arcSize, sweep, 156, 100);
3490 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3491 paint.setColor(SK_ColorBLUE);
3492 paint.setStrokeWidth(3);
3493 }
3494 canvas->drawPath(path, paint);
3495 }
3496 }
3497}
3498##
3499
3500#SeeAlso arcTo Direction
3501
3502##
3503
3504# ------------------------------------------------------------------------------
3505
3506#Method void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3507 Direction sweep, SkScalar x, SkScalar y)
3508
Cary Clark154beea2017-10-26 07:58:48 -04003509Append Arc to Path. Arc is implemented by one or more Conics weighted to
3510describe part of Oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
3511curves from last Path Point to (x, y), choosing one of four possible routes:
3512clockwise or counterclockwise, and smaller or larger.
Cary Clark73fa9722017-08-29 17:36:51 -04003513
Cary Clark154beea2017-10-26 07:58:48 -04003514Arc sweep is always less than 360 degrees. arcTo appends Line to (x, y) if
3515either radii are zero, or if last Path Point equals (x, y). arcTo scales radii
3516(rx, ry) to fit last Path Point and (x, y) if both are greater than zero but
3517too small.
Cary Clark73fa9722017-08-29 17:36:51 -04003518
3519arcTo appends up to four Conic curves.
Cary Clark154beea2017-10-26 07:58:48 -04003520arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value
3521is opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise,
3522while kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003523
3524#Param rx radius in x before x-axis rotation ##
3525#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003526#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003527#Param largeArc chooses smaller or larger Arc ##
3528#Param sweep chooses clockwise or counterclockwise Arc ##
3529#Param x end of Arc ##
3530#Param y end of Arc ##
3531
3532#Example
3533#Height 160
3534void draw(SkCanvas* canvas) {
3535 SkPaint paint;
3536 paint.setAntiAlias(true);
3537 paint.setStyle(SkPaint::kStroke_Style);
3538 for (auto sweep: { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
3539 for (auto arcSize : { SkPath::kSmall_ArcSize, SkPath::kLarge_ArcSize } ) {
3540 SkPath path;
3541 path.moveTo({120, 50});
3542 path.arcTo(70, 40, 30, arcSize, sweep, 120.1, 50);
3543 if (SkPath::kCCW_Direction == sweep && SkPath::kLarge_ArcSize == arcSize) {
3544 paint.setColor(SK_ColorBLUE);
3545 paint.setStrokeWidth(3);
3546 }
3547 canvas->drawPath(path, paint);
3548 }
3549 }
3550}
3551##
3552
3553#SeeAlso rArcTo ArcSize Direction
3554
3555##
3556
3557# ------------------------------------------------------------------------------
3558
3559#Method void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
3560 const SkPoint xy)
3561
3562Append Arc to Path. Arc is implemented by one or more Conic weighted to describe part of Oval
3563with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves from last Path Point to
3564(xy.fX, xy.fY), choosing one of four possible routes: clockwise or counterclockwise,
3565and smaller or larger.
3566
3567Arc sweep is always less than 360 degrees. arcTo appends Line to xy if either radii are zero,
3568or if last Path Point equals (x, y). arcTo scales radii r to fit last Path Point and
Cary Clarkce101242017-09-01 15:51:02 -04003569xy if both are greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003570
3571arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003572arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3573opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
3574kCW_Direction cast to int is zero.
Cary Clark73fa9722017-08-29 17:36:51 -04003575
3576#Param r radii in x and y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003577#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003578#Param largeArc chooses smaller or larger Arc ##
3579#Param sweep chooses clockwise or counterclockwise Arc ##
3580#Param xy end of Arc ##
3581
3582#Example
3583#Height 108
3584void draw(SkCanvas* canvas) {
3585 SkPaint paint;
3586 SkPath path;
3587 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3588 for (auto start : starts) {
3589 path.moveTo(start.fX, start.fY);
3590 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3591 }
3592 canvas->drawPath(path, paint);
3593}
3594##
3595
3596#SeeAlso rArcTo ArcSize Direction
3597
3598##
3599
3600# ------------------------------------------------------------------------------
3601
3602#Method void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
3603 Direction sweep, SkScalar dx, SkScalar dy)
3604
3605Append Arc to Path, relative to last Path Point. Arc is implemented by one or
Cary Clarkce101242017-09-01 15:51:02 -04003606more Conic, weighted to describe part of Oval with radii (rx, ry) rotated by
Cary Clark154beea2017-10-26 07:58:48 -04003607xAxisRotate degrees. Arc curves from last Path Point (x0, y0) to end Point:
3608
Cary Clark73fa9722017-08-29 17:36:51 -04003609#Formula
3610(x0 + dx, y0 + dy)
3611##
3612, choosing one of four possible routes: clockwise or
3613counterclockwise, and smaller or larger. If Path is empty, the start Arc Point
3614is (0, 0).
3615
Cary Clarkce101242017-09-01 15:51:02 -04003616Arc sweep is always less than 360 degrees. arcTo appends Line to end Point
3617if either radii are zero, or if last Path Point equals end Point.
3618arcTo scales radii (rx, ry) to fit last Path Point and end Point if both are
3619greater than zero but too small to describe an arc.
Cary Clark73fa9722017-08-29 17:36:51 -04003620
3621arcTo appends up to four Conic curves.
Cary Clarkce101242017-09-01 15:51:02 -04003622arcTo implements the functionality of SVG_Arc, although SVG "sweep-flag" value is
3623opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
Cary Clark73fa9722017-08-29 17:36:51 -04003624kCW_Direction cast to int is zero.
3625
3626#Param rx radius in x before x-axis rotation ##
3627#Param ry radius in y before x-axis rotation ##
Cary Clarkce101242017-09-01 15:51:02 -04003628#Param xAxisRotate x-axis rotation in degrees; positive values are clockwise ##
Cary Clark73fa9722017-08-29 17:36:51 -04003629#Param largeArc chooses smaller or larger Arc ##
3630#Param sweep chooses clockwise or counterclockwise Arc ##
3631#Param dx x offset end of Arc from last Path Point ##
3632#Param dy y offset end of Arc from last Path Point ##
3633
3634#Example
3635#Height 108
3636void draw(SkCanvas* canvas) {
3637 SkPaint paint;
3638 SkPath path;
3639 const SkPoint starts[] = {{20, 20}, {120, 20}, {70, 60}};
3640 for (auto start : starts) {
3641 path.moveTo(start.fX, start.fY);
3642 path.rArcTo(20, 20, 0, SkPath::kSmall_ArcSize, SkPath::kCCW_Direction, 60, 0);
3643 }
3644 canvas->drawPath(path, paint);
3645}
3646##
3647
3648#SeeAlso arcTo ArcSize Direction
3649
3650##
3651
3652#Topic Arc ##
3653
3654# ------------------------------------------------------------------------------
3655
3656#Method void close()
3657
3658Append kClose_Verb to Path. A closed Contour connects the first and last Point
Cary Clarkce101242017-09-01 15:51:02 -04003659with Line, forming a continuous loop. Open and closed Contour draw the same
Cary Clark73fa9722017-08-29 17:36:51 -04003660with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open Contour draws
3661Paint_Stroke_Cap at Contour start and end; closed Contour draws
3662Paint_Stroke_Join at Contour start and end.
3663
3664close() has no effect if Path is empty or last Path Verb is kClose_Verb.
3665
3666#Example
3667void draw(SkCanvas* canvas) {
3668 SkPaint paint;
3669 paint.setStrokeWidth(15);
3670 paint.setStrokeCap(SkPaint::kRound_Cap);
3671 SkPath path;
3672 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
3673 path.addPoly(points, SK_ARRAY_COUNT(points), false);
3674 for (int loop = 0; loop < 2; ++loop) {
3675 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
3676 SkPaint::kStrokeAndFill_Style} ) {
3677 paint.setStyle(style);
3678 canvas->drawPath(path, paint);
3679 canvas->translate(85, 0);
3680 }
3681 path.close();
3682 canvas->translate(-255, 128);
3683 }
3684}
3685##
3686
3687#SeeAlso
3688
3689##
3690
3691# ------------------------------------------------------------------------------
3692
3693#Method static bool IsInverseFillType(FillType fill)
3694
3695Returns true if fill is inverted and Path with fill represents area outside
3696of its geometric bounds.
3697
3698#Table
3699#Legend
3700# FillType # is inverse ##
3701##
3702# kWinding_FillType # false ##
3703# kEvenOdd_FillType # false ##
3704# kInverseWinding_FillType # true ##
3705# kInverseEvenOdd_FillType # true ##
3706##
3707
3708#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3709 kInverseWinding_FillType, kInverseEvenOdd_FillType
3710##
3711
3712#Return true if Path fills outside its bounds ##
3713
3714#Example
3715#Function
3716#define nameValue(fill) { SkPath::fill, #fill }
3717
3718##
3719void draw(SkCanvas* canvas) {
3720 struct {
3721 SkPath::FillType fill;
3722 const char* name;
3723 } fills[] = {
3724 nameValue(kWinding_FillType),
3725 nameValue(kEvenOdd_FillType),
3726 nameValue(kInverseWinding_FillType),
3727 nameValue(kInverseEvenOdd_FillType),
3728 };
3729 for (auto fill: fills ) {
3730 SkDebugf("IsInverseFillType(%s) == %s\n", fill.name, SkPath::IsInverseFillType(fill.fill) ?
3731 "true" : "false");
3732 }
3733}
3734#StdOut
3735IsInverseFillType(kWinding_FillType) == false
3736IsInverseFillType(kEvenOdd_FillType) == false
3737IsInverseFillType(kInverseWinding_FillType) == true
3738IsInverseFillType(kInverseEvenOdd_FillType) == true
3739##
3740##
3741
3742#SeeAlso FillType getFillType setFillType ConvertToNonInverseFillType
3743
3744##
3745
3746# ------------------------------------------------------------------------------
3747
3748#Method static FillType ConvertToNonInverseFillType(FillType fill)
3749
3750Returns equivalent Fill_Type representing Path fill inside its bounds.
3751.
3752
3753#Table
3754#Legend
3755# FillType # inside FillType ##
3756##
3757# kWinding_FillType # kWinding_FillType ##
3758# kEvenOdd_FillType # kEvenOdd_FillType ##
3759# kInverseWinding_FillType # kWinding_FillType ##
3760# kInverseEvenOdd_FillType # kEvenOdd_FillType ##
3761##
3762
3763#Param fill one of: kWinding_FillType, kEvenOdd_FillType,
3764 kInverseWinding_FillType, kInverseEvenOdd_FillType
3765##
3766
3767#Return fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted ##
3768
3769#Example
3770#Function
3771#define nameValue(fill) { SkPath::fill, #fill }
3772
3773##
3774void draw(SkCanvas* canvas) {
3775 struct {
3776 SkPath::FillType fill;
3777 const char* name;
3778 } fills[] = {
3779 nameValue(kWinding_FillType),
3780 nameValue(kEvenOdd_FillType),
3781 nameValue(kInverseWinding_FillType),
3782 nameValue(kInverseEvenOdd_FillType),
3783 };
3784 for (unsigned i = 0; i < SK_ARRAY_COUNT(fills); ++i) {
3785 if (fills[i].fill != (SkPath::FillType) i) {
3786 SkDebugf("fills array order does not match FillType enum order");
3787 break;
3788 }
3789 SkDebugf("ConvertToNonInverseFillType(%s) == %s\n", fills[i].name,
3790 fills[(int) SkPath::ConvertToNonInverseFillType(fills[i].fill)].name);
3791 }
3792}
3793#StdOut
3794ConvertToNonInverseFillType(kWinding_FillType) == kWinding_FillType
3795ConvertToNonInverseFillType(kEvenOdd_FillType) == kEvenOdd_FillType
3796ConvertToNonInverseFillType(kInverseWinding_FillType) == kWinding_FillType
3797ConvertToNonInverseFillType(kInverseEvenOdd_FillType) == kEvenOdd_FillType
3798##
3799##
3800
3801#SeeAlso FillType getFillType setFillType IsInverseFillType
3802
3803##
3804
3805# ------------------------------------------------------------------------------
3806
3807#Method static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3808 SkScalar w, SkPoint pts[], int pow2)
3809
3810Approximates Conic with Quad array. Conic is constructed from start Point p0,
3811control Point p1, end Point p2, and weight w.
3812Quad array is stored in pts; this storage is supplied by caller.
3813Maximum Quad count is 2 to the pow2.
3814Every third point in array shares last Point of previous Quad and first Point of
3815next Quad. Maximum pts storage size is given by:
3816#Formula
3817(1 + 2 * (1 << pow2)) * sizeof(SkPoint)
3818##
Cary Clark154beea2017-10-26 07:58:48 -04003819.
Cary Clark6fc50412017-09-21 12:31:06 -04003820
Cary Clark154beea2017-10-26 07:58:48 -04003821Returns Quad count used the approximation, which may be smaller
Cary Clark73fa9722017-08-29 17:36:51 -04003822than the number requested.
3823
3824Conic_Weight determines the amount of influence Conic control point has on the curve.
3825w less than one represents an elliptical section. w greater than one represents
3826a hyperbolic section. w equal to one represents a parabolic section.
3827
3828Two Quad curves are sufficient to approximate an elliptical Conic with a sweep
3829of up to 90 degrees; in this case, set pow2 to one.
3830
3831#Param p0 Conic start Point ##
3832#Param p1 Conic control Point ##
3833#Param p2 Conic end Point ##
3834#Param w Conic weight ##
3835#Param pts storage for Quad array ##
3836#Param pow2 Quad count, as power of two, normally 0 to 5 (1 to 32 Quad curves) ##
3837
Cary Clarka523d2d2017-08-30 08:58:10 -04003838#Return number of Quad curves written to pts ##
Cary Clark73fa9722017-08-29 17:36:51 -04003839
3840#Example
3841#Description
3842A pair of Quad curves are drawn in red on top of the elliptical Conic curve in black.
3843The middle curve is nearly circular. The top-right curve is parabolic, which can
3844be drawn exactly with a single Quad.
3845##
3846void draw(SkCanvas* canvas) {
3847 SkPaint conicPaint;
3848 conicPaint.setAntiAlias(true);
3849 conicPaint.setStyle(SkPaint::kStroke_Style);
3850 SkPaint quadPaint(conicPaint);
3851 quadPaint.setColor(SK_ColorRED);
3852 SkPoint conic[] = { {20, 170}, {80, 170}, {80, 230} };
3853 for (auto weight : { .25f, .5f, .707f, .85f, 1.f } ) {
3854 SkPoint quads[5];
3855 SkPath::ConvertConicToQuads(conic[0], conic[1], conic[2], weight, quads, 1);
3856 SkPath path;
3857 path.moveTo(conic[0]);
3858 path.conicTo(conic[1], conic[2], weight);
3859 canvas->drawPath(path, conicPaint);
3860 path.rewind();
3861 path.moveTo(quads[0]);
3862 path.quadTo(quads[1], quads[2]);
3863 path.quadTo(quads[3], quads[4]);
3864 canvas->drawPath(path, quadPaint);
3865 canvas->translate(50, -50);
3866 }
3867}
3868##
3869
3870#SeeAlso Conic Quad
3871
3872##
3873
3874# ------------------------------------------------------------------------------
3875
3876#Method bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const
3877
Cary Clarkce101242017-09-01 15:51:02 -04003878Returns true if Path is equivalent to Rect when filled.
Cary Clark73fa9722017-08-29 17:36:51 -04003879If false: rect, isClosed, and direction are unchanged.
3880If true: rect, isClosed, and direction are written to if not nullptr.
3881
3882rect may be smaller than the Path bounds. Path bounds may include kMove_Verb points
3883that do not alter the area drawn by the returned rect.
3884
3885#Param rect storage for bounds of Rect; may be nullptr ##
3886#Param isClosed storage set to true if Path is closed; may be nullptr ##
3887#Param direction storage set to Rect direction; may be nullptr ##
3888
3889#Return true if Path contains Rect ##
3890
3891#Example
3892#Description
3893After addRect, isRect returns true. Following moveTo permits isRect to return true, but
3894following lineTo does not. addPoly returns true even though rect is not closed, and one
3895side of rect is made up of consecutive line segments.
3896##
3897void draw(SkCanvas* canvas) {
3898 auto debugster = [](const char* prefix, const SkPath& path) -> void {
3899 SkRect rect;
3900 SkPath::Direction direction;
3901 bool isClosed;
3902 path.isRect(&rect, &isClosed, &direction) ?
3903 SkDebugf("%s is rect (%g, %g, %g, %g); is %s" "closed; direction %s\n", prefix,
3904 rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, isClosed ? "" : "not ",
3905 SkPath::kCW_Direction == direction ? "CW" : "CCW") :
3906 SkDebugf("%s is not rect\n", prefix);
3907 };
3908 SkPath path;
3909 debugster("empty", path);
3910 path.addRect({10, 20, 30, 40});
3911 debugster("addRect", path);
3912 path.moveTo(60, 70);
3913 debugster("moveTo", path);
3914 path.lineTo(60, 70);
3915 debugster("lineTo", path);
3916 path.reset();
3917 const SkPoint pts[] = { {0, 0}, {0, 80}, {80, 80}, {80, 0}, {40, 0}, {20, 0} };
3918 path.addPoly(pts, SK_ARRAY_COUNT(pts), false);
3919 debugster("addPoly", path);
3920}
3921#StdOut
3922empty is not rect
3923addRect is rect (10, 20, 30, 40); is closed; direction CW
3924moveTo is rect (10, 20, 30, 40); is closed; direction CW
3925lineTo is not rect
3926addPoly is rect (0, 0, 80, 80); is not closed; direction CCW
3927##
3928##
3929
3930#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isNestedFillRects
3931
3932##
3933
3934# ------------------------------------------------------------------------------
3935
3936#Method bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const
3937
3938Returns true if Path is equivalent to nested Rect pair when filled.
3939If false, rect and dirs are unchanged.
3940If true, rect and dirs are written to if not nullptr:
3941setting rect[0] to outer Rect, and rect[1] to inner Rect;
3942setting dirs[0] to Direction of outer Rect, and dirs[1] to Direction of inner
3943Rect.
3944
3945#Param rect storage for Rect pair; may be nullptr ##
3946#Param dirs storage for Direction pair; may be nullptr ##
3947
3948#Return true if Path contains nested Rect pair ##
3949
3950#Example
3951void draw(SkCanvas* canvas) {
3952 SkPaint paint;
3953 paint.setStyle(SkPaint::kStroke_Style);
3954 paint.setStrokeWidth(5);
3955 SkPath path;
3956 path.addRect({10, 20, 30, 40});
3957 paint.getFillPath(path, &path);
3958 SkRect rects[2];
3959 SkPath::Direction directions[2];
3960 if (path.isNestedFillRects(rects, directions)) {
3961 for (int i = 0; i < 2; ++i) {
3962 SkDebugf("%s (%g, %g, %g, %g); direction %s\n", i ? "inner" : "outer",
3963 rects[i].fLeft, rects[i].fTop, rects[i].fRight, rects[i].fBottom,
3964 SkPath::kCW_Direction == directions[i] ? "CW" : "CCW");
3965 }
3966 } else {
3967 SkDebugf("is not nested rectangles\n");
3968 }
3969}
3970#StdOut
3971outer (7.5, 17.5, 32.5, 42.5); direction CW
3972inner (12.5, 22.5, 27.5, 37.5); direction CCW
3973##
3974##
3975
3976#SeeAlso computeTightBounds conservativelyContainsRect getBounds isConvex isLastContourClosed isRect
3977
3978##
3979
3980# ------------------------------------------------------------------------------
3981
3982#Method void addRect(const SkRect& rect, Direction dir = kCW_Direction)
3983
3984Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
3985starting with top-left corner of Rect; followed by top-right, bottom-right,
3986and bottom-left if dir is kCW_Direction; or followed by bottom-left,
3987bottom-right, and top-right if dir is kCCW_Direction.
3988
3989#Param rect Rect to add as a closed contour ##
3990#Param dir Direction to wind added contour ##
3991
3992#Example
3993#Description
3994The left Rect dashes starting at the top-left corner, to the right.
3995The right Rect dashes starting at the top-left corner, towards the bottom.
3996##
3997#Height 128
3998void draw(SkCanvas* canvas) {
3999 SkPaint paint;
4000 paint.setStrokeWidth(15);
4001 paint.setStrokeCap(SkPaint::kSquare_Cap);
4002 float intervals[] = { 5, 21.75f };
4003 paint.setStyle(SkPaint::kStroke_Style);
4004 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4005 SkPath path;
4006 path.addRect({20, 20, 100, 100}, SkPath::kCW_Direction);
4007 canvas->drawPath(path, paint);
4008 path.rewind();
4009 path.addRect({140, 20, 220, 100}, SkPath::kCCW_Direction);
4010 canvas->drawPath(path, paint);
4011}
4012##
4013
4014#SeeAlso SkCanvas::drawRect Direction
4015
4016##
4017
4018# ------------------------------------------------------------------------------
4019
4020#Method void addRect(const SkRect& rect, Direction dir, unsigned start)
4021
4022Add Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
4023If dir is kCW_Direction, Rect corners are added clockwise; if dir is
4024kCCW_Direction, Rect corners are added counterclockwise.
4025start determines the first corner added.
4026
4027#Table
4028#Legend
4029# start # first corner ##
4030#Legend ##
4031# 0 # top-left ##
4032# 1 # top-right ##
4033# 2 # bottom-right ##
4034# 3 # bottom-left ##
4035#Table ##
4036
4037#Param rect Rect to add as a closed contour ##
4038#Param dir Direction to wind added contour ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004039#Param start initial corner of Rect to add ##
Cary Clark73fa9722017-08-29 17:36:51 -04004040
4041#Example
4042#Height 128
4043#Description
4044The arrow is just after the initial corner and points towards the next
4045corner appended to Path.
4046##
4047void draw(SkCanvas* canvas) {
4048 const SkPoint arrow[] = { {5, -5}, {15, -5}, {20, 0}, {15, 5}, {5, 5}, {10, 0} };
4049 const SkRect rect = {10, 10, 54, 54};
4050 SkPaint rectPaint;
4051 rectPaint.setAntiAlias(true);
4052 rectPaint.setStyle(SkPaint::kStroke_Style);
4053 SkPaint arrowPaint(rectPaint);
4054 SkPath arrowPath;
4055 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4056 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4057 SkPath1DPathEffect::kRotate_Style));
4058 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4059 for (unsigned start : { 0, 1, 2, 3 } ) {
4060 SkPath path;
4061 path.addRect(rect, direction, start);
4062 canvas->drawPath(path, rectPaint);
4063 canvas->drawPath(path, arrowPaint);
4064 canvas->translate(64, 0);
4065 }
4066 canvas->translate(-256, 64);
4067 }
4068}
4069##
4070
4071#SeeAlso SkCanvas::drawRect Direction
4072
4073##
4074
4075# ------------------------------------------------------------------------------
4076
4077#Method void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
4078 Direction dir = kCW_Direction)
4079
4080Add Rect (left, top, right, bottom) to Path,
4081appending kMove_Verb, three kLine_Verb, and kClose_Verb,
4082starting with top-left corner of Rect; followed by top-right, bottom-right,
4083and bottom-left if dir is kCW_Direction; or followed by bottom-left,
4084bottom-right, and top-right if dir is kCCW_Direction.
4085
4086#Param left smaller x of Rect ##
4087#Param top smaller y of Rect ##
4088#Param right larger x of Rect ##
4089#Param bottom larger y of Rect ##
4090#Param dir Direction to wind added contour ##
4091
4092#Example
4093#Description
4094The left Rect dashes start at the top-left corner, and continue to the right.
4095The right Rect dashes start at the top-left corner, and continue down.
4096##
4097#Height 128
4098void draw(SkCanvas* canvas) {
4099 SkPaint paint;
4100 paint.setStrokeWidth(15);
4101 paint.setStrokeCap(SkPaint::kSquare_Cap);
4102 float intervals[] = { 5, 21.75f };
4103 paint.setStyle(SkPaint::kStroke_Style);
4104 paint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
4105 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4106 SkPath path;
4107 path.addRect(20, 20, 100, 100, direction);
4108 canvas->drawPath(path, paint);
4109 canvas->translate(128, 0);
4110 }
4111}
4112##
4113
4114#SeeAlso SkCanvas::drawRect Direction
4115
4116##
4117
4118# ------------------------------------------------------------------------------
4119
4120#Method void addOval(const SkRect& oval, Direction dir = kCW_Direction)
4121
4122Add Oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4123Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4124and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
4125clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4126
4127This form is identical to addOval(oval, dir, 1).
4128
4129#Param oval bounds of ellipse added ##
4130#Param dir Direction to wind ellipse ##
4131
4132#Example
4133#Height 120
4134 SkPaint paint;
4135 SkPath oval;
4136 oval.addOval({20, 20, 160, 80});
4137 canvas->drawPath(oval, paint);
4138##
4139
4140#SeeAlso SkCanvas::drawOval Direction Oval
4141
4142##
4143
4144# ------------------------------------------------------------------------------
4145
4146#Method void addOval(const SkRect& oval, Direction dir, unsigned start)
4147
4148Add Oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
4149Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
4150and half oval height. Oval begins at start and continues
4151clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
4152
4153#Table
4154#Legend
4155# start # Point ##
4156#Legend ##
4157# 0 # oval.centerX(), oval.fTop ##
4158# 1 # oval.fRight, oval.centerY() ##
4159# 2 # oval.centerX(), oval.fBottom ##
4160# 3 # oval.fLeft, oval.centerY() ##
4161#Table ##
4162
4163#Param oval bounds of ellipse added ##
4164#Param dir Direction to wind ellipse ##
4165#Param start index of initial point of ellipse ##
4166
4167#Example
4168#Height 160
4169void draw(SkCanvas* canvas) {
4170 const SkPoint arrow[] = { {0, -5}, {10, 0}, {0, 5} };
4171 const SkRect rect = {10, 10, 54, 54};
4172 SkPaint ovalPaint;
4173 ovalPaint.setAntiAlias(true);
4174 SkPaint textPaint(ovalPaint);
4175 textPaint.setTextAlign(SkPaint::kCenter_Align);
4176 ovalPaint.setStyle(SkPaint::kStroke_Style);
4177 SkPaint arrowPaint(ovalPaint);
4178 SkPath arrowPath;
4179 arrowPath.addPoly(arrow, SK_ARRAY_COUNT(arrow), true);
4180 arrowPaint.setPathEffect(SkPath1DPathEffect::Make(arrowPath, 176, 0,
4181 SkPath1DPathEffect::kRotate_Style));
4182 for (auto direction : { SkPath::kCW_Direction, SkPath::kCCW_Direction } ) {
4183 for (unsigned start : { 0, 1, 2, 3 } ) {
4184 SkPath path;
4185 path.addOval(rect, direction, start);
4186 canvas->drawPath(path, ovalPaint);
4187 canvas->drawPath(path, arrowPaint);
4188 canvas->drawText(&"0123"[start], 1, rect.centerX(), rect.centerY() + 5, textPaint);
4189 canvas->translate(64, 0);
4190 }
4191 canvas->translate(-256, 72);
4192 canvas->drawString(SkPath::kCW_Direction == direction ? "clockwise" : "counterclockwise",
4193 128, 0, textPaint);
4194 }
4195}
4196##
4197
4198#SeeAlso SkCanvas::drawOval Direction Oval
4199
4200##
4201
4202# ------------------------------------------------------------------------------
4203
4204#Method void addCircle(SkScalar x, SkScalar y, SkScalar radius,
4205 Direction dir = kCW_Direction)
4206
4207Add Circle centered at (x, y) of size radius to Path, appending kMove_Verb,
Cary Clark154beea2017-10-26 07:58:48 -04004208four kConic_Verb, and kClose_Verb. Circle begins at:
Cary Clark73fa9722017-08-29 17:36:51 -04004209#Formula
4210(x + radius, y)
4211##
Cary Clark154beea2017-10-26 07:58:48 -04004212, continuing
4213clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Cary Clark73fa9722017-08-29 17:36:51 -04004214
Cary Clark6fc50412017-09-21 12:31:06 -04004215Has no effect if radius is zero or negative.
Cary Clark73fa9722017-08-29 17:36:51 -04004216
4217#Param x center of Circle ##
4218#Param y center of Circle ##
4219#Param radius distance from center to edge ##
4220#Param dir Direction to wind Circle ##
4221
4222#Example
4223void draw(SkCanvas* canvas) {
4224 SkPaint paint;
4225 paint.setAntiAlias(true);
4226 paint.setStyle(SkPaint::kStroke_Style);
4227 paint.setStrokeWidth(10);
4228 for (int size = 10; size < 300; size += 20) {
4229 SkPath path;
4230 path.addCircle(128, 128, size, SkPath::kCW_Direction);
4231 canvas->drawPath(path, paint);
4232 }
4233}
4234##
4235
4236#SeeAlso SkCanvas::drawCircle Direction Circle
4237
4238##
4239
4240# ------------------------------------------------------------------------------
4241
4242#Method void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle)
4243
4244Append Arc to Path, as the start of new Contour. Arc added is part of ellipse
4245bounded by oval, from startAngle through sweepAngle. Both startAngle and
4246sweepAngle are measured in degrees, where zero degrees is aligned with the
4247positive x-axis, and positive sweeps extends Arc clockwise.
4248
4249If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
4250zero, append Oval instead of Arc. Otherwise, sweepAngle values are treated
4251modulo 360, and Arc may or may not draw depending on numeric rounding.
4252
4253#Param oval bounds of ellipse containing Arc ##
4254#Param startAngle starting angle of Arc in degrees ##
4255#Param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360 ##
4256
4257#Example
4258#Description
4259The middle row of the left and right columns draw differently from the entries
4260above and below because sweepAngle is outside of the range of +/-360,
4261and startAngle modulo 90 is not zero.
4262##
4263void draw(SkCanvas* canvas) {
4264 SkPaint paint;
4265 for (auto start : { 0, 90, 135, 180, 270 } ) {
4266 for (auto sweep : { -450.f, -180.f, -90.f, 90.f, 180.f, 360.1f } ) {
4267 SkPath path;
4268 path.addArc({10, 10, 35, 45}, start, sweep);
4269 canvas->drawPath(path, paint);
4270 canvas->translate(252 / 6, 0);
4271 }
4272 canvas->translate(-252, 255 / 5);
4273 }
4274}
4275##
4276
4277#SeeAlso Arc arcTo SkCanvas::drawArc
4278
4279##
4280
4281# ------------------------------------------------------------------------------
4282
4283#Method void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
4284 Direction dir = kCW_Direction)
4285
4286Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4287equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
4288dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner and
4289winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the bottom-left
4290of the upper-left corner and winds counterclockwise.
4291
4292If either rx or ry is too large, rx and ry are scaled uniformly until the
4293corners fit. If rx or ry is less than or equal to zero, addRoundRect appends
4294Rect rect to Path.
4295
4296After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4297
4298#Param rect bounds of Round_Rect ##
4299#Param rx x-radius of rounded corners on the Round_Rect ##
4300#Param ry y-radius of rounded corners on the Round_Rect ##
4301#Param dir Direction to wind Round_Rect ##
4302
4303#Example
4304#Description
4305If either radius is zero, path contains Rect and is drawn red.
4306If sides are only radii, path contains Oval and is drawn blue.
4307All remaining path draws are convex, and are drawn in gray; no
4308paths constructed from addRoundRect are concave, so none are
4309drawn in green.
4310##
4311void draw(SkCanvas* canvas) {
4312 SkPaint paint;
4313 paint.setAntiAlias(true);
4314 for (auto xradius : { 0, 7, 13, 20 } ) {
4315 for (auto yradius : { 0, 9, 18, 40 } ) {
4316 SkPath path;
4317 path.addRoundRect({10, 10, 36, 46}, xradius, yradius);
4318 paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ?
4319 SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN);
4320 canvas->drawPath(path, paint);
4321 canvas->translate(64, 0);
4322 }
4323 canvas->translate(-256, 64);
4324 }
4325}
4326##
4327
4328#SeeAlso addRRect SkCanvas::drawRoundRect
4329
4330##
4331
4332# ------------------------------------------------------------------------------
4333
4334#Method void addRoundRect(const SkRect& rect, const SkScalar radii[],
4335 Direction dir = kCW_Direction)
4336
4337Append Round_Rect to Path, creating a new closed Contour. Round_Rect has bounds
4338equal to rect; each corner is 90 degrees of an ellipse with radii from the
4339array.
4340
4341#Table
4342#Legend
4343# radii index # location ##
4344#Legend ##
4345# 0 # x-radius of top-left corner ##
4346# 1 # y-radius of top-left corner ##
4347# 2 # x-radius of top-right corner ##
4348# 3 # y-radius of top-right corner ##
4349# 4 # x-radius of bottom-right corner ##
4350# 5 # y-radius of bottom-right corner ##
4351# 6 # x-radius of bottom-left corner ##
4352# 7 # y-radius of bottom-left corner ##
4353#Table ##
4354
4355If dir is kCW_Direction, Round_Rect starts at top-left of the lower-left corner
4356and winds clockwise. If dir is kCCW_Direction, Round_Rect starts at the
4357bottom-left of the upper-left corner and winds counterclockwise.
4358
4359If both radii on any side of rect exceed its length, all radii are scaled
4360uniformly until the corners fit. If either radius of a corner is less than or
4361equal to zero, both are treated as zero.
4362
4363After appending, Path may be empty, or may contain: Rect, Oval, or RoundRect.
4364
4365#Param rect bounds of Round_Rect ##
4366#Param radii array of 8 SkScalar values, a radius pair for each corner ##
4367#Param dir Direction to wind Round_Rect ##
4368
4369#Example
4370void draw(SkCanvas* canvas) {
4371 SkPaint paint;
4372 paint.setAntiAlias(true);
4373 SkScalar radii[] = { 80, 100, 0, 0, 40, 60, 0, 0 };
4374 SkPath path;
4375 SkMatrix rotate90;
4376 rotate90.setRotate(90, 128, 128);
4377 for (int i = 0; i < 4; ++i) {
4378 path.addRoundRect({10, 10, 110, 110}, radii);
4379 path.transform(rotate90);
4380 }
4381 canvas->drawPath(path, paint);
4382}
4383##
4384
4385#SeeAlso addRRect SkCanvas::drawRoundRect
4386
4387##
4388
4389# ------------------------------------------------------------------------------
4390
4391#Method void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction)
4392
4393Add rrect to Path, creating a new closed Contour. If
4394dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
4395winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
4396of the upper-left corner and winds counterclockwise.
4397
4398After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4399
4400#Param rrect bounds and radii of rounded rectangle ##
4401#Param dir Direction to wind Round_Rect ##
4402
4403#Example
4404void draw(SkCanvas* canvas) {
4405 SkPaint paint;
4406 paint.setAntiAlias(true);
4407 SkRRect rrect;
4408 SkVector radii[] = {{50, 50}, {0, 0}, {0, 0}, {50, 50}};
4409 rrect.setRectRadii({10, 10, 110, 110}, radii);
4410 SkPath path;
4411 SkMatrix rotate90;
4412 rotate90.setRotate(90, 128, 128);
4413 for (int i = 0; i < 4; ++i) {
4414 path.addRRect(rrect);
4415 path.transform(rotate90);
4416 }
4417 canvas->drawPath(path, paint);
4418}
4419##
4420
4421#SeeAlso addRoundRect SkCanvas::drawRRect
4422
4423##
4424
4425# ------------------------------------------------------------------------------
4426
4427#Method void addRRect(const SkRRect& rrect, Direction dir, unsigned start)
4428
4429Add rrect to Path, creating a new closed Contour. If dir is kCW_Direction, rrect
4430winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
4431start determines the first point of rrect to add.
4432
4433#Table
4434#Legend
4435# start # location ##
4436#Legend ##
4437# 0 # right of top-left corner ##
4438# 1 # left of top-right corner ##
4439# 2 # bottom of top-right corner ##
4440# 3 # top of bottom-right corner ##
4441# 4 # left of bottom-right corner ##
4442# 5 # right of bottom-left corner ##
4443# 6 # top of bottom-left corner ##
4444# 7 # bottom of top-left corner ##
4445#Table ##
4446
4447After appending, Path may be empty, or may contain: Rect, Oval, or Round_Rect.
4448
4449#Param rrect bounds and radii of rounded rectangle ##
4450#Param dir Direction to wind Round_Rect ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004451#Param start index of initial point of Round_Rect ##
Cary Clark73fa9722017-08-29 17:36:51 -04004452
4453#Example
4454void draw(SkCanvas* canvas) {
4455 SkPaint paint;
4456 paint.setAntiAlias(true);
4457 SkRRect rrect;
4458 rrect.setRectXY({40, 40, 215, 215}, 50, 50);
4459 SkPath path;
4460 path.addRRect(rrect);
4461 canvas->drawPath(path, paint);
4462 for (int start = 0; start < 8; ++start) {
4463 SkPath textPath;
4464 textPath.addRRect(rrect, SkPath::kCW_Direction, start);
4465 canvas->drawTextOnPathHV(&"01234567"[start], 1, textPath, 0, -5, paint);
4466 }
4467}
4468##
4469
4470#SeeAlso addRoundRect SkCanvas::drawRRect
4471
4472##
4473
4474# ------------------------------------------------------------------------------
4475
4476#Method void addPoly(const SkPoint pts[], int count, bool close)
4477
Cary Clark6fc50412017-09-21 12:31:06 -04004478Add Contour created from Line array, adding (count - 1) Line segments.
4479Contour added starts at pts[0], then adds a line for every additional Point
4480in pts array. If close is true,appends kClose_Verb to Path, connecting
4481pts[count - 1] and pts[0].
Cary Clark73fa9722017-08-29 17:36:51 -04004482
4483If count is zero, append kMove_Verb to path.
4484Has no effect if count is less than one.
4485
Cary Clarka523d2d2017-08-30 08:58:10 -04004486#Param pts array of Line sharing end and start Point ##
4487#Param count length of Point array ##
Cary Clark73fa9722017-08-29 17:36:51 -04004488#Param close true to add Line connecting Contour end and start ##
4489
4490#Example
4491void draw(SkCanvas* canvas) {
4492 SkPaint paint;
4493 paint.setStrokeWidth(15);
4494 paint.setStrokeCap(SkPaint::kRound_Cap);
4495 const SkPoint points[] = {{20, 20}, {70, 20}, {40, 90}};
4496 for (bool close : { false, true } ) {
4497 SkPath path;
4498 path.addPoly(points, SK_ARRAY_COUNT(points), close);
4499 for (auto style : {SkPaint::kStroke_Style, SkPaint::kFill_Style,
4500 SkPaint::kStrokeAndFill_Style} ) {
4501 paint.setStyle(style);
4502 canvas->drawPath(path, paint);
4503 canvas->translate(85, 0);
4504 }
4505 canvas->translate(-255, 128);
4506 }
4507}
4508##
4509
4510#SeeAlso SkCanvas::drawPoints
4511
4512##
4513
4514# ------------------------------------------------------------------------------
4515
4516#Enum AddPathMode
4517
4518#Code
4519 enum AddPathMode {
4520 kAppend_AddPathMode,
4521 kExtend_AddPathMode,
4522 };
4523##
4524
4525AddPathMode chooses how addPath appends. Adding one Path to another can extend
4526the last Contour or start a new Contour.
4527
4528#Const kAppend_AddPathMode
4529 Path Verbs, Points, and Conic_Weights are appended to destination unaltered.
4530 Since Path Verb_Array begins with kMove_Verb if src is not empty, this
4531 starts a new Contour.
4532##
4533#Const kExtend_AddPathMode
4534 If destination is closed or empty, start a new Contour. If destination
4535 is not empty, add Line from Last_Point to added Path first Point. Skip added
4536 Path initial kMove_Verb, then append remining Verbs, Points, and Conic_Weights.
4537##
4538
4539#Example
4540#Description
4541test is built from path, open on the top row, and closed on the bottom row.
4542The left column uses kAppend_AddPathMode; the right uses kExtend_AddPathMode.
4543The top right composition is made up of one contour; the other three have two.
4544##
4545#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004546 SkPath path, path2;
4547 path.moveTo(20, 20);
4548 path.lineTo(20, 40);
4549 path.lineTo(40, 20);
4550 path2.moveTo(60, 60);
4551 path2.lineTo(80, 60);
4552 path2.lineTo(80, 40);
4553 SkPaint paint;
4554 paint.setStyle(SkPaint::kStroke_Style);
4555 for (int i = 0; i < 2; i++) {
4556 for (auto addPathMode : { SkPath::kAppend_AddPathMode, SkPath::kExtend_AddPathMode } ) {
4557 SkPath test(path);
4558 test.addPath(path2, addPathMode);
4559 canvas->drawPath(test, paint);
4560 canvas->translate(100, 0);
4561 }
4562 canvas->translate(-200, 100);
4563 path.close();
4564 }
Cary Clark73fa9722017-08-29 17:36:51 -04004565##
4566
4567#SeeAlso addPath reverseAddPath
4568
4569##
4570
4571# ------------------------------------------------------------------------------
4572
4573#Method void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
4574 AddPathMode mode = kAppend_AddPathMode)
4575
4576Append src to Path, offset by (dx, dy).
4577
4578If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4579added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4580Verbs, Points, and Conic_Weights.
4581
4582#Param src Path Verbs, Points, and Conic_Weights to add ##
4583#Param dx offset added to src Point_Array x coordinates ##
4584#Param dy offset added to src Point_Array y coordinates ##
4585#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4586
4587#Example
4588#Height 180
Cary Clark8032b982017-07-28 11:04:54 -04004589 SkPaint paint;
4590 paint.setTextSize(128);
4591 paint.setFakeBoldText(true);
4592 SkPath dest, text;
4593 paint.getTextPath("O", 1, 50, 120, &text);
4594 for (int i = 0; i < 3; i++) {
4595 dest.addPath(text, i * 20, i * 20);
4596 }
4597 Simplify(dest, &dest);
4598 paint.setStyle(SkPaint::kStroke_Style);
4599 paint.setStrokeWidth(3);
4600 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004601##
4602
4603#SeeAlso AddPathMode offset() reverseAddPath
4604
4605##
4606
4607# ------------------------------------------------------------------------------
4608
4609#Method void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode)
4610
4611Append src to Path.
4612
4613If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4614added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4615Verbs, Points, and Conic_Weights.
4616
4617#Param src Path Verbs, Points, and Conic_Weights to add ##
4618#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4619
4620#Example
4621#Height 80
Cary Clark8032b982017-07-28 11:04:54 -04004622 SkPaint paint;
4623 paint.setStyle(SkPaint::kStroke_Style);
4624 SkPath dest, path;
4625 path.addOval({-80, 20, 0, 60}, SkPath::kCW_Direction, 1);
4626 for (int i = 0; i < 2; i++) {
4627 dest.addPath(path, SkPath::kExtend_AddPathMode);
4628 dest.offset(100, 0);
4629 }
Cary Clark73fa9722017-08-29 17:36:51 -04004630 canvas->drawPath(dest, paint);
4631##
4632
4633#SeeAlso AddPathMode reverseAddPath
4634
4635##
4636
4637# ------------------------------------------------------------------------------
4638
4639#Method void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode)
4640
4641Append src to Path, transformed by matrix. Transformed curves may have different
4642Verbs, Points, and Conic_Weights.
4643
4644If mode is kAppend_AddPathMode, src Verb_Array, Point_Array, and Conic_Weights are
4645added unaltered. If mode is kExtend_AddPathMode, add Line before appending
4646Verbs, Points, and Conic_Weights.
4647
4648#Param src Path Verbs, Points, and Conic_Weights to add ##
Cary Clarka523d2d2017-08-30 08:58:10 -04004649#Param matrix transform applied to src ##
Cary Clark73fa9722017-08-29 17:36:51 -04004650#Param mode kAppend_AddPathMode or kExtend_AddPathMode ##
4651
4652#Example
4653#Height 160
Cary Clark8032b982017-07-28 11:04:54 -04004654 SkPaint paint;
4655 paint.setStyle(SkPaint::kStroke_Style);
4656 SkPath dest, path;
4657 path.addOval({20, 20, 200, 120}, SkPath::kCW_Direction, 1);
4658 for (int i = 0; i < 6; i++) {
4659 SkMatrix matrix;
4660 matrix.reset();
4661 matrix.setPerspX(i / 400.f);
4662 dest.addPath(path, matrix);
4663 }
4664 canvas->drawPath(dest, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004665##
4666
4667#SeeAlso AddPathMode transform() offset() reverseAddPath
4668
4669##
4670
4671# ------------------------------------------------------------------------------
4672
4673#Method void reverseAddPath(const SkPath& src)
4674
4675Append src to Path, from back to front.
4676Reversed src always appends a new Contour to Path.
4677
4678#Param src Path Verbs, Points, and Conic_Weights to add ##
4679
4680#Example
4681#Height 200
Cary Clark8032b982017-07-28 11:04:54 -04004682 SkPath path;
4683 path.moveTo(20, 20);
4684 path.lineTo(20, 40);
4685 path.lineTo(40, 20);
4686 SkPaint paint;
4687 paint.setStyle(SkPaint::kStroke_Style);
4688 for (int i = 0; i < 2; i++) {
4689 SkPath path2;
4690 path2.moveTo(60, 60);
4691 path2.lineTo(80, 60);
4692 path2.lineTo(80, 40);
4693 for (int j = 0; j < 2; j++) {
4694 SkPath test(path);
4695 test.reverseAddPath(path2);
4696 canvas->drawPath(test, paint);
4697 canvas->translate(100, 0);
4698 path2.close();
4699 }
4700 canvas->translate(-200, 100);
4701 path.close();
4702 }
Cary Clark73fa9722017-08-29 17:36:51 -04004703##
4704
4705#SeeAlso AddPathMode transform() offset() addPath
4706
4707##
4708
4709# ------------------------------------------------------------------------------
4710
4711#Method void offset(SkScalar dx, SkScalar dy, SkPath* dst) const
4712
4713Offset Point_Array by (dx, dy). Offset Path replaces dst.
4714If dst is nullptr, Path is replaced by offset data.
4715
4716#Param dx offset added to Point_Array x coordinates ##
4717#Param dy offset added to Point_Array y coordinates ##
4718#Param dst overwritten, translated copy of Path; may be nullptr ##
4719
4720#Example
4721#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004722 SkPath pattern;
4723 pattern.moveTo(20, 20);
4724 pattern.lineTo(20, 40);
4725 pattern.lineTo(40, 20);
4726 SkPaint paint;
4727 paint.setStyle(SkPaint::kStroke_Style);
4728 for (int i = 0; i < 10; i++) {
4729 SkPath path;
4730 pattern.offset(20 * i, 0, &path);
4731 canvas->drawPath(path, paint);
4732 }
Cary Clark73fa9722017-08-29 17:36:51 -04004733##
4734
4735#SeeAlso addPath transform
4736
4737##
4738
4739# ------------------------------------------------------------------------------
4740
4741#Method void offset(SkScalar dx, SkScalar dy)
4742
4743Offset Point_Array by (dx, dy). Path is replaced by offset data.
4744
4745#Param dx offset added to Point_Array x coordinates ##
4746#Param dy offset added to Point_Array y coordinates ##
4747
4748#Example
4749#Height 60
Cary Clark8032b982017-07-28 11:04:54 -04004750 SkPath path;
4751 path.moveTo(20, 20);
4752 path.lineTo(20, 40);
4753 path.lineTo(40, 20);
4754 SkPaint paint;
4755 paint.setStyle(SkPaint::kStroke_Style);
4756 for (int i = 0; i < 10; i++) {
4757 canvas->drawPath(path, paint);
4758 path.offset(20, 0);
4759 }
Cary Clark73fa9722017-08-29 17:36:51 -04004760##
4761
4762#SeeAlso addPath transform SkCanvas::translate()
4763
4764##
4765
4766# ------------------------------------------------------------------------------
4767
4768#Method void transform(const SkMatrix& matrix, SkPath* dst) const
4769
4770Transform Verb_Array, Point_Array, and weight by matrix.
4771transform may change Verbs and increase their number.
4772Transformed Path replaces dst; if dst is nullptr, original data
4773is replaced.
4774
4775#Param matrix Matrix to apply to Path ##
4776#Param dst overwritten, transformed copy of Path; may be nullptr ##
4777
4778#Example
Cary Clark8032b982017-07-28 11:04:54 -04004779#Height 200
4780 SkPath pattern;
4781 pattern.moveTo(100, 100);
4782 pattern.lineTo(100, 20);
4783 pattern.lineTo(20, 100);
4784 SkPaint paint;
4785 paint.setStyle(SkPaint::kStroke_Style);
4786 for (int i = 0; i < 10; i++) {
4787 SkPath path;
4788 SkMatrix matrix;
4789 matrix.setRotate(36 * i, 100, 100);
4790 pattern.transform(matrix, &path);
4791 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004792 }
4793##
4794
4795#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4796
4797##
4798
4799# ------------------------------------------------------------------------------
4800
4801#Method void transform(const SkMatrix& matrix)
4802
4803Transform Verb_Array, Point_Array, and weight by matrix.
4804transform may change Verbs and increase their number.
4805Path is replaced by transformed data.
4806
4807#Param matrix Matrix to apply to Path ##
4808
4809#Example
Cary Clark8032b982017-07-28 11:04:54 -04004810#Height 200
4811 SkPath path;
4812 path.moveTo(100, 100);
4813 path.quadTo(100, 20, 20, 100);
4814 SkPaint paint;
4815 paint.setStyle(SkPaint::kStroke_Style);
4816 for (int i = 0; i < 10; i++) {
4817 SkMatrix matrix;
4818 matrix.setRotate(36, 100, 100);
4819 path.transform(matrix);
4820 canvas->drawPath(path, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004821 }
4822##
4823
4824#SeeAlso addPath offset SkCanvas::concat() SkMatrix
4825
4826##
4827
4828# ------------------------------------------------------------------------------
4829
Cary Clark8032b982017-07-28 11:04:54 -04004830#Subtopic Last_Point
4831
4832Path is defined cumulatively, often by adding a segment to the end of last
4833Contour. Last_Point of Contour is shared as first Point of added Line or Curve.
4834Last_Point can be read and written directly with getLastPt and setLastPt.
4835
Cary Clark73fa9722017-08-29 17:36:51 -04004836#Method bool getLastPt(SkPoint* lastPt) const
4837
4838 Returns Last_Point on Path in lastPt. Returns false if Point_Array is empty,
4839 storing (0, 0) if lastPt is not nullptr.
4840
4841 #Param lastPt storage for final Point in Point_Array; may be nullptr ##
4842
4843 #Return true if Point_Array contains one or more Points ##
4844
4845 #Example
Cary Clark8032b982017-07-28 11:04:54 -04004846 SkPath path;
4847 path.moveTo(100, 100);
4848 path.quadTo(100, 20, 20, 100);
4849 SkMatrix matrix;
4850 matrix.setRotate(36, 100, 100);
4851 path.transform(matrix);
4852 SkPoint last;
4853 path.getLastPt(&last);
Cary Clark73fa9722017-08-29 17:36:51 -04004854 SkDebugf("last point: %g, %g\n", last.fX, last.fY);
4855 #StdOut
4856 last point: 35.2786, 52.9772
4857 ##
4858 ##
4859
4860 #SeeAlso setLastPt
4861
4862##
4863
4864#Method void setLastPt(SkScalar x, SkScalar y)
4865
4866 Set Last_Point to (x, y). If Point_Array is empty, append kMove_Verb to
4867 Verb_Array and (x, y) to Point_Array.
4868
4869 #Param x set x-coordinate of Last_Point ##
4870 #Param y set y-coordinate of Last_Point ##
4871
4872 #Example
4873 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004874 SkPaint paint;
4875 paint.setTextSize(128);
4876 SkPath path;
4877 paint.getTextPath("@", 1, 60, 100, &path);
4878 path.setLastPt(20, 120);
Cary Clark73fa9722017-08-29 17:36:51 -04004879 canvas->drawPath(path, paint);
4880 ##
4881
4882 #SeeAlso getLastPt
4883
4884##
4885
4886#Method void setLastPt(const SkPoint& p)
4887
4888 Set the last point on the path. If no points have been added, moveTo(p)
4889 is automatically called.
4890
4891 #Param p set value of Last_Point ##
4892
4893 #Example
4894 #Height 128
Cary Clark8032b982017-07-28 11:04:54 -04004895 SkPaint paint;
4896 paint.setTextSize(128);
4897 SkPath path, path2;
4898 paint.getTextPath("A", 1, 60, 100, &path);
4899 paint.getTextPath("Z", 1, 60, 100, &path2);
4900 SkPoint pt, pt2;
4901 path.getLastPt(&pt);
4902 path2.getLastPt(&pt2);
4903 path.setLastPt(pt2);
4904 path2.setLastPt(pt);
4905 canvas->drawPath(path, paint);
4906 canvas->drawPath(path2, paint);
Cary Clark73fa9722017-08-29 17:36:51 -04004907 ##
4908
4909 #SeeAlso getLastPt
4910
4911##
4912
4913#Subtopic Last_Point ##
4914
4915# ------------------------------------------------------------------------------
4916
4917#Enum SegmentMask
4918
4919#Code
4920 enum SegmentMask {
4921 kLine_SegmentMask = 1 << 0,
4922 kQuad_SegmentMask = 1 << 1,
4923 kConic_SegmentMask = 1 << 2,
4924 kCubic_SegmentMask = 1 << 3,
4925 };
4926##
4927
4928SegmentMask constants correspond to each drawing Verb type in Path; for
4929instance, if Path only contains Lines, only the kLine_SegmentMask bit is set.
4930
4931#Bug 6785 ##
4932#Const kLine_SegmentMask 1
4933Set if Verb_Array contains kLine_Verb.
4934##
4935#Const kQuad_SegmentMask 2
4936Set if Verb_Array contains kQuad_Verb. Note that conicTo may add a Quad.
4937##
4938#Const kConic_SegmentMask 4
4939Set if Verb_Array contains kConic_Verb.
4940##
4941#Const kCubic_SegmentMask 8
4942Set if Verb_Array contains kCubic_Verb.
4943##
4944
4945#Example
4946#Description
4947When conicTo has a weight of one, Quad is added to Path.
4948##
4949 SkPath path;
4950 path.conicTo(10, 10, 20, 30, 1);
4951 SkDebugf("Path kConic_SegmentMask is %s\n", path.getSegmentMasks() &
4952 SkPath::kConic_SegmentMask ? "set" : "clear");
4953 SkDebugf("Path kQuad_SegmentMask is %s\n", path.getSegmentMasks() &
4954 SkPath::kQuad_SegmentMask ? "set" : "clear");
4955#StdOut
4956Path kConic_SegmentMask is clear
4957Path kQuad_SegmentMask is set
4958##
4959##
4960
4961#SeeAlso getSegmentMasks Verb
4962
4963##
4964
4965# ------------------------------------------------------------------------------
4966
4967#Method uint32_t getSegmentMasks() const
4968
4969Returns a mask, where each set bit corresponds to a SegmentMask constant
4970if Path contains one or more Verbs of that type.
4971Returns zero if Path contains no Lines, or Curves: Quads, Conics, or Cubics.
4972
4973getSegmentMasks() returns a cached result; it is very fast.
4974
4975#Return SegmentMask bits or zero ##
4976
4977#Example
4978SkPath path;
4979path.quadTo(20, 30, 40, 50);
4980path.close();
4981const char* masks[] = { "line", "quad", "conic", "cubic" };
4982int index = 0;
4983for (auto mask : { SkPath::kLine_SegmentMask, SkPath::kQuad_SegmentMask,
4984 SkPath::kConic_SegmentMask, SkPath::kCubic_SegmentMask } ) {
4985 if (mask & path.getSegmentMasks()) {
4986 SkDebugf("mask %s set\n", masks[index]);
4987 }
4988 ++index;
4989}
4990#StdOut
4991mask quad set
4992##
4993##
4994
4995#SeeAlso getSegmentMasks Verb
4996
4997##
4998
4999# ------------------------------------------------------------------------------
5000
5001#Method bool contains(SkScalar x, SkScalar y) const
5002
5003Returns true if the point (x, y) is contained by Path, taking into
5004account FillType.
5005
5006#Table
5007#Legend
5008# FillType # contains() returns true if Point is enclosed by ##
5009##
5010# kWinding_FillType # a non-zero sum of Contour Directions. ##
5011# kEvenOdd_FillType # an odd number of Contours. ##
5012# kInverseWinding_FillType # a zero sum of Contour Directions. ##
5013# kInverseEvenOdd_FillType # and even number of Contours. ##
5014##
5015
5016#Param x x-coordinate of containment test ##
5017#Param y y-coordinate of containment test ##
5018
5019#Return true if Point is in Path ##
5020
5021#Example
5022SkPath path;
5023SkPaint paint;
5024paint.setTextSize(256);
5025paint.getTextPath("&", 1, 30, 220, &path);
5026for (int y = 2; y < 256; y += 9) {
5027 for (int x = 2; x < 256; x += 9) {
5028 int coverage = 0;
5029 for (int iy = -4; iy <= 4; iy += 2) {
5030 for (int ix = -4; ix <= 4; ix += 2) {
5031 coverage += path.contains(x + ix, y + iy);
5032 }
5033 }
5034 paint.setColor(SkColorSetARGB(0x5f, 0xff * coverage / 25, 0, 0xff * (25 - coverage) / 25));
5035 canvas->drawCircle(x, y, 8, paint);
5036 }
5037}
5038##
5039
5040#SeeAlso conservativelyContainsRect Fill_Type Op
5041
5042##
5043
5044# ------------------------------------------------------------------------------
5045
5046#Method void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const
5047
Cary Clark154beea2017-10-26 07:58:48 -04005048Writes text representation of Path to stream. If stream is nullptr, writes to
5049standard output. Set forceClose to true to get edges used to fill Path.
5050Set dumpAsHex true to generate exact binary representations
Cary Clark73fa9722017-08-29 17:36:51 -04005051of floating point numbers used in Point_Array and Conic_Weights.
5052
5053#Param stream writable Stream receiving Path text representation; may be nullptr ##
5054#Param forceClose true if missing kClose_Verb is output ##
Cary Clarkce101242017-09-01 15:51:02 -04005055#Param dumpAsHex true if SkScalar values are written as hexadecimal ##
Cary Clark73fa9722017-08-29 17:36:51 -04005056
5057#Example
5058 SkPath path;
5059 path.quadTo(20, 30, 40, 50);
5060 for (bool forceClose : { false, true } ) {
5061 for (bool dumpAsHex : { false, true } ) {
5062 path.dump(nullptr, forceClose, dumpAsHex);
5063 SkDebugf("\n");
5064 }
5065 }
5066#StdOut
5067path.setFillType(SkPath::kWinding_FillType);
5068path.moveTo(0, 0);
5069path.quadTo(20, 30, 40, 50);
5070
5071path.setFillType(SkPath::kWinding_FillType);
5072path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5073path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5074
5075path.setFillType(SkPath::kWinding_FillType);
5076path.moveTo(0, 0);
5077path.quadTo(20, 30, 40, 50);
5078path.lineTo(0, 0);
5079path.close();
5080
5081path.setFillType(SkPath::kWinding_FillType);
5082path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5083path.quadTo(SkBits2Float(0x41a00000), SkBits2Float(0x41f00000), SkBits2Float(0x42200000), SkBits2Float(0x42480000)); // 20, 30, 40, 50
5084path.lineTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5085path.close();
5086##
5087##
5088
5089#SeeAlso SkRect::dump() SkRRect::dump() SkPathMeasure::dump()
5090
5091##
5092
5093# ------------------------------------------------------------------------------
5094
5095#Method void dump() const
5096
Cary Clarkce101242017-09-01 15:51:02 -04005097Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005098directly compiled as C++ code. Floating point values are written
5099with limited precision; it may not be possible to reconstruct original Path
5100from output.
5101
5102#Example
5103SkPath path, copy;
5104path.lineTo(6.f / 7, 2.f / 3);
5105path.dump();
5106copy.setFillType(SkPath::kWinding_FillType);
5107copy.moveTo(0, 0);
5108copy.lineTo(0.857143f, 0.666667f);
5109SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5110#StdOut
5111path.setFillType(SkPath::kWinding_FillType);
5112path.moveTo(0, 0);
5113path.lineTo(0.857143f, 0.666667f);
5114path is not equal to copy
5115##
5116##
5117
5118#SeeAlso dumpHex SkRect::dump() SkRRect::dump() SkPathMeasure::dump() writeToMemory
5119
5120##
5121
5122# ------------------------------------------------------------------------------
5123
5124#Method void dumpHex() const
5125
Cary Clarkce101242017-09-01 15:51:02 -04005126Writes text representation of Path to standard output. The representation may be
Cary Clark73fa9722017-08-29 17:36:51 -04005127directly compiled as C++ code. Floating point values are written
5128in hexadecimal to preserve their exact bit pattern. The output reconstructs the
5129original Path.
5130
Cary Clark6fc50412017-09-21 12:31:06 -04005131Use instead of dump() when submitting
5132#A bug reports against Skia # http://bug.skia.org ##
5133.
Cary Clark73fa9722017-08-29 17:36:51 -04005134
5135#Example
5136SkPath path, copy;
5137path.lineTo(6.f / 7, 2.f / 3);
5138path.dumpHex();
5139copy.setFillType(SkPath::kWinding_FillType);
5140copy.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5141copy.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5142SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5143#StdOut
5144path.setFillType(SkPath::kWinding_FillType);
5145path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
5146path.lineTo(SkBits2Float(0x3f5b6db7), SkBits2Float(0x3f2aaaab)); // 0.857143f, 0.666667f
5147path is equal to copy
5148##
5149##
5150
5151#SeeAlso dump SkRect::dumpHex() SkRRect::dumpHex() writeToMemory
5152
5153##
5154
5155# ------------------------------------------------------------------------------
5156
5157#Method size_t writeToMemory(void* buffer) const
5158
5159Writes Path to buffer, returning the number of bytes written.
5160Pass nullptr to obtain the storage size.
5161
5162Writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5163additionally writes computed information like Convexity and bounds.
5164
5165Use only be used in concert with readFromMemory;
5166the format used for Path in memory is not guaranteed.
5167
5168#Param buffer storage for Path; may be nullptr ##
5169
5170#Return size of storage required for Path; always a multiple of 4 ##
5171
5172#Example
5173void draw(SkCanvas* canvas) {
5174 SkPath path, copy;
5175 path.lineTo(6.f / 7, 2.f / 3);
5176 size_t size = path.writeToMemory(nullptr);
5177 SkTDArray<char> storage;
5178 storage.setCount(size);
5179 path.writeToMemory(storage.begin());
5180 copy.readFromMemory(storage.begin(), size);
5181 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5182}
5183#StdOut
5184path is equal to copy
5185##
5186##
5187
5188#SeeAlso serialize readFromMemory dump dumpHex
5189
5190##
5191
5192#Method sk_sp<SkData> serialize() const
5193
5194Write Path to buffer, returning the buffer written to, wrapped in Data.
5195
5196serialize() writes Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5197additionally writes computed information like Convexity and bounds.
5198
5199serialize() should only be used in concert with readFromMemory.
5200The format used for Path in memory is not guaranteed.
5201
5202#Return Path data wrapped in Data buffer ##
5203
5204#Example
5205void draw(SkCanvas* canvas) {
5206 SkPath path, copy;
5207 path.lineTo(6.f / 7, 2.f / 3);
5208 sk_sp<SkData> data = path.serialize();
5209 copy.readFromMemory(data->data(), data->size());
5210 SkDebugf("path is " "%s" "equal to copy\n", path == copy ? "" : "not ");
5211}
5212#StdOut
5213path is equal to copy
5214##
5215##
5216
5217#SeeAlso writeToMemory readFromMemory dump dumpHex
5218##
5219
5220# ------------------------------------------------------------------------------
5221
5222#Method size_t readFromMemory(const void* buffer, size_t length)
5223
5224Initializes Path from buffer of size length. Returns zero if the buffer is
5225data is inconsistent, or the length is too small.
5226
5227Reads Fill_Type, Verb_Array, Point_Array, Conic_Weight, and
5228additionally reads computed information like Convexity and bounds.
5229
5230Used only in concert with writeToMemory;
5231the format used for Path in memory is not guaranteed.
5232
5233#Param buffer storage for Path ##
5234#Param length buffer size in bytes; must be multiple of 4 ##
5235
5236#Return number of bytes read, or zero on failure ##
5237
5238#Example
5239void draw(SkCanvas* canvas) {
5240 SkPath path, copy;
5241 path.lineTo(6.f / 7, 2.f / 3);
5242 size_t size = path.writeToMemory(nullptr);
5243 SkTDArray<char> storage;
5244 storage.setCount(size);
5245 path.writeToMemory(storage.begin());
5246 size_t wrongSize = size - 4;
5247 size_t bytesRead = copy.readFromMemory(storage.begin(), wrongSize);
5248 SkDebugf("length = %u; returned by readFromMemory = %u\n", wrongSize, bytesRead);
5249 size_t largerSize = size + 4;
5250 bytesRead = copy.readFromMemory(storage.begin(), largerSize);
5251 SkDebugf("length = %u; returned by readFromMemory = %u\n", largerSize, bytesRead);
5252}
5253#StdOut
5254length = 60; returned by readFromMemory = 0
5255length = 68; returned by readFromMemory = 64
5256##
5257##
5258
5259#SeeAlso writeToMemory
5260
5261##
5262
5263# ------------------------------------------------------------------------------
5264#Topic Generation_ID
5265#Alias Generation_IDs
5266
5267Generation_ID provides a quick way to check if Verb_Array, Point_Array, or
5268Conic_Weight has changed. Generation_ID is not a hash; identical Paths will
5269not necessarily have matching Generation_IDs.
5270
5271Empty Paths have a Generation_ID of one.
5272
5273#Method uint32_t getGenerationID() const
5274
5275Returns a non-zero, globally unique value. A different value is returned
5276if Verb_Array, Point_Array, or Conic_Weight changes.
5277
5278Setting Fill_Type does not change Generation_ID.
5279
5280Each time the path is modified, a different Generation_ID will be returned.
5281
5282#Bug 1762
5283Fill_Type does affect Generation_ID on Android framework.
5284##
5285
5286#Return non-zero, globally unique value ##
5287
5288#Example
5289SkPath path;
5290SkDebugf("empty genID = %u\n", path.getGenerationID());
5291path.lineTo(1, 2);
5292SkDebugf("1st lineTo genID = %u\n", path.getGenerationID());
5293path.rewind();
5294SkDebugf("empty genID = %u\n", path.getGenerationID());
5295path.lineTo(1, 2);
5296SkDebugf("2nd lineTo genID = %u\n", path.getGenerationID());
5297#StdOut
5298empty genID = 1
52991st lineTo genID = 2
5300empty genID = 1
53012nd lineTo genID = 3
5302##
5303##
5304
5305#SeeAlso operator==(const SkPath& a, const SkPath& b)
5306
5307##
5308
5309#Topic ##
5310
5311# ------------------------------------------------------------------------------
5312
5313#Method bool isValid() const
5314
5315 Returns if Path data is consistent. Corrupt Path data is detected if
5316 internal values are out of range or internal storage does not match
5317 array dimensions.
5318
5319 #Return true if Path data is consistent ##
5320
5321 #NoExample
5322 ##
5323
5324##
5325
5326#Method bool pathRefIsValid() const
5327
5328 Returns if Path data is consistent.
5329
5330 #Deprecated
5331 To be deprecated soon.
5332 ##
5333
5334 #Return true if Path data is consistent ##
5335
5336 #NoExample
5337 ##
5338##
5339
5340# ------------------------------------------------------------------------------
5341
Cary Clark8032b982017-07-28 11:04:54 -04005342#Class Iter
5343
5344Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5345Provides options to treat open Contours as closed, and to ignore
5346degenerate data.
5347
Cary Clark73fa9722017-08-29 17:36:51 -04005348#Code
5349class Iter {
5350public:
5351 Iter();
5352 Iter(const SkPath& path, bool forceClose);
5353 void setPath(const SkPath& path, bool forceClose);
5354 Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
5355 SkScalar conicWeight() const;
5356 bool isCloseLine() const;
5357 bool isClosedContour() const;
5358};
5359##
5360
Cary Clark8032b982017-07-28 11:04:54 -04005361#Example
5362#Height 128
5363#Description
Cary Clark73fa9722017-08-29 17:36:51 -04005364Ignoring the actual Verbs and replacing them with Quads rounds the
Cary Clark8032b982017-07-28 11:04:54 -04005365path of the glyph.
5366##
Cary Clark73fa9722017-08-29 17:36:51 -04005367void draw(SkCanvas* canvas) {
5368 SkPaint paint;
5369 paint.setAntiAlias(true);
5370 paint.setTextSize(256);
5371 SkPath asterisk, path;
5372 paint.getTextPath("*", 1, 50, 192, &asterisk);
5373 SkPath::Iter iter(asterisk, true);
5374 SkPoint start[4], pts[4];
5375 iter.next(start); // skip moveTo
5376 iter.next(start); // first quadTo
5377 path.moveTo((start[0] + start[1]) * 0.5f);
5378 while (SkPath::kClose_Verb != iter.next(pts)) {
5379 path.quadTo(pts[0], (pts[0] + pts[1]) * 0.5f);
5380 }
5381 path.quadTo(start[0], (start[0] + start[1]) * 0.5f);
5382 canvas->drawPath(path, paint);
Cary Clark8032b982017-07-28 11:04:54 -04005383}
5384##
5385
5386#SeeAlso RawIter
5387
5388#Method Iter()
5389
5390Initializes Iter with an empty Path. next() on Iter returns kDone_Verb.
5391Call setPath to initialize Iter at a later time.
5392
Cary Clark73fa9722017-08-29 17:36:51 -04005393#Return Iter of empty Path ##
Cary Clark8032b982017-07-28 11:04:54 -04005394
5395#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005396void draw(SkCanvas* canvas) {
5397 SkPath::Iter iter;
5398 SkPoint points[4];
5399 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
5400 SkPath path;
5401 iter.setPath(path, false);
5402 SkDebugf("iter is " "%s" "done\n", SkPath::kDone_Verb == iter.next(points) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005403}
Cary Clark73fa9722017-08-29 17:36:51 -04005404#StdOut
5405iter is done
5406iter is done
5407##
Cary Clark8032b982017-07-28 11:04:54 -04005408##
5409
5410#SeeAlso setPath
5411
5412##
5413
5414#Method Iter(const SkPath& path, bool forceClose)
5415
5416Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5417If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5418open Contour. path is not altered.
5419
Cary Clark73fa9722017-08-29 17:36:51 -04005420#Param path Path to iterate ##
5421#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005422
Cary Clark73fa9722017-08-29 17:36:51 -04005423#Return Iter of path ##
Cary Clark8032b982017-07-28 11:04:54 -04005424
5425#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005426void draw(SkCanvas* canvas) {
5427 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5428 SkDebugf("%s:\n", prefix);
5429 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5430 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5431 SkPath::Verb verb;
5432 do {
5433 SkPoint points[4];
5434 verb = iter.next(points);
5435 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5436 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5437 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5438 }
5439 if (SkPath::kConic_Verb == verb) {
5440 SkDebugf("weight = %g", iter.conicWeight());
5441 }
5442 SkDebugf("\n");
5443 } while (SkPath::kDone_Verb != verb);
5444 SkDebugf("\n");
5445 };
5446
5447 SkPath path;
5448 path.quadTo(10, 20, 30, 40);
5449 SkPath::Iter openIter(path, false);
5450 debugster("open", openIter);
5451 SkPath::Iter closedIter(path, true);
5452 debugster("closed", closedIter);
Cary Clark8032b982017-07-28 11:04:54 -04005453}
5454#StdOut
5455open:
Cary Clark73fa9722017-08-29 17:36:51 -04005456kMove_Verb {0, 0},
5457kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5458kDone_Verb
5459
5460closed:
5461kMove_Verb {0, 0},
5462kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5463kLine_Verb {30, 40}, {0, 0},
5464kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005465kDone_Verb
5466##
5467##
5468
5469#SeeAlso setPath
5470
5471##
5472
5473#Method void setPath(const SkPath& path, bool forceClose)
5474
5475Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5476If forceClose is true, Iter will add kLine_Verb and kClose_Verb after each
5477open Contour. path is not altered.
5478
Cary Clark73fa9722017-08-29 17:36:51 -04005479#Param path Path to iterate ##
5480#Param forceClose true if open Contours generate kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005481
5482#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005483void draw(SkCanvas* canvas) {
5484 auto debugster = [](const char* prefix, SkPath::Iter& iter) -> void {
5485 SkDebugf("%s:\n", prefix);
5486 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5487 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5488 SkPath::Verb verb;
5489 do {
5490 SkPoint points[4];
5491 verb = iter.next(points);
5492 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5493 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5494 SkDebugf("{%g, %g}, ", points[i].fX, points[i].fY);
5495 }
5496 if (SkPath::kConic_Verb == verb) {
5497 SkDebugf("weight = %g", iter.conicWeight());
5498 }
5499 SkDebugf("\n");
5500 } while (SkPath::kDone_Verb != verb);
5501 SkDebugf("\n");
5502 };
5503
5504 SkPath path;
5505 path.quadTo(10, 20, 30, 40);
5506 SkPath::Iter iter(path, false);
5507 debugster("quad open", iter);
5508 SkPath path2;
5509 path2.conicTo(1, 2, 3, 4, .5f);
5510 iter.setPath(path2, true);
5511 debugster("conic closed", iter);
Cary Clark8032b982017-07-28 11:04:54 -04005512}
5513#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005514quad open:
5515kMove_Verb {0, 0},
5516kQuad_Verb {0, 0}, {10, 20}, {30, 40},
5517kDone_Verb
5518
5519conic closed:
5520kMove_Verb {0, 0},
5521kConic_Verb {0, 0}, {1, 2}, {3, 4}, weight = 0.5
5522kLine_Verb {3, 4}, {0, 0},
5523kClose_Verb {0, 0},
Cary Clark8032b982017-07-28 11:04:54 -04005524kDone_Verb
5525##
5526##
5527
5528#SeeAlso Iter(const SkPath& path, bool forceClose)
5529
5530##
5531
5532#Method Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false)
5533
Cary Clarka523d2d2017-08-30 08:58:10 -04005534Returns next Verb in Verb_Array, and advances Iter.
5535When Verb_Array is exhausted, returns kDone_Verb.
5536
Cary Clark8032b982017-07-28 11:04:54 -04005537Zero to four Points are stored in pts, depending on the returned Verb.
Cary Clarka523d2d2017-08-30 08:58:10 -04005538
Cary Clark8032b982017-07-28 11:04:54 -04005539If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
5540only the last in the series; and skip very small Lines, Quads, and Conics; and
5541skip kClose_Verb following kMove_Verb.
5542if doConsumeDegenerates is true and exact is true, only skip Lines, Quads, and
5543Conics with zero lengths.
5544
Cary Clarka523d2d2017-08-30 08:58:10 -04005545 #Param pts storage for Point data describing returned Verb ##
5546 #Param doConsumeDegenerates if true, skip degenerate Verbs ##
5547 #Param exact skip zero length curves ##
Cary Clark8032b982017-07-28 11:04:54 -04005548
Cary Clark73fa9722017-08-29 17:36:51 -04005549 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005550
5551#Example
5552#Description
5553skip degenerate skips the first in a kMove_Verb pair, the kMove_Verb
5554followed by the kClose_Verb, the zero length Line and the very small Line.
5555
5556skip degenerate if exact skips the same as skip degenerate, but shows
5557the very small Line.
5558
5559skip none shows all of the Verbs and Points in Path.
5560##
Cary Clark73fa9722017-08-29 17:36:51 -04005561void draw(SkCanvas* canvas) {
5562 auto debugster = [](const char* prefix, const SkPath& path, bool degen, bool exact) -> void {
5563 SkPath::Iter iter(path, false);
5564 SkDebugf("%s:\n", prefix);
5565 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5566 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5567 SkPath::Verb verb;
5568 do {
5569 SkPoint points[4];
5570 verb = iter.next(points, degen, exact);
5571 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5572 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5573 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5574 }
5575 SkDebugf("\n");
5576 } while (SkPath::kDone_Verb != verb);
5577 SkDebugf("\n");
5578 };
5579
5580 SkPath path;
5581 path.moveTo(10, 10);
5582 path.moveTo(20, 20);
5583 path.quadTo(10, 20, 30, 40);
5584 path.moveTo(1, 1);
5585 path.close();
5586 path.moveTo(30, 30);
5587 path.lineTo(30, 30);
5588 path.moveTo(30, 30);
5589 path.lineTo(30.00001f, 30);
5590 debugster("skip degenerate", path, true, false);
5591 debugster("skip degenerate if exact", path, true, true);
5592 debugster("skip none", path, false, false);
Cary Clark8032b982017-07-28 11:04:54 -04005593}
5594#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005595skip degenerate:
5596kMove_Verb {20, 20},
5597kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5598kDone_Verb
5599
5600skip degenerate if exact:
5601kMove_Verb {20, 20},
5602kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5603kMove_Verb {30, 30},
5604kLine_Verb {30, 30}, {30.00001, 30},
5605kDone_Verb
5606
5607skip none:
5608kMove_Verb {10, 10},
5609kMove_Verb {20, 20},
5610kQuad_Verb {20, 20}, {10, 20}, {30, 40},
5611kMove_Verb {1, 1},
5612kClose_Verb {1, 1},
5613kMove_Verb {30, 30},
5614kLine_Verb {30, 30}, {30, 30},
5615kMove_Verb {30, 30},
5616kLine_Verb {30, 30}, {30.00001, 30},
5617kDone_Verb
Cary Clark8032b982017-07-28 11:04:54 -04005618##
5619##
5620
5621#SeeAlso Verb IsLineDegenerate IsCubicDegenerate IsQuadDegenerate
5622
5623##
5624
5625#Method SkScalar conicWeight() const
5626
5627 Returns Conic_Weight if next() returned kConic_Verb.
5628
5629 If next() has not been called, or next() did not return kConic_Verb,
5630 result is undefined.
5631
Cary Clark73fa9722017-08-29 17:36:51 -04005632 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005633
5634 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005635 void draw(SkCanvas* canvas) {
5636 SkPath path;
5637 path.conicTo(1, 2, 3, 4, .5f);
5638 SkPath::Iter iter(path, false);
5639 SkPoint p[4];
5640 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5641 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5642 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5643 p[2].fX, p[2].fY);
5644 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005645 }
5646 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005647first verb is move
5648next verb is conic
5649conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005650conic weight: 0.5
5651 ##
5652 ##
5653
5654 #SeeAlso Conic_Weight
5655
5656##
5657
5658#Method bool isCloseLine() const
5659
5660 Returns true if last kLine_Verb returned by next() was generated
5661 by kClose_Verb. When true, the end point returned by next() is
5662 also the start point of Contour.
5663
5664 If next() has not been called, or next() did not return kLine_Verb,
5665 result is undefined.
5666
Cary Clark73fa9722017-08-29 17:36:51 -04005667 #Return true if last kLine_Verb was generated by kClose_Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005668
5669 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005670void draw(SkCanvas* canvas) {
5671 SkPath path;
5672 path.moveTo(6, 7);
5673 path.conicTo(1, 2, 3, 4, .5f);
5674 path.close();
5675 SkPath::Iter iter(path, false);
5676 SkPoint p[4];
5677 SkDebugf("1st verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5678 SkDebugf("moveTo point: {%g,%g}\n", p[0].fX, p[0].fY);
5679 SkDebugf("2nd verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5680 SkDebugf("3rd verb is " "%s" "line\n", SkPath::kLine_Verb == iter.next(p) ? "" : "not ");
5681 SkDebugf("line points: {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY);
5682 SkDebugf("line " "%s" "generated by close\n", iter.isCloseLine() ? "" : "not ");
5683 SkDebugf("4th verb is " "%s" "close\n", SkPath::kClose_Verb == iter.next(p) ? "" : "not ");
Cary Clark8032b982017-07-28 11:04:54 -04005684}
5685 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -040056861st verb is move
5687moveTo point: {6,7}
56882nd verb is conic
56893rd verb is line
5690line points: {3,4}, {6,7}
5691line generated by close
Cary Clark8032b982017-07-28 11:04:54 -040056924th verb is close
5693 ##
5694 ##
5695
5696 #SeeAlso close()
5697##
5698
5699#Method bool isClosedContour() const
5700
5701Returns true if subsequent calls to next() return kClose_Verb before returning
5702kMove_Verb. if true, Contour Iter is processing may end with kClose_Verb, or
5703Iter may have been initialized with force close set to true.
5704
Cary Clark73fa9722017-08-29 17:36:51 -04005705#Return true if Contour is closed ##
Cary Clark8032b982017-07-28 11:04:54 -04005706
5707#Example
Cary Clark73fa9722017-08-29 17:36:51 -04005708void draw(SkCanvas* canvas) {
5709 for (bool forceClose : { false, true } ) {
5710 SkPath path;
5711 path.conicTo(1, 2, 3, 4, .5f);
5712 SkPath::Iter iter(path, forceClose);
5713 SkDebugf("without close(), forceClose is %s: isClosedContour returns %s\n",
5714 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5715 path.close();
5716 iter.setPath(path, forceClose);
5717 SkDebugf("with close(), forceClose is %s: isClosedContour returns %s\n",
5718 forceClose ? "true " : "false", iter.isClosedContour() ? "true" : "false");
5719 }
Cary Clark8032b982017-07-28 11:04:54 -04005720}
5721#StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005722without close(), forceClose is false: isClosedContour returns false
5723with close(), forceClose is false: isClosedContour returns true
5724without close(), forceClose is true : isClosedContour returns true
Cary Clark8032b982017-07-28 11:04:54 -04005725with close(), forceClose is true : isClosedContour returns true
5726##
5727##
5728
5729#SeeAlso Iter(const SkPath& path, bool forceClose)
5730
5731##
Cary Clark73fa9722017-08-29 17:36:51 -04005732
5733#Class Iter ##
5734
Cary Clark8032b982017-07-28 11:04:54 -04005735#Class RawIter
5736
5737Iterates through Verb_Array, and associated Point_Array and Conic_Weight.
5738Verb_Array, Point_Array, and Conic_Weight are returned unaltered.
5739
Cary Clark73fa9722017-08-29 17:36:51 -04005740#Code
5741 class RawIter {
5742 public:
5743 RawIter();
5744 RawIter(const SkPath& path);
5745 void setPath(const SkPath& path);
5746 Verb next(SkPoint pts[4]);
5747 Verb peek() const;
5748 SkScalar conicWeight() const;
5749 }
5750##
5751
Cary Clark8032b982017-07-28 11:04:54 -04005752 #Method RawIter()
5753
5754 Initializes RawIter with an empty Path. next() on RawIter returns kDone_Verb.
5755 Call setPath to initialize Iter at a later time.
5756
Cary Clark73fa9722017-08-29 17:36:51 -04005757 #Return RawIter of empty Path ##
5758
5759 #NoExample
5760 ##
5761 ##
Cary Clark8032b982017-07-28 11:04:54 -04005762
5763 #Method RawIter(const SkPath& path)
5764
5765
5766 Sets RawIter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5767
Cary Clark73fa9722017-08-29 17:36:51 -04005768 #Param path Path to iterate ##
Cary Clark8032b982017-07-28 11:04:54 -04005769
Cary Clark73fa9722017-08-29 17:36:51 -04005770 #Return RawIter of path ##
5771
5772 #NoExample
5773 ##
5774 ##
Cary Clark8032b982017-07-28 11:04:54 -04005775
5776 #Method void setPath(const SkPath& path)
5777
5778 Sets Iter to return elements of Verb_Array, Point_Array, and Conic_Weight in path.
5779
Cary Clark73fa9722017-08-29 17:36:51 -04005780 #Param path Path to iterate ##
5781
5782 #NoExample
5783 ##
5784 ##
Cary Clark8032b982017-07-28 11:04:54 -04005785
5786 #Method Verb next(SkPoint pts[4])
5787
5788 Returns next Verb in Verb_Array, and advances RawIter.
5789 When Verb_Array is exhausted, returns kDone_Verb.
5790 Zero to four Points are stored in pts, depending on the returned Verb.
5791
Cary Clarka523d2d2017-08-30 08:58:10 -04005792 #Param pts storage for Point data describing returned Verb ##
Cary Clark8032b982017-07-28 11:04:54 -04005793
Cary Clark73fa9722017-08-29 17:36:51 -04005794 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005795
5796 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005797 void draw(SkCanvas* canvas) {
5798 SkPath path;
5799 path.moveTo(50, 60);
5800 path.quadTo(10, 20, 30, 40);
5801 path.close();
5802 path.lineTo(30, 30);
5803 path.conicTo(1, 2, 3, 4, .5f);
5804 path.cubicTo(-1, -2, -3, -4, -5, -6);
5805 SkPath::RawIter iter(path);
5806 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5807 const int pointCount[] = { 1 , 2 , 3 , 3 , 4 , 1 , 0 };
5808 SkPath::Verb verb;
5809 do {
5810 SkPoint points[4];
5811 verb = iter.next(points);
5812 SkDebugf("k%s_Verb ", verbStr[(int) verb]);
5813 for (int i = 0; i < pointCount[(int) verb]; ++i) {
5814 SkDebugf("{%1.8g, %1.8g}, ", points[i].fX, points[i].fY);
5815 }
5816 if (SkPath::kConic_Verb == verb) {
5817 SkDebugf("weight = %g", iter.conicWeight());
5818 }
5819 SkDebugf("\n");
5820 } while (SkPath::kDone_Verb != verb);
Cary Clark8032b982017-07-28 11:04:54 -04005821 }
5822 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005823 kMove_Verb {50, 60},
5824 kQuad_Verb {50, 60}, {10, 20}, {30, 40},
5825 kClose_Verb {50, 60},
5826 kMove_Verb {50, 60},
5827 kLine_Verb {50, 60}, {30, 30},
5828 kConic_Verb {30, 30}, {1, 2}, {3, 4}, weight = 0.5
5829 kCubic_Verb {3, 4}, {-1, -2}, {-3, -4}, {-5, -6},
Cary Clark8032b982017-07-28 11:04:54 -04005830 kDone_Verb
5831 ##
5832 ##
5833
5834 #SeeAlso peek()
5835
Cary Clark73fa9722017-08-29 17:36:51 -04005836 ##
Cary Clark8032b982017-07-28 11:04:54 -04005837
5838 #Method Verb peek() const
5839
5840 Returns next Verb, but does not advance RawIter.
5841
Cary Clark73fa9722017-08-29 17:36:51 -04005842 #Return next Verb from Verb_Array ##
Cary Clark8032b982017-07-28 11:04:54 -04005843
5844 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005845 SkPath path;
5846 path.quadTo(10, 20, 30, 40);
5847 path.conicTo(1, 2, 3, 4, .5f);
5848 path.cubicTo(1, 2, 3, 4, .5, 6);
5849 SkPath::RawIter iter(path);
5850 SkPath::Verb verb, peek = iter.peek();
5851 const char* verbStr[] = { "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done" };
5852 do {
5853 SkPoint points[4];
5854 verb = iter.next(points);
5855 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5856 peek = iter.peek();
Cary Clark8032b982017-07-28 11:04:54 -04005857 } while (SkPath::kDone_Verb != verb);
Cary Clark73fa9722017-08-29 17:36:51 -04005858 SkDebugf("peek %s %c= verb %s\n", verbStr[peek], peek == verb ? '=' : '!', verbStr[verb]);
5859 #StdOut
5860 #Volatile
5861 peek Move == verb Move
5862 peek Quad == verb Quad
5863 peek Conic == verb Conic
5864 peek Cubic == verb Cubic
5865 peek Done == verb Done
5866 peek Done == verb Done
5867 ##
Cary Clark8032b982017-07-28 11:04:54 -04005868 ##
5869
5870 #Bug 6832
5871 StdOut isn't really volatile, it just produces the wrong result.
5872 A simple fix changes the output of hairlines and needs to be
5873 investigated to see if the change is correct or not.
5874 https://skia-review.googlesource.com/c/21340/
5875 ##
5876
5877 #SeeAlso next()
5878
Cary Clark73fa9722017-08-29 17:36:51 -04005879 ##
Cary Clark8032b982017-07-28 11:04:54 -04005880
Cary Clark73fa9722017-08-29 17:36:51 -04005881 #Method SkScalar conicWeight() const
5882
Cary Clark8032b982017-07-28 11:04:54 -04005883 Returns Conic_Weight if next() returned kConic_Verb.
5884
5885 If next() has not been called, or next() did not return kConic_Verb,
5886 result is undefined.
Cary Clark73fa9722017-08-29 17:36:51 -04005887
5888 #Return Conic_Weight for Conic Points returned by next() ##
Cary Clark8032b982017-07-28 11:04:54 -04005889
5890 #Example
Cary Clark73fa9722017-08-29 17:36:51 -04005891 void draw(SkCanvas* canvas) {
5892 SkPath path;
5893 path.conicTo(1, 2, 3, 4, .5f);
5894 SkPath::RawIter iter(path);
5895 SkPoint p[4];
5896 SkDebugf("first verb is " "%s" "move\n", SkPath::kMove_Verb == iter.next(p) ? "" : "not ");
5897 SkDebugf("next verb is " "%s" "conic\n", SkPath::kConic_Verb == iter.next(p) ? "" : "not ");
5898 SkDebugf("conic points: {%g,%g}, {%g,%g}, {%g,%g}\n", p[0].fX, p[0].fY, p[1].fX, p[1].fY,
5899 p[2].fX, p[2].fY);
5900 SkDebugf("conic weight: %g\n", iter.conicWeight());
Cary Clark8032b982017-07-28 11:04:54 -04005901 }
5902 #StdOut
Cary Clark73fa9722017-08-29 17:36:51 -04005903 first verb is move
5904 next verb is conic
5905 conic points: {0,0}, {1,2}, {3,4}
Cary Clark8032b982017-07-28 11:04:54 -04005906 conic weight: 0.5
5907 ##
5908 ##
5909
5910 #SeeAlso Conic_Weight
Cary Clark73fa9722017-08-29 17:36:51 -04005911
5912 ##
5913
5914#Class RawIter ##
5915
5916#Class SkPath ##
5917
5918#Topic Path ##