Skip to content

Commit

Permalink
DirectWrite to use aliased if ClearType is empty.
Browse files Browse the repository at this point in the history
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:

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

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

[email protected], [email protected], [email protected], [email protected], [email protected]
BUG=chromium:407945

Review URL: https://codereview.chromium.org/504343007
  • Loading branch information
Ben Wagner committed Aug 27, 2014
1 parent 56fa442 commit b2f7fce
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/core/SkGlyph.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ struct SkGlyph {
void* fDistanceField;
uint8_t fMaskFormat;
int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
int8_t fForceBW;

void init(uint32_t id) {
fID = id;
fImage = NULL;
fPath = NULL;
fDistanceField = NULL;
fMaskFormat = MASK_FORMAT_UNKNOWN;
fForceBW = 0;
}

/**
Expand Down
62 changes: 48 additions & 14 deletions src/ports/SkScalerContext_win_dw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,11 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
}

void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
glyph->fWidth = 0;

this->generateAdvance(glyph);

void SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
DWRITE_RENDERING_MODE renderingMode,
DWRITE_TEXTURE_TYPE textureType,
RECT* bbox)
{
//Measure raster size.
fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
Expand Down Expand Up @@ -430,16 +430,41 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
&run,
1.0f, // pixelsPerDip,
&fXform,
fRenderingMode,
renderingMode,
fMeasuringMode,
0.0f, // baselineOriginX,
0.0f, // baselineOriginY,
&glyphRunAnalysis),
"Could not create glyph run analysis.");

RECT bbox;
HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
HRVM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
"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->fHeight = SkToU16(bbox.bottom - bbox.top);
Expand Down Expand Up @@ -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;
if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
sizeNeeded *= 3;
}
if (sizeNeeded > fBits.count()) {
Expand Down Expand Up @@ -639,7 +667,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
1.0f, // pixelsPerDip,
&fXform,
fRenderingMode,
renderingMode,
fMeasuringMode,
0.0f, // baselineOriginX,
0.0f, // baselineOriginY,
Expand All @@ -653,7 +681,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
bbox.top = glyph.fTop;
bbox.right = glyph.fLeft + glyph.fWidth;
bbox.bottom = glyph.fTop + glyph.fHeight;
HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType,
HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
&bbox,
fBits.begin(),
sizeNeeded),
Expand All @@ -663,15 +691,21 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {

void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
//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) {
sk_bzero(glyph.fImage, glyph.computeImageSize());
return;
}

//Copy the mask into the glyph.
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);
const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
} else if (!isLCD(fRec)) {
Expand Down
9 changes: 8 additions & 1 deletion src/ports/SkScalerContext_win_dw.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ class SkScalerContext_DW : public SkScalerContext {
virtual void generateFontMetrics(SkPaint::FontMetrics*) SK_OVERRIDE;

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;
/** The total matrix without the text height scale. */