Coverage Report

Created: 2024-05-20 07:14

/src/skia/modules/skparagraph/src/OneLineShaper.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2019 Google LLC.
2
#ifndef LineBreaker_DEFINED
3
#define LineBreaker_DEFINED
4
5
#include <functional>  // std::function
6
#include <queue>
7
#include "include/core/SkSpan.h"
8
#include "modules/skparagraph/include/TextStyle.h"
9
#include "modules/skparagraph/src/ParagraphImpl.h"
10
#include "modules/skparagraph/src/Run.h"
11
12
namespace skia {
13
namespace textlayout {
14
15
class ParagraphImpl;
16
class OneLineShaper : public SkShaper::RunHandler {
17
public:
18
    explicit OneLineShaper(ParagraphImpl* paragraph)
19
        : fParagraph(paragraph)
20
        , fHeight(0.0f)
21
        , fUseHalfLeading(false)
22
        , fBaselineShift(0.0f)
23
        , fAdvance(SkPoint::Make(0.0f, 0.0f))
24
        , fUnresolvedGlyphs(0)
25
0
        , fUniqueRunId(paragraph->fRuns.size()){ }
26
27
    bool shape();
28
29
0
    size_t unresolvedGlyphs() { return fUnresolvedGlyphs; }
30
31
    /**
32
     * This method is based on definition of https://unicode.org/reports/tr51/#def_emoji_sequence
33
     * It determines if the string begins with an emoji sequence and,
34
     * if so, return the first codepoint, moving 'begin' pointer to the next once.
35
     * Otherwise it does not move the pointer and returns -1.
36
     */
37
    static SkUnichar getEmojiSequenceStart(SkUnicode* unicode, const char** begin, const char* end);
38
39
private:
40
41
    struct RunBlock {
42
0
        RunBlock() : fRun(nullptr) { }
43
44
        // First unresolved block
45
0
        explicit RunBlock(TextRange text) : fRun(nullptr), fText(text) { }
46
47
        RunBlock(std::shared_ptr<Run> run, TextRange text, GlyphRange glyphs, size_t score)
48
            : fRun(std::move(run))
49
            , fText(text)
50
0
            , fGlyphs(glyphs) { }
51
52
        // Entire run comes as one block fully resolved
53
        explicit RunBlock(std::shared_ptr<Run> run)
54
            : fRun(std::move(run))
55
            , fText(fRun->fTextRange)
56
0
            , fGlyphs(GlyphRange(0, fRun->size())) { }
57
58
        std::shared_ptr<Run> fRun;
59
        TextRange fText;
60
        GlyphRange fGlyphs;
61
0
        bool isFullyResolved() { return fRun != nullptr && fGlyphs.width() == fRun->size(); }
62
    };
63
64
    using ShapeVisitor =
65
            std::function<SkScalar(TextRange textRange, SkSpan<Block>, SkScalar&, TextIndex, uint8_t)>;
66
    bool iterateThroughShapingRegions(const ShapeVisitor& shape);
67
68
    using ShapeSingleFontVisitor =
69
            std::function<void(Block, skia_private::TArray<SkShaper::Feature>)>;
70
    void iterateThroughFontStyles(
71
            TextRange textRange, SkSpan<Block> styleSpan, const ShapeSingleFontVisitor& visitor);
72
73
    enum Resolved {
74
        Nothing,
75
        Something,
76
        Everything
77
    };
78
79
    using TypefaceVisitor = std::function<Resolved(sk_sp<SkTypeface> typeface)>;
80
    void matchResolvedFonts(const TextStyle& textStyle, const TypefaceVisitor& visitor);
81
#ifdef SK_DEBUG
82
    void printState();
83
#endif
84
    void finish(const Block& block, SkScalar height, SkScalar& advanceX);
85
86
0
    void beginLine() override {}
87
0
    void runInfo(const RunInfo&) override {}
88
0
    void commitRunInfo() override {}
89
0
    void commitLine() override {}
90
91
0
    Buffer runBuffer(const RunInfo& info) override {
92
0
        fCurrentRun = std::make_shared<Run>(fParagraph,
93
0
                                           info,
94
0
                                           fCurrentText.start,
95
0
                                           fHeight,
96
0
                                           fUseHalfLeading,
97
0
                                           fBaselineShift,
98
0
                                           ++fUniqueRunId,
99
0
                                           fAdvance.fX);
100
0
        return fCurrentRun->newRunBuffer();
101
0
    }
102
103
    void commitRunBuffer(const RunInfo&) override;
104
105
    TextRange clusteredText(GlyphRange& glyphs);
106
0
    ClusterIndex clusterIndex(GlyphIndex glyph) {
107
0
        return fCurrentText.start + fCurrentRun->fClusterIndexes[glyph];
108
0
    }
109
    void addFullyResolved();
110
    void addUnresolvedWithRun(GlyphRange glyphRange);
111
    void sortOutGlyphs(std::function<void(GlyphRange)>&& sortOutUnresolvedBLock);
112
    ClusterRange normalizeTextRange(GlyphRange glyphRange);
113
    void fillGaps(size_t);
114
115
    ParagraphImpl* fParagraph;
116
    TextRange fCurrentText;
117
    SkScalar fHeight;
118
    bool fUseHalfLeading;
119
    SkScalar fBaselineShift;
120
    SkVector fAdvance;
121
    size_t fUnresolvedGlyphs;
122
    size_t fUniqueRunId;
123
124
    // TODO: Something that is not thead-safe since we don't need it
125
    std::shared_ptr<Run> fCurrentRun;
126
    std::deque<RunBlock> fUnresolvedBlocks;
127
    std::vector<RunBlock> fResolvedBlocks;
128
129
    // Keeping all resolved typefaces
130
    struct FontKey {
131
132
0
        FontKey() {}
133
134
        FontKey(SkUnichar unicode, SkFontStyle fontStyle, SkString locale)
135
0
            : fUnicode(unicode), fFontStyle(fontStyle), fLocale(std::move(locale)) { }
136
        SkUnichar fUnicode;
137
        SkFontStyle fFontStyle;
138
        SkString fLocale;
139
140
        bool operator==(const FontKey& other) const;
141
142
        struct Hasher {
143
            uint32_t operator()(const FontKey& key) const;
144
        };
145
    };
146
147
    skia_private::THashMap<FontKey, sk_sp<SkTypeface>, FontKey::Hasher> fFallbackFonts;
148
};
149
150
}  // namespace textlayout
151
}  // namespace skia
152
#endif