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