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()); |