Add a mutex to protect the DWrite calls.

BUG=skia:4479

Review URL: https://codereview.chromium.org/1421433004
This commit is contained in:
herb 2015-10-21 09:24:37 -07:00 committed by Commit bot
parent fb02cdafda
commit c7378af961

View File

@ -15,6 +15,7 @@
#include "SkHRESULT.h" #include "SkHRESULT.h"
#include "SkMaskGamma.h" #include "SkMaskGamma.h"
#include "SkMatrix22.h" #include "SkMatrix22.h"
#include "SkMutex.h"
#include "SkOTTable_EBLC.h" #include "SkOTTable_EBLC.h"
#include "SkOTTable_EBSC.h" #include "SkOTTable_EBSC.h"
#include "SkOTTable_gasp.h" #include "SkOTTable_gasp.h"
@ -30,11 +31,30 @@
# include <dwrite_1.h> # include <dwrite_1.h>
#endif #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) { static bool isLCD(const SkScalerContext::Rec& rec) {
return SkMask::kLCD16_Format == rec.fMaskFormat; return SkMask::kLCD16_Format == rec.fMaskFormat;
} }
static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) { static bool is_hinted_without_gasp(DWriteFontTypeface* typeface) {
Exclusive l(DWriteFactoryMutex);
AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get()); AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
if (!maxp.fExists) { if (!maxp.fExists) {
return false; 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) { static bool has_bitmap_strike(DWriteFontTypeface* typeface, PPEMRange range) {
Exclusive l(DWriteFactoryMutex);
{ {
AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get()); AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
if (!eblc.fExists) { if (!eblc.fExists) {
@ -337,6 +358,7 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
{ {
Exclusive l(DWriteFactoryMutex);
HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
fTextSizeMeasure, fTextSizeMeasure,
1.0f, // pixelsPerDip 1.0f, // pixelsPerDip
@ -346,12 +368,16 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
&gm), &gm),
"Could not get gdi compatible glyph metrics."); "Could not get gdi compatible glyph metrics.");
} else { } else {
Exclusive l(DWriteFactoryMutex);
HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm), HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
"Could not get design metrics."); "Could not get design metrics.");
} }
DWRITE_FONT_METRICS dwfm; DWRITE_FONT_METRICS dwfm;
fTypeface->fDWriteFontFace->GetMetrics(&dwfm); {
Exclusive l(DWriteFactoryMutex);
fTypeface->fDWriteFontFace->GetMetrics(&dwfm);
}
SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure,
SkIntToScalar(gm.advanceWidth), SkIntToScalar(gm.advanceWidth),
SkIntToScalar(dwfm.designUnitsPerEm)); SkIntToScalar(dwfm.designUnitsPerEm));
@ -398,9 +424,10 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
run.glyphIndices = &glyphId; run.glyphIndices = &glyphId;
run.isSideways = FALSE; run.isSideways = FALSE;
run.glyphOffsets = &offset; run.glyphOffsets = &offset;
{
SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; Exclusive l(DWriteFactoryMutex);
HRM(fTypeface->fFactory->CreateGlyphRunAnalysis( SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
&run, &run,
1.0f, // pixelsPerDip, 1.0f, // pixelsPerDip,
&fXform, &fXform,
@ -409,11 +436,11 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
0.0f, // baselineOriginX, 0.0f, // baselineOriginX,
0.0f, // baselineOriginY, 0.0f, // baselineOriginY,
&glyphRunAnalysis), &glyphRunAnalysis),
"Could not create glyph run analysis."); "Could not create glyph run analysis.");
HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
"Could not get texture bounds.");
HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
"Could not get texture bounds.");
}
return S_OK; return S_OK;
} }
@ -651,30 +678,32 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
run.glyphIndices = &index; run.glyphIndices = &index;
run.isSideways = FALSE; run.isSideways = FALSE;
run.glyphOffsets = &offset; run.glyphOffsets = &offset;
{
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.");
SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; //NOTE: this assumes that the glyph has already been measured
HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, //with an exact same glyph run analysis.
1.0f, // pixelsPerDip, RECT bbox;
&fXform, bbox.left = glyph.fLeft;
renderingMode, bbox.top = glyph.fTop;
fMeasuringMode, bbox.right = glyph.fLeft + glyph.fWidth;
0.0f, // baselineOriginX, bbox.bottom = glyph.fTop + glyph.fHeight;
0.0f, // baselineOriginY, HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
&glyphRunAnalysis), &bbox,
"Could not create glyph run analysis."); fBits.begin(),
sizeNeeded),
//NOTE: this assumes that the glyph has already been measured "Could not draw mask.");
//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(); return fBits.begin();
} }
@ -730,17 +759,20 @@ void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) {
HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath),
"Could not create geometry to path converter."); "Could not create geometry to path converter.");
uint16_t glyphId = glyph.getGlyphID(); 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. Exclusive l(DWriteFactoryMutex);
HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender), //TODO: convert to<->from DIUs? This would make a difference if hinting.
&glyphId, //It may not be needed, it appears that DirectWrite only hints at em size.
nullptr, //advances HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSizeRender),
nullptr, //offsets &glyphId,
1, //num glyphs nullptr, //advances
FALSE, //sideways nullptr, //offsets
FALSE, //rtl 1, //num glyphs
geometryToPath.get()), FALSE, //sideways
"Could not create glyph outline."); FALSE, //rtl
geometryToPath.get()),
"Could not create glyph outline.");
}
path->transform(fSkXform); path->transform(fSkXform);
} }