• 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 "../private/SkTemplates.h"
12 #include "../private/SkAtomics.h"
13 #include "SkPaint.h"
14 #include "SkString.h"
15 #include "SkRefCnt.h"
16 
17 class SkReadBuffer;
18 class SkWriteBuffer;
19 
20 typedef std::function<void(SkTypeface*)> SkTypefaceCataloger;
21 typedef std::function<sk_sp<SkTypeface>(uint32_t)> SkTypefaceResolver;
22 
23 /** \class SkTextBlob
24 
25     SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
26 */
27 class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
28 public:
29     /**
30      *  Returns a conservative blob bounding box.
31      */
bounds()32     const SkRect& bounds() const { return fBounds; }
33 
34     /**
35      *  Return a non-zero, unique value representing the text blob.
36      */
uniqueID()37     uint32_t uniqueID() const { return fUniqueID; }
38 
39     /**
40      *  Serialize to a buffer.
41      */
42     void flatten(SkWriteBuffer&) const;
43 
44     /**
45      *  Recreate an SkTextBlob that was serialized into a buffer.
46      *
47      *  @param  SkReadBuffer Serialized blob data.
48      *  @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
49      *          invalid.
50      */
51     static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
52 
CreateFromBuffer(SkReadBuffer & buffer)53     static const SkTextBlob* CreateFromBuffer(SkReadBuffer& buffer) {
54         return MakeFromBuffer(buffer).release();
55     }
56 
57     enum GlyphPositioning : uint8_t {
58         kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
59         kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
60         kFull_Positioning         = 2  // Point positioning -- two scalars per glyph.
61     };
62 
63     /**
64      *  Serialize the typeface into a data blob, storing type uniqueID of each referenced typeface.
65      *  During this process, each time a typeface is encountered, it is passed to the catalog,
66      *  allowing the caller to what typeface IDs will need to be resolved in Deserialize().
67      */
68     sk_sp<SkData> serialize(const SkTypefaceCataloger&) const;
69 
70     /**
71      *  Re-create a text blob previously serialized. Since the serialized form records the uniqueIDs
72      *  of its typefaces, deserialization requires that the caller provide the corresponding
73      *  SkTypefaces for those IDs.
74      */
75     static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkTypefaceResolver&);
76 
77 private:
78     friend class SkNVRefCnt<SkTextBlob>;
79     class RunRecord;
80 
81     explicit SkTextBlob(const SkRect& bounds);
82 
83     ~SkTextBlob();
84 
85     // Memory for objects of this class is created with sk_malloc rather than operator new and must
86     // be freed with sk_free.
delete(void * p)87     void operator delete(void* p) { sk_free(p); }
new(size_t)88     void* operator new(size_t) {
89         SkFAIL("All blobs are created by placement new.");
90         return sk_malloc_throw(0);
91     }
new(size_t,void * p)92     void* operator new(size_t, void* p) { return p; }
93 
94     static unsigned ScalarsPerGlyph(GlyphPositioning pos);
95 
96     // Call when this blob is part of the key to a cache entry. This allows the cache
97     // to know automatically those entries can be purged when this SkTextBlob is deleted.
notifyAddedToCache()98     void notifyAddedToCache() const {
99         fAddedToCache.store(true);
100     }
101 
102     friend class GrTextBlobCache;
103     friend class SkTextBlobBuilder;
104     friend class SkTextBlobRunIterator;
105 
106     const SkRect           fBounds;
107     const uint32_t         fUniqueID;
108     mutable SkAtomic<bool> fAddedToCache;
109 
110     SkDEBUGCODE(size_t fStorageSize;)
111 
112     // The actual payload resides in externally-managed storage, following the object.
113     // (see the .cpp for more details)
114 
115     typedef SkRefCnt INHERITED;
116 };
117 
118 /** \class SkTextBlobBuilder
119 
120     Helper class for constructing SkTextBlobs.
121  */
122 class SK_API SkTextBlobBuilder {
123 public:
124     SkTextBlobBuilder();
125 
126     ~SkTextBlobBuilder();
127 
128     /**
129      *  Returns an immutable SkTextBlob for the current runs/glyphs,
130      *  or nullptr if no runs were allocated.
131      *
132      *  The builder is reset and can be reused.
133      */
134     sk_sp<SkTextBlob> make();
135 
136     /**
137      *  Glyph and position buffers associated with a run.
138      *
139      *  A run is a sequence of glyphs sharing the same font metrics
140      *  and positioning mode.
141      *
142      *  If textByteCount is 0, utf8text and clusters will be NULL (no
143      *  character information will be associated with the glyphs).
144      *
145      *  utf8text will point to a buffer of size textByteCount bytes.
146      *
147      *  clusters (if not NULL) will point to an array of size count.
148      *  For each glyph, give the byte-offset into the text for the
149      *  first byte in the first character in that glyph's cluster.
150      *  Each value in the array should be an integer less than
151      *  textByteCount.  Values in the array should either be
152      *  monotonically increasing (left-to-right text) or monotonically
153      *  decreasing (right-to-left text).  This definiton is conviently
154      *  the same as used by Harfbuzz's hb_glyph_info_t::cluster field,
155      *  except that Harfbuzz interleaves glyphs and clusters.
156      */
157     struct RunBuffer {
158         SkGlyphID* glyphs;
159         SkScalar* pos;
160         char* utf8text;
161         uint32_t* clusters;
162     };
163 
164     /**
165      *  Allocates a new default-positioned run and returns its writable glyph buffer
166      *  for direct manipulation.
167      *
168      *  @param font    The font to be used for this run.
169      *  @param count   Number of glyphs.
170      *  @param x,y     Position within the blob.
171      *  @param textByteCount length of the original UTF-8 text that
172      *                 corresponds to this sequence of glyphs.  If 0,
173      *                 text will not be included in the textblob.
174      *  @param lang    Language code, currently unimplemented.
175      *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
176      *                 be used when computing the blob bounds, to avoid re-measuring.
177      *
178      *  @return        A writable glyph buffer, valid until the next allocRun() or
179      *                 build() call. The buffer is guaranteed to hold @count@ glyphs.
180      */
181     const RunBuffer& allocRunText(const SkPaint& font,
182                                   int count,
183                                   SkScalar x,
184                                   SkScalar y,
185                                   int textByteCount,
186                                   SkString lang,
187                                   const SkRect* bounds = NULL);
188     const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
189                               const SkRect* bounds = NULL) {
190         return this->allocRunText(font, count, x, y, 0, SkString(), bounds);
191     }
192 
193     /**
194      *  Allocates a new horizontally-positioned run and returns its writable glyph and position
195      *  buffers for direct manipulation.
196      *
197      *  @param font    The font to be used for this run.
198      *  @param count   Number of glyphs.
199      *  @param y       Vertical offset within the blob.
200      *  @param textByteCount length of the original UTF-8 text that
201      *                 corresponds to this sequence of glyphs.  If 0,
202      *                 text will not be included in the textblob.
203      *  @param lang    Language code, currently unimplemented.
204      *  @param bounds  Optional run bounding box. If known in advance (!= NULL), it will
205      *                 be used when computing the blob bounds, to avoid re-measuring.
206      *
207      *  @return        Writable glyph and position buffers, valid until the next allocRun()
208      *                 or build() call. The buffers are guaranteed to hold @count@ elements.
209      */
210     const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
211                                       int textByteCount, SkString lang,
212                                       const SkRect* bounds = NULL);
213     const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
214                                   const SkRect* bounds = NULL) {
215         return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds);
216     }
217 
218     /**
219      *  Allocates a new fully-positioned run and returns its writable glyph and position
220      *  buffers for direct manipulation.
221      *
222      *  @param font   The font to be used for this run.
223      *  @param count  Number of glyphs.
224      *  @param textByteCount length of the original UTF-8 text that
225      *                 corresponds to this sequence of glyphs.  If 0,
226      *                 text will not be included in the textblob.
227      *  @param lang    Language code, currently unimplemented.
228      *  @param bounds Optional run bounding box. If known in advance (!= NULL), it will
229      *                be used when computing the blob bounds, to avoid re-measuring.
230      *
231      *  @return       Writable glyph and position buffers, valid until the next allocRun()
232      *                or build() call. The glyph buffer and position buffer are
233      *                guaranteed to hold @count@ and 2 * @count@ elements, respectively.
234      */
235     const RunBuffer& allocRunTextPos(const SkPaint& font, int count,
236                                      int textByteCount, SkString lang,
237                                      const SkRect* bounds = NULL);
238     const RunBuffer& allocRunPos(const SkPaint& font, int count,
239                                  const SkRect* bounds = NULL) {
240         return this->allocRunTextPos(font, count, 0, SkString(), bounds);
241     }
242 
243 private:
244     void reserve(size_t size);
245     void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
246                        int count, int textBytes, SkPoint offset, const SkRect* bounds);
247     bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
248                   int count, SkPoint offset);
249     void updateDeferredBounds();
250 
251     static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
252     static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
253 
254     SkAutoTMalloc<uint8_t> fStorage;
255     size_t                 fStorageSize;
256     size_t                 fStorageUsed;
257 
258     SkRect                 fBounds;
259     int                    fRunCount;
260     bool                   fDeferredBounds;
261     size_t                 fLastRun; // index into fStorage
262 
263     RunBuffer              fCurrentRunBuffer;
264 };
265 
266 #endif // SkTextBlob_DEFINED
267