blob: b27ec87773c8be0de6d9319dca35ade71faba131 [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 Reed8e74cbc2017-12-08 13:20:01 -050020struct SkSerialProcs;
21struct SkDeserialProcs;
22
Mike Reedaaa30562017-07-21 11:53:23 -040023typedef void (*SkTypefaceCatalogerProc)(SkTypeface*, void* ctx);
24typedef sk_sp<SkTypeface> (*SkTypefaceResolverProc)(uint32_t id, void* ctx);
Mike Reedb99bedd2017-07-11 10:27:40 -040025
fmalita00d5c2c2014-08-21 08:53:26 -070026/** \class SkTextBlob
27
28 SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
29*/
mtkleinb47cd4b2016-08-09 12:20:04 -070030class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
fmalita00d5c2c2014-08-21 08:53:26 -070031public:
32 /**
fmalita3dc40ac2015-01-28 10:56:06 -080033 * Returns a conservative blob bounding box.
fmalita00d5c2c2014-08-21 08:53:26 -070034 */
35 const SkRect& bounds() const { return fBounds; }
36
37 /**
38 * Return a non-zero, unique value representing the text blob.
39 */
joshualitt2af85832015-03-25 13:40:13 -070040 uint32_t uniqueID() const { return fUniqueID; }
fmalita00d5c2c2014-08-21 08:53:26 -070041
fmalita228a6f22014-08-28 13:59:42 -070042 /**
43 * Serialize to a buffer.
44 */
45 void flatten(SkWriteBuffer&) const;
46
47 /**
48 * Recreate an SkTextBlob that was serialized into a buffer.
49 *
50 * @param SkReadBuffer Serialized blob data.
51 * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
52 * invalid.
53 */
reed2ab90572016-08-10 14:16:41 -070054 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
55
halcanary4f0a23a2016-08-30 11:58:33 -070056 enum GlyphPositioning : uint8_t {
fmalita00d5c2c2014-08-21 08:53:26 -070057 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph.
58 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph.
59 kFull_Positioning = 2 // Point positioning -- two scalars per glyph.
60 };
61
Mike Reedb99bedd2017-07-11 10:27:40 -040062 /**
63 * Serialize the typeface into a data blob, storing type uniqueID of each referenced typeface.
64 * During this process, each time a typeface is encountered, it is passed to the catalog,
65 * allowing the caller to what typeface IDs will need to be resolved in Deserialize().
66 */
Mike Reedaaa30562017-07-21 11:53:23 -040067 sk_sp<SkData> serialize(SkTypefaceCatalogerProc, void* ctx) const;
Mike Reedb99bedd2017-07-11 10:27:40 -040068
69 /**
70 * Re-create a text blob previously serialized. Since the serialized form records the uniqueIDs
71 * of its typefaces, deserialization requires that the caller provide the corresponding
72 * SkTypefaces for those IDs.
73 */
Mike Reedaaa30562017-07-21 11:53:23 -040074 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size,
75 SkTypefaceResolverProc, void* ctx);
76
Mike Reed8e74cbc2017-12-08 13:20:01 -050077 sk_sp<SkData> serialize(const SkSerialProcs&) const;
78 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkDeserialProcs&);
79
halcanary33779752015-10-27 14:01:05 -070080private:
mtkleinb47cd4b2016-08-09 12:20:04 -070081 friend class SkNVRefCnt<SkTextBlob>;
fmalita3c196de2014-09-20 05:40:22 -070082 class RunRecord;
83
Florin Malita3a9a7a32017-03-13 09:03:24 -040084 explicit SkTextBlob(const SkRect& bounds);
fmalita00d5c2c2014-08-21 08:53:26 -070085
mtkleinb47cd4b2016-08-09 12:20:04 -070086 ~SkTextBlob();
bsalomon07280312014-11-20 08:02:46 -080087
88 // Memory for objects of this class is created with sk_malloc rather than operator new and must
89 // be freed with sk_free.
90 void operator delete(void* p) { sk_free(p); }
91 void* operator new(size_t) {
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040092 SK_ABORT("All blobs are created by placement new.");
bsalomon07280312014-11-20 08:02:46 -080093 return sk_malloc_throw(0);
94 }
95 void* operator new(size_t, void* p) { return p; }
fmalita00d5c2c2014-08-21 08:53:26 -070096
fmalitab7425172014-08-26 07:56:44 -070097 static unsigned ScalarsPerGlyph(GlyphPositioning pos);
98
Florin Malita4a01ac92017-03-13 16:45:28 -040099 // Call when this blob is part of the key to a cache entry. This allows the cache
100 // to know automatically those entries can be purged when this SkTextBlob is deleted.
Jim Van Verth474d6872017-12-14 13:00:05 -0500101 void notifyAddedToCache(uint32_t cacheID) const {
102 fCacheID.store(cacheID);
Florin Malita4a01ac92017-03-13 16:45:28 -0400103 }
104
105 friend class GrTextBlobCache;
fmalita00d5c2c2014-08-21 08:53:26 -0700106 friend class SkTextBlobBuilder;
halcanary33779752015-10-27 14:01:05 -0700107 friend class SkTextBlobRunIterator;
fmalita00d5c2c2014-08-21 08:53:26 -0700108
Jim Van Verth474d6872017-12-14 13:00:05 -0500109 const SkRect fBounds;
110 const uint32_t fUniqueID;
111 mutable SkAtomic<uint32_t> fCacheID;
fmalita00d5c2c2014-08-21 08:53:26 -0700112
fmalita3c196de2014-09-20 05:40:22 -0700113 SkDEBUGCODE(size_t fStorageSize;)
fmalita00d5c2c2014-08-21 08:53:26 -0700114
fmalita3c196de2014-09-20 05:40:22 -0700115 // The actual payload resides in externally-managed storage, following the object.
116 // (see the .cpp for more details)
fmalita00d5c2c2014-08-21 08:53:26 -0700117
118 typedef SkRefCnt INHERITED;
119};
120
121/** \class SkTextBlobBuilder
122
123 Helper class for constructing SkTextBlobs.
124 */
jbroman3053dfa2014-08-25 06:22:12 -0700125class SK_API SkTextBlobBuilder {
fmalita00d5c2c2014-08-21 08:53:26 -0700126public:
fmalita3c196de2014-09-20 05:40:22 -0700127 SkTextBlobBuilder();
fmalita00d5c2c2014-08-21 08:53:26 -0700128
129 ~SkTextBlobBuilder();
130
131 /**
Florin Malita3a9a7a32017-03-13 09:03:24 -0400132 * Returns an immutable SkTextBlob for the current runs/glyphs,
133 * or nullptr if no runs were allocated.
134 *
135 * The builder is reset and can be reused.
fmalita00d5c2c2014-08-21 08:53:26 -0700136 */
reed2ab90572016-08-10 14:16:41 -0700137 sk_sp<SkTextBlob> make();
138
fmalita00d5c2c2014-08-21 08:53:26 -0700139 /**
140 * Glyph and position buffers associated with a run.
141 *
halcanary4f0a23a2016-08-30 11:58:33 -0700142 * A run is a sequence of glyphs sharing the same font metrics
143 * and positioning mode.
144 *
145 * If textByteCount is 0, utf8text and clusters will be NULL (no
146 * character information will be associated with the glyphs).
147 *
148 * utf8text will point to a buffer of size textByteCount bytes.
149 *
150 * clusters (if not NULL) will point to an array of size count.
151 * For each glyph, give the byte-offset into the text for the
152 * first byte in the first character in that glyph's cluster.
153 * Each value in the array should be an integer less than
154 * textByteCount. Values in the array should either be
155 * monotonically increasing (left-to-right text) or monotonically
156 * decreasing (right-to-left text). This definiton is conviently
157 * the same as used by Harfbuzz's hb_glyph_info_t::cluster field,
158 * except that Harfbuzz interleaves glyphs and clusters.
fmalita00d5c2c2014-08-21 08:53:26 -0700159 */
160 struct RunBuffer {
halcanaryd0e95a52016-07-25 07:18:12 -0700161 SkGlyphID* glyphs;
fmalita00d5c2c2014-08-21 08:53:26 -0700162 SkScalar* pos;
halcanary4f0a23a2016-08-30 11:58:33 -0700163 char* utf8text;
164 uint32_t* clusters;
fmalita00d5c2c2014-08-21 08:53:26 -0700165 };
166
167 /**
168 * Allocates a new default-positioned run and returns its writable glyph buffer
169 * for direct manipulation.
170 *
171 * @param font The font to be used for this run.
172 * @param count Number of glyphs.
173 * @param x,y Position within the blob.
halcanary4f0a23a2016-08-30 11:58:33 -0700174 * @param textByteCount length of the original UTF-8 text that
175 * corresponds to this sequence of glyphs. If 0,
176 * text will not be included in the textblob.
177 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700178 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
179 * be used when computing the blob bounds, to avoid re-measuring.
180 *
181 * @return A writable glyph buffer, valid until the next allocRun() or
182 * build() call. The buffer is guaranteed to hold @count@ glyphs.
183 */
halcanary4f0a23a2016-08-30 11:58:33 -0700184 const RunBuffer& allocRunText(const SkPaint& font,
185 int count,
186 SkScalar x,
187 SkScalar y,
188 int textByteCount,
189 SkString lang,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400190 const SkRect* bounds = nullptr);
fmalita00d5c2c2014-08-21 08:53:26 -0700191 const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400192 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700193 return this->allocRunText(font, count, x, y, 0, SkString(), bounds);
194 }
fmalita00d5c2c2014-08-21 08:53:26 -0700195
196 /**
197 * Allocates a new horizontally-positioned run and returns its writable glyph and position
198 * buffers for direct manipulation.
199 *
200 * @param font The font to be used for this run.
201 * @param count Number of glyphs.
202 * @param y Vertical offset within the blob.
halcanary4f0a23a2016-08-30 11:58:33 -0700203 * @param textByteCount length of the original UTF-8 text that
204 * corresponds to this sequence of glyphs. If 0,
205 * text will not be included in the textblob.
206 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700207 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
208 * be used when computing the blob bounds, to avoid re-measuring.
209 *
210 * @return Writable glyph and position buffers, valid until the next allocRun()
211 * or build() call. The buffers are guaranteed to hold @count@ elements.
212 */
halcanary4f0a23a2016-08-30 11:58:33 -0700213 const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
214 int textByteCount, SkString lang,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400215 const SkRect* bounds = nullptr);
fmalita00d5c2c2014-08-21 08:53:26 -0700216 const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400217 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700218 return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds);
219 }
fmalita00d5c2c2014-08-21 08:53:26 -0700220
221 /**
222 * Allocates a new fully-positioned run and returns its writable glyph and position
223 * buffers for direct manipulation.
224 *
225 * @param font The font to be used for this run.
226 * @param count Number of glyphs.
halcanary4f0a23a2016-08-30 11:58:33 -0700227 * @param textByteCount length of the original UTF-8 text that
228 * corresponds to this sequence of glyphs. If 0,
229 * text will not be included in the textblob.
230 * @param lang Language code, currently unimplemented.
fmalita00d5c2c2014-08-21 08:53:26 -0700231 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
232 * be used when computing the blob bounds, to avoid re-measuring.
233 *
234 * @return Writable glyph and position buffers, valid until the next allocRun()
235 * or build() call. The glyph buffer and position buffer are
236 * guaranteed to hold @count@ and 2 * @count@ elements, respectively.
237 */
halcanary4f0a23a2016-08-30 11:58:33 -0700238 const RunBuffer& allocRunTextPos(const SkPaint& font, int count,
239 int textByteCount, SkString lang,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400240 const SkRect* bounds = nullptr);
halcanary4f0a23a2016-08-30 11:58:33 -0700241 const RunBuffer& allocRunPos(const SkPaint& font, int count,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400242 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700243 return this->allocRunTextPos(font, count, 0, SkString(), bounds);
244 }
fmalita00d5c2c2014-08-21 08:53:26 -0700245
246private:
fmalita3c196de2014-09-20 05:40:22 -0700247 void reserve(size_t size);
fmalita00d5c2c2014-08-21 08:53:26 -0700248 void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
halcanary4f0a23a2016-08-30 11:58:33 -0700249 int count, int textBytes, SkPoint offset, const SkRect* bounds);
fmalita3c196de2014-09-20 05:40:22 -0700250 bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
Florin Malitad923a712017-11-22 10:11:12 -0500251 uint32_t count, SkPoint offset);
fmalita00d5c2c2014-08-21 08:53:26 -0700252 void updateDeferredBounds();
253
fmalita3dc40ac2015-01-28 10:56:06 -0800254 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
255 static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
256
fmalita3c196de2014-09-20 05:40:22 -0700257 SkAutoTMalloc<uint8_t> fStorage;
258 size_t fStorageSize;
259 size_t fStorageUsed;
fmalita00d5c2c2014-08-21 08:53:26 -0700260
fmalita3c196de2014-09-20 05:40:22 -0700261 SkRect fBounds;
262 int fRunCount;
263 bool fDeferredBounds;
264 size_t fLastRun; // index into fStorage
fmalita00d5c2c2014-08-21 08:53:26 -0700265
fmalita3c196de2014-09-20 05:40:22 -0700266 RunBuffer fCurrentRunBuffer;
fmalita00d5c2c2014-08-21 08:53:26 -0700267};
268
269#endif // SkTextBlob_DEFINED