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