Add support for 8 bits/component glyphs, to
authorcaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 22 Jun 2011 13:19:43 +0000 (13:19 +0000)
committercaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 22 Jun 2011 13:19:43 +0000 (13:19 +0000)
better match the fonts produced by CoreText on OS/X.

M    include/config/SkUserConfig.h
M    include/core/SkMask.h
M    include/core/SkScalerContext.h
M    src/core/SkBlitter_ARGB32.cpp
M    src/core/SkScalerContext.cpp
M    src/core/SkPaint.cpp
M    src/gpu/SkGrFontScaler.cpp
M    src/ports/SkFontHost_mac_coretext.cpp
M    src/ports/SkFontHost_mac.cpp
M    gpu/include/GrTypes.h
M    gpu/src/GrAtlas.cpp

git-svn-id: http://skia.googlecode.com/svn/trunk@1672 2bbb7eff-a529-9590-31e7-b0007b416f81

gpu/include/GrTypes.h
gpu/src/GrAtlas.cpp
include/config/SkUserConfig.h
include/core/SkMask.h
include/core/SkScalerContext.h
src/core/SkBlitter_ARGB32.cpp
src/core/SkPaint.cpp
src/core/SkScalerContext.cpp
src/gpu/SkGrFontScaler.cpp
src/ports/SkFontHost_mac.cpp
src/ports/SkFontHost_mac_coretext.cpp

index 76e01b0..2bf4b09 100644 (file)
@@ -247,10 +247,12 @@ enum GrBlendCoeff {
  *  Important that these are 0-based.
  */
 enum GrMaskFormat {
-    kA8_GrMaskFormat,   //!< 1-byte per pixel
-    kA565_GrMaskFormat  //!< 2-bytes per pixel
+    kA8_GrMaskFormat,    //!< 1-byte per pixel
+    kA565_GrMaskFormat,  //!< 2-bytes per pixel
+    kA888_GrMaskFormat,  //!< 4-bytes per pixel
+
+    kCount_GrMaskFormats //!< used to allocate arrays sized for mask formats
 };
-#define kCount_GrMaskFormats    2
 
 /**
  *  Return the number of bytes-per-pixel for the specified mask format.
index e577beb..480a307 100644 (file)
@@ -148,6 +148,8 @@ static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
             return kAlpha_8_GrPixelConfig;
         case kA565_GrMaskFormat:
             return kRGB_565_GrPixelConfig;
+        case kA888_GrMaskFormat:
+            return kRGBA_8888_GrPixelConfig;
         default:
             GrAssert(!"unknown maskformat");
     }
index c56d8cf..80ecdb6 100644 (file)
  */
 //#define SK_SUPPORT_LCDTEXT
 
+/* Define this to pack glyphs using 8 bits per component instead of 5-6-5.
+   This will double the size of the font cache, but will produce fonts with
+   gray levels closer to the designer's intent.
+*/
+//#define SK_SUPPORT_888_TEXT
+
+/* If defined, use CoreText instead of ATSUI on OS X.
+*/
+//#define SK_USE_MAC_CORE_TEXT
+
+
 /*  If zlib is available and you want to support the flate compression
     algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the
     include path.
index f437622..ac495fc 100644 (file)
@@ -47,7 +47,8 @@ struct SkMask {
         kHorizontalLCD_Format,  //!< 4 bytes/pixel: a/r/g/b
         kVerticalLCD_Format,    //!< 4 bytes/pixel: a/r/g/b
         kARGB32_Format,         //!< SkPMColor
-        kLCD16_Format           //!< 565 alpha for r/g/b
+        kLCD16_Format,          //!< 565 alpha for r/g/b
+        kLCD32_Format           //!< 888 alpha for r/g/b
     };
 
     enum {
@@ -110,6 +111,19 @@ struct SkMask {
         return row + (x - fBounds.fLeft);
     }
 
+    /**
+     *  Return the address of the specified 32bit mask. In the debug build,
+     *  this asserts that the mask's format is kLCD32_Format, and that (x,y)
+     *  are contained in the mask's fBounds.
+     */
+    uint32_t* getAddrLCD32(int x, int y) const {
+        SkASSERT(kLCD32_Format == fFormat);
+        SkASSERT(fBounds.contains(x, y));
+        SkASSERT(fImage != NULL);
+        uint32_t* row = (uint32_t*)(fImage + (y - fBounds.fTop) * fRowBytes);
+        return row + (x - fBounds.fLeft);
+    }
+
     /** Return an address into the 32-bit plane of an LCD or VerticalLCD mask
         for the given position.
     */
index cbbbdf0..d7b5eec 100644 (file)
@@ -60,7 +60,9 @@ struct SkGlyph {
         unsigned rb = width;
         if (SkMask::kBW_Format == format) {
             rb = (rb + 7) >> 3;
-               } else if (SkMask::kARGB32_Format == format) {
+               } else if (SkMask::kARGB32_Format == format ||
+                   SkMask::kLCD32_Format == format)
+        {
                        rb <<= 2;
                } else if (SkMask::kLCD16_Format == format) {
                        rb = SkAlign4(rb << 1);
index dec355a..1901937 100644 (file)
@@ -92,6 +92,43 @@ static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[],
     }
 }
 
+static void blit_lcd32_opaque(SkPMColor dst[], const uint32_t src[],
+                              SkPMColor color, int width) {
+    int srcR = SkGetPackedR32(color);
+    int srcG = SkGetPackedG32(color);
+    int srcB = SkGetPackedB32(color);
+
+    for (int i = 0; i < width; i++) {
+        uint32_t mask = src[i];
+        if (0 == mask) {
+            continue;
+        }
+
+        SkPMColor d = dst[i];
+        
+        int maskR = SkGetPackedR32(mask);
+        int maskG = SkGetPackedG32(mask);
+        int maskB = SkGetPackedB32(mask);
+
+        // Now upscale them to 0..256, so we can use SkAlphaBlend
+        maskR = SkAlpha255To256(maskR);
+        maskG = SkAlpha255To256(maskG);
+        maskB = SkAlpha255To256(maskB);
+
+        int maskA = SkMax32(SkMax32(maskR, maskG), maskB);
+
+        int dstA = SkGetPackedA32(d);
+        int dstR = SkGetPackedR32(d);
+        int dstG = SkGetPackedG32(d);
+        int dstB = SkGetPackedB32(d);
+
+        dst[i] = SkPackARGB32(SkAlphaBlend(0xFF, dstA, maskA),
+                              SkAlphaBlend(srcR, dstR, maskR),
+                              SkAlphaBlend(srcG, dstG, maskG),
+                              SkAlphaBlend(srcB, dstB, maskB));
+    }
+}
+
 static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask,
                            const SkIRect& clip, SkPMColor srcColor) {
     int x = clip.fLeft;
@@ -109,6 +146,23 @@ static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask,
     } while (--height != 0);
 }
 
+static void blitmask_lcd32(const SkBitmap& device, const SkMask& mask,
+                           const SkIRect& clip, SkPMColor srcColor) {
+    int x = clip.fLeft;
+    int y = clip.fTop;
+    int width = clip.width();
+    int height = clip.height();
+
+    SkPMColor*         dstRow = device.getAddr32(x, y);
+    const uint32_t* srcRow = mask.getAddrLCD32(x, y);
+
+    do {
+        blit_lcd32_opaque(dstRow, srcRow, srcColor, width);
+        dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
+        srcRow = (const uint32_t*)((const char*)srcRow + mask.fRowBytes);
+    } while (--height != 0);
+}
+
 //////////////////////////////////////////////////////////////////////////////////////
 
 static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
@@ -263,6 +317,9 @@ void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
     } else if (SkMask::kLCD16_Format == mask.fFormat) {
         blitmask_lcd16(fDevice, mask, clip, fPMColor);
         return;
+    } else if (SkMask::kLCD32_Format == mask.fFormat) {
+        blitmask_lcd32(fDevice, mask, clip, fPMColor);
+        return;
     }
 
     int x = clip.fLeft;
@@ -287,6 +344,9 @@ void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
     } else if (SkMask::kLCD16_Format == mask.fFormat) {
         blitmask_lcd16(fDevice, mask, clip, fPMColor);
         return;
+    } else if (SkMask::kLCD32_Format == mask.fFormat) {
+        blitmask_lcd32(fDevice, mask, clip, fPMColor);
+        return;
        }
 
     int x = clip.fLeft;
@@ -395,6 +455,8 @@ void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
                SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
     } else if (SkMask::kLCD16_Format == mask.fFormat) {
         blitmask_lcd16(fDevice, mask, clip, fPMColor);
+    } else if (SkMask::kLCD32_Format == mask.fFormat) {
+        blitmask_lcd32(fDevice, mask, clip, fPMColor);
     } else {
 #if defined(SK_SUPPORT_LCDTEXT)
         const bool      lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
index f9abe3f..0608320 100644 (file)
@@ -1198,7 +1198,11 @@ static SkMask::Format computeMaskFormat(const SkPaint& paint) {
     }
 #else
     if (flags & SkPaint::kLCDRenderText_Flag) {
+#if !defined(SK_SUPPORT_888_TEXT)    
         return SkMask::kLCD16_Format;
+#else
+        return SkMask::kLCD32_Format;
+#endif
     }
 #endif
 
@@ -1294,7 +1298,9 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
 
     rec->fMaskFormat = SkToU8(computeMaskFormat(paint));
 
-    if (SkMask::kLCD16_Format == rec->fMaskFormat) {
+    if (SkMask::kLCD16_Format == rec->fMaskFormat ||
+        SkMask::kLCD32_Format == rec->fMaskFormat)
+    {
         SkFontHost::LCDOrder order = SkFontHost::GetSubpixelOrder();
         SkFontHost::LCDOrientation orient = SkFontHost::GetSubpixelOrientation();
         if (SkFontHost::kNONE_LCDOrder == order) {
index 05439f1..2109531 100644 (file)
@@ -497,6 +497,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
     if (NULL == fMaskFilter &&
         fRec.fMaskFormat != SkMask::kBW_Format &&
         fRec.fMaskFormat != SkMask::kLCD16_Format &&
+        fRec.fMaskFormat != SkMask::kLCD32_Format &&
         (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
     {
         const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
index eb260fb..e82b8a0 100644 (file)
@@ -92,6 +92,8 @@ GrMaskFormat SkGrFontScaler::getMaskFormat() {
             return kA8_GrMaskFormat;
         case SkMask::kLCD16_Format:
             return kA565_GrMaskFormat;
+        case SkMask::kLCD32_Format:
+            return kA888_GrMaskFormat;
         default:
             GrAssert(!"unsupported SkMask::Format");
             return kA8_GrMaskFormat;
index 6adaf32..100eea5 100755 (executable)
@@ -30,7 +30,7 @@
  ** builds unless SK_USE_CORETEXT is defined.
 */
 #ifndef SK_USE_CORETEXT
-    #if TARGET_RT_64_BIT
+    #if TARGET_RT_64_BIT || defined(SK_USE_MAC_CORE_TEXT)
         #define SK_USE_CORETEXT                                     1
     #else
         #define SK_USE_CORETEXT                                     0
index 30a2d67..fd8e284 100644 (file)
@@ -447,6 +447,16 @@ static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
     return SkPackRGB16(r32_to_16(r), g32_to_16(g), b32_to_16(b));
 }
 
+static inline uint32_t rgb_to_lcd32(uint32_t rgb) {
+    // invert, since we draw black-on-white, but we want the original
+    // src mask values.
+    rgb = ~rgb;
+    int r = (rgb >> 16) & 0xFF;
+    int g = (rgb >>  8) & 0xFF;
+    int b = (rgb >>  0) & 0xFF;
+    return SkPackARGB32(0xFF, r, g, b);
+}
+
 #define BITMAP_INFO_RGB     (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
 #define BITMAP_INFO_GRAY    (kCGImageAlphaNone)
 
@@ -475,7 +485,9 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
      *  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 (SkMask::kLCD16_Format == glyph.fMaskFormat) {
+    if (SkMask::kLCD16_Format == glyph.fMaskFormat ||
+        SkMask::kLCD32_Format == glyph.fMaskFormat)
+    {
         colorspace = mColorSpaceRGB;
         info = BITMAP_INFO_RGB;
         // need tmp storage for 32bit RGB offscreen
@@ -523,6 +535,18 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
                 src = (const uint32_t*)((const char*)src + rowBytes);
                 dst = (uint16_t*)((char*)dst + dstRB);
             }
+        } else if (SkMask::kLCD32_Format == glyph.fMaskFormat) {
+            int width = glyph.fWidth;
+            const uint32_t* src = (const uint32_t*)image;
+            uint32_t* dst = (uint32_t*)glyph.fImage;
+            size_t dstRB = glyph.rowBytes();
+            for (int y = 0; y < glyph.fHeight; y++) {
+                for (int i = 0; i < width; i++) {
+                    dst[i] = rgb_to_lcd32(src[i]);
+                }
+                src = (const uint32_t*)((const char*)src + rowBytes);
+                dst = (uint32_t*)((char*)dst + dstRB);
+            }
         } else if (SkMask::kBW_Format == glyph.fMaskFormat) {
             // downsample from A8 to A1
             const uint8_t* src = (const uint8_t*)image;
@@ -698,11 +722,15 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
     CTFontRef ctFont = GetFontRefFromFontID(fontID);
     SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
     CFStringRef fontName = CTFontCopyPostScriptName(ctFont);
-    int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(fontName),
-        kCFStringEncodingUTF8);
+    // Reserve enough room for the worst-case string,
+    // plus 1 byte for the trailing null.
+    int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(
+        fontName), kCFStringEncodingUTF8) + 1;
     info->fFontName.resize(length); 
     CFStringGetCString(fontName, info->fFontName.writable_str(), length,
         kCFStringEncodingUTF8);
+    // Resize to the actual UTF-8 length used, stripping the null character.
+    info->fFontName.resize(strlen(info->fFontName.c_str())); 
     info->fMultiMaster = false;
     CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
     info->fLastGlyphID = SkToU16(glyphCount - 1);