[PATCH weston 6/8] compositor: transform surface coordinates if a surface scaler is used

Jonny Lamb jonny.lamb at collabora.co.uk
Tue Nov 26 09:19:46 PST 2013


Implements wl_surface_scaler.set by setting desired
src_{x,y,width,height} and dst_{width,height} values in the
weston_buffer_viewport struct, then altering coordinates in
weston_surface_to_buffer* functions if there is a scaler set for said
surface.
---
 src/compositor.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/compositor.h | 13 +++++++++
 2 files changed, 89 insertions(+), 8 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index a80fbba..c371939 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -403,10 +403,13 @@ weston_surface_create(struct weston_compositor *compositor)
 
 	surface->buffer_viewport.transform = WL_OUTPUT_TRANSFORM_NORMAL;
 	surface->buffer_viewport.scale = 1;
+	surface->buffer_viewport.scaler_set = 0;
 	surface->pending.buffer_viewport = surface->buffer_viewport;
 	surface->output = NULL;
 	surface->pending.newly_attached = 0;
 
+	surface->surface_scaler_resource = NULL;
+
 	pixman_region32_init(&surface->damage);
 	pixman_region32_init(&surface->opaque);
 	region_init_infinite(&surface->input);
@@ -633,15 +636,38 @@ weston_transformed_region(int width, int height,
 	free(dest_rects);
 }
 
+static void
+scaler_surface_to_buffer(struct weston_surface *surface,
+			 float sx, float sy, float *bx, float *by)
+{
+	if (surface->buffer_viewport.scaler_set) {
+		double a, b;
+
+		a = sx / surface->buffer_viewport.dst_width;
+		b = a * wl_fixed_to_double(surface->buffer_viewport.src_width);
+		*bx = b + wl_fixed_to_double(surface->buffer_viewport.src_x);
+
+		a = sy / surface->buffer_viewport.dst_height;
+		b = a * wl_fixed_to_double(surface->buffer_viewport.src_height);
+		*by = b + wl_fixed_to_double(surface->buffer_viewport.src_y);
+	} else {
+		*bx = sx;
+		*by = sy;
+	}
+}
+
 WL_EXPORT void
 weston_surface_to_buffer_float(struct weston_surface *surface,
 			       float sx, float sy, float *bx, float *by)
 {
+	/* first transform coordinates if the scaler is set */
+	scaler_surface_to_buffer(surface, sx, sy, bx, by);
+
 	weston_transformed_coord(surface->width,
 				 surface->height,
 				 surface->buffer_viewport.transform,
 				 surface->buffer_viewport.scale,
-				 sx, sy, bx, by);
+				 *bx, *by, bx, by);
 }
 
 WL_EXPORT void
@@ -650,11 +676,9 @@ weston_surface_to_buffer(struct weston_surface *surface,
 {
 	float bxf, byf;
 
-	weston_transformed_coord(surface->width,
-				 surface->height,
-				 surface->buffer_viewport.transform,
-				 surface->buffer_viewport.scale,
-				 sx, sy, &bxf, &byf);
+	weston_surface_to_buffer_float(surface,
+				       sx, sy, &bxf, &byf);
+
 	*bx = floorf(bxf);
 	*by = floorf(byf);
 }
@@ -663,6 +687,17 @@ WL_EXPORT pixman_box32_t
 weston_surface_to_buffer_rect(struct weston_surface *surface,
 			      pixman_box32_t rect)
 {
+	float xf, yf;
+
+	/* first transform box coordinates if the scaler is set */
+	scaler_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
+	rect.x1 = floorf(xf);
+	rect.y1 = floorf(yf);
+
+	scaler_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
+	rect.x2 = floorf(xf);
+	rect.y2 = floorf(yf);
+
 	return weston_transformed_rect(surface->width,
 				       surface->height,
 				       surface->buffer_viewport.transform,
@@ -1153,6 +1188,12 @@ weston_surface_set_size_from_buffer(struct weston_surface *surface)
 		return;
 	}
 
+	if (surface->buffer_viewport.scaler_set) {
+		surface->width = surface->buffer_viewport.dst_width;
+		surface->height = surface->buffer_viewport.dst_height;
+		return;
+	}
+
 	switch (surface->buffer_viewport.transform) {
 	case WL_OUTPUT_TRANSFORM_90:
 	case WL_OUTPUT_TRANSFORM_270:
@@ -1958,6 +1999,7 @@ weston_surface_commit(struct weston_surface *surface)
 
 	/* wl_surface.set_buffer_transform */
 	/* wl_surface.set_buffer_scale */
+	/* wl_surface_scaler.set */
 	surface->buffer_viewport = surface->pending.buffer_viewport;
 
 	/* wl_surface.attach */
@@ -2184,6 +2226,7 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
 
 	/* wl_surface.set_buffer_transform */
 	/* wl_surface.set_buffer_scale */
+	/* wl_surface_scaler.set */
 	surface->buffer_viewport = sub->cached.buffer_viewport;
 
 	/* wl_surface.attach */
@@ -3235,6 +3278,11 @@ weston_output_transform_coordinate(struct weston_output *output,
 static void
 destroy_surface_scaler(struct wl_resource *resource)
 {
+	struct weston_surface *surface =
+		wl_resource_get_user_data(resource);
+
+	surface->surface_scaler_resource = NULL;
+	surface->pending.buffer_viewport.scaler_set = 0;
 }
 
 static void
@@ -3254,6 +3302,11 @@ surface_scaler_set(struct wl_client *client,
 		   int32_t dst_width,
 		   int32_t dst_height)
 {
+	struct weston_surface *surface =
+		wl_resource_get_user_data(resource);
+
+	assert(surface->surface_scaler_resource != NULL);
+
 	if (wl_fixed_to_double(src_width) < 0 ||
 	    wl_fixed_to_double(src_height) < 0) {
 		wl_resource_post_error(resource,
@@ -3272,7 +3325,14 @@ surface_scaler_set(struct wl_client *client,
 		return;
 	}
 
-	/* TODO */
+	surface->pending.buffer_viewport.scaler_set = 1;
+
+	surface->pending.buffer_viewport.src_x = src_x;
+	surface->pending.buffer_viewport.src_y = src_y;
+	surface->pending.buffer_viewport.src_width = src_width;
+	surface->pending.buffer_viewport.src_height = src_height;
+	surface->pending.buffer_viewport.dst_width = dst_width;
+	surface->pending.buffer_viewport.dst_height = dst_height;
 }
 
 static const struct wl_surface_scaler_interface surface_scaler_interface = {
@@ -3296,7 +3356,13 @@ scaler_get_surface_scaler(struct wl_client *client,
 	struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
 	struct wl_resource *resource;
 
-	/* TODO: check we don't already have one for this surface */
+	if (surface->surface_scaler_resource) {
+		wl_resource_post_error(scaler,
+			WL_SCALER_ERROR_SCALER_EXISTS,
+			"a surface scaler for that surface already exists");
+		return;
+	}
+
 	resource = wl_resource_create(client, &wl_surface_scaler_interface,
 				      1, id);
 	if (resource == NULL) {
@@ -3306,6 +3372,8 @@ scaler_get_surface_scaler(struct wl_client *client,
 
 	wl_resource_set_implementation(resource, &surface_scaler_interface,
 				       surface, destroy_surface_scaler);
+
+	surface->surface_scaler_resource = resource;
 }
 
 static const struct wl_scaler_interface scaler_interface = {
diff --git a/src/compositor.h b/src/compositor.h
index e31d7db..755057c 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -653,6 +653,15 @@ struct weston_buffer_viewport {
 
 	/* wl_surface.set_scaling_factor */
 	int32_t scale;
+
+	/* bool for whether wl_surface_scaler.set has been
+	 * called yet (before this is called there is no
+	 * cropping or scaling on the surface) */
+	int scaler_set; /* bool */
+
+	wl_fixed_t src_x, src_y;
+	wl_fixed_t src_width, src_height;
+	int32_t dst_width, dst_height;
 };
 
 struct weston_region {
@@ -844,6 +853,9 @@ struct weston_surface {
 	struct weston_buffer_viewport buffer_viewport;
 	int keep_buffer; /* bool for backends to prevent early release */
 
+	/* wl_surface_scaler resource for this surface */
+	struct wl_resource *surface_scaler_resource;
+
 	/* All the pending state, that wl_surface.commit will apply. */
 	struct {
 		/* wl_surface.attach */
@@ -867,6 +879,7 @@ struct weston_surface {
 
 		/* wl_surface.set_buffer_transform */
 		/* wl_surface.set_scaling_factor */
+		/* wl_surface_scaler.set */
 		struct weston_buffer_viewport buffer_viewport;
 	} pending;
 
-- 
1.8.4.2



More information about the wayland-devel mailing list