fix [2931513] Add support for setting the orientation of an ANativeWindow

Also implement support for cropping.

Change-Id: Iba5888dd242bf2feaac9e9ce26e404c1f404c280
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 91ac915..6fc5010 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -54,6 +54,8 @@
 {
     const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
     mFlags = hw.getFlags();
+    mBufferCrop.makeInvalid();
+    mBufferTransform = 0;
 }
 
 LayerBase::~LayerBase()
@@ -345,6 +347,14 @@
     clearWithOpenGL(clip,0,0,0,0);
 }
 
+template <typename T>
+static inline
+void swap(T& a, T& b) {
+    T t(a);
+    a = b;
+    b = t;
+}
+
 void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
@@ -378,37 +388,72 @@
         }
     }
 
-    Region::const_iterator it = clip.begin();
-    Region::const_iterator const end = clip.end();
-    const GLfloat texCoords[4][2] = {
-            { 0,  0 },
-            { 0,  1 },
-            { 1,  1 },
-            { 1,  0 }
+    /*
+     *  compute texture coordinates
+     *  here, we handle NPOT, cropping and buffer transformations
+     */
+
+    GLfloat cl, ct, cr, cb;
+    if (!mBufferCrop.isEmpty()) {
+        // source is cropped
+        const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
+        const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
+        cl = mBufferCrop.left   * us;
+        ct = mBufferCrop.top    * vs;
+        cr = mBufferCrop.right  * us;
+        cb = mBufferCrop.bottom * vs;
+    } else {
+        cl = 0;
+        ct = 0;
+        cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
+        cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
+    }
+
+    struct TexCoords {
+        GLfloat u;
+        GLfloat v;
     };
 
-    glMatrixMode(GL_TEXTURE);
-    glLoadIdentity();
+    enum {
+        // name of the corners in the texture map
+        LB = 0, // left-bottom
+        LT = 1, // left-top
+        RT = 2, // right-top
+        RB = 3  // right-bottom
+    };
+
+    // vertices in screen space
+    int vLT = LB;
+    int vLB = LT;
+    int vRB = RT;
+    int vRT = RB;
 
     // the texture's source is rotated
-    switch (texture.transform) {
-        case HAL_TRANSFORM_ROT_90:
-            glTranslatef(0, 1, 0);
-            glRotatef(-90, 0, 0, 1);
-            break;
-        case HAL_TRANSFORM_ROT_180:
-            glTranslatef(1, 1, 0);
-            glRotatef(-180, 0, 0, 1);
-            break;
-        case HAL_TRANSFORM_ROT_270:
-            glTranslatef(1, 0, 0);
-            glRotatef(-270, 0, 0, 1);
-            break;
+    uint32_t transform = mBufferTransform;
+    if (transform & HAL_TRANSFORM_ROT_90) {
+        vLT = RB;
+        vLB = LB;
+        vRB = LT;
+        vRT = RT;
+    }
+    if (transform & HAL_TRANSFORM_FLIP_V) {
+        swap(vLT, vLB);
+        swap(vRB, vRT);
+    }
+    if (transform & HAL_TRANSFORM_FLIP_H) {
+        swap(vLT, vRB);
+        swap(vLB, vRT);
     }
 
-    if (texture.NPOTAdjust) {
-        glScalef(texture.wScale, texture.hScale, 1.0f);
-    }
+    TexCoords texCoords[4];
+    texCoords[vLT].u = cl;
+    texCoords[vLT].v = ct;
+    texCoords[vLB].u = cl;
+    texCoords[vLB].v = cb;
+    texCoords[vRB].u = cr;
+    texCoords[vRB].v = cb;
+    texCoords[vRT].u = cr;
+    texCoords[vRT].v = ct;
 
     if (needsDithering()) {
         glEnable(GL_DITHER);
@@ -420,6 +465,8 @@
     glVertexPointer(2, GL_FLOAT, 0, mVertices);
     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
 
+    Region::const_iterator it = clip.begin();
+    Region::const_iterator const end = clip.end();
     while (it != end) {
         const Rect& r = *it++;
         const GLint sy = fbHeight - (r.top + r.height());
@@ -429,6 +476,16 @@
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
+void LayerBase::setBufferCrop(const Rect& crop) {
+    if (!crop.isEmpty()) {
+        mBufferCrop = crop;
+    }
+}
+
+void LayerBase::setBufferTransform(uint32_t transform) {
+    mBufferTransform = transform;
+}
+
 void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
     const Layer::State& s(drawingState());