* 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.
return kAlpha_8_GrPixelConfig;
case kA565_GrMaskFormat:
return kRGB_565_GrPixelConfig;
+ case kA888_GrMaskFormat:
+ return kRGBA_8888_GrPixelConfig;
default:
GrAssert(!"unknown maskformat");
}
*/
//#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.
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 {
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.
*/
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);
}
}
+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;
} 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,
} 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;
} 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;
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;
}
#else
if (flags & SkPaint::kLCDRenderText_Flag) {
+#if !defined(SK_SUPPORT_888_TEXT)
return SkMask::kLCD16_Format;
+#else
+ return SkMask::kLCD32_Format;
+#endif
}
#endif
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) {
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;
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;
** 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
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)
* 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
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;
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);