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:
parent
6513cd06ae
commit
a767fa06ca
@ -262,12 +262,18 @@ protected:
|
|||||||
// default impl returns 0, indicating failure.
|
// default impl returns 0, indicating failure.
|
||||||
virtual SkUnichar generateGlyphToChar(uint16_t);
|
virtual SkUnichar generateGlyphToChar(uint16_t);
|
||||||
|
|
||||||
|
void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkPathEffect* fPathEffect;
|
SkPathEffect* fPathEffect;
|
||||||
SkMaskFilter* fMaskFilter;
|
SkMaskFilter* fMaskFilter;
|
||||||
SkRasterizer* fRasterizer;
|
SkRasterizer* fRasterizer;
|
||||||
SkScalar fDevFrameWidth;
|
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,
|
void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
|
||||||
SkPath* devPath, SkMatrix* fillToDevMatrix);
|
SkPath* devPath, SkMatrix* fillToDevMatrix);
|
||||||
|
|
||||||
|
@ -112,6 +112,10 @@ SkScalerContext::SkScalerContext(const SkDescriptor* desc)
|
|||||||
fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
|
fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
|
||||||
fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
|
fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
|
||||||
fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_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() {
|
SkScalerContext::~SkScalerContext() {
|
||||||
@ -254,7 +258,7 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
|
if (fGenerateImageFromPath) {
|
||||||
SkPath devPath, fillPath;
|
SkPath devPath, fillPath;
|
||||||
SkMatrix fillToDevMatrix;
|
SkMatrix fillToDevMatrix;
|
||||||
|
|
||||||
@ -322,6 +326,51 @@ SK_ERROR:
|
|||||||
glyph->fMaskFormat = fRec.fMaskFormat;
|
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) {
|
void SkScalerContext::getImage(const SkGlyph& origGlyph) {
|
||||||
const SkGlyph* glyph = &origGlyph;
|
const SkGlyph* glyph = &origGlyph;
|
||||||
SkGlyph tmpGlyph;
|
SkGlyph tmpGlyph;
|
||||||
@ -343,7 +392,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
|
|||||||
glyph = &tmpGlyph;
|
glyph = &tmpGlyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
|
if (fGenerateImageFromPath) {
|
||||||
SkPath devPath, fillPath;
|
SkPath devPath, fillPath;
|
||||||
SkMatrix fillToDevMatrix;
|
SkMatrix fillToDevMatrix;
|
||||||
|
|
||||||
@ -367,15 +416,14 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
|
|||||||
SkMatrix matrix;
|
SkMatrix matrix;
|
||||||
SkRegion clip;
|
SkRegion clip;
|
||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
SkDraw draw;
|
|
||||||
|
|
||||||
if (SkMask::kA8_Format == fRec.fMaskFormat) {
|
if (SkMask::kBW_Format == fRec.fMaskFormat) {
|
||||||
config = SkBitmap::kA8_Config;
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
} else {
|
|
||||||
SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
|
|
||||||
config = SkBitmap::kA1_Config;
|
config = SkBitmap::kA1_Config;
|
||||||
paint.setAntiAlias(false);
|
paint.setAntiAlias(false);
|
||||||
|
} else {
|
||||||
|
config = SkBitmap::kA8_Config;
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
|
clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
|
||||||
@ -383,14 +431,39 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
|
|||||||
-SkIntToScalar(glyph->fTop));
|
-SkIntToScalar(glyph->fTop));
|
||||||
bm.setConfig(config, glyph->fWidth, glyph->fHeight,
|
bm.setConfig(config, glyph->fWidth, glyph->fHeight,
|
||||||
glyph->rowBytes());
|
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.fClip = &clip;
|
||||||
draw.fMatrix = &matrix;
|
draw.fMatrix = &matrix;
|
||||||
draw.fBitmap = &bm;
|
draw.fBitmap = &bm;
|
||||||
draw.fBounder = NULL;
|
|
||||||
draw.drawPath(devPath, paint);
|
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 {
|
} else {
|
||||||
this->getGlyphContext(*glyph)->generateImage(*glyph);
|
this->getGlyphContext(*glyph)->generateImage(*glyph);
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
#include "tchar.h"
|
#include "tchar.h"
|
||||||
#include "Usp10.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
|
// client3d has to undefine this for now
|
||||||
#define CAN_USE_LOGFONT_NAME
|
#define CAN_USE_LOGFONT_NAME
|
||||||
|
|
||||||
@ -31,6 +36,32 @@ static bool isLCD(const SkScalerContext::Rec& rec) {
|
|||||||
SkMask::kLCD32_Format == rec.fMaskFormat;
|
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;
|
using namespace skia_advanced_typeface_metrics_utils;
|
||||||
|
|
||||||
static const uint16_t BUFFERSIZE = (16384 - 32);
|
static const uint16_t BUFFERSIZE = (16384 - 32);
|
||||||
@ -347,6 +378,10 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
|
|||||||
fHiResMatrix.preScale(scale, scale);
|
fHiResMatrix.preScale(scale, scale);
|
||||||
}
|
}
|
||||||
fSavefont = (HFONT)SelectObject(fDDC, fFont);
|
fSavefont = (HFONT)SelectObject(fDDC, fFont);
|
||||||
|
|
||||||
|
if (needToRenderWithSkia(fRec)) {
|
||||||
|
this->forceGenerateImageFromPath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SkScalerContext_Windows::~SkScalerContext_Windows() {
|
SkScalerContext_Windows::~SkScalerContext_Windows() {
|
||||||
@ -948,17 +983,6 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
|
|||||||
return NULL;
|
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) {
|
void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
|
||||||
unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
|
unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
|
||||||
SkScalerContext::kAutohinting_Flag |
|
SkScalerContext::kAutohinting_Flag |
|
||||||
|
Loading…
Reference in New Issue
Block a user