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