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