1 module skia.SKPath;
2 
3 import skia.Definitions;
4 import skia.Exceptions;
5 import skia.MathTypes;
6 import skia.SKObject;
7 import skia.SkiaApi;
8 import skia.SKRoundRect;
9 import skia.SKMatrix;
10 import skia.SKString;
11 
12 import std.experimental.logger;
13 
14 class SKPath : SKObject, ISKSkipObjectRegistration {
15 	this(void* handle, bool owns) {
16 		super(handle, owns);
17 	}
18 
19 	this() {
20 		this(SkiaApi.sk_path_new(), true);
21 		if (Handle is null) {
22 			throw new InvalidOperationException("Unable to create a new SKPath instance.");
23 		}
24 	}
25 
26 	this(SKPath path) {
27 		this(SkiaApi.sk_path_clone(cast(sk_path_t*) path.Handle), true);
28 		if (Handle is null) {
29 			throw new InvalidOperationException("Unable to copy the SKPath instance.");
30 		}
31 	}
32 
33 	// 	protected override void Dispose (bool disposing)
34 	//   {
35 	//     return super.Dispose (disposing);
36 	//   }
37 
38 	//   override void Dispose()
39 	//   {
40 	//     return super.Dispose();
41 	//   }
42 
43 	protected override void DisposeNative() {
44 		return SkiaApi.sk_path_delete(cast(sk_path_t*) Handle);
45 	}
46 
47 	SKPathFillType FillType() {
48 		return SkiaApi.sk_path_get_filltype(cast(sk_path_t*) Handle);
49 	}
50 
51 	void FillType(SKPathFillType value) {
52 		SkiaApi.sk_path_set_filltype(cast(sk_path_t*) Handle, value);
53 	}
54 
55 	SKPathConvexity Convexity() {
56 		return SkiaApi.sk_path_get_convexity(cast(sk_path_t*) Handle);
57 	}
58 
59 	void Convexity(SKPathConvexity value) {
60 		SkiaApi.sk_path_set_convexity(cast(sk_path_t*) Handle, value);
61 	}
62 
63 	bool IsConcave() {
64 		return Convexity == SKPathConvexity.Concave;
65 	}
66 
67 	bool IsEmpty() {
68 		return VerbCount == 0;
69 	}
70 
71 	bool IsOval() {
72 		return SkiaApi.sk_path_is_oval(cast(sk_path_t*) Handle, null);
73 	}
74 
75 	bool IsRoundRect() {
76 		return SkiaApi.sk_path_is_rrect(cast(sk_path_t*) Handle, null);
77 	}
78 
79 	bool IsLine() {
80 		return SkiaApi.sk_path_is_line(cast(sk_path_t*) Handle, null);
81 	}
82 
83 	bool IsRect() {
84 		return SkiaApi.sk_path_is_rect(cast(sk_path_t*) Handle, null, null, null);
85 	}
86 
87 	SKPathSegmentMask SegmentMasks() {
88 		return cast(SKPathSegmentMask) SkiaApi.sk_path_get_segment_masks(cast(sk_path_t*) Handle);
89 	}
90 
91 	int VerbCount() {
92 		return SkiaApi.sk_path_count_verbs(cast(sk_path_t*) Handle);
93 	}
94 
95 	int PointCount() {
96 		return SkiaApi.sk_path_count_points(cast(sk_path_t*) Handle);
97 	}
98 
99 	// SKPoint this[int index]()
100 	// {
101 	//   return  GetPoint (index);
102 	// }
103 
104 	SKPoint[] Points() {
105 		return GetPoints(PointCount);
106 	}
107 
108 	SKPoint LastPoint() {
109 		SKPoint point;
110 		SkiaApi.sk_path_get_last_point(cast(sk_path_t*) Handle, &point);
111 		return point;
112 	}
113 
114 	SKRect Bounds() {
115 		SKRect rect;
116 		SkiaApi.sk_path_get_bounds(cast(sk_path_t*) Handle, &rect);
117 		return rect;
118 	}
119 
120 	SKRect TightBounds() {
121 		SKRect rect;
122 		if (GetTightBounds(rect)) {
123 			return rect;
124 		} else {
125 			return SKRect.Empty;
126 		}
127 
128 	}
129 
130 	SKRect GetOvalBounds() {
131 		SKRect bounds;
132 		if (SkiaApi.sk_path_is_oval(cast(sk_path_t*) Handle, &bounds)) {
133 			return bounds;
134 		} else {
135 			return SKRect.Empty;
136 		}
137 	}
138 
139 	SKRoundRect GetRoundRect() {
140 		auto rrect = new SKRoundRect();
141 		auto result = SkiaApi.sk_path_is_rrect(cast(sk_path_t*) Handle,
142 				cast(sk_rrect_t*) rrect.Handle);
143 		if (result) {
144 			return rrect;
145 		} else {
146 			rrect.Dispose();
147 			return null;
148 		}
149 	}
150 
151 	SKPoint[] GetLine() {
152 		auto temp = new SKPoint[2];
153 		SKPoint* t = temp.ptr;
154 		{
155 			auto result = SkiaApi.sk_path_is_line(cast(sk_path_t*) Handle, t);
156 			if (result) {
157 				return temp;
158 			} else {
159 				return null;
160 			}
161 		}
162 	}
163 
164 	SKRect GetRect() {
165 		bool isClosed;
166 		SKPathDirection direction;
167 		return GetRect(isClosed, direction);
168 	}
169 
170 	SKRect GetRect(out bool isClosed, out SKPathDirection direction) {
171 		byte c;
172 		SKPathDirection* d = &direction;
173 		{
174 			SKRect rect;
175 			auto result = SkiaApi.sk_path_is_rect(cast(sk_path_t*) Handle,
176 					&rect, cast(bool*)&c, d);
177 			isClosed = c > 0;
178 			if (result) {
179 				return rect;
180 			} else {
181 				return SKRect.Empty;
182 			}
183 		}
184 	}
185 
186 	SKPoint GetPoint(int index) {
187 		if (index < 0 || index >= PointCount)
188 			throw new ArgumentOutOfRangeException(index.stringof);
189 
190 		SKPoint point;
191 		SkiaApi.sk_path_get_point(cast(sk_path_t*) Handle, index, &point);
192 		return point;
193 	}
194 
195 	SKPoint[] GetPoints(int max) {
196 		auto points = new SKPoint[max];
197 		GetPoints(points, max);
198 		return points;
199 	}
200 
201 	int GetPoints(SKPoint[] points, int max) {
202 		SKPoint* p = points.ptr;
203 		return SkiaApi.sk_path_get_points(cast(sk_path_t*) Handle, p, max);
204 	}
205 
206 	bool Contains(float x, float y) {
207 		return SkiaApi.sk_path_contains(cast(sk_path_t*) Handle, x, y);
208 	}
209 
210 	void Offset(SKPoint offset) {
211 		return Offset(offset.X, offset.Y);
212 	}
213 
214 	void Offset(float dx, float dy) {
215 		return Transform(SKMatrix.CreateTranslation(dx, dy));
216 	}
217 
218 	void MoveTo(SKPoint point) {
219 		return SkiaApi.sk_path_move_to(cast(sk_path_t*) Handle, point.X, point.Y);
220 	}
221 
222 	void MoveTo(float x, float y) {
223 		return SkiaApi.sk_path_move_to(cast(sk_path_t*) Handle, x, y);
224 	}
225 
226 	void RMoveTo(SKPoint point) {
227 		return SkiaApi.sk_path_rmove_to(cast(sk_path_t*) Handle, point.X, point.Y);
228 	}
229 
230 	void RMoveTo(float dx, float dy) {
231 		return SkiaApi.sk_path_rmove_to(cast(sk_path_t*) Handle, dx, dy);
232 	}
233 
234 	void LineTo(SKPoint point) {
235 		return SkiaApi.sk_path_line_to(cast(sk_path_t*) Handle, point.X, point.Y);
236 	}
237 
238 	void LineTo(float x, float y) {
239 		return SkiaApi.sk_path_line_to(cast(sk_path_t*) Handle, x, y);
240 	}
241 
242 	void RLineTo(SKPoint point) {
243 		return SkiaApi.sk_path_rline_to(cast(sk_path_t*) Handle, point.X, point.Y);
244 	}
245 
246 	void RLineTo(float dx, float dy) {
247 		return SkiaApi.sk_path_rline_to(cast(sk_path_t*) Handle, dx, dy);
248 	}
249 
250 	void QuadTo(SKPoint point0, SKPoint point1) {
251 		return SkiaApi.sk_path_quad_to(cast(sk_path_t*) Handle, point0.X,
252 				point0.Y, point1.X, point1.Y);
253 	}
254 
255 	void QuadTo(float x0, float y0, float x1, float y1) {
256 		return SkiaApi.sk_path_quad_to(cast(sk_path_t*) Handle, x0, y0, x1, y1);
257 	}
258 
259 	void RQuadTo(SKPoint point0, SKPoint point1) {
260 		return SkiaApi.sk_path_rquad_to(cast(sk_path_t*) Handle, point0.X,
261 				point0.Y, point1.X, point1.Y);
262 	}
263 
264 	void RQuadTo(float dx0, float dy0, float dx1, float dy1) {
265 		return SkiaApi.sk_path_rquad_to(cast(sk_path_t*) Handle, dx0, dy0, dx1, dy1);
266 	}
267 
268 	void ConicTo(SKPoint point0, SKPoint point1, float w) {
269 		return SkiaApi.sk_path_conic_to(cast(sk_path_t*) Handle, point0.X,
270 				point0.Y, point1.X, point1.Y, w);
271 	}
272 
273 	void ConicTo(float x0, float y0, float x1, float y1, float w) {
274 		return SkiaApi.sk_path_conic_to(cast(sk_path_t*) Handle, x0, y0, x1, y1, w);
275 	}
276 
277 	void RConicTo(SKPoint point0, SKPoint point1, float w) {
278 		return SkiaApi.sk_path_rconic_to(cast(sk_path_t*) Handle, point0.X,
279 				point0.Y, point1.X, point1.Y, w);
280 	}
281 
282 	void RConicTo(float dx0, float dy0, float dx1, float dy1, float w) {
283 		return SkiaApi.sk_path_rconic_to(cast(sk_path_t*) Handle, dx0, dy0, dx1, dy1, w);
284 	}
285 
286 	void CubicTo(SKPoint point0, SKPoint point1, SKPoint point2) {
287 		return SkiaApi.sk_path_cubic_to(cast(sk_path_t*) Handle, point0.X,
288 				point0.Y, point1.X, point1.Y, point2.X, point2.Y);
289 	}
290 
291 	void CubicTo(float x0, float y0, float x1, float y1, float x2, float y2) {
292 		return SkiaApi.sk_path_cubic_to(cast(sk_path_t*) Handle, x0, y0, x1, y1, x2, y2);
293 	}
294 
295 	void RCubicTo(SKPoint point0, SKPoint point1, SKPoint point2) {
296 		return SkiaApi.sk_path_rcubic_to(cast(sk_path_t*) Handle, point0.X,
297 				point0.Y, point1.X, point1.Y, point2.X, point2.Y);
298 	}
299 
300 	void RCubicTo(float dx0, float dy0, float dx1, float dy1, float dx2, float dy2) {
301 		return SkiaApi.sk_path_rcubic_to(cast(sk_path_t*) Handle, dx0, dy0, dx1, dy1, dx2, dy2);
302 	}
303 
304 	void ArcTo(SKPoint r, float xAxisRotate, SKPathArcSize largeArc,
305 			SKPathDirection sweep, SKPoint xy) {
306 		return SkiaApi.sk_path_arc_to(cast(sk_path_t*) Handle, r.X, r.Y,
307 				xAxisRotate, largeArc, sweep, xy.X, xy.Y);
308 	}
309 
310 	void ArcTo(float rx, float ry, float xAxisRotate, SKPathArcSize largeArc,
311 			SKPathDirection sweep, float x, float y) {
312 		return SkiaApi.sk_path_arc_to(cast(sk_path_t*) Handle, rx, ry,
313 				xAxisRotate, largeArc, sweep, x, y);
314 	}
315 
316 	void ArcTo(SKRect oval, float startAngle, float sweepAngle, bool forceMoveTo) {
317 		return SkiaApi.sk_path_arc_to_with_oval(cast(sk_path_t*) Handle,
318 				&oval, startAngle, sweepAngle, forceMoveTo);
319 	}
320 
321 	void ArcTo(SKPoint point1, SKPoint point2, float radius) {
322 		return SkiaApi.sk_path_arc_to_with_points(cast(sk_path_t*) Handle,
323 				point1.X, point1.Y, point2.X, point2.Y, radius);
324 	}
325 
326 	void ArcTo(float x1, float y1, float x2, float y2, float radius) {
327 		return SkiaApi.sk_path_arc_to_with_points(cast(sk_path_t*) Handle, x1, y1, x2, y2, radius);
328 	}
329 
330 	void RArcTo(SKPoint r, float xAxisRotate, SKPathArcSize largeArc,
331 			SKPathDirection sweep, SKPoint xy) {
332 		return SkiaApi.sk_path_rarc_to(cast(sk_path_t*) Handle, r.X, r.Y,
333 				xAxisRotate, largeArc, sweep, xy.X, xy.Y);
334 	}
335 
336 	void RArcTo(float rx, float ry, float xAxisRotate, SKPathArcSize largeArc,
337 			SKPathDirection sweep, float x, float y) {
338 		return SkiaApi.sk_path_rarc_to(cast(sk_path_t*) Handle, rx, ry,
339 				xAxisRotate, largeArc, sweep, x, y);
340 	}
341 
342 	void Close() {
343 		return SkiaApi.sk_path_close(cast(sk_path_t*) Handle);
344 	}
345 
346 	void Rewind() {
347 		return SkiaApi.sk_path_rewind(cast(sk_path_t*) Handle);
348 	}
349 
350 	void Reset() {
351 		return SkiaApi.sk_path_reset(cast(sk_path_t*) Handle);
352 	}
353 
354 	void AddRect(SKRect rect, SKPathDirection direction = SKPathDirection.Clockwise) {
355 		return SkiaApi.sk_path_add_rect(cast(sk_path_t*) Handle, &rect, direction);
356 	}
357 
358 	void AddRect(SKRect rect, SKPathDirection direction, uint startIndex) {
359 		if (startIndex > 3)
360 			throw new ArgumentOutOfRangeException(startIndex.stringof,
361 					"Starting index must be in the range of 0..3 (inclusive).");
362 
363 		SkiaApi.sk_path_add_rect_start(cast(sk_path_t*) Handle, &rect, direction, startIndex);
364 	}
365 
366 	void AddRoundRect(SKRoundRect rect, SKPathDirection direction = SKPathDirection.Clockwise) {
367 		if (rect is null)
368 			throw new ArgumentNullException(rect.stringof);
369 		SkiaApi.sk_path_add_rrect(cast(sk_path_t*) Handle,
370 				cast(sk_rrect_t*) rect.Handle, direction);
371 	}
372 
373 	void AddRoundRect(SKRoundRect rect, SKPathDirection direction, uint startIndex) {
374 		if (rect is null)
375 			throw new ArgumentNullException(rect.stringof);
376 		SkiaApi.sk_path_add_rrect_start(cast(sk_path_t*) Handle,
377 				cast(sk_rrect_t*) rect.Handle, direction, startIndex);
378 	}
379 
380 	void AddOval(SKRect rect, SKPathDirection direction = SKPathDirection.Clockwise) {
381 		return SkiaApi.sk_path_add_oval(cast(sk_path_t*) Handle, &rect, direction);
382 	}
383 
384 	void AddArc(SKRect oval, float startAngle, float sweepAngle) {
385 		return SkiaApi.sk_path_add_arc(cast(sk_path_t*) Handle, &oval, startAngle, sweepAngle);
386 	}
387 
388 	bool GetBounds(out SKRect rect) {
389 		auto isEmpty = IsEmpty;
390 		if (isEmpty) {
391 			rect = SKRect.Empty;
392 		} else {
393 			SKRect* r = &rect;
394 			SkiaApi.sk_path_get_bounds(cast(sk_path_t*) Handle, r);
395 		}
396 		return !isEmpty;
397 	}
398 
399 	SKRect ComputeTightBounds() {
400 		SKRect rect;
401 		SkiaApi.sk_path_compute_tight_bounds(cast(sk_path_t*) Handle, &rect);
402 		return rect;
403 	}
404 
405 	void Transform(SKMatrix matrix) {
406 		return SkiaApi.sk_path_transform(cast(sk_path_t*) Handle, &matrix);
407 	}
408 
409 	void Transform(SKMatrix matrix, SKPath destination) {
410 		if (destination is null)
411 			throw new ArgumentNullException(destination.stringof);
412 
413 		SkiaApi.sk_path_transform_to_dest(cast(sk_path_t*) Handle, &matrix,
414 				cast(sk_path_t*) destination.Handle);
415 	}
416 
417 	void AddPath(SKPath other, float dx, float dy, SKPathAddMode mode = SKPathAddMode.Append) {
418 		if (other is null)
419 			throw new ArgumentNullException(other.stringof);
420 
421 		SkiaApi.sk_path_add_path_offset(cast(sk_path_t*) Handle,
422 				cast(sk_path_t*) other.Handle, dx, dy, mode);
423 	}
424 
425 	void AddPath(SKPath other, ref SKMatrix matrix, SKPathAddMode mode = SKPathAddMode.Append) {
426 		if (other is null)
427 			throw new ArgumentNullException(other.stringof);
428 
429 		SKMatrix* m = &matrix;
430 		SkiaApi.sk_path_add_path_matrix(cast(sk_path_t*) Handle,
431 				cast(sk_path_t*) other.Handle, m, mode);
432 	}
433 
434 	void AddPath(SKPath other, SKPathAddMode mode = SKPathAddMode.Append) {
435 		if (other is null)
436 			throw new ArgumentNullException(other.stringof);
437 
438 		SkiaApi.sk_path_add_path(cast(sk_path_t*) Handle, cast(sk_path_t*) other.Handle, mode);
439 	}
440 
441 	void AddPathReverse(SKPath other) {
442 		if (other is null)
443 			throw new ArgumentNullException(other.stringof);
444 
445 		SkiaApi.sk_path_add_path_reverse(cast(sk_path_t*) Handle, cast(sk_path_t*) other.Handle);
446 	}
447 
448 	void AddRoundRect(SKRect rect, float rx, float ry,
449 			SKPathDirection dir = SKPathDirection.Clockwise) {
450 		return SkiaApi.sk_path_add_rounded_rect(cast(sk_path_t*) Handle, &rect, rx, ry, dir);
451 	}
452 
453 	void AddRoundedRect(SKRect rect, float rx, float ry,
454 			SKPathDirection dir = SKPathDirection.Clockwise) {
455 		return AddRoundRect(rect, rx, ry, dir);
456 	}
457 
458 	void AddCircle(float x, float y, float radius, SKPathDirection dir = SKPathDirection.Clockwise) {
459 		return SkiaApi.sk_path_add_circle(cast(sk_path_t*) Handle, x, y, radius, dir);
460 	}
461 
462 	void AddPoly(SKPoint[] points, bool close = true) {
463 		if (points is null)
464 			throw new ArgumentNullException(points.stringof);
465 		SKPoint* p = points.ptr;
466 		SkiaApi.sk_path_add_poly(cast(sk_path_t*) Handle, p, cast(int) points.length, close);
467 	}
468 
469 	Iterator CreateIterator(bool forceClose) {
470 		return new Iterator(this, forceClose);
471 	}
472 
473 	RawIterator CreateRawIterator() {
474 		return new RawIterator(this);
475 	}
476 
477 	bool Op(SKPath other, SKPathOp op, SKPath result) {
478 		if (other is null)
479 			throw new ArgumentNullException(other.stringof);
480 		if (result is null)
481 			throw new ArgumentNullException(result.stringof);
482 
483 		return SkiaApi.sk_pathop_op(cast(sk_path_t*) Handle,
484 				cast(sk_path_t*) other.Handle, op, cast(sk_path_t*) result.Handle);
485 	}
486 
487 	SKPath Op(SKPath other, SKPathOp op) {
488 		auto result = new SKPath();
489 		if (Op(other, op, result)) {
490 			return result;
491 		} else {
492 			result.Dispose();
493 			return null;
494 		}
495 	}
496 
497 	bool Simplify(SKPath result) {
498 		if (result is null)
499 			throw new ArgumentNullException(result.stringof);
500 
501 		return SkiaApi.sk_pathop_simplify(cast(sk_path_t*) Handle, cast(sk_path_t*) result.Handle);
502 	}
503 
504 	SKPath Simplify() {
505 		auto result = new SKPath();
506 		if (Simplify(result)) {
507 			return result;
508 		} else {
509 			result.Dispose();
510 			return null;
511 		}
512 	}
513 
514 	bool GetTightBounds(out SKRect result) {
515 		SKRect* r = &result;
516 		return SkiaApi.sk_pathop_tight_bounds(cast(sk_path_t*) Handle, r);
517 	}
518 
519 	bool ToWinding(SKPath result) {
520 		if (result is null)
521 			throw new ArgumentNullException(result.stringof);
522 
523 		return SkiaApi.sk_pathop_as_winding(cast(sk_path_t*) Handle,
524 				cast(sk_path_t*) result.Handle);
525 	}
526 
527 	SKPath ToWinding() {
528 		SKPath result = new SKPath();
529 		if (ToWinding(result)) {
530 			return result;
531 		} else {
532 			result.Dispose();
533 			return null;
534 		}
535 	}
536 
537 	string ToSvgPathData() {
538 		SKString str = new SKString();
539 		SkiaApi.sk_path_to_svg_string(cast(sk_path_t*) Handle, cast(sk_string_t*) str.Handle);
540 		return cast(string) str;
541 	}
542 
543 	static SKPath ParseSvgPathData(string svgPath) {
544 		auto path = new SKPath();
545 		auto success = SkiaApi.sk_path_parse_svg_string(cast(sk_path_t*) path.Handle, svgPath);
546 		if (!success) {
547 			path.Dispose();
548 			path = null;
549 		}
550 		return path;
551 	}
552 
553 	static SKPoint[] ConvertConicToQuads(SKPoint p0, SKPoint p1, SKPoint p2, float w, int pow2) {
554 		SKPoint[] pts;
555 		ConvertConicToQuads(p0, p1, p2, w, pts, pow2);
556 		return pts;
557 	}
558 
559 	static int ConvertConicToQuads(SKPoint p0, SKPoint p1, SKPoint p2, float w,
560 			out SKPoint[] pts, int pow2) {
561 		auto quadCount = 1 << pow2;
562 		auto ptCount = 2 * quadCount + 1;
563 		pts = new SKPoint[ptCount];
564 		return ConvertConicToQuads(p0, p1, p2, w, pts, pow2);
565 	}
566 
567 	static int ConvertConicToQuads(SKPoint p0, SKPoint p1, SKPoint p2, float w,
568 			SKPoint[] pts, int pow2) {
569 		if (pts is null)
570 			throw new ArgumentNullException(pts.stringof);
571 		SKPoint* ptsptr = pts.ptr;
572 		return SkiaApi.sk_path_convert_conic_to_quads(&p0, &p1, &p2, w, ptsptr, pow2);
573 	}
574 
575 	//
576 
577 	static SKPath GetObject(void* handle, bool owns = true) {
578 		return handle is null ? null : new SKPath(handle, owns);
579 	}
580 
581 	//
582 
583 	class Iterator : SKObject, ISKSkipObjectRegistration {
584 		private const SKPath path;
585 
586 		this(SKPath path, bool forceClose) {
587 			super(SkiaApi.sk_path_create_iter(cast(sk_path_t*) path.Handle, forceClose ? 1 : 0),
588 					true);
589 			this.path = path;
590 		}
591 
592 		protected override void Dispose(bool disposing) {
593 			return super.Dispose(disposing);
594 		}
595 
596 		override void Dispose() {
597 			return super.Dispose();
598 		}
599 
600 		protected override void DisposeNative() {
601 			return SkiaApi.sk_path_iter_destroy(cast(sk_path_iterator_t*) Handle);
602 		}
603 
604 		// [Obsolete ("Use Next(SKPoint[]) instead.")]
605 		SKPathVerb Next(SKPoint[] points, bool doConsumeDegenerates, bool exact) {
606 			return Next(points);
607 		}
608 
609 		SKPathVerb Next(SKPoint[] points) {
610 			if (points is null)
611 				throw new ArgumentNullException(points.stringof);
612 			if (points.length != 4)
613 				throw new ArgumentException("Must be an array of four elements.", points.stringof);
614 
615 			SKPoint* p = points.ptr;
616 			return SkiaApi.sk_path_iter_next(cast(sk_path_iterator_t*) Handle, p);
617 		}
618 
619 		float ConicWeight() {
620 			return SkiaApi.sk_path_iter_conic_weight(cast(sk_path_iterator_t*) Handle);
621 		}
622 
623 		bool IsCloseLine() {
624 			return SkiaApi.sk_path_iter_is_close_line(cast(sk_path_iterator_t*) Handle) != 0;
625 		}
626 
627 		bool IsCloseContour() {
628 			return SkiaApi.sk_path_iter_is_closed_contour(cast(sk_path_iterator_t*) Handle) != 0;
629 		}
630 
631 	}
632 
633 	class RawIterator : SKObject, ISKSkipObjectRegistration {
634 		private const SKPath path;
635 
636 		this(SKPath path) {
637 			super(SkiaApi.sk_path_create_rawiter(cast(sk_path_t*) path.Handle), true);
638 			this.path = path;
639 		}
640 
641 		protected override void Dispose(bool disposing) {
642 			return super.Dispose(disposing);
643 		}
644 
645 		protected override void DisposeNative() {
646 			return SkiaApi.sk_path_rawiter_destroy(cast(sk_path_rawiterator_t*) Handle);
647 		}
648 
649 		SKPathVerb Next(SKPoint[] points) {
650 			if (points is null)
651 				throw new ArgumentNullException(points.stringof);
652 			if (points.length != 4)
653 				throw new ArgumentException("Must be an array of four elements.", points.stringof);
654 			SKPoint* p = points.ptr;
655 			return SkiaApi.sk_path_rawiter_next(cast(sk_path_rawiterator_t*) Handle, p);
656 		}
657 
658 		float ConicWeight() {
659 			return SkiaApi.sk_path_rawiter_conic_weight(cast(sk_path_rawiterator_t*) Handle);
660 		}
661 
662 		SKPathVerb Peek() {
663 			return SkiaApi.sk_path_rawiter_peek(cast(sk_path_rawiterator_t*) Handle);
664 		}
665 
666 	}
667 
668 	class OpBuilder : SKObject, ISKSkipObjectRegistration {
669 		this() {
670 			super(SkiaApi.sk_opbuilder_new(), true);
671 		}
672 
673 		void Add(SKPath path, SKPathOp op) {
674 			return SkiaApi.sk_opbuilder_add(cast(sk_opbuilder_t*) Handle,
675 					cast(sk_path_t*) path.Handle, op);
676 		}
677 
678 		bool Resolve(SKPath result) {
679 			if (result is null)
680 				throw new ArgumentNullException(result.stringof);
681 
682 			return SkiaApi.sk_opbuilder_resolve(cast(sk_opbuilder_t*) Handle,
683 					cast(sk_path_t*) result.Handle);
684 		}
685 
686 		protected override void Dispose(bool disposing) {
687 			return super.Dispose(disposing);
688 		}
689 
690 		protected override void DisposeNative() {
691 			return SkiaApi.sk_opbuilder_destroy(cast(sk_opbuilder_t*) Handle);
692 		}
693 
694 	}
695 }