Have GPU and RemoteGlyphCache share mask position code

Change-Id: I0d8a969107304883ccd71c9b35ade50e3ac5d341
Reviewed-on: https://skia-review.googlesource.com/149048
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/gn/core.gni b/gn/core.gni
index 69e4353..6696887 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -262,6 +262,7 @@
   "$_src/core/SkRegion_path.cpp",
   "$_src/core/SkRemoteGlyphCache.h",
   "$_src/core/SkRemoteGlyphCache.cpp",
+  "$_src/core/SkRemoteGlyphCacheImpl.h",
   "$_src/core/SkResourceCache.cpp",
   "$_src/core/SkRRect.cpp",
   "$_src/core/SkRRectPriv.h",
diff --git a/src/core/SkGlyph.h b/src/core/SkGlyph.h
index d527871..dc4d7db 100644
--- a/src/core/SkGlyph.h
+++ b/src/core/SkGlyph.h
@@ -116,6 +116,7 @@
 struct SkPackedGlyphID : public SkPackedID {
     SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { }
     SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { }
+    SkPackedGlyphID(SkGlyphID code, SkIPoint pt) : SkPackedID(code, pt.x(), pt.y()) { }
     SkPackedGlyphID() : SkPackedID() { }
     SkGlyphID code() const {
         return SkTo<SkGlyphID>(SkPackedID::code());
diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp
index 11688ae..6734c90 100644
--- a/src/core/SkGlyphRun.cpp
+++ b/src/core/SkGlyphRun.cpp
@@ -32,7 +32,7 @@
 #include "SkPaintPriv.h"
 #include "SkPathEffect.h"
 #include "SkRasterClip.h"
-#include "SkRemoteGlyphCache.h"
+#include "SkRemoteGlyphCacheImpl.h"
 #include "SkStrikeCache.h"
 #include "SkTextBlob.h"
 #include "SkTextBlobPriv.h"
@@ -162,20 +162,7 @@
             auto pt = origin + *ptCursor++;
             if (SkScalarsAreFinite(mappedPt.x(), mappedPt.y())) {
                 const SkGlyph& glyph = cache->getGlyphMetrics(glyphID, mappedPt);
-                if (!glyph.isEmpty()) {
-                    // Prevent glyphs from being drawn outside of or straddling the edge
-                    // of device space. Comparisons written a little weirdly so that NaN
-                    // coordinates are treated safely.
-                    auto le = [](float a, int b) { return a <= (float)b; };
-                    auto ge = [](float a, int b) { return a >= (float)b; };
-                    if (le(mappedPt.fX, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) &&
-                        ge(mappedPt.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) &&
-                        le(mappedPt.fY, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) &&
-                        ge(mappedPt.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)))
-                    {
-                        eachGlyph(glyph, pt, mappedPt);
-                    }
-                }
+                eachGlyph(glyph, pt, mappedPt);
             }
         }
     }
@@ -879,43 +866,29 @@
     }
 }
 
-// -- SkRemoteGlyphCache ---------------------------------------------------------------------------
-
+// -- TrackLayerDevice -----------------------------------------------------------------------------
 void SkTextBlobCacheDiffCanvas::TrackLayerDevice::processGlyphRunForMask(
         const SkGlyphRun& glyphRun, const SkMatrix& runMatrix, SkPoint origin) {
     TRACE_EVENT0("skia", "SkTextBlobCacheDiffCanvas::processGlyphRunForMask");
     const SkPaint& runPaint = glyphRun.paint();
 
-    SkSTArenaAlloc<120> arena;
-    SkFindAndPlaceGlyph::MapperInterface* mapper =
-            SkFindAndPlaceGlyph::CreateMapper(runMatrix, origin, 2, &arena);
-
     SkScalerContextEffects effects;
     auto* glyphCacheState = fStrikeServer->getOrCreateCache(
             runPaint, &this->surfaceProps(), &runMatrix,
             SkScalerContextFlags::kFakeGammaAndBoostContrast, &effects);
     SkASSERT(glyphCacheState);
 
-    const bool asPath = false;
-    bool isSubpixel = glyphCacheState->isSubpixel();
-    SkAxisAlignment axisAlignment = glyphCacheState->axisAlignmentForHText();
-    auto glyphs = glyphRun.shuntGlyphsIDs();
-    auto positions = glyphRun.positions();
-    for (uint32_t index = 0; index < glyphRun.runSize(); index++) {
-        SkIPoint subPixelPos{0, 0};
-        if (isSubpixel) {
-            SkPoint glyphPos = mapper->map(positions[index]);
-            subPixelPos = SkFindAndPlaceGlyph::SubpixelAlignment(axisAlignment, glyphPos);
-        }
+    auto perGlyph = [glyphCacheState] (const SkGlyph& glyph, SkPoint mappedPt) {
+        glyphCacheState->addGlyph(glyph.getPackedID(), false);
+    };
 
-        glyphCacheState->addGlyph(
-                SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y()),
-                asPath);
-    }
+    auto perPath = [](const SkGlyph& glyph, SkPoint position) {};
+
+    fPainter.drawGlyphRunAsBMPWithPathFallback(
+            glyphCacheState, glyphRun, origin, runMatrix, perGlyph, perPath);
 }
 
 // -- GrTextContext --------------------------------------------------------------------------------
-
 GrColor generate_filtered_color(const SkPaint& paint, const GrColorSpaceInfo& colorSpaceInfo) {
     GrColor4f filteredColor = SkColorToUnpremulGrColor4f(paint.getColor(), colorSpaceInfo);
     if (paint.getColorFilter() != nullptr) {
@@ -1176,13 +1149,15 @@
             auto perGlyph =
                 [cacheBlob, runIndex, glyphCache, &currStrike, filteredColor, cache{cache.get()}]
                 (const SkGlyph& glyph, SkPoint mappedPt) {
-                    const void* glyphImage = cache->findImage(glyph);
-                    if (glyphImage != nullptr) {
-                        SkScalar sx = SkScalarFloorToScalar(mappedPt.fX),
-                                sy = SkScalarFloorToScalar(mappedPt.fY);
-                        AppendGlyph(cacheBlob, runIndex, glyphCache, &currStrike,
-                                    glyph, GrGlyph::kCoverage_MaskStyle, sx, sy,
-                                    filteredColor, cache, SK_Scalar1, false);
+                    if (!glyph.isEmpty()) {
+                        const void* glyphImage = cache->findImage(glyph);
+                        if (glyphImage != nullptr) {
+                            SkScalar sx = SkScalarFloorToScalar(mappedPt.fX),
+                                     sy = SkScalarFloorToScalar(mappedPt.fY);
+                            AppendGlyph(cacheBlob, runIndex, glyphCache, &currStrike,
+                                        glyph, GrGlyph::kCoverage_MaskStyle, sx, sy,
+                                        filteredColor, cache, SK_Scalar1, false);
+                        }
                     }
                 };
 
@@ -1192,7 +1167,7 @@
                     const SkPath* glyphPath = cache->findPath(glyph);
                     if (glyphPath != nullptr) {
                         SkScalar sx = SkScalarFloorToScalar(position.fX),
-                                sy = SkScalarFloorToScalar(position.fY);
+                                 sy = SkScalarFloorToScalar(position.fY);
                         cacheBlob->appendPathGlyph(
                                 runIndex, *glyphPath, sx, sy, SK_Scalar1, true);
                     }
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index febc9d1..5417ea1 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -18,6 +18,7 @@
 #include "SkFindAndPlaceGlyph.h"
 #include "SkGlyphRun.h"
 #include "SkPathEffect.h"
+#include "SkRemoteGlyphCacheImpl.h"
 #include "SkStrikeCache.h"
 #include "SkTraceEvent.h"
 #include "SkTypeface_remote.h"
@@ -213,11 +214,24 @@
     return *lhs == *rhs;
 }
 
+struct StrikeSpec {
+    StrikeSpec() {}
+    StrikeSpec(SkFontID typefaceID_, SkDiscardableHandleId discardableHandleId_)
+            : typefaceID{typefaceID_}, discardableHandleId(discardableHandleId_) {}
+    SkFontID typefaceID = 0u;
+    SkDiscardableHandleId discardableHandleId = 0u;
+    /* desc */
+    /* n X (glyphs ids) */
+};
+
 // -- TrackLayerDevice -----------------------------------------------------------------------------
 SkTextBlobCacheDiffCanvas::TrackLayerDevice::TrackLayerDevice(
         const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
         const SkTextBlobCacheDiffCanvas::Settings& settings)
-        : SkNoPixelsDevice(bounds, props), fStrikeServer(server), fSettings(settings) {
+    : SkNoPixelsDevice(bounds, props)
+    , fStrikeServer(server)
+    , fSettings(settings)
+    , fPainter{props, kUnknown_SkColorType, SkScalerContextFlags::kFakeGammaAndBoostContrast} {
     SkASSERT(fStrikeServer);
 }
 
@@ -375,16 +389,6 @@
     SkCanvas::onDrawTextBlob(blob, x, y, paint);
 }
 
-struct StrikeSpec {
-    StrikeSpec() {}
-    StrikeSpec(SkFontID typefaceID_, SkDiscardableHandleId discardableHandleId_)
-            : typefaceID{typefaceID_}, discardableHandleId(discardableHandleId_) {}
-    SkFontID typefaceID = 0u;
-    SkDiscardableHandleId discardableHandleId = 0u;
-    /* desc */
-    /* n X (glyphs ids) */
-};
-
 struct WireTypeface {
     WireTypeface() = default;
     WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed)
@@ -429,33 +433,6 @@
     fLockedDescs.clear();
 }
 
-SkStrikeServer::SkGlyphCacheState::SkGlyphCacheState(
-        std::unique_ptr<SkDescriptor> keyDescriptor, uint32_t discardableHandleId)
-        : fKeyDescriptor(std::move(keyDescriptor))
-        , fDiscardableHandleId(discardableHandleId) {
-    SkASSERT(fKeyDescriptor);
-}
-
-SkStrikeServer::SkGlyphCacheState::~SkGlyphCacheState() = default;
-
-void SkStrikeServer::SkGlyphCacheState::ensureScalerContext(
-        const SkPaint& paint,
-        const SkSurfaceProps* props,
-        const SkMatrix* matrix,
-        SkScalerContextFlags flags,
-        SkScalerContextEffects* effects) {
-    if (fContext == nullptr || fDeviceDescriptor == nullptr) {
-        SkScalerContextRec deviceRec;
-        SkScalerContext::MakeRecAndEffects(paint, props, matrix, flags, &deviceRec, effects, true);
-        auto deviceDesc = SkScalerContext::DescriptorGivenRecAndEffects(deviceRec, *effects);
-        auto* tf = paint.getTypeface();
-        fContext = tf->createScalerContext(*effects, deviceDesc.get(), false);
-        fIsSubpixel = fContext->isSubpixel();
-        fAxisAlignmentForHText = fContext->computeAxisAlignmentForHText();
-        fDeviceDescriptor = std::move(deviceDesc);
-    }
-}
-
 SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache(
         const SkPaint& paint,
         const SkSurfaceProps* props,
@@ -518,6 +495,16 @@
     return cacheStatePtr;
 }
 
+// -- SkGlyphCacheState ----------------------------------------------------------------------------
+SkStrikeServer::SkGlyphCacheState::SkGlyphCacheState(
+        std::unique_ptr<SkDescriptor> keyDescriptor, uint32_t discardableHandleId)
+        : fKeyDescriptor(std::move(keyDescriptor))
+        , fDiscardableHandleId(discardableHandleId) {
+    SkASSERT(fKeyDescriptor);
+}
+
+SkStrikeServer::SkGlyphCacheState::~SkGlyphCacheState() = default;
+
 void SkStrikeServer::SkGlyphCacheState::addGlyph(SkPackedGlyphID glyph, bool asPath) {
     auto* cache = asPath ? &fCachedGlyphPaths : &fCachedGlyphImages;
     auto* pending = asPath ? &fPendingGlyphPaths : &fPendingGlyphImages;
@@ -535,8 +522,6 @@
     // TODO(khushalsagar): Write a strike only if it has any pending glyphs.
     serializer->emplace<bool>(this->hasPendingGlyphs());
     if (!this->hasPendingGlyphs()) {
-        // See comment below for reset.
-        fContext.reset();
         return;
     }
 
@@ -603,10 +588,6 @@
         writeGlyphPath(glyphID, serializer);
     }
     fPendingGlyphPaths.clear();
-
-    // Note that we reset the context after serializing pending glyphs since we
-    // don't want to extend the lifetime of the typeface.
-    fContext.reset();
 }
 
 const SkGlyph& SkStrikeServer::SkGlyphCacheState::findGlyph(SkPackedGlyphID glyphID) {
@@ -620,6 +601,37 @@
     return *glyph;
 }
 
+void SkStrikeServer::SkGlyphCacheState::ensureScalerContext(
+        const SkPaint& paint,
+        const SkSurfaceProps* props,
+        const SkMatrix* matrix,
+        SkScalerContextFlags flags,
+        SkScalerContextEffects* effects) {
+    if (fContext == nullptr || fDeviceDescriptor == nullptr) {
+        SkScalerContextRec deviceRec;
+        SkScalerContext::MakeRecAndEffects(paint, props, matrix, flags, &deviceRec, effects, true);
+        auto deviceDesc = SkScalerContext::DescriptorGivenRecAndEffects(deviceRec, *effects);
+        auto* tf = paint.getTypeface();
+        fContext = tf->createScalerContext(*effects, deviceDesc.get(), false);
+        fIsSubpixel = fContext->isSubpixel();
+        fAxisAlignmentForHText = fContext->computeAxisAlignmentForHText();
+        fDeviceDescriptor = std::move(deviceDesc);
+    }
+}
+
+SkVector SkStrikeServer::SkGlyphCacheState::rounding() const {
+    return SkGlyphCacheCommon::PixelRounding(fIsSubpixel, fAxisAlignmentForHText);
+}
+
+const SkGlyph& SkStrikeServer::SkGlyphCacheState::getGlyphMetrics(
+        SkGlyphID glyphID, SkPoint position) {
+    SkIPoint lookupPoint = SkGlyphCacheCommon::SubpixelLookup(fAxisAlignmentForHText, position);
+    SkPackedGlyphID packedGlyphID = fIsSubpixel ? SkPackedGlyphID{glyphID, lookupPoint}
+                                                : SkPackedGlyphID{glyphID};
+
+    return this->findGlyph(packedGlyphID);
+}
+
 void SkStrikeServer::SkGlyphCacheState::writeGlyphPath(const SkPackedGlyphID& glyphID,
                                                        Serializer* serializer) const {
     SkPath path;
@@ -634,7 +646,6 @@
 }
 
 // SkStrikeClient -----------------------------------------
-
 class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner {
 public:
     DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h
index ec8b0eb..d9abb7c 100644
--- a/src/core/SkRemoteGlyphCache.h
+++ b/src/core/SkRemoteGlyphCache.h
@@ -28,11 +28,8 @@
 enum SkAxisAlignment : uint32_t;
 class SkDescriptor;
 class SkGlyphCache;
-class SkGlyphRun;
-class SkGlyphRunList;
 struct SkPackedGlyphID;
 enum SkScalerContextFlags : uint32_t;
-class SkScalerContextRecDescriptor;
 class SkStrikeCache;
 class SkTypefaceProxy;
 struct WireTypeface;
@@ -80,31 +77,9 @@
                         const SkPaint& paint) override;
 
 private:
-    class TrackLayerDevice : public SkNoPixelsDevice {
-    public:
-        TrackLayerDevice(const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
-                         const SkTextBlobCacheDiffCanvas::Settings& settings);
+    class TrackLayerDevice;
 
-        SkBaseDevice* onCreateDevice(const CreateInfo& cinfo, const SkPaint*) override;
 
-    protected:
-        void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
-
-    private:
-        void processGlyphRun(const SkPoint& origin, const SkGlyphRun& glyphRun);
-
-        void processGlyphRunForMask(
-                const SkGlyphRun& glyphRun, const SkMatrix& runMatrix, SkPoint origin);
-
-        void processGlyphRunForPaths(const SkGlyphRun& glyphRun, const SkMatrix& runMatrix);
-
-#if SK_SUPPORT_GPU
-        bool maybeProcessGlyphRunForDFT(const SkGlyphRun& glyphRun, const SkMatrix& runMatrix);
-#endif
-
-        SkStrikeServer* const fStrikeServer;
-        const SkTextBlobCacheDiffCanvas::Settings fSettings;
-    };
 };
 
 using SkDiscardableHandleId = uint32_t;
@@ -147,62 +122,7 @@
     void writeStrikeData(std::vector<uint8_t>* memory);
 
     // Methods used internally in skia ------------------------------------------
-    class SkGlyphCacheState {
-    public:
-        // N.B. SkGlyphCacheState is not valid until ensureScalerContext is called.
-        SkGlyphCacheState(std::unique_ptr<SkDescriptor> keyDescriptor,
-                          SkDiscardableHandleId discardableHandleId);
-        ~SkGlyphCacheState();
-
-        void addGlyph(SkPackedGlyphID, bool pathOnly);
-        void writePendingGlyphs(Serializer* serializer);
-        SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
-        const SkDescriptor& getDeviceDescriptor() {
-            return *fDeviceDescriptor;
-        }
-        bool isSubpixel() const { return fIsSubpixel; }
-        SkAxisAlignment axisAlignmentForHText() const { return fAxisAlignmentForHText; }
-
-        const SkDescriptor& getKeyDescriptor() {
-            return *fKeyDescriptor;
-        }
-        const SkGlyph& findGlyph(SkPackedGlyphID);
-        void ensureScalerContext(const SkPaint& paint,
-                                 const SkSurfaceProps* props,
-                                 const SkMatrix* matrix,
-                                 SkScalerContextFlags flags,
-                                 SkScalerContextEffects* effects);
-
-    private:
-        bool hasPendingGlyphs() const {
-            return !fPendingGlyphImages.empty() || !fPendingGlyphPaths.empty();
-        }
-        void writeGlyphPath(const SkPackedGlyphID& glyphID, Serializer* serializer) const;
-
-        // The set of glyphs cached on the remote client.
-        SkTHashSet<SkPackedGlyphID> fCachedGlyphImages;
-        SkTHashSet<SkPackedGlyphID> fCachedGlyphPaths;
-
-        // The set of glyphs which has not yet been serialized and sent to the
-        // remote client.
-        std::vector<SkPackedGlyphID> fPendingGlyphImages;
-        std::vector<SkPackedGlyphID> fPendingGlyphPaths;
-
-        // The device descriptor is used to create the scaler context. The glyphs to have the
-        // correct device rendering. The key descriptor is used for communication. The GPU side will
-        // create descriptors with out the device filtering, thus matching the key descriptor.
-        std::unique_ptr<SkDescriptor> fDeviceDescriptor;
-        std::unique_ptr<SkDescriptor> fKeyDescriptor;
-        const SkDiscardableHandleId fDiscardableHandleId;
-        // The context built using fDeviceDescriptor
-        std::unique_ptr<SkScalerContext> fContext;
-        bool fIsSubpixel = true;
-        SkAxisAlignment fAxisAlignmentForHText;
-
-        // FallbackTextHelper cases require glyph metrics when analyzing a glyph run, in which case
-        // we cache them here.
-        SkTHashMap<SkPackedGlyphID, SkGlyph> fGlyphMap;
-    };
+    class SkGlyphCacheState;
 
     SkGlyphCacheState* getOrCreateCache(const SkPaint&, const SkSurfaceProps*, const SkMatrix*,
                                         SkScalerContextFlags flags,
diff --git a/src/core/SkRemoteGlyphCacheImpl.h b/src/core/SkRemoteGlyphCacheImpl.h
new file mode 100644
index 0000000..865f37e
--- /dev/null
+++ b/src/core/SkRemoteGlyphCacheImpl.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRemoteGlyphCacheImpl_DEFINED
+#define SkRemoteGlyphCacheImpl_DEFINED
+
+#include "SkRemoteGlyphCache.h"
+#include "SkGlyphRun.h"
+
+class SkStrikeServer::SkGlyphCacheState : public SkGlyphCacheInterface {
+public:
+    // N.B. SkGlyphCacheState is not valid until ensureScalerContext is called.
+    SkGlyphCacheState(std::unique_ptr<SkDescriptor> keyDescriptor,
+                      SkDiscardableHandleId discardableHandleId);
+    ~SkGlyphCacheState() override;
+
+    void addGlyph(SkPackedGlyphID, bool pathOnly);
+    void writePendingGlyphs(Serializer* serializer);
+    SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
+    const SkDescriptor& getDeviceDescriptor() {
+        return *fDeviceDescriptor;
+    }
+    bool isSubpixel() const { return fIsSubpixel; }
+    SkAxisAlignment axisAlignmentForHText() const { return fAxisAlignmentForHText; }
+
+    const SkDescriptor& getKeyDescriptor() {
+        return *fKeyDescriptor;
+    }
+    const SkGlyph& findGlyph(SkPackedGlyphID);
+
+    void ensureScalerContext(const SkPaint& paint,
+                             const SkSurfaceProps* props,
+                             const SkMatrix* matrix,
+                             SkScalerContextFlags flags,
+                             SkScalerContextEffects* effects);
+
+    SkVector rounding() const override;
+
+    const SkGlyph& getGlyphMetrics(SkGlyphID glyphID, SkPoint position) override;
+
+private:
+    bool hasPendingGlyphs() const {
+        return !fPendingGlyphImages.empty() || !fPendingGlyphPaths.empty();
+    }
+    void writeGlyphPath(const SkPackedGlyphID& glyphID, Serializer* serializer) const;
+
+    // The set of glyphs cached on the remote client.
+    SkTHashSet<SkPackedGlyphID> fCachedGlyphImages;
+    SkTHashSet<SkPackedGlyphID> fCachedGlyphPaths;
+
+    // The set of glyphs which has not yet been serialized and sent to the
+    // remote client.
+    std::vector<SkPackedGlyphID> fPendingGlyphImages;
+    std::vector<SkPackedGlyphID> fPendingGlyphPaths;
+
+    // The device descriptor is used to create the scaler context. The glyphs to have the
+    // correct device rendering. The key descriptor is used for communication. The GPU side will
+    // create descriptors with out the device filtering, thus matching the key descriptor.
+    std::unique_ptr<SkDescriptor> fDeviceDescriptor;
+    std::unique_ptr<SkDescriptor> fKeyDescriptor;
+    const SkDiscardableHandleId fDiscardableHandleId;
+    // The context built using fDeviceDescriptor
+    std::unique_ptr<SkScalerContext> fContext;
+    bool fIsSubpixel;
+    SkAxisAlignment fAxisAlignmentForHText;
+
+    // FallbackTextHelper cases require glyph metrics when analyzing a glyph run, in which case
+    // we cache them here.
+    SkTHashMap<SkPackedGlyphID, SkGlyph> fGlyphMap;
+};
+
+class SkTextBlobCacheDiffCanvas::TrackLayerDevice : public SkNoPixelsDevice {
+public:
+    TrackLayerDevice(const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
+                     const SkTextBlobCacheDiffCanvas::Settings& settings);
+
+    SkBaseDevice* onCreateDevice(const CreateInfo& cinfo, const SkPaint*) override;
+
+protected:
+    void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override;
+
+private:
+    void processGlyphRun(const SkPoint& origin, const SkGlyphRun& glyphRun);
+
+    void processGlyphRunForMask(
+            const SkGlyphRun& glyphRun, const SkMatrix& runMatrix, SkPoint origin);
+
+    void processGlyphRunForPaths(const SkGlyphRun& glyphRun, const SkMatrix& runMatrix);
+
+#if SK_SUPPORT_GPU
+    bool maybeProcessGlyphRunForDFT(const SkGlyphRun& glyphRun, const SkMatrix& runMatrix);
+#endif
+
+    SkStrikeServer* const fStrikeServer;
+    const SkTextBlobCacheDiffCanvas::Settings fSettings;
+    SkGlyphRunListPainter fPainter;
+};
+
+#endif // SkRemoteGlyphCacheImpl_DEFINED
diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp
index fd6350e..60ef272 100644
--- a/tests/SkRemoteGlyphCacheTest.cpp
+++ b/tests/SkRemoteGlyphCacheTest.cpp
@@ -9,6 +9,7 @@
 #include "SkGraphics.h"
 #include "SkMutex.h"
 #include "SkRemoteGlyphCache.h"
+#include "SkRemoteGlyphCacheImpl.h"
 #include "SkStrikeCache.h"
 #include "SkSurface.h"
 #include "SkTextBlob.h"