• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 #ifndef TextStyle_DEFINED
3 #define TextStyle_DEFINED
4 
5 #include <optional>
6 #include <vector>
7 #include "include/core/SkColor.h"
8 #include "include/core/SkFont.h"
9 #include "include/core/SkFontMetrics.h"
10 #include "include/core/SkFontStyle.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkScalar.h"
13 #include "modules/skparagraph/include/DartTypes.h"
14 #include "modules/skparagraph/include/FontArguments.h"
15 #include "modules/skparagraph/include/ParagraphPainter.h"
16 #include "modules/skparagraph/include/TextShadow.h"
17 
18 // TODO: Make it external so the other platforms (Android) could use it
19 #define DEFAULT_FONT_FAMILY "sans-serif"
20 
21 namespace skia {
22 namespace textlayout {
23 
24 static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
25     if (SkScalarIsFinite(x)) {
26         return SkScalarNearlyZero(x, tolerance);
27     }
28     return false;
29 }
30 
31 static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) {
32     if (SkScalarIsFinite(x) && SkScalarIsFinite(x)) {
33         return SkScalarNearlyEqual(x, y, tolerance);
34     }
35     // Inf == Inf, anything else is false
36     return x == y;
37 }
38 
39 // Multiple decorations can be applied at once. Ex: Underline and overline is
40 // (0x1 | 0x2)
41 enum TextDecoration {
42     kNoDecoration = 0x0,
43     kUnderline = 0x1,
44     kOverline = 0x2,
45     kLineThrough = 0x4,
46 };
47 constexpr TextDecoration AllTextDecorations[] = {
48         kNoDecoration,
49         kUnderline,
50         kOverline,
51         kLineThrough,
52 };
53 
54 enum TextDecorationStyle { kSolid, kDouble, kDotted, kDashed, kWavy };
55 
56 enum TextDecorationMode { kGaps, kThrough };
57 
58 enum StyleType {
59     kNone,
60     kAllAttributes,
61     kFont,
62     kForeground,
63     kBackground,
64     kShadow,
65     kDecorations,
66     kLetterSpacing,
67     kWordSpacing
68 };
69 
70 struct Decoration {
71     TextDecoration fType;
72     TextDecorationMode fMode;
73     SkColor fColor;
74     TextDecorationStyle fStyle;
75     SkScalar fThicknessMultiplier;
76 
77     bool operator==(const Decoration& other) const {
78         return this->fType == other.fType &&
79                this->fMode == other.fMode &&
80                this->fColor == other.fColor &&
81                this->fStyle == other.fStyle &&
82                this->fThicknessMultiplier == other.fThicknessMultiplier;
83     }
84 };
85 
86 /// Where to vertically align the placeholder relative to the surrounding text.
87 enum class PlaceholderAlignment {
88   /// Match the baseline of the placeholder with the baseline.
89   kBaseline,
90 
91   /// Align the bottom edge of the placeholder with the baseline such that the
92   /// placeholder sits on top of the baseline.
93   kAboveBaseline,
94 
95   /// Align the top edge of the placeholder with the baseline specified in
96   /// such that the placeholder hangs below the baseline.
97   kBelowBaseline,
98 
99   /// Align the top edge of the placeholder with the top edge of the font.
100   /// When the placeholder is very tall, the extra space will hang from
101   /// the top and extend through the bottom of the line.
102   kTop,
103 
104   /// Align the bottom edge of the placeholder with the top edge of the font.
105   /// When the placeholder is very tall, the extra space will rise from
106   /// the bottom and extend through the top of the line.
107   kBottom,
108 
109   /// Align the middle of the placeholder with the middle of the text. When the
110   /// placeholder is very tall, the extra space will grow equally from
111   /// the top and bottom of the line.
112   kMiddle,
113 };
114 
115 struct FontFeature {
FontFeatureFontFeature116     FontFeature(const SkString name, int value) : fName(name), fValue(value) {}
117     bool operator==(const FontFeature& that) const {
118         return fName == that.fName && fValue == that.fValue;
119     }
120     SkString fName;
121     int fValue;
122 };
123 
124 struct PlaceholderStyle {
125     PlaceholderStyle() = default;
PlaceholderStylePlaceholderStyle126     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 
134     bool equals(const PlaceholderStyle&) const;
135 
136     SkScalar fWidth = 0;
137     SkScalar fHeight = 0;
138     PlaceholderAlignment fAlignment = PlaceholderAlignment::kBaseline;
139     TextBaseline fBaseline = TextBaseline::kAlphabetic;
140     // 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.
148     SkScalar fBaselineOffset = 0;
149 };
150 
151 struct RectStyle {
152     SkColor color = 0;
153     SkScalar leftTopRadius = 0.0f;
154     SkScalar rightTopRadius = 0.0f;
155     SkScalar rightBottomRadius = 0.0f;
156     SkScalar leftBottomRadius = 0.0f;
157 };
158 
159 class TextStyle {
160 public:
161     TextStyle() = default;
162     TextStyle(const TextStyle& other) = default;
163     TextStyle& operator=(const TextStyle& other) = default;
164 
165     TextStyle cloneForPlaceholder();
166 
167     bool equals(const TextStyle& other) const;
168     bool equalsByFonts(const TextStyle& that) const;
169     bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
170     bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
171 
172     // Colors
getColor()173     SkColor getColor() const { return fColor; }
setColor(SkColor color)174     void setColor(SkColor color) { fColor = color; }
175 
hasForeground()176     bool hasForeground() const { return fHasForeground; }
getForeground()177     SkPaint getForeground() const {
178         const SkPaint* paint = std::get_if<SkPaint>(&fForeground);
179         return paint ? *paint : SkPaint();
180     }
getForegroundPaintOrID()181     ParagraphPainter::SkPaintOrID getForegroundPaintOrID() const {
182         return fForeground;
183     }
setForegroundPaint(SkPaint paint)184     void setForegroundPaint(SkPaint paint) {
185         fHasForeground = true;
186         fForeground = std::move(paint);
187     }
188     // DEPRECATED: prefer `setForegroundPaint`.
setForegroundColor(SkPaint paint)189     void setForegroundColor(SkPaint paint) { setForegroundPaint(paint); }
190     // Set the foreground to a paint ID.  This is intended for use by clients
191     // that implement a custom ParagraphPainter that can not accept an SkPaint.
setForegroundPaintID(ParagraphPainter::PaintID paintID)192     void setForegroundPaintID(ParagraphPainter::PaintID paintID) {
193         fHasForeground = true;
194         fForeground = paintID;
195     }
clearForegroundColor()196     void clearForegroundColor() { fHasForeground = false; }
197 
hasBackground()198     bool hasBackground() const { return fHasBackground; }
getBackground()199     SkPaint getBackground() const {
200         const SkPaint* paint = std::get_if<SkPaint>(&fBackground);
201         return paint ? *paint : SkPaint();
202     }
getBackgroundPaintOrID()203     ParagraphPainter::SkPaintOrID getBackgroundPaintOrID() const {
204         return fBackground;
205     }
setBackgroundPaint(SkPaint paint)206     void setBackgroundPaint(SkPaint paint) {
207         fHasBackground = true;
208         fBackground = std::move(paint);
209     }
210     // DEPRECATED: prefer `setBackgroundPaint`.
setBackgroundColor(SkPaint paint)211     void setBackgroundColor(SkPaint paint) { setBackgroundPaint(paint); }
setBackgroundPaintID(ParagraphPainter::PaintID paintID)212     void setBackgroundPaintID(ParagraphPainter::PaintID paintID) {
213         fHasBackground = true;
214         fBackground = paintID;
215     }
clearBackgroundColor()216     void clearBackgroundColor() { fHasBackground = false; }
217 
218     // Decorations
getDecoration()219     Decoration getDecoration() const { return fDecoration; }
getDecorationType()220     TextDecoration getDecorationType() const { return fDecoration.fType; }
getDecorationMode()221     TextDecorationMode getDecorationMode() const { return fDecoration.fMode; }
getDecorationColor()222     SkColor getDecorationColor() const { return fDecoration.fColor; }
getDecorationStyle()223     TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
getDecorationThicknessMultiplier()224     SkScalar getDecorationThicknessMultiplier() const {
225         return fDecoration.fThicknessMultiplier;
226     }
setDecoration(TextDecoration decoration)227     void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
setDecorationMode(TextDecorationMode mode)228     void setDecorationMode(TextDecorationMode mode) { fDecoration.fMode = mode; }
setDecorationStyle(TextDecorationStyle style)229     void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
setDecorationColor(SkColor color)230     void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
setDecorationThicknessMultiplier(SkScalar m)231     void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
232 
233     // Weight/Width/Slant
getFontStyle()234     SkFontStyle getFontStyle() const { return fFontStyle; }
setFontStyle(SkFontStyle fontStyle)235     void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
236 
237     // Shadows
getShadowNumber()238     size_t getShadowNumber() const { return fTextShadows.size(); }
getShadows()239     std::vector<TextShadow> getShadows() const { return fTextShadows; }
addShadow(TextShadow shadow)240     void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
resetShadows()241     void resetShadows() { fTextShadows.clear(); }
242 
243     // Font features
getFontFeatureNumber()244     size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
getFontFeatures()245     std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
addFontFeature(const SkString & fontFeature,int value)246     void addFontFeature(const SkString& fontFeature, int value)
247         { fFontFeatures.emplace_back(fontFeature, value); }
resetFontFeatures()248     void resetFontFeatures() { fFontFeatures.clear(); }
249 
250     // Font arguments
getFontArguments()251     const std::optional<FontArguments>& getFontArguments() const { return fFontArguments; }
252     // The contents of the SkFontArguments will be copied into the TextStyle,
253     // and the SkFontArguments can be safely deleted after setFontArguments returns.
254     void setFontArguments(const std::optional<SkFontArguments>& args);
255 
getFontSize()256     SkScalar getFontSize() const { return fFontSize; }
setFontSize(SkScalar size)257     void setFontSize(SkScalar size) { fFontSize = size; }
258 
getFontFamilies()259     const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
setFontFamilies(std::vector<SkString> families)260     void setFontFamilies(std::vector<SkString> families) {
261         fFontFamilies = std::move(families);
262     }
263 
getBaselineShift()264     SkScalar getBaselineShift() const { return fBaselineShift; }
setBaselineShift(SkScalar baselineShift)265     void setBaselineShift(SkScalar baselineShift) { fBaselineShift = baselineShift; }
266 
setHeight(SkScalar height)267     void setHeight(SkScalar height) { fHeight = height; }
getHeight()268     SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
269 
setHeightOverride(bool heightOverride)270     void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
getHeightOverride()271     bool getHeightOverride() const { return fHeightOverride; }
272 
setHalfLeading(bool halfLeading)273     void setHalfLeading(bool halfLeading) { fHalfLeading = halfLeading; }
getHalfLeading()274     bool getHalfLeading() const { return fHalfLeading; }
275 
setLetterSpacing(SkScalar letterSpacing)276     void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
getLetterSpacing()277     SkScalar getLetterSpacing() const { return fLetterSpacing; }
278 
setWordSpacing(SkScalar wordSpacing)279     void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
getWordSpacing()280     SkScalar getWordSpacing() const { return fWordSpacing; }
281 
getTypeface()282     SkTypeface* getTypeface() const { return fTypeface.get(); }
refTypeface()283     sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
setTypeface(sk_sp<SkTypeface> typeface)284     void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
285 
getLocale()286     SkString getLocale() const { return fLocale; }
setLocale(const SkString & locale)287     void setLocale(const SkString& locale) { fLocale = locale; }
288 
getTextBaseline()289     TextBaseline getTextBaseline() const { return fTextBaseline; }
setTextBaseline(TextBaseline baseline)290     void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
291 
292     void getFontMetrics(SkFontMetrics* metrics) const;
293 
isPlaceholder()294     bool isPlaceholder() const { return fIsPlaceholder; }
setPlaceholder()295     void setPlaceholder() { fIsPlaceholder = true; }
296 
getStyleId()297     int getStyleId() const { return fStyleId; }
setStyleId(int styleId)298     void setStyleId(int styleId) { fStyleId = styleId; }
299 
getBackgroundRect()300     RectStyle getBackgroundRect() const { return fBackgroundRect; }
setBackgroundRect(RectStyle rect)301     void setBackgroundRect(RectStyle rect) { fBackgroundRect = rect; }
302 
303 private:
304     static const std::vector<SkString>* kDefaultFontFamilies;
305 
306     Decoration fDecoration = {
307             TextDecoration::kNoDecoration,
308             // TODO: switch back to kGaps when (if) switching flutter to skparagraph
309             TextDecorationMode::kThrough,
310             // It does not make sense to draw a transparent object, so we use this as a default
311             // value to indicate no decoration color was set.
312             SK_ColorTRANSPARENT, TextDecorationStyle::kSolid,
313             // Thickness is applied as a multiplier to the default thickness of the font.
314             1.0f};
315 
316     SkFontStyle fFontStyle;
317 
318     std::vector<SkString> fFontFamilies = *kDefaultFontFamilies;
319 
320     SkScalar fFontSize = 14.0;
321     SkScalar fHeight = 1.0;
322     bool fHeightOverride = false;
323     SkScalar fBaselineShift = 0.0f;
324     // true: half leading.
325     // false: scale ascent/descent with fHeight.
326     bool fHalfLeading = false;
327     SkString fLocale = {};
328     RectStyle fBackgroundRect = {0, 0.0f, 0.0f, 0.0f, 0.0f};
329     SkColor fStyleId = 0;
330     SkScalar fLetterSpacing = 0.0;
331     SkScalar fWordSpacing = 0.0;
332 
333     TextBaseline fTextBaseline = TextBaseline::kAlphabetic;
334 
335     SkColor fColor = SK_ColorWHITE;
336     bool fHasBackground = false;
337     ParagraphPainter::SkPaintOrID fBackground;
338     bool fHasForeground = false;
339     ParagraphPainter::SkPaintOrID fForeground;
340 
341     std::vector<TextShadow> fTextShadows;
342 
343     sk_sp<SkTypeface> fTypeface;
344     bool fIsPlaceholder = false;
345 
346     std::vector<FontFeature> fFontFeatures;
347 
348     std::optional<FontArguments> fFontArguments;
349 };
350 
351 typedef size_t TextIndex;
352 typedef SkRange<size_t> TextRange;
353 const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
354 
355 struct Block {
356     Block() = default;
BlockBlock357     Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
BlockBlock358     Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
359 
addBlock360     void add(TextRange tail) {
361         SkASSERT(fRange.end == tail.start);
362         fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
363     }
364 
365     TextRange fRange = EMPTY_RANGE;
366     TextStyle fStyle;
367 };
368 
369 
370 typedef size_t BlockIndex;
371 typedef SkRange<size_t> BlockRange;
372 const size_t EMPTY_BLOCK = EMPTY_INDEX;
373 const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
374 
375 struct Placeholder {
376     Placeholder() = default;
PlaceholderPlaceholder377     Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
378                 BlockRange blocksBefore, TextRange textBefore)
379             : fRange(start, end)
380             , fStyle(style)
381             , fTextStyle(textStyle)
382             , fBlocksBefore(blocksBefore)
383             , fTextBefore(textBefore) {}
384 
385     TextRange fRange = EMPTY_RANGE;
386     PlaceholderStyle fStyle;
387     TextStyle fTextStyle;
388     BlockRange fBlocksBefore;
389     TextRange fTextBefore;
390 };
391 
392 }  // namespace textlayout
393 }  // namespace skia
394 
395 #endif  // TextStyle_DEFINED
396