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 90e64ede1efb338f7b1424df9857b8b37684dfe4
Author: [email protected] <[email protected]>
AuthorDate: Tue Apr 28 11:50:42 2026 -0600

    edje: expand edje_vg_tree helper API for Phase 2 parser
    
    Phase 2 requires a fuller tree-building substrate than the Phase-1
    test fixture provides. Add six internal helpers:
      - _edje_vg_tree_new() allocates tree with root container
      - _edje_vg_node_new(type) creates nodes with sensible defaults
      - _edje_vg_container_append() adds children to containers
      - _edje_vg_tree_node_by_name() enables shape override resolution
      - _edje_vg_tree_validate_unique_names() detects duplicate VEC001 errors
      - _edje_vg_node_free() is now public (previously _node_free)
    
    Consolidate all node freeing into _edje_vg_node_free to avoid
    redundant logic. Replace the manual EINA_LIST_FOREACH/free pattern
    with EINA_LIST_FREE for simplicity. The Phase-1 round-trip test suite
    still passes (44/44).
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
 src/lib/edje/edje_vg_tree.c              | 119 ++++++++++++++++++++++++++++---
 src/lib/edje/edje_vg_tree.h              |  30 ++++++++
 src/tests/edje/edje_test_vector_states.c |  95 ++++++++++++++++++++++++
 3 files changed, 234 insertions(+), 10 deletions(-)

diff --git a/src/lib/edje/edje_vg_tree.c b/src/lib/edje/edje_vg_tree.c
index 489dd1e467..f535d15a42 100644
--- a/src/lib/edje/edje_vg_tree.c
+++ b/src/lib/edje/edje_vg_tree.c
@@ -134,8 +134,6 @@ _edje_vg_tree_new_for_test(void)
  * _edje_vg_tree_free  — recursive free
  * ========================================================================= */
 
-static void _node_free(Edje_Vg_Node *n);
-
 static void
 _color_binding_free_fields(Edje_Vg_Color_Binding *cb)
 {
@@ -146,8 +144,8 @@ _color_binding_free_fields(Edje_Vg_Color_Binding *cb)
      }
 }
 
-static void
-_node_free(Edje_Vg_Node *n)
+EAPI void
+_edje_vg_node_free(Edje_Vg_Node *n)
 {
    if (!n) return;
 
@@ -173,12 +171,9 @@ _node_free(Edje_Vg_Node *n)
 
       case EDJE_VG_NODE_CONTAINER:
         {
-           Eina_List *l;
            Edje_Vg_Node *child;
-           EINA_LIST_FOREACH(n->container.children, l, child)
-              _node_free(child);
-           eina_list_free(n->container.children);
-           n->container.children = NULL;
+           EINA_LIST_FREE(n->container.children, child)
+             _edje_vg_node_free(child);
         }
         break;
 
@@ -205,7 +200,7 @@ EAPI void
 _edje_vg_tree_free_fields(Edje_Vg_Tree *t)
 {
    if (!t) return;
-   _node_free(t->root);
+   _edje_vg_node_free(t->root);
    t->root = NULL;
 }
 
@@ -217,6 +212,110 @@ _edje_vg_tree_free(Edje_Vg_Tree *t)
    free(t);
 }
 
+/* =========================================================================
+ * Phase 2 construction helpers
+ * ========================================================================= */
+
+EAPI Edje_Vg_Tree *
+_edje_vg_tree_new(void)
+{
+   Edje_Vg_Tree *t = calloc(1, sizeof(Edje_Vg_Tree));
+   if (!t) return NULL;
+   t->root = _edje_vg_node_new(EDJE_VG_NODE_CONTAINER);
+   if (!t->root) { free(t); return NULL; }
+   return t;
+}
+
+EAPI Edje_Vg_Node *
+_edje_vg_node_new(Edje_Vg_Node_Type type)
+{
+   Edje_Vg_Node *n = calloc(1, sizeof(Edje_Vg_Node));
+   if (!n) return NULL;
+   n->type    = type;
+   n->visible = 1;
+   n->color.r = n->color.g = n->color.b = n->color.a = 255;
+   n->xform.sx = n->xform.sy = 1.0;  /* identity scale */
+   if (type == EDJE_VG_NODE_SHAPE)
+     {
+        n->shape.fill.r = n->shape.fill.g =
+           n->shape.fill.b = n->shape.fill.a = 255;
+        n->shape.stroke_width = 1.0;
+        n->shape.stroke_cap   = EFL_GFX_CAP_BUTT;
+        n->shape.stroke_join  = EFL_GFX_JOIN_MITER;
+        n->shape.fill_rule    = EFL_GFX_FILL_RULE_WINDING;
+     }
+   return n;
+}
+
+EAPI void
+_edje_vg_container_append(Edje_Vg_Node *parent, Edje_Vg_Node *child)
+{
+   if (!parent || parent->type != EDJE_VG_NODE_CONTAINER || !child) return;
+   parent->container.children =
+      eina_list_append(parent->container.children, child);
+}
+
+static Edje_Vg_Node *
+_node_by_name_recursive(Edje_Vg_Node *n, const char *name)
+{
+   if (!n || !name) return NULL;
+   if (n->name && !strcmp(n->name, name)) return n;
+   if (n->type == EDJE_VG_NODE_CONTAINER)
+     {
+        Eina_List *l;
+        Edje_Vg_Node *c;
+        EINA_LIST_FOREACH(n->container.children, l, c)
+          {
+             Edje_Vg_Node *r = _node_by_name_recursive(c, name);
+             if (r) return r;
+          }
+     }
+   return NULL;
+}
+
+EAPI Edje_Vg_Node *
+_edje_vg_tree_node_by_name(const Edje_Vg_Tree *t, const char *name)
+{
+   if (!t || !t->root) return NULL;
+   return _node_by_name_recursive(t->root, name);
+}
+
+static Eina_Bool
+_validate_unique_recursive(Edje_Vg_Node *n, Eina_Hash *seen,
+                            const char **dup_out)
+{
+   if (n->name)
+     {
+        if (eina_hash_find(seen, n->name))
+          {
+             if (dup_out) *dup_out = n->name;
+             return EINA_FALSE;
+          }
+        eina_hash_add(seen, n->name, n);
+     }
+   if (n->type == EDJE_VG_NODE_CONTAINER)
+     {
+        Eina_List *l;
+        Edje_Vg_Node *c;
+        EINA_LIST_FOREACH(n->container.children, l, c)
+          if (!_validate_unique_recursive(c, seen, dup_out))
+            return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+_edje_vg_tree_validate_unique_names(const Edje_Vg_Tree *t,
+                                     const char **dup_out)
+{
+   if (!t || !t->root) return EINA_TRUE;
+   Eina_Hash *seen = eina_hash_string_superfast_new(NULL);
+   if (!seen) return EINA_TRUE;  /* OOM: fail open rather than crash */
+   Eina_Bool ok = _validate_unique_recursive(t->root, seen, dup_out);
+   eina_hash_free(seen);
+   return ok;
+}
+
 /* =========================================================================
  * _edje_vg_tree_equal  — recursive structural equality
  * ========================================================================= */
diff --git a/src/lib/edje/edje_vg_tree.h b/src/lib/edje/edje_vg_tree.h
index 97666970f9..0a4877bf37 100644
--- a/src/lib/edje/edje_vg_tree.h
+++ b/src/lib/edje/edje_vg_tree.h
@@ -28,6 +28,36 @@ EAPI void                 _edje_vg_tree_free_fields(Edje_Vg_Tree *t);
 /* Recursive free.  Safe to call with NULL. */
 EAPI void                 _edje_vg_tree_free(Edje_Vg_Tree *t);
 
+/* --- Construction helpers (Phase 2+) ------------------------------------ */
+
+/* Allocate a new, empty tree with a CONTAINER root. */
+EAPI Edje_Vg_Tree *_edje_vg_tree_new(void);
+
+/* Allocate a node of the given type with sane default property values.
+ * color RGBA = 255 white, scale = 1.0 identity.
+ * SHAPE nodes additionally get: stroke_width=1.0, stroke_cap=BUTT,
+ * stroke_join=MITER, fill_rule=WINDING, fill RGBA = 255 white. */
+EAPI Edje_Vg_Node *_edje_vg_node_new(Edje_Vg_Node_Type type);
+
+/* Recursive free.  Safe to call with NULL. */
+EAPI void          _edje_vg_node_free(Edje_Vg_Node *n);
+
+/* Append child to parent (parent must be CONTAINER). No-op on bad args. */
+EAPI void          _edje_vg_container_append(Edje_Vg_Node *parent,
+                                              Edje_Vg_Node *child);
+
+/* Depth-first search for first node whose name equals name.  Returns NULL
+ * if not found. */
+EAPI Edje_Vg_Node *_edje_vg_tree_node_by_name(const Edje_Vg_Tree *t,
+                                                const char *name);
+
+/* Walk the entire tree and verify every named node has a unique name.
+ * Returns EINA_TRUE if all names are unique.  On first collision, returns
+ * EINA_FALSE and sets *dup_out to the duplicate name (stringshare pointer
+ * owned by the node; do NOT free).  dup_out may be NULL. */
+EAPI Eina_Bool     _edje_vg_tree_validate_unique_names(const Edje_Vg_Tree *t,
+                                                        const char **dup_out);
+
 /* --- Eet descriptor accessor -------------------------------------------- */
 
 /* Returns the static Eet_Data_Descriptor for Edje_Vg_Tree.
diff --git a/src/tests/edje/edje_test_vector_states.c b/src/tests/edje/edje_test_vector_states.c
index 6c9a2d7d21..70a3ffcfe1 100644
--- a/src/tests/edje/edje_test_vector_states.c
+++ b/src/tests/edje/edje_test_vector_states.c
@@ -17,13 +17,39 @@
  * edje_private.h.  Redeclare as incomplete struct so the compiler accepts
  * the pointer parameters without knowing the layout. */
 typedef struct _Edje_Vg_Tree Edje_Vg_Tree;
+typedef struct _Edje_Vg_Node Edje_Vg_Node;
 
+typedef enum {
+   EDJE_VG_NODE_SHAPE           = 0,
+   EDJE_VG_NODE_CONTAINER       = 1,
+   EDJE_VG_NODE_GRADIENT_LINEAR = 2,
+   EDJE_VG_NODE_GRADIENT_RADIAL = 3,
+} Edje_Vg_Node_Type;
+
+/* name and type are the first two fields of _Edje_Vg_Node (edje_private.h).
+ * A partial view struct is safe for accessing only those fields.
+ * DO NOT access any other fields through this view. */
+struct _Edje_Vg_Node { const char *name; Edje_Vg_Node_Type type; /* opaque tail */ };
+struct _Edje_Vg_Tree { double vbx, vby, vbw, vbh; Edje_Vg_Node *root; };
+
+/* Phase 1 helpers */
 Edje_Vg_Tree        *_edje_vg_tree_new_for_test(void);
 Eina_Bool            _edje_vg_tree_equal(const Edje_Vg_Tree *a,
                                          const Edje_Vg_Tree *b);
 void                 _edje_vg_tree_free(Edje_Vg_Tree *t);
 Eet_Data_Descriptor *_edje_vg_tree_edd(void);
 
+/* Phase 2 helpers (Task 2.1) */
+Edje_Vg_Tree        *_edje_vg_tree_new(void);
+Edje_Vg_Node        *_edje_vg_node_new(Edje_Vg_Node_Type type);
+void                  _edje_vg_node_free(Edje_Vg_Node *n);
+void                  _edje_vg_container_append(Edje_Vg_Node *parent,
+                                                 Edje_Vg_Node *child);
+Edje_Vg_Node        *_edje_vg_tree_node_by_name(const Edje_Vg_Tree *t,
+                                                  const char *name);
+Eina_Bool             _edje_vg_tree_validate_unique_names(const Edje_Vg_Tree *t,
+                                                           const char **dup_out);
+
 /*
  * edje_vg_tree_eet_roundtrip
  *
@@ -65,8 +91,77 @@ EFL_START_TEST(edje_vg_tree_eet_roundtrip)
 }
 EFL_END_TEST
 
+/*
+ * edje_vg_tree_helpers_basic
+ *
+ * Unit test for the six Phase 2.1 construction helpers:
+ *   _edje_vg_tree_new, _edje_vg_node_new, _edje_vg_node_free,
+ *   _edje_vg_container_append, _edje_vg_tree_node_by_name,
+ *   _edje_vg_tree_validate_unique_names.
+ *
+ * The test accesses only the first two fields of Edje_Vg_Node (name, type)
+ * which are layout-stable at the head of the struct.  Edje_Vg_Tree.root is
+ * the last field after four doubles — accessed via the partial view struct
+ * defined above.
+ */
+EFL_START_TEST(edje_vg_tree_helpers_basic)
+{
+   /* _edje_vg_tree_new: root container auto-created. */
+   Edje_Vg_Tree *t = _edje_vg_tree_new();
+   fail_if(!t);
+   fail_if(t->root == NULL);
+   fail_if(t->root->type != EDJE_VG_NODE_CONTAINER);
+
+   /* _edje_vg_node_new: shape node with correct type. */
+   Edje_Vg_Node *s = _edje_vg_node_new(EDJE_VG_NODE_SHAPE);
+   fail_if(!s);
+   fail_if(s->type != EDJE_VG_NODE_SHAPE);
+
+   /* Set name (first field) — mirrors how the parser will set it. */
+   s->name = eina_stringshare_add("body");
+
+   /* _edje_vg_container_append: append to root, then look up by name. */
+   _edje_vg_container_append(t->root, s);
+   Edje_Vg_Node *found = _edje_vg_tree_node_by_name(t, "body");
+   fail_if(found != s);
+   fail_if(_edje_vg_tree_node_by_name(t, "missing") != NULL);
+   fail_if(_edje_vg_tree_node_by_name(NULL, "body") != NULL);
+
+   /* _edje_vg_tree_validate_unique_names: one unique name — passes. */
+   const char *dup = NULL;
+   fail_if(!_edje_vg_tree_validate_unique_names(t, &dup));
+   fail_if(dup != NULL);
+
+   /* Duplicate detection: add a second "body" node. */
+   Edje_Vg_Node *s2 = _edje_vg_node_new(EDJE_VG_NODE_SHAPE);
+   fail_if(!s2);
+   s2->name = eina_stringshare_add("body");
+   _edje_vg_container_append(t->root, s2);
+   fail_if(_edje_vg_tree_validate_unique_names(t, &dup));
+   fail_if(dup == NULL || strcmp(dup, "body") != 0);
+
+   /* _edje_vg_container_append: no-op on bad args — must not crash. */
+   _edje_vg_container_append(NULL, s2);
+   _edje_vg_container_append(s2, NULL);    /* s2 is SHAPE, not CONTAINER */
+   _edje_vg_container_append(s2, s);       /* s2 is SHAPE — append rejected */
+
+   /* _edje_vg_tree_free: recursively frees s and s2 (both owned by root). */
+   _edje_vg_tree_free(t);
+
+   /* _edje_vg_node_free: NULL-safe. */
+   _edje_vg_node_free(NULL);
+
+   /* _edje_vg_node_new CONTAINER: correct type. */
+   Edje_Vg_Node *c = _edje_vg_node_new(EDJE_VG_NODE_CONTAINER);
+   fail_if(!c);
+   fail_if(c->type != EDJE_VG_NODE_CONTAINER);
+   _edje_vg_node_free(c);
+}
+EFL_END_TEST
+
 void
 edje_test_vector_states(TCase *tc)
 {
    tcase_add_test(tc, edje_vg_tree_eet_roundtrip);
+   tcase_add_test(tc, edje_vg_tree_helpers_basic);
 }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to