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 <string> 12 #include "include/core/SkFont.h" 13 #include "include/core/SkPaint.h" 14 #include "include/core/SkRefCnt.h" 15 #include "include/core/SkString.h" 16 #include "include/private/SkTemplates.h" 17 18 #include <atomic> 19 20 struct SkRSXform; 21 struct SkSerialProcs; 22 struct SkDeserialProcs; 23 24 /** \class SkTextBlob 25 SkTextBlob combines multiple text runs into an immutable container. Each text 26 run consists of glyphs, SkPaint, and position. Only parts of SkPaint related to 27 fonts and text rendering are used by run. 28 */ 29 class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> { 30 public: 31 32 /** Returns conservative bounding box. Uses SkPaint associated with each glyph to 33 determine glyph bounds, and unions all bounds. Returned bounds may be 34 larger than the bounds of all glyphs in runs. 35 36 @return conservative bounding box 37 */ bounds()38 const SkRect& bounds() const { return fBounds; } 39 40 /** Returns a non-zero value unique among all text blobs. 41 42 @return identifier for SkTextBlob 43 */ uniqueID()44 uint32_t uniqueID() const { return fUniqueID; } 45 46 /** Returns the number of intervals that intersect bounds. 47 bounds describes a pair of lines parallel to the text advance. 48 The return count is zero or a multiple of two, and is at most twice the number of glyphs in 49 the the blob. 50 51 Pass nullptr for intervals to determine the size of the interval array. 52 53 Runs within the blob that contain SkRSXform are ignored when computing intercepts. 54 55 @param bounds lower and upper line parallel to the advance 56 @param intervals returned intersections; may be nullptr 57 @param paint specifies stroking, SkPathEffect that affects the result; may be nullptr 58 @return number of intersections; may be zero 59 */ 60 int getIntercepts(const SkScalar bounds[2], SkScalar intervals[], 61 const SkPaint* paint = nullptr) const; 62 63 /** Creates SkTextBlob with a single run. 64 65 font contains attributes used to define the run text. 66 67 When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or 68 SkTextEncoding::kUTF32, this function uses the default 69 character-to-glyph mapping from the SkTypeface in font. It does not 70 perform typeface fallback for characters not found in the SkTypeface. 71 It does not perform kerning or other complex shaping; glyphs are 72 positioned based on their default advances. 73 74 @param text character code points or glyphs drawn 75 @param byteLength byte length of text array 76 @param font text size, typeface, text scale, and so on, used to draw 77 @param encoding text encoding used in the text array 78 @return SkTextBlob constructed from one run 79 */ 80 static sk_sp<SkTextBlob> MakeFromText(const void* text, size_t byteLength, const SkFont& font, 81 SkTextEncoding encoding = SkTextEncoding::kUTF8); 82 83 /** Creates SkTextBlob with a single run. string meaning depends on SkTextEncoding; 84 by default, string is encoded as UTF-8. 85 86 font contains attributes used to define the run text. 87 88 When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or 89 SkTextEncoding::kUTF32, this function uses the default 90 character-to-glyph mapping from the SkTypeface in font. It does not 91 perform typeface fallback for characters not found in the SkTypeface. 92 It does not perform kerning or other complex shaping; glyphs are 93 positioned based on their default advances. 94 95 @param string character code points or glyphs drawn 96 @param font text size, typeface, text scale, and so on, used to draw 97 @param encoding text encoding used in the text array 98 @return SkTextBlob constructed from one run 99 */ 100 static sk_sp<SkTextBlob> MakeFromString(const char* string, const SkFont& font, 101 SkTextEncoding encoding = SkTextEncoding::kUTF8) { 102 if (!string) { 103 return nullptr; 104 } 105 return MakeFromText(string, strlen(string), font, encoding); 106 } 107 108 /** Returns a textblob built from a single run of text with x-positions and a single y value. 109 This is equivalent to using SkTextBlobBuilder and calling allocRunPosH(). 110 Returns nullptr if byteLength is zero. 111 112 @param text character code points or glyphs drawn (based on encoding) 113 @param byteLength byte length of text array 114 @param xpos array of x-positions, must contain values for all of the character points. 115 @param constY shared y-position for each character point, to be paired with each xpos. 116 @param font SkFont used for this run 117 @param encoding specifies the encoding of the text array. 118 @return new textblob or nullptr 119 */ 120 static sk_sp<SkTextBlob> MakeFromPosTextH(const void* text, size_t byteLength, 121 const SkScalar xpos[], SkScalar constY, const SkFont& font, 122 SkTextEncoding encoding = SkTextEncoding::kUTF8); 123 124 /** Returns a textblob built from a single run of text with positions. 125 This is equivalent to using SkTextBlobBuilder and calling allocRunPos(). 126 Returns nullptr if byteLength is zero. 127 128 @param text character code points or glyphs drawn (based on encoding) 129 @param byteLength byte length of text array 130 @param pos array of positions, must contain values for all of the character points. 131 @param font SkFont used for this run 132 @param encoding specifies the encoding of the text array. 133 @return new textblob or nullptr 134 */ 135 static sk_sp<SkTextBlob> MakeFromPosText(const void* text, size_t byteLength, 136 const SkPoint pos[], const SkFont& font, 137 SkTextEncoding encoding = SkTextEncoding::kUTF8); 138 139 static sk_sp<SkTextBlob> MakeFromRSXform(const void* text, size_t byteLength, 140 const SkRSXform xform[], const SkFont& font, 141 SkTextEncoding encoding = SkTextEncoding::kUTF8); 142 143 /** Writes data to allow later reconstruction of SkTextBlob. memory points to storage 144 to receive the encoded data, and memory_size describes the size of storage. 145 Returns bytes used if provided storage is large enough to hold all data; 146 otherwise, returns zero. 147 148 procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. 149 If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx 150 may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc 151 is called with a pointer to SkTypeface and user context. 152 153 @param procs custom serial data encoders; may be nullptr 154 @param memory storage for data 155 @param memory_size size of storage 156 @return bytes written, or zero if required storage is larger than memory_size 157 */ 158 size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const; 159 160 /** Returns storage containing SkData describing SkTextBlob, using optional custom 161 encoders. 162 163 procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. 164 If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx 165 may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc 166 is called with a pointer to SkTypeface and user context. 167 168 @param procs custom serial data encoders; may be nullptr 169 @return storage containing serialized SkTextBlob 170 */ 171 sk_sp<SkData> serialize(const SkSerialProcs& procs) const; 172 173 /** Recreates SkTextBlob that was serialized into data. Returns constructed SkTextBlob 174 if successful; otherwise, returns nullptr. Fails if size is smaller than 175 required data length, or if data does not permit constructing valid SkTextBlob. 176 177 procs.fTypefaceProc permits supplying a custom function to decode SkTypeface. 178 If procs.fTypefaceProc is nullptr, default decoding is used. procs.fTypefaceCtx 179 may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc 180 is called with a pointer to SkTypeface data, data byte length, and user context. 181 182 @param data pointer for serial data 183 @param size size of data 184 @param procs custom serial data decoders; may be nullptr 185 @return SkTextBlob constructed from data in memory 186 */ 187 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, 188 const SkDeserialProcs& procs); 189 190 void dump(std::string &desc, int depth) const; 191 192 private: 193 friend class SkNVRefCnt<SkTextBlob>; 194 class RunRecord; 195 196 enum GlyphPositioning : uint8_t; 197 198 explicit SkTextBlob(const SkRect& bounds); 199 200 ~SkTextBlob(); 201 202 // Memory for objects of this class is created with sk_malloc rather than operator new and must 203 // be freed with sk_free. 204 void operator delete(void* p); 205 void* operator new(size_t); 206 void* operator new(size_t, void* p); 207 208 static unsigned ScalarsPerGlyph(GlyphPositioning pos); 209 210 // Call when this blob is part of the key to a cache entry. This allows the cache 211 // to know automatically those entries can be purged when this SkTextBlob is deleted. notifyAddedToCache(uint32_t cacheID)212 void notifyAddedToCache(uint32_t cacheID) const { 213 fCacheID.store(cacheID); 214 } 215 216 friend class SkGlyphRunList; 217 friend class GrTextBlobCache; 218 friend class SkTextBlobBuilder; 219 friend class SkTextBlobPriv; 220 friend class SkTextBlobRunIterator; 221 222 const SkRect fBounds; 223 const uint32_t fUniqueID; 224 mutable std::atomic<uint32_t> fCacheID; 225 226 SkDEBUGCODE(size_t fStorageSize;) 227 228 // The actual payload resides in externally-managed storage, following the object. 229 // (see the .cpp for more details) 230 231 typedef SkRefCnt INHERITED; 232 }; 233 234 /** \class SkTextBlobBuilder 235 Helper class for constructing SkTextBlob. 236 */ 237 class SK_API SkTextBlobBuilder { 238 public: 239 240 /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs. 241 242 @return empty SkTextBlobBuilder 243 */ 244 SkTextBlobBuilder(); 245 246 /** Deletes data allocated internally by SkTextBlobBuilder. 247 */ 248 ~SkTextBlobBuilder(); 249 250 /** Returns SkTextBlob built from runs of glyphs added by builder. Returned 251 SkTextBlob is immutable; it may be copied, but its contents may not be altered. 252 Returns nullptr if no runs of glyphs were added by builder. 253 254 Resets SkTextBlobBuilder to its initial empty state, allowing it to be 255 reused to build a new set of runs. 256 257 @return SkTextBlob or nullptr 258 */ 259 sk_sp<SkTextBlob> make(); 260 261 /** \struct SkTextBlobBuilder::RunBuffer 262 RunBuffer supplies storage for glyphs and positions within a run. 263 264 A run is a sequence of glyphs sharing font metrics and positioning. 265 Each run may position its glyphs in one of three ways: 266 by specifying where the first glyph is drawn, and allowing font metrics to 267 determine the advance to subsequent glyphs; by specifying a baseline, and 268 the position on that baseline for each glyph in run; or by providing SkPoint 269 array, one per glyph. 270 */ 271 struct RunBuffer { 272 SkGlyphID* glyphs; //!< storage for glyphs in run 273 SkScalar* pos; //!< storage for positions in run 274 char* utf8text; //!< reserved for future use 275 uint32_t* clusters; //!< reserved for future use 276 277 // Helpers, since the "pos" field can be different types (always some number of floats). pointsRunBuffer278 SkPoint* points() const { return reinterpret_cast<SkPoint*>(pos); } xformsRunBuffer279 SkRSXform* xforms() const { return reinterpret_cast<SkRSXform*>(pos); } 280 }; 281 282 /** Returns run with storage for glyphs. Caller must write count glyphs to 283 RunBuffer::glyphs before next call to SkTextBlobBuilder. 284 285 RunBuffer::utf8text, and RunBuffer::clusters should be ignored. 286 287 Glyphs share metrics in font. 288 289 Glyphs are positioned on a baseline at (x, y), using font metrics to 290 determine their relative placement. 291 292 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 293 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 294 is computed from (x, y) and RunBuffer::glyphs metrics. 295 296 @param font SkFont used for this run 297 @param count number of glyphs 298 @param x horizontal offset within the blob 299 @param y vertical offset within the blob 300 @param bounds optional run bounding box 301 @return writable glyph buffer 302 */ 303 const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, 304 const SkRect* bounds = nullptr); 305 306 /** Returns run with storage for glyphs and positions along baseline. Caller must 307 write count glyphs to RunBuffer::glyphs, and count scalars to RunBuffer::pos; 308 before next call to SkTextBlobBuilder. 309 310 RunBuffer::utf8text, and RunBuffer::clusters should be ignored. 311 312 Glyphs share metrics in font. 313 314 Glyphs are positioned on a baseline at y, using x-axis positions written by 315 caller to RunBuffer::pos. 316 317 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 318 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 319 is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. 320 321 @param font SkFont used for this run 322 @param count number of glyphs 323 @param y vertical offset within the blob 324 @param bounds optional run bounding box 325 @return writable glyph buffer and x-axis position buffer 326 */ 327 const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y, 328 const SkRect* bounds = nullptr); 329 330 /** Returns run with storage for glyphs and SkPoint positions. Caller must 331 write count glyphs to RunBuffer::glyphs, and count SkPoint to RunBuffer::pos; 332 before next call to SkTextBlobBuilder. 333 334 RunBuffer::utf8text, and RunBuffer::clusters should be ignored. 335 336 Glyphs share metrics in font. 337 338 Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using 339 two scalar values for each SkPoint. 340 341 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 342 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 343 is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. 344 345 @param font SkFont used for this run 346 @param count number of glyphs 347 @param bounds optional run bounding box 348 @return writable glyph buffer and SkPoint buffer 349 */ 350 const RunBuffer& allocRunPos(const SkFont& font, int count, 351 const SkRect* bounds = nullptr); 352 353 // RunBuffer.pos points to SkRSXform array 354 const RunBuffer& allocRunRSXform(const SkFont& font, int count); 355 356 private: 357 const RunBuffer& allocRunText(const SkFont& font, 358 int count, 359 SkScalar x, 360 SkScalar y, 361 int textByteCount, 362 SkString lang, 363 const SkRect* bounds = nullptr); 364 const RunBuffer& allocRunTextPosH(const SkFont& font, int count, SkScalar y, 365 int textByteCount, SkString lang, 366 const SkRect* bounds = nullptr); 367 const RunBuffer& allocRunTextPos(const SkFont& font, int count, 368 int textByteCount, SkString lang, 369 const SkRect* bounds = nullptr); 370 const RunBuffer& allocRunRSXform(const SkFont& font, int count, 371 int textByteCount, SkString lang, 372 const SkRect* bounds = nullptr); 373 374 void reserve(size_t size); 375 void allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning, 376 int count, int textBytes, SkPoint offset, const SkRect* bounds); 377 bool mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning, 378 uint32_t count, SkPoint offset); 379 void updateDeferredBounds(); 380 381 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); 382 static SkRect TightRunBounds(const SkTextBlob::RunRecord&); 383 384 friend class SkTextBlobPriv; 385 friend class SkTextBlobBuilderPriv; 386 387 SkAutoTMalloc<uint8_t> fStorage; 388 size_t fStorageSize; 389 size_t fStorageUsed; 390 391 SkRect fBounds; 392 int fRunCount; 393 bool fDeferredBounds; 394 size_t fLastRun; // index into fStorage 395 396 RunBuffer fCurrentRunBuffer; 397 }; 398 399 #endif // SkTextBlob_DEFINED 400