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..2824ef0285ca70c94498b4c825355a4eea899cc2 100644 |
--- a/src/ports/SkScalerContext_win_dw.cpp |
+++ b/src/ports/SkScalerContext_win_dw.cpp |
@@ -210,6 +210,15 @@ SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, |
, fTypeface(SkRef(typeface)) |
, fGlyphCount(-1) { |
+#if SK_HAS_DWRITE_2_H |
+ SkTScopedComPtr<IDWriteFactory> factory(SkSafeRefComPtr(sk_get_dwrite_factory())); |
bungeman-skia
2016/05/18 14:50:55
You cannot create a factory here, you must use the
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+ factory->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,48 @@ 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, DWRITE_MEASURING_MODE_NATURAL, nullptr, 0, colorGlyph); |
bungeman-skia
2016/05/18 14:50:55
Need to pass in fXform and fMeasuringMode.
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+ if (SUCCEEDED(hr)) { |
+ return true; |
+ } else { |
+ SkASSERT(hr == DWRITE_E_NOCOLOR); |
+ } |
+ return false; |
bungeman-skia
2016/05/18 14:50:55
The return value handling here should be more like
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+} |
+#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,71 @@ 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)); |
+ HRESULT hr = S_OK; |
bungeman-skia
2016/05/18 14:50:55
Remove this.
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+ |
+ memset(glyph.fImage, 0, glyph.computeImageSize()); |
+ |
+ SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers; |
+ getColorGlyphRun(glyph, &colorLayers); |
+ SkASSERT(colorLayers.get()); |
+ |
+ int layerSize = glyph.fWidth * glyph.fHeight; // layers are drawn in monochrome |
+ SkASSERT_RELEASE(layerSize * sizeof(uint32_t) == glyph.computeImageSize()); |
+ fBits.setCount(layerSize); |
+ |
+ RECT bbox; |
+ bbox.left = glyph.fLeft; |
+ bbox.top = glyph.fTop; |
+ bbox.right = glyph.fLeft + glyph.fWidth; |
+ bbox.bottom = glyph.fTop + glyph.fHeight; |
+ |
+ BOOL hasNextRun = FALSE; |
+ while (SUCCEEDED(colorLayers->MoveNext(&hasNextRun)) && hasNextRun) { |
+ const DWRITE_COLOR_GLYPH_RUN* colorGlyph; |
+ if (!SUCCEEDED(colorLayers->GetCurrentRun(&colorGlyph))) { |
bungeman-skia
2016/05/18 14:50:55
Use the HRNM macro for proper logging and for cons
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+ SkASSERT(false); |
+ return; |
+ } |
+ |
+ SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; |
+ { |
+ Exclusive l(DWriteFactoryMutex); |
+ hr = fTypeface->fFactory->CreateGlyphRunAnalysis(&colorGlyph->glyphRun, |
bungeman-skia
2016/05/18 14:50:55
The result is never checked. Use the HRNM macro li
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+ 1.0f, // pixelsPerDip, |
+ nullptr, |
bungeman-skia
2016/05/18 14:50:55
If you don't pass the fXForm, how does this work f
Ilya Kulshin
2016/05/18 22:43:38
Added fXfrom, but I'm not sure when it will be som
bungeman-skia
2016/05/19 18:52:37
Any time there is skew/rotation.
|
+ DWRITE_RENDERING_MODE_ALIASED, |
+ DWRITE_MEASURING_MODE_NATURAL, |
bungeman-skia
2016/05/18 14:50:55
fRenderingMode and fMeasuringMode
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+ colorGlyph->baselineOriginX, |
+ colorGlyph->baselineOriginY, |
+ &glyphRunAnalysis); |
+ } |
+ //NOTE: this assumes that the glyph has already been measured |
+ //with an exact same glyph run analysis. |
+ { |
+ Shared l(DWriteFactoryMutex); |
+ hr = glyphRunAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_ALIASED_1x1, |
bungeman-skia
2016/05/18 14:50:55
HRNM, fRenderingMode
Ilya Kulshin
2016/05/18 22:43:38
Done.
|
+ &bbox, |
+ fBits.begin(), |
+ layerSize); |
+ } |
+ |
+ uint32_t* colorPixels = reinterpret_cast<uint32_t*>(glyph.fImage); |
+ SkColor color = SkColorSetARGB(colorGlyph->runColor.a * 255, |
bungeman-skia
2016/05/18 14:50:55
Note that if all components of runColor are 0 or (
Ilya Kulshin
2016/05/20 03:41:40
Changed to fRec.getLuminanceColor() and added a co
|
+ colorGlyph->runColor.r * 255, |
reed1
2016/05/18 00:42:53
is runColor premultiplied?
Ilya Kulshin
2016/05/18 00:56:46
I'm not actually sure. It's of type D3DCOLORVALUE.
|
+ colorGlyph->runColor.g * 255, |
+ colorGlyph->runColor.b * 255); |
+ for (int pixel = 0; pixel < layerSize; pixel++) { |
+ if (fBits[pixel] != 0) { |
bungeman-skia
2016/05/18 14:50:54
This seems like a really bad blend, this should be
Ilya Kulshin
2016/05/18 22:43:38
Originally I thought antialiasing/subpixel renderi
|
+ colorPixels[pixel] = color; |
+ } |
+ } |
+ } |
+} |
+#endif |
+ |
void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { |
//Create the mask. |
DWRITE_RENDERING_MODE renderingMode = fRenderingMode; |
@@ -718,6 +840,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()); |