Add implementation for drawBitmap().

Change-Id: Iada9325f3c5642b61c2e0c4cd80bcfbc92cb491e
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d8023859..3010f29 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -54,10 +54,10 @@
 // This array is never used directly but used as a memcpy source in the
 // OpenGLRenderer constructor
 static const TextureVertex gDrawTextureVertices[] = {
-        FV(0.0f, 0.0f, 0.0f, 1.0f),
-        FV(1.0f, 0.0f, 1.0f, 1.0f),
-        FV(0.0f, 1.0f, 0.0f, 0.0f),
-        FV(1.0f, 1.0f, 1.0f, 0.0f)
+        FV(0.0f, 0.0f, 0.0f, 0.0f),
+        FV(1.0f, 0.0f, 1.0f, 0.0f),
+        FV(0.0f, 1.0f, 0.0f, 1.0f),
+        FV(1.0f, 1.0f, 1.0f, 1.0f)
 };
 static const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
 static const GLsizei gDrawTextureVertexCount = 4;
@@ -208,7 +208,7 @@
     resetDrawTextureTexCoords(u1, v1, u2, v1);
 
     drawTextureRect(layer.left, layer.top, layer.right, layer.bottom,
-            current->texture, current->alpha, current->mode, true);
+            current->texture, current->alpha, current->mode, true, true);
 
     resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
 
@@ -378,8 +378,33 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
-    LOGD("Drawing bitmap!");
+void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
+    Texture* texture = mTextureCache.get(bitmap);
+
+    SkXfermode::Mode mode;
+    int alpha;
+
+    if (paint) {
+        const bool isMode = SkXfermode::IsMode(paint->getXfermode(), &mode);
+        if (!isMode) {
+            // Assume SRC_OVER
+            mode = SkXfermode::kSrcOver_Mode;
+        }
+
+        // Skia draws using the color's alpha channel if < 255
+        // Otherwise, it uses the paint's alpha
+        int color = paint->getColor();
+        alpha = (color >> 24) & 0xFF;
+        if (alpha == 255) {
+            alpha = paint->getAlpha();
+        }
+    } else {
+        mode = SkXfermode::kSrcOver_Mode;
+        alpha = 255;
+    }
+
+    drawTextureRect(left, top, left + texture->width, top + texture->height, texture->id,
+            alpha / 255.0f, mode, texture->blend, true);
 }
 
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -443,23 +468,26 @@
 }
 
 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
-        GLuint texture, float alpha, SkXfermode::Mode mode, bool isPremultiplied) {
+        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied) {
     mModelView.loadTranslate(left, top, 0.0f);
     mModelView.scale(right - left, bottom - top, 1.0f);
 
     mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]);
 
-    GLenum sourceMode = gBlends[mode].src;
-    if (!isPremultiplied && sourceMode == GL_ONE) {
-        sourceMode = GL_SRC_ALPHA;
+    if (blend || alpha < 1.0f || mode != SkXfermode::kSrcOver_Mode) {
+        GLenum sourceMode = gBlends[mode].src;
+        if (!isPremultiplied && sourceMode == GL_ONE) {
+            sourceMode = GL_SRC_ALPHA;
+        }
+
+        glEnable(GL_BLEND);
+        glBlendFunc(sourceMode, gBlends[mode].dst);
     }
 
-    // TODO: Try to disable blending when the texture is opaque and alpha == 1.0f
-    glEnable(GL_BLEND);
-    glBlendFunc(sourceMode, gBlends[mode].dst);
-
     glBindTexture(GL_TEXTURE_2D, texture);
 
+    // TODO handle tiling and filtering here
+
     glActiveTexture(GL_TEXTURE0);
     glUniform1i(mDrawTextureShader->sampler, 0);
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e5cc98c..965188f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -102,7 +102,7 @@
     bool quickReject(float left, float top, float right, float bottom);
     bool clipRect(float left, float top, float right, float bottom);
 
-    void drawBitmap(const SkBitmap* bitmap, float left, float top, const SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
     void drawColor(int color, SkXfermode::Mode mode);
     void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
 
@@ -183,10 +183,11 @@
      * @param texture The texture name to map onto the rectangle
      * @param alpha An additional translucency parameter, between 0.0f and 1.0f
      * @param mode The blending mode
+     * @param blend True if the texture contains an alpha channel
      * @param isPremultiplied Indicates whether the texture has premultiplied alpha
      */
     void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
-            float alpha, SkXfermode::Mode mode, bool isPremultiplied = false);
+            float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied = false);
 
     /**
      * Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index c3b1463..4e16507 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -41,7 +41,7 @@
     Texture* texture = mCache.get(bitmap);
     if (!texture) {
         texture = new Texture;
-        generateTexture(bitmap, texture);
+        generateTexture(bitmap, texture, false);
         mCache.put(bitmap, texture);
     } else if (bitmap->getGenerationID() != texture->generation) {
         generateTexture(bitmap, texture, true);
@@ -58,7 +58,14 @@
 }
 
 void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) {
+    SkAutoLockPixels alp(*bitmap);
+    if (!bitmap->readyToDraw()) {
+        LOGE("Cannot generate texture from bitmap");
+        return;
+    }
+
     if (!regenerate) {
+        texture->generation = bitmap->getGenerationID();
         texture->width = bitmap->width();
         texture->height = bitmap->height();
 
@@ -66,25 +73,28 @@
     }
 
     glBindTexture(GL_TEXTURE_2D, texture->id);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
+
+    switch (bitmap->getConfig()) {
+    case SkBitmap::kRGB_565_Config:
+        texture->blend = false;
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap->rowBytesAsPixels(), texture->height, 0,
+                GL_RGB, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
+        break;
+    case SkBitmap::kARGB_8888_Config:
+        texture->blend = true;
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
+        break;
+    default:
+        break;
+    }
 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-    switch (bitmap->getConfig()) {
-    case SkBitmap::kRGB_565_Config:
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, texture->width, texture->height,
-                0, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
-        break;
-    case SkBitmap::kARGB_8888_Config:
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height,
-                0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
-        break;
-    default:
-        break;
-    }
-
     glBindTexture(GL_TEXTURE_2D, 0);
 }
 
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index f9b2823..7a00c67 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -33,7 +33,7 @@
         <activity
                 android:name="LayersActivity"
                 android:label="_Layers"
-                android:theme="@android:style/Theme.Translucent">
+                android:theme="@android:style/Theme.Translucent.NoTitleBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -43,7 +43,7 @@
         <activity
                 android:name="XfermodeActivity"
                 android:label="_Xfermodes"
-                android:theme="@android:style/Theme.Translucent">
+                android:theme="@android:style/Theme.Translucent.NoTitleBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -53,7 +53,7 @@
         <activity
                 android:name="BitmapsActivity"
                 android:label="_Bitmaps"
-                android:theme="@android:style/Theme.Translucent">
+                android:theme="@android:style/Theme.Translucent.NoTitleBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java
index 85e7bf0..dfc8a71 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java
@@ -26,13 +26,24 @@
 import android.graphics.PorterDuffXfermode;
 import android.os.Bundle;
 import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.ScaleAnimation;
 
 @SuppressWarnings({"UnusedDeclaration"})
 public class BitmapsActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(new BitmapsView(this));
+        final BitmapsView view = new BitmapsView(this);
+        setContentView(view);
+        
+        ScaleAnimation a = new ScaleAnimation(1.0f, 2.0f, 1.0f, 2.0f,
+                ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
+                ScaleAnimation.RELATIVE_TO_SELF,0.5f);
+        a.setDuration(2000);
+        a.setRepeatCount(Animation.INFINITE);
+        a.setRepeatMode(Animation.REVERSE);
+        view.startAnimation(a);
     }
 
     static class BitmapsView extends View {