• 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> {
52     struct Run;
53 public:
54     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob);
55 
56     class VertexRegenerator;
57 
58     void generateFromGlyphRunList(GrStrikeCache* glyphCache,
59                                   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(int glyphCount, int runCount, GrColor color);
69 
70     /**
71      * We currently force regeneration of a blob if old or new matrix differ in having perspective.
72      * If we ever change that then the key must contain the perspectiveness when there are distance
73      * fields as perspective distance field use 3 component vertex positions and non-perspective
74      * uses 2.
75      */
76     struct Key {
KeyKey77         Key() {
78             sk_bzero(this, sizeof(Key));
79         }
80         uint32_t fUniqueID;
81         // Color may affect the gamma of the mask we generate, but in a fairly limited way.
82         // Each color is assigned to on of a fixed number of buckets based on its
83         // luminance. For each luminance bucket there is a "canonical color" that
84         // represents the bucket.  This functionality is currently only supported for A8
85         SkColor fCanonicalColor;
86         SkPaint::Style fStyle;
87         SkPixelGeometry fPixelGeometry;
88         bool fHasBlur;
89         uint32_t fScalerContextFlags;
90 
91         bool operator==(const Key& other) const {
92             return 0 == memcmp(this, &other, sizeof(Key));
93         }
94     };
95 
setupKey(const GrTextBlob::Key & key,const SkMaskFilterBase::BlurRec & blurRec,const SkPaint & paint)96     void setupKey(const GrTextBlob::Key& key,
97                   const SkMaskFilterBase::BlurRec& blurRec,
98                   const SkPaint& paint) {
99         fKey = key;
100         if (key.fHasBlur) {
101             fBlurRec = blurRec;
102         }
103         if (key.fStyle != SkPaint::kFill_Style) {
104             fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
105             fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
106             fStrokeInfo.fJoin = paint.getStrokeJoin();
107         }
108     }
109 
GetKey(const GrTextBlob & blob)110     static const Key& GetKey(const GrTextBlob& blob) {
111         return blob.fKey;
112     }
113 
Hash(const Key & key)114     static uint32_t Hash(const Key& key) {
115         return SkOpts::hash(&key, sizeof(Key));
116     }
117 
delete(void * p)118     void operator delete(void* p) {
119         ::operator delete(p);
120     }
121 
new(size_t)122     void* operator new(size_t) {
123         SK_ABORT("All blobs are created by placement new.");
124         return sk_malloc_throw(0);
125     }
126 
new(size_t,void * p)127     void* operator new(size_t, void* p) { return p; }
128 
hasDistanceField()129     bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
hasBitmap()130     bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
setHasDistanceField()131     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
setHasBitmap()132     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
133 
runCountLimit()134     int runCountLimit() const { return fRunCountLimit; }
135 
pushBackRun()136     Run* pushBackRun() {
137         SkASSERT(fRunCount < fRunCountLimit);
138 
139         // If there is more run, then connect up the subruns.
140         if (fRunCount > 0) {
141             SubRun& newRun = fRuns[fRunCount].fSubRunInfo.back();
142             SubRun& lastRun = fRuns[fRunCount - 1].fSubRunInfo.back();
143             newRun.setAsSuccessor(lastRun);
144         }
145 
146         fRunCount++;
147         return &fRuns[fRunCount - 1];
148     }
149 
setMinAndMaxScale(SkScalar scaledMax,SkScalar scaledMin)150     void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
151         // we init fMaxMinScale and fMinMaxScale in the constructor
152         fMaxMinScale = SkMaxScalar(scaledMax, fMaxMinScale);
153         fMinMaxScale = SkMinScalar(scaledMin, fMinMaxScale);
154     }
155 
GetVertexStride(GrMaskFormat maskFormat,bool hasWCoord)156     static size_t GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord) {
157         switch (maskFormat) {
158             case kA8_GrMaskFormat:
159                 return hasWCoord ? kGrayTextDFPerspectiveVASize : kGrayTextVASize;
160             case kARGB_GrMaskFormat:
161                 return hasWCoord ? kColorTextPerspectiveVASize : kColorTextVASize;
162             default:
163                 SkASSERT(!hasWCoord);
164                 return kLCDTextVASize;
165         }
166     }
167 
168     bool mustRegenerate(const SkPaint&, bool, const SkMaskFilterBase::BlurRec& blurRec,
169                         const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
170 
171     void flush(GrTextTarget*, const SkSurfaceProps& props,
172                const GrDistanceFieldAdjustTable* distanceAdjustTable,
173                const SkPaint& paint, const SkPMColor4f& filteredColor, const GrClip& clip,
174                const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
175 
computeSubRunBounds(SkRect * outBounds,int runIndex,int subRunIndex,const SkMatrix & viewMatrix,SkScalar x,SkScalar y,bool needsGlyphTransform)176     void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex,
177                              const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
178                              bool needsGlyphTransform) {
179         // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
180         // into device space.
181         // We handle vertex bounds differently for distance field text and bitmap text because
182         // the vertex bounds of bitmap text are in device space.  If we are flushing multiple runs
183         // from one blob then we are going to pay the price here of mapping the rect for each run.
184         const Run& run = fRuns[runIndex];
185         const SubRun& subRun = run.fSubRunInfo[subRunIndex];
186         *outBounds = subRun.vertexBounds();
187         if (needsGlyphTransform) {
188             // Distance field text is positioned with the (X,Y) as part of the glyph position,
189             // and currently the view matrix is applied on the GPU
190             outBounds->offset(x - fInitialX, y - fInitialY);
191             viewMatrix.mapRect(outBounds);
192         } else {
193             // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
194             // device space.
195             SkMatrix boundsMatrix = fInitialViewMatrixInverse;
196 
197             boundsMatrix.postTranslate(-fInitialX, -fInitialY);
198 
199             boundsMatrix.postTranslate(x, y);
200 
201             boundsMatrix.postConcat(viewMatrix);
202             boundsMatrix.mapRect(outBounds);
203 
204             // Due to floating point numerical inaccuracies, we have to round out here
205             outBounds->roundOut(outBounds);
206         }
207     }
208 
209     // position + local coord
210     static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
211     static const size_t kColorTextPerspectiveVASize = sizeof(SkPoint3) + sizeof(SkIPoint16);
212     static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);
213     static const size_t kGrayTextDFPerspectiveVASize =
214             sizeof(SkPoint3) + sizeof(GrColor) + sizeof(SkIPoint16);
215     static const size_t kLCDTextVASize = kGrayTextVASize;
216     static const size_t kMaxVASize = kGrayTextDFPerspectiveVASize;
217     static const int kVerticesPerGlyph = 4;
218 
219     static void AssertEqual(const GrTextBlob&, const GrTextBlob&);
220 
221     // The color here is the GrPaint color, and it is used to determine whether we
222     // have to regenerate LCD text blobs.
223     // We use this color vs the SkPaint color because it has the colorfilter applied.
initReusableBlob(SkColor luminanceColor,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)224     void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix,
225                           SkScalar x, SkScalar y) {
226         fLuminanceColor = luminanceColor;
227         this->setupViewMatrix(viewMatrix, x, y);
228     }
229 
initThrowawayBlob(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)230     void initThrowawayBlob(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
231         this->setupViewMatrix(viewMatrix, x, y);
232     }
233 
key()234     const Key& key() const { return fKey; }
235 
size()236     size_t size() const { return fSize; }
237 
~GrTextBlob()238     ~GrTextBlob() {
239         for (int i = 0; i < fRunCountLimit; i++) {
240             fRuns[i].~Run();
241         }
242     }
243 
244     ////////////////////////////////////////////////////////////////////////////////////////////////
245     // Internal test methods
246     std::unique_ptr<GrDrawOp> test_makeOp(int glyphCount, uint16_t run, uint16_t subRun,
247                                           const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
248                                           const SkPaint& paint, const SkPMColor4f& filteredColor,
249                                           const SkSurfaceProps&, const GrDistanceFieldAdjustTable*,
250                                           GrTextTarget*);
251 
252 private:
GrTextBlob()253     GrTextBlob()
254         : fMaxMinScale(-SK_ScalarMax)
255         , fMinMaxScale(SK_ScalarMax)
256         , fTextType(0) {}
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 SkPaint& skPaint,
449                        const SkFont& skFont,
450                        const SkDescriptor& skCache);
451 
setRunFontAntiAliasRun452         void setRunFontAntiAlias(bool aa) {
453             fAntiAlias = aa;
454         }
455 
456         // sets the last subrun of runIndex to use distance field text
setSubRunHasDistanceFieldsRun457         void setSubRunHasDistanceFields(bool hasLCD, bool isAntiAlias, bool hasWCoord) {
458             SubRun& subRun = fSubRunInfo.back();
459             subRun.setUseLCDText(hasLCD);
460             subRun.setAntiAliased(isAntiAlias);
461             subRun.setDrawAsDistanceFields();
462             subRun.setHasWCoord(hasWCoord);
463         }
464 
pushBackSubRunRun465         SubRun* pushBackSubRun(const SkAutoDescriptor& desc, GrColor color) {
466             // Forward glyph / vertex information to seed the new sub run
467             SubRun& newSubRun = fSubRunInfo.emplace_back(this, desc, color);
468 
469             const SubRun& prevSubRun = fSubRunInfo.fromBack(1);
470 
471             // Forward glyph / vertex information to seed the new sub run
472             newSubRun.setAsSuccessor(prevSubRun);
473             return &newSubRun;
474         }
475 
476         // Any glyphs that can't be rendered with the base or override descriptor
477         // are rendered as paths
478         struct PathGlyph {
PathGlyphRun::PathGlyph479             PathGlyph(const SkPath& path, SkScalar x, SkScalar y, SkScalar scale, bool preXformed)
480                 : fPath(path)
481                 , fX(x)
482                 , fY(y)
483                 , fScale(scale)
484                 , fPreTransformed(preXformed) {}
485             SkPath fPath;
486             SkScalar fX;
487             SkScalar fY;
488             SkScalar fScale;
489             bool fPreTransformed;
490         };
491 
492 
493         sk_sp<SkTypeface> fTypeface;
494         SkSTArray<1, SubRun> fSubRunInfo;
495         SkAutoDescriptor fDescriptor;
496 
497         // Effects from the paint that are used to build a SkScalerContext.
498         sk_sp<SkPathEffect> fPathEffect;
499         sk_sp<SkMaskFilter> fMaskFilter;
500 
501         // Distance field text cannot draw coloremoji, and so has to fall back.  However,
502         // though the distance field text and the coloremoji may share the same run, they
503         // will have different descriptors.  If fARGBFallbackDescriptor is non-nullptr, then it
504         // will be used in place of the run's descriptor to regen texture coords
505         std::unique_ptr<SkAutoDescriptor> fARGBFallbackDescriptor;
506 
507         SkTArray<PathGlyph> fPathGlyphs;
508 
509         bool fAntiAlias{false};   // needed mainly for rendering paths
510         bool fInitialized{false};
511 
512         GrTextBlob* const fBlob;
513         GrColor fColor;
514     };  // Run
515 
516     inline std::unique_ptr<GrAtlasTextOp> makeOp(
517             const SubRun& info, int glyphCount, uint16_t run, uint16_t subRun,
518             const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
519             const SkPaint& paint, const SkPMColor4f& filteredColor, const SkSurfaceProps&,
520             const GrDistanceFieldAdjustTable*, GrTextTarget*);
521 
522     struct StrokeInfo {
523         SkScalar fFrameWidth;
524         SkScalar fMiterLimit;
525         SkPaint::Join fJoin;
526     };
527 
528     enum TextType {
529         kHasDistanceField_TextType = 0x1,
530         kHasBitmap_TextType = 0x2,
531     };
532 
533     // all glyph / vertex offsets are into these pools.
534     char* fVertices;
535     GrGlyph** fGlyphs;
536     Run* fRuns;
537     SkMaskFilterBase::BlurRec fBlurRec;
538     StrokeInfo fStrokeInfo;
539     Key fKey;
540     SkMatrix fInitialViewMatrix;
541     SkMatrix fInitialViewMatrixInverse;
542     size_t fSize;
543     SkColor fLuminanceColor;
544     SkScalar fInitialX;
545     SkScalar fInitialY;
546 
547     // We can reuse distance field text, but only if the new viewmatrix would not result in
548     // a mip change.  Because there can be multiple runs in a blob, we track the overall
549     // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
550     SkScalar fMaxMinScale;
551     SkScalar fMinMaxScale;
552     int fRunCount{0};
553     int fRunCountLimit;
554     uint8_t fTextType;
555 };
556 
557 /**
558  * Used to produce vertices for a subrun of a blob. The vertices are cached in the blob itself.
559  * This is invoked each time a sub run is drawn. It regenerates the vertex data as required either
560  * because of changes to the atlas or because of different draw parameters (e.g. color change). In
561  * rare cases the draw may have to interrupted and flushed in the middle of the sub run in order to
562  * free up atlas space. Thus, this generator is stateful and should be invoked in a loop until the
563  * entire sub run has been completed.
564  */
565 class GrTextBlob::VertexRegenerator {
566 public:
567     /**
568      * Consecutive VertexRegenerators often use the same SkGlyphCache. If the same instance of
569      * SkAutoGlyphCache is reused then it can save the cost of multiple detach/attach operations of
570      * SkGlyphCache.
571      */
572     VertexRegenerator(GrResourceProvider*, GrTextBlob*, int runIdx, int subRunIdx,
573                       const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
574                       GrDeferredUploadTarget*, GrStrikeCache*, GrAtlasManager*,
575                       SkExclusiveStrikePtr*);
576 
577     struct Result {
578         /**
579          * Was regenerate() able to draw all the glyphs from the sub run? If not flush all glyph
580          * draws and call regenerate() again.
581          */
582         bool fFinished = true;
583 
584         /**
585          * How many glyphs were regenerated. Will be equal to the sub run's glyph count if
586          * fType is kFinished.
587          */
588         int fGlyphsRegenerated = 0;
589 
590         /**
591          * Pointer where the caller finds the first regenerated vertex.
592          */
593         const char* fFirstVertex;
594     };
595 
596     bool regenerate(Result*);
597 
598 private:
599     bool doRegen(Result*, bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs);
600 
601     GrResourceProvider* fResourceProvider;
602     const SkMatrix& fViewMatrix;
603     GrTextBlob* fBlob;
604     GrDeferredUploadTarget* fUploadTarget;
605     GrStrikeCache* fGlyphCache;
606     GrAtlasManager* fFullAtlasManager;
607     SkExclusiveStrikePtr* fLazyCache;
608     Run* fRun;
609     SubRun* fSubRun;
610     GrColor fColor;
611     SkScalar fTransX;
612     SkScalar fTransY;
613 
614     uint32_t fRegenFlags = 0;
615     int fCurrGlyph = 0;
616     bool fBrokenRun = false;
617 };
618 
619 #endif  // GrTextBlob_DEFINED
620