• 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/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 
153     static size_t StorageSize(uint32_t glyphCount, uint32_t textSize,
154                               SkTextBlob::GlyphPositioning positioning,
155                               SkSafeMath* safe);
156 
157     static const RunRecord* First(const SkTextBlob* blob);
158 
159     static const RunRecord* Next(const RunRecord* run);
160 
161     void validate(const uint8_t* storageTop) const;
162 
163 private:
164     friend class SkTextBlobBuilder;
165 
166     enum Flags {
167         kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning
168         kLast_Flag        = 0x04, // set for the last blob run
169         kExtended_Flag    = 0x08, // set for runs with text/cluster info
170     };
171 
172     static const RunRecord* NextUnchecked(const RunRecord* run);
173 
174     static size_t PosCount(uint32_t glyphCount,
175                            SkTextBlob::GlyphPositioning positioning,
176                            SkSafeMath* safe);
177 
178     uint32_t* textSizePtr() const;
179 
180     void grow(uint32_t count);
181 
isExtended()182     bool isExtended() const {
183         return fFlags & kExtended_Flag;
184     }
185 
186     SkFont           fFont;
187     uint32_t         fCount;
188     SkPoint          fOffset;
189     uint32_t         fFlags;
190 
191     SkDEBUGCODE(unsigned fMagic;)
192 };
193 
194 /**
195  *  Iterate through all of the text runs of the text blob.  For example:
196  *    for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
197  *         .....
198  *    }
199  */
200 class SkTextBlobRunIterator {
201 public:
202     SkTextBlobRunIterator(const SkTextBlob* blob);
203 
204     enum GlyphPositioning : uint8_t {
205         kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
206         kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
207         kFull_Positioning         = 2, // Point positioning -- two scalars per glyph.
208         kRSXform_Positioning      = 3, // RSXform positioning -- four scalars per glyph.
209     };
210 
done()211     bool done() const {
212         return !fCurrentRun;
213     }
214     void next();
215 
glyphCount()216     uint32_t glyphCount() const {
217         SkASSERT(!this->done());
218         return fCurrentRun->glyphCount();
219     }
glyphs()220     const uint16_t* glyphs() const {
221         SkASSERT(!this->done());
222         return fCurrentRun->glyphBuffer();
223     }
pos()224     const SkScalar* pos() const {
225         SkASSERT(!this->done());
226         return fCurrentRun->posBuffer();
227     }
228     // alias for pos()
points()229     const SkPoint* points() const {
230         return fCurrentRun->pointBuffer();
231     }
232     // alias for pos()
xforms()233     const SkRSXform* xforms() const {
234         return fCurrentRun->xformBuffer();
235     }
offset()236     const SkPoint& offset() const {
237         SkASSERT(!this->done());
238         return fCurrentRun->offset();
239     }
font()240     const SkFont& font() const {
241         SkASSERT(!this->done());
242         return fCurrentRun->font();
243     }
244     GlyphPositioning positioning() const;
clusters()245     uint32_t* clusters() const {
246         SkASSERT(!this->done());
247         return fCurrentRun->clusterBuffer();
248     }
textSize()249     uint32_t textSize() const {
250         SkASSERT(!this->done());
251         return fCurrentRun->textSize();
252     }
text()253     char* text() const {
254         SkASSERT(!this->done());
255         return fCurrentRun->textBuffer();
256     }
257 
258     bool isLCD() const;
259 
260 private:
261     const SkTextBlob::RunRecord* fCurrentRun;
262 
263     SkDEBUGCODE(uint8_t* fStorageTop;)
264 };
265 
266 #endif // SkTextBlobPriv_DEFINED
267