Home | History | Annotate | Download | only in text
      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 {
     56         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 
     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 
     89     static const Key& GetKey(const GrAtlasTextBlob& blob) {
     90         return blob.fKey;
     91     }
     92 
     93     static uint32_t Hash(const Key& key) {
     94         return SkOpts::hash(&key, sizeof(Key));
     95     }
     96 
     97     void operator delete(void* p) {
     98         GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p);
     99         blob->fPool->release(p);
    100     }
    101     void* operator new(size_t) {
    102         SkFAIL("All blobs are created by placement new.");
    103         return sk_malloc_throw(0);
    104     }
    105 
    106     void* operator new(size_t, void* p) { return p; }
    107     void operator delete(void* target, void* placement) {
    108         ::operator delete(target, placement);
    109     }
    110 
    111     bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
    112     bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
    113     void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
    114     void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
    115 
    116     int runCount() const { return fRunCount; }
    117 
    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
    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 
    136     void setRunDrawAsPaths(int runIndex) {
    137         fRuns[runIndex].fDrawAsPaths = true;
    138     }
    139 
    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
    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 
    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 
    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.
    243     void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix, SkScalar x,
    244                           SkScalar y) {
    245         fLuminanceColor = luminanceColor;
    246         this->setupViewMatrix(viewMatrix, x, y);
    247     }
    248 
    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 
    263     const Key& key() const { return fKey; }
    264 
    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:
    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.
    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 {
    347         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 {
    354             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             }
    365             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
    383             void resetBulkUseToken() { fBulkUseToken.reset(); }
    384             GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
    385             void setStrike(GrAtlasTextStrike* strike) { fStrike.reset(SkRef(strike)); }
    386             GrAtlasTextStrike* strike() const { return fStrike.get(); }
    387 
    388             void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
    389             uint64_t atlasGeneration() const { return fAtlasGeneration; }
    390 
    391             size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
    392             size_t vertexStartIndex() const { return fVertexStartIndex; }
    393             size_t vertexEndIndex() const { return fVertexEndIndex; }
    394             void appendVertices(size_t vertexStride) {
    395                 fVertexEndIndex += vertexStride * kVerticesPerGlyph;
    396             }
    397 
    398             uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
    399             uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
    400             uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
    401             void glyphAppended() { fGlyphEndIndex++; }
    402             void setColor(GrColor color) { fColor = color; }
    403             GrColor color() const { return fColor; }
    404             void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
    405             GrMaskFormat maskFormat() const { return fMaskFormat; }
    406 
    407             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 
    418             const SkRect& vertexBounds() const { return fVertexBounds; }
    419             void joinGlyphBounds(const SkRect& glyphBounds) {
    420                 fVertexBounds.joinNonEmptyArg(glyphBounds);
    421             }
    422 
    423             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
    434             void setDrawAsDistanceFields() { fFlags |= kDrawAsSDF_Flag; }
    435             bool drawAsDistanceFields() const { return SkToBool(fFlags & kDrawAsSDF_Flag); }
    436             void setUseLCDText(bool useLCDText) {
    437                 fFlags = useLCDText ? fFlags | kUseLCDText_Flag : fFlags & ~kUseLCDText_Flag;
    438             }
    439             bool hasUseLCDText() const { return SkToBool(fFlags & kUseLCDText_Flag); }
    440             void setAntiAliased(bool antiAliased) {
    441                 fFlags = antiAliased ? fFlags | kAntiAliased_Flag : fFlags & ~kAntiAliased_Flag;
    442             }
    443             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 
    468         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 {
    508         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