split subrun API into Blob and Op interfaces

Instead of using sub classing to generate the atlas API, give
the atlas portion its own interface. Then the atlas subrun
variants can subclass both interfaces.

Change-Id: I8a0ca3d19bd362877224fa64f6c49a5f50d0ceb5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/336958
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/bench/GlyphQuadFillBench.cpp b/bench/GlyphQuadFillBench.cpp
index c1d8051..6d3a0fa 100644
--- a/bench/GlyphQuadFillBench.cpp
+++ b/bench/GlyphQuadFillBench.cpp
@@ -58,13 +58,15 @@
         }
 
         SkASSERT(fBlob->subRunList().head() != nullptr);
-        GrAtlasSubRun* subRun = static_cast<GrAtlasSubRun*>(fBlob->subRunList().head());
+        GrAtlasSubRun* subRun = fBlob->subRunList().head()->testingOnly_atlasSubRun();
+        SkASSERT(subRun);
         subRun->testingOnly_packedGlyphIDToGrGlyph(&fCache);
         fVertices.reset(new char[subRun->vertexStride() * subRun->glyphCount() * 4]);
     }
 
     void onDraw(int loops, SkCanvas* canvas) override {
-        GrAtlasSubRun* subRun = static_cast<GrAtlasSubRun*>(fBlob->subRunList().head());
+        GrAtlasSubRun* subRun = fBlob->subRunList().head()->testingOnly_atlasSubRun();
+        SkASSERT(subRun);
 
         SkIRect clip = SkIRect::MakeEmpty();
         SkPaint paint;
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 116826a..61508e4 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -471,7 +471,8 @@
         return nullptr;
     }
 
-    GrAtlasSubRun* subRun = static_cast<GrAtlasSubRun*>(blob->subRunList().head());
+    GrAtlasSubRun* subRun = blob->subRunList().head()->testingOnly_atlasSubRun();
+    SkASSERT(subRun);
     GrOp::Owner op;
     std::tie(std::ignore, op) = subRun->makeAtlasTextOp(nullptr, mtxProvider, glyphRunList, rtc);
     return op;
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index 7bec700..63b7cdf 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -182,6 +182,8 @@
 
     bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix) override;
 
+    GrAtlasSubRun* testingOnly_atlasSubRun() override;
+
     static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
                           bool isAntiAliased,
                           const SkStrikeSpec& strikeSpec,
@@ -295,6 +297,10 @@
 
     return alloc->make<PathSubRun>(
             isAntiAliased, strikeSpec, blob, SkSpan(pathData, drawables.size()));
+}
+
+GrAtlasSubRun* PathSubRun::testingOnly_atlasSubRun() {
+    return nullptr;
 };
 
 // -- PathSubRun::PathGlyph ------------------------------------------------------------------------
@@ -438,7 +444,7 @@
 }
 
 // -- DirectMaskSubRun -----------------------------------------------------------------------------
-class DirectMaskSubRun final : public GrAtlasSubRun {
+class DirectMaskSubRun final : public GrSubRun, public GrAtlasSubRun {
 public:
     using DevicePosition = skvx::Vec<2, int16_t>;
 
@@ -462,6 +468,8 @@
 
     bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix) override;
 
+    GrAtlasSubRun* testingOnly_atlasSubRun() override;
+
     size_t vertexStride() const override;
 
     int glyphCount() const override;
@@ -796,8 +804,12 @@
     return outBounds;
 }
 
+GrAtlasSubRun* DirectMaskSubRun::testingOnly_atlasSubRun() {
+    return this;
+}
+
 // -- TransformedMaskSubRun ------------------------------------------------------------------------
-class TransformedMaskSubRun final : public GrAtlasSubRun {
+class TransformedMaskSubRun final : public GrSubRun, public GrAtlasSubRun {
 public:
     struct VertexData {
         const SkPoint pos;
@@ -825,6 +837,8 @@
 
     bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix) override;
 
+    GrAtlasSubRun* testingOnly_atlasSubRun() override;
+
     std::tuple<const GrClip*, GrOp::Owner>
     makeAtlasTextOp(const GrClip* clip,
                     const SkMatrixProvider& viewMatrix,
@@ -896,7 +910,7 @@
     SkSpan<VertexData> vertexData{
             alloc->makeInitializedArray<VertexData>(vertexCount, initializer), vertexCount};
 
-    GrAtlasSubRun* subRun = alloc->make<TransformedMaskSubRun>(
+    GrSubRun* subRun = alloc->make<TransformedMaskSubRun>(
             format, blob, bounds, vertexData,
             GlyphVector::Make(strikeSpec, drawables.get<0>(), alloc));
 
@@ -1053,8 +1067,12 @@
     return drawMatrix.mapRect(outBounds);
 }
 
+GrAtlasSubRun* TransformedMaskSubRun::testingOnly_atlasSubRun() {
+    return this;
+}
+
 // -- SDFTSubRun -----------------------------------------------------------------------------------
-class SDFTSubRun final : public GrAtlasSubRun {
+class SDFTSubRun final : public GrSubRun, public GrAtlasSubRun {
 public:
     struct VertexData {
         const SkPoint pos;
@@ -1083,6 +1101,8 @@
 
     bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix) override;
 
+    GrAtlasSubRun* testingOnly_atlasSubRun() override;
+
     std::tuple<const GrClip*, GrOp::Owner>
     makeAtlasTextOp(const GrClip* clip,
                     const SkMatrixProvider& viewMatrix,
@@ -1330,6 +1350,10 @@
     outBounds.offset(drawOrigin);
     return drawMatrix.mapRect(outBounds);
 }
+
+GrAtlasSubRun* SDFTSubRun::testingOnly_atlasSubRun() {
+    return this;
+}
 }  // namespace
 
 // -- GrTextBlob::Key ------------------------------------------------------------------------------
diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h
index 9670274..c4810fc 100644
--- a/src/gpu/text/GrTextBlob.h
+++ b/src/gpu/text/GrTextBlob.h
@@ -156,10 +156,8 @@
     SkArenaAlloc fAlloc;
 };
 
-// -- GrSubRun -------------------------------------------------------------------------------------
-// There are several types of subrun, which can be broken into two broad classes:
-//   * PathSubRun - handle very large single color glyphs using paths to render the glyph.
-//   * GrAtlasSubRun - this is an abstract class used for atlas drawing.
+// -- GrAtlasSubRun --------------------------------------------------------------------------------
+// GrAtlasSubRun is the API that GrAtlasTextOp uses to generate vertex data for drawing.
 //     There are three different ways GrAtlasSubRun is specialized.
 //      * DirectMaskSubRun - this is by far the most common type of subrun. The mask pixels are
 //        in 1:1 correspondence with the pixels on the device. The destination rectangles in this
@@ -170,29 +168,12 @@
 //        space.
 //      * SDFTSubRun - scaled distance field text handles largish single color glyphs that still
 //        can fit in the atlas; the sizes between direct subruns, and path subruns. The destination
-//        rectangles are in source space.
-class GrSubRun {
-public:
-    virtual ~GrSubRun() = default;
-
-    // Produce GPU ops for this subRun.
-    virtual void draw(const GrClip* clip,
-                      const SkMatrixProvider& viewMatrix,
-                      const SkGlyphRunList& glyphRunList,
-                      GrRenderTargetContext* rtc) const = 0;
-
-    // Given an already cached subRun, can this subRun handle this combination paint, matrix, and
-    // position.
-    virtual bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix) = 0;
-
-private:
-    SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrSubRun);
-};
-
-// -- GrAtlasSubRun --------------------------------------------------------------------------------
-class GrAtlasSubRun : public GrSubRun {
+class GrAtlasSubRun  {
 public:
     static constexpr int kVerticesPerGlyph = 4;
+
+    virtual ~GrAtlasSubRun() = default;
+
     virtual size_t vertexStride() const = 0;
     virtual int glyphCount() const = 0;
 
@@ -213,4 +194,35 @@
     virtual std::tuple<bool, int> regenerateAtlas(
             int begin, int end, GrMeshDrawOp::Target* target) const = 0;
 };
+
+// -- GrSubRun -------------------------------------------------------------------------------------
+// GrSubRun is the API the GrTextBlob uses for the subruns.
+// There are several types of subrun, which can be broken into five classes:
+//   * PathSubRun - handle very large single color glyphs using paths to render the glyph.
+//   * DirectMaskSubRun - handle the majority of the glyphs where the cache entry's pixels are in
+//     1:1 correspondence to the device pixels.
+//   * TransformedMaskSubRun - handle large bitmap/argb glyphs that need to be scaled to the screen.
+//   * SDFTSubRun - use signed distance fields to draw largish glyphs to the screen.
+//   * GrAtlasSubRun - this is an abstract class used for atlas drawing.
+class GrSubRun {
+public:
+    virtual ~GrSubRun() = default;
+
+    // Produce GPU ops for this subRun.
+    virtual void draw(const GrClip* clip,
+                      const SkMatrixProvider& viewMatrix,
+                      const SkGlyphRunList& glyphRunList,
+                      GrRenderTargetContext* rtc) const = 0;
+
+    // Given an already cached subRun, can this subRun handle this combination paint, matrix, and
+    // position.
+    virtual bool canReuse(const SkPaint& paint, const SkMatrix& drawMatrix) = 0;
+
+    // Return the underlying atlas subrun if it exists. Otherwise, return nullptr.
+    // * Don't use this API. It is only to support testing.
+    virtual GrAtlasSubRun* testingOnly_atlasSubRun() = 0;
+
+private:
+    SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrSubRun);
+};
 #endif  // GrTextBlob_DEFINED