Coverage Report

Created: 2024-05-20 07:14

/src/skia/modules/skparagraph/include/TextStyle.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2019 Google LLC.
2
#ifndef TextStyle_DEFINED
3
#define TextStyle_DEFINED
4
5
#include <optional>
6
#include <vector>
7
#include "include/core/SkColor.h"
8
#include "include/core/SkFont.h"
9
#include "include/core/SkFontMetrics.h"
10
#include "include/core/SkFontStyle.h"
11
#include "include/core/SkPaint.h"
12
#include "include/core/SkScalar.h"
13
#include "modules/skparagraph/include/DartTypes.h"
14
#include "modules/skparagraph/include/FontArguments.h"
15
#include "modules/skparagraph/include/ParagraphPainter.h"
16
#include "modules/skparagraph/include/TextShadow.h"
17
18
// TODO: Make it external so the other platforms (Android) could use it
19
#define DEFAULT_FONT_FAMILY "sans-serif"
20
21
namespace skia {
22
namespace textlayout {
23
24
0
static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
25
0
    if (SkIsFinite(x)) {
26
0
        return SkScalarNearlyZero(x, tolerance);
27
0
    }
28
0
    return false;
29
0
}
Unexecuted instantiation: FuzzSkParagraph.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: FontCollection.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: ParagraphBuilderImpl.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: ParagraphCache.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: ParagraphImpl.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: ParagraphStyle.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: Run.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: TextLine.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: TextStyle.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: TextWrapper.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: Decorations.cpp:skia::textlayout::nearlyZero(float, float)
Unexecuted instantiation: OneLineShaper.cpp:skia::textlayout::nearlyZero(float, float)
30
31
0
static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) {
32
0
    if (SkIsFinite(x, y)) {
33
0
        return SkScalarNearlyEqual(x, y, tolerance);
34
0
    }
35
    // Inf == Inf, anything else is false
36
0
    return x == y;
37
0
}
Unexecuted instantiation: FuzzSkParagraph.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: FontCollection.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: ParagraphBuilderImpl.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: ParagraphCache.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: ParagraphImpl.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: ParagraphStyle.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: Run.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: TextLine.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: TextStyle.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: TextWrapper.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: Decorations.cpp:skia::textlayout::nearlyEqual(float, float, float)
Unexecuted instantiation: OneLineShaper.cpp:skia::textlayout::nearlyEqual(float, float, float)
38
39
// Multiple decorations can be applied at once. Ex: Underline and overline is
40
// (0x1 | 0x2)
41
enum TextDecoration {
42
    kNoDecoration = 0x0,
43
    kUnderline = 0x1,
44
    kOverline = 0x2,
45
    kLineThrough = 0x4,
46
};
47
constexpr TextDecoration AllTextDecorations[] = {
48
        kNoDecoration,
49
        kUnderline,
50
        kOverline,
51
        kLineThrough,
52
};
53
54
enum TextDecorationStyle { kSolid, kDouble, kDotted, kDashed, kWavy };
55
56
enum TextDecorationMode { kGaps, kThrough };
57
58
enum StyleType {
59
    kNone,
60
    kAllAttributes,
61
    kFont,
62
    kForeground,
63
    kBackground,
64
    kShadow,
65
    kDecorations,
66
    kLetterSpacing,
67
    kWordSpacing
68
};
69
70
struct Decoration {
71
    TextDecoration fType;
72
    TextDecorationMode fMode;
73
    SkColor fColor;
74
    TextDecorationStyle fStyle;
75
    SkScalar fThicknessMultiplier;
76
77
0
    bool operator==(const Decoration& other) const {
78
0
        return this->fType == other.fType &&
79
0
               this->fMode == other.fMode &&
80
0
               this->fColor == other.fColor &&
81
0
               this->fStyle == other.fStyle &&
82
0
               this->fThicknessMultiplier == other.fThicknessMultiplier;
83
0
    }
84
};
85
86
/// Where to vertically align the placeholder relative to the surrounding text.
87
enum class PlaceholderAlignment {
88
  /// Match the baseline of the placeholder with the baseline.
89
  kBaseline,
90
91
  /// Align the bottom edge of the placeholder with the baseline such that the
92
  /// placeholder sits on top of the baseline.
93
  kAboveBaseline,
94
95
  /// Align the top edge of the placeholder with the baseline specified in
96
  /// such that the placeholder hangs below the baseline.
97
  kBelowBaseline,
98
99
  /// Align the top edge of the placeholder with the top edge of the font.
100
  /// When the placeholder is very tall, the extra space will hang from
101
  /// the top and extend through the bottom of the line.
102
  kTop,
103
104
  /// Align the bottom edge of the placeholder with the top edge of the font.
105
  /// When the placeholder is very tall, the extra space will rise from
106
  /// the bottom and extend through the top of the line.
107
  kBottom,
108
109
  /// Align the middle of the placeholder with the middle of the text. When the
110
  /// placeholder is very tall, the extra space will grow equally from
111
  /// the top and bottom of the line.
112
  kMiddle,
113
};
114
115
struct FontFeature {
116
0
    FontFeature(SkString name, int value) : fName(std::move(name)), fValue(value) {}
117
0
    bool operator==(const FontFeature& that) const {
118
0
        return fName == that.fName && fValue == that.fValue;
119
0
    }
120
    SkString fName;
121
    int fValue;
122
};
123
124
struct PlaceholderStyle {
125
0
    PlaceholderStyle() = default;
126
    PlaceholderStyle(SkScalar width, SkScalar height, PlaceholderAlignment alignment,
127
                     TextBaseline baseline, SkScalar offset)
128
            : fWidth(width)
129
            , fHeight(height)
130
            , fAlignment(alignment)
131
            , fBaseline(baseline)
132
0
            , fBaselineOffset(offset) {}
133
134
    bool equals(const PlaceholderStyle&) const;
135
136
    SkScalar fWidth = 0;
137
    SkScalar fHeight = 0;
138
    PlaceholderAlignment fAlignment = PlaceholderAlignment::kBaseline;
139
    TextBaseline fBaseline = TextBaseline::kAlphabetic;
140
    // Distance from the top edge of the rect to the baseline position. This
141
    // baseline will be aligned against the alphabetic baseline of the surrounding
142
    // text.
143
    //
144
    // Positive values drop the baseline lower (positions the rect higher) and
145
    // small or negative values will cause the rect to be positioned underneath
146
    // the line. When baseline == height, the bottom edge of the rect will rest on
147
    // the alphabetic baseline.
148
    SkScalar fBaselineOffset = 0;
149
};
150
151
class TextStyle {
152
public:
153
0
    TextStyle() = default;
154
0
    TextStyle(const TextStyle& other) = default;
155
0
    TextStyle& operator=(const TextStyle& other) = default;
156
157
    TextStyle cloneForPlaceholder();
158
159
    bool equals(const TextStyle& other) const;
160
    bool equalsByFonts(const TextStyle& that) const;
161
    bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
162
0
    bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
163
164
    // Colors
165
0
    SkColor getColor() const { return fColor; }
166
0
    void setColor(SkColor color) { fColor = color; }
167
168
0
    bool hasForeground() const { return fHasForeground; }
169
0
    SkPaint getForeground() const {
170
0
        const SkPaint* paint = std::get_if<SkPaint>(&fForeground);
171
0
        return paint ? *paint : SkPaint();
172
0
    }
173
0
    ParagraphPainter::SkPaintOrID getForegroundPaintOrID() const {
174
0
        return fForeground;
175
0
    }
176
0
    void setForegroundPaint(SkPaint paint) {
177
0
        fHasForeground = true;
178
0
        fForeground = std::move(paint);
179
0
    }
180
    // DEPRECATED: prefer `setForegroundPaint`.
181
0
    void setForegroundColor(SkPaint paint) { setForegroundPaint(std::move(paint)); }
182
183
    // Set the foreground to a paint ID.  This is intended for use by clients
184
    // that implement a custom ParagraphPainter that can not accept an SkPaint.
185
0
    void setForegroundPaintID(ParagraphPainter::PaintID paintID) {
186
0
        fHasForeground = true;
187
0
        fForeground = paintID;
188
0
    }
189
0
    void clearForegroundColor() { fHasForeground = false; }
190
191
0
    bool hasBackground() const { return fHasBackground; }
192
0
    SkPaint getBackground() const {
193
0
        const SkPaint* paint = std::get_if<SkPaint>(&fBackground);
194
0
        return paint ? *paint : SkPaint();
195
0
    }
196
0
    ParagraphPainter::SkPaintOrID getBackgroundPaintOrID() const {
197
0
        return fBackground;
198
0
    }
199
0
    void setBackgroundPaint(SkPaint paint) {
200
0
        fHasBackground = true;
201
0
        fBackground = std::move(paint);
202
0
    }
203
    // DEPRECATED: prefer `setBackgroundPaint`.
204
0
    void setBackgroundColor(SkPaint paint) { setBackgroundPaint(std::move(paint)); }
205
0
    void setBackgroundPaintID(ParagraphPainter::PaintID paintID) {
206
0
        fHasBackground = true;
207
0
        fBackground = paintID;
208
0
    }
209
0
    void clearBackgroundColor() { fHasBackground = false; }
210
211
    // Decorations
212
0
    Decoration getDecoration() const { return fDecoration; }
213
0
    TextDecoration getDecorationType() const { return fDecoration.fType; }
214
0
    TextDecorationMode getDecorationMode() const { return fDecoration.fMode; }
215
0
    SkColor getDecorationColor() const { return fDecoration.fColor; }
216
0
    TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
217
0
    SkScalar getDecorationThicknessMultiplier() const {
218
0
        return fDecoration.fThicknessMultiplier;
219
0
    }
220
0
    void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
221
0
    void setDecorationMode(TextDecorationMode mode) { fDecoration.fMode = mode; }
222
0
    void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
223
0
    void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
224
0
    void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
225
226
    // Weight/Width/Slant
227
0
    SkFontStyle getFontStyle() const { return fFontStyle; }
228
0
    void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
229
230
    // Shadows
231
0
    size_t getShadowNumber() const { return fTextShadows.size(); }
232
0
    std::vector<TextShadow> getShadows() const { return fTextShadows; }
233
0
    void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
234
0
    void resetShadows() { fTextShadows.clear(); }
235
236
    // Font features
237
0
    size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
238
0
    std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
239
    void addFontFeature(const SkString& fontFeature, int value)
240
0
        { fFontFeatures.emplace_back(fontFeature, value); }
241
0
    void resetFontFeatures() { fFontFeatures.clear(); }
242
243
    // Font arguments
244
0
    const std::optional<FontArguments>& getFontArguments() const { return fFontArguments; }
245
    // The contents of the SkFontArguments will be copied into the TextStyle,
246
    // and the SkFontArguments can be safely deleted after setFontArguments returns.
247
    void setFontArguments(const std::optional<SkFontArguments>& args);
248
249
0
    SkScalar getFontSize() const { return fFontSize; }
250
0
    void setFontSize(SkScalar size) { fFontSize = size; }
251
252
0
    const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
253
0
    void setFontFamilies(std::vector<SkString> families) {
254
0
        fFontFamilies = std::move(families);
255
0
    }
256
257
0
    SkScalar getBaselineShift() const { return fBaselineShift; }
258
0
    void setBaselineShift(SkScalar baselineShift) { fBaselineShift = baselineShift; }
259
260
0
    void setHeight(SkScalar height) { fHeight = height; }
261
0
    SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
262
263
0
    void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
264
0
    bool getHeightOverride() const { return fHeightOverride; }
265
266
0
    void setHalfLeading(bool halfLeading) { fHalfLeading = halfLeading; }
267
0
    bool getHalfLeading() const { return fHalfLeading; }
268
269
0
    void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
270
0
    SkScalar getLetterSpacing() const { return fLetterSpacing; }
271
272
0
    void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
273
0
    SkScalar getWordSpacing() const { return fWordSpacing; }
274
275
0
    SkTypeface* getTypeface() const { return fTypeface.get(); }
276
0
    sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
277
0
    void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
278
279
0
    SkString getLocale() const { return fLocale; }
280
0
    void setLocale(const SkString& locale) { fLocale = locale; }
281
282
0
    TextBaseline getTextBaseline() const { return fTextBaseline; }
283
0
    void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
284
285
    void getFontMetrics(SkFontMetrics* metrics) const;
286
287
0
    bool isPlaceholder() const { return fIsPlaceholder; }
288
0
    void setPlaceholder() { fIsPlaceholder = true; }
289
290
private:
291
    static const std::vector<SkString>* kDefaultFontFamilies;
292
293
    Decoration fDecoration = {
294
            TextDecoration::kNoDecoration,
295
            // TODO: switch back to kGaps when (if) switching flutter to skparagraph
296
            TextDecorationMode::kThrough,
297
            // It does not make sense to draw a transparent object, so we use this as a default
298
            // value to indicate no decoration color was set.
299
            SK_ColorTRANSPARENT, TextDecorationStyle::kSolid,
300
            // Thickness is applied as a multiplier to the default thickness of the font.
301
            1.0f};
302
303
    SkFontStyle fFontStyle;
304
305
    std::vector<SkString> fFontFamilies = *kDefaultFontFamilies;
306
307
    SkScalar fFontSize = 14.0;
308
    SkScalar fHeight = 1.0;
309
    bool fHeightOverride = false;
310
    SkScalar fBaselineShift = 0.0f;
311
    // true: half leading.
312
    // false: scale ascent/descent with fHeight.
313
    bool fHalfLeading = false;
314
    SkString fLocale = {};
315
    SkScalar fLetterSpacing = 0.0;
316
    SkScalar fWordSpacing = 0.0;
317
318
    TextBaseline fTextBaseline = TextBaseline::kAlphabetic;
319
320
    SkColor fColor = SK_ColorWHITE;
321
    bool fHasBackground = false;
322
    ParagraphPainter::SkPaintOrID fBackground;
323
    bool fHasForeground = false;
324
    ParagraphPainter::SkPaintOrID fForeground;
325
326
    std::vector<TextShadow> fTextShadows;
327
328
    sk_sp<SkTypeface> fTypeface;
329
    bool fIsPlaceholder = false;
330
331
    std::vector<FontFeature> fFontFeatures;
332
333
    std::optional<FontArguments> fFontArguments;
334
};
335
336
typedef size_t TextIndex;
337
typedef SkRange<size_t> TextRange;
338
const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
339
340
struct Block {
341
0
    Block() = default;
342
0
    Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
343
0
    Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
344
345
0
    void add(TextRange tail) {
346
0
        SkASSERT(fRange.end == tail.start);
347
0
        fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
348
0
    }
349
350
    TextRange fRange = EMPTY_RANGE;
351
    TextStyle fStyle;
352
};
353
354
355
typedef size_t BlockIndex;
356
typedef SkRange<size_t> BlockRange;
357
const size_t EMPTY_BLOCK = EMPTY_INDEX;
358
const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
359
360
struct Placeholder {
361
    Placeholder() = default;
362
    Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
363
                BlockRange blocksBefore, TextRange textBefore)
364
            : fRange(start, end)
365
            , fStyle(style)
366
            , fTextStyle(textStyle)
367
            , fBlocksBefore(blocksBefore)
368
0
            , fTextBefore(textBefore) {}
369
370
    TextRange fRange = EMPTY_RANGE;
371
    PlaceholderStyle fStyle;
372
    TextStyle fTextStyle;
373
    BlockRange fBlocksBefore;
374
    TextRange fTextBefore;
375
};
376
377
}  // namespace textlayout
378
}  // namespace skia
379
380
#endif  // TextStyle_DEFINED