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 e30a8745aa9cacd5e2dfe4ceebd46074d9beccc8
Author: [email protected] <[email protected]>
AuthorDate: Tue Apr 28 15:12:42 2026 -0600
edje: add vector.use and inline vector{} description authoring (Task 2.8)
Extend Edje descriptions to reference or declare vector trees. Mode A
(vector.use: "name") looks up a tree from toplevel vectors{}; Mode B
(inline vector{}) declares a private tree directly in the description.
Introduce _vg_desc_to_tree side table (pointer-keyed Eina_Hash) to
record description-tree linkages. Task 2.9's serializer reads this to
assign sequential tree_ids after all trees are declared. The side table
is NULL-data-free and freed in _edje_cc_vg_cleanup (still __attribute__
((unused)) until 2.9 wires the call site).
Mode A reuses vg.set boolean (set by _handle_vector_image) to detect
Mode C conflict (image.normal:) instead of checking vg.id >= 0 —
semantically clearer that the flag reflects explicit intent.
Mode B registers VG_* statement and object macros under the inline
vector{} prefix, reusing handlers. Inline trees gain viewbox support by
re-registering st_vectors_vector_viewbox under the inline path.
Runtime still falls through to legacy SVG code for VECTOR parts; Phase 3
will enable tree rendering.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
src/bin/edje/edje_cc_handlers.c | 195 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 192 insertions(+), 3 deletions(-)
diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c
index be09f3f945..b9b9c1e82d 100644
--- a/src/bin/edje/edje_cc_handlers.c
+++ b/src/bin/edje/edje_cc_handlers.c
@@ -182,6 +182,21 @@ static Eina_Array *current_vg_node_stack = NULL;
static Eina_Hash *toplevel_vg_trees = NULL;
static Eina_List *all_vg_trees = NULL;
+/* Task 2.8: maps Edje_Part_Description_Vector* (key, by pointer) to
+ * Edje_Vg_Tree* (value, borrowed). Populated by Mode A (vector.use:) and
+ * Mode B (inline vector{}) handlers; read by Task 2.9's serializer to patch
+ * desc->vg.tree_id after sequential indices are assigned. */
+static Eina_Hash *_vg_desc_to_tree = NULL;
+
+/* Record a description → tree linkage in the side table. */
+static void
+_vg_record_use(Edje_Part_Description_Vector *ed, Edje_Vg_Tree *t)
+{
+ if (!_vg_desc_to_tree)
+ _vg_desc_to_tree = eina_hash_pointer_new(NULL);
+ eina_hash_add(_vg_desc_to_tree, &ed, t);
+}
+
/* Used after Task 2.9. */
static void __attribute__((unused))
_edje_cc_vg_cleanup(void)
@@ -191,14 +206,16 @@ _edje_cc_vg_cleanup(void)
shallow-copy with src->root nullified. The Eina_List wrappers in
all_vg_trees were freed by the same function. So here we only release
our parser-side scaffolding: the toplevel-name hash (borrowed pointers,
- NULL data-free), the node stack (also borrowed), and reset the static
- pointers. */
+ NULL data-free), the node stack (also borrowed), the desc-to-tree side
+ table, and reset the static pointers. */
if (current_vg_node_stack) eina_array_free(current_vg_node_stack);
if (toplevel_vg_trees) eina_hash_free(toplevel_vg_trees);
+ if (_vg_desc_to_tree) eina_hash_free(_vg_desc_to_tree);
current_vg_tree = NULL;
current_vg_node = NULL;
current_vg_node_stack = NULL;
toplevel_vg_trees = NULL;
+ _vg_desc_to_tree = NULL;
all_vg_trees = NULL;
}
@@ -560,6 +577,10 @@ static void st_collections_group_parts_part_description_params_smart(void)
/* vector part parameter */
static void st_collections_group_parts_part_description_vector_frame(void);
+/* Task 2.8: Mode A (vector.use:) and Mode B (inline vector{}) */
+static void st_collections_group_parts_part_description_vector_use(void);
+static void ob_collections_group_parts_part_description_vector(void);
+static void _vg_inline_block_end(void);
static void ob_collections_group_programs_program(void);
static void st_collections_group_programs_program_name(void);
@@ -1106,6 +1127,27 @@ New_Statement_Handler statement_handlers[] =
{"collections.group.parts.part.description.params.choice", st_collections_group_parts_part_description_params_choice},
{"collections.group.parts.part.description.params.*", st_collections_group_parts_part_description_params_smart},
{"collections.group.parts.part.description.vector.frame", st_collections_group_parts_part_description_vector_frame},
+ /* Task 2.8: Mode A — reference a named toplevel tree. */
+ {"collections.group.parts.part.description.vector.use", st_collections_group_parts_part_description_vector_use},
+ /* Task 2.8: Mode B — inline tree; node/property statements at inline prefix. */
+ VG_NODE_ALL_KINDS_STATEMENTS("collections.group.parts.part.description.vector.")
+ VG_NODE_ALL_KINDS_STATEMENTS("collections.group.parts.part.description.vector.container.")
+ VG_NODE_ALL_KINDS_STATEMENTS("collections.group.parts.part.description.vector.container.container.")
+ VG_NODE_ALL_KINDS_STATEMENTS("collections.group.parts.part.description.vector.container.container.container.")
+ VG_SHAPE_STATEMENTS("collections.group.parts.part.description.vector.shape.")
+ VG_SHAPE_STATEMENTS("collections.group.parts.part.description.vector.container.shape.")
+ VG_SHAPE_STATEMENTS("collections.group.parts.part.description.vector.container.container.shape.")
+ VG_SHAPE_STATEMENTS("collections.group.parts.part.description.vector.container.container.container.shape.")
+ VG_GRAD_LINEAR_STATEMENTS("collections.group.parts.part.description.vector.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("collections.group.parts.part.description.vector.container.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("collections.group.parts.part.description.vector.container.container.gradient_linear.")
+ VG_GRAD_LINEAR_STATEMENTS("collections.group.parts.part.description.vector.container.container.container.gradient_linear.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.group.parts.part.description.vector.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.group.parts.part.description.vector.container.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.group.parts.part.description.vector.container.container.gradient_radial.")
+ VG_GRAD_RADIAL_STATEMENTS("collections.group.parts.part.description.vector.container.container.container.gradient_radial.")
+ /* Task 2.8: inline tree viewbox: property (reuse toplevel handler). */
+ {"collections.group.parts.part.description.vector.viewbox", st_vectors_vector_viewbox},
IMAGE_STATEMENTS("collections.group.parts.part.description.")
{
"collections.group.parts.part.description.font", st_fonts_font
@@ -2646,7 +2688,20 @@ New_Object_Handler object_handlers[] =
{"collections.group.parts.part.description.map.zoom", NULL},
{"collections.group.parts.part.description.perspective", NULL},
{"collections.group.parts.part.description.params", NULL},
- {"collections.group.parts.part.description.vector", NULL},
+ /* Task 2.8: Mode B inline vector{} opener and its nested node openers. */
+ {"collections.group.parts.part.description.vector", ob_collections_group_parts_part_description_vector},
+ VG_NODE_OPENERS("collections.group.parts.part.description.vector.")
+ VG_NODE_OPENERS("collections.group.parts.part.description.vector.container.")
+ VG_NODE_OPENERS("collections.group.parts.part.description.vector.container.container.")
+ VG_NODE_OPENERS("collections.group.parts.part.description.vector.container.container.container.")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.gradient_radial")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.container.gradient_radial")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.container.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.container.container.gradient_radial")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.container.container.container.gradient_linear")
+ VG_GRAD_STOP_OPENERS("collections.group.parts.part.description.vector.container.container.container.gradient_radial")
{"collections.group.parts.part.description.color_classes", NULL}, /* dup */
{"collections.group.parts.part.description.color_classes.color_class", ob_color_class}, /* dup */
{"collections.group.parts.part.description.text_classes", NULL}, /* dup */
@@ -2738,6 +2793,12 @@ New_Nested_Handler nested_handlers[] = {
VG_NODE_NESTED_AT("collections.vectors.vector.container")
VG_NODE_NESTED_AT("collections.vectors.vector.container.container")
VG_NODE_NESTED_AT("collections.vectors.vector.container.container.container")
+ /* Task 2.8: inline vector{} block close + nested node closes. */
+ {"collections.group.parts.part.description", "vector", NULL, _vg_inline_block_end },
+ VG_NODE_NESTED_AT("collections.group.parts.part.description.vector")
+ VG_NODE_NESTED_AT("collections.group.parts.part.description.vector.container")
+ VG_NODE_NESTED_AT("collections.group.parts.part.description.vector.container.container")
+ VG_NODE_NESTED_AT("collections.group.parts.part.description.vector.container.container.container")
};
New_Nested_Handler nested_handlers_short[] = {
@@ -14719,6 +14780,134 @@ st_collections_group_parts_part_description_vector_frame(void)
ed->vg.frame = parse_float_range(0, 0.0, 1.0);
}
+/**
+ @page edcref
+
+ @property
+ vector.use
+ @parameters
+ [name]
+ @effect
+ References a tree declared in a toplevel @c vectors {} block by its
+ @c name: identifier. The description will render using that shared
+ tree (Mode A). Mutually exclusive with an inline @c vector {} block
+ inside the same description and with @c image.normal: (Mode C).
+ @since 1.27
+ @endproperty
+ */
+static void
+st_collections_group_parts_part_description_vector_use(void)
+{
+ Edje_Part_Description_Vector *ed;
+ char *name;
+ Edje_Vg_Tree *t;
+
+ check_arg_count(1);
+
+ if (current_part->type != EDJE_PART_TYPE_VECTOR)
+ {
+ ERR("parse error %s:%i. vector.use: only valid on VECTOR parts.",
+ file_in, line - 1);
+ exit(-1);
+ }
+
+ ed = (Edje_Part_Description_Vector *)current_desc;
+
+ /* VEC006: detect mode conflicts with Mode C (image.normal:). */
+ if (ed->vg.set)
+ error_and_abort(NULL, "vector.use: conflicts with image.normal: on the same description (VEC006)");
+
+ /* VEC006: detect duplicate Mode A/B use. */
+ if (_vg_desc_to_tree && eina_hash_find(_vg_desc_to_tree, &ed))
+ error_and_abort(NULL, "vector.use: conflicts with a prior vector.use: or inline vector{} on the same description (VEC006)");
+
+ name = parse_str(0);
+
+ /* VEC005: tree must have been declared. */
+ if (!toplevel_vg_trees)
+ {
+ error_and_abort(NULL, "vector.use: '%s' — no toplevel vectors{} block has been declared (VEC005)", name);
+ }
+ t = eina_hash_find(toplevel_vg_trees, name);
+ if (!t)
+ {
+ error_and_abort(NULL, "vector.use: unknown tree name '%s' (VEC005)", name);
+ }
+
+ /* Record linkage; tree_id stays -1 until Task 2.9's serializer assigns it. */
+ _vg_record_use(ed, t);
+
+ free(name);
+}
+
+/**
+ @page edcref
+
+ @block
+ vector
+ @context
+ description {
+ ..
+ vector {
+ viewbox: 0 0 100 100;
+ shape { path: "M0,0 L100,0 L100,100 Z"; fill.color: 255 0 0 255; }
+ }
+ }
+ @description
+ Inline vector tree declared directly inside a description block (Mode B).
+ Has the same syntax as a toplevel @c vector {} block inside @c vectors {}
+ but the tree is private to this description and not reused by others.
+ Mutually exclusive with @c vector.use: and @c image.normal: on the same
+ description.
+ @since 1.27
+ @endblock
+ */
+static void
+ob_collections_group_parts_part_description_vector(void)
+{
+ Edje_Part_Description_Vector *ed;
+ Edje_Vg_Tree *t;
+
+ if (current_part->type != EDJE_PART_TYPE_VECTOR)
+ {
+ ERR("parse error %s:%i. inline vector{} only valid on VECTOR descriptions.",
+ file_in, line - 1);
+ exit(-1);
+ }
+
+ ed = (Edje_Part_Description_Vector *)current_desc;
+
+ /* VEC006: detect mode conflicts with Mode C (image.normal:). */
+ if (ed->vg.set)
+ error_and_abort(NULL, "inline vector{} conflicts with image.normal: on the same description (VEC006)");
+
+ /* VEC006: detect duplicate Mode A/B use. */
+ if (_vg_desc_to_tree && eina_hash_find(_vg_desc_to_tree, &ed))
+ error_and_abort(NULL, "inline vector{} conflicts with a prior vector.use: or vector{} on the same description (VEC006)");
+
+ t = _edje_vg_tree_new();
+ if (!t) error_and_abort(NULL, "OOM building inline vector tree");
+ all_vg_trees = eina_list_append(all_vg_trees, t);
+ _vg_record_use(ed, t);
+
+ /* Set parser context so subsequent node/property handlers populate this tree. */
+ current_vg_tree = t;
+ current_vg_node = t->root;
+ if (!current_vg_node_stack)
+ current_vg_node_stack = eina_array_new(8);
+ eina_array_clean(current_vg_node_stack);
+}
+
+/* Called when the inline vector{} block closes — clear parser context.
+ * The tree itself stays in all_vg_trees and is owned by Task 2.9. */
+static void
+_vg_inline_block_end(void)
+{
+ current_vg_tree = NULL;
+ current_vg_node = NULL;
+ if (current_vg_node_stack) eina_array_clean(current_vg_node_stack);
+}
+
/** @edcsubsection{collections_group_parts_description_links,
* Group.Parts.Part.Description.Links} */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.