• 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 "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 SkDrawFilter;
28 class SkTextBlob;
29 class SkTextBlobRunIterator;
30 
31 // With this flag enabled, the GrAtlasTextContext will, as a sanity check, regenerate every blob
32 // that comes in to verify the integrity of its cache
33 #define CACHE_SANITY_CHECK 0
34 
35 /*
36  * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
37  * on the GPU.  These are initially created with valid positions and colors, but invalid
38  * texture coordinates.  The GrAtlasTextBlob itself has a few Blob-wide properties, and also
39  * consists of a number of runs.  Runs inside a blob are flushed individually so they can be
40  * reordered.
41  *
42  * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that
43  * the GrAtlas will not evict anything the Blob needs.
44  *
45  * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
46  *
47  * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual
48  */
49 class GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> {
50 public:
51     SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob);
52 
53     static sk_sp<GrAtlasTextBlob> Make(GrMemoryPool* pool, int glyphCount, int runCount);
54 
55     struct Key {
KeyKey56         Key() {
57             sk_bzero(this, sizeof(Key));
58         }
59         uint32_t fUniqueID;
60         // Color may affect the gamma of the mask we generate, but in a fairly limited way.
61         // Each color is assigned to on of a fixed number of buckets based on its
62         // luminance. For each luminance bucket there is a "canonical color" that
63         // represents the bucket.  This functionality is currently only supported for A8
64         SkColor fCanonicalColor;
65         SkPaint::Style fStyle;
66         SkPixelGeometry fPixelGeometry;
67         bool fHasBlur;
68         uint32_t fScalerContextFlags;
69 
70         bool operator==(const Key& other) const {
71             return 0 == memcmp(this, &other, sizeof(Key));
72         }
73     };
74 
setupKey(const GrAtlasTextBlob::Key & key,const SkMaskFilter::BlurRec & blurRec,const SkPaint & paint)75     void setupKey(const GrAtlasTextBlob::Key& key,
76                   const SkMaskFilter::BlurRec& blurRec,
77                   const SkPaint& paint) {
78         fKey = key;
79         if (key.fHasBlur) {
80             fBlurRec = blurRec;
81         }
82         if (key.fStyle != SkPaint::kFill_Style) {
83             fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
84             fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
85             fStrokeInfo.fJoin = paint.getStrokeJoin();
86         }
87     }
88 
GetKey(const GrAtlasTextBlob & blob)89     static const Key& GetKey(const GrAtlasTextBlob& blob) {
90         return blob.fKey;
91     }
92 
Hash(const Key & key)93     static uint32_t Hash(const Key& key) {
94         return SkOpts::hash(&key, sizeof(Key));
95     }
96 
delete(void * p)97     void operator delete(void* p) {
98         GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p);
99         blob->fPool->release(p);
100     }
new(size_t)101     void* operator new(size_t) {
102         SkFAIL("All blobs are created by placement new.");
103         return sk_malloc_throw(0);
104     }
105 
new(size_t,void * p)106     void* operator new(size_t, void* p) { return p; }
delete(void * target,void * placement)107     void operator delete(void* target, void* placement) {
108         ::operator delete(target, placement);
109     }
110 
hasDistanceField()111     bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
hasBitmap()112     bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
setHasDistanceField()113     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
setHasBitmap()114     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
115 
runCount()116     int runCount() const { return fRunCount; }
117 
push_back_run(int currRun)118     void push_back_run(int currRun) {
119         SkASSERT(currRun < fRunCount);
120         if (currRun > 0) {
121             Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back();
122             Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back();
123             newRun.setAsSuccessor(lastRun);
124         }
125     }
126 
127     // sets the last subrun of runIndex to use distance field text
setSubRunHasDistanceFields(int runIndex,bool hasLCD,bool isAntiAlias)128     void setSubRunHasDistanceFields(int runIndex, bool hasLCD, bool isAntiAlias) {
129         Run& run = fRuns[runIndex];
130         Run::SubRunInfo& subRun = run.fSubRunInfo.back();
131         subRun.setUseLCDText(hasLCD);
132         subRun.setAntiAliased(isAntiAlias);
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 luminanceColor,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)243     void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix, SkScalar x,
244                           SkScalar y) {
245         fLuminanceColor = luminanceColor;
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<GrDrawOp> test_makeOp(int glyphCount, int run, int subRun,
274                                           const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
275                                           const GrTextUtils::Paint&, const SkSurfaceProps&,
276                                           const GrDistanceFieldAdjustTable*, GrAtlasGlyphCache*,
277                                           GrRenderTargetContext*);
278 
279 private:
GrAtlasTextBlob()280     GrAtlasTextBlob()
281         : fMaxMinScale(-SK_ScalarMax)
282         , fMinMaxScale(SK_ScalarMax)
283         , fTextType(0) {}
284 
285     void appendLargeGlyph(GrGlyph* glyph, SkGlyphCache* cache, const SkGlyph& skGlyph,
286                           SkScalar x, SkScalar y, SkScalar scale, bool treatAsBMP);
287 
288     inline void flushRun(GrRenderTargetContext* rtc, const GrClip&, int run,
289                          const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
290                          const GrTextUtils::Paint& paint, const SkSurfaceProps& props,
291                          const GrDistanceFieldAdjustTable* distanceAdjustTable,
292                          GrAtlasGlyphCache* cache);
293 
294     void flushBigGlyphs(GrContext* context, GrRenderTargetContext* rtc, const GrClip& clip,
295                         const SkPaint& paint, const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
296                         const SkIRect& clipBounds);
297 
298     void flushRunAsPaths(GrContext* context, GrRenderTargetContext* rtc,
299                          const SkSurfaceProps& props, const SkTextBlobRunIterator& it,
300                          const GrClip& clip, const GrTextUtils::Paint& paint,
301                          SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
302                          const SkIRect& clipBounds, SkScalar x, SkScalar y);
303 
304     // This function will only be called when we are generating a blob from scratch. We record the
305     // initial view matrix and initial offsets(x,y), because we record vertex bounds relative to
306     // these numbers.  When blobs are reused with new matrices, we need to return to model space so
307     // we can update the vertex bounds appropriately.
setupViewMatrix(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)308     void setupViewMatrix(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
309         fInitialViewMatrix = viewMatrix;
310         if (!viewMatrix.invert(&fInitialViewMatrixInverse)) {
311             fInitialViewMatrixInverse = SkMatrix::I();
312             SkDebugf("Could not invert viewmatrix\n");
313         }
314         fInitialX = x;
315         fInitialY = y;
316 
317         // make sure all initial subruns have the correct VM and X/Y applied
318         for (int i = 0; i < fRunCount; i++) {
319             fRuns[i].fSubRunInfo[0].init(fInitialViewMatrix, x, y);
320         }
321     }
322 
323     /*
324      * Each Run inside of the blob can have its texture coordinates regenerated if required.
325      * To determine if regeneration is necessary, fAtlasGeneration is used.  If there have been
326      * any evictions inside of the atlas, then we will simply regenerate Runs.  We could track
327      * this at a more fine grained level, but its not clear if this is worth it, as evictions
328      * should be fairly rare.
329      *
330      * One additional point, each run can contain glyphs with any of the three mask formats.
331      * We call these SubRuns.  Because a subrun must be a contiguous range, we have to create
332      * a new subrun each time the mask format changes in a run.  In theory, a run can have as
333      * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8.  In
334      * practice, the vast majority of runs have only a single subrun.
335      *
336      * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
337      * handle, we have a bit to mark the run as flusahable via rendering as paths.  It is worth
338      * pointing. It would be a bit expensive to figure out ahead of time whether or not a run
339      * can flush in this manner, so we always allocate vertices for the run, regardless of
340      * whether or not it is too large.  The benefit of this strategy is that we can always reuse
341      * a blob allocation regardless of viewmatrix changes.  We could store positions for these
342      * glyphs.  However, its not clear if this is a win because we'd still have to either go the
343      * glyph cache to get the path at flush time, or hold onto the path in the cache, which
344      * would greatly increase the memory of these cached items.
345      */
346     struct Run {
RunRun347         Run()
348             : fInitialized(false)
349             , fDrawAsPaths(false) {
350             // To ensure we always have one subrun, we push back a fresh run here
351             fSubRunInfo.push_back();
352         }
353         struct SubRunInfo {
SubRunInfoRun::SubRunInfo354             SubRunInfo()
355                     : fAtlasGeneration(GrDrawOpAtlas::kInvalidAtlasGeneration)
356                     , fVertexStartIndex(0)
357                     , fVertexEndIndex(0)
358                     , fGlyphStartIndex(0)
359                     , fGlyphEndIndex(0)
360                     , fColor(GrColor_ILLEGAL)
361                     , fMaskFormat(kA8_GrMaskFormat)
362                     , fFlags(0) {
363                 fVertexBounds.setLargestInverted();
364             }
SubRunInfoRun::SubRunInfo365             SubRunInfo(const SubRunInfo& that)
366                 : fBulkUseToken(that.fBulkUseToken)
367                 , fStrike(SkSafeRef(that.fStrike.get()))
368                 , fCurrentViewMatrix(that.fCurrentViewMatrix)
369                 , fVertexBounds(that.fVertexBounds)
370                 , fAtlasGeneration(that.fAtlasGeneration)
371                 , fVertexStartIndex(that.fVertexStartIndex)
372                 , fVertexEndIndex(that.fVertexEndIndex)
373                 , fGlyphStartIndex(that.fGlyphStartIndex)
374                 , fGlyphEndIndex(that.fGlyphEndIndex)
375                 , fX(that.fX)
376                 , fY(that.fY)
377                 , fColor(that.fColor)
378                 , fMaskFormat(that.fMaskFormat)
379                 , fFlags(that.fFlags) {
380             }
381 
382             // TODO when this object is more internal, drop the privacy
resetBulkUseTokenRun::SubRunInfo383             void resetBulkUseToken() { fBulkUseToken.reset(); }
bulkUseTokenRun::SubRunInfo384             GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
setStrikeRun::SubRunInfo385             void setStrike(GrAtlasTextStrike* strike) { fStrike.reset(SkRef(strike)); }
strikeRun::SubRunInfo386             GrAtlasTextStrike* strike() const { return fStrike.get(); }
387 
setAtlasGenerationRun::SubRunInfo388             void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
atlasGenerationRun::SubRunInfo389             uint64_t atlasGeneration() const { return fAtlasGeneration; }
390 
byteCountRun::SubRunInfo391             size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
vertexStartIndexRun::SubRunInfo392             size_t vertexStartIndex() const { return fVertexStartIndex; }
vertexEndIndexRun::SubRunInfo393             size_t vertexEndIndex() const { return fVertexEndIndex; }
appendVerticesRun::SubRunInfo394             void appendVertices(size_t vertexStride) {
395                 fVertexEndIndex += vertexStride * kVerticesPerGlyph;
396             }
397 
glyphCountRun::SubRunInfo398             uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
glyphStartIndexRun::SubRunInfo399             uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
glyphEndIndexRun::SubRunInfo400             uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
glyphAppendedRun::SubRunInfo401             void glyphAppended() { fGlyphEndIndex++; }
setColorRun::SubRunInfo402             void setColor(GrColor color) { fColor = color; }
colorRun::SubRunInfo403             GrColor color() const { return fColor; }
setMaskFormatRun::SubRunInfo404             void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
maskFormatRun::SubRunInfo405             GrMaskFormat maskFormat() const { return fMaskFormat; }
406 
setAsSuccessorRun::SubRunInfo407             void setAsSuccessor(const SubRunInfo& prev) {
408                 fGlyphStartIndex = prev.glyphEndIndex();
409                 fGlyphEndIndex = prev.glyphEndIndex();
410 
411                 fVertexStartIndex = prev.vertexEndIndex();
412                 fVertexEndIndex = prev.vertexEndIndex();
413 
414                 // copy over viewmatrix settings
415                 this->init(prev.fCurrentViewMatrix, prev.fX, prev.fY);
416             }
417 
vertexBoundsRun::SubRunInfo418             const SkRect& vertexBounds() const { return fVertexBounds; }
joinGlyphBoundsRun::SubRunInfo419             void joinGlyphBounds(const SkRect& glyphBounds) {
420                 fVertexBounds.joinNonEmptyArg(glyphBounds);
421             }
422 
initRun::SubRunInfo423             void init(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
424                 fCurrentViewMatrix = viewMatrix;
425                 fX = x;
426                 fY = y;
427             }
428 
429             // This function assumes the translation will be applied before it is called again
430             void computeTranslation(const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
431                                     SkScalar*transX, SkScalar* transY);
432 
433             // df properties
setDrawAsDistanceFieldsRun::SubRunInfo434             void setDrawAsDistanceFields() { fFlags |= kDrawAsSDF_Flag; }
drawAsDistanceFieldsRun::SubRunInfo435             bool drawAsDistanceFields() const { return SkToBool(fFlags & kDrawAsSDF_Flag); }
setUseLCDTextRun::SubRunInfo436             void setUseLCDText(bool useLCDText) {
437                 fFlags = useLCDText ? fFlags | kUseLCDText_Flag : fFlags & ~kUseLCDText_Flag;
438             }
hasUseLCDTextRun::SubRunInfo439             bool hasUseLCDText() const { return SkToBool(fFlags & kUseLCDText_Flag); }
setAntiAliasedRun::SubRunInfo440             void setAntiAliased(bool antiAliased) {
441                 fFlags = antiAliased ? fFlags | kAntiAliased_Flag : fFlags & ~kAntiAliased_Flag;
442             }
isAntiAliasedRun::SubRunInfo443             bool isAntiAliased() const { return SkToBool(fFlags & kAntiAliased_Flag); }
444 
445         private:
446             enum Flag {
447                 kDrawAsSDF_Flag = 0x1,
448                 kUseLCDText_Flag = 0x2,
449                 kAntiAliased_Flag = 0x4
450             };
451 
452             GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
453             sk_sp<GrAtlasTextStrike> fStrike;
454             SkMatrix fCurrentViewMatrix;
455             SkRect fVertexBounds;
456             uint64_t fAtlasGeneration;
457             size_t fVertexStartIndex;
458             size_t fVertexEndIndex;
459             uint32_t fGlyphStartIndex;
460             uint32_t fGlyphEndIndex;
461             SkScalar fX;
462             SkScalar fY;
463             GrColor fColor;
464             GrMaskFormat fMaskFormat;
465             uint32_t fFlags;
466         };
467 
push_backRun468         SubRunInfo& push_back() {
469             // Forward glyph / vertex information to seed the new sub run
470             SubRunInfo& newSubRun = fSubRunInfo.push_back();
471             const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1);
472 
473             newSubRun.setAsSuccessor(prevSubRun);
474             return newSubRun;
475         }
476         static const int kMinSubRuns = 1;
477         sk_sp<SkTypeface> fTypeface;
478         SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo;
479         SkAutoDescriptor fDescriptor;
480 
481         // Effects from the paint that are used to build a SkScalerContext.
482         sk_sp<SkPathEffect> fPathEffect;
483         sk_sp<SkRasterizer> fRasterizer;
484         sk_sp<SkMaskFilter> fMaskFilter;
485 
486         // Distance field text cannot draw coloremoji, and so has to fall back.  However,
487         // though the distance field text and the coloremoji may share the same run, they
488         // will have different descriptors.  If fOverrideDescriptor is non-nullptr, then it
489         // will be used in place of the run's descriptor to regen texture coords
490         std::unique_ptr<SkAutoDescriptor> fOverrideDescriptor; // df properties
491         bool fInitialized;
492         bool fDrawAsPaths;
493     };
494 
495     template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
496     void regenInOp(GrDrawOp::Target* target, GrAtlasGlyphCache* fontCache, GrBlobRegenHelper* helper,
497                    Run* run, Run::SubRunInfo* info, SkAutoGlyphCache*, int glyphCount,
498                    size_t vertexStride, GrColor color, SkScalar transX, SkScalar transY) const;
499 
500     inline std::unique_ptr<GrDrawOp> makeOp(const Run::SubRunInfo& info, int glyphCount, int run,
501                                             int subRun, const SkMatrix& viewMatrix, SkScalar x,
502                                             SkScalar y, const GrTextUtils::Paint& paint,
503                                             const SkSurfaceProps& props,
504                                             const GrDistanceFieldAdjustTable* distanceAdjustTable,
505                                             GrAtlasGlyphCache* cache, GrRenderTargetContext*);
506 
507     struct BigGlyph {
BigGlyphBigGlyph508         BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool treatAsBMP)
509             : fPath(path)
510             , fScale(scale)
511             , fX(vx)
512             , fY(vy)
513             , fTreatAsBMP(treatAsBMP) {}
514         SkPath fPath;
515         SkScalar fScale;
516         SkScalar fX;
517         SkScalar fY;
518         bool fTreatAsBMP;
519     };
520 
521     struct StrokeInfo {
522         SkScalar fFrameWidth;
523         SkScalar fMiterLimit;
524         SkPaint::Join fJoin;
525     };
526 
527     enum TextType {
528         kHasDistanceField_TextType = 0x1,
529         kHasBitmap_TextType = 0x2,
530     };
531 
532     // all glyph / vertex offsets are into these pools.
533     unsigned char* fVertices;
534     GrGlyph** fGlyphs;
535     Run* fRuns;
536     GrMemoryPool* fPool;
537     SkMaskFilter::BlurRec fBlurRec;
538     StrokeInfo fStrokeInfo;
539     SkTArray<BigGlyph> fBigGlyphs;
540     Key fKey;
541     SkMatrix fInitialViewMatrix;
542     SkMatrix fInitialViewMatrixInverse;
543     size_t fSize;
544     SkColor fLuminanceColor;
545     SkScalar fInitialX;
546     SkScalar fInitialY;
547 
548     // We can reuse distance field text, but only if the new viewmatrix would not result in
549     // a mip change.  Because there can be multiple runs in a blob, we track the overall
550     // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
551     SkScalar fMaxMinScale;
552     SkScalar fMinMaxScale;
553     int fRunCount;
554     uint8_t fTextType;
555 };
556 
557 #endif
558