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