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