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 447bff1054515baafe6fced8f03b1c363feeb909
Author: [email protected] <[email protected]>
AuthorDate: Tue Apr 28 15:59:14 2026 -0600
edje: serialize vector trees into .edj and patch tree_ids (Task 2.9)
Write all authored vector trees collected by the parser into separate
edje/vector_trees/<i> eet entries and build Edje_Vg_Directory with a
flat tree array. Each Edje_Part_Description_Vector now points to its
tree via vg.tree_id, resolved via a desc-to-tree side table built
during parsing in _vg_record_use (Task 2.8).
Key design points:
- Three new cross-file accessors (edje_cc_handlers.c → edje_cc_out.c):
_edje_cc_vg_all_trees_get, _edje_cc_vg_desc_to_tree_get, _edje_cc_vg_cleanup.
Parser state (all_vg_trees, _vg_desc_to_tree) is authoring-side only;
serializer needs read-only access and ownership transfer on cleanup.
- eina_hash_pointer_new indexes trees by pointer-to-pointer (&src, &t).
When storing a key, eina memcpys sizeof(intptr_t) from the key argument.
Both index-building and lookup sides must pass addresses consistently:
add with eina_hash_add(map, &tree_ptr, ...), find with
eina_hash_find(map, &tree_ptr, ...). The desc-to-tree hash (built in
_vg_record_use) uses the same convention for lookups in data_write_vectors_trees.
- Trees are shallow-copied into vd->trees[] and src->root is nullified
to keep cleanup single-owner: _edje_cc_vg_cleanup frees only the
list wrappers; the nodes now belong to vector_dir.
- Each tree's color_class names are collected recursively and
stringshared into vd->class_names[] for runtime override binding.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
src/bin/edje/edje_cc.h | 5 +
src/bin/edje/edje_cc_handlers.c | 43 +++++++--
src/bin/edje/edje_cc_out.c | 207 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 245 insertions(+), 10 deletions(-)
diff --git a/src/bin/edje/edje_cc.h b/src/bin/edje/edje_cc.h
index d7063ef466..75c1b86328 100644
--- a/src/bin/edje/edje_cc.h
+++ b/src/bin/edje/edje_cc.h
@@ -300,6 +300,11 @@ int get_param_index(char *str);
void color_tree_root_free(void);
void convert_color_code(char *str, int *r, int *g, int *b, int *a);
+/* Vector-tree parser accessors (Task 2.9) */
+Eina_List *_edje_cc_vg_all_trees_get(void);
+Eina_Hash *_edje_cc_vg_desc_to_tree_get(void);
+void _edje_cc_vg_cleanup(void);
+
void script_rewrite(Code *code);
/* global vars */
diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c
index b9b9c1e82d..4b97083dbb 100644
--- a/src/bin/edje/edje_cc_handlers.c
+++ b/src/bin/edje/edje_cc_handlers.c
@@ -197,17 +197,41 @@ _vg_record_use(Edje_Part_Description_Vector *ed, Edje_Vg_Tree *t)
eina_hash_add(_vg_desc_to_tree, &ed, t);
}
-/* Used after Task 2.9. */
-static void __attribute__((unused))
+Eina_List *
+_edje_cc_vg_all_trees_get(void)
+{
+ return all_vg_trees;
+}
+
+Eina_Hash *
+_edje_cc_vg_desc_to_tree_get(void)
+{
+ return _vg_desc_to_tree;
+}
+
+void
_edje_cc_vg_cleanup(void)
{
- /* Trees themselves are owned by Phase 2.9's data_write_vectors_trees() at
- this point — they've been moved into edje_file->vector_dir->trees[] by
- 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), the desc-to-tree side
- table, and reset the static pointers. */
+ /* Trees themselves: data_write_vectors_trees() has shallow-copied each
+ Edje_Vg_Tree struct into the flat array and nullified src->root. We
+ still own the list-wrapper heap allocations (the Edje_Vg_Tree* pointers
+ in all_vg_trees themselves); free them here. _edje_vg_tree_free_fields
+ is a no-op when root==NULL so it is safe to call. */
+ if (all_vg_trees)
+ {
+ Eina_List *l;
+ Edje_Vg_Tree *t;
+ EINA_LIST_FOREACH(all_vg_trees, l, t)
+ {
+ /* root was nullified by shallow-copy; free only the wrapper. */
+ free(t);
+ }
+ eina_list_free(all_vg_trees);
+ all_vg_trees = NULL;
+ }
+ /* Release parser-side scaffolding. The toplevel hash stores borrowed
+ pointers (the trees are now in all_vg_trees / vd->trees[]); no
+ data-free callback was set. Same for the node stack. */
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);
@@ -216,7 +240,6 @@ _edje_cc_vg_cleanup(void)
current_vg_node_stack = NULL;
toplevel_vg_trees = NULL;
_vg_desc_to_tree = NULL;
- all_vg_trees = NULL;
}
Eina_List *po_files;
diff --git a/src/bin/edje/edje_cc_out.c b/src/bin/edje/edje_cc_out.c
index 08fbf2d517..a06648dbd9 100644
--- a/src/bin/edje/edje_cc_out.c
+++ b/src/bin/edje/edje_cc_out.c
@@ -22,6 +22,7 @@
#include "edje_cc.h"
#include "edje_convert.h"
#include "edje_multisense_convert.h"
+#include "edje_vg_tree.h"
#include <lua.h>
#include <lauxlib.h>
@@ -1455,6 +1456,205 @@ data_write_vectors(Eet_File *ef, int *vector_num)
eina_strbuf_free(buf);
}
+/* =========================================================================
+ * data_write_vectors_trees (Task 2.9)
+ *
+ * Walks all_vg_trees collected by the parser, builds Edje_Vg_Directory,
+ * patches each per-description vg.tree_id, and:
+ * a) assigns edje_file->vector_dir (encoded as part of "edje/file" by
+ * data_write_header via the Eet descriptor).
+ * b) writes each tree as a separate "edje/vector_trees/%u" eet entry so
+ * that "eet -l" shows them as top-level keys.
+ * ========================================================================= */
+
+/* Collect one color-class name into the seen hash. No-op for NULL/empty. */
+static void
+_vg_collect_one(Eina_Hash *seen, const char *name)
+{
+ if (name && *name && !eina_hash_find(seen, name))
+ eina_hash_add(seen, name, (void *)(uintptr_t)1);
+}
+
+/* Recursive walk: visit every Edje_Vg_Color_Binding that might carry a
+ color_class name and add it to seen. */
+static void
+_vg_collect_class_names(const Edje_Vg_Node *n, Eina_Hash *seen)
+{
+ if (!n) return;
+ _vg_collect_one(seen, n->color.color_class);
+ switch (n->type)
+ {
+ case EDJE_VG_NODE_SHAPE:
+ _vg_collect_one(seen, n->shape.fill.color_class);
+ _vg_collect_one(seen, n->shape.stroke_color.color_class);
+ break;
+ case EDJE_VG_NODE_CONTAINER:
+ {
+ Eina_List *l;
+ Edje_Vg_Node *c;
+ EINA_LIST_FOREACH(n->container.children, l, c)
+ _vg_collect_class_names(c, seen);
+ }
+ break;
+ case EDJE_VG_NODE_GRADIENT_LINEAR:
+ case EDJE_VG_NODE_GRADIENT_RADIAL:
+ {
+ unsigned int i;
+ for (i = 0; i < n->gradient.stops_count; i++)
+ _vg_collect_one(seen, n->gradient.stops[i].color.color_class);
+ }
+ break;
+ }
+}
+
+/* Snapshot all unique class names from seen into vd->class_names[]. */
+static void
+_vg_finalize_class_names(Edje_Vg_Directory *vd, Eina_Hash *seen)
+{
+ unsigned int n = eina_hash_population(seen);
+ if (n == 0) return;
+ vd->class_names = calloc(n, sizeof(const char *));
+ if (!vd->class_names)
+ {
+ ERR("OOM allocating class_names array");
+ return;
+ }
+ vd->class_names_count = n;
+ Eina_Iterator *it = eina_hash_iterator_key_new(seen);
+ const char *key;
+ unsigned int i = 0;
+ EINA_ITERATOR_FOREACH(it, key)
+ {
+ /* Borrow a stringshare ref so vd->class_names is self-owning for the
+ duration of the eet encode. _edje_vg_directory_free (Phase 1.4)
+ will call eina_stringshare_del on each slot. */
+ vd->class_names[i++] = eina_stringshare_add(key);
+ }
+ eina_iterator_free(it);
+}
+
+static void
+data_write_vectors_trees(Eet_File *ef, int *tree_num)
+{
+ Eina_List *trees = _edje_cc_vg_all_trees_get();
+ if (!trees) return;
+
+ unsigned int n = eina_list_count(trees);
+ if (n == 0) return;
+
+ /* --- Allocate the directory and its flat tree array. --- */
+ Edje_Vg_Directory *vd = calloc(1, sizeof(Edje_Vg_Directory));
+ if (!vd) error_and_abort(ef, "OOM allocating Edje_Vg_Directory");
+
+ vd->trees = calloc(n, sizeof(Edje_Vg_Tree));
+ if (!vd->trees) error_and_abort(ef, "OOM allocating Edje_Vg_Directory.trees");
+ vd->trees_count = n;
+
+ /* --- Step A: build source-index map BEFORE shallow-copy so we can patch
+ description tree_ids after the copy nullifies src->root.
+
+ The map stores: key = Edje_Vg_Tree* list-wrapper pointer (the pointer
+ value, used as integer key), value = (uintptr_t)(i + 1) to distinguish
+ not-found (0) from index 0.
+
+ We use eina_hash_pointer_new which compares pointer-sized keys. */
+ Eina_Hash *idx_map = eina_hash_pointer_new(NULL);
+ if (!idx_map) error_and_abort(ef, "OOM allocating vg tree index map");
+
+ {
+ Eina_List *l;
+ Edje_Vg_Tree *src;
+ uintptr_t i = 0;
+ EINA_LIST_FOREACH(trees, l, src)
+ {
+ eina_hash_add(idx_map, &src, (void *)(i + 1));
+ i++;
+ }
+ }
+
+ /* --- Step B: shallow-copy each tree struct into the flat array.
+ Ownership of the root node subtree transfers to vd->trees[i].root.
+ Nullify src->root so that _edje_cc_vg_cleanup() doesn't double-free. */
+ {
+ Eina_List *l;
+ Edje_Vg_Tree *src;
+ unsigned int i = 0;
+ EINA_LIST_FOREACH(trees, l, src)
+ {
+ vd->trees[i] = *src;
+ src->root = NULL;
+ i++;
+ }
+ }
+
+ /* --- Step C: collect all color-class names referenced by any node. --- */
+ Eina_Hash *cls_seen = eina_hash_string_superfast_new(NULL);
+ if (cls_seen)
+ {
+ unsigned int i;
+ for (i = 0; i < vd->trees_count; i++)
+ _vg_collect_class_names(vd->trees[i].root, cls_seen);
+ _vg_finalize_class_names(vd, cls_seen);
+ eina_hash_free(cls_seen);
+ }
+
+ /* --- Step D: patch each per-description vg.tree_id. --- */
+ {
+ Eina_Hash *map = _edje_cc_vg_desc_to_tree_get();
+ if (map)
+ {
+ Eina_Iterator *it = eina_hash_iterator_tuple_new(map);
+ Eina_Hash_Tuple *tuple;
+ EINA_ITERATOR_FOREACH(it, tuple)
+ {
+ /* For eina_hash_pointer_new, keys are stored as pointer-sized
+ blobs: _vg_record_use stored &ed (address of local var holding
+ the desc pointer), so eina copied the 8 bytes of the pointer
+ value itself. tuple->key is a pointer TO those 8 bytes, so
+ we must dereference once to recover the original desc pointer.
+ tuple->data is the value stored as-is (Edje_Vg_Tree *). */
+ Edje_Part_Description_Vector *desc =
+ *(Edje_Part_Description_Vector **)tuple->key;
+ Edje_Vg_Tree *t = (Edje_Vg_Tree *)tuple->data;
+
+ /* Look up which flat-array index this tree was assigned.
+ idx_map was built with &src (pointer-to-pointer), so pass &t
+ so eina reads the 8 bytes of t's value for comparison. */
+ uintptr_t idx_plus_1 = (uintptr_t)eina_hash_find(idx_map, &t);
+ if (idx_plus_1 == 0)
+ {
+ WRN("vg desc->tree_id patch: tree not found in index map");
+ continue;
+ }
+ desc->vg.tree_id = (int)(idx_plus_1 - 1);
+ }
+ eina_iterator_free(it);
+ }
+ }
+ eina_hash_free(idx_map);
+
+ /* --- Step E: write each tree as a separate eet entry for eet -l
+ visibility. The trees are also encoded as part of "edje/file" via the
+ Eet descriptor (ADD_SUB -> ADD_VAR_ARRAY chain). --- */
+ {
+ unsigned int i;
+ for (i = 0; i < vd->trees_count; i++)
+ {
+ char key[64];
+ snprintf(key, sizeof(key), "edje/vector_trees/%u", i);
+ if (eet_data_write(ef, _edje_vg_tree_edd(), key, &vd->trees[i],
+ compress_mode) <= 0)
+ WRN("Failed to write eet entry \"%s\"", key);
+ else if (tree_num)
+ (*tree_num)++;
+ }
+ }
+
+ /* --- Step F: hand the directory to edje_file. data_write_header() will
+ encode it as part of the "edje/file" eet entry via the descriptor. --- */
+ edje_file->vector_dir = vd;
+}
+
static void
data_image_sets_init(void)
{
@@ -2913,6 +3113,11 @@ data_write(void)
INF("fontmap: %3.5f", ecore_time_get() - t); t = ecore_time_get();
data_write_vectors(ef, &vector_num);
INF("vectors: %3.5f", ecore_time_get() - t); t = ecore_time_get();
+ {
+ int tree_num = 0;
+ data_write_vectors_trees(ef, &tree_num);
+ INF("Wrote %i vector trees", tree_num);
+ }
data_write_fonts(ef, &font_num);
INF("fonts: %3.5f", ecore_time_get() - t); t = ecore_time_get();
data_write_sounds(ef, &sound_num);
@@ -2951,6 +3156,8 @@ data_write(void)
if (pending_threads + pending_image_threads > 0) exit(-1);
}
+ _edje_cc_vg_cleanup();
+
err = eet_close(ef);
if (err)
{
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.