enable color-luminance in font cache (disabled by default)
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 10 Feb 2012 22:01:45 +0000 (22:01 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 10 Feb 2012 22:01:45 +0000 (22:01 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@3168 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkScalerContext.h
src/core/SkPaint.cpp
src/ports/SkFontHost_mac_coretext.cpp

index b2f6a57..7a83bd7 100644 (file)
@@ -16,6 +16,9 @@
 #include "SkPath.h"
 #include "SkPoint.h"
 
+//#define SK_USE_COLOR_LUMINANCE
+//#define USE_FULL_LUMI
+
 class SkDescriptor;
 class SkMaskFilter;
 class SkPathEffect;
@@ -154,8 +157,6 @@ struct SkGlyph {
     void toMask(SkMask* mask) const;
 };
 
-//#define USE_NEW_LUMINANCE
-
 class SkScalerContext {
 public:
     enum Flags {
@@ -181,7 +182,7 @@ public:
         // Perhaps we can store this (instead) in fMaskFormat, in hight bit?
         kGenA8FromLCD_Flag        = 0x0800,
 
-#ifdef USE_NEW_LUMINANCE
+#ifdef SK_USE_COLOR_LUMINANCE
         kLuminance_Bits           = 3,
 #else
         // luminance : 0 for black text, kLuminance_Max for white text
@@ -193,8 +194,9 @@ public:
     // computed values
     enum {
         kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
+#ifdef SK_USE_COLOR_LUMINANCE
+#else
         kLuminance_Max  = (1 << kLuminance_Bits) - 1,
-#ifndef USE_NEW_LUMINANCE
         kLuminance_Mask = kLuminance_Max << kLuminance_Shift,
 #endif
     };
@@ -205,7 +207,7 @@ public:
         SkScalar    fTextSize, fPreScaleX, fPreSkewX;
         SkScalar    fPost2x2[2][2];
         SkScalar    fFrameWidth, fMiterLimit;
-#ifdef USE_NEW_LUMINANCE
+#ifdef SK_USE_COLOR_LUMINANCE
         uint32_t    fLumBits;
 #endif
         uint8_t     fMaskFormat;
@@ -233,14 +235,35 @@ public:
             return static_cast<SkMask::Format>(fMaskFormat);
         }
         
-#ifdef USE_NEW_LUMINANCE
-        unsigned getLuminanceBits() const {
+#ifdef SK_USE_COLOR_LUMINANCE
+        static unsigned ColorToLumBits(U8CPU x) {
+            SkASSERT(x <= 0xFF);
+            return x >> 7;
+        }
+        static U8CPU LumBitsToColor(unsigned x) {
+            SkASSERT(x <= 1);
+            return x * 0xFF;
+        }
+
+        SkColor getLuminanceColor() const {
+#ifdef USE_FULL_LUMI
             return fLumBits;
+#else
+            unsigned bits = fLumBits;
+            return SkColorSetRGB(LumBitsToColor((bits >> 2) & 1),
+                                 LumBitsToColor((bits >> 1) & 1),
+                                 LumBitsToColor((bits >> 0) & 1));
+#endif
         }
         
-        void setLuminanceBits(unsigned lum) {
-            SkASSERT(lum <= kLuminance_Max);
-            fLumBits = lum;
+        void setLuminanceColor(SkColor c) {
+#ifdef USE_FULL_LUMI
+            fLumBits = c;
+#else
+            fLumBits =  (ColorToLumBits(SkColorGetR(c)) << 2) |
+                        (ColorToLumBits(SkColorGetG(c)) << 1) |
+                        (ColorToLumBits(SkColorGetB(c)) << 0);
+#endif
         }
 #else
         unsigned getLuminanceBits() const {
@@ -251,7 +274,6 @@ public:
             SkASSERT(lum <= kLuminance_Max);
             fFlags = (fFlags & ~kLuminance_Mask) | (lum << kLuminance_Shift);
         }
-#endif
 
         U8CPU getLuminanceByte() const {
             SkASSERT(3 == kLuminance_Bits);
@@ -260,6 +282,7 @@ public:
             lum |= (lum << kLuminance_Bits*2);
             return lum >> (4*kLuminance_Bits - 8);
         }
+#endif
     };
 
     SkScalerContext(const SkDescriptor* desc);
index 7d418f4..4026acb 100644 (file)
@@ -1293,6 +1293,15 @@ static bool justAColor(const SkPaint& paint, SkColor* color) {
     return true;
 }
 
+#ifdef SK_USE_COLOR_LUMINANCE
+static SkColor computeLuminanceColor(const SkPaint& paint) {
+    SkColor c;
+    if (!justAColor(paint, &c)) {
+        c = SkColorSetRGB(0x7F, 0x80, 0x7F);
+    }
+    return c;
+}
+#else
 // returns 0..kLuminance_Max
 static unsigned computeLuminance(const SkPaint& paint) {
     SkColor c;
@@ -1316,6 +1325,7 @@ static unsigned computeLuminance(const SkPaint& paint) {
     // if we're not a single color, return the middle of the luminance range
     return SkScalerContext::kLuminance_Max >> 1;
 }
+#endif
 
 // Beyond this size, LCD doesn't appreciably improve quality, but it always
 // cost more RAM and draws slower, so we set a cap.
@@ -1446,7 +1456,11 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
 
     // these modify fFlags, so do them after assigning fFlags
     rec->setHinting(computeHinting(paint));
+#ifdef SK_USE_COLOR_LUMINANCE
+    rec->setLuminanceColor(computeLuminanceColor(paint));
+#else
     rec->setLuminanceBits(computeLuminance(paint));
+#endif
 
     /*  Allow the fonthost to modify our rec before we use it as a key into the
         cache. This way if we're asking for something that they will ignore,
@@ -1457,7 +1471,11 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
 
     // No need to differentiate gamma if we're BW
     if (SkMask::kBW_Format == rec->fMaskFormat) {
+#ifdef SK_USE_COLOR_LUMINANCE
+        rec->setLuminanceColor(0);
+#else
         rec->setLuminanceBits(0);
+#endif
     }
 }
 
@@ -1481,7 +1499,11 @@ void SkPaint::descriptorProc(const SkMatrix* deviceMatrix,
 
     SkScalerContext::MakeRec(*this, deviceMatrix, &rec);
     if (ignoreGamma) {
+#ifdef SK_USE_COLOR_LUMINANCE
+        rec.setLuminanceColor(0);
+#else
         rec.setLuminanceBits(0);
+#endif
     }
 
     size_t          descSize = sizeof(rec);
index 9c69ed7..0500508 100644 (file)
@@ -132,7 +132,7 @@ static void sk_memset_rect(void* ptr, U8CPU byte, size_t width, size_t height,
 typedef uint32_t CGRGBPixel;
 
 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
-    return pixel >> 24;
+    return pixel & 0xFF;
 }
 
 // The calls to support subpixel are present in 10.5, but are not included in
@@ -593,7 +593,12 @@ private:
     SkMatrix                            fVerticalMatrix; // unit rotated
     SkMatrix                            fMatrix; // with font size
     SkMatrix                            fAdjustBadMatrix; // lion-specific fix
+#ifdef SK_USE_COLOR_LUMINANCE
+    Offscreen                           fBlackScreen;
+    Offscreen                           fWhiteScreen;
+#else
     Offscreen                           fOffscreen;
+#endif
     CTFontRef                           fCTFont;
     CTFontRef                           fCTVerticalFont; // for vertical advance
     CGFontRef                           fCGFont;
@@ -1052,7 +1057,7 @@ static void build_power_table(uint8_t table[], float ee) {
     for (int i = 0; i < 256; i++) {
         float x = i / 255.f;
         x = powf(x, ee);
-        int xx = SkScalarRound(SkFloatToScalar(x * 255));
+        int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255));
         table[i] = SkToU8(xx);
     }
 }
@@ -1069,6 +1074,7 @@ static const uint8_t* getInverseTable(bool isWhite) {
     return isWhite ? gWhiteTable : gTable;
 }
 
+
 static void invertGammaMask(bool isWhite, CGRGBPixel rgb[], int width,
                             int height, size_t rb) {
     const uint8_t* table = getInverseTable(isWhite);
@@ -1097,6 +1103,49 @@ static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
     }
 }
 
+static int lerpScale(int dst, int src, int scale) {
+    return dst + (scale * (src - dst) >> 23);
+}
+
+static CGRGBPixel lerpPixel(CGRGBPixel dst, CGRGBPixel src,
+                            int scaleR, int scaleG, int scaleB) {
+    int sr = (src >> 16) & 0xFF;
+    int sg = (src >>  8) & 0xFF;
+    int sb = (src >>  0) & 0xFF;
+    int dr = (dst >> 16) & 0xFF;
+    int dg = (dst >>  8) & 0xFF;
+    int db = (dst >>  0) & 0xFF;
+
+    int rr = lerpScale(dr, sr, scaleR);
+    int rg = lerpScale(dg, sg, scaleG);
+    int rb = lerpScale(db, sb, scaleB);
+    return (rr << 16) | (rg << 8) | rb;
+}
+
+static void lerpPixels(CGRGBPixel dst[], const CGRGBPixel src[], int width,
+                       int height, int rowBytes, int lumBits) {
+#ifdef SK_USE_COLOR_LUMINANCE
+    int scaleR = (1 << 23) * SkColorGetR(lumBits) / 0xFF;
+    int scaleG = (1 << 23) * SkColorGetG(lumBits) / 0xFF;
+    int scaleB = (1 << 23) * SkColorGetB(lumBits) / 0xFF;
+#else
+    int scale = (1 << 23) * lumBits / SkScalerContext::kLuminance_Max;
+    int scaleR = scale;
+    int scaleG = scale;
+    int scaleB = scale;
+#endif
+
+    for (int y = 0; y < height; ++y) {
+        for (int x = 0; x < width; ++x) {
+            // bit-not the src, since it was drawn from black, so we need the
+            // compliment of those bits
+            dst[x] = lerpPixel(dst[x], ~src[x], scaleR, scaleG, scaleB);
+        }
+        src = (CGRGBPixel*)((char*)src + rowBytes);
+        dst = (CGRGBPixel*)((char*)dst + rowBytes);
+    }
+}
+
 #if 1
 static inline int r32_to_16(int x) { return SkR32ToR16(x); }
 static inline int g32_to_16(int x) { return SkG32ToG16(x); }
@@ -1141,6 +1190,10 @@ static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb) {
 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
     CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
 
+#ifdef SK_USE_COLOR_LUMINANCE
+    unsigned lumBits = fRec.getLuminanceColor();
+    uint32_t xorMask = 0;
+#else
     bool fgColorIsWhite = true;
     bool isWhite = fRec.getLuminanceByte() >= WHITE_LUMINANCE_LIMIT;
     bool isBlack = fRec.getLuminanceByte() <= BLACK_LUMINANCE_LIMIT;
@@ -1161,18 +1214,64 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
             invertGamma = true;
         }
     }
+#endif
 
     size_t cgRowBytes;
+#ifdef SK_USE_COLOR_LUMINANCE
+    CGRGBPixel* cgPixels;
+    
+    //  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);
+        CGRGBPixel* wtPixels = NULL;
+        CGRGBPixel* bkPixels = NULL;
+        bool needBlack = true;
+        bool needWhite = true;
+        
+        if (!isLCD || (SK_ColorWHITE == lumBits)) {
+            needBlack = false;
+        } else if (SK_ColorBLACK == lumBits) {
+            needWhite = false;
+        }
+
+        if (needBlack) {
+            bkPixels = fBlackScreen.getCG(*this, glyph, false, cgGlyph, &cgRowBytes);
+            cgPixels = bkPixels;
+            xorMask = ~0;
+        }
+        if (needWhite) {
+            wtPixels = fWhiteScreen.getCG(*this, glyph, true, cgGlyph, &cgRowBytes);
+            cgPixels = wtPixels;
+            xorMask = 0;
+        }
+
+        if (wtPixels && bkPixels) {
+            lerpPixels(wtPixels, bkPixels, glyph.fWidth, glyph.fHeight, cgRowBytes,
+#ifdef SK_USE_COLOR_LUMINANCE
+                       ~lumBits);
+#else
+                       SkScalerContext::kLuminance_Max - lumBits);
+#endif
+        }
+    }
+#else
     CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, fgColorIsWhite, cgGlyph,
                                             &cgRowBytes);
+#endif
 
     // Draw the glyph
     if (cgPixels != NULL) {
 
+#ifdef SK_USE_COLOR_LUMINANCE
+#else
         if (invertGamma) {
             invertGammaMask(isWhite, (uint32_t*)cgPixels,
                             glyph.fWidth, glyph.fHeight, cgRowBytes);
         }
+#endif
 
         int width = glyph.fWidth;
         switch (glyph.fMaskFormat) {
@@ -1697,6 +1796,7 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
     // for compatibility at the moment, discretize luminance to 3 settings
     // black, white, gray. This helps with fontcache utilization, since we
     // won't create multiple entries that in the end map to the same results.
+#ifndef SK_USE_COLOR_LUMINANCE
     {
         unsigned lum = rec->getLuminanceByte();
         if (lum <= BLACK_LUMINANCE_LIMIT) {
@@ -1708,7 +1808,8 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
         }
         rec->setLuminanceBits(lum);
     }
-    
+#endif
+
     if (SkMask::kLCD16_Format == rec->fMaskFormat
             || SkMask::kLCD32_Format == rec->fMaskFormat) {
         if (supports_LCD()) {