1 /*
2 * Copyright 2018 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 SkTextBlobPriv_DEFINED
9 #define SkTextBlobPriv_DEFINED
10
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkFont.h"
13 #include "include/core/SkImageFilter.h"
14 #include "include/core/SkMaskFilter.h"
15 #include "include/core/SkPathEffect.h"
16 #include "include/core/SkShader.h"
17 #include "include/core/SkTextBlob.h"
18 #include "include/core/SkTypeface.h"
19 #include "src/base/SkSafeMath.h"
20 #include "src/core/SkPaintPriv.h"
21
22 class SkReadBuffer;
23 class SkWriteBuffer;
24
25 class SkTextBlobPriv {
26 public:
27 /**
28 * Serialize to a buffer.
29 */
30 static void Flatten(const SkTextBlob& , SkWriteBuffer&);
31
32 /**
33 * Recreate an SkTextBlob that was serialized into a buffer.
34 *
35 * @param SkReadBuffer Serialized blob data.
36 * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
37 * invalid.
38 */
39 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
40
41 static bool HasRSXForm(const SkTextBlob& blob);
42 };
43
44 //
45 // Textblob data is laid out into externally-managed storage as follows:
46 //
47 // -----------------------------------------------------------------------------
48 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
49 // -----------------------------------------------------------------------------
50 //
51 // Each run record describes a text blob run, and can be used to determine the (implicit)
52 // location of the following record.
53 //
54 // Extended Textblob runs have more data after the Pos[] array:
55 //
56 // -------------------------------------------------------------------------
57 // ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ...
58 // -------------------------------------------------------------------------
59 //
60 // To determine the length of the extended run data, the TextSize must be read.
61 //
62 // Extended Textblob runs may be mixed with non-extended runs.
63
64 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
65
66 class SkTextBlob::RunRecord {
67 public:
RunRecord(uint32_t count,uint32_t textSize,const SkPoint & offset,const SkFont & font,GlyphPositioning pos)68 RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkFont& font, GlyphPositioning pos)
69 : fFont(font)
70 , fCount(count)
71 , fOffset(offset)
72 , fFlags(pos) {
73 SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask);
74
75 SkDEBUGCODE(fMagic = kRunRecordMagic);
76 if (textSize > 0) {
77 fFlags |= kExtended_Flag;
78 *this->textSizePtr() = textSize;
79 }
80 }
81
glyphCount()82 uint32_t glyphCount() const {
83 return fCount;
84 }
85
offset()86 const SkPoint& offset() const {
87 return fOffset;
88 }
89
font()90 const SkFont& font() const {
91 return fFont;
92 }
93
positioning()94 GlyphPositioning positioning() const {
95 return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
96 }
97
glyphBuffer()98 uint16_t* glyphBuffer() const {
99 static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
100 // Glyphs are stored immediately following the record.
101 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
102 }
103
104 // can be aliased with pointBuffer() or xformBuffer()
posBuffer()105 SkScalar* posBuffer() const {
106 // Position scalars follow the (aligned) glyph buffer.
107 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
108 SkAlign4(fCount * sizeof(uint16_t)));
109 }
110
111 // alias for posBuffer()
pointBuffer()112 SkPoint* pointBuffer() const {
113 SkASSERT(this->positioning() == (GlyphPositioning)2);
114 return reinterpret_cast<SkPoint*>(this->posBuffer());
115 }
116
117 // alias for posBuffer()
xformBuffer()118 SkRSXform* xformBuffer() const {
119 SkASSERT(this->positioning() == (GlyphPositioning)3);
120 return reinterpret_cast<SkRSXform*>(this->posBuffer());
121 }
122
textSize()123 uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
124
clusterBuffer()125 uint32_t* clusterBuffer() const {
126 // clusters follow the textSize.
127 return isExtended() ? 1 + this->textSizePtr() : nullptr;
128 }
129
textBuffer()130 char* textBuffer() const {
131 return isExtended()
132 ? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
133 : nullptr;
134 }
135
isLastRun()136 bool isLastRun() const { return SkToBool(fFlags & kLast_Flag); }
137
138 static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
139 SkTextBlob::GlyphPositioning positioning,
140 SkSafeMath* safe);
141
142 static const RunRecord* First(const SkTextBlob* blob);
143
144 static const RunRecord* Next(const RunRecord* run);
145
146 void validate(const uint8_t* storageTop) const;
147
148 private:
149 friend class SkTextBlobBuilder;
150
151 enum Flags {
152 kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
153 kLast_Flag = 0x04, // set for the last blob run
154 kExtended_Flag = 0x08, // set for runs with text/cluster info
155 };
156
157 static const RunRecord* NextUnchecked(const RunRecord* run);
158
159 static size_t PosCount(uint32_t glyphCount,
160 SkTextBlob::GlyphPositioning positioning,
161 SkSafeMath* safe);
162
163 uint32_t* textSizePtr() const;
164
165 void grow(uint32_t count);
166
isExtended()167 bool isExtended() const {
168 return fFlags & kExtended_Flag;
169 }
170
171 SkFont fFont;
172 uint32_t fCount;
173 SkPoint fOffset;
174 uint32_t fFlags;
175
176 SkDEBUGCODE(unsigned fMagic;)
177 };
178
179 /**
180 * Iterate through all of the text runs of the text blob. For example:
181 * for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
182 * .....
183 * }
184 */
185 class SkTextBlobRunIterator {
186 public:
187 SkTextBlobRunIterator(const SkTextBlob* blob);
188
189 enum GlyphPositioning : uint8_t {
190 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph.
191 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph.
192 kFull_Positioning = 2, // Point positioning -- two scalars per glyph.
193 kRSXform_Positioning = 3, // RSXform positioning -- four scalars per glyph.
194 };
195
done()196 bool done() const {
197 return !fCurrentRun;
198 }
199 void next();
200
glyphCount()201 uint32_t glyphCount() const {
202 SkASSERT(!this->done());
203 return fCurrentRun->glyphCount();
204 }
glyphs()205 const uint16_t* glyphs() const {
206 SkASSERT(!this->done());
207 return fCurrentRun->glyphBuffer();
208 }
pos()209 const SkScalar* pos() const {
210 SkASSERT(!this->done());
211 return fCurrentRun->posBuffer();
212 }
213 // alias for pos()
points()214 const SkPoint* points() const {
215 return fCurrentRun->pointBuffer();
216 }
217 // alias for pos()
xforms()218 const SkRSXform* xforms() const {
219 return fCurrentRun->xformBuffer();
220 }
offset()221 const SkPoint& offset() const {
222 SkASSERT(!this->done());
223 return fCurrentRun->offset();
224 }
font()225 const SkFont& font() const {
226 SkASSERT(!this->done());
227 return fCurrentRun->font();
228 }
229 GlyphPositioning positioning() const;
230 unsigned scalarsPerGlyph() const;
clusters()231 uint32_t* clusters() const {
232 SkASSERT(!this->done());
233 return fCurrentRun->clusterBuffer();
234 }
textSize()235 uint32_t textSize() const {
236 SkASSERT(!this->done());
237 return fCurrentRun->textSize();
238 }
text()239 char* text() const {
240 SkASSERT(!this->done());
241 return fCurrentRun->textBuffer();
242 }
243
244 bool isLCD() const;
245
246 private:
247 const SkTextBlob::RunRecord* fCurrentRun;
248
249 SkDEBUGCODE(uint8_t* fStorageTop;)
250 };
251
HasRSXForm(const SkTextBlob & blob)252 inline bool SkTextBlobPriv::HasRSXForm(const SkTextBlob& blob) {
253 for (SkTextBlobRunIterator i{&blob}; !i.done(); i.next()) {
254 if (i.positioning() == SkTextBlobRunIterator::kRSXform_Positioning) {
255 return true;
256 }
257 }
258 return false;
259 }
260
261 #endif // SkTextBlobPriv_DEFINED
262