e_blur: add stroke layer for blur 50/325250/1
authorhojoon-ryou <hojoon.ryou@samsung.com>
Wed, 4 Jun 2025 11:52:31 +0000 (20:52 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Thu, 5 Jun 2025 08:23:04 +0000 (17:23 +0900)
Change-Id: Ie4c62779ff0526f2c1007409b946b28f7f3f0ab4

src/bin/server/e_blur.c
src/include/e_blur.h

index 794560d70e66eb0b273bdfd9af5e438339bf4bfd..e76c8c5c71f188a2b0f44c1194e00b2300bbe37f 100644 (file)
@@ -42,6 +42,7 @@ struct _E_Blur_Manager
 
    struct {
       E_Blur_Dim_Config *dim_config;
+      E_Blur_Stroke_Config *stroke_config;
    } configs;
 };
 
@@ -84,6 +85,7 @@ struct _E_Blur_Rectangle
 
    E_View_Image *view_image;
    E_View_Rect  *dim_rect;
+   E_View_Image *stroke_image;
    E_View_Image *corner_radius_image;
 };
 
@@ -132,6 +134,8 @@ static void _e_blur_rectangle_view_image_new(E_Blur_Rectangle *blur_rectangle, E
 static void _e_blur_rectangle_view_image_free(E_Blur_Rectangle *blur_rectangle);
 static void _e_blur_rectangle_dim_rect_new(E_Blur_Rectangle *blur_rectangle, E_View_Tree *layer_tree, const char *name);
 static void _e_blur_rectangle_dim_rect_free(E_Blur_Rectangle *blur_rectangle);
+static void _e_blur_rectangle_stroke_image_new(E_Blur_Rectangle *blur_rectangle, E_View_Tree *layer_tree, const char *name);
+static void _e_blur_rectangle_stroke_image_free(E_Blur_Rectangle *blur_rectangle);
 static void _e_blur_rectangle_corner_radius_image_new(E_Blur_Rectangle *blur_rectangle, E_View_Tree *layer_tree, const char *name);
 static void _e_blur_rectangle_corner_radius_image_free(E_Blur_Rectangle *blur_rectangle);
 
@@ -244,6 +248,9 @@ _e_blur_rectangle_show(E_Blur_Rectangle *blur_rectangle)
    if (blur_rectangle->dim_rect)
      e_view_show(e_view_rect_view_get(blur_rectangle->dim_rect));
 
+   if (blur_rectangle->stroke_image)
+     e_view_show(e_view_image_view_get(blur_rectangle->stroke_image));
+
    if (blur_rectangle->corner_radius_image)
      e_view_show(e_view_image_view_get(blur_rectangle->corner_radius_image));
 }
@@ -256,6 +263,9 @@ _e_blur_rectangle_hide(E_Blur_Rectangle *blur_rectangle)
    if (blur_rectangle->dim_rect)
      e_view_hide(e_view_rect_view_get(blur_rectangle->dim_rect));
 
+   if (blur_rectangle->stroke_image)
+     e_view_hide(e_view_image_view_get(blur_rectangle->stroke_image));
+
    if (blur_rectangle->corner_radius_image)
      e_view_hide(e_view_image_view_get(blur_rectangle->corner_radius_image));
 }
@@ -269,6 +279,7 @@ _e_blur_rectangle_free(E_Blur_Rectangle *blur_rectangle)
 
    _e_blur_rectangle_view_image_free(blur_rectangle);
    _e_blur_rectangle_dim_rect_free(blur_rectangle);
+   _e_blur_rectangle_stroke_image_free(blur_rectangle);
    _e_blur_rectangle_corner_radius_image_free(blur_rectangle);
 
    if (blur_rectangle->listener.destroy.notify)
@@ -343,6 +354,16 @@ _e_blur_rectangle_geometry_set(E_Blur_Rectangle *blur_rectangle, E_Client *ec)
                              final_w, final_h);
      }
 
+   if (blur_rectangle->stroke_image)
+     {
+        int thickness = _blur_manager->configs.stroke_config->thickness;
+        e_view_image_geometry_set(blur_rectangle->stroke_image,
+                                  final_x - thickness,
+                                  final_y - thickness,
+                                  final_w + thickness * 2,
+                                  final_h + thickness * 2);
+     }
+
    if (blur_rectangle->corner_radius_image)
      e_view_image_geometry_set(blur_rectangle->corner_radius_image,
                                final_x, final_y, final_w, final_h);
@@ -359,6 +380,15 @@ _e_blur_rectangle_filter_set(E_Blur_Rectangle *blur_rectangle)
                  blur_rectangle->rx, blur_rectangle->ry);
 
         e_view_image_gfx_filter_program_set(blur_rectangle->corner_radius_image, program, "rounded_corner");
+
+        if (blur_rectangle->stroke_image)
+          {
+             int thickness = _blur_manager->configs.stroke_config->thickness;
+             snprintf(program, sizeof(program), "rounded_corner { rx = %d, ry = %d}",
+                      blur_rectangle->rx + thickness,
+                      blur_rectangle->ry + thickness);
+             e_view_image_gfx_filter_program_set(blur_rectangle->stroke_image, program, "rounded_corner");
+          }
      }
 
    snprintf(program, sizeof(program), "blur (%d) padding_set (0)",
@@ -504,6 +534,13 @@ _e_blur_cb_restack(struct wl_listener *listener, void *data)
              e_view_place_above(dim_view, img_view);
           }
 
+        if (blur_rectangle->stroke_image)
+          {
+             E_View *stroke_view = e_view_image_view_get(blur_rectangle->stroke_image);
+             e_view_reparent(stroke_view, layer_tree);
+             e_view_place_below(stroke_view, img_view);
+          }
+
         if (blur_rectangle->corner_radius_image)
           {
              E_View *corner_img_view = e_view_image_view_get(blur_rectangle->corner_radius_image);
@@ -667,6 +704,50 @@ _e_blur_rectangle_dim_rect_free(E_Blur_Rectangle *blur_rectangle)
    blur_rectangle->dim_rect = NULL;
 }
 
+static void
+_e_blur_rectangle_stroke_image_new(E_Blur_Rectangle *blur_rectangle, E_View_Tree *layer_tree, const char *name)
+{
+   E_View_Image *stroke_image = NULL;
+   E_View *stroke_view = NULL;
+   unsigned int *pixels = NULL, A, R, G, B;
+
+   EINA_SAFETY_ON_NULL_RETURN(layer_tree);
+   EINA_SAFETY_ON_NULL_RETURN(_blur_manager->configs.stroke_config);
+
+   stroke_image = e_view_image_filled_create(layer_tree);
+   EINA_SAFETY_ON_NULL_RETURN(stroke_image);
+   stroke_view = e_view_image_view_get(stroke_image);
+
+   e_view_image_size_set(stroke_image, 1, 1);
+   pixels = e_view_image_data_get(stroke_image, true);
+   if (!pixels)
+     {
+        e_view_destroy(stroke_view);
+        return;
+     }
+   A = _blur_manager->configs.stroke_config->color.a;
+   R = _blur_manager->configs.stroke_config->color.r;
+   G = _blur_manager->configs.stroke_config->color.g;
+   B = _blur_manager->configs.stroke_config->color.b;
+   *pixels = (A << 24) | (R << 16) | (G << 8) | B;
+   e_view_image_data_set(stroke_image, pixels);
+   e_view_image_data_update_add(stroke_image, 0, 0, 1, 1);
+
+   e_view_name_set(stroke_view, name);
+   e_view_pass_events_set(stroke_view, true);
+
+   blur_rectangle->stroke_image = stroke_image;
+}
+
+static void
+_e_blur_rectangle_stroke_image_free(E_Blur_Rectangle *blur_rectangle)
+{
+   EINA_SAFETY_ON_NULL_RETURN(blur_rectangle);
+   EINA_SAFETY_ON_NULL_RETURN(blur_rectangle->stroke_image);
+   e_view_destroy(e_view_image_view_get(blur_rectangle->stroke_image));
+   blur_rectangle->stroke_image = NULL;
+}
+
 static void
 _e_blur_rectangle_corner_radius_image_new(E_Blur_Rectangle *blur_rectangle, E_View_Tree *layer_tree, const char *name)
 {
@@ -711,7 +792,7 @@ _e_blur_cb_new_rectangle(struct wl_listener *listener, void *data)
    E_Blur *blur;
    E_Blur_Rectangle *blur_rectangle;
    struct ds_tizen_blur_rectangle *tizen_blur_rectangle = data;
-   E_View *dim_view = NULL, *img_view = NULL, *corner_img_view = NULL;
+   E_View *dim_view = NULL, *img_view = NULL, *stroke_view = NULL, *corner_img_view = NULL;
    E_View_Client *blur_view_client;
    E_View_Tree *blur_view_client_tree;
    E_Blur_Hook_Data hook_data;
@@ -752,6 +833,13 @@ _e_blur_cb_new_rectangle(struct wl_listener *listener, void *data)
         dim_view = e_view_rect_view_get(blur_rectangle->dim_rect);
      }
 
+   if (_blur_manager->configs.stroke_config->enabled)
+     {
+        _e_blur_rectangle_stroke_image_new(blur_rectangle, blur_view_client_tree, "blur_stroke_obj");
+        EINA_SAFETY_ON_NULL_GOTO(blur_rectangle->stroke_image, fail);
+        stroke_view = e_view_image_view_get(blur_rectangle->stroke_image);
+     }
+
    if ((blur_rectangle->rx != 0) && (blur_rectangle->ry != 0))
      {
         _e_blur_rectangle_corner_radius_image_new(blur_rectangle, blur_view_client_tree, "blur_corner_radius_image");
@@ -774,6 +862,8 @@ _e_blur_cb_new_rectangle(struct wl_listener *listener, void *data)
      e_view_place_above(corner_img_view, img_view);
    if (dim_view)
      e_view_place_above(dim_view, img_view);
+   if (stroke_view)
+     e_view_place_below(stroke_view, img_view);
 
    // show new E_Views
    if (e_view_client_visible_get(blur_view_client) && _e_blur_enabled_get(blur))
@@ -789,6 +879,7 @@ _e_blur_cb_new_rectangle(struct wl_listener *listener, void *data)
    return;
 
 fail:
+   if (stroke_view) _e_blur_rectangle_stroke_image_free(blur_rectangle);
    if (dim_view) _e_blur_rectangle_dim_rect_free(blur_rectangle);
    if (img_view) _e_blur_rectangle_view_image_free(blur_rectangle);
    if (blur_rectangle) free(blur_rectangle);
@@ -1206,6 +1297,7 @@ e_blur_manager_init(void)
    blur_manager = E_NEW(E_Blur_Manager, 1);
    EINA_SAFETY_ON_NULL_RETURN_VAL(blur_manager, EINA_FALSE);
 
+   // base configs
    blur_manager->configs.dim_config = E_NEW(E_Blur_Dim_Config, 1);
    EINA_SAFETY_ON_NULL_GOTO(blur_manager->configs.dim_config, fail);
    blur_manager->configs.dim_config->enabled = EINA_FALSE;
@@ -1214,6 +1306,15 @@ e_blur_manager_init(void)
    blur_manager->configs.dim_config->color.b = 15;
    blur_manager->configs.dim_config->color.a = 153; // #1A1A1A, 60%, premultiplied alpha
 
+   blur_manager->configs.stroke_config = E_NEW(E_Blur_Stroke_Config, 1);
+   EINA_SAFETY_ON_NULL_GOTO(blur_manager->configs.stroke_config, fail);
+   blur_manager->configs.stroke_config->enabled = EINA_FALSE;
+   blur_manager->configs.stroke_config->color.r = 51;
+   blur_manager->configs.stroke_config->color.g = 51;
+   blur_manager->configs.stroke_config->color.b = 51;
+   blur_manager->configs.stroke_config->color.a = 102; // #808080, 40%, premultiplied alpha
+   blur_manager->configs.stroke_config->thickness = 2; // 2px
+
    blur_manager->tizen_blur_manager = ds_tizen_blur_manager_create(wl_disp);
    EINA_SAFETY_ON_NULL_GOTO(blur_manager->tizen_blur_manager, fail);
 
@@ -1241,6 +1342,7 @@ e_blur_manager_init(void)
 
 fail:
 
+   if (blur_manager->configs.stroke_config) free(blur_manager->configs.stroke_config);
    if (blur_manager->configs.dim_config) free(blur_manager->configs.dim_config);
    free(blur_manager);
 
@@ -1360,7 +1462,7 @@ e_blur_trace_debug(Eina_Bool onoff)
    e_blur_video_capture_trace_debug(onoff);
 }
 
-E_API Eina_Bool 
+E_API Eina_Bool
 e_blur_dim_config_set(E_Blur_Dim_Config *dim_config)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(_blur_manager, EINA_FALSE);
@@ -1460,3 +1562,81 @@ e_blur_dim_config_get(E_Blur_Dim_Config *dim_config)
 
    *dim_config = *_blur_manager->configs.dim_config;
 }
+
+E_API Eina_Bool
+e_blur_stroke_config_set(E_Blur_Stroke_Config *stroke_config)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(_blur_manager, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(_blur_manager->configs.stroke_config, EINA_FALSE);
+
+   E_Blur_Stroke_Config *current_stroke_config = _blur_manager->configs.stroke_config;
+   Eina_Bool before_enabled = current_stroke_config->enabled;
+   Eina_Bool after_enabled = stroke_config->enabled;
+   E_View_Client *view_client;
+   E_View_Tree *view_client_tree;
+   E_Blur *blur;
+   E_Blur_Rectangle *blur_rectangle;
+   Eina_List *l, *ll;
+   unsigned int *pixels, color = 0;
+
+   current_stroke_config->enabled = stroke_config->enabled;
+   current_stroke_config->color.r = stroke_config->color.r;
+   current_stroke_config->color.g = stroke_config->color.g;
+   current_stroke_config->color.b = stroke_config->color.b;
+   current_stroke_config->color.a = stroke_config->color.a;
+   current_stroke_config->thickness = stroke_config->thickness;
+
+   color = (((unsigned int)stroke_config->color.a) << 24)
+           | (((unsigned int)stroke_config->color.r) << 16)
+           | (((unsigned int)stroke_config->color.g) << 8)
+           | ((unsigned int)stroke_config->color.b);
+
+   if (!before_enabled && !after_enabled)
+     return EINA_TRUE;
+
+   EINA_LIST_FOREACH(_blur_manager->blurs, l, blur)
+     {
+        view_client = e_client_view_get(blur->ec);
+        if (!view_client) continue;
+        view_client_tree = e_canvas_layer_view_tree_get(e_comp_canvas_get(), e_view_layer_index_get(e_view_client_view_get(view_client)));
+        if (!view_client_tree) continue;
+        EINA_LIST_FOREACH(blur->blur_rectangles, ll, blur_rectangle)
+          {
+             if (after_enabled)
+               {
+                  if (!blur_rectangle->stroke_image)
+                    {
+                       _e_blur_rectangle_stroke_image_new(blur_rectangle, view_client_tree, "blur_stroke_obj");
+                       EINA_SAFETY_ON_NULL_RETURN_VAL(blur_rectangle->stroke_image, EINA_FALSE);
+                       e_view_place_below(e_view_image_view_get(blur_rectangle->stroke_image),
+                                          e_view_image_view_get(blur_rectangle->view_image));
+                       if (blur->enabled) _e_blur_rectangle_show(blur_rectangle);
+                    }
+                  pixels = e_view_image_data_get(blur_rectangle->stroke_image, true);
+                  if (!pixels)
+                    {
+                       e_view_destroy(e_view_image_view_get(blur_rectangle->stroke_image));
+                       return EINA_FALSE;
+                    }
+                  *pixels = color;
+                  e_view_image_data_set(blur_rectangle->stroke_image, pixels);
+                  e_view_image_data_update_add(blur_rectangle->stroke_image, 0, 0, 1, 1);
+                  _e_blur_rectangle_geometry_set(blur_rectangle, blur->ec);
+                  _e_blur_rectangle_filter_set(blur_rectangle);
+               }
+             else if (before_enabled)
+               _e_blur_rectangle_stroke_image_free(blur_rectangle);
+         }
+     }
+
+   return EINA_TRUE;
+}
+
+E_API void
+e_blur_stroke_config_get(E_Blur_Stroke_Config *stroke_config)
+{
+   EINA_SAFETY_ON_NULL_RETURN(stroke_config);
+   EINA_SAFETY_ON_NULL_RETURN(_blur_manager);
+
+   *stroke_config = *_blur_manager->configs.stroke_config;
+}
index 1ca47bb3d40c78de5b2811fdc4747ab9ba46555a..7ef021e0e86bcc6d23657d3c284bf2e3b51973af 100644 (file)
@@ -8,6 +8,7 @@ extern "C" {
 #include "e_types.h"
 
 typedef struct _E_Blur_Dim_Config E_Blur_Dim_Config;
+typedef struct _E_Blur_Stroke_Config E_Blur_Stroke_Config;
 
 struct _E_Blur_Dim_Config
 {
@@ -20,11 +21,25 @@ struct _E_Blur_Dim_Config
    } color; /* premultiplied alpha */
 };
 
+struct _E_Blur_Stroke_Config
+{
+   Eina_Bool enabled;
+   struct {
+      unsigned char r;
+      unsigned char g;
+      unsigned char b;
+      unsigned char a;
+   } color; /* premultiplied alpha */
+   int thickness;
+};
+
 E_API Eina_Bool e_blur_dim_config_set(E_Blur_Dim_Config *dim_config);
 E_API void e_blur_dim_config_get(E_Blur_Dim_Config *dim_config);
+E_API Eina_Bool e_blur_stroke_config_set(E_Blur_Stroke_Config *stroke_config);
+E_API void e_blur_stroke_config_get(E_Blur_Stroke_Config *stroke_config);
 
 #ifdef  __cplusplus
 }
 #endif
 
-#endif
\ No newline at end of file
+#endif