Make fPathData private and add API for paths

The new API eliminates all need to access the path inner workings.

There are some uses of the cast (SkGlyph*) these are to facilitate
the larger change this is a part of. The will be eliminated when all
is done.

Some of the code has been changed to use strike->glyph(id) and SkGlyph*
to help with the flow of the code.

Change-Id: Id8dc84076f56e1e39450367a0440d15954dbdc71
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/220523
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 8b78272..ba675de 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -460,6 +460,12 @@
     */
     int getVerbs(uint8_t verbs[], int max) const;
 
+    /** Returns the approximate byte size of the SkPath in memory.
+
+        @return  approximate size
+    */
+    size_t approximateBytesUsed() const;
+
     /** Exchanges the verb array, SkPoint array, weights, and SkPath::FillType with other.
         Cached state is also exchanged. swap() internally exchanges pointers, so
         it is lightweight and does not allocate memory.
diff --git a/src/core/SkFont.cpp b/src/core/SkFont.cpp
index e9881e0..3026148 100644
--- a/src/core/SkFont.cpp
+++ b/src/core/SkFont.cpp
@@ -355,14 +355,14 @@
                       void (*proc)(const SkPath*, const SkMatrix&, void*), void* ctx) const {
     SkFont font(*this);
     SkScalar scale = font.setupForAsPaths(nullptr);
-    const SkMatrix mx = SkMatrix::MakeScale(scale, scale);
+    const SkMatrix mx = SkMatrix::MakeScale(scale);
 
     SkStrikeSpec strikeSpec = SkStrikeSpec::MakeCanonicalized(font);
     auto exclusive = strikeSpec.findOrCreateExclusiveStrike();
     auto cache = exclusive.get();
 
     for (int i = 0; i < count; ++i) {
-        proc(cache->findPath(cache->getGlyphIDMetrics(glyphs[i])), mx, ctx);
+        proc(cache->preparePath(cache->glyph(glyphs[i])), mx, ctx);
     }
 }
 
diff --git a/src/core/SkGlyph.cpp b/src/core/SkGlyph.cpp
index 420ea32..817df32 100644
--- a/src/core/SkGlyph.cpp
+++ b/src/core/SkGlyph.cpp
@@ -117,18 +117,47 @@
     return 0u;
 }
 
-SkPath* SkGlyph::addPath(SkScalerContext* scalerContext, SkArenaAlloc* alloc) {
-    if (!this->isEmpty()) {
-        if (fPathData == nullptr) {
-            fPathData = alloc->make<SkGlyph::PathData>();
-            if (scalerContext->getPath(this->getPackedID(), &fPathData->fPath)) {
-                fPathData->fPath.updateBoundsCache();
-                fPathData->fPath.getGenerationID();
-                fPathData->fHasPath = true;
-            }
-        }
+void SkGlyph::installPath(SkArenaAlloc* alloc, const SkPath* path) {
+    SkASSERT(fPathData == nullptr);
+    SkASSERT(!this->setPathHasBeenCalled());
+    fPathData = alloc->make<SkGlyph::PathData>();
+    if (path != nullptr) {
+        fPathData->fPath = *path;
+        fPathData->fPath.updateBoundsCache();
+        fPathData->fPath.getGenerationID();
+        fPathData->fHasPath = true;
     }
-    return this->path();
+}
+
+bool SkGlyph::setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
+    if (!this->setPathHasBeenCalled()) {
+        SkPath path;
+        if (scalerContext->getPath(this->getPackedID(), &path)) {
+            this->installPath(alloc, &path);
+        } else {
+            this->installPath(alloc, nullptr);
+        }
+        return this->path() != nullptr;
+    }
+
+    return false;
+}
+
+bool SkGlyph::setPath(SkArenaAlloc* alloc, const SkPath* path) {
+    if (!this->setPathHasBeenCalled()) {
+        this->installPath(alloc, path);
+        return this->path() != nullptr;
+    }
+    return false;
+}
+
+const SkPath* SkGlyph::path() const {
+    // setPath must have been called previously.
+    SkASSERT(this->setPathHasBeenCalled());
+    if (fPathData->fHasPath) {
+        return &fPathData->fPath;
+    }
+    return nullptr;
 }
 
 static std::tuple<SkScalar, SkScalar> calculate_path_gap(
@@ -136,7 +165,7 @@
 
     // Left and Right of an ever expanding gap around the path.
     SkScalar left  = SK_ScalarMax,
-            right = SK_ScalarMin;
+             right = SK_ScalarMin;
     auto expandGap = [&left, &right](SkScalar v) {
         left  = SkTMin(left, v);
         right = SkTMax(right, v);
diff --git a/src/core/SkGlyph.h b/src/core/SkGlyph.h
index 06c8879..95bda63 100644
--- a/src/core/SkGlyph.h
+++ b/src/core/SkGlyph.h
@@ -153,21 +153,26 @@
 
     SkMask mask(SkPoint position) const;
 
-    SkPath* addPath(SkScalerContext*, SkArenaAlloc*);
+    // If we haven't already tried to associate a path to this glyph
+    // (i.e. setPathHasBeenCalled() returns false), then use the
+    // SkScalerContext or SkPath argument to try to do so.  N.B. this
+    // may still result in no path being associated with this glyph,
+    // e.g. if you pass a null SkPath or the typeface is bitmap-only.
+    //
+    // This setPath() call is sticky... once you call it, the glyph
+    // stays in its state permanently, ignoring any future calls.
+    //
+    // Returns true if this is the first time you called setPath()
+    // and there actually is a path; call path() to get it.
+    bool setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext);
+    bool setPath(SkArenaAlloc* alloc, const SkPath* path);
 
-    SkPath* path() const {
-        return fPathData != nullptr && fPathData->fHasPath ? &fPathData->fPath : nullptr;
-    }
+    // Returns true if that path has been set.
+    bool setPathHasBeenCalled() const { return fPathData != nullptr; }
 
-    bool hasPath() const {
-        // Need to have called getMetrics before calling findPath.
-        SkASSERT(fMaskFormat != MASK_FORMAT_UNKNOWN);
-
-        // Find path must have been called to use this call.
-        SkASSERT(fPathData != nullptr);
-
-        return fPathData != nullptr && fPathData->fHasPath;
-    }
+    // Return a pointer to the path if it exists, otherwise return nullptr. Only works if the
+    // path was previously set.
+    const SkPath* path() const;
 
     int maxDimension() const {
         // width and height are only defined if a metrics call was made.
@@ -190,11 +195,6 @@
 
     void*     fImage    = nullptr;
 
-    // Path data has tricky state. If the glyph isEmpty, then fPathData should always be nullptr,
-    // else if fPathData is not null, then a path has been requested. The fPath field of fPathData
-    // may still be null after the request meaning that there is no path for this glyph.
-    PathData* fPathData = nullptr;
-
     // The width and height of the glyph mask.
     uint16_t  fWidth  = 0,
               fHeight = 0;
@@ -239,6 +239,14 @@
         bool       fHasPath{false};
     };
 
+    // path == nullptr indicates there is no path.
+    void installPath(SkArenaAlloc* alloc, const SkPath* path);
+
+    // Path data has tricky state. If the glyph isEmpty, then fPathData should always be nullptr,
+    // else if fPathData is not null, then a path has been requested. The fPath field of fPathData
+    // may still be null after the request meaning that there is no path for this glyph.
+    PathData* fPathData = nullptr;
+
     // The advance for this glyph.
     float     fAdvanceX = 0,
               fAdvanceY = 0;
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp
index 061bc17..d086fe0 100644
--- a/src/core/SkGlyphRunPainter.cpp
+++ b/src/core/SkGlyphRunPainter.cpp
@@ -167,16 +167,16 @@
                 if (check_glyph_position(position)
                     && !glyph.isEmpty()
                     && glyph.fMaskFormat != SkMask::kARGB32_Format
-                    && glyph.hasPath())
+                    && glyph.path() != nullptr)
                 {
                     // Only draw a path if it exists, and this is not a color glyph.
                     pathsAndPositions.push_back(SkPathPos{glyph.path(), position});
                 } else {
                     // TODO: this is here to have chrome layout tests pass. Remove this when
                     //  fallback for CPU works.
-                    strike->generatePath(glyph);
-                    if (check_glyph_position(position) && !glyph.isEmpty() && glyph.hasPath()) {
-                        pathsAndPositions.push_back(SkPathPos{glyph.path(), position});
+                    const SkPath* path = strike->preparePath((SkGlyph*) &glyph);
+                    if (check_glyph_position(position) && !glyph.isEmpty() && path != nullptr) {
+                        pathsAndPositions.push_back(SkPathPos{path, position});
                     }
                 }
             }
@@ -394,7 +394,8 @@
                            && glyph.maxDimension() <= SkStrikeCommon::kSkSideTooBigForAtlas) {
                     // SDF mask will work.
                     fGlyphPos[glyphsWithMaskCount++] = glyphPos;
-                } else if (glyph.fMaskFormat != SkMask::kARGB32_Format && glyph.hasPath()) {
+                } else if (glyph.fMaskFormat != SkMask::kARGB32_Format
+                           && glyph.path() != nullptr) {
                     // If not color but too big, use a path.
                     fPaths.push_back(glyphPos);
                 } else {
@@ -455,7 +456,8 @@
                 SkPoint position = glyphPos.position;
                 if (glyph.isEmpty()) {
                     // do nothing
-                } else if (glyph.fMaskFormat != SkMask::kARGB32_Format && glyph.hasPath()) {
+                } else if (glyph.fMaskFormat != SkMask::kARGB32_Format
+                           && glyph.path() != nullptr) {
                     // Place paths in fGlyphPos
                     fGlyphPos[glyphsWithPathCount++] = glyphPos;
                 } else {
@@ -512,7 +514,8 @@
 
                 if (glyph.maxDimension() <= SkStrikeCommon::kSkSideTooBigForAtlas) {
                     fGlyphPos[glyphsWithMaskCount++] = glyphPos;
-                } else if (glyph.fMaskFormat != SkMask::kARGB32_Format && glyph.hasPath()) {
+                } else if (glyph.fMaskFormat != SkMask::kARGB32_Format
+                           && glyph.path() != nullptr) {
                     fPaths.push_back(glyphPos);
                 } else {
                     addFallback(glyph, origin + glyphRun.positions()[glyphPos.index]);
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 8ab8ff4..98b2a51 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -700,6 +700,17 @@
     return fPathRef->countVerbs();
 }
 
+size_t SkPath::approximateBytesUsed() const {
+    size_t size = sizeof (SkPath);
+    if (fPathRef != nullptr) {
+        size += fPathRef->countPoints() * sizeof(SkPoint)
+              + fPathRef->countVerbs()
+              + fPathRef->countWeights() * sizeof(SkScalar);
+    }
+
+    return size;
+}
+
 bool SkPath::getLastPt(SkPoint* lastPt) const {
     SkDEBUGCODE(this->validate();)
 
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index 51b31b9..f7c78bf 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -165,25 +165,6 @@
 // Paths use a SkWriter32 which requires 4 byte alignment.
 static const size_t kPathAlignment  = 4u;
 
-bool read_path(Deserializer* deserializer, SkGlyph* glyph, SkStrike* cache) {
-    uint64_t pathSize = 0u;
-    if (!deserializer->read<uint64_t>(&pathSize)) return false;
-
-    if (pathSize == 0u) {
-        cache->initializePath(glyph, nullptr, 0u);
-        return true;
-    }
-
-    auto* path = deserializer->read(pathSize, kPathAlignment);
-    if (!path) return false;
-
-    // Don't overwrite the path if we already have one. We could have used a fallback if the
-    // glyph was missing earlier.
-    if (glyph->fPathData != nullptr) return true;
-
-    return cache->initializePath(glyph, path, pathSize);
-}
-
 size_t SkDescriptorMapOperators::operator()(const SkDescriptor* key) const {
     return key->getChecksum();
 }
@@ -579,20 +560,15 @@
 //
 // A key reason for no path is the fact that the glyph is a color image or is a bitmap only
 // font.
-void SkStrikeServer::SkGlyphCacheState::generatePath(const SkGlyph& glyph) {
+const SkPath* SkStrikeServer::SkGlyphCacheState::preparePath(SkGlyph* glyph) {
 
     // Check to see if we have processed this glyph for a path before.
-    if (glyph.fPathData == nullptr) {
-
-        // Never checked for a path before. Add the path now.
-        auto path = const_cast<SkGlyph&>(glyph).addPath(fContext.get(), &fAlloc);
-        if (path != nullptr) {
-
-            // A path was added make sure to send it to the GPU.
-            fCachedGlyphPaths.add(glyph.getPackedID());
-            fPendingGlyphPaths.push_back(glyph.getPackedID());
-        }
+    if (glyph->setPath(&fAlloc, fContext.get())) {
+        // A path was added make sure to send it to the GPU.
+        fCachedGlyphPaths.add(glyph->getPackedID());
+        fPendingGlyphPaths.push_back(glyph->getPackedID());
     }
+    return glyph->path();
 }
 
 void SkStrikeServer::SkGlyphCacheState::writeGlyphPath(const SkPackedGlyphID& glyphID,
@@ -644,18 +620,13 @@
 
                 // The glyph is too big for the atlas, but it is not color, so it is handled with a
                 // path.
-                if (glyphPtr->fPathData == nullptr) {
-
-                    // Never checked for a path before. Add the path now.
-                    const_cast<SkGlyph&>(*glyphPtr).addPath(fContext.get(), &fAlloc);
-
+                if (glyphPtr->setPath(&fAlloc, fContext.get())) {
                     // Always send the path data, even if its not available, to make sure empty
                     // paths are not incorrectly assumed to be cache misses.
                     fCachedGlyphPaths.add(glyphPtr->getPackedID());
                     fPendingGlyphPaths.push_back(glyphPtr->getPackedID());
                 }
             } else {
-
                 // This will be handled by the fallback strike.
                 SkASSERT(glyphPtr->maxDimension() > maxDimension
                          && glyphPtr->fMaskFormat == SkMask::kARGB32_Format);
@@ -821,15 +792,19 @@
 
             SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph->getPackedID());
 
-            // Update the glyph unless it's already got a path (from fallback),
-            // preserving any image that might be present.
-            if (allocatedGlyph->fPathData == nullptr) {
-                auto* glyphImage = allocatedGlyph->fImage;
-                *allocatedGlyph = *glyph;
-                allocatedGlyph->fImage = glyphImage;
+            SkPath* pathPtr = nullptr;
+            SkPath path;
+            uint64_t pathSize = 0u;
+            if (!deserializer.read<uint64_t>(&pathSize)) READ_FAILURE
+
+            if (pathSize > 0) {
+                auto* pathData = deserializer.read(pathSize, kPathAlignment);
+                if (!pathData) READ_FAILURE
+                if (!path.readFromMemory(const_cast<const void*>(pathData), pathSize)) READ_FAILURE
+                pathPtr = &path;
             }
 
-            if (!read_path(&deserializer, allocatedGlyph, strike.get())) READ_FAILURE
+            strike->preparePath(allocatedGlyph, pathPtr);
         }
     }
 
diff --git a/src/core/SkRemoteGlyphCacheImpl.h b/src/core/SkRemoteGlyphCacheImpl.h
index 696c844..99d0824 100644
--- a/src/core/SkRemoteGlyphCacheImpl.h
+++ b/src/core/SkRemoteGlyphCacheImpl.h
@@ -46,7 +46,7 @@
                                                PreparationDetail detail,
                                                SkGlyphPos results[]) override;
 
-    void generatePath(const SkGlyph& glyph) override;
+    const SkPath* preparePath(SkGlyph* glyph) override;
 
     void onAboutToExitScope() override {}
 
diff --git a/src/core/SkStrike.cpp b/src/core/SkStrike.cpp
index 3f78048..da693ca 100644
--- a/src/core/SkStrike.cpp
+++ b/src/core/SkStrike.cpp
@@ -16,12 +16,6 @@
 #include "src/core/SkMakeUnique.h"
 #include <cctype>
 
-namespace {
-size_t compute_path_size(const SkPath& path) {
-    return sizeof(SkPath) + path.countPoints() * sizeof(SkPoint);
-}
-}  // namespace
-
 SkStrike::SkStrike(
     const SkDescriptor& desc,
     std::unique_ptr<SkScalerContext> scaler,
@@ -71,6 +65,10 @@
     return this->glyph(SkPackedGlyphID{glyphID});
 }
 
+SkGlyph* SkStrike::glyphOrNull(SkPackedGlyphID id) const {
+    return fGlyphMap.findOrNull(id);
+}
+
 SkGlyph* SkStrike::getRawGlyphByID(SkPackedGlyphID id) {
     return this->uninitializedGlyph(id);
 }
@@ -90,6 +88,20 @@
     return *this->glyph(packedGlyphID);
 }
 
+const SkPath* SkStrike::preparePath(SkGlyph* glyph) {
+    if (glyph->setPath(&fAlloc, fScalerContext.get())) {
+        fMemoryUsed += glyph->path()->approximateBytesUsed();
+    }
+    return glyph->path();
+}
+
+const SkPath* SkStrike::preparePath(SkGlyph* glyph, const SkPath* path) {
+    if (glyph->setPath(&fAlloc, path)) {
+        fMemoryUsed += glyph->path()->approximateBytesUsed();
+    }
+    return glyph->path();
+}
+
 const SkDescriptor& SkStrike::getDescriptor() const {
     return *fDesc.getDesc();
 }
@@ -148,46 +160,6 @@
     }
 }
 
-const SkPath* SkStrike::findPath(const SkGlyph& glyph) {
-
-    if (!glyph.isEmpty()) {
-        // If the path already exists, return it.
-        if (glyph.fPathData != nullptr) {
-            if (glyph.fPathData->fHasPath) {
-                return &glyph.fPathData->fPath;
-            }
-            return nullptr;
-        }
-
-        const_cast<SkGlyph&>(glyph).addPath(fScalerContext.get(), &fAlloc);
-        if (glyph.fPathData != nullptr) {
-            fMemoryUsed += compute_path_size(glyph.fPathData->fPath);
-        }
-
-        return glyph.path();
-    }
-
-    return nullptr;
-}
-
-bool SkStrike::initializePath(SkGlyph* glyph, const volatile void* data, size_t size) {
-    SkASSERT(!glyph->fPathData);
-
-    if (glyph->fWidth) {
-        SkGlyph::PathData* pathData = fAlloc.make<SkGlyph::PathData>();
-        glyph->fPathData = pathData;
-        if (size == 0u) return true;
-
-        auto path = skstd::make_unique<SkPath>();
-        if (!pathData->fPath.readFromMemory(const_cast<const void*>(data), size)) {
-            return false;
-        }
-        fMemoryUsed += compute_path_size(glyph->fPathData->fPath);
-        pathData->fHasPath = true;
-    }
-
-    return true;
-}
 
 bool SkStrike::belongsToCache(const SkGlyph* glyph) const {
     return glyph && fGlyphMap.findOrNull(glyph->getPackedID()) == glyph;
@@ -250,7 +222,7 @@
                     }
                 } else if (glyph.fMaskFormat != SkMask::kARGB32_Format) {
                     // The out of atlas glyph is not color so we can draw it using paths.
-                    this->findPath(glyph);
+                    this->preparePath(const_cast<SkGlyph*>(&glyph));
                 } else {
                     // This will be handled by the fallback strike.
                     SkASSERT(glyph.maxDimension() > maxDimension
@@ -285,10 +257,6 @@
     SkDebugf("%s\n", msg.c_str());
 }
 
-void SkStrike::generatePath(const SkGlyph& glyph) {
-    if (!glyph.isEmpty()) { this->findPath(glyph); }
-}
-
 void SkStrike::onAboutToExitScope() { }
 
 #ifdef SK_DEBUG
@@ -299,8 +267,8 @@
         if (glyphPtr->fImage) {
             memoryUsed += glyphPtr->computeImageSize();
         }
-        if (glyphPtr->fPathData) {
-            memoryUsed += compute_path_size(glyphPtr->fPathData->fPath);
+        if (glyphPtr->setPathHasBeenCalled() && glyphPtr->path() != nullptr) {
+            memoryUsed += glyphPtr->path()->approximateBytesUsed();
         }
     });
     SkASSERT(fMemoryUsed == memoryUsed);
diff --git a/src/core/SkStrike.h b/src/core/SkStrike.h
index 019576a..49aeb84 100644
--- a/src/core/SkStrike.h
+++ b/src/core/SkStrike.h
@@ -66,9 +66,18 @@
     SkGlyph* glyph(SkPackedGlyphID id);
     SkGlyph* glyph(SkGlyphID);
 
+    // Return a glyph or nullptr if it does not exits in the strike.
+    SkGlyph* glyphOrNull(SkPackedGlyphID id) const;
+
     // Return a glyph. Create it if it doesn't exist, but zero the data.
     SkGlyph* uninitializedGlyph(SkPackedGlyphID id);
 
+    // If the path has never been set, then use the scaler context to add the glyph.
+    const SkPath* preparePath(SkGlyph*) override;
+
+    // If the path has never been set, then add a path to glyph.
+    const SkPath* preparePath(SkGlyph* glyph, const SkPath* path);
+
     void getAdvances(SkSpan<const SkGlyphID>, SkPoint[]);
 
     /** Returns the number of glyphs for this strike.
@@ -93,16 +102,6 @@
     void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
                         SkGlyph* , SkScalar* array, int* count);
 
-    /** Return the Path associated with the glyph. If it has not been generated this will trigger
-        that.
-    */
-    const SkPath* findPath(const SkGlyph&);
-
-    /** Initializes the path associated with the glyph with |data|. Returns false if
-     *  data is invalid.
-     */
-    bool initializePath(SkGlyph*, const volatile void* data, size_t size);
-
     /** Fallback glyphs used during font remoting if the original glyph can't be found.
      */
     bool belongsToCache(const SkGlyph* glyph) const;
@@ -131,8 +130,6 @@
 
     const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) override;
 
-    void generatePath(const SkGlyph& glyph) override;
-
     const SkDescriptor& getDescriptor() const override;
 
     SkSpan<const SkGlyphPos> prepareForDrawing(const SkGlyphID glyphIDs[],
diff --git a/src/core/SkStrikeCache.cpp b/src/core/SkStrikeCache.cpp
index 747e4cd..26d376b 100644
--- a/src/core/SkStrikeCache.cpp
+++ b/src/core/SkStrikeCache.cpp
@@ -46,8 +46,8 @@
                 glyphIDs, positions, n, maxDimension, detail, results);
     }
 
-    void generatePath(const SkGlyph& glyph) override {
-        fStrike.generatePath(glyph);
+    const SkPath* preparePath(SkGlyph* glyph) override {
+        return fStrike.preparePath(glyph);
     }
 
     const SkDescriptor& getDescriptor() const override {
@@ -349,12 +349,11 @@
     // There is also a problem with accounting for cache size with shared path data.
     for (Node* node = internalGetHead(); node != nullptr; node = node->fNext) {
         if (loose_compare(node->fStrike.getDescriptor(), desc)) {
-            if (node->fStrike.isGlyphCached(glyphID, 0, 0)) {
-                SkGlyph* from = node->fStrike.getRawGlyphByID(SkPackedGlyphID(glyphID));
-                if (from->fPathData != nullptr) {
+            if (SkGlyph *from = node->fStrike.glyphOrNull(SkPackedGlyphID{glyphID})) {
+                if (from->setPathHasBeenCalled() && from->path() != nullptr) {
                     // We can just copy the path out by value here, so no need to worry
                     // about the lifetime of this desperate-match node.
-                    *path = from->fPathData->fPath;
+                    *path = *from->path();
                     return true;
                 }
             }
diff --git a/src/core/SkStrikeInterface.h b/src/core/SkStrikeInterface.h
index 30250cd..a49aefc 100644
--- a/src/core/SkStrikeInterface.h
+++ b/src/core/SkStrikeInterface.h
@@ -70,8 +70,9 @@
                                                        SkGlyphPos results[]) = 0;
 
     virtual const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) = 0;
-    // TODO: Deprecated. Do not use. Remove when ARGB fallback for bitmap device paths is working.
-    virtual void generatePath(const SkGlyph& glyph) = 0;
+
+    // If glyph does not have an existing path, then add a path to glyph using a scaler context.
+    virtual const SkPath* preparePath(SkGlyph* glyph) = 0;
     virtual void onAboutToExitScope() = 0;
 
     struct Deleter {
diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp
index 99517b5..37a5cd6 100644
--- a/src/core/SkTextBlob.cpp
+++ b/src/core/SkTextBlob.cpp
@@ -941,11 +941,11 @@
 
 bool TextInterceptsIter::next(SkScalar* array, int* count) {
     SkASSERT(fGlyphs < fStop);
-    const SkGlyph& glyph = fCache->getGlyphIDMetrics(*fGlyphs++);
+    SkGlyph* glyph = fCache->glyph(*fGlyphs++);
     fXPos += fPrevAdvance * fScale;
-    fPrevAdvance = SkFloatToScalar(glyph.advanceX());
-    if (fCache->findPath(glyph)) {
-        fCache->findIntercepts(fBounds, fScale, fXPos, const_cast<SkGlyph*>(&glyph), array, count);
+    fPrevAdvance = glyph->advanceX();
+    if (fCache->preparePath(glyph) != nullptr) {
+        fCache->findIntercepts(fBounds, fScale, fXPos, glyph, array, count);
     }
     return fGlyphs < fStop;
 }
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 7781f26..35f4dfe 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -778,12 +778,12 @@
     if (fontType == SkAdvancedTypefaceMetrics::kOther_Font) {
         return false;
     }
-    const SkGlyph& glyph = cache->getGlyphIDMetrics(gid);
-    if (glyph.isEmpty()) {
+    SkGlyph* glyph = cache->glyph(gid);
+    if (glyph->isEmpty()) {
         return false;
     }
 
-    bool bitmapOnly = nullptr == cache->findPath(glyph);
+    bool bitmapOnly = nullptr == cache->preparePath(glyph);
     bool convertedToType3 = (font->getType() == SkAdvancedTypefaceMetrics::kOther_Font);
     return convertedToType3 != bitmapOnly;
 }
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index b3076bb..afe2ba7 100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -181,8 +181,8 @@
 }
 
 static bool has_outline_glyph(SkGlyphID gid, SkStrike* cache) {
-    const SkGlyph& glyph = cache->getGlyphIDMetrics(gid);
-    return glyph.isEmpty() || cache->findPath(glyph);
+    SkGlyph* glyph = cache->glyph(gid);
+    return glyph->isEmpty() || cache->preparePath(glyph);
 }
 
 SkPDFFont* SkPDFFont::GetFontResource(SkPDFDocument* doc,
@@ -569,25 +569,24 @@
             characterName.set("g0");
         } else {
             characterName.printf("g%X", gID);
-            const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
-            advance = SkFloatToScalar(glyph.advanceX());
-            glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
-                                          glyph.fWidth, glyph.fHeight);
+            SkGlyph* glyph = cache->glyph(gID);
+            advance = glyph->advanceX();
+            glyphBBox = SkIRect::MakeXYWH(glyph->fLeft, glyph->fTop,
+                                          glyph->fWidth, glyph->fHeight);
             bbox.join(glyphBBox);
-            const SkPath* path = cache->findPath(glyph);
+            const SkPath* path = cache->preparePath(glyph);
             SkDynamicMemoryWStream content;
             if (path && !path->isEmpty()) {
-                setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.advanceX()), glyphBBox, &content);
+                setGlyphWidthAndBoundingBox(glyph->advanceX(), glyphBBox, &content);
                 SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
                 SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(), &content);
             } else {
                 auto pimg = to_image(gID, cache.get());
                 if (!pimg.fImage) {
-                    setGlyphWidthAndBoundingBox(SkFloatToScalar(glyph.advanceX()), glyphBBox,
-                                                &content);
+                    setGlyphWidthAndBoundingBox(glyph->advanceX(), glyphBBox, &content);
                 } else {
                     imageGlyphs.emplace_back(gID, SkPDFSerializeImage(pimg.fImage.get(), doc));
-                    SkPDFUtils::AppendScalar(SkFloatToScalar(glyph.advanceX()), &content);
+                    SkPDFUtils::AppendScalar(glyph->advanceX(), &content);
                     content.writeText(" 0 d0\n");
                     content.writeDecAsText(pimg.fImage->width());
                     content.writeText(" 0 0 ");