1 /*
2 * Copyright (c) 2021-2023 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 "frameworks/bridge/declarative_frontend/jsview/js_text.h"
17
18 #include <cstdint>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
23 #include "core/components_ng/pattern/text/text_layout_property.h"
24 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
25 #endif
26
27 #include "base/geometry/dimension.h"
28 #include "base/log/ace_scoring_log.h"
29 #include "base/log/ace_trace.h"
30 #include "base/utils/utils.h"
31 #include "bridge/common/utils/utils.h"
32 #include "bridge/declarative_frontend/ark_theme/theme_apply/js_theme_utils.h"
33 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
34 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
35 #include "bridge/declarative_frontend/engine/functions/js_function.h"
36 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
37 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
38 #include "bridge/declarative_frontend/jsview/js_layout_manager.h"
39 #include "bridge/declarative_frontend/jsview/js_text.h"
40 #include "bridge/declarative_frontend/jsview/js_utils.h"
41 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
42 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
43 #include "bridge/declarative_frontend/jsview/models/text_model_impl.h"
44 #include "bridge/declarative_frontend/style_string/js_span_string.h"
45 #include "bridge/declarative_frontend/view_stack_processor.h"
46 #include "core/common/container.h"
47 #include "core/components/common/layout/constants.h"
48 #include "core/components/common/properties/text_style_parser.h"
49 #include "core/components_ng/pattern/text/text_model_ng.h"
50 #include "core/event/ace_event_handler.h"
51 #include "core/pipeline/pipeline_base.h"
52
53 namespace OHOS::Ace {
54
55 std::unique_ptr<TextModel> TextModel::instance_ = nullptr;
56 std::mutex TextModel::mutex_;
57
GetInstance()58 TextModel* TextModel::GetInstance()
59 {
60 #ifdef NG_BUILD
61 static NG::TextModelNG instance;
62 return &instance;
63 #else
64 if (Container::IsCurrentUseNewPipeline()) {
65 static NG::TextModelNG instance;
66 return &instance;
67 } else {
68 static Framework::TextModelImpl instance;
69 return &instance;
70 }
71 #endif
72 }
73
74 } // namespace OHOS::Ace
75
76 namespace OHOS::Ace::Framework {
77 namespace {
78
79 const std::vector<TextCase> TEXT_CASES = { TextCase::NORMAL, TextCase::LOWERCASE, TextCase::UPPERCASE };
80 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
81 TextOverflow::MARQUEE };
82 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
83 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END, TextAlign::JUSTIFY,
84 TextAlign::LEFT, TextAlign::RIGHT };
85 const std::vector<TextHeightAdaptivePolicy> HEIGHT_ADAPTIVE_POLICY = { TextHeightAdaptivePolicy::MAX_LINES_FIRST,
86 TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST };
87 const std::vector<LineBreakStrategy> LINE_BREAK_STRATEGY_TYPES = { LineBreakStrategy::GREEDY,
88 LineBreakStrategy::HIGH_QUALITY, LineBreakStrategy::BALANCED };
89 const std::vector<EllipsisMode> ELLIPSIS_MODALS = { EllipsisMode::HEAD, EllipsisMode::MIDDLE, EllipsisMode::TAIL };
90 const std::vector<TextSelectableMode> TEXT_SELECTABLE_MODE = { TextSelectableMode::SELECTABLE_UNFOCUSABLE,
91 TextSelectableMode::SELECTABLE_FOCUSABLE, TextSelectableMode::UNSELECTABLE };
92 constexpr TextDecorationStyle DEFAULT_TEXT_DECORATION_STYLE = TextDecorationStyle::SOLID;
93 const int32_t DEFAULT_VARIABLE_FONT_WEIGHT = 400;
94 }; // namespace
95
SetWidth(const JSCallbackInfo & info)96 void JSText::SetWidth(const JSCallbackInfo& info)
97 {
98 JSViewAbstract::JsWidth(info);
99 TextModel::GetInstance()->OnSetWidth();
100 }
101
SetHeight(const JSCallbackInfo & info)102 void JSText::SetHeight(const JSCallbackInfo& info)
103 {
104 JSViewAbstract::JsHeight(info);
105 TextModel::GetInstance()->OnSetHeight();
106 }
107
SetFont(const JSCallbackInfo & info)108 void JSText::SetFont(const JSCallbackInfo& info)
109 {
110 Font font;
111 auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
112 CHECK_NULL_VOID(pipelineContext);
113 auto theme = pipelineContext->GetTheme<TextTheme>();
114 CHECK_NULL_VOID(theme);
115 font.fontSize = theme->GetTextStyle().GetFontSize();
116 font.fontWeight = theme->GetTextStyle().GetFontWeight();
117 font.fontFamilies = theme->GetTextStyle().GetFontFamilies();
118 font.fontStyle = theme->GetTextStyle().GetFontStyle();
119 GetFontInfo(info, font);
120 TextModel::GetInstance()->SetFont(font);
121 if (info.Length() < 2) { // 2 : two args
122 return;
123 }
124 auto tmpInfo = info[1];
125 if (!tmpInfo->IsObject()) {
126 return;
127 }
128 auto paramObject = JSRef<JSObject>::Cast(tmpInfo);
129 auto enableVariableFontWeight = paramObject->GetProperty("enableVariableFontWeight");
130 if (enableVariableFontWeight->IsBoolean()) {
131 TextModel::GetInstance()->SetEnableVariableFontWeight(enableVariableFontWeight->ToBoolean());
132 } else {
133 TextModel::GetInstance()->SetEnableVariableFontWeight(false);
134 }
135 }
136
GetFontInfo(const JSCallbackInfo & info,Font & font)137 void JSText::GetFontInfo(const JSCallbackInfo& info, Font& font)
138 {
139 auto tmpInfo = info[0];
140 if (!tmpInfo->IsObject()) {
141 return;
142 }
143 auto paramObject = JSRef<JSObject>::Cast(tmpInfo);
144 auto fontSize = paramObject->GetProperty(static_cast<int32_t>(ArkUIIndex::SIZE));
145 CalcDimension size;
146 RefPtr<ResourceObject> fontSizeResObj;
147 UnRegisterResource("FontSize");
148 if (ParseJsDimensionFpNG(fontSize, size, fontSizeResObj, false) && size.IsNonNegative()) {
149 font.fontSize = size;
150 if (SystemProperties::ConfigChangePerform() && fontSizeResObj) {
151 RegisterResource<CalcDimension>("FontSize", fontSizeResObj, size);
152 }
153 }
154 std::string weight;
155 auto fontWeight = paramObject->GetProperty(static_cast<int32_t>(ArkUIIndex::WEIGHT));
156 if (!fontWeight->IsNull()) {
157 int32_t variableFontWeight = DEFAULT_VARIABLE_FONT_WEIGHT;
158 ParseJsInt32(fontWeight, variableFontWeight);
159 TextModel::GetInstance()->SetVariableFontWeight(variableFontWeight);
160 if (fontWeight->IsNumber()) {
161 weight = std::to_string(fontWeight->ToNumber<int32_t>());
162 } else {
163 JSContainerBase::ParseJsString(fontWeight, weight);
164 }
165 font.fontWeight = ConvertStrToFontWeight(weight);
166 }
167 auto fontFamily = paramObject->GetProperty(static_cast<int32_t>(ArkUIIndex::FAMILY));
168 if (!fontFamily->IsNull()) {
169 std::vector<std::string> fontFamilies;
170 RefPtr<ResourceObject> fontFamiliesResObj;
171 UnRegisterResource("FontFamily");
172 if (JSContainerBase::ParseJsFontFamilies(fontFamily, fontFamilies, fontFamiliesResObj)) {
173 font.fontFamilies = fontFamilies;
174 if (SystemProperties::ConfigChangePerform() && fontFamiliesResObj) {
175 RegisterResource<std::vector<std::string>>(
176 "FontFamily", fontFamiliesResObj, fontFamilies);
177 }
178 }
179 }
180 auto style = paramObject->GetProperty(static_cast<int32_t>(ArkUIIndex::STYLE));
181 if (!style->IsNull() || style->IsNumber()) {
182 font.fontStyle = static_cast<FontStyle>(style->ToNumber<int32_t>());
183 }
184 }
185
SetFontSize(const JSCallbackInfo & info)186 void JSText::SetFontSize(const JSCallbackInfo& info)
187 {
188 if (info.Length() < 1) {
189 return;
190 }
191 CalcDimension fontSize;
192 RefPtr<ResourceObject> resObj;
193 UnRegisterResource("FontSize");
194 JSRef<JSVal> args = info[0];
195 if (!ParseJsDimensionFpNG(args, fontSize, resObj, false) || fontSize.IsNegative()) {
196 auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
197 CHECK_NULL_VOID(pipelineContext);
198 auto theme = pipelineContext->GetTheme<TextTheme>();
199 CHECK_NULL_VOID(theme);
200 fontSize = theme->GetTextStyle().GetFontSize();
201 TextModel::GetInstance()->SetFontSize(fontSize);
202 return;
203 }
204 TextModel::GetInstance()->SetFontSize(fontSize);
205 if (SystemProperties::ConfigChangePerform() && resObj) {
206 RegisterResource<CalcDimension>("FontSize", resObj, fontSize);
207 }
208 }
209
SetFontWeight(const JSCallbackInfo & info)210 void JSText::SetFontWeight(const JSCallbackInfo& info)
211 {
212 if (info.Length() < 1) {
213 return;
214 }
215 JSRef<JSVal> args = info[0];
216 std::string fontWeight;
217 int32_t variableFontWeight = DEFAULT_VARIABLE_FONT_WEIGHT;
218 ParseJsInt32(args, variableFontWeight);
219 TextModel::GetInstance()->SetVariableFontWeight(variableFontWeight);
220
221 if (args->IsNumber()) {
222 fontWeight = args->ToString();
223 } else {
224 ParseJsString(args, fontWeight);
225 }
226 TextModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(fontWeight));
227
228 if (info.Length() < 2) { // 2 : two args
229 return;
230 }
231 auto tmpInfo = info[1];
232 if (!tmpInfo->IsObject()) {
233 return;
234 }
235 auto paramObject = JSRef<JSObject>::Cast(tmpInfo);
236 auto enableVariableFontWeight = paramObject->GetProperty("enableVariableFontWeight");
237 if (enableVariableFontWeight->IsBoolean()) {
238 TextModel::GetInstance()->SetEnableVariableFontWeight(enableVariableFontWeight->ToBoolean());
239 } else {
240 TextModel::GetInstance()->SetEnableVariableFontWeight(false);
241 }
242 }
243
SetMinFontScale(const JSCallbackInfo & info)244 void JSText::SetMinFontScale(const JSCallbackInfo& info)
245 {
246 double minFontScale;
247 RefPtr<ResourceObject> resourceObject;
248 UnRegisterResource("MinFontScale");
249 if (info.Length() < 1 || !ParseJsDouble(info[0], minFontScale, resourceObject)) {
250 return;
251 }
252 auto minFontScaleValue = static_cast<float>(std::clamp(minFontScale, 0.0, 1.0));
253 if (SystemProperties::ConfigChangePerform() && resourceObject) {
254 RegisterResource<float>("MinFontScale", resourceObject, minFontScaleValue);
255 }
256 TextModel::GetInstance()->SetMinFontScale(minFontScaleValue);
257 }
258
SetMaxFontScale(const JSCallbackInfo & info)259 void JSText::SetMaxFontScale(const JSCallbackInfo& info)
260 {
261 double maxFontScale;
262 RefPtr<ResourceObject> resourceObject;
263 UnRegisterResource("MaxFontScale");
264 if (info.Length() < 1 || !ParseJsDouble(info[0], maxFontScale, resourceObject)) {
265 return;
266 }
267 auto maxFontScaleValue = static_cast<float>(std::max(maxFontScale, 1.0));
268 if (SystemProperties::ConfigChangePerform() && resourceObject) {
269 RegisterResource<float>("MaxFontScale", resourceObject, maxFontScaleValue);
270 }
271 TextModel::GetInstance()->SetMaxFontScale(maxFontScaleValue);
272 }
273
SetForegroundColor(const JSCallbackInfo & info)274 void JSText::SetForegroundColor(const JSCallbackInfo& info)
275 {
276 if (info.Length() < 1) {
277 return;
278 }
279 ForegroundColorStrategy strategy;
280 if (ParseJsColorStrategy(info[0], strategy)) {
281 TextModel::GetInstance()->SetTextColor(Color::FOREGROUND);
282 ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy);
283 return;
284 }
285 SetTextColor(info);
286 }
287
SetTextColor(const JSCallbackInfo & info)288 void JSText::SetTextColor(const JSCallbackInfo& info)
289 {
290 if (info.Length() < 1) {
291 return;
292 }
293 Color textColor;
294 RefPtr<ResourceObject> resourceObject;
295 UnRegisterResource("TextColor");
296 JSRef<JSVal> args = info[0];
297 if (!ParseJsColor(args, textColor, resourceObject)) {
298 TextModel::GetInstance()->ResetTextColor();
299 return;
300 }
301 if (SystemProperties::ConfigChangePerform() && resourceObject) {
302 RegisterResource<Color>("TextColor", resourceObject, textColor);
303 }
304 TextModel::GetInstance()->SetTextColor(textColor);
305 }
306
SetTextShadow(const JSCallbackInfo & info)307 void JSText::SetTextShadow(const JSCallbackInfo& info)
308 {
309 if (info.Length() < 1) {
310 return;
311 }
312 std::vector<Shadow> shadows;
313 JSRef<JSVal> args = info[0];
314 ParseTextShadowFromShadowObject(args, shadows);
315 TextModel::GetInstance()->SetTextShadow(shadows);
316 }
317
SetTextOverflow(const JSCallbackInfo & info)318 void JSText::SetTextOverflow(const JSCallbackInfo& info)
319 {
320 do {
321 auto tmpInfo = info[0];
322 if (!tmpInfo->IsObject()) {
323 break;
324 }
325 JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
326 JSRef<JSVal> overflowValue = obj->GetProperty("overflow");
327 if (!overflowValue->IsNumber() && !overflowValue->IsUndefined()) {
328 break;
329 }
330 auto overflow = overflowValue->ToNumber<int32_t>();
331 if(overflowValue->IsUndefined()) {
332 overflow = 0;
333 } else if (overflow < 0 || overflow >= static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
334 break;
335 }
336 TextModel::GetInstance()->SetTextOverflow(TEXT_OVERFLOWS[overflow]);
337 } while (false);
338
339 info.SetReturnValue(info.This());
340 }
341
SetWordBreak(const JSCallbackInfo & info)342 void JSText::SetWordBreak(const JSCallbackInfo& info)
343 {
344 JSRef<JSVal> args = info[0];
345 if (!args->IsNumber()) {
346 return;
347 }
348 uint32_t index = args->ToNumber<uint32_t>();
349 if (index < WORD_BREAK_TYPES.size()) {
350 TextModel::GetInstance()->SetWordBreak(WORD_BREAK_TYPES[index]);
351 }
352 }
353
SetEllipsisMode(const JSCallbackInfo & info)354 void JSText::SetEllipsisMode(const JSCallbackInfo& info)
355 {
356 JSRef<JSVal> args = info[0];
357 if (!args->IsNumber()) {
358 return;
359 }
360 uint32_t index = args->ToNumber<uint32_t>();
361 if (index < ELLIPSIS_MODALS.size()) {
362 TextModel::GetInstance()->SetEllipsisMode(ELLIPSIS_MODALS[index]);
363 }
364 }
365
SetLineBreakStrategy(const JSCallbackInfo & info)366 void JSText::SetLineBreakStrategy(const JSCallbackInfo& info)
367 {
368 if (info.Length() < 1) {
369 TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
370 return;
371 }
372 if (!info[0]->IsNumber()) {
373 TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
374 return;
375 }
376 auto index = info[0]->ToNumber<int32_t>();
377 if (index < 0 || index >= static_cast<int32_t>(LINE_BREAK_STRATEGY_TYPES.size())) {
378 TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
379 return;
380 }
381 TextModel::GetInstance()->SetLineBreakStrategy(LINE_BREAK_STRATEGY_TYPES[index]);
382 }
383
SetTextSelection(const JSCallbackInfo & info)384 void JSText::SetTextSelection(const JSCallbackInfo& info)
385 {
386 if (info.Length() < 1) {
387 return;
388 }
389 JSRef<JSVal> argsStartIndex = info[0];
390 JSRef<JSVal> argsEndIndex = info[1];
391 if (!argsStartIndex->IsNumber() || !argsEndIndex->IsNumber()) {
392 return;
393 }
394 auto startIndex = argsStartIndex->ToNumber<int32_t>();
395 auto endIndex = argsEndIndex->ToNumber<int32_t>();
396 TextModel::GetInstance()->SetTextSelection(startIndex, endIndex);
397 }
398
SetTextCaretColor(const JSCallbackInfo & info)399 void JSText::SetTextCaretColor(const JSCallbackInfo& info)
400 {
401 if (info.Length() < 1) {
402 return;
403 }
404 Color caretColor;
405 RefPtr<ResourceObject> resObj;
406 UnRegisterResource("TextCaretColor");
407 if (!ParseJsColor(info[0], caretColor, resObj)) {
408 auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
409 CHECK_NULL_VOID(pipelineContext);
410 auto theme = pipelineContext->GetTheme<TextTheme>();
411 CHECK_NULL_VOID(theme);
412 caretColor = theme->GetCaretColor();
413 }
414 if (SystemProperties::ConfigChangePerform() && resObj) {
415 RegisterResource<Color>("TextCaretColor", resObj, caretColor);
416 }
417 TextModel::GetInstance()->SetTextCaretColor(caretColor);
418 }
419
SetSelectedBackgroundColor(const JSCallbackInfo & info)420 void JSText::SetSelectedBackgroundColor(const JSCallbackInfo& info)
421 {
422 if (info.Length() < 1) {
423 return;
424 }
425 Color selectedColor;
426 RefPtr<ResourceObject> resObj;
427 UnRegisterResource("SelectedBackgroundColor");
428 if (!ParseJsColor(info[0], selectedColor, resObj)) {
429 auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
430 CHECK_NULL_VOID(pipelineContext);
431 auto theme = pipelineContext->GetTheme<TextTheme>();
432 CHECK_NULL_VOID(theme);
433 selectedColor = theme->GetSelectedColor();
434 }
435 if (SystemProperties::ConfigChangePerform() && resObj) {
436 RegisterResource<Color>("SelectedBackgroundColor", resObj, selectedColor);
437 }
438 // Alpha = 255 means opaque
439 if (selectedColor.GetAlpha() == JSThemeUtils::DEFAULT_ALPHA) {
440 // Default setting of 20% opacity
441 selectedColor = selectedColor.ChangeOpacity(JSThemeUtils::DEFAULT_OPACITY);
442 }
443 TextModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
444 }
445
SetTextSelectableMode(const JSCallbackInfo & info)446 void JSText::SetTextSelectableMode(const JSCallbackInfo& info)
447 {
448 if (info.Length() < 1) {
449 TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
450 return;
451 }
452 if (!info[0]->IsNumber()) {
453 TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
454 return;
455 }
456 auto index = info[0]->ToNumber<int32_t>();
457 if (index < 0 || index >= static_cast<int32_t>(TEXT_SELECTABLE_MODE.size())) {
458 TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
459 return;
460 }
461 TextModel::GetInstance()->SetTextSelectableMode(TEXT_SELECTABLE_MODE[index]);
462 }
463
SetMaxLines(const JSCallbackInfo & info)464 void JSText::SetMaxLines(const JSCallbackInfo& info)
465 {
466 JSRef<JSVal> args = info[0];
467 auto value = Infinity<int32_t>();
468 if (args->ToString() != "Infinity") {
469 ParseJsInt32(args, value);
470 }
471 TextModel::GetInstance()->SetMaxLines(value);
472 }
473
SetTextIndent(const JSCallbackInfo & info)474 void JSText::SetTextIndent(const JSCallbackInfo& info)
475 {
476 CalcDimension value;
477 RefPtr<ResourceObject> resObj;
478 JSRef<JSVal> args = info[0];
479
480 if (!ParseJsDimensionFpNG(args, value, resObj)) {
481 value.Reset();
482 TextModel::GetInstance()->SetTextIndent(value);
483 UnRegisterResource("TextIndent");
484 return;
485 }
486 if (SystemProperties::ConfigChangePerform() && resObj) {
487 RegisterResource<CalcDimension>("TextIndent", resObj, value);
488 }
489 TextModel::GetInstance()->SetTextIndent(value);
490 }
491
SetFontStyle(int32_t value)492 void JSText::SetFontStyle(int32_t value)
493 {
494 if (value < 0 || value >= static_cast<int32_t>(FONT_STYLES.size())) {
495 if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
496 return;
497 }
498 value = 0;
499 }
500 TextModel::GetInstance()->SetItalicFontStyle(FONT_STYLES[value]);
501 }
502
SetTextAlign(int32_t value)503 void JSText::SetTextAlign(int32_t value)
504 {
505 if (value < 0 || value >= static_cast<int32_t>(TEXT_ALIGNS.size())) {
506 if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
507 return;
508 }
509 value = 0;
510 }
511 TextModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
512 }
513
SetAlign(const JSCallbackInfo & info)514 void JSText::SetAlign(const JSCallbackInfo& info)
515 {
516 JSViewAbstract::JsAlign(info);
517 JSRef<JSVal> args = info[0];
518 if (!args->IsNumber()) {
519 return;
520 }
521 TextModel::GetInstance()->OnSetAlign();
522 }
523
SetLineHeight(const JSCallbackInfo & info)524 void JSText::SetLineHeight(const JSCallbackInfo& info)
525 {
526 CalcDimension value;
527 JSRef<JSVal> args = info[0];
528 RefPtr<ResourceObject> resObj;
529
530 if (!ParseJsDimensionFpNG(args, value, resObj)) {
531 value.Reset();
532 TextModel::GetInstance()->SetLineHeight(value);
533 UnRegisterResource("LineHeight");
534 return;
535 }
536 if (SystemProperties::ConfigChangePerform() && resObj) {
537 RegisterResource<CalcDimension>("LineHeight", resObj, value);
538 }
539 if (value.IsNegative()) {
540 value.Reset();
541 }
542 TextModel::GetInstance()->SetLineHeight(value);
543 }
544
SetLineSpacing(const JSCallbackInfo & info)545 void JSText::SetLineSpacing(const JSCallbackInfo& info)
546 {
547 CalcDimension value;
548 JSRef<JSVal> args = info[0];
549 UnRegisterResource("LineSpacing");
550 RefPtr<ResourceObject> resObj;
551 if (!ParseLengthMetricsToPositiveDimension(args, value, resObj)) {
552 value.Reset();
553 }
554 if (value.IsNegative()) {
555 value.Reset();
556 }
557 TextModel::GetInstance()->SetLineSpacing(value);
558 if (SystemProperties::ConfigChangePerform() && resObj) {
559 RegisterResource<CalcDimension>("LineSpacing", resObj, value);
560 }
561 if (info.Length() < 2) { // 2 : two args
562 TextModel::GetInstance()->SetIsOnlyBetweenLines(false);
563 return;
564 }
565 auto jsonValue = info[1];
566 if (!jsonValue->IsObject()) {
567 TextModel::GetInstance()->SetIsOnlyBetweenLines(false);
568 return;
569 }
570 auto paramObject = JSRef<JSObject>::Cast(jsonValue);
571 auto param = paramObject->GetProperty("onlyBetweenLines");
572 if (!param->IsBoolean() || param->IsUndefined() || param->IsNull()) {
573 TextModel::GetInstance()->SetIsOnlyBetweenLines(false);
574 } else {
575 auto isOnlyBetweenLines = param->ToBoolean();
576 TextModel::GetInstance()->SetIsOnlyBetweenLines(isOnlyBetweenLines);
577 }
578 }
579
SetFontFamily(const JSCallbackInfo & info)580 void JSText::SetFontFamily(const JSCallbackInfo& info)
581 {
582 std::vector<std::string> fontFamilies;
583 RefPtr<ResourceObject> resObj;
584 UnRegisterResource("FontFamily");
585 JSRef<JSVal> args = info[0];
586 ParseJsFontFamilies(args, fontFamilies, resObj);
587 if (SystemProperties::ConfigChangePerform() && resObj) {
588 RegisterResource<std::vector<std::string>>("FontFamily", resObj, fontFamilies);
589 }
590 TextModel::GetInstance()->SetFontFamily(fontFamilies);
591 }
592
SetMinFontSize(const JSCallbackInfo & info)593 void JSText::SetMinFontSize(const JSCallbackInfo& info)
594 {
595 if (info.Length() < 1) {
596 return;
597 }
598 auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
599 CHECK_NULL_VOID(pipelineContext);
600 auto theme = pipelineContext->GetTheme<TextTheme>();
601 CHECK_NULL_VOID(theme);
602 CalcDimension minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
603 JSRef<JSVal> args = info[0];
604 RefPtr<ResourceObject> resObj;
605 if (!ParseJsDimensionFpNG(args, minFontSize, resObj, false)) {
606 minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
607 TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
608 UnRegisterResource("AdaptMinFontSize");
609 return;
610 }
611 if (SystemProperties::ConfigChangePerform() && resObj) {
612 RegisterResource<CalcDimension>("AdaptMinFontSize", resObj, minFontSize);
613 }
614 if (minFontSize.IsNegative()) {
615 minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
616 }
617 TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
618 }
619
SetMaxFontSize(const JSCallbackInfo & info)620 void JSText::SetMaxFontSize(const JSCallbackInfo& info)
621 {
622 if (info.Length() < 1) {
623 return;
624 }
625 auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
626 CHECK_NULL_VOID(pipelineContext);
627 auto theme = pipelineContext->GetTheme<TextTheme>();
628 CHECK_NULL_VOID(theme);
629 CalcDimension maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
630 JSRef<JSVal> args = info[0];
631 RefPtr<ResourceObject> resObj;
632 if (!ParseJsDimensionFpNG(args, maxFontSize, resObj, false)) {
633 maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
634 TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
635 UnRegisterResource("AdaptMaxFontSize");
636 return;
637 }
638 if (maxFontSize.IsNegative()) {
639 maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
640 }
641 if (SystemProperties::ConfigChangePerform() && resObj) {
642 RegisterResource<CalcDimension>("AdaptMaxFontSize", resObj, maxFontSize);
643 }
644 TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
645 }
646
SetLetterSpacing(const JSCallbackInfo & info)647 void JSText::SetLetterSpacing(const JSCallbackInfo& info)
648 {
649 CalcDimension value;
650 JSRef<JSVal> args = info[0];
651 RefPtr<ResourceObject> resObj;
652 UnRegisterResource("LetterSpacing");
653 if (!ParseJsDimensionFpNG(args, value, resObj, false)) {
654 value.Reset();
655 TextModel::GetInstance()->SetLetterSpacing(value);
656 return;
657 }
658 if (SystemProperties::ConfigChangePerform() && resObj) {
659 RegisterResource<CalcDimension>("LetterSpacing", resObj, value);
660 }
661 TextModel::GetInstance()->SetLetterSpacing(value);
662 }
663
SetTextCase(int32_t value)664 void JSText::SetTextCase(int32_t value)
665 {
666 if (value < 0 || value >= static_cast<int32_t>(TEXT_CASES.size())) {
667 if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
668 return;
669 }
670 value = 0;
671 }
672 TextModel::GetInstance()->SetTextCase(TEXT_CASES[value]);
673 }
674
SetBaselineOffset(const JSCallbackInfo & info)675 void JSText::SetBaselineOffset(const JSCallbackInfo& info)
676 {
677 CalcDimension value;
678 JSRef<JSVal> args = info[0];
679 RefPtr<ResourceObject> resObj;
680 if (!ParseJsDimensionFpNG(args, value, resObj, false)) {
681 value.Reset();
682 TextModel::GetInstance()->SetBaselineOffset(value);
683 UnRegisterResource("BaselineOffset");
684 return;
685 }
686 if (SystemProperties::ConfigChangePerform() && resObj) {
687 RegisterResource<CalcDimension>("BaselineOffset", resObj, value);
688 }
689 TextModel::GetInstance()->SetBaselineOffset(value);
690 }
691
SetDecoration(const JSCallbackInfo & info)692 void JSText::SetDecoration(const JSCallbackInfo& info)
693 {
694 auto tmpInfo = info[0];
695 UnRegisterResource("TextDecorationColor");
696 if (tmpInfo->IsUndefined()) {
697 TextModel::GetInstance()->SetTextDecoration(TextDecoration::NONE);
698 info.ReturnSelf();
699 return;
700 }
701 if (!tmpInfo->IsObject()) {
702 info.ReturnSelf();
703 return;
704 }
705 JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
706 JSRef<JSVal> typeValue = obj->GetProperty("type");
707 JSRef<JSVal> colorValue = obj->GetProperty("color");
708 JSRef<JSVal> styleValue = obj->GetProperty("style");
709 JSRef<JSVal> thicknessScaleValue = obj->GetProperty("thicknessScale");
710
711 TextDecoration textDecoration;
712 if (typeValue->IsNumber()) {
713 textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
714 } else {
715 auto theme = GetTheme<TextTheme>();
716 CHECK_NULL_VOID(theme);
717 textDecoration = theme->GetTextDecoration();
718 }
719 Color result;
720 RefPtr<ResourceObject> resObj;
721 if (!ParseJsColor(colorValue, result, resObj)) {
722 auto theme = GetTheme<TextTheme>();
723 CHECK_NULL_VOID(theme);
724 if (Container::CurrentColorMode() == ColorMode::DARK) {
725 result = theme->GetTextStyle().GetTextColor();
726 } else {
727 result = theme->GetTextStyle().GetTextDecorationColor();
728 }
729 }
730 if (SystemProperties::ConfigChangePerform() && resObj) {
731 RegisterResource<Color>("TextDecorationColor", resObj, result);
732 }
733 auto style =
734 styleValue->IsNumber() ? styleValue->ToNumber<int32_t>() : static_cast<int32_t>(DEFAULT_TEXT_DECORATION_STYLE);
735 float lineThicknessScale = thicknessScaleValue->IsNumber() ? thicknessScaleValue->ToNumber<float>() : 1.0f;
736 lineThicknessScale = lineThicknessScale < 0 ? 1.0f : lineThicknessScale;
737 TextModel::GetInstance()->SetTextDecoration(textDecoration);
738 TextModel::GetInstance()->SetTextDecorationColor(result);
739 TextModel::GetInstance()->SetTextDecorationStyle(static_cast<TextDecorationStyle>(style));
740 TextModel::GetInstance()->SetLineThicknessScale(lineThicknessScale);
741 info.ReturnSelf();
742 }
743
SetHeightAdaptivePolicy(int32_t value)744 void JSText::SetHeightAdaptivePolicy(int32_t value)
745 {
746 if (value < 0 || value >= static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICY.size())) {
747 if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
748 return;
749 }
750 value = 0;
751 }
752 TextModel::GetInstance()->SetHeightAdaptivePolicy(HEIGHT_ADAPTIVE_POLICY[value]);
753 }
754
JsOnClick(const JSCallbackInfo & info)755 void JSText::JsOnClick(const JSCallbackInfo& info)
756 {
757 JSRef<JSVal> args = info[0];
758 if (Container::IsCurrentUseNewPipeline()) {
759 if (args->IsUndefined() && IsDisableEventVersion()) {
760 TextModel::GetInstance()->ClearOnClick();
761 return;
762 }
763 if (!args->IsFunction()) {
764 return;
765 }
766 auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
767 auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(args));
768 auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = frameNode]
769 (BaseEventInfo* info) {
770 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
771 auto* clickInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
772 ACE_SCORING_EVENT("Text.onClick");
773 PipelineContext::SetCallBackNode(node);
774 func->Execute(*clickInfo);
775 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
776 std::u16string label = u"";
777 auto frameNode = node.Upgrade();
778 if (frameNode) {
779 auto pattern = frameNode->GetPattern();
780 CHECK_NULL_VOID(pattern);
781 auto layoutProperty = pattern->GetLayoutProperty<NG::TextLayoutProperty>();
782 CHECK_NULL_VOID(layoutProperty);
783 label = layoutProperty->GetContent().value_or(u"");
784 }
785 JSInteractableView::ReportClickEvent(node, label);
786 #endif
787 };
788 double distanceThreshold = std::numeric_limits<double>::infinity();
789 if (info.Length() > 1 && info[1]->IsNumber()) {
790 distanceThreshold = info[1]->ToNumber<double>();
791 distanceThreshold = Dimension(distanceThreshold, DimensionUnit::VP).ConvertToPx();
792 }
793 TextModel::GetInstance()->SetOnClick(std::move(onClick), distanceThreshold);
794
795 auto focusHub = NG::ViewStackProcessor::GetInstance()->GetOrCreateMainFrameNodeFocusHub();
796 CHECK_NULL_VOID(focusHub);
797 focusHub->SetFocusable(true, false);
798 } else {
799 JsOnClickWithoutNGBUILD(info);
800 }
801 }
802
JsOnClickWithoutNGBUILD(const JSCallbackInfo & info)803 void JSText::JsOnClickWithoutNGBUILD(const JSCallbackInfo& info)
804 {
805 #ifndef NG_BUILD
806 JSRef<JSVal> args = info[0];
807 if (args->IsFunction()) {
808 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
809 auto impl = inspector ? inspector->GetInspectorFunctionImpl() : nullptr;
810 auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
811 RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(args));
812 auto onClickId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl,
813 node = frameNode](const BaseEventInfo* info) {
814 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
815 const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
816 auto newInfo = *clickInfo;
817 if (impl) {
818 impl->UpdateEventInfo(newInfo);
819 }
820 ACE_SCORING_EVENT("Text.onClick");
821 PipelineContext::SetCallBackNode(node);
822 func->Execute(newInfo);
823 };
824 double distanceThreshold = std::numeric_limits<double>::infinity();
825 if (info.Length() > 1 && info[1]->IsNumber()) {
826 distanceThreshold = info[1]->ToNumber<double>();
827 distanceThreshold = Dimension(distanceThreshold, DimensionUnit::VP).ConvertToPx();
828 }
829 TextModel::GetInstance()->SetOnClick(std::move(onClickId), distanceThreshold);
830 }
831 #endif
832 }
833
JsRemoteMessage(const JSCallbackInfo & info)834 void JSText::JsRemoteMessage(const JSCallbackInfo& info)
835 {
836 JSInteractableView::JsCommonRemoteMessage(info);
837 auto callback = JSInteractableView::GetRemoteMessageEventCallback(info);
838 TextModel::GetInstance()->SetRemoteMessage(std::move(callback));
839 }
840
Create(const JSCallbackInfo & info)841 void JSText::Create(const JSCallbackInfo& info)
842 {
843 std::u16string data;
844 if (info.Length() <= 0) {
845 TextModel::GetInstance()->Create(data);
846 UnRegisterResource("Content");
847 return;
848 }
849
850 if (info[0]->IsObject() && JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>()) {
851 auto *spanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
852 if (spanString == nullptr) {
853 return;
854 }
855 auto spanStringController = spanString->GetController();
856 if (spanStringController) {
857 TextModel::GetInstance()->Create(spanStringController);
858 } else {
859 TextModel::GetInstance()->Create(data);
860 }
861 UnRegisterResource("Content");
862 } else {
863 RefPtr<ResourceObject> resObj;
864 auto ret = ParseJsString(info[0], data, resObj);
865 UtfUtils::HandleInvalidUTF16(reinterpret_cast<uint16_t*>(data.data()), data.length(), 0);
866 TextModel::GetInstance()->Create(data);
867 UnRegisterResource("Content");
868 if (ret && SystemProperties::ConfigChangePerform() && resObj) {
869 RegisterResource<std::u16string>("Content", resObj, data);
870 }
871 }
872
873 if (info.Length() <= 1 || !info[1]->IsObject()) {
874 return;
875 }
876
877 JSTextController* jsController = nullptr;
878 auto paramObject = JSRef<JSObject>::Cast(info[1]);
879 auto controllerObj = paramObject->GetProperty("controller");
880 if (!controllerObj->IsUndefined() && !controllerObj->IsNull() && controllerObj->IsObject()) {
881 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextController>();
882 }
883
884 RefPtr<TextControllerBase> controller = TextModel::GetInstance()->GetTextController();
885 if (!controller) {
886 TAG_LOGW(AceLogTag::ACE_TEXT, "JSText::Create controller is null");
887 }
888
889 if (jsController) {
890 jsController->SetController(controller);
891 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN)) {
892 auto styledString = jsController->GetStyledString();
893 if (styledString && controller) {
894 controller->SetStyledString(styledString, false);
895 jsController->ClearStyledString();
896 }
897 }
898 }
899 }
900
SetCopyOption(const JSCallbackInfo & info)901 void JSText::SetCopyOption(const JSCallbackInfo& info)
902 {
903 if (info.Length() == 0) {
904 return;
905 }
906 auto copyOptions = CopyOptions::None;
907 auto tmpInfo = info[0];
908 if (tmpInfo->IsNumber()) {
909 auto emunNumber = tmpInfo->ToNumber<int>();
910 copyOptions = static_cast<CopyOptions>(emunNumber);
911 }
912 TextModel::GetInstance()->SetCopyOption(copyOptions);
913 }
914
SetOnCopy(const JSCallbackInfo & info)915 void JSText::SetOnCopy(const JSCallbackInfo& info)
916 {
917 JSRef<JSVal> args = info[0];
918 CHECK_NULL_VOID(args->IsFunction());
919 JsEventCallback<void(const std::u16string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(args));
920 TextModel::GetInstance()->SetOnCopy(std::move(callback));
921 }
922
JsOnDragStart(const JSCallbackInfo & info)923 void JSText::JsOnDragStart(const JSCallbackInfo& info)
924 {
925 JSRef<JSVal> args = info[0];
926 CHECK_NULL_VOID(args->IsFunction());
927 RefPtr<JsDragFunction> jsOnDragStartFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(args));
928 WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
929 auto onDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc),
930 targetNode = frameNode](
931 const RefPtr<DragEvent>& info, const std::string& extraParams) -> NG::DragDropBaseInfo {
932 NG::DragDropBaseInfo itemInfo;
933 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo);
934 PipelineContext::SetCallBackNode(targetNode);
935 auto ret = func->Execute(info, extraParams);
936 if (!ret->IsObject()) {
937 return itemInfo;
938 }
939 auto node = ParseDragNode(ret);
940 if (node) {
941 itemInfo.node = node;
942 return itemInfo;
943 }
944 auto builderObj = JSRef<JSObject>::Cast(ret);
945 #if defined(PIXEL_MAP_SUPPORTED)
946 auto pixmap = builderObj->GetProperty("pixelMap");
947 itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap);
948 #endif
949 auto extraInfo = builderObj->GetProperty("extraInfo");
950 ParseJsString(extraInfo, itemInfo.extraInfo);
951 node = ParseDragNode(builderObj->GetProperty("builder"));
952 itemInfo.node = node;
953 return itemInfo;
954 };
955
956 TextModel::GetInstance()->SetOnDragStart(std::move(onDragStart));
957 }
958
JsFocusable(const JSCallbackInfo & info)959 void JSText::JsFocusable(const JSCallbackInfo& info)
960 {
961 auto tmpInfo = info[0];
962 if (!tmpInfo->IsBoolean()) {
963 return;
964 }
965 JSInteractableView::SetFocusable(tmpInfo->ToBoolean());
966 JSInteractableView::SetFocusNode(false);
967 }
968
JsDraggable(const JSCallbackInfo & info)969 void JSText::JsDraggable(const JSCallbackInfo& info)
970 {
971 auto tmpInfo = info[0];
972 if (!tmpInfo->IsBoolean()) {
973 return;
974 }
975 ViewAbstractModel::GetInstance()->SetDraggable(tmpInfo->ToBoolean());
976 }
977
JsEnableDataDetector(const JSCallbackInfo & info)978 void JSText::JsEnableDataDetector(const JSCallbackInfo& info)
979 {
980 if (info.Length() < 1) {
981 LOGI("The argv is wrong, it is supposed to have at least 1 argument");
982 return;
983 }
984 auto tmpInfo = info[0];
985 if (!tmpInfo->IsBoolean()) {
986 TextModel::GetInstance()->SetTextDetectEnable(false);
987 return;
988 }
989 auto enable = tmpInfo->ToBoolean();
990 TextModel::GetInstance()->SetTextDetectEnable(enable);
991 }
992
JsDataDetectorConfig(const JSCallbackInfo & info)993 void JSText::JsDataDetectorConfig(const JSCallbackInfo& info)
994 {
995 if (info.Length() < 1) {
996 LOGI("The argv is wrong, it is supposed to have at least 1 argument");
997 return;
998 }
999 JSRef<JSVal> args = info[0];
1000 if (!args->IsObject()) {
1001 return;
1002 }
1003
1004 TextDetectConfig textDetectConfig;
1005 if (!ParseDataDetectorConfig(info, textDetectConfig)) {
1006 return;
1007 }
1008 TextModel::GetInstance()->SetTextDetectConfig(textDetectConfig);
1009 }
1010
BindSelectionMenu(const JSCallbackInfo & info)1011 void JSText::BindSelectionMenu(const JSCallbackInfo& info)
1012 {
1013 // TextSpanType
1014 NG::TextSpanType textSpanType = NG::TextSpanType::TEXT;
1015 bool isValidTextSpanType = true;
1016 JSRef<JSVal> argsSpanType = info[0];
1017 if (argsSpanType->IsNumber()) {
1018 auto spanTypeId = argsSpanType->ToNumber<int32_t>();
1019 isValidTextSpanType = NG::TextSpanTypeMapper::GetTextSpanTypeFromJsType(spanTypeId, textSpanType);
1020 }
1021
1022 // Builder
1023 JSRef<JSVal> argsMenuObj = info[1];
1024 if (!argsMenuObj->IsObject()) {
1025 return;
1026 }
1027 JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(argsMenuObj);
1028 auto builder = menuObj->GetProperty("builder");
1029 if (!builder->IsFunction()) {
1030 return;
1031 }
1032 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
1033 CHECK_NULL_VOID(builderFunc);
1034
1035 // TextResponseType
1036 uint32_t resquiredParameterCount = 3;
1037 JSRef<JSVal> argsResponse = info[resquiredParameterCount - 1];
1038 NG::TextResponseType responseType = NG::TextResponseType::LONG_PRESS;
1039 if (argsResponse->IsNumber()) {
1040 auto response = argsResponse->ToNumber<int32_t>();
1041 responseType = static_cast<NG::TextResponseType>(response);
1042 }
1043
1044 WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1045 std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc),
1046 node = frameNode]() {
1047 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1048 ACE_SCORING_EVENT("BindSelectionMenu");
1049 PipelineContext::SetCallBackNode(node);
1050 func->Execute();
1051 };
1052
1053 // SelectionMenuOptions
1054 NG::SelectMenuParam menuParam;
1055 menuParam.isValid = isValidTextSpanType;
1056 if (info.Length() > static_cast<uint32_t>(resquiredParameterCount)) {
1057 JSRef<JSVal> argsMenuOptions = info[resquiredParameterCount];
1058 if (argsMenuOptions->IsObject()) {
1059 ParseMenuParam(info, argsMenuOptions, menuParam);
1060 }
1061 }
1062
1063 TextModel::GetInstance()->BindSelectionMenu(textSpanType, responseType, buildFunc, menuParam);
1064 }
1065
SetOnTextSelectionChange(const JSCallbackInfo & info)1066 void JSText::SetOnTextSelectionChange(const JSCallbackInfo& info)
1067 {
1068 JSRef<JSVal> args = info[0];
1069 CHECK_NULL_VOID(args->IsFunction());
1070 JsEventCallback<void(int32_t, int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(args));
1071 TextModel::GetInstance()->SetOnTextSelectionChange(std::move(callback));
1072 }
1073
JsClip(const JSCallbackInfo & info)1074 void JSText::JsClip(const JSCallbackInfo& info)
1075 {
1076 JSViewAbstract::JsClip(info);
1077 JSRef<JSVal> args = info[0];
1078 if (args->IsBoolean()) {
1079 TextModel::GetInstance()->SetClipEdge(args->ToBoolean());
1080 }
1081 }
1082
SetFontFeature(const JSCallbackInfo & info)1083 void JSText::SetFontFeature(const JSCallbackInfo& info)
1084 {
1085 if (info.Length() < 1) {
1086 return;
1087 }
1088
1089 if (!info[0]->IsString() && !info[0]->IsObject()) {
1090 return;
1091 }
1092 std::string fontFeatureSettings = info[0]->ToString();
1093 TextModel::GetInstance()->SetFontFeature(ParseFontFeatureSettings(fontFeatureSettings));
1094 }
1095
JsResponseRegion(const JSCallbackInfo & info)1096 void JSText::JsResponseRegion(const JSCallbackInfo& info)
1097 {
1098 JSViewAbstract::JsResponseRegion(info);
1099 TextModel::GetInstance()->SetResponseRegion(true);
1100 }
1101
SetHalfLeading(const JSCallbackInfo & info)1102 void JSText::SetHalfLeading(const JSCallbackInfo& info)
1103 {
1104 if (info.Length() < 1) {
1105 return;
1106 }
1107 auto halfLeading = info[0];
1108 if (!halfLeading->IsBoolean()) {
1109 TextModel::GetInstance()->SetHalfLeading(false);
1110 return;
1111 }
1112 auto enable = halfLeading->ToBoolean();
1113 TextModel::GetInstance()->SetHalfLeading(enable);
1114 }
1115
SetEnableHapticFeedback(const JSCallbackInfo & info)1116 void JSText::SetEnableHapticFeedback(const JSCallbackInfo& info)
1117 {
1118 bool state = true;
1119 if (info.Length() > 0 && info[0]->IsBoolean()) {
1120 state = info[0]->ToBoolean();
1121 }
1122 TextModel::GetInstance()->SetEnableHapticFeedback(state);
1123 }
1124
SetOptimizeTrailingSpace(const JSCallbackInfo & info)1125 void JSText::SetOptimizeTrailingSpace(const JSCallbackInfo& info)
1126 {
1127 bool state = false;
1128
1129 if (info.Length() > 0 && info[0]->IsBoolean()) {
1130 state = info[0]->ToBoolean();
1131 }
1132
1133 TextModel::GetInstance()->SetOptimizeTrailingSpace(state);
1134 }
1135
SetEnableAutoSpacing(const JSCallbackInfo & info)1136 void JSText::SetEnableAutoSpacing(const JSCallbackInfo& info)
1137 {
1138 bool enabled = false;
1139 if (info.Length() > 0 && info[0]->IsBoolean()) {
1140 enabled = info[0]->ToBoolean();
1141 }
1142 TextModel::GetInstance()->SetEnableAutoSpacing(enabled);
1143 }
1144
SetTextVerticalAlign(const JSCallbackInfo & info)1145 void JSText::SetTextVerticalAlign(const JSCallbackInfo& info)
1146 {
1147 TextVerticalAlign verticalAlign = TextVerticalAlign::BASELINE;
1148 if (info.Length() > 0 && info[0]->IsNumber()) {
1149 verticalAlign = static_cast<TextVerticalAlign>(info[0]->ToNumber<int32_t>());
1150 }
1151 TextModel::GetInstance()->SetTextVerticalAlign(verticalAlign);
1152 }
1153
SetShaderStyle(const JSCallbackInfo & info)1154 void JSText::SetShaderStyle(const JSCallbackInfo& info)
1155 {
1156 if (info.Length() < 1 || !info[0]->IsObject()) {
1157 TextModel::GetInstance()->ResetGradientShaderStyle();
1158 return;
1159 }
1160 NG::Gradient gradient;
1161 ParseShaderStyle(info, gradient);
1162 }
1163
ParseShaderStyle(const JSCallbackInfo & info,NG::Gradient & gradient)1164 void JSText::ParseShaderStyle(const JSCallbackInfo& info, NG::Gradient& gradient)
1165 {
1166 CalcDimension value;
1167 if (info.Length() < 1 || (info.Length() > 0 && !info[0]->IsObject())) {
1168 TextModel::GetInstance()->ResetGradientShaderStyle();
1169 return;
1170 }
1171 auto shaderStyleObj = JSRef<JSObject>::Cast(info[0]);
1172 if (shaderStyleObj->HasProperty("options")) {
1173 auto optionsValue = shaderStyleObj->GetProperty("options");
1174 shaderStyleObj = JSRef<JSObject>::Cast(optionsValue);
1175 }
1176 if (shaderStyleObj->HasProperty("center") && shaderStyleObj->HasProperty("radius")) {
1177 NewRadialGradient(shaderStyleObj, gradient);
1178 TextModel::GetInstance()->SetGradientShaderStyle(gradient);
1179 } else if (shaderStyleObj->HasProperty("colors")) {
1180 NewLinearGradient(shaderStyleObj, gradient);
1181 TextModel::GetInstance()->SetGradientShaderStyle(gradient);
1182 } else if (shaderStyleObj->HasProperty("color")) {
1183 Color textColor;
1184 auto infoColor = shaderStyleObj->GetProperty("color");
1185 ParseJsColor(infoColor, textColor);
1186 TextModel::GetInstance()->SetColorShaderStyle(textColor);
1187 } else {
1188 TextModel::GetInstance()->ResetGradientShaderStyle();
1189 }
1190 }
1191
SetContentTransition(const JSCallbackInfo & info)1192 void JSText::SetContentTransition(const JSCallbackInfo& info)
1193 {
1194 if (info.Length() > 0 && !info[0]->IsObject()) {
1195 TextModel::GetInstance()->ResetContentTransition();
1196 return;
1197 }
1198 auto contentTransitionObj = JSRef<JSObject>::Cast(info[0]);
1199 TextFlipDirection direction = TextFlipDirection::DOWN;
1200 bool enableBlur = false;
1201 if (contentTransitionObj->HasProperty("flipDirection")) {
1202 auto directionObj = contentTransitionObj->GetProperty("flipDirection");
1203 if (directionObj->IsNumber()) {
1204 direction = static_cast<TextFlipDirection>(directionObj->ToNumber<int32_t>());
1205 }
1206 }
1207 if (contentTransitionObj->HasProperty("enableBlur")) {
1208 auto enableBlurObj = contentTransitionObj->GetProperty("enableBlur");
1209 if (enableBlurObj->IsBoolean()) {
1210 enableBlur = enableBlurObj->ToBoolean();
1211 }
1212 }
1213 TextModel::GetInstance()->SetContentTransition(TextEffectStrategy::FLIP, direction, enableBlur);
1214 }
1215
JSBind(BindingTarget globalObj)1216 void JSText::JSBind(BindingTarget globalObj)
1217 {
1218 JSClass<JSText>::Declare("Text");
1219 MethodOptions opt = MethodOptions::NONE;
1220 JSClass<JSText>::StaticMethod("create", &JSText::Create, opt);
1221 JSClass<JSText>::StaticMethod("width", &JSText::SetWidth);
1222 JSClass<JSText>::StaticMethod("height", &JSText::SetHeight);
1223 JSClass<JSText>::StaticMethod("font", &JSText::SetFont, opt);
1224 JSClass<JSText>::StaticMethod("fontColor", &JSText::SetTextColor, opt);
1225 JSClass<JSText>::StaticMethod("textShadow", &JSText::SetTextShadow, opt);
1226 JSClass<JSText>::StaticMethod("fontSize", &JSText::SetFontSize, opt);
1227 JSClass<JSText>::StaticMethod("fontWeight", &JSText::SetFontWeight, opt);
1228 JSClass<JSText>::StaticMethod("minFontScale", &JSText::SetMinFontScale, opt);
1229 JSClass<JSText>::StaticMethod("maxFontScale", &JSText::SetMaxFontScale, opt);
1230 JSClass<JSText>::StaticMethod("wordBreak", &JSText::SetWordBreak, opt);
1231 JSClass<JSText>::StaticMethod("lineBreakStrategy", &JSText::SetLineBreakStrategy, opt);
1232 JSClass<JSText>::StaticMethod("selection", &JSText::SetTextSelection, opt);
1233 JSClass<JSText>::StaticMethod("ellipsisMode", &JSText::SetEllipsisMode, opt);
1234 JSClass<JSText>::StaticMethod("textSelectable", &JSText::SetTextSelectableMode, opt);
1235 JSClass<JSText>::StaticMethod("maxLines", &JSText::SetMaxLines, opt);
1236 JSClass<JSText>::StaticMethod("textIndent", &JSText::SetTextIndent);
1237 JSClass<JSText>::StaticMethod("textOverflow", &JSText::SetTextOverflow, opt);
1238 JSClass<JSText>::StaticMethod("fontStyle", &JSText::SetFontStyle, opt);
1239 JSClass<JSText>::StaticMethod("align", &JSText::SetAlign, opt);
1240 JSClass<JSText>::StaticMethod("textAlign", &JSText::SetTextAlign, opt);
1241 JSClass<JSText>::StaticMethod("lineHeight", &JSText::SetLineHeight, opt);
1242 JSClass<JSText>::StaticMethod("lineSpacing", &JSText::SetLineSpacing, opt);
1243 JSClass<JSText>::StaticMethod("fontFamily", &JSText::SetFontFamily, opt);
1244 JSClass<JSText>::StaticMethod("minFontSize", &JSText::SetMinFontSize, opt);
1245 JSClass<JSText>::StaticMethod("maxFontSize", &JSText::SetMaxFontSize, opt);
1246 JSClass<JSText>::StaticMethod("letterSpacing", &JSText::SetLetterSpacing, opt);
1247 JSClass<JSText>::StaticMethod("textCase", &JSText::SetTextCase, opt);
1248 JSClass<JSText>::StaticMethod("baselineOffset", &JSText::SetBaselineOffset, opt);
1249 JSClass<JSText>::StaticMethod("caretColor", &JSText::SetTextCaretColor);
1250 JSClass<JSText>::StaticMethod("selectedBackgroundColor", &JSText::SetSelectedBackgroundColor);
1251 JSClass<JSText>::StaticMethod("decoration", &JSText::SetDecoration);
1252 JSClass<JSText>::StaticMethod("heightAdaptivePolicy", &JSText::SetHeightAdaptivePolicy);
1253 JSClass<JSText>::StaticMethod("contentTransition", &JSText::SetContentTransition);
1254 JSClass<JSText>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
1255 JSClass<JSText>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
1256 JSClass<JSText>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
1257 JSClass<JSText>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
1258 JSClass<JSText>::StaticMethod("remoteMessage", &JSText::JsRemoteMessage);
1259 JSClass<JSText>::StaticMethod("copyOption", &JSText::SetCopyOption);
1260 JSClass<JSText>::StaticMethod("onClick", &JSText::JsOnClick);
1261 JSClass<JSText>::StaticMethod("onCopy", &JSText::SetOnCopy);
1262 JSClass<JSText>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
1263 JSClass<JSText>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
1264 JSClass<JSText>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
1265 JSClass<JSText>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
1266 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FIFTEEN)) {
1267 JSClass<JSText>::StaticMethod("onDragStart", &JSText::JsOnDragStart);
1268 } else {
1269 JSClass<JSText>::StaticMethod("onDragStart", &JSViewAbstract::JsOnDragStart);
1270 }
1271 JSClass<JSText>::StaticMethod("focusable", &JSText::JsFocusable);
1272 JSClass<JSText>::StaticMethod("draggable", &JSText::JsDraggable);
1273 JSClass<JSText>::StaticMethod("enableDataDetector", &JSText::JsEnableDataDetector);
1274 JSClass<JSText>::StaticMethod("dataDetectorConfig", &JSText::JsDataDetectorConfig);
1275 JSClass<JSText>::StaticMethod("bindSelectionMenu", &JSText::BindSelectionMenu);
1276 JSClass<JSText>::StaticMethod("onTextSelectionChange", &JSText::SetOnTextSelectionChange);
1277 JSClass<JSText>::StaticMethod("clip", &JSText::JsClip);
1278 JSClass<JSText>::StaticMethod("foregroundColor", &JSText::SetForegroundColor);
1279 JSClass<JSText>::StaticMethod("fontFeature", &JSText::SetFontFeature);
1280 JSClass<JSText>::StaticMethod("marqueeOptions", &JSText::SetMarqueeOptions);
1281 JSClass<JSText>::StaticMethod("onMarqueeStateChange", &JSText::SetOnMarqueeStateChange);
1282 JSClass<JSText>::StaticMethod("editMenuOptions", &JSText::EditMenuOptions);
1283 JSClass<JSText>::StaticMethod("responseRegion", &JSText::JsResponseRegion);
1284 JSClass<JSText>::StaticMethod("halfLeading", &JSText::SetHalfLeading);
1285 JSClass<JSText>::StaticMethod("enableHapticFeedback", &JSText::SetEnableHapticFeedback);
1286 JSClass<JSText>::StaticMethod("optimizeTrailingSpace", &JSText::SetOptimizeTrailingSpace);
1287 JSClass<JSText>::StaticMethod("enableAutoSpacing", &JSText::SetEnableAutoSpacing);
1288 JSClass<JSText>::StaticMethod("textVerticalAlign", &JSText::SetTextVerticalAlign);
1289 JSClass<JSText>::StaticMethod("shaderStyle", &JSText::SetShaderStyle);
1290 JSClass<JSText>::InheritAndBind<JSContainerBase>(globalObj);
1291 }
1292
CloseSelectionMenu()1293 void JSTextController::CloseSelectionMenu()
1294 {
1295 auto controller = controllerWeak_.Upgrade();
1296 CHECK_NULL_VOID(controller);
1297 controller->CloseSelectionMenu();
1298 }
1299
GetLayoutManager(const JSCallbackInfo & args)1300 void JSTextController::GetLayoutManager(const JSCallbackInfo& args)
1301 {
1302 JSRef<JSObject> obj = JSClass<JSLayoutManager>::NewInstance();
1303 auto jsLayoutManager = Referenced::Claim(obj->Unwrap<JSLayoutManager>());
1304 CHECK_NULL_VOID(jsLayoutManager);
1305 jsLayoutManager->IncRefCount();
1306 auto controller = controllerWeak_.Upgrade();
1307 CHECK_NULL_VOID(controller);
1308 auto layoutInfoInterface = controller->GetLayoutInfoInterface();
1309 jsLayoutManager->SetLayoutInfoInterface(layoutInfoInterface);
1310 args.SetReturnValue(obj);
1311 }
1312
SetStyledString(const JSCallbackInfo & info)1313 void JSTextController::SetStyledString(const JSCallbackInfo& info)
1314 {
1315 if (info.Length() != 1 || !info[0]->IsObject()) {
1316 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1317 return;
1318 }
1319 auto* spanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
1320 if (!spanString) {
1321 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1322 return;
1323 }
1324 auto spanStringController = spanString->GetController();
1325 CHECK_NULL_VOID(spanStringController);
1326 auto controller = controllerWeak_.Upgrade();
1327 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN) && !controller) {
1328 styledString_ = spanStringController;
1329 }
1330 CHECK_NULL_VOID(controller);
1331 controller->SetStyledString(spanStringController, true);
1332 auto thisObj = info.This();
1333 thisObj->SetPropertyObject("STYLED_STRING_IN_CONTROLLER", info[0]);
1334 }
1335
JSBind(BindingTarget globalObj)1336 void JSTextController::JSBind(BindingTarget globalObj)
1337 {
1338 JSClass<JSTextController>::Declare("TextController");
1339 JSClass<JSTextController>::Method("closeSelectionMenu", &JSTextController::CloseSelectionMenu);
1340 JSClass<JSTextController>::CustomMethod("setStyledString", &JSTextController::SetStyledString);
1341 JSClass<JSTextController>::CustomMethod("getLayoutManager", &JSTextController::GetLayoutManager);
1342 JSClass<JSTextController>::Bind(globalObj, JSTextController::Constructor, JSTextController::Destructor);
1343 }
1344
ParseMenuParam(const JSCallbackInfo & info,const JSRef<JSObject> & menuOptions,NG::SelectMenuParam & menuParam)1345 void JSText::ParseMenuParam(
1346 const JSCallbackInfo& info, const JSRef<JSObject>& menuOptions, NG::SelectMenuParam& menuParam)
1347 {
1348 WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1349 auto onAppearValue = menuOptions->GetProperty("onAppear");
1350 if (onAppearValue->IsFunction()) {
1351 RefPtr<JsFunction> jsOnAppearFunc =
1352 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAppearValue));
1353 auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc), node = frameNode](
1354 int32_t start, int32_t end) {
1355 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1356 ACE_SCORING_EVENT("onAppear");
1357
1358 JSRef<JSVal> params[2];
1359 params[0] = JSRef<JSVal>::Make(ToJSValue(start));
1360 params[1] = JSRef<JSVal>::Make(ToJSValue(end));
1361 PipelineContext::SetCallBackNode(node);
1362 func->ExecuteJS(2, params);
1363 };
1364 menuParam.onAppear = std::move(onAppear);
1365 }
1366
1367 auto onDisappearValue = menuOptions->GetProperty("onDisappear");
1368 if (onDisappearValue->IsFunction()) {
1369 RefPtr<JsFunction> jsOnDisAppearFunc =
1370 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDisappearValue));
1371 auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc),
1372 node = frameNode]() {
1373 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1374 ACE_SCORING_EVENT("onDisappear");
1375 PipelineContext::SetCallBackNode(node);
1376 func->Execute();
1377 };
1378 menuParam.onDisappear = std::move(onDisappear);
1379 }
1380 menuParam.onMenuShow = ParseMenuCallback(frameNode, menuOptions, info, "onMenuShow");
1381 menuParam.onMenuHide = ParseMenuCallback(frameNode, menuOptions, info, "onMenuHide");
1382 menuParam.previewMenuOptions = ParsePreviewMenuOptions(menuOptions);
1383 }
1384
ParseMenuCallback(const WeakPtr<NG::FrameNode> & frameNode,const JSRef<JSObject> & menuOptions,const JSCallbackInfo & info,const std::string & name)1385 std::function<void(int32_t, int32_t)> JSText::ParseMenuCallback(const WeakPtr<NG::FrameNode>& frameNode,
1386 const JSRef<JSObject>& menuOptions, const JSCallbackInfo& info, const std::string& name)
1387 {
1388 auto onMenuCallbackValue = menuOptions->GetProperty(name.c_str());
1389 if (onMenuCallbackValue->IsFunction()) {
1390 RefPtr<JsFunction> jsOnMenuCallbackFunc =
1391 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onMenuCallbackValue));
1392 auto onMenuCallback = [execCtx = info.GetExecutionContext(), func = std::move(jsOnMenuCallbackFunc),
1393 node = frameNode, eventName = name](int32_t start, int32_t end) {
1394 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1395 ACE_SCORING_EVENT(eventName);
1396
1397 JSRef<JSVal> params[2];
1398 params[0] = JSRef<JSVal>::Make(ToJSValue(start));
1399 params[1] = JSRef<JSVal>::Make(ToJSValue(end));
1400 PipelineContext::SetCallBackNode(node);
1401 func->ExecuteJS(2, params);
1402 };
1403 return onMenuCallback;
1404 }
1405 return nullptr;
1406 }
1407
ParsePreviewMenuOptions(const JSRef<JSObject> & menuOptions)1408 NG::PreviewMenuOptions JSText::ParsePreviewMenuOptions(const JSRef<JSObject>& menuOptions)
1409 {
1410 NG::PreviewMenuOptions previewMenuOptions;
1411 auto jsPreviewMenuOp = menuOptions->GetProperty("previewMenuOptions");
1412 CHECK_EQUAL_RETURN(jsPreviewMenuOp->IsObject(), false, previewMenuOptions);
1413 auto jsPreviewMenuOpObj = JSRef<JSObject>::Cast(jsPreviewMenuOp);
1414 CHECK_EQUAL_RETURN(jsPreviewMenuOpObj->IsUndefined(), true, previewMenuOptions);
1415 JSRef<JSVal> jsHapticFeedbackMode = jsPreviewMenuOpObj->GetProperty("hapticFeedbackMode");
1416 CHECK_EQUAL_RETURN(jsHapticFeedbackMode->IsNumber(), false, previewMenuOptions);
1417 auto hapticFeedbackMode = static_cast<HapticFeedbackMode>(jsHapticFeedbackMode->ToNumber<int32_t>());
1418 if (hapticFeedbackMode >= HapticFeedbackMode::DISABLED && hapticFeedbackMode <= HapticFeedbackMode::AUTO) {
1419 previewMenuOptions.hapticFeedbackMode = hapticFeedbackMode;
1420 }
1421 return previewMenuOptions;
1422 }
1423
SetMarqueeOptions(const JSCallbackInfo & info)1424 void JSText::SetMarqueeOptions(const JSCallbackInfo& info)
1425 {
1426 if (info.Length() < 1) {
1427 return;
1428 }
1429
1430 auto args = info[0];
1431 NG::TextMarqueeOptions options;
1432
1433 if (!args->IsObject()) {
1434 TextModel::GetInstance()->SetMarqueeOptions(options);
1435 return;
1436 }
1437
1438 auto paramObject = JSRef<JSObject>::Cast(args);
1439 ParseMarqueeParam(paramObject, options);
1440 TextModel::GetInstance()->SetMarqueeOptions(options);
1441 }
1442
ParseMarqueeParam(const JSRef<JSObject> & paramObject,NG::TextMarqueeOptions & options)1443 void JSText::ParseMarqueeParam(const JSRef<JSObject>& paramObject, NG::TextMarqueeOptions& options)
1444 {
1445 auto getStart = paramObject->GetProperty("start");
1446 if (getStart->IsBoolean()) {
1447 options.UpdateTextMarqueeStart(getStart->ToBoolean());
1448 }
1449
1450 auto getLoop = paramObject->GetProperty("loop");
1451 if (getLoop->IsNumber()) {
1452 int32_t loop = static_cast<int32_t>(getLoop->ToNumber<double>());
1453 if (loop == std::numeric_limits<int32_t>::max() || loop <= 0) {
1454 loop = -1;
1455 }
1456 options.UpdateTextMarqueeLoop(loop);
1457 }
1458
1459 auto getStep = paramObject->GetProperty("step");
1460 if (getStep->IsNumber()) {
1461 auto step = getStep->ToNumber<double>();
1462 if (GreatNotEqual(step, 0.0)) {
1463 options.UpdateTextMarqueeStep(Dimension(step, DimensionUnit::VP).ConvertToPx());
1464 }
1465 }
1466
1467 auto delay = paramObject->GetProperty("delay");
1468 if (delay->IsNumber()) {
1469 auto delayDouble = delay->ToNumber<double>();
1470 auto delayValue = static_cast<int32_t>(delayDouble);
1471 if (delayValue < 0) {
1472 delayValue = 0;
1473 }
1474 options.UpdateTextMarqueeDelay(delayValue);
1475 }
1476
1477 auto getFromStart = paramObject->GetProperty("fromStart");
1478 if (getFromStart->IsBoolean()) {
1479 options.UpdateTextMarqueeDirection(
1480 getFromStart->ToBoolean() ? MarqueeDirection::DEFAULT : MarqueeDirection::DEFAULT_REVERSE);
1481 }
1482
1483 auto getFadeout = paramObject->GetProperty("fadeout");
1484 if (getFadeout->IsBoolean()) {
1485 options.UpdateTextMarqueeFadeout(getFadeout->ToBoolean());
1486 }
1487
1488 auto getStartPolicy = paramObject->GetProperty("marqueeStartPolicy");
1489 if (getStartPolicy->IsNumber()) {
1490 auto startPolicy = static_cast<MarqueeStartPolicy>(getStartPolicy->ToNumber<int32_t>());
1491 options.UpdateTextMarqueeStartPolicy(startPolicy);
1492 }
1493 }
1494
SetOnMarqueeStateChange(const JSCallbackInfo & info)1495 void JSText::SetOnMarqueeStateChange(const JSCallbackInfo& info)
1496 {
1497 if (!info[0]->IsFunction()) {
1498 return;
1499 }
1500
1501 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
1502 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1503 auto onMarqueeStateChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
1504 int32_t value) {
1505 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1506 ACE_SCORING_EVENT("Text.onMarqueeStateChange");
1507 PipelineContext::SetCallBackNode(node);
1508 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(value));
1509 func->ExecuteJS(1, &newJSVal);
1510 };
1511
1512 TextModel::GetInstance()->SetOnMarqueeStateChange(std::move(onMarqueeStateChange));
1513 }
1514
EditMenuOptions(const JSCallbackInfo & info)1515 void JSText::EditMenuOptions(const JSCallbackInfo& info)
1516 {
1517 NG::OnCreateMenuCallback onCreateMenuCallback;
1518 NG::OnMenuItemClickCallback onMenuItemClick;
1519 NG::OnPrepareMenuCallback onPrepareMenuCallback;
1520 JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick, onPrepareMenuCallback);
1521 TextModel::GetInstance()->SetSelectionMenuOptions(
1522 std::move(onCreateMenuCallback), std::move(onMenuItemClick), std::move(onPrepareMenuCallback));
1523 }
1524 } // namespace OHOS::Ace::Framework
1525