/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkTextBlob_DEFINED #define SkTextBlob_DEFINED #include "../private/SkTemplates.h" #include "../private/SkAtomics.h" #include "SkPaint.h" #include "SkString.h" #include "SkRefCnt.h" struct SkSerialProcs; struct SkDeserialProcs; /** \class SkTextBlob SkTextBlob combines multiple text runs into an immutable, ref-counted structure. */ class SK_API SkTextBlob final : public SkNVRefCnt { public: /** * Returns a conservative blob bounding box. */ const SkRect& bounds() const { return fBounds; } /** * Return a non-zero, unique value representing the text blob. */ uint32_t uniqueID() const { return fUniqueID; } static sk_sp MakeFromText( const void* text, size_t byteLength, const SkPaint& paint); /** * Similar to serialize above, but writes directly into |memory|. Returns bytes written or 0u * if serialization failed due to insufficient size. */ size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const; sk_sp serialize(const SkSerialProcs& procs) const; static sk_sp Deserialize(const void* data, size_t size, const SkDeserialProcs& procs); private: friend class SkNVRefCnt; class RunRecord; enum GlyphPositioning : uint8_t; explicit SkTextBlob(const SkRect& bounds); ~SkTextBlob(); // Memory for objects of this class is created with sk_malloc rather than operator new and must // be freed with sk_free. void operator delete(void* p); void* operator new(size_t); void* operator new(size_t, void* p); static unsigned ScalarsPerGlyph(GlyphPositioning pos); // Call when this blob is part of the key to a cache entry. This allows the cache // to know automatically those entries can be purged when this SkTextBlob is deleted. void notifyAddedToCache(uint32_t cacheID) const { fCacheID.store(cacheID); } friend class SkGlyphRunList; friend class GrTextBlobCache; friend class SkTextBlobBuilder; friend class SkTextBlobPriv; friend class SkTextBlobRunIterator; const SkRect fBounds; const uint32_t fUniqueID; mutable SkAtomic fCacheID; SkDEBUGCODE(size_t fStorageSize;) // The actual payload resides in externally-managed storage, following the object. // (see the .cpp for more details) typedef SkRefCnt INHERITED; }; /** \class SkTextBlobBuilder Helper class for constructing SkTextBlobs. */ class SK_API SkTextBlobBuilder { public: SkTextBlobBuilder(); ~SkTextBlobBuilder(); /** * Returns an immutable SkTextBlob for the current runs/glyphs, * or nullptr if no runs were allocated. * * The builder is reset and can be reused. */ sk_sp make(); /** * Glyph and position buffers associated with a run. * * A run is a sequence of glyphs sharing the same font metrics * and positioning mode. * * If textByteCount is 0, utf8text and clusters will be NULL (no * character information will be associated with the glyphs). * * utf8text will point to a buffer of size textByteCount bytes. * * clusters (if not NULL) will point to an array of size count. * For each glyph, give the byte-offset into the text for the * first byte in the first character in that glyph's cluster. * Each value in the array should be an integer less than * textByteCount. Values in the array should either be * monotonically increasing (left-to-right text) or monotonically * decreasing (right-to-left text). This definiton is conviently * the same as used by Harfbuzz's hb_glyph_info_t::cluster field, * except that Harfbuzz interleaves glyphs and clusters. */ struct RunBuffer { SkGlyphID* glyphs; SkScalar* pos; char* utf8text; uint32_t* clusters; }; /** * Allocates a new default-positioned run and returns its writable glyph buffer * for direct manipulation. * * @param font The font to be used for this run. * @param count Number of glyphs. * @param x,y Position within the blob. * @param textByteCount length of the original UTF-8 text that * corresponds to this sequence of glyphs. If 0, * text will not be included in the textblob. * @param lang Language code, currently unimplemented. * @param bounds Optional run bounding box. If known in advance (!= NULL), it will * be used when computing the blob bounds, to avoid re-measuring. * * @return A writable glyph buffer, valid until the next allocRun() or * build() call. The buffer is guaranteed to hold @count@ glyphs. */ const RunBuffer& allocRunText(const SkPaint& font, int count, SkScalar x, SkScalar y, int textByteCount, SkString lang, const SkRect* bounds = nullptr); const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y, const SkRect* bounds = nullptr) { return this->allocRunText(font, count, x, y, 0, SkString(), bounds); } /** * Allocates a new horizontally-positioned run and returns its writable glyph and position * buffers for direct manipulation. * * @param font The font to be used for this run. * @param count Number of glyphs. * @param y Vertical offset within the blob. * @param textByteCount length of the original UTF-8 text that * corresponds to this sequence of glyphs. If 0, * text will not be included in the textblob. * @param lang Language code, currently unimplemented. * @param bounds Optional run bounding box. If known in advance (!= NULL), it will * be used when computing the blob bounds, to avoid re-measuring. * * @return Writable glyph and position buffers, valid until the next allocRun() * or build() call. The buffers are guaranteed to hold @count@ elements. */ const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y, int textByteCount, SkString lang, const SkRect* bounds = nullptr); const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y, const SkRect* bounds = nullptr) { return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds); } /** * Allocates a new fully-positioned run and returns its writable glyph and position * buffers for direct manipulation. * * @param font The font to be used for this run. * @param count Number of glyphs. * @param textByteCount length of the original UTF-8 text that * corresponds to this sequence of glyphs. If 0, * text will not be included in the textblob. * @param lang Language code, currently unimplemented. * @param bounds Optional run bounding box. If known in advance (!= NULL), it will * be used when computing the blob bounds, to avoid re-measuring. * * @return Writable glyph and position buffers, valid until the next allocRun() * or build() call. The glyph buffer and position buffer are * guaranteed to hold @count@ and 2 * @count@ elements, respectively. */ const RunBuffer& allocRunTextPos(const SkPaint& font, int count, int textByteCount, SkString lang, const SkRect* bounds = nullptr); const RunBuffer& allocRunPos(const SkPaint& font, int count, const SkRect* bounds = nullptr) { return this->allocRunTextPos(font, count, 0, SkString(), bounds); } private: void reserve(size_t size); void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, int count, int textBytes, SkPoint offset, const SkRect* bounds); bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, uint32_t count, SkPoint offset); void updateDeferredBounds(); static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); static SkRect TightRunBounds(const SkTextBlob::RunRecord&); SkAutoTMalloc fStorage; size_t fStorageSize; size_t fStorageUsed; SkRect fBounds; int fRunCount; bool fDeferredBounds; size_t fLastRun; // index into fStorage RunBuffer fCurrentRunBuffer; }; #endif // SkTextBlob_DEFINED