• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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     bool operator==(const Decoration& other) const {
75         return this->fType == other.fType &&
76                this->fMode == other.fMode &&
77                this->fColor == other.fColor &&
78                this->fStyle == other.fStyle &&
79                this->fThicknessMultiplier == other.fThicknessMultiplier;
80     }
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 {
FontFeatureFontFeature113     FontFeature(const SkString name, int value) : fName(name), fValue(value) {}
114     bool operator==(const FontFeature& that) const {
115         return fName == that.fName && fValue == that.fValue;
116     }
117     SkString fName;
118     int fValue;
119 };
120 
121 struct PlaceholderStyle {
122     PlaceholderStyle() = default;
PlaceholderStylePlaceholderStyle123     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 
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     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     bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
157 
158     // Colors
getColor()159     SkColor getColor() const { return fColor; }
setColor(SkColor color)160     void setColor(SkColor color) { fColor = color; }
161 
hasForeground()162     bool hasForeground() const { return fHasForeground; }
getForeground()163     SkPaint getForeground() const { return fForeground; }
setForegroundColor(SkPaint paint)164     void setForegroundColor(SkPaint paint) {
165         fHasForeground = true;
166         fForeground = std::move(paint);
167     }
clearForegroundColor()168     void clearForegroundColor() { fHasForeground = false; }
169 
hasBackground()170     bool hasBackground() const { return fHasBackground; }
getBackground()171     SkPaint getBackground() const { return fBackground; }
setBackgroundColor(SkPaint paint)172     void setBackgroundColor(SkPaint paint) {
173         fHasBackground = true;
174         fBackground = std::move(paint);
175     }
clearBackgroundColor()176     void clearBackgroundColor() { fHasBackground = false; }
177 
178     // Decorations
getDecoration()179     Decoration getDecoration() const { return fDecoration; }
getDecorationType()180     TextDecoration getDecorationType() const { return fDecoration.fType; }
getDecorationMode()181     TextDecorationMode getDecorationMode() const { return fDecoration.fMode; }
getDecorationColor()182     SkColor getDecorationColor() const { return fDecoration.fColor; }
getDecorationStyle()183     TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
getDecorationThicknessMultiplier()184     SkScalar getDecorationThicknessMultiplier() const {
185         return fDecoration.fThicknessMultiplier;
186     }
setDecoration(TextDecoration decoration)187     void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
setDecorationMode(TextDecorationMode mode)188     void setDecorationMode(TextDecorationMode mode) { fDecoration.fMode = mode; }
setDecorationStyle(TextDecorationStyle style)189     void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
setDecorationColor(SkColor color)190     void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
setDecorationThicknessMultiplier(SkScalar m)191     void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
192 
193     // Weight/Width/Slant
getFontStyle()194     SkFontStyle getFontStyle() const { return fFontStyle; }
setFontStyle(SkFontStyle fontStyle)195     void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
196 
197     // Shadows
getShadowNumber()198     size_t getShadowNumber() const { return fTextShadows.size(); }
getShadows()199     std::vector<TextShadow> getShadows() const { return fTextShadows; }
addShadow(TextShadow shadow)200     void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
resetShadows()201     void resetShadows() { fTextShadows.clear(); }
202 
203     // Font features
getFontFeatureNumber()204     size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
getFontFeatures()205     std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
addFontFeature(const SkString & fontFeature,int value)206     void addFontFeature(const SkString& fontFeature, int value)
207         { fFontFeatures.emplace_back(fontFeature, value); }
resetFontFeatures()208     void resetFontFeatures() { fFontFeatures.clear(); }
209 
getFontSize()210     SkScalar getFontSize() const { return fFontSize; }
setFontSize(SkScalar size)211     void setFontSize(SkScalar size) { fFontSize = size; }
212 
getFontFamilies()213     const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
setFontFamilies(std::vector<SkString> families)214     void setFontFamilies(std::vector<SkString> families) {
215         fFontFamilies = std::move(families);
216     }
217 
getBaselineShift()218     SkScalar getBaselineShift() const { return fBaselineShift; }
setBaselineShift(SkScalar baselineShift)219     void setBaselineShift(SkScalar baselineShift) { fBaselineShift = baselineShift; }
220 
setHeight(SkScalar height)221     void setHeight(SkScalar height) { fHeight = height; }
getHeight()222     SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
223 
setHeightOverride(bool heightOverride)224     void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
getHeightOverride()225     bool getHeightOverride() const { return fHeightOverride; }
226 
setHalfLeading(bool halfLeading)227     void setHalfLeading(bool halfLeading) { fHalfLeading = halfLeading; }
getHalfLeading()228     bool getHalfLeading() const { return fHalfLeading; }
229 
setLetterSpacing(SkScalar letterSpacing)230     void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
getLetterSpacing()231     SkScalar getLetterSpacing() const { return fLetterSpacing; }
232 
setWordSpacing(SkScalar wordSpacing)233     void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
getWordSpacing()234     SkScalar getWordSpacing() const { return fWordSpacing; }
235 
getTypeface()236     SkTypeface* getTypeface() const { return fTypeface.get(); }
refTypeface()237     sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
setTypeface(sk_sp<SkTypeface> typeface)238     void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
239 
getLocale()240     SkString getLocale() const { return fLocale; }
setLocale(const SkString & locale)241     void setLocale(const SkString& locale) { fLocale = locale; }
242 
getTextBaseline()243     TextBaseline getTextBaseline() const { return fTextBaseline; }
setTextBaseline(TextBaseline baseline)244     void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
245 
246     void getFontMetrics(SkFontMetrics* metrics) const;
247 
isPlaceholder()248     bool isPlaceholder() const { return fIsPlaceholder; }
setPlaceholder()249     void setPlaceholder() { fIsPlaceholder = true; }
250 
251 private:
252     static const std::vector<SkString> kDefaultFontFamilies;
253 
254     Decoration fDecoration = {
255             TextDecoration::kNoDecoration,
256             // TODO: switch back to kGaps when (if) switching flutter to skparagraph
257             TextDecorationMode::kThrough,
258             // It does not make sense to draw a transparent object, so we use this as a default
259             // value to indicate no decoration color was set.
260             SK_ColorTRANSPARENT, TextDecorationStyle::kSolid,
261             // Thickness is applied as a multiplier to the default thickness of the font.
262             1.0f};
263 
264     SkFontStyle fFontStyle;
265 
266     std::vector<SkString> fFontFamilies = kDefaultFontFamilies;
267 
268     SkScalar fFontSize = 14.0;
269     SkScalar fHeight = 1.0;
270     bool fHeightOverride = false;
271     SkScalar fBaselineShift = 0.0f;
272     // true: half leading.
273     // false: scale ascent/descent with fHeight.
274     bool fHalfLeading = false;
275     SkString fLocale = {};
276     SkScalar fLetterSpacing = 0.0;
277     SkScalar fWordSpacing = 0.0;
278 
279     TextBaseline fTextBaseline = TextBaseline::kAlphabetic;
280 
281     SkColor fColor = SK_ColorWHITE;
282     bool fHasBackground = false;
283     SkPaint fBackground;
284     bool fHasForeground = false;
285     SkPaint fForeground;
286 
287     std::vector<TextShadow> fTextShadows;
288 
289     sk_sp<SkTypeface> fTypeface;
290     bool fIsPlaceholder = false;
291 
292     std::vector<FontFeature> fFontFeatures;
293 };
294 
295 typedef size_t TextIndex;
296 typedef SkRange<size_t> TextRange;
297 const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
298 
299 struct Block {
300     Block() = default;
BlockBlock301     Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
BlockBlock302     Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
303 
addBlock304     void add(TextRange tail) {
305         SkASSERT(fRange.end == tail.start);
306         fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
307     }
308 
309     TextRange fRange = EMPTY_RANGE;
310     TextStyle fStyle;
311 };
312 
313 
314 typedef size_t BlockIndex;
315 typedef SkRange<size_t> BlockRange;
316 const size_t EMPTY_BLOCK = EMPTY_INDEX;
317 const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
318 
319 struct Placeholder {
320     Placeholder() = default;
PlaceholderPlaceholder321     Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
322                 BlockRange blocksBefore, TextRange textBefore)
323             : fRange(start, end)
324             , fStyle(style)
325             , fTextStyle(textStyle)
326             , fBlocksBefore(blocksBefore)
327             , fTextBefore(textBefore) {}
328 
329     TextRange fRange = EMPTY_RANGE;
330     PlaceholderStyle fStyle;
331     TextStyle fTextStyle;
332     BlockRange fBlocksBefore;
333     TextRange fTextBefore;
334 };
335 
336 }  // namespace textlayout
337 }  // namespace skia
338 
339 #endif  // TextStyle_DEFINED
340