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