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