Chromium Code Reviews| 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..f4199ff6f80ab09124a1bd19f353115b4525c3d8 100644 |
| --- a/src/ports/SkScalerContext_win_dw.cpp |
| +++ b/src/ports/SkScalerContext_win_dw.cpp |
| @@ -10,6 +10,7 @@ |
| #undef GetGlyphIndices |
| +#include "SkCanvas.h" |
| #include "SkDWrite.h" |
| #include "SkDWriteGeometrySink.h" |
| #include "SkEndian.h" |
| @@ -210,6 +211,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 +467,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 +516,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 +766,80 @@ 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()); |
| + |
| + SkAutoTUnref<SkCanvas> canvas( |
|
reed1
2016/05/20 12:27:32
If this routine shows up in a profile, two ways to
Ilya Kulshin
2016/05/20 20:34:56
Haven't had a chance to profile this, but switched
|
| + SkCanvas::NewRasterDirect( |
| + SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType), |
| + glyph.fImage, |
| + glyph.ComputeRowBytes(glyph.fWidth, SkMask::Format::kARGB32_Format))); |
| + |
| + 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(colorGlyph->runColor.a * 255, |
| + colorGlyph->runColor.r * 255, |
| + colorGlyph->runColor.g * 255, |
| + 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, |
| + // so I'm not sure it's even possible (it might be reserved for a run with a mix of |
| + // color and non-color glyphs, which never happens here). 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); |
| + // If only DirectWrite had a "GetGlyphrunOutlineForThisGlyphRun" API... |
| + 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."); |
| + } |
| + |
| + path.transform(fSkXform); |
| + path.offset(-glyph.fLeft, -glyph.fTop); |
| + canvas->drawPath(path, paint); |
| + } |
| + canvas->flush(); |
|
reed1
2016/05/20 12:27:32
not needed, since the canvas goes out of scope bef
Ilya Kulshin
2016/05/20 20:34:55
Acknowledged.
|
| +} |
| +#endif |
| + |
| void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { |
| //Create the mask. |
| DWRITE_RENDERING_MODE renderingMode = fRenderingMode; |
| @@ -718,6 +848,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()); |