suport A8 grayscale text with COLOR_LUMINANCE build option



git-svn-id: http://skia.googlecode.com/svn/trunk@3197 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 86bc49e..3b9714e 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1302,13 +1302,29 @@
     return c;
 }
 
+#define assert_byte(x)  SkASSERT(0 == ((x) >> 8))
+
 static U8CPU reduce_lumbits(U8CPU x) {
     static const uint8_t gReduceBits[] = {
         0x0, 0x55, 0xAA, 0xFF
     };
+    assert_byte(x);
     return gReduceBits[x >> 6];
 }
 
+static unsigned computeLuminance(SkColor c) {
+    int r = SkColorGetR(c);
+    int g = SkColorGetG(c);
+    int b = SkColorGetB(c);
+    // compute luminance
+    // R=0.2126 G=0.7152 B=0.0722
+    // scaling by 127 yields 27, 92, 9
+    int luminance = r * 27 + g * 92 + b * 9;
+    luminance >>= 7;
+    assert_byte(luminance);
+    return luminance;
+}
+
 #else
 // returns 0..kLuminance_Max
 static unsigned computeLuminance(const SkPaint& paint) {
@@ -1477,22 +1493,38 @@
      */
     SkFontHost::FilterRec(rec);
 
-    // No need to differentiate gamma if we're BW
-    if (SkMask::kBW_Format == rec->fMaskFormat) {
+    switch (rec->fMaskFormat) {
+        case SkMask::kLCD16_Format:
+        case SkMask::kLCD32_Format: {
 #ifdef SK_USE_COLOR_LUMINANCE
-        rec->setLuminanceColor(0);
+            // filter down the luminance color to a finite number of bits
+            SkColor c = rec->getLuminanceColor();
+            c = SkColorSetRGB(reduce_lumbits(SkColorGetR(c)),
+                              reduce_lumbits(SkColorGetG(c)),
+                              reduce_lumbits(SkColorGetB(c)));
+            rec->setLuminanceColor(c);
+#endif
+            break;
+        }
+        case SkMask::kA8_Format: {
+#ifdef SK_USE_COLOR_LUMINANCE
+            // filter down the luminance to a single component, since A8 can't
+            // use per-component information
+            unsigned lum = computeLuminance(rec->getLuminanceColor());
+            // reduce to our finite number of bits
+            lum = reduce_lumbits(lum);
+            rec->setLuminanceColor(SkColorSetRGB(lum, lum, lum));
+#endif
+            break;
+        }
+        case SkMask::kBW_Format:
+            // No need to differentiate gamma if we're BW
+#ifdef SK_USE_COLOR_LUMINANCE
+            rec->setLuminanceColor(0);
 #else
-        rec->setLuminanceBits(0);
+            rec->setLuminanceBits(0);
 #endif
-    } else {
-#ifdef SK_USE_COLOR_LUMINANCE
-        // filter down the luminance color to a finite number of bits
-        SkColor c = rec->getLuminanceColor();
-        c = SkColorSetRGB(reduce_lumbits(SkColorGetR(c)),
-                          reduce_lumbits(SkColorGetG(c)),
-                          reduce_lumbits(SkColorGetB(c)));
-        rec->setLuminanceColor(c);
-#endif
+            break;
     }
 }
 
diff --git a/src/ports/SkFontHost_mac_coretext.cpp b/src/ports/SkFontHost_mac_coretext.cpp
index 19b91ad..e5fedc1 100644
--- a/src/ports/SkFontHost_mac_coretext.cpp
+++ b/src/ports/SkFontHost_mac_coretext.cpp
@@ -1081,6 +1081,28 @@
     return isWhite ? gWhiteTable : gTable;
 }
 
+static const uint8_t* getGammaTable(U8CPU luminance) {
+    static uint8_t gGammaTables[4][256];
+    static bool gInited;
+    if (!gInited) {
+#if 1
+        float start = 1.1;
+        float stop = 2.1;
+        for (int i = 0; i < 4; ++i) {
+            float g = start + (stop - start) * i / 3;
+            build_power_table(gGammaTables[i], 1/g);
+        }
+#else
+        build_power_table(gGammaTables[0], 1);
+        build_power_table(gGammaTables[1], 1);
+        build_power_table(gGammaTables[2], 1);
+        build_power_table(gGammaTables[3], 1);
+#endif
+        gInited = true;
+    }
+    SkASSERT(0 == (luminance >> 8));
+    return gGammaTables[luminance >> 6];
+}
 
 static void invertGammaMask(bool isWhite, CGRGBPixel rgb[], int width,
                             int height, size_t rb) {
@@ -1197,9 +1219,18 @@
 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
     CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
 
+    const bool isLCD = isLCDFormat(glyph.fMaskFormat);
+    const bool isBW = SkMask::kBW_Format == glyph.fMaskFormat;
+    const bool isA8 = !isLCD && !isBW;
+    
 #ifdef SK_USE_COLOR_LUMINANCE
     unsigned lumBits = fRec.getLuminanceColor();
     uint32_t xorMask = 0;
+
+    if (isA8) {
+        // for A8, we just want a component (they're all the same)
+        lumBits = SkColorGetR(lumBits);
+    }
 #else
     bool fgColorIsWhite = true;
     bool isWhite = fRec.getLuminanceByte() >= WHITE_LUMINANCE_LIMIT;
@@ -1212,7 +1243,7 @@
      *  extract the r,g,b values, invert-them, and now we have the original
      *  src mask components, which we pack into our 16bit mask.
      */
-    if (isLCDFormat(glyph.fMaskFormat)) {
+    if (isLCD) {
         if (isBlack) {
             xorMask = ~0;
             fgColorIsWhite = false;
@@ -1226,19 +1257,15 @@
     size_t cgRowBytes;
 #ifdef SK_USE_COLOR_LUMINANCE
     CGRGBPixel* cgPixels;
+    const uint8_t* gammaTable = NULL;
     
-    //  If we're gray or lum==max, we just want WHITE
-    //  If lum is 0 we just want BLACK
-    //  Else lerp
-
-    {
-        bool isLCD = isLCDFormat(glyph.fMaskFormat);
+    if (isLCD) {
         CGRGBPixel* wtPixels = NULL;
         CGRGBPixel* bkPixels = NULL;
         bool needBlack = true;
         bool needWhite = true;
 
-        if (!isLCD || (SK_ColorWHITE == lumBits)) {
+        if (SK_ColorWHITE == lumBits) {
             needBlack = false;
         } else if (SK_ColorBLACK == lumBits) {
             needWhite = false;
@@ -1257,11 +1284,12 @@
 
         if (wtPixels && bkPixels) {
             lerpPixels(wtPixels, bkPixels, glyph.fWidth, glyph.fHeight, cgRowBytes,
-#ifdef SK_USE_COLOR_LUMINANCE
                        ~lumBits);
-#else
-                       SkScalerContext::kLuminance_Max - lumBits);
-#endif
+        }
+    } else {    // isA8 or isBW
+        cgPixels = fWhiteScreen.getCG(*this, glyph, true, cgGlyph, &cgRowBytes);
+        if (isA8) {
+            gammaTable = getGammaTable(lumBits);
         }
     }
 #else
@@ -1310,7 +1338,11 @@
                 size_t dstRB = glyph.rowBytes();
                 for (int y = 0; y < glyph.fHeight; y++) {
                     for (int i = 0; i < width; ++i) {
-                        dst[i] = CGRGBPixel_getAlpha(cgPixels[i]);
+                        unsigned alpha8 = CGRGBPixel_getAlpha(cgPixels[i]);
+#ifdef SK_USE_COLOR_LUMINANCE
+                        alpha8 = gammaTable[alpha8];
+#endif
+                        dst[i] = alpha8;
                     }
                     cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
                     dst += dstRB;
@@ -1801,7 +1833,7 @@
     rec->setHinting(h);
 
 #ifdef SK_USE_COLOR_LUMINANCE
-    {
+    if (isLCDFormat(rec->fMaskFormat)) {
         SkColor c = rec->getLuminanceColor();
         // apply our chosen scaling between Black and White cg output
         int r = SkColorGetR(c)*2/3;