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  
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  
216  inline std::pair<bool, FontWeight> ParseFontWeight(const std::string& weight,
217      FontWeight defaultFontWeight = FontWeight::NORMAL)
218  {
219      return StringUtils::ParseFontWeight(weight, defaultFontWeight);
220  }
221  
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  
ConvertStrToFontFamilies(const std::string & family)332  inline std::vector<std::string> ConvertStrToFontFamilies(const std::string& family)
333  {
334      std::vector<std::string> fontFamilies;
335      std::stringstream stream(family);
336      std::string fontFamily;
337      while (getline(stream, fontFamily, ',')) {
338          fontFamilies.emplace_back(fontFamily);
339      }
340      return fontFamilies;
341  }
342  
ConvertStrToFlexDirection(const std::string & flexKey)343  inline FlexDirection ConvertStrToFlexDirection(const std::string& flexKey)
344  {
345      return flexKey == DOM_FLEX_COLUMN ? FlexDirection::COLUMN : FlexDirection::ROW;
346  }
347  
ConvertStrToFlexAlign(const std::string & flexKey)348  inline FlexAlign ConvertStrToFlexAlign(const std::string& flexKey)
349  {
350      static const LinearMapNode<FlexAlign> flexMap[] = {
351          { DOM_ALIGN_ITEMS_BASELINE, FlexAlign::BASELINE },
352          { DOM_JUSTIFY_CONTENT_CENTER, FlexAlign::CENTER },
353          { DOM_JUSTIFY_CONTENT_END, FlexAlign::FLEX_END },
354          { DOM_JUSTIFY_CONTENT_START, FlexAlign::FLEX_START },
355          { DOM_JUSTIFY_CONTENT_AROUND, FlexAlign::SPACE_AROUND },
356          { DOM_JUSTIFY_CONTENT_BETWEEN, FlexAlign::SPACE_BETWEEN },
357          { DOM_JUSTIFY_CONTENT_EVENLY, FlexAlign::SPACE_EVENLY },
358          { DOM_ALIGN_ITEMS_STRETCH, FlexAlign::STRETCH },
359      };
360      auto index = BinarySearchFindIndex(flexMap, ArraySize(flexMap), flexKey.c_str());
361      return index < 0 ? FlexAlign::FLEX_START : flexMap[index].value;
362  }
363  
ConvertStrToOffset(const std::string & value)364  inline Offset ConvertStrToOffset(const std::string& value)
365  {
366      Offset offset;
367      std::vector<std::string> offsetValues;
368      std::stringstream stream(value);
369      std::string offsetValue;
370      while (getline(stream, offsetValue, ' ')) {
371          offsetValues.emplace_back(offsetValue);
372      }
373      // To avoid illegal input, such as "100px ".
374      offsetValues.resize(OFFSET_VALUE_NUMBER);
375      offset.SetX(StringToDouble(offsetValues[0]));
376      offset.SetY(StringToDouble(offsetValues[1]));
377      return offset;
378  }
379  
ConvertStrToQrcodeType(const std::string & value)380  inline QrcodeType ConvertStrToQrcodeType(const std::string& value)
381  {
382      return value == "circle" ? QrcodeType::CIRCLE : QrcodeType::RECT;
383  }
384  
ConvertStrToAnimationCurve(const std::string & value)385  inline AnimationCurve ConvertStrToAnimationCurve(const std::string& value)
386  {
387      return value == "standard" ? AnimationCurve::STANDARD : AnimationCurve::FRICTION;
388  }
389  
ConvertStrToTextInputAction(const std::string & action)390  inline TextInputAction ConvertStrToTextInputAction(const std::string& action)
391  {
392      TextInputAction inputAction;
393      if (action == INPUT_ACTION_NEXT) {
394          inputAction = TextInputAction::NEXT;
395      } else if (action == INPUT_ACTION_GO) {
396          inputAction = TextInputAction::GO;
397      } else if (action == INPUT_ACTION_DONE) {
398          inputAction = TextInputAction::DONE;
399      } else if (action == INPUT_ACTION_SEND) {
400          inputAction = TextInputAction::SEND;
401      } else if (action == INPUT_ACTION_SEARCH) {
402          inputAction = TextInputAction::SEARCH;
403      } else {
404          inputAction = TextInputAction::UNSPECIFIED;
405      }
406      return inputAction;
407  }
408  
ConvertStrToTextInputType(const std::string & type)409  inline TextInputType ConvertStrToTextInputType(const std::string& type)
410  {
411      TextInputType inputType;
412      if (type == DOM_INPUT_TYPE_NUMBER) {
413          inputType = TextInputType::NUMBER;
414      } else if (type == DOM_INPUT_TYPE_DATE || type == DOM_INPUT_TYPE_TIME) {
415          inputType = TextInputType::DATETIME;
416      } else if (type == DOM_INPUT_TYPE_EMAIL) {
417          inputType = TextInputType::EMAIL_ADDRESS;
418      } else if (type == DOM_INPUT_TYPE_PASSWORD) {
419          inputType = TextInputType::VISIBLE_PASSWORD;
420      } else {
421          inputType = TextInputType::TEXT;
422      }
423      return inputType;
424  }
425  
ConvertStrToTabBarMode(const std::string & value)426  inline TabBarMode ConvertStrToTabBarMode(const std::string& value)
427  {
428      std::string temp = value;
429      transform(temp.begin(), temp.end(), temp.begin(), tolower);
430      return temp == "fixed" ? TabBarMode::FIXED : TabBarMode::SCROLLABLE;
431  }
432  
433  ACE_FORCE_EXPORT RefPtr<Curve> CreateBuiltinCurve(const std::string& aniTimFunc);
434  
435  ACE_FORCE_EXPORT RefPtr<Curve> CreateCustomCurve(const std::string& aniTimFunc);
436  
437  ACE_FORCE_EXPORT RefPtr<Curve> CreateCurve(const std::function<float(float)>& jsFunc);
438  
439  ACE_FORCE_EXPORT RefPtr<Curve> CreateCurve(const std::string& aniTimFunc, bool useDefault = true);
440  
441  ACE_FORCE_EXPORT bool ParseCurveParam(
442      const std::string& aniTimFunc, std::string& curveName, std::vector<std::string>& paramsVector);
443  
444  ACE_FORCE_EXPORT RefPtr<Curve> CreateCurveExceptSpring(
445      const std::string& aniTimFunc, const std::function<float(float)>& jsFunc = nullptr);
446  
447  ACE_EXPORT TransitionType ParseTransitionType(const std::string& transitionType);
448  
449  ACE_EXPORT RefPtr<ClipPath> CreateClipPath(const std::string& value);
450  
StringToFillMode(const std::string & fillMode)451  inline FillMode StringToFillMode(const std::string& fillMode)
452  {
453      if (fillMode == DOM_ANIMATION_FILL_MODE_FORWARDS) {
454          return FillMode::FORWARDS;
455      } else if (fillMode == DOM_ANIMATION_FILL_MODE_BACKWARDS) {
456          return FillMode::BACKWARDS;
457      } else if (fillMode == DOM_ANIMATION_FILL_MODE_BOTH) {
458          return FillMode::BOTH;
459      } else {
460          return FillMode::NONE;
461      }
462  }
463  
StringToAnimationDirection(const std::string & direction)464  inline AnimationDirection StringToAnimationDirection(const std::string& direction)
465  {
466      if (direction == DOM_ANIMATION_DIRECTION_ALTERNATE) {
467          return AnimationDirection::ALTERNATE;
468      } else if (direction == DOM_ANIMATION_DIRECTION_REVERSE) {
469          return AnimationDirection::REVERSE;
470      } else if (direction == DOM_ANIMATION_DIRECTION_ALTERNATE_REVERSE) {
471          return AnimationDirection::ALTERNATE_REVERSE;
472      } else {
473          return AnimationDirection::NORMAL;
474      }
475  }
476  
StringToAnimationOperation(const std::string & direction)477  inline AnimationOperation StringToAnimationOperation(const std::string& direction)
478  {
479      if (direction == DOM_ANIMATION_PLAY_STATE_IDLE) {
480          return AnimationOperation::CANCEL;
481      } else if (direction == DOM_ANIMATION_PLAY_STATE_RUNNING) {
482          return AnimationOperation::RUNNING;
483      } else if (direction == DOM_ANIMATION_PLAY_STATE_PAUSED) {
484          return AnimationOperation::PAUSE;
485      } else if (direction == DOM_ANIMATION_PLAY_STATE_FINISHED) {
486          return AnimationOperation::FINISH;
487      } else {
488          return AnimationOperation::NONE;
489      }
490  }
491  
RemoveHeadTailSpace(std::string & value)492  inline void RemoveHeadTailSpace(std::string& value)
493  {
494      if (!value.empty()) {
495          auto start = value.find_first_not_of(' ');
496          if (start == std::string::npos) {
497              value.clear();
498          } else {
499              value = value.substr(start, value.find_last_not_of(' ') - start + 1);
500          }
501      }
502  }
503  
StrToGradientDirection(const std::string & direction)504  inline GradientDirection StrToGradientDirection(const std::string& direction)
505  {
506      static const LinearMapNode<GradientDirection> gradientDirectionTable[] = {
507          { DOM_GRADIENT_DIRECTION_LEFT, GradientDirection::LEFT },
508          { DOM_GRADIENT_DIRECTION_RIGHT, GradientDirection::RIGHT },
509          { DOM_GRADIENT_DIRECTION_TOP, GradientDirection::TOP },
510          { DOM_GRADIENT_DIRECTION_BOTTOM, GradientDirection::BOTTOM },
511      };
512  
513      auto index = BinarySearchFindIndex(gradientDirectionTable, ArraySize(gradientDirectionTable), direction.c_str());
514      return index < 0 ? GradientDirection::BOTTOM : gradientDirectionTable[index].value;
515  }
516  
517  std::string CurveIntToString(int curve);
518  
519  bool ParseBackgroundImagePosition(const std::string& value, BackgroundImagePosition& backgroundImagePosition);
520  
521  bool ParseBackgroundImageSize(const std::string& value, BackgroundImageSize& backgroundImageSize);
522  
523  ImageObjectPosition ParseImageObjectPosition(const std::string& value);
524  
525  std::optional<RadialSizeType> ParseRadialGradientSize(const std::string& value);
526  
StartWith(const std::string & dst,const std::string & prefix)527  inline bool StartWith(const std::string& dst, const std::string& prefix)
528  {
529      return dst.compare(0, prefix.size(), prefix) == 0;
530  }
531  
EndWith(const std::string & dst,const std::string & suffix)532  inline bool EndWith(const std::string& dst, const std::string& suffix)
533  {
534      return dst.size() >= suffix.size() && dst.compare(dst.size() - suffix.size(), suffix.size(), suffix) == 0;
535  }
536  
ConvertTimeStr(const std::string & str)537  inline double ConvertTimeStr(const std::string& str)
538  {
539      std::string time(str);
540      StringUtils::TrimStr(time);
541      double result = 0.0;
542      if (EndWith(time, "ms")) {
543          // remove 2 char "ms"
544          result = StringToDouble(std::string(time.begin(), time.end() - 2.0));
545      } else if (EndWith(time, "s")) {
546          // transform s to ms
547          result = StringToDouble(std::string(time.begin(), time.end() - 1.0)) * 1000.0;
548      } else if (EndWith(time, "m")) {
549          // transform m to ms
550          result = StringToDouble(std::string(time.begin(), time.end() - 1.0)) * 60.0 * 1000.0;
551      } else {
552          result = StringToDouble(str);
553      }
554      return result;
555  }
556  
ConvertStrToWordBreak(const std::string & wordBreak)557  inline WordBreak ConvertStrToWordBreak(const std::string& wordBreak)
558  {
559      return StringUtils::StringToWordBreak(wordBreak);
560  }
561  
CheckTransformEnum(const std::string & str)562  inline bool CheckTransformEnum(const std::string& str)
563  {
564      const static std::unordered_set<std::string> offsetKeywords = { "left", "right", "center", "top", "bottom" };
565  
566      return offsetKeywords.find(str) != offsetKeywords.end();
567  }
568  
ConvertStrToTransformOrigin(const std::string & str,Axis axis)569  inline std::pair<bool, Dimension> ConvertStrToTransformOrigin(const std::string& str, Axis axis)
570  {
571      const static std::unordered_map<std::string, Dimension> xOffsetKeywords = {
572          { "left", 0.0_pct },
573          { "right", 1.0_pct },
574          { "center", 0.5_pct },
575      };
576      const static std::unordered_map<std::string, Dimension> yOffsetKeywords = {
577          { "top", 0.0_pct },
578          { "bottom", 1.0_pct },
579          { "center", 0.5_pct },
580      };
581  
582      if (axis == Axis::HORIZONTAL) {
583          auto pos = xOffsetKeywords.find(str);
584          if (pos != xOffsetKeywords.end()) {
585              return std::make_pair(true, pos->second);
586          }
587      } else if (axis == Axis::VERTICAL) {
588          auto pos = yOffsetKeywords.find(str);
589          if (pos != yOffsetKeywords.end()) {
590              return std::make_pair(true, pos->second);
591          }
592      }
593  
594      return std::make_pair(false, Dimension {});
595  }
596  
ParseUtf8TextLength(std::string & text)597  inline int32_t ParseUtf8TextLength(std::string& text)
598  {
599      int32_t trueLength = 0;
600      int32_t stringLength = 0;
601      while (stringLength < static_cast<int32_t>(text.length())) {
602          uint8_t stringChar = static_cast<uint8_t>(text[stringLength++]);
603          if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
604              trueLength++;
605          }
606      }
607      return trueLength;
608  }
609  
ParseUtf8TextSubstrStartPos(std::string & text,int32_t targetPos)610  inline int32_t ParseUtf8TextSubstrStartPos(std::string& text, int32_t targetPos)
611  {
612      int32_t truePos = 0;
613      int32_t stringPos = 0;
614      while ((stringPos < static_cast<int32_t>(text.length())) && (truePos < targetPos)) {
615          uint8_t stringChar = static_cast<uint8_t>(text[stringPos++]);
616          if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
617              truePos++;
618          }
619      }
620      return stringPos;
621  }
622  
ParseUtf8TextSubstrEndPos(std::string & text,int32_t targetPos)623  inline int32_t ParseUtf8TextSubstrEndPos(std::string& text, int32_t targetPos)
624  {
625      auto stringPos = ParseUtf8TextSubstrStartPos(text, targetPos);
626      while (stringPos < static_cast<int32_t>(text.length())) {
627          uint8_t stringChar = static_cast<uint8_t>(text[stringPos]);
628          if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
629              break;
630          }
631          stringPos++;
632      }
633      return stringPos;
634  }
635  
HandleEscapeCharaterInUtf8TextForJson(std::string & text)636  inline void HandleEscapeCharaterInUtf8TextForJson(std::string& text)
637  {
638      for (size_t pos = 0; pos < text.size(); pos++) {
639          if ((text.at(pos) == DOUBLE_QUOTATION) || (text.at(pos) == BACKSLASH) ||
640              ((text.at(pos) >= ESCAPE_CHARATER_START) && (text.at(pos) <= ESCAPE_CHARATER_END))) {
641              std::ostringstream is;
642              is << UNICODE_HEAD << std::hex << std::setw(UNICODE_LENGTH) << std::setfill(UNICODE_BODY)
643                 << int(text.at(pos));
644              text.replace(pos, 1, is.str());
645          }
646      }
647  }
648  
ParseResourceInputNumberParam(const std::string & param)649  inline int32_t ParseResourceInputNumberParam(const std::string& param)
650  {
651      if (!StringUtils::IsNumber(param) || param.empty()) {
652          return INVALID_PARAM;
653      } else {
654          errno = 0;
655          char* pEnd = nullptr;
656          int64_t result = std::strtol(param.c_str(), &pEnd, STRTOL_BASE);
657          return ((result < INT_MIN || result > INT_MAX) || errno == ERANGE) ? INT_MAX : static_cast<int32_t>(result);
658      }
659  }
660  
ReplacePlaceHolderArray(std::string & resultStr,const std::vector<std::string> & arrayResult)661  inline void ReplacePlaceHolderArray(std::string& resultStr, const std::vector<std::string>& arrayResult)
662  {
663      auto size = arrayResult.size();
664      size_t startPos = 0;
665      for (size_t i = 0; i < size; i++) {
666          std::string placeHolder;
667          placeHolder += LEFT_CURLY_BRACES;
668          placeHolder += (i + '0');
669          placeHolder += RIGHT_CURLY_BRACES;
670          if (startPos < resultStr.length()) {
671              auto pos = resultStr.find(placeHolder, startPos);
672              if (pos != std::string::npos) {
673                  resultStr.replace(pos, PLACE_HOLDER_LENGTH, arrayResult[i]);
674                  startPos = pos + arrayResult[i].length();
675              }
676          }
677      }
678  }
679  
ReplacePlaceHolder(std::string & resultStr,const std::unique_ptr<JsonValue> & argsPtr)680  inline void ReplacePlaceHolder(std::string& resultStr, const std::unique_ptr<JsonValue>& argsPtr)
681  {
682      auto placeHolderKey = argsPtr->GetChild()->GetKey();
683      std::string placeHolder;
684      placeHolder += LEFT_CURLY_BRACES;
685      placeHolder += placeHolderKey;
686      placeHolder += RIGHT_CURLY_BRACES;
687      auto pos = resultStr.find(placeHolder);
688      if (pos != std::string::npos) {
689          resultStr.replace(pos, placeHolder.length(), argsPtr->GetChild()->GetString());
690      }
691  }
692  
ParserPluralResource(const std::unique_ptr<JsonValue> & argsPtr,const std::string & choice,const std::string & count)693  inline std::string ParserPluralResource(
694      const std::unique_ptr<JsonValue>& argsPtr, const std::string& choice, const std::string& count)
695  {
696      std::string valueStr;
697      std::string defaultPluralStr(DEFAULT_PLURAL_CHOICE);
698      if (argsPtr->Contains(choice)) {
699          valueStr = argsPtr->GetValue(choice)->GetString();
700      } else if (argsPtr->Contains(defaultPluralStr)) {
701          valueStr = argsPtr->GetValue(defaultPluralStr)->GetString();
702      } else {
703          return std::string();
704      }
705  
706      std::string pluralStr(PLURAL_COUNT_POS);
707      auto pos = valueStr.find(pluralStr);
708      if (pos != std::string::npos) {
709          valueStr.replace(pos, pluralStr.length(), count);
710      }
711      return valueStr;
712  }
713  
714  } // namespace OHOS::Ace::Framework
715  
716  #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_COMMON_UTILS_UTILS_H
717