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 
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 
42 class SkTextBlobBuilderPriv {
43 public:
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 
81 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
82 
83 class SkTextBlob::RunRecord {
84 public:
RunRecord(uint32_t count,uint32_t textSize,const SkPoint & offset,const SkFont & font,GlyphPositioning pos)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 
glyphCount()99     uint32_t glyphCount() const {
100         return fCount;
101     }
102 
offset()103     const SkPoint& offset() const {
104         return fOffset;
105     }
106 
font()107     const SkFont& font() const {
108         return fFont;
109     }
110 
positioning()111     GlyphPositioning positioning() const {
112         return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
113     }
114 
glyphBuffer()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()
posBuffer()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()
pointBuffer()129     SkPoint* pointBuffer() const {
130         SkASSERT(this->positioning() == (GlyphPositioning)2);
131         return reinterpret_cast<SkPoint*>(this->posBuffer());
132     }
133 
134     // alias for posBuffer()
xformBuffer()135     SkRSXform* xformBuffer() const {
136         SkASSERT(this->positioning() == (GlyphPositioning)3);
137         return reinterpret_cast<SkRSXform*>(this->posBuffer());
138     }
139 
textSize()140     uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
141 
clusterBuffer()142     uint32_t* clusterBuffer() const {
143         // clusters follow the textSize.
144         return isExtended() ? 1 + this->textSizePtr() : nullptr;
145     }
146 
textBuffer()147     char* textBuffer() const {
148         return isExtended()
149                ? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
150                : nullptr;
151     }
152 
isLastRun()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 
165 private:
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 
isExtended()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  */
202 class SkTextBlobRunIterator {
203 public:
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 
done()213     bool done() const {
214         return !fCurrentRun;
215     }
216     void next();
217 
glyphCount()218     uint32_t glyphCount() const {
219         SkASSERT(!this->done());
220         return fCurrentRun->glyphCount();
221     }
glyphs()222     const uint16_t* glyphs() const {
223         SkASSERT(!this->done());
224         return fCurrentRun->glyphBuffer();
225     }
pos()226     const SkScalar* pos() const {
227         SkASSERT(!this->done());
228         return fCurrentRun->posBuffer();
229     }
230     // alias for pos()
points()231     const SkPoint* points() const {
232         return fCurrentRun->pointBuffer();
233     }
234     // alias for pos()
xforms()235     const SkRSXform* xforms() const {
236         return fCurrentRun->xformBuffer();
237     }
offset()238     const SkPoint& offset() const {
239         SkASSERT(!this->done());
240         return fCurrentRun->offset();
241     }
font()242     const SkFont& font() const {
243         SkASSERT(!this->done());
244         return fCurrentRun->font();
245     }
246     GlyphPositioning positioning() const;
clusters()247     uint32_t* clusters() const {
248         SkASSERT(!this->done());
249         return fCurrentRun->clusterBuffer();
250     }
textSize()251     uint32_t textSize() const {
252         SkASSERT(!this->done());
253         return fCurrentRun->textSize();
254     }
text()255     char* text() const {
256         SkASSERT(!this->done());
257         return fCurrentRun->textBuffer();
258     }
259 
260     bool isLCD() const;
261 
262 private:
263     const SkTextBlob::RunRecord* fCurrentRun;
264 
265     SkDEBUGCODE(uint8_t* fStorageTop;)
266 };
267 
268 #endif // SkTextBlobPriv_DEFINED
269