blob: 08509d7343f52844975bc66137b0903773f55fb7 [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 {
54 kAllAttributes,
Julia Lavrovaa3552c52019-05-30 16:12:56 -040055 kFont,
56 kForeground,
57 kBackground,
58 kShadow,
59 kDecorations,
60 kLetterSpacing,
61 kWordSpacing
62};
63
Julia Lavrova5207f352019-06-21 12:22:32 -040064struct Decoration {
65 TextDecoration fType;
66 SkColor fColor;
67 TextDecorationStyle fStyle;
68 SkScalar fThicknessMultiplier;
69
70 bool operator==(const Decoration& other) const {
71 return this->fType == other.fType &&
72 this->fColor == other.fColor &&
73 this->fStyle == other.fStyle &&
74 this->fThicknessMultiplier == other.fThicknessMultiplier;
75 }
76};
77
Julia Lavrova916a9042019-08-08 16:51:27 -040078/// Where to vertically align the placeholder relative to the surrounding text.
79enum class PlaceholderAlignment {
80 /// Match the baseline of the placeholder with the baseline.
81 kBaseline,
82
83 /// Align the bottom edge of the placeholder with the baseline such that the
84 /// placeholder sits on top of the baseline.
85 kAboveBaseline,
86
87 /// Align the top edge of the placeholder with the baseline specified in
88 /// such that the placeholder hangs below the baseline.
89 kBelowBaseline,
90
91 /// Align the top edge of the placeholder with the top edge of the font.
92 /// When the placeholder is very tall, the extra space will hang from
93 /// the top and extend through the bottom of the line.
94 kTop,
95
96 /// Align the bottom edge of the placeholder with the top edge of the font.
97 /// When the placeholder is very tall, the extra space will rise from
98 /// the bottom and extend through the top of the line.
99 kBottom,
100
101 /// Align the middle of the placeholder with the middle of the text. When the
102 /// placeholder is very tall, the extra space will grow equally from
103 /// the top and bottom of the line.
104 kMiddle,
105};
106
Julia Lavrovac5313e62019-12-10 12:11:17 -0500107struct FontFeature {
108 FontFeature(const SkString name, int value) : fName(name), fValue(value) { }
109 FontFeature(const FontFeature& other) : fName(other.fName), fValue(other.fValue) { }
110 bool operator==(const FontFeature& other) const {
111 return fName == other.fName && fValue == other.fValue;
112 }
113 SkString fName;
114 int fValue;
115};
116
Julia Lavrova916a9042019-08-08 16:51:27 -0400117struct PlaceholderStyle {
Julia Lavrovac0360582020-02-05 10:17:53 -0500118 PlaceholderStyle()
119 : fWidth(0)
120 , fHeight(0)
121 , fAlignment(PlaceholderAlignment::kBaseline)
122 , fBaseline(TextBaseline::kAlphabetic)
123 , fBaselineOffset(0) {}
124
Julia Lavrova916a9042019-08-08 16:51:27 -0400125 PlaceholderStyle(SkScalar width, SkScalar height, PlaceholderAlignment alignment,
126 TextBaseline baseline, SkScalar offset)
127 : fWidth(width)
128 , fHeight(height)
129 , fAlignment(alignment)
130 , fBaseline(baseline)
131 , fBaselineOffset(offset) {}
132
Julia Lavrova4cf18742020-01-14 13:24:45 -0500133 bool equals(const PlaceholderStyle& other) const;
134
Julia Lavrovac0360582020-02-05 10:17:53 -0500135 SkScalar fWidth;
136 SkScalar fHeight;
Julia Lavrova916a9042019-08-08 16:51:27 -0400137 PlaceholderAlignment fAlignment;
Julia Lavrova916a9042019-08-08 16:51:27 -0400138 TextBaseline fBaseline;
Julia Lavrova916a9042019-08-08 16:51:27 -0400139 // Distance from the top edge of the rect to the baseline position. This
140 // baseline will be aligned against the alphabetic baseline of the surrounding
141 // text.
142 //
143 // Positive values drop the baseline lower (positions the rect higher) and
144 // small or negative values will cause the rect to be positioned underneath
145 // the line. When baseline == height, the bottom edge of the rect will rest on
146 // the alphabetic baseline.
Julia Lavrovac0360582020-02-05 10:17:53 -0500147 SkScalar fBaselineOffset;
Julia Lavrova916a9042019-08-08 16:51:27 -0400148};
149
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400150class TextStyle {
151public:
152 TextStyle();
Julia Lavrova916a9042019-08-08 16:51:27 -0400153 TextStyle(const TextStyle& other, bool placeholder);
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400154 ~TextStyle() = default;
155
156 bool equals(const TextStyle& other) const;
Julia Lavrova4cf18742020-01-14 13:24:45 -0500157 bool equalsByFonts(const TextStyle& that) const;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400158 bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
159 bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
160
161 // Colors
162 SkColor getColor() const { return fColor; }
163 void setColor(SkColor color) { fColor = color; }
164
165 bool hasForeground() const { return fHasForeground; }
166 SkPaint getForeground() const { return fForeground; }
167 void setForegroundColor(SkPaint paint) {
168 fHasForeground = true;
169 fForeground = std::move(paint);
170 }
171 void clearForegroundColor() { fHasForeground = false; }
172
173 bool hasBackground() const { return fHasBackground; }
174 SkPaint getBackground() const { return fBackground; }
175 void setBackgroundColor(SkPaint paint) {
176 fHasBackground = true;
177 fBackground = std::move(paint);
178 }
179 void clearBackgroundColor() { fHasBackground = false; }
180
181 // Decorations
Julia Lavrova5207f352019-06-21 12:22:32 -0400182 Decoration getDecoration() const { return fDecoration; }
183 TextDecoration getDecorationType() const { return fDecoration.fType; }
184 SkColor getDecorationColor() const { return fDecoration.fColor; }
185 TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400186 SkScalar getDecorationThicknessMultiplier() const {
Julia Lavrova5207f352019-06-21 12:22:32 -0400187 return fDecoration.fThicknessMultiplier;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400188 }
Julia Lavrova5207f352019-06-21 12:22:32 -0400189 void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
190 void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
191 void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
192 void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400193
194 // Weight/Width/Slant
195 SkFontStyle getFontStyle() const { return fFontStyle; }
196 void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
197
198 // Shadows
199 size_t getShadowNumber() const { return fTextShadows.size(); }
200 std::vector<TextShadow> getShadows() const { return fTextShadows; }
201 void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
202 void resetShadows() { fTextShadows.clear(); }
203
Julia Lavrovac5313e62019-12-10 12:11:17 -0500204 // Font features
205 size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
206 std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
207 void addFontFeature(const SkString& fontFeature, int value)
208 { fFontFeatures.emplace_back(fontFeature, value); }
209 void resetFontFeatures() { fFontFeatures.clear(); }
210
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400211 SkScalar getFontSize() const { return fFontSize; }
212 void setFontSize(SkScalar size) { fFontSize = size; }
213
214 const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
215 void setFontFamilies(std::vector<SkString> families) {
216 fFontFamilies = std::move(families);
217 }
218
219 void setHeight(SkScalar height) { fHeight = height; }
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400220 SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
221
222 void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
223 bool getHeightOverride() const { return fHeightOverride; }
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400224
225 void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
226 SkScalar getLetterSpacing() const { return fLetterSpacing; }
227
228 void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
229 SkScalar getWordSpacing() const { return fWordSpacing; }
230
231 SkTypeface* getTypeface() const { return fTypeface.get(); }
232 sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
233 void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
234
235 SkString getLocale() const { return fLocale; }
236 void setLocale(const SkString& locale) { fLocale = locale; }
237
238 TextBaseline getTextBaseline() const { return fTextBaseline; }
239 void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
240
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400241 void getFontMetrics(SkFontMetrics* metrics) const;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400242
Julia Lavrova916a9042019-08-08 16:51:27 -0400243 bool isPlaceholder() const { return fIsPlaceholder; }
244 void setPlaceholder() { fIsPlaceholder = true; }
245
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400246private:
Julia Lavrova916a9042019-08-08 16:51:27 -0400247
Julia Lavrova5207f352019-06-21 12:22:32 -0400248 Decoration fDecoration;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400249
250 SkFontStyle fFontStyle;
251
252 std::vector<SkString> fFontFamilies;
253 SkScalar fFontSize;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400254 SkScalar fHeight;
Julia Lavrovadb9f6692019-08-01 16:02:17 -0400255 bool fHeightOverride;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400256 SkString fLocale;
257 SkScalar fLetterSpacing;
258 SkScalar fWordSpacing;
259
260 TextBaseline fTextBaseline;
261
262 SkColor fColor;
263 bool fHasBackground;
264 SkPaint fBackground;
265 bool fHasForeground;
266 SkPaint fForeground;
267
268 std::vector<TextShadow> fTextShadows;
269
270 sk_sp<SkTypeface> fTypeface;
Julia Lavrova916a9042019-08-08 16:51:27 -0400271 bool fIsPlaceholder;
Julia Lavrovac5313e62019-12-10 12:11:17 -0500272
273 std::vector<FontFeature> fFontFeatures;
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400274};
Julia Lavrova5207f352019-06-21 12:22:32 -0400275
276typedef size_t TextIndex;
277typedef SkRange<size_t> TextRange;
278const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
279
280
281struct Block {
282 Block() : fRange(EMPTY_RANGE), fStyle() { }
Julia Lavrova916a9042019-08-08 16:51:27 -0400283 Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
284 Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
285
Julia Lavrova90bfd1c2019-12-04 11:43:32 -0500286 Block(const Block& other) : fRange(other.fRange), fStyle(other.fStyle) {}
Julia Lavrova5207f352019-06-21 12:22:32 -0400287
288 void add(TextRange tail) {
289 SkASSERT(fRange.end == tail.start);
290 fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
291 }
Julia Lavrova90bfd1c2019-12-04 11:43:32 -0500292
Julia Lavrova5207f352019-06-21 12:22:32 -0400293 TextRange fRange;
294 TextStyle fStyle;
295};
296
Julia Lavrova916a9042019-08-08 16:51:27 -0400297
298typedef size_t BlockIndex;
299typedef SkRange<size_t> BlockRange;
300const size_t EMPTY_BLOCK = EMPTY_INDEX;
301const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
302
303struct Placeholder {
304 Placeholder() : fRange(EMPTY_RANGE), fStyle() {}
305
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400306 Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
307 BlockRange blocksBefore, TextRange textBefore)
Julia Lavrova916a9042019-08-08 16:51:27 -0400308 : fRange(start, end)
309 , fStyle(style)
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400310 , fTextStyle(textStyle)
Julia Lavrova916a9042019-08-08 16:51:27 -0400311 , fBlocksBefore(blocksBefore)
312 , fTextBefore(textBefore) {}
313
Julia Lavrova90bfd1c2019-12-04 11:43:32 -0500314 Placeholder(const Placeholder& other)
315 : fRange(other.fRange)
316 , fStyle(other.fStyle)
317 , fTextStyle(other.fTextStyle)
318 , fBlocksBefore(other.fBlocksBefore)
319 , fTextBefore(other.fTextBefore) {}
Julia Lavrova916a9042019-08-08 16:51:27 -0400320
321 TextRange fRange;
322 PlaceholderStyle fStyle;
Julia Lavrovaf3ed2732019-09-05 14:35:17 -0400323 TextStyle fTextStyle;
Julia Lavrova916a9042019-08-08 16:51:27 -0400324 BlockRange fBlocksBefore;
325 TextRange fTextBefore;
326};
327
Julia Lavrovaa3552c52019-05-30 16:12:56 -0400328} // namespace textlayout
329} // namespace skia
330
331#endif // TextStyle_DEFINED