This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch edje-vector-intergration
in repository efl.
View the commit online.
commit 92a2a3d577590255160b0ac45bab067ed11ec43a
Author: [email protected] <[email protected]>
AuthorDate: Tue Apr 28 13:38:37 2026 -0600
edje: parse vector gradient geometry and stop blocks (Task 2.7)
Adds gradient_linear (start/end) and gradient_radial (center/focal/radius)
geometry handlers, a shared spread: parser (PAD|REFLECT|REPEAT), and
recursive stop {} blocks that append to the gradient's stops array.
Macros VG_GRAD_LINEAR_STATEMENTS, VG_GRAD_RADIAL_STATEMENTS, and
VG_GRAD_STOP_OPENERS replicate entries at every nesting depth, mirroring
the VG_SHAPE_STATEMENTS pattern from Task 2.6.
Also sets gradient.is_radial = 1 in _edje_vg_node_new for
EDJE_VG_NODE_GRADIENT_RADIAL so the runtime can distinguish kinds
without inspecting the node type at every callsite.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
src/bin/edje/edje_cc_handlers.c | 334 ++++++++++++++++++++++++++++++++++++++++
src/lib/edje/edje_vg_tree.c | 2 +
2 files changed, 336 insertions(+)
diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c
index 06fa22529d..be09f3f945 100644
--- a/src/bin/edje/edje_cc_handlers.c
+++ b/src/bin/edje/edje_cc_handlers.c
@@ -309,6 +309,17 @@ static void st_vg_shape_stroke_cap(void);
static void st_vg_shape_stroke_join(void);
static void st_vg_shape_stroke_dash(void);
static void st_vg_shape_fill_rule(void);
+/* Task 2.7: gradient geometry and stop handlers */
+static void st_vg_grad_start(void);
+static void st_vg_grad_end(void);
+static void st_vg_grad_center(void);
+static void st_vg_grad_focal(void);
+static void st_vg_grad_radius(void);
+static void st_vg_grad_spread(void);
+static void ob_vg_grad_stop(void);
+static void st_vg_grad_stop_offset(void);
+static void st_vg_grad_stop_color(void);
+static void st_vg_grad_stop_color_class(void);
static void ob_filters_filter(void);
static void ob_filters_filter_script(void);
@@ -717,6 +728,32 @@ static void _handle_vector_image(void);
{PFX "stroke.dash", st_vg_shape_stroke_dash}, /* dup */ \
{PFX "fill_rule", st_vg_shape_fill_rule}, /* dup */
+/* Task 2.7: gradient_linear-specific statements.
+ * PFX is the fully-qualified gradient_linear prefix with trailing dot. */
+#define VG_GRAD_LINEAR_STATEMENTS(PFX) \
+ {PFX "start", st_vg_grad_start}, /* dup */ \
+ {PFX "end", st_vg_grad_end}, /* dup */ \
+ {PFX "spread", st_vg_grad_spread}, /* dup */ \
+ {PFX "stop.offset", st_vg_grad_stop_offset}, /* dup */ \
+ {PFX "stop.color", st_vg_grad_stop_color}, /* dup */ \
+ {PFX "stop.color_class", st_vg_grad_stop_color_class}, /* dup */
+
+/* Task 2.7: gradient_radial-specific statements.
+ * PFX is the fully-qualified gradient_radial prefix with trailing dot. */
+#define VG_GRAD_RADIAL_STATEMENTS(PFX) \
+ {PFX "center", st_vg_grad_center}, /* dup */ \
+ {PFX "focal", st_vg_grad_focal}, /* dup */ \
+ {PFX "radius", st_vg_grad_radius}, /* dup */ \
+ {PFX "spread", st_vg_grad_spread}, /* dup */ \
+ {PFX "stop.offset", st_vg_grad_stop_offset}, /* dup */ \
+ {PFX "stop.color", st_vg_grad_stop_color}, /* dup */ \
+ {PFX "stop.color_class", st_vg_grad_stop_color_class}, /* dup */
+
+/* Expands stop openers for both gradient kinds at a given parent prefix.
+ * PARENT_PFX must end without a dot (e.g. "vectors.vector.gradient_linear"). */
+#define VG_GRAD_STOP_OPENERS(PARENT_PFX) \
+ {PARENT_PFX ".stop", ob_vg_grad_stop}, /* dup */
+
New_Statement_Handler statement_handlers[] =
{
{"id", st_id},
@@ -739,6 +776,15 @@ New_Statement_Handler statement_handlers[] =
VG_SHAPE_STATEMENTS("vectors.vector.container.shape.")
VG_SHAPE_STATEMENTS("vectors.vector.container.container.shape.")
VG_SHAPE_STATEMENTS("vectors.vector.container.container.container.shape.")
+ /* Task 2.7: gradient-specific statements — toplevel vectors.vector prefix. */
+ VG_GRAD_LINEAR_STATEMENTS("vectors.vector.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("vectors.vector.container.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("vectors.vector.container.container.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("vectors.vector.container.container.container.gradient_linear.")
+ VG_GRAD_RADIAL_STATEMENTS("vectors.vector.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("vectors.vector.container.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("vectors.vector.container.container.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("vectors.vector.container.container.container.gradient_radial.")
{
"data.item", st_data_item
},
@@ -767,6 +813,15 @@ New_Statement_Handler statement_handlers[] =
VG_SHAPE_STATEMENTS("collections.vectors.vector.container.shape.")
VG_SHAPE_STATEMENTS("collections.vectors.vector.container.container.shape.")
VG_SHAPE_STATEMENTS("collections.vectors.vector.container.container.container.shape.")
+ /* Task 2.7: gradient-specific statements — collections.vectors.vector prefix. */
+ VG_GRAD_LINEAR_STATEMENTS("collections.vectors.vector.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("collections.vectors.vector.container.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("collections.vectors.vector.container.container.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("collections.vectors.vector.container.container.container.gradient_linear.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.vectors.vector.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.vectors.vector.container.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.vectors.vector.container.container.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.vectors.vector.container.container.container.gradient_radial.")
{
"collections.base_scale", st_collections_base_scale
},
@@ -2120,6 +2175,267 @@ st_vg_shape_fill_rule(void)
free(s);
}
+/* -----------------------------------------------------------------------
+ * Task 2.7: Gradient-specific property handlers and stop block
+ *
+ * Geometry handlers (start/end, center/focal/radius) are type-specific.
+ * spread and stop statements are valid on both gradient kinds.
+ *
+ * Guard macros enforce node kind before writing any field.
+ * ----------------------------------------------------------------------- */
+
+#define EXPECT_GRADIENT_LINEAR() \
+ do { \
+ if (!current_vg_node || \
+ current_vg_node->type != EDJE_VG_NODE_GRADIENT_LINEAR) \
+ error_and_abort(NULL, "linear-gradient-only property on wrong node"); \
+ } while (0)
+
+#define EXPECT_GRADIENT_RADIAL() \
+ do { \
+ if (!current_vg_node || \
+ current_vg_node->type != EDJE_VG_NODE_GRADIENT_RADIAL) \
+ error_and_abort(NULL, "radial-gradient-only property on wrong node"); \
+ } while (0)
+
+#define EXPECT_GRADIENT_ANY() \
+ do { \
+ if (!current_vg_node || \
+ (current_vg_node->type != EDJE_VG_NODE_GRADIENT_LINEAR && \
+ current_vg_node->type != EDJE_VG_NODE_GRADIENT_RADIAL)) \
+ error_and_abort(NULL, "gradient-only property on non-gradient node"); \
+ } while (0)
+
+/**
+ * @page edcref
+ * @property
+ * start
+ * @parameters
+ * [x] [y]
+ * @effect
+ * Start point of a linear gradient in viewbox units.
+ * Only valid inside a gradient_linear {} block.
+ * @endproperty
+ */
+static void
+st_vg_grad_start(void)
+{
+ check_arg_count(2);
+ EXPECT_GRADIENT_LINEAR();
+ current_vg_node->gradient.x0 = parse_float(0);
+ current_vg_node->gradient.y0 = parse_float(1);
+}
+
+/**
+ * @page edcref
+ * @property
+ * end
+ * @parameters
+ * [x] [y]
+ * @effect
+ * End point of a linear gradient in viewbox units.
+ * Only valid inside a gradient_linear {} block.
+ * @endproperty
+ */
+static void
+st_vg_grad_end(void)
+{
+ check_arg_count(2);
+ EXPECT_GRADIENT_LINEAR();
+ current_vg_node->gradient.x1 = parse_float(0);
+ current_vg_node->gradient.y1 = parse_float(1);
+}
+
+/**
+ * @page edcref
+ * @property
+ * center
+ * @parameters
+ * [x] [y]
+ * @effect
+ * Center point of a radial gradient in viewbox units.
+ * Only valid inside a gradient_radial {} block.
+ * @endproperty
+ */
+static void
+st_vg_grad_center(void)
+{
+ check_arg_count(2);
+ EXPECT_GRADIENT_RADIAL();
+ current_vg_node->gradient.x0 = parse_float(0);
+ current_vg_node->gradient.y0 = parse_float(1);
+}
+
+/**
+ * @page edcref
+ * @property
+ * focal
+ * @parameters
+ * [x] [y]
+ * @effect
+ * Focal point of a radial gradient in viewbox units.
+ * Only valid inside a gradient_radial {} block.
+ * @endproperty
+ */
+static void
+st_vg_grad_focal(void)
+{
+ check_arg_count(2);
+ EXPECT_GRADIENT_RADIAL();
+ current_vg_node->gradient.x1 = parse_float(0);
+ current_vg_node->gradient.y1 = parse_float(1);
+}
+
+/**
+ * @page edcref
+ * @property
+ * radius
+ * @parameters
+ * [float]
+ * @effect
+ * Radius of a radial gradient in viewbox units.
+ * Only valid inside a gradient_radial {} block.
+ * @endproperty
+ */
+static void
+st_vg_grad_radius(void)
+{
+ check_arg_count(1);
+ EXPECT_GRADIENT_RADIAL();
+ current_vg_node->gradient.radius = parse_float(0);
+}
+
+/**
+ * @page edcref
+ * @property
+ * spread
+ * @parameters
+ * [PAD|REFLECT|REPEAT]
+ * @effect
+ * Spread method applied outside the gradient bounds.
+ * PAD repeats the terminal stop color; REFLECT mirrors the gradient;
+ * REPEAT tiles it. Default is PAD.
+ * Valid on both gradient_linear and gradient_radial nodes.
+ * @endproperty
+ */
+static void
+st_vg_grad_spread(void)
+{
+ check_arg_count(1);
+ EXPECT_GRADIENT_ANY();
+ char *s = parse_str(0);
+ if (!strcmp(s, "PAD")) current_vg_node->gradient.spread = EFL_GFX_GRADIENT_SPREAD_PAD;
+ else if (!strcmp(s, "REFLECT")) current_vg_node->gradient.spread = EFL_GFX_GRADIENT_SPREAD_REFLECT;
+ else if (!strcmp(s, "REPEAT")) current_vg_node->gradient.spread = EFL_GFX_GRADIENT_SPREAD_REPEAT;
+ else
+ {
+ free(s);
+ error_and_abort(NULL, "spread: unknown value (PAD|REFLECT|REPEAT)");
+ }
+ free(s);
+}
+
+/**
+ * @page edcref
+ * @block
+ * stop
+ * @context
+ * gradient_linear, gradient_radial
+ * @description
+ * Defines one color stop in the gradient. Each stop {} block appends
+ * a new entry to the gradient's stop list. Stops are ordered by the
+ * offset value; ordering is not enforced at parse time (VEC004 is
+ * Phase 7).
+ * @endblock
+ */
+static void
+ob_vg_grad_stop(void)
+{
+ EXPECT_GRADIENT_ANY();
+ unsigned int n = current_vg_node->gradient.stops_count + 1;
+ Edje_Vg_Stop *bigger = realloc(current_vg_node->gradient.stops,
+ n * sizeof(Edje_Vg_Stop));
+ if (!bigger) error_and_abort(NULL, "OOM growing gradient stops array");
+ memset(&bigger[n - 1], 0, sizeof(Edje_Vg_Stop));
+ /* Default stop color: opaque white, matching node color default. */
+ bigger[n - 1].color.r = bigger[n - 1].color.g =
+ bigger[n - 1].color.b = bigger[n - 1].color.a = 255;
+ current_vg_node->gradient.stops = bigger;
+ current_vg_node->gradient.stops_count = n;
+ /* The active stop is the last element; stop {} has no sub-blocks so
+ no stack push is needed. Statements write to [stops_count - 1]. */
+}
+
+/* Returns a pointer to the last stop in current_vg_node's stops array.
+ * Aborts if there is no active gradient or no stop has been opened. */
+static Edje_Vg_Stop *
+_current_stop(void)
+{
+ EXPECT_GRADIENT_ANY();
+ if (current_vg_node->gradient.stops_count == 0)
+ error_and_abort(NULL, "stop property used before any stop {} block");
+ return ¤t_vg_node->gradient.stops[current_vg_node->gradient.stops_count - 1];
+}
+
+/**
+ * @page edcref
+ * @property
+ * offset
+ * @parameters
+ * [float 0.0-1.0]
+ * @effect
+ * Position of this stop along the gradient axis. Must be in [0.0, 1.0].
+ * @endproperty
+ */
+static void
+st_vg_grad_stop_offset(void)
+{
+ check_arg_count(1);
+ _current_stop()->offset = parse_float_range(0, 0.0, 1.0);
+}
+
+/**
+ * @page edcref
+ * @property
+ * color
+ * @parameters
+ * [red] [green] [blue] [alpha]
+ * @effect
+ * Base color of this gradient stop as non-premultiplied RGBA integers
+ * each in [0, 255]. Default is 255 255 255 255.
+ * @endproperty
+ */
+static void
+st_vg_grad_stop_color(void)
+{
+ check_arg_count(4);
+ Edje_Vg_Stop *s = _current_stop();
+ s->color.r = parse_int_range(0, 0, 255);
+ s->color.g = parse_int_range(1, 0, 255);
+ s->color.b = parse_int_range(2, 0, 255);
+ s->color.a = parse_int_range(3, 0, 255);
+}
+
+/**
+ * @page edcref
+ * @property
+ * color_class
+ * @parameters
+ * [string]
+ * @effect
+ * Associates a color class with this stop's color slot. At runtime
+ * the resolved class value overrides the base color.
+ * @endproperty
+ */
+static void
+st_vg_grad_stop_color_class(void)
+{
+ check_arg_count(1);
+ char *str = parse_str(0);
+ eina_stringshare_replace(&_current_stop()->color.color_class, str);
+ free(str);
+}
+
#define PROGRAM_OBJECTS(PREFIX) \
{PREFIX ".program", ob_collections_group_programs_program}, /* dup */ \
{PREFIX ".program.script", ob_collections_group_programs_program_script}, /* dup */ \
@@ -2167,6 +2483,15 @@ New_Object_Handler object_handlers[] =
VG_NODE_OPENERS("vectors.vector.container.")
VG_NODE_OPENERS("vectors.vector.container.container.")
VG_NODE_OPENERS("vectors.vector.container.container.container.")
+ /* Task 2.7: stop block openers for gradients at every nesting depth. */
+ VG_GRAD_STOP_OPENERS("vectors.vector.gradient_linear")
+ VG_GRAD_STOP_OPENERS("vectors.vector.gradient_radial")
+ VG_GRAD_STOP_OPENERS("vectors.vector.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("vectors.vector.container.gradient_radial")
+ VG_GRAD_STOP_OPENERS("vectors.vector.container.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("vectors.vector.container.container.gradient_radial")
+ VG_GRAD_STOP_OPENERS("vectors.vector.container.container.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("vectors.vector.container.container.container.gradient_radial")
{"text_classes", NULL},
{"text_classes.text_class", ob_text_class},
{"size_classes", NULL},
@@ -2195,6 +2520,15 @@ New_Object_Handler object_handlers[] =
VG_NODE_OPENERS("collections.vectors.vector.container.")
VG_NODE_OPENERS("collections.vectors.vector.container.container.")
VG_NODE_OPENERS("collections.vectors.vector.container.container.container.")
+ /* Task 2.7: stop block openers for gradients at every nesting depth. */
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.gradient_radial")
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.container.gradient_radial")
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.container.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.container.container.gradient_radial")
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.container.container.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.vectors.vector.container.container.container.gradient_radial")
{"collections.text_classes", NULL},
{"collections.text_classes.text_class", ob_text_class}, /* dup */
{"collections.size_classes", NULL}, /* dup */
diff --git a/src/lib/edje/edje_vg_tree.c b/src/lib/edje/edje_vg_tree.c
index f535d15a42..94395737e5 100644
--- a/src/lib/edje/edje_vg_tree.c
+++ b/src/lib/edje/edje_vg_tree.c
@@ -244,6 +244,8 @@ _edje_vg_node_new(Edje_Vg_Node_Type type)
n->shape.stroke_join = EFL_GFX_JOIN_MITER;
n->shape.fill_rule = EFL_GFX_FILL_RULE_WINDING;
}
+ else if (type == EDJE_VG_NODE_GRADIENT_RADIAL)
+ n->gradient.is_radial = 1; /* Task 2.7: disambiguate at runtime */
return n;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.