blob: dd70cff6e3d8b0ba89ba20c405c11701df8bb5ed [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 GrTextBlob_DEFINED
#define GrTextBlob_DEFINED
#include "include/core/SkPathEffect.h"
#include "include/core/SkPoint3.h"
#include "include/core/SkSurfaceProps.h"
#include "src/core/SkDescriptor.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkOpts.h"
#include "src/core/SkRectPriv.h"
#include "src/core/SkStrikeCache.h"
#include "src/core/SkStrikeSpec.h"
#include "src/core/SkTInternalLList.h"
#include "src/gpu/GrColor.h"
#include "src/gpu/GrDrawOpAtlas.h"
#include "src/gpu/text/GrStrikeCache.h"
#include "src/gpu/text/GrTextContext.h"
#include "src/gpu/text/GrTextTarget.h"
class GrAtlasManager;
class GrAtlasTextOp;
struct GrDistanceFieldAdjustTable;
struct GrGlyph;
class SkTextBlob;
class SkTextBlobRunIterator;
/*
* A GrTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
* on the GPU. These are initially created with valid positions and colors, but invalid
* texture coordinates. The GrTextBlob itself has a few Blob-wide properties, and also
* consists of a number of runs. Runs inside a blob are flushed individually so they can be
* reordered.
*
* The only thing(aside from a memcopy) required to flush a GrTextBlob is to ensure that
* the GrAtlas will not evict anything the Blob needs.
*
*/
class GrTextBlob final : public SkNVRefCnt<GrTextBlob>, public SkGlyphRunPainterInterface {
public:
class SubRun;
class VertexRegenerator;
using SubRunBufferSpec = std::tuple<uint32_t, uint32_t, size_t, size_t>;
enum SubRunType {
kDirectMask,
kTransformedMask,
kTransformedPath,
kTransformedSDFT
};
struct Key {
Key();
uint32_t fUniqueID;
// Color may affect the gamma of the mask we generate, but in a fairly limited way.
// Each color is assigned to on of a fixed number of buckets based on its
// luminance. For each luminance bucket there is a "canonical color" that
// represents the bucket. This functionality is currently only supported for A8
SkColor fCanonicalColor;
SkPaint::Style fStyle;
SkPixelGeometry fPixelGeometry;
bool fHasBlur;
uint32_t fScalerContextFlags;
bool operator==(const Key& other) const;
};
// Any glyphs that can't be rendered with the base or override descriptor
// are rendered as paths
struct PathGlyph {
PathGlyph(const SkPath& path, SkPoint origin);
SkPath fPath;
SkPoint fOrigin;
};
SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob);
// Change memory management to handle the data after GrTextBlob, but in the same allocation
// of memory. Only allow placement new.
void operator delete(void* p);
void* operator new(size_t);
void* operator new(size_t, void* p);
~GrTextBlob() override;
// Make an empty GrTextBlob, with all the invariants set to make the right decisions when
// adding SubRuns.
static sk_sp<GrTextBlob> Make(const SkGlyphRunList& glyphRunList,
GrStrikeCache* strikeCache,
const SkMatrix& viewMatrix,
GrColor color,
bool forceWForDistanceFields);
// Key manipulation functions
void setupKey(const GrTextBlob::Key& key,
const SkMaskFilterBase::BlurRec& blurRec,
const SkPaint& paint);
static const Key& GetKey(const GrTextBlob& blob);
static uint32_t Hash(const Key& key);
bool hasDistanceField() const;
bool hasBitmap() const;
bool hasPerspective() const;
void setHasDistanceField();
void setHasBitmap();
void setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax);
static size_t GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord);
bool mustRegenerate(const SkPaint&, bool, const SkMaskFilterBase::BlurRec& blurRec,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
void flush(GrTextTarget*, const SkSurfaceProps& props,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
const SkPaint& paint, const SkPMColor4f& filteredColor, const GrClip& clip,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
void computeSubRunBounds(SkRect* outBounds, const SubRun& subRun,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
bool needsGlyphTransform);
// Normal text mask, SDFT, or color.
struct Mask2DVertex {
SkPoint devicePos;
GrColor color;
SkIPoint16 atlasPos;
};
struct ARGB2DVertex {
SkPoint devicePos;
SkIPoint16 atlasPos;
};
// Perspective SDFT or SDFT forced to 3D or perspective color.
struct SDFT3DVertex {
SkPoint3 devicePos;
GrColor color;
SkIPoint16 atlasPos;
};
struct ARGB3DVertex {
SkPoint3 devicePos;
SkIPoint16 atlasPos;
};
static const int kVerticesPerGlyph = 4;
const Key& key() const;
size_t size() const;
// Internal test methods
std::unique_ptr<GrDrawOp> test_makeOp(int glyphCount,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
const SkPaint& paint, const SkPMColor4f& filteredColor,
const SkSurfaceProps&, const GrDistanceFieldAdjustTable*,
GrTextTarget*);
bool hasW(SubRunType type) const;
SubRun* makeSubRun(SubRunType type,
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format);
void addSingleMaskFormat(
SubRunType type,
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
GrMaskFormat format);
void addMultiMaskFormat(
SubRunType type,
const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec);
void addSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
const SkFont& runFont,
SkScalar minScale,
SkScalar maxScale);
private:
enum TextType {
kHasDistanceField_TextType = 0x1,
kHasBitmap_TextType = 0x2,
};
struct StrokeInfo {
SkScalar fFrameWidth;
SkScalar fMiterLimit;
SkPaint::Join fJoin;
};
GrTextBlob(size_t allocSize,
GrStrikeCache* strikeCache,
const SkMatrix& viewMatrix,
SkPoint origin,
GrColor color,
SkColor initialLuminance,
bool forceWForDistanceFields);
void insertSubRun(SubRun* subRun);
std::unique_ptr<GrAtlasTextOp> makeOp(
SubRun& info, int glyphCount,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
const SkPaint& paint, const SkPMColor4f& filteredColor, const SkSurfaceProps&,
const GrDistanceFieldAdjustTable*, GrTextTarget*);
// Methods to satisfy SkGlyphRunPainterInterface
void processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec) override;
void processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkFont& runFont,
const SkStrikeSpec& strikeSpec) override;
void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec,
const SkFont& runFont,
SkScalar minScale,
SkScalar maxScale) override;
void processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
const SkStrikeSpec& strikeSpec) override;
// Overall size of this struct plus vertices and glyphs at the end.
const size_t fSize;
// Lifetime: The GrStrikeCache is owned by and has the same lifetime as the GrRecordingContext.
// The GrRecordingContext also owns the GrTextBlob cache which owns this GrTextBlob.
GrStrikeCache* const fStrikeCache;
// The initial view matrix and its inverse. This is used for moving additional draws of this
// same text blob. We record the initial view matrix and initial offsets(x,y), because we
// record vertex bounds relative to these numbers. When blobs are reused with new matrices,
// we need to return to source space so we can update the vertex bounds appropriately.
const SkMatrix fInitialViewMatrix;
const SkMatrix fInitialViewMatrixInverse;
// Initial position of this blob. Used for calculating position differences when reusing this
// blob.
const SkPoint fInitialOrigin;
// From the distance field options to force distance fields to have a W coordinate.
const bool fForceWForDistanceFields;
// The color of the text to draw for solid colors.
const GrColor fColor;
const SkColor fInitialLuminance;
// Pool of bytes for vertex data.
char* fVertices;
// How much (in bytes) of the vertex data is used while accumulating SubRuns.
size_t fVerticesCursor{0};
// Pointers to every glyph that will be drawn.
GrGlyph** fGlyphs;
// Number of glyphs stored in fGlyphs while accumulating SubRuns.
uint32_t fGlyphsCursor{0};
SkMaskFilterBase::BlurRec fBlurRec;
StrokeInfo fStrokeInfo;
Key fKey;
// We can reuse distance field text, but only if the new view matrix would not result in
// a mip change. Because there can be multiple runs in a blob, we track the overall
// maximum minimum scale, and minimum maximum scale, we can support before we need to regen
SkScalar fMaxMinScale{-SK_ScalarMax};
SkScalar fMinMaxScale{SK_ScalarMax};
uint8_t fTextType{0};
SubRun* fFirstSubRun{nullptr};
SubRun* fLastSubRun{nullptr};
SkArenaAlloc fAlloc;
};
/**
* Used to produce vertices for a subrun of a blob. The vertices are cached in the blob itself.
* This is invoked each time a sub run is drawn. It regenerates the vertex data as required either
* because of changes to the atlas or because of different draw parameters (e.g. color change). In
* rare cases the draw may have to interrupted and flushed in the middle of the sub run in order to
* free up atlas space. Thus, this generator is stateful and should be invoked in a loop until the
* entire sub run has been completed.
*/
class GrTextBlob::VertexRegenerator {
public:
/**
* Consecutive VertexRegenerators often use the same SkGlyphCache. If the same instance of
* SkAutoGlyphCache is reused then it can save the cost of multiple detach/attach operations of
* SkGlyphCache.
*/
VertexRegenerator(GrResourceProvider*, GrTextBlob*,
GrTextBlob::SubRun* subRun,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
GrDeferredUploadTarget*, GrStrikeCache*, GrAtlasManager*);
struct Result {
/**
* Was regenerate() able to draw all the glyphs from the sub run? If not flush all glyph
* draws and call regenerate() again.
*/
bool fFinished = true;
/**
* How many glyphs were regenerated. Will be equal to the sub run's glyph count if
* fType is kFinished.
*/
int fGlyphsRegenerated = 0;
/**
* Pointer where the caller finds the first regenerated vertex.
*/
const char* fFirstVertex;
};
bool regenerate(Result*);
private:
bool doRegen(Result*, bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs);
GrResourceProvider* fResourceProvider;
const SkMatrix& fViewMatrix;
GrTextBlob* fBlob;
GrDeferredUploadTarget* fUploadTarget;
GrStrikeCache* fGrStrikeCache;
GrAtlasManager* fFullAtlasManager;
SkTLazy<SkBulkGlyphMetricsAndImages> fMetricsAndImages;
SubRun* fSubRun;
GrColor fColor;
SkScalar fTransX;
SkScalar fTransY;
uint32_t fRegenFlags = 0;
int fCurrGlyph = 0;
bool fBrokenRun = false;
};
#endif // GrTextBlob_DEFINED