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