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