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