• 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 "include/core/SkPathEffect.h"
12 #include "include/core/SkPoint3.h"
13 #include "include/core/SkSurfaceProps.h"
14 #include "src/core/SkDescriptor.h"
15 #include "src/core/SkMaskFilterBase.h"
16 #include "src/core/SkOpts.h"
17 #include "src/core/SkRectPriv.h"
18 #include "src/core/SkStrikeCache.h"
19 #include "src/core/SkStrikeSpec.h"
20 #include "src/core/SkTInternalLList.h"
21 #include "src/gpu/GrColor.h"
22 #include "src/gpu/GrDrawOpAtlas.h"
23 #include "src/gpu/text/GrStrikeCache.h"
24 #include "src/gpu/text/GrTextContext.h"
25 #include "src/gpu/text/GrTextTarget.h"
26 
27 class GrAtlasManager;
28 struct GrDistanceFieldAdjustTable;
29 struct GrGlyph;
30 
31 class SkTextBlob;
32 class SkTextBlobRunIterator;
33 
34 // With this flag enabled, the GrTextContext will, as a sanity check, regenerate every blob
35 // that comes in to verify the integrity of its cache
36 #define CACHE_SANITY_CHECK 0
37 
38 /*
39  * A GrTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
40  * on the GPU.  These are initially created with valid positions and colors, but invalid
41  * texture coordinates.  The GrTextBlob itself has a few Blob-wide properties, and also
42  * consists of a number of runs.  Runs inside a blob are flushed individually so they can be
43  * reordered.
44  *
45  * The only thing(aside from a memcopy) required to flush a GrTextBlob is to ensure that
46  * the GrAtlas will not evict anything the Blob needs.
47  *
48  * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
49  *
50  * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual
51  */
52 class GrTextBlob : public SkNVRefCnt<GrTextBlob>, public SkGlyphRunPainterInterface {
53     struct Run;
54 public:
55     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob);
56 
57     class VertexRegenerator;
58 
59     void generateFromGlyphRunList(const GrShaderCaps& shaderCaps,
60                                   const GrTextContext::Options& options,
61                                   const SkPaint& paint,
62                                   SkScalerContextFlags scalerContextFlags,
63                                   const SkMatrix& viewMatrix,
64                                   const SkSurfaceProps& props,
65                                   const SkGlyphRunList& glyphRunList,
66                                   SkGlyphRunListPainter* glyphPainter);
67 
68     static sk_sp<GrTextBlob> Make(
69             int glyphCount,
70             int runCount,
71             GrColor color,
72             GrStrikeCache* strikeCache);
73 
74     /**
75      * We currently force regeneration of a blob if old or new matrix differ in having perspective.
76      * If we ever change that then the key must contain the perspectiveness when there are distance
77      * fields as perspective distance field use 3 component vertex positions and non-perspective
78      * uses 2.
79      */
80     struct Key {
KeyKey81         Key() {
82             sk_bzero(this, sizeof(Key));
83         }
84         uint32_t fUniqueID;
85         // Color may affect the gamma of the mask we generate, but in a fairly limited way.
86         // Each color is assigned to on of a fixed number of buckets based on its
87         // luminance. For each luminance bucket there is a "canonical color" that
88         // represents the bucket.  This functionality is currently only supported for A8
89         SkColor fCanonicalColor;
90         SkPaint::Style fStyle;
91         SkPixelGeometry fPixelGeometry;
92         bool fHasBlur;
93         uint32_t fScalerContextFlags;
94 
95         bool operator==(const Key& other) const {
96             return 0 == memcmp(this, &other, sizeof(Key));
97         }
98     };
99 
setupKey(const GrTextBlob::Key & key,const SkMaskFilterBase::BlurRec & blurRec,const SkPaint & paint)100     void setupKey(const GrTextBlob::Key& key,
101                   const SkMaskFilterBase::BlurRec& blurRec,
102                   const SkPaint& paint) {
103         fKey = key;
104         if (key.fHasBlur) {
105             fBlurRec = blurRec;
106         }
107         if (key.fStyle != SkPaint::kFill_Style) {
108             fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
109             fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
110             fStrokeInfo.fJoin = paint.getStrokeJoin();
111         }
112     }
113 
GetKey(const GrTextBlob & blob)114     static const Key& GetKey(const GrTextBlob& blob) {
115         return blob.fKey;
116     }
117 
Hash(const Key & key)118     static uint32_t Hash(const Key& key) {
119         return SkOpts::hash(&key, sizeof(Key));
120     }
121 
delete(void * p)122     void operator delete(void* p) {
123         ::operator delete(p);
124     }
125 
new(size_t)126     void* operator new(size_t) {
127         SK_ABORT("All blobs are created by placement new.");
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 SkStrikeSpec & strikeSpec,GrColor color)278         SubRun(Run* run, const SkStrikeSpec& strikeSpec, GrColor color)
279             : fColor{color}
280             , fRun{run}
281             , fStrikeSpec{strikeSpec} {}
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 
strikeSpec()351         const SkStrikeSpec& strikeSpec() const { return fStrikeSpec; }
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 SkStrikeSpec& fStrikeSpec;
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, fStrikeSpec, 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             fFallbackStrikeSpec.reset(new SkStrikeSpec{});
419             // Push back a new subrun to fill and set the override descriptor
420             SubRun* subRun = this->pushBackSubRun(*fFallbackStrikeSpec, 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 SkStrikeSpec& 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         SkSTArray<1, SubRun> fSubRunInfo;
491         SkStrikeSpec fStrikeSpec;
492 
493         // Distance field text cannot draw coloremoji, and so has to fall back.  However,
494         // though the distance field text and the coloremoji may share the same run, they
495         // will have different descriptors.  If fFallbackStrikeSpec is non-nullptr, then it
496         // will be used in place of the run's descriptor to regen texture coords
497         std::unique_ptr<SkStrikeSpec> fFallbackStrikeSpec;
498 
499         SkTArray<PathGlyph> fPathGlyphs;
500 
501         bool fAntiAlias{false};   // needed mainly for rendering paths
502         bool fInitialized{false};
503 
504         GrTextBlob* const fBlob;
505         GrColor fColor;
506     };  // Run
507 
508     std::unique_ptr<GrAtlasTextOp> makeOp(
509             const SubRun& info, int glyphCount, uint16_t run, uint16_t subRun,
510             const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
511             const SkPaint& paint, const SkPMColor4f& filteredColor, const SkSurfaceProps&,
512             const GrDistanceFieldAdjustTable*, GrTextTarget*);
513 
514     // currentRun, startRun, and the process* calls are all used by the SkGlyphRunPainter, and
515     // live in SkGlyphRunPainter.cpp file.
516     Run* currentRun();
517 
518     void startRun(const SkGlyphRun& glyphRun, bool useSDFT) override;
519 
520     void processDeviceMasks(SkSpan<const SkGlyphPos> masks,
521                             const SkStrikeSpec& strikeSpec) override;
522 
523     void processSourcePaths(SkSpan<const SkGlyphPos> paths,
524                             const SkStrikeSpec& strikeSpec) override;
525 
526     void processDevicePaths(SkSpan<const SkGlyphPos> paths) override;
527 
528     void processSourceSDFT(SkSpan<const SkGlyphPos> masks,
529                            const SkStrikeSpec& strikeSpec,
530                            const SkFont& runFont,
531                            SkScalar minScale,
532                            SkScalar maxScale,
533                            bool hasWCoord) override;
534 
535     void processSourceFallback(SkSpan<const SkGlyphPos> masks,
536                                const SkStrikeSpec& strikeSpec,
537                                bool hasW) override;
538 
539     void processDeviceFallback(SkSpan<const SkGlyphPos> masks,
540                                const SkStrikeSpec& strikeSpec) override;
541 
542     struct StrokeInfo {
543         SkScalar fFrameWidth;
544         SkScalar fMiterLimit;
545         SkPaint::Join fJoin;
546     };
547 
548     enum TextType {
549         kHasDistanceField_TextType = 0x1,
550         kHasBitmap_TextType = 0x2,
551     };
552 
553     // all glyph / vertex offsets are into these pools.
554     char* fVertices;
555     GrGlyph** fGlyphs;
556     Run* fRuns;
557 
558     // Lifetime: The GrStrikeCache is owned by and has the same lifetime as the GrRecordingContext.
559     // The GrRecordingContext also owns the GrTextBlob cache which owns this GrTextBlob.
560     GrStrikeCache* const fStrikeCache;
561     SkMaskFilterBase::BlurRec fBlurRec;
562     StrokeInfo fStrokeInfo;
563     Key fKey;
564     SkMatrix fInitialViewMatrix;
565     SkMatrix fInitialViewMatrixInverse;
566     size_t fSize;
567     SkColor fLuminanceColor;
568     SkScalar fInitialX;
569     SkScalar fInitialY;
570 
571     // We can reuse distance field text, but only if the new viewmatrix would not result in
572     // a mip change.  Because there can be multiple runs in a blob, we track the overall
573     // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
574     SkScalar fMaxMinScale{-SK_ScalarMax};
575     SkScalar fMinMaxScale{SK_ScalarMax};
576     int fRunCount{0};
577     int fRunCountLimit;
578     uint8_t fTextType{0};
579 };
580 
581 /**
582  * Used to produce vertices for a subrun of a blob. The vertices are cached in the blob itself.
583  * This is invoked each time a sub run is drawn. It regenerates the vertex data as required either
584  * because of changes to the atlas or because of different draw parameters (e.g. color change). In
585  * rare cases the draw may have to interrupted and flushed in the middle of the sub run in order to
586  * free up atlas space. Thus, this generator is stateful and should be invoked in a loop until the
587  * entire sub run has been completed.
588  */
589 class GrTextBlob::VertexRegenerator {
590 public:
591     /**
592      * Consecutive VertexRegenerators often use the same SkGlyphCache. If the same instance of
593      * SkAutoGlyphCache is reused then it can save the cost of multiple detach/attach operations of
594      * SkGlyphCache.
595      */
596     VertexRegenerator(GrResourceProvider*, GrTextBlob*, int runIdx, int subRunIdx,
597                       const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
598                       GrDeferredUploadTarget*, GrStrikeCache*, GrAtlasManager*,
599                       SkExclusiveStrikePtr*);
600 
601     struct Result {
602         /**
603          * Was regenerate() able to draw all the glyphs from the sub run? If not flush all glyph
604          * draws and call regenerate() again.
605          */
606         bool fFinished = true;
607 
608         /**
609          * How many glyphs were regenerated. Will be equal to the sub run's glyph count if
610          * fType is kFinished.
611          */
612         int fGlyphsRegenerated = 0;
613 
614         /**
615          * Pointer where the caller finds the first regenerated vertex.
616          */
617         const char* fFirstVertex;
618     };
619 
620     bool regenerate(Result*);
621 
622 private:
623     bool doRegen(Result*, bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs);
624 
625     GrResourceProvider* fResourceProvider;
626     const SkMatrix& fViewMatrix;
627     GrTextBlob* fBlob;
628     GrDeferredUploadTarget* fUploadTarget;
629     GrStrikeCache* fGlyphCache;
630     GrAtlasManager* fFullAtlasManager;
631     SkExclusiveStrikePtr* fLazyStrike;
632     SubRun* fSubRun;
633     GrColor fColor;
634     SkScalar fTransX;
635     SkScalar fTransY;
636 
637     uint32_t fRegenFlags = 0;
638     int fCurrGlyph = 0;
639     bool fBrokenRun = false;
640 };
641 
642 #endif  // GrTextBlob_DEFINED
643