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