• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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