From c7378af961cabef5b77c4dae40d8d3b9c1471a9e Mon Sep 17 00:00:00 2001 From: herb Date: Wed, 21 Oct 2015 09:24:37 -0700 Subject: [PATCH] Add a mutex to protect the DWrite calls. BUG=skia:4479 Review URL: https://codereview.chromium.org/1421433004 --- src/ports/SkScalerContext_win_dw.cpp | 118 ++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 43 deletions(-) diff --git a/src/ports/SkScalerContext_win_dw.cpp b/src/ports/SkScalerContext_win_dw.cpp index e259479..eec6566 100644 --- a/src/ports/SkScalerContext_win_dw.cpp +++ b/src/ports/SkScalerContext_win_dw.cpp @@ -15,6 +15,7 @@ #include "SkHRESULT.h" #include "SkMaskGamma.h" #include "SkMatrix22.h" +#include "SkMutex.h" #include "SkOTTable_EBLC.h" #include "SkOTTable_EBSC.h" #include "SkOTTable_gasp.h" @@ -30,11 +31,30 @@ # include #endif +/* Note: + * In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe. + * The DWriteFactoryMutex protects the calls that are problematic. + */ +SK_DECLARE_STATIC_MUTEX(DWriteFactoryMutex); + +class Exclusive { +public: + Exclusive(SkBaseMutex& mutex) : fMutex(mutex) { + fMutex.acquire(); + } + ~Exclusive() { + fMutex.release(); + } +private: + SkBaseMutex& fMutex; +}; + static bool isLCD(const SkScalerContext::Rec& rec) { return SkMask::kLCD16_Format == rec.fMaskFormat; } static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { + Exclusive l(DWriteFactoryMutex); AutoTDWriteTable maxp(typeface->fDWriteFontFace.get()); if (!maxp.fExists) { return false; @@ -104,6 +124,7 @@ static void expand_range_if_gridfit_only(DWriteFontTypeface* typeface, int size, } static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) { + Exclusive l(DWriteFactoryMutex); { AutoTDWriteTable eblc(typeface->fDWriteFontFace.get()); if (!eblc.fExists) { @@ -337,6 +358,7 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) { + Exclusive l(DWriteFactoryMutex); HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( fTextSizeMeasure, 1.0f, // pixelsPerDip @@ -346,12 +368,16 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { &gm), "Could not get gdi compatible glyph metrics."); } else { + Exclusive l(DWriteFactoryMutex); HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), "Could not get design metrics."); } DWRITE_FONT_METRICS dwfm; - fTypeface->fDWriteFontFace->GetMetrics(&dwfm); + { + Exclusive l(DWriteFactoryMutex); + fTypeface->fDWriteFontFace->GetMetrics(&dwfm); + } SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, SkIntToScalar(gm.advanceWidth), SkIntToScalar(dwfm.designUnitsPerEm)); @@ -398,9 +424,10 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, run.glyphIndices = &glyphId; run.isSideways = FALSE; run.glyphOffsets = &offset; - - SkTScopedComPtr glyphRunAnalysis; - HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( + { + Exclusive l(DWriteFactoryMutex); + SkTScopedComPtr glyphRunAnalysis; + HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( &run, 1.0f, // pixelsPerDip, &fXform, @@ -409,11 +436,11 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph, 0.0f, // baselineOriginX, 0.0f, // baselineOriginY, &glyphRunAnalysis), - "Could not create glyph run analysis."); - - HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), - "Could not get texture bounds."); + "Could not create glyph run analysis."); + HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox), + "Could not get texture bounds."); + } return S_OK; } @@ -651,30 +678,32 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph, run.glyphIndices = &index; run.isSideways = FALSE; run.glyphOffsets = &offset; - - SkTScopedComPtr glyphRunAnalysis; - HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, - 1.0f, // pixelsPerDip, - &fXform, - renderingMode, - fMeasuringMode, - 0.0f, // baselineOriginX, - 0.0f, // baselineOriginY, - &glyphRunAnalysis), - "Could not create glyph run analysis."); - - //NOTE: this assumes that the glyph has already been measured - //with an exact same glyph run analysis. - RECT bbox; - bbox.left = glyph.fLeft; - bbox.top = glyph.fTop; - bbox.right = glyph.fLeft + glyph.fWidth; - bbox.bottom = glyph.fTop + glyph.fHeight; - HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, - &bbox, - fBits.begin(), - sizeNeeded), - "Could not draw mask."); + { + Exclusive l(DWriteFactoryMutex); + SkTScopedComPtr glyphRunAnalysis; + HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, + 1.0f, // pixelsPerDip, + &fXform, + renderingMode, + fMeasuringMode, + 0.0f, // baselineOriginX, + 0.0f, // baselineOriginY, + &glyphRunAnalysis), + "Could not create glyph run analysis."); + + //NOTE: this assumes that the glyph has already been measured + //with an exact same glyph run analysis. + RECT bbox; + bbox.left = glyph.fLeft; + bbox.top = glyph.fTop; + bbox.right = glyph.fLeft + glyph.fWidth; + bbox.bottom = glyph.fTop + glyph.fHeight; + HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType, + &bbox, + fBits.begin(), + sizeNeeded), + "Could not draw mask."); + } return fBits.begin(); } @@ -730,17 +759,20 @@ void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), "Could not create geometry to path converter."); uint16_t glyphId = glyph.getGlyphID(); - //TODO: convert to<->from DIUs? This would make a difference if hinting. - //It may not be needed, it appears that DirectWrite only hints at em size. - HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), - &glyphId, - nullptr, //advances - nullptr, //offsets - 1, //num glyphs - FALSE, //sideways - FALSE, //rtl - geometryToPath.get()), - "Could not create glyph outline."); + { + Exclusive l(DWriteFactoryMutex); + //TODO: convert to<->from DIUs? This would make a difference if hinting. + //It may not be needed, it appears that DirectWrite only hints at em size. + HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), + &glyphId, + nullptr, //advances + nullptr, //offsets + 1, //num glyphs + FALSE, //sideways + FALSE, //rtl + geometryToPath.get()), + "Could not create glyph outline."); + } path->transform(fSkXform); } -- 2.7.4