make adding a text blob to GrTextBlobCache thread safe

Change-Id: I18d3b05e4913114e44905a6020baca90bf437320
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/375056
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrSurfaceDrawContext.cpp b/src/gpu/GrSurfaceDrawContext.cpp
index 3803946..51ee7eb 100644
--- a/src/gpu/GrSurfaceDrawContext.cpp
+++ b/src/gpu/GrSurfaceDrawContext.cpp
@@ -426,7 +426,9 @@
         blob = GrTextBlob::Make(glyphRunList, drawMatrix);
         if (canCache) {
             blob->addKey(key);
-            textBlobCache->add(glyphRunList, blob);
+            // The blob may already have been created on a different thread. Use the first one
+            // that was there.
+            blob = textBlobCache->addOrReturnExisting(glyphRunList, blob);
         }
 
         bool supportsSDFT = fContext->priv().caps()->shaderCaps()->supportsDistanceFieldText();
diff --git a/src/gpu/text/GrTextBlobCache.cpp b/src/gpu/text/GrTextBlobCache.cpp
index 815a775..baee93ee2 100644
--- a/src/gpu/text/GrTextBlobCache.cpp
+++ b/src/gpu/text/GrTextBlobCache.cpp
@@ -20,10 +20,12 @@
         , fMessageBusID(messageBusID)
         , fPurgeBlobInbox(messageBusID) { }
 
-void GrTextBlobCache::add(const SkGlyphRunList& glyphRunList, sk_sp<GrTextBlob> blob) {
+sk_sp<GrTextBlob> GrTextBlobCache::addOrReturnExisting(
+        const SkGlyphRunList& glyphRunList, sk_sp<GrTextBlob> blob) {
     SkAutoSpinlock lock{fSpinLock};
-    this->internalAdd(std::move(blob));
+    blob = this->internalAdd(std::move(blob));
     glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID);
+    return blob;
 }
 
 sk_sp<GrTextBlob> GrTextBlobCache::find(const GrTextBlob::Key& key) {
@@ -133,20 +135,23 @@
     }
 }
 
-void GrTextBlobCache::internalAdd(sk_sp<GrTextBlob> blob) {
+sk_sp<GrTextBlob> GrTextBlobCache::internalAdd(sk_sp<GrTextBlob> blob) {
     auto  id      = GrTextBlob::GetKey(*blob).fUniqueID;
     auto* idEntry = fBlobIDCache.find(id);
     if (!idEntry) {
         idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id));
     }
 
-    // Safe to retain a raw ptr temporarily here, because the cache will hold a ref.
-    GrTextBlob* rawBlobPtr = blob.get();
-    fBlobList.addToHead(rawBlobPtr);
-    fCurrentSize += blob->size();
-    idEntry->addBlob(std::move(blob));
+    if (sk_sp<GrTextBlob> alreadyIn = idEntry->find(GrTextBlob::GetKey(*blob)); alreadyIn) {
+        blob = std::move(alreadyIn);
+    } else {
+        fBlobList.addToHead(blob.get());
+        fCurrentSize += blob->size();
+        idEntry->addBlob(blob);
+    }
 
-    this->internalCheckPurge(rawBlobPtr);
+    this->internalCheckPurge(blob.get());
+    return blob;
 }
 
 GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry() : fID(SK_InvalidGenID) {}
diff --git a/src/gpu/text/GrTextBlobCache.h b/src/gpu/text/GrTextBlobCache.h
index c973384..8e86092d 100644
--- a/src/gpu/text/GrTextBlobCache.h
+++ b/src/gpu/text/GrTextBlobCache.h
@@ -22,8 +22,9 @@
 public:
     GrTextBlobCache(uint32_t messageBusID);
 
-    void add(const SkGlyphRunList& glyphRunList,
-             sk_sp<GrTextBlob> blob) SK_EXCLUDES(fSpinLock);
+    // If not already in the cache, then add it else, return the text blob from the cache.
+    sk_sp<GrTextBlob> addOrReturnExisting(
+            const SkGlyphRunList& glyphRunList, sk_sp<GrTextBlob> blob) SK_EXCLUDES(fSpinLock);
 
     sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) SK_EXCLUDES(fSpinLock);
 
@@ -73,7 +74,7 @@
 
     void internalPurgeStaleBlobs() SK_REQUIRES(fSpinLock);
 
-    void internalAdd(sk_sp<GrTextBlob> blob) SK_REQUIRES(fSpinLock);
+    sk_sp<GrTextBlob> internalAdd(sk_sp<GrTextBlob> blob) SK_REQUIRES(fSpinLock);
     void internalRemove(GrTextBlob* blob) SK_REQUIRES(fSpinLock);
 
     void internalCheckPurge(GrTextBlob* blob = nullptr) SK_REQUIRES(fSpinLock);