[gegl] buffer: add gegl_tile_backend_command(); pre-0.4.10 compatibility
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] buffer: add gegl_tile_backend_command(); pre-0.4.10 compatibility
- Date: Sun, 19 Aug 2018 23:40:27 +0000 (UTC)
commit 30047e65723ebb44fcde9c6b5f60ceecb43b0895
Author: Ell <ell_se yahoo com>
Date: Sun Aug 19 19:19:37 2018 -0400
buffer: add gegl_tile_backend_command(); pre-0.4.10 compatibility
Tile backends currently assert in their command handlers that the
input command is between 0 and GEGL_TILE_LAST_COMMAND (this is true
for the built-in backends, but we can assume it's also true for
custom backends.) This prevents us from adding new tile commands
without breaking the ABI.
Instead, add a new gegl_tile_backend_command() function, which acts
as a default command handler for tile backends, and to which their
handlers should forward unhandled commands (this function currently
simply performs the range check for the command -- however, against
the GEGL_TILE_LAST_COMMAND value of the runtime GEGL -- and returns
NULL; we can add differet default behaviors for different commands
as necessary.)
In order to remain backward compatible with tile backends compiled
against older versions of GEGL, which still contain the above
assertion, we replace the subclass's command handler with a thunk
upon construction, which tests whether the original handler
forwards unhandled commands to gegl_tile_backend_command(), and re-
replaces the handler with either the original handler if it does,
or a compatibility shim, which only forwards pre-0.4.10 commands to
the original handler, if it doesn't.
gegl/buffer/gegl-buffer-backend.h | 6 ++-
gegl/buffer/gegl-buffer-types.h | 20 +++----
gegl/buffer/gegl-tile-backend.c | 108 ++++++++++++++++++++++++++++++++++++++
gegl/buffer/gegl-tile-backend.h | 21 ++++++++
4 files changed, 145 insertions(+), 10 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-backend.h b/gegl/buffer/gegl-buffer-backend.h
index b2cee230f..f7a415f58 100644
--- a/gegl/buffer/gegl-buffer-backend.h
+++ b/gegl/buffer/gegl-buffer-backend.h
@@ -46,7 +46,11 @@ typedef enum
GEGL_TILE_FLUSH,
GEGL_TILE_REFETCH,
GEGL_TILE_REINIT,
- GEGL_TILE_COPY,
+
+ _GEGL_TILE_LAST_0_4_8_COMMAND,
+
+ GEGL_TILE_COPY = _GEGL_TILE_LAST_0_4_8_COMMAND,
+
GEGL_TILE_LAST_COMMAND
} GeglTileCommand;
diff --git a/gegl/buffer/gegl-buffer-types.h b/gegl/buffer/gegl-buffer-types.h
index c6d8333c0..9d55db2e2 100644
--- a/gegl/buffer/gegl-buffer-types.h
+++ b/gegl/buffer/gegl-buffer-types.h
@@ -30,18 +30,20 @@
struct _GeglTileBackendPrivate
{
- gint tile_width;
- gint tile_height;
- const Babl *format; /* defaults to the babl format "R'G'B'A u8" */
- gint px_size; /* size of a single pixel in bytes */
- gint tile_size; /* size of an entire tile in bytes */
+ gint tile_width;
+ gint tile_height;
+ const Babl *format; /* defaults to the babl format "R'G'B'A u8" */
+ gint px_size; /* size of a single pixel in bytes */
+ gint tile_size; /* size of an entire tile in bytes */
- gboolean flush_on_destroy;
+ gboolean flush_on_destroy;
- GeglRectangle extent;
+ GeglRectangle extent;
- gpointer storage;
- gboolean shared;
+ gpointer storage;
+ gboolean shared;
+
+ GeglTileSourceCommand command;
};
typedef struct _GeglTileHandlerChain GeglTileHandlerChain;
diff --git a/gegl/buffer/gegl-tile-backend.c b/gegl/buffer/gegl-tile-backend.c
index 03c5a854b..720fa5ffc 100644
--- a/gegl/buffer/gegl-tile-backend.c
+++ b/gegl/buffer/gegl-tile-backend.c
@@ -115,10 +115,93 @@ set_property (GObject *gobject,
}
}
+/* before 0.4.10, tile backends used to assert that
+ * '0 <= command < GEGL_TILE_LAST_COMMAND' in their command handlers, which
+ * prevented us from adding new tile commands without breaking the abi, since
+ * GEGL_TILE_LAST_COMMAND is a compile-time constant. tile backends are now
+ * expected to forward unhandled commands to gegl_tile_backend_command()
+ * instead.
+ *
+ * in order to keep supporting tile backends that were compiled against 0.4.8
+ * or earlier, we replace the backend's command handler with a thunk
+ * (tile_command_check_0_4_8()) upon construction, which tests whether the
+ * backend forwards unhandled commands to gegl_tile_backend_command(), and
+ * subsequently replaces the command handler with either the original command
+ * handler if it does, or a compatibility shim (tile_command()) if it doesn't.
+ */
+
+/* this is the actual default command handler, called by
+ * gegl_tile_backend_command(). currently, it simply validates the command
+ * range, and returns NULL to any command. we can add special behavior for
+ * different commands as needed.
+ */
+static inline gpointer
+_gegl_tile_backend_command (GeglTileBackend *backend,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data)
+{
+ g_return_val_if_fail (command >= 0 && command < GEGL_TILE_LAST_COMMAND, NULL);
+
+ return NULL;
+}
+
+/* this is a compatibility shim for backends compiled against 0.4.8 or earlier.
+ * it forwards commands that were present in these versions to the original
+ * handler, and newer commands to the default handler.
+ */
+static gpointer
+tile_command (GeglTileSource *source,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data)
+{
+ GeglTileBackend *backend = GEGL_TILE_BACKEND (source);
+
+ if (command < _GEGL_TILE_LAST_0_4_8_COMMAND)
+ return backend->priv->command (source, command, x, y, z, data);
+
+ return _gegl_tile_backend_command (backend, command, x, y, z, data);
+}
+
+/* this is a thunk, testing whether the backend forwards unhandled commands to
+ * gegl_tile_backend_command(). if it does, we replace the thunk by the
+ * original handler; if it doesn't, we assume the backend can't handle post-
+ * 0.4.8 commands, and replace the thunk with the compatibility shim.
+ */
+static gpointer
+tile_command_check_0_4_8 (GeglTileSource *source,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data)
+{
+ GeglTileBackend *backend = GEGL_TILE_BACKEND (source);
+
+ /* start by replacing the thunk by the compatibility shim */
+ source->command = tile_command;
+
+ /* pass the original handler a dummy command. we use GEGL_TILE_IS_CACHED,
+ * since backends shouldn't handle this command. if the handler forwards the
+ * command to gegl_tile_backend_command(), it will replace the shim by the
+ * original handler.
+ */
+ backend->priv->command (source, GEGL_TILE_IS_CACHED, 0, 0, 0, NULL);
+
+ /* forward the command to either the shim or the original handler */
+ return source->command (source, command, x, y, z, data);
+}
+
static void
constructed (GObject *object)
{
GeglTileBackend *backend = GEGL_TILE_BACKEND (object);
+ GeglTileSource *source = GEGL_TILE_SOURCE (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
@@ -127,6 +210,9 @@ constructed (GObject *object)
backend->priv->px_size = babl_format_get_bytes_per_pixel (backend->priv->format);
backend->priv->tile_size = backend->priv->tile_width * backend->priv->tile_height * backend->priv->px_size;
+
+ backend->priv->command = source->command;
+ source->command = tile_command_check_0_4_8;
}
static void
@@ -242,6 +328,28 @@ gegl_tile_backend_get_flush_on_destroy (GeglTileBackend *tile_backend)
return tile_backend->priv->flush_on_destroy;
}
+gpointer
+gegl_tile_backend_command (GeglTileBackend *backend,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data)
+{
+ /* we've been called during the tile_command() test, which means the backend
+ * is post-0.4.8 compatible. replace the shim with the original handler.
+ */
+ if (backend->priv->command)
+ {
+ GeglTileSource *source = GEGL_TILE_SOURCE (backend);
+
+ source->command = backend->priv->command;
+ backend->priv->command = NULL;
+ }
+
+ return _gegl_tile_backend_command (backend, command, x, y, z, data);
+}
+
void
gegl_tile_backend_unlink_swap (gchar *path)
{
diff --git a/gegl/buffer/gegl-tile-backend.h b/gegl/buffer/gegl-tile-backend.h
index 3f0224993..3d1f806a2 100644
--- a/gegl/buffer/gegl-tile-backend.h
+++ b/gegl/buffer/gegl-tile-backend.h
@@ -121,6 +121,27 @@ void gegl_tile_backend_set_flush_on_destroy (GeglTileBackend *tile_backend,
gboolean gegl_tile_backend_get_flush_on_destroy (GeglTileBackend *tile_backend);
+/**
+ * gegl_tile_backend_command:
+ * @backend: a #GeglTileBackend
+ * @command: the tile command
+ * @x: x coordinate
+ * @y: y coordinate
+ * @z: tile zoom level
+ * @data: user data
+ *
+ * The default tile-backend command handler. Tile backends should forward
+ * commands they don't handle themselves to this function.
+ *
+ * Returns: Command result.
+ */
+gpointer gegl_tile_backend_command (GeglTileBackend *backend,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data);
+
GType gegl_tile_backend_get_type (void) G_GNUC_CONST;
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]