blob: 956c6a092dfd1cf8ab86ebc38389938ae2a7981e [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
fmalita00d5c2c2014-08-21 08:53:26 -070020/** \class SkTextBlob
21
22 SkTextBlob combines multiple text runs into an immutable, ref-counted structure.
23*/
mtkleinb47cd4b2016-08-09 12:20:04 -070024class SK_API SkTextBlob final : public SkNVRefCnt<SkTextBlob> {
fmalita00d5c2c2014-08-21 08:53:26 -070025public:
26 /**
fmalita3dc40ac2015-01-28 10:56:06 -080027 * Returns a conservative blob bounding box.
fmalita00d5c2c2014-08-21 08:53:26 -070028 */
29 const SkRect& bounds() const { return fBounds; }
30
31 /**
32 * Return a non-zero, unique value representing the text blob.
33 */
joshualitt2af85832015-03-25 13:40:13 -070034 uint32_t uniqueID() const { return fUniqueID; }
fmalita00d5c2c2014-08-21 08:53:26 -070035
fmalita228a6f22014-08-28 13:59:42 -070036 /**
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 */
reed2ab90572016-08-10 14:16:41 -070048 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
49
50 static const SkTextBlob* CreateFromBuffer(SkReadBuffer& buffer) {
51 return MakeFromBuffer(buffer).release();
52 }
fmalita228a6f22014-08-28 13:59:42 -070053
halcanary4f0a23a2016-08-30 11:58:33 -070054 enum GlyphPositioning : uint8_t {
fmalita00d5c2c2014-08-21 08:53:26 -070055 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
halcanary33779752015-10-27 14:01:05 -070060private:
mtkleinb47cd4b2016-08-09 12:20:04 -070061 friend class SkNVRefCnt<SkTextBlob>;
fmalita3c196de2014-09-20 05:40:22 -070062 class RunRecord;
63
Florin Malita3a9a7a32017-03-13 09:03:24 -040064 explicit SkTextBlob(const SkRect& bounds);
fmalita00d5c2c2014-08-21 08:53:26 -070065
mtkleinb47cd4b2016-08-09 12:20:04 -070066 ~SkTextBlob();
bsalomon07280312014-11-20 08:02:46 -080067
68 // Memory for objects of this class is created with sk_malloc rather than operator new and must
69 // be freed with sk_free.
70 void operator delete(void* p) { sk_free(p); }
71 void* operator new(size_t) {
72 SkFAIL("All blobs are created by placement new.");
73 return sk_malloc_throw(0);
74 }
75 void* operator new(size_t, void* p) { return p; }
fmalita00d5c2c2014-08-21 08:53:26 -070076
fmalitab7425172014-08-26 07:56:44 -070077 static unsigned ScalarsPerGlyph(GlyphPositioning pos);
78
Florin Malita4a01ac92017-03-13 16:45:28 -040079 // 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.
81 void notifyAddedToCache() const {
82 fAddedToCache.store(true);
83 }
84
85 friend class GrTextBlobCache;
fmalita00d5c2c2014-08-21 08:53:26 -070086 friend class SkTextBlobBuilder;
halcanary33779752015-10-27 14:01:05 -070087 friend class SkTextBlobRunIterator;
fmalita00d5c2c2014-08-21 08:53:26 -070088
Florin Malita4a01ac92017-03-13 16:45:28 -040089 const SkRect fBounds;
90 const uint32_t fUniqueID;
91 mutable SkAtomic<bool> fAddedToCache;
fmalita00d5c2c2014-08-21 08:53:26 -070092
fmalita3c196de2014-09-20 05:40:22 -070093 SkDEBUGCODE(size_t fStorageSize;)
fmalita00d5c2c2014-08-21 08:53:26 -070094
fmalita3c196de2014-09-20 05:40:22 -070095 // The actual payload resides in externally-managed storage, following the object.
96 // (see the .cpp for more details)
fmalita00d5c2c2014-08-21 08:53:26 -070097
98 typedef SkRefCnt INHERITED;
99};
100
101/** \class SkTextBlobBuilder
102
103 Helper class for constructing SkTextBlobs.
104 */
jbroman3053dfa2014-08-25 06:22:12 -0700105class SK_API SkTextBlobBuilder {
fmalita00d5c2c2014-08-21 08:53:26 -0700106public:
fmalita3c196de2014-09-20 05:40:22 -0700107 SkTextBlobBuilder();
fmalita00d5c2c2014-08-21 08:53:26 -0700108
109 ~SkTextBlobBuilder();
110
111 /**
Florin Malita3a9a7a32017-03-13 09:03:24 -0400112 * 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.
fmalita00d5c2c2014-08-21 08:53:26 -0700116 */
reed2ab90572016-08-10 14:16:41 -0700117 sk_sp<SkTextBlob> make();
118
fmalita00d5c2c2014-08-21 08:53:26 -0700119 /**
120 * Glyph and position buffers associated with a run.
121 *
halcanary4f0a23a2016-08-30 11:58:33 -0700122 * 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.
fmalita00d5c2c2014-08-21 08:53:26 -0700139 */
140 struct RunBuffer {
halcanaryd0e95a52016-07-25 07:18:12 -0700141 SkGlyphID* glyphs;
fmalita00d5c2c2014-08-21 08:53:26 -0700142 SkScalar* pos;
halcanary4f0a23a2016-08-30 11:58:33 -0700143 char* utf8text;
144 uint32_t* clusters;
fmalita00d5c2c2014-08-21 08:53:26 -0700145 };
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.
halcanary4f0a23a2016-08-30 11:58:33 -0700154 * @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.
fmalita00d5c2c2014-08-21 08:53:26 -0700158 * @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 */
halcanary4f0a23a2016-08-30 11:58:33 -0700164 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);
fmalita00d5c2c2014-08-21 08:53:26 -0700171 const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
halcanary4f0a23a2016-08-30 11:58:33 -0700172 const SkRect* bounds = NULL) {
173 return this->allocRunText(font, count, x, y, 0, SkString(), bounds);
174 }
fmalita00d5c2c2014-08-21 08:53:26 -0700175
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.
halcanary4f0a23a2016-08-30 11:58:33 -0700183 * @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.
fmalita00d5c2c2014-08-21 08:53:26 -0700187 * @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 */
halcanary4f0a23a2016-08-30 11:58:33 -0700193 const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
194 int textByteCount, SkString lang,
195 const SkRect* bounds = NULL);
fmalita00d5c2c2014-08-21 08:53:26 -0700196 const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
halcanary4f0a23a2016-08-30 11:58:33 -0700197 const SkRect* bounds = NULL) {
198 return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds);
199 }
fmalita00d5c2c2014-08-21 08:53:26 -0700200
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.
halcanary4f0a23a2016-08-30 11:58:33 -0700207 * @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.
fmalita00d5c2c2014-08-21 08:53:26 -0700211 * @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 */
halcanary4f0a23a2016-08-30 11:58:33 -0700218 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 }
fmalita00d5c2c2014-08-21 08:53:26 -0700225
226private:
fmalita3c196de2014-09-20 05:40:22 -0700227 void reserve(size_t size);
fmalita00d5c2c2014-08-21 08:53:26 -0700228 void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
halcanary4f0a23a2016-08-30 11:58:33 -0700229 int count, int textBytes, SkPoint offset, const SkRect* bounds);
fmalita3c196de2014-09-20 05:40:22 -0700230 bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
231 int count, SkPoint offset);
fmalita00d5c2c2014-08-21 08:53:26 -0700232 void updateDeferredBounds();
233
fmalita3dc40ac2015-01-28 10:56:06 -0800234 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
235 static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
236
fmalita3c196de2014-09-20 05:40:22 -0700237 SkAutoTMalloc<uint8_t> fStorage;
238 size_t fStorageSize;
239 size_t fStorageUsed;
fmalita00d5c2c2014-08-21 08:53:26 -0700240
fmalita3c196de2014-09-20 05:40:22 -0700241 SkRect fBounds;
242 int fRunCount;
243 bool fDeferredBounds;
244 size_t fLastRun; // index into fStorage
fmalita00d5c2c2014-08-21 08:53:26 -0700245
fmalita3c196de2014-09-20 05:40:22 -0700246 RunBuffer fCurrentRunBuffer;
fmalita00d5c2c2014-08-21 08:53:26 -0700247};
248
249#endif // SkTextBlob_DEFINED