aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/ports/SkFontMgr_fontconfig.cpp24
1 files changed, 19 insertions, 5 deletions
diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp
index be4b17dd12..95c963d69f 100644
--- a/src/ports/SkFontMgr_fontconfig.cpp
+++ b/src/ports/SkFontMgr_fontconfig.cpp
@@ -73,10 +73,9 @@ void DeleteThreadFcLocked(void* v) { delete static_cast<bool*>(v); }
static_cast<bool*>(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcLocked))
#endif
-struct FCLocker {
+class FCLocker {
// Assume FcGetVersion() has always been thread safe.
-
- FCLocker() {
+ static void lock() {
if (FcGetVersion() < 21091) {
gFCMutex.acquire();
} else {
@@ -85,8 +84,7 @@ struct FCLocker {
SkDEBUGCODE(*threadLocked = true);
}
}
-
- ~FCLocker() {
+ static void unlock() {
AssertHeld();
if (FcGetVersion() < 21091) {
gFCMutex.release();
@@ -95,6 +93,20 @@ struct FCLocker {
}
}
+public:
+ FCLocker() { lock(); }
+ ~FCLocker() { unlock(); }
+
+ /** If acquire and release were free, FCLocker would be used around each call into FontConfig.
+ * Instead a much more granular approach is taken, but this means there are times when the
+ * mutex is held when it should not be. A Suspend will drop the lock until it is destroyed.
+ * While a Suspend exists, FontConfig should not be used without re-taking the lock.
+ */
+ struct Suspend {
+ Suspend() { unlock(); }
+ ~Suspend() { lock(); }
+ };
+
static void AssertHeld() { SkDEBUGCODE(
if (FcGetVersion() < 21091) {
gFCMutex.assertHeld();
@@ -652,6 +664,8 @@ class SkFontMgr_fontconfig : public SkFontMgr {
FcPatternReference(pattern);
face = SkTypeface_fontconfig::Create(pattern);
if (face) {
+ // Cannot hold the lock when calling add; an evicted typeface may need to lock.
+ FCLocker::Suspend suspend;
fTFCache.add(face);
}
}