1 module skia.SKMask;
2 
3 import skia.Definitions;
4 import skia.MathTypes;
5 import skia.SkiaApi;
6 import skia.IDisposable;
7 import skia.Exceptions;
8 
9 import std.format;
10 
11 struct SKMask {
12 	SKRectI fBounds;
13 	uint fRowBytes;
14 	SKMaskFormat fFormat;
15 	void* fImage;
16 	this(void* image, SKRectI bounds, uint rowBytes, SKMaskFormat format) {
17 		fBounds = bounds;
18 		fRowBytes = rowBytes;
19 		fFormat = format;
20 		fImage = cast(byte*) image;
21 	}
22 
23 	this(SKRectI bounds, uint rowBytes, SKMaskFormat format) {
24 		fBounds = bounds;
25 		fRowBytes = rowBytes;
26 		fFormat = format;
27 		fImage = null;
28 	}
29 
30 	// properties
31 
32 	// readonly void* Image() 
33 	void* Image() {
34 		return cast(void*) fImage;
35 	}
36 
37 	void Image(void* value) {
38 		fImage = cast(byte*) value;
39 	}
40 
41 	// Span!(byte) GetImageSpan ()
42 	// {
43 	//   return new byte[] (cast(void*)Image, cast(int)ComputeTotalImageSize ());
44 	// }
45 
46 	// readonly SKRectI Bounds() 
47 	SKRectI Bounds() {
48 		return fBounds;
49 	}
50 
51 	void Bounds(SKRectI value) {
52 		fBounds = value;
53 	}
54 
55 	uint RowBytes() {
56 		return fRowBytes;
57 	}
58 
59 	// void uint RowBytes(uint value)
60 	// {
61 	//   fRowBytes = value;
62 	// }
63 
64 	// readonly SKMaskFormat Format()
65 	// {
66 	// 	return fFormat;
67 	// }
68 
69 	void Format(SKMaskFormat value) {
70 		fFormat = value;
71 	}
72 
73 	const bool IsEmpty() {
74 		SKMask* t = cast(SKMask*)&this;
75 		return SkiaApi.sk_mask_is_empty(t);
76 	}
77 
78 	// allocate / free
79 
80 	long AllocateImage() {
81 		SKMask* t = &this;
82 		{
83 			auto size = SkiaApi.sk_mask_compute_total_image_size(t);
84 			fImage = SkiaApi.sk_mask_alloc_image(size);
85 			return cast(long) size;
86 		}
87 	}
88 
89 	void FreeImage() {
90 		if (fImage !is null) {
91 			SKMask.FreeImage(cast(void*) fImage);
92 			fImage = null;
93 		}
94 	}
95 
96 	// Compute*
97 
98 	const long ComputeImageSize() {
99 		SKMask* t = cast(SKMask*)&this;
100 		return cast(long) SkiaApi.sk_mask_compute_image_size(t);
101 	}
102 
103 	const long ComputeTotalImageSize() {
104 		SKMask* t = cast(SKMask*)&this;
105 		return cast(long) SkiaApi.sk_mask_compute_total_image_size(t);
106 	}
107 
108 	// GetAddr*
109 
110 	const byte GetAddr1(int x, int y) {
111 		SKMask* t = cast(SKMask*)&this;
112 		return *SkiaApi.sk_mask_get_addr_1(t, x, y);
113 	}
114 
115 	const byte GetAddr8(int x, int y) {
116 		SKMask* t = cast(SKMask*)&this;
117 		return *SkiaApi.sk_mask_get_addr_8(t, x, y);
118 	}
119 
120 	const ushort GetAddr16(int x, int y) {
121 		SKMask* t = cast(SKMask*)&this;
122 		return *SkiaApi.sk_mask_get_addr_lcd_16(t, x, y);
123 	}
124 
125 	const uint GetAddr32(int x, int y) {
126 		SKMask* t = cast(SKMask*)&this;
127 		return *SkiaApi.sk_mask_get_addr_32(t, x, y);
128 	}
129 
130 	const void* GetAddr(int x, int y) {
131 		SKMask* t = cast(SKMask*)&this;
132 		return cast(void*) SkiaApi.sk_mask_get_addr(t, x, y);
133 	}
134 
135 	// statics
136 
137 	static void* AllocateImage(long size) {
138 		return cast(void*) SkiaApi.sk_mask_alloc_image(cast(void*) size);
139 	}
140 
141 	static void FreeImage(void* image) {
142 		return SkiaApi.sk_mask_free_image(cast(byte*) image);
143 	}
144 
145 	static SKMask Create(byte[] image, SKRectI bounds, uint rowBytes, SKMaskFormat format) {
146 		return Create(cast(const(byte)[]) image, bounds, rowBytes, format);
147 	}
148 
149 	static SKMask Create(const(byte)[] image, SKRectI bounds, uint rowBytes, SKMaskFormat format) {
150 		// create the mask
151 		auto mask = SKMask(bounds, rowBytes, format);
152 
153 		// calculate the size
154 		auto imageSize = cast(int) mask.ComputeTotalImageSize();
155 
156 		// is there the right amount of space in the mask
157 		if (image.length != imageSize) {
158 			// Note: buffer.Length must match bounds.Height * rowBytes
159 			auto expectedSize = bounds.Height * rowBytes;
160 			auto message = "Length of image ({image.Length}) does not match the computed size of the mask ({expectedSize}). Check the {bounds.stringof} and {rowBytes.stringof}.";
161 			throw new ArgumentException(message);
162 		}
163 
164 		// allocate and copy the image data
165 		mask.AllocateImage();
166 		// image.CopyTo (new byte[] (cast(void*)mask.Image, imageSize));
167 
168 		byte* buffer = cast(byte*)mask.Image;
169 		for(size_t i = 0; i<imageSize; i++) {
170 			buffer[i] = image[i];
171 		}
172 
173 		// return the mask
174 		return mask;
175 	}
176 }
177 
178 class SKAutoMaskFreeImage : IDisposable {
179 	private void* image;
180 
181 	this(void* maskImage) {
182 		image = maskImage;
183 	}
184 
185 	void Dispose() {
186 		if (image !is null) {
187 			SKMask.FreeImage(image);
188 			image = null;
189 		}
190 	}
191 }