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