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 "js_run.h"
17 #include "napi_common.h"
18 #include "utils/text_log.h"
19 #include "canvas_napi/js_canvas.h"
20 #include "font_napi/js_font.h"
21 #include "recording/recording_canvas.h"
22 #include "typography_types.h"
23
24 namespace OHOS::Rosen {
25 std::mutex JsRun::constructorMutex_;
26 thread_local napi_ref JsRun::constructor_ = nullptr;
27 const std::string CLASS_NAME = "Run";
Constructor(napi_env env,napi_callback_info info)28 napi_value JsRun::Constructor(napi_env env, napi_callback_info info)
29 {
30 size_t argCount = 0;
31 napi_value jsThis = nullptr;
32 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
33 if (status != napi_ok) {
34 TEXT_LOGE("Failed to get parameter, ret %{public}d", status);
35 return nullptr;
36 }
37
38 JsRun* jsRun = new(std::nothrow) JsRun();
39 if (!jsRun) {
40 TEXT_LOGE("Failed to new run");
41 return nullptr;
42 }
43
44 status = napi_wrap(env, jsThis, jsRun,
45 JsRun::Destructor, nullptr, nullptr);
46 if (status != napi_ok) {
47 delete jsRun;
48 TEXT_LOGE("Failed to wrap run, ret %{public}d", status);
49 return nullptr;
50 }
51
52 return jsThis;
53 }
54
Init(napi_env env,napi_value exportObj)55 napi_value JsRun::Init(napi_env env, napi_value exportObj)
56 {
57 if (!CreateConstructor(env)) {
58 TEXT_LOGE("Failed to create constructor");
59 return nullptr;
60 }
61 napi_value constructor = nullptr;
62 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
63 if (status != napi_ok) {
64 TEXT_LOGE("Failed to get reference, ret %{public}d", status);
65 return nullptr;
66 }
67
68 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
69 if (status != napi_ok) {
70 TEXT_LOGE("Failed to set named property, ret %{public}d", status);
71 return nullptr;
72 }
73
74 return exportObj;
75 }
76
CreateConstructor(napi_env env)77 bool JsRun::CreateConstructor(napi_env env)
78 {
79 std::lock_guard<std::mutex> lock(constructorMutex_);
80 if (constructor_) {
81 return true;
82 }
83 napi_property_descriptor properties[] = {
84 DECLARE_NAPI_FUNCTION("getGlyphCount", JsRun::GetGlyphCount),
85 DECLARE_NAPI_FUNCTION("getGlyphs", JsRun::GetGlyphs),
86 DECLARE_NAPI_FUNCTION("getPositions", JsRun::GetPositions),
87 DECLARE_NAPI_FUNCTION("getOffsets", JsRun::GetOffsets),
88 DECLARE_NAPI_FUNCTION("getFont", JsRun::GetFont),
89 DECLARE_NAPI_FUNCTION("getStringRange", JsRun::GetStringRange),
90 DECLARE_NAPI_FUNCTION("getStringIndices", JsRun::GetStringIndices),
91 DECLARE_NAPI_FUNCTION("getImageBounds", JsRun::GetImageBounds),
92 DECLARE_NAPI_FUNCTION("getTypographicBounds", JsRun::GetTypographicBounds),
93 DECLARE_NAPI_FUNCTION("paint", JsRun::Paint),
94 DECLARE_NAPI_FUNCTION("getTextDirection", JsRun::GetTextDirection),
95 DECLARE_NAPI_FUNCTION("getAdvances", JsRun::GetAdvances),
96 };
97
98 napi_value constructor = nullptr;
99 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
100 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
101 if (status != napi_ok) {
102 TEXT_LOGE("Failed to define class, ret %{public}d", status);
103 return false;
104 }
105
106 status = napi_create_reference(env, constructor, 1, &constructor_);
107 if (status != napi_ok) {
108 TEXT_LOGE("Failed to create reference, ret %{public}d", status);
109 return false;
110 }
111 return true;
112 }
113
Destructor(napi_env env,void * nativeObject,void * finalize)114 void JsRun::Destructor(napi_env env, void* nativeObject, void* finalize)
115 {
116 (void)finalize;
117 if (nativeObject != nullptr) {
118 JsRun* jsRun = reinterpret_cast<JsRun*>(nativeObject);
119 delete jsRun;
120 }
121 }
122
CreateRun(napi_env env,napi_callback_info info)123 napi_value JsRun::CreateRun(napi_env env, napi_callback_info info)
124 {
125 if (!CreateConstructor(env)) {
126 TEXT_LOGE("Failed to create constructor");
127 return nullptr;
128 }
129 napi_value result = nullptr;
130 napi_value constructor = nullptr;
131 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
132 if (status != napi_ok) {
133 TEXT_LOGE("Failed to get reference, ret %{public}d", status);
134 return nullptr;
135 }
136
137 status = napi_new_instance(env, constructor, 0, nullptr, &result);
138 if (status != napi_ok) {
139 TEXT_LOGE("Failed to new instance, ret %{public}d", status);
140 return nullptr;
141 }
142 return result;
143 }
144
JsRun()145 JsRun::JsRun()
146 {
147 }
148
SetRun(std::unique_ptr<Run> run)149 void JsRun::SetRun(std::unique_ptr<Run> run)
150 {
151 run_ = std::move(run);
152 }
153
GetGlyphCount(napi_env env,napi_callback_info info)154 napi_value JsRun::GetGlyphCount(napi_env env, napi_callback_info info)
155 {
156 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
157 return (me != nullptr) ? me->OnGetGlyphCount(env, info) : nullptr;
158 }
159
OnGetGlyphCount(napi_env env,napi_callback_info info)160 napi_value JsRun::OnGetGlyphCount(napi_env env, napi_callback_info info)
161 {
162 if (!run_) {
163 TEXT_LOGE("Null run");
164 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "JsRun::OnGetGlyphCount run is nullptr.");
165 }
166 int64_t count = static_cast<int64_t>(run_->GetGlyphCount());
167 return CreateJsNumber(env, count);
168 }
169
GetGlyphs(napi_env env,napi_callback_info info)170 napi_value JsRun::GetGlyphs(napi_env env, napi_callback_info info)
171 {
172 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
173 return (me != nullptr) ? me->OnGetGlyphs(env, info) : nullptr;
174 }
175
OnGetGlyphs(napi_env env,napi_callback_info info)176 napi_value JsRun::OnGetGlyphs(napi_env env, napi_callback_info info)
177 {
178 if (!run_) {
179 TEXT_LOGE("Null run");
180 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed run is nullptr");
181 }
182
183 size_t argc = ARGC_ONE;
184 int64_t start = 0;
185 int64_t end = 0;
186 napi_value argv[ARGC_ONE] = {nullptr};
187 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
188 if (status != napi_ok) {
189 TEXT_LOGE("Failed to get parameter, ret %{public}d", static_cast<int>(status));
190 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
191 } else if (argc == ARGC_ONE) {
192 if (!GetStartEndParams(env, argv[0], start, end)) {
193 return NapiGetUndefined(env);
194 }
195 }
196
197 std::vector<uint16_t> glyphs = run_->GetGlyphs(start, end);
198 napi_value napiGlyphs = nullptr;
199 NAPI_CALL(env, napi_create_array(env, &napiGlyphs));
200 size_t glyphSize = glyphs.size();
201 for (size_t index = 0; index < glyphSize; ++index) {
202 NAPI_CALL(env, napi_set_element(env, napiGlyphs, index,
203 CreateJsNumber(env, static_cast<uint32_t>(glyphs.at(index)))));
204 }
205 return napiGlyphs;
206 }
207
GetPositions(napi_env env,napi_callback_info info)208 napi_value JsRun::GetPositions(napi_env env, napi_callback_info info)
209 {
210 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
211 return (me != nullptr) ? me->OnGetPositions(env, info) : nullptr;
212 }
213
OnGetPositions(napi_env env,napi_callback_info info)214 napi_value JsRun::OnGetPositions(napi_env env, napi_callback_info info)
215 {
216 if (!run_) {
217 TEXT_LOGE("Null run");
218 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed run is nullptr.");
219 }
220
221 size_t argc = ARGC_ONE;
222 int64_t start = 0;
223 int64_t end = 0;
224 napi_value argv[ARGC_ONE] = {nullptr};
225 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
226 if (status != napi_ok) {
227 TEXT_LOGE("Failed to get the info");
228 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
229 } else if (argc == ARGC_ONE) {
230 if (!GetStartEndParams(env, argv[0], start, end)) {
231 return NapiGetUndefined(env);
232 }
233 }
234
235 std::vector<Drawing::Point> positions = run_->GetPositions(start, end);
236 napi_value napiPositions = nullptr;
237 NAPI_CALL(env, napi_create_array(env, &napiPositions));
238 size_t positionSize = positions.size();
239 for (size_t index = 0; index < positionSize; ++index) {
240 NAPI_CALL(env, napi_set_element(env, napiPositions, index,
241 GetPointAndConvertToJsValue(env, positions.at(index))));
242 }
243 return napiPositions;
244 }
245
GetAdvances(napi_env env,napi_callback_info info)246 napi_value JsRun::GetAdvances(napi_env env, napi_callback_info info)
247 {
248 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
249 return (me != nullptr) ? me->OnGetAdvances(env, info) : nullptr;
250 }
251
OnGetAdvances(napi_env env,napi_callback_info info)252 napi_value JsRun::OnGetAdvances(napi_env env, napi_callback_info info)
253 {
254 if (!run_) {
255 TEXT_LOGE("Failed run is nullptr");
256 return NapiGetUndefined(env);
257 }
258
259 size_t argc = ARGC_ONE;
260 int64_t start = 0;
261 int64_t end = 0;
262 napi_value argv[ARGC_ONE] = {nullptr};
263 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
264 if (status != napi_ok || argc < ARGC_ONE) {
265 TEXT_LOGE("Failed to get parameter, argc %{public}zu, ret %{public}d", argc, status);
266 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
267 }
268 if (!GetStartEndParams(env, argv[0], start, end)) {
269 return NapiGetUndefined(env);
270 }
271
272 std::vector<Drawing::Point> advances = run_->GetAdvances(start, end);
273 napi_value napiAdvances = nullptr;
274 NAPI_CALL(env, napi_create_array(env, &napiAdvances));
275 size_t advanceSize = advances.size();
276 for (size_t index = 0; index < advanceSize; ++index) {
277 NAPI_CALL(env, napi_set_element(env, napiAdvances, index,
278 GetPointAndConvertToJsValue(env, advances.at(index))));
279 }
280 return napiAdvances;
281 }
282
GetTextDirection(napi_env env,napi_callback_info info)283 napi_value JsRun::GetTextDirection(napi_env env, napi_callback_info info)
284 {
285 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
286 return (me != nullptr) ? me->OnGetTextDirection(env, info) : nullptr;
287 }
288
OnGetTextDirection(napi_env env,napi_callback_info info)289 napi_value JsRun::OnGetTextDirection(napi_env env, napi_callback_info info)
290 {
291 if (!run_) {
292 TEXT_LOGE("Failed run is nullptr");
293 return NapiGetUndefined(env);
294 }
295
296 TextDirection textDirection = run_->GetTextDirection();
297 return CreateJsNumber(env, (int)textDirection);
298 }
299
GetOffsets(napi_env env,napi_callback_info info)300 napi_value JsRun::GetOffsets(napi_env env, napi_callback_info info)
301 {
302 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
303 return (me != nullptr) ? me->OnGetOffsets(env, info) : nullptr;
304 }
305
OnGetOffsets(napi_env env,napi_callback_info info)306 napi_value JsRun::OnGetOffsets(napi_env env, napi_callback_info info)
307 {
308 if (!run_) {
309 TEXT_LOGE("Null run");
310 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "JsRun::OnGetOffsets run is nullptr.");
311 }
312
313 std::vector<Drawing::Point> offsets = run_->GetOffsets();
314 napi_value napiOffsets = nullptr;
315 NAPI_CALL(env, napi_create_array(env, &napiOffsets));
316 size_t offsetSize = offsets.size();
317 for (size_t index = 0; index < offsetSize; ++index) {
318 NAPI_CALL(env, napi_set_element(env, napiOffsets, index,
319 GetPointAndConvertToJsValue(env, offsets.at(index))));
320 }
321 return napiOffsets;
322 }
323
GetFont(napi_env env,napi_callback_info info)324 napi_value JsRun::GetFont(napi_env env, napi_callback_info info)
325 {
326 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
327 return (me != nullptr) ? me->OnGetFont(env, info) : nullptr;
328 }
329
OnGetFont(napi_env env,napi_callback_info info)330 napi_value JsRun::OnGetFont(napi_env env, napi_callback_info info)
331 {
332 if (!run_) {
333 TEXT_LOGE("Null run");
334 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "JsRun::OnGetFont run is nullptr.");
335 }
336
337 std::shared_ptr<Drawing::Font> fontPtr = std::make_shared<Drawing::Font>(run_->GetFont());
338 if (!fontPtr) {
339 TEXT_LOGE("Null font");
340 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "JsRun::OnGetFont fontPtr is nullptr.");
341 }
342
343 napi_value resultValue = Drawing::JsFont::CreateFont(env, info);
344 if (!resultValue) {
345 TEXT_LOGE("Failed to create font");
346 return nullptr;
347 }
348 Drawing::JsFont* jsFont = nullptr;
349 napi_unwrap(env, resultValue, reinterpret_cast<void**>(&jsFont));
350 if (!jsFont) {
351 TEXT_LOGE("Failed to unwrap font");
352 return nullptr;
353 }
354 jsFont->SetFont(fontPtr);
355 return resultValue;
356 }
357
Paint(napi_env env,napi_callback_info info)358 napi_value JsRun::Paint(napi_env env, napi_callback_info info)
359 {
360 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
361 return (me != nullptr) ? me->OnPaint(env, info) : nullptr;
362 }
363
OnPaint(napi_env env,napi_callback_info info)364 napi_value JsRun::OnPaint(napi_env env, napi_callback_info info)
365 {
366 if (run_ == nullptr) {
367 TEXT_LOGE("Null run");
368 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "JsRun::OnPaint run is nullptr.");
369 }
370 size_t argc = ARGC_THREE;
371 napi_value argv[ARGC_THREE] = {nullptr};
372 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
373 if (status != napi_ok || argc < ARGC_THREE) {
374 TEXT_LOGE("Failed to get parameter, argc %{public}zu, ret %{public}d", argc, status);
375 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
376 }
377 if (argv[0] == nullptr) {
378 TEXT_LOGE("Invalid argv[0]");
379 return NapiGetUndefined(env);
380 }
381 Drawing::JsCanvas* jsCanvas = nullptr;
382 double x = 0.0;
383 double y = 0.0;
384 napi_unwrap(env, argv[0], reinterpret_cast<void **>(&jsCanvas));
385 if (!jsCanvas || !jsCanvas->GetCanvas() ||
386 !(argv[ARGC_ONE] != nullptr && ConvertFromJsValue(env, argv[ARGC_ONE], x) &&
387 argv[ARGC_TWO] != nullptr && ConvertFromJsValue(env, argv[ARGC_TWO], y))) {
388 TEXT_LOGE("Failed to get paint parameter");
389 return NapiGetUndefined(env);
390 }
391 run_->Paint(jsCanvas->GetCanvas(), x, y);
392
393 return NapiGetUndefined(env);
394 }
395
SetParagraph(std::shared_ptr<Typography> paragraph)396 void JsRun::SetParagraph(std::shared_ptr<Typography> paragraph)
397 {
398 paragraph_ = paragraph;
399 }
400
GetStringRange(napi_env env,napi_callback_info info)401 napi_value JsRun::GetStringRange(napi_env env, napi_callback_info info)
402 {
403 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
404 return (me != nullptr) ? me->OnGetStringRange(env, info) : nullptr;
405 }
406
OnGetStringRange(napi_env env,napi_callback_info info)407 napi_value JsRun::OnGetStringRange(napi_env env, napi_callback_info info)
408 {
409 if (!run_) {
410 TEXT_LOGE("Null run");
411 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed run is nullptr.");
412 }
413 uint64_t location = 0;
414 uint64_t length = 0;
415 run_->GetStringRange(&location, &length);
416 napi_value objValue = nullptr;
417 napi_create_object(env, &objValue);
418 if (objValue != nullptr) {
419 napi_status status = napi_set_named_property(env, objValue, "start", CreateJsNumber(env, location));
420 if (status != napi_ok) {
421 TEXT_LOGE("Failed to set named property, ret %{public}d", status);
422 return nullptr;
423 }
424 status = napi_set_named_property(env, objValue, "end", CreateJsNumber(env, length));
425 if (status != napi_ok) {
426 TEXT_LOGE("Failed to set named property, ret %{public}d", status);
427 return nullptr;
428 }
429 }
430 return objValue;
431 }
432
GetStringIndices(napi_env env,napi_callback_info info)433 napi_value JsRun::GetStringIndices(napi_env env, napi_callback_info info)
434 {
435 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
436 return (me != nullptr) ? me->OnGetStringIndices(env, info) : nullptr;
437 }
438
OnGetStringIndices(napi_env env,napi_callback_info info)439 napi_value JsRun::OnGetStringIndices(napi_env env, napi_callback_info info)
440 {
441 if (!run_) {
442 TEXT_LOGE("Null run");
443 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed run is nullptr.");
444 }
445
446 size_t argc = ARGC_ONE;
447 int64_t start = 0;
448 int64_t end = 0;
449 napi_value argv[ARGC_ONE] = {nullptr};
450 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
451 if (status != napi_ok) {
452 TEXT_LOGE("Failed to get the info");
453 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
454 } else if (argc == ARGC_ONE) {
455 if (!GetStartEndParams(env, argv[0], start, end)) {
456 TEXT_LOGE("Failed to GetStringIndices: invalid start and end");
457 return NapiGetUndefined(env);
458 }
459 }
460
461 std::vector<uint64_t> stringIndices = run_->GetStringIndices(start, end);
462 napi_value napiStringIndices = nullptr;
463 NAPI_CALL(env, napi_create_array(env, &napiStringIndices));
464 size_t stringIndicesSize = stringIndices.size();
465 for (size_t index = 0; index < stringIndicesSize; ++index) {
466 NAPI_CALL(env, napi_set_element(env, napiStringIndices, index,
467 CreateJsNumber(env, stringIndices.at(index))));
468 }
469 return napiStringIndices;
470 }
471
GetImageBounds(napi_env env,napi_callback_info info)472 napi_value JsRun::GetImageBounds(napi_env env, napi_callback_info info)
473 {
474 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
475 return (me != nullptr) ? me->OnGetImageBounds(env, info) : nullptr;
476 }
477
OnGetImageBounds(napi_env env,napi_callback_info info)478 napi_value JsRun::OnGetImageBounds(napi_env env, napi_callback_info info)
479 {
480 if (!run_) {
481 TEXT_LOGE("Null run");
482 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed run is nullptr.");
483 }
484 Drawing::Rect imageBounds = run_->GetImageBounds();
485 return GetRectAndConvertToJsValue(env, imageBounds);
486 }
487
GetTypographicBounds(napi_env env,napi_callback_info info)488 napi_value JsRun::GetTypographicBounds(napi_env env, napi_callback_info info)
489 {
490 JsRun* me = CheckParamsAndGetThis<JsRun>(env, info);
491 return (me != nullptr) ? me->OnGetTypographicBounds(env, info) : nullptr;
492 }
493
OnGetTypographicBounds(napi_env env,napi_callback_info info)494 napi_value JsRun::OnGetTypographicBounds(napi_env env, napi_callback_info info)
495 {
496 if (!run_) {
497 TEXT_LOGE("Null run");
498 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed run is nullptr.");
499 }
500
501 float ascent = 0.0;
502 float descent = 0.0;
503 float leading = 0.0;
504 float width = run_->GetTypographicBounds(&ascent, &descent, &leading);
505 return GetTypographicBoundsAndConvertToJsValue(env, ascent, descent, leading, width);
506 }
507 } // namespace OHOS::Rosen
508