1 /*
2 * Copyright (c) 2024 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 OHOS_JS_TEXT_UTILS_H
17 #define OHOS_JS_TEXT_UTILS_H
18
19 #include <codecvt>
20 #include <map>
21
22 #include "draw/color.h"
23 #include "native_engine/native_engine.h"
24 #include "native_engine/native_value.h"
25 #include "text_style.h"
26 #include "typography.h"
27 #include "typography_create.h"
28 #include "typography_style.h"
29 #include "utils/point.h"
30 #include "utils/text_log.h"
31
32 namespace OHOS::Rosen {
33 constexpr size_t ARGC_ONE = 1;
34 constexpr size_t ARGC_TWO = 2;
35 constexpr size_t ARGC_THREE = 3;
36 constexpr size_t ARGC_FOUR = 4;
37 constexpr size_t ARGC_FIVE = 5;
38 constexpr size_t ARGC_SIX = 6;
39
40 struct ResourceInfo {
41 int32_t resId = 0;
42 int32_t type = 0;
43 std::vector<std::string> params;
44 std::string bundleName;
45 std::string moduleName;
46 };
47
48 enum class ResourceType {
49 COLOR = 10001,
50 FLOAT,
51 STRING,
52 PLURAL,
53 BOOLEAN,
54 INTARRAY,
55 INTEGER,
56 PATTERN,
57 STRARRAY,
58 MEDIA = 20000,
59 RAWFILE = 30000
60 };
61
62 enum class TextErrorCode : int32_t {
63 ERROR = -1,
64 OK = 0,
65 ERROR_NO_PERMISSION = 201, // the value do not change. It is defined on all system
66 ERROR_INVALID_PARAM = 401, // the value do not change. It is defined on all system
67 ERROR_DEVICE_NOT_SUPPORT = 801, // the value do not change. It is defined on all system
68 ERROR_ABNORMAL_PARAM_VALUE = 18600001, // the value do not change. It is defined on color manager system
69 ERROR_NO_MEMORY = 8800100, // no memory
70 };
71
72 #define GET_UNWRAP_PARAM(argc, value) \
73 do { \
74 if ((napi_unwrap(env, argv[argc], reinterpret_cast<void**>(&value)) != napi_ok) || value == nullptr) { \
75 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, \
76 std::string("Incorrect ") + __FUNCTION__ + " parameter" + std::to_string(argc) + " type."); \
77 } \
78 } while (0)
79
80
81 #define NAPI_CHECK_AND_THROW_ERROR(ret, errorCode, errorMessage) \
82 do { \
83 if (!(ret)) { \
84 TEXT_LOGE("%{public}s", #errorMessage); \
85 return NapiThrowError(env, errorCode, errorMessage); \
86 } \
87 } while (0)
88
89 #define NAPI_CHECK_AND_CLOSE_SCOPE(env, statement, scope, ret) \
90 do { \
91 if ((statement) != napi_ok) { \
92 TEXT_LOGE("%{public}s failed", #statement); \
93 napi_close_handle_scope(env, scope); \
94 return ret; \
95 } \
96 } while (0)
97
98 template<class T>
99 T* CheckParamsAndGetThis(const napi_env env, napi_callback_info info, const char* name = nullptr)
100 {
101 if (env == nullptr || info == nullptr) {
102 return nullptr;
103 }
104 napi_value object = nullptr;
105 napi_value propertyNameValue = nullptr;
106 napi_value pointerValue = nullptr;
107 napi_get_cb_info(env, info, nullptr, nullptr, &object, nullptr);
108 if (object != nullptr && name != nullptr) {
109 napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &propertyNameValue);
110 }
111 napi_value& resObject = propertyNameValue ? propertyNameValue : object;
112 if (resObject) {
113 return napi_unwrap(env, resObject, (void **)(&pointerValue)) == napi_ok ?
114 reinterpret_cast<T*>(pointerValue) : nullptr;
115 }
116 return nullptr;
117 }
118
119 template<typename T, size_t N>
ArraySize(T (&)[N])120 inline constexpr size_t ArraySize(T (&)[N]) noexcept
121 {
122 return N;
123 }
124
CreateJsUndefined(napi_env env)125 inline napi_value CreateJsUndefined(napi_env env)
126 {
127 napi_value result = nullptr;
128 napi_get_undefined(env, &result);
129 return result;
130 }
131
CreateJsNull(napi_env env)132 inline napi_value CreateJsNull(napi_env env)
133 {
134 napi_value result = nullptr;
135 napi_get_null(env, &result);
136 return result;
137 }
138
CreateJsNumber(napi_env env,int32_t value)139 inline napi_value CreateJsNumber(napi_env env, int32_t value)
140 {
141 napi_value result = nullptr;
142 napi_create_int32(env, value, &result);
143 return result;
144 }
145
CreateJsNumber(napi_env env,uint32_t value)146 inline napi_value CreateJsNumber(napi_env env, uint32_t value)
147 {
148 napi_value result = nullptr;
149 napi_create_uint32(env, value, &result);
150 return result;
151 }
152
CreateJsNumber(napi_env env,int64_t value)153 inline napi_value CreateJsNumber(napi_env env, int64_t value)
154 {
155 napi_value result = nullptr;
156 napi_create_int64(env, value, &result);
157 return result;
158 }
159
CreateJsNumber(napi_env env,uint64_t value)160 inline napi_value CreateJsNumber(napi_env env, uint64_t value)
161 {
162 napi_value result = nullptr;
163 napi_create_int64(env, value, &result);
164 return result;
165 }
166
CreateJsNumber(napi_env env,double value)167 inline napi_value CreateJsNumber(napi_env env, double value)
168 {
169 napi_value result = nullptr;
170 napi_create_double(env, value, &result);
171 return result;
172 }
173
174 template<class T>
CreateJsValue(napi_env env,const T & value)175 napi_value CreateJsValue(napi_env env, const T& value)
176 {
177 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
178 napi_value result = nullptr;
179 if constexpr (std::is_same_v<ValueType, bool>) {
180 napi_get_boolean(env, value, &result);
181 return result;
182 } else if constexpr (std::is_arithmetic_v<ValueType>) {
183 return CreateJsNumber(env, value);
184 } else if constexpr (std::is_same_v<ValueType, std::string>) {
185 napi_create_string_utf8(env, value.c_str(), value.length(), &result);
186 return result;
187 } else if constexpr (std::is_enum_v<ValueType>) {
188 return CreateJsNumber(env, static_cast<std::make_signed_t<ValueType>>(value));
189 } else if constexpr (std::is_same_v<ValueType, const char*>) {
190 (value != nullptr) ? napi_create_string_utf8(env, value, strlen(value), &result) :
191 napi_get_undefined(env, &result);
192 return result;
193 } else {
194 return result;
195 }
196 }
197
ConvertFromJsNumber(napi_env env,napi_value jsValue,int32_t & value)198 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, int32_t& value)
199 {
200 return napi_get_value_int32(env, jsValue, &value) == napi_ok;
201 }
202
ConvertFromJsNumber(napi_env env,napi_value jsValue,uint32_t & value)203 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, uint32_t& value)
204 {
205 return napi_get_value_uint32(env, jsValue, &value) == napi_ok;
206 }
207
ConvertFromJsNumber(napi_env env,napi_value jsValue,int64_t & value)208 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, int64_t& value)
209 {
210 return napi_get_value_int64(env, jsValue, &value) == napi_ok;
211 }
212
ConvertFromJsNumber(napi_env env,napi_value jsValue,uint64_t & value)213 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, uint64_t& value)
214 {
215 int64_t num;
216 auto res = napi_get_value_int64(env, jsValue, &num);
217 if (res == napi_ok) {
218 value = static_cast<uint64_t>(num);
219 }
220 return res == napi_ok;
221 }
222
ConvertFromJsNumber(napi_env env,napi_value jsValue,double & value)223 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, double& value)
224 {
225 return napi_get_value_double(env, jsValue, &value) == napi_ok;
226 }
227
ConvertFromJsNumber(napi_env env,napi_value jsValue,bool & value)228 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, bool& value)
229 {
230 return napi_get_value_bool(env, jsValue, &value) == napi_ok;
231 }
232
233 template<class T>
ConvertFromJsValue(napi_env env,napi_value jsValue,T & value)234 bool ConvertFromJsValue(napi_env env, napi_value jsValue, T& value)
235 {
236 if (jsValue == nullptr) {
237 return false;
238 }
239
240 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
241 if constexpr (std::is_same_v<ValueType, bool>) {
242 return napi_get_value_bool(env, jsValue, &value) == napi_ok;
243 } else if constexpr (std::is_arithmetic_v<ValueType>) {
244 return ConvertFromJsNumber(env, jsValue, value);
245 } else if constexpr (std::is_same_v<ValueType, std::string>) {
246 size_t len = 0;
247 if (napi_get_value_string_utf8(env, jsValue, nullptr, 0, &len) != napi_ok) {
248 return false;
249 }
250 auto buffer = std::make_unique<char[]>(len + 1);
251 size_t strLength = 0;
252 if (napi_get_value_string_utf8(env, jsValue, buffer.get(), len + 1, &strLength) == napi_ok) {
253 value = buffer.get();
254 return true;
255 }
256 return false;
257 } else if constexpr (std::is_enum_v<ValueType>) {
258 std::make_signed_t<ValueType> numberValue = 0;
259 if (!ConvertFromJsNumber(env, jsValue, numberValue)) {
260 return false;
261 }
262 value = static_cast<ValueType>(numberValue);
263 return true;
264 }
265 return false;
266 }
267
ConvertClampFromJsValue(napi_env env,napi_value jsValue,int32_t & value,int32_t lo,int32_t hi)268 inline bool ConvertClampFromJsValue(napi_env env, napi_value jsValue, int32_t& value, int32_t lo, int32_t hi)
269 {
270 if (jsValue == nullptr) {
271 return false;
272 }
273 bool ret = napi_get_value_int32(env, jsValue, &value) == napi_ok;
274 value = std::clamp(value, lo, hi);
275 return ret;
276 }
277
GetDoubleAndConvertToJsValue(napi_env env,double d)278 inline napi_value GetDoubleAndConvertToJsValue(napi_env env, double d)
279 {
280 napi_value value = nullptr;
281 (void)napi_create_double(env, d, &value);
282 return value;
283 }
284
GetStringAndConvertToJsValue(napi_env env,std::string str)285 inline napi_value GetStringAndConvertToJsValue(napi_env env, std::string str)
286 {
287 napi_value objValue = nullptr;
288 napi_create_string_utf8(env, str.c_str(), str.length(), &objValue);
289 return objValue;
290 }
291
NapiGetUndefined(napi_env env)292 inline napi_value NapiGetUndefined(napi_env env)
293 {
294 napi_value result = nullptr;
295 napi_get_undefined(env, &result);
296 return result;
297 }
298
GetPointAndConvertToJsValue(napi_env env,Drawing::Point & point)299 inline napi_value GetPointAndConvertToJsValue(napi_env env, Drawing::Point& point)
300 {
301 napi_value objValue = nullptr;
302 napi_create_object(env, &objValue);
303 if (objValue != nullptr) {
304 napi_set_named_property(env, objValue, "x", CreateJsNumber(env, point.GetX()));
305 napi_set_named_property(env, objValue, "y", CreateJsNumber(env, point.GetY()));
306 }
307 return objValue;
308 }
309
GetPointXFromJsNumber(napi_env env,napi_value argValue,Drawing::Point & point)310 inline void GetPointXFromJsNumber(napi_env env, napi_value argValue, Drawing::Point& point)
311 {
312 napi_value objValue = nullptr;
313 double targetX = 0;
314 if (napi_get_named_property(env, argValue, "x", &objValue) != napi_ok ||
315 napi_get_value_double(env, objValue, &targetX) != napi_ok) {
316 TEXT_LOGE("The Parameter of number x about JsPoint is unvaild");
317 return;
318 }
319 point.SetX(targetX);
320 return;
321 }
322
GetPointYFromJsNumber(napi_env env,napi_value argValue,Drawing::Point & point)323 inline void GetPointYFromJsNumber(napi_env env, napi_value argValue, Drawing::Point& point)
324 {
325 napi_value objValue = nullptr;
326 double targetY = 0;
327 if (napi_get_named_property(env, argValue, "y", &objValue) != napi_ok ||
328 napi_get_value_double(env, objValue, &targetY) != napi_ok) {
329 TEXT_LOGE("The Parameter of number y about JsPoint is unvaild");
330 return;
331 }
332 point.SetY(targetY);
333 return;
334 }
335
GetPointFromJsValue(napi_env env,napi_value argValue,Drawing::Point & point)336 inline void GetPointFromJsValue(napi_env env, napi_value argValue, Drawing::Point& point)
337 {
338 GetPointXFromJsNumber(env, argValue, point);
339 GetPointYFromJsNumber(env, argValue, point);
340 return;
341 }
342
343 void BindNativeFunction(napi_env env, napi_value object, const char* name, const char* moduleName, napi_callback func);
344 napi_value CreateJsError(napi_env env, int32_t errCode, const std::string& message);
345
346 napi_value NapiThrowError(napi_env env, TextErrorCode err, const std::string& message);
347
Str8ToStr16(const std::string & str)348 inline std::u16string Str8ToStr16(const std::string &str)
349 {
350 return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(str);
351 }
352
SetDoubleValueFromJS(napi_env env,napi_value argValue,const std::string str,double & cValue)353 inline void SetDoubleValueFromJS(napi_env env, napi_value argValue, const std::string str, double& cValue)
354 {
355 napi_value tempValue = nullptr;
356 napi_get_named_property(env, argValue, str.c_str(), &tempValue);
357 if (tempValue == nullptr) {
358 return;
359 }
360 ConvertFromJsValue(env, tempValue, cValue);
361 }
362
SetBoolValueFromJS(napi_env env,napi_value argValue,const std::string str,bool & cValue)363 inline void SetBoolValueFromJS(napi_env env, napi_value argValue, const std::string str, bool& cValue)
364 {
365 napi_value tempValue = nullptr;
366 napi_get_named_property(env, argValue, str.c_str(), &tempValue);
367 if (tempValue == nullptr) {
368 return;
369 }
370 ConvertFromJsValue(env, tempValue, cValue);
371 }
372
GetPositionWithAffinityAndConvertToJsValue(napi_env env,IndexAndAffinity * positionWithAffinity)373 inline napi_value GetPositionWithAffinityAndConvertToJsValue(napi_env env,
374 IndexAndAffinity* positionWithAffinity)
375 {
376 napi_value objValue = nullptr;
377 napi_create_object(env, &objValue);
378 if (positionWithAffinity != nullptr && objValue != nullptr) {
379 napi_set_named_property(env, objValue, "position", CreateJsNumber(env, positionWithAffinity->index));
380 napi_set_named_property(env, objValue, "affinity", CreateJsNumber(env, (int)positionWithAffinity->affinity));
381 }
382 return objValue;
383 }
384
GetRangeAndConvertToJsValue(napi_env env,Boundary * range)385 inline napi_value GetRangeAndConvertToJsValue(napi_env env, Boundary* range)
386 {
387 napi_value objValue = nullptr;
388 napi_create_object(env, &objValue);
389 if (range != nullptr && objValue != nullptr) {
390 napi_set_named_property(env, objValue, "start", CreateJsNumber(env, range->leftIndex));
391 napi_set_named_property(env, objValue, "end", CreateJsNumber(env, range->rightIndex));
392 }
393 return objValue;
394 }
395
GetRectAndConvertToJsValue(napi_env env,Drawing::Rect rect)396 inline napi_value GetRectAndConvertToJsValue(napi_env env, Drawing::Rect rect)
397 {
398 napi_value objValue = nullptr;
399 napi_create_object(env, &objValue);
400 if (objValue != nullptr) {
401 napi_set_named_property(env, objValue, "left", CreateJsNumber(env, rect.GetLeft()));
402 napi_set_named_property(env, objValue, "top", CreateJsNumber(env, rect.GetTop()));
403 napi_set_named_property(env, objValue, "right", CreateJsNumber(env, rect.GetRight()));
404 napi_set_named_property(env, objValue, "bottom", CreateJsNumber(env, rect.GetBottom()));
405 }
406 return objValue;
407 }
408
CreateTextRectJsValue(napi_env env,TextRect textrect)409 inline napi_value CreateTextRectJsValue(napi_env env, TextRect textrect)
410 {
411 napi_value objValue = nullptr;
412 napi_create_object(env, &objValue);
413 if (objValue != nullptr) {
414 napi_set_named_property(env, objValue, "rect", GetRectAndConvertToJsValue(env, textrect.rect));
415 napi_set_named_property(env, objValue, "direction", CreateJsNumber(env, (int)textrect.direction));
416 }
417 return objValue;
418 }
419
CreateArrayStringJsValue(napi_env env,const std::vector<std::string> & vectorString)420 inline napi_value CreateArrayStringJsValue(napi_env env, const std::vector<std::string>& vectorString)
421 {
422 napi_value jsArray = nullptr;
423 if (napi_create_array_with_length(env, vectorString.size(), &jsArray) == napi_ok) {
424 size_t index = 0;
425 for (const auto& family : vectorString) {
426 napi_value jsString;
427 napi_create_string_utf8(env, family.c_str(), family.length(), &jsString);
428 napi_set_element(env, jsArray, index++, jsString);
429 }
430 }
431 return jsArray;
432 }
433
CreateStringJsValue(napi_env env,std::u16string & u16String)434 inline napi_value CreateStringJsValue(napi_env env, std::u16string& u16String)
435 {
436 napi_value jsStr = nullptr;
437 napi_create_string_utf16(env, reinterpret_cast<const char16_t*>(u16String.c_str()), u16String.length(), &jsStr);
438 return jsStr;
439 }
440
441 napi_value CreateTextStyleJsValue(napi_env env, TextStyle textStyle);
442
443 napi_value CreateFontMetricsJsValue(napi_env env, Drawing::FontMetrics& fontMetrics);
444
CreateRunMetricsJsValue(napi_env env,RunMetrics runMetrics)445 inline napi_value CreateRunMetricsJsValue(napi_env env, RunMetrics runMetrics)
446 {
447 napi_value objValue = nullptr;
448 napi_create_object(env, &objValue);
449 if (objValue != nullptr) {
450 napi_set_named_property(env, objValue, "textStyle", CreateTextStyleJsValue(env, *(runMetrics.textStyle)));
451 napi_set_named_property(env, objValue, "fontMetrics", CreateFontMetricsJsValue(env, runMetrics.fontMetrics));
452 }
453 return objValue;
454 }
455
456 napi_value ConvertMapToNapiMap(napi_env env, const std::map<size_t, RunMetrics>& map);
457
458 napi_value CreateLineMetricsJsValue(napi_env env, OHOS::Rosen::LineMetrics& lineMetrics);
459
SetFontMetricsFloatValueFromJS(napi_env env,napi_value argValue,const std::string & str,float & cValue)460 inline void SetFontMetricsFloatValueFromJS(napi_env env, napi_value argValue, const std::string& str, float& cValue)
461 {
462 napi_value tempValue = nullptr;
463 napi_get_named_property(env, argValue, str.c_str(), &tempValue);
464 if (tempValue == nullptr) {
465 return;
466 }
467 double tempValuechild = 0.0;
468
469 ConvertFromJsValue(env, tempValue, tempValuechild);
470 cValue = static_cast<float>(tempValuechild);
471 }
472
SetLineMetricsDoubleValueFromJS(napi_env env,napi_value argValue,const std::string str,double & cValue)473 inline void SetLineMetricsDoubleValueFromJS(napi_env env, napi_value argValue, const std::string str, double& cValue)
474 {
475 napi_value tempValue = nullptr;
476 napi_get_named_property(env, argValue, str.c_str(), &tempValue);
477 if (tempValue == nullptr) {
478 return;
479 }
480 ConvertFromJsValue(env, tempValue, cValue);
481 }
482
SetLineMetricsSizeTValueFromJS(napi_env env,napi_value argValue,const std::string str,size_t & cValue)483 inline void SetLineMetricsSizeTValueFromJS(napi_env env, napi_value argValue, const std::string str, size_t& cValue)
484 {
485 napi_value tempValue = nullptr;
486 napi_get_named_property(env, argValue, str.c_str(), &tempValue);
487 if (tempValue == nullptr) {
488 return;
489 }
490
491 uint32_t tempValuechild = 0;
492 ConvertFromJsValue(env, tempValue, tempValuechild);
493 cValue = static_cast<size_t>(tempValuechild);
494 }
495
496 bool OnMakeFontFamilies(napi_env& env, napi_value jsValue, std::vector<std::string> &fontFamilies);
497
498 bool SetColorFromJS(napi_env env, napi_value argValue, const std::string& str, Drawing::Color& colorSrc);
499
500 bool GetDecorationFromJS(napi_env env, napi_value argValue, TextStyle& textStyle);
501
502 bool GetTextStyleFromJS(napi_env env, napi_value argValue, TextStyle& textStyle);
503
504 bool GetParagraphStyleFromJS(napi_env env, napi_value argValue, TypographyStyle& pographyStyle);
505
506 bool GetPlaceholderSpanFromJS(napi_env env, napi_value argValue, PlaceholderSpan& placeholderSpan);
507
508 void ParsePartTextStyle(napi_env env, napi_value argValue, TextStyle& textStyle);
509
510 void SetTextStyleBaseType(napi_env env, napi_value argValue, TextStyle& textStyle);
511
512 void ReceiveFontFeature(napi_env env, napi_value argValue, TextStyle& textStyle);
513
514 void ReceiveFontVariation(napi_env env, napi_value argValue, TextStyle& textStyle);
515
516 size_t GetParamLen(napi_env env, napi_value param);
517
518 bool GetFontMetricsFromJS(napi_env env, napi_value argValue, Drawing::FontMetrics& fontMetrics);
519
520 bool GetRunMetricsFromJS(napi_env env, napi_value argValue, RunMetrics& runMetrics);
521
522 bool GetNamePropertyFromJS(napi_env env, napi_value argValue, const std::string& str, napi_value& propertyValue);
523
524 template<class Type>
SetEnumValueFromJS(napi_env env,napi_value argValue,const std::string str,Type & typeValue)525 void SetEnumValueFromJS(napi_env env, napi_value argValue, const std::string str, Type& typeValue)
526 {
527 napi_value propertyValue = nullptr;
528 if (!GetNamePropertyFromJS(env, argValue, str, propertyValue)) {
529 return;
530 }
531
532 ConvertFromJsValue(env, propertyValue, typeValue);
533 }
534
535 void ScanShadowValue(napi_env env, napi_value allShadowValue, uint32_t arrayLength, TextStyle& textStyle);
536
537 void SetTextShadowProperty(napi_env env, napi_value argValue, TextStyle& textStyle);
538
539 bool SetStrutStyleFromJS(napi_env env, napi_value strutStyleValue, TypographyStyle& typographyStyle);
540
541 void SetRectStyleFromJS(napi_env env, napi_value argValue, RectStyle& rectStyle);
542 } // namespace OHOS::Rosen
543 #endif // OHOS_JS_TEXT_UTILS_H