check-point for kLCD16_Format mask support

disabled for now in SkPaint.cpp (for further testing)



git-svn-id: http://skia.googlecode.com/svn/trunk@917 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-03-10 15:06:27 +00:00
parent 649a862186
commit f88d6765a5
7 changed files with 249 additions and 49 deletions

View File

@ -47,6 +47,7 @@ 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
};
enum {
@ -96,6 +97,19 @@ struct SkMask {
return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes;
}
/**
* Return the address of the specified 16bit mask. In the debug build,
* this asserts that the mask's format is kLCD16_Format, and that (x,y)
* are contained in the mask's fBounds.
*/
uint16_t* getAddrLCD16(int x, int y) const {
SkASSERT(kLCD16_Format == fFormat);
SkASSERT(fBounds.contains(x, y));
SkASSERT(fImage != NULL);
uint16_t* row = (uint16_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.
*/

View File

@ -53,18 +53,27 @@ struct SkGlyph {
fMaskFormat = MASK_FORMAT_UNKNOWN;
}
unsigned rowBytes() const {
unsigned rb = fWidth;
if (SkMask::kBW_Format == fMaskFormat) {
/**
* Compute the rowbytes for the specified width and mask-format.
*/
static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) {
unsigned rb = width;
if (SkMask::kBW_Format == format) {
rb = (rb + 7) >> 3;
} else if (SkMask::kARGB32_Format == fMaskFormat) {
} else if (SkMask::kARGB32_Format == format) {
rb <<= 2;
} else if (SkMask::kLCD16_Format == format) {
rb = SkAlign4(rb << 1);
} else {
rb = SkAlign4(rb);
}
return rb;
}
unsigned rowBytes() const {
return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat);
}
bool isJustAdvance() const {
return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
}

View File

@ -23,6 +23,12 @@
#include "SkColorPriv.h"
#include "SkImageDecoder.h"
static void setNamedTypeface(SkPaint* paint, const char name[]) {
SkTypeface* face = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
paint->setTypeface(face);
SkSafeUnref(face);
}
#if 0
static int newscale(U8CPU a, U8CPU b, int shift) {
unsigned prod = a * b + (1 << (shift - 1));
@ -193,7 +199,10 @@ protected:
SkPaint labelP;
labelP.setAntiAlias(true);
labelP.setLCDRenderText(true);
labelP.setTextAlign(SkPaint::kCenter_Align);
setNamedTypeface(&labelP, "Menlo Regular");
// labelP.setTextSize(SkIntToScalar(11));
const int W = 5;

View File

@ -38,6 +38,74 @@ extern uint32_t BlendLCDPixelWithBlack(const uint32_t alphaPixel, const uint32_t
using namespace skia_blitter_support;
#endif
///////////////////////////////////////////////////////////////////////////////
static int upscale31To256(int value) {
SkASSERT((unsigned)value <= 31);
// 0..31 -> 0..255
value = (value << 3) | (value >> 2);
// 0..255 -> 0..256
value += (value >> 7);
SkASSERT((unsigned)value <= 256);
return value;
}
static void blit_lcd16_opaque(SkPMColor dst[], const uint16_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++) {
uint16_t mask = src[i];
if (0 == mask) {
continue;
}
/* We want all of these in 5bits, hence the shifts in case one of them
* (green) is 6bits.
*/
int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
// Now upscale them to 0..256, so we can use SkAlphaBlend
maskR = upscale31To256(maskR);
maskG = upscale31To256(maskG);
maskB = upscale31To256(maskB);
int maskA = SkMax32(SkMax32(maskR, maskG), maskB);
SkPMColor d = dst[i];
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;
int y = clip.fTop;
int width = clip.width();
int height = clip.height();
SkPMColor* dstRow = device.getAddr32(x, y);
const uint16_t* srcRow = mask.getAddrLCD16(x, y);
do {
blit_lcd16_opaque(dstRow, srcRow, srcColor, width);
dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
srcRow = (const uint16_t*)((const char*)srcRow + mask.fRowBytes);
} while (--height != 0);
}
//////////////////////////////////////////////////////////////////////////////////////
static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
@ -189,6 +257,9 @@ void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
} else if (SkMask::kARGB32_Format == mask.fFormat) {
SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
return;
} else if (SkMask::kLCD16_Format == mask.fFormat) {
blitmask_lcd16(fDevice, mask, clip, fPMColor);
return;
}
int x = clip.fLeft;
@ -210,6 +281,9 @@ void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
} else if (SkMask::kARGB32_Format == mask.fFormat) {
SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
return;
} else if (SkMask::kLCD16_Format == mask.fFormat) {
blitmask_lcd16(fDevice, mask, clip, fPMColor);
return;
}
int x = clip.fLeft;
@ -319,6 +393,8 @@ void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
SkARGB32_BlitBW(fDevice, mask, clip, black);
} else if (SkMask::kARGB32_Format == mask.fFormat) {
SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
} else if (SkMask::kLCD16_Format == mask.fFormat) {
blitmask_lcd16(fDevice, mask, clip, fPMColor);
} else {
#if defined(SK_SUPPORT_LCDTEXT)
const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;

View File

@ -1104,6 +1104,22 @@ static void add_flattenable(SkDescriptor* desc, uint32_t tag,
buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
}
static bool canSupportLCD16(const SkPaint& paint) {
#if 0
return !paint.getShader() &&
!paint.getXfermode() && // unless its srcover
!paint.getMaskFilter() &&
!paint.getRasterizer() &&
!paint.getColorFilter() &&
!paint.getPathEffect() &&
!paint.isFakeBoldText() &&
paint.getStyle() == SkPaint::kFill_Style;
#else
// disable for now, while we test more
return false;
#endif
}
static SkMask::Format computeMaskFormat(const SkPaint& paint) {
uint32_t flags = paint.getFlags();
@ -1111,6 +1127,12 @@ static SkMask::Format computeMaskFormat(const SkPaint& paint) {
if (!(flags & SkPaint::kAntiAlias_Flag))
return SkMask::kBW_Format;
if (flags & SkPaint::kLCDRenderText_Flag) {
if (canSupportLCD16(paint)) {
return SkMask::kLCD16_Format;
}
}
#if defined(SK_SUPPORT_LCDTEXT)
if (flags & SkPaint::kLCDRenderText_Flag) {
return SkFontHost::GetSubpixelOrientation() == SkFontHost::kHorizontal_LCDOrientation ?

View 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.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
{
const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;

View File

@ -21,7 +21,7 @@
#include "SkString.h"
#include "SkPaint.h"
#include "SkFloatingPoint.h"
#include "SkUtils.h"
@ -328,7 +328,8 @@ private:
private:
CGColorSpaceRef mColorSpace;
CGColorSpaceRef mColorSpaceGray;
CGColorSpaceRef mColorSpaceRGB;
CGAffineTransform mTransform;
CTFontRef mFont;
@ -352,7 +353,11 @@ SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
// Initialise ourselves
mColorSpace = CGColorSpaceCreateDeviceGray();
// mColorSpaceRGB = CGColorSpaceCreateDeviceRGB();
// mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
mColorSpaceGray = CGColorSpaceCreateDeviceGray();
const float inv = 1.0f / FONT_CANONICAL_POINTSIZE;
mTransform = CGAffineTransformMake(SkScalarToFloat(skMatrix[SkMatrix::kMScaleX]) * inv,
-SkScalarToFloat(skMatrix[SkMatrix::kMSkewY]) * inv,
@ -369,7 +374,8 @@ SkScalerContext_Mac::~SkScalerContext_Mac(void)
{
// Clean up
CFSafeRelease(mColorSpace);
CFSafeRelease(mColorSpaceGray);
CFSafeRelease(mColorSpaceRGB);
CFSafeRelease(mFont);
}
@ -437,8 +443,27 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph)
glyph->fLeft = sk_float_round2int(CGRectGetMinX(theBounds));
}
void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
{ CGContextRef cgContext;
#include "SkColorPriv.h"
static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb >> 0) & 0xFF;
// invert, since we draw black-on-white, but we want the original
// src mask values.
r = 255 - r;
g = 255 - g;
b = 255 - b;
return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
}
#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
#define BITMAP_INFO_GRAY (kCGImageAlphaNone)
void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
CGContextRef cgContext;
CGGlyph cgGlyph;
CGFontRef cgFont;
@ -447,17 +472,61 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
cgFont = CTFontCopyGraphicsFont(mFont, NULL);
cgContext = CGBitmapContextCreate( glyph.fImage, glyph.fWidth, glyph.fHeight, 8,
glyph.rowBytes(), mColorSpace, kCGImageAlphaNone);
SkAutoSMalloc<1024> storage;
CGColorSpaceRef colorspace = mColorSpaceGray;
uint32_t info = BITMAP_INFO_GRAY;
void* image = glyph.fImage;
size_t rowBytes = glyph.rowBytes();
float grayColor = 1; // white
/* For LCD16, we first create a temp offscreen cg-context in 32bit,
* erase to white, and then draw a black glyph into it. Then we can
* 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) {
colorspace = mColorSpaceRGB;
info = BITMAP_INFO_RGB;
// need tmp storage for 32bit RGB offscreen
rowBytes = glyph.fWidth << 2;
size_t size = glyph.fHeight * rowBytes;
image = storage.realloc(size);
// we draw black-on-white (and invert in rgb_to_lcd16)
sk_memset32((uint32_t*)image, 0xFFFFFFFF, size >> 2);
grayColor = 0; // black
}
cgContext = CGBitmapContextCreate(image, glyph.fWidth, glyph.fHeight, 8,
rowBytes, colorspace, info);
// Draw the glyph
if (cgFont != NULL && cgContext != NULL) {
CGContextSetGrayFillColor( cgContext, 1.0, 1.0);
CGContextSetAllowsFontSubpixelQuantization(cgContext, true);
CGContextSetShouldSubpixelQuantizeFonts(cgContext, true);
CGContextSetGrayFillColor( cgContext, grayColor, 1.0);
CGContextSetTextDrawingMode(cgContext, kCGTextFill);
CGContextSetFont( cgContext, cgFont);
CGContextSetFontSize( cgContext, FONT_CANONICAL_POINTSIZE);
CGContextSetTextMatrix( cgContext, mTransform);
CGContextShowGlyphsAtPoint( cgContext, -glyph.fLeft, glyph.fTop + glyph.fHeight, &cgGlyph, 1);
if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
// downsample from rgba to rgb565
int width = glyph.fWidth;
const uint32_t* src = (const uint32_t*)image;
uint16_t* dst = (uint16_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_lcd16(src[i]);
}
src = (const uint32_t*)((const char*)src + rowBytes);
dst = (uint16_t*)((char*)dst + dstRB);
}
}
}
// Clean up