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 "include/core/SkFont.h" 12 #include "include/core/SkFontTypes.h" 13 #include "include/core/SkRect.h" 14 #include "include/core/SkRefCnt.h" 15 #include "include/core/SkScalar.h" 16 #include "include/core/SkTypes.h" 17 #include "include/private/base/SkDebug.h" 18 #include "include/private/base/SkTemplates.h" 19 20 #include <atomic> 21 #include <cstdint> 22 #include <cstring> 23 24 class SkData; 25 class SkPaint; 26 class SkTypeface; 27 struct SkDeserialProcs; 28 struct SkPoint; 29 struct SkRSXform; 30 struct SkSerialProcs; 31 32 namespace sktext { 33 class GlyphRunList; 34 } 35 36 /** \class SkTextBlob 37 SkTextBlob combines multiple text runs into an immutable container. Each text 38 run consists of glyphs, SkPaint, and position. Only parts of SkPaint related to 39 fonts and text rendering are used by run. 40 */ 41 class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> { 42 private: 43 class RunRecord; 44 45 public: 46 47 /** Returns conservative bounding box. Uses SkPaint associated with each glyph to 48 determine glyph bounds, and unions all bounds. Returned bounds may be 49 larger than the bounds of all glyphs in runs. 50 51 @return conservative bounding box 52 */ bounds()53 const SkRect& bounds() const { return fBounds; } 54 55 /** Returns a non-zero value unique among all text blobs. 56 57 @return identifier for SkTextBlob 58 */ uniqueID()59 uint32_t uniqueID() const { return fUniqueID; } 60 61 /** Returns the number of intervals that intersect bounds. 62 bounds describes a pair of lines parallel to the text advance. 63 The return count is zero or a multiple of two, and is at most twice the number of glyphs in 64 the the blob. 65 66 Pass nullptr for intervals to determine the size of the interval array. 67 68 Runs within the blob that contain SkRSXform are ignored when computing intercepts. 69 70 @param bounds lower and upper line parallel to the advance 71 @param intervals returned intersections; may be nullptr 72 @param paint specifies stroking, SkPathEffect that affects the result; may be nullptr 73 @return number of intersections; may be zero 74 */ 75 int getIntercepts(const SkScalar bounds[2], SkScalar intervals[], 76 const SkPaint* paint = nullptr) const; 77 78 /** Creates SkTextBlob with a single run. 79 80 font contains attributes used to define the run text. 81 82 When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or 83 SkTextEncoding::kUTF32, this function uses the default 84 character-to-glyph mapping from the SkTypeface in font. It does not 85 perform typeface fallback for characters not found in the SkTypeface. 86 It does not perform kerning or other complex shaping; glyphs are 87 positioned based on their default advances. 88 89 @param text character code points or glyphs drawn 90 @param byteLength byte length of text array 91 @param font text size, typeface, text scale, and so on, used to draw 92 @param encoding text encoding used in the text array 93 @return SkTextBlob constructed from one run 94 */ 95 static sk_sp<SkTextBlob> MakeFromText(const void* text, size_t byteLength, const SkFont& font, 96 SkTextEncoding encoding = SkTextEncoding::kUTF8); 97 98 /** Creates SkTextBlob with a single run. string meaning depends on SkTextEncoding; 99 by default, string is encoded as UTF-8. 100 101 font contains attributes used to define the run text. 102 103 When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or 104 SkTextEncoding::kUTF32, this function uses the default 105 character-to-glyph mapping from the SkTypeface in font. It does not 106 perform typeface fallback for characters not found in the SkTypeface. 107 It does not perform kerning or other complex shaping; glyphs are 108 positioned based on their default advances. 109 110 @param string character code points or glyphs drawn 111 @param font text size, typeface, text scale, and so on, used to draw 112 @param encoding text encoding used in the text array 113 @return SkTextBlob constructed from one run 114 */ 115 static sk_sp<SkTextBlob> MakeFromString(const char* string, const SkFont& font, 116 SkTextEncoding encoding = SkTextEncoding::kUTF8) { 117 if (!string) { 118 return nullptr; 119 } 120 return MakeFromText(string, strlen(string), font, encoding); 121 } 122 123 /** Returns a textblob built from a single run of text with x-positions and a single y value. 124 This is equivalent to using SkTextBlobBuilder and calling allocRunPosH(). 125 Returns nullptr if byteLength is zero. 126 127 @param text character code points or glyphs drawn (based on encoding) 128 @param byteLength byte length of text array 129 @param xpos array of x-positions, must contain values for all of the character points. 130 @param constY shared y-position for each character point, to be paired with each xpos. 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> MakeFromPosTextH(const void* text, size_t byteLength, 136 const SkScalar xpos[], SkScalar constY, const SkFont& font, 137 SkTextEncoding encoding = SkTextEncoding::kUTF8); 138 139 /** Returns a textblob built from a single run of text with positions. 140 This is equivalent to using SkTextBlobBuilder and calling allocRunPos(). 141 Returns nullptr if byteLength is zero. 142 143 @param text character code points or glyphs drawn (based on encoding) 144 @param byteLength byte length of text array 145 @param pos array of positions, must contain values for all of the character points. 146 @param font SkFont used for this run 147 @param encoding specifies the encoding of the text array. 148 @return new textblob or nullptr 149 */ 150 static sk_sp<SkTextBlob> MakeFromPosText(const void* text, size_t byteLength, 151 const SkPoint pos[], const SkFont& font, 152 SkTextEncoding encoding = SkTextEncoding::kUTF8); 153 154 static sk_sp<SkTextBlob> MakeFromRSXform(const void* text, size_t byteLength, 155 const SkRSXform xform[], const SkFont& font, 156 SkTextEncoding encoding = SkTextEncoding::kUTF8); 157 158 /** Writes data to allow later reconstruction of SkTextBlob. memory points to storage 159 to receive the encoded data, and memory_size describes the size of storage. 160 Returns bytes used if provided storage is large enough to hold all data; 161 otherwise, returns zero. 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 @param memory storage for data 170 @param memory_size size of storage 171 @return bytes written, or zero if required storage is larger than memory_size 172 173 example: https://fiddle.skia.org/c/@TextBlob_serialize 174 */ 175 size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const; 176 177 /** Returns storage containing SkData describing SkTextBlob, using optional custom 178 encoders. 179 180 procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. 181 If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx 182 may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc 183 is called with a pointer to SkTypeface and user context. 184 185 @param procs custom serial data encoders; may be nullptr 186 @return storage containing serialized SkTextBlob 187 188 example: https://fiddle.skia.org/c/@TextBlob_serialize_2 189 */ 190 sk_sp<SkData> serialize(const SkSerialProcs& procs) const; 191 192 /** Recreates SkTextBlob that was serialized into data. Returns constructed SkTextBlob 193 if successful; otherwise, returns nullptr. Fails if size is smaller than 194 required data length, or if data does not permit constructing valid SkTextBlob. 195 196 procs.fTypefaceProc permits supplying a custom function to decode SkTypeface. 197 If procs.fTypefaceProc is nullptr, default decoding is used. procs.fTypefaceCtx 198 may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc 199 is called with a pointer to SkTypeface data, data byte length, and user context. 200 201 @param data pointer for serial data 202 @param size size of data 203 @param procs custom serial data decoders; may be nullptr 204 @return SkTextBlob constructed from data in memory 205 */ 206 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, 207 const SkDeserialProcs& procs); 208 209 class SK_API Iter { 210 public: 211 struct Run { 212 SkTypeface* fTypeface; 213 int fGlyphCount; 214 const uint16_t* fGlyphIndices; 215 #ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED 216 const uint32_t* fClusterIndex_forTest; 217 int fUtf8Size_forTest; 218 const char* fUtf8_forTest; 219 #endif 220 }; 221 222 Iter(const SkTextBlob&); 223 224 /** 225 * Returns true for each "run" inside the textblob, setting the Run fields (if not null). 226 * If this returns false, there are no more runs, and the Run parameter will be ignored. 227 */ 228 bool next(Run*); 229 230 // Experimental, DO NO USE, will change/go-away 231 struct ExperimentalRun { 232 SkFont font; 233 int count; 234 const uint16_t* glyphs; 235 const SkPoint* positions; 236 }; 237 bool experimentalNext(ExperimentalRun*); 238 239 private: 240 const RunRecord* fRunRecord; 241 }; 242 243 private: 244 friend class SkNVRefCnt<SkTextBlob>; 245 246 enum GlyphPositioning : uint8_t; 247 248 explicit SkTextBlob(const SkRect& bounds); 249 250 ~SkTextBlob(); 251 252 // Memory for objects of this class is created with sk_malloc rather than operator new and must 253 // be freed with sk_free. 254 void operator delete(void* p); 255 void* operator new(size_t); 256 void* operator new(size_t, void* p); 257 258 static unsigned ScalarsPerGlyph(GlyphPositioning pos); 259 260 using PurgeDelegate = void (*)(uint32_t blobID, uint32_t cacheID); 261 262 // Call when this blob is part of the key to a cache entry. This allows the cache 263 // to know automatically those entries can be purged when this SkTextBlob is deleted. notifyAddedToCache(uint32_t cacheID,PurgeDelegate purgeDelegate)264 void notifyAddedToCache(uint32_t cacheID, PurgeDelegate purgeDelegate) const { 265 fCacheID.store(cacheID); 266 fPurgeDelegate.store(purgeDelegate); 267 } 268 269 friend class sktext::GlyphRunList; 270 friend class SkTextBlobBuilder; 271 friend class SkTextBlobPriv; 272 friend class SkTextBlobRunIterator; 273 274 const SkRect fBounds; 275 const uint32_t fUniqueID; 276 mutable std::atomic<uint32_t> fCacheID; 277 mutable std::atomic<PurgeDelegate> fPurgeDelegate; 278 279 SkDEBUGCODE(size_t fStorageSize;) 280 281 // The actual payload resides in externally-managed storage, following the object. 282 // (see the .cpp for more details) 283 284 using INHERITED = SkRefCnt; 285 }; 286 287 /** \class SkTextBlobBuilder 288 Helper class for constructing SkTextBlob. 289 */ 290 class SK_API SkTextBlobBuilder { 291 public: 292 293 /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs. 294 295 @return empty SkTextBlobBuilder 296 297 example: https://fiddle.skia.org/c/@TextBlobBuilder_empty_constructor 298 */ 299 SkTextBlobBuilder(); 300 301 /** Deletes data allocated internally by SkTextBlobBuilder. 302 */ 303 ~SkTextBlobBuilder(); 304 305 /** Returns SkTextBlob built from runs of glyphs added by builder. Returned 306 SkTextBlob is immutable; it may be copied, but its contents may not be altered. 307 Returns nullptr if no runs of glyphs were added by builder. 308 309 Resets SkTextBlobBuilder to its initial empty state, allowing it to be 310 reused to build a new set of runs. 311 312 @return SkTextBlob or nullptr 313 314 example: https://fiddle.skia.org/c/@TextBlobBuilder_make 315 */ 316 sk_sp<SkTextBlob> make(); 317 318 /** \struct SkTextBlobBuilder::RunBuffer 319 RunBuffer supplies storage for glyphs and positions within a run. 320 321 A run is a sequence of glyphs sharing font metrics and positioning. 322 Each run may position its glyphs in one of three ways: 323 by specifying where the first glyph is drawn, and allowing font metrics to 324 determine the advance to subsequent glyphs; by specifying a baseline, and 325 the position on that baseline for each glyph in run; or by providing SkPoint 326 array, one per glyph. 327 */ 328 struct RunBuffer { 329 SkGlyphID* glyphs; //!< storage for glyph indexes in run 330 SkScalar* pos; //!< storage for glyph positions in run 331 char* utf8text; //!< storage for text UTF-8 code units in run 332 uint32_t* clusters; //!< storage for glyph clusters (index of UTF-8 code unit) 333 334 // Helpers, since the "pos" field can be different types (always some number of floats). pointsRunBuffer335 SkPoint* points() const { return reinterpret_cast<SkPoint*>(pos); } xformsRunBuffer336 SkRSXform* xforms() const { return reinterpret_cast<SkRSXform*>(pos); } 337 }; 338 339 /** Returns run with storage for glyphs. Caller must write count glyphs to 340 RunBuffer::glyphs before next call to SkTextBlobBuilder. 341 342 RunBuffer::pos, RunBuffer::utf8text, and RunBuffer::clusters should be ignored. 343 344 Glyphs share metrics in font. 345 346 Glyphs are positioned on a baseline at (x, y), using font metrics to 347 determine their relative placement. 348 349 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 350 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 351 is computed from (x, y) and RunBuffer::glyphs metrics. 352 353 @param font SkFont used for this run 354 @param count number of glyphs 355 @param x horizontal offset within the blob 356 @param y vertical offset within the blob 357 @param bounds optional run bounding box 358 @return writable glyph buffer 359 */ 360 const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, 361 const SkRect* bounds = nullptr); 362 363 /** Returns run with storage for glyphs and positions along baseline. Caller must 364 write count glyphs to RunBuffer::glyphs and count scalars to RunBuffer::pos 365 before next call to SkTextBlobBuilder. 366 367 RunBuffer::utf8text and RunBuffer::clusters should be ignored. 368 369 Glyphs share metrics in font. 370 371 Glyphs are positioned on a baseline at y, using x-axis positions written by 372 caller to RunBuffer::pos. 373 374 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 375 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 376 is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. 377 378 @param font SkFont used for this run 379 @param count number of glyphs 380 @param y vertical offset within the blob 381 @param bounds optional run bounding box 382 @return writable glyph buffer and x-axis position buffer 383 */ 384 const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y, 385 const SkRect* bounds = nullptr); 386 387 /** Returns run with storage for glyphs and SkPoint positions. Caller must 388 write count glyphs to RunBuffer::glyphs and count SkPoint to RunBuffer::pos 389 before next call to SkTextBlobBuilder. 390 391 RunBuffer::utf8text and RunBuffer::clusters should be ignored. 392 393 Glyphs share metrics in font. 394 395 Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using 396 two scalar values for each SkPoint. 397 398 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 399 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 400 is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. 401 402 @param font SkFont used for this run 403 @param count number of glyphs 404 @param bounds optional run bounding box 405 @return writable glyph buffer and SkPoint buffer 406 */ 407 const RunBuffer& allocRunPos(const SkFont& font, int count, 408 const SkRect* bounds = nullptr); 409 410 // RunBuffer.pos points to SkRSXform array 411 const RunBuffer& allocRunRSXform(const SkFont& font, int count); 412 413 /** Returns run with storage for glyphs, text, and clusters. Caller must 414 write count glyphs to RunBuffer::glyphs, textByteCount UTF-8 code units 415 into RunBuffer::utf8text, and count monotonic indexes into utf8text 416 into RunBuffer::clusters before next call to SkTextBlobBuilder. 417 418 RunBuffer::pos should be ignored. 419 420 Glyphs share metrics in font. 421 422 Glyphs are positioned on a baseline at (x, y), using font metrics to 423 determine their relative placement. 424 425 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 426 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 427 is computed from (x, y) and RunBuffer::glyphs metrics. 428 429 @param font SkFont used for this run 430 @param count number of glyphs 431 @param x horizontal offset within the blob 432 @param y vertical offset within the blob 433 @param textByteCount number of UTF-8 code units 434 @param bounds optional run bounding box 435 @return writable glyph buffer, text buffer, and cluster buffer 436 */ 437 const RunBuffer& allocRunText(const SkFont& font, int count, SkScalar x, SkScalar y, 438 int textByteCount, const SkRect* bounds = nullptr); 439 440 /** Returns run with storage for glyphs, positions along baseline, text, 441 and clusters. Caller must write count glyphs to RunBuffer::glyphs, 442 count scalars to RunBuffer::pos, textByteCount UTF-8 code units into 443 RunBuffer::utf8text, and count monotonic indexes into utf8text into 444 RunBuffer::clusters before next call to SkTextBlobBuilder. 445 446 Glyphs share metrics in font. 447 448 Glyphs are positioned on a baseline at y, using x-axis positions written by 449 caller to RunBuffer::pos. 450 451 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 452 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 453 is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. 454 455 @param font SkFont used for this run 456 @param count number of glyphs 457 @param y vertical offset within the blob 458 @param textByteCount number of UTF-8 code units 459 @param bounds optional run bounding box 460 @return writable glyph buffer, x-axis position buffer, text buffer, and cluster buffer 461 */ 462 const RunBuffer& allocRunTextPosH(const SkFont& font, int count, SkScalar y, int textByteCount, 463 const SkRect* bounds = nullptr); 464 465 /** Returns run with storage for glyphs, SkPoint positions, text, and 466 clusters. Caller must write count glyphs to RunBuffer::glyphs, count 467 SkPoint to RunBuffer::pos, textByteCount UTF-8 code units into 468 RunBuffer::utf8text, and count monotonic indexes into utf8text into 469 RunBuffer::clusters before next call to SkTextBlobBuilder. 470 471 Glyphs share metrics in font. 472 473 Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using 474 two scalar values for each SkPoint. 475 476 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 477 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 478 is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. 479 480 @param font SkFont used for this run 481 @param count number of glyphs 482 @param textByteCount number of UTF-8 code units 483 @param bounds optional run bounding box 484 @return writable glyph buffer, SkPoint buffer, text buffer, and cluster buffer 485 */ 486 const RunBuffer& allocRunTextPos(const SkFont& font, int count, int textByteCount, 487 const SkRect* bounds = nullptr); 488 489 // RunBuffer.pos points to SkRSXform array 490 const RunBuffer& allocRunTextRSXform(const SkFont& font, int count, int textByteCount, 491 const SkRect* bounds = nullptr); 492 493 private: 494 void reserve(size_t size); 495 void allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning, 496 int count, int textBytes, SkPoint offset, const SkRect* bounds); 497 bool mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning, 498 uint32_t count, SkPoint offset); 499 void updateDeferredBounds(); 500 501 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); 502 static SkRect TightRunBounds(const SkTextBlob::RunRecord&); 503 504 friend class SkTextBlobPriv; 505 friend class SkTextBlobBuilderPriv; 506 507 skia_private::AutoTMalloc<uint8_t> fStorage; 508 size_t fStorageSize; 509 size_t fStorageUsed; 510 511 SkRect fBounds; 512 int fRunCount; 513 bool fDeferredBounds; 514 size_t fLastRun; // index into fStorage 515 516 RunBuffer fCurrentRunBuffer; 517 }; 518 519 #endif // SkTextBlob_DEFINED 520