Choose hwrotation at runtime

If the prop persist.twrp.rotation is set to 0, 90, 180, or 270,
that will be used. If the prop is not set, the existing rotation
board config flags will be honored.

Note: This flag will only rotate graphics. If a set of devices
needs differing touch rotation, that support will need added
separately.

Change-Id: I6996c07bc0ae7bb8555b3d480b2917a17a365eb3
diff --git a/minuitwrp/graphics.cpp b/minuitwrp/graphics.cpp
index c3d6ca5..b387b70 100644
--- a/minuitwrp/graphics.cpp
+++ b/minuitwrp/graphics.cpp
@@ -31,6 +31,7 @@
 
 #include <time.h>
 
+#include <cutils/properties.h>
 #include <pixelflinger/pixelflinger.h>
 #include "../gui/placement.h"
 #include "minui.h"
@@ -60,6 +61,8 @@
 GGLSurface gr_mem_surface;
 static int gr_is_curr_clr_opaque = 0;
 
+unsigned int gr_rotation = 0;
+
 int gr_textEx_scaleW(int x, int y, const char *s, void* pFont, int max_width, int placement, int scale)
 {
     GGLContext *gl = gr_context;
@@ -114,17 +117,20 @@
 {
     GGLContext *gl = gr_context;
 
-#if TW_ROTATION == 0
-    gl->scissor(gl, x, y, w, h);
-#elif TW_ROTATION == 90
-    gl->scissor(gl, gr_draw->width - y - h, x, h, w);
-#elif TW_ROTATION == 270
-    gl->scissor(gl, y, gr_draw->height - x - w, h, w);
-#else
-    int t_disp = gr_draw->height - y - h;
-    int l_disp = gr_draw->width - x - w;
-    gl->scissor(gl, l_disp, t_disp, w, h);
-#endif
+    switch (gr_rotation) {
+        case 90:
+            gl->scissor(gl, gr_draw->width - y - h, x, h, w);
+            break;
+        case 180:
+            gl->scissor(gl, gr_draw->width - x - w, gr_draw->height - y - h, w, h);
+            break;
+        case 270:
+            gl->scissor(gl, y, gr_draw->height - x - w, h, w);
+            break;
+        default:
+            gl->scissor(gl, x, y, w, h);
+            break;
+    }
     gl->enable(gl, GGL_SCISSOR_TEST);
 }
 
@@ -142,10 +148,10 @@
     GGLContext *gl = gr_context;
     int x0_disp, y0_disp, x1_disp, y1_disp;
 
-    x0_disp = ROTATION_X_DISP(x0, y0, gr_draw);
-    y0_disp = ROTATION_Y_DISP(x0, y0, gr_draw);
-    x1_disp = ROTATION_X_DISP(x1, y1, gr_draw);
-    y1_disp = ROTATION_Y_DISP(x1, y1, gr_draw);
+    x0_disp = ROTATION_X_DISP(x0, y0, gr_draw->width);
+    y0_disp = ROTATION_Y_DISP(x0, y0, gr_draw->height);
+    x1_disp = ROTATION_X_DISP(x1, y1, gr_draw->width);
+    y1_disp = ROTATION_Y_DISP(x1, y1, gr_draw->height);
 
     if(gr_is_curr_clr_opaque)
         gl->disable(gl, GGL_BLEND);
@@ -245,10 +251,10 @@
     if(gr_is_curr_clr_opaque)
         gl->disable(gl, GGL_BLEND);
 
-    x0_disp = ROTATION_X_DISP(x, y, gr_draw);
-    y0_disp = ROTATION_Y_DISP(x, y, gr_draw);
-    x1_disp = ROTATION_X_DISP(x + w, y + h, gr_draw);
-    y1_disp = ROTATION_Y_DISP(x + w, y + h, gr_draw);
+    x0_disp = ROTATION_X_DISP(x, y, gr_draw->width);
+    y0_disp = ROTATION_Y_DISP(x, y, gr_draw->height);
+    x1_disp = ROTATION_X_DISP(x + w, y + h, gr_draw->width);
+    y1_disp = ROTATION_Y_DISP(x + w, y + h, gr_draw->height);
     l_disp = std::min(x0_disp, x1_disp);
     r_disp = std::max(x0_disp, x1_disp);
     t_disp = std::min(y0_disp, y1_disp);
@@ -275,35 +281,36 @@
     int dx0_disp, dy0_disp, dx1_disp, dy1_disp;
     int l_disp, r_disp, t_disp, b_disp;
 
-    // Figuring out display coordinates works for TW_ROTATION == 0 too,
+    // Figuring out display coordinates works for gr_rotation == 0 too,
     // and isn't as expensive as allocating and rotating another surface,
     // so we do this anyway.
-    dx0_disp = ROTATION_X_DISP(dx, dy, gr_draw);
-    dy0_disp = ROTATION_Y_DISP(dx, dy, gr_draw);
-    dx1_disp = ROTATION_X_DISP(dx + w, dy + h, gr_draw);
-    dy1_disp = ROTATION_Y_DISP(dx + w, dy + h, gr_draw);
+    dx0_disp = ROTATION_X_DISP(dx, dy, gr_draw->width);
+    dy0_disp = ROTATION_Y_DISP(dx, dy, gr_draw->height);
+    dx1_disp = ROTATION_X_DISP(dx + w, dy + h, gr_draw->width);
+    dy1_disp = ROTATION_Y_DISP(dx + w, dy + h, gr_draw->height);
     l_disp = std::min(dx0_disp, dx1_disp);
     r_disp = std::max(dx0_disp, dx1_disp);
     t_disp = std::min(dy0_disp, dy1_disp);
     b_disp = std::max(dy0_disp, dy1_disp);
 
-#if TW_ROTATION != 0
-    // Do not perform relatively expensive operation if not needed
     GGLSurface surface_rotated;
-    surface_rotated.version = sizeof(surface_rotated);
-    // Skip the **(TW_ROTATION == 0)** || (TW_ROTATION == 180) check
-    // because we are under a TW_ROTATION != 0 conditional compilation statement
-    surface_rotated.width   = (TW_ROTATION == 180) ? surface->width  : surface->height;
-    surface_rotated.height  = (TW_ROTATION == 180) ? surface->height : surface->width;
-    surface_rotated.stride  = surface_rotated.width;
-    surface_rotated.format  = surface->format;
-    surface_rotated.data    = (GGLubyte*) malloc(surface_rotated.stride * surface_rotated.height * 4);
-    surface_ROTATION_transform((gr_surface) &surface_rotated, (const gr_surface) surface, 4);
+    if (gr_rotation != 0) {
+        // Do not perform relatively expensive operation if not needed
+        surface_rotated.version = sizeof(surface_rotated);
+        // Skip the **(gr_rotation == 0)** || (gr_rotation == 180) check
+        // because we are under a gr_rotation != 0 conditional compilation statement
+        surface_rotated.width   = (gr_rotation == 180) ? surface->width  : surface->height;
+        surface_rotated.height  = (gr_rotation == 180) ? surface->height : surface->width;
+        surface_rotated.stride  = surface_rotated.width;
+        surface_rotated.format  = surface->format;
+        surface_rotated.data    = (GGLubyte*) malloc(surface_rotated.stride * surface_rotated.height * 4);
+        surface_ROTATION_transform((gr_surface) &surface_rotated, (const gr_surface) surface, 4);
 
-    gl->bindTexture(gl, &surface_rotated);
-#else
-    gl->bindTexture(gl, surface);
-#endif
+        gl->bindTexture(gl, &surface_rotated);
+    } else {
+        gl->bindTexture(gl, surface);
+    }
+
     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -312,9 +319,8 @@
     gl->recti(gl, l_disp, t_disp, r_disp, b_disp);
     gl->disable(gl, GGL_TEXTURE_2D);
 
-#if TW_ROTATION != 0
-    free(surface_rotated.data);
-#endif
+    if (gr_rotation != 0)
+        free(surface_rotated.data);
 
     if(surface->format == GGL_PIXEL_FORMAT_RGBX_8888)
         gl->enable(gl, GGL_BLEND);
@@ -355,6 +361,14 @@
 {
     gr_draw = NULL;
 
+    char gr_rotation_string[PROPERTY_VALUE_MAX];
+    char default_rotation[4];
+    snprintf(default_rotation, 4, "%d", TW_ROTATION);
+    property_get("persist.twrp.rotation", gr_rotation_string, default_rotation);
+    gr_rotation = atoi(gr_rotation_string);
+    if (!(gr_rotation == 90 || gr_rotation == 180 || gr_rotation == 270))
+        gr_rotation = 0;
+
 #ifdef MSM_BSP
     gr_backend = open_overlay();
     if (gr_backend) {
@@ -431,14 +445,14 @@
 
 int gr_fb_width(void)
 {
-    return (TW_ROTATION == 0 || TW_ROTATION == 180) ?
+    return (gr_rotation == 0 || gr_rotation == 180) ?
             gr_draw->width  - 2 * overscan_offset_x :
             gr_draw->height - 2 * overscan_offset_y;
 }
 
 int gr_fb_height(void)
 {
-    return (TW_ROTATION == 0 || TW_ROTATION == 180) ?
+    return (gr_rotation == 0 || gr_rotation == 180) ?
             gr_draw->height - 2 * overscan_offset_y :
             gr_draw->width  - 2 * overscan_offset_x;
 }
diff --git a/minuitwrp/graphics_overlay.cpp b/minuitwrp/graphics_overlay.cpp
index 4dff7f4..a53faa8 100644
--- a/minuitwrp/graphics_overlay.cpp
+++ b/minuitwrp/graphics_overlay.cpp
@@ -324,7 +324,7 @@
             overlayL.dst_rect.h = gr_fb.height;
             overlayL.alpha = 0xFF;
             // If this worked, life would have been so much easier
-            //switch (TW_ROTATION) {
+            //switch (gr_rotation) {
                 //case   0:  overlayL.flags = MDP_ROT_NOP; break;
                 //case  90:  overlayL.flags = MDP_ROT_90;  break;
                 //case 180:  overlayL.flags = MDP_ROT_180; break;
@@ -368,7 +368,7 @@
             overlayL.dst_rect.h = height;
             overlayL.alpha = 0xFF;
             // If this worked, life would have been so much easier
-            //switch (TW_ROTATION) {
+            //switch (gr_rotation) {
                 //case   0:  overlayL.flags = MDP_ROT_NOP; break;
                 //case  90:  overlayL.flags = MDP_ROT_90;  break;
                 //case 180:  overlayL.flags = MDP_ROT_180; break;
@@ -403,7 +403,7 @@
             overlayR.alpha = 0xFF;
             overlayR.flags = MDSS_MDP_RIGHT_MIXER;
             // If this worked, life would have been so much easier
-            //switch (TW_ROTATION) {
+            //switch (gr_rotation) {
                 //case   0:  overlayR.flags |= MDP_ROT_NOP; break;
                 //case  90:  overlayR.flags |= MDP_ROT_90;  break;
                 //case 180:  overlayR.flags |= MDP_ROT_180; break;
diff --git a/minuitwrp/graphics_utils.cpp b/minuitwrp/graphics_utils.cpp
index c591e53..0bc8682 100644
--- a/minuitwrp/graphics_utils.cpp
+++ b/minuitwrp/graphics_utils.cpp
@@ -26,6 +26,7 @@
 struct fb_var_screeninfo vi;
 extern GGLSurface gr_mem_surface;
 extern GRSurface* gr_draw;
+extern unsigned int gr_rotation;
 
 int gr_save_screenshot(const char *dest)
 {
@@ -123,6 +124,20 @@
     return res;
 }
 
+int ROTATION_X_DISP(int x, int y, int w) {
+    return ((gr_rotation ==   0) ? (x) :
+            (gr_rotation ==  90) ? (w - (y) - 1) :
+            (gr_rotation == 180) ? (w - (x) - 1) :
+            (gr_rotation == 270) ? (y) : -1);
+}
+
+int ROTATION_Y_DISP(int x, int y, int h) {
+    return ((gr_rotation ==   0) ? (y) :
+            (gr_rotation ==  90) ? (x) :
+            (gr_rotation == 180) ? (h - (y) - 1) :
+            (gr_rotation == 270) ? (h - (x) - 1) : -1);
+}
+
 #define MATRIX_ELEMENT(matrix, row, col, row_size, elem_size) \
     (((uint8_t*) (matrix)) + (((row) * (elem_size)) * (row_size)) + ((col) * (elem_size)))
 
@@ -135,8 +150,8 @@
             /* input pointer from src->data */                                \
             const uint##bits_per_pixel##_t *ip;                               \
             /* Display coordinates (in dst) corresponding to (x, y) in src */ \
-            size_t x_disp = ROTATION_X_DISP(x, y, dst);                     \
-            size_t y_disp = ROTATION_Y_DISP(x, y, dst);                     \
+            size_t x_disp = ROTATION_X_DISP(x, y, dst->width);                \
+            size_t y_disp = ROTATION_Y_DISP(x, y, dst->height);               \
                                                                               \
             ip = (const uint##bits_per_pixel##_t*)                            \
                  MATRIX_ELEMENT(src->data, y, x,                              \
diff --git a/minuitwrp/minui.h b/minuitwrp/minui.h
index 2c462e7..a6c2a71 100644
--- a/minuitwrp/minui.h
+++ b/minuitwrp/minui.h
@@ -76,16 +76,9 @@
 
 // Transform minuitwrp API coordinates into display coordinates,
 // for panels that are hardware-mounted in a rotated manner.
-#define ROTATION_X_DISP(x, y, surface) \
-    ((TW_ROTATION ==   0) ? (x) : \
-     (TW_ROTATION ==  90) ? ((surface)->width - (y) - 1) : \
-     (TW_ROTATION == 180) ? ((surface)->width - (x) - 1) : \
-     (TW_ROTATION == 270) ? (y) : -1)
-#define ROTATION_Y_DISP(x, y, surface) \
-    ((TW_ROTATION ==   0) ? (y) : \
-     (TW_ROTATION ==  90) ? (x) : \
-     (TW_ROTATION == 180) ? ((surface)->height - (y) - 1) : \
-     (TW_ROTATION == 270) ? ((surface)->height - (x) - 1) : -1)
+int ROTATION_X_DISP(int x, int y, int w);
+
+int ROTATION_Y_DISP(int x, int y, int h);
 
 void surface_ROTATION_transform(gr_surface dst_ptr, const gr_surface src_ptr, size_t num_bytes_per_pixel);
 
diff --git a/minuitwrp/truetype.cpp b/minuitwrp/truetype.cpp
index 0416b0e..9c7c79b 100644
--- a/minuitwrp/truetype.cpp
+++ b/minuitwrp/truetype.cpp
@@ -20,6 +20,8 @@
 #define STRING_CACHE_MAX_ENTRIES 400
 #define STRING_CACHE_TRUNCATE_ENTRIES 150
 
+extern unsigned int gr_rotation;
+
 typedef struct
 {
     int size;
@@ -725,20 +727,20 @@
         return -1;
     }
 
-#if TW_ROTATION != 0
-    // Do not perform relatively expensive operation if not needed
     GGLSurface string_surface_rotated;
-    string_surface_rotated.version = sizeof(string_surface_rotated);
-    // Skip the **(TW_ROTATION == 0)** || (TW_ROTATION == 180) check
-    // because we are under a TW_ROTATION != 0 conditional compilation statement
-    string_surface_rotated.width   = (TW_ROTATION == 180) ? e->surface.width  : e->surface.height;
-    string_surface_rotated.height  = (TW_ROTATION == 180) ? e->surface.height : e->surface.width;
-    string_surface_rotated.stride  = string_surface_rotated.width;
-    string_surface_rotated.format  = e->surface.format;
-    // e->surface.format is GGL_PIXEL_FORMAT_A_8 (grayscale)
-    string_surface_rotated.data    = (GGLubyte*) malloc(string_surface_rotated.stride * string_surface_rotated.height * 1);
-    surface_ROTATION_transform((gr_surface) &string_surface_rotated, (const gr_surface) &e->surface, 1);
-#endif
+    if (gr_rotation != 0) {
+        // Do not perform relatively expensive operation if not needed
+        string_surface_rotated.version = sizeof(string_surface_rotated);
+        // Skip the **(gr_rotation == 0)** || (gr_rotation == 180) check
+        // because we are under a gr_rotation != 0 conditional compilation statement
+        string_surface_rotated.width   = (gr_rotation == 180) ? e->surface.width  : e->surface.height;
+        string_surface_rotated.height  = (gr_rotation == 180) ? e->surface.height : e->surface.width;
+        string_surface_rotated.stride  = string_surface_rotated.width;
+        string_surface_rotated.format  = e->surface.format;
+        // e->surface.format is GGL_PIXEL_FORMAT_A_8 (grayscale)
+        string_surface_rotated.data    = (GGLubyte*) malloc(string_surface_rotated.stride * string_surface_rotated.height * 1);
+        surface_ROTATION_transform((gr_surface) &string_surface_rotated, (const gr_surface) &e->surface, 1);
+    }
 
     int y_bottom = y + e->surface.height;
     int res = e->rendered_bytes;
@@ -753,26 +755,26 @@
         }
     }
 
-    // Figuring out display coordinates works for TW_ROTATION == 0 too,
+    // Figuring out display coordinates works for gr_rotation == 0 too,
     // and isn't as expensive as allocating and rotating another surface,
     // so we do this anyway.
     int x0_disp, y0_disp, x1_disp, y1_disp;
     int l_disp, r_disp, t_disp, b_disp;
 
-    x0_disp = ROTATION_X_DISP(x, y, gr_draw);
-    y0_disp = ROTATION_Y_DISP(x, y, gr_draw);
-    x1_disp = ROTATION_X_DISP(x + e->surface.width, y_bottom, gr_draw);
-    y1_disp = ROTATION_Y_DISP(x + e->surface.width, y_bottom, gr_draw);
+    x0_disp = ROTATION_X_DISP(x, y, gr_draw->width);
+    y0_disp = ROTATION_Y_DISP(x, y, gr_draw->height);
+    x1_disp = ROTATION_X_DISP(x + e->surface.width, y_bottom, gr_draw->width);
+    y1_disp = ROTATION_Y_DISP(x + e->surface.width, y_bottom, gr_draw->height);
     l_disp = std::min(x0_disp, x1_disp);
     r_disp = std::max(x0_disp, x1_disp);
     t_disp = std::min(y0_disp, y1_disp);
     b_disp = std::max(y0_disp, y1_disp);
 
-#if TW_ROTATION != 0
-    gl->bindTexture(gl, &string_surface_rotated);
-#else
-    gl->bindTexture(gl, &e->surface);
-#endif
+    if (gr_rotation != 0) {
+        gl->bindTexture(gl, &string_surface_rotated);
+    } else {
+        gl->bindTexture(gl, &e->surface);
+    }
     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -782,9 +784,8 @@
     gl->recti(gl, l_disp, t_disp, r_disp, b_disp);
     gl->disable(gl, GGL_TEXTURE_2D);
 
-#if TW_ROTATION != 0
-    free(string_surface_rotated.data);
-#endif
+    if (gr_rotation != 0)
+        free(string_surface_rotated.data);
 
     pthread_mutex_unlock(&font->mutex);
     return res;