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