blob: c68ad4147b91e5fa57d6dc979c6625358fe3680a [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
Herb Derby8a6348e2018-07-12 15:30:35 -040017class SkGlyphRunList;
fmalitab7425172014-08-26 07:56:44 -070018class SkReadBuffer;
19class SkWriteBuffer;
20
Mike Reed8e74cbc2017-12-08 13:20:01 -050021struct SkSerialProcs;
22struct SkDeserialProcs;
23
Mike Reedaaa30562017-07-21 11:53:23 -040024typedef void (*SkTypefaceCatalogerProc)(SkTypeface*, void* ctx);
25typedef sk_sp<SkTypeface> (*SkTypefaceResolverProc)(uint32_t id, void* ctx);
Mike Reedb99bedd2017-07-11 10:27:40 -040026
fmalita00d5c2c2014-08-21 08:53:26 -070027/** \class SkTextBlob
28
29 SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
30*/
mtkleinb47cd4b2016-08-09 12:20:04 -070031class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
fmalita00d5c2c2014-08-21 08:53:26 -070032public:
33 /**
fmalita3dc40ac2015-01-28 10:56:06 -080034 * Returns a conservative blob bounding box.
fmalita00d5c2c2014-08-21 08:53:26 -070035 */
36 const SkRect& bounds() const { return fBounds; }
37
38 /**
39 * Return a non-zero, unique value representing the text blob.
40 */
joshualitt2af85832015-03-25 13:40:13 -070041 uint32_t uniqueID() const { return fUniqueID; }
fmalita00d5c2c2014-08-21 08:53:26 -070042
fmalita228a6f22014-08-28 13:59:42 -070043 /**
44 * Serialize to a buffer.
45 */
46 void flatten(SkWriteBuffer&) const;
47
48 /**
49 * Recreate an SkTextBlob that was serialized into a buffer.
50 *
51 * @param SkReadBuffer Serialized blob data.
52 * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
53 * invalid.
54 */
reed2ab90572016-08-10 14:16:41 -070055 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
56
halcanary4f0a23a2016-08-30 11:58:33 -070057 enum GlyphPositioning : uint8_t {
fmalita00d5c2c2014-08-21 08:53:26 -070058 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
Mike Reedb99bedd2017-07-11 10:27:40 -040063 /**
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 */
Mike Reedaaa30562017-07-21 11:53:23 -040068 sk_sp<SkData> serialize(SkTypefaceCatalogerProc, void* ctx) const;
Mike Reedb99bedd2017-07-11 10:27:40 -040069
70 /**
Khushal42f8bc42018-04-03 17:51:40 -070071 * Similar to serialize above, but writes directly into |memory|. Returns bytes written or 0u
72 * if serialization failed due to insufficient size.
73 */
74 size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const;
75
76 /**
Mike Reedb99bedd2017-07-11 10:27:40 -040077 * Re-create a text blob previously serialized. Since the serialized form records the uniqueIDs
78 * of its typefaces, deserialization requires that the caller provide the corresponding
79 * SkTypefaces for those IDs.
80 */
Mike Reedaaa30562017-07-21 11:53:23 -040081 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size,
82 SkTypefaceResolverProc, void* ctx);
83
Mike Reed8e74cbc2017-12-08 13:20:01 -050084 sk_sp<SkData> serialize(const SkSerialProcs&) const;
Mike Reedf6eb1f92017-12-19 17:12:13 -050085 sk_sp<SkData> serialize() const;
Mike Reed8e74cbc2017-12-08 13:20:01 -050086 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkDeserialProcs&);
Mike Reedf6eb1f92017-12-19 17:12:13 -050087 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size);
Mike Reed8e74cbc2017-12-08 13:20:01 -050088
halcanary33779752015-10-27 14:01:05 -070089private:
mtkleinb47cd4b2016-08-09 12:20:04 -070090 friend class SkNVRefCnt<SkTextBlob>;
fmalita3c196de2014-09-20 05:40:22 -070091 class RunRecord;
92
Florin Malita3a9a7a32017-03-13 09:03:24 -040093 explicit SkTextBlob(const SkRect& bounds);
fmalita00d5c2c2014-08-21 08:53:26 -070094
mtkleinb47cd4b2016-08-09 12:20:04 -070095 ~SkTextBlob();
bsalomon07280312014-11-20 08:02:46 -080096
97 // Memory for objects of this class is created with sk_malloc rather than operator new and must
98 // be freed with sk_free.
Yong-Hwan Baek688a8e52018-07-09 14:14:26 +090099 void operator delete(void* p);
100 void* operator new(size_t);
101 void* operator new(size_t, void* p);
fmalita00d5c2c2014-08-21 08:53:26 -0700102
fmalitab7425172014-08-26 07:56:44 -0700103 static unsigned ScalarsPerGlyph(GlyphPositioning pos);
104
Florin Malita4a01ac92017-03-13 16:45:28 -0400105 // Call when this blob is part of the key to a cache entry. This allows the cache
106 // to know automatically those entries can be purged when this SkTextBlob is deleted.
Jim Van Verth474d6872017-12-14 13:00:05 -0500107 void notifyAddedToCache(uint32_t cacheID) const {
108 fCacheID.store(cacheID);
Florin Malita4a01ac92017-03-13 16:45:28 -0400109 }
110
Herb Derby8a6348e2018-07-12 15:30:35 -0400111 friend class SkGlyphRunList;
Florin Malita4a01ac92017-03-13 16:45:28 -0400112 friend class GrTextBlobCache;
fmalita00d5c2c2014-08-21 08:53:26 -0700113 friend class SkTextBlobBuilder;
halcanary33779752015-10-27 14:01:05 -0700114 friend class SkTextBlobRunIterator;
fmalita00d5c2c2014-08-21 08:53:26 -0700115
Jim Van Verth474d6872017-12-14 13:00:05 -0500116 const SkRect fBounds;
117 const uint32_t fUniqueID;
118 mutable SkAtomic<uint32_t> fCacheID;
fmalita00d5c2c2014-08-21 08:53:26 -0700119
fmalita3c196de2014-09-20 05:40:22 -0700120 SkDEBUGCODE(size_t fStorageSize;)
fmalita00d5c2c2014-08-21 08:53:26 -0700121
fmalita3c196de2014-09-20 05:40:22 -0700122 // The actual payload resides in externally-managed storage, following the object.
123 // (see the .cpp for more details)
fmalita00d5c2c2014-08-21 08:53:26 -0700124
125 typedef SkRefCnt INHERITED;
126};
127
128/** \class SkTextBlobBuilder
129
130 Helper class for constructing SkTextBlobs.
131 */
jbroman3053dfa2014-08-25 06:22:12 -0700132class SK_API SkTextBlobBuilder {
fmalita00d5c2c2014-08-21 08:53:26 -0700133public:
fmalita3c196de2014-09-20 05:40:22 -0700134 SkTextBlobBuilder();
fmalita00d5c2c2014-08-21 08:53:26 -0700135
136 ~SkTextBlobBuilder();
137
138 /**
Florin Malita3a9a7a32017-03-13 09:03:24 -0400139 * Returns an immutable SkTextBlob for the current runs/glyphs,
140 * or nullptr if no runs were allocated.
141 *
142 * The builder is reset and can be reused.
fmalita00d5c2c2014-08-21 08:53:26 -0700143 */
reed2ab90572016-08-10 14:16:41 -0700144 sk_sp<SkTextBlob> make();
145
fmalita00d5c2c2014-08-21 08:53:26 -0700146 /**
147 * Glyph and position buffers associated with a run.
148 *
halcanary4f0a23a2016-08-30 11:58:33 -0700149 * A run is a sequence of glyphs sharing the same font metrics
150 * and positioning mode.
151 *
152 * If textByteCount is 0, utf8text and clusters will be NULL (no
153 * character information will be associated with the glyphs).
154 *
155 * utf8text will point to a buffer of size textByteCount bytes.
156 *
157 * clusters (if not NULL) will point to an array of size count.
158 * For each glyph, give the byte-offset into the text for the
159 * first byte in the first character in that glyph's cluster.
160 * Each value in the array should be an integer less than
161 * textByteCount. Values in the array should either be
162 * monotonically increasing (left-to-right text) or monotonically
163 * decreasing (right-to-left text). This definiton is conviently
164 * the same as used by Harfbuzz's hb_glyph_info_t::cluster field,
165 * except that Harfbuzz interleaves glyphs and clusters.
fmalita00d5c2c2014-08-21 08:53:26 -0700166 */
167 struct RunBuffer {
halcanaryd0e95a52016-07-25 07:18:12 -0700168 SkGlyphID* glyphs;
fmalita00d5c2c2014-08-21 08:53:26 -0700169 SkScalar* pos;
halcanary4f0a23a2016-08-30 11:58:33 -0700170 char* utf8text;
171 uint32_t* clusters;
fmalita00d5c2c2014-08-21 08:53:26 -0700172 };
173
174 /**
175 * Allocates a new default-positioned run and returns its writable glyph buffer
176 * for direct manipulation.
177 *
178 * @param font The font to be used for this run.
179 * @param count Number of glyphs.
180 * @param x,y Position within the blob.
halcanary4f0a23a2016-08-30 11:58:33 -0700181 * @param textByteCount length of the original UTF-8 text that
182 * corresponds to this sequence of glyphs. If 0,
183 * text will not be included in the textblob.
184 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700185 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
186 * be used when computing the blob bounds, to avoid re-measuring.
187 *
188 * @return A writable glyph buffer, valid until the next allocRun() or
189 * build() call. The buffer is guaranteed to hold @count@ glyphs.
190 */
halcanary4f0a23a2016-08-30 11:58:33 -0700191 const RunBuffer& allocRunText(const SkPaint& font,
192 int count,
193 SkScalar x,
194 SkScalar y,
195 int textByteCount,
196 SkString lang,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400197 const SkRect* bounds = nullptr);
fmalita00d5c2c2014-08-21 08:53:26 -0700198 const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400199 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700200 return this->allocRunText(font, count, x, y, 0, SkString(), bounds);
201 }
fmalita00d5c2c2014-08-21 08:53:26 -0700202
203 /**
204 * Allocates a new horizontally-positioned run and returns its writable glyph and position
205 * buffers for direct manipulation.
206 *
207 * @param font The font to be used for this run.
208 * @param count Number of glyphs.
209 * @param y Vertical offset within the blob.
halcanary4f0a23a2016-08-30 11:58:33 -0700210 * @param textByteCount length of the original UTF-8 text that
211 * corresponds to this sequence of glyphs. If 0,
212 * text will not be included in the textblob.
213 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700214 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
215 * be used when computing the blob bounds, to avoid re-measuring.
216 *
217 * @return Writable glyph and position buffers, valid until the next allocRun()
218 * or build() call. The buffers are guaranteed to hold @count@ elements.
219 */
halcanary4f0a23a2016-08-30 11:58:33 -0700220 const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
221 int textByteCount, SkString lang,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400222 const SkRect* bounds = nullptr);
fmalita00d5c2c2014-08-21 08:53:26 -0700223 const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400224 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700225 return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds);
226 }
fmalita00d5c2c2014-08-21 08:53:26 -0700227
228 /**
229 * Allocates a new fully-positioned run and returns its writable glyph and position
230 * buffers for direct manipulation.
231 *
232 * @param font The font to be used for this run.
233 * @param count Number of glyphs.
halcanary4f0a23a2016-08-30 11:58:33 -0700234 * @param textByteCount length of the original UTF-8 text that
235 * corresponds to this sequence of glyphs. If 0,
236 * text will not be included in the textblob.
237 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700238 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
239 * be used when computing the blob bounds, to avoid re-measuring.
240 *
241 * @return Writable glyph and position buffers, valid until the next allocRun()
242 * or build() call. The glyph buffer and position buffer are
243 * guaranteed to hold @count@ and 2 * @count@ elements, respectively.
244 */
halcanary4f0a23a2016-08-30 11:58:33 -0700245 const RunBuffer& allocRunTextPos(const SkPaint& font, int count,
246 int textByteCount, SkString lang,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400247 const SkRect* bounds = nullptr);
halcanary4f0a23a2016-08-30 11:58:33 -0700248 const RunBuffer& allocRunPos(const SkPaint& font, int count,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400249 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700250 return this->allocRunTextPos(font, count, 0, SkString(), bounds);
251 }
fmalita00d5c2c2014-08-21 08:53:26 -0700252
253private:
fmalita3c196de2014-09-20 05:40:22 -0700254 void reserve(size_t size);
fmalita00d5c2c2014-08-21 08:53:26 -0700255 void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
halcanary4f0a23a2016-08-30 11:58:33 -0700256 int count, int textBytes, SkPoint offset, const SkRect* bounds);
fmalita3c196de2014-09-20 05:40:22 -0700257 bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
Florin Malitad923a712017-11-22 10:11:12 -0500258 uint32_t count, SkPoint offset);
fmalita00d5c2c2014-08-21 08:53:26 -0700259 void updateDeferredBounds();
260
fmalita3dc40ac2015-01-28 10:56:06 -0800261 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
262 static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
263
fmalita3c196de2014-09-20 05:40:22 -0700264 SkAutoTMalloc<uint8_t> fStorage;
265 size_t fStorageSize;
266 size_t fStorageUsed;
fmalita00d5c2c2014-08-21 08:53:26 -0700267
fmalita3c196de2014-09-20 05:40:22 -0700268 SkRect fBounds;
269 int fRunCount;
270 bool fDeferredBounds;
271 size_t fLastRun; // index into fStorage
fmalita00d5c2c2014-08-21 08:53:26 -0700272
fmalita3c196de2014-09-20 05:40:22 -0700273 RunBuffer fCurrentRunBuffer;
fmalita00d5c2c2014-08-21 08:53:26 -0700274};
275
276#endif // SkTextBlob_DEFINED