1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components/declaration/text/text_declaration.h"
17
18 #include "base/utils/string_utils.h"
19 #include "core/components/common/properties/text_style_parser.h"
20 #include "core/components/declaration/common/declaration_constants.h"
21 #include "frameworks/bridge/common/utils/utils.h"
22 #include "frameworks/core/components/text/text_theme.h"
23
24 namespace OHOS::Ace {
25 namespace {
26
27 constexpr Dimension DEFAULT_LETTER_SPACING = 0.0_px; // unit is px
28 constexpr Dimension DEFAULT_LINE_HEIGHT = 0.0_px; // unit is px
29 constexpr Dimension DEFAULT_FONT_SIZE = 14.0_px;
30 const char DEFAULT_FONT_FAMILY[] = "sans-serif";
31
32 } // namespace
33
34 using namespace Framework;
35
InitSpecialized()36 void TextDeclaration::InitSpecialized()
37 {
38 AddSpecializedAttribute(DeclarationConstants::DEFAULT_TEXT_ATTR);
39 AddSpecializedStyle(DeclarationConstants::DEFAULT_TEXT_STYLE);
40 }
41
InitializeStyle()42 void TextDeclaration::InitializeStyle()
43 {
44 auto& style = MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
45 if (!style.IsValid()) {
46 return;
47 }
48
49 RefPtr<TextTheme> theme = GetTheme<TextTheme>();
50 if (theme) {
51 style.textStyle = theme->GetTextStyle();
52 style.focusColor = theme->GetTextStyle().GetTextColor();
53 std::vector<std::string> defaultFontFamilis;
54 defaultFontFamilis.emplace_back(DEFAULT_FONT_FAMILY);
55 style.textStyle.SetFontFamilies(defaultFontFamilis);
56 style.textStyle.SetLetterSpacing(DEFAULT_LETTER_SPACING);
57 style.textStyle.SetLineHeight(DEFAULT_LINE_HEIGHT, false);
58 }
59 }
60
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)61 bool TextDeclaration::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
62 {
63 if (attr.first == DOM_VALUE) {
64 SetData(attr.second);
65 return true;
66 }
67 return false;
68 }
69
SetSpecializedStyle(const std::pair<std::string,std::string> & style)70 bool TextDeclaration::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
71 {
72 // static linear map must be sorted by key.
73 static const LinearMapNode<void (*)(const std::string&, TextDeclaration&)> textStyleOperators[] = {
74 { DOM_TEXT_ADAPT_HEIGHT,
75 [](const std::string& val, TextDeclaration& declaration) {
76 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
77 if (specializedStyle.IsValid()) {
78 specializedStyle.textStyle.SetAdaptHeight(StringToBool(val));
79 }
80 } },
81 { DOM_TEXT_ALLOW_SCALE,
82 [](const std::string& val, TextDeclaration& declaration) {
83 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
84 if (specializedStyle.IsValid()) {
85 specializedStyle.textStyle.SetAllowScale(StringToBool(val));
86 }
87 } },
88 { DOM_TEXT_COLOR,
89 [](const std::string& val, TextDeclaration& declaration) {
90 declaration.hasSetTextColor_ = true;
91 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
92 if (specializedStyle.IsValid()) {
93 const auto& color = val.empty() ? Color::BLACK : declaration.ParseColor(val);
94 specializedStyle.textStyle.SetTextColor(color);
95 specializedStyle.focusColor = color;
96 }
97 } },
98 { DOM_TEXT_FONT_FAMILY,
99 [](const std::string& val, TextDeclaration& declaration) {
100 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
101 if (specializedStyle.IsValid()) {
102 specializedStyle.textStyle.SetFontFamilies(declaration.ParseFontFamilies(val));
103 }
104 } },
105 { DOM_TEXT_FONT_FEATURE_SETTINGS,
106 [](const std::string& val, TextDeclaration& declaration) {
107 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
108 if (specializedStyle.IsValid()) {
109 specializedStyle.textStyle.SetFontFeatures(ParseFontFeatureSettings(val));
110 }
111 } },
112 { DOM_TEXT_FONT_SIZE,
113 [](const std::string& val, TextDeclaration& declaration) {
114 declaration.hasSetTextFontSize_ = true;
115 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
116 if (specializedStyle.IsValid()) {
117 auto fontSize = val.empty() ? DEFAULT_FONT_SIZE : declaration.ParseDimension(val);
118 specializedStyle.textStyle.SetFontSize(fontSize);
119 }
120 } },
121 { DOM_TEXT_FONT_SIZE_STEP,
122 [](const std::string& val, TextDeclaration& declaration) {
123 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
124 if (specializedStyle.IsValid()) {
125 specializedStyle.textStyle.SetAdaptFontSizeStep(declaration.ParseDimension(val));
126 }
127 } },
128 { DOM_TEXT_FONT_STYLE,
129 [](const std::string& val, TextDeclaration& declaration) {
130 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
131 if (specializedStyle.IsValid()) {
132 specializedStyle.textStyle.SetFontStyle(ConvertStrToFontStyle(val));
133 }
134 } },
135 { DOM_TEXT_FONT_VARIANT,
136 [](const std::string& val, TextDeclaration& declaration) {
137 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
138 if (specializedStyle.IsValid()) {
139 specializedStyle.textStyle.SetFontFeatures(ParseFontVariants(val));
140 }
141 } },
142 { DOM_TEXT_FONT_WEIGHT,
143 [](const std::string& val, TextDeclaration& declaration) {
144 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
145 if (specializedStyle.IsValid()) {
146 specializedStyle.textStyle.SetFontWeight(ConvertStrToFontWeight(val));
147 }
148 } },
149 { DOM_TEXT_LETTER_SPACING,
150 [](const std::string& val, TextDeclaration& declaration) {
151 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
152 if (specializedStyle.IsValid()) {
153 specializedStyle.textStyle.SetLetterSpacing(declaration.ParseDimension(val));
154 }
155 } },
156 { DOM_TEXT_LINE_HEIGHT,
157 [](const std::string& val, TextDeclaration& declaration) {
158 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
159 if (specializedStyle.IsValid()) {
160 if (val == "normal") {
161 specializedStyle.textStyle.SetLineHeight(Dimension(0.0));
162 } else {
163 specializedStyle.textStyle.SetLineHeight(declaration.ParseLineHeight(val));
164 }
165 }
166 } },
167 { DOM_TEXT_LINES,
168 [](const std::string& val, TextDeclaration& declaration) {
169 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
170 if (specializedStyle.IsValid()) {
171 specializedStyle.textStyle.SetMaxLines(StringUtils::StringToInt(val));
172 }
173 } },
174 { DOM_TEXT_MAX_FONT_SIZE,
175 [](const std::string& val, TextDeclaration& declaration) {
176 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
177 if (specializedStyle.IsValid()) {
178 specializedStyle.textStyle.SetAdaptMaxFontSize(declaration.ParseDimension(val));
179 }
180 } },
181 { DOM_TEXT_MAX_LINES,
182 [](const std::string& val, TextDeclaration& declaration) {
183 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
184 if (specializedStyle.IsValid()) {
185 specializedStyle.textStyle.SetMaxLines(StringUtils::StringToUint(val, UINT32_MAX));
186 declaration.SetAutoMaxLines(val == DOM_AUTO);
187 }
188 } },
189 { DOM_TEXT_MIN_FONT_SIZE,
190 [](const std::string& val, TextDeclaration& declaration) {
191 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
192 if (specializedStyle.IsValid()) {
193 specializedStyle.textStyle.SetAdaptMinFontSize(declaration.ParseDimension(val));
194 }
195 } },
196 { DOM_TEXT_PREFER_FONT_SIZES,
197 [](const std::string& val, TextDeclaration& declaration) {
198 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
199 if (specializedStyle.IsValid()) {
200 specializedStyle.textStyle.SetPreferFontSizes(declaration.ParsePreferFontSizes(val));
201 }
202 } },
203 { DOM_TEXT_ALIGN,
204 [](const std::string& val, TextDeclaration& declaration) {
205 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
206 if (specializedStyle.IsValid()) {
207 specializedStyle.textStyle.SetTextAlign(ConvertStrToTextAlign(val));
208 }
209 } },
210 { DOM_TEXT_DECORATION,
211 [](const std::string& val, TextDeclaration& declaration) {
212 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
213 if (specializedStyle.IsValid()) {
214 specializedStyle.textStyle.SetTextDecoration(ConvertStrToTextDecoration(val));
215 }
216 } },
217 { DOM_TEXT_DECORATION_COLOR,
218 [](const std::string& val, TextDeclaration& declaration) {
219 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
220 if (specializedStyle.IsValid()) {
221 specializedStyle.textStyle.SetTextDecorationColor(declaration.ParseColor(val));
222 }
223 } },
224 { DOM_TEXT_INDENT, [](const std::string& val, TextDeclaration& declaration) {
225 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
226 if (specializedStyle.IsValid()) {
227 specializedStyle.textStyle.SetTextIndent(StringToDimension(val));
228 }
229 } },
230 { DOM_TEXT_OVERFLOW,
231 [](const std::string& val, TextDeclaration& declaration) {
232 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
233 if (specializedStyle.IsValid()) {
234 specializedStyle.textStyle.SetTextOverflow(ConvertStrToTextOverflow(val));
235 }
236 } },
237 { DOM_TEXT_SHADOW,
238 [](const std::string& val, TextDeclaration& declaration) {
239 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
240 if (specializedStyle.IsValid()) {
241 specializedStyle.textStyle.SetTextShadows(TextDeclaration::ParseTextShadow(val, declaration));
242 }
243 } },
244 { DOM_TEXT_VERTICAL_ALIGN,
245 [](const std::string& val, TextDeclaration& declaration) {
246 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
247 if (specializedStyle.IsValid()) {
248 specializedStyle.textStyle.SetTextVerticalAlign(ConvertStrToTextVerticalAlign(val));
249 }
250 } },
251 { DOM_TEXT_WHITE_SPACE, [](const std::string& val, TextDeclaration& declaration) {
252 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
253 if (specializedStyle.IsValid()) {
254 specializedStyle.textStyle.SetWhiteSpace(ConvertStrToWhiteSpace(val));
255 }
256 } },
257 { DOM_TEXT_WORD_BREAK,
258 [](const std::string& val, TextDeclaration& declaration) {
259 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
260 if (specializedStyle.IsValid()) {
261 specializedStyle.textStyle.SetWordBreak(ConvertStrToWordBreak(val));
262 }
263 } },
264 { DOM_TEXT_WORD_SPACING,
265 [](const std::string& val, TextDeclaration& declaration) {
266 auto& specializedStyle = declaration.MaybeResetStyle<TextSpecializedStyle>(StyleTag::SPECIALIZED_STYLE);
267 if (specializedStyle.IsValid()) {
268 if (val == "normal") {
269 specializedStyle.textStyle.SetWordSpacing(Dimension(0.0));
270 } else {
271 specializedStyle.textStyle.SetWordSpacing(StringToDimension(val));
272 }
273 }
274 } },
275 };
276 auto operatorIter = BinarySearchFindIndex(textStyleOperators, ArraySize(textStyleOperators), style.first.c_str());
277 if (operatorIter != -1) {
278 textStyleOperators[operatorIter].value(style.second, *this);
279 return true;
280 }
281 return false;
282 }
283
ParseTextShadow(const std::string & val,TextDeclaration & declaration)284 std::vector<Shadow> TextDeclaration::ParseTextShadow(const std::string& val, TextDeclaration& declaration)
285 {
286 std::vector<Shadow> textShadowList;
287 std::vector<std::string> textShadowValues;
288 StringUtils::SplitStr(val, ",", textShadowValues);
289 auto IsValidDimension = [](const std::string& str) {
290 return str.find("px") != std::string::npos || str == "0";
291 };
292
293 for (auto &textShadowValue : textShadowValues) {
294 std::vector<std::string> textShadowProps;
295 StringUtils::SplitStr(textShadowValue, " ", textShadowProps);
296 Shadow textShadow;
297 size_t pos = 0;
298 switch (static_cast<TextShadowSettings>(textShadowProps.size())) {
299 case TextShadowSettings::OFFSET_ONLY:
300 // text shadow values format:offsetx, offsety
301 textShadow.SetOffsetX(declaration.ParseDouble(textShadowProps[pos++]));
302 textShadow.SetOffsetY(declaration.ParseDouble(textShadowProps[pos]));
303 break;
304 case TextShadowSettings::OFFSET_EXTRA:
305 // support text shadow values format: offsetx offsety [blur-radius | color]
306 if (IsValidDimension(textShadowProps[0])) {
307 textShadow.SetOffsetX(declaration.ParseDouble(textShadowProps[pos++]));
308 textShadow.SetOffsetY(declaration.ParseDouble(textShadowProps[pos++]));
309 if (IsValidDimension(textShadowProps[pos])) {
310 // text shadow values format: offsetx offsety blur-radius
311 textShadow.SetBlurRadius(declaration.ParseDouble(textShadowProps[pos]));
312 } else {
313 // text shadow values format: offsetx offsety color
314 textShadow.SetColor(declaration.ParseColor(textShadowProps[pos]));
315 }
316 } else {
317 // text shadow values format:color offsetx offsety
318 textShadow.SetColor(declaration.ParseColor(textShadowProps[pos++]));
319 textShadow.SetOffsetX(declaration.ParseDouble(textShadowProps[pos++]));
320 textShadow.SetOffsetY(declaration.ParseDouble(textShadowProps[pos]));
321 }
322 break;
323 case TextShadowSettings::OFFSET_BLUR_CLOR:
324 if (IsValidDimension(textShadowProps[pos])) {
325 // text shadow values format: offsetx offsety blur-radius color
326 textShadow.SetOffsetX(declaration.ParseDouble(textShadowProps[pos++]));
327 textShadow.SetOffsetY(declaration.ParseDouble(textShadowProps[pos++]));
328 textShadow.SetBlurRadius(declaration.ParseDouble(textShadowProps[pos++]));
329 textShadow.SetColor(declaration.ParseColor(textShadowProps[pos]));
330 } else {
331 // text shadow values format:color offsetx offsety
332 textShadow.SetColor(declaration.ParseColor(textShadowProps[pos++]));
333 textShadow.SetOffsetX(declaration.ParseDouble(textShadowProps[pos++]));
334 textShadow.SetOffsetY(declaration.ParseDouble(textShadowProps[pos++]));
335 textShadow.SetBlurRadius(declaration.ParseDouble(textShadowProps[pos]));
336 }
337 break;
338 default:
339 break;
340 }
341 textShadowList.emplace_back(textShadow);
342 }
343 return textShadowList;
344 }
345
346 } // namespace OHOS::Ace
347