diff options
author | kulshin <kulshin@chromium.org> | 2016-06-01 08:31:28 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-06-01 08:31:28 -0700 |
commit | c4b091543b4082fd1a2f356ef3b478073c5f9418 (patch) | |
tree | 7c8c9906ce58ab635405a510988894594c55b986 /src/ports/SkScalerContext_win_dw.cpp | |
parent | 740cc88ee3d63c75e52d31238f2a32600cc57a8c (diff) |
Implement support for rendering color emoji on Windows
This change adds support to the DirectWrite scaler context
for detection of color fonts. If it detects a color font and
the glyph is a color glyph, it will use DirectWrite's
TranslateColorGlyphRun API and generate an image of the
glyph that can then be rendered.
Chromium tests: https://codereview.chromium.org/2003853002
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1984943002
Review-Url: https://codereview.chromium.org/1984943002
Diffstat (limited to 'src/ports/SkScalerContext_win_dw.cpp')
-rw-r--r-- | src/ports/SkScalerContext_win_dw.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/ports/SkScalerContext_win_dw.cpp b/src/ports/SkScalerContext_win_dw.cpp index 4609d04851..6f1d6fedc3 100644 --- a/src/ports/SkScalerContext_win_dw.cpp +++ b/src/ports/SkScalerContext_win_dw.cpp @@ -10,6 +10,7 @@ #undef GetGlyphIndices +#include "SkDraw.h" #include "SkDWrite.h" #include "SkDWriteGeometrySink.h" #include "SkEndian.h" @@ -23,6 +24,7 @@ #include "SkOTTable_gasp.h" #include "SkOTTable_maxp.h" #include "SkPath.h" +#include "SkRasterClip.h" #include "SkScalerContext.h" #include "SkScalerContext_win_dw.h" #include "SkSharedMutex.h" @@ -210,6 +212,14 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, , fTypeface(SkRef(typeface)) , fGlyphCount(-1) { +#if SK_HAS_DWRITE_2_H + fTypeface->fFactory->QueryInterface<IDWriteFactory2>(&fFactory2); + + SkTScopedComPtr<IDWriteFontFace2> fontFace2; + fTypeface->fDWriteFontFace->QueryInterface<IDWriteFontFace2>(&fontFace2); + fIsColorFont = fFactory2.get() && fontFace2.get() && fontFace2->IsColorFont(); +#endif + // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC // except when bi-level rendering is requested or there are embedded // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). @@ -458,6 +468,47 @@ static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) { return true; } +bool SkScalerContext_DW::isColorGlyph(const SkGlyph& glyph) { +#if SK_HAS_DWRITE_2_H + SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayer; + if (getColorGlyphRun(glyph, &colorLayer)) { + return true; + } +#endif + return false; +} + +#if SK_HAS_DWRITE_2_H +bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph, + IDWriteColorGlyphRunEnumerator** colorGlyph) +{ + FLOAT advance = 0; + UINT16 glyphId = glyph.getGlyphID(); + + DWRITE_GLYPH_OFFSET offset; + offset.advanceOffset = 0.0f; + offset.ascenderOffset = 0.0f; + + DWRITE_GLYPH_RUN run; + run.glyphCount = 1; + run.glyphAdvances = &advance; + run.fontFace = fTypeface->fDWriteFontFace.get(); + run.fontEmSize = SkScalarToFloat(fTextSizeRender); + run.bidiLevel = 0; + run.glyphIndices = &glyphId; + run.isSideways = FALSE; + run.glyphOffsets = &offset; + + HRESULT hr = fFactory2->TranslateColorGlyphRun( + 0, 0, &run, nullptr, fMeasuringMode, &fXform, 0, colorGlyph); + if (hr == DWRITE_E_NOCOLOR) { + return false; + } + HRBM(hr, "Failed to translate color glyph run"); + return true; +} +#endif + void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { glyph->fWidth = 0; glyph->fHeight = 0; @@ -466,6 +517,12 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { this->generateAdvance(glyph); +#if SK_HAS_DWRITE_2_H + if (fIsColorFont && isColorGlyph(*glyph)) { + glyph->fMaskFormat = SkMask::kARGB32_Format; + } +#endif + RECT bbox; HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox), "Requested bounding box could not be determined."); @@ -710,6 +767,77 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, return fBits.begin(); } +#if SK_HAS_DWRITE_2_H +void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) { + SkASSERT(isColorGlyph(glyph)); + SkASSERT(glyph.fMaskFormat == SkMask::Format::kARGB32_Format); + + memset(glyph.fImage, 0, glyph.computeImageSize()); + + SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; + getColorGlyphRun(glyph, &colorLayers); + SkASSERT(colorLayers.get()); + + SkMatrix matrix = fSkXform; + matrix.postTranslate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); + SkRasterClip rc(SkIRect::MakeWH(glyph.fWidth, glyph.fHeight)); + SkDraw draw; + draw.fDst = SkPixmap(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType), + glyph.fImage, + glyph.ComputeRowBytes(glyph.fWidth, SkMask::Format::kARGB32_Format)); + draw.fMatrix = &matrix; + draw.fRC = &rc; + + SkPaint paint; + if (fRenderingMode != DWRITE_RENDERING_MODE_ALIASED) { + paint.setFlags(SkPaint::Flags::kAntiAlias_Flag); + } + + BOOL hasNextRun = FALSE; + while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { + const DWRITE_COLOR_GLYPH_RUN* colorGlyph; + HRVM(colorLayers->GetCurrentRun(&colorGlyph), "Could not get current color glyph run"); + + SkColor color; + if (colorGlyph->paletteIndex != 0xffff) { + color = SkColorSetARGB(SkFloatToIntRound(colorGlyph->runColor.a * 255), + SkFloatToIntRound(colorGlyph->runColor.r * 255), + SkFloatToIntRound(colorGlyph->runColor.g * 255), + SkFloatToIntRound(colorGlyph->runColor.b * 255)); + } else { + // If all components of runColor are 0 or (equivalently) paletteIndex is 0xFFFF then + // the 'current brush' is used. fRec.getLuminanceColor() is kinda sorta what is wanted + // here, but not really, it will often be the wrong value because it wan't designed for + // this. + // In practice, I've not encountered a color glyph that uses the current brush color. + // If this assert ever fires, we should verify that the color is rendered properly. + SkASSERT(false); + color = fRec.getLuminanceColor(); + } + paint.setColor(color); + + SkPath path; + SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; + HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath), + "Could not create geometry to path converter."); + { + Exclusive l(DWriteFactoryMutex); + HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline( + colorGlyph->glyphRun.fontEmSize, + colorGlyph->glyphRun.glyphIndices, + colorGlyph->glyphRun.glyphAdvances, + colorGlyph->glyphRun.glyphOffsets, + colorGlyph->glyphRun.glyphCount, + colorGlyph->glyphRun.isSideways, + colorGlyph->glyphRun.bidiLevel % 2, //rtl + geometryToPath.get()), + "Could not create glyph outline."); + } + draw.drawPath(path, paint, nullptr, true /* pathIsMutable */); + } +} +#endif + void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { //Create the mask. DWRITE_RENDERING_MODE renderingMode = fRenderingMode; @@ -718,6 +846,14 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { renderingMode = DWRITE_RENDERING_MODE_ALIASED; textureType = DWRITE_TEXTURE_ALIASED_1x1; } + +#if SK_HAS_DWRITE_2_H + if (SkMask::kARGB32_Format == glyph.fMaskFormat) { + generateColorGlyphImage(glyph); + return; + } +#endif + const void* bits = this->drawDWMask(glyph, renderingMode, textureType); if (!bits) { sk_bzero(glyph.fImage, glyph.computeImageSize()); |