• 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 #ifdef ENABLE_TEXT_ENHANCE
18 #include "drawing.h"
19 #endif // ENABLE_TEXT_ENHANCE
20 // TODO: Make it external so the other platforms (Android) could use it
21 #define DEFAULT_FONT_FAMILY "sans-serif"
22 
23 namespace skia {
24 namespace textlayout {
25 #ifdef ENABLE_TEXT_ENHANCE
26 const SkScalar TEXT_BADGE_FONT_SIZE_SCALE = 0.65;
27 const SkScalar SUPERSCRIPT_BASELINE_SHIFT_SCALE = -0.7;
28 const SkScalar SUBSCRIPT_BASELINE_SHIFT_SCALE = 0.2;
29 #endif
30 
31 static inline bool nearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero) {
32     if (SkIsFinite(x)) {
33         return SkScalarNearlyZero(x, tolerance);
34     }
35     return false;
36 }
37 
38 static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_ScalarNearlyZero) {
39 #ifdef ENABLE_TEXT_ENHANCE
40     if (SkIsNaN(x) && SkIsNaN(y)) {
41         // Generally NaN has no equality, but it will break the invariant of the hashtable
42         // in ParagraphCache, resulting in errors. This fix is only a backstop for
43         // this condition, other functions may still be unreliable in the presence of NaN.
44         return true;
45     }
46 #endif
47     if (SkIsFinite(x, y)) {
48         return SkScalarNearlyEqual(x, y, tolerance);
49     }
50     // Inf == Inf, anything else is false
51     return x == y;
52 }
53 
54 // Multiple decorations can be applied at once. Ex: Underline and overline is
55 // (0x1 | 0x2)
56 enum TextDecoration {
57     kNoDecoration = 0x0,
58     kUnderline = 0x1,
59     kOverline = 0x2,
60     kLineThrough = 0x4,
61 };
62 constexpr TextDecoration AllTextDecorations[] = {
63         kNoDecoration,
64         kUnderline,
65         kOverline,
66         kLineThrough,
67 };
68 
69 enum TextDecorationStyle { kSolid, kDouble, kDotted, kDashed, kWavy };
70 
71 enum TextDecorationMode { kGaps, kThrough };
72 
73 enum StyleType {
74     kNone,
75     kAllAttributes,
76     kFont,
77     kForeground,
78     kBackground,
79     kShadow,
80     kDecorations,
81     kLetterSpacing,
82     kWordSpacing
83 };
84 
85 struct Decoration {
86     TextDecoration fType;
87     TextDecorationMode fMode;
88     SkColor fColor;
89     TextDecorationStyle fStyle;
90     SkScalar fThicknessMultiplier;
91 
92     bool operator==(const Decoration& other) const {
93         return this->fType == other.fType &&
94                this->fMode == other.fMode &&
95                this->fColor == other.fColor &&
96                this->fStyle == other.fStyle &&
97                this->fThicknessMultiplier == other.fThicknessMultiplier;
98     }
99 };
100 
101 /// Where to vertically align the placeholder relative to the surrounding text.
102 enum class PlaceholderAlignment {
103   /// Match the baseline of the placeholder with the baseline.
104   kBaseline,
105 
106   /// Align the bottom edge of the placeholder with the baseline such that the
107   /// placeholder sits on top of the baseline.
108   kAboveBaseline,
109 
110   /// Align the top edge of the placeholder with the baseline specified in
111   /// such that the placeholder hangs below the baseline.
112   kBelowBaseline,
113 
114   /// Align the top edge of the placeholder with the top edge of the font.
115   /// When the placeholder is very tall, the extra space will hang from
116   /// the top and extend through the bottom of the line.
117   kTop,
118 
119   /// Align the bottom edge of the placeholder with the top edge of the font.
120   /// When the placeholder is very tall, the extra space will rise from
121   /// the bottom and extend through the top of the line.
122   kBottom,
123 
124   /// Align the middle of the placeholder with the middle of the text. When the
125   /// placeholder is very tall, the extra space will grow equally from
126   /// the top and bottom of the line.
127   kMiddle,
128 
129 #ifdef ENABLE_TEXT_ENHANCE
130   // Follow text vertically aligned
131   kFollow,
132 #endif
133 };
134 
135 struct FontFeature {
FontFeatureFontFeature136     FontFeature(SkString name, int value) : fName(std::move(name)), fValue(value) {}
137     bool operator==(const FontFeature& that) const {
138         return fName == that.fName && fValue == that.fValue;
139     }
140     SkString fName;
141     int fValue;
142 };
143 
144 struct PlaceholderStyle {
145     PlaceholderStyle() = default;
PlaceholderStylePlaceholderStyle146     PlaceholderStyle(SkScalar width, SkScalar height, PlaceholderAlignment alignment,
147                      TextBaseline baseline, SkScalar offset)
148             : fWidth(width)
149             , fHeight(height)
150             , fAlignment(alignment)
151             , fBaseline(baseline)
152             , fBaselineOffset(offset) {}
153 
154     bool equals(const PlaceholderStyle&) const;
155 
156     SkScalar fWidth = 0;
157     SkScalar fHeight = 0;
158     PlaceholderAlignment fAlignment = PlaceholderAlignment::kBaseline;
159     TextBaseline fBaseline = TextBaseline::kAlphabetic;
160     // Distance from the top edge of the rect to the baseline position. This
161     // baseline will be aligned against the alphabetic baseline of the surrounding
162     // text.
163     //
164     // Positive values drop the baseline lower (positions the rect higher) and
165     // small or negative values will cause the rect to be positioned underneath
166     // the line. When baseline == height, the bottom edge of the rect will rest on
167     // the alphabetic baseline.
168     SkScalar fBaselineOffset = 0;
169 };
170 
171 #ifdef ENABLE_TEXT_ENHANCE
172 struct RectStyle {
173     SkColor color{0};
174     SkScalar leftTopRadius{0.0f};
175     SkScalar rightTopRadius{0.0f};
176     SkScalar rightBottomRadius{0.0f};
177     SkScalar leftBottomRadius{0.0f};
178 
179     bool operator ==(const RectStyle& rhs) const {
180         return color == rhs.color &&
181             leftTopRadius == rhs.leftTopRadius &&
182             rightTopRadius == rhs.rightTopRadius &&
183             rightBottomRadius == rhs.rightBottomRadius &&
184             leftBottomRadius == rhs.leftBottomRadius;
185     }
186 
187     bool operator !=(const RectStyle& rhs) const {
188         return !(color == rhs.color &&
189             leftTopRadius == rhs.leftTopRadius &&
190             rightTopRadius == rhs.rightTopRadius &&
191             rightBottomRadius == rhs.rightBottomRadius &&
192             leftBottomRadius == rhs.leftBottomRadius);
193     }
194 };
195 
196 enum class TextBadgeType {
197     BADGE_NONE,
198     SUPERSCRIPT,
199     SUBSCRIPT,
200 };
201 #endif
202 
203 class TextStyle {
204 public:
205     TextStyle() = default;
206     TextStyle(const TextStyle& other) = default;
207     TextStyle& operator=(const TextStyle& other) = default;
208 
209     TextStyle cloneForPlaceholder();
210 
211     bool equals(const TextStyle& other) const;
212     bool equalsByFonts(const TextStyle& that) const;
213     bool matchOneAttribute(StyleType styleType, const TextStyle& other) const;
214     bool operator==(const TextStyle& rhs) const { return this->equals(rhs); }
215 
216     // Colors
getColor()217     SkColor getColor() const { return fColor; }
setColor(SkColor color)218     void setColor(SkColor color) { fColor = color; }
219 
hasForeground()220     bool hasForeground() const { return fHasForeground; }
getForeground()221     SkPaint getForeground() const {
222         const SkPaint* paint = std::get_if<SkPaint>(&fForeground);
223         return paint ? *paint : SkPaint();
224     }
getForegroundPaintOrID()225     ParagraphPainter::SkPaintOrID getForegroundPaintOrID() const {
226         return fForeground;
227     }
setForegroundPaint(SkPaint paint)228     void setForegroundPaint(SkPaint paint) {
229         fHasForeground = true;
230         fForeground = std::move(paint);
231     }
232     // DEPRECATED: prefer `setForegroundPaint`.
setForegroundColor(SkPaint paint)233     void setForegroundColor(SkPaint paint) { setForegroundPaint(std::move(paint)); }
234 
235     // Set the foreground to a paint ID.  This is intended for use by clients
236     // that implement a custom ParagraphPainter that can not accept an SkPaint.
setForegroundPaintID(ParagraphPainter::PaintID paintID)237     void setForegroundPaintID(ParagraphPainter::PaintID paintID) {
238         fHasForeground = true;
239         fForeground = paintID;
240     }
clearForegroundColor()241     void clearForegroundColor() { fHasForeground = false; }
242 
hasBackground()243     bool hasBackground() const { return fHasBackground; }
getBackground()244     SkPaint getBackground() const {
245         const SkPaint* paint = std::get_if<SkPaint>(&fBackground);
246         return paint ? *paint : SkPaint();
247     }
getBackgroundPaintOrID()248     ParagraphPainter::SkPaintOrID getBackgroundPaintOrID() const {
249         return fBackground;
250     }
setBackgroundPaint(SkPaint paint)251     void setBackgroundPaint(SkPaint paint) {
252         fHasBackground = true;
253         fBackground = std::move(paint);
254     }
255     // DEPRECATED: prefer `setBackgroundPaint`.
setBackgroundColor(SkPaint paint)256     void setBackgroundColor(SkPaint paint) { setBackgroundPaint(std::move(paint)); }
setBackgroundPaintID(ParagraphPainter::PaintID paintID)257     void setBackgroundPaintID(ParagraphPainter::PaintID paintID) {
258         fHasBackground = true;
259         fBackground = paintID;
260     }
clearBackgroundColor()261     void clearBackgroundColor() { fHasBackground = false; }
262 
263     // Decorations
getDecoration()264     Decoration getDecoration() const { return fDecoration; }
getDecorationType()265     TextDecoration getDecorationType() const { return fDecoration.fType; }
getDecorationMode()266     TextDecorationMode getDecorationMode() const { return fDecoration.fMode; }
getDecorationColor()267     SkColor getDecorationColor() const { return fDecoration.fColor; }
getDecorationStyle()268     TextDecorationStyle getDecorationStyle() const { return fDecoration.fStyle; }
getDecorationThicknessMultiplier()269     SkScalar getDecorationThicknessMultiplier() const {
270         return fDecoration.fThicknessMultiplier;
271     }
setDecoration(TextDecoration decoration)272     void setDecoration(TextDecoration decoration) { fDecoration.fType = decoration; }
setDecorationMode(TextDecorationMode mode)273     void setDecorationMode(TextDecorationMode mode) { fDecoration.fMode = mode; }
setDecorationStyle(TextDecorationStyle style)274     void setDecorationStyle(TextDecorationStyle style) { fDecoration.fStyle = style; }
setDecorationColor(SkColor color)275     void setDecorationColor(SkColor color) { fDecoration.fColor = color; }
setDecorationThicknessMultiplier(SkScalar m)276     void setDecorationThicknessMultiplier(SkScalar m) { fDecoration.fThicknessMultiplier = m; }
277 
278     // Weight/Width/Slant
279 #ifdef ENABLE_TEXT_ENHANCE
getFontStyle()280     RSFontStyle getFontStyle() const { return fFontStyle; }
setFontStyle(RSFontStyle fontStyle)281     void setFontStyle(RSFontStyle fontStyle) { fFontStyle = fontStyle; }
282 #else
getFontStyle()283     SkFontStyle getFontStyle() const { return fFontStyle; }
setFontStyle(SkFontStyle fontStyle)284     void setFontStyle(SkFontStyle fontStyle) { fFontStyle = fontStyle; }
285 #endif
286 
287     // Shadows
getShadowNumber()288     size_t getShadowNumber() const { return fTextShadows.size(); }
getShadows()289     std::vector<TextShadow> getShadows() const { return fTextShadows; }
addShadow(TextShadow shadow)290     void addShadow(TextShadow shadow) { fTextShadows.emplace_back(shadow); }
resetShadows()291     void resetShadows() { fTextShadows.clear(); }
292 
293     // Font features
getFontFeatureNumber()294     size_t getFontFeatureNumber() const { return fFontFeatures.size(); }
getFontFeatures()295     std::vector<FontFeature> getFontFeatures() const { return fFontFeatures; }
addFontFeature(const SkString & fontFeature,int value)296     void addFontFeature(const SkString& fontFeature, int value)
297         { fFontFeatures.emplace_back(fontFeature, value); }
resetFontFeatures()298     void resetFontFeatures() { fFontFeatures.clear(); }
299 
300     // Font arguments
getFontArguments()301     const std::optional<FontArguments>& getFontArguments() const { return fFontArguments; }
302     // The contents of the SkFontArguments will be copied into the TextStyle,
303     // and the SkFontArguments can be safely deleted after setFontArguments returns.
304     void setFontArguments(const std::optional<SkFontArguments>& args);
305 
getFontSize()306     SkScalar getFontSize() const { return fFontSize; }
setFontSize(SkScalar size)307     void setFontSize(SkScalar size) { fFontSize = size; }
308 
getFontFamilies()309     const std::vector<SkString>& getFontFamilies() const { return fFontFamilies; }
310 
311 #ifdef ENABLE_TEXT_ENHANCE
312     void setFontFamilies(std::vector<SkString> families);
313 
getBaselineShift()314     SkScalar getBaselineShift() const { return fBaselineShift; }
getVerticalAlignShift()315     SkScalar getVerticalAlignShift() const { return fVerticalAlignShift; };
getTotalVerticalShift()316     SkScalar getTotalVerticalShift() const { return fBaselineShift + getBadgeBaseLineShift(); }
setVerticalAlignShift(SkScalar shift)317     void setVerticalAlignShift(SkScalar shift) { fVerticalAlignShift = shift; }
318 #else
setFontFamilies(std::vector<SkString> families)319     void setFontFamilies(std::vector<SkString> families) {
320         fFontFamilies = std::move(families);
321     }
322 
getBaselineShift()323     SkScalar getBaselineShift() const { return fBaselineShift; }
324 #endif
325 
setBaselineShift(SkScalar baselineShift)326     void setBaselineShift(SkScalar baselineShift) { fBaselineShift = baselineShift; }
327 
setHeight(SkScalar height)328     void setHeight(SkScalar height) { fHeight = height; }
getHeight()329     SkScalar getHeight() const { return fHeightOverride ? fHeight : 0; }
330 
setHeightOverride(bool heightOverride)331     void setHeightOverride(bool heightOverride) { fHeightOverride = heightOverride; }
getHeightOverride()332     bool getHeightOverride() const { return fHeightOverride; }
333 
setHalfLeading(bool halfLeading)334     void setHalfLeading(bool halfLeading) { fHalfLeading = halfLeading; }
getHalfLeading()335     bool getHalfLeading() const { return fHalfLeading; }
336 
setLetterSpacing(SkScalar letterSpacing)337     void setLetterSpacing(SkScalar letterSpacing) { fLetterSpacing = letterSpacing; }
getLetterSpacing()338     SkScalar getLetterSpacing() const { return fLetterSpacing; }
339 
setWordSpacing(SkScalar wordSpacing)340     void setWordSpacing(SkScalar wordSpacing) { fWordSpacing = wordSpacing; }
getWordSpacing()341     SkScalar getWordSpacing() const { return fWordSpacing; }
342 
343 #ifdef ENABLE_TEXT_ENHANCE
getTypeface()344     RSTypeface* getTypeface() const { return fTypeface.get(); }
refTypeface()345     std::shared_ptr<RSTypeface> refTypeface() const { return fTypeface; }
setTypeface(std::shared_ptr<RSTypeface> typeface)346     void setTypeface(std::shared_ptr<RSTypeface> typeface) { fTypeface = std::move(typeface); }
347 #else
getTypeface()348     SkTypeface* getTypeface() const { return fTypeface.get(); }
refTypeface()349     sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
setTypeface(sk_sp<SkTypeface> typeface)350     void setTypeface(sk_sp<SkTypeface> typeface) { fTypeface = std::move(typeface); }
351 #endif
352 
getLocale()353     SkString getLocale() const { return fLocale; }
setLocale(const SkString & locale)354     void setLocale(const SkString& locale) { fLocale = locale; }
355 
getTextBaseline()356     TextBaseline getTextBaseline() const { return fTextBaseline; }
setTextBaseline(TextBaseline baseline)357     void setTextBaseline(TextBaseline baseline) { fTextBaseline = baseline; }
358 
359 #ifdef ENABLE_TEXT_ENHANCE
360     void getFontMetrics(RSFontMetrics* metrics) const;
361 #else
362     void getFontMetrics(SkFontMetrics* metrics) const;
363 #endif
364 
isPlaceholder()365     bool isPlaceholder() const { return fIsPlaceholder; }
setPlaceholder()366     void setPlaceholder() { fIsPlaceholder = true; }
367 
368 #ifdef ENABLE_TEXT_ENHANCE
getStyleId()369     int getStyleId() const { return fStyleId; }
setStyleId(int styleId)370     void setStyleId(int styleId) { fStyleId = static_cast<SkColor>(styleId); }
getTextStyleUid()371     size_t getTextStyleUid() const { return fTextStyleUid; }
setTextStyleUid(size_t textStyleUid)372     void setTextStyleUid(size_t textStyleUid) { fTextStyleUid = textStyleUid; }
getBackgroundRect()373     RectStyle getBackgroundRect() const { return fBackgroundRect; }
setBackgroundRect(RectStyle rect)374     void setBackgroundRect(RectStyle rect) { fBackgroundRect = rect; }
isCustomSymbol()375     bool isCustomSymbol() const { return fIsCustomSymbol; }
376 
setCustomSymbol(bool state)377     void setCustomSymbol(bool state) { fIsCustomSymbol = state; }
378 
getTextBadgeType()379     TextBadgeType getTextBadgeType() const { return fBadgeType; }
380 
setTextBadgeType(TextBadgeType badgeType)381     void setTextBadgeType(TextBadgeType badgeType) { fBadgeType = badgeType; }
382 
383     SkScalar getBadgeBaseLineShift() const;
384 
385     SkScalar getCorrectFontSize() const;
386 #endif
387 private:
388     static const std::vector<SkString>* kDefaultFontFamilies;
389 
390     Decoration fDecoration = {
391             TextDecoration::kNoDecoration,
392 #ifdef ENABLE_TEXT_ENHANCE
393             TextDecorationMode::kGaps,
394 #else
395             // TODO: switch back to kGaps when (if) switching flutter to skparagraph
396             TextDecorationMode::kThrough,
397 #endif
398             // It does not make sense to draw a transparent object, so we use this as a default
399             // value to indicate no decoration color was set.
400             SK_ColorTRANSPARENT, TextDecorationStyle::kSolid,
401             // Thickness is applied as a multiplier to the default thickness of the font.
402             1.0f};
403 
404 #ifdef ENABLE_TEXT_ENHANCE
405     RSFontStyle fFontStyle;
406 #else
407     SkFontStyle fFontStyle;
408 #endif
409 
410     std::vector<SkString> fFontFamilies = *kDefaultFontFamilies;
411 
412     SkScalar fFontSize = 14.0;
413     SkScalar fHeight = 1.0;
414     bool fHeightOverride = false;
415     SkScalar fBaselineShift = 0.0f;
416     // true: half leading.
417     // false: scale ascent/descent with fHeight.
418     bool fHalfLeading = false;
419     SkString fLocale = {};
420     SkScalar fLetterSpacing = 0.0;
421     SkScalar fWordSpacing = 0.0;
422 #ifdef ENABLE_TEXT_ENHANCE
423     RectStyle fBackgroundRect = {0, 0.0f, 0.0f, 0.0f, 0.0f};
424     SkColor fStyleId = {0};
425     size_t fTextStyleUid{0};
426     SkScalar fVerticalAlignShift{0.0f};
427 #endif
428 
429     TextBaseline fTextBaseline = TextBaseline::kAlphabetic;
430 
431     SkColor fColor = SK_ColorWHITE;
432     bool fHasBackground = false;
433     ParagraphPainter::SkPaintOrID fBackground;
434     bool fHasForeground = false;
435     ParagraphPainter::SkPaintOrID fForeground;
436 
437     std::vector<TextShadow> fTextShadows;
438 
439 #ifdef ENABLE_TEXT_ENHANCE
440     bool fIsCustomSymbol{false};
441     std::shared_ptr<RSTypeface> fTypeface;
442 #else
443     sk_sp<SkTypeface> fTypeface;
444 #endif
445     bool fIsPlaceholder = false;
446 
447     std::vector<FontFeature> fFontFeatures;
448 
449     std::optional<FontArguments> fFontArguments;
450 
451 #ifdef ENABLE_TEXT_ENHANCE
452     TextBadgeType fBadgeType{TextBadgeType::BADGE_NONE};
453 #endif
454 };
455 
456 typedef size_t TextIndex;
457 typedef SkRange<size_t> TextRange;
458 const SkRange<size_t> EMPTY_TEXT = EMPTY_RANGE;
459 
460 struct Block {
461     Block() = default;
BlockBlock462     Block(size_t start, size_t end, const TextStyle& style) : fRange(start, end), fStyle(style) {}
BlockBlock463     Block(TextRange textRange, const TextStyle& style) : fRange(textRange), fStyle(style) {}
464 
addBlock465     void add(TextRange tail) {
466         SkASSERT(fRange.end == tail.start);
467         fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
468     }
469 
470     TextRange fRange = EMPTY_RANGE;
471     TextStyle fStyle;
472 };
473 
474 
475 typedef size_t BlockIndex;
476 typedef SkRange<size_t> BlockRange;
477 const size_t EMPTY_BLOCK = EMPTY_INDEX;
478 const SkRange<size_t> EMPTY_BLOCKS = EMPTY_RANGE;
479 
480 struct Placeholder {
481     Placeholder() = default;
PlaceholderPlaceholder482     Placeholder(size_t start, size_t end, const PlaceholderStyle& style, const TextStyle& textStyle,
483                 BlockRange blocksBefore, TextRange textBefore)
484             : fRange(start, end)
485             , fStyle(style)
486             , fTextStyle(textStyle)
487             , fBlocksBefore(blocksBefore)
488             , fTextBefore(textBefore) {}
489 
490     TextRange fRange = EMPTY_RANGE;
491     PlaceholderStyle fStyle;
492     TextStyle fTextStyle;
493     BlockRange fBlocksBefore;
494     TextRange fTextBefore;
495 };
496 
497 }  // namespace textlayout
498 }  // namespace skia
499 
500 #endif  // TextStyle_DEFINED
501