Home | History | Annotate | Download | only in text
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef GrTextBlob_DEFINED
      9 #define GrTextBlob_DEFINED
     10 
     11 #include "GrColor.h"
     12 #include "GrDrawOpAtlas.h"
     13 #include "GrStrikeCache.h"
     14 #include "GrTextTarget.h"
     15 #include "text/GrTextContext.h"
     16 #include "SkDescriptor.h"
     17 #include "SkMaskFilterBase.h"
     18 #include "SkOpts.h"
     19 #include "SkPathEffect.h"
     20 #include "SkPoint3.h"
     21 #include "SkRectPriv.h"
     22 #include "SkStrikeCache.h"
     23 #include "SkSurfaceProps.h"
     24 #include "SkTInternalLList.h"
     25 
     26 class GrAtlasManager;
     27 struct GrDistanceFieldAdjustTable;
     28 struct GrGlyph;
     29 
     30 class SkTextBlob;
     31 class SkTextBlobRunIterator;
     32 
     33 // With this flag enabled, the GrTextContext will, as a sanity check, regenerate every blob
     34 // that comes in to verify the integrity of its cache
     35 #define CACHE_SANITY_CHECK 0
     36 
     37 /*
     38  * A GrTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
     39  * on the GPU.  These are initially created with valid positions and colors, but invalid
     40  * texture coordinates.  The GrTextBlob itself has a few Blob-wide properties, and also
     41  * consists of a number of runs.  Runs inside a blob are flushed individually so they can be
     42  * reordered.
     43  *
     44  * The only thing(aside from a memcopy) required to flush a GrTextBlob is to ensure that
     45  * the GrAtlas will not evict anything the Blob needs.
     46  *
     47  * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
     48  *
     49  * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual
     50  */
     51 class GrTextBlob : public SkNVRefCnt<GrTextBlob>, public SkGlyphRunPainterInterface {
     52     struct Run;
     53 public:
     54     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob);
     55 
     56     class VertexRegenerator;
     57 
     58     void generateFromGlyphRunList(const GrShaderCaps& shaderCaps,
     59                                   const GrTextContext::Options& options,
     60                                   const SkPaint& paint,
     61                                   SkScalerContextFlags scalerContextFlags,
     62                                   const SkMatrix& viewMatrix,
     63                                   const SkSurfaceProps& props,
     64                                   const SkGlyphRunList& glyphRunList,
     65                                   SkGlyphRunListPainter* glyphPainter);
     66 
     67     static sk_sp<GrTextBlob> Make(
     68             int glyphCount,
     69             int runCount,
     70             GrColor color,
     71             GrStrikeCache* strikeCache);
     72 
     73     /**
     74      * We currently force regeneration of a blob if old or new matrix differ in having perspective.
     75      * If we ever change that then the key must contain the perspectiveness when there are distance
     76      * fields as perspective distance field use 3 component vertex positions and non-perspective
     77      * uses 2.
     78      */
     79     struct Key {
     80         Key() {
     81             sk_bzero(this, sizeof(Key));
     82         }
     83         uint32_t fUniqueID;
     84         // Color may affect the gamma of the mask we generate, but in a fairly limited way.
     85         // Each color is assigned to on of a fixed number of buckets based on its
     86         // luminance. For each luminance bucket there is a "canonical color" that
     87         // represents the bucket.  This functionality is currently only supported for A8
     88         SkColor fCanonicalColor;
     89         SkPaint::Style fStyle;
     90         SkPixelGeometry fPixelGeometry;
     91         bool fHasBlur;
     92         uint32_t fScalerContextFlags;
     93 
     94         bool operator==(const Key& other) const {
     95             return 0 == memcmp(this, &other, sizeof(Key));
     96         }
     97     };
     98 
     99     void setupKey(const GrTextBlob::Key& key,
    100                   const SkMaskFilterBase::BlurRec& blurRec,
    101                   const SkPaint& paint) {
    102         fKey = key;
    103         if (key.fHasBlur) {
    104             fBlurRec = blurRec;
    105         }
    106         if (key.fStyle != SkPaint::kFill_Style) {
    107             fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
    108             fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
    109             fStrokeInfo.fJoin = paint.getStrokeJoin();
    110         }
    111     }
    112 
    113     static const Key& GetKey(const GrTextBlob& blob) {
    114         return blob.fKey;
    115     }
    116 
    117     static uint32_t Hash(const Key& key) {
    118         return SkOpts::hash(&key, sizeof(Key));
    119     }
    120 
    121     void operator delete(void* p) {
    122         ::operator delete(p);
    123     }
    124 
    125     void* operator new(size_t) {
    126         SK_ABORT("All blobs are created by placement new.");
    127         return sk_malloc_throw(0);
    128     }
    129 
    130     void* operator new(size_t, void* p) { return p; }
    131 
    132     bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
    133     bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
    134     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
    135     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
    136 
    137     int runCountLimit() const { return fRunCountLimit; }
    138 
    139     Run* pushBackRun() {
    140         SkASSERT(fRunCount < fRunCountLimit);
    141 
    142         // If there is more run, then connect up the subruns.
    143         if (fRunCount > 0) {
    144             SubRun& newRun = fRuns[fRunCount].fSubRunInfo.back();
    145             SubRun& lastRun = fRuns[fRunCount - 1].fSubRunInfo.back();
    146             newRun.setAsSuccessor(lastRun);
    147         }
    148 
    149         fRunCount++;
    150         return this->currentRun();
    151     }
    152 
    153     void setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax) {
    154         // we init fMaxMinScale and fMinMaxScale in the constructor
    155         fMaxMinScale = SkMaxScalar(scaledMin, fMaxMinScale);
    156         fMinMaxScale = SkMinScalar(scaledMax, fMinMaxScale);
    157     }
    158 
    159     static size_t GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord) {
    160         switch (maskFormat) {
    161             case kA8_GrMaskFormat:
    162                 return hasWCoord ? kGrayTextDFPerspectiveVASize : kGrayTextVASize;
    163             case kARGB_GrMaskFormat:
    164                 return hasWCoord ? kColorTextPerspectiveVASize : kColorTextVASize;
    165             default:
    166                 SkASSERT(!hasWCoord);
    167                 return kLCDTextVASize;
    168         }
    169     }
    170 
    171     bool mustRegenerate(const SkPaint&, bool, const SkMaskFilterBase::BlurRec& blurRec,
    172                         const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
    173 
    174     void flush(GrTextTarget*, const SkSurfaceProps& props,
    175                const GrDistanceFieldAdjustTable* distanceAdjustTable,
    176                const SkPaint& paint, const SkPMColor4f& filteredColor, const GrClip& clip,
    177                const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
    178 
    179     void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex,
    180                              const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
    181                              bool needsGlyphTransform) {
    182         // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
    183         // into device space.
    184         // We handle vertex bounds differently for distance field text and bitmap text because
    185         // the vertex bounds of bitmap text are in device space.  If we are flushing multiple runs
    186         // from one blob then we are going to pay the price here of mapping the rect for each run.
    187         const Run& run = fRuns[runIndex];
    188         const SubRun& subRun = run.fSubRunInfo[subRunIndex];
    189         *outBounds = subRun.vertexBounds();
    190         if (needsGlyphTransform) {
    191             // Distance field text is positioned with the (X,Y) as part of the glyph position,
    192             // and currently the view matrix is applied on the GPU
    193             outBounds->offset(x - fInitialX, y - fInitialY);
    194             viewMatrix.mapRect(outBounds);
    195         } else {
    196             // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
    197             // device space.
    198             SkMatrix boundsMatrix = fInitialViewMatrixInverse;
    199 
    200             boundsMatrix.postTranslate(-fInitialX, -fInitialY);
    201 
    202             boundsMatrix.postTranslate(x, y);
    203 
    204             boundsMatrix.postConcat(viewMatrix);
    205             boundsMatrix.mapRect(outBounds);
    206 
    207             // Due to floating point numerical inaccuracies, we have to round out here
    208             outBounds->roundOut(outBounds);
    209         }
    210     }
    211 
    212     // position + local coord
    213     static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
    214     static const size_t kColorTextPerspectiveVASize = sizeof(SkPoint3) + sizeof(SkIPoint16);
    215     static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);
    216     static const size_t kGrayTextDFPerspectiveVASize =
    217             sizeof(SkPoint3) + sizeof(GrColor) + sizeof(SkIPoint16);
    218     static const size_t kLCDTextVASize = kGrayTextVASize;
    219     static const size_t kMaxVASize = kGrayTextDFPerspectiveVASize;
    220     static const int kVerticesPerGlyph = 4;
    221 
    222     static void AssertEqual(const GrTextBlob&, const GrTextBlob&);
    223 
    224     // The color here is the GrPaint color, and it is used to determine whether we
    225     // have to regenerate LCD text blobs.
    226     // We use this color vs the SkPaint color because it has the colorfilter applied.
    227     void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix,
    228                           SkScalar x, SkScalar y) {
    229         fLuminanceColor = luminanceColor;
    230         this->setupViewMatrix(viewMatrix, x, y);
    231     }
    232 
    233     void initThrowawayBlob(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
    234         this->setupViewMatrix(viewMatrix, x, y);
    235     }
    236 
    237     const Key& key() const { return fKey; }
    238 
    239     size_t size() const { return fSize; }
    240 
    241     ~GrTextBlob() override {
    242         for (int i = 0; i < fRunCountLimit; i++) {
    243             fRuns[i].~Run();
    244         }
    245     }
    246 
    247     ////////////////////////////////////////////////////////////////////////////////////////////////
    248     // Internal test methods
    249     std::unique_ptr<GrDrawOp> test_makeOp(int glyphCount, uint16_t run, uint16_t subRun,
    250                                           const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
    251                                           const SkPaint& paint, const SkPMColor4f& filteredColor,
    252                                           const SkSurfaceProps&, const GrDistanceFieldAdjustTable*,
    253                                           GrTextTarget*);
    254 
    255 private:
    256     GrTextBlob(GrStrikeCache* strikeCache) : fStrikeCache{strikeCache} { }
    257 
    258     // This function will only be called when we are generating a blob from scratch. We record the
    259     // initial view matrix and initial offsets(x,y), because we record vertex bounds relative to
    260     // these numbers.  When blobs are reused with new matrices, we need to return to model space so
    261     // we can update the vertex bounds appropriately.
    262     void setupViewMatrix(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
    263         fInitialViewMatrix = viewMatrix;
    264         if (!viewMatrix.invert(&fInitialViewMatrixInverse)) {
    265             fInitialViewMatrixInverse = SkMatrix::I();
    266         }
    267         fInitialX = x;
    268         fInitialY = y;
    269 
    270         // make sure all initial subruns have the correct VM and X/Y applied
    271         for (int i = 0; i < fRunCountLimit; i++) {
    272             fRuns[i].fSubRunInfo[0].init(fInitialViewMatrix, x, y);
    273         }
    274     }
    275 
    276     class SubRun {
    277     public:
    278         SubRun(Run* run, const SkAutoDescriptor& desc, GrColor color)
    279             : fColor{color}
    280             , fRun{run}
    281             , fDesc{desc} {}
    282 
    283         // When used with emplace_back, this constructs a SubRun from the last SubRun in an array.
    284         //SubRun(SkSTArray<1, SubRun>* subRunList)
    285         //    : fColor{subRunList->fromBack(1).fColor} { }
    286 
    287         void appendGlyph(GrGlyph* glyph, SkRect dstRect);
    288 
    289         // TODO when this object is more internal, drop the privacy
    290         void resetBulkUseToken() { fBulkUseToken.reset(); }
    291         GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
    292         void setStrike(sk_sp<GrTextStrike> strike) { fStrike = std::move(strike); }
    293         GrTextStrike* strike() const { return fStrike.get(); }
    294         sk_sp<GrTextStrike> refStrike() const { return fStrike; }
    295 
    296         void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
    297         uint64_t atlasGeneration() const { return fAtlasGeneration; }
    298 
    299         size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
    300         size_t vertexStartIndex() const { return fVertexStartIndex; }
    301         size_t vertexEndIndex() const { return fVertexEndIndex; }
    302 
    303         uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
    304         uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
    305         uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
    306         void setColor(GrColor color) { fColor = color; }
    307         GrColor color() const { return fColor; }
    308         void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
    309         GrMaskFormat maskFormat() const { return fMaskFormat; }
    310 
    311         void setAsSuccessor(const SubRun& prev) {
    312             fGlyphStartIndex = prev.glyphEndIndex();
    313             fGlyphEndIndex = fGlyphStartIndex;
    314 
    315             fVertexStartIndex = prev.vertexEndIndex();
    316             fVertexEndIndex = fVertexStartIndex;
    317 
    318             // copy over viewmatrix settings
    319             this->init(prev.fCurrentViewMatrix, prev.fX, prev.fY);
    320         }
    321 
    322         const SkRect& vertexBounds() const { return fVertexBounds; }
    323         void joinGlyphBounds(const SkRect& glyphBounds) {
    324             fVertexBounds.joinNonEmptyArg(glyphBounds);
    325         }
    326 
    327         void init(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
    328             fCurrentViewMatrix = viewMatrix;
    329             fX = x;
    330             fY = y;
    331         }
    332 
    333         // This function assumes the translation will be applied before it is called again
    334         void computeTranslation(const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
    335                                 SkScalar* transX, SkScalar* transY);
    336 
    337         // df properties
    338         void setDrawAsDistanceFields() { fFlags.drawAsSdf = true; }
    339         bool drawAsDistanceFields() const { return fFlags.drawAsSdf; }
    340         void setUseLCDText(bool useLCDText) { fFlags.useLCDText = useLCDText; }
    341         bool hasUseLCDText() const { return fFlags.useLCDText; }
    342         void setAntiAliased(bool antiAliased) { fFlags.antiAliased = antiAliased; }
    343         bool isAntiAliased() const { return fFlags.antiAliased; }
    344         void setHasWCoord(bool hasW) { fFlags.hasWCoord = hasW; }
    345         bool hasWCoord() const { return fFlags.hasWCoord; }
    346         void setNeedsTransform(bool needsTransform) { fFlags.needsTransform = needsTransform; }
    347         bool needsTransform() const { return fFlags.needsTransform; }
    348         void setFallback() { fFlags.argbFallback = true; }
    349         bool isFallback() { return fFlags.argbFallback; }
    350 
    351         const SkDescriptor* desc() const { return fDesc.getDesc(); }
    352 
    353     private:
    354         GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
    355         sk_sp<GrTextStrike> fStrike;
    356         SkMatrix fCurrentViewMatrix;
    357         SkRect fVertexBounds = SkRectPriv::MakeLargestInverted();
    358         uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration};
    359         size_t fVertexStartIndex{0};
    360         size_t fVertexEndIndex{0};
    361         uint32_t fGlyphStartIndex{0};
    362         uint32_t fGlyphEndIndex{0};
    363         SkScalar fX;
    364         SkScalar fY;
    365         GrColor fColor{GrColor_ILLEGAL};
    366         GrMaskFormat fMaskFormat{kA8_GrMaskFormat};
    367         struct {
    368             bool drawAsSdf:1;
    369             bool useLCDText:1;
    370             bool antiAliased:1;
    371             bool hasWCoord:1;
    372             bool needsTransform:1;
    373             bool argbFallback:1;
    374         } fFlags{false, false, false, false, false, false};
    375         Run* const fRun;
    376         const SkAutoDescriptor& fDesc;
    377     };  // SubRunInfo
    378 
    379     /*
    380      * Each Run inside of the blob can have its texture coordinates regenerated if required.
    381      * To determine if regeneration is necessary, fAtlasGeneration is used.  If there have been
    382      * any evictions inside of the atlas, then we will simply regenerate Runs.  We could track
    383      * this at a more fine grained level, but its not clear if this is worth it, as evictions
    384      * should be fairly rare.
    385      *
    386      * One additional point, each run can contain glyphs with any of the three mask formats.
    387      * We call these SubRuns.  Because a subrun must be a contiguous range, we have to create
    388      * a new subrun each time the mask format changes in a run.  In theory, a run can have as
    389      * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8.  In
    390      * practice, the vast majority of runs have only a single subrun.
    391      *
    392      * Finally, for runs where the entire thing is too large for the GrTextContext to
    393      * handle, we have a bit to mark the run as flushable via rendering as paths or as scaled
    394      * glyphs. It would be a bit expensive to figure out ahead of time whether or not a run
    395      * can flush in this manner, so we always allocate vertices for the run, regardless of
    396      * whether or not it is too large.  The benefit of this strategy is that we can always reuse
    397      * a blob allocation regardless of viewmatrix changes.  We could store positions for these
    398      * glyphs, however, it's not clear if this is a win because we'd still have to either go to the
    399      * glyph cache to get the path at flush time, or hold onto the path in the cache, which
    400      * would greatly increase the memory of these cached items.
    401      */
    402     struct Run {
    403         explicit Run(GrTextBlob* blob, GrColor color)
    404         : fBlob{blob}, fColor{color} {
    405             // To ensure we always have one subrun, we push back a fresh run here
    406             fSubRunInfo.emplace_back(this, fDescriptor, color);
    407         }
    408 
    409         // sets the last subrun of runIndex to use w values
    410         void setSubRunHasW(bool hasWCoord) {
    411             SubRun& subRun = this->fSubRunInfo.back();
    412             subRun.setHasWCoord(hasWCoord);
    413         }
    414 
    415         // inits the override descriptor on the current run.  All following subruns must use this
    416         // descriptor
    417         SubRun* initARGBFallback() {
    418             fARGBFallbackDescriptor.reset(new SkAutoDescriptor{});
    419             // Push back a new subrun to fill and set the override descriptor
    420             SubRun* subRun = this->pushBackSubRun(*fARGBFallbackDescriptor, fColor);
    421             subRun->setMaskFormat(kARGB_GrMaskFormat);
    422             subRun->setFallback();
    423             return subRun;
    424         }
    425 
    426         // Appends a glyph to the blob as a path only.
    427         void appendPathGlyph(
    428                 const SkPath& path, SkPoint position, SkScalar scale, bool preTransformed);
    429 
    430         // Append a glyph to the sub run taking care to switch the glyph if needed.
    431         void switchSubRunIfNeededAndAppendGlyph(GrGlyph* glyph,
    432                                                 const sk_sp<GrTextStrike>& strike,
    433                                                 const SkRect& destRect,
    434                                                 bool needsTransform);
    435 
    436         // Used when the glyph in the cache has the CTM already applied, therefore no transform
    437         // is needed during rendering.
    438         void appendDeviceSpaceGlyph(const sk_sp<GrTextStrike>& strike,
    439                                     const SkGlyph& skGlyph,
    440                                     SkPoint origin);
    441 
    442         // The glyph is oriented upright in the cache and needs to be transformed onto the screen.
    443         void appendSourceSpaceGlyph(const sk_sp<GrTextStrike>& strike,
    444                                     const SkGlyph& skGlyph,
    445                                     SkPoint origin,
    446                                     SkScalar textScale);
    447 
    448         void setupFont(const SkStrikeSpec& strikeSpec);
    449 
    450         void setRunFontAntiAlias(bool aa) {
    451             fAntiAlias = aa;
    452         }
    453 
    454         // sets the last subrun of runIndex to use distance field text
    455         void setSubRunHasDistanceFields(bool hasLCD, bool isAntiAlias, bool hasWCoord) {
    456             SubRun& subRun = fSubRunInfo.back();
    457             subRun.setUseLCDText(hasLCD);
    458             subRun.setAntiAliased(isAntiAlias);
    459             subRun.setDrawAsDistanceFields();
    460             subRun.setHasWCoord(hasWCoord);
    461         }
    462 
    463         SubRun* pushBackSubRun(const SkAutoDescriptor& desc, GrColor color) {
    464             // Forward glyph / vertex information to seed the new sub run
    465             SubRun& newSubRun = fSubRunInfo.emplace_back(this, desc, color);
    466 
    467             const SubRun& prevSubRun = fSubRunInfo.fromBack(1);
    468 
    469             // Forward glyph / vertex information to seed the new sub run
    470             newSubRun.setAsSuccessor(prevSubRun);
    471             return &newSubRun;
    472         }
    473 
    474         // Any glyphs that can't be rendered with the base or override descriptor
    475         // are rendered as paths
    476         struct PathGlyph {
    477             PathGlyph(const SkPath& path, SkScalar x, SkScalar y, SkScalar scale, bool preXformed)
    478                 : fPath(path)
    479                 , fX(x)
    480                 , fY(y)
    481                 , fScale(scale)
    482                 , fPreTransformed(preXformed) {}
    483             SkPath fPath;
    484             SkScalar fX;
    485             SkScalar fY;
    486             SkScalar fScale;
    487             bool fPreTransformed;
    488         };
    489 
    490 
    491         sk_sp<SkTypeface> fTypeface;
    492         SkSTArray<1, SubRun> fSubRunInfo;
    493         SkAutoDescriptor fDescriptor;
    494 
    495         // Effects from the paint that are used to build a SkScalerContext.
    496         sk_sp<SkPathEffect> fPathEffect;
    497         sk_sp<SkMaskFilter> fMaskFilter;
    498 
    499         // Distance field text cannot draw coloremoji, and so has to fall back.  However,
    500         // though the distance field text and the coloremoji may share the same run, they
    501         // will have different descriptors.  If fARGBFallbackDescriptor is non-nullptr, then it
    502         // will be used in place of the run's descriptor to regen texture coords
    503         std::unique_ptr<SkAutoDescriptor> fARGBFallbackDescriptor;
    504 
    505         SkTArray<PathGlyph> fPathGlyphs;
    506 
    507         bool fAntiAlias{false};   // needed mainly for rendering paths
    508         bool fInitialized{false};
    509 
    510         GrTextBlob* const fBlob;
    511         GrColor fColor;
    512     };  // Run
    513 
    514     std::unique_ptr<GrAtlasTextOp> makeOp(
    515             const SubRun& info, int glyphCount, uint16_t run, uint16_t subRun,
    516             const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
    517             const SkPaint& paint, const SkPMColor4f& filteredColor, const SkSurfaceProps&,
    518             const GrDistanceFieldAdjustTable*, GrTextTarget*);
    519 
    520     // currentRun, startRun, and the process* calls are all used by the SkGlyphRunPainter, and
    521     // live in SkGlyphRunPainter.cpp file.
    522     Run* currentRun();
    523 
    524     void startRun(const SkGlyphRun& glyphRun, bool useSDFT) override;
    525 
    526     void processDeviceMasks(SkSpan<const SkGlyphPos> masks,
    527                             SkStrikeInterface* strike) override;
    528 
    529     void processSourcePaths(SkSpan<const SkGlyphPos> paths,
    530                             SkStrikeInterface* strike, SkScalar cacheToSourceScale) override;
    531 
    532     void processDevicePaths(SkSpan<const SkGlyphPos> paths) override;
    533 
    534     void processSourceSDFT(SkSpan<const SkGlyphPos> masks,
    535                            SkStrikeInterface* strike,
    536                            const SkFont& runFont,
    537                            SkScalar cacheToSourceScale,
    538                            SkScalar minScale,
    539                            SkScalar maxScale,
    540                            bool hasWCoord) override;
    541 
    542     void processSourceFallback(SkSpan<const SkGlyphPos> masks,
    543                                SkStrikeInterface* strike,
    544                                SkScalar cacheToSourceScale,
    545                                bool hasW) override;
    546 
    547     void processDeviceFallback(SkSpan<const SkGlyphPos> masks,
    548                                SkStrikeInterface* strike) override;
    549 
    550     struct StrokeInfo {
    551         SkScalar fFrameWidth;
    552         SkScalar fMiterLimit;
    553         SkPaint::Join fJoin;
    554     };
    555 
    556     enum TextType {
    557         kHasDistanceField_TextType = 0x1,
    558         kHasBitmap_TextType = 0x2,
    559     };
    560 
    561     // all glyph / vertex offsets are into these pools.
    562     char* fVertices;
    563     GrGlyph** fGlyphs;
    564     Run* fRuns;
    565 
    566     // Lifetime: The GrStrikeCache is owned by and has the same lifetime as the GrRecordingContext.
    567     // The GrRecordingContext also owns the GrTextBlob cache which owns this GrTextBlob.
    568     GrStrikeCache* const fStrikeCache;
    569     SkMaskFilterBase::BlurRec fBlurRec;
    570     StrokeInfo fStrokeInfo;
    571     Key fKey;
    572     SkMatrix fInitialViewMatrix;
    573     SkMatrix fInitialViewMatrixInverse;
    574     size_t fSize;
    575     SkColor fLuminanceColor;
    576     SkScalar fInitialX;
    577     SkScalar fInitialY;
    578 
    579     // We can reuse distance field text, but only if the new viewmatrix would not result in
    580     // a mip change.  Because there can be multiple runs in a blob, we track the overall
    581     // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
    582     SkScalar fMaxMinScale{-SK_ScalarMax};
    583     SkScalar fMinMaxScale{SK_ScalarMax};
    584     int fRunCount{0};
    585     int fRunCountLimit;
    586     uint8_t fTextType{0};
    587 };
    588 
    589 /**
    590  * Used to produce vertices for a subrun of a blob. The vertices are cached in the blob itself.
    591  * This is invoked each time a sub run is drawn. It regenerates the vertex data as required either
    592  * because of changes to the atlas or because of different draw parameters (e.g. color change). In
    593  * rare cases the draw may have to interrupted and flushed in the middle of the sub run in order to
    594  * free up atlas space. Thus, this generator is stateful and should be invoked in a loop until the
    595  * entire sub run has been completed.
    596  */
    597 class GrTextBlob::VertexRegenerator {
    598 public:
    599     /**
    600      * Consecutive VertexRegenerators often use the same SkGlyphCache. If the same instance of
    601      * SkAutoGlyphCache is reused then it can save the cost of multiple detach/attach operations of
    602      * SkGlyphCache.
    603      */
    604     VertexRegenerator(GrResourceProvider*, GrTextBlob*, int runIdx, int subRunIdx,
    605                       const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
    606                       GrDeferredUploadTarget*, GrStrikeCache*, GrAtlasManager*,
    607                       SkExclusiveStrikePtr*);
    608 
    609     struct Result {
    610         /**
    611          * Was regenerate() able to draw all the glyphs from the sub run? If not flush all glyph
    612          * draws and call regenerate() again.
    613          */
    614         bool fFinished = true;
    615 
    616         /**
    617          * How many glyphs were regenerated. Will be equal to the sub run's glyph count if
    618          * fType is kFinished.
    619          */
    620         int fGlyphsRegenerated = 0;
    621 
    622         /**
    623          * Pointer where the caller finds the first regenerated vertex.
    624          */
    625         const char* fFirstVertex;
    626     };
    627 
    628     bool regenerate(Result*);
    629 
    630 private:
    631     bool doRegen(Result*, bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs);
    632 
    633     GrResourceProvider* fResourceProvider;
    634     const SkMatrix& fViewMatrix;
    635     GrTextBlob* fBlob;
    636     GrDeferredUploadTarget* fUploadTarget;
    637     GrStrikeCache* fGlyphCache;
    638     GrAtlasManager* fFullAtlasManager;
    639     SkExclusiveStrikePtr* fLazyCache;
    640     Run* fRun;
    641     SubRun* fSubRun;
    642     GrColor fColor;
    643     SkScalar fTransX;
    644     SkScalar fTransY;
    645 
    646     uint32_t fRegenFlags = 0;
    647     int fCurrGlyph = 0;
    648     bool fBrokenRun = false;
    649 };
    650 
    651 #endif  // GrTextBlob_DEFINED
    652