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_text_theme.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/text/text_theme.h"
50 #include "core/components_ng/base/view_stack_processor.h"
51 #include "core/components_ng/event/gesture_event_hub.h"
52 #include "core/components_ng/pattern/text/text_model.h"
53 #include "core/components_ng/pattern/text/text_model_ng.h"
54 #include "core/event/ace_event_handler.h"
55 #include "core/pipeline/pipeline_base.h"
56 
57 namespace OHOS::Ace {
58 
59 std::unique_ptr<TextModel> TextModel::instance_ = nullptr;
60 std::mutex TextModel::mutex_;
61 
GetInstance()62 TextModel* TextModel::GetInstance()
63 {
64 #ifdef NG_BUILD
65     static NG::TextModelNG instance;
66     return &instance;
67 #else
68     if (Container::IsCurrentUseNewPipeline()) {
69         static NG::TextModelNG instance;
70         return &instance;
71     } else {
72         static Framework::TextModelImpl instance;
73         return &instance;
74     }
75 #endif
76 }
77 
78 } // namespace OHOS::Ace
79 
80 namespace OHOS::Ace::Framework {
81 namespace {
82 
83 const std::vector<TextCase> TEXT_CASES = { TextCase::NORMAL, TextCase::LOWERCASE, TextCase::UPPERCASE };
84 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
85     TextOverflow::MARQUEE };
86 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
87 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END, TextAlign::JUSTIFY,
88     TextAlign::LEFT, TextAlign::RIGHT };
89 const std::vector<TextHeightAdaptivePolicy> HEIGHT_ADAPTIVE_POLICY = { TextHeightAdaptivePolicy::MAX_LINES_FIRST,
90     TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST };
91 const std::vector<LineBreakStrategy> LINE_BREAK_STRATEGY_TYPES = { LineBreakStrategy::GREEDY,
92     LineBreakStrategy::HIGH_QUALITY, LineBreakStrategy::BALANCED };
93 const std::vector<EllipsisMode> ELLIPSIS_MODALS = { EllipsisMode::HEAD, EllipsisMode::MIDDLE, EllipsisMode::TAIL };
94 const std::vector<TextSelectableMode> TEXT_SELECTABLE_MODE = { TextSelectableMode::SELECTABLE_UNFOCUSABLE,
95     TextSelectableMode::SELECTABLE_FOCUSABLE, TextSelectableMode::UNSELECTABLE };
96 constexpr TextDecorationStyle DEFAULT_TEXT_DECORATION_STYLE = TextDecorationStyle::SOLID;
97 const int32_t DEFAULT_VARIABLE_FONT_WEIGHT = 400;
98 }; // namespace
99 
SetWidth(const JSCallbackInfo & info)100 void JSText::SetWidth(const JSCallbackInfo& info)
101 {
102     JSViewAbstract::JsWidth(info);
103     TextModel::GetInstance()->OnSetWidth();
104 }
105 
SetHeight(const JSCallbackInfo & info)106 void JSText::SetHeight(const JSCallbackInfo& info)
107 {
108     JSViewAbstract::JsHeight(info);
109     TextModel::GetInstance()->OnSetHeight();
110 }
111 
SetFont(const JSCallbackInfo & info)112 void JSText::SetFont(const JSCallbackInfo& info)
113 {
114     Font font;
115     GetFontInfo(info, font);
116     TextModel::GetInstance()->SetFont(font);
117     if (info.Length() < 2) { // 2 : two args
118         return;
119     }
120     auto tmpInfo = info[1];
121     if (!tmpInfo->IsObject()) {
122         return;
123     }
124     auto paramObject = JSRef<JSObject>::Cast(tmpInfo);
125     auto enableVariableFontWeight = paramObject->GetProperty("enableVariableFontWeight");
126     if (enableVariableFontWeight->IsBoolean()) {
127         TextModel::GetInstance()->SetEnableVariableFontWeight(enableVariableFontWeight->ToBoolean());
128     } else {
129         TextModel::GetInstance()->SetEnableVariableFontWeight(false);
130     }
131 }
132 
GetFontInfo(const JSCallbackInfo & info,Font & font)133 void JSText::GetFontInfo(const JSCallbackInfo& info, Font& font)
134 {
135     auto tmpInfo = info[0];
136     auto pipelineContext = PipelineContext::GetCurrentContext();
137     CHECK_NULL_VOID(pipelineContext);
138     auto theme = pipelineContext->GetTheme<TextTheme>();
139     CHECK_NULL_VOID(theme);
140     font.fontSize = theme->GetTextStyle().GetFontSize();
141     font.fontWeight = theme->GetTextStyle().GetFontWeight();
142     font.fontFamilies = theme->GetTextStyle().GetFontFamilies();
143     font.fontStyle = theme->GetTextStyle().GetFontStyle();
144 
145     if (!tmpInfo->IsObject()) {
146         return;
147     }
148     auto paramObject = JSRef<JSObject>::Cast(tmpInfo);
149     auto fontSize = paramObject->GetProperty(static_cast<int32_t>(ArkUIIndex::SIZE));
150     CalcDimension size;
151     if (ParseJsDimensionFpNG(fontSize, size, false) && size.IsNonNegative()) {
152         font.fontSize = size;
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         if (JSContainerBase::ParseJsFontFamilies(fontFamily, fontFamilies)) {
171             font.fontFamilies = fontFamilies;
172         }
173     }
174     auto style = paramObject->GetProperty(static_cast<int32_t>(ArkUIIndex::STYLE));
175     if (!style->IsNull() || style->IsNumber()) {
176         font.fontStyle = static_cast<FontStyle>(style->ToNumber<int32_t>());
177     }
178 }
179 
SetFontSize(const JSCallbackInfo & info)180 void JSText::SetFontSize(const JSCallbackInfo& info)
181 {
182     if (info.Length() < 1) {
183         return;
184     }
185     CalcDimension fontSize;
186     JSRef<JSVal> args = info[0];
187     if (!ParseJsDimensionFpNG(args, fontSize, false) || fontSize.IsNegative()) {
188         auto pipelineContext = PipelineBase::GetCurrentContext();
189         CHECK_NULL_VOID(pipelineContext);
190         auto theme = pipelineContext->GetTheme<TextTheme>();
191         CHECK_NULL_VOID(theme);
192         fontSize = theme->GetTextStyle().GetFontSize();
193         TextModel::GetInstance()->SetFontSize(fontSize);
194         return;
195     }
196     TextModel::GetInstance()->SetFontSize(fontSize);
197 }
198 
SetFontWeight(const JSCallbackInfo & info)199 void JSText::SetFontWeight(const JSCallbackInfo& info)
200 {
201     if (info.Length() < 1) {
202         return;
203     }
204     JSRef<JSVal> args = info[0];
205     std::string fontWeight;
206     int32_t variableFontWeight = DEFAULT_VARIABLE_FONT_WEIGHT;
207     ParseJsInt32(args, variableFontWeight);
208     TextModel::GetInstance()->SetVariableFontWeight(variableFontWeight);
209 
210     if (args->IsNumber()) {
211         fontWeight = args->ToString();
212     } else {
213         ParseJsString(args, fontWeight);
214     }
215     TextModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(fontWeight));
216 
217     if (info.Length() < 2) { // 2 : two args
218         return;
219     }
220     auto tmpInfo = info[1];
221     if (!tmpInfo->IsObject()) {
222         return;
223     }
224     auto paramObject = JSRef<JSObject>::Cast(tmpInfo);
225     auto enableVariableFontWeight = paramObject->GetProperty("enableVariableFontWeight");
226     if (enableVariableFontWeight->IsBoolean()) {
227         TextModel::GetInstance()->SetEnableVariableFontWeight(enableVariableFontWeight->ToBoolean());
228     } else {
229         TextModel::GetInstance()->SetEnableVariableFontWeight(false);
230     }
231 }
232 
SetMinFontScale(const JSCallbackInfo & info)233 void JSText::SetMinFontScale(const JSCallbackInfo& info)
234 {
235     double minFontScale;
236     if (info.Length() < 1 || !ParseJsDouble(info[0], minFontScale)) {
237         return;
238     }
239     if (LessOrEqual(minFontScale, 0.0f)) {
240         TextModel::GetInstance()->SetMinFontScale(0.0f);
241         return;
242     }
243     if (GreatOrEqual(minFontScale, 1.0f)) {
244         TextModel::GetInstance()->SetMinFontScale(1.0f);
245         return;
246     }
247     TextModel::GetInstance()->SetMinFontScale(static_cast<float>(minFontScale));
248 }
249 
SetMaxFontScale(const JSCallbackInfo & info)250 void JSText::SetMaxFontScale(const JSCallbackInfo& info)
251 {
252     double maxFontScale;
253     if (info.Length() < 1 || !ParseJsDouble(info[0], maxFontScale)) {
254         return;
255     }
256     if (LessOrEqual(maxFontScale, 1.0f)) {
257         TextModel::GetInstance()->SetMaxFontScale(1.0f);
258         return;
259     }
260     TextModel::GetInstance()->SetMaxFontScale(static_cast<float>(maxFontScale));
261 }
262 
SetForegroundColor(const JSCallbackInfo & info)263 void JSText::SetForegroundColor(const JSCallbackInfo& info)
264 {
265     if (info.Length() < 1) {
266         return;
267     }
268     ForegroundColorStrategy strategy;
269     if (ParseJsColorStrategy(info[0], strategy)) {
270         TextModel::GetInstance()->SetTextColor(Color::FOREGROUND);
271         ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy);
272         return;
273     }
274     SetTextColor(info);
275 }
276 
SetTextColor(const JSCallbackInfo & info)277 void JSText::SetTextColor(const JSCallbackInfo& info)
278 {
279     if (info.Length() < 1) {
280         return;
281     }
282     Color textColor;
283     JSRef<JSVal> args = info[0];
284     if (!ParseJsColor(args, textColor)) {
285         auto pipelineContext = PipelineBase::GetCurrentContext();
286         CHECK_NULL_VOID(pipelineContext);
287         auto theme = pipelineContext->GetTheme<TextTheme>();
288         CHECK_NULL_VOID(theme);
289         textColor = theme->GetTextStyle().GetTextColor();
290     }
291     TextModel::GetInstance()->SetTextColor(textColor);
292 }
293 
SetTextShadow(const JSCallbackInfo & info)294 void JSText::SetTextShadow(const JSCallbackInfo& info)
295 {
296     if (info.Length() < 1) {
297         return;
298     }
299     std::vector<Shadow> shadows;
300     JSRef<JSVal> args = info[0];
301     ParseTextShadowFromShadowObject(args, shadows);
302     TextModel::GetInstance()->SetTextShadow(shadows);
303 }
304 
SetTextOverflow(const JSCallbackInfo & info)305 void JSText::SetTextOverflow(const JSCallbackInfo& info)
306 {
307     do {
308         auto tmpInfo = info[0];
309         if (!tmpInfo->IsObject()) {
310             break;
311         }
312         JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
313         JSRef<JSVal> overflowValue = obj->GetProperty("overflow");
314         if (!overflowValue->IsNumber() && !overflowValue->IsUndefined()) {
315             break;
316         }
317         auto overflow = overflowValue->ToNumber<int32_t>();
318         if (overflowValue->IsUndefined()) {
319             overflow = 0;
320         } else if (overflow < 0 || overflow >= static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
321             break;
322         }
323         TextModel::GetInstance()->SetTextOverflow(TEXT_OVERFLOWS[overflow]);
324     } while (false);
325 
326     info.SetReturnValue(info.This());
327 }
328 
SetWordBreak(const JSCallbackInfo & info)329 void JSText::SetWordBreak(const JSCallbackInfo& info)
330 {
331     JSRef<JSVal> args = info[0];
332     if (!args->IsNumber()) {
333         return;
334     }
335     uint32_t index = args->ToNumber<uint32_t>();
336     if (index < WORD_BREAK_TYPES.size()) {
337         TextModel::GetInstance()->SetWordBreak(WORD_BREAK_TYPES[index]);
338     }
339 }
340 
SetEllipsisMode(const JSCallbackInfo & info)341 void JSText::SetEllipsisMode(const JSCallbackInfo& info)
342 {
343     JSRef<JSVal> args = info[0];
344     if (!args->IsNumber()) {
345         return;
346     }
347     uint32_t index = args->ToNumber<uint32_t>();
348     if (index < ELLIPSIS_MODALS.size()) {
349         TextModel::GetInstance()->SetEllipsisMode(ELLIPSIS_MODALS[index]);
350     }
351 }
352 
SetLineBreakStrategy(const JSCallbackInfo & info)353 void JSText::SetLineBreakStrategy(const JSCallbackInfo& info)
354 {
355     if (info.Length() < 1) {
356         TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
357         return;
358     }
359     if (!info[0]->IsNumber()) {
360         TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
361         return;
362     }
363     auto index = info[0]->ToNumber<int32_t>();
364     if (index < 0 || index >= static_cast<int32_t>(LINE_BREAK_STRATEGY_TYPES.size())) {
365         TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
366         return;
367     }
368     TextModel::GetInstance()->SetLineBreakStrategy(LINE_BREAK_STRATEGY_TYPES[index]);
369 }
370 
SetTextSelection(const JSCallbackInfo & info)371 void JSText::SetTextSelection(const JSCallbackInfo& info)
372 {
373     if (info.Length() < 1) {
374         return;
375     }
376     JSRef<JSVal> argsStartIndex = info[0];
377     JSRef<JSVal> argsEndIndex = info[1];
378     if (!argsStartIndex->IsNumber() || !argsEndIndex->IsNumber()) {
379         return;
380     }
381     auto startIndex = argsStartIndex->ToNumber<int32_t>();
382     auto endIndex = argsEndIndex->ToNumber<int32_t>();
383     if (startIndex == -1 && endIndex == -1) {
384         TextModel::GetInstance()->SetTextSelection(startIndex, endIndex);
385         return;
386     }
387     if (startIndex >= endIndex) {
388         return;
389     }
390     TextModel::GetInstance()->SetTextSelection(startIndex, endIndex);
391 }
392 
SetTextCaretColor(const JSCallbackInfo & info)393 void JSText::SetTextCaretColor(const JSCallbackInfo& info)
394 {
395     if (info.Length() < 1) {
396         return;
397     }
398     Color caretColor;
399     if (!ParseJsColor(info[0], caretColor)) {
400         auto pipelineContext = PipelineContext::GetCurrentContextSafely();
401         CHECK_NULL_VOID(pipelineContext);
402         auto theme = pipelineContext->GetTheme<TextTheme>();
403         CHECK_NULL_VOID(theme);
404         caretColor = theme->GetCaretColor();
405     }
406     TextModel::GetInstance()->SetTextCaretColor(caretColor);
407 }
408 
SetSelectedBackgroundColor(const JSCallbackInfo & info)409 void JSText::SetSelectedBackgroundColor(const JSCallbackInfo& info)
410 {
411     if (info.Length() < 1) {
412         return;
413     }
414     Color selectedColor;
415     if (!ParseJsColor(info[0], selectedColor)) {
416         auto pipelineContext = PipelineContext::GetCurrentContextSafely();
417         CHECK_NULL_VOID(pipelineContext);
418         auto theme = pipelineContext->GetTheme<TextTheme>();
419         CHECK_NULL_VOID(theme);
420         selectedColor = theme->GetSelectedColor();
421     }
422     // Alpha = 255 means opaque
423     if (selectedColor.GetAlpha() == JSThemeUtils::DEFAULT_ALPHA) {
424         // Default setting of 20% opacity
425         selectedColor = selectedColor.ChangeOpacity(JSThemeUtils::DEFAULT_OPACITY);
426     }
427     TextModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
428 }
429 
SetTextSelectableMode(const JSCallbackInfo & info)430 void JSText::SetTextSelectableMode(const JSCallbackInfo& info)
431 {
432     if (info.Length() < 1) {
433         TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
434         return;
435     }
436     if (!info[0]->IsNumber()) {
437         TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
438         return;
439     }
440     auto index = info[0]->ToNumber<int32_t>();
441     if (index < 0 || index >= static_cast<int32_t>(TEXT_SELECTABLE_MODE.size())) {
442         TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
443         return;
444     }
445     TextModel::GetInstance()->SetTextSelectableMode(TEXT_SELECTABLE_MODE[index]);
446 }
447 
SetMaxLines(const JSCallbackInfo & info)448 void JSText::SetMaxLines(const JSCallbackInfo& info)
449 {
450     JSRef<JSVal> args = info[0];
451     auto value = Infinity<int32_t>();
452     if (args->ToString() != "Infinity") {
453         ParseJsInt32(args, value);
454     }
455     TextModel::GetInstance()->SetMaxLines(value);
456 }
457 
SetTextIndent(const JSCallbackInfo & info)458 void JSText::SetTextIndent(const JSCallbackInfo& info)
459 {
460     CalcDimension value;
461     JSRef<JSVal> args = info[0];
462     if (!ParseJsDimensionFpNG(args, value)) {
463         value.Reset();
464         TextModel::GetInstance()->SetTextIndent(value);
465         return;
466     }
467     TextModel::GetInstance()->SetTextIndent(value);
468 }
469 
SetFontStyle(int32_t value)470 void JSText::SetFontStyle(int32_t value)
471 {
472     if (value < 0 || value >= static_cast<int32_t>(FONT_STYLES.size())) {
473         if (!(AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE))) {
474             return;
475         }
476         value = 0;
477     }
478     TextModel::GetInstance()->SetItalicFontStyle(FONT_STYLES[value]);
479 }
480 
SetTextAlign(int32_t value)481 void JSText::SetTextAlign(int32_t value)
482 {
483     if (value < 0 || value >= static_cast<int32_t>(TEXT_ALIGNS.size())) {
484         if (!(AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE))) {
485             return;
486         }
487         value = 0;
488     }
489     TextModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
490 }
491 
SetAlign(const JSCallbackInfo & info)492 void JSText::SetAlign(const JSCallbackInfo& info)
493 {
494     JSViewAbstract::JsAlign(info);
495     JSRef<JSVal> args = info[0];
496     if (!args->IsNumber()) {
497         return;
498     }
499     TextModel::GetInstance()->OnSetAlign();
500 }
501 
SetLineHeight(const JSCallbackInfo & info)502 void JSText::SetLineHeight(const JSCallbackInfo& info)
503 {
504     CalcDimension value;
505     JSRef<JSVal> args = info[0];
506     if (!ParseJsDimensionFpNG(args, value)) {
507         value.Reset();
508         TextModel::GetInstance()->SetLineHeight(value);
509         return;
510     }
511     if (value.IsNegative()) {
512         value.Reset();
513     }
514     TextModel::GetInstance()->SetLineHeight(value);
515 }
516 
SetLineSpacing(const JSCallbackInfo & info)517 void JSText::SetLineSpacing(const JSCallbackInfo& info)
518 {
519     CalcDimension value;
520     JSRef<JSVal> args = info[0];
521     if (!ParseLengthMetricsToPositiveDimension(args, value)) {
522         value.Reset();
523     }
524     if (value.IsNegative()) {
525         value.Reset();
526     }
527     TextModel::GetInstance()->SetLineSpacing(value);
528 }
529 
SetFontFamily(const JSCallbackInfo & info)530 void JSText::SetFontFamily(const JSCallbackInfo& info)
531 {
532     std::vector<std::string> fontFamilies;
533     JSRef<JSVal> args = info[0];
534     ParseJsFontFamilies(args, fontFamilies);
535     TextModel::GetInstance()->SetFontFamily(fontFamilies);
536 }
537 
SetMinFontSize(const JSCallbackInfo & info)538 void JSText::SetMinFontSize(const JSCallbackInfo& info)
539 {
540     if (info.Length() < 1) {
541         return;
542     }
543     auto pipelineContext = PipelineBase::GetCurrentContext();
544     CHECK_NULL_VOID(pipelineContext);
545     auto theme = pipelineContext->GetTheme<TextTheme>();
546     CHECK_NULL_VOID(theme);
547     CalcDimension minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
548     JSRef<JSVal> args = info[0];
549     if (!ParseJsDimensionFpNG(args, minFontSize, false)) {
550         minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
551         TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
552         return;
553     }
554     if (minFontSize.IsNegative()) {
555         minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
556     }
557     TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
558 }
559 
SetMaxFontSize(const JSCallbackInfo & info)560 void JSText::SetMaxFontSize(const JSCallbackInfo& info)
561 {
562     if (info.Length() < 1) {
563         return;
564     }
565     auto pipelineContext = PipelineBase::GetCurrentContext();
566     CHECK_NULL_VOID(pipelineContext);
567     auto theme = pipelineContext->GetTheme<TextTheme>();
568     CHECK_NULL_VOID(theme);
569     CalcDimension maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
570     JSRef<JSVal> args = info[0];
571     if (!ParseJsDimensionFpNG(args, maxFontSize, false)) {
572         maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
573         TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
574         return;
575     }
576     if (maxFontSize.IsNegative()) {
577         maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
578     }
579     TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
580 }
581 
SetLetterSpacing(const JSCallbackInfo & info)582 void JSText::SetLetterSpacing(const JSCallbackInfo& info)
583 {
584     CalcDimension value;
585     JSRef<JSVal> args = info[0];
586     if (!ParseJsDimensionFpNG(args, value, false)) {
587         value.Reset();
588         TextModel::GetInstance()->SetLetterSpacing(value);
589         return;
590     }
591     TextModel::GetInstance()->SetLetterSpacing(value);
592 }
593 
SetTextCase(int32_t value)594 void JSText::SetTextCase(int32_t value)
595 {
596     if (value < 0 || value >= static_cast<int32_t>(TEXT_CASES.size())) {
597         if (!(AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE))) {
598             return;
599         }
600         value = 0;
601     }
602     TextModel::GetInstance()->SetTextCase(TEXT_CASES[value]);
603 }
604 
SetBaselineOffset(const JSCallbackInfo & info)605 void JSText::SetBaselineOffset(const JSCallbackInfo& info)
606 {
607     CalcDimension value;
608     JSRef<JSVal> args = info[0];
609     if (!ParseJsDimensionFpNG(args, value, false)) {
610         value.Reset();
611         TextModel::GetInstance()->SetBaselineOffset(value);
612         return;
613     }
614     TextModel::GetInstance()->SetBaselineOffset(value);
615 }
616 
SetDecoration(const JSCallbackInfo & info)617 void JSText::SetDecoration(const JSCallbackInfo& info)
618 {
619     auto tmpInfo = info[0];
620     if (tmpInfo->IsUndefined()) {
621         TextModel::GetInstance()->SetTextDecoration(TextDecoration::NONE);
622         info.ReturnSelf();
623         return;
624     }
625     if (!tmpInfo->IsObject()) {
626         info.ReturnSelf();
627         return;
628     }
629     JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
630     JSRef<JSVal> typeValue = obj->GetProperty("type");
631     JSRef<JSVal> colorValue = obj->GetProperty("color");
632     JSRef<JSVal> styleValue = obj->GetProperty("style");
633 
634     TextDecoration textDecoration;
635     if (typeValue->IsNumber()) {
636         textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
637     } else {
638         auto theme = GetTheme<TextTheme>();
639         CHECK_NULL_VOID(theme);
640         textDecoration = theme->GetTextStyle().GetTextDecoration();
641     }
642     Color result;
643     if (!ParseJsColor(colorValue, result)) {
644         auto theme = GetTheme<TextTheme>();
645         CHECK_NULL_VOID(theme);
646         if (SystemProperties::GetColorMode() == ColorMode::DARK) {
647             result = theme->GetTextStyle().GetTextColor();
648         } else {
649             result = theme->GetTextStyle().GetTextDecorationColor();
650         }
651     }
652     std::optional<TextDecorationStyle> textDecorationStyle;
653     if (styleValue->IsNumber()) {
654         textDecorationStyle = static_cast<TextDecorationStyle>(styleValue->ToNumber<int32_t>());
655     } else {
656         textDecorationStyle = DEFAULT_TEXT_DECORATION_STYLE;
657     }
658     TextModel::GetInstance()->SetTextDecoration(textDecoration);
659     TextModel::GetInstance()->SetTextDecorationColor(result);
660     if (textDecorationStyle) {
661         TextModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value());
662     }
663     info.ReturnSelf();
664 }
665 
SetHeightAdaptivePolicy(int32_t value)666 void JSText::SetHeightAdaptivePolicy(int32_t value)
667 {
668     if (value < 0 || value >= static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICY.size())) {
669         if (!(AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE))) {
670             return;
671         }
672         value = 0;
673     }
674     TextModel::GetInstance()->SetHeightAdaptivePolicy(HEIGHT_ADAPTIVE_POLICY[value]);
675 }
676 
JsOnClick(const JSCallbackInfo & info)677 void JSText::JsOnClick(const JSCallbackInfo& info)
678 {
679     JSRef<JSVal> args = info[0];
680     if (Container::IsCurrentUseNewPipeline()) {
681         if (args->IsUndefined() && IsDisableEventVersion()) {
682             TextModel::GetInstance()->ClearOnClick();
683             return;
684         }
685         if (!args->IsFunction()) {
686             return;
687         }
688         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
689         auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(args));
690         auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = frameNode]
691             (BaseEventInfo* info) {
692             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
693             auto* clickInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
694             ACE_SCORING_EVENT("Text.onClick");
695             PipelineContext::SetCallBackNode(node);
696             func->Execute(*clickInfo);
697 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
698             std::string label = "";
699             if (!node.Invalid()) {
700                 auto pattern = node.GetRawPtr()->GetPattern();
701                 CHECK_NULL_VOID(pattern);
702                 auto layoutProperty = pattern->GetLayoutProperty<NG::TextLayoutProperty>();
703                 CHECK_NULL_VOID(layoutProperty);
704                 label = layoutProperty->GetContent().value_or("");
705             }
706             JSInteractableView::ReportClickEvent(node, label);
707 #endif
708         };
709         TextModel::GetInstance()->SetOnClick(std::move(onClick));
710 
711         auto focusHub = NG::ViewStackProcessor::GetInstance()->GetOrCreateMainFrameNodeFocusHub();
712         CHECK_NULL_VOID(focusHub);
713         focusHub->SetFocusable(true, false);
714     } else {
715         JsOnClickWithoutNGBUILD(info);
716     }
717 }
718 
JsOnClickWithoutNGBUILD(const JSCallbackInfo & info)719 void JSText::JsOnClickWithoutNGBUILD(const JSCallbackInfo& info)
720 {
721 #ifndef NG_BUILD
722     JSRef<JSVal> args = info[0];
723     if (args->IsFunction()) {
724         auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
725         auto impl = inspector ? inspector->GetInspectorFunctionImpl() : nullptr;
726         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
727         RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(args));
728         auto onClickId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl,
729                              node = frameNode](const BaseEventInfo* info) {
730             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
731             const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
732             auto newInfo = *clickInfo;
733             if (impl) {
734                 impl->UpdateEventInfo(newInfo);
735             }
736             ACE_SCORING_EVENT("Text.onClick");
737             PipelineContext::SetCallBackNode(node);
738             func->Execute(newInfo);
739         };
740         TextModel::GetInstance()->SetOnClick(std::move(onClickId));
741     }
742 #endif
743 }
744 
JsRemoteMessage(const JSCallbackInfo & info)745 void JSText::JsRemoteMessage(const JSCallbackInfo& info)
746 {
747     JSInteractableView::JsCommonRemoteMessage(info);
748     auto callback = JSInteractableView::GetRemoteMessageEventCallback(info);
749     TextModel::GetInstance()->SetRemoteMessage(std::move(callback));
750 }
751 
Create(const JSCallbackInfo & info)752 void JSText::Create(const JSCallbackInfo& info)
753 {
754     std::string data;
755     if (info.Length() <= 0) {
756         TextModel::GetInstance()->Create(data);
757         return;
758     }
759 
760     if (info[0]->IsObject() && JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>()) {
761         auto *spanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
762         if (spanString == nullptr) {
763             return;
764         }
765         auto spanStringController = spanString->GetController();
766         if (spanStringController) {
767             TextModel::GetInstance()->Create(spanStringController);
768         } else {
769             TextModel::GetInstance()->Create(data);
770         }
771     } else {
772         ParseJsString(info[0], data);
773         TextModel::GetInstance()->Create(data);
774     }
775 
776     JSTextTheme::ApplyTheme();
777     if (info.Length() <= 1 || !info[1]->IsObject()) {
778         return;
779     }
780 
781     JSTextController* jsController = nullptr;
782     auto paramObject = JSRef<JSObject>::Cast(info[1]);
783     auto controllerObj = paramObject->GetProperty("controller");
784     if (!controllerObj->IsUndefined() && !controllerObj->IsNull() && controllerObj->IsObject()) {
785         jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextController>();
786     }
787 
788     RefPtr<TextControllerBase> controller = TextModel::GetInstance()->GetTextController();
789     if (jsController) {
790         jsController->SetController(controller);
791     }
792 }
793 
SetCopyOption(const JSCallbackInfo & info)794 void JSText::SetCopyOption(const JSCallbackInfo& info)
795 {
796     if (info.Length() == 0) {
797         return;
798     }
799     auto copyOptions = CopyOptions::None;
800     auto tmpInfo = info[0];
801     if (tmpInfo->IsNumber()) {
802         auto emunNumber = tmpInfo->ToNumber<int>();
803         copyOptions = static_cast<CopyOptions>(emunNumber);
804     }
805     TextModel::GetInstance()->SetCopyOption(copyOptions);
806 }
807 
SetOnCopy(const JSCallbackInfo & info)808 void JSText::SetOnCopy(const JSCallbackInfo& info)
809 {
810     JSRef<JSVal> args = info[0];
811     CHECK_NULL_VOID(args->IsFunction());
812     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(args));
813     TextModel::GetInstance()->SetOnCopy(std::move(callback));
814 }
815 
JsOnDragStart(const JSCallbackInfo & info)816 void JSText::JsOnDragStart(const JSCallbackInfo& info)
817 {
818     JSRef<JSVal> args = info[0];
819     CHECK_NULL_VOID(args->IsFunction());
820     RefPtr<JsDragFunction> jsOnDragStartFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(args));
821     auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
822     auto onDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc),
823                            targetNode = frameNode](
824                            const RefPtr<DragEvent>& info, const std::string& extraParams) -> NG::DragDropBaseInfo {
825         NG::DragDropBaseInfo itemInfo;
826         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo);
827         PipelineContext::SetCallBackNode(targetNode);
828         auto ret = func->Execute(info, extraParams);
829         if (!ret->IsObject()) {
830             return itemInfo;
831         }
832         auto node = ParseDragNode(ret);
833         if (node) {
834             itemInfo.node = node;
835             return itemInfo;
836         }
837         auto builderObj = JSRef<JSObject>::Cast(ret);
838 #if defined(PIXEL_MAP_SUPPORTED)
839         auto pixmap = builderObj->GetProperty("pixelMap");
840         itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap);
841 #endif
842         auto extraInfo = builderObj->GetProperty("extraInfo");
843         ParseJsString(extraInfo, itemInfo.extraInfo);
844         node = ParseDragNode(builderObj->GetProperty("builder"));
845         itemInfo.node = node;
846         return itemInfo;
847     };
848 
849     TextModel::GetInstance()->SetOnDragStart(std::move(onDragStart));
850 }
851 
JsOnDragEnter(const JSCallbackInfo & info)852 void JSText::JsOnDragEnter(const JSCallbackInfo& info)
853 {
854     JSRef<JSVal> args = info[0];
855     CHECK_NULL_VOID(args->IsFunction());
856     auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
857     RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(args));
858     auto onDragEnterId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc), node = frameNode](
859                              const RefPtr<DragEvent>& info, const std::string& extraParams) {
860         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
861         ACE_SCORING_EVENT("onDragEnter");
862         PipelineContext::SetCallBackNode(node);
863         func->Execute(info, extraParams);
864     };
865     TextModel::GetInstance()->SetOnDragEnter(std::move(onDragEnterId));
866 }
867 
JsOnDragMove(const JSCallbackInfo & info)868 void JSText::JsOnDragMove(const JSCallbackInfo& info)
869 {
870     JSRef<JSVal> args = info[0];
871     CHECK_NULL_VOID(args->IsFunction());
872     auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
873     RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(args));
874     auto onDragMoveId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc), node = frameNode](
875                             const RefPtr<DragEvent>& info, const std::string& extraParams) {
876         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
877         ACE_SCORING_EVENT("onDragMove");
878         PipelineContext::SetCallBackNode(node);
879         func->Execute(info, extraParams);
880     };
881     TextModel::GetInstance()->SetOnDragMove(std::move(onDragMoveId));
882 }
883 
JsOnDragLeave(const JSCallbackInfo & info)884 void JSText::JsOnDragLeave(const JSCallbackInfo& info)
885 {
886     JSRef<JSVal> args = info[0];
887     CHECK_NULL_VOID(args->IsFunction());
888     auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
889     RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(args));
890     auto onDragLeaveId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc), node = frameNode](
891                              const RefPtr<DragEvent>& info, const std::string& extraParams) {
892         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
893         ACE_SCORING_EVENT("onDragLeave");
894         PipelineContext::SetCallBackNode(node);
895         func->Execute(info, extraParams);
896     };
897     TextModel::GetInstance()->SetOnDragLeave(std::move(onDragLeaveId));
898 }
899 
JsOnDrop(const JSCallbackInfo & info)900 void JSText::JsOnDrop(const JSCallbackInfo& info)
901 {
902     JSRef<JSVal> args = info[0];
903     CHECK_NULL_VOID(args->IsFunction());
904     RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(args));
905     auto onDropId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
906                         const RefPtr<DragEvent>& info, const std::string& extraParams) {
907         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
908         ACE_SCORING_EVENT("onDrop");
909         func->Execute(info, extraParams);
910     };
911     TextModel::GetInstance()->SetOnDrop(std::move(onDropId));
912 }
913 
JsFocusable(const JSCallbackInfo & info)914 void JSText::JsFocusable(const JSCallbackInfo& info)
915 {
916     auto tmpInfo = info[0];
917     if (!tmpInfo->IsBoolean()) {
918         return;
919     }
920     JSInteractableView::SetFocusable(tmpInfo->ToBoolean());
921     JSInteractableView::SetFocusNode(false);
922 }
923 
JsDraggable(const JSCallbackInfo & info)924 void JSText::JsDraggable(const JSCallbackInfo& info)
925 {
926     auto tmpInfo = info[0];
927     if (!tmpInfo->IsBoolean()) {
928         return;
929     }
930     ViewAbstractModel::GetInstance()->SetDraggable(tmpInfo->ToBoolean());
931 }
932 
JsEnableDataDetector(const JSCallbackInfo & info)933 void JSText::JsEnableDataDetector(const JSCallbackInfo& info)
934 {
935     if (info.Length() < 1) {
936         LOGI("The argv is wrong, it is supposed to have at least 1 argument");
937         return;
938     }
939     auto tmpInfo = info[0];
940     if (!tmpInfo->IsBoolean()) {
941         TextModel::GetInstance()->SetTextDetectEnable(false);
942         return;
943     }
944     auto enable = tmpInfo->ToBoolean();
945     TextModel::GetInstance()->SetTextDetectEnable(enable);
946 }
947 
JsDataDetectorConfig(const JSCallbackInfo & info)948 void JSText::JsDataDetectorConfig(const JSCallbackInfo& info)
949 {
950     if (info.Length() < 1) {
951         LOGI("The argv is wrong, it is supposed to have at least 1 argument");
952         return;
953     }
954     JSRef<JSVal> args = info[0];
955     if (!args->IsObject()) {
956         return;
957     }
958 
959     TextDetectConfig textDetectConfig;
960     if (!ParseDataDetectorConfig(info, textDetectConfig)) {
961         return;
962     }
963     TextModel::GetInstance()->SetTextDetectConfig(textDetectConfig);
964 }
965 
BindSelectionMenu(const JSCallbackInfo & info)966 void JSText::BindSelectionMenu(const JSCallbackInfo& info)
967 {
968     // TextSpanType
969     NG::TextSpanType testSpanType = NG::TextSpanType::TEXT;
970     JSRef<JSVal> argsSpanType = info[0];
971     if (argsSpanType->IsNumber()) {
972         auto spanType = argsSpanType->ToNumber<int32_t>();
973         testSpanType = static_cast<NG::TextSpanType>(spanType);
974     }
975 
976     // Builder
977     JSRef<JSVal> argsMenuObj = info[1];
978     if (!argsMenuObj->IsObject()) {
979         return;
980     }
981     JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(argsMenuObj);
982     auto builder = menuObj->GetProperty("builder");
983     if (!builder->IsFunction()) {
984         return;
985     }
986     auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
987     CHECK_NULL_VOID(builderFunc);
988 
989     // TextResponseType
990     int32_t resquiredParameterCount = 3;
991     JSRef<JSVal> argsResponse = info[resquiredParameterCount - 1];
992     NG::TextResponseType responseType = NG::TextResponseType::LONG_PRESS;
993     if (argsResponse->IsNumber()) {
994         auto response = argsResponse->ToNumber<int32_t>();
995         responseType = static_cast<NG::TextResponseType>(response);
996     }
997 
998     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
999     std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc),
1000                                           node = frameNode]() {
1001         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1002         ACE_SCORING_EVENT("BindSelectionMenu");
1003         PipelineContext::SetCallBackNode(node);
1004         func->Execute();
1005     };
1006 
1007     // SelectionMenuOptions
1008     NG::SelectMenuParam menuParam;
1009     if (info.Length() > resquiredParameterCount) {
1010         JSRef<JSVal> argsMenuOptions = info[resquiredParameterCount];
1011         if (argsMenuOptions->IsObject()) {
1012             ParseMenuParam(info, argsMenuOptions, menuParam);
1013         }
1014     }
1015 
1016     TextModel::GetInstance()->BindSelectionMenu(testSpanType, responseType, buildFunc, menuParam);
1017 }
1018 
SetOnTextSelectionChange(const JSCallbackInfo & info)1019 void JSText::SetOnTextSelectionChange(const JSCallbackInfo& info)
1020 {
1021     JSRef<JSVal> args = info[0];
1022     CHECK_NULL_VOID(args->IsFunction());
1023     JsEventCallback<void(int32_t, int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(args));
1024     TextModel::GetInstance()->SetOnTextSelectionChange(std::move(callback));
1025 }
1026 
JsClip(const JSCallbackInfo & info)1027 void JSText::JsClip(const JSCallbackInfo& info)
1028 {
1029     JSViewAbstract::JsClip(info);
1030     JSRef<JSVal> args = info[0];
1031     if (args->IsBoolean()) {
1032         TextModel::GetInstance()->SetClipEdge(args->ToBoolean());
1033     }
1034 }
1035 
SetFontFeature(const JSCallbackInfo & info)1036 void JSText::SetFontFeature(const JSCallbackInfo& info)
1037 {
1038     if (info.Length() < 1) {
1039         return;
1040     }
1041 
1042     if (!info[0]->IsString() && !info[0]->IsObject()) {
1043         return;
1044     }
1045     std::string fontFeatureSettings = info[0]->ToString();
1046     TextModel::GetInstance()->SetFontFeature(ParseFontFeatureSettings(fontFeatureSettings));
1047 }
1048 
JsResponseRegion(const JSCallbackInfo & info)1049 void JSText::JsResponseRegion(const JSCallbackInfo& info)
1050 {
1051     JSViewAbstract::JsResponseRegion(info);
1052     TextModel::GetInstance()->SetResponseRegion(true);
1053 }
1054 
SetHalfLeading(const JSCallbackInfo & info)1055 void JSText::SetHalfLeading(const JSCallbackInfo& info)
1056 {
1057     if (info.Length() < 1) {
1058         return;
1059     }
1060     auto halfLeading = info[0];
1061     if (!halfLeading->IsBoolean()) {
1062         TextModel::GetInstance()->SetHalfLeading(false);
1063         return;
1064     }
1065     auto enable = halfLeading->ToBoolean();
1066     TextModel::GetInstance()->SetHalfLeading(enable);
1067 }
1068 
SetEnableHapticFeedback(const JSCallbackInfo & info)1069 void JSText::SetEnableHapticFeedback(const JSCallbackInfo& info)
1070 {
1071     bool state = true;
1072     if (info.Length() > 0 && info[0]->IsBoolean()) {
1073         state = info[0]->ToBoolean();
1074     }
1075     TextModel::GetInstance()->SetEnableHapticFeedback(state);
1076 }
1077 
JSBind(BindingTarget globalObj)1078 void JSText::JSBind(BindingTarget globalObj)
1079 {
1080     JSClass<JSText>::Declare("Text");
1081     MethodOptions opt = MethodOptions::NONE;
1082     JSClass<JSText>::StaticMethod("create", &JSText::Create, opt);
1083     JSClass<JSText>::StaticMethod("width", &JSText::SetWidth);
1084     JSClass<JSText>::StaticMethod("height", &JSText::SetHeight);
1085     JSClass<JSText>::StaticMethod("font", &JSText::SetFont, opt);
1086     JSClass<JSText>::StaticMethod("fontColor", &JSText::SetTextColor, opt);
1087     JSClass<JSText>::StaticMethod("textShadow", &JSText::SetTextShadow, opt);
1088     JSClass<JSText>::StaticMethod("fontSize", &JSText::SetFontSize, opt);
1089     JSClass<JSText>::StaticMethod("fontWeight", &JSText::SetFontWeight, opt);
1090     JSClass<JSText>::StaticMethod("minFontScale", &JSText::SetMinFontScale, opt);
1091     JSClass<JSText>::StaticMethod("maxFontScale", &JSText::SetMaxFontScale, opt);
1092     JSClass<JSText>::StaticMethod("wordBreak", &JSText::SetWordBreak, opt);
1093     JSClass<JSText>::StaticMethod("lineBreakStrategy", &JSText::SetLineBreakStrategy, opt);
1094     JSClass<JSText>::StaticMethod("selection", &JSText::SetTextSelection, opt);
1095     JSClass<JSText>::StaticMethod("ellipsisMode", &JSText::SetEllipsisMode, opt);
1096     JSClass<JSText>::StaticMethod("textSelectable", &JSText::SetTextSelectableMode, opt);
1097     JSClass<JSText>::StaticMethod("maxLines", &JSText::SetMaxLines, opt);
1098     JSClass<JSText>::StaticMethod("textIndent", &JSText::SetTextIndent);
1099     JSClass<JSText>::StaticMethod("textOverflow", &JSText::SetTextOverflow, opt);
1100     JSClass<JSText>::StaticMethod("fontStyle", &JSText::SetFontStyle, opt);
1101     JSClass<JSText>::StaticMethod("align", &JSText::SetAlign, opt);
1102     JSClass<JSText>::StaticMethod("textAlign", &JSText::SetTextAlign, opt);
1103     JSClass<JSText>::StaticMethod("lineHeight", &JSText::SetLineHeight, opt);
1104     JSClass<JSText>::StaticMethod("lineSpacing", &JSText::SetLineSpacing, opt);
1105     JSClass<JSText>::StaticMethod("fontFamily", &JSText::SetFontFamily, opt);
1106     JSClass<JSText>::StaticMethod("minFontSize", &JSText::SetMinFontSize, opt);
1107     JSClass<JSText>::StaticMethod("maxFontSize", &JSText::SetMaxFontSize, opt);
1108     JSClass<JSText>::StaticMethod("letterSpacing", &JSText::SetLetterSpacing, opt);
1109     JSClass<JSText>::StaticMethod("textCase", &JSText::SetTextCase, opt);
1110     JSClass<JSText>::StaticMethod("baselineOffset", &JSText::SetBaselineOffset, opt);
1111     JSClass<JSText>::StaticMethod("caretColor", &JSText::SetTextCaretColor);
1112     JSClass<JSText>::StaticMethod("selectedBackgroundColor", &JSText::SetSelectedBackgroundColor);
1113     JSClass<JSText>::StaticMethod("decoration", &JSText::SetDecoration);
1114     JSClass<JSText>::StaticMethod("heightAdaptivePolicy", &JSText::SetHeightAdaptivePolicy);
1115     JSClass<JSText>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
1116     JSClass<JSText>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
1117     JSClass<JSText>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
1118     JSClass<JSText>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
1119     JSClass<JSText>::StaticMethod("remoteMessage", &JSText::JsRemoteMessage);
1120     JSClass<JSText>::StaticMethod("copyOption", &JSText::SetCopyOption);
1121     JSClass<JSText>::StaticMethod("onClick", &JSText::JsOnClick);
1122     JSClass<JSText>::StaticMethod("onCopy", &JSText::SetOnCopy);
1123     JSClass<JSText>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
1124     JSClass<JSText>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
1125     JSClass<JSText>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
1126     JSClass<JSText>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
1127     JSClass<JSText>::StaticMethod("onDragStart", &JSText::JsOnDragStart);
1128     JSClass<JSText>::StaticMethod("onDragEnter", &JSText::JsOnDragEnter);
1129     JSClass<JSText>::StaticMethod("onDragMove", &JSText::JsOnDragMove);
1130     JSClass<JSText>::StaticMethod("onDragLeave", &JSText::JsOnDragLeave);
1131     JSClass<JSText>::StaticMethod("onDrop", &JSText::JsOnDrop);
1132     JSClass<JSText>::StaticMethod("focusable", &JSText::JsFocusable);
1133     JSClass<JSText>::StaticMethod("draggable", &JSText::JsDraggable);
1134     JSClass<JSText>::StaticMethod("enableDataDetector", &JSText::JsEnableDataDetector);
1135     JSClass<JSText>::StaticMethod("dataDetectorConfig", &JSText::JsDataDetectorConfig);
1136     JSClass<JSText>::StaticMethod("bindSelectionMenu", &JSText::BindSelectionMenu);
1137     JSClass<JSText>::StaticMethod("onTextSelectionChange", &JSText::SetOnTextSelectionChange);
1138     JSClass<JSText>::StaticMethod("clip", &JSText::JsClip);
1139     JSClass<JSText>::StaticMethod("foregroundColor", &JSText::SetForegroundColor);
1140     JSClass<JSText>::StaticMethod("fontFeature", &JSText::SetFontFeature);
1141     JSClass<JSText>::StaticMethod("editMenuOptions", &JSText::EditMenuOptions);
1142     JSClass<JSText>::StaticMethod("responseRegion", &JSText::JsResponseRegion);
1143     JSClass<JSText>::StaticMethod("halfLeading", &JSText::SetHalfLeading);
1144     JSClass<JSText>::StaticMethod("enableHapticFeedback", &JSText::SetEnableHapticFeedback);
1145     JSClass<JSText>::InheritAndBind<JSContainerBase>(globalObj);
1146 }
1147 
CloseSelectionMenu()1148 void JSTextController::CloseSelectionMenu()
1149 {
1150     auto controller = controllerWeak_.Upgrade();
1151     CHECK_NULL_VOID(controller);
1152     controller->CloseSelectionMenu();
1153 }
1154 
GetLayoutManager(const JSCallbackInfo & args)1155 void JSTextController::GetLayoutManager(const JSCallbackInfo& args)
1156 {
1157     JSRef<JSObject> obj = JSClass<JSLayoutManager>::NewInstance();
1158     auto jsLayoutManager = Referenced::Claim(obj->Unwrap<JSLayoutManager>());
1159     CHECK_NULL_VOID(jsLayoutManager);
1160     jsLayoutManager->IncRefCount();
1161     auto controller = controllerWeak_.Upgrade();
1162     CHECK_NULL_VOID(controller);
1163     auto layoutInfoInterface = controller->GetLayoutInfoInterface();
1164     jsLayoutManager->SetLayoutInfoInterface(layoutInfoInterface);
1165     args.SetReturnValue(obj);
1166 }
1167 
SetStyledString(const JSCallbackInfo & info)1168 void JSTextController::SetStyledString(const JSCallbackInfo& info)
1169 {
1170     if (info.Length() != 1 || !info[0]->IsObject()) {
1171         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1172         return;
1173     }
1174     auto* spanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
1175     if (!spanString) {
1176         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1177         return;
1178     }
1179     auto controller = controllerWeak_.Upgrade();
1180     CHECK_NULL_VOID(controller);
1181     auto spanStringController = spanString->GetController();
1182     CHECK_NULL_VOID(spanStringController);
1183     controller->SetStyledString(spanStringController);
1184     auto thisObj = info.This();
1185     thisObj->SetPropertyObject("STYLED_STRING_IN_CONTROLLER", info[0]);
1186 }
1187 
JSBind(BindingTarget globalObj)1188 void JSTextController::JSBind(BindingTarget globalObj)
1189 {
1190     JSClass<JSTextController>::Declare("TextController");
1191     JSClass<JSTextController>::Method("closeSelectionMenu", &JSTextController::CloseSelectionMenu);
1192     JSClass<JSTextController>::CustomMethod("setStyledString", &JSTextController::SetStyledString);
1193     JSClass<JSTextController>::CustomMethod("getLayoutManager", &JSTextController::GetLayoutManager);
1194     JSClass<JSTextController>::Bind(globalObj, JSTextController::Constructor, JSTextController::Destructor);
1195 }
1196 
ParseMenuParam(const JSCallbackInfo & info,const JSRef<JSObject> & menuOptions,NG::SelectMenuParam & menuParam)1197 void JSText::ParseMenuParam(
1198     const JSCallbackInfo& info, const JSRef<JSObject>& menuOptions, NG::SelectMenuParam& menuParam)
1199 {
1200     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1201     auto onAppearValue = menuOptions->GetProperty("onAppear");
1202     if (onAppearValue->IsFunction()) {
1203         RefPtr<JsFunction> jsOnAppearFunc =
1204             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAppearValue));
1205         auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc), node = frameNode](
1206                             int32_t start, int32_t end) {
1207             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1208             ACE_SCORING_EVENT("onAppear");
1209 
1210             JSRef<JSVal> params[2];
1211             params[0] = JSRef<JSVal>::Make(ToJSValue(start));
1212             params[1] = JSRef<JSVal>::Make(ToJSValue(end));
1213             PipelineContext::SetCallBackNode(node);
1214             func->ExecuteJS(2, params);
1215         };
1216         menuParam.onAppear = std::move(onAppear);
1217     }
1218 
1219     auto onDisappearValue = menuOptions->GetProperty("onDisappear");
1220     if (onDisappearValue->IsFunction()) {
1221         RefPtr<JsFunction> jsOnDisAppearFunc =
1222             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDisappearValue));
1223         auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc),
1224                                node = frameNode]() {
1225             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1226             ACE_SCORING_EVENT("onDisappear");
1227             PipelineContext::SetCallBackNode(node);
1228             func->Execute();
1229         };
1230         menuParam.onDisappear = std::move(onDisappear);
1231     }
1232 }
1233 
EditMenuOptions(const JSCallbackInfo & info)1234 void JSText::EditMenuOptions(const JSCallbackInfo& info)
1235 {
1236     NG::OnCreateMenuCallback onCreateMenuCallback;
1237     NG::OnMenuItemClickCallback onMenuItemClick;
1238     JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick);
1239     TextModel::GetInstance()->SetSelectionMenuOptions(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
1240 }
1241 } // namespace OHOS::Ace::Framework
1242