Merge "Antialiasing for rectangles"
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 80a7bed..5a86fe3 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1458,6 +1458,79 @@
 }
 
 /**
+ * This function uses a similar approach to that of AA lines in the drawLines() function.
+ * We expand the rectangle by a half pixel in screen space on all sides, and use a fragment
+ * shader to compute the translucency of the color, determined by whether a given pixel is
+ * within that boundary region and how far into the region it is.
+ */
+void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom,
+        int color, SkXfermode::Mode mode)
+{
+    float inverseScaleX = 1.0f;
+    float inverseScaleY = 1.0f;
+    // The quad that we use needs to account for scaling.
+    if (!mSnapshot->transform->isPureTranslate()) {
+        Matrix4 *mat = mSnapshot->transform;
+        float m00 = mat->data[Matrix4::kScaleX];
+        float m01 = mat->data[Matrix4::kSkewY];
+        float m02 = mat->data[2];
+        float m10 = mat->data[Matrix4::kSkewX];
+        float m11 = mat->data[Matrix4::kScaleX];
+        float m12 = mat->data[6];
+        float scaleX = sqrt(m00 * m00 + m01 * m01);
+        float scaleY = sqrt(m10 * m10 + m11 * m11);
+        inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
+        inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
+    }
+
+    setupDraw();
+    setupDrawAALine();
+    setupDrawColor(color);
+    setupDrawColorFilter();
+    setupDrawShader();
+    setupDrawBlending(true, mode);
+    setupDrawProgram();
+    setupDrawModelViewIdentity(true);
+    setupDrawColorUniforms();
+    setupDrawColorFilterUniforms();
+    setupDrawShaderIdentityUniforms();
+
+    AAVertex rects[4];
+    AAVertex* aaVertices = &rects[0];
+    void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
+    void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
+
+    float boundarySizeX = .5 * inverseScaleX;
+    float boundarySizeY = .5 * inverseScaleY;
+
+    // Adjust the rect by the AA boundary padding
+    left -= boundarySizeX;
+    right += boundarySizeX;
+    top -= boundarySizeY;
+    bottom += boundarySizeY;
+
+    float width = right - left;
+    float height = bottom - top;
+
+    float boundaryWidthProportion = (width != 0) ? (2 * boundarySizeX) / width : 0;
+    float boundaryHeightProportion = (height != 0) ? (2 * boundarySizeY) / height : 0;
+    setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, boundaryWidthProportion);
+    int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
+    int inverseBoundaryLengthSlot = mCaches.currentProgram->getUniform("inverseBoundaryLength");
+    glUniform1f(boundaryLengthSlot, boundaryHeightProportion);
+    glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryHeightProportion));
+
+    if (!quickReject(left, top, right, bottom)) {
+        AAVertex::set(aaVertices++, left, bottom, 1, 1);
+        AAVertex::set(aaVertices++, left, top, 1, 0);
+        AAVertex::set(aaVertices++, right, bottom, 0, 1);
+        AAVertex::set(aaVertices++, right, top, 0, 0);
+        dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    }
+}
+
+/**
  * We draw lines as quads (tristrips). Using GL_LINES can be difficult because the rasterization
  * rules for those lines produces some unexpected results, and may vary between hardware devices.
  * The basics of lines-as-quads is easy; we simply find the normal to the line and position the
@@ -1848,7 +1921,11 @@
     }
 
     int color = p->getColor();
-    drawColorRect(left, top, right, bottom, color, mode);
+    if (p->isAntiAlias()) {
+        drawAARect(left, top, right, bottom, color, mode);
+    } else {
+        drawColorRect(left, top, right, bottom, color, mode);
+    }
 }
 
 void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 271e4b1..ffacbfc 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -285,6 +285,9 @@
 
     void drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint);
 
+    void drawAARect(float left, float top, float right, float bottom,
+            int color, SkXfermode::Mode mode);
+
     /**
      * Draws a textured rectangle with the specified texture. The specified coordinates
      * are transformed by the current snapshot's transform matrix.
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 6285880..c1aa215 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -93,6 +93,15 @@
         </activity>
         
         <activity
+                android:name="ColoredRectsActivity"
+                android:label="_Rects">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="SimplePatchActivity"
                 android:label="_SimplePatch"
                 android:theme="@android:style/Theme.Translucent.NoTitleBar">
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
new file mode 100644
index 0000000..e8cdbc3
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 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.android.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ColoredRectsActivity extends Activity {
+    private ObjectAnimator mAnimator;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
+        FrameLayout frame = new FrameLayout(this);
+        final RectsView gpuView = new RectsView(this, 0, Color.GREEN);
+        frame.addView(gpuView);
+        final RectsView swView = new RectsView(this, 400, Color.RED);
+        swView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+        frame.addView(swView);
+        final RectsView hwBothView = new RectsView(this, 850, Color.GREEN);
+        // Don't actually need to render to a hw layer, but it's a good sanity-check that
+        // we're rendering to/from layers correctly
+        hwBothView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        frame.addView(hwBothView);
+        final RectsView swBothView = new RectsView(this, 854, Color.RED);
+        swBothView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+        frame.addView(swBothView);
+        setContentView(frame);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+    }
+
+    public static class RectsView extends View {
+
+        private float mOffset;
+        private int mColor;
+
+        public RectsView(Context c, float offset, int color) {
+            super(c);
+            mOffset = offset;
+            mColor = color;
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            Paint p = new Paint();
+            p.setColor(mColor);
+            float yOffset = 10;
+
+            for (int i = 0; i < 2; ++i) {
+                canvas.save();
+                canvas.translate(mOffset, yOffset);
+                canvas.drawRect(0, 0, 20, 10, p);
+                canvas.drawRect(35, 0, 45, 20, p);
+                canvas.translate(0, -yOffset);
+                canvas.scale(2, 2);
+                canvas.translate(60, yOffset/2);
+                canvas.drawRect(0, 0, 20, 10, p);
+                canvas.translate(15, 0);
+                canvas.drawRect(35, 0, 45, 20, p);
+                canvas.restore();
+
+                yOffset += 100;
+
+                canvas.save();
+                canvas.save();
+                canvas.translate(mOffset + 10, yOffset);
+                canvas.rotate(45);
+                canvas.drawRect(0, 0, 20, 10, p);
+                canvas.restore();
+                canvas.save();
+                canvas.translate(mOffset + 70, yOffset);
+                canvas.rotate(5);
+                canvas.drawRect(0, 0, 20, 10, p);
+                canvas.restore();
+                canvas.save();
+                canvas.translate(mOffset + 140, yOffset);
+                canvas.scale(2, 2);
+                canvas.rotate(5);
+                canvas.drawRect(0, 0, 20, 10, p);
+                canvas.restore();
+                canvas.save();
+                canvas.translate(mOffset + 210, yOffset);
+                canvas.scale(2, 2);
+                canvas.rotate(45);
+                canvas.drawRect(0, 0, 20, 10, p);
+                canvas.restore();
+                canvas.restore();
+
+                yOffset += 100;
+
+                p.setAntiAlias(true);
+            }
+        }
+    }
+}