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