• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "styled_number_format_addon.h"
17 
18 #include "error_util.h"
19 #include "i18n_hilog.h"
20 #include "variable_convertor.h"
21 
22 namespace OHOS {
23 namespace Global {
24 namespace I18n {
StyledNumberFormatAddon()25 StyledNumberFormatAddon::StyledNumberFormatAddon()
26 {
27 }
28 
~StyledNumberFormatAddon()29 StyledNumberFormatAddon::~StyledNumberFormatAddon()
30 {
31     for (auto iter = styledNumberFormatOptions_.begin(); iter != styledNumberFormatOptions_.end(); ++iter) {
32         napi_delete_reference(env_, iter->second);
33     }
34 }
35 
Destructor(napi_env env,void * nativeObject,void * hint)36 void StyledNumberFormatAddon::Destructor(napi_env env, void *nativeObject, void *hint)
37 {
38     if (!nativeObject) {
39         return;
40     }
41     delete reinterpret_cast<StyledNumberFormatAddon *>(nativeObject);
42     nativeObject = nullptr;
43 }
44 
InitStyledNumberFormat(napi_env env,napi_value exports)45 napi_value StyledNumberFormatAddon::InitStyledNumberFormat(napi_env env, napi_value exports)
46 {
47     napi_property_descriptor properties[] = {
48         DECLARE_NAPI_FUNCTION("format", Format)
49     };
50     napi_value styledNumberFormatConstructor = nullptr;
51     napi_status status = napi_define_class(env, "StyledNumberFormat", NAPI_AUTO_LENGTH, constructor, nullptr,
52         sizeof(properties) / sizeof(napi_property_descriptor), properties, &styledNumberFormatConstructor);
53     if (status != napi_ok) {
54         HILOG_ERROR_I18N("Failed to define class StyledNumberFormat at Init.");
55         return nullptr;
56     }
57     status = napi_set_named_property(env, exports, "StyledNumberFormat", styledNumberFormatConstructor);
58     if (status != napi_ok) {
59         HILOG_ERROR_I18N("Set property failed when InitStyledNumberFormat");
60         return nullptr;
61     }
62     return exports;
63 }
64 
constructor(napi_env env,napi_callback_info info)65 napi_value StyledNumberFormatAddon::constructor(napi_env env, napi_callback_info info)
66 {
67     size_t argc = 2;
68     napi_value argv[2] = { nullptr };
69     napi_value thisVar = nullptr;
70     void *data = nullptr;
71     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
72     if (status != napi_ok) {
73         HILOG_ERROR_I18N("StyledNumberFormatAddon::constructor get callback info error");
74         return nullptr;
75     }
76 
77     if (argc < 1) {
78         ErrorUtil::NapiNotFoundError(env, I18N_NOT_FOUND, "numberFormat", true);
79         return nullptr;
80     }
81 
82     NumberFormatAddon *numberFormatAddon = nullptr;
83     SimpleNumberFormatAddon *simpleNumberFormatAddon = nullptr;
84 
85     GetNumberFmtOrSimpleNumberFmt(env, argv[0], &numberFormatAddon, &simpleNumberFormatAddon);
86 
87     if (!numberFormatAddon && !simpleNumberFormatAddon) {
88         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "numberFormat", "intl.NumberFormat or SimpleNumberFormat", true);
89         return nullptr;
90     }
91 
92     std::unique_ptr<StyledNumberFormatAddon> obj = std::make_unique<StyledNumberFormatAddon>();
93     if (!obj) {
94         HILOG_ERROR_I18N("StyledNumberFormatAddon::constructor make unique ptr error");
95         return nullptr;
96     }
97     status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), Destructor, nullptr, nullptr);
98     if (status != napi_ok) {
99         HILOG_ERROR_I18N("StyledNumberFormatAddon::constructor napi_wrap error");
100         return nullptr;
101     }
102     if (!obj->InitStyledNumberFormatContent(env, numberFormatAddon, simpleNumberFormatAddon, argv[1])) {
103         return nullptr;
104     }
105     obj.release();
106     return thisVar;
107 }
108 
Format(napi_env env,napi_callback_info info)109 napi_value StyledNumberFormatAddon::Format(napi_env env, napi_callback_info info)
110 {
111     size_t argc = 1;
112     napi_value argv[1] = { 0 };
113     napi_value thisVar = nullptr;
114     void *data = nullptr;
115     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
116     if (status != napi_ok) {
117         HILOG_ERROR_I18N("StyledNumberFormatAddon::Format: Get cb info failed.");
118         return VariableConvertor::CreateString(env, "");
119     } else if (argc < 1) {
120         ErrorUtil::NapiNotFoundError(env, I18N_NOT_FOUND, "value", true);
121         return VariableConvertor::CreateString(env, "");
122     }
123 
124     napi_valuetype valueType = napi_valuetype::napi_undefined;
125     status = napi_typeof(env, argv[0], &valueType);
126     if (status != napi_ok) {
127         HILOG_ERROR_I18N("StyledNumberFormatAddon::Format: Failed to get type of argv[0].");
128         return VariableConvertor::CreateString(env, "");
129     } else if (valueType != napi_valuetype::napi_number) {
130         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "value", "number", true);
131         return VariableConvertor::CreateString(env, "");
132     }
133 
134     double number = 0;
135     napi_get_value_double(env, argv[0], &number);
136     StyledNumberFormatAddon *obj = nullptr;
137     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
138     if (status != napi_ok || !obj || !obj->styledNumberFormat_) {
139         HILOG_ERROR_I18N("Format: Get StyledNumberFormat object failed");
140         return VariableConvertor::CreateString(env, "");
141     }
142 
143     std::string formattedNumber = obj->styledNumberFormat_->Format(number);
144     std::vector<StyledNumberFormat::NumberPart> numberParts = obj->styledNumberFormat_->ParseToParts(number);
145 
146     napi_value styleOption = CreateStyleOptions(env, numberParts, obj->styledNumberFormatOptions_);
147 
148     napi_value styledString = CreateStyledString(env, formattedNumber, styleOption);
149     return styledString;
150 }
151 
InitStyledNumberFormatContent(napi_env env,NumberFormatAddon * numberFormatAddon,SimpleNumberFormatAddon * simpleNumberFormatAddon,napi_value options)152 bool StyledNumberFormatAddon::InitStyledNumberFormatContent(napi_env env, NumberFormatAddon* numberFormatAddon,
153     SimpleNumberFormatAddon* simpleNumberFormatAddon, napi_value options)
154 {
155     if (numberFormatAddon) {
156         styledNumberFormat_ =
157             std::make_unique<StyledNumberFormat>(true, numberFormatAddon->CopyNumberFormat(), nullptr);
158     } else if (simpleNumberFormatAddon) {
159         styledNumberFormat_ =
160             std::make_unique<StyledNumberFormat>(false, nullptr, simpleNumberFormatAddon->CopySimpleNumberFormat());
161     }
162 
163     if (options) {
164         SetTextStyle(env, options, "integer");
165         SetTextStyle(env, options, "decimal");
166         SetTextStyle(env, options, "fraction");
167         SetTextStyle(env, options, "unit");
168     }
169 
170     env_ = env;
171     return styledNumberFormat_ != nullptr;
172 }
173 
SetTextStyle(napi_env env,napi_value options,const std::string & optionName)174 void StyledNumberFormatAddon::SetTextStyle(napi_env env, napi_value options, const std::string &optionName)
175 {
176     napi_value optionValue = nullptr;
177     napi_valuetype type = napi_undefined;
178     napi_status status = napi_typeof(env, options, &type);
179     if (status != napi_ok && type != napi_object) {
180         HILOG_ERROR_I18N("setTextStyle: option is not an object");
181         return;
182     }
183     bool hasProperty = false;
184     status = napi_has_named_property(env, options, optionName.c_str(), &hasProperty);
185     if (status != napi_ok || !hasProperty) {
186         HILOG_ERROR_I18N("setTextStyle: Has not named %{public}s property", optionName.c_str());
187         return;
188     }
189     status = napi_get_named_property(env, options, optionName.c_str(), &optionValue);
190     if (status != napi_ok) {
191         HILOG_ERROR_I18N("setTextStyle: Get named property for %{public}s failed.", optionName.c_str());
192         return;
193     }
194 
195     styledNumberFormatOptions_[optionName] = nullptr;
196     if (!optionValue) {
197         HILOG_ERROR_I18N("setTextStyle: %{public}s is nullptr.", optionName.c_str());
198         return;
199     }
200     status = napi_create_reference(env, optionValue, 1, &styledNumberFormatOptions_[optionName]);
201     if (status != napi_ok) {
202         HILOG_ERROR_I18N("setTextStyle: create reference for %{public}s failed.", optionName.c_str());
203         styledNumberFormatOptions_[optionName] = nullptr;
204         return;
205     }
206 }
207 
CreateStyledString(napi_env env,const std::string & formattedNumber,napi_value styleOption)208 napi_value StyledNumberFormatAddon::CreateStyledString(napi_env env, const std::string &formattedNumber,
209     napi_value styleOption)
210 {
211     size_t argc = 2;    // StyledString need 2 args
212     napi_value argv[2] = {nullptr};
213     argv[0] = VariableConvertor::CreateString(env, formattedNumber);
214     argv[1] = styleOption;
215 
216     napi_value global = nullptr;
217     napi_status status = napi_get_global(env, &global);
218     if (status != napi_ok) {
219         HILOG_ERROR_I18N("CreateStyledString: get global object failed");
220         return nullptr;
221     }
222     napi_value constructor = nullptr;
223     status = napi_get_named_property(env, global, "StyledString", &constructor);
224     if (status != napi_ok) {
225         HILOG_ERROR_I18N("CreateStyledString: get StyledString failed");
226         return nullptr;
227     }
228 
229     napi_value styleString = nullptr;
230     status = napi_new_instance(env, constructor, argc, argv, &styleString);
231     if (status != napi_ok) {
232         HILOG_ERROR_I18N("CreateStyledString: napi_new_instance failed");
233         return nullptr;
234     }
235     return styleString;
236 }
237 
CreateStyleOptions(napi_env env,const std::vector<StyledNumberFormat::NumberPart> & numberParts,const std::unordered_map<std::string,napi_ref> & styledNumberFormatOptions)238 napi_value StyledNumberFormatAddon::CreateStyleOptions(napi_env env,
239     const std::vector<StyledNumberFormat::NumberPart> &numberParts,
240     const std::unordered_map<std::string, napi_ref> &styledNumberFormatOptions)
241 {
242     napi_value result = nullptr;
243     napi_status status = napi_create_array(env, &result);
244     if (status != napi_ok) {
245         HILOG_ERROR_I18N("CreateStyleOption: create array failed");
246         return nullptr;
247     }
248 
249     unsigned int index = 0;
250     for (size_t i = 0; i < numberParts.size(); ++i) {
251         auto iter = styledNumberFormatOptions.find(numberParts[i].part_name);
252         if (iter == styledNumberFormatOptions.end()) {
253             continue;
254         }
255         napi_ref textStyleRef = iter->second;
256         napi_value option = CreateStyleOption(env, numberParts[i], textStyleRef);
257         status = napi_set_element(env, result, index, option);
258         if (status != napi_ok) {
259             HILOG_ERROR_I18N("CreateStyleoption: set array %{public}u failed", index);
260             return nullptr;
261         }
262         index += 1;
263     }
264     return result;
265 }
266 
CreateStyleOption(napi_env env,StyledNumberFormat::NumberPart numberPart,napi_ref textStyleRef)267 napi_value StyledNumberFormatAddon::CreateStyleOption(napi_env env,
268     StyledNumberFormat::NumberPart numberPart, napi_ref textStyleRef)
269 {
270     if (!textStyleRef) {
271         HILOG_ERROR_I18N("CreateStyleoption: options do not have %{public}s",
272             numberPart.part_name.c_str());
273         return nullptr;
274     }
275     napi_value textStyle = nullptr;
276     napi_status status = napi_get_reference_value(env, textStyleRef, &textStyle);
277     if (status != napi_ok) {
278         HILOG_ERROR_I18N("CreateStyleoption: Failed to create reference at textStyle %{public}s",
279             numberPart.part_name.c_str());
280         return nullptr;
281     }
282     napi_value option = nullptr;
283     status = napi_create_object(env, &option);
284     if (status != napi_ok) {
285         HILOG_ERROR_I18N("CreateStyleoption: create object failed");
286         return nullptr;
287     }
288     napi_value start = nullptr;
289     status = napi_create_int32(env, numberPart.start, &start);
290     if (status != napi_ok) {
291         HILOG_ERROR_I18N("CreateStyleoption: create int32 failed");
292         return nullptr;
293     }
294     napi_value length = nullptr;
295     status = napi_create_int32(env, numberPart.length, &length);
296     if (status != napi_ok) {
297         HILOG_ERROR_I18N("CreateStyleoption: create int32 failed");
298         return nullptr;
299     }
300     napi_value styledKey = nullptr;
301     status = napi_create_int32(env, 0, &styledKey);
302     if (status != napi_ok) {
303         HILOG_ERROR_I18N("CreateStyleoption: create int32 failed");
304         return nullptr;
305     }
306     SetNamedProperty(env, option, "start", start);
307     SetNamedProperty(env, option, "length", length);
308     SetNamedProperty(env, option, "styledKey", styledKey);
309     SetNamedProperty(env, option, "styledValue", textStyle);
310     return option;
311 }
312 
SetNamedProperty(napi_env env,napi_value & option,const std::string & name,napi_value & property)313 void StyledNumberFormatAddon::SetNamedProperty(napi_env env, napi_value &option, const std::string& name,
314     napi_value &property)
315 {
316     napi_status status = napi_set_named_property(env, option, name.c_str(), property);
317     if (status != napi_ok) {
318         HILOG_ERROR_I18N("CreateStyleoption: set property %{public}s failed", name.c_str());
319     }
320 }
321 
GetNumberFmtOrSimpleNumberFmt(napi_env env,napi_value arg,NumberFormatAddon ** numberFormatAddon,SimpleNumberFormatAddon ** simpleNumberFormatAddon)322 void StyledNumberFormatAddon::GetNumberFmtOrSimpleNumberFmt(napi_env env, napi_value arg,
323     NumberFormatAddon **numberFormatAddon, SimpleNumberFormatAddon **simpleNumberFormatAddon)
324 {
325     napi_valuetype valueType = napi_valuetype::napi_undefined;
326     napi_status status = napi_typeof(env, arg, &valueType);
327     if (status != napi_ok) {
328         HILOG_ERROR_I18N("StyledNumberFormatAddon::constructor Failed to get type.");
329         return;
330     } else if (valueType != napi_valuetype::napi_object) {
331         ErrorUtil::NapiThrow(env, I18N_NOT_FOUND, "intl.NumberFormat or SimpleNumberFormat", "", true);
332         return;
333     }
334 
335     napi_value numFmtConstructor = nullptr;
336     napi_value intlModule;
337     status = napi_load_module(env, "@ohos.intl", &intlModule);
338     if (status != napi_ok) {
339         HILOG_ERROR_I18N("StyledNumberFormatAddon::constructor Failed to get intl module.");
340         return;
341     }
342     status = napi_get_named_property(env, intlModule, "NumberFormat", &numFmtConstructor);
343     if (status != napi_ok) {
344         HILOG_ERROR_I18N("StyledNumberFormatAddon::constructo: get NumberFormat  constructor failed");
345         return;
346     }
347 
348     bool isNumberFormat = true;
349     status = napi_instanceof(env, arg, numFmtConstructor, &isNumberFormat);
350     if (status != napi_ok) {
351         HILOG_ERROR_I18N("StyledNumberFormatAddon::constructor Failed to get instance of argv 0.");
352         return;
353     }
354     if (isNumberFormat) {
355         status = napi_unwrap(env, arg, reinterpret_cast<void **>(numberFormatAddon));
356         if (status != napi_ok) {
357             *numberFormatAddon = nullptr;
358         }
359     } else {
360         status = napi_unwrap(env, arg, reinterpret_cast<void **>(simpleNumberFormatAddon));
361         if (status != napi_ok) {
362             *simpleNumberFormatAddon = nullptr;
363         }
364     }
365 }
366 } // namespace I18n
367 } // namespace Global
368 } // namespace OHOS