Correctly set the viewport in layers.

Bug #2919295

Change-Id: I16ce79ab0d5747cb01c6c1abe531da3dfd93fb54
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 74d50e4..264ad3d 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -260,10 +260,10 @@
     }
 
     float vertices[] = {
-            r.left, r.top,
-            r.right, r.top,
-            r.right, r.bottom,
-            r.left, r.bottom
+        r.left, r.top,
+        r.right, r.top,
+        r.right, r.bottom,
+        r.left, r.bottom
     };
 
     float x, y, z;
@@ -297,8 +297,8 @@
 
 void Matrix4::dump() const {
     LOGD("Matrix4[simple=%d", mSimpleMatrix);
-    LOGD("  %f %f %f %f", data[kScaleX], data[kSkewX], data[ 8], data[kTranslateX]);
-    LOGD("  %f %f %f %f", data[kSkewY], data[kScaleY], data[ 9], data[kTranslateY]);
+    LOGD("  %f %f %f %f", data[kScaleX], data[kSkewX], data[8], data[kTranslateX]);
+    LOGD("  %f %f %f %f", data[kSkewY], data[kScaleY], data[9], data[kTranslateY]);
     LOGD("  %f %f %f %f", data[2], data[6], data[kScaleZ], data[kTranslateZ]);
     LOGD("  %f %f %f %f", data[kPerspective0], data[kPerspective1], data[11], data[kPerspective2]);
     LOGD("]");
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 700355a..f35c380 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -183,12 +183,12 @@
 
 void OpenGLRenderer::setViewport(int width, int height) {
     glViewport(0, 0, width, height);
-
     mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
     mWidth = width;
     mHeight = height;
     mFirstSnapshot->height = height;
+    mFirstSnapshot->viewport.set(0, 0, width, height);
 }
 
 void OpenGLRenderer::prepare() {
@@ -254,6 +254,8 @@
     sp<Snapshot> previous = mSnapshot->previous;
 
     if (restoreOrtho) {
+        Rect& r = previous->viewport;
+        glViewport(r.left, r.top, r.right, r.bottom);
         mOrthoMatrix.load(current->orthoMatrix);
     }
 
@@ -267,39 +269,6 @@
     return restoreClip;
 }
 
-void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
-    if (!current->layer) {
-        LOGE("Attempting to compose a layer that does not exist");
-        return;
-    }
-
-    // Unbind current FBO and restore previous one
-    // Most of the time, previous->fbo will be 0 to bind the default buffer
-    glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
-
-    // Restore the clip from the previous snapshot
-    const Rect& clip = previous->clipRect;
-    glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
-
-    Layer* layer = current->layer;
-    const Rect& rect = layer->layer;
-
-    drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
-            layer->texture, layer->alpha, layer->mode, layer->blend);
-
-    LayerSize size(rect.getWidth(), rect.getHeight());
-    // Failing to add the layer to the cache should happen only if the
-    // layer is too large
-    if (!mLayerCache.put(size, layer)) {
-        LAYER_LOGD("Deleting layer");
-
-        glDeleteFramebuffers(1, &layer->fbo);
-        glDeleteTextures(1, &layer->texture);
-
-        delete layer;
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Layers
 ///////////////////////////////////////////////////////////////////////////////
@@ -366,21 +335,58 @@
 
     // Creates a new snapshot to draw into the FBO
     saveSnapshot();
-    // TODO: This doesn't preserve other transformations (check Skia first)
+
     mSnapshot->transform.loadTranslate(-left, -top, 0.0f);
     mSnapshot->setClip(0.0f, 0.0f, right - left, bottom - top);
+    mSnapshot->viewport.set(0.0f, 0.0f, right - left, bottom - top);
     mSnapshot->height = bottom - top;
+
     setScissorFromClip();
 
     mSnapshot->flags = Snapshot::kFlagDirtyOrtho | Snapshot::kFlagClipSet;
     mSnapshot->orthoMatrix.load(mOrthoMatrix);
 
     // Change the ortho projection
-    mOrthoMatrix.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
+    glViewport(0, 0, right - left, bottom - top);
+    // Don't flip the FBO, it will get flipped when drawing back to the framebuffer
+    mOrthoMatrix.loadOrtho(0.0f, right - left, 0.0f, bottom - top, -1.0f, 1.0f);
 
     return true;
 }
 
+void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
+    if (!current->layer) {
+        LOGE("Attempting to compose a layer that does not exist");
+        return;
+    }
+
+    // Unbind current FBO and restore previous one
+    // Most of the time, previous->fbo will be 0 to bind the default buffer
+    glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
+
+    // Restore the clip from the previous snapshot
+    const Rect& clip = previous->clipRect;
+    glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
+
+    Layer* layer = current->layer;
+    const Rect& rect = layer->layer;
+
+    drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
+            layer->texture, layer->alpha, layer->mode, layer->blend);
+
+    LayerSize size(rect.getWidth(), rect.getHeight());
+    // Failing to add the layer to the cache should happen only if the
+    // layer is too large
+    if (!mLayerCache.put(size, layer)) {
+        LAYER_LOGD("Deleting layer");
+
+        glDeleteFramebuffers(1, &layer->fbo);
+        glDeleteTextures(1, &layer->texture);
+
+        delete layer;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Transforms
 ///////////////////////////////////////////////////////////////////////////////
@@ -424,14 +430,9 @@
 }
 
 bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
-    SkRect sr;
-    sr.set(left, top, right, bottom);
+    Rect r(left, top, right, bottom);
+    mSnapshot->transform.mapRect(r);
 
-    SkMatrix m;
-    mSnapshot->transform.copyTo(m);
-    m.mapRect(&sr);
-
-    Rect r(sr.fLeft, sr.fTop, sr.fRight, sr.fBottom);
     return !mSnapshot->clipRect.intersects(r);
 }
 
@@ -759,7 +760,6 @@
          mModelView.loadIdentity();
      }
      mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
-
      glUniform4f(mCurrentProgram->color, r, g, b, a);
 
      textureUnit++;
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 9495bee..21b2bef 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -57,7 +57,8 @@
             flags(0),
             previous(s),
             layer(NULL),
-            fbo(s->fbo) {
+            fbo(s->fbo),
+            viewport(s->viewport) {
         if ((s->flags & Snapshot::kFlagClipSet) &&
                 !(s->flags & Snapshot::kFlagDirtyLocalClip)) {
             localClip.set(s->localClip);
@@ -180,6 +181,11 @@
     GLuint fbo;
 
     /**
+     * Current viewport.
+     */
+    Rect viewport;
+
+    /**
      * Contains the previous ortho matrix.
      */
     mat4 orthoMatrix;
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 9c86187..5fbe9e5 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -47,7 +47,7 @@
 
     ShadowText(const ShadowText& shadow):
             paint(shadow.paint), radius(shadow.radius), len(shadow.len), hash(shadow.hash) {
-        text = new char[len];
+        text = new char[shadow.len];
         memcpy(text, shadow.text, shadow.len);
     }
 
diff --git a/tests/HwAccelerationTest/res/layout/stack.xml b/tests/HwAccelerationTest/res/layout/stack.xml
new file mode 100644
index 0000000..b4d2d73a
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/stack.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:paddingTop="0dp"
+    android:paddingBottom="0dp"
+    android:paddingLeft="12dp"
+    android:paddingRight="12dp"
+    android:focusable="true">
+    <StackView
+        android:id="@+id/stack_view" 
+        android:layout_width="348px" 
+        android:layout_height="374px"
+        android:layout_gravity="center"
+        android:background="#00000000"
+        android:cacheColorHint="#00000000"
+        android:autoStart="true" />
+</FrameLayout>
diff --git a/tests/HwAccelerationTest/res/layout/stack_item.xml b/tests/HwAccelerationTest/res/layout/stack_item.xml
new file mode 100644
index 0000000..3504018
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/stack_item.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/stack_item"  
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"> 
+    <FrameLayout  
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"> 
+        <ImageView android:id="@+id/textview_icon"
+            android:layout_height="250dip"
+            android:layout_width="250dip"
+            android:layout_gravity="center" />
+        <TextView android:id="@+id/mini_text"
+            android:layout_width="wrap_content" 
+            android:layout_height="wrap_content" 
+            android:layout_gravity="center" />
+    </FrameLayout>
+    <TextView 
+        android:layout_width="wrap_content" 
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        android:layout_gravity="center" />
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/StackActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/StackActivity.java
index 46c790c..5c8db6e 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/StackActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/StackActivity.java
@@ -19,14 +19,13 @@
 import android.app.Activity;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AbsListView;
 import android.widget.ArrayAdapter;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.StackView;
+import android.widget.TextView;
 
 @SuppressWarnings({"UnusedDeclaration"})
 public class StackActivity extends Activity {
@@ -34,32 +33,27 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        StackView stack = new StackView(this);
+        setContentView(R.layout.stack);
+
+        StackView stack = (StackView) findViewById(R.id.stack_view);
         stack.setAdapter(new ArrayAdapter<Drawable>(this, android.R.layout.simple_list_item_1,
                 android.R.id.text1, new Drawable[] {
             getResources().getDrawable(R.drawable.sunset1),
             getResources().getDrawable(R.drawable.sunset2),
-            getResources().getDrawable(R.drawable.sunset1),
-            getResources().getDrawable(R.drawable.sunset2),
-            getResources().getDrawable(R.drawable.sunset1),
-            getResources().getDrawable(R.drawable.sunset2)                
         }) {
             @Override
             public View getView(int position, View convertView, ViewGroup parent) {
-                ImageView image;
-                if (convertView == null) {
-                    image = new ImageView(StackActivity.this);
-                } else {
-                    image = (ImageView) convertView;
+                View item = convertView;
+                if (item == null) {
+                    item = LayoutInflater.from(getContext()).inflate(
+                            R.layout.stack_item, null, false);                    
                 }
-                image.setImageDrawable(getItem(position % getCount()));
-                return image;
+                ((ImageView) item.findViewById(R.id.textview_icon)).setImageDrawable(
+                        getItem(position % getCount()));
+                ((TextView) item.findViewById(R.id.mini_text)).setText("" + position);
+                return item;
             }
         });
         stack.setDisplayedChild(0);
-
-        FrameLayout layout = new FrameLayout(this);
-        layout.addView(stack, new FrameLayout.LayoutParams(500, 500, Gravity.CENTER));
-        setContentView(layout);
     }
 }