d2a00ca
From 0e4e268844ea38075535eb5b233dda325da4481d Mon Sep 17 00:00:00 2001
d2a00ca
From: Hans de Goede <hdegoede@redhat.com>
d2a00ca
Date: Wed, 6 Dec 2017 17:37:12 +0100
d2a00ca
Subject: [PATCH 3/6] pixel-buffer: Add the concept of device rotation
d2a00ca
d2a00ca
On some devices the LCD panel is mounted in the casing in such a way
d2a00ca
that the up/top side of the panel does not match with the top side of
d2a00ca
the device (e.g. it is mounted upside-down).
d2a00ca
d2a00ca
This commit adds support to the ply-pixel-buffer code to create
d2a00ca
buffers which take device rotation into account and which will rotate
d2a00ca
the picture to compensate.
d2a00ca
d2a00ca
https://bugs.freedesktop.org/show_bug.cgi?id=104714
d2a00ca
---
d2a00ca
 src/libply-splash-core/ply-pixel-buffer.c | 109 ++++++++++++++++++++--
d2a00ca
 src/libply-splash-core/ply-pixel-buffer.h |   9 ++
d2a00ca
 2 files changed, 110 insertions(+), 8 deletions(-)
d2a00ca
d2a00ca
diff --git a/src/libply-splash-core/ply-pixel-buffer.c b/src/libply-splash-core/ply-pixel-buffer.c
d2a00ca
index 52a3f86..a337407 100644
d2a00ca
--- a/src/libply-splash-core/ply-pixel-buffer.c
d2a00ca
+++ b/src/libply-splash-core/ply-pixel-buffer.c
d2a00ca
@@ -50,6 +50,7 @@ struct _ply_pixel_buffer
d2a00ca
         ply_region_t   *updated_areas; /* in device pixels */
d2a00ca
         uint32_t        is_opaque : 1;
d2a00ca
         int             device_scale;
d2a00ca
+        int             device_rotation;
d2a00ca
 };
d2a00ca
 
d2a00ca
 static inline void ply_pixel_buffer_blend_value_at_pixel (ply_pixel_buffer_t *buffer,
d2a00ca
@@ -153,6 +154,52 @@ make_pixel_value_translucent (uint32_t pixel_value,
d2a00ca
         return (alpha << 24) | (red << 16) | (green << 8) | blue;
d2a00ca
 }
d2a00ca
 
d2a00ca
+static inline void ply_pixel_buffer_set_pixel (ply_pixel_buffer_t *buffer,
d2a00ca
+                                               int                 x,
d2a00ca
+                                               int                 y,
d2a00ca
+                                               uint32_t            pixel_value)
d2a00ca
+{
d2a00ca
+        switch (buffer->device_rotation) {
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_UPRIGHT:
d2a00ca
+                buffer->bytes[y * buffer->area.width + x] = pixel_value;
d2a00ca
+                break;
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_UPSIDE_DOWN:
d2a00ca
+                x = (buffer->area.width - 1) - x;
d2a00ca
+                y = (buffer->area.height - 1) - y;
d2a00ca
+                buffer->bytes[y * buffer->area.width + x] = pixel_value;
d2a00ca
+                break;
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE:
d2a00ca
+                y = (buffer->area.height - 1) - y;
d2a00ca
+                buffer->bytes[x * buffer->area.height + y] = pixel_value;
d2a00ca
+                break;
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE:
d2a00ca
+                x = (buffer->area.width - 1) - x;
d2a00ca
+                buffer->bytes[x * buffer->area.height + y] = pixel_value;
d2a00ca
+                break;
d2a00ca
+        }
d2a00ca
+}
d2a00ca
+
d2a00ca
+static inline uint32_t ply_pixel_buffer_get_pixel (ply_pixel_buffer_t *buffer,
d2a00ca
+                                                   int                 x,
d2a00ca
+                                                   int                 y)
d2a00ca
+{
d2a00ca
+        switch (buffer->device_rotation) {
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_UPRIGHT:
d2a00ca
+                return buffer->bytes[y * buffer->area.width + x];
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_UPSIDE_DOWN:
d2a00ca
+                x = (buffer->area.width - 1) - x;
d2a00ca
+                y = (buffer->area.height - 1) - y;
d2a00ca
+                return buffer->bytes[y * buffer->area.width + x];
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE:
d2a00ca
+                y = (buffer->area.height - 1) - y;
d2a00ca
+                return buffer->bytes[x * buffer->area.height + y];
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE:
d2a00ca
+                x = (buffer->area.width - 1) - x;
d2a00ca
+                return buffer->bytes[x * buffer->area.height + y];
d2a00ca
+        }
d2a00ca
+        return 0;
d2a00ca
+}
d2a00ca
+
d2a00ca
 static inline void
d2a00ca
 ply_pixel_buffer_blend_value_at_pixel (ply_pixel_buffer_t *buffer,
d2a00ca
                                        int                 x,
d2a00ca
@@ -162,12 +209,12 @@ ply_pixel_buffer_blend_value_at_pixel (ply_pixel_buffer_t *buffer,
d2a00ca
         uint32_t old_pixel_value;
d2a00ca
 
d2a00ca
         if ((pixel_value >> 24) != 0xff) {
d2a00ca
-                old_pixel_value = buffer->bytes[y * buffer->area.width + x];
d2a00ca
+                old_pixel_value = ply_pixel_buffer_get_pixel (buffer, x, y);
d2a00ca
 
d2a00ca
                 pixel_value = blend_two_pixel_values (pixel_value, old_pixel_value);
d2a00ca
         }
d2a00ca
 
d2a00ca
-        buffer->bytes[y * buffer->area.width + x] = pixel_value;
d2a00ca
+        ply_pixel_buffer_set_pixel (buffer, x, y, pixel_value);
d2a00ca
 }
d2a00ca
 
d2a00ca
 static void
d2a00ca
@@ -222,6 +269,35 @@ ply_pixel_buffer_crop_area_to_clip_area (ply_pixel_buffer_t *buffer,
d2a00ca
         }
d2a00ca
 }
d2a00ca
 
d2a00ca
+static void ply_pixel_buffer_add_updated_area (ply_pixel_buffer_t *buffer,
d2a00ca
+                                               ply_rectangle_t    *area)
d2a00ca
+{
d2a00ca
+        ply_rectangle_t updated_area = *area;
d2a00ca
+
d2a00ca
+        switch (buffer->device_rotation) {
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_UPRIGHT:
d2a00ca
+                break;
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_UPSIDE_DOWN:
d2a00ca
+                updated_area.x = buffer->area.width - area->width - area->x;
d2a00ca
+                updated_area.y = buffer->area.height - area->height - area->y;
d2a00ca
+                break;
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE:
d2a00ca
+                updated_area.x = buffer->area.height - area->height - area->y;
d2a00ca
+                updated_area.y = area->x;
d2a00ca
+                updated_area.height = area->width;
d2a00ca
+                updated_area.width = area->height;
d2a00ca
+                break;
d2a00ca
+        case PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE:
d2a00ca
+                updated_area.x = area->y;
d2a00ca
+                updated_area.y = buffer->area.width - area->width - area->x;
d2a00ca
+                updated_area.height = area->width;
d2a00ca
+                updated_area.width = area->height;
d2a00ca
+                break;
d2a00ca
+        }
d2a00ca
+
d2a00ca
+        ply_region_add_rectangle (buffer->updated_areas, &updated_area);
d2a00ca
+}
d2a00ca
+
d2a00ca
 static void
d2a00ca
 ply_pixel_buffer_fill_area_with_pixel_value (ply_pixel_buffer_t *buffer,
d2a00ca
                                              ply_rectangle_t    *fill_area,
d2a00ca
@@ -251,7 +327,7 @@ ply_pixel_buffer_fill_area_with_pixel_value (ply_pixel_buffer_t *buffer,
d2a00ca
                 }
d2a00ca
         }
d2a00ca
 
d2a00ca
-        ply_region_add_rectangle (buffer->updated_areas, &cropped_area);
d2a00ca
+        ply_pixel_buffer_add_updated_area (buffer, &cropped_area);
d2a00ca
 }
d2a00ca
 
d2a00ca
 void
d2a00ca
@@ -281,9 +357,24 @@ ply_pixel_buffer_pop_clip_area (ply_pixel_buffer_t *buffer)
d2a00ca
 ply_pixel_buffer_t *
d2a00ca
 ply_pixel_buffer_new (unsigned long width,
d2a00ca
                       unsigned long height)
d2a00ca
+{
d2a00ca
+        return ply_pixel_buffer_new_with_device_rotation (
d2a00ca
+                        width, height, PLY_PIXEL_BUFFER_ROTATE_UPRIGHT);
d2a00ca
+}
d2a00ca
+
d2a00ca
+ply_pixel_buffer_t *
d2a00ca
+ply_pixel_buffer_new_with_device_rotation (unsigned long width,
d2a00ca
+                                           unsigned long height,
d2a00ca
+                                           int device_rotation)
d2a00ca
 {
d2a00ca
         ply_pixel_buffer_t *buffer;
d2a00ca
 
d2a00ca
+        if (device_rotation >= PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE) {
d2a00ca
+                unsigned long tmp = width;
d2a00ca
+                width = height;
d2a00ca
+                height = tmp;
d2a00ca
+        }
d2a00ca
+
d2a00ca
         buffer = calloc (1, sizeof(ply_pixel_buffer_t));
d2a00ca
 
d2a00ca
         buffer->updated_areas = ply_region_new ();
d2a00ca
@@ -292,6 +383,7 @@ ply_pixel_buffer_new (unsigned long width,
d2a00ca
         buffer->area.height = height;
d2a00ca
         buffer->logical_area = buffer->area;
d2a00ca
         buffer->device_scale = 1;
d2a00ca
+        buffer->device_rotation = device_rotation;
d2a00ca
 
d2a00ca
         buffer->clip_areas = ply_list_new ();
d2a00ca
         ply_pixel_buffer_push_clip_area (buffer, &buffer->area);
d2a00ca
@@ -447,7 +539,7 @@ ply_pixel_buffer_fill_with_gradient (ply_pixel_buffer_t *buffer,
d2a00ca
 
d2a00ca
         for (y = buffer->area.y; y < buffer->area.y + buffer->area.height; y++) {
d2a00ca
                 if (cropped_area.y <= y && y < cropped_area.y + cropped_area.height) {
d2a00ca
-                        if (cropped_area.width < UNROLLED_PIXEL_COUNT) {
d2a00ca
+                        if (cropped_area.width < UNROLLED_PIXEL_COUNT || buffer->device_rotation) {
d2a00ca
                                 for (x = cropped_area.x; x < cropped_area.x + cropped_area.width; x++) {
d2a00ca
                                         pixel = 0xff000000;
d2a00ca
                                         RANDOMIZE (noise);
d2a00ca
@@ -457,7 +549,7 @@ ply_pixel_buffer_fill_with_gradient (ply_pixel_buffer_t *buffer,
d2a00ca
                                         RANDOMIZE (noise);
d2a00ca
                                         pixel |= (((blue + noise) & COLOR_MASK) >> BLUE_SHIFT);
d2a00ca
 
d2a00ca
-                                        buffer->bytes[y * buffer->area.width + x] = pixel;
d2a00ca
+                                        ply_pixel_buffer_set_pixel (buffer, x, y, pixel);
d2a00ca
                                 }
d2a00ca
                         } else {
d2a00ca
                                 uint32_t shaded_set[UNROLLED_PIXEL_COUNT];
d2a00ca
@@ -485,7 +577,7 @@ ply_pixel_buffer_fill_with_gradient (ply_pixel_buffer_t *buffer,
d2a00ca
                 blue += blue_step;
d2a00ca
         }
d2a00ca
 
d2a00ca
-        ply_region_add_rectangle (buffer->updated_areas, &cropped_area);
d2a00ca
+        ply_pixel_buffer_add_updated_area (buffer, &cropped_area);
d2a00ca
 }
d2a00ca
 
d2a00ca
 void
d2a00ca
@@ -671,7 +763,7 @@ ply_pixel_buffer_fill_with_argb32_data_at_opacity_with_clip_and_scale (ply_pixel
d2a00ca
                 }
d2a00ca
         }
d2a00ca
 
d2a00ca
-        ply_region_add_rectangle (buffer->updated_areas, &cropped_area);
d2a00ca
+        ply_pixel_buffer_add_updated_area (buffer, &cropped_area);
d2a00ca
 }
d2a00ca
 
d2a00ca
 void
d2a00ca
@@ -756,7 +848,8 @@ ply_pixel_buffer_fill_with_buffer_at_opacity_with_clip (ply_pixel_buffer_t *canv
d2a00ca
 
d2a00ca
         /* Fast path to memcpy if we need no blending or scaling */
d2a00ca
         if (opacity == 1.0 && ply_pixel_buffer_is_opaque (source) &&
d2a00ca
-            canvas->device_scale == source->device_scale) {
d2a00ca
+            canvas->device_scale == source->device_scale &&
d2a00ca
+            canvas->device_rotation == PLY_PIXEL_BUFFER_ROTATE_UPRIGHT) {
d2a00ca
                 ply_rectangle_t cropped_area;
d2a00ca
 
d2a00ca
                 cropped_area.x = x_offset;
d2a00ca
diff --git a/src/libply-splash-core/ply-pixel-buffer.h b/src/libply-splash-core/ply-pixel-buffer.h
d2a00ca
index 595e9bd..7736dd3 100644
d2a00ca
--- a/src/libply-splash-core/ply-pixel-buffer.h
d2a00ca
+++ b/src/libply-splash-core/ply-pixel-buffer.h
d2a00ca
@@ -37,9 +37,18 @@ typedef struct _ply_pixel_buffer ply_pixel_buffer_t;
d2a00ca
          | ((uint8_t) (CLAMP (g * 255.0, 0.0, 255.0)) << 8)                      \
d2a00ca
          | ((uint8_t) (CLAMP (b * 255.0, 0.0, 255.0))))
d2a00ca
 
d2a00ca
+#define PLY_PIXEL_BUFFER_ROTATE_UPRIGHT             0
d2a00ca
+#define PLY_PIXEL_BUFFER_ROTATE_UPSIDE_DOWN         1
d2a00ca
+#define PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE           2
d2a00ca
+#define PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE   3
d2a00ca
+
d2a00ca
 #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
d2a00ca
 ply_pixel_buffer_t *ply_pixel_buffer_new (unsigned long width,
d2a00ca
                                           unsigned long height);
d2a00ca
+ply_pixel_buffer_t *
d2a00ca
+ply_pixel_buffer_new_with_device_rotation (unsigned long width,
d2a00ca
+                                           unsigned long height,
d2a00ca
+                                           int device_rotation);
d2a00ca
 void ply_pixel_buffer_free (ply_pixel_buffer_t *buffer);
d2a00ca
 void ply_pixel_buffer_get_size (ply_pixel_buffer_t *buffer,
d2a00ca
                                 ply_rectangle_t    *size);
d2a00ca
-- 
d2a00ca
2.17.0
d2a00ca