detect when LCD is really just BW, and remark the glyph as that.
allows us to take a much faster blitter. TODO: inform SkGlyphCache of this, so it can shrink its allocation for the image buffer (since BW takes up 1/16 as much ram) TODO(2): allow for A8->BW conversion my having scalercontext set a flag if it really-wants A8 (i.e. we have a maskfilter) git-svn-id: http://skia.googlecode.com/svn/trunk@2301 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
98b11f1c21
commit
5e2df64215
@ -293,6 +293,10 @@ const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
|
|||||||
// check that alloc() actually succeeded
|
// check that alloc() actually succeeded
|
||||||
if (glyph.fImage) {
|
if (glyph.fImage) {
|
||||||
fScalerContext->getImage(glyph);
|
fScalerContext->getImage(glyph);
|
||||||
|
// TODO: the scaler may have changed the maskformat during
|
||||||
|
// getImage (e.g. from AA or LCD to BW) which means we may have
|
||||||
|
// overallocated the buffer. Check if the new computedImageSize
|
||||||
|
// is smaller, and if so, strink the alloc size in fImageAlloc.
|
||||||
fMemoryUsed += size;
|
fMemoryUsed += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,10 +600,12 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
|
|||||||
// correspond to an embedded bitmap font, but not sure.
|
// correspond to an embedded bitmap font, but not sure.
|
||||||
// LayoutTests/fast/text/backslash-to-yen-sign-euc.html
|
// LayoutTests/fast/text/backslash-to-yen-sign-euc.html
|
||||||
//
|
//
|
||||||
glyph->fWidth += 4;
|
if (glyph->fWidth) { // don't outset an empty glyph
|
||||||
glyph->fHeight += 4;
|
glyph->fWidth += 4;
|
||||||
glyph->fTop -= 2;
|
glyph->fHeight += 4;
|
||||||
glyph->fLeft -= 2;
|
glyph->fTop -= 2;
|
||||||
|
glyph->fLeft -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (fHiResFont) {
|
if (fHiResFont) {
|
||||||
SelectObject(fDDC, fHiResFont);
|
SelectObject(fDDC, fHiResFont);
|
||||||
@ -658,15 +660,19 @@ void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPa
|
|||||||
|
|
||||||
#include "SkColorPriv.h"
|
#include "SkColorPriv.h"
|
||||||
|
|
||||||
static inline uint8_t rgb_to_a8(uint32_t rgb) {
|
// always packed xxRRGGBB
|
||||||
// can pick any component, since we're grayscale
|
typedef uint32_t SkGdiRGB;
|
||||||
int r = (rgb >> 16) & 0xFF;
|
|
||||||
// invert, since we draw black-on-white, but we want the original
|
// gdi's bitmap is upside-down, so we reverse dst walking in Y
|
||||||
// src mask values.
|
// whenever we copy it into skia's buffer
|
||||||
return 255 - r;
|
|
||||||
|
static inline uint8_t rgb_to_a8(SkGdiRGB rgb) {
|
||||||
|
// can pick any component (low 3 bytes), since we're grayscale
|
||||||
|
// but must invert since we draw black-on-white
|
||||||
|
return ~rgb & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
|
static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb) {
|
||||||
rgb = ~rgb; // 255 - each component
|
rgb = ~rgb; // 255 - each component
|
||||||
int r = (rgb >> 16) & 0xFF;
|
int r = (rgb >> 16) & 0xFF;
|
||||||
int g = (rgb >> 8) & 0xFF;
|
int g = (rgb >> 8) & 0xFF;
|
||||||
@ -674,6 +680,99 @@ static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
|
|||||||
return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
|
return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_black_or_white(SkGdiRGB c) {
|
||||||
|
c &= 0x00FFFFFF;
|
||||||
|
bool isBW = 0 == c || 0x00FFFFFF == c;
|
||||||
|
bool isBW2 = 0 == ((c + (c & 1)) & 0x00FFFFFF);
|
||||||
|
SkASSERT(isBW == isBW2);
|
||||||
|
return isBW;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) {
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
if (!is_black_or_white(src[x])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src = (const SkGdiRGB*)((const char*)src + srcRB);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
|
||||||
|
const SkGlyph& glyph) {
|
||||||
|
const int width = glyph.fWidth;
|
||||||
|
const size_t dstRB = (width + 7) >> 3;
|
||||||
|
uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
|
||||||
|
|
||||||
|
int byteCount = width >> 3;
|
||||||
|
int bitCount = width & 7;
|
||||||
|
|
||||||
|
// adjust srcRB to skip the values in our byteCount loop,
|
||||||
|
// since we increment src locally there
|
||||||
|
srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
|
||||||
|
|
||||||
|
for (int y = 0; y < glyph.fHeight; ++y) {
|
||||||
|
if (byteCount > 0) {
|
||||||
|
unsigned byte = 0;
|
||||||
|
for (int i = 0; i < byteCount; ++i) {
|
||||||
|
byte |= src[0] & (1 << 7);
|
||||||
|
byte |= src[1] & (1 << 6);
|
||||||
|
byte |= src[2] & (1 << 5);
|
||||||
|
byte |= src[3] & (1 << 4);
|
||||||
|
byte |= src[4] & (1 << 3);
|
||||||
|
byte |= src[5] & (1 << 2);
|
||||||
|
byte |= src[6] & (1 << 1);
|
||||||
|
byte |= src[7] & (1 << 0);
|
||||||
|
dst[i] = ~byte;
|
||||||
|
src += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bitCount > 0) {
|
||||||
|
unsigned byte = 0;
|
||||||
|
unsigned mask = 0x80;
|
||||||
|
for (int i = 0; i < bitCount; i++) {
|
||||||
|
byte |= ~src[i] & mask;
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
dst[byteCount] = byte;
|
||||||
|
}
|
||||||
|
src = (const SkGdiRGB*)((const char*)src + srcRB);
|
||||||
|
dst -= dstRB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
|
||||||
|
const SkGlyph& glyph) {
|
||||||
|
const size_t dstRB = glyph.rowBytes();
|
||||||
|
const int width = glyph.fWidth;
|
||||||
|
uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
|
||||||
|
|
||||||
|
for (int y = 0; y < glyph.fHeight; y++) {
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
dst[i] = rgb_to_a8(src[i]);
|
||||||
|
}
|
||||||
|
src = (const SkGdiRGB*)((const char*)src + srcRB);
|
||||||
|
dst -= dstRB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
|
||||||
|
const SkGlyph& glyph) {
|
||||||
|
const size_t dstRB = glyph.rowBytes();
|
||||||
|
const int width = glyph.fWidth;
|
||||||
|
uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
|
||||||
|
|
||||||
|
for (int y = 0; y < glyph.fHeight; y++) {
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
dst[i] = rgb_to_lcd16(src[i]);
|
||||||
|
}
|
||||||
|
src = (const SkGdiRGB*)((const char*)src + srcRB);
|
||||||
|
dst = (uint16_t*)((char*)dst - dstRB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
|
void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
|
||||||
|
|
||||||
SkAutoMutexAcquire ac(gFTMutex);
|
SkAutoMutexAcquire ac(gFTMutex);
|
||||||
@ -694,7 +793,6 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
|
|||||||
size_t dstRB = glyph.rowBytes();
|
size_t dstRB = glyph.rowBytes();
|
||||||
if (isBW) {
|
if (isBW) {
|
||||||
const uint8_t* src = (const uint8_t*)bits;
|
const uint8_t* src = (const uint8_t*)bits;
|
||||||
// gdi's bitmap is upside-down, so we reverse dst walking in Y
|
|
||||||
uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
|
uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
|
||||||
for (int y = 0; y < glyph.fHeight; y++) {
|
for (int y = 0; y < glyph.fHeight; y++) {
|
||||||
memcpy(dst, src, dstRB);
|
memcpy(dst, src, dstRB);
|
||||||
@ -702,26 +800,23 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
|
|||||||
dst -= dstRB;
|
dst -= dstRB;
|
||||||
}
|
}
|
||||||
} else if (isAA) {
|
} else if (isAA) {
|
||||||
const uint32_t* src = (const uint32_t*)bits;
|
const SkGdiRGB* src = (const SkGdiRGB*)bits;
|
||||||
// gdi's bitmap is upside-down, so we reverse dst walking in Y
|
#if 0 // can't do this (yet) since caller may really want gray8 for maskfilters
|
||||||
uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
|
if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
|
||||||
for (int y = 0; y < glyph.fHeight; y++) {
|
rgb_to_bw(src, srcRB, glyph);
|
||||||
for (int i = 0; i < width; i++) {
|
((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
|
||||||
dst[i] = rgb_to_a8(src[i]);
|
} else
|
||||||
}
|
#endif
|
||||||
src = (const uint32_t*)((const char*)src + srcRB);
|
{
|
||||||
dst -= dstRB;
|
rgb_to_a8(src, srcRB, glyph);
|
||||||
}
|
}
|
||||||
} else { // LCD16
|
} else { // LCD16
|
||||||
const uint32_t* src = (const uint32_t*)bits;
|
const SkGdiRGB* src = (const SkGdiRGB*)bits;
|
||||||
// gdi's bitmap is upside-down, so we reverse dst walking in Y
|
if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
|
||||||
uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
|
rgb_to_bw(src, srcRB, glyph);
|
||||||
for (int y = 0; y < glyph.fHeight; y++) {
|
((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
|
||||||
for (int i = 0; i < width; i++) {
|
} else {
|
||||||
dst[i] = rgb_to_lcd16(src[i]);
|
rgb_to_lcd16(src, srcRB, glyph);
|
||||||
}
|
|
||||||
src = (const uint32_t*)((const char*)src + srcRB);
|
|
||||||
dst = (uint16_t*)((char*)dst - dstRB);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user