1 // Copyright 2019 Google LLC.
2 #include "include/core/SkColor.h"
3 #include "include/core/SkFontStyle.h"
4 #include "modules/skparagraph/include/TextStyle.h"
5
6 namespace skia {
7 namespace textlayout {
8
9 const std::vector<SkString> TextStyle::kDefaultFontFamilies = { SkString(DEFAULT_FONT_FAMILY) };
10
TextStyle(const TextStyle & other,bool placeholder)11 TextStyle::TextStyle(const TextStyle& other, bool placeholder) {
12 fColor = other.fColor;
13 fFontSize = other.fFontSize;
14 fFontFamilies = other.fFontFamilies;
15 fDecoration = other.fDecoration;
16 fHasBackground = other.fHasBackground;
17 fHasForeground = other.fHasForeground;
18 fBackground = other.fBackground;
19 fForeground = other.fForeground;
20 fHeightOverride = other.fHeightOverride;
21 fIsPlaceholder = placeholder;
22 fFontFeatures = other.fFontFeatures;
23 fHalfLeading = other.fHalfLeading;
24 fBaselineShift = other.fBaselineShift;
25 }
26
equals(const TextStyle & other) const27 bool TextStyle::equals(const TextStyle& other) const {
28
29 if (fIsPlaceholder || other.fIsPlaceholder) {
30 return false;
31 }
32
33 if (fColor != other.fColor) {
34 return false;
35 }
36 if (!(fDecoration == other.fDecoration)) {
37 return false;
38 }
39 if (!(fFontStyle == other.fFontStyle)) {
40 return false;
41 }
42 if (fFontFamilies != other.fFontFamilies) {
43 return false;
44 }
45 if (fLetterSpacing != other.fLetterSpacing) {
46 return false;
47 }
48 if (fWordSpacing != other.fWordSpacing) {
49 return false;
50 }
51 if (fHeight != other.fHeight) {
52 return false;
53 }
54 if (fHalfLeading != other.fHalfLeading) {
55 return false;
56 }
57 if (fBaselineShift != other.fBaselineShift) {
58 return false;
59 }
60 if (fFontSize != other.fFontSize) {
61 return false;
62 }
63 if (fLocale != other.fLocale) {
64 return false;
65 }
66 if (fHasForeground != other.fHasForeground || fForeground != other.fForeground) {
67 return false;
68 }
69 if (fHasBackground != other.fHasBackground || fBackground != other.fBackground) {
70 return false;
71 }
72 if (fTextShadows.size() != other.fTextShadows.size()) {
73 return false;
74 }
75 for (size_t i = 0; i < fTextShadows.size(); ++i) {
76 if (fTextShadows[i] != other.fTextShadows[i]) {
77 return false;
78 }
79 }
80 if (fFontFeatures.size() != other.fFontFeatures.size()) {
81 return false;
82 }
83 for (size_t i = 0; i < fFontFeatures.size(); ++i) {
84 if (!(fFontFeatures[i] == other.fFontFeatures[i])) {
85 return false;
86 }
87 }
88
89 return true;
90 }
91
equalsByFonts(const TextStyle & that) const92 bool TextStyle::equalsByFonts(const TextStyle& that) const {
93
94 return !fIsPlaceholder && !that.fIsPlaceholder &&
95 fFontStyle == that.fFontStyle &&
96 fFontFamilies == that.fFontFamilies &&
97 fFontFeatures == that.fFontFeatures &&
98 nearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
99 nearlyEqual(fWordSpacing, that.fWordSpacing) &&
100 nearlyEqual(fHeight, that.fHeight) &&
101 nearlyEqual(fBaselineShift, that.fBaselineShift) &&
102 nearlyEqual(fFontSize, that.fFontSize) &&
103 fLocale == that.fLocale;
104 }
105
matchOneAttribute(StyleType styleType,const TextStyle & other) const106 bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
107 switch (styleType) {
108 case kForeground:
109 return (!fHasForeground && !other.fHasForeground && fColor == other.fColor) ||
110 ( fHasForeground && other.fHasForeground && fForeground == other.fForeground);
111
112 case kBackground:
113 return (!fHasBackground && !other.fHasBackground) ||
114 ( fHasBackground && other.fHasBackground && fBackground == other.fBackground);
115
116 case kShadow:
117 if (fTextShadows.size() != other.fTextShadows.size()) {
118 return false;
119 }
120
121 for (int32_t i = 0; i < SkToInt(fTextShadows.size()); ++i) {
122 if (fTextShadows[i] != other.fTextShadows[i]) {
123 return false;
124 }
125 }
126 return true;
127
128 case kDecorations:
129 return this->fDecoration == other.fDecoration;
130
131 case kLetterSpacing:
132 return fLetterSpacing == other.fLetterSpacing;
133
134 case kWordSpacing:
135 return fWordSpacing == other.fWordSpacing;
136
137 case kAllAttributes:
138 return this->equals(other);
139
140 case kFont:
141 // TODO: should not we take typefaces in account?
142 return fFontStyle == other.fFontStyle &&
143 fLocale == other.fLocale &&
144 fFontFamilies == other.fFontFamilies &&
145 fFontSize == other.fFontSize &&
146 fHeight == other.fHeight &&
147 fHeight == other.fHeight &&
148 fHalfLeading == other.fHalfLeading &&
149 fBaselineShift == other.fBaselineShift;
150 default:
151 SkASSERT(false);
152 return false;
153 }
154 }
155
getFontMetrics(SkFontMetrics * metrics) const156 void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
157 SkFont font(fTypeface, fFontSize);
158 font.setEdging(SkFont::Edging::kAntiAlias);
159 font.setSubpixel(true);
160 font.setHinting(SkFontHinting::kSlight);
161 font.getMetrics(metrics);
162 if (fHeightOverride) {
163 auto multiplier = fHeight * fFontSize;
164 auto height = metrics->fDescent - metrics->fAscent + metrics->fLeading;
165 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2) * multiplier / height;
166 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2) * multiplier / height;
167
168 } else {
169 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2);
170 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2);
171 }
172 // If we shift the baseline we need to make sure the shifted text fits the line
173 metrics->fAscent += fBaselineShift;
174 metrics->fDescent += fBaselineShift;
175 }
176
equals(const PlaceholderStyle & other) const177 bool PlaceholderStyle::equals(const PlaceholderStyle& other) const {
178 return nearlyEqual(fWidth, other.fWidth) &&
179 nearlyEqual(fHeight, other.fHeight) &&
180 fAlignment == other.fAlignment &&
181 fBaseline == other.fBaseline &&
182 (fAlignment != PlaceholderAlignment::kBaseline ||
183 nearlyEqual(fBaselineOffset, other.fBaselineOffset));
184 }
185
186 } // namespace textlayout
187 } // namespace skia
188