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 GrAtlasTextOp_DEFINED
9#define GrAtlasTextOp_DEFINED
10
11#include "ops/GrMeshDrawOp.h"
12
13#include "text/GrAtlasTextContext.h"
14#include "text/GrDistanceFieldAdjustTable.h"
15
16class GrAtlasTextOp final : public GrMeshDrawOp {
17public:
18    DEFINE_OP_CLASS_ID
19
20    ~GrAtlasTextOp() override {
21        for (int i = 0; i < fGeoCount; i++) {
22            fGeoData[i].fBlob->unref();
23        }
24    }
25
26    static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph;
27    static const int kIndicesPerGlyph = 6;
28
29    typedef GrAtlasTextBlob Blob;
30    struct Geometry {
31        SkMatrix fViewMatrix;
32        Blob* fBlob;
33        SkScalar fX;
34        SkScalar fY;
35        int fRun;
36        int fSubRun;
37        GrColor fColor;
38    };
39
40    static std::unique_ptr<GrAtlasTextOp> MakeBitmap(GrMaskFormat maskFormat, int glyphCount,
41                                                     GrAtlasGlyphCache* fontCache) {
42        std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp);
43
44        op->fFontCache = fontCache;
45        switch (maskFormat) {
46            case kA8_GrMaskFormat:
47                op->fMaskType = kGrayscaleCoverageMask_MaskType;
48                break;
49            case kA565_GrMaskFormat:
50                op->fMaskType = kLCDCoverageMask_MaskType;
51                break;
52            case kARGB_GrMaskFormat:
53                op->fMaskType = kColorBitmapMask_MaskType;
54                break;
55        }
56        op->fNumGlyphs = glyphCount;
57        op->fGeoCount = 1;
58        op->fFilteredColor = 0;
59        op->fFontCache = fontCache;
60        op->fUseBGR = false;
61        return op;
62    }
63
64    static std::unique_ptr<GrAtlasTextOp> MakeDistanceField(
65            int glyphCount, GrAtlasGlyphCache* fontCache,
66            const GrDistanceFieldAdjustTable* distanceAdjustTable,
67            bool useGammaCorrectDistanceTable, SkColor filteredColor, bool isLCD, bool useBGR) {
68        std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp);
69
70        op->fFontCache = fontCache;
71        op->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType;
72        op->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
73        op->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable;
74        op->fFilteredColor = filteredColor;
75        op->fUseBGR = useBGR;
76        op->fNumGlyphs = glyphCount;
77        op->fGeoCount = 1;
78        return op;
79    }
80
81    // To avoid even the initial copy of the struct, we have a getter for the first item which
82    // is used to seed the op with its initial geometry.  After seeding, the client should call
83    // init() so the op can initialize itself
84    Geometry& geometry() { return fGeoData[0]; }
85
86    void init() {
87        const Geometry& geo = fGeoData[0];
88        fColor = geo.fColor;
89        SkRect bounds;
90        geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX,
91                                       geo.fY);
92        // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
93        // we treat this as a set of non-AA rects rendered with a texture.
94        this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
95    }
96
97    const char* name() const override { return "AtlasTextOp"; }
98
99    SkString dumpInfo() const override;
100
101private:
102    void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor*,
103                                            GrPipelineAnalysisCoverage*) const override;
104    void applyPipelineOptimizations(const GrPipelineOptimizations&) override;
105
106    struct FlushInfo {
107        sk_sp<const GrBuffer> fVertexBuffer;
108        sk_sp<const GrBuffer> fIndexBuffer;
109        sk_sp<GrGeometryProcessor> fGeometryProcessor;
110        int fGlyphsToFlush;
111        int fVertexOffset;
112    };
113
114    void onPrepareDraws(Target* target) const override;
115
116    GrAtlasTextOp() : INHERITED(ClassID()) {}  // initialized in factory functions.
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 || kLCDDistanceField_MaskType == fMaskType;
139    }
140
141    inline void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const;
142
143    GrColor color() const { return fColor; }
144    const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
145    bool usesLocalCoords() const { return fUsesLocalCoords; }
146    int numGlyphs() const { return fNumGlyphs; }
147
148    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
149
150    // TODO just use class params
151    // TODO trying to figure out why lcd is so whack
152    sk_sp<GrGeometryProcessor> setupDfProcessor(GrResourceProvider*,
153                                                const SkMatrix& viewMatrix, SkColor filteredColor,
154                                                GrColor color, sk_sp<GrTextureProxy> proxy) const;
155
156    GrColor fColor;
157    bool fUsesLocalCoords;
158    int fNumGlyphs;
159
160    // The minimum number of Geometry we will try to allocate.
161    enum { kMinGeometryAllocated = 4 };
162    SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData;
163    int fGeoCount;
164
165    enum MaskType {
166        kGrayscaleCoverageMask_MaskType,
167        kLCDCoverageMask_MaskType,
168        kColorBitmapMask_MaskType,
169        kGrayscaleDistanceField_MaskType,
170        kLCDDistanceField_MaskType,
171    } fMaskType;
172    bool fUseBGR;  // fold this into the enum?
173
174    GrAtlasGlyphCache* fFontCache;
175
176    // Distance field properties
177    sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
178    SkColor fFilteredColor;
179    bool fUseGammaCorrectDistanceTable;
180
181    friend class GrBlobRegenHelper;  // Needs to trigger flushes
182
183    typedef GrMeshDrawOp INHERITED;
184};
185
186/*
187 * A simple helper class to abstract the interface GrAtlasTextBlob needs to regenerate itself.
188 * It'd be nicer if this was nested, but we need to forward declare it in GrAtlasTextBlob.h
189 */
190class GrBlobRegenHelper {
191public:
192    GrBlobRegenHelper(const GrAtlasTextOp* op, GrMeshDrawOp::Target* target,
193                      GrAtlasTextOp::FlushInfo* flushInfo)
194            : fOp(op), fTarget(target), fFlushInfo(flushInfo) {}
195
196    void flush();
197
198    void incGlyphCount(int glyphCount = 1) { fFlushInfo->fGlyphsToFlush += glyphCount; }
199
200private:
201    const GrAtlasTextOp* fOp;
202    GrMeshDrawOp::Target* fTarget;
203    GrAtlasTextOp::FlushInfo* fFlushInfo;
204};
205
206#endif
207