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 
16 class GrAtlasTextOp final : public GrMeshDrawOp {
17 public:
18     DEFINE_OP_CLASS_ID
19 
~GrAtlasTextOp()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 
MakeBitmap(GrMaskFormat maskFormat,int glyphCount,GrAtlasGlyphCache * fontCache)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 
MakeDistanceField(int glyphCount,GrAtlasGlyphCache * fontCache,const GrDistanceFieldAdjustTable * distanceAdjustTable,bool useGammaCorrectDistanceTable,SkColor filteredColor,bool isLCD,bool useBGR)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
geometry()84     Geometry& geometry() { return fGeoData[0]; }
85 
init()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 
name()97     const char* name() const override { return "AtlasTextOp"; }
98 
99     SkString dumpInfo() const override;
100 
101 private:
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 
GrAtlasTextOp()116     GrAtlasTextOp() : INHERITED(ClassID()) {}  // initialized in factory functions.
117 
maskFormat()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 
usesDistanceFields()132     bool usesDistanceFields() const {
133         return kGrayscaleDistanceField_MaskType == fMaskType ||
134                kLCDDistanceField_MaskType == fMaskType;
135     }
136 
isLCD()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 
color()143     GrColor color() const { return fColor; }
viewMatrix()144     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
usesLocalCoords()145     bool usesLocalCoords() const { return fUsesLocalCoords; }
numGlyphs()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  */
190 class GrBlobRegenHelper {
191 public:
GrBlobRegenHelper(const GrAtlasTextOp * op,GrMeshDrawOp::Target * target,GrAtlasTextOp::FlushInfo * flushInfo)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 
200 private:
201     const GrAtlasTextOp* fOp;
202     GrMeshDrawOp::Target* fTarget;
203     GrAtlasTextOp::FlushInfo* fFlushInfo;
204 };
205 
206 #endif
207