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