Add a mutex to protect the DWrite calls.
authorherb <herb@google.com>
Wed, 21 Oct 2015 16:24:37 +0000 (09:24 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 21 Oct 2015 16:24:37 +0000 (09:24 -0700)
BUG=skia:4479

Review URL: https://codereview.chromium.org/1421433004

src/ports/SkScalerContext_win_dw.cpp

index e259479..eec6566 100644 (file)
@@ -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"
 #  include <dwrite_1.h>
 #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<SkOTTableMaximumProfile> 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<SkOTTableEmbeddedBitmapLocation> 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<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
-    HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
+    {
+        Exclusive l(DWriteFactoryMutex);
+        SkTScopedComPtr<IDWriteGlyphRunAnalysis> 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<IDWriteGlyphRunAnalysis> 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<IDWriteGlyphRunAnalysis> 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);
 }