| Index: src/ports/SkScalerContext_win_dw.cpp | 
| diff --git a/src/ports/SkScalerContext_win_dw.cpp b/src/ports/SkScalerContext_win_dw.cpp | 
| index 4609d04851870891c7b60bb32485e62af90255ed..6f1d6fedc324c0d7199674c8a459dff5a1c78325 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()); | 
|  |