blob: 0e1adef6091bcf0154760357e883dfbb7f4a2d6b [file] [log] [blame]
/*
* 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 "SkPaint.h"
#include "SkString.h"
#include "SkRefCnt.h"
#include <atomic>
struct SkSerialProcs;
struct SkDeserialProcs;
/** \class SkTextBlob
SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
*/
class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
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<SkTextBlob> MakeFromText(
const void* text, size_t byteLength, const SkPaint& paint);
static sk_sp<SkTextBlob> MakeFromString(const char* string, const SkPaint& paint) {
if (!string) {
return nullptr;
}
return MakeFromText(string, strlen(string), 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<SkData> serialize(const SkSerialProcs& procs) const;
static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size,
const SkDeserialProcs& procs);
private:
friend class SkNVRefCnt<SkTextBlob>;
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 std::atomic<uint32_t> 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<SkTextBlob> 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 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& 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 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& 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 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& allocRunPos(const SkPaint& font, int count,
const SkRect* bounds = nullptr) {
return this->allocRunTextPos(font, count, 0, SkString(), bounds);
}
private:
const RunBuffer& allocRunText(const SkPaint& font,
int count,
SkScalar x,
SkScalar y,
int textByteCount,
SkString lang,
const SkRect* bounds = nullptr);
const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
int textByteCount, SkString lang,
const SkRect* bounds = nullptr);
const RunBuffer& allocRunTextPos(const SkPaint& font, int count,
int textByteCount, SkString lang,
const SkRect* bounds = nullptr);
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&);
friend class SkTextBlobPriv;
friend class SkTextBlobBuilderPriv;
SkAutoTMalloc<uint8_t> fStorage;
size_t fStorageSize;
size_t fStorageUsed;
SkRect fBounds;
int fRunCount;
bool fDeferredBounds;
size_t fLastRun; // index into fStorage
RunBuffer fCurrentRunBuffer;
};
#endif // SkTextBlob_DEFINED