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