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