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 #ifdef ENABLE_TEXT_ENHANCE
6 #include "modules/skparagraph/src/Run.h"
7 #endif
8
9 namespace skia {
10 namespace textlayout {
11
12 #ifdef ENABLE_TEXT_ENHANCE
13 struct SkStringHash {
operator ()skia::textlayout::SkStringHash14 size_t operator()(const SkString& s) const {
15 size_t hash = 0;
16 for (size_t i = 0; i < s.size(); ++i) {
17 hash ^= std::hash<char>()(s.c_str()[i]);
18 }
19 return hash;
20 }
21 };
22
23 const std::unordered_map<SkString, SkString, SkStringHash> GENERIC_FAMILY_NAME_MAP = {
24 { SkString{"HarmonyOS Sans"}, SkString{"HarmonyOS-Sans"} },
25 { SkString{"HarmonyOS Sans Condensed"}, SkString{"HarmonyOS-Sans-Condensed"} },
26 { SkString{"HarmonyOS Sans Digit"}, SkString{"HarmonyOS-Sans-Digit"} },
27 { SkString{"Noto Serif"}, SkString{"serif"} },
28 { SkString{"Noto Sans Mono"}, SkString{"monospace"} }
29 };
30 #endif
31
32 const std::vector<SkString>* TextStyle::kDefaultFontFamilies =
33 new std::vector<SkString>{SkString(DEFAULT_FONT_FAMILY)};
34
cloneForPlaceholder()35 TextStyle TextStyle::cloneForPlaceholder() {
36 TextStyle result;
37 result.fColor = fColor;
38 result.fFontSize = fFontSize;
39 result.fFontFamilies = fFontFamilies;
40 result.fDecoration = fDecoration;
41 result.fHasBackground = fHasBackground;
42 result.fHasForeground = fHasForeground;
43 result.fBackground = fBackground;
44 result.fForeground = fForeground;
45 result.fHeightOverride = fHeightOverride;
46 result.fIsPlaceholder = true;
47 result.fFontFeatures = fFontFeatures;
48 result.fHalfLeading = fHalfLeading;
49 result.fBaselineShift = fBaselineShift;
50 result.fFontArguments = fFontArguments;
51 #ifdef ENABLE_TEXT_ENHANCE
52 result.fBackgroundRect = fBackgroundRect;
53 result.fStyleId = fStyleId;
54 result.fTextStyleUid = fTextStyleUid;
55 #endif
56 return result;
57 }
58
equals(const TextStyle & other) const59 bool TextStyle::equals(const TextStyle& other) const {
60
61 if (fIsPlaceholder || other.fIsPlaceholder) {
62 return false;
63 }
64
65 if (fColor != other.fColor) {
66 return false;
67 }
68 if (!(fDecoration == other.fDecoration)) {
69 return false;
70 }
71 if (!(fFontStyle == other.fFontStyle)) {
72 return false;
73 }
74 if (fFontFamilies != other.fFontFamilies) {
75 return false;
76 }
77 if (fLetterSpacing != other.fLetterSpacing) {
78 return false;
79 }
80 if (fWordSpacing != other.fWordSpacing) {
81 return false;
82 }
83 if (fHeight != other.fHeight) {
84 return false;
85 }
86 if (fHeightOverride != other.fHeightOverride) {
87 return false;
88 }
89 if (fHalfLeading != other.fHalfLeading) {
90 return false;
91 }
92 if (fBaselineShift != other.fBaselineShift) {
93 return false;
94 }
95 if (fFontSize != other.fFontSize) {
96 return false;
97 }
98 if (fLocale != other.fLocale) {
99 return false;
100 }
101 if (fHasForeground != other.fHasForeground || fForeground != other.fForeground) {
102 return false;
103 }
104 if (fHasBackground != other.fHasBackground || fBackground != other.fBackground) {
105 return false;
106 }
107 if (fTextShadows.size() != other.fTextShadows.size()) {
108 return false;
109 }
110 for (size_t i = 0; i < fTextShadows.size(); ++i) {
111 if (fTextShadows[i] != other.fTextShadows[i]) {
112 return false;
113 }
114 }
115 if (fFontFeatures.size() != other.fFontFeatures.size()) {
116 return false;
117 }
118 for (size_t i = 0; i < fFontFeatures.size(); ++i) {
119 if (!(fFontFeatures[i] == other.fFontFeatures[i])) {
120 return false;
121 }
122 }
123 if (fFontArguments != other.fFontArguments) {
124 return false;
125 }
126 #ifdef ENABLE_TEXT_ENHANCE
127 if (fStyleId != other.fStyleId || fBackgroundRect != other.fBackgroundRect) {
128 return false;
129 }
130 #endif
131 return true;
132 }
133
equalsByFonts(const TextStyle & that) const134 bool TextStyle::equalsByFonts(const TextStyle& that) const {
135
136 return !fIsPlaceholder && !that.fIsPlaceholder &&
137 fFontStyle == that.fFontStyle &&
138 fFontFamilies == that.fFontFamilies &&
139 fFontFeatures == that.fFontFeatures &&
140 fFontArguments == that.getFontArguments() &&
141 nearlyEqual(fLetterSpacing, that.fLetterSpacing) &&
142 nearlyEqual(fWordSpacing, that.fWordSpacing) &&
143 nearlyEqual(fHeight, that.fHeight) &&
144 nearlyEqual(fBaselineShift, that.fBaselineShift) &&
145 nearlyEqual(fFontSize, that.fFontSize) &&
146 #ifdef ENABLE_TEXT_ENHANCE
147 fLocale == that.fLocale &&
148 fStyleId == that.fStyleId &&
149 fBackgroundRect == that.fBackgroundRect;
150 #else
151 fLocale == that.fLocale;
152 #endif
153 }
154
matchOneAttribute(StyleType styleType,const TextStyle & other) const155 bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
156 switch (styleType) {
157 case kForeground:
158 return (!fHasForeground && !other.fHasForeground && fColor == other.fColor) ||
159 ( fHasForeground && other.fHasForeground && fForeground == other.fForeground);
160
161 case kBackground:
162 return (!fHasBackground && !other.fHasBackground) ||
163 ( fHasBackground && other.fHasBackground && fBackground == other.fBackground);
164
165 case kShadow:
166 if (fTextShadows.size() != other.fTextShadows.size()) {
167 return false;
168 }
169
170 for (int32_t i = 0; i < SkToInt(fTextShadows.size()); ++i) {
171 if (fTextShadows[i] != other.fTextShadows[i]) {
172 return false;
173 }
174 }
175 return true;
176
177 case kDecorations:
178 return this->fDecoration == other.fDecoration;
179
180 case kLetterSpacing:
181 return fLetterSpacing == other.fLetterSpacing;
182
183 case kWordSpacing:
184 return fWordSpacing == other.fWordSpacing;
185
186 case kAllAttributes:
187 return this->equals(other);
188
189 case kFont:
190 // TODO: should not we take typefaces in account?
191 return fFontStyle == other.fFontStyle &&
192 fLocale == other.fLocale &&
193 fFontFamilies == other.fFontFamilies &&
194 #ifdef ENABLE_TEXT_ENHANCE
195 getCorrectFontSize() == other.getCorrectFontSize() &&
196 fHeight == other.fHeight &&
197 fHalfLeading == other.fHalfLeading &&
198 getTotalVerticalShift() == other.getTotalVerticalShift() &&
199 fFontArguments == other.fFontArguments &&
200 fStyleId == other.fStyleId &&
201 fBackgroundRect == other.fBackgroundRect;
202 #else
203 fFontSize == other.fFontSize &&
204 fHeight == other.fHeight &&
205 fHalfLeading == other.fHalfLeading &&
206 fBaselineShift == other.fBaselineShift &&
207 fFontArguments == other.fFontArguments;
208 #endif
209 default:
210 SkASSERT(false);
211 return false;
212 }
213 }
214
215 #ifdef ENABLE_TEXT_ENHANCE
getFontMetrics(RSFontMetrics * metrics) const216 void TextStyle::getFontMetrics(RSFontMetrics* metrics) const {
217 #else
218 void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
219 #endif
220 #ifdef ENABLE_TEXT_ENHANCE
221 RSFont font(fTypeface, fFontSize, 1, 0);
222 font.SetEdging(RSDrawing::FontEdging::ANTI_ALIAS);
223 font.SetHinting(RSDrawing::FontHinting::SLIGHT);
224 font.SetSubpixel(true);
225 auto compressFont = font;
226 scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
227 compressFont.GetMetrics(metrics);
228 metricsIncludeFontPadding(metrics, font);
229 #else
230 SkFont font(fTypeface, fFontSize);
231 font.setEdging(SkFont::Edging::kAntiAlias);
232 font.setSubpixel(true);
233 font.setHinting(SkFontHinting::kSlight);
234 font.getMetrics(metrics);
235 #endif
236 if (fHeightOverride) {
237 auto multiplier = fHeight * fFontSize;
238 auto height = metrics->fDescent - metrics->fAscent + metrics->fLeading;
239 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2) * multiplier / height;
240 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2) * multiplier / height;
241
242 } else {
243 metrics->fAscent = (metrics->fAscent - metrics->fLeading / 2);
244 metrics->fDescent = (metrics->fDescent + metrics->fLeading / 2);
245 }
246 // If we shift the baseline we need to make sure the shifted text fits the line
247 metrics->fAscent += fBaselineShift;
248 metrics->fDescent += fBaselineShift;
249 }
250
251 void TextStyle::setFontArguments(const std::optional<SkFontArguments>& args) {
252 if (!args) {
253 fFontArguments.reset();
254 return;
255 }
256
257 fFontArguments.emplace(*args);
258 }
259
260 bool PlaceholderStyle::equals(const PlaceholderStyle& other) const {
261 return nearlyEqual(fWidth, other.fWidth) &&
262 nearlyEqual(fHeight, other.fHeight) &&
263 fAlignment == other.fAlignment &&
264 fBaseline == other.fBaseline &&
265 (fAlignment != PlaceholderAlignment::kBaseline ||
266 nearlyEqual(fBaselineOffset, other.fBaselineOffset));
267 }
268
269 #ifdef ENABLE_TEXT_ENHANCE
270 void TextStyle::setFontFamilies(std::vector<SkString> families) {
271 std::for_each(families.begin(), families.end(), [](SkString& familyName) {
272 if (GENERIC_FAMILY_NAME_MAP.count(familyName)) {
273 familyName = GENERIC_FAMILY_NAME_MAP.at(familyName);
274 }
275 });
276 fFontFamilies = std::move(families);
277 }
278
279 SkScalar TextStyle::getBadgeBaseLineShift() const {
280 if (getTextBadgeType() == TextBadgeType::BADGE_NONE) {
281 return 0.0;
282 }
283
284 SkScalar actualFontSize = getFontSize() * TEXT_BADGE_FONT_SIZE_SCALE;
285 return getTextBadgeType() == TextBadgeType::SUPERSCRIPT ? actualFontSize * SUPERSCRIPT_BASELINE_SHIFT_SCALE :
286 actualFontSize * SUBSCRIPT_BASELINE_SHIFT_SCALE;
287 }
288
289 SkScalar TextStyle::getCorrectFontSize() const {
290 if (getTextBadgeType() == TextBadgeType::BADGE_NONE) {
291 return getFontSize();
292 }
293
294 return getFontSize() * TEXT_BADGE_FONT_SIZE_SCALE;
295 };
296 #endif
297
298 } // namespace textlayout
299 } // namespace skia
300