[weston] ivi-layout: implement surface clipping

Submitted by Nobuhiko Tanibata on Aug. 24, 2015, 12:11 a.m.

Details

Message ID 1440375088-13402-1-git-send-email-nobuhiko_tanibata@xddp.denso.co.jp
State Superseded
Headers show

Not browsing as part of any series.

Commit Message

Nobuhiko Tanibata Aug. 24, 2015, 12:11 a.m.
From: Nobuhiko Tanibata <NOBUHIKO_TANIBATA@xddp.denso.co.jp>

View clip region is set in surface-local coordinates. To compute that
region, the ivi-layer destination rectangle in the global coordinates
are transformed back into the surface-local coordinates.

The transformation is computed by first forming the transformation
matric for the forward mappings, and then inverting it. The inverse
matric is used to transform the destination rectangles to the
surface-local coordinate system. The intersection of the rectangles is
the view clip mask.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA@xddp.denso.co.jp>
Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
---
 ivi-shell/ivi-layout.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 142 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c
index d412069..69adac7 100644
--- a/ivi-shell/ivi-layout.c
+++ b/ivi-shell/ivi-layout.c
@@ -58,6 +58,7 @@ 
 #include "config.h"
 
 #include <string.h>
+#include <assert.h>
 
 #include "compositor.h"
 #include "ivi-layout-export.h"
@@ -66,6 +67,8 @@ 
 #include "shared/helpers.h"
 #include "shared/os-compatibility.h"
 
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
 struct link_layer {
 	struct ivi_layout_layer *ivilayer;
 	struct wl_list link;
@@ -586,18 +589,127 @@  calc_transformation_matrix(struct ivi_rectangle *source_rect,
 	weston_matrix_translate(m, translate_x, translate_y, 0.0f);
 }
 
+/*
+ * This computes intersected rect_output from two ivi_rectangles
+ */
+static void
+ivi_rectangle_intersect(const struct ivi_rectangle *rect1,
+		        const struct ivi_rectangle *rect2,
+		        struct ivi_rectangle *rect_output)
+{
+	int32_t rect1_right = rect1->x + rect1->width;
+	int32_t rect1_bottom = rect1->y + rect1->height;
+	int32_t rect2_right = rect2->x + rect2->width;
+	int32_t rect2_bottom = rect2->y + rect2->height;
+
+	rect_output->x = max(rect1->x, rect2->x);
+	rect_output->y = max(rect1->y, rect2->y);
+	rect_output->width = rect1_right < rect2_right ?
+			     rect1_right - rect_output->x : 
+			     rect2_right - rect_output->x;
+	rect_output->height = rect1_bottom < rect2_bottom ?
+			      rect1_bottom - rect_output->y : 
+			      rect2_bottom - rect_output->y;
+
+	if (rect_output->width < 0 || rect_output->height < 0) {
+		rect_output->width = 0;
+		rect_output->height = 0;
+	}
+}
+
+/*
+ * Transform rect_input by the inverse of matrix, intersect with boundingbox,
+ * and store the result in rect_output.
+ * The boundingbox must be given in the same coordinate space as rect_output.
+ * Additionally, there are the following restrictions on the matrix:
+ * - no projective transformations
+ * - no skew
+ * - only multiples of 90-degree rotations supported
+ *
+ * In failure case of weston_matrix_invert, rect_output is set to boundingbox
+ * as a fail-safe with log.
+ */
+static void
+calc_inverse_matrix_transform(const struct weston_matrix *matrix,
+			      const struct ivi_rectangle *rect_input,
+			      const struct ivi_rectangle *boundingbox,
+			      struct ivi_rectangle *rect_output)
+{
+	struct weston_matrix m;
+	struct weston_vector top_left;
+	struct weston_vector bottom_right;
+
+	assert(boundingbox != rect_output);
+
+	if (weston_matrix_invert(&m, matrix) < 0) {
+		weston_log("ivi-shell: calc_inverse_matrix_transform fails to invert a matrix.\n");
+		weston_log("ivi-shell: boundingbox is set to the rect_output.\n");
+		rect_output->x = boundingbox->x;
+		rect_output->y = boundingbox->y;
+		rect_output->width = boundingbox->width;
+		rect_output->height = boundingbox->height;
+	}
+
+	/* The vectors and matrices involved will always produce f[3] == 1.0. */
+	top_left.f[0] = rect_input->x;
+	top_left.f[1] = rect_input->y;
+	top_left.f[2] = 0.0f;
+	top_left.f[3] = 1.0f;
+
+	bottom_right.f[0] = rect_input->x + rect_input->width;
+	bottom_right.f[1] = rect_input->y + rect_input->height;
+	bottom_right.f[2] = 0.0f;
+	bottom_right.f[3] = 1.0f;
+
+	weston_matrix_transform(&m, &top_left);
+	weston_matrix_transform(&m, &bottom_right);
+
+	if (top_left.f[0] < bottom_right.f[0]) {
+		rect_output->x = top_left.f[0];
+		rect_output->width = bottom_right.f[0] - rect_output->x;
+	} else {
+		rect_output->x = bottom_right.f[0];
+		rect_output->width = top_left.f[0] - rect_output->x;
+	}
+
+	if (top_left.f[1] < bottom_right.f[1]) {
+		rect_output->y = top_left.f[1];
+		rect_output->height = bottom_right.f[1] - rect_output->y;
+	} else {
+		rect_output->y = bottom_right.f[1];
+		rect_output->height = top_left.f[1] - rect_output->y;
+	}
+
+	ivi_rectangle_intersect(rect_output, boundingbox, rect_output);
+}
+
 /**
- * This computes the whole transformation matrix from surface-local
+ * This computes the whole transformation matrix:m from surface-local
  * coordinates to global coordinates. It is assumed that
  * weston_view::geometry.{x,y} are zero.
+ *
+ * Additionally, this computes the mask on surface-local coordinates as a
+ * ivi_rectangle. This can be set to weston_view_set_mask.
+ * 
+ * The mask is computed by following steps
+ * - destination rectangle of layer is inversed to surface-local cooodinates
+ *   by inversed matrix:m.
+ * - the area is intersected by intersected area between weston_surface and
+ *   source rectangle of ivi_surface.
  */
 static void
-calc_surface_to_global_matrix(struct ivi_layout_layer *ivilayer,
-			      struct ivi_layout_surface *ivisurf,
-			      struct weston_matrix *m)
+calc_surface_to_global_matrix_and_mask_to_weston_surface(
+	struct ivi_layout_layer *ivilayer,
+	struct ivi_layout_surface *ivisurf,
+	struct weston_matrix *m,
+	struct ivi_rectangle *result)
 {
 	const struct ivi_layout_surface_properties *sp = &ivisurf->prop;
 	const struct ivi_layout_layer_properties *lp = &ivilayer->prop;
+	struct ivi_rectangle weston_surface_rect = { 0,
+						     0,
+						     ivisurf->surface->width,
+						     ivisurf->surface->height };
 	struct ivi_rectangle surface_source_rect = { sp->source_x,
 						     sp->source_y,
 						     sp->source_width,
@@ -614,7 +726,15 @@  calc_surface_to_global_matrix(struct ivi_layout_layer *ivilayer,
 						     lp->dest_y,
 						     lp->dest_width,
 						     lp->dest_height };
+	struct ivi_rectangle surface_result;
 
+	/*
+	 * the whole transformation matrix:m from surface-local
+	 * coordinates to global coordinates, which is computed by
+	 * two steps,
+	 * - surface-local coordinates to layer-local coordinates
+	 * - layer-local coordinates to global coordinates
+	 */
 	calc_transformation_matrix(&surface_source_rect,
 				   &surface_dest_rect,
 				   sp->orientation, m);
@@ -622,6 +742,18 @@  calc_surface_to_global_matrix(struct ivi_layout_layer *ivilayer,
 	calc_transformation_matrix(&layer_source_rect,
 				   &layer_dest_rect,
 				   lp->orientation, m);
+
+	/* this intersected ivi_rectangle would be used for masking
+	 * weston_surface
+	 */
+	ivi_rectangle_intersect(&surface_source_rect, &weston_surface_rect,
+				&surface_result);
+
+	/* calc masking area of weston_surface from m */
+	calc_inverse_matrix_transform(m,
+				      &layer_dest_rect,
+				      &surface_result,
+				      result);
 }
 
 static void
@@ -629,6 +761,7 @@  update_prop(struct ivi_layout_layer *ivilayer,
 	    struct ivi_layout_surface *ivisurf)
 {
 	struct weston_view *tmpview;
+	struct ivi_rectangle r;
 	bool can_calc = true;
 
 	if (!ivilayer->event_mask && !ivisurf->event_mask) {
@@ -657,10 +790,13 @@  update_prop(struct ivi_layout_layer *ivilayer,
 		wl_list_remove(&ivisurf->transform.link);
 		weston_matrix_init(&ivisurf->transform.matrix);
 
-		calc_surface_to_global_matrix(ivilayer, ivisurf, &ivisurf->transform.matrix);
+		calc_surface_to_global_matrix_and_mask_to_weston_surface(
+			ivilayer, ivisurf, &ivisurf->transform.matrix, &r);
 
 		if (tmpview != NULL) {
-			wl_list_insert(&tmpview->geometry.transformation_list, &ivisurf->transform.link);
+			weston_view_set_mask(tmpview, r.x, r.y, r.width, r.height);
+			wl_list_insert(&tmpview->geometry.transformation_list,
+				       &ivisurf->transform.link);
 
 			weston_view_set_transform_parent(tmpview, NULL);
 		}