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