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 "GrAtlasGlyphCache.h"
12 #include "GrColor.h"
13 #include "GrDrawOpAtlas.h"
14 #include "GrMemoryPool.h"
15 #include "GrTextUtils.h"
16 #include "SkDescriptor.h"
17 #include "SkMaskFilter.h"
18 #include "SkOpts.h"
19 #include "SkPathEffect.h"
20 #include "SkRasterizer.h"
21 #include "SkSurfaceProps.h"
22 #include "SkTInternalLList.h"
23 
24 class GrBlobRegenHelper;
25 struct GrDistanceFieldAdjustTable;
26 class GrMemoryPool;
27 class GrMeshDrawOp;
28 class SkDrawFilter;
29 class SkTextBlob;
30 class SkTextBlobRunIterator;
31 
32 // With this flag enabled, the GrAtlasTextContext will, as a sanity check, regenerate every blob
33 // that comes in to verify the integrity of its cache
34 #define CACHE_SANITY_CHECK 0
35 
36 /*
37  * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
38  * on the GPU.  These are initially created with valid positions and colors, but invalid
39  * texture coordinates.  The GrAtlasTextBlob itself has a few Blob-wide properties, and also
40  * consists of a number of runs.  Runs inside a blob are flushed individually so they can be
41  * reordered.
42  *
43  * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that
44  * the GrAtlas will not evict anything the Blob needs.
45  *
46  * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
47  *
48  * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual
49  */
50 class GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> {
51 public:
52     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob);
53 
54     static sk_sp<GrAtlasTextBlob> Make(GrMemoryPool* pool, int glyphCount, int runCount);
55 
56     struct Key {
KeyKey57         Key() {
58             sk_bzero(this, sizeof(Key));
59         }
60         uint32_t fUniqueID;
61         // Color may affect the gamma of the mask we generate, but in a fairly limited way.
62         // Each color is assigned to on of a fixed number of buckets based on its
63         // luminance. For each luminance bucket there is a "canonical color" that
64         // represents the bucket.  This functionality is currently only supported for A8
65         SkColor fCanonicalColor;
66         SkPaint::Style fStyle;
67         SkPixelGeometry fPixelGeometry;
68         bool fHasBlur;
69         uint32_t fScalerContextFlags;
70 
71         bool operator==(const Key& other) const {
72             return 0 == memcmp(this, &other, sizeof(Key));
73         }
74     };
75 
setupKey(const GrAtlasTextBlob::Key & key,const SkMaskFilter::BlurRec & blurRec,const SkPaint & paint)76     void setupKey(const GrAtlasTextBlob::Key& key,
77                   const SkMaskFilter::BlurRec& blurRec,
78                   const SkPaint& paint) {
79         fKey = key;
80         if (key.fHasBlur) {
81             fBlurRec = blurRec;
82         }
83         if (key.fStyle != SkPaint::kFill_Style) {
84             fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
85             fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
86             fStrokeInfo.fJoin = paint.getStrokeJoin();
87         }
88     }
89 
GetKey(const GrAtlasTextBlob & blob)90     static const Key& GetKey(const GrAtlasTextBlob& blob) {
91         return blob.fKey;
92     }
93 
Hash(const Key & key)94     static uint32_t Hash(const Key& key) {
95         return SkOpts::hash(&key, sizeof(Key));
96     }
97 
delete(void * p)98     void operator delete(void* p) {
99         GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p);
100         blob->fPool->release(p);
101     }
new(size_t)102     void* operator new(size_t) {
103         SkFAIL("All blobs are created by placement new.");
104         return sk_malloc_throw(0);
105     }
106 
new(size_t,void * p)107     void* operator new(size_t, void* p) { return p; }
delete(void * target,void * placement)108     void operator delete(void* target, void* placement) {
109         ::operator delete(target, placement);
110     }
111 
hasDistanceField()112     bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
hasBitmap()113     bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
setHasDistanceField()114     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
setHasBitmap()115     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
116 
runCount()117     int runCount() const { return fRunCount; }
118 
push_back_run(int currRun)119     void push_back_run(int currRun) {
120         SkASSERT(currRun < fRunCount);
121         if (currRun > 0) {
122             Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back();
123             Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back();
124             newRun.setAsSuccessor(lastRun);
125         }
126     }
127 
128     // sets the last subrun of runIndex to use distance field text
setSubRunHasDistanceFields(int runIndex,bool hasLCD)129     void setSubRunHasDistanceFields(int runIndex, bool hasLCD) {
130         Run& run = fRuns[runIndex];
131         Run::SubRunInfo& subRun = run.fSubRunInfo.back();
132         subRun.setUseLCDText(hasLCD);
133         subRun.setDrawAsDistanceFields();
134     }
135 
setRunDrawAsPaths(int runIndex)136     void setRunDrawAsPaths(int runIndex) {
137         fRuns[runIndex].fDrawAsPaths = true;
138     }
139 
setMinAndMaxScale(SkScalar scaledMax,SkScalar scaledMin)140     void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
141         // we init fMaxMinScale and fMinMaxScale in the constructor
142         fMaxMinScale = SkMaxScalar(scaledMax, fMaxMinScale);
143         fMinMaxScale = SkMinScalar(scaledMin, fMinMaxScale);
144     }
145 
146     // inits the override descriptor on the current run.  All following subruns must use this
147     // descriptor
initOverride(int runIndex)148     void initOverride(int runIndex) {
149         Run& run = fRuns[runIndex];
150         // Push back a new subrun to fill and set the override descriptor
151         run.push_back();
152         run.fOverrideDescriptor.reset(new SkAutoDescriptor);
153     }
154 
155     SkGlyphCache* setupCache(int runIndex,
156                              const SkSurfaceProps& props,
157                              uint32_t scalerContextFlags,
158                              const SkPaint& skPaint,
159                              const SkMatrix* viewMatrix);
160 
161     // Appends a glyph to the blob.  If the glyph is too large, the glyph will be appended
162     // as a path.
163     void appendGlyph(int runIndex,
164                      const SkRect& positions,
165                      GrColor color,
166                      GrAtlasTextStrike* strike,
167                      GrGlyph* glyph,
168                      SkGlyphCache*, const SkGlyph& skGlyph,
169                      SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP);
170 
GetVertexStride(GrMaskFormat maskFormat)171     static size_t GetVertexStride(GrMaskFormat maskFormat) {
172         switch (maskFormat) {
173             case kA8_GrMaskFormat:
174                 return kGrayTextVASize;
175             case kARGB_GrMaskFormat:
176                 return kColorTextVASize;
177             default:
178                 return kLCDTextVASize;
179         }
180     }
181 
182     bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilter::BlurRec& blurRec,
183                         const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
184 
185     // flush a GrAtlasTextBlob associated with a SkTextBlob
186     void flushCached(GrContext* context, GrRenderTargetContext* rtc, const SkTextBlob* blob,
187                      const SkSurfaceProps& props,
188                      const GrDistanceFieldAdjustTable* distanceAdjustTable,
189                      const GrTextUtils::Paint&, SkDrawFilter* drawFilter, const GrClip& clip,
190                      const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y);
191 
192     // flush a throwaway GrAtlasTextBlob *not* associated with an SkTextBlob
193     void flushThrowaway(GrContext* context, GrRenderTargetContext* rtc, const SkSurfaceProps& props,
194                         const GrDistanceFieldAdjustTable* distanceAdjustTable,
195                         const GrTextUtils::Paint& paint, const GrClip& clip,
196                         const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
197                         SkScalar y);
198 
computeSubRunBounds(SkRect * outBounds,int runIndex,int subRunIndex,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)199     void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex,
200                              const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
201         // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
202         // into device space.
203         // We handle vertex bounds differently for distance field text and bitmap text because
204         // the vertex bounds of bitmap text are in device space.  If we are flushing multiple runs
205         // from one blob then we are going to pay the price here of mapping the rect for each run.
206         const Run& run = fRuns[runIndex];
207         const Run::SubRunInfo& subRun = run.fSubRunInfo[subRunIndex];
208         *outBounds = subRun.vertexBounds();
209         if (subRun.drawAsDistanceFields()) {
210             // Distance field text is positioned with the (X,Y) as part of the glyph position,
211             // and currently the view matrix is applied on the GPU
212             outBounds->offset(x - fInitialX, y - fInitialY);
213             viewMatrix.mapRect(outBounds);
214         } else {
215             // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
216             // device space.
217             SkMatrix boundsMatrix = fInitialViewMatrixInverse;
218 
219             boundsMatrix.postTranslate(-fInitialX, -fInitialY);
220 
221             boundsMatrix.postTranslate(x, y);
222 
223             boundsMatrix.postConcat(viewMatrix);
224             boundsMatrix.mapRect(outBounds);
225 
226             // Due to floating point numerical inaccuracies, we have to round out here
227             outBounds->roundOut(outBounds);
228         }
229     }
230 
231     // position + local coord
232     static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
233     static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);
234     static const size_t kLCDTextVASize = kGrayTextVASize;
235     static const size_t kMaxVASize = kGrayTextVASize;
236     static const int kVerticesPerGlyph = 4;
237 
238     static void AssertEqual(const GrAtlasTextBlob&, const GrAtlasTextBlob&);
239 
240     // The color here is the GrPaint color, and it is used to determine whether we
241     // have to regenerate LCD text blobs.
242     // We use this color vs the SkPaint color because it has the colorfilter applied.
initReusableBlob(SkColor filteredColor,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)243     void initReusableBlob(SkColor filteredColor, const SkMatrix& viewMatrix, SkScalar x,
244                           SkScalar y) {
245         fFilteredPaintColor = filteredColor;
246         this->setupViewMatrix(viewMatrix, x, y);
247     }
248 
initThrowawayBlob(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)249     void initThrowawayBlob(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
250         this->setupViewMatrix(viewMatrix, x, y);
251     }
252 
253     /**
254      * Consecutive calls to regenInOp often use the same SkGlyphCache. If the same instance of
255      * SkAutoGlyphCache is passed to multiple calls of regenInOp then it can save the cost of
256      * multiple detach/attach operations of SkGlyphCache.
257      */
258     void regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fontCache,
259                    GrBlobRegenHelper* helper, int run, int subRun, SkAutoGlyphCache*,
260                    size_t vertexStride, const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
261                    GrColor color, void** vertices, size_t* byteCount, int* glyphCount);
262 
key()263     const Key& key() const { return fKey; }
264 
~GrAtlasTextBlob()265     ~GrAtlasTextBlob() {
266         for (int i = 0; i < fRunCount; i++) {
267             fRuns[i].~Run();
268         }
269     }
270 
271     ////////////////////////////////////////////////////////////////////////////////////////////////
272     // Internal test methods
273     std::unique_ptr<GrMeshDrawOp> test_makeOp(int glyphCount, int run, int subRun,
274                                               const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
275                                               const GrTextUtils::Paint& paint,
276                                               const SkSurfaceProps& props,
277                                               const GrDistanceFieldAdjustTable* distanceAdjustTable,
278                                               GrAtlasGlyphCache* cache);
279 
280 private:
GrAtlasTextBlob()281     GrAtlasTextBlob()
282         : fMaxMinScale(-SK_ScalarMax)
283         , fMinMaxScale(SK_ScalarMax)
284         , fTextType(0) {}
285 
286     void appendLargeGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph,
287                           SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP);
288 
289     inline void flushRun(GrRenderTargetContext* rtc, const GrClip&, int run,
290                          const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
291                          const GrTextUtils::Paint& paint, const SkSurfaceProps& props,
292                          const GrDistanceFieldAdjustTable* distanceAdjustTable,
293                          GrAtlasGlyphCache* cache);
294 
295     void flushBigGlyphs(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip,
296                         const SkPaint& paint, const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
297                         const SkIRect& clipBounds);
298 
299     void flushRunAsPaths(GrContext* context, GrRenderTargetContext* rtc,
300                          const SkSurfaceProps& props, const SkTextBlobRunIterator& it,
301                          const GrClip& clip, const GrTextUtils::Paint& paint,
302                          SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
303                          const SkIRect& clipBounds, SkScalar x, SkScalar y);
304 
305     // This function will only be called when we are generating a blob from scratch. We record the
306     // initial view matrix and initial offsets(x,y), because we record vertex bounds relative to
307     // these numbers.  When blobs are reused with new matrices, we need to return to model space so
308     // we can update the vertex bounds appropriately.
setupViewMatrix(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)309     void setupViewMatrix(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
310         fInitialViewMatrix = viewMatrix;
311         if (!viewMatrix.invert(&fInitialViewMatrixInverse)) {
312             fInitialViewMatrixInverse = SkMatrix::I();
313             SkDebugf("Could not invert viewmatrix\n");
314         }
315         fInitialX = x;
316         fInitialY = y;
317 
318         // make sure all initial subruns have the correct VM and X/Y applied
319         for (int i = 0; i < fRunCount; i++) {
320             fRuns[i].fSubRunInfo[0].init(fInitialViewMatrix, x, y);
321         }
322     }
323 
324     /*
325      * Each Run inside of the blob can have its texture coordinates regenerated if required.
326      * To determine if regeneration is necessary, fAtlasGeneration is used.  If there have been
327      * any evictions inside of the atlas, then we will simply regenerate Runs.  We could track
328      * this at a more fine grained level, but its not clear if this is worth it, as evictions
329      * should be fairly rare.
330      *
331      * One additional point, each run can contain glyphs with any of the three mask formats.
332      * We call these SubRuns.  Because a subrun must be a contiguous range, we have to create
333      * a new subrun each time the mask format changes in a run.  In theory, a run can have as
334      * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8.  In
335      * practice, the vast majority of runs have only a single subrun.
336      *
337      * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
338      * handle, we have a bit to mark the run as flusahable via rendering as paths.  It is worth
339      * pointing. It would be a bit expensive to figure out ahead of time whether or not a run
340      * can flush in this manner, so we always allocate vertices for the run, regardless of
341      * whether or not it is too large.  The benefit of this strategy is that we can always reuse
342      * a blob allocation regardless of viewmatrix changes.  We could store positions for these
343      * glyphs.  However, its not clear if this is a win because we'd still have to either go the
344      * glyph cache to get the path at flush time, or hold onto the path in the cache, which
345      * would greatly increase the memory of these cached items.
346      */
347     struct Run {
RunRun348         Run()
349             : fInitialized(false)
350             , fDrawAsPaths(false) {
351             // To ensure we always have one subrun, we push back a fresh run here
352             fSubRunInfo.push_back();
353         }
354         struct SubRunInfo {
SubRunInfoRun::SubRunInfo355             SubRunInfo()
356                     : fAtlasGeneration(GrDrawOpAtlas::kInvalidAtlasGeneration)
357                     , fVertexStartIndex(0)
358                     , fVertexEndIndex(0)
359                     , fGlyphStartIndex(0)
360                     , fGlyphEndIndex(0)
361                     , fColor(GrColor_ILLEGAL)
362                     , fMaskFormat(kA8_GrMaskFormat)
363                     , fDrawAsDistanceFields(false)
364                     , fUseLCDText(false) {
365                 fVertexBounds.setLargestInverted();
366             }
SubRunInfoRun::SubRunInfo367             SubRunInfo(const SubRunInfo& that)
368                 : fBulkUseToken(that.fBulkUseToken)
369                 , fStrike(SkSafeRef(that.fStrike.get()))
370                 , fCurrentViewMatrix(that.fCurrentViewMatrix)
371                 , fVertexBounds(that.fVertexBounds)
372                 , fAtlasGeneration(that.fAtlasGeneration)
373                 , fVertexStartIndex(that.fVertexStartIndex)
374                 , fVertexEndIndex(that.fVertexEndIndex)
375                 , fGlyphStartIndex(that.fGlyphStartIndex)
376                 , fGlyphEndIndex(that.fGlyphEndIndex)
377                 , fX(that.fX)
378                 , fY(that.fY)
379                 , fColor(that.fColor)
380                 , fMaskFormat(that.fMaskFormat)
381                 , fDrawAsDistanceFields(that.fDrawAsDistanceFields)
382                 , fUseLCDText(that.fUseLCDText) {
383             }
384 
385             // TODO when this object is more internal, drop the privacy
resetBulkUseTokenRun::SubRunInfo386             void resetBulkUseToken() { fBulkUseToken.reset(); }
bulkUseTokenRun::SubRunInfo387             GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
setStrikeRun::SubRunInfo388             void setStrike(GrAtlasTextStrike* strike) { fStrike.reset(SkRef(strike)); }
strikeRun::SubRunInfo389             GrAtlasTextStrike* strike() const { return fStrike.get(); }
390 
setAtlasGenerationRun::SubRunInfo391             void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
atlasGenerationRun::SubRunInfo392             uint64_t atlasGeneration() const { return fAtlasGeneration; }
393 
byteCountRun::SubRunInfo394             size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
vertexStartIndexRun::SubRunInfo395             size_t vertexStartIndex() const { return fVertexStartIndex; }
vertexEndIndexRun::SubRunInfo396             size_t vertexEndIndex() const { return fVertexEndIndex; }
appendVerticesRun::SubRunInfo397             void appendVertices(size_t vertexStride) {
398                 fVertexEndIndex += vertexStride * kVerticesPerGlyph;
399             }
400 
glyphCountRun::SubRunInfo401             uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
glyphStartIndexRun::SubRunInfo402             uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
glyphEndIndexRun::SubRunInfo403             uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
glyphAppendedRun::SubRunInfo404             void glyphAppended() { fGlyphEndIndex++; }
setColorRun::SubRunInfo405             void setColor(GrColor color) { fColor = color; }
colorRun::SubRunInfo406             GrColor color() const { return fColor; }
setMaskFormatRun::SubRunInfo407             void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
maskFormatRun::SubRunInfo408             GrMaskFormat maskFormat() const { return fMaskFormat; }
409 
setAsSuccessorRun::SubRunInfo410             void setAsSuccessor(const SubRunInfo& prev) {
411                 fGlyphStartIndex = prev.glyphEndIndex();
412                 fGlyphEndIndex = prev.glyphEndIndex();
413 
414                 fVertexStartIndex = prev.vertexEndIndex();
415                 fVertexEndIndex = prev.vertexEndIndex();
416 
417                 // copy over viewmatrix settings
418                 this->init(prev.fCurrentViewMatrix, prev.fX, prev.fY);
419             }
420 
vertexBoundsRun::SubRunInfo421             const SkRect& vertexBounds() const { return fVertexBounds; }
joinGlyphBoundsRun::SubRunInfo422             void joinGlyphBounds(const SkRect& glyphBounds) {
423                 fVertexBounds.joinNonEmptyArg(glyphBounds);
424             }
425 
initRun::SubRunInfo426             void init(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
427                 fCurrentViewMatrix = viewMatrix;
428                 fX = x;
429                 fY = y;
430             }
431 
432             // This function assumes the translation will be applied before it is called again
433             void computeTranslation(const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
434                                     SkScalar*transX, SkScalar* transY);
435 
436             // df properties
setUseLCDTextRun::SubRunInfo437             void setUseLCDText(bool useLCDText) { fUseLCDText = useLCDText; }
hasUseLCDTextRun::SubRunInfo438             bool hasUseLCDText() const { return fUseLCDText; }
setDrawAsDistanceFieldsRun::SubRunInfo439             void setDrawAsDistanceFields() { fDrawAsDistanceFields = true; }
drawAsDistanceFieldsRun::SubRunInfo440             bool drawAsDistanceFields() const { return fDrawAsDistanceFields; }
441 
442         private:
443             GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
444             sk_sp<GrAtlasTextStrike> fStrike;
445             SkMatrix fCurrentViewMatrix;
446             SkRect fVertexBounds;
447             uint64_t fAtlasGeneration;
448             size_t fVertexStartIndex;
449             size_t fVertexEndIndex;
450             uint32_t fGlyphStartIndex;
451             uint32_t fGlyphEndIndex;
452             SkScalar fX;
453             SkScalar fY;
454             GrColor fColor;
455             GrMaskFormat fMaskFormat;
456             bool fDrawAsDistanceFields; // df property
457             bool fUseLCDText; // df property
458         };
459 
push_backRun460         SubRunInfo& push_back() {
461             // Forward glyph / vertex information to seed the new sub run
462             SubRunInfo& newSubRun = fSubRunInfo.push_back();
463             const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1);
464 
465             newSubRun.setAsSuccessor(prevSubRun);
466             return newSubRun;
467         }
468         static const int kMinSubRuns = 1;
469         sk_sp<SkTypeface> fTypeface;
470         SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo;
471         SkAutoDescriptor fDescriptor;
472 
473         // Effects from the paint that are used to build a SkScalerContext.
474         sk_sp<SkPathEffect> fPathEffect;
475         sk_sp<SkRasterizer> fRasterizer;
476         sk_sp<SkMaskFilter> fMaskFilter;
477 
478         // Distance field text cannot draw coloremoji, and so has to fall back.  However,
479         // though the distance field text and the coloremoji may share the same run, they
480         // will have different descriptors.  If fOverrideDescriptor is non-nullptr, then it
481         // will be used in place of the run's descriptor to regen texture coords
482         std::unique_ptr<SkAutoDescriptor> fOverrideDescriptor; // df properties
483         bool fInitialized;
484         bool fDrawAsPaths;
485     };
486 
487     template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
488     void regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fontCache, GrBlobRegenHelper* helper,
489                    Run* run, Run::SubRunInfo* info, SkAutoGlyphCache*, int glyphCount,
490                    size_t vertexStride, GrColor color, SkScalar transX, SkScalar transY) const;
491 
492     inline std::unique_ptr<GrMeshDrawOp> makeOp(
493             const Run::SubRunInfo& info, int glyphCount, int run, int subRun,
494             const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const GrTextUtils::Paint& paint,
495             const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable,
496             bool useGammaCorrectDistanceTable, GrAtlasGlyphCache* cache);
497 
498     struct BigGlyph {
BigGlyphBigGlyph499         BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool treatAsBMP)
500             : fPath(path)
501             , fScale(scale)
502             , fX(vx)
503             , fY(vy)
504             , fTreatAsBMP(treatAsBMP) {}
505         SkPath fPath;
506         SkScalar fScale;
507         SkScalar fX;
508         SkScalar fY;
509         bool fTreatAsBMP;
510     };
511 
512     struct StrokeInfo {
513         SkScalar fFrameWidth;
514         SkScalar fMiterLimit;
515         SkPaint::Join fJoin;
516     };
517 
518     enum TextType {
519         kHasDistanceField_TextType = 0x1,
520         kHasBitmap_TextType = 0x2,
521     };
522 
523     // all glyph / vertex offsets are into these pools.
524     unsigned char* fVertices;
525     GrGlyph** fGlyphs;
526     Run* fRuns;
527     GrMemoryPool* fPool;
528     SkMaskFilter::BlurRec fBlurRec;
529     StrokeInfo fStrokeInfo;
530     SkTArray<BigGlyph> fBigGlyphs;
531     Key fKey;
532     SkMatrix fInitialViewMatrix;
533     SkMatrix fInitialViewMatrixInverse;
534     size_t fSize;
535     SkColor fFilteredPaintColor;
536     SkScalar fInitialX;
537     SkScalar fInitialY;
538 
539     // We can reuse distance field text, but only if the new viewmatrix would not result in
540     // a mip change.  Because there can be multiple runs in a blob, we track the overall
541     // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
542     SkScalar fMaxMinScale;
543     SkScalar fMinMaxScale;
544     int fRunCount;
545     uint8_t fTextType;
546 };
547 
548 #endif
549