Add support for 8 bits/component glyphs, to

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
This commit is contained in:
caryclark@google.com 2011-06-22 13:19:43 +00:00
Родитель 3c898186c9
Коммит 1eeaf0ba23
11 изменённых файлов: 140 добавлений и 10 удалений

Просмотреть файл

@ -248,9 +248,11 @@ enum GrBlendCoeff {
*/ */
enum GrMaskFormat { enum GrMaskFormat {
kA8_GrMaskFormat, //!< 1-byte per pixel kA8_GrMaskFormat, //!< 1-byte per pixel
kA565_GrMaskFormat //!< 2-bytes 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 the number of bytes-per-pixel for the specified mask format.

Просмотреть файл

@ -148,6 +148,8 @@ static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
return kAlpha_8_GrPixelConfig; return kAlpha_8_GrPixelConfig;
case kA565_GrMaskFormat: case kA565_GrMaskFormat:
return kRGB_565_GrPixelConfig; return kRGB_565_GrPixelConfig;
case kA888_GrMaskFormat:
return kRGBA_8888_GrPixelConfig;
default: default:
GrAssert(!"unknown maskformat"); GrAssert(!"unknown maskformat");
} }

Просмотреть файл

@ -117,6 +117,17 @@
*/ */
//#define SK_SUPPORT_LCDTEXT //#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 /* If zlib is available and you want to support the flate compression
algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the
include path. include path.

Просмотреть файл

@ -47,7 +47,8 @@ struct SkMask {
kHorizontalLCD_Format, //!< 4 bytes/pixel: a/r/g/b kHorizontalLCD_Format, //!< 4 bytes/pixel: a/r/g/b
kVerticalLCD_Format, //!< 4 bytes/pixel: a/r/g/b kVerticalLCD_Format, //!< 4 bytes/pixel: a/r/g/b
kARGB32_Format, //!< SkPMColor 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 { enum {
@ -110,6 +111,19 @@ struct SkMask {
return row + (x - fBounds.fLeft); 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 /** Return an address into the 32-bit plane of an LCD or VerticalLCD mask
for the given position. for the given position.
*/ */

Просмотреть файл

@ -60,7 +60,9 @@ struct SkGlyph {
unsigned rb = width; unsigned rb = width;
if (SkMask::kBW_Format == format) { if (SkMask::kBW_Format == format) {
rb = (rb + 7) >> 3; rb = (rb + 7) >> 3;
} else if (SkMask::kARGB32_Format == format) { } else if (SkMask::kARGB32_Format == format ||
SkMask::kLCD32_Format == format)
{
rb <<= 2; rb <<= 2;
} else if (SkMask::kLCD16_Format == format) { } else if (SkMask::kLCD16_Format == format) {
rb = SkAlign4(rb << 1); rb = SkAlign4(rb << 1);

Просмотреть файл

@ -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, static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask,
const SkIRect& clip, SkPMColor srcColor) { const SkIRect& clip, SkPMColor srcColor) {
int x = clip.fLeft; int x = clip.fLeft;
@ -109,6 +146,23 @@ static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask,
} while (--height != 0); } 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, 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) { } else if (SkMask::kLCD16_Format == mask.fFormat) {
blitmask_lcd16(fDevice, mask, clip, fPMColor); blitmask_lcd16(fDevice, mask, clip, fPMColor);
return; return;
} else if (SkMask::kLCD32_Format == mask.fFormat) {
blitmask_lcd32(fDevice, mask, clip, fPMColor);
return;
} }
int x = clip.fLeft; int x = clip.fLeft;
@ -287,6 +344,9 @@ void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
} else if (SkMask::kLCD16_Format == mask.fFormat) { } else if (SkMask::kLCD16_Format == mask.fFormat) {
blitmask_lcd16(fDevice, mask, clip, fPMColor); blitmask_lcd16(fDevice, mask, clip, fPMColor);
return; return;
} else if (SkMask::kLCD32_Format == mask.fFormat) {
blitmask_lcd32(fDevice, mask, clip, fPMColor);
return;
} }
int x = clip.fLeft; 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); SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
} else if (SkMask::kLCD16_Format == mask.fFormat) { } else if (SkMask::kLCD16_Format == mask.fFormat) {
blitmask_lcd16(fDevice, mask, clip, fPMColor); blitmask_lcd16(fDevice, mask, clip, fPMColor);
} else if (SkMask::kLCD32_Format == mask.fFormat) {
blitmask_lcd32(fDevice, mask, clip, fPMColor);
} else { } else {
#if defined(SK_SUPPORT_LCDTEXT) #if defined(SK_SUPPORT_LCDTEXT)
const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format; const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;

Просмотреть файл

@ -1198,7 +1198,11 @@ static SkMask::Format computeMaskFormat(const SkPaint& paint) {
} }
#else #else
if (flags & SkPaint::kLCDRenderText_Flag) { if (flags & SkPaint::kLCDRenderText_Flag) {
#if !defined(SK_SUPPORT_888_TEXT)
return SkMask::kLCD16_Format; return SkMask::kLCD16_Format;
#else
return SkMask::kLCD32_Format;
#endif
} }
#endif #endif
@ -1294,7 +1298,9 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
rec->fMaskFormat = SkToU8(computeMaskFormat(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::LCDOrder order = SkFontHost::GetSubpixelOrder();
SkFontHost::LCDOrientation orient = SkFontHost::GetSubpixelOrientation(); SkFontHost::LCDOrientation orient = SkFontHost::GetSubpixelOrientation();
if (SkFontHost::kNONE_LCDOrder == order) { if (SkFontHost::kNONE_LCDOrder == order) {

Просмотреть файл

@ -497,6 +497,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
if (NULL == fMaskFilter && if (NULL == fMaskFilter &&
fRec.fMaskFormat != SkMask::kBW_Format && fRec.fMaskFormat != SkMask::kBW_Format &&
fRec.fMaskFormat != SkMask::kLCD16_Format && fRec.fMaskFormat != SkMask::kLCD16_Format &&
fRec.fMaskFormat != SkMask::kLCD32_Format &&
(fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0) (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
{ {
const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable; const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;

Просмотреть файл

@ -92,6 +92,8 @@ GrMaskFormat SkGrFontScaler::getMaskFormat() {
return kA8_GrMaskFormat; return kA8_GrMaskFormat;
case SkMask::kLCD16_Format: case SkMask::kLCD16_Format:
return kA565_GrMaskFormat; return kA565_GrMaskFormat;
case SkMask::kLCD32_Format:
return kA888_GrMaskFormat;
default: default:
GrAssert(!"unsupported SkMask::Format"); GrAssert(!"unsupported SkMask::Format");
return kA8_GrMaskFormat; return kA8_GrMaskFormat;

Просмотреть файл

@ -30,7 +30,7 @@
** builds unless SK_USE_CORETEXT is defined. ** builds unless SK_USE_CORETEXT is defined.
*/ */
#ifndef SK_USE_CORETEXT #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 #define SK_USE_CORETEXT 1
#else #else
#define SK_USE_CORETEXT 0 #define SK_USE_CORETEXT 0

Просмотреть файл

@ -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)); 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_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
#define BITMAP_INFO_GRAY (kCGImageAlphaNone) #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 * extract the r,g,b values, invert-them, and now we have the original
* src mask components, which we pack into our 16bit mask. * 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; colorspace = mColorSpaceRGB;
info = BITMAP_INFO_RGB; info = BITMAP_INFO_RGB;
// need tmp storage for 32bit RGB offscreen // 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); src = (const uint32_t*)((const char*)src + rowBytes);
dst = (uint16_t*)((char*)dst + dstRB); 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) { } else if (SkMask::kBW_Format == glyph.fMaskFormat) {
// downsample from A8 to A1 // downsample from A8 to A1
const uint8_t* src = (const uint8_t*)image; const uint8_t* src = (const uint8_t*)image;
@ -698,11 +722,15 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
CTFontRef ctFont = GetFontRefFromFontID(fontID); CTFontRef ctFont = GetFontRefFromFontID(fontID);
SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics; SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
CFStringRef fontName = CTFontCopyPostScriptName(ctFont); CFStringRef fontName = CTFontCopyPostScriptName(ctFont);
int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(fontName), // Reserve enough room for the worst-case string,
kCFStringEncodingUTF8); // plus 1 byte for the trailing null.
int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(
fontName), kCFStringEncodingUTF8) + 1;
info->fFontName.resize(length); info->fFontName.resize(length);
CFStringGetCString(fontName, info->fFontName.writable_str(), length, CFStringGetCString(fontName, info->fFontName.writable_str(), length,
kCFStringEncodingUTF8); kCFStringEncodingUTF8);
// Resize to the actual UTF-8 length used, stripping the null character.
info->fFontName.resize(strlen(info->fFontName.c_str()));
info->fMultiMaster = false; info->fMultiMaster = false;
CFIndex glyphCount = CTFontGetGlyphCount(ctFont); CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
info->fLastGlyphID = SkToU16(glyphCount - 1); info->fLastGlyphID = SkToU16(glyphCount - 1);