1 module skia.SKPaint;
2 
3 import skia.SKObject;
4 import skia.SKFont;
5 import skia.SkiaApi;
6 import skia.SKColor;
7 import skia.SKColorF;
8 import skia.SKColorFilter;
9 import skia.SKShader;
10 import skia.SKMaskFilter;
11 import skia.SKColorSpace;
12 import skia.SKImageFilter;
13 import skia.SKTypeface;
14 import skia.Definitions;
15 import skia.SKPath;
16 import skia.MathTypes;
17 import skia.SKPathEffect;
18 import skia.SKTextBlob;
19 import skia.Exceptions;
20 
21 import std.experimental.logger;
22 
23 enum SKPaintHinting {
24 	NoHinting = 0,
25 	Slight = 1,
26 	Normal = 2,
27 	Full = 3,
28 }
29 
30 class SKPaint : SKObject, ISKSkipObjectRegistration {
31 	private SKFont font;
32 
33 	this(void* handle, bool owns) {
34 		super(handle, owns);
35 	}
36 
37 	this() {
38 		this(SkiaApi.sk_compatpaint_new(), true);
39 		if (Handle is null) {
40 			throw new InvalidOperationException("Unable to create a new SKPaint instance.");
41 		}
42 	}
43 
44 	this(SKFont font) {
45 		this(null, true);
46 
47 		if (font is null)
48 			throw new ArgumentNullException(font.stringof);
49 
50 		Handle = SkiaApi.sk_compatpaint_new_with_font(cast(sk_font_t*) font.Handle);
51 
52 		if (Handle is null)
53 			throw new InvalidOperationException("Unable to create a new SKPaint instance.");
54 	}
55 
56 	protected override void Dispose(bool disposing) {
57 		return super.Dispose(disposing);
58 	}
59 
60 	override void Dispose() {
61 		return super.Dispose();
62 	}
63 
64 	protected override void DisposeNative() {
65 		return SkiaApi.sk_compatpaint_delete(cast(sk_compatpaint_t*) Handle);
66 	}
67 
68 	// Reset
69 
70 	void Reset() {
71 		return SkiaApi.sk_compatpaint_reset(cast(sk_compatpaint_t*) Handle);
72 	}
73 
74 	// properties
75 
76 	bool IsAntialias() {
77 		return SkiaApi.sk_paint_is_antialias(cast(sk_paint_t*) Handle);
78 	}
79 
80 	void IsAntialias(bool value) {
81 		SkiaApi.sk_paint_set_antialias(cast(sk_paint_t*) Handle, value);
82 	}
83 
84 	bool IsDither() {
85 		return SkiaApi.sk_paint_is_dither(cast(sk_paint_t*) Handle);
86 	}
87 
88 	void IsDither(bool value) {
89 		SkiaApi.sk_paint_set_dither(cast(sk_paint_t*) Handle, value);
90 	}
91 
92 	bool IsVerticalText() {
93 		return false;
94 	}
95 
96 	bool IsLinearText() {
97 		return GetFont().LinearMetrics;
98 	}
99 
100 	void SubpixelText(bool value) {
101 		GetFont().Subpixel = value;
102 	}
103 
104 	bool LcdRenderText() {
105 		return GetFont().Edging == SKFontEdging.SubpixelAntialias;
106 	}
107 
108 	void LcdRenderText(bool value) {
109 		GetFont().Edging = value ? SKFontEdging.SubpixelAntialias : SKFontEdging.Antialias;
110 	}
111 
112 	bool IsEmbeddedBitmapText() {
113 		return GetFont().EmbeddedBitmaps;
114 	}
115 
116 	void IsEmbeddedBitmapText(bool value) {
117 		GetFont().EmbeddedBitmaps = value;
118 	}
119 
120 	bool IsAutohinted() {
121 		return GetFont().ForceAutoHinting;
122 	}
123 
124 	void IsAutohinted(bool value) {
125 		GetFont().ForceAutoHinting = value;
126 	}
127 
128 	SKPaintHinting HintingLevel() {
129 		return cast(SKPaintHinting) GetFont().Hinting;
130 	}
131 
132 	void HintingLevel(SKPaintHinting value) {
133 		GetFont().Hinting = cast(SKFontHinting) value;
134 	}
135 
136 	bool FakeBoldText() {
137 		return GetFont().Embolden;
138 	}
139 
140 	void FakeBoldText(bool value) {
141 		GetFont().Embolden = value;
142 	}
143 
144 	bool DeviceKerningEnabled() {
145 		return false;
146 	}
147 
148 	bool IsStroke() {
149 		return Style != SKPaintStyle.Fill;
150 	}
151 
152 	void IsStroke(bool value) {
153 		Style = value ? SKPaintStyle.Stroke : SKPaintStyle.Fill;
154 	}
155 
156 	SKPaintStyle Style() {
157 		return SkiaApi.sk_paint_get_style(cast(sk_paint_t*) Handle);
158 	}
159 
160 	void Style(SKPaintStyle value) {
161 		SkiaApi.sk_paint_set_style(cast(sk_paint_t*) Handle, value);
162 	}
163 
164 	SKColor Color() {
165 		return cast(SKColor) SkiaApi.sk_paint_get_color(cast(sk_paint_t*) Handle);
166 	}
167 
168 	void Color(SKColor value) {
169 		SkiaApi.sk_paint_set_color(cast(sk_paint_t*) Handle, cast(uint) value);
170 	}
171 
172 	SKColorF ColorF() {
173 
174 		SKColorF color4f;
175 		SkiaApi.sk_paint_get_color4f(cast(sk_paint_t*) Handle, &color4f);
176 		return color4f;
177 	}
178 
179 	void ColorF(SKColorF value) {
180 
181 		SkiaApi.sk_paint_set_color4f(cast(sk_paint_t*) Handle, &value, null);
182 	}
183 
184 	void SetColor(SKColorF color, SKColorSpace colorspace) {
185 		return SkiaApi.sk_paint_set_color4f(cast(sk_paint_t*) Handle, &color,
186 				cast(sk_colorspace_t*)(colorspace.Handle ? colorspace.Handle : null));
187 	}
188 
189 	float StrokeWidth() {
190 		return SkiaApi.sk_paint_get_stroke_width(cast(sk_paint_t*) Handle);
191 	}
192 
193 	void StrokeWidth(float value) {
194 		SkiaApi.sk_paint_set_stroke_width(cast(sk_paint_t*) Handle, value);
195 	}
196 
197 	float StrokeMiter() {
198 		return SkiaApi.sk_paint_get_stroke_miter(cast(sk_paint_t*) Handle);
199 	}
200 
201 	void StrokeMiter(float value) {
202 		SkiaApi.sk_paint_get_stroke_miter(cast(sk_paint_t*) Handle);
203 	}
204 
205 	SKStrokeCap StrokeCap() {
206 		return SkiaApi.sk_paint_get_stroke_cap(cast(sk_paint_t*) Handle);
207 	}
208 
209 	void StrokeCap(SKStrokeCap value) {
210 		SkiaApi.sk_paint_set_stroke_cap(cast(sk_paint_t*) Handle, value);
211 	}
212 
213 	SKStrokeJoin StrokeJoin() {
214 		return SkiaApi.sk_paint_get_stroke_join(cast(sk_paint_t*) Handle);
215 	}
216 
217 	void StrokeJoin(SKStrokeJoin value) {
218 		SkiaApi.sk_paint_set_stroke_join(cast(sk_paint_t*) Handle, value);
219 	}
220 
221 	SKShader Shader() {
222 		return SKShader.GetObject(SkiaApi.sk_paint_get_shader(cast(sk_paint_t*) Handle));
223 	}
224 
225 	void Shader(SKShader value) {
226 		SkiaApi.sk_paint_set_shader(cast(sk_paint_t*) Handle,
227 				cast(sk_shader_t*)(value is null ? null : value.Handle));
228 	}
229 
230 	SKMaskFilter MaskFilter() {
231 		return SKMaskFilter.GetObject(SkiaApi.sk_paint_get_maskfilter(cast(sk_paint_t*) Handle));
232 	}
233 
234 	void MaskFilter(SKMaskFilter value) {
235 		SkiaApi.sk_paint_set_maskfilter(cast(sk_paint_t*) Handle,
236 				cast(sk_maskfilter_t*)(value is null ? null : value.Handle));
237 	}
238 
239 	SKColorFilter ColorFilter() {
240 		return SKColorFilter.GetObject(SkiaApi.sk_paint_get_colorfilter(cast(sk_paint_t*) Handle));
241 	}
242 
243 	void ColorFilter(SKColorFilter value) {
244 		SkiaApi.sk_paint_set_colorfilter(cast(sk_paint_t*) Handle,
245 				cast(sk_colorfilter_t*)(value is null ? null : value.Handle));
246 	}
247 
248 	SKImageFilter ImageFilter() {
249 		return SKImageFilter.GetObject(SkiaApi.sk_paint_get_imagefilter(cast(sk_paint_t*) Handle));
250 	}
251 
252 	void ImageFilter(SKImageFilter value) {
253 		SkiaApi.sk_paint_set_imagefilter(cast(sk_paint_t*) Handle,
254 				cast(sk_imagefilter_t*)(value is null ? null : value.Handle));
255 	}
256 
257 	SKBlendMode BlendMode() {
258 		return SkiaApi.sk_paint_get_blendmode(cast(sk_paint_t*) Handle);
259 	}
260 
261 	void BlendMode(SKBlendMode value) {
262 		SkiaApi.sk_paint_set_blendmode(cast(sk_paint_t*) Handle, value);
263 	}
264 
265 	SKFilterQuality FilterQuality() {
266 		return SkiaApi.sk_paint_get_filter_quality(cast(sk_paint_t*) Handle);
267 	}
268 
269 	void FilterQuality(SKFilterQuality value) {
270 		SkiaApi.sk_paint_set_filter_quality(cast(sk_paint_t*) Handle, value);
271 	}
272 
273 	SKTypeface Typeface() {
274 		return GetFont().Typeface;
275 	}
276 
277 	void Typeface(SKTypeface value) {
278 		GetFont().Typeface = value;
279 	}
280 
281 	float TextSize() {
282 		return GetFont().Size;
283 	}
284 
285 	void TextSize(float value) {
286 		GetFont().Size = value;
287 	}
288 
289 	SKTextAlign TextAlign() {
290 		return SkiaApi.sk_compatpaint_get_text_align(cast(sk_compatpaint_t*) Handle);
291 
292 	}
293 
294 	void TextAlign(SKTextAlign value) {
295 		SkiaApi.sk_compatpaint_set_text_align(cast(sk_compatpaint_t*) Handle, value);
296 	}
297 
298 	SKTextEncoding TextEncoding() {
299 		return SkiaApi.sk_compatpaint_get_text_encoding(cast(sk_compatpaint_t*) Handle);
300 	}
301 
302 	void TextEncoding(SKTextEncoding value) {
303 
304 		SkiaApi.sk_compatpaint_set_text_encoding(cast(sk_compatpaint_t*) Handle, value);
305 	}
306 
307 	float TextScaleX() {
308 		return GetFont().ScaleX;
309 	}
310 
311 	void TextScaleX(float value) {
312 		GetFont().ScaleX = value;
313 	}
314 
315 	float TextSkewX() {
316 		return GetFont().SkewX;
317 	}
318 
319 	void TextSkewX(float value) {
320 		GetFont().SkewX = value;
321 	}
322 
323 	SKPathEffect PathEffect() {
324 		return SKPathEffect.GetObject(SkiaApi.sk_paint_get_path_effect(cast(sk_paint_t*) Handle));
325 	}
326 
327 	void PathEffect(SKPathEffect value) {
328 		SkiaApi.sk_paint_set_path_effect(cast(sk_paint_t*) Handle,
329 				cast(sk_path_effect_t*)(value is null ? null : value.Handle));
330 	}
331 
332 	// FontSpacing
333 
334 	float FontSpacing() {
335 		return GetFont().Spacing;
336 	}
337 
338 	// FontMetrics
339 
340 	SKFontMetrics FontMetrics() {
341 		return GetFont().Metrics;
342 	}
343 
344 	float GetFontMetrics(out SKFontMetrics metrics) {
345 		return GetFont().GetFontMetrics(metrics);
346 	}
347 
348 	float GetFontMetrics(out SKFontMetrics metrics, float scale) {
349 		return GetFontMetrics(metrics);
350 	}
351 
352 	// Clone
353 
354 	SKPaint Clone() {
355 		return GetObject(SkiaApi.sk_compatpaint_clone(cast(sk_compatpaint_t*) Handle));
356 	}
357 
358 	// MeasureText
359 
360 	float MeasureText(string text) {
361 		return GetFont().MeasureText(text, this);
362 	}
363 
364 	// float MeasureText(const(char)[] text) {
365 	// 	return GetFont().MeasureText(text, this);
366 	// }
367 
368 	float MeasureText(byte[] text) {
369 		return GetFont().MeasureText(text, TextEncoding, this);
370 	}
371 
372 	float MeasureText(const(byte)[] text) {
373 		return GetFont().MeasureText(text, TextEncoding, this);
374 	}
375 
376 	float MeasureText(void* buffer, int length) {
377 		return GetFont().MeasureText(buffer, length, TextEncoding, this);
378 	}
379 
380 	float MeasureText(void* buffer, void* length) {
381 		return GetFont().MeasureText(buffer, cast(int) length, TextEncoding, this);
382 	}
383 
384 	float MeasureText(string text, ref SKRect bounds) {
385 		return GetFont().MeasureText(text, bounds, this);
386 	}
387 
388 	// float MeasureText(const(char)[] text, ref SKRect bounds) {
389 	// 	return GetFont().MeasureText(text, bounds, this);
390 	// }
391 
392 	float MeasureText(byte[] text, ref SKRect bounds) {
393 		return GetFont().MeasureText(text, TextEncoding, bounds, this);
394 	}
395 
396 	float MeasureText(const(byte)[] text, ref SKRect bounds) {
397 		return GetFont().MeasureText(text, TextEncoding, bounds, this);
398 	}
399 
400 	float MeasureText(void* buffer, int length, ref SKRect bounds) {
401 		return GetFont().MeasureText(buffer, length, TextEncoding, bounds, this);
402 	}
403 
404 	float MeasureText(void* buffer, void* length, ref SKRect bounds) {
405 		return GetFont().MeasureText(buffer, cast(int) length, TextEncoding, bounds, this);
406 	}
407 
408 	// BreakText
409 
410 	long BreakText(string text, float maxWidth) {
411 		float measuredWidth;
412 		return GetFont().BreakText(text, maxWidth, measuredWidth, this);
413 	}
414 
415 	long BreakText(string text, float maxWidth, out float measuredWidth) {
416 		return GetFont().BreakText(text, maxWidth, measuredWidth, this);
417 	}
418 
419 	long BreakText(string text, float maxWidth, out float measuredWidth, out string measuredText) {
420 		if (text is null)
421 			throw new ArgumentNullException(text.stringof);
422 
423 		auto charsRead = GetFont().BreakText(text, maxWidth, measuredWidth, this);
424 		if (charsRead == 0) {
425 			measuredText = null;
426 			return 0;
427 		}
428 		if (charsRead == text.length) {
429 			measuredText = text;
430 			return text.length;
431 		}
432 		measuredText = text[0 .. charsRead];
433 		return charsRead;
434 	}
435 
436 	long BreakText(const(char)[] text, float maxWidth) {
437 		float measuredWidth;
438 		return GetFont().BreakText(text, maxWidth, measuredWidth, this);
439 	}
440 
441 	long BreakText(const(char)[] text, float maxWidth, out float measuredWidth) {
442 		return GetFont().BreakText(text, maxWidth, measuredWidth, this);
443 	}
444 
445 	long BreakText(byte[] text, float maxWidth) {
446 		float measuredWidth;
447 		return GetFont().BreakText(text, TextEncoding, maxWidth, measuredWidth, this);
448 	}
449 
450 	long BreakText(byte[] text, float maxWidth, out float measuredWidth) {
451 		return GetFont().BreakText(text, TextEncoding, maxWidth, measuredWidth, this);
452 
453 	}
454 
455 	long BreakText(const(byte)[] text, float maxWidth) {
456 		float measuredWidth;
457 		return GetFont().BreakText(text, TextEncoding, maxWidth, measuredWidth, this);
458 	}
459 
460 	long BreakText(const(byte)[] text, float maxWidth, out float measuredWidth) {
461 		return GetFont().BreakText(text, TextEncoding, maxWidth, measuredWidth, this);
462 	}
463 
464 	long BreakText(void* buffer, int length, float maxWidth) {
465 		float measuredWidth;
466 		return GetFont().BreakText(buffer, length, TextEncoding, maxWidth, measuredWidth, this);
467 	}
468 
469 	long BreakText(void* buffer, int length, float maxWidth, out float measuredWidth) {
470 		return GetFont().BreakText(buffer, length, TextEncoding, maxWidth, measuredWidth, this);
471 	}
472 
473 	long BreakText(void* buffer, void* length, float maxWidth) {
474 		float measuredWidth;
475 		return GetFont().BreakText(buffer, cast(int) length, TextEncoding,
476 				maxWidth, measuredWidth, this);
477 	}
478 
479 	long BreakText(void* buffer, void* length, float maxWidth, out float measuredWidth) {
480 		return GetFont().BreakText(buffer, cast(int) length, TextEncoding,
481 				maxWidth, measuredWidth, this);
482 	}
483 
484 	// GetTextPath
485 
486 	SKPath GetTextPath(string text, float x, float y) {
487 		return GetFont().GetTextPath(text, SKPoint(x, y));
488 	}
489 
490 	SKPath GetTextPath(const(char)[] text, float x, float y) {
491 		return GetFont().GetTextPath(text, SKPoint(x, y));
492 	}
493 
494 	SKPath GetTextPath(byte[] text, float x, float y) {
495 		return GetFont().GetTextPath(text, TextEncoding, SKPoint(x, y));
496 	}
497 
498 	SKPath GetTextPath(const(byte)[] text, float x, float y) {
499 		return GetFont().GetTextPath(text, TextEncoding, SKPoint(x, y));
500 	}
501 
502 	SKPath GetTextPath(void* buffer, int length, float x, float y) {
503 		return GetFont().GetTextPath(buffer, length, TextEncoding, SKPoint(x, y));
504 
505 	}
506 
507 	SKPath GetTextPath(void* buffer, void* length, float x, float y) {
508 		return GetFont().GetTextPath(buffer, cast(int) length, TextEncoding, SKPoint(x, y));
509 	}
510 
511 	SKPath GetTextPath(string text, SKPoint[] points) {
512 		return GetFont().GetTextPath(text, points);
513 	}
514 
515 	SKPath GetTextPath(const(char)[] text, const(SKPoint)[] points) {
516 		return GetFont().GetTextPath(text, points);
517 	}
518 
519 	SKPath GetTextPath(byte[] text, SKPoint[] points) {
520 		return GetFont().GetTextPath(text, TextEncoding, points);
521 	}
522 
523 	SKPath GetTextPath(const(byte)[] text, const(SKPoint)[] points) {
524 		return GetFont().GetTextPath(text, TextEncoding, points);
525 	}
526 
527 	SKPath GetTextPath(void* buffer, int length, SKPoint[] points) {
528 		return GetFont().GetTextPath(buffer, length, TextEncoding, points);
529 	}
530 
531 	SKPath GetTextPath(void* buffer, int length, const(SKPoint)[] points) {
532 		return GetFont().GetTextPath(buffer, length, TextEncoding, points);
533 	}
534 
535 	SKPath GetTextPath(void* buffer, void* length, SKPoint[] points) {
536 		return GetFont().GetTextPath(buffer, cast(int) length, TextEncoding, points);
537 	}
538 
539 	// GetFillPath
540 
541 	SKPath GetFillPath(SKPath src) {
542 		return GetFillPath(src, 1f);
543 	}
544 
545 	SKPath GetFillPath(SKPath src, float resScale) {
546 		auto dst = new SKPath();
547 
548 		if (GetFillPath(src, dst, resScale)) {
549 			return dst;
550 		} else {
551 			dst.Dispose();
552 			return null;
553 		}
554 	}
555 
556 	SKPath GetFillPath(SKPath src, SKRect cullRect) {
557 		return GetFillPath(src, cullRect, 1f);
558 	}
559 
560 	SKPath GetFillPath(SKPath src, SKRect cullRect, float resScale) {
561 		auto dst = new SKPath();
562 
563 		if (GetFillPath(src, dst, cullRect, resScale)) {
564 			return dst;
565 		} else {
566 			dst.Dispose();
567 			return null;
568 		}
569 	}
570 
571 	bool GetFillPath(SKPath src, SKPath dst) {
572 		return GetFillPath(src, dst, 1f);
573 	}
574 
575 	bool GetFillPath(SKPath src, SKPath dst, float resScale) {
576 		if (src is null)
577 			throw new ArgumentNullException(src.stringof);
578 		if (dst is null)
579 			throw new ArgumentNullException(dst.stringof);
580 
581 		return SkiaApi.sk_paint_get_fill_path(cast(sk_paint_t*) Handle,
582 				cast(sk_path_t*) src.Handle, cast(sk_path_t*) dst.Handle, null, resScale);
583 	}
584 
585 	bool GetFillPath(SKPath src, SKPath dst, SKRect cullRect) {
586 		return GetFillPath(src, dst, cullRect, 1f);
587 	}
588 
589 	bool GetFillPath(SKPath src, SKPath dst, SKRect cullRect, float resScale) {
590 		if (src is null)
591 			throw new ArgumentNullException(src.stringof);
592 		if (dst is null)
593 			throw new ArgumentNullException(dst.stringof);
594 
595 		return SkiaApi.sk_paint_get_fill_path(cast(sk_paint_t*) Handle,
596 				cast(sk_path_t*) src.Handle, cast(sk_path_t*) dst.Handle, &cullRect, resScale);
597 	}
598 
599 	// CountGlyphs
600 
601 	int CountGlyphs(string text) {
602 		return GetFont().CountGlyphs(text);
603 	}
604 
605 	int CountGlyphs(const(char)[] text) {
606 		return GetFont().CountGlyphs(text);
607 	}
608 
609 	int CountGlyphs(byte[] text) {
610 		return GetFont().CountGlyphs(text, TextEncoding);
611 	}
612 
613 	int CountGlyphs(const(byte)[] text) {
614 		return GetFont().CountGlyphs(text, TextEncoding);
615 	}
616 
617 	int CountGlyphs(void* text, int length) {
618 		return GetFont().CountGlyphs(text, length, TextEncoding);
619 	}
620 
621 	// GetGlyphs
622 
623 	ushort[] GetGlyphs(string text) {
624 		return GetFont().GetGlyphs(text);
625 	}
626 
627 	ushort[] GetGlyphs(const(char)[] text) {
628 		return GetFont().GetGlyphs(text);
629 	}
630 
631 	ushort[] GetGlyphs(byte[] text) {
632 		return GetFont().GetGlyphs(text, TextEncoding);
633 	}
634 
635 	ushort[] GetGlyphs(const(byte)[] text) {
636 		return GetFont().GetGlyphs(text, TextEncoding);
637 	}
638 
639 	ushort[] GetGlyphs(void* text, int length) {
640 		return GetFont().GetGlyphs(text, length, TextEncoding);
641 	}
642 
643 	// ContainsGlyphs
644 
645 	bool ContainsGlyphs(string text) {
646 		return GetFont().ContainsGlyphs(text);
647 	}
648 
649 	bool ContainsGlyphs(const(char)[] text) {
650 		return GetFont().ContainsGlyphs(text);
651 	}
652 
653 	bool ContainsGlyphs(byte[] text) {
654 		return GetFont().ContainsGlyphs(text, TextEncoding);
655 	}
656 
657 	bool ContainsGlyphs(const(byte)[] text) {
658 		return GetFont().ContainsGlyphs(text, TextEncoding);
659 	}
660 
661 	bool ContainsGlyphs(void* text, int length) {
662 		return GetFont().ContainsGlyphs(text, length, TextEncoding);
663 	}
664 
665 	bool ContainsGlyphs(void* text, void* length) {
666 		return GetFont().ContainsGlyphs(text, cast(int) length, TextEncoding);
667 	}
668 
669 	// GetGlyphPositions
670 
671 	SKPoint[] GetGlyphPositions(string text, SKPoint origin = SKPoint.Empty) {
672 		return GetFont().GetGlyphPositions(text, origin);
673 	}
674 
675 	SKPoint[] GetGlyphPositions(const(char)[] text, SKPoint origin = SKPoint.Empty) {
676 		return GetFont().GetGlyphPositions(text, origin);
677 	}
678 
679 	SKPoint[] GetGlyphPositions(const(byte)[] text, SKPoint origin = SKPoint.Empty) {
680 		return GetFont().GetGlyphPositions(text, TextEncoding, origin);
681 	}
682 
683 	SKPoint[] GetGlyphPositions(void* text, int length, SKPoint origin = SKPoint.Empty) {
684 		return GetFont().GetGlyphPositions(text, length, TextEncoding, origin);
685 	}
686 
687 	// GetGlyphOffsets
688 
689 	float[] GetGlyphOffsets(string text, float origin = 0f) {
690 		return GetFont().GetGlyphOffsets(text, origin);
691 	}
692 
693 	float[] GetGlyphOffsets(const(char)[] text, float origin = 0f) {
694 		return GetFont().GetGlyphOffsets(text, origin);
695 	}
696 
697 	float[] GetGlyphOffsets(byte[] text, float origin = 0f) {
698 		return GetFont().GetGlyphOffsets(text, TextEncoding, origin);
699 	}
700 
701 	float[] GetGlyphOffsets(void* text, int length, float origin = 0f) {
702 		return GetFont().GetGlyphOffsets(text, length, TextEncoding, origin);
703 	}
704 
705 	// GetGlyphWidths
706 
707 	float[] GetGlyphWidths(string text) {
708 		return GetFont().GetGlyphWidths(text, this);
709 	}
710 
711 	float[] GetGlyphWidths(char[] text) {
712 		return GetFont().GetGlyphWidths(text, this);
713 	}
714 
715 	float[] GetGlyphWidths(byte[] text) {
716 		return GetFont().GetGlyphWidths(text, TextEncoding, this);
717 	}
718 
719 	float[] GetGlyphWidths(void* text, int length) {
720 		return GetFont().GetGlyphWidths(text, length, TextEncoding, this);
721 	}
722 
723 	float[] GetGlyphWidths(string text, out SKRect[] bounds) {
724 		return GetFont().GetGlyphWidths(text, bounds, this);
725 	}
726 
727 	float[] GetGlyphWidths(char[] text, out SKRect[] bounds) {
728 		return GetFont().GetGlyphWidths(text, bounds, this);
729 	}
730 
731 	float[] GetGlyphWidths(byte[] text, out SKRect[] bounds) {
732 		return GetFont().GetGlyphWidths(text, TextEncoding, bounds, this);
733 	}
734 
735 	float[] GetGlyphWidths(void* text, int length, out SKRect[] bounds) {
736 		return GetFont().GetGlyphWidths(text, length, TextEncoding, bounds, this);
737 	}
738 
739 	// GetTextIntercepts
740 
741 	float[] GetTextIntercepts(string text, float x, float y, float upperBounds, float lowerBounds) {
742 		return GetTextIntercepts(cast(char[]) text, x, y, upperBounds, lowerBounds);
743 	}
744 
745 	float[] GetTextIntercepts(char[] text, float x, float y, float upperBounds, float lowerBounds) {
746 		if (text is null)
747 			throw new ArgumentNullException(text.stringof);
748 
749 		auto blob = SKTextBlob.Create(cast(byte[]) text, SKTextEncoding.Utf8,
750 				GetFont(), SKPoint(x, y));
751 		scope (exit) {
752 			blob.Dispose();
753 		}
754 
755 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
756 	}
757 
758 	float[] GetTextIntercepts(byte[] text, float x, float y, float upperBounds, float lowerBounds) {
759 		return GetTextIntercepts(cast(const(byte)[]) text, x, y, upperBounds, lowerBounds);
760 	}
761 
762 	float[] GetTextIntercepts(const(byte)[] text, float x, float y,
763 			float upperBounds, float lowerBounds) {
764 		if (text is null)
765 			throw new ArgumentNullException(text.stringof);
766 
767 		auto blob = SKTextBlob.Create(text, TextEncoding, GetFont(), SKPoint(x, y));
768 		scope (exit) {
769 			blob.Dispose();
770 		}
771 
772 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
773 	}
774 
775 	float[] GetTextIntercepts(void* text, void* length, float x, float y,
776 			float upperBounds, float lowerBounds) {
777 		return GetTextIntercepts(text, cast(int) length, x, y, upperBounds, lowerBounds);
778 	}
779 
780 	float[] GetTextIntercepts(void* text, int length, float x, float y,
781 			float upperBounds, float lowerBounds) {
782 		if (text is null && length != 0)
783 			throw new ArgumentNullException(text.stringof);
784 
785 		auto blob = SKTextBlob.Create(text, length, TextEncoding, GetFont(), SKPoint(x, y));
786 		scope (exit) {
787 			blob.Dispose();
788 		}
789 
790 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
791 	}
792 
793 	// GetTextIntercepts (SKTextBlob)
794 
795 	float[] GetTextIntercepts(SKTextBlob text, float upperBounds, float lowerBounds) {
796 		if (text is null)
797 			throw new ArgumentNullException(text.stringof);
798 
799 		return text.GetIntercepts(upperBounds, lowerBounds, this);
800 	}
801 
802 	// GetPositionedTextIntercepts
803 
804 	float[] GetPositionedTextIntercepts(string text, SKPoint[] positions,
805 			float upperBounds, float lowerBounds) {
806 		return GetPositionedTextIntercepts(cast(const(char)[]) text, positions,
807 				upperBounds, lowerBounds);
808 	}
809 
810 	float[] GetPositionedTextIntercepts(const(char)[] text,
811 			const(SKPoint)[] positions, float upperBounds, float lowerBounds) {
812 		if (text is null)
813 			throw new ArgumentNullException(text.stringof);
814 
815 		auto blob = SKTextBlob.CreatePositioned(text, GetFont(), positions);
816 		scope (exit) {
817 			blob.Dispose();
818 		}
819 
820 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
821 	}
822 
823 	float[] GetPositionedTextIntercepts(byte[] text, SKPoint[] positions,
824 			float upperBounds, float lowerBounds) {
825 		return GetPositionedTextIntercepts(cast(const(byte)[]) text, positions,
826 				upperBounds, lowerBounds);
827 	}
828 
829 	float[] GetPositionedTextIntercepts(const(byte)[] text,
830 			const(SKPoint)[] positions, float upperBounds, float lowerBounds) {
831 		if (text is null)
832 			throw new ArgumentNullException(text.stringof);
833 
834 		auto blob = SKTextBlob.CreatePositioned(text, TextEncoding, GetFont(), positions);
835 		scope (exit) {
836 			blob.Dispose();
837 		}
838 
839 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
840 	}
841 
842 	float[] GetPositionedTextIntercepts(void* text, int length,
843 			SKPoint[] positions, float upperBounds, float lowerBounds) {
844 		return GetPositionedTextIntercepts(text, cast(void*) length, positions,
845 				upperBounds, lowerBounds);
846 	}
847 
848 	float[] GetPositionedTextIntercepts(void* text, void* length,
849 			SKPoint[] positions, float upperBounds, float lowerBounds) {
850 		if (text is null && length !is null)
851 			throw new ArgumentNullException(text.stringof);
852 
853 		auto blob = SKTextBlob.CreatePositioned(text, cast(int) length,
854 				TextEncoding, GetFont(), positions);
855 		scope (exit) {
856 			blob.Dispose();
857 		}
858 
859 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
860 	}
861 
862 	// GetHorizontalTextIntercepts
863 
864 	float[] GetHorizontalTextIntercepts(string text, float[] xpositions, float y,
865 			float upperBounds, float lowerBounds) {
866 		return GetHorizontalTextIntercepts(cast(const(char)[]) text, xpositions,
867 				y, upperBounds, lowerBounds);
868 	}
869 
870 	float[] GetHorizontalTextIntercepts(const(char)[] text,
871 			const(float)[] xpositions, float y, float upperBounds, float lowerBounds) {
872 		if (text is null)
873 			throw new ArgumentNullException(text.stringof);
874 
875 		auto blob = SKTextBlob.CreateHorizontal(text, GetFont(), xpositions, y);
876 		scope (exit) {
877 			blob.Dispose();
878 		}
879 
880 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
881 	}
882 
883 	float[] GetHorizontalTextIntercepts(byte[] text, float[] xpositions, float y,
884 			float upperBounds, float lowerBounds) {
885 		return GetHorizontalTextIntercepts(cast(const(byte)[]) text, xpositions,
886 				y, upperBounds, lowerBounds);
887 	}
888 
889 	float[] GetHorizontalTextIntercepts(const(byte)[] text,
890 			const(float)[] xpositions, float y, float upperBounds, float lowerBounds) {
891 		if (text is null)
892 			throw new ArgumentNullException(text.stringof);
893 
894 		auto blob = SKTextBlob.CreateHorizontal(text, TextEncoding, GetFont(), xpositions, y);
895 		scope (exit) {
896 			blob.Dispose();
897 		}
898 
899 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
900 	}
901 
902 	float[] GetHorizontalTextIntercepts(void* text, int length,
903 			float[] xpositions, float y, float upperBounds, float lowerBounds) {
904 		return GetHorizontalTextIntercepts(text, cast(void*) length,
905 				xpositions, y, upperBounds, lowerBounds);
906 	}
907 
908 	float[] GetHorizontalTextIntercepts(void* text, void* length,
909 			float[] xpositions, float y, float upperBounds, float lowerBounds) {
910 		if (text is null && length !is null)
911 			throw new ArgumentNullException(text.stringof);
912 
913 		auto blob = SKTextBlob.CreateHorizontal(text, cast(int) length,
914 				TextEncoding, GetFont(), xpositions, y);
915 		scope (exit) {
916 			blob.Dispose();
917 		}
918 
919 		return blob.GetIntercepts(upperBounds, lowerBounds, this);
920 	}
921 
922 	// Font
923 
924 	SKFont ToFont() {
925 		return SKFont.GetObject(SkiaApi.sk_compatpaint_make_font(cast(sk_compatpaint_t*) Handle));
926 	}
927 
928 	SKFont GetFont() {
929 		if(font is null) {
930 			sk_font_t* fontPtr = SkiaApi.sk_compatpaint_get_font(
931 					cast(sk_compatpaint_t*) Handle);
932 			SKFont skFont = SKFont.GetObject(fontPtr, false);
933 			font = OwnedBy(skFont, this);
934 		}
935 
936 		return font;
937 		// return font ? font : OwnedBy(SKFont.GetObject(SkiaApi.sk_compatpaint_get_font(
938 		// 		cast(sk_compatpaint_t*) Handle), false), this);
939 	}
940 
941 	//
942 
943 	static SKPaint GetObject(void* handle) {
944 		return handle is null ? null : new SKPaint(handle, true);
945 	}
946 
947 }