blob: 0276f324f8197d39b19e6a76ac8b508952a27d14 [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
Mike Reed8e74cbc2017-12-08 13:20:01 -050017struct SkSerialProcs;
18struct SkDeserialProcs;
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
Herb Derbyc3bc69f2018-07-27 16:28:01 -040036 static sk_sp<SkTextBlob> MakeFromText(
Herb Derby4b3a5152018-07-17 16:10:30 -040037 const void* text, size_t byteLength, const SkPaint& paint);
38
Cary Clarke12a0902018-08-09 10:07:33 -040039 static sk_sp<SkTextBlob> MakeFromString(const char* string, const SkPaint& paint) {
40 if (!string) {
41 return nullptr;
42 }
43 return MakeFromText(string, strlen(string), paint);
44 }
45
Mike Reedb99bedd2017-07-11 10:27:40 -040046 /**
Khushal42f8bc42018-04-03 17:51:40 -070047 * Similar to serialize above, but writes directly into |memory|. Returns bytes written or 0u
48 * if serialization failed due to insufficient size.
49 */
50 size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const;
51
Cary Clark785586a2018-07-19 10:07:01 -040052 sk_sp<SkData> serialize(const SkSerialProcs& procs) const;
Mike Reedaaa30562017-07-21 11:53:23 -040053
Cary Clark785586a2018-07-19 10:07:01 -040054 static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size,
55 const SkDeserialProcs& procs);
Mike Reed8e74cbc2017-12-08 13:20:01 -050056
halcanary33779752015-10-27 14:01:05 -070057private:
mtkleinb47cd4b2016-08-09 12:20:04 -070058 friend class SkNVRefCnt<SkTextBlob>;
fmalita3c196de2014-09-20 05:40:22 -070059 class RunRecord;
60
Florin Malitaab54e732018-07-27 09:47:15 -040061 enum GlyphPositioning : uint8_t;
62
Florin Malita3a9a7a32017-03-13 09:03:24 -040063 explicit SkTextBlob(const SkRect& bounds);
fmalita00d5c2c2014-08-21 08:53:26 -070064
mtkleinb47cd4b2016-08-09 12:20:04 -070065 ~SkTextBlob();
bsalomon07280312014-11-20 08:02:46 -080066
67 // Memory for objects of this class is created with sk_malloc rather than operator new and must
68 // be freed with sk_free.
Yong-Hwan Baek688a8e52018-07-09 14:14:26 +090069 void operator delete(void* p);
70 void* operator new(size_t);
71 void* operator new(size_t, void* p);
fmalita00d5c2c2014-08-21 08:53:26 -070072
fmalitab7425172014-08-26 07:56:44 -070073 static unsigned ScalarsPerGlyph(GlyphPositioning pos);
74
Florin Malita4a01ac92017-03-13 16:45:28 -040075 // Call when this blob is part of the key to a cache entry. This allows the cache
76 // to know automatically those entries can be purged when this SkTextBlob is deleted.
Jim Van Verth474d6872017-12-14 13:00:05 -050077 void notifyAddedToCache(uint32_t cacheID) const {
78 fCacheID.store(cacheID);
Florin Malita4a01ac92017-03-13 16:45:28 -040079 }
80
Herb Derby8a6348e2018-07-12 15:30:35 -040081 friend class SkGlyphRunList;
Florin Malita4a01ac92017-03-13 16:45:28 -040082 friend class GrTextBlobCache;
fmalita00d5c2c2014-08-21 08:53:26 -070083 friend class SkTextBlobBuilder;
Cary Clark53c87692018-07-17 08:59:34 -040084 friend class SkTextBlobPriv;
halcanary33779752015-10-27 14:01:05 -070085 friend class SkTextBlobRunIterator;
fmalita00d5c2c2014-08-21 08:53:26 -070086
Jim Van Verth474d6872017-12-14 13:00:05 -050087 const SkRect fBounds;
88 const uint32_t fUniqueID;
89 mutable SkAtomic<uint32_t> fCacheID;
fmalita00d5c2c2014-08-21 08:53:26 -070090
fmalita3c196de2014-09-20 05:40:22 -070091 SkDEBUGCODE(size_t fStorageSize;)
fmalita00d5c2c2014-08-21 08:53:26 -070092
fmalita3c196de2014-09-20 05:40:22 -070093 // The actual payload resides in externally-managed storage, following the object.
94 // (see the .cpp for more details)
fmalita00d5c2c2014-08-21 08:53:26 -070095
96 typedef SkRefCnt INHERITED;
97};
98
99/** \class SkTextBlobBuilder
100
101 Helper class for constructing SkTextBlobs.
102 */
jbroman3053dfa2014-08-25 06:22:12 -0700103class SK_API SkTextBlobBuilder {
fmalita00d5c2c2014-08-21 08:53:26 -0700104public:
fmalita3c196de2014-09-20 05:40:22 -0700105 SkTextBlobBuilder();
fmalita00d5c2c2014-08-21 08:53:26 -0700106
107 ~SkTextBlobBuilder();
108
109 /**
Florin Malita3a9a7a32017-03-13 09:03:24 -0400110 * Returns an immutable SkTextBlob for the current runs/glyphs,
111 * or nullptr if no runs were allocated.
112 *
113 * The builder is reset and can be reused.
fmalita00d5c2c2014-08-21 08:53:26 -0700114 */
reed2ab90572016-08-10 14:16:41 -0700115 sk_sp<SkTextBlob> make();
116
fmalita00d5c2c2014-08-21 08:53:26 -0700117 /**
118 * Glyph and position buffers associated with a run.
119 *
halcanary4f0a23a2016-08-30 11:58:33 -0700120 * A run is a sequence of glyphs sharing the same font metrics
121 * and positioning mode.
122 *
123 * If textByteCount is 0, utf8text and clusters will be NULL (no
124 * character information will be associated with the glyphs).
125 *
126 * utf8text will point to a buffer of size textByteCount bytes.
127 *
128 * clusters (if not NULL) will point to an array of size count.
129 * For each glyph, give the byte-offset into the text for the
130 * first byte in the first character in that glyph's cluster.
131 * Each value in the array should be an integer less than
132 * textByteCount. Values in the array should either be
133 * monotonically increasing (left-to-right text) or monotonically
134 * decreasing (right-to-left text). This definiton is conviently
135 * the same as used by Harfbuzz's hb_glyph_info_t::cluster field,
136 * except that Harfbuzz interleaves glyphs and clusters.
fmalita00d5c2c2014-08-21 08:53:26 -0700137 */
138 struct RunBuffer {
halcanaryd0e95a52016-07-25 07:18:12 -0700139 SkGlyphID* glyphs;
fmalita00d5c2c2014-08-21 08:53:26 -0700140 SkScalar* pos;
halcanary4f0a23a2016-08-30 11:58:33 -0700141 char* utf8text;
142 uint32_t* clusters;
fmalita00d5c2c2014-08-21 08:53:26 -0700143 };
144
145 /**
146 * Allocates a new default-positioned run and returns its writable glyph buffer
147 * for direct manipulation.
148 *
149 * @param font The font to be used for this run.
150 * @param count Number of glyphs.
151 * @param x,y Position within the blob.
152 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
153 * be used when computing the blob bounds, to avoid re-measuring.
154 *
155 * @return A writable glyph buffer, valid until the next allocRun() or
156 * build() call. The buffer is guaranteed to hold @count@ glyphs.
157 */
158 const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400159 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700160 return this->allocRunText(font, count, x, y, 0, SkString(), bounds);
161 }
fmalita00d5c2c2014-08-21 08:53:26 -0700162
163 /**
164 * Allocates a new horizontally-positioned run and returns its writable glyph and position
165 * buffers for direct manipulation.
166 *
167 * @param font The font to be used for this run.
168 * @param count Number of glyphs.
169 * @param y Vertical offset within the blob.
170 * @param bounds Optional run bounding box. If known in advance (!= NULL), it will
171 * be used when computing the blob bounds, to avoid re-measuring.
172 *
173 * @return Writable glyph and position buffers, valid until the next allocRun()
174 * or build() call. The buffers are guaranteed to hold @count@ elements.
175 */
176 const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400177 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700178 return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds);
179 }
fmalita00d5c2c2014-08-21 08:53:26 -0700180
181 /**
182 * Allocates a new fully-positioned run and returns its writable glyph and position
183 * buffers for direct manipulation.
184 *
185 * @param font The font to be used for this run.
186 * @param count Number of glyphs.
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 glyph buffer and position buffer are
192 * guaranteed to hold @count@ and 2 * @count@ elements, respectively.
193 */
halcanary4f0a23a2016-08-30 11:58:33 -0700194 const RunBuffer& allocRunPos(const SkPaint& font, int count,
Ben Wagnera93a14a2017-08-28 10:34:05 -0400195 const SkRect* bounds = nullptr) {
halcanary4f0a23a2016-08-30 11:58:33 -0700196 return this->allocRunTextPos(font, count, 0, SkString(), bounds);
197 }
fmalita00d5c2c2014-08-21 08:53:26 -0700198
199private:
Cary Clarke12a0902018-08-09 10:07:33 -0400200 const RunBuffer& allocRunText(const SkPaint& font,
201 int count,
202 SkScalar x,
203 SkScalar y,
204 int textByteCount,
205 SkString lang,
206 const SkRect* bounds = nullptr);
207 const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y,
208 int textByteCount, SkString lang,
209 const SkRect* bounds = nullptr);
210 const RunBuffer& allocRunTextPos(const SkPaint& font, int count,
211 int textByteCount, SkString lang,
212 const SkRect* bounds = nullptr);
fmalita3c196de2014-09-20 05:40:22 -0700213 void reserve(size_t size);
fmalita00d5c2c2014-08-21 08:53:26 -0700214 void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
halcanary4f0a23a2016-08-30 11:58:33 -0700215 int count, int textBytes, SkPoint offset, const SkRect* bounds);
fmalita3c196de2014-09-20 05:40:22 -0700216 bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
Florin Malitad923a712017-11-22 10:11:12 -0500217 uint32_t count, SkPoint offset);
fmalita00d5c2c2014-08-21 08:53:26 -0700218 void updateDeferredBounds();
219
fmalita3dc40ac2015-01-28 10:56:06 -0800220 static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&);
221 static SkRect TightRunBounds(const SkTextBlob::RunRecord&);
222
Cary Clarke12a0902018-08-09 10:07:33 -0400223 friend class SkTextBlobPriv;
224 friend class SkTextBlobBuilderPriv;
225
fmalita3c196de2014-09-20 05:40:22 -0700226 SkAutoTMalloc<uint8_t> fStorage;
227 size_t fStorageSize;
228 size_t fStorageUsed;
fmalita00d5c2c2014-08-21 08:53:26 -0700229
fmalita3c196de2014-09-20 05:40:22 -0700230 SkRect fBounds;
231 int fRunCount;
232 bool fDeferredBounds;
233 size_t fLastRun; // index into fStorage
fmalita00d5c2c2014-08-21 08:53:26 -0700234
fmalita3c196de2014-09-20 05:40:22 -0700235 RunBuffer fCurrentRunBuffer;
fmalita00d5c2c2014-08-21 08:53:26 -0700236};
237
238#endif // SkTextBlob_DEFINED