Introduce SkScopedStrike

A SkScopedStrike allows drawGlyphRunAsBMPWithPathFallback
to control the scope of SkStrikeInterface objects generated
by both RemoteGlyphCache and SkStrikeCache.

* introduce onAboutToExitScope() into the SkStrikeInterface

Change-Id: I87a1e623ee9a8375f4e063290d74a466f96c9933
Reviewed-on: https://skia-review.googlesource.com/c/191293
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp
index 7a26a62..04ce802 100644
--- a/src/core/SkGlyphRunPainter.cpp
+++ b/src/core/SkGlyphRunPainter.cpp
@@ -372,7 +372,7 @@
 
 template <typename EmptiesT, typename MasksT, typename PathsT>
 void SkGlyphRunListPainter::drawGlyphRunAsBMPWithPathFallback(
-        SkStrikeInterface* strike, const SkGlyphRun& glyphRun,
+        SkScopedStrike&& strike, const SkGlyphRun& glyphRun,
         SkPoint origin, const SkMatrix& deviceMatrix,
         EmptiesT&& processEmpties, MasksT&& processMasks, PathsT&& processPaths) {
     ScopedBuffers _ = this->ensureBuffers(glyphRun);
@@ -420,7 +420,7 @@
     }
     if (glyphCount > 0) {
         mapping.mapPoints(fPositions, glyphCount);
-        processMasks(SkSpan<const GlyphAndPos>{fMasks, SkTo<size_t>(glyphCount)}, strike);
+        processMasks(SkSpan<const GlyphAndPos>{fMasks, SkTo<size_t>(glyphCount)}, strike.get());
     }
     if (!fPaths.empty()) {
         processPaths(SkSpan<const GlyphAndPos>{fPaths});
@@ -826,9 +826,18 @@
             // Ensure the blob is set for bitmaptext
             this->setHasBitmap();
 
-            auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(
-                    runFont, runPaint, props, scalerContextFlags, viewMatrix);
-            run->setupFont(runPaint, runFont, cache->getDescriptor());
+            SkScalerContextEffects effects;
+            SkAutoDescriptor ad;
+
+            SkScalerContext::CreateDescriptorAndEffectsUsingPaint(runFont, runPaint,props,
+                    scalerContextFlags,viewMatrix, &ad, &effects);
+
+            SkTypeface* typeface = runFont.getTypefaceOrDefault();
+
+            auto strikeCache = SkStrikeCache::GlobalStrikeCache();
+            auto strike = strikeCache->findOrCreateScopedStrike(*ad.getDesc(), effects, *typeface);
+
+            run->setupFont(runPaint, runFont, strike->getDescriptor());
 
             auto processEmpties = [](SkSpan<const SkGlyph*>glyphs) {};
 
@@ -858,7 +867,7 @@
                 };
 
             glyphPainter->drawGlyphRunAsBMPWithPathFallback(
-                    cache.get(), glyphRun, origin, viewMatrix,
+                    std::move(strike), glyphRun, origin, viewMatrix,
                     std::move(processEmpties), std::move(processMasks), std::move(processPaths));
         }
     }
@@ -942,6 +951,8 @@
             SkScalerContextFlags::kFakeGammaAndBoostContrast, &effects);
     SkASSERT(glyphCacheState);
 
+    SkScopedStrike strike{glyphCacheState};
+
     auto processEmpties = [] (SkSpan<const SkGlyph*>glyphs) { };
 
     auto processMasks = [] (
@@ -950,7 +961,7 @@
     auto processPaths = [] (SkSpan<const SkGlyphRunListPainter::GlyphAndPos> paths) { };
 
     fPainter.drawGlyphRunAsBMPWithPathFallback(
-            glyphCacheState, glyphRun, origin, runMatrix,
+            std::move(strike), glyphRun, origin, runMatrix,
             std::move(processEmpties), std::move(processMasks), std::move(processPaths));
 }
 
diff --git a/src/core/SkGlyphRunPainter.h b/src/core/SkGlyphRunPainter.h
index 7b3d8fe..1e2a4a2 100644
--- a/src/core/SkGlyphRunPainter.h
+++ b/src/core/SkGlyphRunPainter.h
@@ -26,8 +26,17 @@
     virtual const SkDescriptor& getDescriptor() const = 0;
     virtual const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) = 0;
     virtual bool decideCouldDrawFromPath(const SkGlyph& glyph) = 0;
+    virtual void onAboutToExitScope() = 0;
+
+    struct Deleter {
+        void operator()(SkStrikeInterface* ptr) const {
+            ptr->onAboutToExitScope();
+        }
+    };
 };
 
+using SkScopedStrike = std::unique_ptr<SkStrikeInterface, SkStrikeInterface::Deleter>;
+
 class SkStrikeCommon {
 public:
     static SkVector PixelRounding(bool isSubpixel, SkAxisAlignment axisAlignment);
@@ -80,7 +89,7 @@
 
     template <typename EmptiesT, typename MasksT, typename PathsT>
     void drawGlyphRunAsBMPWithPathFallback(
-            SkStrikeInterface* cache, const SkGlyphRun& glyphRun,
+            SkScopedStrike&& strike, const SkGlyphRun& glyphRun,
             SkPoint origin, const SkMatrix& deviceMatrix,
             EmptiesT&& processEmpties, MasksT&& processMasks, PathsT&& processPaths);
 
diff --git a/src/core/SkRemoteGlyphCacheImpl.h b/src/core/SkRemoteGlyphCacheImpl.h
index 789f611..d36c1b7 100644
--- a/src/core/SkRemoteGlyphCacheImpl.h
+++ b/src/core/SkRemoteGlyphCacheImpl.h
@@ -41,6 +41,8 @@
 
     bool decideCouldDrawFromPath(const SkGlyph& glyph) override;
 
+    void onAboutToExitScope() override {}
+
 private:
     bool hasPendingGlyphs() const {
         return !fPendingGlyphImages.empty() || !fPendingGlyphPaths.empty();
diff --git a/src/core/SkStrike.cpp b/src/core/SkStrike.cpp
index c3c1179..20be04b 100644
--- a/src/core/SkStrike.cpp
+++ b/src/core/SkStrike.cpp
@@ -423,6 +423,8 @@
     return !glyph.isEmpty() && this->findPath(glyph) != nullptr;
 }
 
+void SkStrike::onAboutToExitScope() { }
+
 #ifdef SK_DEBUG
 void SkStrike::forceValidate() const {
     size_t memoryUsed = sizeof(*this);
diff --git a/src/core/SkStrike.h b/src/core/SkStrike.h
index d01b9a9..e5c3da3 100644
--- a/src/core/SkStrike.h
+++ b/src/core/SkStrike.h
@@ -129,6 +129,7 @@
 
     const SkDescriptor& getDescriptor() const override;
 
+    void onAboutToExitScope() override;
 
     /** Return the approx RAM usage for this cache. */
     size_t getMemoryUsed() const { return fMemoryUsed; }
diff --git a/src/core/SkStrikeCache.cpp b/src/core/SkStrikeCache.cpp
index 6d94740..eba1b6d 100644
--- a/src/core/SkStrikeCache.cpp
+++ b/src/core/SkStrikeCache.cpp
@@ -44,6 +44,10 @@
         return fCache.getDescriptor();
     }
 
+    void onAboutToExitScope() override {
+        fStrikeCache->attachNode(this);
+    }
+
     SkStrikeCache* const            fStrikeCache;
     Node*                           fNext{nullptr};
     Node*                           fPrev{nullptr};
@@ -165,6 +169,17 @@
     return node;
 }
 
+SkScopedStrike SkStrikeCache::findOrCreateScopedStrike(const SkDescriptor& desc,
+                                                       const SkScalerContextEffects& effects,
+                                                       const SkTypeface& typeface) {
+    Node* node = this->findAndDetachStrike(desc);
+    if (node == nullptr) {
+        auto scaler = CreateScalerContext(desc, effects, typeface);
+        node = this->createStrike(desc, std::move(scaler));
+    }
+    return SkScopedStrike{node};
+}
+
 SkExclusiveStrikePtr SkStrikeCache::FindOrCreateStrikeExclusive(
         const SkFont& font,
         const SkPaint& paint,
diff --git a/src/core/SkStrikeCache.h b/src/core/SkStrikeCache.h
index bcef370..374fe93 100644
--- a/src/core/SkStrikeCache.h
+++ b/src/core/SkStrikeCache.h
@@ -114,6 +114,10 @@
                                    SkStrike* targetCache);
     bool desperationSearchForPath(const SkDescriptor& desc, SkGlyphID glyphID, SkPath* path);
 
+    SkScopedStrike findOrCreateScopedStrike(const SkDescriptor& desc,
+                                            const SkScalerContextEffects& effects,
+                                            const SkTypeface& typeface);
+
     static ExclusiveStrikePtr FindOrCreateStrikeExclusive(
             const SkFont& font,
             const SkPaint& paint,