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 "canvas_napi/js_canvas.h"
17 #include "js_text_line.h"
18 #include "recording/recording_canvas.h"
19 #include "run_napi/js_run.h"
20 #include "utils/text_log.h"
21
22 namespace OHOS::Rosen {
23 namespace {
24 const std::string CLASS_NAME = "TextLine";
25 }
26
27 std::mutex JsTextLine::constructorMutex_;
28 thread_local napi_ref JsTextLine::constructor_ = nullptr;
29
Constructor(napi_env env,napi_callback_info info)30 napi_value JsTextLine::Constructor(napi_env env, napi_callback_info info)
31 {
32 size_t argCount = 0;
33 napi_value jsThis = nullptr;
34 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
35 if (status != napi_ok) {
36 TEXT_LOGE("Failed to get parameter, ret %{public}d", status);
37 return nullptr;
38 }
39 JsTextLine *jsTextLineBase = new(std::nothrow) JsTextLine();
40 if (!jsTextLineBase) {
41 TEXT_LOGE("Failed to new text line");
42 return nullptr;
43 }
44 status = napi_wrap(env, jsThis, jsTextLineBase,
45 JsTextLine::Destructor, nullptr, nullptr);
46 if (status != napi_ok) {
47 delete jsTextLineBase;
48 TEXT_LOGE("Failed to wrap text line, ret %{public}d", status);
49 return nullptr;
50 }
51 return jsThis;
52 }
53
54
Init(napi_env env,napi_value exportObj)55 napi_value JsTextLine::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 return exportObj;
74 }
75
CreateConstructor(napi_env env)76 bool JsTextLine::CreateConstructor(napi_env env)
77 {
78 std::lock_guard<std::mutex> lock(constructorMutex_);
79 if (constructor_) {
80 return true;
81 }
82 napi_property_descriptor properties[] = {
83 DECLARE_NAPI_FUNCTION("getGlyphCount", JsTextLine::GetGlyphCount),
84 DECLARE_NAPI_FUNCTION("getGlyphRuns", JsTextLine::GetGlyphRuns),
85 DECLARE_NAPI_FUNCTION("getTextRange", JsTextLine::GetTextRange),
86 DECLARE_NAPI_FUNCTION("paint", JsTextLine::Paint),
87 DECLARE_NAPI_FUNCTION("createTruncatedLine", JsTextLine::CreateTruncatedLine),
88 DECLARE_NAPI_FUNCTION("getTrailingSpaceWidth", JsTextLine::GetTrailingSpaceWidth),
89 DECLARE_NAPI_FUNCTION("getTypographicBounds", JsTextLine::GetTypographicBounds),
90 DECLARE_NAPI_FUNCTION("getImageBounds", JsTextLine::GetImageBounds),
91 DECLARE_NAPI_FUNCTION("getStringIndexForPosition", JsTextLine::GetStringIndexForPosition),
92 DECLARE_NAPI_FUNCTION("getOffsetForStringIndex", JsTextLine::GetOffsetForStringIndex),
93 DECLARE_NAPI_FUNCTION("enumerateCaretOffsets", JsTextLine::EnumerateCaretOffsets),
94 DECLARE_NAPI_FUNCTION("getAlignmentOffset", JsTextLine::GetAlignmentOffset),
95 };
96
97 napi_value constructor = nullptr;
98 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
99 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
100 if (status != napi_ok) {
101 TEXT_LOGE("Failed to define class, ret %{public}d", status);
102 return false;
103 }
104
105 status = napi_create_reference(env, constructor, 1, &constructor_);
106 if (status != napi_ok) {
107 TEXT_LOGE("Failed to create reference, ret %{public}d", status);
108 return false;
109 }
110 return true;
111 }
112
Destructor(napi_env env,void * nativeObject,void * finalize)113 void JsTextLine::Destructor(napi_env env, void *nativeObject, void *finalize)
114 {
115 (void)finalize;
116 if (nativeObject != nullptr) {
117 JsTextLine *napi = reinterpret_cast<JsTextLine *>(nativeObject);
118 delete napi;
119 }
120 }
121
CreateTextLine(napi_env env,napi_callback_info info)122 napi_value JsTextLine::CreateTextLine(napi_env env, napi_callback_info info)
123 {
124 if (!CreateConstructor(env)) {
125 TEXT_LOGE("Failed to create constructor");
126 return nullptr;
127 }
128 napi_value result = nullptr;
129 napi_value constructor = nullptr;
130 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
131 if (status != napi_ok) {
132 TEXT_LOGE("Failed to get reference, ret %{public}d", status);
133 return nullptr;
134 }
135
136 status = napi_new_instance(env, constructor, 0, nullptr, &result);
137 if (status != napi_ok) {
138 TEXT_LOGE("Failed to new instance, ret %{public}d", status);
139 return nullptr;
140 }
141 return result;
142 }
143
JsTextLine()144 JsTextLine::JsTextLine()
145 {
146 }
147
SetTextLine(std::unique_ptr<TextLineBase> textLine)148 void JsTextLine::SetTextLine(std::unique_ptr<TextLineBase> textLine)
149 {
150 textLine_ = std::move(textLine);
151 }
152
GetGlyphCount(napi_env env,napi_callback_info info)153 napi_value JsTextLine::GetGlyphCount(napi_env env, napi_callback_info info)
154 {
155 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
156 return (me != nullptr) ? me->OnGetGlyphCount(env, info) : nullptr;
157 }
158
GetGlyphRuns(napi_env env,napi_callback_info info)159 napi_value JsTextLine::GetGlyphRuns(napi_env env, napi_callback_info info)
160 {
161 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
162 return (me != nullptr) ? me->OnGetGlyphRuns(env, info) : nullptr;
163 }
164
GetTextRange(napi_env env,napi_callback_info info)165 napi_value JsTextLine::GetTextRange(napi_env env, napi_callback_info info)
166 {
167 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
168 return (me != nullptr) ? me->OnGetTextRange(env, info) : nullptr;
169 }
170
Paint(napi_env env,napi_callback_info info)171 napi_value JsTextLine::Paint(napi_env env, napi_callback_info info)
172 {
173 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
174 return (me != nullptr) ? me->OnPaint(env, info) : nullptr;
175 }
176
CreateTruncatedLine(napi_env env,napi_callback_info info)177 napi_value JsTextLine::CreateTruncatedLine(napi_env env, napi_callback_info info)
178 {
179 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
180 return (me != nullptr) ? me->OnCreateTruncatedLine(env, info, constructor_) : nullptr;
181 }
182
GetTypographicBounds(napi_env env,napi_callback_info info)183 napi_value JsTextLine::GetTypographicBounds(napi_env env, napi_callback_info info)
184 {
185 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
186 return (me != nullptr) ? me->OnGetTypographicBounds(env, info) : nullptr;
187 }
188
GetImageBounds(napi_env env,napi_callback_info info)189 napi_value JsTextLine::GetImageBounds(napi_env env, napi_callback_info info)
190 {
191 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
192 return (me != nullptr) ? me->OnGetImageBounds(env, info) : nullptr;
193 }
194
GetTrailingSpaceWidth(napi_env env,napi_callback_info info)195 napi_value JsTextLine::GetTrailingSpaceWidth(napi_env env, napi_callback_info info)
196 {
197 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
198 return (me != nullptr) ? me->OnGetTrailingSpaceWidth(env, info) : nullptr;
199 }
200
GetStringIndexForPosition(napi_env env,napi_callback_info info)201 napi_value JsTextLine::GetStringIndexForPosition(napi_env env, napi_callback_info info)
202 {
203 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
204 return (me != nullptr) ? me->OnGetStringIndexForPosition(env, info) : nullptr;
205 }
206
GetOffsetForStringIndex(napi_env env,napi_callback_info info)207 napi_value JsTextLine::GetOffsetForStringIndex(napi_env env, napi_callback_info info)
208 {
209 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
210 return (me != nullptr) ? me->OnGetOffsetForStringIndex(env, info) : nullptr;
211 }
212
EnumerateCaretOffsets(napi_env env,napi_callback_info info)213 napi_value JsTextLine::EnumerateCaretOffsets(napi_env env, napi_callback_info info)
214 {
215 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
216 return (me != nullptr) ? me->OnEnumerateCaretOffsets(env, info) : nullptr;
217 }
218
GetAlignmentOffset(napi_env env,napi_callback_info info)219 napi_value JsTextLine::GetAlignmentOffset(napi_env env, napi_callback_info info)
220 {
221 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
222 return (me != nullptr) ? me->OnGetAlignmentOffset(env, info) : nullptr;
223 }
224
OnGetGlyphCount(napi_env env,napi_callback_info info)225 napi_value JsTextLine::OnGetGlyphCount(napi_env env, napi_callback_info info)
226 {
227 if (textLine_ == nullptr) {
228 TEXT_LOGE("Null text line");
229 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
230 }
231
232 uint32_t textSize = textLine_->GetGlyphCount();
233 return CreateJsValue(env, textSize);
234 }
235
OnGetGlyphRuns(napi_env env,napi_callback_info info)236 napi_value JsTextLine::OnGetGlyphRuns(napi_env env, napi_callback_info info)
237 {
238 if (textLine_ == nullptr) {
239 TEXT_LOGE("Null text line");
240 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
241 }
242 std::vector<std::unique_ptr<Run>> runs = textLine_->GetGlyphRuns();
243 if (runs.empty()) {
244 TEXT_LOGE("Run is empty");
245 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
246 }
247 napi_value array = nullptr;
248 NAPI_CALL(env, napi_create_array(env, &array));
249 uint32_t index = 0;
250 for (std::unique_ptr<Run>& item : runs) {
251 napi_value itemObject = JsRun::CreateRun(env, info);
252 if (!itemObject) {
253 TEXT_LOGE("Failed to create run");
254 continue;
255 }
256 JsRun* jsRun = nullptr;
257 napi_unwrap(env, itemObject, reinterpret_cast<void**>(&jsRun));
258 if (!jsRun) {
259 TEXT_LOGE("Failed to unwrap run");
260 continue;
261 }
262 jsRun->SetRun(std::move(item));
263 jsRun->SetParagraph(paragraph_);
264 napi_set_element(env, array, index++, itemObject);
265 }
266 return array;
267 }
268
OnGetTextRange(napi_env env,napi_callback_info info)269 napi_value JsTextLine::OnGetTextRange(napi_env env, napi_callback_info info)
270 {
271 if (textLine_ == nullptr) {
272 TEXT_LOGE("Null text line");
273 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
274 }
275
276 Boundary boundary = textLine_->GetTextRange();
277 napi_value objValue = nullptr;
278 napi_create_object(env, &objValue);
279 if (objValue != nullptr) {
280 napi_set_named_property(env, objValue, "start", CreateJsNumber(env, boundary.leftIndex));
281 napi_set_named_property(env, objValue, "end", CreateJsNumber(env, boundary.rightIndex));
282 }
283 return objValue;
284 }
285
OnPaint(napi_env env,napi_callback_info info)286 napi_value JsTextLine::OnPaint(napi_env env, napi_callback_info info)
287 {
288 if (textLine_ == nullptr) {
289 TEXT_LOGE("Null text line");
290 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
291 }
292 size_t argc = ARGC_THREE;
293 napi_value argv[ARGC_THREE] = {nullptr};
294 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
295 if (status != napi_ok || argc < ARGC_THREE) {
296 TEXT_LOGE("Failed to get paramter, argc %{public}zu, ret %{public}d", argc, status);
297 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
298 }
299 if (argv[0] == nullptr) {
300 TEXT_LOGE("Null argv[0]");
301 return NapiGetUndefined(env);
302 }
303 Drawing::JsCanvas* jsCanvas = nullptr;
304 napi_unwrap(env, argv[0], reinterpret_cast<void**>(&jsCanvas));
305 if (!jsCanvas || !jsCanvas->GetCanvas()) {
306 TEXT_LOGE("Failed to get canvas");
307 return NapiGetUndefined(env);
308 }
309 double x = 0.0;
310 double y = 0.0;
311 if (!(argv[ARGC_ONE] != nullptr && ConvertFromJsValue(env, argv[ARGC_ONE], x) &&
312 argv[ARGC_TWO] != nullptr && ConvertFromJsValue(env, argv[ARGC_TWO], y))) {
313 return NapiGetUndefined(env);
314 }
315 textLine_->Paint(jsCanvas->GetCanvas(), x, y);
316
317 return NapiGetUndefined(env);
318 }
319
OnCreateTruncatedLine(napi_env env,napi_callback_info info,napi_ref constructor)320 napi_value JsTextLine::OnCreateTruncatedLine(napi_env env, napi_callback_info info, napi_ref constructor)
321 {
322 if (textLine_ == nullptr) {
323 TEXT_LOGE("Null text line");
324 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
325 }
326
327 size_t argc = ARGC_THREE;
328 napi_value argv[ARGC_THREE] = {nullptr};
329 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
330 if (status != napi_ok || argc < ARGC_THREE) {
331 TEXT_LOGE("Failed to get argc(%{public}zu)", argc);
332 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
333 }
334
335 double width = 0.0;
336 if (!ConvertFromJsValue(env, argv[0], width)) {
337 TEXT_LOGE("Failed to convert width");
338 return NapiGetUndefined(env);
339 }
340 uint32_t ellipsisMode = 0;
341 if (!ConvertFromJsValue(env, argv[ARGC_ONE], ellipsisMode)) {
342 TEXT_LOGE("Failed to convert ellipsisMode");
343 return NapiGetUndefined(env);
344 }
345 std::string ellipsisStr = "";
346 if (!ConvertFromJsValue(env, argv[ARGC_TWO], ellipsisStr)) {
347 TEXT_LOGE("Failed to convert ellipsisStr");
348 return NapiGetUndefined(env);
349 }
350
351 std::unique_ptr<TextLineBase> textLine = textLine_->CreateTruncatedLine(width, EllipsisModal(ellipsisMode),
352 ellipsisStr);
353 if (textLine == nullptr) {
354 TEXT_LOGE("Failed to create truncated textLine");
355 return NapiGetUndefined(env);
356 }
357
358 napi_value itemObject = JsTextLine::CreateTextLine(env, info);
359 if (itemObject == nullptr) {
360 TEXT_LOGE("Failed to create js textLine");
361 return NapiGetUndefined(env);
362 }
363
364 JsTextLine* jsTextLine = nullptr;
365 status = napi_unwrap(env, itemObject, reinterpret_cast<void**>(&jsTextLine));
366 if (status != napi_ok || jsTextLine == nullptr) {
367 TEXT_LOGE("Failed to napi_unwrap jsTextLine");
368 return NapiGetUndefined(env);
369 }
370 jsTextLine->SetTextLine(std::move(textLine));
371 jsTextLine->SetParagraph(paragraph_);
372
373 return itemObject;
374 }
375
OnGetTypographicBounds(napi_env env,napi_callback_info info)376 napi_value JsTextLine::OnGetTypographicBounds(napi_env env, napi_callback_info info)
377 {
378 if (textLine_ == nullptr) {
379 TEXT_LOGE("Null text line");
380 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
381 }
382
383 double ascent = 0.0;
384 double descent = 0.0;
385 double leading = 0.0;
386 double width = textLine_->GetTypographicBounds(&ascent, &descent, &leading);
387
388 napi_value objValue = nullptr;
389 napi_status status = napi_create_object(env, &objValue);
390 if (status != napi_ok || objValue == nullptr) {
391 TEXT_LOGE("Failed to create object, ret %{public}d", static_cast<int>(status));
392 return NapiGetUndefined(env);
393 }
394
395 status = napi_set_named_property(env, objValue, "ascent", CreateJsNumber(env, ascent));
396 if (status != napi_ok) {
397 TEXT_LOGE("Failed to set ascent, ret %{public}d", static_cast<int>(status));
398 return NapiGetUndefined(env);
399 }
400 status = napi_set_named_property(env, objValue, "descent", CreateJsNumber(env, descent));
401 if (status != napi_ok) {
402 TEXT_LOGE("Failed to set descent, ret %{public}d", static_cast<int>(status));
403 return NapiGetUndefined(env);
404 }
405 status = napi_set_named_property(env, objValue, "leading", CreateJsNumber(env, leading));
406 if (status != napi_ok) {
407 TEXT_LOGE("Failed to set leading, ret %{public}d", static_cast<int>(status));
408 return NapiGetUndefined(env);
409 }
410 status = napi_set_named_property(env, objValue, "width", CreateJsNumber(env, width));
411 if (status != napi_ok) {
412 TEXT_LOGE("Failed to set width, ret %{public}d", static_cast<int>(status));
413 return NapiGetUndefined(env);
414 }
415
416 return objValue;
417 }
418
OnGetImageBounds(napi_env env,napi_callback_info info)419 napi_value JsTextLine::OnGetImageBounds(napi_env env, napi_callback_info info)
420 {
421 if (textLine_ == nullptr) {
422 TEXT_LOGE("Null text line");
423 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
424 }
425
426 Drawing::Rect rect = textLine_->GetImageBounds();
427 return GetRectAndConvertToJsValue(env, rect);
428 }
429
OnGetTrailingSpaceWidth(napi_env env,napi_callback_info info)430 napi_value JsTextLine::OnGetTrailingSpaceWidth(napi_env env, napi_callback_info info)
431 {
432 if (textLine_ == nullptr) {
433 TEXT_LOGE("Null text line");
434 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
435 }
436
437 double width = textLine_->GetTrailingSpaceWidth();
438 return CreateJsValue(env, width);
439 }
440
OnGetStringIndexForPosition(napi_env env,napi_callback_info info)441 napi_value JsTextLine::OnGetStringIndexForPosition(napi_env env, napi_callback_info info)
442 {
443 if (textLine_ == nullptr) {
444 TEXT_LOGE("Null text line");
445 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
446 }
447 size_t argc = ARGC_ONE;
448 napi_value argv[ARGC_ONE] = {nullptr};
449 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
450 if (status != napi_ok || argc < ARGC_ONE) {
451 TEXT_LOGE("Failed to get argc(%{public}zu)", argc);
452 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
453 }
454
455 double x = 0.0;
456 double y = 0.0;
457 napi_value tempValue = nullptr;
458 status = napi_get_named_property(env, argv[0], "x", &tempValue);
459 if (status != napi_ok || tempValue == nullptr) {
460 TEXT_LOGE("Failed to get x, ret %{public}d", static_cast<int>(status));
461 return NapiGetUndefined(env);
462 }
463 if (!ConvertFromJsValue(env, tempValue, x)) {
464 TEXT_LOGE("Failed to convert x");
465 return NapiGetUndefined(env);
466 }
467 status = napi_get_named_property(env, argv[0], "y", &tempValue);
468 if (status != napi_ok || tempValue == nullptr) {
469 TEXT_LOGE("Failed to get y, ret %{public}d", static_cast<int>(status));
470 return NapiGetUndefined(env);
471 }
472 if (!ConvertFromJsValue(env, tempValue, y)) {
473 TEXT_LOGE("Failed to convert y");
474 return NapiGetUndefined(env);
475 }
476
477 SkPoint point = {x, y};
478 int32_t index = textLine_->GetStringIndexForPosition(point);
479 return CreateJsValue(env, index);
480 }
481
OnGetOffsetForStringIndex(napi_env env,napi_callback_info info)482 napi_value JsTextLine::OnGetOffsetForStringIndex(napi_env env, napi_callback_info info)
483 {
484 if (textLine_ == nullptr) {
485 TEXT_LOGE("Null text line");
486 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
487 }
488 size_t argc = ARGC_ONE;
489 napi_value argv[ARGC_ONE] = {nullptr};
490 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
491 if (status != napi_ok || argc < ARGC_ONE) {
492 TEXT_LOGE("Failed to get argc(%{public}zu)", argc);
493 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
494 }
495
496 int32_t index = 0;
497 if (!ConvertFromJsValue(env, argv[0], index)) {
498 TEXT_LOGE("Failed to convert index");
499 return NapiGetUndefined(env);
500 }
501
502 double offset = textLine_->GetOffsetForStringIndex(index);
503 return CreateJsValue(env, offset);
504 }
505
CallJsFunc(napi_env env,napi_value callback,int32_t index,double leftOffset,double rightOffset)506 bool CallJsFunc(napi_env env, napi_value callback, int32_t index, double leftOffset, double rightOffset)
507 {
508 napi_value jsLeadingEdgeTrue = CreateJsValue(env, true);
509 napi_value jsLeadingEdgeFalse = CreateJsValue(env, false);
510 napi_value jsIndex = CreateJsValue(env, index);
511 for (size_t i = 0; i < ARGC_TWO; i++) {
512 napi_value jsOffset = (i == 0) ? CreateJsValue(env, leftOffset) : CreateJsValue(env, rightOffset);
513 napi_value jsLeadingEdge = (i == 0) ? jsLeadingEdgeTrue : jsLeadingEdgeFalse;
514 napi_value retVal = nullptr;
515 napi_value params[ARGC_THREE] = {jsOffset, jsIndex, jsLeadingEdge};
516 napi_status status = napi_call_function(env, nullptr, callback, ARGC_THREE, params, &retVal);
517 if (status != napi_ok) {
518 TEXT_LOGE("Failed to napi_call_function");
519 return false;
520 }
521
522 bool stop = false;
523 if (!ConvertFromJsValue(env, retVal, stop)) {
524 TEXT_LOGE("Failed to convert stop");
525 return false;
526 }
527 if (stop) {
528 TEXT_LOGI("Js call stoped");
529 return false;
530 }
531 }
532
533 return true;
534 }
535
OnEnumerateCaretOffsets(napi_env env,napi_callback_info info)536 napi_value JsTextLine::OnEnumerateCaretOffsets(napi_env env, napi_callback_info info)
537 {
538 TEXT_ERROR_CHECK(textLine_ != nullptr,
539 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params."), "TextLine is nullptr");
540
541 size_t argc = ARGC_ONE;
542 napi_value argv[ARGC_ONE];
543 napi_value jsCallback = nullptr;
544 napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsCallback, nullptr);
545 if (status != napi_ok || argc < ARGC_ONE) {
546 TEXT_LOGE("Failed to get argc(%{public}zu)", argc);
547 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
548 }
549 napi_valuetype valueType = napi_undefined;
550 status = napi_typeof(env, argv[0], &valueType);
551 if (status != napi_ok || valueType != napi_function) {
552 TEXT_LOGE("Failed to get napi type or argc is not function");
553 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
554 }
555 napi_ref refCallback = nullptr;
556 std::unique_ptr<napi_ref, std::function<void(napi_ref*)>> refCallbackGuard(&refCallback, [env](napi_ref* ref) {
557 if (ref != nullptr && *ref != nullptr) {
558 TEXT_CHECK(napi_delete_reference(env, *ref) == napi_ok, TEXT_LOGE("Failed to release ref callback"));
559 }
560 });
561 status = napi_create_reference(env, argv[0], 1, &refCallback);
562 if (status != napi_ok) {
563 TEXT_LOGE("Failed to create reference");
564 return NapiGetUndefined(env);
565 }
566
567 napi_value callback = nullptr;
568 if ((napi_get_reference_value(env, refCallback, &callback)) != napi_ok) {
569 TEXT_LOGE("Failed to get reference");
570 return NapiGetUndefined(env);
571 }
572
573 bool isHardBreak = false;
574 std::map<int32_t, double> offsetMap = textLine_->GetIndexAndOffsets(isHardBreak);
575 double leftOffset = 0.0;
576 for (auto it = offsetMap.begin(); it != offsetMap.end(); ++it) {
577 if (!CallJsFunc(env, callback, it->first, leftOffset, it->second)) {
578 return NapiGetUndefined(env);
579 }
580 leftOffset = it->second;
581 }
582 if (isHardBreak && offsetMap.size() > 0) {
583 if (!CallJsFunc(env, callback, offsetMap.rbegin()->first + 1, leftOffset, leftOffset)) {
584 return NapiGetUndefined(env);
585 }
586 }
587
588 return NapiGetUndefined(env);
589 }
590
OnGetAlignmentOffset(napi_env env,napi_callback_info info)591 napi_value JsTextLine::OnGetAlignmentOffset(napi_env env, napi_callback_info info)
592 {
593 if (textLine_ == nullptr) {
594 TEXT_LOGE("Null text line");
595 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
596 }
597
598 size_t argc = ARGC_TWO;
599 napi_value argv[ARGC_TWO] = {nullptr};
600 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
601 if (status != napi_ok || argc < ARGC_TWO) {
602 TEXT_LOGE("Failed to get argc(%{public}zu)", argc);
603 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
604 }
605
606 double alignmentFactor = 0.0;
607 if (!ConvertFromJsValue(env, argv[0], alignmentFactor)) {
608 TEXT_LOGE("Failed to convert alignmentFactor");
609 return NapiGetUndefined(env);
610 }
611 double alignmentWidth = 0.0;
612 if (!ConvertFromJsValue(env, argv[ARGC_ONE], alignmentWidth)) {
613 TEXT_LOGE("Failed to convert alignmentWidth");
614 return NapiGetUndefined(env);
615 }
616
617 double offset = textLine_->GetAlignmentOffset(alignmentFactor, alignmentWidth);
618 return CreateJsValue(env, offset);
619 }
620
GetTextLineBase()621 std::unique_ptr<TextLineBase> JsTextLine::GetTextLineBase()
622 {
623 return std::move(textLine_);
624 }
625
SetParagraph(std::shared_ptr<Typography> paragraph)626 void JsTextLine::SetParagraph(std::shared_ptr<Typography> paragraph)
627 {
628 paragraph_ = paragraph;
629 }
630 } // namespace OHOS::Rosen