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