• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkColorFilter.h"
12 #include "SkDrawLooper.h"
13 #include "SkFont.h"
14 #include "SkImageFilter.h"
15 #include "SkMaskFilter.h"
16 #include "SkPaintPriv.h"
17 #include "SkPathEffect.h"
18 #include "SkSafeMath.h"
19 #include "SkShader.h"
20 #include "SkTextBlob.h"
21 #include "SkTypeface.h"
22 
23 class SkReadBuffer;
24 class SkWriteBuffer;
25 
26 class SkTextBlobPriv {
27 public:
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 
43 class SkTextBlobBuilderPriv {
44 public:
45     static const SkTextBlobBuilder::RunBuffer& AllocRunText(SkTextBlobBuilder* builder,
46             const SkFont& font, int count, SkScalar x, SkScalar y, int textByteCount,
47             SkString lang, const SkRect* bounds = nullptr) {
48         return builder->allocRunText(font, count, x, y, textByteCount, lang, bounds);
49     }
50     static const SkTextBlobBuilder::RunBuffer& AllocRunTextPosH(SkTextBlobBuilder* builder,
51             const SkFont& font, int count, SkScalar y, int textByteCount, SkString lang,
52             const SkRect* bounds = nullptr) {
53         return builder->allocRunTextPosH(font, count, y, textByteCount, lang, bounds);
54     }
55     static const SkTextBlobBuilder::RunBuffer& AllocRunTextPos(SkTextBlobBuilder* builder,
56             const SkFont& font, int count, int textByteCount, SkString lang,
57             const SkRect* bounds = nullptr) {
58         return builder->allocRunTextPos(font, count, textByteCount, lang, bounds);
59     }
60 };
61 
62 //
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 
82 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
83 
84 class SkTextBlob::RunRecord {
85 public:
RunRecord(uint32_t count,uint32_t textSize,const SkPoint & offset,const SkFont & font,GlyphPositioning pos)86     RunRecord(uint32_t count, uint32_t textSize,  const SkPoint& offset, const SkFont& font, GlyphPositioning pos)
87             : 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 
glyphCount()100     uint32_t glyphCount() const {
101         return fCount;
102     }
103 
offset()104     const SkPoint& offset() const {
105         return fOffset;
106     }
107 
font()108     const SkFont& font() const {
109         return fFont;
110     }
111 
positioning()112     GlyphPositioning positioning() const {
113         return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask);
114     }
115 
glyphBuffer()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     // can be aliased with pointBuffer() or xformBuffer()
posBuffer()123     SkScalar* posBuffer() const {
124         // Position scalars follow the (aligned) glyph buffer.
125         return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
126                                            SkAlign4(fCount * sizeof(uint16_t)));
127     }
128 
129     // alias for posBuffer()
pointBuffer()130     SkPoint* pointBuffer() const {
131         SkASSERT(this->positioning() == (GlyphPositioning)2);
132         return reinterpret_cast<SkPoint*>(this->posBuffer());
133     }
134 
135     // alias for posBuffer()
xformBuffer()136     SkRSXform* xformBuffer() const {
137         SkASSERT(this->positioning() == (GlyphPositioning)3);
138         return reinterpret_cast<SkRSXform*>(this->posBuffer());
139     }
140 
textSize()141     uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; }
142 
clusterBuffer()143     uint32_t* clusterBuffer() const {
144         // clusters follow the textSize.
145         return isExtended() ? 1 + this->textSizePtr() : nullptr;
146     }
147 
textBuffer()148     char* textBuffer() const {
149         return isExtended()
150                ? reinterpret_cast<char*>(this->clusterBuffer() + fCount)
151                : nullptr;
152     }
153 
154     static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
155                               SkTextBlob::GlyphPositioning positioning,
156                               SkSafeMath* safe);
157 
158     static const RunRecord* First(const SkTextBlob* blob);
159 
160     static const RunRecord* Next(const RunRecord* run);
161 
162     void validate(const uint8_t* storageTop) const;
163 
164 private:
165     friend class SkTextBlobBuilder;
166 
167     enum Flags {
168         kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
169         kLast_Flag        = 0x04, // set for the last blob run
170         kExtended_Flag    = 0x08, // set for runs with text/cluster info
171     };
172 
173     static const RunRecord* NextUnchecked(const RunRecord* run);
174 
175     static size_t PosCount(uint32_t glyphCount,
176                            SkTextBlob::GlyphPositioning positioning,
177                            SkSafeMath* safe);
178 
179     uint32_t* textSizePtr() const;
180 
181     void grow(uint32_t count);
182 
isExtended()183     bool isExtended() const {
184         return fFlags & kExtended_Flag;
185     }
186 
187     SkFont           fFont;
188     uint32_t         fCount;
189     SkPoint          fOffset;
190     uint32_t         fFlags;
191 
192     SkDEBUGCODE(unsigned fMagic;)
193 };
194 
195 /**
196  *  Iterate through all of the text runs of the text blob.  For example:
197  *    for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
198  *         .....
199  *    }
200  */
201 class SkTextBlobRunIterator {
202 public:
203     SkTextBlobRunIterator(const SkTextBlob* blob);
204 
205     enum GlyphPositioning : uint8_t {
206         kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
207         kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
208         kFull_Positioning         = 2, // Point positioning -- two scalars per glyph.
209         kRSXform_Positioning      = 3, // RSXform positioning -- four scalars per glyph.
210     };
211 
done()212     bool done() const {
213         return !fCurrentRun;
214     }
215     void next();
216 
glyphCount()217     uint32_t glyphCount() const {
218         SkASSERT(!this->done());
219         return fCurrentRun->glyphCount();
220     }
glyphs()221     const uint16_t* glyphs() const {
222         SkASSERT(!this->done());
223         return fCurrentRun->glyphBuffer();
224     }
pos()225     const SkScalar* pos() const {
226         SkASSERT(!this->done());
227         return fCurrentRun->posBuffer();
228     }
229     // alias for pos()
points()230     const SkPoint* points() const {
231         return fCurrentRun->pointBuffer();
232     }
233     // alias for pos()
xforms()234     const SkRSXform* xforms() const {
235         return fCurrentRun->xformBuffer();
236     }
offset()237     const SkPoint& offset() const {
238         SkASSERT(!this->done());
239         return fCurrentRun->offset();
240     }
font()241     const SkFont& font() const {
242         SkASSERT(!this->done());
243         return fCurrentRun->font();
244     }
245     GlyphPositioning positioning() const;
clusters()246     uint32_t* clusters() const {
247         SkASSERT(!this->done());
248         return fCurrentRun->clusterBuffer();
249     }
textSize()250     uint32_t textSize() const {
251         SkASSERT(!this->done());
252         return fCurrentRun->textSize();
253     }
text()254     char* text() const {
255         SkASSERT(!this->done());
256         return fCurrentRun->textBuffer();
257     }
258 
259     bool isLCD() const;
260 
261 private:
262     const SkTextBlob::RunRecord* fCurrentRun;
263 
264     SkDEBUGCODE(uint8_t* fStorageTop;)
265 };
266 
267 #endif // SkTextBlobPriv_DEFINED
268