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
19struct SkRSXform;
20struct SkSerialProcs;
21struct 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*/
28class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
29private:
30 class RunRecord;
31
32public:
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
216private:
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*/
260class SK_API SkTextBlobBuilder {
261public:
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
383private:
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