add api for scalers to force us to use skia to generate their bits from their

path. This may allow the windows scaler to do that if GDI is giving bad
results (i.e. not respecting the request for antialiasing).



git-svn-id: http://skia.googlecode.com/svn/trunk@2054 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-08-05 21:40:26 +00:00
parent 6513cd06ae
commit a767fa06ca
3 changed files with 125 additions and 22 deletions

View File

@ -262,12 +262,18 @@ protected:
// default impl returns 0, indicating failure.
virtual SkUnichar generateGlyphToChar(uint16_t);
void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
private:
SkPathEffect* fPathEffect;
SkMaskFilter* fMaskFilter;
SkRasterizer* fRasterizer;
SkScalar fDevFrameWidth;
// if this is set, we draw the image from a path, rather than
// calling generateImage.
bool fGenerateImageFromPath;
void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
SkPath* devPath, SkMatrix* fillToDevMatrix);

View File

@ -112,6 +112,10 @@ SkScalerContext::SkScalerContext(const SkDescriptor* desc)
fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
// initialize based on our settings. subclasses can also force this
fGenerateImageFromPath = fRec.fFrameWidth > 0 || fPathEffect != NULL ||
fRasterizer != NULL;
}
SkScalerContext::~SkScalerContext() {
@ -254,7 +258,7 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) {
return;
}
if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
if (fGenerateImageFromPath) {
SkPath devPath, fillPath;
SkMatrix fillToDevMatrix;
@ -322,6 +326,51 @@ SK_ERROR:
glyph->fMaskFormat = fRec.fMaskFormat;
}
static bool isLCD(const SkScalerContext::Rec& rec) {
return SkMask::kLCD16_Format == rec.fMaskFormat ||
SkMask::kLCD32_Format == rec.fMaskFormat;
}
static uint16_t a8_to_rgb565(unsigned a8) {
return SkPackRGB16(a8 >> 3, a8 >> 2, a8 >> 3);
}
static void copyToLCD16(const SkBitmap& src, const SkGlyph& dst) {
SkASSERT(SkBitmap::kA8_Config == src.config());
SkASSERT(SkMask::kLCD16_Format == dst.fMaskFormat);
const uint8_t* srcP = src.getAddr8(0, 0);
size_t srcRB = src.rowBytes();
uint16_t* dstP = (uint16_t*)dst.fImage;
size_t dstRB = dst.rowBytes();
for (int y = 0; y < dst.fHeight; ++y) {
for (int x = 0; x < dst.fWidth; ++x) {
dstP[x] = a8_to_rgb565(srcP[x]);
}
srcP += srcRB;
dstP = (uint16_t*)((char*)dstP + dstRB);
}
}
static void copyToLCD32(const SkBitmap& src, const SkGlyph& dst) {
SkASSERT(SkBitmap::kA8_Config == src.config());
SkASSERT(SkMask::kLCD32_Format == dst.fMaskFormat);
const uint8_t* srcP = src.getAddr8(0, 0);
size_t srcRB = src.rowBytes();
SkPMColor* dstP = (SkPMColor*)dst.fImage;
size_t dstRB = dst.rowBytes();
for (int y = 0; y < dst.fHeight; ++y) {
for (int x = 0; x < dst.fWidth; ++x) {
unsigned a8 = srcP[x];
a8 = a8 | (a8 << 8);
dstP[x] = a8 | (a8 << 16);
}
srcP += srcRB;
dstP = (SkPMColor*)((char*)dstP + dstRB);
}
}
void SkScalerContext::getImage(const SkGlyph& origGlyph) {
const SkGlyph* glyph = &origGlyph;
SkGlyph tmpGlyph;
@ -343,7 +392,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
glyph = &tmpGlyph;
}
if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
if (fGenerateImageFromPath) {
SkPath devPath, fillPath;
SkMatrix fillToDevMatrix;
@ -367,15 +416,14 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
SkMatrix matrix;
SkRegion clip;
SkPaint paint;
SkDraw draw;
if (SkMask::kA8_Format == fRec.fMaskFormat) {
config = SkBitmap::kA8_Config;
paint.setAntiAlias(true);
} else {
SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
if (SkMask::kBW_Format == fRec.fMaskFormat) {
config = SkBitmap::kA1_Config;
paint.setAntiAlias(false);
} else {
config = SkBitmap::kA8_Config;
paint.setAntiAlias(true);
}
clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
@ -383,14 +431,39 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
-SkIntToScalar(glyph->fTop));
bm.setConfig(config, glyph->fWidth, glyph->fHeight,
glyph->rowBytes());
bm.setPixels(glyph->fImage);
sk_bzero(glyph->fImage, bm.height() * bm.rowBytes());
bool needCopyBack;
if (isLCD(fRec)) {
bm.allocPixels();
bm.lockPixels();
needCopyBack = true;
} else {
bm.setPixels(glyph->fImage);
needCopyBack = false;
}
sk_bzero(bm.getPixels(), bm.getSafeSize());
SkDraw draw;
sk_bzero(&draw, sizeof(draw));
draw.fClip = &clip;
draw.fMatrix = &matrix;
draw.fBitmap = &bm;
draw.fBounder = NULL;
draw.drawPath(devPath, paint);
// for now we just upscale A8 to lcd. Later we may respect the LCD
// request by scaling horizontally/vertiacally 3x
if (needCopyBack) {
switch (fRec.fMaskFormat) {
case SkMask::kLCD16_Format:
copyToLCD16(bm, *glyph);
break;
case SkMask::kLCD32_Format:
copyToLCD32(bm, *glyph);
break;
default:
SkASSERT(!"bad format for copyback");
}
}
}
} else {
this->getGlyphContext(*glyph)->generateImage(*glyph);

View File

@ -23,6 +23,11 @@
#include "tchar.h"
#include "Usp10.h"
// define this in your Makefile or .gyp to enforce AA requests
// which GDI ignores at small sizes. This flag guarantees AA
// for rotated text, regardless of GDI's notions.
//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
// client3d has to undefine this for now
#define CAN_USE_LOGFONT_NAME
@ -31,6 +36,32 @@ static bool isLCD(const SkScalerContext::Rec& rec) {
SkMask::kLCD32_Format == rec.fMaskFormat;
}
static bool bothZero(SkScalar a, SkScalar b) {
return 0 == a && 0 == b;
}
// returns false if there is any non-90-rotation or skew
static bool isAxisAligned(const SkScalerContext::Rec& rec) {
return 0 == rec.fPreSkewX &&
(bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
}
static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
// What we really want to catch is when GDI will ignore the AA request and give
// us BW instead. Smallish rotated text is one heuristic, so this code is just
// an approximation. We shouldn't need to do this for larger sizes, but at those
// sizes, the quality difference gets less and less between our general
// scanconverter and GDI's.
if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
return true;
}
#endif
// false means allow GDI to generate the bits
return false;
}
using namespace skia_advanced_typeface_metrics_utils;
static const uint16_t BUFFERSIZE = (16384 - 32);
@ -347,6 +378,10 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
fHiResMatrix.preScale(scale, scale);
}
fSavefont = (HFONT)SelectObject(fDDC, fFont);
if (needToRenderWithSkia(fRec)) {
this->forceGenerateImageFromPath();
}
}
SkScalerContext_Windows::~SkScalerContext_Windows() {
@ -948,17 +983,6 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
return NULL;
}
static bool bothZero(SkScalar a, SkScalar b) {
return 0 == a && 0 == b;
}
// returns false if there is any non-90-rotation or skew
static bool isAxisAligned(const SkScalerContext::Rec& rec) {
return 0 == rec.fPreSkewX &&
(bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
}
void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
SkScalerContext::kAutohinting_Flag |