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