2018-03-06 02:41:13 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2018 Benjamin Otte
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
|
|
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include "gdkmemorytextureprivate.h"
|
2021-09-22 00:01:41 +00:00
|
|
|
|
|
2024-06-17 17:10:56 +00:00
|
|
|
|
#include "gdkcolorstateprivate.h"
|
2021-09-22 00:01:41 +00:00
|
|
|
|
#include "gdkmemoryformatprivate.h"
|
2018-03-06 02:41:13 +00:00
|
|
|
|
|
2021-02-21 05:13:57 +00:00
|
|
|
|
/**
|
|
|
|
|
* GdkMemoryTexture:
|
|
|
|
|
*
|
|
|
|
|
* A `GdkTexture` representing image data in memory.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-03-06 02:41:13 +00:00
|
|
|
|
struct _GdkMemoryTexture
|
|
|
|
|
{
|
|
|
|
|
GdkTexture parent_instance;
|
|
|
|
|
|
|
|
|
|
GBytes *bytes;
|
|
|
|
|
gsize stride;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkMemoryTextureClass
|
|
|
|
|
{
|
|
|
|
|
GdkTextureClass parent_class;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE)
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdk_memory_texture_dispose (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (object);
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&self->bytes, g_bytes_unref);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (gdk_memory_texture_parent_class)->dispose (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2021-10-07 04:19:41 +00:00
|
|
|
|
gdk_memory_texture_download (GdkTexture *texture,
|
|
|
|
|
GdkMemoryFormat format,
|
2024-07-13 22:51:05 +00:00
|
|
|
|
GdkColorState *color_state,
|
2021-10-07 04:19:41 +00:00
|
|
|
|
guchar *data,
|
|
|
|
|
gsize stride)
|
2018-03-06 02:41:13 +00:00
|
|
|
|
{
|
|
|
|
|
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
|
|
|
|
|
|
|
|
|
|
gdk_memory_convert (data, stride,
|
2021-10-07 04:19:41 +00:00
|
|
|
|
format,
|
2024-07-13 22:51:05 +00:00
|
|
|
|
color_state,
|
2021-09-22 00:01:41 +00:00
|
|
|
|
(guchar *) g_bytes_get_data (self->bytes, NULL),
|
|
|
|
|
self->stride,
|
2021-10-07 00:41:30 +00:00
|
|
|
|
texture->format,
|
2024-07-13 22:51:05 +00:00
|
|
|
|
texture->color_state,
|
2021-09-22 00:01:41 +00:00
|
|
|
|
gdk_texture_get_width (texture),
|
|
|
|
|
gdk_texture_get_height (texture));
|
2021-09-10 00:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-06 02:41:13 +00:00
|
|
|
|
static void
|
|
|
|
|
gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
|
|
texture_class->download = gdk_memory_texture_download;
|
2021-10-07 04:19:41 +00:00
|
|
|
|
|
2018-03-06 02:41:13 +00:00
|
|
|
|
gobject_class->dispose = gdk_memory_texture_dispose;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gdk_memory_texture_init (GdkMemoryTexture *self)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-11 19:18:56 +00:00
|
|
|
|
static GBytes *
|
|
|
|
|
gdk_memory_sanitize (GBytes *bytes,
|
|
|
|
|
int width,
|
|
|
|
|
int height,
|
|
|
|
|
GdkMemoryFormat format,
|
|
|
|
|
gsize stride,
|
|
|
|
|
gsize *out_stride)
|
|
|
|
|
{
|
|
|
|
|
gsize align, size, copy_stride, bpp;
|
|
|
|
|
const guchar *data;
|
|
|
|
|
guchar *copy;
|
|
|
|
|
int y;
|
|
|
|
|
|
|
|
|
|
data = g_bytes_get_data (bytes, &size);
|
|
|
|
|
align = gdk_memory_format_alignment (format);
|
|
|
|
|
|
|
|
|
|
if (GPOINTER_TO_SIZE (data) % align == 0 &&
|
|
|
|
|
stride % align == 0)
|
|
|
|
|
{
|
|
|
|
|
*out_stride = stride;
|
2024-08-11 02:23:15 +00:00
|
|
|
|
return bytes;
|
2021-09-11 19:18:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bpp = gdk_memory_format_bytes_per_pixel (format);
|
|
|
|
|
copy_stride = bpp * width;
|
|
|
|
|
/* align to multiples of 4, just to be sure */
|
|
|
|
|
copy_stride = (copy_stride + 3) & ~3;
|
|
|
|
|
copy = g_malloc (copy_stride * height);
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
|
memcpy (copy + y * copy_stride, data + y * stride, bpp * width);
|
|
|
|
|
|
2024-08-11 02:23:15 +00:00
|
|
|
|
g_bytes_unref (bytes);
|
|
|
|
|
|
2021-09-11 19:18:56 +00:00
|
|
|
|
*out_stride = copy_stride;
|
|
|
|
|
return g_bytes_new_take (copy, copy_stride * height);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-14 18:05:41 +00:00
|
|
|
|
GdkTexture *
|
|
|
|
|
gdk_memory_texture_new_from_builder (GdkMemoryTextureBuilder *builder)
|
|
|
|
|
{
|
|
|
|
|
GdkMemoryTexture *self;
|
|
|
|
|
GdkTexture *texture, *update_texture;
|
|
|
|
|
|
|
|
|
|
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
|
|
|
|
|
"width", gdk_memory_texture_builder_get_width (builder),
|
|
|
|
|
"height", gdk_memory_texture_builder_get_height (builder),
|
2024-07-14 19:52:00 +00:00
|
|
|
|
"color-state", gdk_memory_texture_builder_get_color_state (builder),
|
2024-07-14 18:05:41 +00:00
|
|
|
|
NULL);
|
|
|
|
|
texture = GDK_TEXTURE (self);
|
|
|
|
|
|
|
|
|
|
texture->format = gdk_memory_texture_builder_get_format (builder);
|
|
|
|
|
self->bytes = gdk_memory_sanitize (g_bytes_ref (gdk_memory_texture_builder_get_bytes (builder)),
|
|
|
|
|
texture->width,
|
|
|
|
|
texture->height,
|
|
|
|
|
texture->format,
|
|
|
|
|
gdk_memory_texture_builder_get_stride (builder),
|
|
|
|
|
&self->stride);
|
|
|
|
|
|
|
|
|
|
update_texture = gdk_memory_texture_builder_get_update_texture (builder);
|
|
|
|
|
if (update_texture)
|
|
|
|
|
{
|
|
|
|
|
cairo_region_t *update_region = gdk_memory_texture_builder_get_update_region (builder);
|
|
|
|
|
if (update_region)
|
|
|
|
|
{
|
|
|
|
|
update_region = cairo_region_copy (update_region);
|
|
|
|
|
cairo_region_intersect_rectangle (update_region,
|
|
|
|
|
&(cairo_rectangle_int_t) {
|
|
|
|
|
0, 0,
|
|
|
|
|
update_texture->width, update_texture->height
|
|
|
|
|
});
|
|
|
|
|
gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return GDK_TEXTURE (self);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-28 20:20:19 +00:00
|
|
|
|
/**
|
|
|
|
|
* gdk_memory_texture_new:
|
|
|
|
|
* @width: the width of the texture
|
|
|
|
|
* @height: the height of the texture
|
|
|
|
|
* @format: the format of the data
|
2021-02-21 05:13:57 +00:00
|
|
|
|
* @bytes: the `GBytes` containing the pixel data
|
2018-04-28 20:20:19 +00:00
|
|
|
|
* @stride: rowstride for the data
|
|
|
|
|
*
|
|
|
|
|
* Creates a new texture for a blob of image data.
|
2021-02-21 05:13:57 +00:00
|
|
|
|
*
|
2022-01-06 16:40:26 +00:00
|
|
|
|
* The `GBytes` must contain @stride × @height pixels
|
2018-04-28 20:20:19 +00:00
|
|
|
|
* in the given format.
|
|
|
|
|
*
|
2022-01-06 16:39:06 +00:00
|
|
|
|
* Returns: (type GdkMemoryTexture): A newly-created `GdkTexture`
|
2018-04-28 20:20:19 +00:00
|
|
|
|
*/
|
2018-03-06 02:41:13 +00:00
|
|
|
|
GdkTexture *
|
|
|
|
|
gdk_memory_texture_new (int width,
|
|
|
|
|
int height,
|
|
|
|
|
GdkMemoryFormat format,
|
|
|
|
|
GBytes *bytes,
|
|
|
|
|
gsize stride)
|
|
|
|
|
{
|
|
|
|
|
GdkMemoryTexture *self;
|
|
|
|
|
|
2021-09-11 19:18:56 +00:00
|
|
|
|
g_return_val_if_fail (width > 0, NULL);
|
|
|
|
|
g_return_val_if_fail (height > 0, NULL);
|
|
|
|
|
g_return_val_if_fail (bytes != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
|
2023-07-24 14:12:51 +00:00
|
|
|
|
/* needs to be this complex to support subtexture of the bottom right part */
|
2024-07-02 20:46:56 +00:00
|
|
|
|
g_return_val_if_fail (g_bytes_get_size (bytes) >= gdk_memory_format_min_buffer_size (format, stride, width, height), NULL);
|
2021-09-11 19:18:56 +00:00
|
|
|
|
|
2024-08-11 02:23:15 +00:00
|
|
|
|
bytes = gdk_memory_sanitize (g_bytes_ref (bytes), width, height, format, stride, &stride);
|
2021-09-11 19:18:56 +00:00
|
|
|
|
|
2018-03-06 02:41:13 +00:00
|
|
|
|
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
|
|
|
|
|
"width", width,
|
|
|
|
|
"height", height,
|
2024-06-17 17:10:56 +00:00
|
|
|
|
"color-state", GDK_COLOR_STATE_SRGB,
|
2018-03-06 02:41:13 +00:00
|
|
|
|
NULL);
|
|
|
|
|
|
2021-10-07 00:41:30 +00:00
|
|
|
|
GDK_TEXTURE (self)->format = format;
|
2021-09-11 19:18:56 +00:00
|
|
|
|
self->bytes = bytes;
|
2018-03-06 02:41:13 +00:00
|
|
|
|
self->stride = stride;
|
|
|
|
|
|
|
|
|
|
return GDK_TEXTURE (self);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-12 22:07:08 +00:00
|
|
|
|
GdkTexture *
|
|
|
|
|
gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
|
|
|
|
|
int x,
|
|
|
|
|
int y,
|
|
|
|
|
int width,
|
|
|
|
|
int height)
|
|
|
|
|
{
|
|
|
|
|
GdkTexture *texture, *result;
|
2024-07-02 20:46:56 +00:00
|
|
|
|
gsize offset, size;
|
2021-10-12 22:07:08 +00:00
|
|
|
|
GBytes *bytes;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE (source), NULL);
|
2023-02-13 00:08:53 +00:00
|
|
|
|
g_return_val_if_fail (x >= 0 && x < GDK_TEXTURE (source)->width, NULL);
|
|
|
|
|
g_return_val_if_fail (y >= 0 && y < GDK_TEXTURE (source)->height, NULL);
|
|
|
|
|
g_return_val_if_fail (width > 0 && x + width <= GDK_TEXTURE (source)->width, NULL);
|
|
|
|
|
g_return_val_if_fail (height > 0 && y + height <= GDK_TEXTURE (source)->height, NULL);
|
2021-10-12 22:07:08 +00:00
|
|
|
|
|
|
|
|
|
texture = GDK_TEXTURE (source);
|
2024-07-02 20:46:56 +00:00
|
|
|
|
offset = y * source->stride + x * gdk_memory_format_bytes_per_pixel (texture->format);
|
|
|
|
|
size = gdk_memory_format_min_buffer_size (texture->format, source->stride, width, height);
|
2021-10-12 22:07:08 +00:00
|
|
|
|
bytes = g_bytes_new_from_bytes (source->bytes, offset, size);
|
|
|
|
|
|
2022-05-08 17:53:04 +00:00
|
|
|
|
result = gdk_memory_texture_new (width,
|
|
|
|
|
height,
|
2021-10-12 22:07:08 +00:00
|
|
|
|
texture->format,
|
|
|
|
|
bytes,
|
|
|
|
|
source->stride);
|
|
|
|
|
g_bytes_unref (bytes);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-07 04:19:41 +00:00
|
|
|
|
GdkMemoryTexture *
|
2024-06-19 05:56:28 +00:00
|
|
|
|
gdk_memory_texture_from_texture (GdkTexture *texture)
|
2021-10-07 04:19:41 +00:00
|
|
|
|
{
|
|
|
|
|
GdkTexture *result;
|
|
|
|
|
GBytes *bytes;
|
|
|
|
|
guchar *data;
|
|
|
|
|
gsize stride;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
|
|
|
|
|
|
|
|
|
|
if (GDK_IS_MEMORY_TEXTURE (texture))
|
2024-06-19 05:56:28 +00:00
|
|
|
|
return g_object_ref (GDK_MEMORY_TEXTURE (texture));
|
2021-10-07 04:19:41 +00:00
|
|
|
|
|
2024-06-19 05:56:28 +00:00
|
|
|
|
stride = texture->width * gdk_memory_format_bytes_per_pixel (texture->format);
|
2021-10-07 04:19:41 +00:00
|
|
|
|
data = g_malloc_n (stride, texture->height);
|
|
|
|
|
|
2024-07-13 22:51:05 +00:00
|
|
|
|
gdk_texture_do_download (texture, texture->format, texture->color_state, data, stride);
|
2023-02-14 05:18:37 +00:00
|
|
|
|
bytes = g_bytes_new_take (data, stride * texture->height);
|
2021-10-07 04:19:41 +00:00
|
|
|
|
result = gdk_memory_texture_new (texture->width,
|
|
|
|
|
texture->height,
|
2024-06-19 05:56:28 +00:00
|
|
|
|
texture->format,
|
2021-10-07 04:19:41 +00:00
|
|
|
|
bytes,
|
|
|
|
|
stride);
|
|
|
|
|
g_bytes_unref (bytes);
|
|
|
|
|
|
|
|
|
|
return GDK_MEMORY_TEXTURE (result);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-14 05:18:37 +00:00
|
|
|
|
GBytes *
|
2023-02-14 06:45:52 +00:00
|
|
|
|
gdk_memory_texture_get_bytes (GdkMemoryTexture *self,
|
|
|
|
|
gsize *out_stride)
|
2023-02-14 05:18:37 +00:00
|
|
|
|
{
|
2023-02-14 06:45:52 +00:00
|
|
|
|
*out_stride = self->stride;
|
2023-02-14 05:18:37 +00:00
|
|
|
|
return self->bytes;
|
|
|
|
|
}
|
|
|
|
|
|