| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef GrAtlasTextBatch_DEFINED |
| #define GrAtlasTextBatch_DEFINED |
| |
| #include "batches/GrVertexBatch.h" |
| |
| #include "text/GrAtlasTextContext.h" |
| #include "text/GrDistanceFieldAdjustTable.h" |
| |
| class GrAtlasTextBatch : public GrVertexBatch { |
| public: |
| DEFINE_BATCH_CLASS_ID |
| |
| static const int kVerticesPerGlyph = GrAtlasTextBlob::kVerticesPerGlyph; |
| static const int kIndicesPerGlyph = 6; |
| |
| typedef GrAtlasTextBlob Blob; |
| struct Geometry { |
| SkMatrix fViewMatrix; |
| Blob* fBlob; |
| SkScalar fX; |
| SkScalar fY; |
| int fRun; |
| int fSubRun; |
| GrColor fColor; |
| }; |
| |
| static GrAtlasTextBatch* CreateBitmap(GrMaskFormat maskFormat, int glyphCount, |
| GrBatchFontCache* fontCache) { |
| GrAtlasTextBatch* batch = new GrAtlasTextBatch; |
| |
| batch->fFontCache = fontCache; |
| switch (maskFormat) { |
| case kA8_GrMaskFormat: |
| batch->fMaskType = kGrayscaleCoverageMask_MaskType; |
| break; |
| case kA565_GrMaskFormat: |
| batch->fMaskType = kLCDCoverageMask_MaskType; |
| break; |
| case kARGB_GrMaskFormat: |
| batch->fMaskType = kColorBitmapMask_MaskType; |
| break; |
| } |
| batch->fBatch.fNumGlyphs = glyphCount; |
| batch->fGeoCount = 1; |
| batch->fFilteredColor = 0; |
| batch->fFontCache = fontCache; |
| batch->fUseBGR = false; |
| return batch; |
| } |
| |
| static GrAtlasTextBatch* CreateDistanceField( |
| int glyphCount, GrBatchFontCache* fontCache, |
| const GrDistanceFieldAdjustTable* distanceAdjustTable, |
| bool useGammaCorrectDistanceTable, |
| SkColor filteredColor, bool isLCD, |
| bool useBGR) { |
| GrAtlasTextBatch* batch = new GrAtlasTextBatch; |
| |
| batch->fFontCache = fontCache; |
| batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType; |
| batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable)); |
| batch->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable; |
| batch->fFilteredColor = filteredColor; |
| batch->fUseBGR = useBGR; |
| batch->fBatch.fNumGlyphs = glyphCount; |
| batch->fGeoCount = 1; |
| return batch; |
| } |
| |
| // to avoid even the initial copy of the struct, we have a getter for the first item which |
| // is used to seed the batch with its initial geometry. After seeding, the client should call |
| // init() so the Batch can initialize itself |
| Geometry& geometry() { return fGeoData[0]; } |
| |
| void init() { |
| const Geometry& geo = fGeoData[0]; |
| fBatch.fColor = geo.fColor; |
| SkRect bounds; |
| geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, |
| geo.fY); |
| // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds |
| // we treat this as a set of non-AA rects rendered with a texture. |
| this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); |
| } |
| |
| const char* name() const override { return "TextBatch"; } |
| |
| SkString dumpInfo() const override; |
| |
| protected: |
| void computePipelineOptimizations(GrInitInvariantOutput* color, |
| GrInitInvariantOutput* coverage, |
| GrBatchToXPOverrides* overrides) const override; |
| |
| |
| private: |
| void initBatchTracker(const GrXPOverridesForBatch& overrides) override; |
| |
| struct FlushInfo { |
| sk_sp<const GrBuffer> fVertexBuffer; |
| sk_sp<const GrBuffer> fIndexBuffer; |
| sk_sp<GrGeometryProcessor> fGeometryProcessor; |
| int fGlyphsToFlush; |
| int fVertexOffset; |
| }; |
| |
| void onPrepareDraws(Target* target) const override; |
| |
| GrAtlasTextBatch() : INHERITED(ClassID()) {} // initialized in factory functions. |
| |
| ~GrAtlasTextBatch() { |
| for (int i = 0; i < fGeoCount; i++) { |
| fGeoData[i].fBlob->unref(); |
| } |
| } |
| |
| GrMaskFormat maskFormat() const { |
| switch (fMaskType) { |
| case kLCDCoverageMask_MaskType: |
| return kA565_GrMaskFormat; |
| case kColorBitmapMask_MaskType: |
| return kARGB_GrMaskFormat; |
| case kGrayscaleCoverageMask_MaskType: |
| case kGrayscaleDistanceField_MaskType: |
| case kLCDDistanceField_MaskType: |
| return kA8_GrMaskFormat; |
| } |
| return kA8_GrMaskFormat; // suppress warning |
| } |
| |
| bool usesDistanceFields() const { |
| return kGrayscaleDistanceField_MaskType == fMaskType || |
| kLCDDistanceField_MaskType == fMaskType; |
| } |
| |
| bool isLCD() const { |
| return kLCDCoverageMask_MaskType == fMaskType || |
| kLCDDistanceField_MaskType == fMaskType; |
| } |
| |
| inline void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const; |
| |
| GrColor color() const { return fBatch.fColor; } |
| const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } |
| bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } |
| int numGlyphs() const { return fBatch.fNumGlyphs; } |
| |
| bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override; |
| |
| // TODO just use class params |
| // TODO trying to figure out why lcd is so whack |
| sk_sp<GrGeometryProcessor> setupDfProcessor(const SkMatrix& viewMatrix, SkColor filteredColor, |
| GrColor color, GrTexture* texture) const; |
| |
| struct BatchTracker { |
| GrColor fColor; |
| bool fUsesLocalCoords; |
| bool fColorIgnored; |
| bool fCoverageIgnored; |
| int fNumGlyphs; |
| }; |
| |
| BatchTracker fBatch; |
| // The minimum number of Geometry we will try to allocate. |
| enum { kMinGeometryAllocated = 4 }; |
| SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData; |
| int fGeoCount; |
| |
| enum MaskType { |
| kGrayscaleCoverageMask_MaskType, |
| kLCDCoverageMask_MaskType, |
| kColorBitmapMask_MaskType, |
| kGrayscaleDistanceField_MaskType, |
| kLCDDistanceField_MaskType, |
| } fMaskType; |
| bool fUseBGR; // fold this into the enum? |
| |
| GrBatchFontCache* fFontCache; |
| |
| // Distance field properties |
| sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable; |
| SkColor fFilteredColor; |
| bool fUseGammaCorrectDistanceTable; |
| |
| friend class GrBlobRegenHelper; // Needs to trigger flushes |
| |
| typedef GrVertexBatch INHERITED; |
| }; |
| |
| /* |
| * A simple helper class to abstract the interface GrAtlasTextBlob needs to regenerate itself. |
| * It'd be nicer if this was nested, but we need to forward declare it in GrAtlasTextBlob.h |
| */ |
| class GrBlobRegenHelper { |
| public: |
| GrBlobRegenHelper(const GrAtlasTextBatch* batch, |
| GrVertexBatch::Target* target, |
| GrAtlasTextBatch::FlushInfo* flushInfo) |
| : fBatch(batch) |
| , fTarget(target) |
| , fFlushInfo(flushInfo) {} |
| |
| void flush(); |
| |
| void incGlyphCount(int glyphCount = 1) { |
| fFlushInfo->fGlyphsToFlush += glyphCount; |
| } |
| |
| private: |
| const GrAtlasTextBatch* fBatch; |
| GrVertexBatch::Target* fTarget; |
| GrAtlasTextBatch::FlushInfo* fFlushInfo; |
| }; |
| |
| #endif |