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