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 55d3e3e1881aab25d5734f7ac1326f46766c6974
Author: [email protected] <[email protected]>
AuthorDate: Wed Apr 29 10:34:45 2026 -0600

    edje: hybrid lerp design for smooth VG state transitions (Phase 5.3)
    
    Implement Task 5.3: make _edje_vector_recalc_apply honor ep->param2 during
    transitions so that tree-based state changes interpolate instead of step.
    
    The implementation uses a three-tree hybrid approach:
    1. Working tree A: dup base_a + apply chosen_desc overrides (if any)
    2. Working tree B: dup base_b + apply param2 overrides (if any)
    3. Lerp tree: in-memory blend of A/B non-path properties via _edje_vg_tree_lerp
    
    All three are materialized to Efl_VG hierarchies. The lerp tree becomes root
    (which holds the interpolated viewbox + blended properties); efl_a and efl_b
    are short-lived references passed to efl_gfx_path_interpolate(root, efl_a,
    efl_b, pos), which walks the Efl_VG tree and recursively updates path command
    sequences. If topology mismatches, the call returns false silently and root
    retains B's paths (step semantics per spec ยง5.2).
    
    Fall-through to src_a render when:
    - param2 == NULL (no transition active)
    - Next description's tree_id < 0 (Mode C โ€” static SVG bridging deferred)
    - Materialization of any tree fails
    
    Memory ordering is type-correct throughout: efl_a and efl_b are unref'd
    after efl_gfx_path_interpolate consumes them; root is unref'd after adoption
    by efl_canvas_vg_object_root_node_set; lerp_tree freed before the !root error
    path; working_a and working_b freed at branch end.
    
    Performance note: three Efl_VG instantiations per frame at 60fps โ‰ˆ 180/sec for
    moderate trees. Caching (by description-pointer + override-list-hash +
    classes_dirty flag) deferred to Phase 5+.
    
    62/62 tests pass; valgrind reports no new leaks.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
 src/lib/edje/edje_calc.c | 123 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 90 insertions(+), 33 deletions(-)

diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c
index 3fb4b751be..3965d49703 100644
--- a/src/lib/edje/edje_calc.c
+++ b/src/lib/edje/edje_calc.c
@@ -3283,10 +3283,14 @@ _edje_vector_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3 EIN
    if (chosen_desc->vg.tree_id >= 0)
      {
         Edje_Real_Part_Vector *rpv = ep->typedata.vector;
-        const Edje_Vg_Tree *base;
-        Edje_Vg_Tree *working = NULL;
-        const Edje_Vg_Tree *materialize_src;
+        const Edje_Vg_Tree *base_a;
+        Edje_Vg_Tree *working_a = NULL;
+        Edje_Vg_Tree *working_b = NULL;
+        Edje_Vg_Tree *lerp_tree = NULL;
+        Efl_VG *efl_a = NULL, *efl_b = NULL;
         Eina_Rect viewbox;
+        Eina_List *l;
+        Edje_Vg_Override *ovr;
 
         if (!ed->file->vector_dir ||
             (unsigned int)chosen_desc->vg.tree_id >= ed->file->vector_dir->trees_count)
@@ -3297,48 +3301,108 @@ _edje_vector_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3 EIN
              return;
           }
 
-        base = &ed->file->vector_dir->trees[chosen_desc->vg.tree_id];
+        base_a = &ed->file->vector_dir->trees[chosen_desc->vg.tree_id];
 
         /* Cache the tree pointer; useful for class-dirty invalidation in
            Phase 6. */
-        rpv->cached_base_tree = base;
+        rpv->cached_base_tree = base_a;
         rpv->cached_tree_id = chosen_desc->vg.tree_id;
 
-        viewbox = EINA_RECT(base->vbx, base->vby, base->vbw, base->vbh);
-
         /* Phase 4: when per-description overrides are present, dup the base
-           tree, apply each override in order, then materialise the working
-           copy.  When there are no overrides, skip the dup and materialise the
-           immutable base tree directly (fast path, unchanged from Phase 3). */
+           tree, apply each override in order.  When there are no overrides,
+           skip the dup and use the immutable base tree directly (fast path). */
         if (chosen_desc->vg.overrides)
           {
-             Eina_List *l;
-             Edje_Vg_Override *ovr;
-
-             working = _edje_vg_tree_dup(base);
-             if (!working)
+             working_a = _edje_vg_tree_dup(base_a);
+             if (!working_a)
                {
                   ERR("Failed to dup base tree for override application (tree_id=%d)",
                       chosen_desc->vg.tree_id);
                   return;
                }
              EINA_LIST_FOREACH(chosen_desc->vg.overrides, l, ovr)
-               _edje_vg_tree_apply_override(working, ovr);
-             materialize_src = working;
+               _edje_vg_tree_apply_override(working_a, ovr);
           }
-        else
+        const Edje_Vg_Tree *src_a = working_a ? working_a : base_a;
+
+        /* Phase 5: when a transition is active (param2 non-NULL and pos > 0),
+           try to build a lerp tree across both descriptions.  If the next
+           description is not tree-based (tree_id < 0, e.g. Mode-C SVG), fall
+           through to the direct-materialise path instead; Mode-C bridging is
+           deferred. */
+        root = NULL;
+        if (ep->param2 && NEQ(pos, ZERO))
           {
-             materialize_src = base;
+             Edje_Part_Description_Vector *next_desc =
+                (Edje_Part_Description_Vector *)ep->param2->description;
+
+             if (next_desc->vg.tree_id >= 0 &&
+                 (unsigned int)next_desc->vg.tree_id < ed->file->vector_dir->trees_count)
+               {
+                  const Edje_Vg_Tree *base_b =
+                     &ed->file->vector_dir->trees[next_desc->vg.tree_id];
+
+                  /* Build B's working tree (dup + apply overrides if any). */
+                  if (next_desc->vg.overrides)
+                    {
+                       working_b = _edje_vg_tree_dup(base_b);
+                       if (working_b)
+                         {
+                            EINA_LIST_FOREACH(next_desc->vg.overrides, l, ovr)
+                              _edje_vg_tree_apply_override(working_b, ovr);
+                         }
+                    }
+                  const Edje_Vg_Tree *src_b = working_b ? working_b : base_b;
+
+                  /* Build the lerp tree: structure mirrors B with non-path
+                     properties lerped from A. Paths stay at B's value here;
+                     efl_gfx_path_interpolate handles them below. */
+                  lerp_tree = _edje_vg_tree_lerp(src_a, src_b, TO_DOUBLE(pos));
+
+                  /* Materialise all three trees. efl_a and efl_b are
+                     short-lived references used only for path interpolation. */
+                  efl_a = _edje_vg_tree_to_efl_vg(src_a);
+                  efl_b = _edje_vg_tree_to_efl_vg(src_b);
+                  if (lerp_tree) root = _edje_vg_tree_to_efl_vg(lerp_tree);
+
+                  /* Path-only interpolation: walks the Efl_VG hierarchy and
+                     updates each shape's path in `root` via the EFL-native
+                     interpolator.  Returns EINA_FALSE on topology mismatch โ€”
+                     root already holds B's paths (step semantics), so failure
+                     is safe to ignore. */
+                  if (root && efl_a && efl_b)
+                    efl_gfx_path_interpolate(root, efl_a, efl_b, TO_DOUBLE(pos));
+
+                  /* Release auxiliary A/B VG trees; root is independent. */
+                  if (efl_a) efl_unref(efl_a);
+                  if (efl_b) efl_unref(efl_b);
+               }
           }
 
-        /* TODO Phase 5: cache the materialised Efl_VG to avoid the
-           dup-and-walk cost on every recalc.  Cache key:
-           (tree_id, override-list-hash, classes_dirty).  Phase 4 added the
-           dup-and-apply-overrides flow; Phase 5 needs the materialised cache
-           for transition perf at 60fps. */
-        root = _edje_vg_tree_to_efl_vg(materialize_src);
+        /* No transition active, transition fell through (Mode-C next desc),
+           or lerp_tree materialise failed: fall back to direct src_a render. */
+        if (!root)
+          root = _edje_vg_tree_to_efl_vg(src_a);
 
-        if (working) _edje_vg_tree_free(working);
+        /* Viewbox: use lerped viewbox when transition is active (the lerp tree
+           already has the interpolated vbx/vby/vbw/vbh); else use base_a. */
+        if (lerp_tree)
+          viewbox = EINA_RECT(lerp_tree->vbx, lerp_tree->vby,
+                              lerp_tree->vbw, lerp_tree->vbh);
+        else
+          viewbox = EINA_RECT(base_a->vbx, base_a->vby,
+                              base_a->vbw, base_a->vbh);
+
+        /* TODO Phase 5+: cache materialised Efl_VG hierarchies to avoid the
+           dup-and-walk cost on every recalc.  During a transition we currently
+           build three Efl_VG instances per frame (A, B, and OUT).  At 60fps
+           this is 180 instantiations/sec for moderately-sized trees.  Cache
+           key: (description pointer, override-list-hash, classes_dirty). */
+
+        /* Free working trees and the lerp tree; root is the only survivor. */
+        if (lerp_tree) _edje_vg_tree_free(lerp_tree);
+        if (working_a) _edje_vg_tree_free(working_a);
+        if (working_b) _edje_vg_tree_free(working_b);
 
         if (!root)
           {
@@ -3352,13 +3416,6 @@ _edje_vector_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3 EIN
            caller-side ref from efl_add_ref so the tree is owned exclusively
            by the VG object from this point forward. */
         efl_unref(root);
-        root = NULL;
-
-        /* Phase 3 deferral: when ep->param2 is non-NULL (transition active), we
-           skip the legacy interpolation flow.  Mode A/B descriptions with the
-           same tree_id on both sides will naturally converge on the same root;
-           different tree_ids produce a step-at-pos=1 cut.  Phase 5 owns
-           smooth interpolation across tree-based states. */
         return;
      }
 

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

Reply via email to