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