aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ports/SkScalerContext_win_dw.cpp
diff options
context:
space:
mode:
authorGravatar kulshin <kulshin@chromium.org>2016-06-01 08:31:28 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-06-01 08:31:28 -0700
commitc4b091543b4082fd1a2f356ef3b478073c5f9418 (patch)
tree7c8c9906ce58ab635405a510988894594c55b986 /src/ports/SkScalerContext_win_dw.cpp
parent740cc88ee3d63c75e52d31238f2a32600cc57a8c (diff)
Implement support for rendering color emoji on Windows
This change adds support to the DirectWrite scaler context for detection of color fonts. If it detects a color font and the glyph is a color glyph, it will use DirectWrite's TranslateColorGlyphRun API and generate an image of the glyph that can then be rendered. Chromium tests: https://codereview.chromium.org/2003853002 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1984943002 Review-Url: https://codereview.chromium.org/1984943002
Diffstat (limited to 'src/ports/SkScalerContext_win_dw.cpp')
-rw-r--r--src/ports/SkScalerContext_win_dw.cpp136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/ports/SkScalerContext_win_dw.cpp b/src/ports/SkScalerContext_win_dw.cpp
index 4609d04851..6f1d6fedc3 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());