1 module skia.SKDrawable;
2 
3 import skia.Definitions;
4 import skia.Exceptions;
5 import skia.GRDefinitions;
6 import skia.MathTypes;
7 import skia.SKCanvas;
8 import skia.SKPictureRecorder;
9 import skia.SKObject;
10 import skia.SKMatrix;
11 import skia.SKPicture;
12 import skia.SkiaApi;
13 
14 import core.atomic;
15 
16 class SKDrawable : SKObject {
17 	private __gshared SKManagedDrawableDelegates delegates;
18 
19 	private shared int fromNative;
20 
21 	shared static this ()
22 	{
23 		delegates.fDraw = &DrawInternal;
24 		delegates.fGetBounds = &GetBoundsInternal;
25 		delegates.fNewPictureSnapshot = &NewPictureSnapshotInternal;
26 		delegates.fDestroy = &DestroyInternal;
27 
28 		SkiaApi.sk_manageddrawable_set_procs (delegates);
29 	}
30 
31 	this() {
32 		this(true);
33 	}
34 
35 	protected this(bool owns) {
36 		super(null, owns);
37 		// auto ctx = DelegateProxies.CreateUserData(this, true);
38 		void* ctx = cast(void*) this;
39 		Handle = SkiaApi.sk_manageddrawable_new(ctx);
40 
41 		if (Handle is null) {
42 			throw new InvalidOperationException("Unable to create a new SKDrawable instance.");
43 		}
44 	}
45 
46 	this(void* x, bool owns) {
47 		super(x, owns);
48 	}
49 
50 	// protected override void Dispose(bool disposing) {
51 	// 	return super.Dispose(disposing);
52 	// }
53 
54 	protected override void DisposeNative() {
55 		// if (Interlocked.CompareExchange(fromNative, 0, 0) == 0)
56 		int v = cas(&fromNative, 0, 0);
57 		if (v == 0)
58 			SkiaApi.sk_drawable_unref(cast(sk_drawable_t*) Handle);
59 	}
60 
61 	uint GenerationId() {
62 		return SkiaApi.sk_drawable_get_generation_id(cast(sk_drawable_t*) Handle);
63 	}
64 
65 	SKRect Bounds() {
66 		SKRect bounds;
67 		SkiaApi.sk_drawable_get_bounds(cast(sk_drawable_t*) Handle, &bounds);
68 		return bounds;
69 	}
70 
71 	void Draw(SKCanvas canvas, ref SKMatrix matrix) {
72 		SKMatrix* m = &matrix;
73 		SkiaApi.sk_drawable_draw(cast(sk_drawable_t*) Handle, cast(sk_canvas_t*) canvas.Handle, m);
74 	}
75 
76 	void Draw(SKCanvas canvas, float x, float y) {
77 		auto matrix = SKMatrix.CreateTranslation(x, y);
78 		Draw(canvas, matrix);
79 	}
80 
81 	// do not unref as this is a plain pointer return, not a reference counted pointer
82 	SKPicture Snapshot ()
83 	{
84 	  return 	SKPicture.GetObject (SkiaApi.sk_drawable_new_picture_snapshot (cast(sk_drawable_t*)Handle), true, false);
85 	}
86 
87 	void NotifyDrawingChanged() {
88 		return SkiaApi.sk_drawable_notify_drawing_changed(cast(sk_drawable_t*) Handle);
89 	}
90 
91 	protected void OnDraw(SKCanvas canvas) {
92 	}
93 
94 	protected SKRect OnGetBounds() {
95 		return SKRect.Empty;
96 	}
97 
98 	protected SKPicture OnSnapshot() {
99 		SKPictureRecorder recorder = new SKPictureRecorder();
100 		scope (exit) {
101 			recorder.Dispose();
102 		}
103 
104 		auto canvas = recorder.BeginRecording(Bounds);
105 		Draw(canvas, 0, 0);
106 		return recorder.EndRecording();
107 	}
108 
109 extern (C) {
110 	private static void DrawInternal(void* d, void* context, void* canvas) {
111 		// auto drawable = DelegateProxies.GetUserData!(SKDrawable)(cast(void*) context, _);
112 		SKDrawable drawable = cast(SKDrawable) context;
113 		drawable.OnDraw(SKCanvas.GetObject(canvas, false));
114 	}
115 
116 	private static void GetBoundsInternal(void* d, void* context, SKRect* rect) {
117 		// auto drawable = DelegateProxies.GetUserData!(SKDrawable)(cast(void*) context, _);
118 		SKDrawable drawable = cast(SKDrawable) context;
119 		auto bounds = drawable.OnGetBounds();
120 		*rect = bounds;
121 	}
122 
123 	private static void* NewPictureSnapshotInternal(void* d, void* context) {
124 		// auto drawable = DelegateProxies.GetUserData!(SKDrawable)(cast(void*) context, _);
125 		SKDrawable drawable = cast(SKDrawable) context;
126 		return drawable.OnSnapshot().Handle ? drawable.OnSnapshot().Handle : null;
127 	}
128 
129 	private static void DestroyInternal (void* d, void* context)
130 	{
131 		// auto drawable = DelegateProxies.GetUserData<SKDrawable> (cast(void*)context,  var gch);
132 		SKDrawable drawable = cast(SKDrawable) context;
133 		if (drawable !is null) {
134 			// Interlocked.Exchange ( drawable.fromNative, 1);
135 			atomicStore(drawable.fromNative, 1);
136 			drawable.Dispose ();
137 		}
138 	}
139 }
140 
141 	static SKDrawable GetObject(void* handle) {
142 		return GetOrAddObject!(SKDrawable)(handle, delegate SKDrawable(h, o) {
143 			return new SKDrawable(h, o);
144 		});
145 		// return GetOrAddObject!(SKDrawable) (handle, (h, o){return new SKDrawable (h, o);});
146 	}
147 
148 }