blob: d24b6440d7ec35ec8a0130e9964f36ee5fb35ae4 [file] [log] [blame]
Julia Lavrovaa3552c52019-05-30 16:12:56 -04001// Copyright 2019 Google LLC.
2#ifndef TextStyle_DEFINED
3#define TextStyle_DEFINED
4
5#include <vector>
Julia Lavrovaa3552c52019-05-30 16:12:56 -04006#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"
Julia Lavrova916a9042019-08-08 16:51:27 -040011#include "include/core/SkScalar.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040012#include "modules/skparagraph/include/DartTypes.h"
13#include "modules/skparagraph/include/TextShadow.h"
Julia Lavrovaa3552c52019-05-30 16:12:56 -040014
15// TODO: Make it external so the other platforms (Android) could use it
16#define DEFAULT_FONT_FAMILY "sans-serif"
17
18namespace skia {
19namespace textlayout {
20
Julia Lavrovac0360582020-02-05 10:17:53 -050021static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
22 if (SkScalarIsFinite(x)) {
23 return SkScalarNearlyZero(x, tolerance);
24 }
25 return false;
26}
27
28static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) {
29 if (SkScalarIsFinite(x) && SkScalarIsFinite(x)) {
30 return SkScalarNearlyEqual(x, y, tolerance);
31 }
32 // Inf == Inf, anything else is false
33 return x == y;
34}
35
Julia Lavrovaa3552c52019-05-30 16:12:56 -040036// Multiple decorations can be applied at once. Ex: Underline and overline is
37// (0x1 | 0x2)
38enum TextDecoration {
39 kNoDecoration = 0x0,
40 kUnderline = 0x1,
41 kOverline = 0x2,
42 kLineThrough = 0x4,
43};
Julia Lavrovab5c69a42019-07-11 09:34:39 -040044constexpr TextDecoration AllTextDecorations[] = {
Julia Lavrovaa3552c52019-05-30 16:12:56 -040045 kNoDecoration,
46 kUnderline,
47 kOverline,
48 kLineThrough,
49};
50
51enum TextDecorationStyle { kSolid, kDouble, kDotted, kDashed, kWavy };
52
53enum StyleType {
Julia Lavrova76ae22e2020-02-26 12:14:18 -050054 kNone,
Julia Lavrovaa3552c52019-05-30 16:12:56 -040055 kAllAttributes,
Julia Lavrovaa3552c52019-05-30 16:12:56 -040056 kFont,
57 kForeground,
58 kBackground,
59 kShadow,
60 kDecorations,
61 kLetterSpacing,
62 kWordSpacing
63};
64
Julia Lavrova5207f352019-06-21 12:22:32 -040065struct Decoration {
66 TextDecoration fType;
67 SkColor fColor;
68 TextDecorationStyle fStyle;
69 SkScalar fThicknessMultiplier;
70
71 bool operator==(const Decoration& other) const {
72 return this->fType == other.fType &&
73 this->fColor == other.fColor &&
74 this->fStyle == other.fStyle &&
75 this->fThicknessMultiplier == other.fThicknessMultiplier;
76 }
77};
78
Julia Lavrova916a9042019-08-08 16:51:27 -040079/// Where to vertically align the placeholder relative to the surrounding text.
80enum class PlaceholderAlignment {
81 /// Match the baseline of the placeholder with the baseline.
82 kBaseline,
83
84 /// Align the bottom edge of the placeholder with the baseline such that the
85 /// placeholder sits on top of the baseline.
86 kAboveBaseline,
87
88 /// Align the top edge of the placeholder with the baseline specified in
89 /// such that the placeholder hangs below the baseline.
90 kBelowBaseline,
91
92 /// Align the top edge of the placeholder with the top edge of the font.
93 /// When the placeholder is very tall, the extra space will hang from
94 /// the top and extend through the bottom of the line.
95 kTop,
96
97 /// Align the bottom edge of the placeholder with the top edge of the font.
98 /// When the placeholder is very tall, the extra space will rise from
99 /// the bottom and extend through the top of the line.
100 kBottom,
101
102 /// Align the middle of the placeholder with the middle of the text. When the
103 /// placeholder is very tall, the extra space will grow equally from
104 /// the top and bottom of the line.
105 kMiddle,
106};
107
Julia Lavrovac5313e62019-12-10 12:11:17 -0500108struct FontFeature {
109 FontFeature(const SkString name, int value) : fName(name), fValue(value) { }
110 FontFeature(const FontFeature& other) : fName(other.fName), fValue(other.fValue) { }
111 bool operator==(const FontFeature& other) const {
112 return fName == other.fName && fValue == other.fValue;
113 }
114 SkString fName;
115 int fValue;
116};
117
Julia Lavrova916a9042019-08-08 16:51:27 -0400118struct PlaceholderStyle {
Julia Lavrovac0360582020-02-05 10:17:53 -0500119 PlaceholderStyle()
120 : fWidth(0)
121 , fHeight(0)
122 , fAlignment(PlaceholderAlignment::kBaseline)
123 , fBaseline(TextBaseline::kAlphabetic)
124 , fBaselineOffset(0) {}
125
Julia Lavrova916a9042019-08-08 16:51:27 -0400126 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 , fBaselineOffset(offset) {}
133
Julia Lavrova4cf18742020-01-14 13:24:45 -0500134 bool equals(const PlaceholderStyle& other) const;
135
Julia Lavrovac0360582020-02-05 10:17:53 -0500136 SkScalar fWidth;
137 SkScalar fHeight;
Julia Lavrova916a9042019-08-08 16:51:27 -0400138 PlaceholderAlignment fAlignment;
Julia Lavrova916a9042019-08-08 16:51:27 -0400139 TextBaseline fBaseline;
Julia Lavrova916a9042019-08-08 16:51:27 -0400140 // 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.
Julia Lavrovac0360582020-02-05 10:17:53 -0500148 SkScalar fBaselineOffset;
Julia Lavrova916a9042019-08-08 16:51:27 -0400149};
150
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400151class TextStyle {
152public:
153 TextStyle();
Julia Lavrova916a9042019-08-08 16:51:27 -0400154 TextStyle(const TextStyle& other, bool placeholder);
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400155 ~TextStyle() = default;
156
157 bool equals(const TextStyle& other) const;
Julia Lavrova4cf18742020-01-14 13:24:45 -0500158 bool equalsByFonts(const TextStyle& that) const;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400159 bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
160 bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
161
162 // Colors
163 SkColor getColor() const { return fColor; }
164 void setColor(SkColor color) { fColor = color; }
165
166 bool hasForeground() const { return fHasForeground; }
167 SkPaint getForeground() const { return fForeground; }
168 void setForegroundColor(SkPaint paint) {
169 fHasForeground = true;
170 fForeground = std::move(paint);
171 }
172 void clearForegroundColor() { fHasForeground = false; }
173
174 bool hasBackground() const { return fHasBackground; }
175 SkPaint getBackground() const { return fBackground; }
176 void setBackgroundColor(SkPaint paint) {
177 fHasBackground = true;
178 fBackground = std::move(paint);
179 }
180 void clearBackgroundColor() { fHasBackground = false; }
181
182 // Decorations
Julia Lavrova5207f352019-06-21 12:22:32 -0400183 Decoration getDecoration() const { return fDecoration; }
184 TextDecoration getDecorationType() const { return fDecoration.fType; }
185 SkColor getDecorationColor() const { return fDecoration.fColor; }
186 TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400187 SkScalar getDecorationThicknessMultiplier() const {
Julia Lavrova5207f352019-06-21 12:22:32 -0400188 return fDecoration.fThicknessMultiplier;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400189 }
Julia Lavrova5207f352019-06-21 12:22:32 -0400190 void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
191 void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
192 void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
193 void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400194
195 // Weight/Width/Slant
196 SkFontStyle getFontStyle() const { return fFontStyle; }
197 void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
198
199 // Shadows
200 size_t getShadowNumber() const { return fTextShadows.size(); }
201 std::vector<TextShadow> getShadows() const { return fTextShadows; }
202 void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
203 void resetShadows() { fTextShadows.clear(); }
204
Julia Lavrovac5313e62019-12-10 12:11:17 -0500205 // Font features
206 size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
207 std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
208 void addFontFeature(const SkString& fontFeature, int value)
209 { fFontFeatures.emplace_back(fontFeature, value); }
210 void resetFontFeatures() { fFontFeatures.clear(); }
211
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400212 SkScalar getFontSize() const { return fFontSize; }
213 void setFontSize(SkScalar size) { fFontSize = size; }
214
215 const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
216 void setFontFamilies(std::vector<SkString> families) {
217 fFontFamilies = std::move(families);
218 }
219
220 void setHeight(SkScalar height) { fHeight = height; }
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400221 SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
222
223 void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
224 bool getHeightOverride() const { return fHeightOverride; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400225
226 void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
227 SkScalar getLetterSpacing() const { return fLetterSpacing; }
228
229 void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
230 SkScalar getWordSpacing() const { return fWordSpacing; }
231
232 SkTypeface* getTypeface() const { return fTypeface.get(); }
233 sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
234 void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
235
236 SkString getLocale() const { return fLocale; }
237 void setLocale(const SkString& locale) { fLocale = locale; }
238
239 TextBaseline getTextBaseline() const { return fTextBaseline; }
240 void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
241
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400242 void getFontMetrics(SkFontMetrics* metrics) const;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400243
Julia Lavrova916a9042019-08-08 16:51:27 -0400244 bool isPlaceholder() const { return fIsPlaceholder; }
245 void setPlaceholder() { fIsPlaceholder = true; }
246
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400247private:
Julia Lavrova916a9042019-08-08 16:51:27 -0400248
Julia Lavrova5207f352019-06-21 12:22:32 -0400249 Decoration fDecoration;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400250
251 SkFontStyle fFontStyle;
252
253 std::vector<SkString> fFontFamilies;
254 SkScalar fFontSize;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400255 SkScalar fHeight;
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400256 bool fHeightOverride;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400257 SkString fLocale;
258 SkScalar fLetterSpacing;
259 SkScalar fWordSpacing;
260
261 TextBaseline fTextBaseline;
262
263 SkColor fColor;
264 bool fHasBackground;
265 SkPaint fBackground;
266 bool fHasForeground;
267 SkPaint fForeground;
268
269 std::vector<TextShadow> fTextShadows;
270
271 sk_sp<SkTypeface> fTypeface;
Julia Lavrova916a9042019-08-08 16:51:27 -0400272 bool fIsPlaceholder;
Julia Lavrovac5313e62019-12-10 12:11:17 -0500273
274 std::vector<FontFeature> fFontFeatures;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400275};
Julia Lavrova5207f352019-06-21 12:22:32 -0400276
277typedef size_t TextIndex;
278typedef SkRange<size_t> TextRange;
279const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
280
281
282struct Block {
283 Block() : fRange(EMPTY_RANGE), fStyle() { }
Julia Lavrova916a9042019-08-08 16:51:27 -0400284 Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
285 Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
286
Julia Lavrova90bfd1c2019-12-04 11:43:32 -0500287 Block(const Block& other) : fRange(other.fRange), fStyle(other.fStyle) {}
Julia Lavrova5207f352019-06-21 12:22:32 -0400288
289 void add(TextRange tail) {
290 SkASSERT(fRange.end == tail.start);
291 fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
292 }
Julia Lavrova90bfd1c2019-12-04 11:43:32 -0500293
Julia Lavrova5207f352019-06-21 12:22:32 -0400294 TextRange fRange;
295 TextStyle fStyle;
296};
297
Julia Lavrova916a9042019-08-08 16:51:27 -0400298
299typedef size_t BlockIndex;
300typedef SkRange<size_t> BlockRange;
301const size_t EMPTY_BLOCK = EMPTY_INDEX;
302const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
303
304struct Placeholder {
305 Placeholder() : fRange(EMPTY_RANGE), fStyle() {}
306
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400307 Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
308 BlockRange blocksBefore, TextRange textBefore)
Julia Lavrova916a9042019-08-08 16:51:27 -0400309 : fRange(start, end)
310 , fStyle(style)
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400311 , fTextStyle(textStyle)
Julia Lavrova916a9042019-08-08 16:51:27 -0400312 , fBlocksBefore(blocksBefore)
313 , fTextBefore(textBefore) {}
314
Julia Lavrova90bfd1c2019-12-04 11:43:32 -0500315 Placeholder(const Placeholder& other)
316 : fRange(other.fRange)
317 , fStyle(other.fStyle)
318 , fTextStyle(other.fTextStyle)
319 , fBlocksBefore(other.fBlocksBefore)
320 , fTextBefore(other.fTextBefore) {}
Julia Lavrova916a9042019-08-08 16:51:27 -0400321
322 TextRange fRange;
323 PlaceholderStyle fStyle;
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400324 TextStyle fTextStyle;
Julia Lavrova916a9042019-08-08 16:51:27 -0400325 BlockRange fBlocksBefore;
326 TextRange fTextBefore;
327};
328
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400329} // namespace textlayout
330} // namespace skia
331
332#endif // TextStyle_DEFINED