1 /*
2 * Copyright (c) 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 #include <optional>
17 #include <string>
18
19 #include "interfaces/napi/kits/utils/napi_utils.h"
20 #include "js_native_api.h"
21 #include "js_native_api_types.h"
22 #include "napi/native_api.h"
23 #include "napi/native_engine/native_value.h"
24 #include "napi/native_node_api.h"
25
26 #include "base/geometry/dimension.h"
27 #include "base/geometry/size.h"
28 #include "bridge/common/utils/engine_helper.h"
29 #include "bridge/js_frontend/engine/common/js_engine.h"
30 #include "core/components/common/layout/constants.h"
31 #include "core/components/common/properties/text_style.h"
32 #include "frameworks/base/utils/measure_util.h"
33
34 namespace OHOS::Ace::Napi {
HandleIntStyle(napi_value fontStyleNApi,napi_env env)35 static int32_t HandleIntStyle(napi_value fontStyleNApi, napi_env env)
36 {
37 size_t ret = 0;
38 int32_t fontStyleInt = 0;
39 std::string fontStyleStr;
40 napi_valuetype valueType = napi_undefined;
41 napi_typeof(env, fontStyleNApi, &valueType);
42 if (valueType == napi_string) {
43 size_t fontStyleLen = GetParamLen(fontStyleNApi) + 1;
44 std::unique_ptr<char[]> fontStyleTemp = std::make_unique<char[]>(fontStyleLen);
45 napi_get_value_string_utf8(env, fontStyleNApi, fontStyleTemp.get(), fontStyleLen, &ret);
46 fontStyleStr = fontStyleTemp.get();
47 fontStyleInt = StringUtils::StringToInt(fontStyleStr);
48 } else if (valueType == napi_number) {
49 napi_get_value_int32(env, fontStyleNApi, &fontStyleInt);
50 } else if (valueType == napi_object) {
51 ResourceInfo recv;
52 if (!ParseResourceParam(env, fontStyleNApi, recv)) {
53 LOGE("can not parse resource info from inout params.");
54 return fontStyleInt;
55 }
56 if (!ParseString(recv, fontStyleStr)) {
57 LOGE("can not get message from resource manager.");
58 return fontStyleInt;
59 }
60 fontStyleInt = StringUtils::StringToInt(fontStyleStr);
61 } else {
62 LOGE("The parameter type is incorrect.");
63 return fontStyleInt;
64 }
65 return fontStyleInt;
66 }
67
HandleStringType(napi_value ParameterNApi,napi_env env)68 static std::string HandleStringType(napi_value ParameterNApi, napi_env env)
69 {
70 size_t ret = 0;
71 std::string ParameterStr;
72 int32_t ParameterInt = 0;
73 napi_valuetype valueType = napi_undefined;
74 napi_typeof(env, ParameterNApi, &valueType);
75 if (valueType == napi_string) {
76 size_t ParameterLen = GetParamLen(ParameterNApi) + 1;
77 std::unique_ptr<char[]> Parameter = std::make_unique<char[]>(ParameterLen);
78 napi_get_value_string_utf8(env, ParameterNApi, Parameter.get(), ParameterLen, &ret);
79 ParameterStr = Parameter.get();
80 } else if (valueType == napi_number) {
81 napi_get_value_int32(env, ParameterNApi, &ParameterInt);
82 ParameterStr = std::to_string(ParameterInt);
83 } else if (valueType == napi_object) {
84 ResourceInfo recv;
85 if (!ParseResourceParam(env, ParameterNApi, recv)) {
86 LOGE("can not parse resource info from inout params.");
87 return ParameterStr;
88 }
89 if (!ParseString(recv, ParameterStr)) {
90 LOGE("can not get message from resource manager.");
91 return ParameterStr;
92 }
93 } else {
94 LOGE("The parameter type is incorrect.");
95 return ParameterStr;
96 }
97 return ParameterStr;
98 }
99
HandleDimensionType(napi_value ParameterNApi,napi_env env)100 static std::optional<Dimension> HandleDimensionType(napi_value ParameterNApi, napi_env env)
101 {
102 size_t ret = 0;
103 std::string ParameterStr;
104 napi_valuetype valueType = napi_undefined;
105 napi_typeof(env, ParameterNApi, &valueType);
106 Dimension Parameter;
107 if (valueType == napi_number) {
108 double ParameterValue;
109 napi_get_value_double(env, ParameterNApi, &ParameterValue);
110 Parameter.SetValue(ParameterValue);
111 Parameter.SetUnit(DimensionUnit::VP);
112 } else if (valueType == napi_string) {
113 size_t ParameterLen = GetParamLen(ParameterNApi) + 1;
114 std::unique_ptr<char[]> ParameterTemp = std::make_unique<char[]>(ParameterLen);
115 napi_get_value_string_utf8(env, ParameterNApi, ParameterTemp.get(), ParameterLen, &ret);
116 ParameterStr = ParameterTemp.get();
117 Parameter = StringUtils::StringToDimensionWithUnit(ParameterStr, DimensionUnit::VP);
118 } else if (valueType == napi_object) {
119 ResourceInfo recv;
120 if (!ParseResourceParam(env, ParameterNApi, recv)) {
121 LOGE("can not parse resource info from inout params.");
122 return std::nullopt;
123 }
124 if (!ParseString(recv, ParameterStr)) {
125 LOGE("can not get message from resource manager.");
126 return std::nullopt;
127 }
128 Parameter = StringUtils::StringToDimensionWithUnit(ParameterStr, DimensionUnit::VP);
129 } else {
130 return std::nullopt;
131 }
132 return Parameter;
133 }
134
JSMeasureText(napi_env env,napi_callback_info info)135 static napi_value JSMeasureText(napi_env env, napi_callback_info info)
136 {
137 size_t argc = 1;
138 napi_value result = nullptr;
139 napi_value argv = nullptr;
140 napi_value thisvar = nullptr;
141 void* data = nullptr;
142 napi_get_cb_info(env, info, &argc, &argv, &thisvar, &data);
143
144 napi_value textContentNApi = nullptr;
145 napi_value fontSizeNApi = nullptr;
146 napi_value fontStyleNApi = nullptr;
147 napi_value fontWeightNApi = nullptr;
148 napi_value fontFamilyNApi = nullptr;
149 napi_value letterSpacingNApi = nullptr;
150
151 napi_valuetype valueType = napi_undefined;
152 napi_typeof(env, argv, &valueType);
153 if (valueType == napi_object) {
154 napi_get_named_property(env, argv, "textContent", &textContentNApi);
155 napi_get_named_property(env, argv, "fontSize", &fontSizeNApi);
156 napi_get_named_property(env, argv, "fontStyle", &fontStyleNApi);
157 napi_get_named_property(env, argv, "fontWeight", &fontWeightNApi);
158 napi_get_named_property(env, argv, "fontFamily", &fontFamilyNApi);
159 napi_get_named_property(env, argv, "letterSpacing", &letterSpacingNApi);
160 } else {
161 return nullptr;
162 }
163 std::optional<Dimension> fontSizeNum = HandleDimensionType(fontSizeNApi, env);
164 std::optional<Dimension> letterSpace = HandleDimensionType(letterSpacingNApi, env);
165 int32_t fontStyle = HandleIntStyle(fontStyleNApi, env);
166 std::string textContent = HandleStringType(textContentNApi, env);
167 std::string fontWeight = HandleStringType(fontWeightNApi, env);
168 std::string fontFamily = HandleStringType(fontFamilyNApi, env);
169 MeasureContext context;
170 context.textContent = textContent;
171 context.fontSize = fontSizeNum;
172 context.fontStyle = static_cast<FontStyle>(fontStyle);
173 context.fontWeight = fontWeight;
174 context.fontFamily = fontFamily;
175 context.letterSpacing = letterSpace;
176 auto delegate = EngineHelper::GetCurrentDelegate();
177 if (!delegate) {
178 return nullptr;
179 }
180 double textWidth = delegate->MeasureText(context);
181 napi_create_double(env, textWidth, &result);
182 return result;
183 }
184
JSMeasureTextSize(napi_env env,napi_callback_info info)185 static napi_value JSMeasureTextSize(napi_env env, napi_callback_info info)
186 {
187 size_t argc = 1;
188 napi_value result = nullptr;
189 napi_value argv = nullptr;
190 napi_value thisvar = nullptr;
191 void* data = nullptr;
192 napi_get_cb_info(env, info, &argc, &argv, &thisvar, &data);
193
194 napi_value textContentNApi = nullptr;
195 napi_value constraintWidthNApi = nullptr;
196 napi_value fontSizeNApi = nullptr;
197 napi_value fontStyleNApi = nullptr;
198 napi_value fontWeightNApi = nullptr;
199 napi_value fontFamilyNApi = nullptr;
200 napi_value letterSpacingNApi = nullptr;
201 napi_value textAlignNApi = nullptr;
202 napi_value textOverFlowNApi = nullptr;
203 napi_value maxLinesNApi = nullptr;
204 napi_value lineHeightNApi = nullptr;
205 napi_value baselineOffsetNApi = nullptr;
206 napi_value textCaseNApi = nullptr;
207
208 napi_valuetype valueType = napi_undefined;
209 napi_typeof(env, argv, &valueType);
210 MeasureContext context;
211 if (valueType == napi_object) {
212 napi_get_named_property(env, argv, "textContent", &textContentNApi);
213 napi_get_named_property(env, argv, "constraintWidth", &constraintWidthNApi);
214 napi_get_named_property(env, argv, "fontSize", &fontSizeNApi);
215 napi_get_named_property(env, argv, "fontStyle", &fontStyleNApi);
216 napi_get_named_property(env, argv, "fontWeight", &fontWeightNApi);
217 napi_get_named_property(env, argv, "fontFamily", &fontFamilyNApi);
218 napi_get_named_property(env, argv, "letterSpacing", &letterSpacingNApi);
219 napi_get_named_property(env, argv, "textAlign", &textAlignNApi);
220 napi_get_named_property(env, argv, "overflow", &textOverFlowNApi);
221 napi_get_named_property(env, argv, "maxLines", &maxLinesNApi);
222 napi_get_named_property(env, argv, "lineHeight", &lineHeightNApi);
223 napi_get_named_property(env, argv, "baselineOffset", &baselineOffsetNApi);
224 napi_get_named_property(env, argv, "textCase", &textCaseNApi);
225 } else {
226 return nullptr;
227 }
228 std::optional<Dimension> fontSizeNum = HandleDimensionType(fontSizeNApi, env);
229 std::optional<Dimension> letterSpace = HandleDimensionType(letterSpacingNApi, env);
230 std::optional<Dimension> constraintWidth = HandleDimensionType(constraintWidthNApi, env);
231 std::optional<Dimension> lineHeight = HandleDimensionType(lineHeightNApi, env);
232 std::optional<Dimension> baselineOffset = HandleDimensionType(baselineOffsetNApi, env);
233 int32_t fontStyle = HandleIntStyle(fontStyleNApi, env);
234 int32_t textAlign = HandleIntStyle(textAlignNApi, env);
235 int32_t textOverFlow = HandleIntStyle(textOverFlowNApi, env);
236 int32_t maxlines = HandleIntStyle(maxLinesNApi, env);
237 int32_t textCase = HandleIntStyle(textCaseNApi, env);
238 std::string textContent = HandleStringType(textContentNApi, env);
239 std::string fontWeight = HandleStringType(fontWeightNApi, env);
240 std::string fontFamily = HandleStringType(fontFamilyNApi, env);
241 context.textContent = textContent;
242 context.constraintWidth = constraintWidth;
243 context.fontSize = fontSizeNum;
244 context.fontStyle = static_cast<FontStyle>(fontStyle);
245 context.fontWeight = fontWeight;
246 context.fontFamily = fontFamily;
247 context.letterSpacing = letterSpace;
248 context.textAlign = static_cast<TextAlign>(textAlign);
249 context.textOverlayFlow = static_cast<TextOverflow>(textOverFlow);
250 context.maxlines = maxlines;
251 context.lineHeight = lineHeight;
252 context.baselineOffset = baselineOffset;
253 context.textCase = static_cast<TextCase>(textCase);
254 auto delegate = EngineHelper::GetCurrentDelegate();
255 if (!delegate) {
256 return nullptr;
257 }
258 Size textSize = delegate->MeasureTextSize(context);
259
260 napi_escapable_handle_scope scope = nullptr;
261 napi_open_escapable_handle_scope(env, &scope);
262 if (scope == nullptr) {
263 return result;
264 }
265
266 napi_value resultArray[2] = { 0 };
267 napi_create_double(env, textSize.Width(), &resultArray[0]);
268 napi_create_double(env, textSize.Height(), &resultArray[1]);
269
270 napi_create_object(env, &result);
271 napi_set_named_property(env, result, "width", resultArray[0]);
272 napi_set_named_property(env, result, "height", resultArray[1]);
273
274 napi_value newResult = nullptr;
275 napi_escape_handle(env, scope, result, &newResult);
276 napi_close_escapable_handle_scope(env, scope);
277 return result;
278 }
279
MeasureExport(napi_env env,napi_value exports)280 static napi_value MeasureExport(napi_env env, napi_value exports)
281 {
282 napi_property_descriptor measureDesc[] = {
283 DECLARE_NAPI_FUNCTION("measureText", JSMeasureText),
284 DECLARE_NAPI_FUNCTION("measureTextSize", JSMeasureTextSize),
285 };
286 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(measureDesc) / sizeof(measureDesc[0]), measureDesc));
287 return exports;
288 }
289
290 static napi_module measureModule = {
291 .nm_version = 1,
292 .nm_flags = 0,
293 .nm_filename = nullptr,
294 .nm_register_func = MeasureExport,
295 .nm_modname = "measure",
296 .nm_priv = ((void*)0),
297 .reserved = { 0 },
298 };
299
MeasureRegister()300 extern "C" __attribute__((constructor)) void MeasureRegister()
301 {
302 napi_module_register(&measureModule);
303 }
304 } // namespace OHOS::Ace::Napi
305