Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/core/SkGlyph.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2006 The Android Open Source Project
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 SkGlyph_DEFINED
9
#define SkGlyph_DEFINED
10
11
#include "include/core/SkDrawable.h"
12
#include "include/core/SkPath.h"
13
#include "include/core/SkPicture.h"
14
#include "include/core/SkPoint.h"
15
#include "include/core/SkRect.h"
16
#include "include/core/SkRefCnt.h"
17
#include "include/core/SkScalar.h"
18
#include "include/core/SkString.h"
19
#include "include/core/SkTypes.h"
20
#include "include/private/base/SkDebug.h"
21
#include "include/private/base/SkFixed.h"
22
#include "include/private/base/SkTo.h"
23
#include "src/base/SkVx.h"
24
#include "src/core/SkChecksum.h"
25
#include "src/core/SkMask.h"
26
27
#include <algorithm>
28
#include <cmath>
29
#include <cstddef>
30
#include <cstdint>
31
#include <limits>
32
#include <optional>
33
34
class SkArenaAlloc;
35
class SkCanvas;
36
class SkGlyph;
37
class SkReadBuffer;
38
class SkScalerContext;
39
class SkWriteBuffer;
40
namespace sktext {
41
class StrikeForGPU;
42
}  // namespace sktext
43
44
// -- SkPackedGlyphID ------------------------------------------------------------------------------
45
// A combination of SkGlyphID and sub-pixel position information.
46
struct SkPackedGlyphID {
47
    inline static constexpr uint32_t kImpossibleID = ~0u;
48
    enum {
49
        // Lengths
50
        kGlyphIDLen     = 16u,
51
        kSubPixelPosLen = 2u,
52
53
        // Bit positions
54
        kSubPixelX = 0u,
55
        kGlyphID   = kSubPixelPosLen,
56
        kSubPixelY = kGlyphIDLen + kSubPixelPosLen,
57
        kEndData   = kGlyphIDLen + 2 * kSubPixelPosLen,
58
59
        // Masks
60
        kGlyphIDMask     = (1u << kGlyphIDLen) - 1,
61
        kSubPixelPosMask = (1u << kSubPixelPosLen) - 1,
62
        kMaskAll         = (1u << kEndData) - 1,
63
64
        // Location of sub pixel info in a fixed pointer number.
65
        kFixedPointBinaryPointPos = 16u,
66
        kFixedPointSubPixelPosBits = kFixedPointBinaryPointPos - kSubPixelPosLen,
67
    };
68
69
    inline static const constexpr SkScalar kSubpixelRound =
70
            1.f / (1u << (SkPackedGlyphID::kSubPixelPosLen + 1));
71
72
    inline static const constexpr SkIPoint kXYFieldMask{kSubPixelPosMask << kSubPixelX,
73
                                                        kSubPixelPosMask << kSubPixelY};
74
75
    struct Hash {
76
0
         uint32_t operator() (SkPackedGlyphID packedID) const {
77
0
            return packedID.hash();
78
0
        }
79
    };
80
81
    constexpr explicit SkPackedGlyphID(SkGlyphID glyphID)
82
1.01M
            : fID{(uint32_t)glyphID << kGlyphID} { }
83
84
    constexpr SkPackedGlyphID(SkGlyphID glyphID, SkFixed x, SkFixed y)
85
0
            : fID {PackIDXY(glyphID, x, y)} { }
86
87
    constexpr SkPackedGlyphID(SkGlyphID glyphID, uint32_t x, uint32_t y)
88
0
            : fID {PackIDSubXSubY(glyphID, x, y)} { }
89
90
    SkPackedGlyphID(SkGlyphID glyphID, SkPoint pt, SkIPoint mask)
91
196k
        : fID{PackIDSkPoint(glyphID, pt, mask)} { }
92
93
1.27M
    constexpr explicit SkPackedGlyphID(uint32_t v) : fID{v & kMaskAll} { }
94
69.4k
    constexpr SkPackedGlyphID() : fID{kImpossibleID} {}
95
96
1.14M
    bool operator==(const SkPackedGlyphID& that) const {
97
1.14M
        return fID == that.fID;
98
1.14M
    }
99
0
    bool operator!=(const SkPackedGlyphID& that) const {
100
0
        return !(*this == that);
101
0
    }
102
0
    bool operator<(SkPackedGlyphID that) const {
103
0
        return this->fID < that.fID;
104
0
    }
105
106
183k
    SkGlyphID glyphID() const {
107
183k
        return (fID >> kGlyphID) & kGlyphIDMask;
108
183k
    }
109
110
84.7k
    uint32_t value() const {
111
84.7k
        return fID;
112
84.7k
    }
113
114
28.5k
    SkFixed getSubXFixed() const {
115
28.5k
        return this->subToFixed(kSubPixelX);
116
28.5k
    }
117
118
28.5k
    SkFixed getSubYFixed() const {
119
28.5k
        return this->subToFixed(kSubPixelY);
120
28.5k
    }
121
122
1.37M
    uint32_t hash() const {
123
1.37M
        return SkChecksum::CheapMix(fID);
124
1.37M
    }
125
126
0
    SkString dump() const {
127
0
        SkString str;
128
0
        str.appendf("glyphID: %d, x: %d, y:%d", glyphID(), getSubXFixed(), getSubYFixed());
129
0
        return str;
130
0
    }
131
132
0
    SkString shortDump() const {
133
0
        SkString str;
134
0
        str.appendf("0x%x|%1u|%1u", this->glyphID(),
135
0
                                    this->subPixelField(kSubPixelX),
136
0
                                    this->subPixelField(kSubPixelY));
137
0
        return str;
138
0
    }
139
140
private:
141
0
    static constexpr uint32_t PackIDSubXSubY(SkGlyphID glyphID, uint32_t x, uint32_t y) {
142
0
        SkASSERT(x < (1u << kSubPixelPosLen));
143
0
        SkASSERT(y < (1u << kSubPixelPosLen));
144
0
145
0
        return (x << kSubPixelX) | (y << kSubPixelY) | (glyphID << kGlyphID);
146
0
    }
147
148
    // Assumptions: pt is properly rounded. mask is set for the x or y fields.
149
    //
150
    // A sub-pixel field is a number on the interval [2^kSubPixel, 2^(kSubPixel + kSubPixelPosLen)).
151
    // Where kSubPixel is either kSubPixelX or kSubPixelY. Given a number x on [0, 1) we can
152
    // generate a sub-pixel field using:
153
    //    sub-pixel-field = x * 2^(kSubPixel + kSubPixelPosLen)
154
    //
155
    // We can generate the integer sub-pixel field by &-ing the integer part of sub-filed with the
156
    // sub-pixel field mask.
157
    //    int-sub-pixel-field = int(sub-pixel-field) & (kSubPixelPosMask << kSubPixel)
158
    //
159
    // The last trick is to extend the range from [0, 1) to [0, 2). The extend range is
160
    // necessary because the modulo 1 calculation (pt - floor(pt)) generates numbers on [-1, 1).
161
    // This does not round (floor) properly when converting to integer. Adding one to the range
162
    // causes truncation and floor to be the same. Coincidentally, masking to produce the field also
163
    // removes the +1.
164
196k
    static uint32_t PackIDSkPoint(SkGlyphID glyphID, SkPoint pt, SkIPoint mask) {
165
    #if 0
166
        // TODO: why does this code not work on GCC 8.3 x86 Debug builds?
167
        using namespace skvx;
168
        using XY = Vec<2, float>;
169
        using SubXY = Vec<2, int>;
170
171
        const XY magic = {1.f * (1u << (kSubPixelPosLen + kSubPixelX)),
172
                          1.f * (1u << (kSubPixelPosLen + kSubPixelY))};
173
        XY pos{pt.x(), pt.y()};
174
        XY subPos = (pos - floor(pos)) + 1.0f;
175
        SubXY sub = cast<int>(subPos * magic) & SubXY{mask.x(), mask.y()};
176
    #else
177
196k
        const float magicX = 1.f * (1u << (kSubPixelPosLen + kSubPixelX)),
178
196k
                    magicY = 1.f * (1u << (kSubPixelPosLen + kSubPixelY));
179
180
196k
        float x = pt.x(),
181
196k
              y = pt.y();
182
196k
        x = (x - floorf(x)) + 1.0f;
183
196k
        y = (y - floorf(y)) + 1.0f;
184
196k
        int sub[] = {
185
196k
            (int)(x * magicX) & mask.x(),
186
196k
            (int)(y * magicY) & mask.y(),
187
196k
        };
188
196k
    #endif
189
190
196k
        SkASSERT(sub[0] / (1u << kSubPixelX) < (1u << kSubPixelPosLen));
191
196k
        SkASSERT(sub[1] / (1u << kSubPixelY) < (1u << kSubPixelPosLen));
192
196k
        return (glyphID << kGlyphID) | sub[0] | sub[1];
193
196k
    }
194
195
0
    static constexpr uint32_t PackIDXY(SkGlyphID glyphID, SkFixed x, SkFixed y) {
196
0
        return PackIDSubXSubY(glyphID, FixedToSub(x), FixedToSub(y));
197
0
    }
198
199
0
    static constexpr uint32_t FixedToSub(SkFixed n) {
200
0
        return ((uint32_t)n >> kFixedPointSubPixelPosBits) & kSubPixelPosMask;
201
0
    }
202
203
57.1k
    constexpr uint32_t subPixelField(uint32_t subPixelPosBit) const {
204
57.1k
        return (fID >> subPixelPosBit) & kSubPixelPosMask;
205
57.1k
    }
206
207
57.1k
    constexpr SkFixed subToFixed(uint32_t subPixelPosBit) const {
208
57.1k
        uint32_t subPixelPosition = this->subPixelField(subPixelPosBit);
209
57.1k
        return subPixelPosition << kFixedPointSubPixelPosBits;
210
57.1k
    }
211
212
    uint32_t fID;
213
};
214
215
// -- SkAxisAlignment ------------------------------------------------------------------------------
216
// SkAxisAlignment specifies the x component of a glyph's position is rounded when kX, and the y
217
// component is rounded when kY. If kNone then neither are rounded.
218
enum class SkAxisAlignment : uint32_t {
219
    kNone,
220
    kX,
221
    kY,
222
};
223
224
// round and ignorePositionMask are used to calculate the subpixel position of a glyph.
225
// The per component (x or y) calculation is:
226
//
227
//   subpixelOffset = (floor((viewportPosition + rounding) & mask) >> 14) & 3
228
//
229
// where mask is either 0 or ~0, and rounding is either
230
// 1/2 for non-subpixel or 1/8 for subpixel.
231
struct SkGlyphPositionRoundingSpec {
232
    SkGlyphPositionRoundingSpec(bool isSubpixel, SkAxisAlignment axisAlignment);
233
    const SkVector halfAxisSampleFreq;
234
    const SkIPoint ignorePositionMask;
235
    const SkIPoint ignorePositionFieldMask;
236
237
private:
238
    static SkVector HalfAxisSampleFreq(bool isSubpixel, SkAxisAlignment axisAlignment);
239
    static SkIPoint IgnorePositionMask(bool isSubpixel, SkAxisAlignment axisAlignment);
240
    static SkIPoint IgnorePositionFieldMask(bool isSubpixel, SkAxisAlignment axisAlignment);
241
};
242
243
class SkGlyphRect;
244
namespace skglyph {
245
SkGlyphRect rect_union(SkGlyphRect, SkGlyphRect);
246
SkGlyphRect rect_intersection(SkGlyphRect, SkGlyphRect);
247
}  // namespace skglyph
248
249
// SkGlyphRect encodes rectangles with coordinates using SkScalar. It is specialized for
250
// rectangle union and intersection operations.
251
class SkGlyphRect {
252
public:
253
    SkGlyphRect() = default;
254
    SkGlyphRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
255
31.4k
            : fRect{-left, -top, right, bottom} { }
256
0
    bool empty() const {
257
0
        return -fRect[0] >= fRect[2] || -fRect[1] >= fRect[3];
258
0
    }
259
4.03k
    SkRect rect() const {
260
4.03k
        return SkRect::MakeLTRB(-fRect[0], -fRect[1], fRect[2], fRect[3]);
261
4.03k
    }
262
27.4k
    SkGlyphRect offset(SkScalar x, SkScalar y) const {
263
27.4k
        return SkGlyphRect{fRect + Storage{-x, -y, x, y}};
264
27.4k
    }
265
27.4k
    SkGlyphRect offset(SkPoint pt) const {
266
27.4k
        return this->offset(pt.x(), pt.y());
267
27.4k
    }
268
0
    SkGlyphRect scaleAndOffset(SkScalar scale, SkPoint offset) const {
269
0
        auto [x, y] = offset;
270
0
        return fRect * scale + Storage{-x, -y, x, y};
271
0
    }
272
6.14k
    SkGlyphRect inset(SkScalar dx, SkScalar dy) const {
273
6.14k
        return fRect - Storage{dx, dy, dx, dy};
274
6.14k
    }
275
27.4k
    SkPoint leftTop() const { return -this->negLeftTop(); }
276
0
    SkPoint rightBottom() const { return {fRect[2], fRect[3]}; }
277
0
    SkPoint widthHeight() const { return this->rightBottom() + negLeftTop(); }
278
    friend SkGlyphRect skglyph::rect_union(SkGlyphRect, SkGlyphRect);
279
    friend SkGlyphRect skglyph::rect_intersection(SkGlyphRect, SkGlyphRect);
280
281
private:
282
27.4k
    SkPoint negLeftTop() const { return {fRect[0], fRect[1]}; }
283
    using Storage = skvx::Vec<4, SkScalar>;
284
61.0k
    SkGlyphRect(Storage rect) : fRect{rect} { }
285
    Storage fRect;
286
};
287
288
namespace skglyph {
289
4.03k
inline SkGlyphRect empty_rect() {
290
4.03k
    constexpr SkScalar max = std::numeric_limits<SkScalar>::max();
291
4.03k
    return {max, max, -max, -max};
292
4.03k
}
293
0
inline SkGlyphRect full_rect() {
294
0
    constexpr SkScalar max = std::numeric_limits<SkScalar>::max();
295
0
    return {-max, -max, max, max};
296
0
}
297
27.4k
inline SkGlyphRect rect_union(SkGlyphRect a, SkGlyphRect b) {
298
27.4k
    return skvx::max(a.fRect, b.fRect);
299
27.4k
}
300
0
inline SkGlyphRect rect_intersection(SkGlyphRect a, SkGlyphRect b) {
301
0
    return skvx::min(a.fRect, b.fRect);
302
0
}
303
304
enum class GlyphAction {
305
    kUnset,
306
    kAccept,
307
    kReject,
308
    kDrop,
309
    kSize,
310
};
311
312
enum ActionType {
313
    kDirectMask = 0,
314
    kDirectMaskCPU = 2,
315
    kMask = 4,
316
    kSDFT = 6,
317
    kPath = 8,
318
    kDrawable = 10,
319
};
320
321
enum ActionTypeSize {
322
    kTotalBits = 12
323
};
324
}  // namespace skglyph
325
326
// SkGlyphDigest contains a digest of information for making GPU drawing decisions. It can be
327
// referenced instead of the glyph itself in many situations. In the remote glyphs cache the
328
// SkGlyphDigest is the only information that needs to be stored in the cache.
329
class SkGlyphDigest {
330
public:
331
    // An atlas consists of plots, and plots hold glyphs. The minimum a plot can be is 256x256.
332
    // This means that the maximum size a glyph can be is 256x256.
333
    static constexpr uint16_t kSkSideTooBigForAtlas = 256;
334
335
    // Default ctor is only needed for the hash table.
336
    SkGlyphDigest() = default;
337
    SkGlyphDigest(size_t index, const SkGlyph& glyph);
338
805k
    int index()          const { return fIndex; }
339
0
    bool isEmpty()       const { return fIsEmpty; }
340
0
    bool isColor()       const { return fFormat == SkMask::kARGB32_Format; }
341
21.3k
    SkMask::Format maskFormat() const { return static_cast<SkMask::Format>(fFormat); }
342
343
1.78M
    skglyph::GlyphAction actionFor(skglyph::ActionType actionType) const {
344
1.78M
        return static_cast<skglyph::GlyphAction>((fActions >> actionType) & 0b11);
345
1.78M
    }
346
347
    void setActionFor(skglyph::ActionType, SkGlyph*, sktext::StrikeForGPU*);
348
349
18.3k
    uint16_t maxDimension() const {
350
18.3k
        return std::max(fWidth, fHeight);
351
18.3k
    }
352
353
17.8k
    bool fitsInAtlasDirect() const {
354
17.8k
        return this->maxDimension() <= kSkSideTooBigForAtlas;
355
17.8k
    }
356
357
29
    bool fitsInAtlasInterpolated() const {
358
        // Include the padding needed for interpolating the glyph when drawing.
359
29
        return this->maxDimension() <= kSkSideTooBigForAtlas - 2;
360
29
    }
361
362
27.4k
    SkGlyphRect bounds() const {
363
27.4k
        return SkGlyphRect(fLeft, fTop, (SkScalar)fLeft + fWidth, (SkScalar)fTop + fHeight);
364
27.4k
    }
365
366
    static bool FitsInAtlas(const SkGlyph& glyph);
367
368
    // GetKey and Hash implement the required methods for THashTable.
369
1.27M
    static SkPackedGlyphID GetKey(SkGlyphDigest digest) {
370
1.27M
        return SkPackedGlyphID{SkTo<uint32_t>(digest.fPackedID)};
371
1.27M
    }
372
1.35M
    static uint32_t Hash(SkPackedGlyphID packedID) {
373
1.35M
        return packedID.hash();
374
1.35M
    }
375
376
private:
377
40.5k
    void setAction(skglyph::ActionType actionType, skglyph::GlyphAction action) {
378
40.5k
        using namespace skglyph;
379
40.5k
        SkASSERT(action != GlyphAction::kUnset);
380
40.5k
        SkASSERT(this->actionFor(actionType) == GlyphAction::kUnset);
381
40.5k
        const uint64_t mask = 0b11 << actionType;
382
40.5k
        fActions &= ~mask;
383
40.5k
        fActions |= SkTo<uint64_t>(action) << actionType;
384
40.5k
    }
385
386
    static_assert(SkPackedGlyphID::kEndData == 20);
387
    static_assert(SkMask::kCountMaskFormats <= 8);
388
    static_assert(SkTo<int>(skglyph::GlyphAction::kSize) <= 4);
389
    struct {
390
        uint64_t fPackedID : SkPackedGlyphID::kEndData;
391
        uint64_t fIndex    : SkPackedGlyphID::kEndData;
392
        uint64_t fIsEmpty  : 1;
393
        uint64_t fFormat   : 3;
394
        uint64_t fActions  : skglyph::ActionTypeSize::kTotalBits;
395
    };
396
    int16_t fLeft, fTop;
397
    uint16_t fWidth, fHeight;
398
};
399
400
class SkPictureBackedGlyphDrawable final : public SkDrawable {
401
public:
402
    static sk_sp<SkPictureBackedGlyphDrawable>MakeFromBuffer(SkReadBuffer& buffer);
403
    static void FlattenDrawable(SkWriteBuffer& buffer, SkDrawable* drawable);
404
    SkPictureBackedGlyphDrawable(sk_sp<SkPicture> self);
405
406
private:
407
    sk_sp<SkPicture> fPicture;
408
    SkRect onGetBounds() override;
409
    size_t onApproximateBytesUsed() override;
410
    void onDraw(SkCanvas* canvas) override;
411
};
412
413
class SkGlyph {
414
public:
415
    static std::optional<SkGlyph> MakeFromBuffer(SkReadBuffer&);
416
    // SkGlyph() is used for testing.
417
13.2k
    constexpr SkGlyph() : SkGlyph{SkPackedGlyphID()} { }
418
    SkGlyph(const SkGlyph&);
419
    SkGlyph& operator=(const SkGlyph&);
420
    SkGlyph(SkGlyph&&);
421
    SkGlyph& operator=(SkGlyph&&);
422
    ~SkGlyph();
423
100k
    constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} { }
424
425
261k
    SkVector advanceVector() const { return SkVector{fAdvanceX, fAdvanceY}; }
426
192k
    SkScalar advanceX() const { return fAdvanceX; }
427
0
    SkScalar advanceY() const { return fAdvanceY; }
428
429
183k
    SkGlyphID getGlyphID() const { return fID.glyphID(); }
430
140k
    SkPackedGlyphID getPackedID() const { return fID; }
431
5.24k
    SkFixed getSubXFixed() const { return fID.getSubXFixed(); }
432
5.24k
    SkFixed getSubYFixed() const { return fID.getSubYFixed(); }
433
434
    size_t rowBytes() const;
435
    size_t rowBytesUsingFormat(SkMask::Format format) const;
436
437
    // Call this to set all the metrics fields to 0 (e.g. if the scaler
438
    // encounters an error measuring a glyph). Note: this does not alter the
439
    // fImage, fPath, fID, fMaskFormat fields.
440
    void zeroMetrics();
441
442
    SkMask mask() const;
443
444
    SkMask mask(SkPoint position) const;
445
446
    // Image
447
    // If we haven't already tried to associate an image with this glyph
448
    // (i.e. setImageHasBeenCalled() returns false), then use the
449
    // SkScalerContext or const void* argument to set the image.
450
    bool setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext);
451
    bool setImage(SkArenaAlloc* alloc, const void* image);
452
453
    // Merge the 'from' glyph into this glyph using alloc to allocate image data. Return the number
454
    // of bytes allocated. Copy the width, height, top, left, format, and image into this glyph
455
    // making a copy of the image using the alloc.
456
    size_t setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from);
457
458
    // Returns true if the image has been set.
459
15.0k
    bool setImageHasBeenCalled() const {
460
        // Check for empty bounds first to guard against fImage somehow being set.
461
15.0k
        return this->isEmpty() || fImage != nullptr || this->imageTooLarge();
462
15.0k
    }
463
464
    // Return a pointer to the path if the image exists, otherwise return nullptr.
465
17.1k
    const void* image() const { SkASSERT(this->setImageHasBeenCalled()); return fImage; }
466
467
    // Return the size of the image.
468
    size_t imageSize() const;
469
470
    // Path
471
    // If we haven't already tried to associate a path to this glyph
472
    // (i.e. setPathHasBeenCalled() returns false), then use the
473
    // SkScalerContext or SkPath argument to try to do so.  N.B. this
474
    // may still result in no path being associated with this glyph,
475
    // e.g. if you pass a null SkPath or the typeface is bitmap-only.
476
    //
477
    // This setPath() call is sticky... once you call it, the glyph
478
    // stays in its state permanently, ignoring any future calls.
479
    //
480
    // Returns true if this is the first time you called setPath()
481
    // and there actually is a path; call path() to get it.
482
    bool setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext);
483
    bool setPath(SkArenaAlloc* alloc, const SkPath* path, bool hairline, bool modified);
484
485
    // Returns true if that path has been set.
486
210k
    bool setPathHasBeenCalled() const { return fPathData != nullptr; }
487
488
    // Return a pointer to the path if it exists, otherwise return nullptr. Only works if the
489
    // path was previously set.
490
    const SkPath* path() const;
491
    bool pathIsHairline() const;
492
    bool pathIsModified() const;
493
494
    bool setDrawable(SkArenaAlloc* alloc, SkScalerContext* scalerContext);
495
    bool setDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable);
496
2.17k
    bool setDrawableHasBeenCalled() const { return fDrawableData != nullptr; }
497
    SkDrawable* drawable() const;
498
499
    // Format
500
0
    bool isColor() const { return fMaskFormat == SkMask::kARGB32_Format; }
501
213k
    SkMask::Format maskFormat() const { return fMaskFormat; }
502
    size_t formatAlignment() const;
503
504
    // Bounds
505
0
    int maxDimension() const { return std::max(fWidth, fHeight); }
506
18.8k
    SkIRect iRect() const { return SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight); }
507
241k
    SkRect rect()   const { return SkRect::MakeXYWH(fLeft, fTop, fWidth, fHeight);  }
508
0
    SkGlyphRect glyphRect() const {
509
0
        return SkGlyphRect(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
510
0
    }
511
85.3k
    int left()   const { return fLeft;   }
512
85.3k
    int top()    const { return fTop;    }
513
4.57M
    int width()  const { return fWidth;  }
514
98.4k
    int height() const { return fHeight; }
515
220k
    bool isEmpty() const {
516
220k
        return fWidth == 0 || fHeight == 0;
517
220k
    }
518
45.1k
    bool imageTooLarge() const { return fWidth >= kMaxGlyphWidth; }
519
520
13.3k
    uint16_t extraBits() const { return fScalerContextBits; }
521
522
    // Make sure that the intercept information is on the glyph and return it, or return it if it
523
    // already exists.
524
    // * bounds - [0] - top of underline; [1] - bottom of underline.
525
    // * scale, xPos - information about how wide the gap is.
526
    // * array - accumulated gaps for many characters if not null.
527
    // * count - the number of gaps.
528
    void ensureIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
529
                          SkScalar* array, int* count, SkArenaAlloc* alloc);
530
531
    // Deprecated. Do not use. The last use is in SkChromeRemoteCache, and will be deleted soon.
532
0
    void setImage(void* image) { fImage = image; }
533
534
    // Serialize/deserialize functions.
535
    // Flatten the metrics portions, but no drawing data.
536
    void flattenMetrics(SkWriteBuffer&) const;
537
538
    // Flatten just the the mask data.
539
    void flattenImage(SkWriteBuffer&) const;
540
541
    // Read the image data, store it in the alloc, and add it to the glyph.
542
    size_t addImageFromBuffer(SkReadBuffer&, SkArenaAlloc*);
543
544
    // Flatten just the path data.
545
    void flattenPath(SkWriteBuffer&) const;
546
547
    // Read the path data, create the glyph's path data in the alloc, and add it to the glyph.
548
    size_t addPathFromBuffer(SkReadBuffer&, SkArenaAlloc*);
549
550
    // Flatten just the drawable data.
551
    void flattenDrawable(SkWriteBuffer&) const;
552
553
    // Read the drawable data, create the glyph's drawable data in the alloc, and add it to the
554
    // glyph.
555
    size_t addDrawableFromBuffer(SkReadBuffer&, SkArenaAlloc*);
556
557
private:
558
    // There are two sides to an SkGlyph, the scaler side (things that create glyph data) have
559
    // access to all the fields. Scalers are assumed to maintain all the SkGlyph invariants. The
560
    // consumer side has a tighter interface.
561
    friend class SkScalerContext;
562
    friend class SkGlyphTestPeer;
563
564
    inline static constexpr uint16_t kMaxGlyphWidth = 1u << 13u;
565
566
    // Support horizontal and vertical skipping strike-through / underlines.
567
    // The caller walks the linked list looking for a match. For a horizontal underline,
568
    // the fBounds contains the top and bottom of the underline. The fInterval pair contains the
569
    // beginning and end of the intersection of the bounds and the glyph's path.
570
    // If interval[0] >= interval[1], no intersection was found.
571
    struct Intercept {
572
        Intercept* fNext;
573
        SkScalar   fBounds[2];    // for horz underlines, the boundaries in Y
574
        SkScalar   fInterval[2];  // the outside intersections of the axis and the glyph
575
    };
576
577
    struct PathData {
578
        Intercept* fIntercept{nullptr};
579
        SkPath     fPath;
580
        bool       fHasPath{false};
581
        // A normal user-path will have patheffects applied to it and eventually become a dev-path.
582
        // A dev-path is always a fill-path, except when it is hairline.
583
        // The fPath is a dev-path, so sidecar the paths hairline status.
584
        // This allows the user to avoid filling paths which should not be filled.
585
        bool       fHairline{false};
586
        // This is set if the path is significantly different from what a reasonable interpreter of
587
        // the underlying font data would produce. This is set if any non-identity matrix, stroke,
588
        // path effect, emboldening, etc is applied.
589
        // This allows Document implementations to know if a glyph should be drawn out of the font
590
        // data or needs to be embedded differently.
591
        bool       fModified{false};
592
    };
593
594
    struct DrawableData {
595
        Intercept* fIntercept{nullptr};
596
        sk_sp<SkDrawable> fDrawable;
597
        bool fHasDrawable{false};
598
    };
599
600
    size_t allocImage(SkArenaAlloc* alloc);
601
602
0
    void installImage(void* imageData) {
603
0
        SkASSERT(!this->setImageHasBeenCalled());
604
0
        fImage = imageData;
605
0
    }
Unexecuted instantiation: SkGlyph::installImage(void*)
Unexecuted instantiation: SkGlyph::installImage(void*)
606
607
    // path == nullptr indicates that there is no path.
608
    void installPath(SkArenaAlloc* alloc, const SkPath* path, bool hairline, bool modified);
609
610
    // drawable == nullptr indicates that there is no path.
611
    void installDrawable(SkArenaAlloc* alloc, sk_sp<SkDrawable> drawable);
612
613
    // The width and height of the glyph mask.
614
    uint16_t  fWidth  = 0,
615
              fHeight = 0;
616
617
    // The offset from the glyphs origin on the baseline to the top left of the glyph mask.
618
    int16_t   fTop  = 0,
619
              fLeft = 0;
620
621
    // fImage must remain null if the glyph is empty or if width > kMaxGlyphWidth.
622
    void*     fImage    = nullptr;
623
624
    // Path data has tricky state. If the glyph isEmpty, then fPathData should always be nullptr,
625
    // else if fPathData is not null, then a path has been requested. The fPath field of fPathData
626
    // may still be null after the request meaning that there is no path for this glyph.
627
    PathData* fPathData = nullptr;
628
    DrawableData* fDrawableData = nullptr;
629
630
    // The advance for this glyph.
631
    float     fAdvanceX = 0,
632
              fAdvanceY = 0;
633
634
    SkMask::Format fMaskFormat{SkMask::kBW_Format};
635
636
    // Used by the SkScalerContext to pass state from generateMetrics to generateImage.
637
    // Usually specifies which glyph representation was used to generate the metrics.
638
    uint16_t  fScalerContextBits = 0;
639
640
    // An SkGlyph can be created with just a packedID, but generally speaking some glyph factory
641
    // needs to actually fill out the glyph before it can be used as part of that system.
642
    SkDEBUGCODE(bool fAdvancesBoundsFormatAndInitialPathDone{false};)
643
644
    SkPackedGlyphID fID;
645
};
646
647
#endif