1/*
2 * Copyright © 2018 Benjamin Otte
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include "gdkmemorytextureprivate.h"
23
24#include "gdkmemoryformatprivate.h"
25#include "gsk/gl/fp16private.h"
26
27/**
28 * GdkMemoryTexture:
29 *
30 * A `GdkTexture` representing image data in memory.
31 */
32
33struct _GdkMemoryTexture
34{
35 GdkTexture parent_instance;
36
37 GBytes *bytes;
38 gsize stride;
39};
40
41struct _GdkMemoryTextureClass
42{
43 GdkTextureClass parent_class;
44};
45
46G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE)
47
48static void
49gdk_memory_texture_dispose (GObject *object)
50{
51 GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (object);
52
53 g_clear_pointer (&self->bytes, g_bytes_unref);
54
55 G_OBJECT_CLASS (gdk_memory_texture_parent_class)->dispose (object);
56}
57
58static void
59gdk_memory_texture_download (GdkTexture *texture,
60 GdkMemoryFormat format,
61 guchar *data,
62 gsize stride)
63{
64 GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
65
66 gdk_memory_convert (dest_data: data, dest_stride: stride,
67 dest_format: format,
68 src_data: (guchar *) g_bytes_get_data (bytes: self->bytes, NULL),
69 src_stride: self->stride,
70 src_format: texture->format,
71 width: gdk_texture_get_width (texture),
72 height: gdk_texture_get_height (texture));
73}
74
75static void
76gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
77{
78 GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
79 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
80
81 texture_class->download = gdk_memory_texture_download;
82
83 gobject_class->dispose = gdk_memory_texture_dispose;
84}
85
86static void
87gdk_memory_texture_init (GdkMemoryTexture *self)
88{
89}
90
91static GBytes *
92gdk_memory_sanitize (GBytes *bytes,
93 int width,
94 int height,
95 GdkMemoryFormat format,
96 gsize stride,
97 gsize *out_stride)
98{
99 gsize align, size, copy_stride, bpp;
100 const guchar *data;
101 guchar *copy;
102 int y;
103
104 data = g_bytes_get_data (bytes, size: &size);
105 align = gdk_memory_format_alignment (format);
106
107 if (GPOINTER_TO_SIZE (data) % align == 0 &&
108 stride % align == 0)
109 {
110 *out_stride = stride;
111 return g_bytes_ref (bytes);
112 }
113
114 bpp = gdk_memory_format_bytes_per_pixel (format);
115 copy_stride = bpp * width;
116 /* align to multiples of 4, just to be sure */
117 copy_stride = (copy_stride + 3) & ~3;
118 copy = g_malloc (n_bytes: copy_stride * height);
119 for (y = 0; y < height; y++)
120 memcpy (dest: copy + y * copy_stride, src: data + y * stride, n: bpp * width);
121
122 *out_stride = copy_stride;
123 return g_bytes_new_take (data: copy, size: copy_stride * height);
124}
125
126/**
127 * gdk_memory_texture_new:
128 * @width: the width of the texture
129 * @height: the height of the texture
130 * @format: the format of the data
131 * @bytes: the `GBytes` containing the pixel data
132 * @stride: rowstride for the data
133 *
134 * Creates a new texture for a blob of image data.
135 *
136 * The `GBytes` must contain @stride × @height pixels
137 * in the given format.
138 *
139 * Returns: (type GdkMemoryTexture): A newly-created `GdkTexture`
140 */
141GdkTexture *
142gdk_memory_texture_new (int width,
143 int height,
144 GdkMemoryFormat format,
145 GBytes *bytes,
146 gsize stride)
147{
148 GdkMemoryTexture *self;
149
150 g_return_val_if_fail (width > 0, NULL);
151 g_return_val_if_fail (height > 0, NULL);
152 g_return_val_if_fail (bytes != NULL, NULL);
153 g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
154
155 bytes = gdk_memory_sanitize (bytes, width, height, format, stride, out_stride: &stride);
156
157 self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
158 first_property_name: "width", width,
159 "height", height,
160 NULL);
161
162 GDK_TEXTURE (self)->format = format;
163 self->bytes = bytes;
164 self->stride = stride;
165
166 return GDK_TEXTURE (self);
167}
168
169GdkTexture *
170gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
171 int x,
172 int y,
173 int width,
174 int height)
175{
176 GdkTexture *texture, *result;
177 gsize bpp, offset, size;
178 GBytes *bytes;
179
180 g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE (source), NULL);
181 g_return_val_if_fail (x < 0 || x >= GDK_TEXTURE (source)->width, NULL);
182 g_return_val_if_fail (y < 0 || y >= GDK_TEXTURE (source)->height, NULL);
183 g_return_val_if_fail (width <= 0 || x + width > GDK_TEXTURE (source)->width, NULL);
184 g_return_val_if_fail (height <= 0 || y + height > GDK_TEXTURE (source)->height, NULL);
185
186 texture = GDK_TEXTURE (source);
187 bpp = gdk_memory_format_bytes_per_pixel (format: texture->format);
188 offset = y * source->stride + x * bpp;
189 size = source->stride * (height - 1) + x * bpp;
190 bytes = g_bytes_new_from_bytes (bytes: source->bytes, offset, length: size);
191
192 result = gdk_memory_texture_new (width: texture->width,
193 height: texture->height,
194 format: texture->format,
195 bytes,
196 stride: source->stride);
197 g_bytes_unref (bytes);
198
199 return result;
200}
201
202GdkMemoryTexture *
203gdk_memory_texture_from_texture (GdkTexture *texture,
204 GdkMemoryFormat format)
205{
206 GdkTexture *result;
207 GBytes *bytes;
208 guchar *data;
209 gsize stride;
210
211 g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
212
213 if (GDK_IS_MEMORY_TEXTURE (texture))
214 {
215 GdkMemoryTexture *memtex = GDK_MEMORY_TEXTURE (texture);
216
217 if (gdk_texture_get_format (self: texture) == format)
218 return g_object_ref (memtex);
219 }
220
221 stride = texture->width * gdk_memory_format_bytes_per_pixel (format);
222 data = g_malloc_n (n_blocks: stride, n_block_bytes: texture->height);
223
224 gdk_texture_do_download (texture, format, data, stride);
225 bytes = g_bytes_new_take (data, size: stride);
226 result = gdk_memory_texture_new (width: texture->width,
227 height: texture->height,
228 format,
229 bytes,
230 stride);
231 g_bytes_unref (bytes);
232
233 return GDK_MEMORY_TEXTURE (result);
234}
235
236const guchar *
237gdk_memory_texture_get_data (GdkMemoryTexture *self)
238{
239 return g_bytes_get_data (bytes: self->bytes, NULL);
240}
241
242gsize
243gdk_memory_texture_get_stride (GdkMemoryTexture *self)
244{
245 return self->stride;
246}
247
248

source code of gtk/gdk/gdkmemorytexture.c