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 }; 203 204 Iter(const SkTextBlob&); 205 206 /** 207 * Returns true for each "run" inside the textblob, setting the Run fields (if not null). 208 * If this returns false, there are no more runs, and the Run parameter will be ignored. 209 */ 210 bool next(Run*); 211 212 private: 213 const RunRecord* fRunRecord; 214 }; 215 216 private: 217 friend class SkNVRefCnt<SkTextBlob>; 218 219 enum GlyphPositioning : uint8_t; 220 221 explicit SkTextBlob(const SkRect& bounds); 222 223 ~SkTextBlob(); 224 225 // Memory for objects of this class is created with sk_malloc rather than operator new and must 226 // be freed with sk_free. 227 void operator delete(void* p); 228 void* operator new(size_t); 229 void* operator new(size_t, void* p); 230 231 static unsigned ScalarsPerGlyph(GlyphPositioning pos); 232 233 // Call when this blob is part of the key to a cache entry. This allows the cache 234 // to know automatically those entries can be purged when this SkTextBlob is deleted. notifyAddedToCache(uint32_t cacheID)235 void notifyAddedToCache(uint32_t cacheID) const { 236 fCacheID.store(cacheID); 237 } 238 239 friend class SkGlyphRunList; 240 friend class GrTextBlobCache; 241 friend class SkTextBlobBuilder; 242 friend class SkTextBlobPriv; 243 friend class SkTextBlobRunIterator; 244 245 const SkRect fBounds; 246 const uint32_t fUniqueID; 247 mutable std::atomic<uint32_t> fCacheID; 248 249 SkDEBUGCODE(size_t fStorageSize;) 250 251 // The actual payload resides in externally-managed storage, following the object. 252 // (see the .cpp for more details) 253 254 typedef SkRefCnt INHERITED; 255 }; 256 257 /** \class SkTextBlobBuilder 258 Helper class for constructing SkTextBlob. 259 */ 260 class SK_API SkTextBlobBuilder { 261 public: 262 263 /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs. 264 265 @return empty SkTextBlobBuilder 266 267 example: https://fiddle.skia.org/c/@TextBlobBuilder_empty_constructor 268 */ 269 SkTextBlobBuilder(); 270 271 /** Deletes data allocated internally by SkTextBlobBuilder. 272 */ 273 ~SkTextBlobBuilder(); 274 275 /** Returns SkTextBlob built from runs of glyphs added by builder. Returned 276 SkTextBlob is immutable; it may be copied, but its contents may not be altered. 277 Returns nullptr if no runs of glyphs were added by builder. 278 279 Resets SkTextBlobBuilder to its initial empty state, allowing it to be 280 reused to build a new set of runs. 281 282 @return SkTextBlob or nullptr 283 284 example: https://fiddle.skia.org/c/@TextBlobBuilder_make 285 */ 286 sk_sp<SkTextBlob> make(); 287 288 /** \struct SkTextBlobBuilder::RunBuffer 289 RunBuffer supplies storage for glyphs and positions within a run. 290 291 A run is a sequence of glyphs sharing font metrics and positioning. 292 Each run may position its glyphs in one of three ways: 293 by specifying where the first glyph is drawn, and allowing font metrics to 294 determine the advance to subsequent glyphs; by specifying a baseline, and 295 the position on that baseline for each glyph in run; or by providing SkPoint 296 array, one per glyph. 297 */ 298 struct RunBuffer { 299 SkGlyphID* glyphs; //!< storage for glyphs in run 300 SkScalar* pos; //!< storage for positions in run 301 char* utf8text; //!< reserved for future use 302 uint32_t* clusters; //!< reserved for future use 303 304 // Helpers, since the "pos" field can be different types (always some number of floats). pointsRunBuffer305 SkPoint* points() const { return reinterpret_cast<SkPoint*>(pos); } xformsRunBuffer306 SkRSXform* xforms() const { return reinterpret_cast<SkRSXform*>(pos); } 307 }; 308 309 /** Returns run with storage for glyphs. Caller must write count glyphs to 310 RunBuffer::glyphs before next call to SkTextBlobBuilder. 311 312 RunBuffer::utf8text, and RunBuffer::clusters should be ignored. 313 314 Glyphs share metrics in font. 315 316 Glyphs are positioned on a baseline at (x, y), using font metrics to 317 determine their relative placement. 318 319 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 320 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 321 is computed from (x, y) and RunBuffer::glyphs metrics. 322 323 @param font SkFont used for this run 324 @param count number of glyphs 325 @param x horizontal offset within the blob 326 @param y vertical offset within the blob 327 @param bounds optional run bounding box 328 @return writable glyph buffer 329 */ 330 const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, 331 const SkRect* bounds = nullptr); 332 333 /** Returns run with storage for glyphs and positions along baseline. Caller must 334 write count glyphs to RunBuffer::glyphs, and count scalars to RunBuffer::pos; 335 before next call to SkTextBlobBuilder. 336 337 RunBuffer::utf8text, and RunBuffer::clusters should be ignored. 338 339 Glyphs share metrics in font. 340 341 Glyphs are positioned on a baseline at y, using x-axis positions written by 342 caller to RunBuffer::pos. 343 344 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 345 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 346 is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. 347 348 @param font SkFont used for this run 349 @param count number of glyphs 350 @param y vertical offset within the blob 351 @param bounds optional run bounding box 352 @return writable glyph buffer and x-axis position buffer 353 */ 354 const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y, 355 const SkRect* bounds = nullptr); 356 357 /** Returns run with storage for glyphs and SkPoint positions. Caller must 358 write count glyphs to RunBuffer::glyphs, and count SkPoint to RunBuffer::pos; 359 before next call to SkTextBlobBuilder. 360 361 RunBuffer::utf8text, and RunBuffer::clusters should be ignored. 362 363 Glyphs share metrics in font. 364 365 Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using 366 two scalar values for each SkPoint. 367 368 bounds defines an optional bounding box, used to suppress drawing when SkTextBlob 369 bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds 370 is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. 371 372 @param font SkFont used for this run 373 @param count number of glyphs 374 @param bounds optional run bounding box 375 @return writable glyph buffer and SkPoint buffer 376 */ 377 const RunBuffer& allocRunPos(const SkFont& font, int count, 378 const SkRect* bounds = nullptr); 379 380 // RunBuffer.pos points to SkRSXform array 381 const RunBuffer& allocRunRSXform(const SkFont& font, int count); 382 383 private: 384 const RunBuffer& allocRunText(const SkFont& font, 385 int count, 386 SkScalar x, 387 SkScalar y, 388 int textByteCount, 389 SkString lang, 390 const SkRect* bounds = nullptr); 391 const RunBuffer& allocRunTextPosH(const SkFont& font, int count, SkScalar y, 392 int textByteCount, SkString lang, 393 const SkRect* bounds = nullptr); 394 const RunBuffer& allocRunTextPos(const SkFont& font, int count, 395 int textByteCount, SkString lang, 396 const SkRect* bounds = nullptr); 397 const RunBuffer& allocRunRSXform(const SkFont& font, int count, 398 int textByteCount, SkString lang, 399 const SkRect* bounds = nullptr); 400 401 void reserve(size_t size); 402 void allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning, 403 int count, int textBytes, SkPoint offset, const SkRect* bounds); 404 bool mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning, 405 uint32_t count, SkPoint offset); 406 void updateDeferredBounds(); 407 408 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); 409 static SkRect TightRunBounds(const SkTextBlob::RunRecord&); 410 411 friend class SkTextBlobPriv; 412 friend class SkTextBlobBuilderPriv; 413 414 SkAutoTMalloc<uint8_t> fStorage; 415 size_t fStorageSize; 416 size_t fStorageUsed; 417 418 SkRect fBounds; 419 int fRunCount; 420 bool fDeferredBounds; 421 size_t fLastRun; // index into fStorage 422 423 RunBuffer fCurrentRunBuffer; 424 }; 425 426 #endif // SkTextBlob_DEFINED 427