• 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 GrAtlasTextBlob_DEFINED
9 #define GrAtlasTextBlob_DEFINED
10 
11 #include "GrColor.h"
12 #include "GrDrawOpAtlas.h"
13 #include "GrGlyphCache.h"
14 #include "GrMemoryPool.h"
15 #include "GrTextUtils.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 "SkSurfaceProps.h"
23 #include "SkTInternalLList.h"
24 
25 class GrAtlasManager;
26 struct GrDistanceFieldAdjustTable;
27 struct GrGlyph;
28 class GrGlyphCache;
29 class GrMemoryPool;
30 class GrRestrictedAtlasManager;
31 
32 class SkDrawFilter;
33 class SkTextBlob;
34 class SkTextBlobRunIterator;
35 
36 // With this flag enabled, the GrAtlasTextContext will, as a sanity check, regenerate every blob
37 // that comes in to verify the integrity of its cache
38 #define CACHE_SANITY_CHECK 0
39 
40 /*
41  * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
42  * on the GPU.  These are initially created with valid positions and colors, but invalid
43  * texture coordinates.  The GrAtlasTextBlob itself has a few Blob-wide properties, and also
44  * consists of a number of runs.  Runs inside a blob are flushed individually so they can be
45  * reordered.
46  *
47  * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that
48  * the GrAtlas will not evict anything the Blob needs.
49  *
50  * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
51  *
52  * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual
53  */
54 class GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> {
55 public:
56     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob);
57 
58     class VertexRegenerator;
59 
60     static sk_sp<GrAtlasTextBlob> Make(GrMemoryPool*, int glyphCount, int runCount);
61 
62     /**
63      * We currently force regeneration of a blob if old or new matrix differ in having perspective.
64      * If we ever change that then the key must contain the perspectiveness when there are distance
65      * fields as perspective distance field use 3 component vertex positions and non-perspective
66      * uses 2.
67      */
68     struct Key {
KeyKey69         Key() {
70             sk_bzero(this, sizeof(Key));
71         }
72         uint32_t fUniqueID;
73         // Color may affect the gamma of the mask we generate, but in a fairly limited way.
74         // Each color is assigned to on of a fixed number of buckets based on its
75         // luminance. For each luminance bucket there is a "canonical color" that
76         // represents the bucket.  This functionality is currently only supported for A8
77         SkColor fCanonicalColor;
78         SkPaint::Style fStyle;
79         SkPixelGeometry fPixelGeometry;
80         bool fHasBlur;
81         uint32_t fScalerContextFlags;
82 
83         bool operator==(const Key& other) const {
84             return 0 == memcmp(this, &other, sizeof(Key));
85         }
86     };
87 
setupKey(const GrAtlasTextBlob::Key & key,const SkMaskFilterBase::BlurRec & blurRec,const SkPaint & paint)88     void setupKey(const GrAtlasTextBlob::Key& key,
89                   const SkMaskFilterBase::BlurRec& blurRec,
90                   const SkPaint& paint) {
91         fKey = key;
92         if (key.fHasBlur) {
93             fBlurRec = blurRec;
94         }
95         if (key.fStyle != SkPaint::kFill_Style) {
96             fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
97             fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
98             fStrokeInfo.fJoin = paint.getStrokeJoin();
99         }
100     }
101 
GetKey(const GrAtlasTextBlob & blob)102     static const Key& GetKey(const GrAtlasTextBlob& blob) {
103         return blob.fKey;
104     }
105 
Hash(const Key & key)106     static uint32_t Hash(const Key& key) {
107         return SkOpts::hash(&key, sizeof(Key));
108     }
109 
delete(void * p)110     void operator delete(void* p) {
111         GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p);
112         if (blob->fPool) {
113             blob->fPool->release(p);
114         } else {
115             ::operator delete(p);
116         }
117     }
new(size_t)118     void* operator new(size_t) {
119         SK_ABORT("All blobs are created by placement new.");
120         return sk_malloc_throw(0);
121     }
122 
new(size_t,void * p)123     void* operator new(size_t, void* p) { return p; }
delete(void * target,void * placement)124     void operator delete(void* target, void* placement) {
125         ::operator delete(target, placement);
126     }
127 
hasDistanceField()128     bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
hasBitmap()129     bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
setHasDistanceField()130     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
setHasBitmap()131     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
132 
runCount()133     int runCount() const { return fRunCount; }
134 
push_back_run(int currRun)135     void push_back_run(int currRun) {
136         SkASSERT(currRun < fRunCount);
137         if (currRun > 0) {
138             Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back();
139             Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back();
140             newRun.setAsSuccessor(lastRun);
141         }
142     }
143 
144     // sets the last subrun of runIndex to use distance field text
setSubRunHasDistanceFields(int runIndex,bool hasLCD,bool isAntiAlias,bool hasWCoord)145     void setSubRunHasDistanceFields(int runIndex, bool hasLCD, bool isAntiAlias, bool hasWCoord) {
146         Run& run = fRuns[runIndex];
147         Run::SubRunInfo& subRun = run.fSubRunInfo.back();
148         subRun.setUseLCDText(hasLCD);
149         subRun.setAntiAliased(isAntiAlias);
150         subRun.setDrawAsDistanceFields();
151         subRun.setHasWCoord(hasWCoord);
152     }
153 
setRunPaintFlags(int runIndex,uint16_t paintFlags)154     void setRunPaintFlags(int runIndex, uint16_t paintFlags) {
155         fRuns[runIndex].fPaintFlags = paintFlags & Run::kPaintFlagsMask;
156     }
157 
setMinAndMaxScale(SkScalar scaledMax,SkScalar scaledMin)158     void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
159         // we init fMaxMinScale and fMinMaxScale in the constructor
160         fMaxMinScale = SkMaxScalar(scaledMax, fMaxMinScale);
161         fMinMaxScale = SkMinScalar(scaledMin, fMinMaxScale);
162     }
163 
164     // inits the override descriptor on the current run.  All following subruns must use this
165     // descriptor
initOverride(int runIndex)166     void initOverride(int runIndex) {
167         Run& run = fRuns[runIndex];
168         // Push back a new subrun to fill and set the override descriptor
169         run.push_back();
170         run.fOverrideDescriptor.reset(new SkAutoDescriptor);
171     }
172 
173     SkGlyphCache* setupCache(int runIndex,
174                              const SkSurfaceProps& props,
175                              SkScalerContextFlags scalerContextFlags,
176                              const SkPaint& skPaint,
177                              const SkMatrix* viewMatrix);
178 
179     // Appends a glyph to the blob.  If the glyph is too large, the glyph will be appended
180     // as a path.
181     void appendGlyph(int runIndex,
182                      const SkRect& positions,
183                      GrColor color,
184                      sk_sp<GrTextStrike> strike,
185                      GrGlyph* glyph,
186                      SkGlyphCache*, const SkGlyph& skGlyph,
187                      SkScalar x, SkScalar y, SkScalar scale, bool preTransformed);
188 
189     // Appends a glyph to the blob as a path only.
190     void appendPathGlyph(int runIndex, const SkPath& path,
191                          SkScalar x, SkScalar y, SkScalar scale, bool preTransformed);
192 
GetVertexStride(GrMaskFormat maskFormat,bool isDistanceFieldWithWCoord)193     static size_t GetVertexStride(GrMaskFormat maskFormat, bool isDistanceFieldWithWCoord) {
194         switch (maskFormat) {
195             case kA8_GrMaskFormat:
196                 return isDistanceFieldWithWCoord ? kGrayTextDFPerspectiveVASize : kGrayTextVASize;
197             case kARGB_GrMaskFormat:
198                 SkASSERT(!isDistanceFieldWithWCoord);
199                 return kColorTextVASize;
200             default:
201                 SkASSERT(!isDistanceFieldWithWCoord);
202                 return kLCDTextVASize;
203         }
204     }
205 
206     bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec,
207                         const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
208 
209     void flush(GrRestrictedAtlasManager*, GrTextUtils::Target*, const SkSurfaceProps& props,
210                const GrDistanceFieldAdjustTable* distanceAdjustTable,
211                const GrTextUtils::Paint& paint, const GrClip& clip,
212                const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
213                SkScalar y);
214 
computeSubRunBounds(SkRect * outBounds,int runIndex,int subRunIndex,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)215     void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex,
216                              const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
217         // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
218         // into device space.
219         // We handle vertex bounds differently for distance field text and bitmap text because
220         // the vertex bounds of bitmap text are in device space.  If we are flushing multiple runs
221         // from one blob then we are going to pay the price here of mapping the rect for each run.
222         const Run& run = fRuns[runIndex];
223         const Run::SubRunInfo& subRun = run.fSubRunInfo[subRunIndex];
224         *outBounds = subRun.vertexBounds();
225         if (subRun.drawAsDistanceFields()) {
226             // Distance field text is positioned with the (X,Y) as part of the glyph position,
227             // and currently the view matrix is applied on the GPU
228             outBounds->offset(x - fInitialX, y - fInitialY);
229             viewMatrix.mapRect(outBounds);
230         } else {
231             // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
232             // device space.
233             SkMatrix boundsMatrix = fInitialViewMatrixInverse;
234 
235             boundsMatrix.postTranslate(-fInitialX, -fInitialY);
236 
237             boundsMatrix.postTranslate(x, y);
238 
239             boundsMatrix.postConcat(viewMatrix);
240             boundsMatrix.mapRect(outBounds);
241 
242             // Due to floating point numerical inaccuracies, we have to round out here
243             outBounds->roundOut(outBounds);
244         }
245     }
246 
247     // position + local coord
248     static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
249     static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);
250     static const size_t kGrayTextDFPerspectiveVASize =
251             sizeof(SkPoint3) + sizeof(GrColor) + sizeof(SkIPoint16);
252     static const size_t kLCDTextVASize = kGrayTextVASize;
253     static const size_t kMaxVASize = kGrayTextDFPerspectiveVASize;
254     static const int kVerticesPerGlyph = 4;
255 
256     static void AssertEqual(const GrAtlasTextBlob&, const GrAtlasTextBlob&);
257 
258     // The color here is the GrPaint color, and it is used to determine whether we
259     // have to regenerate LCD text blobs.
260     // We use this color vs the SkPaint color because it has the colorfilter applied.
initReusableBlob(SkColor luminanceColor,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)261     void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix,
262                           SkScalar x, SkScalar y) {
263         fLuminanceColor = luminanceColor;
264         this->setupViewMatrix(viewMatrix, x, y);
265     }
266 
initThrowawayBlob(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)267     void initThrowawayBlob(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
268         this->setupViewMatrix(viewMatrix, x, y);
269     }
270 
key()271     const Key& key() const { return fKey; }
272 
~GrAtlasTextBlob()273     ~GrAtlasTextBlob() {
274         for (int i = 0; i < fRunCount; i++) {
275             fRuns[i].~Run();
276         }
277     }
278 
279     ////////////////////////////////////////////////////////////////////////////////////////////////
280     // Internal test methods
281     std::unique_ptr<GrDrawOp> test_makeOp(int glyphCount, uint16_t run, uint16_t subRun,
282                                           const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
283                                           const GrTextUtils::Paint&, const SkSurfaceProps&,
284                                           const GrDistanceFieldAdjustTable*,
285                                           GrRestrictedAtlasManager*, GrTextUtils::Target*);
286 
287 private:
GrAtlasTextBlob()288     GrAtlasTextBlob()
289         : fMaxMinScale(-SK_ScalarMax)
290         , fMinMaxScale(SK_ScalarMax)
291         , fTextType(0) {}
292 
293 
294     // This function will only be called when we are generating a blob from scratch. We record the
295     // initial view matrix and initial offsets(x,y), because we record vertex bounds relative to
296     // these numbers.  When blobs are reused with new matrices, we need to return to model space so
297     // we can update the vertex bounds appropriately.
setupViewMatrix(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)298     void setupViewMatrix(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
299         fInitialViewMatrix = viewMatrix;
300         if (!viewMatrix.invert(&fInitialViewMatrixInverse)) {
301             fInitialViewMatrixInverse = SkMatrix::I();
302             SkDebugf("Could not invert viewmatrix\n");
303         }
304         fInitialX = x;
305         fInitialY = y;
306 
307         // make sure all initial subruns have the correct VM and X/Y applied
308         for (int i = 0; i < fRunCount; i++) {
309             fRuns[i].fSubRunInfo[0].init(fInitialViewMatrix, x, y);
310         }
311     }
312 
313     /*
314      * Each Run inside of the blob can have its texture coordinates regenerated if required.
315      * To determine if regeneration is necessary, fAtlasGeneration is used.  If there have been
316      * any evictions inside of the atlas, then we will simply regenerate Runs.  We could track
317      * this at a more fine grained level, but its not clear if this is worth it, as evictions
318      * should be fairly rare.
319      *
320      * One additional point, each run can contain glyphs with any of the three mask formats.
321      * We call these SubRuns.  Because a subrun must be a contiguous range, we have to create
322      * a new subrun each time the mask format changes in a run.  In theory, a run can have as
323      * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8.  In
324      * practice, the vast majority of runs have only a single subrun.
325      *
326      * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
327      * handle, we have a bit to mark the run as flushable via rendering as paths or as scaled
328      * glyphs. It would be a bit expensive to figure out ahead of time whether or not a run
329      * can flush in this manner, so we always allocate vertices for the run, regardless of
330      * whether or not it is too large.  The benefit of this strategy is that we can always reuse
331      * a blob allocation regardless of viewmatrix changes.  We could store positions for these
332      * glyphs, however, it's not clear if this is a win because we'd still have to either go to the
333      * glyph cache to get the path at flush time, or hold onto the path in the cache, which
334      * would greatly increase the memory of these cached items.
335      */
336     struct Run {
RunRun337         Run() : fPaintFlags(0)
338               , fInitialized(false) {
339             // To ensure we always have one subrun, we push back a fresh run here
340             fSubRunInfo.push_back();
341         }
342         struct SubRunInfo {
SubRunInfoRun::SubRunInfo343             SubRunInfo()
344                     : fAtlasGeneration(GrDrawOpAtlas::kInvalidAtlasGeneration)
345                     , fVertexStartIndex(0)
346                     , fVertexEndIndex(0)
347                     , fGlyphStartIndex(0)
348                     , fGlyphEndIndex(0)
349                     , fColor(GrColor_ILLEGAL)
350                     , fMaskFormat(kA8_GrMaskFormat)
351                     , fFlags(0) {
352                 fVertexBounds = SkRectPriv::MakeLargestInverted();
353             }
SubRunInfoRun::SubRunInfo354             SubRunInfo(const SubRunInfo& that)
355                 : fBulkUseToken(that.fBulkUseToken)
356                 , fStrike(SkSafeRef(that.fStrike.get()))
357                 , fCurrentViewMatrix(that.fCurrentViewMatrix)
358                 , fVertexBounds(that.fVertexBounds)
359                 , fAtlasGeneration(that.fAtlasGeneration)
360                 , fVertexStartIndex(that.fVertexStartIndex)
361                 , fVertexEndIndex(that.fVertexEndIndex)
362                 , fGlyphStartIndex(that.fGlyphStartIndex)
363                 , fGlyphEndIndex(that.fGlyphEndIndex)
364                 , fX(that.fX)
365                 , fY(that.fY)
366                 , fColor(that.fColor)
367                 , fMaskFormat(that.fMaskFormat)
368                 , fFlags(that.fFlags) {
369             }
370 
371             // TODO when this object is more internal, drop the privacy
resetBulkUseTokenRun::SubRunInfo372             void resetBulkUseToken() { fBulkUseToken.reset(); }
bulkUseTokenRun::SubRunInfo373             GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
setStrikeRun::SubRunInfo374             void setStrike(sk_sp<GrTextStrike> strike) { fStrike = std::move(strike); }
strikeRun::SubRunInfo375             GrTextStrike* strike() const { return fStrike.get(); }
refStrikeRun::SubRunInfo376             sk_sp<GrTextStrike> refStrike() const { return fStrike; }
377 
setAtlasGenerationRun::SubRunInfo378             void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
atlasGenerationRun::SubRunInfo379             uint64_t atlasGeneration() const { return fAtlasGeneration; }
380 
byteCountRun::SubRunInfo381             size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
vertexStartIndexRun::SubRunInfo382             size_t vertexStartIndex() const { return fVertexStartIndex; }
vertexEndIndexRun::SubRunInfo383             size_t vertexEndIndex() const { return fVertexEndIndex; }
appendVerticesRun::SubRunInfo384             void appendVertices(size_t vertexStride) {
385                 fVertexEndIndex += vertexStride * kVerticesPerGlyph;
386             }
387 
glyphCountRun::SubRunInfo388             uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
glyphStartIndexRun::SubRunInfo389             uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
glyphEndIndexRun::SubRunInfo390             uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
glyphAppendedRun::SubRunInfo391             void glyphAppended() { fGlyphEndIndex++; }
setColorRun::SubRunInfo392             void setColor(GrColor color) { fColor = color; }
colorRun::SubRunInfo393             GrColor color() const { return fColor; }
setMaskFormatRun::SubRunInfo394             void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
maskFormatRun::SubRunInfo395             GrMaskFormat maskFormat() const { return fMaskFormat; }
396 
setAsSuccessorRun::SubRunInfo397             void setAsSuccessor(const SubRunInfo& prev) {
398                 fGlyphStartIndex = prev.glyphEndIndex();
399                 fGlyphEndIndex = prev.glyphEndIndex();
400 
401                 fVertexStartIndex = prev.vertexEndIndex();
402                 fVertexEndIndex = prev.vertexEndIndex();
403 
404                 // copy over viewmatrix settings
405                 this->init(prev.fCurrentViewMatrix, prev.fX, prev.fY);
406             }
407 
vertexBoundsRun::SubRunInfo408             const SkRect& vertexBounds() const { return fVertexBounds; }
joinGlyphBoundsRun::SubRunInfo409             void joinGlyphBounds(const SkRect& glyphBounds) {
410                 fVertexBounds.joinNonEmptyArg(glyphBounds);
411             }
412 
initRun::SubRunInfo413             void init(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
414                 fCurrentViewMatrix = viewMatrix;
415                 fX = x;
416                 fY = y;
417             }
418 
419             // This function assumes the translation will be applied before it is called again
420             void computeTranslation(const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
421                                     SkScalar* transX, SkScalar* transY);
422 
423             // df properties
setDrawAsDistanceFieldsRun::SubRunInfo424             void setDrawAsDistanceFields() { fFlags |= kDrawAsSDF_Flag; }
drawAsDistanceFieldsRun::SubRunInfo425             bool drawAsDistanceFields() const { return SkToBool(fFlags & kDrawAsSDF_Flag); }
setUseLCDTextRun::SubRunInfo426             void setUseLCDText(bool useLCDText) {
427                 fFlags = useLCDText ? fFlags | kUseLCDText_Flag : fFlags & ~kUseLCDText_Flag;
428             }
hasUseLCDTextRun::SubRunInfo429             bool hasUseLCDText() const { return SkToBool(fFlags & kUseLCDText_Flag); }
setAntiAliasedRun::SubRunInfo430             void setAntiAliased(bool antiAliased) {
431                 fFlags = antiAliased ? fFlags | kAntiAliased_Flag : fFlags & ~kAntiAliased_Flag;
432             }
isAntiAliasedRun::SubRunInfo433             bool isAntiAliased() const { return SkToBool(fFlags & kAntiAliased_Flag); }
setHasWCoordRun::SubRunInfo434             void setHasWCoord(bool hasW) {
435                 fFlags  = hasW ? (fFlags | kHasWCoord_Flag) : fFlags & ~kHasWCoord_Flag;
436             }
hasWCoordRun::SubRunInfo437             bool hasWCoord() const { return SkToBool(fFlags & kHasWCoord_Flag); }
438 
439         private:
440             enum Flag {
441                 kDrawAsSDF_Flag = 0x1,
442                 kUseLCDText_Flag = 0x2,
443                 kAntiAliased_Flag = 0x4,
444                 kHasWCoord_Flag = 0x8
445             };
446 
447             GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
448             sk_sp<GrTextStrike> fStrike;
449             SkMatrix fCurrentViewMatrix;
450             SkRect fVertexBounds;
451             uint64_t fAtlasGeneration;
452             size_t fVertexStartIndex;
453             size_t fVertexEndIndex;
454             uint32_t fGlyphStartIndex;
455             uint32_t fGlyphEndIndex;
456             SkScalar fX;
457             SkScalar fY;
458             GrColor fColor;
459             GrMaskFormat fMaskFormat;
460             uint32_t fFlags;
461         };  // SubRunInfo
462 
push_backRun463         SubRunInfo& push_back() {
464             // Forward glyph / vertex information to seed the new sub run
465             SubRunInfo& newSubRun = fSubRunInfo.push_back();
466             const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1);
467 
468             newSubRun.setAsSuccessor(prevSubRun);
469             return newSubRun;
470         }
471         static const int kMinSubRuns = 1;
472         sk_sp<SkTypeface> fTypeface;
473         SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo;
474         SkAutoDescriptor fDescriptor;
475 
476         // Effects from the paint that are used to build a SkScalerContext.
477         sk_sp<SkPathEffect> fPathEffect;
478         sk_sp<SkMaskFilter> fMaskFilter;
479 
480         // Distance field text cannot draw coloremoji, and so has to fall back.  However,
481         // though the distance field text and the coloremoji may share the same run, they
482         // will have different descriptors.  If fOverrideDescriptor is non-nullptr, then it
483         // will be used in place of the run's descriptor to regen texture coords
484         std::unique_ptr<SkAutoDescriptor> fOverrideDescriptor; // df properties
485 
486         // Any glyphs that can't be rendered with the base or override descriptor
487         // are rendered as paths
488         struct PathGlyph {
PathGlyphRun::PathGlyph489             PathGlyph(const SkPath& path, SkScalar x, SkScalar y, SkScalar scale, bool preXformed)
490                 : fPath(path)
491                 , fX(x)
492                 , fY(y)
493                 , fScale(scale)
494                 , fPreTransformed(preXformed) {}
495             SkPath fPath;
496             SkScalar fX;
497             SkScalar fY;
498             SkScalar fScale;
499             bool fPreTransformed;
500         };
501 
502         SkTArray<PathGlyph> fPathGlyphs;
503 
504         struct {
505             unsigned fPaintFlags : 16;   // needed mainly for rendering paths
506             bool fInitialized : 1;
507         };
508         // the only flags we need to set
509         static constexpr auto kPaintFlagsMask = SkPaint::kAntiAlias_Flag;
510     };  // Run
511 
512     inline std::unique_ptr<GrAtlasTextOp> makeOp(
513             const Run::SubRunInfo& info, int glyphCount, uint16_t run, uint16_t subRun,
514             const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
515             const GrTextUtils::Paint&, const SkSurfaceProps&,
516             const GrDistanceFieldAdjustTable*, GrRestrictedAtlasManager* , GrTextUtils::Target*);
517 
518     struct StrokeInfo {
519         SkScalar fFrameWidth;
520         SkScalar fMiterLimit;
521         SkPaint::Join fJoin;
522     };
523 
524     enum TextType {
525         kHasDistanceField_TextType = 0x1,
526         kHasBitmap_TextType = 0x2,
527     };
528 
529     // all glyph / vertex offsets are into these pools.
530     char* fVertices;
531     GrGlyph** fGlyphs;
532     Run* fRuns;
533     GrMemoryPool* fPool;   // this will be null when DDLs are being recorded
534     SkMaskFilterBase::BlurRec fBlurRec;
535     StrokeInfo fStrokeInfo;
536     Key fKey;
537     SkMatrix fInitialViewMatrix;
538     SkMatrix fInitialViewMatrixInverse;
539     size_t fSize;
540     SkColor fLuminanceColor;
541     SkScalar fInitialX;
542     SkScalar fInitialY;
543 
544     // We can reuse distance field text, but only if the new viewmatrix would not result in
545     // a mip change.  Because there can be multiple runs in a blob, we track the overall
546     // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
547     SkScalar fMaxMinScale;
548     SkScalar fMinMaxScale;
549     int fRunCount;
550     uint8_t fTextType;
551 };
552 
553 /**
554  * Used to produce vertices for a subrun of a blob. The vertices are cached in the blob itself.
555  * This is invoked each time a sub run is drawn. It regenerates the vertex data as required either
556  * because of changes to the atlas or because of different draw parameters (e.g. color change). In
557  * rare cases the draw may have to interrupted and flushed in the middle of the sub run in order to
558  * free up atlas space. Thus, this generator is stateful and should be invoked in a loop until the
559  * entire sub run has been completed.
560  */
561 class GrAtlasTextBlob::VertexRegenerator {
562 public:
563     /**
564      * Consecutive VertexRegenerators often use the same SkGlyphCache. If the same instance of
565      * SkAutoGlyphCache is reused then it can save the cost of multiple detach/attach operations of
566      * SkGlyphCache.
567      */
568     VertexRegenerator(GrResourceProvider*, GrAtlasTextBlob*, int runIdx, int subRunIdx,
569                       const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
570                       GrDeferredUploadTarget*, GrGlyphCache*, GrAtlasManager*,
571                       SkAutoGlyphCache*);
572 
573     struct Result {
574         /**
575          * Was regenerate() able to draw all the glyphs from the sub run? If not flush all glyph
576          * draws and call regenerate() again.
577          */
578         bool fFinished = true;
579 
580         /**
581          * How many glyphs were regenerated. Will be equal to the sub run's glyph count if
582          * fType is kFinished.
583          */
584         int fGlyphsRegenerated = 0;
585 
586         /**
587          * Pointer where the caller finds the first regenerated vertex.
588          */
589         const char* fFirstVertex;
590     };
591 
592     Result regenerate();
593 
594 private:
595     template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
596     Result doRegen();
597 
598     GrResourceProvider* fResourceProvider;
599     const SkMatrix& fViewMatrix;
600     GrAtlasTextBlob* fBlob;
601     GrDeferredUploadTarget* fUploadTarget;
602     GrGlyphCache* fGlyphCache;
603     GrAtlasManager* fFullAtlasManager;
604     SkAutoGlyphCache* fLazyCache;
605     Run* fRun;
606     Run::SubRunInfo* fSubRun;
607     GrColor fColor;
608     SkScalar fTransX;
609     SkScalar fTransY;
610 
611     uint32_t fRegenFlags = 0;
612     int fCurrGlyph = 0;
613     bool fBrokenRun = false;
614 };
615 
616 #endif
617