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.

Reply via email to