• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
KeyKey80         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 
setupKey(const GrTextBlob::Key & key,const SkMaskFilterBase::BlurRec & blurRec,const SkPaint & paint)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 
GetKey(const GrTextBlob & blob)113     static const Key& GetKey(const GrTextBlob& blob) {
114         return blob.fKey;
115     }
116 
Hash(const Key & key)117     static uint32_t Hash(const Key& key) {
118         return SkOpts::hash(&key, sizeof(Key));
119     }
120 
delete(void * p)121     void operator delete(void* p) {
122         ::operator delete(p);
123     }
124 
new(size_t)125     void* operator new(size_t) {
126         SK_ABORT("All blobs are created by placement new.");
127         return sk_malloc_throw(0);
128     }
129 
new(size_t,void * p)130     void* operator new(size_t, void* p) { return p; }
131 
hasDistanceField()132     bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
hasBitmap()133     bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
setHasDistanceField()134     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
setHasBitmap()135     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
136 
runCountLimit()137     int runCountLimit() const { return fRunCountLimit; }
138 
pushBackRun()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 
setMinAndMaxScale(SkScalar scaledMin,SkScalar scaledMax)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 
GetVertexStride(GrMaskFormat maskFormat,bool hasWCoord)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 
computeSubRunBounds(SkRect * outBounds,int runIndex,int subRunIndex,const SkMatrix & viewMatrix,SkScalar x,SkScalar y,bool needsGlyphTransform)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.
initReusableBlob(SkColor luminanceColor,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)227     void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix,
228                           SkScalar x, SkScalar y) {
229         fLuminanceColor = luminanceColor;
230         this->setupViewMatrix(viewMatrix, x, y);
231     }
232 
initThrowawayBlob(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)233     void initThrowawayBlob(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
234         this->setupViewMatrix(viewMatrix, x, y);
235     }
236 
key()237     const Key& key() const { return fKey; }
238 
size()239     size_t size() const { return fSize; }
240 
~GrTextBlob()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:
GrTextBlob(GrStrikeCache * strikeCache)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.
setupViewMatrix(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)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:
SubRun(Run * run,const SkAutoDescriptor & desc,GrColor color)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
resetBulkUseToken()290         void resetBulkUseToken() { fBulkUseToken.reset(); }
bulkUseToken()291         GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
setStrike(sk_sp<GrTextStrike> strike)292         void setStrike(sk_sp<GrTextStrike> strike) { fStrike = std::move(strike); }
strike()293         GrTextStrike* strike() const { return fStrike.get(); }
refStrike()294         sk_sp<GrTextStrike> refStrike() const { return fStrike; }
295 
setAtlasGeneration(uint64_t atlasGeneration)296         void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
atlasGeneration()297         uint64_t atlasGeneration() const { return fAtlasGeneration; }
298 
byteCount()299         size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
vertexStartIndex()300         size_t vertexStartIndex() const { return fVertexStartIndex; }
vertexEndIndex()301         size_t vertexEndIndex() const { return fVertexEndIndex; }
302 
glyphCount()303         uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
glyphStartIndex()304         uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
glyphEndIndex()305         uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
setColor(GrColor color)306         void setColor(GrColor color) { fColor = color; }
color()307         GrColor color() const { return fColor; }
setMaskFormat(GrMaskFormat format)308         void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
maskFormat()309         GrMaskFormat maskFormat() const { return fMaskFormat; }
310 
setAsSuccessor(const SubRun & prev)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 
vertexBounds()322         const SkRect& vertexBounds() const { return fVertexBounds; }
joinGlyphBounds(const SkRect & glyphBounds)323         void joinGlyphBounds(const SkRect& glyphBounds) {
324             fVertexBounds.joinNonEmptyArg(glyphBounds);
325         }
326 
init(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)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
setDrawAsDistanceFields()338         void setDrawAsDistanceFields() { fFlags.drawAsSdf = true; }
drawAsDistanceFields()339         bool drawAsDistanceFields() const { return fFlags.drawAsSdf; }
setUseLCDText(bool useLCDText)340         void setUseLCDText(bool useLCDText) { fFlags.useLCDText = useLCDText; }
hasUseLCDText()341         bool hasUseLCDText() const { return fFlags.useLCDText; }
setAntiAliased(bool antiAliased)342         void setAntiAliased(bool antiAliased) { fFlags.antiAliased = antiAliased; }
isAntiAliased()343         bool isAntiAliased() const { return fFlags.antiAliased; }
setHasWCoord(bool hasW)344         void setHasWCoord(bool hasW) { fFlags.hasWCoord = hasW; }
hasWCoord()345         bool hasWCoord() const { return fFlags.hasWCoord; }
setNeedsTransform(bool needsTransform)346         void setNeedsTransform(bool needsTransform) { fFlags.needsTransform = needsTransform; }
needsTransform()347         bool needsTransform() const { return fFlags.needsTransform; }
setFallback()348         void setFallback() { fFlags.argbFallback = true; }
isFallback()349         bool isFallback() { return fFlags.argbFallback; }
350 
desc()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 {
RunRun403         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
setSubRunHasWRun410         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
initARGBFallbackRun417         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 
setRunFontAntiAliasRun450         void setRunFontAntiAlias(bool aa) {
451             fAntiAlias = aa;
452         }
453 
454         // sets the last subrun of runIndex to use distance field text
setSubRunHasDistanceFieldsRun455         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 
pushBackSubRunRun463         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 {
PathGlyphRun::PathGlyph477             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