• 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 #if defined (ENABLE_DDGR_OPTIMIZE)
198     void TextBlobSetShareParas(int fId, int fSize, void* fPtr);
199     void TextBlobFlatten(SkWriteBuffer& buffer);
200 #endif
201 
202     class SK_API Iter {
203     public:
204         struct Run {
205             SkTypeface*     fTypeface;
206             int             fGlyphCount;
207             const uint16_t* fGlyphIndices;
208 #ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED
209             const uint32_t* fClusterIndex_forTest;
210             int             fUtf8Size_forTest;
211             const char*     fUtf8_forTest;
212 #endif
213         };
214 
215         Iter(const SkTextBlob&);
216 
217         /**
218          * Returns true for each "run" inside the textblob, setting the Run fields (if not null).
219          * If this returns false, there are no more runs, and the Run parameter will be ignored.
220          */
221         bool next(Run*);
222 
223         // Experimental, DO NO USE, will change/go-away
224         struct ExperimentalRun {
225             SkFont          font;
226             int             count;
227             const uint16_t* glyphs;
228             const SkPoint*  positions;
229         };
230         bool experimentalNext(ExperimentalRun*);
231 
232     private:
233         const RunRecord* fRunRecord;
234     };
235 
236     /** Writes text representation of SkTextBlob to string.
237 
238         @param desc     the string storing a description of parameters.
239         @param depth    the number of tabs preceding each line.
240     */
241     void dump(std::string& desc, int depth) const;
242 private:
243     friend class SkNVRefCnt<SkTextBlob>;
244 
245     enum GlyphPositioning : uint8_t;
246 
247     explicit SkTextBlob(const SkRect& bounds);
248 
249     ~SkTextBlob();
250 
251     // Memory for objects of this class is created with sk_malloc rather than operator new and must
252     // be freed with sk_free.
253     void operator delete(void* p);
254     void* operator new(size_t);
255     void* operator new(size_t, void* p);
256 
257     static unsigned ScalarsPerGlyph(GlyphPositioning pos);
258 
259     // Call when this blob is part of the key to a cache entry. This allows the cache
260     // to know automatically those entries can be purged when this SkTextBlob is deleted.
notifyAddedToCache(uint32_t cacheID)261     void notifyAddedToCache(uint32_t cacheID) const {
262         fCacheID.store(cacheID);
263     }
264 
265     friend class SkGlyphRunList;
266     friend class GrTextBlobCache;
267     friend class SkTextBlobBuilder;
268     friend class SkTextBlobPriv;
269     friend class SkTextBlobRunIterator;
270 
271     const SkRect                  fBounds;
272     const uint32_t                fUniqueID;
273     mutable std::atomic<uint32_t> fCacheID;
274 
275     SkDEBUGCODE(size_t fStorageSize;)
276 
277     // The actual payload resides in externally-managed storage, following the object.
278     // (see the .cpp for more details)
279 
280     using INHERITED = SkRefCnt;
281 
282 #if defined (ENABLE_DDGR_OPTIMIZE)
283     int fd_ = -1;
284     int fdSize_ = 0;
285     void* fdPtr_ = nullptr;
286 #endif
287 };
288 
289 /** \class SkTextBlobBuilder
290     Helper class for constructing SkTextBlob.
291 */
292 class SK_API SkTextBlobBuilder {
293 public:
294 
295     /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs.
296 
297         @return  empty SkTextBlobBuilder
298 
299         example: https://fiddle.skia.org/c/@TextBlobBuilder_empty_constructor
300     */
301     SkTextBlobBuilder();
302 
303     /** Deletes data allocated internally by SkTextBlobBuilder.
304     */
305     ~SkTextBlobBuilder();
306 
307     /** Returns SkTextBlob built from runs of glyphs added by builder. Returned
308         SkTextBlob is immutable; it may be copied, but its contents may not be altered.
309         Returns nullptr if no runs of glyphs were added by builder.
310 
311         Resets SkTextBlobBuilder to its initial empty state, allowing it to be
312         reused to build a new set of runs.
313 
314         @return  SkTextBlob or nullptr
315 
316         example: https://fiddle.skia.org/c/@TextBlobBuilder_make
317     */
318     sk_sp<SkTextBlob> make();
319 
320     /** \struct SkTextBlobBuilder::RunBuffer
321         RunBuffer supplies storage for glyphs and positions within a run.
322 
323         A run is a sequence of glyphs sharing font metrics and positioning.
324         Each run may position its glyphs in one of three ways:
325         by specifying where the first glyph is drawn, and allowing font metrics to
326         determine the advance to subsequent glyphs; by specifying a baseline, and
327         the position on that baseline for each glyph in run; or by providing SkPoint
328         array, one per glyph.
329     */
330     struct RunBuffer {
331         SkGlyphID* glyphs;   //!< storage for glyph indexes in run
332         SkScalar*  pos;      //!< storage for glyph positions in run
333         char*      utf8text; //!< storage for text UTF-8 code units in run
334         uint32_t*  clusters; //!< storage for glyph clusters (index of UTF-8 code unit)
335 
336         // Helpers, since the "pos" field can be different types (always some number of floats).
pointsRunBuffer337         SkPoint*    points() const { return reinterpret_cast<SkPoint*>(pos); }
xformsRunBuffer338         SkRSXform*  xforms() const { return reinterpret_cast<SkRSXform*>(pos); }
339     };
340 
341     /** Returns run with storage for glyphs. Caller must write count glyphs to
342         RunBuffer::glyphs before next call to SkTextBlobBuilder.
343 
344         RunBuffer::pos, RunBuffer::utf8text, and RunBuffer::clusters should be ignored.
345 
346         Glyphs share metrics in font.
347 
348         Glyphs are positioned on a baseline at (x, y), using font metrics to
349         determine their relative placement.
350 
351         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
352         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
353         is computed from (x, y) and RunBuffer::glyphs metrics.
354 
355         @param font    SkFont used for this run
356         @param count   number of glyphs
357         @param x       horizontal offset within the blob
358         @param y       vertical offset within the blob
359         @param bounds  optional run bounding box
360         @return writable glyph buffer
361     */
362     const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y,
363                               const SkRect* bounds = nullptr);
364 
365     /** Returns run with storage for glyphs and positions along baseline. Caller must
366         write count glyphs to RunBuffer::glyphs and count scalars to RunBuffer::pos
367         before next call to SkTextBlobBuilder.
368 
369         RunBuffer::utf8text and RunBuffer::clusters should be ignored.
370 
371         Glyphs share metrics in font.
372 
373         Glyphs are positioned on a baseline at y, using x-axis positions written by
374         caller to RunBuffer::pos.
375 
376         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
377         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
378         is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics.
379 
380         @param font    SkFont used for this run
381         @param count   number of glyphs
382         @param y       vertical offset within the blob
383         @param bounds  optional run bounding box
384         @return writable glyph buffer and x-axis position buffer
385     */
386     const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y,
387                                   const SkRect* bounds = nullptr);
388 
389     /** Returns run with storage for glyphs and SkPoint positions. Caller must
390         write count glyphs to RunBuffer::glyphs and count SkPoint to RunBuffer::pos
391         before next call to SkTextBlobBuilder.
392 
393         RunBuffer::utf8text and RunBuffer::clusters should be ignored.
394 
395         Glyphs share metrics in font.
396 
397         Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using
398         two scalar values for each SkPoint.
399 
400         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
401         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
402         is computed from RunBuffer::pos, and RunBuffer::glyphs metrics.
403 
404         @param font    SkFont used for this run
405         @param count   number of glyphs
406         @param bounds  optional run bounding box
407         @return writable glyph buffer and SkPoint buffer
408     */
409     const RunBuffer& allocRunPos(const SkFont& font, int count,
410                                  const SkRect* bounds = nullptr);
411 
412     // RunBuffer.pos points to SkRSXform array
413     const RunBuffer& allocRunRSXform(const SkFont& font, int count);
414 
415     /** Returns run with storage for glyphs, text, and clusters. Caller must
416         write count glyphs to RunBuffer::glyphs, textByteCount UTF-8 code units
417         into RunBuffer::utf8text, and count monotonic indexes into utf8text
418         into RunBuffer::clusters before next call to SkTextBlobBuilder.
419 
420         RunBuffer::pos should be ignored.
421 
422         Glyphs share metrics in font.
423 
424         Glyphs are positioned on a baseline at (x, y), using font metrics to
425         determine their relative placement.
426 
427         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
428         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
429         is computed from (x, y) and RunBuffer::glyphs metrics.
430 
431         @param font          SkFont used for this run
432         @param count         number of glyphs
433         @param x             horizontal offset within the blob
434         @param y             vertical offset within the blob
435         @param textByteCount number of UTF-8 code units
436         @param bounds        optional run bounding box
437         @return writable glyph buffer, text buffer, and cluster buffer
438     */
439     const RunBuffer& allocRunText(const SkFont& font, int count, SkScalar x, SkScalar y,
440                                   int textByteCount, const SkRect* bounds = nullptr);
441 
442     /** Returns run with storage for glyphs, positions along baseline, text,
443         and clusters. Caller must write count glyphs to RunBuffer::glyphs,
444         count scalars to RunBuffer::pos, textByteCount UTF-8 code units into
445         RunBuffer::utf8text, and count monotonic indexes into utf8text into
446         RunBuffer::clusters before next call to SkTextBlobBuilder.
447 
448         Glyphs share metrics in font.
449 
450         Glyphs are positioned on a baseline at y, using x-axis positions written by
451         caller to RunBuffer::pos.
452 
453         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
454         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
455         is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics.
456 
457         @param font          SkFont used for this run
458         @param count         number of glyphs
459         @param y             vertical offset within the blob
460         @param textByteCount number of UTF-8 code units
461         @param bounds        optional run bounding box
462         @return writable glyph buffer, x-axis position buffer, text buffer, and cluster buffer
463     */
464     const RunBuffer& allocRunTextPosH(const SkFont& font, int count, SkScalar y, int textByteCount,
465                                       const SkRect* bounds = nullptr);
466 
467     /** Returns run with storage for glyphs, SkPoint positions, text, and
468         clusters. Caller must write count glyphs to RunBuffer::glyphs, count
469         SkPoint to RunBuffer::pos, textByteCount UTF-8 code units into
470         RunBuffer::utf8text, and count monotonic indexes into utf8text into
471         RunBuffer::clusters before next call to SkTextBlobBuilder.
472 
473         Glyphs share metrics in font.
474 
475         Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using
476         two scalar values for each SkPoint.
477 
478         bounds defines an optional bounding box, used to suppress drawing when SkTextBlob
479         bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds
480         is computed from RunBuffer::pos, and RunBuffer::glyphs metrics.
481 
482         @param font          SkFont used for this run
483         @param count         number of glyphs
484         @param textByteCount number of UTF-8 code units
485         @param bounds        optional run bounding box
486         @return writable glyph buffer, SkPoint buffer, text buffer, and cluster buffer
487     */
488     const RunBuffer& allocRunTextPos(const SkFont& font, int count, int textByteCount,
489                                      const SkRect* bounds = nullptr);
490 
491     // RunBuffer.pos points to SkRSXform array
492     const RunBuffer& allocRunTextRSXform(const SkFont& font, int count, int textByteCount,
493                                          const SkRect* bounds = nullptr);
494 
495 private:
496     void reserve(size_t size);
497     void allocInternal(const SkFont& font, SkTextBlob::GlyphPositioning positioning,
498                        int count, int textBytes, SkPoint offset, const SkRect* bounds);
499     bool mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning,
500                   uint32_t count, SkPoint offset);
501     void updateDeferredBounds();
502 
503     static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
504     static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
505 
506     friend class SkTextBlobPriv;
507     friend class SkTextBlobBuilderPriv;
508 
509     SkAutoTMalloc<uint8_t> fStorage;
510     size_t                 fStorageSize;
511     size_t                 fStorageUsed;
512 
513     SkRect                 fBounds;
514     int                    fRunCount;
515     bool                   fDeferredBounds;
516     size_t                 fLastRun; // index into fStorage
517 
518     RunBuffer              fCurrentRunBuffer;
519 };
520 
521 /** function GetGlyphIDforTextBlob:
522     Obtain the path of the first glyph from SkTextBlob blob
523 */
524 SK_API void GetGlyphIDforTextBlob(const SkTextBlob* blob, std::vector<SkGlyphID>& glyphIds);
525 
526 SK_API SkPath GetPathforTextBlob(const SkGlyphID& glyphId, const SkTextBlob* blob);
527 
528 SK_API void GetPointsForTextBlob(const SkTextBlob* blob, std::vector<SkPoint>& points);
529 
530 #endif // SkTextBlob_DEFINED
531