transform core add
authorSungBae, Park <sb34.park@samsung.com>
Fri, 25 Mar 2016 12:01:14 +0000 (21:01 +0900)
committerGwanglim Lee <gl77.lee@samsung.com>
Tue, 29 Mar 2016 12:41:23 +0000 (21:41 +0900)
Signed-off-by: SungBae, Park <sb34.park@samsung.com>
Change-Id: Ie5c743f9c73561b5a8b8f4b88ecf779ebf007ce0

src/bin/Makefile.mk
src/bin/e_client.c
src/bin/e_client.h
src/bin/e_comp_object.c
src/bin/e_comp_object.h
src/bin/e_includes.h
src/bin/e_info_client.c
src/bin/e_info_server.c
src/bin/e_util_transform.c [new file with mode: 0644]
src/bin/e_util_transform.h [new file with mode: 0644]

index 89c4d6f..7c6b6bb 100644 (file)
@@ -78,7 +78,8 @@ src/bin/e_utils.h \
 src/bin/e_win.h \
 src/bin/e_xinerama.h \
 src/bin/e_zoomap.h \
-src/bin/e_zone.h
+src/bin/e_zone.h \
+src/bin/e_util_transform.h
 
 if HAVE_WAYLAND
 ENLIGHTENMENTHEADERS += \
@@ -151,6 +152,7 @@ src/bin/e_win.c \
 src/bin/e_xinerama.c \
 src/bin/e_zoomap.c \
 src/bin/e_zone.c \
+src/bin/e_util_transform.c \
 $(ENLIGHTENMENTHEADERS)
 
 if HAVE_WAYLAND
index f8ed7b2..3404b21 100644 (file)
@@ -898,6 +898,18 @@ _e_client_del(E_Client *ec)
      e_pixmap_client_set(ec->pixmap, NULL);
    ec->pixmap = NULL;
 
+   if (ec->transform_core.transform_list)
+     {
+        E_Util_Transform *transform;
+
+        EINA_LIST_FREE(ec->transform_core.transform_list, transform)
+          {
+             e_util_transform_unref(transform);
+          }
+     }
+
+   ec->transform_core.result.enable = EINA_FALSE;
+
    e_client_visibility_calculate();
 }
 
@@ -2442,6 +2454,7 @@ _e_client_eval(E_Client *ec)
      }
 #endif
 
+   e_client_transform_core_update(ec);
    _e_client_hook_call(E_CLIENT_HOOK_EVAL_END, ec);
 
    TRACE_DS_END();
@@ -2593,6 +2606,10 @@ _e_client_visibility_zone_calculate(E_Zone *zone)
    Eina_Iterator *it;
    Eina_Bool canvas_vis = EINA_TRUE;
    Eina_Bool ec_vis, ec_opaque, changed;
+   int x = 0;
+   int y = 0;
+   int w = 0;
+   int h = 0;
    const int edge = 1;
 
    if (!zone) return;
@@ -2622,6 +2639,7 @@ _e_client_visibility_zone_calculate(E_Zone *zone)
         /* check if external animation is running */
         if (evas_object_data_get(ec->frame, "effect_running")) continue;
 
+        e_client_geometry_get(ec, &x, &y, &w, &h);
         ec_vis = ec_opaque = changed = EINA_FALSE;
 
         ////////////////////////////////////////////////////////////////////////
@@ -2644,7 +2662,7 @@ _e_client_visibility_zone_calculate(E_Zone *zone)
                   it = eina_tiler_iterator_new(t);
                   EINA_ITERATOR_FOREACH(it, _r)
                     {
-                       if (E_INTERSECTS(ec->x, ec->y, ec->w, ec->h,
+                       if (E_INTERSECTS(x, y, w, h,
                                         _r->x, _r->y, _r->w, _r->h))
                          {
                             ec_vis = EINA_TRUE;
@@ -2679,10 +2697,10 @@ _e_client_visibility_zone_calculate(E_Zone *zone)
                   if ((!ec->argb) || (ec_opaque))
                     {
                        EINA_RECTANGLE_SET(&r,
-                                          ec->x,
-                                          ec->y,
-                                          ec->w + edge,
-                                          ec->h + edge);
+                                          x,
+                                          y,
+                                          w + edge,
+                                          h + edge);
                        eina_tiler_rect_del(t, &r);
 
                        if (eina_tiler_empty(t))
@@ -2736,6 +2754,199 @@ _e_client_visibility_zone_calculate(E_Zone *zone)
    TRACE_DS_END();
 }
 
+
+static Eina_Bool
+_e_client_transform_core_check_change(E_Client *ec)
+{
+   Eina_Bool check = EINA_FALSE;
+
+   if (!ec) return EINA_FALSE;
+
+   // check client position or size change
+   if (ec->x != ec->transform_core.backup.client_x ||
+       ec->y != ec->transform_core.backup.client_y ||
+       ec->w != ec->transform_core.backup.client_w ||
+       ec->h != ec->transform_core.backup.client_h)
+     {
+        check = EINA_TRUE;
+        ec->transform_core.backup.client_x = ec->x;
+        ec->transform_core.backup.client_y = ec->y;
+        ec->transform_core.backup.client_w = ec->w;
+        ec->transform_core.backup.client_h = ec->h;
+     }
+
+   // check new transform or del transform
+   if (ec->transform_core.changed)
+     {
+        check = EINA_TRUE;
+        ec->transform_core.changed = EINA_FALSE;
+     }
+
+   // check each transform change
+   if (ec->transform_core.transform_list)
+     {
+        Eina_List *l;
+        Eina_List *l_next;
+        E_Util_Transform *transform;
+
+        EINA_LIST_FOREACH_SAFE(ec->transform_core.transform_list, l, l_next, transform)
+          {
+             // del transform check
+             if (e_util_transform_ref_count_get(transform) <= 1)
+               {
+                  ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform);
+                  e_util_transform_unref(transform);
+                  check = EINA_TRUE;
+                  continue;
+               }
+
+             // transform change test
+             if (e_util_transform_change_get(transform))
+               {
+                  check = EINA_TRUE;
+                  e_util_transform_change_unset(transform);
+               }
+          }
+     }
+
+   // check parent matrix change
+#ifdef HAVE_WAYLAND_ONLY
+   if (ec->comp_data)
+     {
+        E_Comp_Wl_Client_Data *cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+
+        if (cdata->sub.data)
+          {
+             E_Client *parent = cdata->sub.data->parent;
+
+             if (parent && parent->transform_core.result.enable)
+               {
+                  ec->transform_core.parent.enable = EINA_TRUE;
+
+                  if (!e_util_transform_matrix_equal_check(&ec->transform_core.parent.matrix,
+                                                           &parent->transform_core.result.matrix))
+                    {
+                       check = EINA_TRUE;
+                       ec->transform_core.parent.matrix = parent->transform_core.result.matrix;
+                    }
+               }
+             else if (ec->transform_core.parent.enable)
+               {
+                  ec->transform_core.parent.enable = EINA_FALSE;
+                  e_util_transform_matrix_load_identity(&ec->transform_core.parent.matrix);
+                  check = EINA_TRUE;
+               }
+          }
+     }
+#endif
+
+   return check;
+}
+
+static void
+_e_client_transform_core_boundary_update(E_Client *ec,  E_Util_Transform_Rect_Vertex *vertices)
+{
+   double minx, miny;
+   double maxx, maxy;
+   double initValue = 99999;
+   int i;
+
+   if (!ec) return;
+   if (!ec->frame) return;
+   if (!ec->transform_core.result.enable) return;
+   if (!vertices) return;
+
+   minx = initValue;
+   miny = initValue;
+   maxx = -initValue;
+   maxy = -initValue;
+
+   for (i = 0 ; i < 4 ; ++i)
+     {
+        double x = 0.0;
+        double y = 0.0;
+        e_util_transform_vertices_pos_get(vertices, i, &x, &y, 0, 0);
+
+        if (x < minx) minx = x;
+        if (y < miny) miny = y;
+        if (x > maxx) maxx = x;
+        if (y > maxy) maxy = y;
+     }
+
+   ec->transform_core.result.boundary.x = (int)(minx + 0.5);
+   ec->transform_core.result.boundary.y = (int)(miny + 0.5);
+   ec->transform_core.result.boundary.w = (int)(maxx - minx + 0.5);
+   ec->transform_core.result.boundary.h = (int)(maxy - miny + 0.5);
+
+   ELOGF("COMP", "[Transform][boundary][%d %d %d %d]", ec->pixmap, ec,
+         ec->transform_core.result.boundary.x, ec->transform_core.result.boundary.y,
+         ec->transform_core.result.boundary.w, ec->transform_core.result.boundary.h);
+}
+
+static void
+_e_client_transform_core_vertices_apply(E_Client *ec EINA_UNUSED, Evas_Object *obj, E_Util_Transform_Rect_Vertex *vertices)
+{
+   if (!obj) return;
+
+   if (vertices)
+     {
+        Evas_Map *map = evas_map_new(4);
+
+        if (map)
+          {
+             int i;
+             evas_map_util_points_populate_from_object_full(map, obj, 0);
+             evas_map_util_points_color_set(map, 255, 255, 255, 255);
+
+             for (i = 0 ; i < 4 ; ++i)
+               {
+                  double dx = 0.0;
+                  double dy = 0.0;
+                  int x = 0;
+                  int y = 0;
+
+                  e_util_transform_vertices_pos_get(vertices, i, &dx, &dy, 0, 0);
+
+                  x = (int)(dx + 0.5);
+                  y = (int)(dy + 0.5);
+
+                  evas_map_point_coord_set(map, i, x, y, 1.0);
+               }
+
+             evas_object_map_set(obj, map);
+             evas_object_map_enable_set(obj, EINA_TRUE);
+
+             evas_map_free(map);
+          }
+     }
+   else
+      evas_object_map_enable_set(obj, EINA_FALSE);
+}
+
+static void
+_e_client_transform_core_sub_update(E_Client *ec, E_Util_Transform_Rect_Vertex *vertices)
+{
+#ifdef HAVE_WAYLAND_ONLY
+   Eina_List *l;
+   E_Client *subc;
+   E_Comp_Wl_Client_Data *cdata;
+
+   if (!ec) return;
+   if (!ec->comp_data) return;
+
+   cdata = (E_Comp_Wl_Client_Data*)ec->comp_data;
+
+   if (cdata->sub.below_obj)
+      _e_client_transform_core_vertices_apply(ec, cdata->sub.below_obj, vertices);
+
+   EINA_LIST_FOREACH(cdata->sub.list, l, subc)
+      e_client_transform_core_update(subc);
+
+   EINA_LIST_FOREACH(cdata->sub.below_list, l, subc)
+      e_client_transform_core_update(subc);
+#endif
+}
+
 E_API void
 e_client_visibility_calculate(void)
 {
@@ -3641,18 +3852,40 @@ e_client_zone_set(E_Client *ec, E_Zone *zone)
 E_API void
 e_client_geometry_get(E_Client *ec, int *x, int *y, int *w, int *h)
 {
+   int gx = 0;
+   int gy = 0;
+   int gw = 0;
+   int gh = 0;
+
    E_OBJECT_CHECK(ec);
    E_OBJECT_TYPE_CHECK(ec, E_CLIENT_TYPE);
 
-   if (ec->frame)
-     evas_object_geometry_get(ec->frame, x, y, w, h);
+   if (e_client_transform_core_enable_get(ec))
+     {
+        gx = ec->transform_core.result.boundary.x;
+        gy = ec->transform_core.result.boundary.y;
+        gw = ec->transform_core.result.boundary.w;
+        gh = ec->transform_core.result.boundary.h;
+     }
    else
      {
-        if (x) *x = ec->x;
-        if (y) *y = ec->y;
-        if (w) *w = ec->w;
-        if (h) *h = ec->h;
+        if (ec->frame)
+          {
+             evas_object_geometry_get(ec->frame, &gx, &gy, &gw, &gh);
+          }
+        else
+          {
+             gx = ec->x;
+             gy = ec->y;
+             gw = ec->w;
+             gh = ec->h;
+          }
      }
+
+   if (x) *x = gx;
+   if (y) *y = gy;
+   if (w) *w = gw;
+   if (h) *h = gh;
 }
 
 E_API E_Client *
@@ -5539,3 +5772,149 @@ e_client_transform_clear(E_Client *ec)
    ec->transform.angle = 0.0;
    ec->transformed = EINA_FALSE;
 }
+
+E_API Eina_Bool e_client_transform_core_enable_get(E_Client *ec)
+{
+   if (!ec) return EINA_FALSE;
+   return ec->transform_core.result.enable;
+}
+
+E_API void e_client_transform_core_add(E_Client *ec, E_Util_Transform *transform)
+{
+   if (!ec) return;
+   if (!transform) return;
+
+   // duplication check
+   if (ec->transform_core.transform_list &&
+       eina_list_data_find(ec->transform_core.transform_list, transform) == transform)
+     {
+        return;
+     }
+
+   ec->transform_core.transform_list = eina_list_append(ec->transform_core.transform_list, transform);
+   ec->transform_core.changed = EINA_TRUE;
+   e_util_transform_ref(transform);
+   e_client_transform_core_update(ec);
+}
+
+E_API void e_client_transform_core_remove(E_Client *ec, E_Util_Transform *transform)
+{
+   if (!ec) return;
+   if (!transform) return;
+
+   if (ec->transform_core.transform_list &&
+       eina_list_data_find(ec->transform_core.transform_list, transform) == transform)
+     {
+        ec->transform_core.transform_list = eina_list_remove(ec->transform_core.transform_list, transform);
+        e_util_transform_unref(transform);
+        ec->transform_core.changed = EINA_TRUE;
+     }
+
+   e_client_transform_core_update(ec);
+}
+
+E_API void e_client_transform_core_update(E_Client *ec)
+{
+   if (!ec) return;
+   if (ec->new_client) return;
+   if (!_e_client_transform_core_check_change(ec)) return;
+
+   if (ec->transform_core.transform_list || ec->transform_core.parent.enable)
+     {
+        E_Util_Transform_Rect source_rect;
+        E_Util_Transform_Matrix matrix, boundary_matrix;
+        Eina_List *l;
+        Eina_Bool keep_ratio = EINA_FALSE;
+        E_Util_Transform *temp_trans;
+
+        // 1. init state
+        ec->transform_core.result.enable = EINA_TRUE;
+        e_util_transform_rect_client_rect_get(&source_rect, ec);
+        e_util_transform_init(&ec->transform_core.result.transform);
+
+        // 2. merge transform
+        EINA_LIST_FOREACH(ec->transform_core.transform_list, l, temp_trans)
+          {
+             ec->transform_core.result.transform = e_util_transform_merge(&ec->transform_core.result.transform, temp_trans);
+          }
+
+        // 3. covert to matrix and apply keep_ratio
+        boundary_matrix = e_util_transform_convert_to_matrix(&ec->transform_core.result.transform, &source_rect);
+        keep_ratio = e_util_transform_keep_ratio_get(&ec->transform_core.result.transform);
+
+        if (keep_ratio)
+          {
+             ec->transform_core.result.transform = e_util_transform_keep_ratio_apply(&ec->transform_core.result.transform, ec->w, ec->h);
+             matrix = e_util_transform_convert_to_matrix(&ec->transform_core.result.transform, &source_rect);
+          }
+        else
+           matrix = boundary_matrix;
+
+        if (keep_ratio != ec->transform_core.keep_ratio)
+          {
+             if (keep_ratio)
+               {
+                  e_comp_object_transform_bg_set(ec->frame, EINA_TRUE);
+               }
+             else
+               {
+                  e_comp_object_transform_bg_set(ec->frame, EINA_FALSE);
+               }
+
+             ec->transform_core.keep_ratio = keep_ratio;
+          }
+
+        // 3.5 parent matrix multiply
+        if (ec->transform_core.parent.enable)
+          {
+             matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix,
+                                                       &matrix);
+             boundary_matrix = e_util_transform_matrix_multiply(&ec->transform_core.parent.matrix,
+                                                                &boundary_matrix);
+          }
+
+        // 4. apply matrix to vertices
+        ec->transform_core.result.matrix = matrix;
+        ec->transform_core.result.vertices = e_util_transform_rect_to_vertices(&source_rect);
+        ec->transform_core.result.boundary.vertices = e_util_transform_rect_to_vertices(&source_rect);
+        ec->transform_core.result.vertices = e_util_transform_matrix_multiply_rect_vertex(&matrix,
+                                                                                          &ec->transform_core.result.vertices);
+        ec->transform_core.result.boundary.vertices = e_util_transform_matrix_multiply_rect_vertex(&boundary_matrix,
+                                                                                                   &ec->transform_core.result.boundary.vertices);
+
+        // 5. apply vertices
+        e_comp_object_transform_bg_vertices_set(ec->frame, &ec->transform_core.result.boundary.vertices);
+        _e_client_transform_core_boundary_update(ec, &ec->transform_core.result.boundary.vertices);
+        _e_client_transform_core_vertices_apply(ec, ec->frame, &ec->transform_core.result.vertices);
+
+        // 6. subsurface update'
+        _e_client_transform_core_sub_update(ec, &ec->transform_core.result.vertices);
+     }
+   else
+     {
+        ec->transform_core.result.enable = EINA_FALSE;
+        _e_client_transform_core_vertices_apply(ec, ec->frame, NULL);
+        _e_client_transform_core_sub_update(ec, NULL);
+     }
+
+   e_client_visibility_calculate();
+}
+
+E_API int
+e_client_transform_core_transform_count_get(E_Client *ec)
+{
+   if (!ec) return 0;
+   if (!ec->transform_core.transform_list) return 0;
+   return eina_list_count(ec->transform_core.transform_list);
+}
+
+E_API E_Util_Transform*
+e_client_transform_core_transform_get(E_Client *ec, int index)
+{
+   if (!ec) return NULL;
+   if (!ec->transform_core.transform_list) return NULL;
+   if (index < 0 || index >= e_client_transform_core_transform_count_get(ec))
+      return NULL;
+
+   return (E_Util_Transform*)eina_list_nth(ec->transform_core.transform_list, index);
+}
index 1a02c50..424bded 100644 (file)
@@ -828,6 +828,39 @@ struct E_Client
       Eina_Bool saved;
       E_Layer   saved_layer; // original layer
    } changable_layer[E_CHANGABLE_LAYER_TYPE_MAX];
+
+ struct
+   {
+       Eina_List *transform_list;
+       Eina_Bool  keep_ratio;
+       Eina_Bool  changed;
+
+       struct
+       {
+           int client_x, client_y, client_w, client_h;
+       } backup;
+
+       struct
+       {
+           Eina_Bool                    enable;
+           E_Util_Transform_Matrix      matrix;
+           E_Util_Transform_Rect_Vertex vertices;
+           E_Util_Transform             transform;
+
+           struct
+           {
+               E_Util_Transform_Rect_Vertex vertices;
+               int x, y, w, h;
+           } boundary;
+
+       } result;
+
+       struct
+       {
+           Eina_Bool               enable;
+           E_Util_Transform_Matrix matrix;
+       } parent;
+   } transform_core;
 };
 
 #define e_client_focus_policy_click(ec) \
@@ -971,6 +1004,13 @@ E_API void e_client_cursor_map_apply(E_Client *ec, int rotation, int x, int y);
 
 YOLO E_API void e_client_focus_stack_set(Eina_List *l);
 
+E_API Eina_Bool         e_client_transform_core_enable_get(E_Client *ec);
+E_API void              e_client_transform_core_add(E_Client *ec, E_Util_Transform *transform);
+E_API void              e_client_transform_core_remove(E_Client *ec, E_Util_Transform *transform);
+E_API void              e_client_transform_core_update(E_Client *ec);
+E_API int               e_client_transform_core_transform_count_get(E_Client *ec);
+E_API E_Util_Transform *e_client_transform_core_transform_get(E_Client *ec, int index);
+
 /**
  * Move window to coordinates that do not account client decorations yet.
  *
index d7bad62..ba83734 100644 (file)
@@ -86,6 +86,7 @@ typedef struct _E_Comp_Object
    Evas_Object         *shobj;  // shadow object
    Evas_Object         *effect_obj; // effects object
    Evas_Object         *mask_obj; // mask object: transparent parts of this comp object allow to copy the alpha to current H/W plane.
+   Evas_Object         *transform_bg_obj; // transform backgroung with keep_ratio option
    unsigned int         layer; //e_comp_canvas_layer_map(cw->ec->layer)
    Eina_List           *obj_mirror;  // extra mirror objects
    Eina_Tiler          *updates; //render update regions
@@ -275,6 +276,24 @@ _e_comp_object_cb_mirror_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj
 
 /////////////////////////////////////
 
+static void
+_e_comp_object_transform_bg_stack_update(Evas_Object *obj)
+{
+    API_ENTRY;
+    EINA_SAFETY_ON_NULL_RETURN(cw->ec);
+    if (cw->ec->input_only) return;
+    if (!cw->transform_bg_obj) return;
+
+    if (evas_object_layer_get(obj) != evas_object_layer_get(cw->transform_bg_obj))
+    {
+        int layer = evas_object_layer_get(obj);
+        evas_object_layer_set(cw->transform_bg_obj, layer);
+    }
+    evas_object_stack_below(cw->transform_bg_obj, obj);
+}
+
+/////////////////////////////////////
+
 static inline Eina_Bool
 _e_comp_shaped_check(int w, int h, const Eina_Rectangle *rects, int num)
 {
@@ -1453,6 +1472,7 @@ _e_comp_intercept_stack_above(void *data, Evas_Object *obj, Evas_Object *above)
 
    TRACE_DS_BEGIN(COMP:INTERCEPT STACK ABOVE);
    _e_comp_intercept_stack_helper(data, above, evas_object_stack_above);
+   _e_comp_object_transform_bg_stack_update(obj);
    TRACE_DS_END();
 }
 
@@ -1464,6 +1484,7 @@ _e_comp_intercept_stack_below(void *data, Evas_Object *obj, Evas_Object *below)
 
    TRACE_DS_BEGIN(COMP:INTERCEPT STACK BELOW);
    _e_comp_intercept_stack_helper(data, below, evas_object_stack_below);
+   _e_comp_object_transform_bg_stack_update(obj);
    TRACE_DS_END();
 }
 
@@ -1494,6 +1515,7 @@ _e_comp_intercept_lower(void *data, Evas_Object *obj)
    if (e_comp->hwc &&e_comp->nocomp_ec == cw->ec) e_comp_nocomp_end(__FUNCTION__);
    e_comp_render_queue();
    e_comp_shape_queue();
+   _e_comp_object_transform_bg_stack_update(obj);
 
 end:
    TRACE_DS_END();
@@ -1545,6 +1567,7 @@ _e_comp_intercept_raise(void *data, Evas_Object *obj)
       e_comp_nocomp_end(__FUNCTION__);
    e_comp_render_queue();
    e_comp_shape_queue();
+   _e_comp_object_transform_bg_stack_update(obj);
 
 end:
    TRACE_DS_END();
@@ -1770,6 +1793,9 @@ _e_comp_intercept_show(void *data, Evas_Object *obj EINA_UNUSED)
    if (cw->mask_obj)
      evas_object_resize(cw->mask_obj, cw->w, cw->h);
 
+   if (cw->transform_bg_obj)
+      evas_object_resize(cw->transform_bg_obj, cw->w, cw->h);
+
    _e_comp_intercept_show_helper(cw);
 }
 
@@ -2157,6 +2183,7 @@ _e_comp_smart_hide(Evas_Object *obj)
    evas_object_hide(cw->clip);
    if (cw->input_obj) evas_object_hide(cw->input_obj);
    evas_object_hide(cw->effect_obj);
+   if (cw->transform_bg_obj) evas_object_hide(cw->transform_bg_obj);
    if (cw->ec->dead)
      {
         Evas_Object *o;
@@ -2230,6 +2257,7 @@ _e_comp_smart_show(Evas_Object *obj)
    if (cw->ec->internal_elm_win && (!evas_object_visible_get(cw->ec->internal_elm_win)))
      evas_object_show(cw->ec->internal_elm_win);
    if (cw->mask_obj) evas_object_show(cw->mask_obj);
+   if (cw->transform_bg_obj) evas_object_show(cw->transform_bg_obj);
    e_comp_render_queue();
    if (cw->ec->input_only)
      {
@@ -2296,6 +2324,7 @@ _e_comp_smart_del(Evas_Object *obj)
    evas_object_del(cw->input_obj);
    evas_object_del(cw->obj);
    evas_object_del(cw->mask_obj);
+   evas_object_del(cw->transform_bg_obj);
    e_comp_shape_queue();
    eina_stringshare_del(cw->frame_theme);
    eina_stringshare_del(cw->frame_name);
@@ -2372,6 +2401,8 @@ _e_comp_smart_resize(Evas_Object *obj, int w, int h)
             cw->input_rect.w, cw->input_rect.h);
         if (cw->mask_obj)
           evas_object_resize(cw->mask_obj, w, h);
+        if (cw->transform_bg_obj)
+          evas_object_resize(cw->transform_bg_obj, w, h);
         /* resize render update tiler */
         if (!first)
           {
@@ -3624,6 +3655,7 @@ e_comp_object_dirty(Evas_Object *obj)
      evas_object_image_data_set(cw->obj, NULL);
    evas_object_image_size_set(cw->obj, w, h);
    if (cw->mask_obj) evas_object_resize(cw->mask_obj, w, h);
+   if (cw->transform_bg_obj) evas_object_resize(cw->transform_bg_obj, w, h);
 
    RENDER_DEBUG("SIZE [%p]: %dx%d", cw->ec, w, h);
    if (cw->pending_updates)
@@ -4276,3 +4308,81 @@ e_comp_object_size_update(Evas_Object *obj, int w, int h)
 
    evas_object_image_size_set(cw->obj, w, h);
 }
+
+E_API void
+e_comp_object_transform_bg_set(Evas_Object *obj, Eina_Bool set)
+{
+   Eina_Bool transform_set = EINA_FALSE;
+   API_ENTRY;
+   EINA_SAFETY_ON_NULL_RETURN(cw->ec);
+   if (cw->ec->input_only) return;
+
+   transform_set = !!set;
+
+   if (transform_set)
+     {
+        if (!cw->transform_bg_obj)
+          {
+             Evas_Object *o = evas_object_rectangle_add(e_comp->evas);
+             evas_object_move(o, 0, 0);
+             evas_object_resize(o, cw->w, cw->h);
+             evas_object_render_op_set(o, EVAS_RENDER_COPY);
+             evas_object_color_set(o, 0, 0, 0, 255);
+             if (cw->visible) evas_object_show(o);
+
+             cw->transform_bg_obj = o;
+          }
+        _e_comp_object_transform_bg_stack_update(obj);
+     }
+   else
+     {
+        if (cw->transform_bg_obj)
+          {
+             evas_object_smart_member_del(cw->transform_bg_obj);
+             E_FREE_FUNC(cw->transform_bg_obj, evas_object_del);
+          }
+     }
+}
+
+E_API void
+e_comp_object_transform_bg_vertices_set(Evas_Object *obj, E_Util_Transform_Rect_Vertex *vertices)
+{
+   API_ENTRY;
+   EINA_SAFETY_ON_NULL_RETURN(cw->ec);
+   if (cw->ec->input_only) return;
+   if (!cw->transform_bg_obj) return;
+
+   if (vertices)
+     {
+        Evas_Map *map = evas_map_new(4);
+
+        if (map)
+          {
+             int i;
+             evas_map_util_points_populate_from_object_full(map, cw->transform_bg_obj, 0);
+             evas_map_util_points_color_set(map, 255, 255, 255, 255);
+
+             for (i = 0 ; i < 4 ; ++i)
+               {
+                  double dx, dy;
+                  int x, y;
+
+                  e_util_transform_vertices_pos_get(vertices, i, &dx, &dy, 0, 0);
+
+                  x = (int)(dx + 0.5);
+                  y = (int)(dy + 0.5);
+
+                  evas_map_point_coord_set(map, i, x, y, 1.0);
+               }
+
+             evas_object_map_set(cw->transform_bg_obj, map);
+             evas_object_map_enable_set(cw->transform_bg_obj, EINA_TRUE);
+
+             evas_map_free(map);
+          }
+     }
+   else
+     {
+        evas_object_map_enable_set(cw->transform_bg_obj, EINA_FALSE);
+     }
+}
index 4660433..258481a 100644 (file)
@@ -115,7 +115,8 @@ E_API unsigned int e_comp_object_is_animating(Evas_Object *obj);
 E_API void e_comp_object_alpha_set(Evas_Object *obj, Eina_Bool alpha);
 E_API void e_comp_object_mask_set(Evas_Object *obj, Eina_Bool set);
 E_API void e_comp_object_size_update(Evas_Object *obj, int w, int h);
-
+E_API void e_comp_object_transform_bg_set(Evas_Object *obj, Eina_Bool set);
+E_API void e_comp_object_transform_bg_vertices_set(Evas_Object *obj, E_Util_Transform_Rect_Vertex *vertices);
 #endif
 #endif
 
index 1d0b2e7..c4c2712 100644 (file)
@@ -8,6 +8,7 @@
 #include "e_randr2.h"
 #include "e_pixmap.h"
 #include "e_comp_object.h"
+#include "e_util_transform.h"
 #include "e_client.h"
 #include "e_pointer.h"
 #include "e_config.h"
index 97f0f23..c3769bc 100644 (file)
@@ -885,6 +885,39 @@ _e_info_client_proc_fps_info(int argc, char **argv)
    while (keepRunning);
 }
 
+static void
+_e_info_client_proc_transform_set(int argc, char **argv)
+{
+   int32_t id_enable_xy_sxsy_angle[8];
+   int i;
+
+   if (argc < 5)
+     {
+        printf("Error Check Args: enlightenment_info -transform [windowID] [transform id] [enable] [x] [y] [scale_x(percent)] [scale_y(percent)] [degree] [keep_ratio]\n");
+        return;
+     }
+
+   id_enable_xy_sxsy_angle[0] = 0;      // transform id
+   id_enable_xy_sxsy_angle[1] = 1;      // enable
+   id_enable_xy_sxsy_angle[2] = 0;      // move x
+   id_enable_xy_sxsy_angle[3] = 0;      // move y
+   id_enable_xy_sxsy_angle[4] = 100;    // scale x percent
+   id_enable_xy_sxsy_angle[5] = 100;    // scale y percent
+   id_enable_xy_sxsy_angle[6] = 0;      // rotation degree
+   id_enable_xy_sxsy_angle[7] = 0;      // keep ratio
+
+   for (i = 0 ; i < 8 &&  i+3 < argc; ++i)
+      id_enable_xy_sxsy_angle[i] = atoi(argv[i+3]);
+
+   if (!_e_info_client_eldbus_message_with_args("transform_message", NULL, "siiiiiiii",
+                                                argv[2], id_enable_xy_sxsy_angle[0] , id_enable_xy_sxsy_angle[1], id_enable_xy_sxsy_angle[2],
+                                                id_enable_xy_sxsy_angle[3], id_enable_xy_sxsy_angle[4], id_enable_xy_sxsy_angle[5],
+                                                id_enable_xy_sxsy_angle[6], id_enable_xy_sxsy_angle[7]))
+     {
+        printf("_e_info_client_eldbus_message_with_args error");
+        return;
+     }
+}
 static struct
 {
    const char *option;
@@ -944,7 +977,13 @@ static struct
       "fps", NULL,
       "Print FPS in every sec",
       _e_info_client_proc_fps_info
-   }
+   },
+   {
+      "transform",
+      "[id enable x y w h angle keep_ratio]",
+      "Set transform in runtime",
+      _e_info_client_proc_transform_set
+   },
 };
 
 static void
index e889a17..d4836d1 100644 (file)
@@ -20,13 +20,28 @@ typedef struct _E_Info_Server
    Eldbus_Service_Interface *iface;
 } E_Info_Server;
 
+typedef struct _E_Info_Transform
+{
+   E_Client         *ec;
+   E_Util_Transform *transform;
+   int               id;
+   int               enable;
+} E_Info_Transform;
+
 static E_Info_Server e_info_server;
+static Eina_List    *e_info_transform_list = NULL;
 
 #define VALUE_TYPE_FOR_TOPVWINS "uuisiiiiibbiibbis"
 #define VALUE_TYPE_REQUEST_RESLIST "ui"
 #define VALUE_TYPE_REPLY_RESLIST "ssi"
 #define VALUE_TYPE_FOR_INPUTDEV "ssi"
 
+static E_Info_Transform *_e_info_transform_new(E_Client *ec, int id, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio);
+static E_Info_Transform *_e_info_transform_find(E_Client *ec, int id);
+static void              _e_info_transform_set(E_Info_Transform *transform, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio);
+static void              _e_info_transform_del(E_Info_Transform *transform);
+static void              _e_info_transform_del_with_id(E_Client *ec, int id);
+
 static void
 _msg_clients_append(Eldbus_Message_Iter *iter)
 {
@@ -417,7 +432,34 @@ _msg_window_prop_client_append(Eldbus_Message_Iter *iter, E_Client *target_ec)
    __WINDOW_PROP_ARG_APPEND("Maximize_override", target_ec->maximize_override ? char_True : char_False);
    __WINDOW_PROP_ARG_APPEND("Transformed", target_ec->transformed ? char_True : char_False);
    __WINDOW_PROP_ARG_APPEND_TYPE("Ignore_first_unmap", "%c", target_ec->ignore_first_unmap);
+   __WINDOW_PROP_ARG_APPEND_TYPE("Transform_count", "%d", e_client_transform_core_transform_count_get(target_ec));
+   if (e_client_transform_core_transform_count_get(target_ec) > 0)
+     {
+        int i;
+        int count = e_client_transform_core_transform_count_get(target_ec);
+
+        __WINDOW_PROP_ARG_APPEND(" ", "[id] [move] [scale] [rotation] [keep_ratio]");
+        for (i = 0 ; i < count ; ++i)
+          {
+             double dx, dy, dsx, dsy, drz;
+             int x, y, rz;
+             int keep_ratio;
 
+             E_Util_Transform *transform = e_client_transform_core_transform_get(target_ec, i);
+             if (!transform) continue;
+
+             e_util_transform_move_get(transform, &dx, &dy, NULL);
+             e_util_transform_scale_get(transform, &dsx, &dsy, NULL);
+             e_util_transform_rotation_get(transform, NULL, NULL, &drz);
+             keep_ratio = e_util_transform_keep_ratio_get(transform);
+
+             x = (int)(dx + 0.5);
+             y = (int)(dy + 0.5);
+             rz = (int)(drz + 0.5);
+
+             __WINDOW_PROP_ARG_APPEND_TYPE("Transform", "[%d] [%d, %d] [%2.1f, %2.1f] [%d] [%d]", i, x, y, dsx, dsy, rz, keep_ratio);
+          }
+     }
 #undef __WINDOW_PROP_ARG_APPEND
 #undef __WINDOW_PROP_ARG_APPEND_TYPE
 }
@@ -739,6 +781,63 @@ _e_info_server_cb_fps_info_get(const Eldbus_Service_Interface *iface EINA_UNUSED
    return reply;
 }
 
+static Eldbus_Message *
+e_info_server_cb_transform_message(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
+{
+   Eldbus_Message *reply = eldbus_message_method_return_new(msg);
+   uint32_t enable, transform_id;
+   uint32_t x, y, sx, sy, degree;
+   uint32_t keep_ratio;
+   const char *value = NULL;
+   int32_t value_number;
+   Evas_Object *o;
+   E_Client *ec;
+
+   if (!eldbus_message_arguments_get(msg, "siiiiiiii", &value, &transform_id, &enable, &x, &y, &sx, &sy, &degree, &keep_ratio))
+     {
+        ERR("Error getting arguments.");
+        return reply;
+     }
+
+   if (strlen(value) >= 2 && value[0] == '0' && value[1] == 'x')
+      sscanf(value, "%x", &value_number);
+   else
+      sscanf(value, "%d", &value_number);
+
+   for (o = evas_object_top_get(e_comp->evas); o; o = evas_object_below_get(o))
+     {
+        ec = evas_object_data_get(o, "E_Client");
+        Ecore_Window win;
+        E_Info_Transform *transform_info;
+
+        if (!ec) continue;
+
+        win = e_client_util_win_get(ec);
+
+        if (win != value_number) continue;
+        transform_info = _e_info_transform_find(ec, transform_id);
+
+        if (transform_info)
+          {
+             _e_info_transform_set(transform_info, enable, x, y, sx, sy, degree, keep_ratio);
+
+             if (!enable)
+                _e_info_transform_del_with_id(ec, transform_id);
+          }
+        else
+          {
+             if (enable)
+               {
+                  _e_info_transform_new(ec, transform_id, enable, x, y, sx, sy, degree, keep_ratio);
+               }
+          }
+
+        break;
+     }
+
+   return reply;
+}
+
 static const Eldbus_Method methods[] = {
    { "get_window_info", NULL, ELDBUS_ARGS({"a("VALUE_TYPE_FOR_TOPVWINS")", "array of ec"}), _e_info_server_cb_window_info_get, 0 },
    { "dump_topvwins", ELDBUS_ARGS({"s", "directory"}), NULL, _e_info_server_cb_topvwins_dump, 0 },
@@ -751,6 +850,7 @@ static const Eldbus_Method methods[] = {
    { "get_res_lists", ELDBUS_ARGS({VALUE_TYPE_REQUEST_RESLIST, "client resource"}), ELDBUS_ARGS({"a("VALUE_TYPE_REPLY_RESLIST")", "array of client resources"}), _e_info_server_cb_res_lists_get, 0 },
    { "get_input_devices", NULL, ELDBUS_ARGS({"a("VALUE_TYPE_FOR_INPUTDEV")", "array of input"}), _e_info_server_cb_input_device_info_get, 0},
    { "get_fps_info", NULL, ELDBUS_ARGS({"s", "fps request"}), _e_info_server_cb_fps_info_get, 0},
+   { "transform_message", ELDBUS_ARGS({"siiiiiiii", "transform_message"}), NULL, e_info_server_cb_transform_message, 0},
    { NULL, NULL, NULL, NULL, 0 }
 };
 
@@ -795,6 +895,20 @@ e_info_server_shutdown(void)
         e_info_server.conn = NULL;
      }
 
+   if (e_info_transform_list)
+     {
+        E_Info_Transform *info;
+        Eina_List *l, *l_next;
+
+        EINA_LIST_FOREACH_SAFE(e_info_transform_list, l, l_next, info)
+          {
+             _e_info_transform_del(info);
+          }
+
+        eina_list_free(e_info_transform_list);
+        e_info_transform_list = NULL;
+     }
+
    eldbus_shutdown();
 
    return 1;
@@ -871,3 +985,86 @@ e_info_server_dump_client(E_Client *ec, char *fname)
    if (img) evas_object_del(img);
    if (ee) ecore_evas_free(ee);
 }
+
+
+static E_Info_Transform*
+_e_info_transform_new(E_Client *ec, int id, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio)
+{
+   E_Info_Transform *result = NULL;
+   result = _e_info_transform_find(ec, id);
+
+   if (!result)
+     {
+        result = (E_Info_Transform*)malloc(sizeof(E_Info_Transform));
+        memset(result, 0, sizeof(E_Info_Transform));
+        result->id = id;
+        result->ec = ec;
+        result->transform = e_util_transform_new();
+        _e_info_transform_set(result, enable, x, y, sx, sy, degree, keep_ratio);
+        e_info_transform_list = eina_list_append(e_info_transform_list, result);
+
+     }
+
+   return result;
+}
+
+static E_Info_Transform*
+_e_info_transform_find(E_Client *ec, int id)
+{
+   Eina_List *l;
+   E_Info_Transform *transform;
+   E_Info_Transform *result = NULL;
+
+   EINA_LIST_FOREACH(e_info_transform_list, l, transform)
+     {
+        if (transform->ec == ec && transform->id == id)
+          {
+             result =  transform;
+             break;
+          }
+     }
+
+   return result;
+}
+
+static void
+_e_info_transform_set(E_Info_Transform *transform, int enable, int x, int y, int sx, int sy, int degree, int keep_ratio)
+{
+   if (!transform) return;
+   if (!transform->transform) return;
+
+   e_util_transform_move(transform->transform, (double)x, (double)y, 0.0);
+   e_util_transform_scale(transform->transform, (double)sx / 100.0, (double)sy / 100.0, 1.0);
+   e_util_transform_rotation(transform->transform, 0.0, 0.0, degree);
+   e_util_transform_keep_ratio_set(transform->transform, keep_ratio);
+
+   if (enable)
+      e_client_transform_core_add(transform->ec, transform->transform);
+   else
+      e_client_transform_core_remove(transform->ec, transform->transform);
+
+   e_client_transform_core_update(transform->ec);
+}
+
+static void
+_e_info_transform_del(E_Info_Transform *transform)
+{
+   if (!transform) return;
+
+   e_info_transform_list = eina_list_remove(e_info_transform_list, transform);
+   e_client_transform_core_remove(transform->ec, transform->transform);
+   e_util_transform_del(transform->transform);
+   free(transform);
+}
+
+static void
+_e_info_transform_del_with_id(E_Client *ec, int id)
+{
+   E_Info_Transform *transform = NULL;
+   if (!ec) return;
+
+   transform = _e_info_transform_find(ec, id);
+
+   if (transform)
+      _e_info_transform_del(transform);
+}
diff --git a/src/bin/e_util_transform.c b/src/bin/e_util_transform.c
new file mode 100644 (file)
index 0000000..4ccf965
--- /dev/null
@@ -0,0 +1,648 @@
+#include "e.h"
+#define E_UTIL_TRANSFORM_IS_ZERO(p) ((p) > -1e-21 && (p) < 1e-21)
+
+E_API E_Util_Transform*
+e_util_transform_new(void)
+{
+   E_Util_Transform *transform = (E_Util_Transform*)malloc(sizeof(E_Util_Transform));
+   if (transform)
+     {
+        transform->ref_count = 0;
+        e_util_transform_init(transform);
+        e_util_transform_ref(transform);
+     }
+   return transform;
+}
+
+E_API void
+e_util_transform_del(E_Util_Transform *transform)
+{
+   if (!transform) return;
+   e_util_transform_unref(transform);
+}
+
+E_API void
+e_util_transform_init(E_Util_Transform *transform)
+{
+   int back_ref_count = 0;
+   if (!transform) return;
+
+   back_ref_count = transform->ref_count;
+   memset(transform, 0, sizeof(E_Util_Transform));
+   transform->scale.value[0] = 1.0;
+   transform->scale.value[1] = 1.0;
+   transform->scale.value[2] = 1.0;
+   transform->changed = EINA_TRUE;
+   transform->ref_count = back_ref_count;
+}
+
+E_API void
+e_util_transform_ref(E_Util_Transform *transform)
+{
+   if (!transform) return;
+   transform->ref_count += 1;
+}
+
+E_API void
+e_util_transform_unref(E_Util_Transform *transform)
+{
+   if (!transform) return;
+   transform->ref_count -= 1;
+   if (transform->ref_count <= 0)
+      free(transform);
+}
+
+E_API int
+e_util_transform_ref_count_get(E_Util_Transform *transform)
+{
+   if (!transform) return 0;
+   return transform->ref_count;
+}
+
+E_API void
+e_util_transform_move(E_Util_Transform *transform, double x, double y, double z)
+{
+   if (!transform) return;
+
+   transform->move.value[0] = x;
+   transform->move.value[1] = y;
+   transform->move.value[2] = z;
+   transform->changed = EINA_TRUE;
+}
+
+E_API void
+e_util_transform_scale(E_Util_Transform *transform, double sx, double sy, double sz)
+{
+   if (!transform) return;
+
+   transform->scale.value[0] = sx;
+   transform->scale.value[1] = sy;
+   transform->scale.value[2] = sz;
+   transform->changed = EINA_TRUE;
+}
+
+E_API void
+e_util_transform_rotation(E_Util_Transform *transform, double rx, double ry, double rz)
+{
+   if (!transform) return;
+
+   transform->rotation.value[0] = rx;
+   transform->rotation.value[1] = ry;
+   transform->rotation.value[2] = rz;
+   transform->changed = EINA_TRUE;
+}
+
+E_API void
+e_util_transform_source_to_target(E_Util_Transform *transform,
+                                  E_Util_Transform_Rect *dest,
+                                  E_Util_Transform_Rect *source)
+{
+   if (!transform) return;
+   if (!dest || !source) return;
+
+   e_util_transform_init(transform);
+
+   if ((dest->x != source->x) || (dest->y != source->y))
+      e_util_transform_move(transform, dest->x - source->x, dest->y - source->y, 0.0);
+
+   if ((dest->w != source->w) || (dest->w != source->w))
+     {
+        if (!E_UTIL_TRANSFORM_IS_ZERO(source->w) &&
+            !E_UTIL_TRANSFORM_IS_ZERO(source->h))
+          {
+             e_util_transform_scale(transform, dest->w / source->w, dest->h / source->h, 1.0);
+          }
+     }
+
+   transform->changed = EINA_TRUE;
+}
+
+E_API E_Util_Transform
+e_util_transform_merge(E_Util_Transform *trans1, E_Util_Transform *trans2)
+{
+   E_Util_Transform result;
+   int i;
+
+   e_util_transform_init(&result);
+
+   if (!trans1) return result;
+   if (!trans2) return result;
+
+   for (i = 0 ; i < 3 ; ++i)
+      result.move.value[i] = trans1->move.value[i] + trans2->move.value[i];
+
+   for (i = 0 ; i < 3 ; ++i)
+      result.scale.value[i] = trans1->scale.value[i] * trans2->scale.value[i];
+
+   for (i = 0 ; i < 3 ; ++i)
+      result.rotation.value[i] = trans1->rotation.value[i] + trans2->rotation.value[i];
+
+   if (trans1->keep_ratio || trans2->keep_ratio)
+      result.keep_ratio = EINA_TRUE;
+
+   result.changed = EINA_TRUE;
+
+   return result;
+}
+
+E_API E_Util_Transform_Matrix
+e_util_transform_convert_to_matrix(E_Util_Transform *transform, E_Util_Transform_Rect *source_rect)
+{
+   E_Util_Transform_Matrix result;
+   e_util_transform_matrix_load_identity(&result);
+
+   if (!transform) return result;
+   if (!source_rect) return result;
+
+   double dest_w = source_rect->w * transform->scale.value[0];
+   double dest_h = source_rect->h * transform->scale.value[1];
+
+   e_util_transform_matrix_translate(&result, -source_rect->x - source_rect->w / 2.0, -source_rect->y - source_rect->h / 2.0, 0.0);
+   e_util_transform_matrix_scale(&result, transform->scale.value[0], transform->scale.value[1], transform->scale.value[2]);
+
+   if (!E_UTIL_TRANSFORM_IS_ZERO(transform->rotation.value[0]))
+      e_util_transform_matrix_rotation_x(&result, transform->rotation.value[0]);
+   if (!E_UTIL_TRANSFORM_IS_ZERO(transform->rotation.value[1]))
+      e_util_transform_matrix_rotation_y(&result, transform->rotation.value[1]);
+   if (!E_UTIL_TRANSFORM_IS_ZERO(transform->rotation.value[2]))
+      e_util_transform_matrix_rotation_z(&result, transform->rotation.value[2]);
+
+   e_util_transform_matrix_translate(&result, source_rect->x + transform->move.value[0] + (dest_w / 2.0),
+                                     source_rect->y + transform->move.value[1] + (dest_h / 2.0), 0.0);
+
+   return result;
+}
+
+E_API Eina_Bool
+e_util_transform_change_get(E_Util_Transform *transform)
+{
+   if (!transform) return EINA_FALSE;
+   return transform->changed;
+}
+
+E_API void
+e_util_transform_change_unset(E_Util_Transform *transform)
+{
+   if (!transform) return;
+   transform->changed = EINA_FALSE;
+}
+
+E_API void
+e_util_transform_keep_ratio_set(E_Util_Transform *transform, Eina_Bool enable)
+{
+   if (!transform) return;
+   if (transform->keep_ratio == enable) return;
+   transform->keep_ratio = enable;
+   transform->changed = EINA_TRUE;
+}
+
+E_API Eina_Bool
+e_util_transform_keep_ratio_get(E_Util_Transform *transform)
+{
+   if (!transform) return EINA_FALSE;
+   return transform->keep_ratio;
+}
+
+E_API E_Util_Transform
+e_util_transform_keep_ratio_apply(E_Util_Transform *transform, int origin_w, int origin_h)
+{
+   int i;
+   E_Util_Transform result;
+   E_Util_Transform_Vertex move_ver;
+   E_Util_Transform_Matrix matrix;
+
+   e_util_transform_vertex_init(&move_ver, 0.0, 0.0, 0.0, 1.0);
+   e_util_transform_matrix_load_identity(&matrix);
+
+   if (!transform) return result;
+
+   memcpy(&result, transform, sizeof(E_Util_Transform));
+
+   if (transform->scale.value[0] > transform->scale.value[1])
+      result.scale.value[0] = result.scale.value[1] = transform->scale.value[1];
+   else
+      result.scale.value[0] = result.scale.value[1] = transform->scale.value[0];
+
+   move_ver.vertex[0] += (transform->scale.value[0] - result.scale.value[0]) * origin_w * 0.5;
+   move_ver.vertex[1] += (transform->scale.value[1] - result.scale.value[1]) * origin_h * 0.5;
+
+   for(i = 0 ; i < 3 ; ++i)
+      result.move.value[i] += move_ver.vertex[i];
+
+   return result;
+}
+
+E_API void
+e_util_transform_move_get(E_Util_Transform *transform, double *x, double *y, double *z)
+{
+   if (!transform) return;
+   if (x) *x = transform->move.value[0];
+   if (y) *y = transform->move.value[1];
+   if (z) *z = transform->move.value[2];
+}
+
+E_API void
+e_util_transform_scale_get(E_Util_Transform *transform, double *x, double *y, double *z)
+{
+   if (!transform) return;
+   if (x) *x = transform->scale.value[0];
+   if (y) *y = transform->scale.value[1];
+   if (z) *z = transform->scale.value[2];
+}
+
+E_API void
+e_util_transform_rotation_get(E_Util_Transform *transform, double *x, double *y, double *z)
+{
+   if (!transform) return;
+   if (x) *x = transform->rotation.value[0];
+   if (y) *y = transform->rotation.value[1];
+   if (z) *z = transform->rotation.value[2];
+}
+
+E_API void
+e_util_transform_log(E_Util_Transform *transform, const char *str)
+{
+   if (!transform) return;
+   if (!str) return;
+
+   printf("[e_util_transform_log : %s\n", str);
+   printf("[move     : %2.1f, %2.1f, %2.1f]\n", transform->move.value[0], transform->move.value[1], transform->move.value[2]);
+   printf("[scale    : %2.1f, %2.1f, %2.1f]\n", transform->scale.value[0], transform->scale.value[1], transform->scale.value[2]);
+   printf("[rotation : %2.1f, %2.1f, %2.1f]\n", transform->rotation.value[0], transform->rotation.value[1], transform->rotation.value[2]);
+
+}
+
+E_API void
+e_util_transform_rect_init(E_Util_Transform_Rect *rect, int x, int y, int w, int h)
+{
+   if (!rect) return;
+
+   rect->x = x;
+   rect->y = y;
+   rect->w = w;
+   rect->h = h;
+}
+
+E_API void
+e_util_transform_rect_client_rect_get(E_Util_Transform_Rect *rect, E_Client *ec)
+{
+   if (!rect || !ec) return;
+   e_util_transform_rect_init(rect, ec->x, ec->y, ec->w, ec->h);
+}
+
+E_API E_Util_Transform_Rect_Vertex
+e_util_transform_rect_to_vertices(E_Util_Transform_Rect *rect)
+{
+   E_Util_Transform_Rect_Vertex result;
+   int i;
+
+   e_util_transform_vertices_init(&result);
+
+   if (!rect) return result;
+
+   // LT, RT, RB, LB
+   result.vertices[0].vertex[0] = rect->x;
+   result.vertices[0].vertex[1] = rect->y;
+
+   result.vertices[1].vertex[0] = rect->x + rect->w;
+   result.vertices[1].vertex[1] = rect->y;
+
+   result.vertices[2].vertex[0] = rect->x + rect->w;
+   result.vertices[2].vertex[1] = rect->y + rect->h;
+
+   result.vertices[3].vertex[0] = rect->x;
+   result.vertices[3].vertex[1] = rect->y + rect->h;
+
+   for (i = 0 ; i < 4 ; ++i)
+     {
+        result.vertices[i].vertex[2] = 1.0;
+        result.vertices[i].vertex[3] = 1.0;
+     }
+
+   return result;
+}
+
+
+E_API void
+e_util_transform_vertex_init(E_Util_Transform_Vertex *vertex, double x, double y, double z, double w)
+{
+   if (!vertex) return;
+
+   vertex->vertex[0] = x;
+   vertex->vertex[1] = y;
+   vertex->vertex[2] = z;
+   vertex->vertex[3] = w;
+}
+
+E_API void
+e_util_transform_vertex_pos_get(E_Util_Transform_Vertex *vertex, double *x, double *y, double *z, double *w)
+{
+   if (!vertex) return;
+
+   if (x) *x = vertex->vertex[0];
+   if (y) *y = vertex->vertex[1];
+   if (z) *z = vertex->vertex[2];
+   if (w) *w = vertex->vertex[3];
+}
+
+E_API void
+e_util_transform_vertices_init(E_Util_Transform_Rect_Vertex *vertices)
+{
+   int i;
+   if (!vertices) return;
+
+   for (i = 0 ; i < 4 ; ++i)
+      e_util_transform_vertex_init(&vertices->vertices[i], 0.0, 0.0, 0.0, 1.0);
+}
+
+E_API E_Util_Transform_Rect
+e_util_transform_vertices_to_rect(E_Util_Transform_Rect_Vertex *vertices)
+{
+   E_Util_Transform_Rect result;
+   e_util_transform_rect_init(&result, 0, 0, 0, 0);
+
+   if (vertices)
+     {
+        result.x = (int)(vertices->vertices[0].vertex[0] + 0.5);
+        result.y = (int)(vertices->vertices[0].vertex[1] + 0.5);
+        result.w = (int)(vertices->vertices[2].vertex[0] - vertices->vertices[0].vertex[0] + 0.5);
+        result.h = (int)(vertices->vertices[2].vertex[1] - vertices->vertices[0].vertex[1] + 0.5);
+     }
+
+   return result;
+}
+
+E_API void
+e_util_transform_vertices_pos_get(E_Util_Transform_Rect_Vertex *vertices, int index,
+                                  double *x, double *y, double *z, double *w)
+{
+   if (!vertices) return;
+   if (index < 0 || index >= 4) return;
+
+   e_util_transform_vertex_pos_get(&vertices->vertices[index], x, y, z, w);
+}
+
+E_API void
+e_util_transform_matrix_load_identity(E_Util_Transform_Matrix *matrix)
+{
+   if (!matrix) return;
+
+   matrix->mat[0][0] = 1; matrix->mat[0][1] = 0; matrix->mat[0][2] = 0; matrix->mat[0][3] = 0;
+   matrix->mat[1][0] = 0; matrix->mat[1][1] = 1; matrix->mat[1][2] = 0; matrix->mat[1][3] = 0;
+   matrix->mat[2][0] = 0; matrix->mat[2][1] = 0; matrix->mat[2][2] = 1; matrix->mat[2][3] = 0;
+   matrix->mat[3][0] = 0; matrix->mat[3][1] = 0; matrix->mat[3][2] = 0; matrix->mat[3][3] = 1;
+}
+
+E_API void
+e_util_transform_matrix_translate(E_Util_Transform_Matrix *matrix, double x, double y, double z)
+{
+   E_Util_Transform_Matrix source;
+
+   if (!matrix) return;
+
+   source = *matrix;
+
+   //   | 1 0 0 dx|     |m00 m01 m02 m03|
+   //   | 0 1 0 dy|     |m10 m11 m12 m13|
+   //   | 0 0 1 dz|  *  |m20 m21 m22 m23|
+   //   | 0 0 0 1 |     |m30 m31 m32 m33|
+
+   matrix->mat[0][0] = source.mat[0][0] + x * source.mat[3][0];
+   matrix->mat[0][1] = source.mat[0][1] + x * source.mat[3][1];
+   matrix->mat[0][2] = source.mat[0][2] + x * source.mat[3][2];
+   matrix->mat[0][3] = source.mat[0][3] + x * source.mat[3][3];
+
+   matrix->mat[1][0] = source.mat[1][0] + y * source.mat[3][0];
+   matrix->mat[1][1] = source.mat[1][1] + y * source.mat[3][1];
+   matrix->mat[1][2] = source.mat[1][2] + y * source.mat[3][2];
+   matrix->mat[1][3] = source.mat[1][3] + y * source.mat[3][3];
+
+   matrix->mat[2][0] = source.mat[2][0] + z * source.mat[3][0];
+   matrix->mat[2][1] = source.mat[2][1] + z * source.mat[3][1];
+   matrix->mat[2][2] = source.mat[2][2] + z * source.mat[3][2];
+   matrix->mat[2][3] = source.mat[2][3] + z * source.mat[3][3];
+}
+
+E_API void
+e_util_transform_matrix_rotation_x(E_Util_Transform_Matrix *matrix, double degree)
+{
+   E_Util_Transform_Matrix source;
+   double radian = 0.0;
+   double s, c;
+
+   if (!matrix) return;
+
+   source = *matrix;
+   radian = degree * M_PI / 180.0;
+   s = sin(radian);
+   c = cos(radian);
+
+   //   | 1  0  0  0 |     |m00 m01 m02 m03|
+   //   | 0  c -s  0 |     |m10 m11 m12 m13|
+   //   | 0  s  c  0 |  *  |m20 m21 m22 m23|
+   //   | 0  0  0  1 |     |m30 m31 m32 m33|
+
+   matrix->mat[1][0] = c * source.mat[1][0] + (-s) * source.mat[2][0];
+   matrix->mat[1][1] = c * source.mat[1][1] + (-s) * source.mat[2][1];
+   matrix->mat[1][2] = c * source.mat[1][2] + (-s) * source.mat[2][2];
+   matrix->mat[1][3] = c * source.mat[1][3] + (-s) * source.mat[2][3];
+
+   matrix->mat[2][0] = s * source.mat[1][0] + c * source.mat[2][0];
+   matrix->mat[2][1] = s * source.mat[1][1] + c * source.mat[2][1];
+   matrix->mat[2][2] = s * source.mat[1][2] + c * source.mat[2][2];
+   matrix->mat[2][3] = s * source.mat[1][3] + c * source.mat[2][3];
+}
+
+E_API void
+e_util_transform_matrix_rotation_y(E_Util_Transform_Matrix *matrix, double degree)
+{
+   E_Util_Transform_Matrix source;
+   double radian = 0.0;
+   double s, c;
+
+   if (!matrix) return;
+
+   source = *matrix;
+   radian = degree * M_PI / 180.0;
+   s = sin(radian);
+   c = cos(radian);
+
+   //   | c  0  s  0 |     |m00 m01 m02 m03|
+   //   | 0  1  0  0 |     |m10 m11 m12 m13|
+   //   |-s  0  c  0 |  *  |m20 m21 m22 m23|
+   //   | 0  0  0  1 |     |m30 m31 m32 m33|
+
+   matrix->mat[0][0] = c * source.mat[0][0] + s * source.mat[2][0];
+   matrix->mat[0][1] = c * source.mat[0][1] + s * source.mat[2][1];
+   matrix->mat[0][2] = c * source.mat[0][2] + s * source.mat[2][2];
+   matrix->mat[0][3] = c * source.mat[0][3] + s * source.mat[2][3];
+
+   matrix->mat[2][0] = (-s) * source.mat[0][0] + c * source.mat[2][0];
+   matrix->mat[2][0] = (-s) * source.mat[0][1] + c * source.mat[2][1];
+   matrix->mat[2][0] = (-s) * source.mat[0][2] + c * source.mat[2][2];
+   matrix->mat[2][0] = (-s) * source.mat[0][3] + c * source.mat[2][3];
+}
+
+E_API void
+e_util_transform_matrix_rotation_z(E_Util_Transform_Matrix *matrix, double degree)
+{
+   E_Util_Transform_Matrix source;
+   double radian = 0.0;
+   double s, c;
+
+   if (!matrix) return;
+
+   source = *matrix;
+   radian = degree * M_PI / 180.0;
+   s = sin(radian);
+   c = cos(radian);
+
+   //   | c -s  0  0 |     |m00 m01 m02 m03|
+   //   | s  c  0  0 |     |m10 m11 m12 m13|
+   //   | 0  0  1  0 |  *  |m20 m21 m22 m23|
+   //   | 0  0  0  1 |     |m30 m31 m32 m33|
+
+   matrix->mat[0][0] = c * source.mat[0][0] + (-s) * source.mat[1][0];
+   matrix->mat[0][1] = c * source.mat[0][1] + (-s) * source.mat[1][1];
+   matrix->mat[0][2] = c * source.mat[0][2] + (-s) * source.mat[1][2];
+   matrix->mat[0][3] = c * source.mat[0][3] + (-s) * source.mat[1][3];
+
+   matrix->mat[1][0] = s * source.mat[0][0] + c * source.mat[1][0];
+   matrix->mat[1][1] = s * source.mat[0][1] + c * source.mat[1][1];
+   matrix->mat[1][2] = s * source.mat[0][2] + c * source.mat[1][2];
+   matrix->mat[1][3] = s * source.mat[0][3] + c * source.mat[1][3];
+}
+
+E_API void
+e_util_transform_matrix_scale(E_Util_Transform_Matrix *matrix, double sx, double sy, double sz)
+{
+   E_Util_Transform_Matrix source;
+
+   if (!matrix) return;
+
+   source = *matrix;
+
+   //   | sx 0 0 0|     |m00 m01 m02 m03|
+   //   | 0 sy 0 0|     |m10 m11 m12 m13|
+   //   | 0 0 sz 0|  *  |m20 m21 m22 m23|
+   //   | 0 0  0 1|     |m30 m31 m32 m33|
+
+   matrix->mat[0][0] = sx * source.mat[0][0];
+   matrix->mat[0][1] = sx * source.mat[0][1];
+   matrix->mat[0][2] = sx * source.mat[0][2];
+   matrix->mat[0][3] = sx * source.mat[0][3];
+
+   matrix->mat[1][0] = sy * source.mat[1][0];
+   matrix->mat[1][1] = sy * source.mat[1][1];
+   matrix->mat[1][2] = sy * source.mat[1][2];
+   matrix->mat[1][3] = sy * source.mat[1][3];
+
+   matrix->mat[2][0] = sz * source.mat[2][0];
+   matrix->mat[2][1] = sz * source.mat[2][1];
+   matrix->mat[2][2] = sz * source.mat[2][2];
+   matrix->mat[2][3] = sz * source.mat[2][3];
+}
+
+E_API E_Util_Transform_Matrix
+e_util_transform_matrix_multiply(E_Util_Transform_Matrix *matrix1,
+                                 E_Util_Transform_Matrix *matrix2)
+{
+   E_Util_Transform_Matrix result;
+   int row, col, i;
+   e_util_transform_matrix_load_identity(&result);
+
+   if (!matrix1) return result;
+   if (!matrix2) return result;
+   //   |m00 m01 m02 m03|     |m00 m01 m02 m03|
+   //   |m10 m11 m12 m13|     |m10 m11 m12 m13|
+   //   |m20 m21 m22 m23|  *  |m20 m21 m22 m23|
+   //   |m30 m31 m32 m33|     |m30 m31 m32 m33|
+
+   for (row = 0 ; row < 4 ; ++row)
+     {
+        for (col = 0 ; col < 4; ++col)
+          {
+             double sum = 0.0;
+
+             for (i = 0 ; i < 4 ; ++i)
+               {
+                  sum += matrix1->mat[row][i] * matrix2->mat[i][col];
+               }
+
+             result.mat[row][col] = sum;
+          }
+     }
+
+   return result;
+}
+
+E_API E_Util_Transform_Vertex
+e_util_transform_matrix_multiply_vertex(E_Util_Transform_Matrix *matrix,
+                                        E_Util_Transform_Vertex *vertex)
+{
+   E_Util_Transform_Vertex result;
+   int row, col;
+
+   e_util_transform_vertex_init(&result, 0.0, 0.0, 0.0, 1.0);
+   if (!vertex) return result;
+   if (!matrix) return result;
+
+   //   |m00 m01 m02 m03|     |x|
+   //   |m10 m11 m12 m13|     |y|
+   //   |m20 m21 m22 m23|  *  |z|
+   //   |m30 m31 m32 m33|     |w|
+
+   for (row = 0 ; row < 4 ; ++row)
+     {
+        double sum = 0.0;
+
+        for (col = 0 ; col < 4; ++col)
+          {
+             sum += matrix->mat[row][col] * vertex->vertex[col];
+          }
+
+        result.vertex[row] = sum;
+     }
+
+   return result;
+}
+
+E_API E_Util_Transform_Rect_Vertex
+e_util_transform_matrix_multiply_rect_vertex(E_Util_Transform_Matrix *matrix,
+                                             E_Util_Transform_Rect_Vertex *vertices)
+{
+   E_Util_Transform_Rect_Vertex result;
+   int i;
+   e_util_transform_vertices_init(&result);
+
+   if (!matrix) return result;
+   if (!vertices) return result;
+
+   for (i = 0 ; i < 4 ; ++i)
+      result.vertices[i] = e_util_transform_matrix_multiply_vertex(matrix, &vertices->vertices[i]);
+
+   return result;
+}
+
+E_API Eina_Bool
+e_util_transform_matrix_equal_check(E_Util_Transform_Matrix *matrix,
+                                    E_Util_Transform_Matrix *matrix2)
+{
+   int row, col;
+   Eina_Bool result = EINA_TRUE;
+   if (!matrix || !matrix2) return EINA_FALSE;
+
+   for (row = 0 ; row < 4 && result ; ++row)
+     {
+        for (col = 0 ; col < 4 ; ++col)
+          {
+             if (matrix->mat[row][col] != matrix2->mat[row][col])
+               {
+                  result = EINA_FALSE;
+                  break;
+               }
+          }
+     }
+
+   return result;
+}
diff --git a/src/bin/e_util_transform.h b/src/bin/e_util_transform.h
new file mode 100644 (file)
index 0000000..62d10f4
--- /dev/null
@@ -0,0 +1,103 @@
+#ifdef E_TYPEDEFS
+
+typedef struct _E_Util_Transform_Value       E_Util_Transform_Value;
+typedef struct _E_Util_Transform             E_Util_Transform;
+typedef struct _E_Util_Transform_Rect        E_Util_Transform_Rect;
+typedef struct _E_Util_Transform_Vertex      E_Util_Transform_Vertex;
+typedef struct _E_Util_Transform_Rect_Vertex E_Util_Transform_Rect_Vertex;
+typedef struct _E_Util_Transform_Matrix      E_Util_Transform_Matrix;
+
+#else
+#ifndef E_UTIL_TRANSFORM_H_
+#define E_UTIL_TRANSFORM_H_
+
+struct _E_Util_Transform_Value
+{
+   double value[3];
+};
+
+struct _E_Util_Transform
+{
+   E_Util_Transform_Value scale;
+   E_Util_Transform_Value move;
+   E_Util_Transform_Value rotation;
+   int                    ref_count;
+   Eina_Bool              keep_ratio;
+   Eina_Bool              changed;
+};
+
+struct _E_Util_Transform_Rect
+{
+   int x;
+   int y;
+   int w;
+   int h;
+};
+
+struct _E_Util_Transform_Vertex
+{
+   double vertex[4];
+};
+
+struct _E_Util_Transform_Rect_Vertex
+{
+   E_Util_Transform_Vertex vertices[4];
+};
+
+struct _E_Util_Transform_Matrix
+{
+   double mat[4][4];
+};
+
+E_API E_Util_Transform            *e_util_transform_new(void);
+E_API void                         e_util_transform_del(E_Util_Transform *transform);
+E_API void                         e_util_transform_ref(E_Util_Transform *transform);
+E_API void                         e_util_transform_unref(E_Util_Transform *transform);
+E_API int                          e_util_transform_ref_count_get(E_Util_Transform *transform);
+E_API void                         e_util_transform_init(E_Util_Transform *transform);
+E_API void                         e_util_transform_move(E_Util_Transform *transform, double x, double y, double z);
+E_API void                         e_util_transform_scale(E_Util_Transform *transform, double sx, double sy, double sz);
+E_API void                         e_util_transform_rotation(E_Util_Transform *transform, double rx, double ry, double rz);
+E_API void                         e_util_transform_source_to_target(E_Util_Transform *transform,
+                                                                     E_Util_Transform_Rect *dest,
+                                                                     E_Util_Transform_Rect *source);
+E_API E_Util_Transform             e_util_transform_merge(E_Util_Transform *trans1, E_Util_Transform *trans2);
+E_API E_Util_Transform_Matrix      e_util_transform_convert_to_matrix(E_Util_Transform *transform, E_Util_Transform_Rect *source_rect);
+E_API Eina_Bool                    e_util_transform_change_get(E_Util_Transform *transform);
+E_API void                         e_util_transform_change_unset(E_Util_Transform *transform);
+E_API void                         e_util_transform_keep_ratio_set(E_Util_Transform *transform, Eina_Bool enable);
+E_API Eina_Bool                    e_util_transform_keep_ratio_get(E_Util_Transform *transform);
+E_API E_Util_Transform             e_util_transform_keep_ratio_apply(E_Util_Transform *transform, int origin_w, int origin_h);
+E_API void                         e_util_transform_move_get(E_Util_Transform *transform, double *x, double *y, double *z);
+E_API void                         e_util_transform_scale_get(E_Util_Transform *transform, double *x, double *y, double *z);
+E_API void                         e_util_transform_rotation_get(E_Util_Transform *transform, double *x, double *y, double *z);
+E_API void                         e_util_transform_log(E_Util_Transform *transform, const char *str);
+
+E_API void                         e_util_transform_rect_init(E_Util_Transform_Rect *rect, int x, int y, int w, int h);
+E_API void                         e_util_transform_rect_client_rect_get(E_Util_Transform_Rect *rect, E_Client *ec);
+E_API E_Util_Transform_Rect_Vertex e_util_transform_rect_to_vertices(E_Util_Transform_Rect *rect);
+
+E_API void                         e_util_transform_vertex_init(E_Util_Transform_Vertex *vertex, double x, double y, double z, double w);
+E_API void                         e_util_transform_vertex_pos_get(E_Util_Transform_Vertex *vertex, double *x, double *y, double *z, double *w);
+
+E_API void                         e_util_transform_vertices_init(E_Util_Transform_Rect_Vertex *vertices);
+E_API E_Util_Transform_Rect        e_util_transform_vertices_to_rect(E_Util_Transform_Rect_Vertex *vertex);
+E_API void                         e_util_transform_vertices_pos_get(E_Util_Transform_Rect_Vertex *vertices, int index,
+                                                                     double *x, double *y, double *z, double *w);
+
+E_API void                         e_util_transform_matrix_load_identity(E_Util_Transform_Matrix *matrix);
+E_API void                         e_util_transform_matrix_translate(E_Util_Transform_Matrix *matrix, double x, double y, double z);
+E_API void                         e_util_transform_matrix_rotation_x(E_Util_Transform_Matrix *matrix, double degree);
+E_API void                         e_util_transform_matrix_rotation_y(E_Util_Transform_Matrix *matrix, double degree);
+E_API void                         e_util_transform_matrix_rotation_z(E_Util_Transform_Matrix *matrix, double degree);
+E_API void                         e_util_transform_matrix_scale(E_Util_Transform_Matrix *matrix, double sx, double sy, double sz);
+E_API E_Util_Transform_Matrix      e_util_transform_matrix_multiply(E_Util_Transform_Matrix *matrix1,
+                                                                    E_Util_Transform_Matrix *matrix2);
+E_API E_Util_Transform_Vertex      e_util_transform_matrix_multiply_vertex(E_Util_Transform_Matrix *matrix,
+                                                                           E_Util_Transform_Vertex *vertex);
+E_API E_Util_Transform_Rect_Vertex e_util_transform_matrix_multiply_rect_vertex(E_Util_Transform_Matrix *matrix,
+                                                                                E_Util_Transform_Rect_Vertex *vertices);
+E_API Eina_Bool                    e_util_transform_matrix_equal_check(E_Util_Transform_Matrix *matrix,
+                                                                       E_Util_Transform_Matrix *matrix2);
+#endif
+#endif