DirectWrite to use aliased if ClearType is empty.

Some CJK fonts with some versions of DirectWrite return valid
data for bitmaps, but not for cleartype data.

For reference, two screenshots. M37 Stable and then with this patch:

http://imgur.com/9pf3rB9,EiTb6Li

See https://code.google.com/p/chromium/issues/detail?id=396624#c10 for
content of test html file.

R=eae@chromium.org, reed@google.com, shrikant@chromium.org, bungeman@chromium.org, cpu@chromium.org
BUG=chromium:407945

Review URL: https://codereview.chromium.org/504343007
This commit is contained in:
Ben Wagner 2014-08-27 19:17:41 -04:00
parent 56fa442503
commit b2f7fce9e0
3 changed files with 58 additions and 15 deletions

View File

@ -32,6 +32,7 @@ struct SkGlyph {
void* fDistanceField; void* fDistanceField;
uint8_t fMaskFormat; uint8_t fMaskFormat;
int8_t fRsbDelta, fLsbDelta; // used by auto-kerning int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
int8_t fForceBW;
void init(uint32_t id) { void init(uint32_t id) {
fID = id; fID = id;
@ -39,6 +40,7 @@ struct SkGlyph {
fPath = NULL; fPath = NULL;
fDistanceField = NULL; fDistanceField = NULL;
fMaskFormat = MASK_FORMAT_UNKNOWN; fMaskFormat = MASK_FORMAT_UNKNOWN;
fForceBW = 0;
} }
/** /**

View File

@ -398,11 +398,11 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY); glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
} }
void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { void SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
glyph->fWidth = 0; DWRITE_RENDERING_MODE renderingMode,
DWRITE_TEXTURE_TYPE textureType,
this->generateAdvance(glyph); RECT* bbox)
{
//Measure raster size. //Measure raster size.
fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
@ -430,16 +430,41 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
&run, &run,
1.0f, // pixelsPerDip, 1.0f, // pixelsPerDip,
&fXform, &fXform,
fRenderingMode, renderingMode,
fMeasuringMode, fMeasuringMode,
0.0f, // baselineOriginX, 0.0f, // baselineOriginX,
0.0f, // baselineOriginY, 0.0f, // baselineOriginY,
&glyphRunAnalysis), &glyphRunAnalysis),
"Could not create glyph run analysis."); "Could not create glyph run analysis.");
RECT bbox; HRVM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
"Could not get texture bounds."); "Could not get texture bounds.");
}
void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
glyph->fWidth = 0;
this->generateAdvance(glyph);
RECT bbox;
this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox);
// GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
// glyphs of the specified texture type. When this happens, try with the
// alternate texture type.
if (bbox.left == bbox.right || bbox.top == bbox.bottom) {
if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
this->getBoundingBox(glyph,
DWRITE_RENDERING_MODE_ALIASED,
DWRITE_TEXTURE_ALIASED_1x1,
&bbox);
if (bbox.left != bbox.right && bbox.top != bbox.bottom) {
glyph->fForceBW = 1;
}
}
// TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
// fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
}
glyph->fWidth = SkToU16(bbox.right - bbox.left); glyph->fWidth = SkToU16(bbox.right - bbox.left);
glyph->fHeight = SkToU16(bbox.bottom - bbox.top); glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
@ -602,9 +627,12 @@ static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
} }
} }
const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) { const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
DWRITE_RENDERING_MODE renderingMode,
DWRITE_TEXTURE_TYPE textureType)
{
int sizeNeeded = glyph.fWidth * glyph.fHeight; int sizeNeeded = glyph.fWidth * glyph.fHeight;
if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) { if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
sizeNeeded *= 3; sizeNeeded *= 3;
} }
if (sizeNeeded > fBits.count()) { if (sizeNeeded > fBits.count()) {
@ -639,7 +667,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
1.0f, // pixelsPerDip, 1.0f, // pixelsPerDip,
&fXform, &fXform,
fRenderingMode, renderingMode,
fMeasuringMode, fMeasuringMode,
0.0f, // baselineOriginX, 0.0f, // baselineOriginX,
0.0f, // baselineOriginY, 0.0f, // baselineOriginY,
@ -653,7 +681,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
bbox.top = glyph.fTop; bbox.top = glyph.fTop;
bbox.right = glyph.fLeft + glyph.fWidth; bbox.right = glyph.fLeft + glyph.fWidth;
bbox.bottom = glyph.fTop + glyph.fHeight; bbox.bottom = glyph.fTop + glyph.fHeight;
HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType, HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
&bbox, &bbox,
fBits.begin(), fBits.begin(),
sizeNeeded), sizeNeeded),
@ -663,7 +691,13 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
//Create the mask. //Create the mask.
const void* bits = this->drawDWMask(glyph); DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
DWRITE_TEXTURE_TYPE textureType = fTextureType;
if (glyph.fForceBW) {
renderingMode = DWRITE_RENDERING_MODE_ALIASED;
textureType = DWRITE_TEXTURE_ALIASED_1x1;
}
const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
if (!bits) { if (!bits) {
sk_bzero(glyph.fImage, glyph.computeImageSize()); sk_bzero(glyph.fImage, glyph.computeImageSize());
return; return;
@ -671,7 +705,7 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
//Copy the mask into the glyph. //Copy the mask into the glyph.
const uint8_t* src = (const uint8_t*)bits; const uint8_t* src = (const uint8_t*)bits;
if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) { if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
bilevel_to_bw(src, glyph); bilevel_to_bw(src, glyph);
const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
} else if (!isLCD(fRec)) { } else if (!isLCD(fRec)) {

View File

@ -33,7 +33,14 @@ protected:
virtual void generateFontMetrics(SkPaint::FontMetrics*) SK_OVERRIDE; virtual void generateFontMetrics(SkPaint::FontMetrics*) SK_OVERRIDE;
private: private:
const void* drawDWMask(const SkGlyph& glyph); const void* drawDWMask(const SkGlyph& glyph,
DWRITE_RENDERING_MODE renderingMode,
DWRITE_TEXTURE_TYPE textureType);
void getBoundingBox(SkGlyph* glyph,
DWRITE_RENDERING_MODE renderingMode,
DWRITE_TEXTURE_TYPE textureType,
RECT* bbox);
SkTDArray<uint8_t> fBits; SkTDArray<uint8_t> fBits;
/** The total matrix without the text height scale. */ /** The total matrix without the text height scale. */