blob: 149e652513303777e46bd9d55e0e9e151d53873e [file] [log] [blame]
Cary Clark53c87692018-07-17 08:59:34 -04001/*
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
Herb Derby434377a2018-10-02 16:48:17 -040011#include "SkColorFilter.h"
12#include "SkDrawLooper.h"
13#include "SkImageFilter.h"
14#include "SkMaskFilter.h"
15#include "SkPaintPriv.h"
16#include "SkPathEffect.h"
17#include "SkSafeMath.h"
18#include "SkShader.h"
Cary Clark53c87692018-07-17 08:59:34 -040019#include "SkTextBlob.h"
Herb Derby434377a2018-10-02 16:48:17 -040020#include "SkTypeface.h"
Cary Clark53c87692018-07-17 08:59:34 -040021
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
Cary Clarke12a0902018-08-09 10:07:33 -040042class SkTextBlobBuilderPriv {
43public:
44 static const SkTextBlobBuilder::RunBuffer& AllocRunText(SkTextBlobBuilder* builder,
45 const SkPaint& 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 }
Ben Wagner41e40472018-09-24 13:01:54 -040049 static const SkTextBlobBuilder::RunBuffer& AllocRunTextPosH(SkTextBlobBuilder* builder,
50 const SkPaint& 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 }
Cary Clarke12a0902018-08-09 10:07:33 -040054 static const SkTextBlobBuilder::RunBuffer& AllocRunTextPos(SkTextBlobBuilder* builder,
55 const SkPaint& font, int count, int textByteCount, SkString lang,
56 const SkRect* bounds = nullptr) {
57 return builder->allocRunTextPos(font, count, textByteCount, lang, bounds);
58 }
59};
60
Herb Derby434377a2018-10-02 16:48:17 -040061// TODO(fmalita): replace with SkFont.
62class SkRunFont : SkNoncopyable {
63public:
64 SkRunFont(const SkPaint& paint);
65
66 void applyToPaint(SkPaint* paint) const;
67
68 bool operator==(const SkRunFont& other) const;
69
70 bool operator!=(const SkRunFont& other) const {
71 return !(*this == other);
72 }
73
74 uint32_t flags() const { return fFlags; }
75
76private:
77 friend SkPaint;
78 const static uint32_t kFlagsMask =
79 SkPaint::kAntiAlias_Flag |
80 SkPaint::kFakeBoldText_Flag |
81 SkPaint::kLinearText_Flag |
82 SkPaint::kSubpixelText_Flag |
83 SkPaint::kLCDRenderText_Flag |
84 SkPaint::kEmbeddedBitmapText_Flag |
Mike Reedc88cc772018-10-23 12:05:47 -040085 SkPaint::kAutoHinting_Flag ;
Herb Derby434377a2018-10-02 16:48:17 -040086
87 SkScalar fSize;
88 SkScalar fScaleX;
89
90 // Keep this sk_sp off the first position, to avoid interfering with SkNoncopyable
91 // empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694).
92 sk_sp<SkTypeface> fTypeface;
93 SkScalar fSkewX;
94
Mike Reedfbebece2018-11-07 15:15:15 -050095 static_assert(static_cast<unsigned>(kFull_SkFontHinting) < 4, "insufficient_hinting_bits");
Herb Derby434377a2018-10-02 16:48:17 -040096 uint32_t fHinting : 2;
97 static_assert((kFlagsMask & 0xffff) == kFlagsMask, "insufficient_flags_bits");
98 uint32_t fFlags : 16;
99
100 typedef SkNoncopyable INHERITED;
101};
102
103//
104// Textblob data is laid out into externally-managed storage as follows:
105//
106// -----------------------------------------------------------------------------
107// | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
108// -----------------------------------------------------------------------------
109//
110// Each run record describes a text blob run, and can be used to determine the (implicit)
111// location of the following record.
112//
113// Extended Textblob runs have more data after the Pos[] array:
114//
115// -------------------------------------------------------------------------
116// ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ...
117// -------------------------------------------------------------------------
118//
119// To determine the length of the extended run data, the TextSize must be read.
120//
121// Extended Textblob runs may be mixed with non-extended runs.
122
123SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
124
125class SkTextBlob::RunRecord {
126public:
127 RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos)
128 : fFont(font)
129 , fCount(count)
130 , fOffset(offset)
131 , fFlags(pos) {
132 SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask);
133
134 SkDEBUGCODE(fMagic = kRunRecordMagic);
135 if (textSize > 0) {
136 fFlags |= kExtended_Flag;
137 *this->textSizePtr() = textSize;
138 }
139 }
140
141 uint32_t glyphCount() const {
142 return fCount;
143 }
144
145 const SkPoint& offset() const {
146 return fOffset;
147 }
148
149 const SkRunFont& font() const {
150 return fFont;
151 }
152
153 GlyphPositioning positioning() const {
154 return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
155 }
156
157 uint16_t* glyphBuffer() const {
158 static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
159 // Glyphs are stored immediately following the record.
160 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
161 }
162
163 SkScalar* posBuffer() const {
164 // Position scalars follow the (aligned) glyph buffer.
165 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
166 SkAlign4(fCount * sizeof(uint16_t)));
167 }
168
169 uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
170
171 uint32_t* clusterBuffer() const {
172 // clusters follow the textSize.
173 return isExtended() ? 1 + this->textSizePtr() : nullptr;
174 }
175
176 char* textBuffer() const {
177 return isExtended()
178 ? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
179 : nullptr;
180 }
181
182 static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
183 SkTextBlob::GlyphPositioning positioning,
184 SkSafeMath* safe);
185
186 static const RunRecord* First(const SkTextBlob* blob);
187
188 static const RunRecord* Next(const RunRecord* run);
189
190 void validate(const uint8_t* storageTop) const;
191
192private:
193 friend class SkTextBlobBuilder;
194
195 enum Flags {
196 kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
197 kLast_Flag = 0x04, // set for the last blob run
198 kExtended_Flag = 0x08, // set for runs with text/cluster info
199 };
200
201 static const RunRecord* NextUnchecked(const RunRecord* run);
202
203 static size_t PosCount(uint32_t glyphCount,
204 SkTextBlob::GlyphPositioning positioning,
205 SkSafeMath* safe);
206
207 uint32_t* textSizePtr() const;
208
209 void grow(uint32_t count);
210
211 bool isExtended() const {
212 return fFlags & kExtended_Flag;
213 }
214
215 SkRunFont fFont;
216 uint32_t fCount;
217 SkPoint fOffset;
218 uint32_t fFlags;
219
220 SkDEBUGCODE(unsigned fMagic;)
221};
222
223// (paint->getFlags() & ~kFlagsMask) | fFlags
224inline SkPaint::SkPaint(const SkPaint& basePaint, const SkRunFont& runFont)
225 : fTypeface{runFont.fTypeface}
226 , fPathEffect{basePaint.fPathEffect}
227 , fShader{basePaint.fShader}
228 , fMaskFilter{basePaint.fMaskFilter}
229 , fColorFilter{basePaint.fColorFilter}
230 , fDrawLooper{basePaint.fDrawLooper}
231 , fImageFilter{basePaint.fImageFilter}
232 , fTextSize{runFont.fSize}
233 , fTextScaleX{runFont.fScaleX}
234 , fTextSkewX{runFont.fSkewX}
235 , fColor4f{basePaint.fColor4f}
236 , fWidth{basePaint.fWidth}
237 , fMiterLimit{basePaint.fMiterLimit}
238 , fBlendMode{basePaint.fBlendMode}
239 , fBitfieldsUInt{(basePaint.fBitfieldsUInt & ~SkRunFont::kFlagsMask) | runFont.fFlags} {
240 fBitfields.fTextEncoding = kGlyphID_TextEncoding;
241 fBitfields.fHinting = runFont.fHinting;
Herb Derby434377a2018-10-02 16:48:17 -0400242}
243
Florin Malitaab54e732018-07-27 09:47:15 -0400244/**
245 * Iterate through all of the text runs of the text blob. For example:
246 * for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
247 * .....
248 * }
249 */
250class SkTextBlobRunIterator {
251public:
252 SkTextBlobRunIterator(const SkTextBlob* blob);
253
254 enum GlyphPositioning : uint8_t {
255 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph.
256 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph.
257 kFull_Positioning = 2 // Point positioning -- two scalars per glyph.
258 };
259
Herb Derby434377a2018-10-02 16:48:17 -0400260 bool done() const {
261 return !fCurrentRun;
262 }
Florin Malitaab54e732018-07-27 09:47:15 -0400263 void next();
264
Herb Derby434377a2018-10-02 16:48:17 -0400265 uint32_t glyphCount() const {
266 SkASSERT(!this->done());
267 return fCurrentRun->glyphCount();
268 }
269 const uint16_t* glyphs() const {
270 SkASSERT(!this->done());
271 return fCurrentRun->glyphBuffer();
272 }
273 const SkScalar* pos() const {
274 SkASSERT(!this->done());
275 return fCurrentRun->posBuffer();
276 }
277 const SkPoint& offset() const {
278 SkASSERT(!this->done());
279 return fCurrentRun->offset();
280 }
281 const SkRunFont& runFont() const {
282 SkASSERT(!this->done());
283 return fCurrentRun->font();
284 }
Florin Malitaab54e732018-07-27 09:47:15 -0400285 void applyFontToPaint(SkPaint*) const;
286 GlyphPositioning positioning() const;
Herb Derby434377a2018-10-02 16:48:17 -0400287 uint32_t* clusters() const {
288 SkASSERT(!this->done());
289 return fCurrentRun->clusterBuffer();
290 }
291 uint32_t textSize() const {
292 SkASSERT(!this->done());
293 return fCurrentRun->textSize();
294 }
295 char* text() const {
296 SkASSERT(!this->done());
297 return fCurrentRun->textBuffer();
298 }
Florin Malitaab54e732018-07-27 09:47:15 -0400299
300 bool isLCD() const;
301
302private:
303 const SkTextBlob::RunRecord* fCurrentRun;
304
305 SkDEBUGCODE(uint8_t* fStorageTop;)
306};
307
Cary Clark53c87692018-07-17 08:59:34 -0400308#endif // SkTextBlobPriv_DEFINED