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