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 | */ |
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 | */ |
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. |
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). |
305 | SkPoint* points() const { return reinterpret_cast<SkPoint*>(pos); } |
306 | 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 | |