• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <string>
19 
20 struct SkRSXform;
21 struct SkSerialProcs;
22 struct SkDeserialProcs;
23 
24 /** \class SkTextBlob
25     SkTextBlob combines multiple text runs into an immutable container. Each text
26     run consists of glyphs, SkPaint, and position. Only parts of SkPaint related to
27     fonts and text rendering are used by run.
28 */
29 class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
30 private:
31     class RunRecord;
32 
33 public:
34 
35     /** Returns conservative bounding box. Uses SkPaint associated with each glyph to
36         determine glyph bounds, and unions all bounds. Returned bounds may be
37         larger than the bounds of all glyphs in runs.
38 
39         @return  conservative bounding box
40     */
bounds()41     const SkRect& bounds() const { return fBounds; }
42 
43     /** Returns a non-zero value unique among all text blobs.
44 
45         @return  identifier for SkTextBlob
46     */
uniqueID()47     uint32_t uniqueID() const { return fUniqueID; }
48 
49     /** Returns the number of intervals that intersect bounds.
50         bounds describes a pair of lines parallel to the text advance.
51         The return count is zero or a multiple of two, and is at most twice the number of glyphs in
52         the the blob.
53 
54         Pass nullptr for intervals to determine the size of the interval array.
55 
56         Runs within the blob that contain SkRSXform are ignored when computing intercepts.
57 
58         @param bounds     lower and upper line parallel to the advance
59         @param intervals  returned intersections; may be nullptr
60         @param paint      specifies stroking, SkPathEffect that affects the result; may be nullptr
61         @return           number of intersections; may be zero
62      */
63     int getIntercepts(const SkScalar bounds[2], SkScalar intervals[],
64                       const SkPaint* paint = nullptr) const;
65 
66     /** Creates SkTextBlob with a single run.
67 
68         font contains attributes used to define the run text.
69 
70         When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or
71         SkTextEncoding::kUTF32, this function uses the default
72         character-to-glyph mapping from the SkTypeface in font.  It does not
73         perform typeface fallback for characters not found in the SkTypeface.
74         It does not perform kerning or other complex shaping; glyphs are
75         positioned based on their default advances.
76 
77         @param text        character code points or glyphs drawn
78         @param byteLength  byte length of text array
79         @param font        text size, typeface, text scale, and so on, used to draw
80         @param encoding    text encoding used in the text array
81         @return            SkTextBlob constructed from one run
82     */
83     static sk_sp<SkTextBlob> MakeFromText(const void* text, size_t byteLength, const SkFont& font,
84                                           SkTextEncoding encoding = SkTextEncoding::kUTF8);
85 
86     /** Creates SkTextBlob with a single run. string meaning depends on SkTextEncoding;
87         by default, string is encoded as UTF-8.
88 
89         font contains attributes used to define the run text.
90 
91         When encoding is SkTextEncoding::kUTF8, SkTextEncoding::kUTF16, or
92         SkTextEncoding::kUTF32, this function uses the default
93         character-to-glyph mapping from the SkTypeface in font.  It does not
94         perform typeface fallback for characters not found in the SkTypeface.
95         It does not perform kerning or other complex shaping; glyphs are
96         positioned based on their default advances.
97 
98         @param string   character code points or glyphs drawn
99         @param font     text size, typeface, text scale, and so on, used to draw
100         @param encoding text encoding used in the text array
101         @return         SkTextBlob constructed from one run
102     */
103     static sk_sp<SkTextBlob> MakeFromString(const char* string, const SkFont& font,
104                                             SkTextEncoding encoding = SkTextEncoding::kUTF8) {
105         if (!string) {
106             return nullptr;
107         }
108         return MakeFromText(string, strlen(string), font, encoding);
109     }
110 
111     /** Returns a textblob built from a single run of text with x-positions and a single y value.
112         This is equivalent to using SkTextBlobBuilder and calling allocRunPosH().
113         Returns nullptr if byteLength is zero.
114 
115         @param text        character code points or glyphs drawn (based on encoding)
116         @param byteLength  byte length of text array
117         @param xpos    array of x-positions, must contain values for all of the character points.
118         @param constY  shared y-position for each character point, to be paired with each xpos.
119         @param font    SkFont used for this run
120         @param encoding specifies the encoding of the text array.
121         @return        new textblob or nullptr
122      */
123     static sk_sp<SkTextBlob> MakeFromPosTextH(const void* text, size_t byteLength,
124                                       const SkScalar xpos[], SkScalar constY, const SkFont& font,
125                                       SkTextEncoding encoding = SkTextEncoding::kUTF8);
126 
127     /** Returns a textblob built from a single run of text with positions.
128         This is equivalent to using SkTextBlobBuilder and calling allocRunPos().
129         Returns nullptr if byteLength is zero.
130 
131         @param text        character code points or glyphs drawn (based on encoding)
132         @param byteLength  byte length of text array
133         @param pos     array of positions, must contain values for all of the character points.
134         @param font    SkFont used for this run
135         @param encoding specifies the encoding of the text array.
136         @return        new textblob or nullptr
137      */
138     static sk_sp<SkTextBlob> MakeFromPosText(const void* text, size_t byteLength,
139                                              const SkPoint pos[], const SkFont& font,
140                                              SkTextEncoding encoding = SkTextEncoding::kUTF8);
141 
142     static sk_sp<SkTextBlob> MakeFromRSXform(const void* text, size_t byteLength,
143                                              const SkRSXform xform[], const SkFont& font,
144                                              SkTextEncoding encoding = SkTextEncoding::kUTF8);
145 
146     /** Writes data to allow later reconstruction of SkTextBlob. memory points to storage
147         to receive the encoded data, and memory_size describes the size of storage.
148         Returns bytes used if provided storage is large enough to hold all data;
149         otherwise, returns zero.
150 
151         procs.fTypefaceProc permits supplying a custom function to encode SkTypeface.
152         If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx
153         may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc
154         is called with a pointer to SkTypeface and user context.
155 
156         @param procs       custom serial data encoders; may be nullptr
157         @param memory      storage for data
158         @param memory_size size of storage
159         @return            bytes written, or zero if required storage is larger than memory_size
160 
161         example: https://fiddle.skia.org/c/@TextBlob_serialize
162     */
163     size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const;
164 
165     /** Returns storage containing SkData describing SkTextBlob, using optional custom
166         encoders.
167 
168         procs.fTypefaceProc permits supplying a custom function to encode SkTypeface.
169         If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx
170         may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc
171         is called with a pointer to SkTypeface and user context.
172 
173         @param procs  custom serial data encoders; may be nullptr
174         @return       storage containing serialized SkTextBlob
175 
176         example: https://fiddle.skia.org/c/@TextBlob_serialize_2
177     */
178     sk_sp<SkData> serialize(const SkSerialProcs& procs) const;
179 
180     /** Recreates SkTextBlob that was serialized into data. Returns constructed SkTextBlob
181         if successful; otherwise, returns nullptr. Fails if size is smaller than
182         required data length, or if data does not permit constructing valid SkTextBlob.
183 
184         procs.fTypefaceProc permits supplying a custom function to decode SkTypeface.
185         If procs.fTypefaceProc is nullptr, default decoding is used. procs.fTypefaceCtx
186         may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc
187         is called with a pointer to SkTypeface data, data byte length, and user context.
188 
189         @param data   pointer for serial data
190         @param size   size of data
191         @param procs  custom serial data decoders; may be nullptr
192         @return       SkTextBlob constructed from data in memory
193     */
194     static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size,
195                                          const SkDeserialProcs& procs);
196 
197     class SK_API Iter {
198     public:
199         struct Run {
200             SkTypeface*     fTypeface;
201             int             fGlyphCount;
202             const uint16_t* fGlyphIndices;
203 #ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED
204             const uint32_t* fClusterIndex_forTest;
205             int             fUtf8Size_forTest;
206             const char*     fUtf8_forTest;
207 #endif
208         };
209 
210         Iter(const SkTextBlob&);
211 
212         /**
213          * Returns true for each "run" inside the textblob, setting the Run fields (if not null).
214          * If this returns false, there are no more runs, and the Run parameter will be ignored.
215          */
216         bool next(Run*);
217 
218         // Experimental, DO NO USE, will change/go-away
219         struct ExperimentalRun {
220             SkFont          font;
221             int             count;
222             const uint16_t* glyphs;
223             const SkPoint*  positions;
224         };
225         bool experimentalNext(ExperimentalRun*);
226 
227     private:
228         const RunRecord* fRunRecord;
229     };
230 
231     /** Writes text representation of SkTextBlob to string.
232 
233         @param desc     the string storing a description of parameters.
234         @param depth    the number of tabs preceding each line.
235     */
236     void dump(std::string& desc, int depth) const;
237 private:
238     friend class SkNVRefCnt<SkTextBlob>;
239 
240     enum GlyphPositioning : uint8_t;
241 
242     explicit SkTextBlob(const SkRect& bounds);
243 
244     ~SkTextBlob();
245 
246     // Memory for objects of this class is created with sk_malloc rather than operator new and must
247     // be freed with sk_free.
248     void operator delete(void* p);
249     void* operator new(size_t);
250     void* operator new(size_t, void* p);
251 
252     static unsigned ScalarsPerGlyph(GlyphPositioning pos);
253 
254     // Call when this blob is part of the key to a cache entry. This allows the cache
255     // to know automatically those entries can be purged when this SkTextBlob is deleted.
notifyAddedToCache(uint32_t cacheID)256     void notifyAddedToCache(uint32_t cacheID) const {
257         fCacheID.store(cacheID);
258     }
259 
260     friend class SkGlyphRunList;
261     friend class GrTextBlobCache;
262     friend class SkTextBlobBuilder;
263     friend class SkTextBlobPriv;
264     friend class SkTextBlobRunIterator;
265 
266     const SkRect                  fBounds;
267     const uint32_t                fUniqueID;
268     mutable std::atomic<uint32_t> fCacheID;
269 
270     SkDEBUGCODE(size_t fStorageSize;)
271 
272     // The actual payload resides in externally-managed storage, following the object.
273     // (see the .cpp for more details)
274 
275     using INHERITED = SkRefCnt;
276 };
277 
278 /** \class SkTextBlobBuilder
279     Helper class for constructing SkTextBlob.
280 */
281 class SK_API SkTextBlobBuilder {
282 public:
283 
284     /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs.
285 
286         @return  empty SkTextBlobBuilder
287 
288         example: https://fiddle.skia.org/c/@TextBlobBuilder_empty_constructor
289     */
290     SkTextBlobBuilder();
291 
292     /** Deletes data allocated internally by SkTextBlobBuilder.
293     */
294     ~SkTextBlobBuilder();
295 
296     /** Returns SkTextBlob built from runs of glyphs added by builder. Returned
297         SkTextBlob is immutable; it may be copied, but its contents may not be altered.
298         Returns nullptr if no runs of glyphs were added by builder.
299 
300         Resets SkTextBlobBuilder to its initial empty state, allowing it to be
301         reused to build a new set of runs.
302 
303         @return  SkTextBlob or nullptr
304 
305         example: https://fiddle.skia.org/c/@TextBlobBuilder_make
306     */
307     sk_sp<SkTextBlob> make();
308 
309     /** \struct SkTextBlobBuilder::RunBuffer
310         RunBuffer supplies storage for glyphs and positions within a run.
311 
312         A run is a sequence of glyphs sharing font metrics and positioning.
313         Each run may position its glyphs in one of three ways:
314         by specifying where the first glyph is drawn, and allowing font metrics to
315         determine the advance to subsequent glyphs; by specifying a baseline, and
316         the position on that baseline for each glyph in run; or by providing SkPoint
317         array, one per glyph.
318     */
319     struct RunBuffer {
320         SkGlyphID* glyphs;   //!< storage for glyph indexes in run
321         SkScalar*  pos;      //!< storage for glyph positions in run
322         char*      utf8text; //!< storage for text UTF-8 code units in run
323         uint32_t*  clusters; //!< storage for glyph clusters (index of UTF-8 code unit)
324 
325         // Helpers, since the "pos" field can be different types (always some number of floats).
pointsRunBuffer326         SkPoint*    points() const { return reinterpret_cast<SkPoint*>(pos); }
xformsRunBuffer327         SkRSXform*  xforms() const { return reinterpret_cast<SkRSXform*>(pos); }
328     };
329 
330     /** Returns run with storage for glyphs. Caller must write count glyphs to
331         RunBuffer::glyphs before next call to SkTextBlobBuilder.
332 
333         RunBuffer::pos, RunBuffer::utf8text, and RunBuffer::clusters should be ignored.
334 
335         Glyphs share metrics in font.
336 
337         Glyphs are positioned on a baseline at (x, y), using font metrics to
338         determine their relative placement.
339 
340         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
341         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
342         is computed from (x, y) and RunBuffer::glyphs metrics.
343 
344         @param font    SkFont used for this run
345         @param count   number of glyphs
346         @param x       horizontal offset within the blob
347         @param y       vertical offset within the blob
348         @param bounds  optional run bounding box
349         @return writable glyph buffer
350     */
351     const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y,
352                               const SkRect* bounds = nullptr);
353 
354     /** Returns run with storage for glyphs and positions along baseline. Caller must
355         write count glyphs to RunBuffer::glyphs and count scalars to RunBuffer::pos
356         before next call to SkTextBlobBuilder.
357 
358         RunBuffer::utf8text and RunBuffer::clusters should be ignored.
359 
360         Glyphs share metrics in font.
361 
362         Glyphs are positioned on a baseline at y, using x-axis positions written by
363         caller to RunBuffer::pos.
364 
365         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
366         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
367         is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics.
368 
369         @param font    SkFont used for this run
370         @param count   number of glyphs
371         @param y       vertical offset within the blob
372         @param bounds  optional run bounding box
373         @return writable glyph buffer and x-axis position buffer
374     */
375     const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y,
376                                   const SkRect* bounds = nullptr);
377 
378     /** Returns run with storage for glyphs and SkPoint positions. Caller must
379         write count glyphs to RunBuffer::glyphs and count SkPoint to RunBuffer::pos
380         before next call to SkTextBlobBuilder.
381 
382         RunBuffer::utf8text and RunBuffer::clusters should be ignored.
383 
384         Glyphs share metrics in font.
385 
386         Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using
387         two scalar values for each SkPoint.
388 
389         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
390         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
391         is computed from RunBuffer::pos, and RunBuffer::glyphs metrics.
392 
393         @param font    SkFont used for this run
394         @param count   number of glyphs
395         @param bounds  optional run bounding box
396         @return writable glyph buffer and SkPoint buffer
397     */
398     const RunBuffer& allocRunPos(const SkFont& font, int count,
399                                  const SkRect* bounds = nullptr);
400 
401     // RunBuffer.pos points to SkRSXform array
402     const RunBuffer& allocRunRSXform(const SkFont& font, int count);
403 
404     /** Returns run with storage for glyphs, text, and clusters. Caller must
405         write count glyphs to RunBuffer::glyphs, textByteCount UTF-8 code units
406         into RunBuffer::utf8text, and count monotonic indexes into utf8text
407         into RunBuffer::clusters before next call to SkTextBlobBuilder.
408 
409         RunBuffer::pos should be ignored.
410 
411         Glyphs share metrics in font.
412 
413         Glyphs are positioned on a baseline at (x, y), using font metrics to
414         determine their relative placement.
415 
416         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
417         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
418         is computed from (x, y) and RunBuffer::glyphs metrics.
419 
420         @param font          SkFont used for this run
421         @param count         number of glyphs
422         @param x             horizontal offset within the blob
423         @param y             vertical offset within the blob
424         @param textByteCount number of UTF-8 code units
425         @param bounds        optional run bounding box
426         @return writable glyph buffer, text buffer, and cluster buffer
427     */
428     const RunBuffer& allocRunText(const SkFont& font, int count, SkScalar x, SkScalar y,
429                                   int textByteCount, const SkRect* bounds = nullptr);
430 
431     /** Returns run with storage for glyphs, positions along baseline, text,
432         and clusters. Caller must write count glyphs to RunBuffer::glyphs,
433         count scalars to RunBuffer::pos, textByteCount UTF-8 code units into
434         RunBuffer::utf8text, and count monotonic indexes into utf8text into
435         RunBuffer::clusters before next call to SkTextBlobBuilder.
436 
437         Glyphs share metrics in font.
438 
439         Glyphs are positioned on a baseline at y, using x-axis positions written by
440         caller to RunBuffer::pos.
441 
442         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
443         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
444         is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics.
445 
446         @param font          SkFont used for this run
447         @param count         number of glyphs
448         @param y             vertical offset within the blob
449         @param textByteCount number of UTF-8 code units
450         @param bounds        optional run bounding box
451         @return writable glyph buffer, x-axis position buffer, text buffer, and cluster buffer
452     */
453     const RunBuffer& allocRunTextPosH(const SkFont& font, int count, SkScalar y, int textByteCount,
454                                       const SkRect* bounds = nullptr);
455 
456     /** Returns run with storage for glyphs, SkPoint positions, text, and
457         clusters. Caller must write count glyphs to RunBuffer::glyphs, count
458         SkPoint to RunBuffer::pos, textByteCount UTF-8 code units into
459         RunBuffer::utf8text, and count monotonic indexes into utf8text into
460         RunBuffer::clusters before next call to SkTextBlobBuilder.
461 
462         Glyphs share metrics in font.
463 
464         Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using
465         two scalar values for each SkPoint.
466 
467         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
468         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
469         is computed from RunBuffer::pos, and RunBuffer::glyphs metrics.
470 
471         @param font          SkFont used for this run
472         @param count         number of glyphs
473         @param textByteCount number of UTF-8 code units
474         @param bounds        optional run bounding box
475         @return writable glyph buffer, SkPoint buffer, text buffer, and cluster buffer
476     */
477     const RunBuffer& allocRunTextPos(const SkFont& font, int count, int textByteCount,
478                                      const SkRect* bounds = nullptr);
479 
480     // RunBuffer.pos points to SkRSXform array
481     const RunBuffer& allocRunTextRSXform(const SkFont& font, int count, int textByteCount,
482                                          const SkRect* bounds = nullptr);
483 
484 private:
485     void reserve(size_t size);
486     void allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning,
487                        int count, int textBytes, SkPoint offset, const SkRect* bounds);
488     bool mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning,
489                   uint32_t count, SkPoint offset);
490     void updateDeferredBounds();
491 
492     static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
493     static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
494 
495     friend class SkTextBlobPriv;
496     friend class SkTextBlobBuilderPriv;
497 
498     SkAutoTMalloc<uint8_t> fStorage;
499     size_t                 fStorageSize;
500     size_t                 fStorageUsed;
501 
502     SkRect                 fBounds;
503     int                    fRunCount;
504     bool                   fDeferredBounds;
505     size_t                 fLastRun; // index into fStorage
506 
507     RunBuffer              fCurrentRunBuffer;
508 };
509 
510 /** function GetGlyphIDforTextBlob:
511     Obtain the path of the first glyph from SkTextBlob blob
512 */
513 SK_API void GetGlyphIDforTextBlob(const SkTextBlob* blob, std::vector<SkGlyphID>& glyphIds);
514 
515 SK_API SkPath GetPathforTextBlob(const SkGlyphID& glyphId, const SkTextBlob* blob);
516 
517 SK_API void GetPointsForTextBlob(const SkTextBlob* blob, std::vector<SkPoint>& points);
518 
519 #endif // SkTextBlob_DEFINED
520