blob: b43a41f1fc8725f4e1b3773c77d9fce64b501405 [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
Julia Lavrova18db52f2020-05-04 15:03:18 -040053enum TextDecorationMode { kGaps, kThrough };
54
Julia Lavrovaa3552c52019-05-30 16:12:56 -040055enum StyleType {
Julia Lavrova76ae22e2020-02-26 12:14:18 -050056 kNone,
Julia Lavrovaa3552c52019-05-30 16:12:56 -040057 kAllAttributes,
Julia Lavrovaa3552c52019-05-30 16:12:56 -040058 kFont,
59 kForeground,
60 kBackground,
61 kShadow,
62 kDecorations,
63 kLetterSpacing,
64 kWordSpacing
65};
66
Julia Lavrova5207f352019-06-21 12:22:32 -040067struct Decoration {
68 TextDecoration fType;
Julia Lavrova18db52f2020-05-04 15:03:18 -040069 TextDecorationMode fMode;
Julia Lavrova5207f352019-06-21 12:22:32 -040070 SkColor fColor;
71 TextDecorationStyle fStyle;
72 SkScalar fThicknessMultiplier;
73
74 bool operator==(const Decoration& other) const {
75 return this->fType == other.fType &&
Julia Lavrova18db52f2020-05-04 15:03:18 -040076 this->fMode == other.fMode &&
Julia Lavrova5207f352019-06-21 12:22:32 -040077 this->fColor == other.fColor &&
78 this->fStyle == other.fStyle &&
79 this->fThicknessMultiplier == other.fThicknessMultiplier;
80 }
81};
82
Julia Lavrova916a9042019-08-08 16:51:27 -040083/// Where to vertically align the placeholder relative to the surrounding text.
84enum 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
Julia Lavrovac5313e62019-12-10 12:11:17 -0500112struct FontFeature {
John Stiles059ed672020-07-27 15:53:28 -0400113 FontFeature(const SkString name, int value) : fName(name), fValue(value) {}
Ben Wagner833313b2020-03-23 17:22:24 -0400114 bool operator==(const FontFeature& that) const {
115 return fName == that.fName && fValue == that.fValue;
Julia Lavrovac5313e62019-12-10 12:11:17 -0500116 }
117 SkString fName;
118 int fValue;
119};
120
Julia Lavrova916a9042019-08-08 16:51:27 -0400121struct PlaceholderStyle {
John Stiles059ed672020-07-27 15:53:28 -0400122 PlaceholderStyle() = default;
Julia Lavrova916a9042019-08-08 16:51:27 -0400123 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 , fBaselineOffset(offset) {}
130
Ben Wagner833313b2020-03-23 17:22:24 -0400131 bool equals(const PlaceholderStyle&) const;
Julia Lavrova4cf18742020-01-14 13:24:45 -0500132
John Stiles059ed672020-07-27 15:53:28 -0400133 SkScalar fWidth = 0;
134 SkScalar fHeight = 0;
135 PlaceholderAlignment fAlignment = PlaceholderAlignment::kBaseline;
136 TextBaseline fBaseline = TextBaseline::kAlphabetic;
Julia Lavrova916a9042019-08-08 16:51:27 -0400137 // 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.
John Stiles059ed672020-07-27 15:53:28 -0400145 SkScalar fBaselineOffset = 0;
Julia Lavrova916a9042019-08-08 16:51:27 -0400146};
147
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400148class TextStyle {
149public:
John Stiles059ed672020-07-27 15:53:28 -0400150 TextStyle() = default;
Julia Lavrova916a9042019-08-08 16:51:27 -0400151 TextStyle(const TextStyle& other, bool placeholder);
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400152
153 bool equals(const TextStyle& other) const;
Julia Lavrova4cf18742020-01-14 13:24:45 -0500154 bool equalsByFonts(const TextStyle& that) const;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400155 bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
156 bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
157
158 // Colors
159 SkColor getColor() const { return fColor; }
160 void setColor(SkColor color) { fColor = color; }
161
162 bool hasForeground() const { return fHasForeground; }
163 SkPaint getForeground() const { return fForeground; }
164 void setForegroundColor(SkPaint paint) {
165 fHasForeground = true;
166 fForeground = std::move(paint);
167 }
168 void clearForegroundColor() { fHasForeground = false; }
169
170 bool hasBackground() const { return fHasBackground; }
171 SkPaint getBackground() const { return fBackground; }
172 void setBackgroundColor(SkPaint paint) {
173 fHasBackground = true;
174 fBackground = std::move(paint);
175 }
176 void clearBackgroundColor() { fHasBackground = false; }
177
178 // Decorations
Julia Lavrova5207f352019-06-21 12:22:32 -0400179 Decoration getDecoration() const { return fDecoration; }
180 TextDecoration getDecorationType() const { return fDecoration.fType; }
Julia Lavrova18db52f2020-05-04 15:03:18 -0400181 TextDecorationMode getDecorationMode() const { return fDecoration.fMode; }
Julia Lavrova5207f352019-06-21 12:22:32 -0400182 SkColor getDecorationColor() const { return fDecoration.fColor; }
183 TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400184 SkScalar getDecorationThicknessMultiplier() const {
Julia Lavrova5207f352019-06-21 12:22:32 -0400185 return fDecoration.fThicknessMultiplier;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400186 }
Julia Lavrova5207f352019-06-21 12:22:32 -0400187 void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
Julia Lavrova18db52f2020-05-04 15:03:18 -0400188 void setDecorationMode(TextDecorationMode mode) { fDecoration.fMode = mode; }
Julia Lavrova5207f352019-06-21 12:22:32 -0400189 void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
190 void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
191 void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400192
193 // Weight/Width/Slant
194 SkFontStyle getFontStyle() const { return fFontStyle; }
195 void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
196
197 // Shadows
198 size_t getShadowNumber() const { return fTextShadows.size(); }
199 std::vector<TextShadow> getShadows() const { return fTextShadows; }
200 void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
201 void resetShadows() { fTextShadows.clear(); }
202
Julia Lavrovac5313e62019-12-10 12:11:17 -0500203 // Font features
204 size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
205 std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
206 void addFontFeature(const SkString& fontFeature, int value)
207 { fFontFeatures.emplace_back(fontFeature, value); }
208 void resetFontFeatures() { fFontFeatures.clear(); }
209
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400210 SkScalar getFontSize() const { return fFontSize; }
211 void setFontSize(SkScalar size) { fFontSize = size; }
212
213 const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
214 void setFontFamilies(std::vector<SkString> families) {
215 fFontFamilies = std::move(families);
216 }
217
218 void setHeight(SkScalar height) { fHeight = height; }
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400219 SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
220
221 void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
222 bool getHeightOverride() const { return fHeightOverride; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400223
224 void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
225 SkScalar getLetterSpacing() const { return fLetterSpacing; }
226
227 void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
228 SkScalar getWordSpacing() const { return fWordSpacing; }
229
230 SkTypeface* getTypeface() const { return fTypeface.get(); }
231 sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
232 void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
233
234 SkString getLocale() const { return fLocale; }
235 void setLocale(const SkString& locale) { fLocale = locale; }
236
237 TextBaseline getTextBaseline() const { return fTextBaseline; }
238 void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
239
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400240 void getFontMetrics(SkFontMetrics* metrics) const;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400241
Julia Lavrova916a9042019-08-08 16:51:27 -0400242 bool isPlaceholder() const { return fIsPlaceholder; }
243 void setPlaceholder() { fIsPlaceholder = true; }
244
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400245private:
John Stiles059ed672020-07-27 15:53:28 -0400246 Decoration fDecoration = {
247 TextDecoration::kNoDecoration,
248 // TODO: switch back to kGaps when (if) switching flutter to skparagraph
249 TextDecorationMode::kThrough,
250 // It does not make sense to draw a transparent object, so we use this as a default
251 // value to indicate no decoration color was set.
252 SK_ColorTRANSPARENT, TextDecorationStyle::kSolid,
253 // Thickness is applied as a multiplier to the default thickness of the font.
254 1.0f};
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400255
256 SkFontStyle fFontStyle;
257
John Stiles059ed672020-07-27 15:53:28 -0400258 std::vector<SkString> fFontFamilies = { SkString(DEFAULT_FONT_FAMILY) };
259 SkScalar fFontSize = 14.0;
260 SkScalar fHeight = 1.0;
261 bool fHeightOverride = false;
262 SkString fLocale = {};
263 SkScalar fLetterSpacing = 0.0;
264 SkScalar fWordSpacing = 0.0;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400265
John Stiles059ed672020-07-27 15:53:28 -0400266 TextBaseline fTextBaseline = TextBaseline::kAlphabetic;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400267
John Stiles059ed672020-07-27 15:53:28 -0400268 SkColor fColor = SK_ColorWHITE;
269 bool fHasBackground = false;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400270 SkPaint fBackground;
John Stiles059ed672020-07-27 15:53:28 -0400271 bool fHasForeground = false;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400272 SkPaint fForeground;
273
274 std::vector<TextShadow> fTextShadows;
275
276 sk_sp<SkTypeface> fTypeface;
John Stiles059ed672020-07-27 15:53:28 -0400277 bool fIsPlaceholder = false;
Julia Lavrovac5313e62019-12-10 12:11:17 -0500278
279 std::vector<FontFeature> fFontFeatures;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400280};
Julia Lavrova5207f352019-06-21 12:22:32 -0400281
282typedef size_t TextIndex;
283typedef SkRange<size_t> TextRange;
284const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
285
Julia Lavrova5207f352019-06-21 12:22:32 -0400286struct Block {
John Stiles059ed672020-07-27 15:53:28 -0400287 Block() = default;
Julia Lavrova916a9042019-08-08 16:51:27 -0400288 Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
289 Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
290
Julia Lavrova5207f352019-06-21 12:22:32 -0400291 void add(TextRange tail) {
292 SkASSERT(fRange.end == tail.start);
293 fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
294 }
Julia Lavrova90bfd1c2019-12-04 11:43:32 -0500295
John Stiles059ed672020-07-27 15:53:28 -0400296 TextRange fRange = EMPTY_RANGE;
Julia Lavrova5207f352019-06-21 12:22:32 -0400297 TextStyle fStyle;
298};
299
Julia Lavrova916a9042019-08-08 16:51:27 -0400300
301typedef size_t BlockIndex;
302typedef SkRange<size_t> BlockRange;
303const size_t EMPTY_BLOCK = EMPTY_INDEX;
304const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
305
306struct Placeholder {
John Stiles059ed672020-07-27 15:53:28 -0400307 Placeholder() = default;
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400308 Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
309 BlockRange blocksBefore, TextRange textBefore)
Julia Lavrova916a9042019-08-08 16:51:27 -0400310 : fRange(start, end)
311 , fStyle(style)
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400312 , fTextStyle(textStyle)
Julia Lavrova916a9042019-08-08 16:51:27 -0400313 , fBlocksBefore(blocksBefore)
314 , fTextBefore(textBefore) {}
315
John Stiles059ed672020-07-27 15:53:28 -0400316 TextRange fRange = EMPTY_RANGE;
Julia Lavrova916a9042019-08-08 16:51:27 -0400317 PlaceholderStyle fStyle;
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400318 TextStyle fTextStyle;
Julia Lavrova916a9042019-08-08 16:51:27 -0400319 BlockRange fBlocksBefore;
320 TextRange fTextBefore;
321};
322
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400323} // namespace textlayout
324} // namespace skia
325
326#endif // TextStyle_DEFINED