1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#ifndef SkTextBlob_DEFINED 9#define SkTextBlob_DEFINED 10 11#include "../private/SkTemplates.h" 12#include "../private/SkAtomics.h" 13#include "SkPaint.h" 14#include "SkString.h" 15#include "SkRefCnt.h" 16 17class SkReadBuffer; 18class SkWriteBuffer; 19 20struct SkSerialProcs; 21struct SkDeserialProcs; 22 23typedef void (*SkTypefaceCatalogerProc)(SkTypeface*, void* ctx); 24typedef sk_sp<SkTypeface> (*SkTypefaceResolverProc)(uint32_t id, void* ctx); 25 26/** \class SkTextBlob 27 28 SkTextBlob combines multiple text runs into an immutable, ref-counted structure. 29*/ 30class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> { 31public: 32 /** 33 * Returns a conservative blob bounding box. 34 */ 35 const SkRect& bounds() const { return fBounds; } 36 37 /** 38 * Return a non-zero, unique value representing the text blob. 39 */ 40 uint32_t uniqueID() const { return fUniqueID; } 41 42 /** 43 * Serialize to a buffer. 44 */ 45 void flatten(SkWriteBuffer&) const; 46 47 /** 48 * Recreate an SkTextBlob that was serialized into a buffer. 49 * 50 * @param SkReadBuffer Serialized blob data. 51 * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is 52 * invalid. 53 */ 54 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&); 55 56 enum GlyphPositioning : uint8_t { 57 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph. 58 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph. 59 kFull_Positioning = 2 // Point positioning -- two scalars per glyph. 60 }; 61 62 /** 63 * Serialize the typeface into a data blob, storing type uniqueID of each referenced typeface. 64 * During this process, each time a typeface is encountered, it is passed to the catalog, 65 * allowing the caller to what typeface IDs will need to be resolved in Deserialize(). 66 */ 67 sk_sp<SkData> serialize(SkTypefaceCatalogerProc, void* ctx) const; 68 69 /** 70 * Re-create a text blob previously serialized. Since the serialized form records the uniqueIDs 71 * of its typefaces, deserialization requires that the caller provide the corresponding 72 * SkTypefaces for those IDs. 73 */ 74 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, 75 SkTypefaceResolverProc, void* ctx); 76 77 sk_sp<SkData> serialize(const SkSerialProcs&) const; 78 sk_sp<SkData> serialize() const; 79 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkDeserialProcs&); 80 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size); 81 82private: 83 friend class SkNVRefCnt<SkTextBlob>; 84 class RunRecord; 85 86 explicit SkTextBlob(const SkRect& bounds); 87 88 ~SkTextBlob(); 89 90 // Memory for objects of this class is created with sk_malloc rather than operator new and must 91 // be freed with sk_free. 92 void operator delete(void* p) { sk_free(p); } 93 void* operator new(size_t) { 94 SK_ABORT("All blobs are created by placement new."); 95 return sk_malloc_throw(0); 96 } 97 void* operator new(size_t, void* p) { return p; } 98 99 static unsigned ScalarsPerGlyph(GlyphPositioning pos); 100 101 // Call when this blob is part of the key to a cache entry. This allows the cache 102 // to know automatically those entries can be purged when this SkTextBlob is deleted. 103 void notifyAddedToCache(uint32_t cacheID) const { 104 fCacheID.store(cacheID); 105 } 106 107 friend class GrTextBlobCache; 108 friend class SkTextBlobBuilder; 109 friend class SkTextBlobRunIterator; 110 111 const SkRect fBounds; 112 const uint32_t fUniqueID; 113 mutable SkAtomic<uint32_t> fCacheID; 114 115 SkDEBUGCODE(size_t fStorageSize;) 116 117 // The actual payload resides in externally-managed storage, following the object. 118 // (see the .cpp for more details) 119 120 typedef SkRefCnt INHERITED; 121}; 122 123/** \class SkTextBlobBuilder 124 125 Helper class for constructing SkTextBlobs. 126 */ 127class SK_API SkTextBlobBuilder { 128public: 129 SkTextBlobBuilder(); 130 131 ~SkTextBlobBuilder(); 132 133 /** 134 * Returns an immutable SkTextBlob for the current runs/glyphs, 135 * or nullptr if no runs were allocated. 136 * 137 * The builder is reset and can be reused. 138 */ 139 sk_sp<SkTextBlob> make(); 140 141 /** 142 * Glyph and position buffers associated with a run. 143 * 144 * A run is a sequence of glyphs sharing the same font metrics 145 * and positioning mode. 146 * 147 * If textByteCount is 0, utf8text and clusters will be NULL (no 148 * character information will be associated with the glyphs). 149 * 150 * utf8text will point to a buffer of size textByteCount bytes. 151 * 152 * clusters (if not NULL) will point to an array of size count. 153 * For each glyph, give the byte-offset into the text for the 154 * first byte in the first character in that glyph's cluster. 155 * Each value in the array should be an integer less than 156 * textByteCount. Values in the array should either be 157 * monotonically increasing (left-to-right text) or monotonically 158 * decreasing (right-to-left text). This definiton is conviently 159 * the same as used by Harfbuzz's hb_glyph_info_t::cluster field, 160 * except that Harfbuzz interleaves glyphs and clusters. 161 */ 162 struct RunBuffer { 163 SkGlyphID* glyphs; 164 SkScalar* pos; 165 char* utf8text; 166 uint32_t* clusters; 167 }; 168 169 /** 170 * Allocates a new default-positioned run and returns its writable glyph buffer 171 * for direct manipulation. 172 * 173 * @param font The font to be used for this run. 174 * @param count Number of glyphs. 175 * @param x,y Position within the blob. 176 * @param textByteCount length of the original UTF-8 text that 177 * corresponds to this sequence of glyphs. If 0, 178 * text will not be included in the textblob. 179 * @param lang Language code, currently unimplemented. 180 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will 181 * be used when computing the blob bounds, to avoid re-measuring. 182 * 183 * @return A writable glyph buffer, valid until the next allocRun() or 184 * build() call. The buffer is guaranteed to hold @count@ glyphs. 185 */ 186 const RunBuffer& allocRunText(const SkPaint& font, 187 int count, 188 SkScalar x, 189 SkScalar y, 190 int textByteCount, 191 SkString lang, 192 const SkRect* bounds = nullptr); 193 const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y, 194 const SkRect* bounds = nullptr) { 195 return this->allocRunText(font, count, x, y, 0, SkString(), bounds); 196 } 197 198 /** 199 * Allocates a new horizontally-positioned run and returns its writable glyph and position 200 * buffers for direct manipulation. 201 * 202 * @param font The font to be used for this run. 203 * @param count Number of glyphs. 204 * @param y Vertical offset within the blob. 205 * @param textByteCount length of the original UTF-8 text that 206 * corresponds to this sequence of glyphs. If 0, 207 * text will not be included in the textblob. 208 * @param lang Language code, currently unimplemented. 209 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will 210 * be used when computing the blob bounds, to avoid re-measuring. 211 * 212 * @return Writable glyph and position buffers, valid until the next allocRun() 213 * or build() call. The buffers are guaranteed to hold @count@ elements. 214 */ 215 const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y, 216 int textByteCount, SkString lang, 217 const SkRect* bounds = nullptr); 218 const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y, 219 const SkRect* bounds = nullptr) { 220 return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds); 221 } 222 223 /** 224 * Allocates a new fully-positioned run and returns its writable glyph and position 225 * buffers for direct manipulation. 226 * 227 * @param font The font to be used for this run. 228 * @param count Number of glyphs. 229 * @param textByteCount length of the original UTF-8 text that 230 * corresponds to this sequence of glyphs. If 0, 231 * text will not be included in the textblob. 232 * @param lang Language code, currently unimplemented. 233 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will 234 * be used when computing the blob bounds, to avoid re-measuring. 235 * 236 * @return Writable glyph and position buffers, valid until the next allocRun() 237 * or build() call. The glyph buffer and position buffer are 238 * guaranteed to hold @count@ and 2 * @count@ elements, respectively. 239 */ 240 const RunBuffer& allocRunTextPos(const SkPaint& font, int count, 241 int textByteCount, SkString lang, 242 const SkRect* bounds = nullptr); 243 const RunBuffer& allocRunPos(const SkPaint& font, int count, 244 const SkRect* bounds = nullptr) { 245 return this->allocRunTextPos(font, count, 0, SkString(), bounds); 246 } 247 248private: 249 void reserve(size_t size); 250 void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, 251 int count, int textBytes, SkPoint offset, const SkRect* bounds); 252 bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, 253 uint32_t count, SkPoint offset); 254 void updateDeferredBounds(); 255 256 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); 257 static SkRect TightRunBounds(const SkTextBlob::RunRecord&); 258 259 SkAutoTMalloc<uint8_t> fStorage; 260 size_t fStorageSize; 261 size_t fStorageUsed; 262 263 SkRect fBounds; 264 int fRunCount; 265 bool fDeferredBounds; 266 size_t fLastRun; // index into fStorage 267 268 RunBuffer fCurrentRunBuffer; 269}; 270 271#endif // SkTextBlob_DEFINED 272