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