blob: 0738ce7f205912f2bbb61d4998044279d8372116 [file] [log] [blame]
/*
* 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 GrAtlasTextOp_DEFINED
#define GrAtlasTextOp_DEFINED
#include "ops/GrMeshDrawOp.h"
#include "text/GrAtlasTextContext.h"
#include "text/GrDistanceFieldAdjustTable.h"
class GrAtlasTextOp final : public GrMeshDrawOp {
public:
DEFINE_OP_CLASS_ID
~GrAtlasTextOp() override {
for (int i = 0; i < fGeoCount; i++) {
fGeoData[i].fBlob->unref();
}
}
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 std::unique_ptr<GrAtlasTextOp> MakeBitmap(GrPaint&& paint, GrMaskFormat maskFormat,
int glyphCount, GrAtlasGlyphCache* fontCache) {
std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp(std::move(paint)));
op->fFontCache = fontCache;
switch (maskFormat) {
case kA8_GrMaskFormat:
op->fMaskType = kGrayscaleCoverageMask_MaskType;
break;
case kA565_GrMaskFormat:
op->fMaskType = kLCDCoverageMask_MaskType;
break;
case kARGB_GrMaskFormat:
op->fMaskType = kColorBitmapMask_MaskType;
break;
}
op->fNumGlyphs = glyphCount;
op->fGeoCount = 1;
op->fLuminanceColor = 0;
op->fFontCache = fontCache;
return op;
}
static std::unique_ptr<GrAtlasTextOp> MakeDistanceField(
GrPaint&& paint, int glyphCount, GrAtlasGlyphCache* fontCache,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
bool useGammaCorrectDistanceTable, SkColor luminanceColor, bool isLCD, bool useBGR,
bool isAntiAliased) {
std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp(std::move(paint)));
op->fFontCache = fontCache;
op->fMaskType = !isAntiAliased ? kAliasedDistanceField_MaskType
: isLCD ? (useBGR ? kLCDBGRDistanceField_MaskType
: kLCDDistanceField_MaskType)
: kGrayscaleDistanceField_MaskType;
op->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
op->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable;
op->fLuminanceColor = luminanceColor;
op->fNumGlyphs = glyphCount;
op->fGeoCount = 1;
return op;
}
// To avoid even the initial copy of the struct, we have a getter for the first item which
// is used to seed the op with its initial geometry. After seeding, the client should call
// init() so the op can initialize itself
Geometry& geometry() { return fGeoData[0]; }
void init() {
const Geometry& geo = fGeoData[0];
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 "AtlasTextOp"; }
void visitProxies(const VisitProxyFunc& func) const override {
fProcessors.visitProxies(func);
const sk_sp<GrTextureProxy>* proxies = fFontCache->getProxies(this->maskFormat());
for (int i = 0; i < kMaxTextures; ++i) {
if (proxies[i]) {
func(proxies[i].get());
}
}
}
SkString dumpInfo() const override;
FixedFunctionFlags fixedFunctionFlags() const override;
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip,
GrPixelConfigIsClamped dstIsClamped) override;
private:
GrAtlasTextOp(GrPaint&& paint)
: INHERITED(ClassID())
, fColor(paint.getColor())
, fSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint))
, fProcessors(std::move(paint)) {}
struct FlushInfo {
sk_sp<const GrBuffer> fVertexBuffer;
sk_sp<const GrBuffer> fIndexBuffer;
sk_sp<GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
int fGlyphsToFlush;
int fVertexOffset;
};
void onPrepareDraws(Target*) override;
GrMaskFormat maskFormat() const {
switch (fMaskType) {
case kLCDCoverageMask_MaskType:
return kA565_GrMaskFormat;
case kColorBitmapMask_MaskType:
return kARGB_GrMaskFormat;
case kGrayscaleCoverageMask_MaskType:
case kAliasedDistanceField_MaskType:
case kGrayscaleDistanceField_MaskType:
case kLCDDistanceField_MaskType:
case kLCDBGRDistanceField_MaskType:
return kA8_GrMaskFormat;
}
return kA8_GrMaskFormat; // suppress warning
}
bool usesDistanceFields() const {
return kAliasedDistanceField_MaskType == fMaskType ||
kGrayscaleDistanceField_MaskType == fMaskType ||
kLCDDistanceField_MaskType == fMaskType ||
kLCDBGRDistanceField_MaskType == fMaskType;
}
bool isLCD() const {
return kLCDCoverageMask_MaskType == fMaskType ||
kLCDDistanceField_MaskType == fMaskType ||
kLCDBGRDistanceField_MaskType == fMaskType;
}
inline void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const;
GrColor color() const { return fColor; }
const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
bool usesLocalCoords() const { return fUsesLocalCoords; }
int numGlyphs() const { return fNumGlyphs; }
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
static constexpr auto kMaxTextures = 4;
// TODO just use class params
sk_sp<GrGeometryProcessor> setupDfProcessor(const SkMatrix& viewMatrix, SkColor luminanceColor,
GrColor color,
const sk_sp<GrTextureProxy> [kMaxTextures]) const;
// The minimum number of Geometry we will try to allocate.
enum { kMinGeometryAllocated = 4 };
enum MaskType {
kGrayscaleCoverageMask_MaskType,
kLCDCoverageMask_MaskType,
kColorBitmapMask_MaskType,
kAliasedDistanceField_MaskType,
kGrayscaleDistanceField_MaskType,
kLCDDistanceField_MaskType,
kLCDBGRDistanceField_MaskType,
};
SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData;
GrColor fColor;
uint32_t fSRGBFlags;
GrProcessorSet fProcessors;
bool fUsesLocalCoords;
bool fCanCombineOnTouchOrOverlap;
int fGeoCount;
int fNumGlyphs;
MaskType fMaskType;
GrAtlasGlyphCache* fFontCache;
// Distance field properties
sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
SkColor fLuminanceColor;
bool fUseGammaCorrectDistanceTable;
friend class GrBlobRegenHelper; // Needs to trigger flushes
typedef GrMeshDrawOp 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 GrAtlasTextOp* op, GrMeshDrawOp::Target* target,
GrAtlasTextOp::FlushInfo* flushInfo)
: fOp(op), fTarget(target), fFlushInfo(flushInfo) {}
void flush();
void incGlyphCount(int glyphCount = 1) { fFlushInfo->fGlyphsToFlush += glyphCount; }
private:
const GrAtlasTextOp* fOp;
GrMeshDrawOp::Target* fTarget;
GrAtlasTextOp::FlushInfo* fFlushInfo;
};
#endif