-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
Copy pathCanvas.vala
178 lines (139 loc) · 5.08 KB
/
Canvas.vala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* Copyright 2024 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#if HAS_MUTTER46
public class Gala.Drawing.Canvas : GLib.Object, Clutter.Content {
private int width = -1;
private int height = -1;
private float scale_factor = 1.0f;
private Cogl.Context? cogl_context;
private Cogl.Texture? texture = null;
private Cogl.Bitmap? bitmap = null;
private bool dirty = false;
public signal void draw (Cairo.Context cr, int width, int height);
public override void attached (Clutter.Actor actor) {
#if HAS_MUTTER47
cogl_context = actor.context.get_backend ().get_cogl_context ();
#else
cogl_context = Clutter.get_default_backend ().get_cogl_context ();
#endif
}
public override void detached (Clutter.Actor actor) {
cogl_context = null;
}
private void emit_draw () requires (width > 0 && height > 0 && cogl_context != null) {
dirty = true;
int real_width = (int) Math.ceilf (width * scale_factor);
int real_height = (int) Math.ceilf (height * scale_factor);
if (bitmap == null) {
bitmap = new Cogl.Bitmap.with_size (cogl_context, real_width, real_height, Cogl.PixelFormat.CAIRO_ARGB32_COMPAT);
}
unowned Cogl.Buffer? buffer = bitmap.get_buffer ();
if (buffer == null) {
return;
}
buffer.set_update_hint (Cogl.BufferUpdateHint.DYNAMIC);
void* data = buffer.map (Cogl.BufferAccess.READ_WRITE, Cogl.BufferMapHint.DISCARD);
Cairo.ImageSurface surface;
bool mapped_buffer;
if (data != null) {
var bitmap_stride = bitmap.get_rowstride ();
surface = new Cairo.ImageSurface.for_data ((uchar[]) data, Cairo.Format.ARGB32, real_width, real_height, bitmap_stride);
mapped_buffer = true;
} else {
surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, real_width, real_height);
mapped_buffer = false;
}
surface.set_device_scale (scale_factor, scale_factor);
var cr = new Cairo.Context (surface);
draw ((owned) cr, width, height);
if (mapped_buffer) {
buffer.unmap ();
} else {
int size = surface.get_stride () * height;
buffer.set_data (0, surface.get_data (), size);
}
}
public bool get_preferred_size (out float out_width, out float out_height) {
if (width < 0 || width < 0) {
out_width = 0;
out_height = 0;
return false;
}
out_width = Math.ceilf (width * scale_factor);
out_height = Math.ceilf (height * scale_factor);
return true;
}
public void invalidate () {
bitmap = null;
if (width <= 0 || height <= 0) {
return;
}
emit_draw ();
}
public void invalidate_size () { }
public void paint_content (Clutter.Actor actor, Clutter.PaintNode root, Clutter.PaintContext paint_context) {
if (bitmap == null) {
return;
}
if (dirty) {
texture = null;
}
if (texture == null) {
texture = new Cogl.Texture2D.from_bitmap (bitmap);
}
if (texture == null) {
return;
}
var node = actor.create_texture_paint_node (texture);
root.add_child (node);
dirty = false;
}
public void set_size (int new_width, int new_height) requires (new_width >= -1 && new_height >= -1) {
if (new_width == width && new_height == height) {
return;
}
width = new_width;
height = new_height;
invalidate ();
}
public void set_scale_factor (float new_scale_factor) requires (new_scale_factor > 0.0f) {
if (new_scale_factor != scale_factor) {
scale_factor = new_scale_factor;
invalidate ();
}
}
}
#else
public class Gala.Drawing.Canvas : GLib.Object, Clutter.Content {
public Clutter.Canvas canvas;
construct {
canvas = new Clutter.Canvas ();
canvas.draw.connect (on_draw);
}
public signal void draw (Cairo.Context cr, int width, int height);
public bool get_preferred_size (out float out_width, out float out_height) {
return canvas.get_preferred_size (out out_width, out out_height);
}
public void invalidate () {
canvas.invalidate ();
}
public void invalidate_size () {
canvas.invalidate_size ();
}
public void paint_content (Clutter.Actor actor, Clutter.PaintNode root, Clutter.PaintContext paint_context) {
canvas.paint_content (actor, root, paint_context);
}
public void set_size (int new_width, int new_height) requires (new_width >= -1 && new_height >= -1) {
canvas.set_size (new_width, new_height);
}
public void set_scale_factor (float new_scale_factor) requires (new_scale_factor > 0.0f) {
canvas.set_scale_factor (new_scale_factor);
}
private bool on_draw (Cairo.Context cr, int width, int height) {
draw (cr, width, height);
return true;
}
}
#endif