e_comp_wl: Added an API to get buffer/output viewport and transform of E_Client. 83/217383/7
authorSeunghun Lee <shiin.lee@samsung.com>
Thu, 7 Nov 2019 07:47:47 +0000 (16:47 +0900)
committerSeunghun Lee <shiin.lee@samsung.com>
Tue, 12 Nov 2019 05:54:05 +0000 (14:54 +0900)
Change-Id: I72e21d5052030ff92453fba231d4f5a432eca76f

src/bin/e_comp_wl.c
src/bin/e_comp_wl.h

index a14d5a5..b72482c 100644 (file)
@@ -5739,3 +5739,277 @@ e_comp_wl_surface_state_buffer_set(E_Comp_Wl_Surface_State *state, E_Comp_Wl_Buf
 {
    _e_comp_wl_surface_state_buffer_set(state, buffer);
 }
+
+static void
+buffer_transform(int width, int height, uint32_t transform, int32_t scale,
+                 int sx, int sy, int *dx, int *dy)
+{
+   switch (transform)
+     {
+      case WL_OUTPUT_TRANSFORM_NORMAL:
+      default:
+         *dx = sx, *dy = sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED:
+         *dx = width - sx, *dy = sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_90:
+         *dx = height - sy, *dy = sx;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+         *dx = height - sy, *dy = width - sx;
+         break;
+      case WL_OUTPUT_TRANSFORM_180:
+         *dx = width - sx, *dy = height - sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+         *dx = sx, *dy = height - sy;
+         break;
+      case WL_OUTPUT_TRANSFORM_270:
+         *dx = sy, *dy = width - sx;
+         break;
+      case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+         *dx = sy, *dy = sx;
+         break;
+     }
+
+   *dx *= scale;
+   *dy *= scale;
+}
+
+static void
+_buffer_viewport_get(E_Comp_Wl_Buffer_Viewport *vp, int bw, int bh, Eina_Rectangle *out)
+{
+   int x1, y1, x2, y2;
+   int tx1, ty1, tx2, ty2;
+   int width_from_buffer, height_from_buffer;
+
+   switch (vp->buffer.transform)
+     {
+      case WL_OUTPUT_TRANSFORM_90:
+      case WL_OUTPUT_TRANSFORM_270:
+      case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+      case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+         width_from_buffer = bh / vp->buffer.scale;
+         height_from_buffer = bw / vp->buffer.scale;
+         break;
+      default:
+         width_from_buffer = bw / vp->buffer.scale;
+         height_from_buffer = bh / vp->buffer.scale;
+         break;
+     }
+
+   if (vp->buffer.src_width == wl_fixed_from_int(-1))
+     {
+        x1 = 0.0;
+        y1 = 0.0;
+        x2 = width_from_buffer;
+        y2 = height_from_buffer;
+     }
+   else
+     {
+        x1 = wl_fixed_to_int(vp->buffer.src_x);
+        y1 = wl_fixed_to_int(vp->buffer.src_y);
+        x2 = wl_fixed_to_int(vp->buffer.src_x + vp->buffer.src_width);
+        y2 = wl_fixed_to_int(vp->buffer.src_y + vp->buffer.src_height);
+     }
+
+   buffer_transform(width_from_buffer, height_from_buffer,
+                    vp->buffer.transform, vp->buffer.scale, x1, y1, &tx1, &ty1);
+   buffer_transform(width_from_buffer, height_from_buffer,
+                    vp->buffer.transform, vp->buffer.scale, x2, y2, &tx2, &ty2);
+
+   out->x = (tx1 <= tx2) ? tx1 : tx2;
+   out->y = (ty1 <= ty2) ? ty1 : ty2;
+   out->w = (tx1 <= tx2) ? tx2 - tx1 : tx1 - tx2;
+   out->h = (ty1 <= ty2) ? ty2 - ty1 : ty1 - ty2;
+}
+
+/**
+ * Convert given four coordinates to elements of rectangle
+ * @in   p[4]        Coordinates to be converted
+ * @out  rect        x, y, width, and height
+ *       transform   Angle which represents TDM_TRANSFORM of rectangle
+ * @return EINA_FALSE in following case, otherwise EINA_TRUE.
+ *   1. The given coordinates are not represented by rectangle.
+ *   2. All angles except for 0, 90, 180, 270.
+ */
+static Eina_Bool
+_coords_to_rectangle_convert(Evas_Point p[4], Eina_Rectangle *rect, uint *rotation)
+{
+   Eina_Bool ret = EINA_FALSE;
+
+   if ((p[0].y == p[1].y) && (p[1].x == p[2].x) && (p[2].y == p[3].y) && (p[3].x == p[0].x))
+     {
+        /* 0 or 180 */
+        if ((p[0].x < p[2].x) && (p[0].y < p[2].y))
+          {
+             if (rotation)
+               *rotation = TDM_TRANSFORM_NORMAL;
+
+             if (rect)
+               EINA_RECTANGLE_SET(rect, p[0].x, p[0].y, p[2].x - p[0].x, p[2].y - p[0].y);
+
+             ret = EINA_TRUE;
+          }
+        else if ((p[0].x > p[2].x) && (p[0].y > p[2].y))
+          {
+             if (rotation)
+               *rotation = TDM_TRANSFORM_180;
+
+             if (rect)
+               EINA_RECTANGLE_SET(rect, p[2].x, p[2].y, p[0].x - p[2].x, p[0].y - p[2].y);
+
+             ret = EINA_TRUE;
+          }
+     }
+   else if ((p[0].x == p[1].x) && (p[1].y == p[2].y) && (p[2].x == p[3].x) && (p[3].y == p[0].y))
+     {
+        /* 90 or 270 */
+        if ((p[0].x > p[2].x) && (p[0].y < p[2].y))
+          {
+             if (rotation)
+               *rotation = TDM_TRANSFORM_90;
+
+             if (rect)
+               EINA_RECTANGLE_SET(rect, p[2].x, p[0].y, p[0].x - p[2].x, p[2].y - p[0].y);
+
+             ret = EINA_TRUE;
+          }
+        else if ((p[0].x < p[2].x) && (p[0].y > p[2].y))
+          {
+             if (rotation)
+               *rotation = TDM_TRANSFORM_270;
+
+             if (rect)
+               EINA_RECTANGLE_SET(rect, p[0].x, p[2].y, p[2].x - p[0].x, p[0].y - p[2].y);
+
+             ret = EINA_TRUE;
+          }
+     }
+
+   return ret;
+}
+
+static Eina_Bool
+_output_viewport_get_from_evas_map(const Evas_Map *m, Eina_Rectangle *out, unsigned int *rotation)
+{
+   Evas_Point p[4];
+   int i;
+
+   for (i = 0; i < 4; i++)
+     evas_map_point_coord_get(m, i, &p[i].x, &p[i].y, NULL);
+
+   if (!_coords_to_rectangle_convert(p, out, rotation))
+     {
+        DBG("Cannot convert given coords to rectangle.\n"
+            "p1(%d %d) p2(%d %d) p3(%d %d) p4(%d %d)",
+            p[0].x, p[0].y, p[1].x, p[1].y,
+            p[2].x, p[2].y, p[3].x, p[3].y);
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static unsigned int
+_transform_merge_with_rotation(enum wl_output_transform transform, unsigned int rotation)
+{
+   int trans_rotation, flip;
+
+   trans_rotation = transform & 0x3;
+   flip = transform & 0x4;
+
+   return (flip + (trans_rotation + rotation) % 4);
+}
+
+static void
+_e_comp_wl_surface_output_viewport_get(E_Client *ec, Eina_Rectangle *out)
+{
+   E_Comp_Wl_Subsurf_Data *sdata = NULL;
+
+   if (!out)
+     return;
+
+   if (!ec->comp_data)
+     return;
+
+   sdata = ec->comp_data->sub.data;
+   if (sdata)
+     {
+        if (sdata->parent)
+          {
+             out->x = sdata->parent->x + sdata->position.x;
+             out->y = sdata->parent->y + sdata->position.y;
+          }
+        else
+          {
+             out->x = sdata->position.x;
+             out->y = sdata->position.y;
+          }
+     }
+   else
+     {
+        out->x = ec->x;
+        out->y = ec->y;
+     }
+
+   out->w = ec->comp_data->width_from_viewport;
+   out->w = (out->w + 1) & ~1;
+   out->h = ec->comp_data->height_from_viewport;
+
+   e_comp_object_frame_xy_unadjust(ec->frame, out->x, out->y, &out->x, &out->y);
+   e_comp_object_frame_wh_unadjust(ec->frame, out->w, out->h, &out->w, &out->h);
+}
+
+EINTERN Eina_Bool
+e_comp_wl_surface_viewport_get(E_Client *ec, Eina_Rectangle *buffer_viewport, Eina_Rectangle *output_viewport, unsigned int *transform)
+{
+   E_Comp_Wl_Buffer *buffer;
+   E_Comp_Wl_Buffer_Viewport *vp;
+   const Evas_Map *m;
+   enum wl_output_transform buffer_transform;
+   unsigned int rotation;
+   Eina_Bool res = EINA_FALSE;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE);
+
+   if (e_object_is_del(E_OBJECT(ec)))
+     return EINA_FALSE;
+
+   vp = &ec->comp_data->scaler.buffer_viewport;
+
+   if (buffer_viewport)
+     {
+        buffer = ec->comp_data->buffer_ref.buffer;
+        /* Getting a viewport of buffer needs geometry of buffer. */
+        if (!buffer)
+          return EINA_FALSE;
+
+        _buffer_viewport_get(vp, buffer->w, buffer->h, buffer_viewport);
+     }
+
+   if ((output_viewport) || (transform))
+     {
+        m = evas_object_map_get(ec->frame);
+        if (m)
+          res = _output_viewport_get_from_evas_map(m, output_viewport, &rotation);
+        else
+          _e_comp_wl_surface_output_viewport_get(ec, output_viewport);
+
+        if (transform)
+          {
+             buffer_transform = e_comp_wl_output_buffer_transform_get(ec);
+             /* NOTE Merge transform value from evas_map with E_Comp_Wl_Buffer_Viewport's one.
+              * Since buffer.transform isn't applied using evas_map,
+              * it has to be taken into account here to apply buffer.transform
+              * and rotation of e_client_transform together. */
+             if (res)
+               *transform = _transform_merge_with_rotation(buffer_transform, rotation);
+             else
+               *transform = (unsigned int)buffer_transform;
+          }
+     }
+
+   return EINA_TRUE;
+}
index 75afbce..882e177 100644 (file)
@@ -611,5 +611,6 @@ EINTERN void    e_comp_wl_hook_call(E_Comp_Wl_Hook_Point hookpoint, E_Client *ec
 EINTERN void    e_comp_wl_surface_state_finish(E_Comp_Wl_Surface_State *state);
 EINTERN void    e_comp_wl_surface_state_buffer_set(E_Comp_Wl_Surface_State *state, E_Comp_Wl_Buffer *buffer);
 
+EINTERN Eina_Bool e_comp_wl_surface_viewport_get(E_Client *ec, Eina_Rectangle *buffer_viewport, Eina_Rectangle *output_viewport, unsigned int *transform);
 # endif
 #endif