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 static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
22     if (SkScalarIsFinite(x)) {
23         return SkScalarNearlyZero(x, tolerance);
24     }
25     return false;
26 }
27 
28 static 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 
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 StyleType {
54     kNone,
55     kAllAttributes,
56     kFont,
57     kForeground,
58     kBackground,
59     kShadow,
60     kDecorations,
61     kLetterSpacing,
62     kWordSpacing
63 };
64 
65 struct 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 
79 /// Where to vertically align the placeholder relative to the surrounding text.
80 enum 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 
108 struct FontFeature {
FontFeatureFontFeature109     FontFeature(const SkString name, int value) : fName(name), fValue(value) { }
110     bool operator==(const FontFeature& that) const {
111         return fName == that.fName && fValue == that.fValue;
112     }
113     SkString fName;
114     int fValue;
115 };
116 
117 struct PlaceholderStyle {
PlaceholderStylePlaceholderStyle118     PlaceholderStyle()
119             : fWidth(0)
120             , fHeight(0)
121             , fAlignment(PlaceholderAlignment::kBaseline)
122             , fBaseline(TextBaseline::kAlphabetic)
123             , fBaselineOffset(0) {}
124 
PlaceholderStylePlaceholderStyle125     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 
133     bool equals(const PlaceholderStyle&) const;
134 
135     SkScalar fWidth;
136     SkScalar fHeight;
137     PlaceholderAlignment fAlignment;
138     TextBaseline fBaseline;
139     // 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.
147     SkScalar fBaselineOffset;
148 };
149 
150 class TextStyle {
151 public:
152     TextStyle();
153     TextStyle(const TextStyle& other, bool placeholder);
154     ~TextStyle() = default;
155 
156     bool equals(const TextStyle& other) const;
157     bool equalsByFonts(const TextStyle& that) const;
158     bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
159     bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
160 
161     // Colors
getColor()162     SkColor getColor() const { return fColor; }
setColor(SkColor color)163     void setColor(SkColor color) { fColor = color; }
164 
hasForeground()165     bool hasForeground() const { return fHasForeground; }
getForeground()166     SkPaint getForeground() const { return fForeground; }
setForegroundColor(SkPaint paint)167     void setForegroundColor(SkPaint paint) {
168         fHasForeground = true;
169         fForeground = std::move(paint);
170     }
clearForegroundColor()171     void clearForegroundColor() { fHasForeground = false; }
172 
hasBackground()173     bool hasBackground() const { return fHasBackground; }
getBackground()174     SkPaint getBackground() const { return fBackground; }
setBackgroundColor(SkPaint paint)175     void setBackgroundColor(SkPaint paint) {
176         fHasBackground = true;
177         fBackground = std::move(paint);
178     }
clearBackgroundColor()179     void clearBackgroundColor() { fHasBackground = false; }
180 
181     // Decorations
getDecoration()182     Decoration getDecoration() const { return fDecoration; }
getDecorationType()183     TextDecoration getDecorationType() const { return fDecoration.fType; }
getDecorationColor()184     SkColor getDecorationColor() const { return fDecoration.fColor; }
getDecorationStyle()185     TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
getDecorationThicknessMultiplier()186     SkScalar getDecorationThicknessMultiplier() const {
187         return fDecoration.fThicknessMultiplier;
188     }
setDecoration(TextDecoration decoration)189     void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
setDecorationStyle(TextDecorationStyle style)190     void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
setDecorationColor(SkColor color)191     void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
setDecorationThicknessMultiplier(SkScalar m)192     void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
193 
194     // Weight/Width/Slant
getFontStyle()195     SkFontStyle getFontStyle() const { return fFontStyle; }
setFontStyle(SkFontStyle fontStyle)196     void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
197 
198     // Shadows
getShadowNumber()199     size_t getShadowNumber() const { return fTextShadows.size(); }
getShadows()200     std::vector<TextShadow> getShadows() const { return fTextShadows; }
addShadow(TextShadow shadow)201     void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
resetShadows()202     void resetShadows() { fTextShadows.clear(); }
203 
204     // Font features
getFontFeatureNumber()205     size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
getFontFeatures()206     std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
addFontFeature(const SkString & fontFeature,int value)207     void addFontFeature(const SkString& fontFeature, int value)
208         { fFontFeatures.emplace_back(fontFeature, value); }
resetFontFeatures()209     void resetFontFeatures() { fFontFeatures.clear(); }
210 
getFontSize()211     SkScalar getFontSize() const { return fFontSize; }
setFontSize(SkScalar size)212     void setFontSize(SkScalar size) { fFontSize = size; }
213 
getFontFamilies()214     const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
setFontFamilies(std::vector<SkString> families)215     void setFontFamilies(std::vector<SkString> families) {
216         fFontFamilies = std::move(families);
217     }
218 
setHeight(SkScalar height)219     void setHeight(SkScalar height) { fHeight = height; }
getHeight()220     SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
221 
setHeightOverride(bool heightOverride)222     void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
getHeightOverride()223     bool getHeightOverride() const { return fHeightOverride; }
224 
setLetterSpacing(SkScalar letterSpacing)225     void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
getLetterSpacing()226     SkScalar getLetterSpacing() const { return fLetterSpacing; }
227 
setWordSpacing(SkScalar wordSpacing)228     void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
getWordSpacing()229     SkScalar getWordSpacing() const { return fWordSpacing; }
230 
getTypeface()231     SkTypeface* getTypeface() const { return fTypeface.get(); }
refTypeface()232     sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
setTypeface(sk_sp<SkTypeface> typeface)233     void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
234 
getLocale()235     SkString getLocale() const { return fLocale; }
setLocale(const SkString & locale)236     void setLocale(const SkString& locale) { fLocale = locale; }
237 
getTextBaseline()238     TextBaseline getTextBaseline() const { return fTextBaseline; }
setTextBaseline(TextBaseline baseline)239     void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
240 
241     void getFontMetrics(SkFontMetrics* metrics) const;
242 
isPlaceholder()243     bool isPlaceholder() const { return fIsPlaceholder; }
setPlaceholder()244     void setPlaceholder() { fIsPlaceholder = true; }
245 
246 private:
247 
248     Decoration fDecoration;
249 
250     SkFontStyle fFontStyle;
251 
252     std::vector<SkString> fFontFamilies;
253     SkScalar fFontSize;
254     SkScalar fHeight;
255     bool fHeightOverride;
256     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;
271     bool fIsPlaceholder;
272 
273     std::vector<FontFeature> fFontFeatures;
274 };
275 
276 typedef size_t TextIndex;
277 typedef SkRange<size_t> TextRange;
278 const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
279 
280 
281 struct Block {
BlockBlock282     Block() : fRange(EMPTY_RANGE), fStyle() { }
BlockBlock283     Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
BlockBlock284     Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
285 
BlockBlock286     Block(const Block& other) : fRange(other.fRange), fStyle(other.fStyle) {}
287 
addBlock288     void add(TextRange tail) {
289         SkASSERT(fRange.end == tail.start);
290         fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
291     }
292 
293     TextRange fRange;
294     TextStyle fStyle;
295 };
296 
297 
298 typedef size_t BlockIndex;
299 typedef SkRange<size_t> BlockRange;
300 const size_t EMPTY_BLOCK = EMPTY_INDEX;
301 const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
302 
303 struct Placeholder {
PlaceholderPlaceholder304     Placeholder() : fRange(EMPTY_RANGE), fStyle() {}
305 
PlaceholderPlaceholder306     Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
307                 BlockRange blocksBefore, TextRange textBefore)
308             : fRange(start, end)
309             , fStyle(style)
310             , fTextStyle(textStyle)
311             , fBlocksBefore(blocksBefore)
312             , fTextBefore(textBefore) {}
313 
PlaceholderPlaceholder314     Placeholder(const Placeholder& other)
315             : fRange(other.fRange)
316             , fStyle(other.fStyle)
317             , fTextStyle(other.fTextStyle)
318             , fBlocksBefore(other.fBlocksBefore)
319             , fTextBefore(other.fTextBefore) {}
320 
321     TextRange fRange;
322     PlaceholderStyle fStyle;
323     TextStyle fTextStyle;
324     BlockRange fBlocksBefore;
325     TextRange fTextBefore;
326 };
327 
328 }  // namespace textlayout
329 }  // namespace skia
330 
331 #endif  // TextStyle_DEFINED
332