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