Cleanup, better code reuse.

Change-Id: Ib86a7309ae579cce3b7cf464782c34e70a74c616
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index da5b9dd..700355a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -562,82 +562,6 @@
     drawColorRect(left, top, right, bottom, color, mode);
 }
 
-void OpenGLRenderer::renderShadow(const ShadowTexture* texture, float x, float y,
-        SkXfermode::Mode mode) {
-    const float sx = x - texture->left + mShadowDx;
-    const float sy = y - texture->top + mShadowDy;
-
-    const GLfloat a = ((mShadowColor >> 24) & 0xFF) / 255.0f;
-    const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f;
-    const GLfloat g = a * ((mShadowColor >>  8) & 0xFF) / 255.0f;
-    const GLfloat b = a * ((mShadowColor      ) & 0xFF) / 255.0f;
-
-    GLuint textureUnit = 0;
-    renderTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, false);
-}
-
-void OpenGLRenderer::renderTextureAlpha8(const Texture* texture, GLuint& textureUnit,
-        float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode,
-        bool applyFilters) {
-     // Describe the required shaders
-     ProgramDescription description;
-     description.hasTexture = true;
-     description.hasAlpha8Texture = true;
-
-     if (applyFilters) {
-         if (mShader) {
-             mShader->describe(description, mExtensions);
-         }
-         if (mColorFilter) {
-             mColorFilter->describe(description, mExtensions);
-         }
-     }
-
-     // Build and use the appropriate shader
-     useProgram(mProgramCache.get(description));
-
-     // Setup the blending mode
-     chooseBlending(true, mode);
-     bindTexture(texture->id, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
-     glUniform1i(mCurrentProgram->getUniform("sampler"), textureUnit);
-
-     int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
-     glEnableVertexAttribArray(texCoordsSlot);
-
-     // Setup attributes
-     glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
-             gMeshStride, &mMeshVertices[0].position[0]);
-     glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
-             gMeshStride, &mMeshVertices[0].texture[0]);
-
-     // Setup uniforms
-     mModelView.loadTranslate(x, y, 0.0f);
-     mModelView.scale(texture->width, texture->height, 1.0f);
-     mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
-
-     glUniform4f(mCurrentProgram->color, r, g, b, a);
-
-     textureUnit++;
-     if (applyFilters) {
-         // Setup attributes and uniforms required by the shaders
-         if (mShader) {
-             mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit);
-         }
-         if (mColorFilter) {
-             mColorFilter->setupProgram(mCurrentProgram);
-         }
-     }
-
-     // Draw the mesh
-     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
-
-     glDisableVertexAttribArray(texCoordsSlot);
-}
-
-#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
-#define kStdUnderline_Offset    (1.0f / 9.0f)
-#define kStdUnderline_Thickness (1.0f / 18.0f)
-
 void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
         float x, float y, SkPaint* paint) {
     if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
@@ -668,7 +592,12 @@
         const ShadowTexture* shadow = mDropShadowCache.get(paint, text, bytesCount,
                 count, mShadowRadius);
         const AutoTexture autoCleanup(shadow);
-        renderShadow(shadow, x, y, mode);
+
+        setupShadow(shadow, x, y, mode);
+
+        // Draw the mesh
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+        glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords"));
     }
 
     uint32_t color = paint->getColor();
@@ -677,94 +606,19 @@
     const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
     const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
 
-    mModelView.loadIdentity();
-
     GLuint textureUnit = 0;
-    // Needs to be set prior to calling FontRenderer::getTexture()
     glActiveTexture(gTextureUnits[textureUnit]);
 
-    ProgramDescription description;
-    description.hasTexture = true;
-    description.hasAlpha8Texture = true;
-    if (mShader) {
-        mShader->describe(description, mExtensions);
-    }
-    if (mColorFilter) {
-        mColorFilter->describe(description, mExtensions);
-    }
-
-    useProgram(mProgramCache.get(description));
-    mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
-
-    // Text is always blended, no need to check the shader
-    chooseBlending(true, mode);
-    bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
-    glUniform1i(mCurrentProgram->getUniform("sampler"), textureUnit);
-
-    int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
-    glEnableVertexAttribArray(texCoordsSlot);
-
-    // Always premultiplied
-    glUniform4f(mCurrentProgram->color, r, g, b, a);
-
-    textureUnit++;
-    // Setup attributes and uniforms required by the shaders
-    if (mShader) {
-        mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit);
-    }
-    if (mColorFilter) {
-        mColorFilter->setupProgram(mCurrentProgram);
-    }
+    setupTextureAlpha8(mFontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a,
+            mode, false, true);
 
     const Rect& clip = mSnapshot->getLocalClip();
     mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    glDisableVertexAttribArray(texCoordsSlot);
+    glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords"));
 
-    // Handle underline and strike-through
-    uint32_t flags = paint->getFlags();
-    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
-        float underlineWidth = length;
-        // If length is > 0.0f, we already measured the text for the text alignment
-        if (length <= 0.0f) {
-            underlineWidth = paint->measureText(text, bytesCount);
-        }
-
-        float offsetX = 0;
-        switch (paint->getTextAlign()) {
-            case SkPaint::kCenter_Align:
-                offsetX = underlineWidth * 0.5f;
-                break;
-            case SkPaint::kRight_Align:
-                offsetX = underlineWidth;
-                break;
-            default:
-                break;
-        }
-
-        if (underlineWidth > 0.0f) {
-            float textSize = paint->getTextSize();
-            float height = textSize * kStdUnderline_Thickness;
-
-            float left = x - offsetX;
-            float top = 0.0f;
-            float right = left + underlineWidth;
-            float bottom = 0.0f;
-
-            if (flags & SkPaint::kUnderlineText_Flag) {
-                top = y + textSize * kStdUnderline_Offset;
-                bottom = top + height;
-                drawRect(left, top, right, bottom, paint);
-            }
-
-            if (flags & SkPaint::kStrikeThruText_Flag) {
-                top = y + textSize * kStdStrikeThru_Offset;
-                bottom = top + height;
-                drawRect(left, top, right, bottom, paint);
-            }
-        }
-    }
+    drawTextDecorations(text, bytesCount, length, x, y, paint);
 }
 
 void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
@@ -787,7 +641,12 @@
 
     const float x = texture->left - texture->offset;
     const float y = texture->top - texture->offset;
-    renderTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true);
+
+    setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true);
+
+    // Draw the mesh
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+    glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords"));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -837,6 +696,135 @@
 // Drawing implementation
 ///////////////////////////////////////////////////////////////////////////////
 
+void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y,
+        SkXfermode::Mode mode) {
+    const float sx = x - texture->left + mShadowDx;
+    const float sy = y - texture->top + mShadowDy;
+
+    const GLfloat a = ((mShadowColor >> 24) & 0xFF) / 255.0f;
+    const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f;
+    const GLfloat g = a * ((mShadowColor >>  8) & 0xFF) / 255.0f;
+    const GLfloat b = a * ((mShadowColor      ) & 0xFF) / 255.0f;
+
+    GLuint textureUnit = 0;
+    setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false);
+}
+
+void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit,
+        float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode,
+        bool transforms, bool applyFilters) {
+    setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit,
+            x, y, r, g, b, a, mode, transforms, applyFilters);
+}
+
+void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
+        GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
+        SkXfermode::Mode mode, bool transforms, bool applyFilters) {
+     // Describe the required shaders
+     ProgramDescription description;
+     description.hasTexture = true;
+     description.hasAlpha8Texture = true;
+
+     if (applyFilters) {
+         if (mShader) {
+             mShader->describe(description, mExtensions);
+         }
+         if (mColorFilter) {
+             mColorFilter->describe(description, mExtensions);
+         }
+     }
+
+     // Build and use the appropriate shader
+     useProgram(mProgramCache.get(description));
+
+     // Setup the blending mode
+     chooseBlending(true, mode);
+     bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
+     glUniform1i(mCurrentProgram->getUniform("sampler"), textureUnit);
+
+     int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
+     glEnableVertexAttribArray(texCoordsSlot);
+
+     // Setup attributes
+     glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
+             gMeshStride, &mMeshVertices[0].position[0]);
+     glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
+             gMeshStride, &mMeshVertices[0].texture[0]);
+
+     // Setup uniforms
+     if (transforms) {
+         mModelView.loadTranslate(x, y, 0.0f);
+         mModelView.scale(width, height, 1.0f);
+     } else {
+         mModelView.loadIdentity();
+     }
+     mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+
+     glUniform4f(mCurrentProgram->color, r, g, b, a);
+
+     textureUnit++;
+     if (applyFilters) {
+         // Setup attributes and uniforms required by the shaders
+         if (mShader) {
+             mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit);
+         }
+         if (mColorFilter) {
+             mColorFilter->setupProgram(mCurrentProgram);
+         }
+     }
+}
+
+#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
+#define kStdUnderline_Offset    (1.0f / 9.0f)
+#define kStdUnderline_Thickness (1.0f / 18.0f)
+
+void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
+        float x, float y, SkPaint* paint) {
+    // Handle underline and strike-through
+    uint32_t flags = paint->getFlags();
+    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
+        float underlineWidth = length;
+        // If length is > 0.0f, we already measured the text for the text alignment
+        if (length <= 0.0f) {
+            underlineWidth = paint->measureText(text, bytesCount);
+        }
+
+        float offsetX = 0;
+        switch (paint->getTextAlign()) {
+            case SkPaint::kCenter_Align:
+                offsetX = underlineWidth * 0.5f;
+                break;
+            case SkPaint::kRight_Align:
+                offsetX = underlineWidth;
+                break;
+            default:
+                break;
+        }
+
+        if (underlineWidth > 0.0f) {
+            float textSize = paint->getTextSize();
+            float height = textSize * kStdUnderline_Thickness;
+
+            float left = x - offsetX;
+            float top = 0.0f;
+            float right = left + underlineWidth;
+            float bottom = 0.0f;
+
+            if (flags & SkPaint::kUnderlineText_Flag) {
+                top = y + textSize * kStdUnderline_Offset;
+                bottom = top + height;
+                drawRect(left, top, right, bottom, paint);
+            }
+
+            if (flags & SkPaint::kStrikeThruText_Flag) {
+                top = y + textSize * kStdStrikeThru_Offset;
+                bottom = top + height;
+                drawRect(left, top, right, bottom, paint);
+            }
+        }
+    }
+}
+
 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
         int color, SkXfermode::Mode mode, bool ignoreTransform) {
     // If a shader is set, preserve only the alpha
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 948ff13..49143a5 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -226,17 +226,17 @@
             GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount = 0);
 
     /**
-     * Renders the specified shadow.
+     * Prepares the renderer to draw the specified shadow.
      *
      * @param texture The shadow texture
      * @param x The x coordinate of the shadow
      * @param y The y coordinate of the shadow
      * @param mode The blending mode
      */
-    void renderShadow(const ShadowTexture* texture, float x, float y, SkXfermode::Mode mode);
+    void setupShadow(const ShadowTexture* texture, float x, float y, SkXfermode::Mode mode);
 
     /**
-     * Renders the specified Alpha8 texture as a rectangle.
+     * Prepares the renderer to draw the specified Alpha8 texture as a rectangle.
      *
      * @param texture The texture to render with
      * @param textureUnit The texture unit to use, may be modified
@@ -247,11 +247,50 @@
      * @param b The blue component of the color
      * @param a The alpha component of the color
      * @param mode The blending mode
+     * @param transforms True if the matrix passed to the shader should be multiplied
+     *        by the model-view matrix
      * @param applyFilters Whether or not to take color filters and
      *        shaders into account
      */
-    void renderTextureAlpha8(const Texture* texture, GLuint& textureUnit, float x, float y,
-            float r, float g, float b, float a, SkXfermode::Mode mode, bool applyFilters);
+    void setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, float x, float y,
+            float r, float g, float b, float a, SkXfermode::Mode mode, bool transforms,
+            bool applyFilters);
+
+    /**
+     * Prepares the renderer to draw the specified Alpha8 texture as a rectangle.
+     *
+     * @param texture The texture to render with
+     * @param width The width of the texture
+     * @param height The height of the texture
+     * @param textureUnit The texture unit to use, may be modified
+     * @param x The x coordinate of the rectangle to draw
+     * @param y The y coordinate of the rectangle to draw
+     * @param r The red component of the color
+     * @param g The green component of the color
+     * @param b The blue component of the color
+     * @param a The alpha component of the color
+     * @param mode The blending mode
+     * @param transforms True if the matrix passed to the shader should be multiplied
+     *        by the model-view matrix
+     * @param applyFilters Whether or not to take color filters and
+     *        shaders into account
+     */
+    void setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
+            GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
+            SkXfermode::Mode mode, bool transforms, bool applyFilters);
+
+    /**
+     * Draws text underline and strike-through if needed.
+     *
+     * @param text The text to decor
+     * @param bytesCount The number of bytes in the text
+     * @param length The length in pixels of the text, can be <= 0.0f to force a measurement
+     * @param x The x coordinate where the text will be drawn
+     * @param y The y coordinate where the text will be drawn
+     * @param paint The paint to draw the text with
+     */
+    void drawTextDecorations(const char* text, int bytesCount, float length,
+            float x, float y, SkPaint* paint);
 
     /**
      * Resets the texture coordinates stored in mMeshVertices. Setting the values
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 181b4c8..775dc24 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -189,5 +189,14 @@
             </intent-filter>
         </activity>
 
+        <activity
+                android:name="StackActivity"
+                android:label="_Stacks">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/StackActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/StackActivity.java
new file mode 100644
index 0000000..46c790c
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/StackActivity.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.Gravity;
+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;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class StackActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        StackView stack = new StackView(this);
+        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;
+                }
+                image.setImageDrawable(getItem(position % getCount()));
+                return image;
+            }
+        });
+        stack.setDisplayedChild(0);
+
+        FrameLayout layout = new FrameLayout(this);
+        layout.addView(stack, new FrameLayout.LayoutParams(500, 500, Gravity.CENTER));
+        setContentView(layout);
+    }
+}