1 /*
2  * Copyright (c) 2021-2022 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_BRIDGE_COMMON_UTILS_UTILS_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BRIDGE_COMMON_UTILS_UTILS_H
18 
19 #include <algorithm>
20 #include <cctype>
21 #include <climits>
22 #include <cmath>
23 #include <cstring>
24 #include <iomanip>
25 #include <map>
26 #include <optional>
27 #include <sstream>
28 #include <string>
29 #include <unordered_map>
30 #include <unordered_set>
31 
32 #include "base/error/error_code.h"
33 #include "base/geometry/axis.h"
34 #include "base/json/json_util.h"
35 #include "base/log/log.h"
36 #include "base/resource/asset_manager.h"
37 #include "base/utils/linear_map.h"
38 #include "base/utils/string_utils.h"
39 #include "base/utils/utils.h"
40 #include "core/animation/animation_pub.h"
41 #include "core/animation/curve.h"
42 #include "core/animation/curves.h"
43 #include "core/animation/spring_curve.h"
44 #include "core/common/ime/text_input_action.h"
45 #include "core/common/ime/text_input_type.h"
46 #include "core/components/common/layout/constants.h"
47 #include "core/components/common/properties/clip_path.h"
48 #include "core/components/common/properties/decoration.h"
49 #include "core/components/common/properties/text_style.h"
50 #include "frameworks/bridge/common/dom/dom_type.h"
51 
52 namespace OHOS::Ace::Framework {
53 
54 constexpr int32_t OFFSET_VALUE_NUMBER = 2;
55 constexpr uint8_t UTF8_CHARATER_HEAD = 0xc0;
56 constexpr uint8_t UTF8_CHARATER_BODY = 0x80;
57 constexpr int32_t UNICODE_LENGTH = 4;
58 constexpr int32_t STRTOL_BASE = 10;
59 constexpr int32_t INVALID_PARAM = -1;
60 constexpr int32_t PLACE_HOLDER_LENGTH = 3;
61 
62 constexpr char INPUT_ACTION_NEXT[] = "next";
63 constexpr char INPUT_ACTION_GO[] = "go";
64 constexpr char INPUT_ACTION_DONE[] = "done";
65 constexpr char INPUT_ACTION_SEND[] = "send";
66 constexpr char INPUT_ACTION_SEARCH[] = "search";
67 constexpr char PLURAL_COUNT_POS[] = "{count}";
68 constexpr char DEFAULT_PLURAL_CHOICE[] = "other";
69 
70 const char DOUBLE_QUOTATION = '"';
71 const char BACKSLASH = '\\';
72 const char ESCAPE_CHARATER_START = '\x00';
73 const char ESCAPE_CHARATER_END = '\x1f';
74 const char UNICODE_BODY = '0';
75 const char UNICODE_HEAD[] = "\\u";
76 const char LEFT_CURLY_BRACES = '{';
77 const char RIGHT_CURLY_BRACES = '}';
78 
79 template<class T>
GetAssetContentImpl(const RefPtr<AssetManager>& assetManager, const std::string& url, T& content)80 bool GetAssetContentImpl(const RefPtr<AssetManager>& assetManager, const std::string& url, T& content)
81 {
82     if (!assetManager) {
83         return false;
84     }
85     auto jsAsset = assetManager->GetAsset(url);
86     if (jsAsset == nullptr) {
87         return false;
88     }
89     auto bufLen = jsAsset->GetSize();
90     auto buffer = jsAsset->GetData();
91     if ((buffer == nullptr) || (bufLen <= 0)) {
92         return false;
93     }
94     content.assign(buffer, buffer + bufLen);
95     return true;
96 }
97 
98 template<class T>
GetAssetContentAllowEmpty(const RefPtr<AssetManager>& assetManager, const std::string& url, T& content)99 bool GetAssetContentAllowEmpty(const RefPtr<AssetManager>& assetManager, const std::string& url, T& content)
100 {
101     if (!assetManager) {
102         return false;
103     }
104     auto jsAsset = assetManager->GetAsset(url);
105     if (jsAsset == nullptr) {
106         return false;
107     }
108     auto bufLen = jsAsset->GetSize();
109     auto buffer = jsAsset->GetData();
110     content.assign(buffer, buffer + bufLen);
111     return true;
112 }
113 
GetAssetPathImpl(const RefPtr<AssetManager>& assetManager, const std::string& url)114 inline std::string GetAssetPathImpl(const RefPtr<AssetManager>& assetManager, const std::string& url)
115 {
116     if (!assetManager) {
117         return {};
118     }
119     return assetManager->GetAssetPath(url, true);
120 }
121 
ParseFileData(const std::string& data)122 inline std::unique_ptr<JsonValue> ParseFileData(const std::string& data)
123 {
124     const char* endMsg = nullptr;
125     auto fileData = JsonUtil::ParseJsonString(data, &endMsg);
126     if (!fileData) {
127         return nullptr;
128     }
129     return fileData;
130 }
131 
StringToDouble(const std::string& value)132 inline double StringToDouble(const std::string& value)
133 {
134     return StringUtils::StringToDouble(value);
135 }
136 
StringToDimension(const std::string& value)137 inline Dimension StringToDimension(const std::string& value)
138 {
139     return StringUtils::StringToDimension(value);
140 }
141 
StringToDimensionWithUnit(const std::string& value, DimensionUnit defaultUnit = DimensionUnit::PX)142 inline Dimension StringToDimensionWithUnit(const std::string& value, DimensionUnit defaultUnit = DimensionUnit::PX)
143 {
144     return StringUtils::StringToDimensionWithUnit(value, defaultUnit);
145 }
146 
StringToInt(const std::string& value)147 inline int32_t StringToInt(const std::string& value)
148 {
149     return StringUtils::StringToInt(value);
150 }
151 
StringToBool(const std::string& value)152 inline bool StringToBool(const std::string& value)
153 {
154     return value == "true";
155 }
156 
ConvertStrToBorderStyle(const std::string& style)157 inline BorderStyle ConvertStrToBorderStyle(const std::string& style)
158 {
159     static const LinearMapNode<BorderStyle> borderStyleTable[] = {
160         { "dashed", BorderStyle::DASHED },
161         { "dotted", BorderStyle::DOTTED },
162         { "solid", BorderStyle::SOLID },
163     };
164 
165     auto index = BinarySearchFindIndex(borderStyleTable, ArraySize(borderStyleTable), style.c_str());
166     return index < 0 ? BorderStyle::NONE : borderStyleTable[index].value;
167 }
168 
ConvertStrToBorderImageRepeat(const std::string& repeat)169 inline BorderImageRepeat ConvertStrToBorderImageRepeat(const std::string& repeat)
170 {
171     static const LinearMapNode<BorderImageRepeat> borderImageRepeatTable[] = {
172         { "repeat", BorderImageRepeat::REPEAT },
173         { "round", BorderImageRepeat::ROUND },
174         { "space", BorderImageRepeat::SPACE },
175         { "stretch", BorderImageRepeat::STRETCH },
176     };
177 
178     auto index = BinarySearchFindIndex(borderImageRepeatTable, ArraySize(borderImageRepeatTable), repeat.c_str());
179     return index < 0 ? BorderImageRepeat::STRETCH : borderImageRepeatTable[index].value;
180 }
181 
ConvertStrToBadgePosition(const std::string& badgePosition)182 inline BadgePosition ConvertStrToBadgePosition(const std::string& badgePosition)
183 {
184     static const LinearMapNode<BadgePosition> badgePositionTable[] = {
185         { "left", BadgePosition::LEFT },
186         { "right", BadgePosition::RIGHT },
187         { "rightTop", BadgePosition::RIGHT_TOP },
188     };
189     auto index = BinarySearchFindIndex(badgePositionTable, ArraySize(badgePositionTable), badgePosition.c_str());
190     return index < 0 ? BadgePosition::RIGHT_TOP : badgePositionTable[index].value;
191 }
192 
ConvertStrToBoxSizing(const std::string& value)193 inline BoxSizing ConvertStrToBoxSizing(const std::string& value)
194 {
195     static const LinearMapNode<BoxSizing> boxSizingTable[] = {
196         { "border-box", BoxSizing::BORDER_BOX },
197         { "content-box", BoxSizing::CONTENT_BOX },
198     };
199     auto index = BinarySearchFindIndex(boxSizingTable, ArraySize(boxSizingTable), value.c_str());
200     return index < 0 ? BoxSizing::BORDER_BOX : boxSizingTable[index].value;
201 }
202 
ConvertStrToImageRepeat(const std::string& repeat)203 inline ImageRepeat ConvertStrToImageRepeat(const std::string& repeat)
204 {
205     static const LinearMapNode<ImageRepeat> imageRepeatTable[] = {
206         { "no-repeat", ImageRepeat::NO_REPEAT },
207         { "repeat", ImageRepeat::REPEAT },
208         { "repeat-x", ImageRepeat::REPEAT_X },
209         { "repeat-y", ImageRepeat::REPEAT_Y },
210     };
211 
212     auto index = BinarySearchFindIndex(imageRepeatTable, ArraySize(imageRepeatTable), repeat.c_str());
213     return index < 0 ? ImageRepeat::NO_REPEAT : imageRepeatTable[index].value;
214 }
215 
ParseFontWeight( const std::string& weight, FontWeight defaultFontWeight = FontWeight::NORMAL)216 inline std::pair<bool, FontWeight> ParseFontWeight(
217     const std::string& weight, FontWeight defaultFontWeight = FontWeight::NORMAL)
218 {
219     return StringUtils::ParseFontWeight(weight, defaultFontWeight);
220 }
221 
ConvertStrToFontWeight(const std::string& weight, FontWeight defaultFontWeight = FontWeight::NORMAL)222 inline FontWeight ConvertStrToFontWeight(const std::string& weight, FontWeight defaultFontWeight = FontWeight::NORMAL)
223 {
224     return StringUtils::StringToFontWeight(weight, defaultFontWeight);
225 }
226 
ConvertStrToTextDecoration(const std::string& textDecoration)227 inline TextDecoration ConvertStrToTextDecoration(const std::string& textDecoration)
228 {
229     // this map should be sorted by key.
230     static const LinearMapNode<TextDecoration> textDecorationTable[] = {
231         { DOM_TEXT_DECORATION_INHERIT, TextDecoration::INHERIT },
232         { DOM_TEXT_DECORATION_LINETHROUGH, TextDecoration::LINE_THROUGH },
233         { DOM_TEXT_DECORATION_NONE, TextDecoration::NONE },
234         { DOM_TEXT_DECORATION_OVERLINE, TextDecoration::OVERLINE },
235         { DOM_TEXT_DECORATION_UNDERLINE, TextDecoration::UNDERLINE },
236     };
237 
238     auto index = BinarySearchFindIndex(textDecorationTable, ArraySize(textDecorationTable), textDecoration.c_str());
239     return index < 0 ? TextDecoration::NONE : textDecorationTable[index].value;
240 }
241 
ConvertStrToTextDecorationStyle(const std::string& textDecorationStyle)242 inline TextDecorationStyle ConvertStrToTextDecorationStyle(const std::string& textDecorationStyle)
243 {
244     // this map should be sorted by key.
245     static const LinearMapNode<TextDecorationStyle> textDecorationStyleTable[] = {
246         { DOM_TEXT_DECORATION_STYLE_DASHED, TextDecorationStyle::DASHED },
247         { DOM_TEXT_DECORATION_STYLE_DOTTED, TextDecorationStyle::DOTTED },
248         { DOM_TEXT_DECORATION_STYLE_DOUBLE, TextDecorationStyle::DOUBLE },
249         { DOM_TEXT_DECORATION_STYLE_SOLID, TextDecorationStyle::SOLID },
250         { DOM_TEXT_DECORATION_STYLE_WAVY, TextDecorationStyle::WAVY },
251     };
252 
253     auto index = BinarySearchFindIndex(
254         textDecorationStyleTable, ArraySize(textDecorationStyleTable), textDecorationStyle.c_str());
255     return index < 0 ? TextDecorationStyle::SOLID : textDecorationStyleTable[index].value;
256 }
257 
ConvertStrToWhiteSpace(const std::string& whiteSpace)258 inline WhiteSpace ConvertStrToWhiteSpace(const std::string& whiteSpace)
259 {
260     // this map should be sorted by key.
261     static const LinearMapNode<WhiteSpace> whiteSpaceTable[] = {
262         { DOM_WHITE_SPACE_INHERIT, WhiteSpace::INHERIT },
263         { DOM_WHITE_SPACE_NORMAL, WhiteSpace::NORMAL },
264         { DOM_WHITE_SPACE_NOWRAP, WhiteSpace::NOWRAP },
265         { DOM_WHITE_SPACE_PRE, WhiteSpace::PRE },
266         { DOM_WHITE_SPACE_PRELINE, WhiteSpace::PRE_LINE },
267         { DOM_WHITE_SPACE_PREWRAP, WhiteSpace::PRE_WRAP },
268     };
269 
270     auto index = BinarySearchFindIndex(whiteSpaceTable, ArraySize(whiteSpaceTable), whiteSpace.c_str());
271     return index < 0 ? WhiteSpace::NORMAL : whiteSpaceTable[index].value;
272 }
273 
ConvertStrToTextVerticalAlign(const std::string& align)274 inline VerticalAlign ConvertStrToTextVerticalAlign(const std::string& align)
275 {
276     static const LinearMapNode<VerticalAlign> textVerticalAlignTable[] = {
277         { DOM_BOTTOM, VerticalAlign::BOTTOM },
278         { DOM_MIDDLE, VerticalAlign::CENTER },
279         { DOM_TOP, VerticalAlign::TOP },
280     };
281     auto index = BinarySearchFindIndex(textVerticalAlignTable, ArraySize(textVerticalAlignTable), align.c_str());
282     return index < 0 ? VerticalAlign::NONE : textVerticalAlignTable[index].value;
283 }
284 
ConvertStrToFontStyle(const std::string& fontStyle)285 inline FontStyle ConvertStrToFontStyle(const std::string& fontStyle)
286 {
287     return fontStyle == DOM_TEXT_FONT_STYLE_ITALIC ? FontStyle::ITALIC : FontStyle::NORMAL;
288 }
289 
ConvertStrToTextAlign(const std::string& align)290 inline TextAlign ConvertStrToTextAlign(const std::string& align)
291 {
292     static const LinearMapNode<TextAlign> textAlignTable[] = {
293         { DOM_CENTER, TextAlign::CENTER },
294         { DOM_END, TextAlign::END },
295         { DOM_LEFT, TextAlign::LEFT },
296         { DOM_RIGHT, TextAlign::RIGHT },
297         { DOM_START, TextAlign::START },
298     };
299 
300     auto index = BinarySearchFindIndex(textAlignTable, ArraySize(textAlignTable), align.c_str());
301     return index < 0 ? TextAlign::CENTER : textAlignTable[index].value;
302 }
303 
ConvertStrToTextOverflow(const std::string& overflow)304 inline TextOverflow ConvertStrToTextOverflow(const std::string& overflow)
305 {
306     return overflow == DOM_ELLIPSIS ? TextOverflow::ELLIPSIS : TextOverflow::CLIP;
307 }
308 
ConvertStrToOverflow(const std::string& val)309 inline Overflow ConvertStrToOverflow(const std::string& val)
310 {
311     const LinearMapNode<Overflow> overflowTable[] = {
312         { "auto", Overflow::SCROLL },
313         { "hidden", Overflow::FORCE_CLIP },
314         { "scroll", Overflow::SCROLL },
315         { "visible", Overflow::OBSERVABLE },
316     };
317     auto index = BinarySearchFindIndex(overflowTable, ArraySize(overflowTable), val.c_str());
318     return index < 0 ? Overflow::CLIP : overflowTable[index].value;
319 }
320 
ConvertStrToTextDirection(const std::string& val)321 inline TextDirection ConvertStrToTextDirection(const std::string& val)
322 {
323     const LinearMapNode<TextDirection> textDirectionTable[] = {
324         { "inherit", TextDirection::INHERIT },
325         { "ltr", TextDirection::LTR },
326         { "rtl", TextDirection::RTL },
327     };
328     auto index = BinarySearchFindIndex(textDirectionTable, ArraySize(textDirectionTable), val.c_str());
329     return index < 0 ? TextDirection::LTR : textDirectionTable[index].value;
330 }
331 
ConvertStrToTextFieldOverflowX(const std::string& val)332 inline TextFieldOverflowX ConvertStrToTextFieldOverflowX(const std::string& val)
333 {
334     const LinearMapNode<TextFieldOverflowX> textFieldOverflowXTable[] = {
335         { "auto", TextFieldOverflowX::AUTO },
336         { "hidden", TextFieldOverflowX::HIDDEN },
337         { "scroll", TextFieldOverflowX::SCROLL },
338     };
339     auto index = BinarySearchFindIndex(textFieldOverflowXTable, ArraySize(textFieldOverflowXTable), val.c_str());
340     return index < 0 ? TextFieldOverflowX::HIDDEN : textFieldOverflowXTable[index].value;
341 }
342 
ConvertStrToFontFamilies(const std::string& family)343 inline std::vector<std::string> ConvertStrToFontFamilies(const std::string& family)
344 {
345     std::vector<std::string> fontFamilies;
346     std::stringstream stream(family);
347     std::string fontFamily;
348     while (getline(stream, fontFamily, ',')) {
349         fontFamilies.emplace_back(fontFamily);
350     }
351     return fontFamilies;
352 }
353 
ConvertStrToFlexDirection(const std::string& flexKey)354 inline FlexDirection ConvertStrToFlexDirection(const std::string& flexKey)
355 {
356     return flexKey == DOM_FLEX_COLUMN ? FlexDirection::COLUMN : FlexDirection::ROW;
357 }
358 
ConvertStrToFlexAlign(const std::string& flexKey)359 inline FlexAlign ConvertStrToFlexAlign(const std::string& flexKey)
360 {
361     static const LinearMapNode<FlexAlign> flexMap[] = {
362         { DOM_ALIGN_ITEMS_BASELINE, FlexAlign::BASELINE },
363         { DOM_JUSTIFY_CONTENT_CENTER, FlexAlign::CENTER },
364         { DOM_JUSTIFY_CONTENT_END, FlexAlign::FLEX_END },
365         { DOM_JUSTIFY_CONTENT_START, FlexAlign::FLEX_START },
366         { DOM_JUSTIFY_CONTENT_AROUND, FlexAlign::SPACE_AROUND },
367         { DOM_JUSTIFY_CONTENT_BETWEEN, FlexAlign::SPACE_BETWEEN },
368         { DOM_JUSTIFY_CONTENT_EVENLY, FlexAlign::SPACE_EVENLY },
369         { DOM_ALIGN_ITEMS_STRETCH, FlexAlign::STRETCH },
370     };
371     auto index = BinarySearchFindIndex(flexMap, ArraySize(flexMap), flexKey.c_str());
372     return index < 0 ? FlexAlign::FLEX_START : flexMap[index].value;
373 }
374 
ConvertStrToOffset(const std::string& value)375 inline Offset ConvertStrToOffset(const std::string& value)
376 {
377     Offset offset;
378     std::vector<std::string> offsetValues;
379     std::stringstream stream(value);
380     std::string offsetValue;
381     while (getline(stream, offsetValue, ' ')) {
382         offsetValues.emplace_back(offsetValue);
383     }
384     // To avoid illegal input, such as "100px ".
385     offsetValues.resize(OFFSET_VALUE_NUMBER);
386     offset.SetX(StringToDouble(offsetValues[0]));
387     offset.SetY(StringToDouble(offsetValues[1]));
388     return offset;
389 }
390 
ConvertStrToQrcodeType(const std::string& value)391 inline QrcodeType ConvertStrToQrcodeType(const std::string& value)
392 {
393     return value == "circle" ? QrcodeType::CIRCLE : QrcodeType::RECT;
394 }
395 
ConvertStrToAnimationCurve(const std::string& value)396 inline AnimationCurve ConvertStrToAnimationCurve(const std::string& value)
397 {
398     return value == "standard" ? AnimationCurve::STANDARD : AnimationCurve::FRICTION;
399 }
400 
ConvertStrToTextInputAction(const std::string& action)401 inline TextInputAction ConvertStrToTextInputAction(const std::string& action)
402 {
403     TextInputAction inputAction;
404     if (action == INPUT_ACTION_NEXT) {
405         inputAction = TextInputAction::NEXT;
406     } else if (action == INPUT_ACTION_GO) {
407         inputAction = TextInputAction::GO;
408     } else if (action == INPUT_ACTION_DONE) {
409         inputAction = TextInputAction::DONE;
410     } else if (action == INPUT_ACTION_SEND) {
411         inputAction = TextInputAction::SEND;
412     } else if (action == INPUT_ACTION_SEARCH) {
413         inputAction = TextInputAction::SEARCH;
414     } else {
415         inputAction = TextInputAction::UNSPECIFIED;
416     }
417     return inputAction;
418 }
419 
ConvertStrToTextInputType(const std::string& type)420 inline TextInputType ConvertStrToTextInputType(const std::string& type)
421 {
422     TextInputType inputType;
423     if (type == DOM_INPUT_TYPE_NUMBER) {
424         inputType = TextInputType::NUMBER;
425     } else if (type == DOM_INPUT_TYPE_DATE || type == DOM_INPUT_TYPE_TIME) {
426         inputType = TextInputType::DATETIME;
427     } else if (type == DOM_INPUT_TYPE_EMAIL) {
428         inputType = TextInputType::EMAIL_ADDRESS;
429     } else if (type == DOM_INPUT_TYPE_PASSWORD) {
430         inputType = TextInputType::VISIBLE_PASSWORD;
431     } else {
432         inputType = TextInputType::TEXT;
433     }
434     return inputType;
435 }
436 
ConvertStrToTabBarMode(const std::string& value)437 inline TabBarMode ConvertStrToTabBarMode(const std::string& value)
438 {
439     std::string temp = value;
440     transform(temp.begin(), temp.end(), temp.begin(), tolower);
441     return temp == "fixed" ? TabBarMode::FIXED : TabBarMode::SCROLLABLE;
442 }
443 
444 ACE_FORCE_EXPORT RefPtr<Curve> CreateBuiltinCurve(const std::string& aniTimFunc);
445 
446 ACE_FORCE_EXPORT RefPtr<Curve> CreateCustomCurve(const std::string& aniTimFunc);
447 
448 ACE_FORCE_EXPORT RefPtr<Curve> CreateCurve(const std::function<float(float)>& jsFunc);
449 
450 ACE_FORCE_EXPORT RefPtr<Curve> CreateCurve(const std::string& aniTimFunc, bool useDefault = true);
451 
452 ACE_FORCE_EXPORT bool ParseCurveParam(
453     const std::string& aniTimFunc, std::string& curveName, std::vector<std::string>& paramsVector);
454 
455 ACE_FORCE_EXPORT RefPtr<Curve> CreateCurveExceptSpring(
456     const std::string& aniTimFunc, const std::function<float(float)>& jsFunc = nullptr);
457 
458 ACE_EXPORT TransitionType ParseTransitionType(const std::string& transitionType);
459 
460 ACE_EXPORT RefPtr<ClipPath> CreateClipPath(const std::string& value);
461 
StringToFillMode(const std::string& fillMode)462 inline FillMode StringToFillMode(const std::string& fillMode)
463 {
464     if (fillMode == DOM_ANIMATION_FILL_MODE_FORWARDS) {
465         return FillMode::FORWARDS;
466     } else if (fillMode == DOM_ANIMATION_FILL_MODE_BACKWARDS) {
467         return FillMode::BACKWARDS;
468     } else if (fillMode == DOM_ANIMATION_FILL_MODE_BOTH) {
469         return FillMode::BOTH;
470     } else {
471         return FillMode::NONE;
472     }
473 }
474 
StringToAnimationDirection(const std::string& direction)475 inline AnimationDirection StringToAnimationDirection(const std::string& direction)
476 {
477     if (direction == DOM_ANIMATION_DIRECTION_ALTERNATE) {
478         return AnimationDirection::ALTERNATE;
479     } else if (direction == DOM_ANIMATION_DIRECTION_REVERSE) {
480         return AnimationDirection::REVERSE;
481     } else if (direction == DOM_ANIMATION_DIRECTION_ALTERNATE_REVERSE) {
482         return AnimationDirection::ALTERNATE_REVERSE;
483     } else {
484         return AnimationDirection::NORMAL;
485     }
486 }
487 
StringToAnimationOperation(const std::string& direction)488 inline AnimationOperation StringToAnimationOperation(const std::string& direction)
489 {
490     if (direction == DOM_ANIMATION_PLAY_STATE_IDLE) {
491         return AnimationOperation::CANCEL;
492     } else if (direction == DOM_ANIMATION_PLAY_STATE_RUNNING) {
493         return AnimationOperation::RUNNING;
494     } else if (direction == DOM_ANIMATION_PLAY_STATE_PAUSED) {
495         return AnimationOperation::PAUSE;
496     } else if (direction == DOM_ANIMATION_PLAY_STATE_FINISHED) {
497         return AnimationOperation::FINISH;
498     } else {
499         return AnimationOperation::NONE;
500     }
501 }
502 
RemoveHeadTailSpace(std::string& value)503 inline void RemoveHeadTailSpace(std::string& value)
504 {
505     if (!value.empty()) {
506         auto start = value.find_first_not_of(' ');
507         if (start == std::string::npos) {
508             value.clear();
509         } else {
510             value = value.substr(start, value.find_last_not_of(' ') - start + 1);
511         }
512     }
513 }
514 
StrToGradientDirection(const std::string& direction)515 inline GradientDirection StrToGradientDirection(const std::string& direction)
516 {
517     static const LinearMapNode<GradientDirection> gradientDirectionTable[] = {
518         { DOM_GRADIENT_DIRECTION_LEFT, GradientDirection::LEFT },
519         { DOM_GRADIENT_DIRECTION_RIGHT, GradientDirection::RIGHT },
520         { DOM_GRADIENT_DIRECTION_TOP, GradientDirection::TOP },
521         { DOM_GRADIENT_DIRECTION_BOTTOM, GradientDirection::BOTTOM },
522     };
523 
524     auto index = BinarySearchFindIndex(gradientDirectionTable, ArraySize(gradientDirectionTable), direction.c_str());
525     return index < 0 ? GradientDirection::BOTTOM : gradientDirectionTable[index].value;
526 }
527 
528 std::string CurveIntToString(int curve);
529 
530 bool ParseBackgroundImagePosition(const std::string& value, BackgroundImagePosition& backgroundImagePosition);
531 
532 bool ParseBackgroundImageSize(const std::string& value, BackgroundImageSize& backgroundImageSize);
533 
534 ImageObjectPosition ParseImageObjectPosition(const std::string& value);
535 
536 std::optional<RadialSizeType> ParseRadialGradientSize(const std::string& value);
537 
StartWith(const std::string& dst, const std::string& prefix)538 inline bool StartWith(const std::string& dst, const std::string& prefix)
539 {
540     return dst.compare(0, prefix.size(), prefix) == 0;
541 }
542 
EndWith(const std::string& dst, const std::string& suffix)543 inline bool EndWith(const std::string& dst, const std::string& suffix)
544 {
545     return dst.size() >= suffix.size() && dst.compare(dst.size() - suffix.size(), suffix.size(), suffix) == 0;
546 }
547 
ConvertTimeStr(const std::string& str)548 inline double ConvertTimeStr(const std::string& str)
549 {
550     std::string time(str);
551     StringUtils::TrimStr(time);
552     double result = 0.0;
553     if (EndWith(time, "ms")) {
554         // remove 2 char "ms"
555         result = StringToDouble(std::string(time.begin(), time.end() - 2.0));
556     } else if (EndWith(time, "s")) {
557         // transform s to ms
558         result = StringToDouble(std::string(time.begin(), time.end() - 1.0)) * 1000.0;
559     } else if (EndWith(time, "m")) {
560         // transform m to ms
561         result = StringToDouble(std::string(time.begin(), time.end() - 1.0)) * 60.0 * 1000.0;
562     } else {
563         result = StringToDouble(str);
564     }
565     return result;
566 }
567 
ConvertStrToWordBreak(const std::string& wordBreak)568 inline WordBreak ConvertStrToWordBreak(const std::string& wordBreak)
569 {
570     return StringUtils::StringToWordBreak(wordBreak);
571 }
572 
CheckTransformEnum(const std::string& str)573 inline bool CheckTransformEnum(const std::string& str)
574 {
575     const static std::unordered_set<std::string> offsetKeywords = { "left", "right", "center", "top", "bottom" };
576 
577     return offsetKeywords.find(str) != offsetKeywords.end();
578 }
579 
ConvertStrToTransformOrigin(const std::string& str, Axis axis)580 inline std::pair<bool, Dimension> ConvertStrToTransformOrigin(const std::string& str, Axis axis)
581 {
582     const static std::unordered_map<std::string, Dimension> xOffsetKeywords = {
583         { "left", 0.0_pct },
584         { "right", 1.0_pct },
585         { "center", 0.5_pct },
586     };
587     const static std::unordered_map<std::string, Dimension> yOffsetKeywords = {
588         { "top", 0.0_pct },
589         { "bottom", 1.0_pct },
590         { "center", 0.5_pct },
591     };
592 
593     if (axis == Axis::HORIZONTAL) {
594         auto pos = xOffsetKeywords.find(str);
595         if (pos != xOffsetKeywords.end()) {
596             return std::make_pair(true, pos->second);
597         }
598     } else if (axis == Axis::VERTICAL) {
599         auto pos = yOffsetKeywords.find(str);
600         if (pos != yOffsetKeywords.end()) {
601             return std::make_pair(true, pos->second);
602         }
603     }
604 
605     return std::make_pair(false, Dimension {});
606 }
607 
ParseUtf8TextLength(std::string& text)608 inline int32_t ParseUtf8TextLength(std::string& text)
609 {
610     int32_t trueLength = 0;
611     int32_t stringLength = 0;
612     while (stringLength < static_cast<int32_t>(text.length())) {
613         uint8_t stringChar = static_cast<uint8_t>(text[stringLength++]);
614         if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
615             trueLength++;
616         }
617     }
618     return trueLength;
619 }
620 
ParseUtf8TextSubstrStartPos(std::string& text, int32_t targetPos)621 inline int32_t ParseUtf8TextSubstrStartPos(std::string& text, int32_t targetPos)
622 {
623     int32_t truePos = 0;
624     int32_t stringPos = 0;
625     while ((stringPos < static_cast<int32_t>(text.length())) && (truePos < targetPos)) {
626         uint8_t stringChar = static_cast<uint8_t>(text[stringPos++]);
627         if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
628             truePos++;
629         }
630     }
631     return stringPos;
632 }
633 
ParseUtf8TextSubstrEndPos(std::string& text, int32_t targetPos)634 inline int32_t ParseUtf8TextSubstrEndPos(std::string& text, int32_t targetPos)
635 {
636     auto stringPos = ParseUtf8TextSubstrStartPos(text, targetPos);
637     while (stringPos < static_cast<int32_t>(text.length())) {
638         uint8_t stringChar = static_cast<uint8_t>(text[stringPos]);
639         if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
640             break;
641         }
642         stringPos++;
643     }
644     return stringPos;
645 }
646 
HandleEscapeCharaterInUtf8TextForJson(std::string& text)647 inline void HandleEscapeCharaterInUtf8TextForJson(std::string& text)
648 {
649     for (size_t pos = 0; pos < text.size(); pos++) {
650         if ((text.at(pos) == DOUBLE_QUOTATION) || (text.at(pos) == BACKSLASH) ||
651             ((text.at(pos) >= ESCAPE_CHARATER_START) && (text.at(pos) <= ESCAPE_CHARATER_END))) {
652             std::ostringstream is;
653             is << UNICODE_HEAD << std::hex << std::setw(UNICODE_LENGTH) << std::setfill(UNICODE_BODY)
654                << int(text.at(pos));
655             text.replace(pos, 1, is.str());
656         }
657     }
658 }
659 
ParseResourceInputNumberParam(const std::string& param)660 inline int32_t ParseResourceInputNumberParam(const std::string& param)
661 {
662     if (!StringUtils::IsNumber(param) || param.empty()) {
663         return INVALID_PARAM;
664     } else {
665         errno = 0;
666         char* pEnd = nullptr;
667         int64_t result = std::strtol(param.c_str(), &pEnd, STRTOL_BASE);
668         return ((result < INT_MIN || result > INT_MAX) || errno == ERANGE) ? INT_MAX : static_cast<int32_t>(result);
669     }
670 }
671 
ReplacePlaceHolderArray(std::string& resultStr, const std::vector<std::string>& arrayResult)672 inline void ReplacePlaceHolderArray(std::string& resultStr, const std::vector<std::string>& arrayResult)
673 {
674     auto size = arrayResult.size();
675     size_t startPos = 0;
676     for (size_t i = 0; i < size; i++) {
677         std::string placeHolder;
678         placeHolder += LEFT_CURLY_BRACES;
679         placeHolder += (i + '0');
680         placeHolder += RIGHT_CURLY_BRACES;
681         if (startPos < resultStr.length()) {
682             auto pos = resultStr.find(placeHolder, startPos);
683             if (pos != std::string::npos) {
684                 resultStr.replace(pos, PLACE_HOLDER_LENGTH, arrayResult[i]);
685                 startPos = pos + arrayResult[i].length();
686             }
687         }
688     }
689 }
690 
ReplacePlaceHolder(std::string& resultStr, const std::unique_ptr<JsonValue>& argsPtr)691 inline void ReplacePlaceHolder(std::string& resultStr, const std::unique_ptr<JsonValue>& argsPtr)
692 {
693     auto placeHolderKey = argsPtr->GetChild()->GetKey();
694     std::string placeHolder;
695     placeHolder += LEFT_CURLY_BRACES;
696     placeHolder += placeHolderKey;
697     placeHolder += RIGHT_CURLY_BRACES;
698     auto pos = resultStr.find(placeHolder);
699     if (pos != std::string::npos) {
700         resultStr.replace(pos, placeHolder.length(), argsPtr->GetChild()->GetString());
701     }
702 }
703 
ParserPluralResource( const std::unique_ptr<JsonValue>& argsPtr, const std::string& choice, const std::string& count)704 inline std::string ParserPluralResource(
705     const std::unique_ptr<JsonValue>& argsPtr, const std::string& choice, const std::string& count)
706 {
707     std::string valueStr;
708     std::string defaultPluralStr(DEFAULT_PLURAL_CHOICE);
709     if (argsPtr->Contains(choice)) {
710         valueStr = argsPtr->GetValue(choice)->GetString();
711     } else if (argsPtr->Contains(defaultPluralStr)) {
712         valueStr = argsPtr->GetValue(defaultPluralStr)->GetString();
713     } else {
714         return std::string();
715     }
716 
717     std::string pluralStr(PLURAL_COUNT_POS);
718     auto pos = valueStr.find(pluralStr);
719     if (pos != std::string::npos) {
720         valueStr.replace(pos, pluralStr.length(), count);
721     }
722     return valueStr;
723 }
724 
725 } // namespace OHOS::Ace::Framework
726 
727 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_COMMON_UTILS_UTILS_H
728