Only take DWrite mutex on older versions
If IDWriteFontFace4 is present on the created typeface, don't take any extra locks. This should imply a new enough dwrite.dll to avoid thread safety issues in the DirectWrite caches reported with Windows 8 and 8.1. Bug: chromium:615880 See-also: https://codereview.chromium.org/1421433004 See-also: https://codereview.chromium.org/1424093002 Change-Id: I4d7adfdbd2e7ef5fd22dc7b10c9bf25eea48651e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/418416 Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
parent
cc2d073020
commit
597da9e5e2
@ -41,25 +41,63 @@
|
||||
#include <dwrite_1.h>
|
||||
#include <dwrite_3.h>
|
||||
|
||||
namespace {
|
||||
|
||||
/* Note:
|
||||
* In versions 8 and 8.1 of Windows, some calls in DWrite are not thread safe.
|
||||
* The mutex returned from get_dwrite_factory_mutex() protects the calls that are
|
||||
* The mutex returned from maybe_dw_mutex protects the calls that are
|
||||
* problematic.
|
||||
*/
|
||||
static SkSharedMutex& get_dwrite_factory_mutex() {
|
||||
static SkSharedMutex* maybe_dw_mutex(DWriteFontTypeface& typeface) {
|
||||
static SkSharedMutex mutex;
|
||||
return mutex;
|
||||
return typeface.fDWriteFontFace4 ? nullptr : &mutex;
|
||||
}
|
||||
|
||||
typedef SkAutoSharedMutexExclusive Exclusive;
|
||||
typedef SkAutoSharedMutexShared Shared;
|
||||
class SK_SCOPED_CAPABILITY Exclusive {
|
||||
public:
|
||||
explicit Exclusive(SkSharedMutex* maybe_lock) SK_ACQUIRE(*maybe_lock)
|
||||
: fLock(maybe_lock) {
|
||||
if (fLock) {
|
||||
fLock->acquire();
|
||||
}
|
||||
}
|
||||
~Exclusive() SK_RELEASE_CAPABILITY() {
|
||||
if (fLock) {
|
||||
fLock->release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkSharedMutex* fLock;
|
||||
};
|
||||
class SK_SCOPED_CAPABILITY Shared {
|
||||
public:
|
||||
explicit Shared(SkSharedMutex* maybe_lock) SK_ACQUIRE_SHARED(*maybe_lock)
|
||||
: fLock(maybe_lock) {
|
||||
if (fLock) {
|
||||
fLock->acquireShared();
|
||||
}
|
||||
}
|
||||
|
||||
// You would think this should be SK_RELEASE_SHARED_CAPABILITY, but SK_SCOPED_CAPABILITY
|
||||
// doesn't fully understand the difference between shared and exclusive.
|
||||
// Please review https://reviews.llvm.org/D52578 for more information.
|
||||
~Shared() SK_RELEASE_CAPABILITY() {
|
||||
if (fLock) {
|
||||
fLock->releaseShared();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkSharedMutex* fLock;
|
||||
};
|
||||
|
||||
static bool isLCD(const SkScalerContextRec& rec) {
|
||||
return SkMask::kLCD16_Format == rec.fMaskFormat;
|
||||
}
|
||||
|
||||
static bool is_hinted(DWriteFontTypeface* typeface) {
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
Exclusive l(maybe_dw_mutex(*typeface));
|
||||
AutoTDWriteTable<SkOTTableMaximumProfile> maxp(typeface->fDWriteFontFace.get());
|
||||
if (!maxp.fExists) {
|
||||
return false;
|
||||
@ -130,7 +168,7 @@ static bool is_gridfit_only(GaspRange::Behavior flags) {
|
||||
}
|
||||
|
||||
static bool has_bitmap_strike(DWriteFontTypeface* typeface, GaspRange range) {
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
Exclusive l(maybe_dw_mutex(*typeface));
|
||||
{
|
||||
AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWriteFontFace.get());
|
||||
if (!eblc.fExists) {
|
||||
@ -215,6 +253,8 @@ static bool is_axis_aligned(const SkScalerContextRec& rec) {
|
||||
both_zero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
|
||||
}
|
||||
|
||||
} //namespace
|
||||
|
||||
SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef,
|
||||
const SkScalerContextEffects& effects,
|
||||
const SkDescriptor* desc)
|
||||
@ -386,8 +426,8 @@ SkScalerContext_DW::~SkScalerContext_DW() {
|
||||
bool SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
|
||||
glyph->fAdvanceX = 0;
|
||||
glyph->fAdvanceY = 0;
|
||||
|
||||
uint16_t glyphId = glyph->getGlyphID();
|
||||
DWriteFontTypeface* typeface = this->getDWriteTypeface();
|
||||
|
||||
// DirectWrite treats all out of bounds glyph ids as having the same data as glyph 0.
|
||||
// For consistency with all other backends, treat out of range glyph ids as an error.
|
||||
@ -400,8 +440,8 @@ bool SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
|
||||
if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode ||
|
||||
DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode)
|
||||
{
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
|
||||
Exclusive l(maybe_dw_mutex(*typeface));
|
||||
HRBM(typeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics(
|
||||
fTextSizeMeasure,
|
||||
1.0f, // pixelsPerDip
|
||||
// This parameter does not act like the lpmat2 parameter to GetGlyphOutlineW.
|
||||
@ -412,15 +452,15 @@ bool SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
|
||||
&gm),
|
||||
"Could not get gdi compatible glyph metrics.");
|
||||
} else {
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
|
||||
Exclusive l(maybe_dw_mutex(*typeface));
|
||||
HRBM(typeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm),
|
||||
"Could not get design metrics.");
|
||||
}
|
||||
|
||||
DWRITE_FONT_METRICS dwfm;
|
||||
{
|
||||
Shared l(get_dwrite_factory_mutex());
|
||||
this->getDWriteTypeface()->fDWriteFontFace->GetMetrics(&dwfm);
|
||||
Shared l(maybe_dw_mutex(*typeface));
|
||||
typeface->fDWriteFontFace->GetMetrics(&dwfm);
|
||||
}
|
||||
SkScalar advanceX = fTextSizeMeasure * gm.advanceWidth / dwfm.designUnitsPerEm;
|
||||
|
||||
@ -444,6 +484,8 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
|
||||
DWRITE_TEXTURE_TYPE textureType,
|
||||
RECT* bbox)
|
||||
{
|
||||
DWriteFontTypeface* typeface = this->getDWriteTypeface();
|
||||
|
||||
//Measure raster size.
|
||||
fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
|
||||
fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
|
||||
@ -459,7 +501,7 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
|
||||
DWRITE_GLYPH_RUN run;
|
||||
run.glyphCount = 1;
|
||||
run.glyphAdvances = &advance;
|
||||
run.fontFace = this->getDWriteTypeface()->fDWriteFontFace.get();
|
||||
run.fontFace = typeface->fDWriteFontFace.get();
|
||||
run.fontEmSize = SkScalarToFloat(fTextSizeRender);
|
||||
run.bidiLevel = 0;
|
||||
run.glyphIndices = &glyphId;
|
||||
@ -468,13 +510,13 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
|
||||
|
||||
SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
|
||||
{
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
Exclusive l(maybe_dw_mutex(*typeface));
|
||||
// IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
|
||||
if (this->getDWriteTypeface()->fFactory2 &&
|
||||
if (typeface->fFactory2 &&
|
||||
(fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
|
||||
fAntiAliasMode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE))
|
||||
{
|
||||
HRM(this->getDWriteTypeface()->fFactory2->CreateGlyphRunAnalysis(
|
||||
HRM(typeface->fFactory2->CreateGlyphRunAnalysis(
|
||||
&run,
|
||||
&fXform,
|
||||
renderingMode,
|
||||
@ -486,7 +528,7 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
|
||||
&glyphRunAnalysis),
|
||||
"Could not create DW2 glyph run analysis.");
|
||||
} else {
|
||||
HRM(this->getDWriteTypeface()->fFactory->CreateGlyphRunAnalysis(&run,
|
||||
HRM(typeface->fFactory->CreateGlyphRunAnalysis(&run,
|
||||
1.0f, // pixelsPerDip,
|
||||
&fXform,
|
||||
renderingMode,
|
||||
@ -498,7 +540,7 @@ HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
|
||||
}
|
||||
}
|
||||
{
|
||||
Shared l(get_dwrite_factory_mutex());
|
||||
Shared l(maybe_dw_mutex(*typeface));
|
||||
HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
|
||||
"Could not get texture bounds.");
|
||||
}
|
||||
@ -553,7 +595,9 @@ bool SkScalerContext_DW::getColorGlyphRun(const SkGlyph& glyph,
|
||||
|
||||
void SkScalerContext_DW::generateColorMetrics(SkGlyph* glyph) {
|
||||
SkTScopedComPtr<IDWriteColorGlyphRunEnumerator> colorLayers;
|
||||
HRVM(getColorGlyphRun(*glyph, &colorLayers), "Could not get color glyph run");
|
||||
if (!getColorGlyphRun(*glyph, &colorLayers)) {
|
||||
return;
|
||||
}
|
||||
SkASSERT(colorLayers.get());
|
||||
|
||||
SkRect bounds = SkRect::MakeEmpty();
|
||||
@ -567,7 +611,7 @@ void SkScalerContext_DW::generateColorMetrics(SkGlyph* glyph) {
|
||||
HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
|
||||
"Could not create geometry to path converter.");
|
||||
{
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
|
||||
HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
|
||||
colorGlyph->glyphRun.fontEmSize,
|
||||
colorGlyph->glyphRun.glyphIndices,
|
||||
@ -923,6 +967,8 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
|
||||
DWRITE_RENDERING_MODE renderingMode,
|
||||
DWRITE_TEXTURE_TYPE textureType)
|
||||
{
|
||||
DWriteFontTypeface* typeface = this->getDWriteTypeface();
|
||||
|
||||
int sizeNeeded = glyph.width() * glyph.height();
|
||||
if (DWRITE_TEXTURE_CLEARTYPE_3x1 == textureType) {
|
||||
sizeNeeded *= 3;
|
||||
@ -957,7 +1003,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
|
||||
{
|
||||
SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
|
||||
{
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
Exclusive l(maybe_dw_mutex(*typeface));
|
||||
// IDWriteFactory2::CreateGlyphRunAnalysis is very bad at aliased glyphs.
|
||||
if (this->getDWriteTypeface()->fFactory2 &&
|
||||
(fGridFitMode == DWRITE_GRID_FIT_MODE_DISABLED ||
|
||||
@ -993,7 +1039,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
|
||||
bbox.right = glyph.left() + glyph.width();
|
||||
bbox.bottom = glyph.top() + glyph.height();
|
||||
{
|
||||
Shared l(get_dwrite_factory_mutex());
|
||||
Shared l(maybe_dw_mutex(*typeface));
|
||||
HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
|
||||
&bbox,
|
||||
fBits.begin(),
|
||||
@ -1058,7 +1104,7 @@ void SkScalerContext_DW::generateColorGlyphImage(const SkGlyph& glyph) {
|
||||
HRVM(SkDWriteGeometrySink::Create(&path, &geometryToPath),
|
||||
"Could not create geometry to path converter.");
|
||||
{
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
|
||||
HRVM(colorGlyph->glyphRun.fontFace->GetGlyphRunOutline(
|
||||
colorGlyph->glyphRun.fontEmSize,
|
||||
colorGlyph->glyphRun.glyphIndices,
|
||||
@ -1198,7 +1244,7 @@ bool SkScalerContext_DW::generatePath(SkGlyphID glyph, SkPath* path) {
|
||||
"Could not create geometry to path converter.");
|
||||
UINT16 glyphId = SkTo<UINT16>(glyph);
|
||||
{
|
||||
Exclusive l(get_dwrite_factory_mutex());
|
||||
Exclusive l(maybe_dw_mutex(*this->getDWriteTypeface()));
|
||||
//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.
|
||||
HRBM(this->getDWriteTypeface()->fDWriteFontFace->GetGlyphRunOutline(
|
||||
|
Loading…
Reference in New Issue
Block a user