blob: 2fe852c762b042ec4ab117014e676f469144f690 [file] [log] [blame]
fmalita00d5c2c2014-08-21 08:53:26 -07001/*
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
bungemanbf521ff2016-02-17 13:13:44 -080011#include "../private/SkTemplates.h"
Florin Malita4a01ac92017-03-13 16:45:28 -040012#include "../private/SkAtomics.h"
fmalita00d5c2c2014-08-21 08:53:26 -070013#include "SkPaint.h"
halcanary4f0a23a2016-08-30 11:58:33 -070014#include "SkString.h"
fmalita00d5c2c2014-08-21 08:53:26 -070015#include "SkRefCnt.h"
fmalita00d5c2c2014-08-21 08:53:26 -070016
fmalitab7425172014-08-26 07:56:44 -070017class SkReadBuffer;
18class SkWriteBuffer;
19
Mike Reedaaa30562017-07-21 11:53:23 -040020#ifdef SK_SUPPORT_LEGACY_TEXTBLOB_SERIAL_API
Mike Reedb99bedd2017-07-11 10:27:40 -040021typedef std::function<void(SkTypeface*)> SkTypefaceCataloger;
22typedef std::function<sk_sp<SkTypeface>(uint32_t)> SkTypefaceResolver;
Mike Reedaaa30562017-07-21 11:53:23 -040023#endif
24
25typedef void (*SkTypefaceCatalogerProc)(SkTypeface*, void* ctx);
26typedef sk_sp<SkTypeface> (*SkTypefaceResolverProc)(uint32_t id, void* ctx);
Mike Reedb99bedd2017-07-11 10:27:40 -040027
fmalita00d5c2c2014-08-21 08:53:26 -070028/** \class SkTextBlob
29
30 SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
31*/
mtkleinb47cd4b2016-08-09 12:20:04 -070032class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
fmalita00d5c2c2014-08-21 08:53:26 -070033public:
34 /**
fmalita3dc40ac2015-01-28 10:56:06 -080035 * Returns a conservative blob bounding box.
fmalita00d5c2c2014-08-21 08:53:26 -070036 */
37 const SkRect& bounds() const { return fBounds; }
38
39 /**
40 * Return a non-zero, unique value representing the text blob.
41 */
joshualitt2af85832015-03-25 13:40:13 -070042 uint32_t uniqueID() const { return fUniqueID; }
fmalita00d5c2c2014-08-21 08:53:26 -070043
fmalita228a6f22014-08-28 13:59:42 -070044 /**
45 * Serialize to a buffer.
46 */
47 void flatten(SkWriteBuffer&) const;
48
49 /**
50 * Recreate an SkTextBlob that was serialized into a buffer.
51 *
52 * @param SkReadBuffer Serialized blob data.
53 * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
54 * invalid.
55 */
reed2ab90572016-08-10 14:16:41 -070056 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
57
58 static const SkTextBlob* CreateFromBuffer(SkReadBuffer& buffer) {
59 return MakeFromBuffer(buffer).release();
60 }
fmalita228a6f22014-08-28 13:59:42 -070061
halcanary4f0a23a2016-08-30 11:58:33 -070062 enum GlyphPositioning : uint8_t {
fmalita00d5c2c2014-08-21 08:53:26 -070063 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph.
64 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph.
65 kFull_Positioning = 2 // Point positioning -- two scalars per glyph.
66 };
67
Mike Reedb99bedd2017-07-11 10:27:40 -040068 /**
69 * Serialize the typeface into a data blob, storing type uniqueID of each referenced typeface.
70 * During this process, each time a typeface is encountered, it is passed to the catalog,
71 * allowing the caller to what typeface IDs will need to be resolved in Deserialize().
72 */
Mike Reedaaa30562017-07-21 11:53:23 -040073 sk_sp<SkData> serialize(SkTypefaceCatalogerProc, void* ctx) const;
Mike Reedb99bedd2017-07-11 10:27:40 -040074
75 /**
76 * Re-create a text blob previously serialized. Since the serialized form records the uniqueIDs
77 * of its typefaces, deserialization requires that the caller provide the corresponding
78 * SkTypefaces for those IDs.
79 */
Mike Reedaaa30562017-07-21 11:53:23 -040080 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size,
81 SkTypefaceResolverProc, void* ctx);
82
83#ifdef SK_SUPPORT_LEGACY_TEXTBLOB_SERIAL_API
84 sk_sp<SkData> serialize(const SkTypefaceCataloger&) const;
Mike Reedb99bedd2017-07-11 10:27:40 -040085 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkTypefaceResolver&);
Mike Reedaaa30562017-07-21 11:53:23 -040086#endif
Mike Reedb99bedd2017-07-11 10:27:40 -040087
halcanary33779752015-10-27 14:01:05 -070088private:
mtkleinb47cd4b2016-08-09 12:20:04 -070089 friend class SkNVRefCnt<SkTextBlob>;
fmalita3c196de2014-09-20 05:40:22 -070090 class RunRecord;
91
Florin Malita3a9a7a32017-03-13 09:03:24 -040092 explicit SkTextBlob(const SkRect& bounds);
fmalita00d5c2c2014-08-21 08:53:26 -070093
mtkleinb47cd4b2016-08-09 12:20:04 -070094 ~SkTextBlob();
bsalomon07280312014-11-20 08:02:46 -080095
96 // Memory for objects of this class is created with sk_malloc rather than operator new and must
97 // be freed with sk_free.
98 void operator delete(void* p) { sk_free(p); }
99 void* operator new(size_t) {
100 SkFAIL("All blobs are created by placement new.");
101 return sk_malloc_throw(0);
102 }
103 void* operator new(size_t, void* p) { return p; }
fmalita00d5c2c2014-08-21 08:53:26 -0700104
fmalitab7425172014-08-26 07:56:44 -0700105 static unsigned ScalarsPerGlyph(GlyphPositioning pos);
106
Florin Malita4a01ac92017-03-13 16:45:28 -0400107 // Call when this blob is part of the key to a cache entry. This allows the cache
108 // to know automatically those entries can be purged when this SkTextBlob is deleted.
109 void notifyAddedToCache() const {
110 fAddedToCache.store(true);
111 }
112
113 friend class GrTextBlobCache;
fmalita00d5c2c2014-08-21 08:53:26 -0700114 friend class SkTextBlobBuilder;
halcanary33779752015-10-27 14:01:05 -0700115 friend class SkTextBlobRunIterator;
fmalita00d5c2c2014-08-21 08:53:26 -0700116
Florin Malita4a01ac92017-03-13 16:45:28 -0400117 const SkRect fBounds;
118 const uint32_t fUniqueID;
119 mutable SkAtomic<bool> fAddedToCache;
fmalita00d5c2c2014-08-21 08:53:26 -0700120
fmalita3c196de2014-09-20 05:40:22 -0700121 SkDEBUGCODE(size_t fStorageSize;)
fmalita00d5c2c2014-08-21 08:53:26 -0700122
fmalita3c196de2014-09-20 05:40:22 -0700123 // The actual payload resides in externally-managed storage, following the object.
124 // (see the .cpp for more details)
fmalita00d5c2c2014-08-21 08:53:26 -0700125
126 typedef SkRefCnt INHERITED;
127};
128
129/** \class SkTextBlobBuilder
130
131 Helper class for constructing SkTextBlobs.
132 */
jbroman3053dfa2014-08-25 06:22:12 -0700133class SK_API SkTextBlobBuilder {
fmalita00d5c2c2014-08-21 08:53:26 -0700134public:
fmalita3c196de2014-09-20 05:40:22 -0700135 SkTextBlobBuilder();
fmalita00d5c2c2014-08-21 08:53:26 -0700136
137 ~SkTextBlobBuilder();
138
139 /**
Florin Malita3a9a7a32017-03-13 09:03:24 -0400140 * Returns an immutable SkTextBlob for the current runs/glyphs,
141 * or nullptr if no runs were allocated.
142 *
143 * The builder is reset and can be reused.
fmalita00d5c2c2014-08-21 08:53:26 -0700144 */
reed2ab90572016-08-10 14:16:41 -0700145 sk_sp<SkTextBlob> make();
146
fmalita00d5c2c2014-08-21 08:53:26 -0700147 /**
148 * Glyph and position buffers associated with a run.
149 *
halcanary4f0a23a2016-08-30 11:58:33 -0700150 * A run is a sequence of glyphs sharing the same font metrics
151 * and positioning mode.
152 *
153 * If textByteCount is 0, utf8text and clusters will be NULL (no
154 * character information will be associated with the glyphs).
155 *
156 * utf8text will point to a buffer of size textByteCount bytes.
157 *
158 * clusters (if not NULL) will point to an array of size count.
159 * For each glyph, give the byte-offset into the text for the
160 * first byte in the first character in that glyph's cluster.
161 * Each value in the array should be an integer less than
162 * textByteCount. Values in the array should either be
163 * monotonically increasing (left-to-right text) or monotonically
164 * decreasing (right-to-left text). This definiton is conviently
165 * the same as used by Harfbuzz's hb_glyph_info_t::cluster field,
166 * except that Harfbuzz interleaves glyphs and clusters.
fmalita00d5c2c2014-08-21 08:53:26 -0700167 */
168 struct RunBuffer {
halcanaryd0e95a52016-07-25 07:18:12 -0700169 SkGlyphID* glyphs;
fmalita00d5c2c2014-08-21 08:53:26 -0700170 SkScalar* pos;
halcanary4f0a23a2016-08-30 11:58:33 -0700171 char* utf8text;
172 uint32_t* clusters;
fmalita00d5c2c2014-08-21 08:53:26 -0700173 };
174
175 /**
176 * Allocates a new default-positioned run and returns its writable glyph buffer
177 * for direct manipulation.
178 *
179 * @param font The font to be used for this run.
180 * @param count Number of glyphs.
181 * @param x,y Position within the blob.
halcanary4f0a23a2016-08-30 11:58:33 -0700182 * @param textByteCount length of the original UTF-8 text that
183 * corresponds to this sequence of glyphs. If 0,
184 * text will not be included in the textblob.
185 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700186 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
187 * be used when computing the blob bounds, to avoid re-measuring.
188 *
189 * @return A writable glyph buffer, valid until the next allocRun() or
190 * build() call. The buffer is guaranteed to hold @count@ glyphs.
191 */
halcanary4f0a23a2016-08-30 11:58:33 -0700192 const RunBuffer& allocRunText(const SkPaint& font,
193 int count,
194 SkScalar x,
195 SkScalar y,
196 int textByteCount,
197 SkString lang,
198 const SkRect* bounds = NULL);
fmalita00d5c2c2014-08-21 08:53:26 -0700199 const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
halcanary4f0a23a2016-08-30 11:58:33 -0700200 const SkRect* bounds = NULL) {
201 return this->allocRunText(font, count, x, y, 0, SkString(), bounds);
202 }
fmalita00d5c2c2014-08-21 08:53:26 -0700203
204 /**
205 * Allocates a new horizontally-positioned run and returns its writable glyph and position
206 * buffers for direct manipulation.
207 *
208 * @param font The font to be used for this run.
209 * @param count Number of glyphs.
210 * @param y Vertical offset within the blob.
halcanary4f0a23a2016-08-30 11:58:33 -0700211 * @param textByteCount length of the original UTF-8 text that
212 * corresponds to this sequence of glyphs. If 0,
213 * text will not be included in the textblob.
214 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700215 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
216 * be used when computing the blob bounds, to avoid re-measuring.
217 *
218 * @return Writable glyph and position buffers, valid until the next allocRun()
219 * or build() call. The buffers are guaranteed to hold @count@ elements.
220 */
halcanary4f0a23a2016-08-30 11:58:33 -0700221 const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
222 int textByteCount, SkString lang,
223 const SkRect* bounds = NULL);
fmalita00d5c2c2014-08-21 08:53:26 -0700224 const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
halcanary4f0a23a2016-08-30 11:58:33 -0700225 const SkRect* bounds = NULL) {
226 return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds);
227 }
fmalita00d5c2c2014-08-21 08:53:26 -0700228
229 /**
230 * Allocates a new fully-positioned run and returns its writable glyph and position
231 * buffers for direct manipulation.
232 *
233 * @param font The font to be used for this run.
234 * @param count Number of glyphs.
halcanary4f0a23a2016-08-30 11:58:33 -0700235 * @param textByteCount length of the original UTF-8 text that
236 * corresponds to this sequence of glyphs. If 0,
237 * text will not be included in the textblob.
238 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700239 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
240 * be used when computing the blob bounds, to avoid re-measuring.
241 *
242 * @return Writable glyph and position buffers, valid until the next allocRun()
243 * or build() call. The glyph buffer and position buffer are
244 * guaranteed to hold @count@ and 2 * @count@ elements, respectively.
245 */
halcanary4f0a23a2016-08-30 11:58:33 -0700246 const RunBuffer& allocRunTextPos(const SkPaint& font, int count,
247 int textByteCount, SkString lang,
248 const SkRect* bounds = NULL);
249 const RunBuffer& allocRunPos(const SkPaint& font, int count,
250 const SkRect* bounds = NULL) {
251 return this->allocRunTextPos(font, count, 0, SkString(), bounds);
252 }
fmalita00d5c2c2014-08-21 08:53:26 -0700253
254private:
fmalita3c196de2014-09-20 05:40:22 -0700255 void reserve(size_t size);
fmalita00d5c2c2014-08-21 08:53:26 -0700256 void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
halcanary4f0a23a2016-08-30 11:58:33 -0700257 int count, int textBytes, SkPoint offset, const SkRect* bounds);
fmalita3c196de2014-09-20 05:40:22 -0700258 bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
259 int count, SkPoint offset);
fmalita00d5c2c2014-08-21 08:53:26 -0700260 void updateDeferredBounds();
261
fmalita3dc40ac2015-01-28 10:56:06 -0800262 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
263 static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
264
fmalita3c196de2014-09-20 05:40:22 -0700265 SkAutoTMalloc<uint8_t> fStorage;
266 size_t fStorageSize;
267 size_t fStorageUsed;
fmalita00d5c2c2014-08-21 08:53:26 -0700268
fmalita3c196de2014-09-20 05:40:22 -0700269 SkRect fBounds;
270 int fRunCount;
271 bool fDeferredBounds;
272 size_t fLastRun; // index into fStorage
fmalita00d5c2c2014-08-21 08:53:26 -0700273
fmalita3c196de2014-09-20 05:40:22 -0700274 RunBuffer fCurrentRunBuffer;
fmalita00d5c2c2014-08-21 08:53:26 -0700275};
276
277#endif // SkTextBlob_DEFINED