{
_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;
+}