1 module skia.SKData;
2 
3 import skia.Definitions;
4 import skia.DelegateProxies;
5 import skia.Exceptions;
6 import skia.SkiaApi;
7 import skia.SKObject;
8 import skia.SKStream;
9 
10 import std.algorithm;
11 import std.math;
12 import std.range;
13 import std..string;
14 
15 
16 /**
17  * 
18  */
19 class SKData : SKObject, ISKNonVirtualReferenceCounted
20 {
21 	// We pick a value that is the largest multiple of 4096 that is still smaller than the large object heap threshold (85K).
22 	// The CopyTo/CopyToAsync buffer is short-lived and is likely to be collected at Gen0, and it offers a significant
23 	// improvement in Copy performance.
24 	enum int CopyBufferSize = 81920;
25 
26 	private __gshared SKData empty;
27 
28 	shared static this()
29 	{
30 		empty = new SKDataStatic (SkiaApi.sk_data_new_empty ());
31 	}
32 
33 	static void EnsureStaticInstanceAreInitialized ()
34 	{
35 		// IMPORTANT: do not remove to ensure that the static instances
36 		//            are initialized before any access is made to them
37 	}
38 
39 	this (void* x, bool owns)
40 	{
41 		super (x, owns);
42 	}
43 
44 	protected override void Dispose (bool disposing)
45 	{
46 		return super.Dispose (disposing);
47 	}
48 
49 	override void Dispose ()
50 	{
51 		 super.Dispose ();
52 	}
53 
54 	void ReferenceNative () { return SkiaApi.sk_data_ref (cast(sk_data_t*)Handle); }
55 
56 	void UnreferenceNative () { return SkiaApi.sk_data_unref (cast(sk_data_t*)Handle); }
57 
58 	static SKData Empty () { return empty; }
59 
60 	// CreateCopy
61 
62 	static SKData CreateCopy (void* bytes, ulong length)
63 	{
64 		// if (!PlatformConfiguration.Is64Bit && length > uint.max)
65 		// 	throw new ArgumentOutOfRangeException (length.stringof, "The length exceeds the size of pointers.");
66 		return GetObject (SkiaApi.sk_data_new_with_copy (cast(void*)bytes, cast(size_t) length));
67 	}
68 
69 	static SKData CreateCopy ( byte[] bytes)
70 	{
71 		return CreateCopy (bytes, bytes.length);
72 	}
73 
74 	static SKData CreateCopy (byte[] bytes, size_t length)
75 	{
76 		byte* b = bytes.ptr;
77 		return GetObject (SkiaApi.sk_data_new_with_copy (b, length));
78 	}
79 
80 	// static SKData CreateCopy (const(byte)[] bytes)
81 	// {
82 	// 	byte* b = bytes.ptr;
83 	// 	return CreateCopy (cast(void*)b, bytes.length);
84 	// }
85 
86 	// Create
87 
88 	static SKData Create (int size)
89 	{
90 		return GetObject (SkiaApi.sk_data_new_uninitialized (cast(size_t) size));
91 	}
92 
93 	static SKData Create (size_t size)
94 	{
95 		version(X86) {
96 			if (size > uint.max)
97 				throw new ArgumentOutOfRangeException (size.stringof, "The size exceeds the size of pointers.");
98 		}
99 			
100 		return GetObject (SkiaApi.sk_data_new_uninitialized (size));
101 	}
102 
103 	static SKData Create (string filename)
104 	{
105 		if (filename.empty())
106 			throw new ArgumentException ("The filename cannot be empty.", filename.stringof);
107 
108 		// auto utf8path = StringUtilities.GetEncodedText (filename, SKTextEncoding.Utf8, true);
109 		auto utf8path = filename.toStringz();
110 		byte* u = cast(byte*)utf8path;
111 		return GetObject (SkiaApi.sk_data_new_from_file (u.stringof));
112 	}
113 
114 	// static SKData Create (Stream stream)
115 	// {
116 	// 	if (stream is null)
117 	// 		throw new ArgumentNullException (stream.stringof);
118 	// 	if (stream.CanSeek) {
119 	// 		return Create (stream, stream.Length);
120 	// 	} else {
121 	// 		auto memory =  new SKDynamicMemoryWStream ();
122 	// 		scope(exit) {
123 	// 		    memory.Dispose();
124 	// 		}
125 
126 	// 		using (var managed = new SKManagedStream (stream)) {
127 	// 			managed.CopyTo (memory);
128 	// 		}
129 	// 		return memory.DetachAsData ();
130 	// 	}
131 	// }
132 
133 	// static SKData Create (Stream stream, int length)
134 	// {
135 	// 	if (stream is null)
136 	// 		throw new ArgumentNullException (stream.stringof);
137 
138 	// 	 SKManagedStream managed = new SKManagedStream (stream);
139 	// 	return Create (managed, length);
140 	// }
141 
142 	// static SKData Create (Stream stream, ulong length)
143 	// {
144 	// 	if (stream is null)
145 	// 		throw new ArgumentNullException (stream.stringof);
146 
147 	// 	 SKManagedStream managed = new SKManagedStream (stream);
148 	// 	return Create (managed, length);
149 	// }
150 
151 	// static SKData Create (Stream stream, long length)
152 	// {
153 	// 	if (stream is null)
154 	// 		throw new ArgumentNullException (stream.stringof);
155 
156 	// 	SKManagedStream managed = new SKManagedStream (stream);
157 	// 	return Create (managed, length);
158 	// }
159 
160 	static SKData Create (SKStream stream)
161 	{
162 		if (stream is null)
163 			throw new ArgumentNullException (stream.stringof);
164 
165 		return Create (stream, stream.Length);
166 	}
167 
168 	static SKData Create (SKStream stream, int length)
169 	{
170 		if (stream is null)
171 			throw new ArgumentNullException (stream.stringof);
172 
173 		return GetObject (SkiaApi.sk_data_new_from_stream (cast(sk_stream_t*)stream.Handle, cast(size_t)length));
174 	}
175 
176 	static SKData Create (SKStream stream, ulong length)
177 	{
178 		if (stream is null)
179 			throw new ArgumentNullException (stream.stringof);
180 
181 		return GetObject (SkiaApi.sk_data_new_from_stream (cast(sk_stream_t*)stream.Handle, cast(size_t)length));
182 	}
183 
184 	static SKData Create (SKStream stream, long length)
185 	{
186 		if (stream is null)
187 			throw new ArgumentNullException (stream.stringof);
188 
189 		return GetObject (SkiaApi.sk_data_new_from_stream (cast(sk_stream_t*)stream.Handle, cast(size_t)length));
190 	}
191 
192 	// static SKData Create (void* address, int length)
193 	// {
194 	// 	return Create (address, length, null, null);
195 	// }
196 
197   static SKData Create (void* address, size_t length)
198 	{
199 		return Create (address, length, null, null);
200 	}
201 
202 	static SKData Create (void* address, size_t length, SKDataReleaseDelegate releaseProc)
203 	{
204 		return Create (address, length, releaseProc, null);
205 	}
206 
207 	static SKData Create (void* address, size_t length, SKDataReleaseDelegate releaseProc, void* context)
208 	{
209 		// SKDataReleaseDelegate del = releaseProc !is null && context !is null
210 		// 	? new SKDataReleaseDelegate ((addr, _) () { return releaseProc (addr, context)) }
211 		// 	: releaseProc;
212 
213 
214 		SKDataReleaseDelegate del = releaseProc;
215 		if(releaseProc !is null && context !is null) {
216 			del = (addr, _t) { releaseProc (addr, context); };
217 		}
218 
219 
220 		// https://www.cnblogs.com/zhaox583132460/p/3402243.html
221 		// FIXME: Needing refactor or cleanup -@putao at 2021-01-10T21:25:11+08:00
222 		// More tests needed
223 		SKDataReleaseDelegateWrapper wrapper = SKDataReleaseDelegateWrapper(del);
224 
225 		void* ctx = cast(void*)&wrapper;
226 		SKDataReleaseProxyDelegate releaseProxy = DelegateProxies.SKDataReleaseDelegateProxy;
227 		SKDataReleaseProxyDelegate proxy = DelegateProxies.Create (releaseProxy, ctx);
228 
229 		return GetObject (SkiaApi.sk_data_new_with_proc (cast(void*)address, length, proxy, ctx));
230 	}
231 
232 	static SKData FromCString (string str)
233 	{
234 		// auto bytes = Encoding.ASCII.GetBytes (str ?? string.Empty);
235 		byte[] bytes = cast(byte[])str.dup;
236 
237 		return SKData.CreateCopy (bytes, bytes.length + 1); // + 1 for the terminating char
238 	}
239 
240 	// Subset
241 
242 	SKData Subset (ulong offset, ulong length)
243 	{
244 		version(X86) {
245 			if (length > uint.max)
246 				throw new ArgumentOutOfRangeException (length.stringof, "The length exceeds the size of pointers.");
247 			if (offset > uint.max)
248 				throw new ArgumentOutOfRangeException (offset.stringof, "The offset exceeds the size of pointers.");
249 		}
250 		return GetObject (SkiaApi.sk_data_new_subset (cast(sk_data_t*)Handle, cast(size_t) offset, cast(size_t) length));
251 	}
252 
253 	// ToArray
254 
255 	byte[] ToArray ()
256 	{
257 		byte[] array = cast(byte[])AsSpan ().dup;
258 		// GC.KeepAlive (this);
259 		return array;
260 	}
261 
262 	// properties
263 
264 	bool IsEmpty () { return Size == 0; }
265 
266 	long Size () { return cast(long)SkiaApi.sk_data_get_size (cast(sk_data_t*)Handle); }
267 
268 	void* Data () { return cast(void*)SkiaApi.sk_data_get_data (cast(sk_data_t*)Handle); }
269 
270 	// AsStream
271 
272 	// Stream AsStream ()
273 	// {
274 	// 	return new SKDataStream (this, false);
275 	// }
276 
277 
278 	// Stream AsStream (bool streamDisposesData)
279 	// {
280 	// 	return new SKDataStream (this, streamDisposesData);
281 	// }
282 
283 
284 	// AsSpan
285 
286 	const(byte)[] AsSpan ()
287 	{
288 		void* data = cast(void*)Data;
289 		return cast(const(byte)[]) data[0 .. Size()];
290 	}
291 
292 	// SaveTo
293 	void SaveTo (DataWriter target)
294 	{
295 		if (target is null)
296 			throw new ArgumentNullException (target.stringof);
297 
298 		void* ptr = Data;
299 		long total = Size;
300 		// ubyte[] buffer =  new ubyte[CopyBufferSize];
301 
302 		for (long left = total; left > 0;) {
303 			auto copyCount = cast(int)min (CopyBufferSize, left);
304 			target(cast(ubyte[]) ptr[0..copyCount]);
305 			left -= copyCount;
306 			ptr += copyCount;
307 		}
308 	}	
309 
310 	// void SaveTo (Stream target)
311 	// {
312 	// 	if (target is null)
313 	// 		throw new ArgumentNullException (target.stringof);
314 
315 	// 	void* ptr = Data;
316 	// 	long total = Size;
317 	// 	byte[] buffer =  new byte[CopyBufferSize]; // Utils.RentArray<byte> (CopyBufferSize);
318 	// 	scope(exit) {
319 	// 	    buffer.Dispose();
320 	// 	}
321 
322 	// 	for (var left = total; left > 0;) {
323 	// 		auto copyCount = cast(int)min (CopyBufferSize, left);
324 	// 		// Marshal.Copy (ptr, buffer, 0, copyCount);
325 	// 		buffer[0..copyCount] = ptr[0..copyCount];
326 
327 	// 		left -= copyCount;
328 	// 		ptr += copyCount;
329 	// 		target.Write (buffer, 0, copyCount);
330 	// 	}
331 	// 	// GC.KeepAlive (this);
332 	// }
333 
334 	static SKData GetObject (void* handle)
335 	{
336     return GetOrAddObject!(SKData)(handle, delegate SKData (h, o) { return new SKData (h, o);});
337 	}
338  }
339 
340 	//
341 
342 	// private class SKDataStream // : UnmanagedMemoryStream
343 	// {
344 	// 	private SKData host;
345 	// 	private bool disposeHost;
346 
347 	// 	this (SKData host, bool disposeHost = false)
348 	// 	{
349 	// 		// super(cast(byte *) host.Data, host.Size);
350 	// 		this.host = host;
351 	// 		this.disposeHost = disposeHost;
352 	// 	}
353 
354 	// 	protected  void Dispose (bool disposing)
355 	// 	// protected override void Dispose (bool disposing)
356 	// 	{
357 	// 		super.Dispose (disposing);
358 	// 		if (disposeHost) {
359 	// 			if(host !is null) host.Dispose ();
360 	// 		}
361 	// 		host = null;
362 	// 	}
363 	// }
364 
365 	//
366 
367 	private final class SKDataStatic : SKData
368 	{
369 		this (void* x)
370 		{
371 			super (x, true);
372 			IgnorePublicDispose = true;
373 		}
374 	}
375