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 41a7dcae4987d1784864a51f81ac95b5b55bd402
Author: [email protected] <[email protected]>
AuthorDate: Wed Apr 29 15:20:15 2026 -0600

    edje: fix materializer's fill-vs-node-color ordering (Task 6.4)
    
    Spec §3.2 defines node-level color as multiplicative: the effective fill is
    (node × fill / 255) per channel, premultiplied by alpha.  The Phase 3.1
    materializer called _apply_color_binding twice on the same shape — first
    for fill RGBA, then for node-level color — causing the second write to
    clobber the first.  Phase 4.6 and 5.4 tests worked around this by asserting
    on stroke properties instead of fill.
    
    Split _apply_common into _apply_common_no_color (name + visibility +
    transform) and the unchanged _apply_common.  Add _apply_shape_combined_color
    helper that computes the multiplicative combine in 8-bit arithmetic,
    premultiplies alpha, and makes a single efl_gfx_color_set call.  Flat-fill
    shapes now use the combined helper; gradient-fill shapes apply node-level
    color directly to the gradient paint object (the gradient-rendered shape
    itself, no flat fill RGBA to combine).
    
    edje_vg_render_box_a_hover now asserts both fill color (default 200,0,0,255,
    hover 200,200,0,255) and stroke width.  Add new end-to-end test
    edje_vg_render_box_classed_fill that proves color-class pipeline works:
    class registered → resolved at cache rebuild → combined with node-level
    color → correct fill RGBA readable.  No effect on existing render output —
    all pre-existing tests use default white (255,255,255,255) for node-level
    color, so multiplicative combine yields the fill unchanged.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
 src/lib/edje/edje_vg_tree.c              |  57 +++++++++++++++--
 src/tests/edje/edje_test_vector_states.c | 105 ++++++++++++++++++++++++++++++-
 2 files changed, 155 insertions(+), 7 deletions(-)

diff --git a/src/lib/edje/edje_vg_tree.c b/src/lib/edje/edje_vg_tree.c
index 8f4eaf3064..ca941164cc 100644
--- a/src/lib/edje/edje_vg_tree.c
+++ b/src/lib/edje/edje_vg_tree.c
@@ -1409,19 +1409,57 @@ _apply_transform(Efl_VG *vg, const Edje_Vg_Transform *xf)
 }
 
 /* --------------------------------------------------------------------------
- * Common node properties: name, visibility, color, transform.
+ * Common node properties without color: name, visibility, transform.
+ * Used by the shape materializer which applies a combined color separately.
  * -------------------------------------------------------------------------- */
 static void
-_apply_common(Efl_VG *vg, const Edje_Vg_Node *n)
+_apply_common_no_color(Efl_VG *vg, const Edje_Vg_Node *n)
 {
    if (n->name)
       efl_name_set(vg, n->name);
    if (!n->visible)
       efl_gfx_entity_visible_set(vg, EINA_FALSE);
-   _apply_color_binding(vg, &n->color);
    _apply_transform(vg, &n->xform);
 }
 
+/* --------------------------------------------------------------------------
+ * Common node properties: name, visibility, color, transform.
+ * -------------------------------------------------------------------------- */
+static void
+_apply_common(Efl_VG *vg, const Edje_Vg_Node *n)
+{
+   _apply_common_no_color(vg, n);
+   _apply_color_binding(vg, &n->color);
+}
+
+/* --------------------------------------------------------------------------
+ * Apply the multiplicative combination of node-level color × fill color on a
+ * shape object.  Spec §3.2: the node-level color is "multiplicative" — for
+ * shapes the effective fill is node × fill / 255 per channel.
+ *
+ * After Phase 6.2 both bindings carry already-resolved RGBA (no color_class
+ * refs remain), so this is a straightforward 8-bit multiply followed by the
+ * same premul step that _apply_color_binding uses.
+ * -------------------------------------------------------------------------- */
+static void
+_apply_shape_combined_color(Efl_Canvas_Vg_Shape *s,
+                            const Edje_Vg_Color_Binding *node,
+                            const Edje_Vg_Color_Binding *fill)
+{
+   int r = (node->r * fill->r) / 255;
+   int g = (node->g * fill->g) / 255;
+   int b = (node->b * fill->b) / 255;
+   int a = (node->a * fill->a) / 255;
+   /* Pre-multiply alpha, matching the existing _apply_color_binding contract. */
+   if (a < 255)
+     {
+        r = (r * a) / 255;
+        g = (g * a) / 255;
+        b = (b * a) / 255;
+     }
+   efl_gfx_color_set(s, r, g, b, a);
+}
+
 /* --------------------------------------------------------------------------
  * Pass 1 helper — collect all named gradient data-nodes into the hash.
  * Instantiates the Efl_VG gradient objects (no parent) so that shapes can
@@ -1528,10 +1566,17 @@ _shape_to_efl_vg(const Edje_Vg_Node *n, Efl_VG *parent,
         else
            WRN("gradient_ref '%s' not found in tree — fill left unset",
                n->shape.gradient_ref);
+        /* For gradient-filled shapes apply the node-level color directly
+         * (no flat fill binding to combine against). */
+        _apply_color_binding(s, &n->color);
      }
    else
      {
-        _apply_color_binding(s, &n->shape.fill);
+        /* Flat fill: combine node-level color × fill color per spec §3.2.
+         * Both are pre-resolved (Phase 6.2) so no class refs remain here.
+         * A single efl_gfx_color_set call replaces the old two-call pattern
+         * (fill first, then node-level overwrote it). */
+        _apply_shape_combined_color(s, &n->color, &n->shape.fill);
      }
 
    /* Stroke */
@@ -1563,8 +1608,8 @@ _shape_to_efl_vg(const Edje_Vg_Node *n, Efl_VG *parent,
    /* Fill rule */
    efl_gfx_shape_fill_rule_set(s, n->shape.fill_rule);
 
-   /* Common: name, visibility, node-level color, transform */
-   _apply_common(s, n);
+   /* Common: name, visibility, transform — color already handled above. */
+   _apply_common_no_color(s, n);
 
    return s;
 }
diff --git a/src/tests/edje/edje_test_vector_states.c b/src/tests/edje/edje_test_vector_states.c
index 6b058f8aad..23c51969af 100644
--- a/src/tests/edje/edje_test_vector_states.c
+++ b/src/tests/edje/edje_test_vector_states.c
@@ -916,6 +916,7 @@ EFL_START_TEST(edje_vg_render_box_a_hover)
    Efl_Canvas_Vg_Node *vg_root;
    Efl_Canvas_Vg_Node *body_node;
    double sw;
+   int r, g, b, a;
 
    /* --- Setup: buffer canvas, edje object, load group --- */
    ee = ecore_evas_buffer_new(VG_RENDER_W, VG_RENDER_H);
@@ -956,13 +957,24 @@ EFL_START_TEST(edje_vg_render_box_a_hover)
    ck_assert_msg(sw >= 0.5 && sw <= 1.5,
                  "Default state stroke width %.2f != expected ~1.0", sw);
 
+   /* Default fill: tile_a body fill.color = (200,0,0,255); node-level color is
+    * default white (255,255,255,255).  Combined per spec §3.2:
+    *   r = 200*255/255 = 200, g = 0, b = 0, a = 255.
+    * Task 6.4 fix: single efl_gfx_color_set call with combined value — no
+    * longer clobbered by the node-level color write. */
+   efl_gfx_color_get(body_node, &r, &g, &b, &a);
+   ck_assert_msg(r == 200 && g == 0 && b == 0 && a == 255,
+                 "Default state fill (%d,%d,%d,%d) != expected (200,0,0,255)",
+                 r, g, b, a);
+
    /* --- Switch to hover state via signal --- */
    edje_object_signal_emit(obj, "test,hover", "test");
    edje_object_message_signal_process(obj);
 
    /* Recalc drives _edje_vector_recalc_apply with the new chosen_desc
     * (hover), which has overrides.  The override path dups the base tree
-    * and applies stroke.width: 4 before rematerializing. */
+    * and applies fill.color: (200,200,0,255) and stroke.width: 4 before
+    * rematerializing. */
    edje_object_calc_force(obj);
    ecore_evas_manual_render(ee);
 
@@ -987,6 +999,14 @@ EFL_START_TEST(edje_vg_render_box_a_hover)
                  "Hover state stroke width %.2f != expected ~4.0 (override not applied)",
                  sw);
 
+   /* The hover override also sets fill.color: (200,200,0,255).  With the
+    * Task 6.4 fix the combined color is node white × fill = (200,200,0,255).
+    * Assert fill color is now readable correctly. */
+   efl_gfx_color_get(body_node, &r, &g, &b, &a);
+   ck_assert_msg(r == 200 && g == 200 && b == 0 && a == 255,
+                 "Hover state fill (%d,%d,%d,%d) != expected (200,200,0,255)",
+                 r, g, b, a);
+
    /* --- Cleanup --- */
    evas_object_del(obj);
    ecore_evas_free(ee);
@@ -1768,6 +1788,87 @@ EFL_START_TEST(edje_vg_override_class_clear)
 }
 EFL_END_TEST
 
+/*
+ * edje_vg_render_box_classed_fill  (Task 6.4)
+ *
+ * End-to-end test for fill color class resolution combined with the Task 6.4
+ * materializer fix.
+ *
+ * Fixture: ui/box_classed
+ *   Uses tile_classed: body fill.color_class = "vg_accent" (80,140,255,255).
+ *   Default node-level color is white (255,255,255,255).
+ *
+ * Expected fill RGBA after Task 6.2 resolve + Task 6.4 combine:
+ *   resolved fill = vg_accent = (80,140,255,255)  (class resolved to raw RGBA)
+ *   node-level    = white     = (255,255,255,255)
+ *   combined      = (80*255/255, 140*255/255, 255*255/255, 255*255/255)
+ *                 = (80, 140, 255, 255)
+ *   premul step: alpha = 255, so no change to rgb.
+ *   Final efl_gfx_color_set value: (80, 140, 255, 255).
+ *
+ * Before Task 6.4: _apply_common clobbered the fill RGBA with the node-level
+ * white, making efl_gfx_color_get return (255,255,255,255) instead.  This
+ * test would have failed against (80,140,255,255) before the fix.
+ */
+EFL_START_TEST(edje_vg_render_box_classed_fill)
+{
+   const char *edj = TESTS_BUILD_DIR "/data/test_vector_states.edj";
+   Ecore_Evas *ee;
+   Evas *evas;
+   Evas_Object *obj;
+   Evas_Object *vg_part;
+   Efl_Canvas_Vg_Node *vg_root;
+   Efl_Canvas_Vg_Node *body_node;
+   int r, g, b, a;
+
+   /* --- Setup: buffer canvas, edje object, load group --- */
+   ee = ecore_evas_buffer_new(VG_RENDER_W, VG_RENDER_H);
+   fail_if(!ee);
+   ecore_evas_show(ee);
+   ecore_evas_manual_render_set(ee, EINA_TRUE);
+
+   evas = ecore_evas_get(ee);
+   fail_if(!evas);
+
+   obj = edje_object_add(evas);
+   fail_if(!obj);
+
+   fail_unless(edje_object_file_set(obj, edj, "ui/box_classed"));
+
+   evas_object_resize(obj, VG_RENDER_W, VG_RENDER_H);
+   evas_object_move(obj, 0, 0);
+   evas_object_show(obj);
+
+   edje_object_calc_force(obj);
+   ecore_evas_manual_render(ee);
+
+   /* --- Fetch the materialized body shape --- */
+   vg_part = (Evas_Object *)edje_object_part_object_get(obj, "vg");
+   fail_if(!vg_part);
+
+   vg_root = efl_canvas_vg_object_root_node_get(vg_part);
+   fail_if(vg_root == NULL);
+   fail_if(!efl_isa(vg_root, EFL_CANVAS_VG_CONTAINER_CLASS));
+
+   body_node = efl_canvas_vg_container_child_get(vg_root, "body");
+   fail_if(body_node == NULL);
+   fail_if(!efl_isa(body_node, EFL_CANVAS_VG_SHAPE_CLASS));
+
+   /* Phase 6.2 resolved vg_accent → raw (80,140,255,255) before materializing.
+    * Task 6.4 combined with node-level white: (80,140,255,255).
+    * Alpha == 255 so premul is a no-op.  Assert the fill color. */
+   efl_gfx_color_get(body_node, &r, &g, &b, &a);
+   ck_assert_msg(r == 80 && g == 140 && b == 255 && a == 255,
+                 "Classed fill (%d,%d,%d,%d) != expected vg_accent (80,140,255,255) — "
+                 "class resolve or fill+node combine broken",
+                 r, g, b, a);
+
+   /* --- Cleanup --- */
+   evas_object_del(obj);
+   ecore_evas_free(ee);
+}
+EFL_END_TEST
+
 void
 edje_test_vector_states(TCase *tc)
 {
@@ -1803,4 +1904,6 @@ edje_test_vector_states(TCase *tc)
    tcase_add_test(tc, edje_vg_runtime_class_retint);
    /* Phase 6.3 override-side empty-string class clear */
    tcase_add_test(tc, edje_vg_override_class_clear);
+   /* Phase 6.4 fill × node-level combined color + class resolution end-to-end */
+   tcase_add_test(tc, edje_vg_render_box_classed_fill);
 }

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

Reply via email to