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 GrAtlasTextBatch_DEFINED
9#define GrAtlasTextBatch_DEFINED
10
11#include "batches/GrVertexBatch.h"
12
13#include "text/GrAtlasTextContext.h"
14#include "text/GrDistanceFieldAdjustTable.h"
15
16class GrAtlasTextBatch : public GrVertexBatch {
17public:
18    DEFINE_BATCH_CLASS_ID
19
20    static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph;
21    static const int kIndicesPerGlyph = 6;
22
23    typedef GrAtlasTextBlob Blob;
24    struct Geometry {
25        SkMatrix fViewMatrix;
26        Blob* fBlob;
27        SkScalar fX;
28        SkScalar fY;
29        int fRun;
30        int fSubRun;
31        GrColor fColor;
32    };
33
34    static GrAtlasTextBatch* CreateBitmap(GrMaskFormat maskFormat, int glyphCount,
35                                          GrBatchFontCache* fontCache) {
36        GrAtlasTextBatch* batch = new GrAtlasTextBatch;
37
38        batch->fFontCache = fontCache;
39        switch (maskFormat) {
40            case kA8_GrMaskFormat:
41                batch->fMaskType = kGrayscaleCoverageMask_MaskType;
42                break;
43            case kA565_GrMaskFormat:
44                batch->fMaskType = kLCDCoverageMask_MaskType;
45                break;
46            case kARGB_GrMaskFormat:
47                batch->fMaskType = kColorBitmapMask_MaskType;
48                break;
49        }
50        batch->fBatch.fNumGlyphs = glyphCount;
51        batch->fGeoCount = 1;
52        batch->fFilteredColor = 0;
53        batch->fFontCache = fontCache;
54        batch->fUseBGR = false;
55        return batch;
56    }
57
58    static GrAtlasTextBatch* CreateDistanceField(
59                                              int glyphCount, GrBatchFontCache* fontCache,
60                                              const GrDistanceFieldAdjustTable* distanceAdjustTable,
61                                              SkColor filteredColor, bool isLCD,
62                                              bool useBGR) {
63        GrAtlasTextBatch* batch = new GrAtlasTextBatch;
64
65        batch->fFontCache = fontCache;
66        batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType;
67        batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
68        batch->fFilteredColor = filteredColor;
69        batch->fUseBGR = useBGR;
70        batch->fBatch.fNumGlyphs = glyphCount;
71        batch->fGeoCount = 1;
72        return batch;
73    }
74
75    // to avoid even the initial copy of the struct, we have a getter for the first item which
76    // is used to seed the batch with its initial geometry.  After seeding, the client should call
77    // init() so the Batch can initialize itself
78    Geometry& geometry() { return fGeoData[0]; }
79
80    void init() {
81        const Geometry& geo = fGeoData[0];
82        fBatch.fColor = geo.fColor;
83
84        geo.fBlob->computeSubRunBounds(&fBounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX,
85                                       geo.fY);
86    }
87
88    const char* name() const override { return "TextBatch"; }
89
90    SkString dumpInfo() const override;
91
92protected:
93    void computePipelineOptimizations(GrInitInvariantOutput* color,
94                                      GrInitInvariantOutput* coverage,
95                                      GrBatchToXPOverrides* overrides) const override;
96
97
98private:
99    void initBatchTracker(const GrXPOverridesForBatch& overrides) override;
100
101    struct FlushInfo {
102        SkAutoTUnref<const GrVertexBuffer> fVertexBuffer;
103        SkAutoTUnref<const GrIndexBuffer> fIndexBuffer;
104        int fGlyphsToFlush;
105        int fVertexOffset;
106    };
107
108    void onPrepareDraws(Target* target) const override;
109
110    GrAtlasTextBatch() : INHERITED(ClassID()) {} // initialized in factory functions.
111
112    ~GrAtlasTextBatch() {
113        for (int i = 0; i < fGeoCount; i++) {
114            fGeoData[i].fBlob->unref();
115        }
116    }
117
118    GrMaskFormat maskFormat() const {
119        switch (fMaskType) {
120            case kLCDCoverageMask_MaskType:
121                return kA565_GrMaskFormat;
122            case kColorBitmapMask_MaskType:
123                return kARGB_GrMaskFormat;
124            case kGrayscaleCoverageMask_MaskType:
125            case kGrayscaleDistanceField_MaskType:
126            case kLCDDistanceField_MaskType:
127                return kA8_GrMaskFormat;
128        }
129        return kA8_GrMaskFormat; // suppress warning
130    }
131
132    bool usesDistanceFields() const {
133        return kGrayscaleDistanceField_MaskType == fMaskType ||
134               kLCDDistanceField_MaskType == fMaskType;
135    }
136
137    bool isLCD() const {
138        return kLCDCoverageMask_MaskType == fMaskType ||
139               kLCDDistanceField_MaskType == fMaskType;
140    }
141
142    inline void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const;
143
144    GrColor color() const { return fBatch.fColor; }
145    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
146    bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
147    int numGlyphs() const { return fBatch.fNumGlyphs; }
148
149    bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override;
150
151    // TODO just use class params
152    // TODO trying to figure out why lcd is so whack
153    GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor filteredColor,
154                                          GrColor color, GrTexture* texture) const;
155
156    struct BatchTracker {
157        GrColor fColor;
158        bool fUsesLocalCoords;
159        bool fColorIgnored;
160        bool fCoverageIgnored;
161        int fNumGlyphs;
162    };
163
164    BatchTracker fBatch;
165    // The minimum number of Geometry we will try to allocate.
166    enum { kMinGeometryAllocated = 4 };
167    SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData;
168    int fGeoCount;
169
170    enum MaskType {
171        kGrayscaleCoverageMask_MaskType,
172        kLCDCoverageMask_MaskType,
173        kColorBitmapMask_MaskType,
174        kGrayscaleDistanceField_MaskType,
175        kLCDDistanceField_MaskType,
176    } fMaskType;
177    bool fUseBGR; // fold this into the enum?
178
179    GrBatchFontCache* fFontCache;
180
181    // Distance field properties
182    SkAutoTUnref<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
183    SkColor fFilteredColor;
184
185    friend class GrBlobRegenHelper; // Needs to trigger flushes
186
187    typedef GrVertexBatch INHERITED;
188};
189
190/*
191 * A simple helper class to abstract the interface GrAtlasTextBlob needs to regenerate itself.
192 * It'd be nicer if this was nested, but we need to forward declare it in GrAtlasTextBlob.h
193 */
194class GrBlobRegenHelper {
195public:
196    GrBlobRegenHelper(const GrAtlasTextBatch* batch,
197                      GrVertexBatch::Target* target,
198                      GrAtlasTextBatch::FlushInfo* flushInfo,
199                      const GrGeometryProcessor* gp)
200        : fBatch(batch)
201        , fTarget(target)
202        , fFlushInfo(flushInfo)
203        , fGP(gp) {}
204
205    void flush();
206
207    void incGlyphCount(int glyphCount = 1) {
208        fFlushInfo->fGlyphsToFlush += glyphCount;
209    }
210
211private:
212    const GrAtlasTextBatch* fBatch;
213    GrVertexBatch::Target* fTarget;
214    GrAtlasTextBatch::FlushInfo* fFlushInfo;
215    const GrGeometryProcessor* fGP;
216};
217
218#endif
219