Add support for non-antialiased text

Change-Id: I17c073955ab94abc9b409e5fcfbc675faa07c5ba
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 3208c70..0e3e4f8 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -814,7 +814,6 @@
         SkPath* path, float hOffset, float vOffset, SkPaint* paint) {
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
 
-    paint->setAntiAlias(true);
     text = refText(text, bytesCount);
     path = refPath(path);
     paint = refPaint(paint);
@@ -833,7 +832,6 @@
         const float* positions, SkPaint* paint) {
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
 
-    paint->setAntiAlias(true);
     text = refText(text, bytesCount);
     positions = refBuffer<float>(positions, count * 2);
     paint = refPaint(paint);
@@ -851,14 +849,6 @@
         float x, float y, const float* positions, SkPaint* paint, float length) {
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
 
-    // TODO: We should probably make a copy of the paint instead of modifying
-    //       it; modifying the paint will change its generationID the first
-    //       time, which might impact caches. More investigation needed to
-    //       see if it matters.
-    //       If we make a copy, then drawTextDecorations() should *not* make
-    //       its own copy as it does right now.
-    // Beware: this needs Glyph encoding (already done on the Paint constructor)
-    paint->setAntiAlias(true);
     if (length < 0.0f) length = paint->measureText(text, bytesCount);
 
     text = refText(text, bytesCount);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 5c1eb38..97988f7 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -218,12 +218,14 @@
         cacheTexture->allocateTexture();
     }
 
-    uint8_t* cacheBuffer = cacheTexture->getTexture();
-    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
-    unsigned int stride = glyph.rowBytes();
+    // Tells us whether the glyphs is B&W (1 bit per pixel)
+    // or anti-aliased (8 bits per pixel)
+    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
 
+    uint8_t* cacheBuffer = cacheTexture->getTexture();
     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
 
+    // Zero out the borders
     for (cacheX = startX - TEXTURE_BORDER_SIZE; cacheX < endX + TEXTURE_BORDER_SIZE; cacheX++) {
         cacheBuffer[(startY - TEXTURE_BORDER_SIZE) * cacheWidth + cacheX] = 0;
         cacheBuffer[(endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + cacheX] = 0;
@@ -235,20 +237,49 @@
         cacheBuffer[cacheY * cacheWidth + endX + TEXTURE_BORDER_SIZE - 1] = 0;
     }
 
-    if (mGammaTable) {
-        for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
-            for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
-                uint8_t tempCol = bitmapBuffer[bY * stride + bX];
-                cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
+    // Copy the glyph image, taking the mask format into account
+    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
+    int stride = glyph.rowBytes();
+
+    switch (format) {
+        case SkMask::kA8_Format: {
+            if (mGammaTable) {
+                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
+                    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
+                        uint8_t tempCol = bitmapBuffer[bY + bX];
+                        cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
+                    }
+                }
+            } else {
+                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
+                    memcpy(&cacheBuffer[cacheY * cacheWidth + startX], &bitmapBuffer[bY],
+                            glyph.fWidth);
+                }
             }
+            break;
         }
-    } else {
-        for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
-            for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
-                uint8_t tempCol = bitmapBuffer[bY * stride + bX];
-                cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol;
+        case SkMask::kBW_Format: {
+            static const uint8_t COLORS[2] = { 0, 255 };
+
+            for (cacheY = startY; cacheY < endY; cacheY++) {
+                cacheX = startX;
+                int rowBytes = stride;
+                uint8_t* buffer = bitmapBuffer;
+
+                while (--rowBytes >= 0) {
+                    uint8_t b = *buffer++;
+                    for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
+                        cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
+                    }
+                }
+
+                bitmapBuffer += stride;
             }
+            break;
         }
+        default:
+            ALOGW("Unkown glyph format: 0x%x", format);
+            break;
     }
 
     cachedGlyph->mIsValid = true;
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 34afe97..128e8b8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -50,6 +50,7 @@
     mScaleX = paint->getTextScaleX();
     mStyle = paint->getStyle();
     mStrokeWidth = paint->getStrokeWidth();
+    mAntiAliasing = paint->isAntiAlias();
 }
 
 Font::~Font() {
@@ -68,6 +69,7 @@
     hash = JenkinsHashMix(hash, android::hash_type(mScaleX));
     hash = JenkinsHashMix(hash, android::hash_type(mStyle));
     hash = JenkinsHashMix(hash, android::hash_type(mStrokeWidth));
+    hash = JenkinsHashMix(hash, int(mAntiAliasing));
     return JenkinsHashWhiten(hash);
 }
 
@@ -94,6 +96,9 @@
     if (lhs.mStrokeWidth < rhs.mStrokeWidth) return -1;
     if (lhs.mStrokeWidth > rhs.mStrokeWidth) return +1;
 
+    deltaInt = int(lhs.mAntiAliasing) - int(rhs.mAntiAliasing);
+    if (deltaInt != 0) return deltaInt;
+
     return 0;
 }
 
@@ -384,7 +389,9 @@
     uint32_t startY = 0;
 
     // Get the bitmap for the glyph
-    paint->findImage(skiaGlyph, NULL);
+    if (!skiaGlyph.fImage) {
+        paint->findImage(skiaGlyph, NULL);
+    }
     mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
 
     if (!glyph->mIsValid) {
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 6ddf162..7a64a67 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -68,6 +68,7 @@
         float mScaleX;
         uint8_t mStyle;
         float mStrokeWidth;
+        bool mAntiAliasing;
     };
 
     ~Font();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 57ce1d6..14d1058 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -42,6 +42,15 @@
         </activity>
 
         <activity
+                android:name="NoAATextActivity"
+                android:label="_NoAAText">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="ScaledPathsActivity"
                 android:label="_ScaledPaths">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/NoAATextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/NoAATextActivity.java
new file mode 100644
index 0000000..5bd2f583
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/NoAATextActivity.java
@@ -0,0 +1,57 @@
+/*
+ * 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.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class NoAATextActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final ScaledNoAA view = new ScaledNoAA(this);
+        setContentView(view);
+    }
+
+    public static class ScaledNoAA extends View {
+        private static final String TEXT = "Hello libhwui!";
+
+        private final Paint mPaint;
+
+        public ScaledNoAA(Context c) {
+            super(c);
+
+            mPaint = new Paint();
+            mPaint.setTextSize(60.0f);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.drawARGB(255, 255, 255, 255);
+            canvas.drawText(TEXT, 30.0f, 150.0f, mPaint);
+        }
+    }
+}