blob: 499086dc31d6e1e2871d38b689a8f68aab0ce10b [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"
Mike Reedb3f4aac2018-12-05 15:40:29 -050013#include "SkFont.h"
Herb Derby434377a2018-10-02 16:48:17 -040014#include "SkImageFilter.h"
15#include "SkMaskFilter.h"
16#include "SkPaintPriv.h"
17#include "SkPathEffect.h"
18#include "SkSafeMath.h"
19#include "SkShader.h"
Cary Clark53c87692018-07-17 08:59:34 -040020#include "SkTextBlob.h"
Herb Derby434377a2018-10-02 16:48:17 -040021#include "SkTypeface.h"
Cary Clark53c87692018-07-17 08:59:34 -040022
23class SkReadBuffer;
24class SkWriteBuffer;
25
26class SkTextBlobPriv {
27public:
28 /**
29 * Serialize to a buffer.
30 */
31 static void Flatten(const SkTextBlob& , SkWriteBuffer&);
32
33 /**
34 * Recreate an SkTextBlob that was serialized into a buffer.
35 *
36 * @param SkReadBuffer Serialized blob data.
37 * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is
38 * invalid.
39 */
40 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&);
41};
42
Cary Clarke12a0902018-08-09 10:07:33 -040043class SkTextBlobBuilderPriv {
44public:
45 static const SkTextBlobBuilder::RunBuffer& AllocRunText(SkTextBlobBuilder* builder,
Mike Reed6d595682018-12-05 17:28:14 -050046 const SkFont& font, int count, SkScalar x, SkScalar y, int textByteCount,
Cary Clarke12a0902018-08-09 10:07:33 -040047 SkString lang, const SkRect* bounds = nullptr) {
48 return builder->allocRunText(font, count, x, y, textByteCount, lang, bounds);
49 }
Ben Wagner41e40472018-09-24 13:01:54 -040050 static const SkTextBlobBuilder::RunBuffer& AllocRunTextPosH(SkTextBlobBuilder* builder,
Mike Reed6d595682018-12-05 17:28:14 -050051 const SkFont& font, int count, SkScalar y, int textByteCount, SkString lang,
Ben Wagner41e40472018-09-24 13:01:54 -040052 const SkRect* bounds = nullptr) {
53 return builder->allocRunTextPosH(font, count, y, textByteCount, lang, bounds);
54 }
Cary Clarke12a0902018-08-09 10:07:33 -040055 static const SkTextBlobBuilder::RunBuffer& AllocRunTextPos(SkTextBlobBuilder* builder,
Mike Reed6d595682018-12-05 17:28:14 -050056 const SkFont& font, int count, int textByteCount, SkString lang,
Cary Clarke12a0902018-08-09 10:07:33 -040057 const SkRect* bounds = nullptr) {
58 return builder->allocRunTextPos(font, count, textByteCount, lang, bounds);
59 }
60};
61
Herb Derby434377a2018-10-02 16:48:17 -040062//
63// Textblob data is laid out into externally-managed storage as follows:
64//
65// -----------------------------------------------------------------------------
66// | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
67// -----------------------------------------------------------------------------
68//
69// Each run record describes a text blob run, and can be used to determine the (implicit)
70// location of the following record.
71//
72// Extended Textblob runs have more data after the Pos[] array:
73//
74// -------------------------------------------------------------------------
75// ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ...
76// -------------------------------------------------------------------------
77//
78// To determine the length of the extended run data, the TextSize must be read.
79//
80// Extended Textblob runs may be mixed with non-extended runs.
81
82SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
83
84class SkTextBlob::RunRecord {
85public:
Mike Reedb3f4aac2018-12-05 15:40:29 -050086 RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkFont& font, GlyphPositioning pos)
Herb Derby434377a2018-10-02 16:48:17 -040087 : fFont(font)
88 , fCount(count)
89 , fOffset(offset)
90 , fFlags(pos) {
91 SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask);
92
93 SkDEBUGCODE(fMagic = kRunRecordMagic);
94 if (textSize > 0) {
95 fFlags |= kExtended_Flag;
96 *this->textSizePtr() = textSize;
97 }
98 }
99
100 uint32_t glyphCount() const {
101 return fCount;
102 }
103
104 const SkPoint& offset() const {
105 return fOffset;
106 }
107
Mike Reed7b7ab592018-12-05 21:32:05 -0500108 const SkFont& font() const {
Herb Derby434377a2018-10-02 16:48:17 -0400109 return fFont;
110 }
111
112 GlyphPositioning positioning() const {
113 return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
114 }
115
116 uint16_t* glyphBuffer() const {
117 static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
118 // Glyphs are stored immediately following the record.
119 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
120 }
121
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 uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
129
130 uint32_t* clusterBuffer() const {
131 // clusters follow the textSize.
132 return isExtended() ? 1 + this->textSizePtr() : nullptr;
133 }
134
135 char* textBuffer() const {
136 return isExtended()
137 ? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
138 : nullptr;
139 }
140
141 static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
142 SkTextBlob::GlyphPositioning positioning,
143 SkSafeMath* safe);
144
145 static const RunRecord* First(const SkTextBlob* blob);
146
147 static const RunRecord* Next(const RunRecord* run);
148
149 void validate(const uint8_t* storageTop) const;
150
151private:
152 friend class SkTextBlobBuilder;
153
154 enum Flags {
155 kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
156 kLast_Flag = 0x04, // set for the last blob run
157 kExtended_Flag = 0x08, // set for runs with text/cluster info
158 };
159
160 static const RunRecord* NextUnchecked(const RunRecord* run);
161
162 static size_t PosCount(uint32_t glyphCount,
163 SkTextBlob::GlyphPositioning positioning,
164 SkSafeMath* safe);
165
166 uint32_t* textSizePtr() const;
167
168 void grow(uint32_t count);
169
170 bool isExtended() const {
171 return fFlags & kExtended_Flag;
172 }
173
Mike Reed7b7ab592018-12-05 21:32:05 -0500174 SkFont fFont;
Herb Derby434377a2018-10-02 16:48:17 -0400175 uint32_t fCount;
176 SkPoint fOffset;
177 uint32_t fFlags;
178
179 SkDEBUGCODE(unsigned fMagic;)
180};
181
Florin Malitaab54e732018-07-27 09:47:15 -0400182/**
183 * Iterate through all of the text runs of the text blob. For example:
184 * for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
185 * .....
186 * }
187 */
188class SkTextBlobRunIterator {
189public:
190 SkTextBlobRunIterator(const SkTextBlob* blob);
191
192 enum GlyphPositioning : uint8_t {
193 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph.
194 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph.
Mike Reed30cf62b2018-12-20 11:18:24 -0500195 kFull_Positioning = 2, // Point positioning -- two scalars per glyph.
196 kRSXform_Positioning = 3, // RSXform positioning -- four scalars per glyph.
Florin Malitaab54e732018-07-27 09:47:15 -0400197 };
198
Herb Derby434377a2018-10-02 16:48:17 -0400199 bool done() const {
200 return !fCurrentRun;
201 }
Florin Malitaab54e732018-07-27 09:47:15 -0400202 void next();
203
Herb Derby434377a2018-10-02 16:48:17 -0400204 uint32_t glyphCount() const {
205 SkASSERT(!this->done());
206 return fCurrentRun->glyphCount();
207 }
208 const uint16_t* glyphs() const {
209 SkASSERT(!this->done());
210 return fCurrentRun->glyphBuffer();
211 }
212 const SkScalar* pos() const {
213 SkASSERT(!this->done());
214 return fCurrentRun->posBuffer();
215 }
216 const SkPoint& offset() const {
217 SkASSERT(!this->done());
218 return fCurrentRun->offset();
219 }
Mike Reed6d595682018-12-05 17:28:14 -0500220 const SkFont& font() const {
221 SkASSERT(!this->done());
222 return fCurrentRun->font();
223 }
Florin Malitaab54e732018-07-27 09:47:15 -0400224 void applyFontToPaint(SkPaint*) const;
225 GlyphPositioning positioning() const;
Herb Derby434377a2018-10-02 16:48:17 -0400226 uint32_t* clusters() const {
227 SkASSERT(!this->done());
228 return fCurrentRun->clusterBuffer();
229 }
230 uint32_t textSize() const {
231 SkASSERT(!this->done());
232 return fCurrentRun->textSize();
233 }
234 char* text() const {
235 SkASSERT(!this->done());
236 return fCurrentRun->textBuffer();
237 }
Florin Malitaab54e732018-07-27 09:47:15 -0400238
239 bool isLCD() const;
240
241private:
242 const SkTextBlob::RunRecord* fCurrentRun;
243
244 SkDEBUGCODE(uint8_t* fStorageTop;)
245};
246
Cary Clark53c87692018-07-17 08:59:34 -0400247#endif // SkTextBlobPriv_DEFINED