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