/* * 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, 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->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; geo.fBlob->computeSubRunBounds(&fBounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, geo.fY); } 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 { SkAutoTUnref<const GrVertexBuffer> fVertexBuffer; SkAutoTUnref<const GrIndexBuffer> fIndexBuffer; 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 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 SkAutoTUnref<const GrDistanceFieldAdjustTable> fDistanceAdjustTable; SkColor fFilteredColor; 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, const GrGeometryProcessor* gp) : fBatch(batch) , fTarget(target) , fFlushInfo(flushInfo) , fGP(gp) {} void flush(); void incGlyphCount(int glyphCount = 1) { fFlushInfo->fGlyphsToFlush += glyphCount; } private: const GrAtlasTextBatch* fBatch; GrVertexBatch::Target* fTarget; GrAtlasTextBatch::FlushInfo* fFlushInfo; const GrGeometryProcessor* fGP; }; #endif