• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/declarative_frontend/jsview/js_text.h"
17 
18 #include <cstdint>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
23 #include "core/components_ng/pattern/text/text_layout_property.h"
24 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
25 #endif
26 
27 #include "base/geometry/dimension.h"
28 #include "base/log/ace_scoring_log.h"
29 #include "base/log/ace_trace.h"
30 #include "base/utils/utils.h"
31 #include "bridge/common/utils/utils.h"
32 #include "bridge/declarative_frontend/ark_theme/theme_apply/js_theme_utils.h"
33 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
34 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
35 #include "bridge/declarative_frontend/engine/functions/js_function.h"
36 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
37 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
38 #include "bridge/declarative_frontend/jsview/js_layout_manager.h"
39 #include "bridge/declarative_frontend/jsview/js_text.h"
40 #include "bridge/declarative_frontend/jsview/js_utils.h"
41 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
42 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
43 #include "bridge/declarative_frontend/jsview/models/text_model_impl.h"
44 #include "bridge/declarative_frontend/style_string/js_span_string.h"
45 #include "bridge/declarative_frontend/view_stack_processor.h"
46 #include "core/common/container.h"
47 #include "core/components/common/layout/constants.h"
48 #include "core/components/common/properties/text_style_parser.h"
49 #include "core/components_ng/pattern/text/text_model_ng.h"
50 #include "core/event/ace_event_handler.h"
51 #include "core/pipeline/pipeline_base.h"
52 #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::GetCurrentContextSafelyWithCheck();
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()) {
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()) {
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 = PipelineContext::GetCurrentContextSafelyWithCheck();
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         TextModel::GetInstance()->ResetTextColor();
282         return;
283     }
284     TextModel::GetInstance()->SetTextColor(textColor);
285 }
286 
SetTextShadow(const JSCallbackInfo & info)287 void JSText::SetTextShadow(const JSCallbackInfo& info)
288 {
289     if (info.Length() < 1) {
290         return;
291     }
292     std::vector<Shadow> shadows;
293     JSRef<JSVal> args = info[0];
294     ParseTextShadowFromShadowObject(args, shadows);
295     TextModel::GetInstance()->SetTextShadow(shadows);
296 }
297 
SetTextOverflow(const JSCallbackInfo & info)298 void JSText::SetTextOverflow(const JSCallbackInfo& info)
299 {
300     do {
301         auto tmpInfo = info[0];
302         if (!tmpInfo->IsObject()) {
303             break;
304         }
305         JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
306         JSRef<JSVal> overflowValue = obj->GetProperty("overflow");
307         if (!overflowValue->IsNumber() && !overflowValue->IsUndefined()) {
308             break;
309         }
310         auto overflow = overflowValue->ToNumber<int32_t>();
311         if(overflowValue->IsUndefined()) {
312             overflow = 0;
313         } else if (overflow < 0 || overflow >= static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
314             break;
315         }
316         TextModel::GetInstance()->SetTextOverflow(TEXT_OVERFLOWS[overflow]);
317     } while (false);
318 
319     info.SetReturnValue(info.This());
320 }
321 
SetWordBreak(const JSCallbackInfo & info)322 void JSText::SetWordBreak(const JSCallbackInfo& info)
323 {
324     JSRef<JSVal> args = info[0];
325     if (!args->IsNumber()) {
326         return;
327     }
328     uint32_t index = args->ToNumber<uint32_t>();
329     if (index < WORD_BREAK_TYPES.size()) {
330         TextModel::GetInstance()->SetWordBreak(WORD_BREAK_TYPES[index]);
331     }
332 }
333 
SetEllipsisMode(const JSCallbackInfo & info)334 void JSText::SetEllipsisMode(const JSCallbackInfo& info)
335 {
336     JSRef<JSVal> args = info[0];
337     if (!args->IsNumber()) {
338         return;
339     }
340     uint32_t index = args->ToNumber<uint32_t>();
341     if (index < ELLIPSIS_MODALS.size()) {
342         TextModel::GetInstance()->SetEllipsisMode(ELLIPSIS_MODALS[index]);
343     }
344 }
345 
SetLineBreakStrategy(const JSCallbackInfo & info)346 void JSText::SetLineBreakStrategy(const JSCallbackInfo& info)
347 {
348     if (info.Length() < 1) {
349         TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
350         return;
351     }
352     if (!info[0]->IsNumber()) {
353         TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
354         return;
355     }
356     auto index = info[0]->ToNumber<int32_t>();
357     if (index < 0 || index >= static_cast<int32_t>(LINE_BREAK_STRATEGY_TYPES.size())) {
358         TextModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
359         return;
360     }
361     TextModel::GetInstance()->SetLineBreakStrategy(LINE_BREAK_STRATEGY_TYPES[index]);
362 }
363 
SetTextSelection(const JSCallbackInfo & info)364 void JSText::SetTextSelection(const JSCallbackInfo& info)
365 {
366     if (info.Length() < 1) {
367         return;
368     }
369     JSRef<JSVal> argsStartIndex = info[0];
370     JSRef<JSVal> argsEndIndex = info[1];
371     if (!argsStartIndex->IsNumber() || !argsEndIndex->IsNumber()) {
372         return;
373     }
374     auto startIndex = argsStartIndex->ToNumber<int32_t>();
375     auto endIndex = argsEndIndex->ToNumber<int32_t>();
376     TextModel::GetInstance()->SetTextSelection(startIndex, endIndex);
377 }
378 
SetTextCaretColor(const JSCallbackInfo & info)379 void JSText::SetTextCaretColor(const JSCallbackInfo& info)
380 {
381     if (info.Length() < 1) {
382         return;
383     }
384     Color caretColor;
385     if (!ParseJsColor(info[0], caretColor)) {
386         auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
387         CHECK_NULL_VOID(pipelineContext);
388         auto theme = pipelineContext->GetTheme<TextTheme>();
389         CHECK_NULL_VOID(theme);
390         caretColor = theme->GetCaretColor();
391     }
392     TextModel::GetInstance()->SetTextCaretColor(caretColor);
393 }
394 
SetSelectedBackgroundColor(const JSCallbackInfo & info)395 void JSText::SetSelectedBackgroundColor(const JSCallbackInfo& info)
396 {
397     if (info.Length() < 1) {
398         return;
399     }
400     Color selectedColor;
401     if (!ParseJsColor(info[0], selectedColor)) {
402         auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
403         CHECK_NULL_VOID(pipelineContext);
404         auto theme = pipelineContext->GetTheme<TextTheme>();
405         CHECK_NULL_VOID(theme);
406         selectedColor = theme->GetSelectedColor();
407     }
408     // Alpha = 255 means opaque
409     if (selectedColor.GetAlpha() == JSThemeUtils::DEFAULT_ALPHA) {
410         // Default setting of 20% opacity
411         selectedColor = selectedColor.ChangeOpacity(JSThemeUtils::DEFAULT_OPACITY);
412     }
413     TextModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
414 }
415 
SetTextSelectableMode(const JSCallbackInfo & info)416 void JSText::SetTextSelectableMode(const JSCallbackInfo& info)
417 {
418     if (info.Length() < 1) {
419         TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
420         return;
421     }
422     if (!info[0]->IsNumber()) {
423         TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
424         return;
425     }
426     auto index = info[0]->ToNumber<int32_t>();
427     if (index < 0 || index >= static_cast<int32_t>(TEXT_SELECTABLE_MODE.size())) {
428         TextModel::GetInstance()->SetTextSelectableMode(TextSelectableMode::SELECTABLE_UNFOCUSABLE);
429         return;
430     }
431     TextModel::GetInstance()->SetTextSelectableMode(TEXT_SELECTABLE_MODE[index]);
432 }
433 
SetMaxLines(const JSCallbackInfo & info)434 void JSText::SetMaxLines(const JSCallbackInfo& info)
435 {
436     JSRef<JSVal> args = info[0];
437     auto value = Infinity<int32_t>();
438     if (args->ToString() != "Infinity") {
439         ParseJsInt32(args, value);
440     }
441     TextModel::GetInstance()->SetMaxLines(value);
442 }
443 
SetTextIndent(const JSCallbackInfo & info)444 void JSText::SetTextIndent(const JSCallbackInfo& info)
445 {
446     CalcDimension value;
447     JSRef<JSVal> args = info[0];
448     if (!ParseJsDimensionFpNG(args, value)) {
449         value.Reset();
450         TextModel::GetInstance()->SetTextIndent(value);
451         return;
452     }
453     TextModel::GetInstance()->SetTextIndent(value);
454 }
455 
SetFontStyle(int32_t value)456 void JSText::SetFontStyle(int32_t value)
457 {
458     if (value < 0 || value >= static_cast<int32_t>(FONT_STYLES.size())) {
459         if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
460             return;
461         }
462         value = 0;
463     }
464     TextModel::GetInstance()->SetItalicFontStyle(FONT_STYLES[value]);
465 }
466 
SetTextAlign(int32_t value)467 void JSText::SetTextAlign(int32_t value)
468 {
469     if (value < 0 || value >= static_cast<int32_t>(TEXT_ALIGNS.size())) {
470         if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
471             return;
472         }
473         value = 0;
474     }
475     TextModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
476 }
477 
SetAlign(const JSCallbackInfo & info)478 void JSText::SetAlign(const JSCallbackInfo& info)
479 {
480     JSViewAbstract::JsAlign(info);
481     JSRef<JSVal> args = info[0];
482     if (!args->IsNumber()) {
483         return;
484     }
485     TextModel::GetInstance()->OnSetAlign();
486 }
487 
SetLineHeight(const JSCallbackInfo & info)488 void JSText::SetLineHeight(const JSCallbackInfo& info)
489 {
490     CalcDimension value;
491     JSRef<JSVal> args = info[0];
492     if (!ParseJsDimensionFpNG(args, value)) {
493         value.Reset();
494         TextModel::GetInstance()->SetLineHeight(value);
495         return;
496     }
497     if (value.IsNegative()) {
498         value.Reset();
499     }
500     TextModel::GetInstance()->SetLineHeight(value);
501 }
502 
SetLineSpacing(const JSCallbackInfo & info)503 void JSText::SetLineSpacing(const JSCallbackInfo& info)
504 {
505     CalcDimension value;
506     JSRef<JSVal> args = info[0];
507     if (!ParseLengthMetricsToPositiveDimension(args, value)) {
508         value.Reset();
509     }
510     if (value.IsNegative()) {
511         value.Reset();
512     }
513     TextModel::GetInstance()->SetLineSpacing(value);
514 }
515 
SetFontFamily(const JSCallbackInfo & info)516 void JSText::SetFontFamily(const JSCallbackInfo& info)
517 {
518     std::vector<std::string> fontFamilies;
519     JSRef<JSVal> args = info[0];
520     ParseJsFontFamilies(args, fontFamilies);
521     TextModel::GetInstance()->SetFontFamily(fontFamilies);
522 }
523 
SetMinFontSize(const JSCallbackInfo & info)524 void JSText::SetMinFontSize(const JSCallbackInfo& info)
525 {
526     if (info.Length() < 1) {
527         return;
528     }
529     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
530     CHECK_NULL_VOID(pipelineContext);
531     auto theme = pipelineContext->GetTheme<TextTheme>();
532     CHECK_NULL_VOID(theme);
533     CalcDimension minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
534     JSRef<JSVal> args = info[0];
535     if (!ParseJsDimensionFpNG(args, minFontSize, false)) {
536         minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
537         TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
538         return;
539     }
540     if (minFontSize.IsNegative()) {
541         minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
542     }
543     TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
544 }
545 
SetMaxFontSize(const JSCallbackInfo & info)546 void JSText::SetMaxFontSize(const JSCallbackInfo& info)
547 {
548     if (info.Length() < 1) {
549         return;
550     }
551     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
552     CHECK_NULL_VOID(pipelineContext);
553     auto theme = pipelineContext->GetTheme<TextTheme>();
554     CHECK_NULL_VOID(theme);
555     CalcDimension maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
556     JSRef<JSVal> args = info[0];
557     if (!ParseJsDimensionFpNG(args, maxFontSize, false)) {
558         maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
559         TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
560         return;
561     }
562     if (maxFontSize.IsNegative()) {
563         maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
564     }
565     TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
566 }
567 
SetLetterSpacing(const JSCallbackInfo & info)568 void JSText::SetLetterSpacing(const JSCallbackInfo& info)
569 {
570     CalcDimension value;
571     JSRef<JSVal> args = info[0];
572     if (!ParseJsDimensionFpNG(args, value, false)) {
573         value.Reset();
574         TextModel::GetInstance()->SetLetterSpacing(value);
575         return;
576     }
577     TextModel::GetInstance()->SetLetterSpacing(value);
578 }
579 
SetTextCase(int32_t value)580 void JSText::SetTextCase(int32_t value)
581 {
582     if (value < 0 || value >= static_cast<int32_t>(TEXT_CASES.size())) {
583         if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
584             return;
585         }
586         value = 0;
587     }
588     TextModel::GetInstance()->SetTextCase(TEXT_CASES[value]);
589 }
590 
SetBaselineOffset(const JSCallbackInfo & info)591 void JSText::SetBaselineOffset(const JSCallbackInfo& info)
592 {
593     CalcDimension value;
594     JSRef<JSVal> args = info[0];
595     if (!ParseJsDimensionFpNG(args, value, false)) {
596         value.Reset();
597         TextModel::GetInstance()->SetBaselineOffset(value);
598         return;
599     }
600     TextModel::GetInstance()->SetBaselineOffset(value);
601 }
602 
SetDecoration(const JSCallbackInfo & info)603 void JSText::SetDecoration(const JSCallbackInfo& info)
604 {
605     auto tmpInfo = info[0];
606     if (tmpInfo->IsUndefined()) {
607         TextModel::GetInstance()->SetTextDecoration(TextDecoration::NONE);
608         info.ReturnSelf();
609         return;
610     }
611     if (!tmpInfo->IsObject()) {
612         info.ReturnSelf();
613         return;
614     }
615     JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
616     JSRef<JSVal> typeValue = obj->GetProperty("type");
617     JSRef<JSVal> colorValue = obj->GetProperty("color");
618     JSRef<JSVal> styleValue = obj->GetProperty("style");
619 
620     TextDecoration textDecoration;
621     if (typeValue->IsNumber()) {
622         textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
623     } else {
624         auto theme = GetTheme<TextTheme>();
625         CHECK_NULL_VOID(theme);
626         textDecoration = theme->GetTextStyle().GetTextDecoration();
627     }
628     Color result;
629     if (!ParseJsColor(colorValue, result)) {
630         auto theme = GetTheme<TextTheme>();
631         CHECK_NULL_VOID(theme);
632         if (Container::CurrentColorMode() == ColorMode::DARK) {
633             result = theme->GetTextStyle().GetTextColor();
634         } else {
635             result = theme->GetTextStyle().GetTextDecorationColor();
636         }
637     }
638     std::optional<TextDecorationStyle> textDecorationStyle;
639     if (styleValue->IsNumber()) {
640         textDecorationStyle = static_cast<TextDecorationStyle>(styleValue->ToNumber<int32_t>());
641     } else {
642         textDecorationStyle = DEFAULT_TEXT_DECORATION_STYLE;
643     }
644     TextModel::GetInstance()->SetTextDecoration(textDecoration);
645     TextModel::GetInstance()->SetTextDecorationColor(result);
646     if (textDecorationStyle) {
647         TextModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value());
648     }
649     info.ReturnSelf();
650 }
651 
SetHeightAdaptivePolicy(int32_t value)652 void JSText::SetHeightAdaptivePolicy(int32_t value)
653 {
654     if (value < 0 || value >= static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICY.size())) {
655         if (!(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE))) {
656             return;
657         }
658         value = 0;
659     }
660     TextModel::GetInstance()->SetHeightAdaptivePolicy(HEIGHT_ADAPTIVE_POLICY[value]);
661 }
662 
JsOnClick(const JSCallbackInfo & info)663 void JSText::JsOnClick(const JSCallbackInfo& info)
664 {
665     JSRef<JSVal> args = info[0];
666     if (Container::IsCurrentUseNewPipeline()) {
667         if (args->IsUndefined() && IsDisableEventVersion()) {
668             TextModel::GetInstance()->ClearOnClick();
669             return;
670         }
671         if (!args->IsFunction()) {
672             return;
673         }
674         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
675         auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(args));
676         auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = frameNode]
677             (BaseEventInfo* info) {
678             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
679             auto* clickInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
680             ACE_SCORING_EVENT("Text.onClick");
681             PipelineContext::SetCallBackNode(node);
682             func->Execute(*clickInfo);
683 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
684             std::u16string label = u"";
685             auto frameNode = node.Upgrade();
686             if (frameNode) {
687                 auto pattern = frameNode->GetPattern();
688                 CHECK_NULL_VOID(pattern);
689                 auto layoutProperty = pattern->GetLayoutProperty<NG::TextLayoutProperty>();
690                 CHECK_NULL_VOID(layoutProperty);
691                 label = layoutProperty->GetContent().value_or(u"");
692             }
693             JSInteractableView::ReportClickEvent(node, label);
694 #endif
695         };
696         double distanceThreshold = std::numeric_limits<double>::infinity();
697         if (info.Length() > 1 && info[1]->IsNumber()) {
698             distanceThreshold = info[1]->ToNumber<double>();
699             distanceThreshold = Dimension(distanceThreshold, DimensionUnit::VP).ConvertToPx();
700         }
701         TextModel::GetInstance()->SetOnClick(std::move(onClick), distanceThreshold);
702 
703         auto focusHub = NG::ViewStackProcessor::GetInstance()->GetOrCreateMainFrameNodeFocusHub();
704         CHECK_NULL_VOID(focusHub);
705         focusHub->SetFocusable(true, false);
706     } else {
707         JsOnClickWithoutNGBUILD(info);
708     }
709 }
710 
JsOnClickWithoutNGBUILD(const JSCallbackInfo & info)711 void JSText::JsOnClickWithoutNGBUILD(const JSCallbackInfo& info)
712 {
713 #ifndef NG_BUILD
714     JSRef<JSVal> args = info[0];
715     if (args->IsFunction()) {
716         auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
717         auto impl = inspector ? inspector->GetInspectorFunctionImpl() : nullptr;
718         auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
719         RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(args));
720         auto onClickId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl,
721                              node = frameNode](const BaseEventInfo* info) {
722             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
723             const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
724             auto newInfo = *clickInfo;
725             if (impl) {
726                 impl->UpdateEventInfo(newInfo);
727             }
728             ACE_SCORING_EVENT("Text.onClick");
729             PipelineContext::SetCallBackNode(node);
730             func->Execute(newInfo);
731         };
732         double distanceThreshold = std::numeric_limits<double>::infinity();
733         if (info.Length() > 1 && info[1]->IsNumber()) {
734             distanceThreshold = info[1]->ToNumber<double>();
735             distanceThreshold = Dimension(distanceThreshold, DimensionUnit::VP).ConvertToPx();
736         }
737         TextModel::GetInstance()->SetOnClick(std::move(onClickId), distanceThreshold);
738     }
739 #endif
740 }
741 
JsRemoteMessage(const JSCallbackInfo & info)742 void JSText::JsRemoteMessage(const JSCallbackInfo& info)
743 {
744     JSInteractableView::JsCommonRemoteMessage(info);
745     auto callback = JSInteractableView::GetRemoteMessageEventCallback(info);
746     TextModel::GetInstance()->SetRemoteMessage(std::move(callback));
747 }
748 
Create(const JSCallbackInfo & info)749 void JSText::Create(const JSCallbackInfo& info)
750 {
751     std::u16string data;
752     if (info.Length() <= 0) {
753         TextModel::GetInstance()->Create(data);
754         return;
755     }
756 
757     JSRef<JSVal> args = info[0];
758     if (args->IsObject() && JSRef<JSObject>::Cast(args)->Unwrap<JSSpanString>()) {
759         auto *spanString = JSRef<JSObject>::Cast(args)->Unwrap<JSSpanString>();
760         if (spanString == nullptr) {
761             return;
762         }
763         auto spanStringController = spanString->GetController();
764         if (spanStringController) {
765             TextModel::GetInstance()->Create(spanStringController);
766         } else {
767             TextModel::GetInstance()->Create(data);
768         }
769     } else {
770         ParseJsString(args, data);
771         UtfUtils::HandleInvalidUTF16(reinterpret_cast<uint16_t*>(data.data()), data.length(), 0);
772         TextModel::GetInstance()->Create(data);
773     }
774 
775     if (info.Length() <= 1 || !info[1]->IsObject()) {
776         return;
777     }
778 
779     JSTextController* jsController = nullptr;
780     auto paramObject = JSRef<JSObject>::Cast(info[1]);
781     auto controllerObj = paramObject->GetProperty("controller");
782     if (!controllerObj->IsUndefined() && !controllerObj->IsNull() && controllerObj->IsObject()) {
783         jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextController>();
784     }
785 
786     RefPtr<TextControllerBase> controller = TextModel::GetInstance()->GetTextController();
787     if (jsController) {
788         jsController->SetController(controller);
789         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN)) {
790             auto styledString = jsController->GetStyledString();
791             if (styledString) {
792                 controller->SetStyledString(styledString, false);
793                 jsController->ClearStyledString();
794             }
795         }
796     }
797 }
798 
SetCopyOption(const JSCallbackInfo & info)799 void JSText::SetCopyOption(const JSCallbackInfo& info)
800 {
801     if (info.Length() == 0) {
802         return;
803     }
804     auto copyOptions = CopyOptions::None;
805     auto tmpInfo = info[0];
806     if (tmpInfo->IsNumber()) {
807         auto emunNumber = tmpInfo->ToNumber<int>();
808         copyOptions = static_cast<CopyOptions>(emunNumber);
809     }
810     TextModel::GetInstance()->SetCopyOption(copyOptions);
811 }
812 
SetOnCopy(const JSCallbackInfo & info)813 void JSText::SetOnCopy(const JSCallbackInfo& info)
814 {
815     JSRef<JSVal> args = info[0];
816     CHECK_NULL_VOID(args->IsFunction());
817     JsEventCallback<void(const std::u16string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(args));
818     TextModel::GetInstance()->SetOnCopy(std::move(callback));
819 }
820 
JsOnDragStart(const JSCallbackInfo & info)821 void JSText::JsOnDragStart(const JSCallbackInfo& info)
822 {
823     JSRef<JSVal> args = info[0];
824     CHECK_NULL_VOID(args->IsFunction());
825     RefPtr<JsDragFunction> jsOnDragStartFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(args));
826     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
827     auto onDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc),
828                            targetNode = frameNode](
829                            const RefPtr<DragEvent>& info, const std::string& extraParams) -> NG::DragDropBaseInfo {
830         NG::DragDropBaseInfo itemInfo;
831         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo);
832         PipelineContext::SetCallBackNode(targetNode);
833         auto ret = func->Execute(info, extraParams);
834         if (!ret->IsObject()) {
835             return itemInfo;
836         }
837         auto node = ParseDragNode(ret);
838         if (node) {
839             itemInfo.node = node;
840             return itemInfo;
841         }
842         auto builderObj = JSRef<JSObject>::Cast(ret);
843 #if defined(PIXEL_MAP_SUPPORTED)
844         auto pixmap = builderObj->GetProperty("pixelMap");
845         itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap);
846 #endif
847         auto extraInfo = builderObj->GetProperty("extraInfo");
848         ParseJsString(extraInfo, itemInfo.extraInfo);
849         node = ParseDragNode(builderObj->GetProperty("builder"));
850         itemInfo.node = node;
851         return itemInfo;
852     };
853 
854     TextModel::GetInstance()->SetOnDragStart(std::move(onDragStart));
855 }
856 
JsFocusable(const JSCallbackInfo & info)857 void JSText::JsFocusable(const JSCallbackInfo& info)
858 {
859     auto tmpInfo = info[0];
860     if (!tmpInfo->IsBoolean()) {
861         return;
862     }
863     JSInteractableView::SetFocusable(tmpInfo->ToBoolean());
864     JSInteractableView::SetFocusNode(false);
865 }
866 
JsDraggable(const JSCallbackInfo & info)867 void JSText::JsDraggable(const JSCallbackInfo& info)
868 {
869     auto tmpInfo = info[0];
870     if (!tmpInfo->IsBoolean()) {
871         return;
872     }
873     ViewAbstractModel::GetInstance()->SetDraggable(tmpInfo->ToBoolean());
874 }
875 
JsEnableDataDetector(const JSCallbackInfo & info)876 void JSText::JsEnableDataDetector(const JSCallbackInfo& info)
877 {
878     if (info.Length() < 1) {
879         return;
880     }
881     auto tmpInfo = info[0];
882     if (!tmpInfo->IsBoolean()) {
883         TextModel::GetInstance()->SetTextDetectEnable(false);
884         return;
885     }
886     auto enable = tmpInfo->ToBoolean();
887     TextModel::GetInstance()->SetTextDetectEnable(enable);
888 }
889 
JsDataDetectorConfig(const JSCallbackInfo & info)890 void JSText::JsDataDetectorConfig(const JSCallbackInfo& info)
891 {
892     if (info.Length() < 1) {
893         return;
894     }
895     JSRef<JSVal> args = info[0];
896     if (!args->IsObject()) {
897         return;
898     }
899 
900     TextDetectConfig textDetectConfig;
901     if (!ParseDataDetectorConfig(info, textDetectConfig)) {
902         return;
903     }
904     TextModel::GetInstance()->SetTextDetectConfig(textDetectConfig);
905 }
906 
BindSelectionMenu(const JSCallbackInfo & info)907 void JSText::BindSelectionMenu(const JSCallbackInfo& info)
908 {
909     // TextSpanType
910     NG::TextSpanType textSpanType = NG::TextSpanType::TEXT;
911     bool isValidTextSpanType = true;
912     JSRef<JSVal> argsSpanType = info[0];
913     if (argsSpanType->IsNumber()) {
914         auto spanTypeId = argsSpanType->ToNumber<int32_t>();
915         isValidTextSpanType = NG::TextSpanTypeMapper::GetTextSpanTypeFromJsType(spanTypeId, textSpanType);
916     }
917 
918     // Builder
919     JSRef<JSVal> argsMenuObj = info[1];
920     if (!argsMenuObj->IsObject()) {
921         return;
922     }
923     JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(argsMenuObj);
924     auto builder = menuObj->GetProperty("builder");
925     if (!builder->IsFunction()) {
926         return;
927     }
928     auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
929     CHECK_NULL_VOID(builderFunc);
930 
931     // TextResponseType
932     uint32_t resquiredParameterCount = 3;
933     JSRef<JSVal> argsResponse = info[resquiredParameterCount - 1];
934     NG::TextResponseType responseType = NG::TextResponseType::LONG_PRESS;
935     if (argsResponse->IsNumber()) {
936         auto response = argsResponse->ToNumber<int32_t>();
937         responseType = static_cast<NG::TextResponseType>(response);
938     }
939 
940     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
941     std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc),
942                                           node = frameNode]() {
943         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
944         ACE_SCORING_EVENT("BindSelectionMenu");
945         PipelineContext::SetCallBackNode(node);
946         func->Execute();
947     };
948 
949     // SelectionMenuOptions
950     NG::SelectMenuParam menuParam;
951     menuParam.isValid = isValidTextSpanType;
952     if (info.Length() > static_cast<uint32_t>(resquiredParameterCount)) {
953         JSRef<JSVal> argsMenuOptions = info[resquiredParameterCount];
954         if (argsMenuOptions->IsObject()) {
955             ParseMenuParam(info, argsMenuOptions, menuParam);
956         }
957     }
958 
959     TextModel::GetInstance()->BindSelectionMenu(textSpanType, responseType, buildFunc, menuParam);
960 }
961 
SetOnTextSelectionChange(const JSCallbackInfo & info)962 void JSText::SetOnTextSelectionChange(const JSCallbackInfo& info)
963 {
964     JSRef<JSVal> args = info[0];
965     CHECK_NULL_VOID(args->IsFunction());
966     JsEventCallback<void(int32_t, int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(args));
967     TextModel::GetInstance()->SetOnTextSelectionChange(std::move(callback));
968 }
969 
JsClip(const JSCallbackInfo & info)970 void JSText::JsClip(const JSCallbackInfo& info)
971 {
972     JSViewAbstract::JsClip(info);
973     JSRef<JSVal> args = info[0];
974     if (args->IsBoolean()) {
975         TextModel::GetInstance()->SetClipEdge(args->ToBoolean());
976     }
977 }
978 
SetFontFeature(const JSCallbackInfo & info)979 void JSText::SetFontFeature(const JSCallbackInfo& info)
980 {
981     if (info.Length() < 1) {
982         return;
983     }
984 
985     if (!info[0]->IsString() && !info[0]->IsObject()) {
986         return;
987     }
988     std::string fontFeatureSettings = info[0]->ToString();
989     TextModel::GetInstance()->SetFontFeature(ParseFontFeatureSettings(fontFeatureSettings));
990 }
991 
JsResponseRegion(const JSCallbackInfo & info)992 void JSText::JsResponseRegion(const JSCallbackInfo& info)
993 {
994     JSViewAbstract::JsResponseRegion(info);
995     TextModel::GetInstance()->SetResponseRegion(true);
996 }
997 
SetHalfLeading(const JSCallbackInfo & info)998 void JSText::SetHalfLeading(const JSCallbackInfo& info)
999 {
1000     if (info.Length() < 1) {
1001         return;
1002     }
1003     auto halfLeading = info[0];
1004     if (!halfLeading->IsBoolean()) {
1005         TextModel::GetInstance()->SetHalfLeading(false);
1006         return;
1007     }
1008     auto enable = halfLeading->ToBoolean();
1009     TextModel::GetInstance()->SetHalfLeading(enable);
1010 }
1011 
SetEnableHapticFeedback(const JSCallbackInfo & info)1012 void JSText::SetEnableHapticFeedback(const JSCallbackInfo& info)
1013 {
1014     bool state = true;
1015     if (info.Length() > 0 && info[0]->IsBoolean()) {
1016         state = info[0]->ToBoolean();
1017     }
1018     TextModel::GetInstance()->SetEnableHapticFeedback(state);
1019 }
1020 
JSBind(BindingTarget globalObj)1021 void JSText::JSBind(BindingTarget globalObj)
1022 {
1023     JSClass<JSText>::Declare("Text");
1024     MethodOptions opt = MethodOptions::NONE;
1025     JSClass<JSText>::StaticMethod("create", &JSText::Create, opt);
1026     JSClass<JSText>::StaticMethod("width", &JSText::SetWidth);
1027     JSClass<JSText>::StaticMethod("height", &JSText::SetHeight);
1028     JSClass<JSText>::StaticMethod("font", &JSText::SetFont, opt);
1029     JSClass<JSText>::StaticMethod("fontColor", &JSText::SetTextColor, opt);
1030     JSClass<JSText>::StaticMethod("textShadow", &JSText::SetTextShadow, opt);
1031     JSClass<JSText>::StaticMethod("fontSize", &JSText::SetFontSize, opt);
1032     JSClass<JSText>::StaticMethod("fontWeight", &JSText::SetFontWeight, opt);
1033     JSClass<JSText>::StaticMethod("minFontScale", &JSText::SetMinFontScale, opt);
1034     JSClass<JSText>::StaticMethod("maxFontScale", &JSText::SetMaxFontScale, opt);
1035     JSClass<JSText>::StaticMethod("wordBreak", &JSText::SetWordBreak, opt);
1036     JSClass<JSText>::StaticMethod("lineBreakStrategy", &JSText::SetLineBreakStrategy, opt);
1037     JSClass<JSText>::StaticMethod("ellipsisMode", &JSText::SetEllipsisMode, opt);
1038     JSClass<JSText>::StaticMethod("selection", &JSText::SetTextSelection, opt);
1039     JSClass<JSText>::StaticMethod("textSelectable", &JSText::SetTextSelectableMode, opt);
1040     JSClass<JSText>::StaticMethod("maxLines", &JSText::SetMaxLines, opt);
1041     JSClass<JSText>::StaticMethod("textIndent", &JSText::SetTextIndent);
1042     JSClass<JSText>::StaticMethod("textOverflow", &JSText::SetTextOverflow, opt);
1043     JSClass<JSText>::StaticMethod("fontStyle", &JSText::SetFontStyle, opt);
1044     JSClass<JSText>::StaticMethod("align", &JSText::SetAlign, opt);
1045     JSClass<JSText>::StaticMethod("textAlign", &JSText::SetTextAlign, opt);
1046     JSClass<JSText>::StaticMethod("lineHeight", &JSText::SetLineHeight, opt);
1047     JSClass<JSText>::StaticMethod("lineSpacing", &JSText::SetLineSpacing, opt);
1048     JSClass<JSText>::StaticMethod("fontFamily", &JSText::SetFontFamily, opt);
1049     JSClass<JSText>::StaticMethod("minFontSize", &JSText::SetMinFontSize, opt);
1050     JSClass<JSText>::StaticMethod("maxFontSize", &JSText::SetMaxFontSize, opt);
1051     JSClass<JSText>::StaticMethod("letterSpacing", &JSText::SetLetterSpacing, opt);
1052     JSClass<JSText>::StaticMethod("textCase", &JSText::SetTextCase, opt);
1053     JSClass<JSText>::StaticMethod("baselineOffset", &JSText::SetBaselineOffset, opt);
1054     JSClass<JSText>::StaticMethod("caretColor", &JSText::SetTextCaretColor);
1055     JSClass<JSText>::StaticMethod("selectedBackgroundColor", &JSText::SetSelectedBackgroundColor);
1056     JSClass<JSText>::StaticMethod("decoration", &JSText::SetDecoration);
1057     JSClass<JSText>::StaticMethod("heightAdaptivePolicy", &JSText::SetHeightAdaptivePolicy);
1058     JSClass<JSText>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
1059     JSClass<JSText>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
1060     JSClass<JSText>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
1061     JSClass<JSText>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
1062     JSClass<JSText>::StaticMethod("remoteMessage", &JSText::JsRemoteMessage);
1063     JSClass<JSText>::StaticMethod("copyOption", &JSText::SetCopyOption);
1064     JSClass<JSText>::StaticMethod("onClick", &JSText::JsOnClick);
1065     JSClass<JSText>::StaticMethod("onCopy", &JSText::SetOnCopy);
1066     JSClass<JSText>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
1067     JSClass<JSText>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
1068     JSClass<JSText>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
1069     JSClass<JSText>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
1070     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FIFTEEN)) {
1071         JSClass<JSText>::StaticMethod("onDragStart", &JSText::JsOnDragStart);
1072     } else {
1073         JSClass<JSText>::StaticMethod("onDragStart", &JSViewAbstract::JsOnDragStart);
1074     }
1075     JSClass<JSText>::StaticMethod("focusable", &JSText::JsFocusable);
1076     JSClass<JSText>::StaticMethod("draggable", &JSText::JsDraggable);
1077     JSClass<JSText>::StaticMethod("enableDataDetector", &JSText::JsEnableDataDetector);
1078     JSClass<JSText>::StaticMethod("dataDetectorConfig", &JSText::JsDataDetectorConfig);
1079     JSClass<JSText>::StaticMethod("bindSelectionMenu", &JSText::BindSelectionMenu);
1080     JSClass<JSText>::StaticMethod("onTextSelectionChange", &JSText::SetOnTextSelectionChange);
1081     JSClass<JSText>::StaticMethod("clip", &JSText::JsClip);
1082     JSClass<JSText>::StaticMethod("fontFeature", &JSText::SetFontFeature);
1083     JSClass<JSText>::StaticMethod("foregroundColor", &JSText::SetForegroundColor);
1084     JSClass<JSText>::StaticMethod("marqueeOptions", &JSText::SetMarqueeOptions);
1085     JSClass<JSText>::StaticMethod("onMarqueeStateChange", &JSText::SetOnMarqueeStateChange);
1086     JSClass<JSText>::StaticMethod("editMenuOptions", &JSText::EditMenuOptions);
1087     JSClass<JSText>::StaticMethod("responseRegion", &JSText::JsResponseRegion);
1088     JSClass<JSText>::StaticMethod("halfLeading", &JSText::SetHalfLeading);
1089     JSClass<JSText>::StaticMethod("enableHapticFeedback", &JSText::SetEnableHapticFeedback);
1090     JSClass<JSText>::InheritAndBind<JSContainerBase>(globalObj);
1091 }
1092 
CloseSelectionMenu()1093 void JSTextController::CloseSelectionMenu()
1094 {
1095     auto controller = controllerWeak_.Upgrade();
1096     CHECK_NULL_VOID(controller);
1097     controller->CloseSelectionMenu();
1098 }
1099 
GetLayoutManager(const JSCallbackInfo & args)1100 void JSTextController::GetLayoutManager(const JSCallbackInfo& args)
1101 {
1102     JSRef<JSObject> obj = JSClass<JSLayoutManager>::NewInstance();
1103     auto jsLayoutManager = Referenced::Claim(obj->Unwrap<JSLayoutManager>());
1104     CHECK_NULL_VOID(jsLayoutManager);
1105     jsLayoutManager->IncRefCount();
1106     auto controller = controllerWeak_.Upgrade();
1107     CHECK_NULL_VOID(controller);
1108     auto layoutInfoInterface = controller->GetLayoutInfoInterface();
1109     jsLayoutManager->SetLayoutInfoInterface(layoutInfoInterface);
1110     args.SetReturnValue(obj);
1111 }
1112 
SetStyledString(const JSCallbackInfo & info)1113 void JSTextController::SetStyledString(const JSCallbackInfo& info)
1114 {
1115     if (info.Length() != 1 || !info[0]->IsObject()) {
1116         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1117         return;
1118     }
1119     auto* spanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
1120     if (!spanString) {
1121         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1122         return;
1123     }
1124     auto spanStringController = spanString->GetController();
1125     CHECK_NULL_VOID(spanStringController);
1126     auto controller = controllerWeak_.Upgrade();
1127     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN) && !controller) {
1128         styledString_ = spanStringController;
1129     }
1130     CHECK_NULL_VOID(controller);
1131     controller->SetStyledString(spanStringController, true);
1132     auto thisObj = info.This();
1133     thisObj->SetPropertyObject("STYLED_STRING_IN_CONTROLLER", info[0]);
1134 }
1135 
JSBind(BindingTarget globalObj)1136 void JSTextController::JSBind(BindingTarget globalObj)
1137 {
1138     JSClass<JSTextController>::Declare("TextController");
1139     JSClass<JSTextController>::Method("closeSelectionMenu", &JSTextController::CloseSelectionMenu);
1140     JSClass<JSTextController>::CustomMethod("setStyledString", &JSTextController::SetStyledString);
1141     JSClass<JSTextController>::CustomMethod("getLayoutManager", &JSTextController::GetLayoutManager);
1142     JSClass<JSTextController>::Bind(globalObj, JSTextController::Constructor, JSTextController::Destructor);
1143 }
1144 
ParseMenuParam(const JSCallbackInfo & info,const JSRef<JSObject> & menuOptions,NG::SelectMenuParam & menuParam)1145 void JSText::ParseMenuParam(
1146     const JSCallbackInfo& info, const JSRef<JSObject>& menuOptions, NG::SelectMenuParam& menuParam)
1147 {
1148     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1149     auto onAppearValue = menuOptions->GetProperty("onAppear");
1150     if (onAppearValue->IsFunction()) {
1151         RefPtr<JsFunction> jsOnAppearFunc =
1152             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAppearValue));
1153         auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc), node = frameNode](
1154                             int32_t start, int32_t end) {
1155             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1156             ACE_SCORING_EVENT("onAppear");
1157 
1158             JSRef<JSVal> params[2];
1159             params[0] = JSRef<JSVal>::Make(ToJSValue(start));
1160             params[1] = JSRef<JSVal>::Make(ToJSValue(end));
1161             PipelineContext::SetCallBackNode(node);
1162             func->ExecuteJS(2, params);
1163         };
1164         menuParam.onAppear = std::move(onAppear);
1165     }
1166 
1167     auto onDisappearValue = menuOptions->GetProperty("onDisappear");
1168     if (onDisappearValue->IsFunction()) {
1169         RefPtr<JsFunction> jsOnDisAppearFunc =
1170             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDisappearValue));
1171         auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc),
1172                                node = frameNode]() {
1173             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1174             ACE_SCORING_EVENT("onDisappear");
1175             PipelineContext::SetCallBackNode(node);
1176             func->Execute();
1177         };
1178         menuParam.onDisappear = std::move(onDisappear);
1179     }
1180     menuParam.onMenuShow = ParseMenuCallback(frameNode, menuOptions, info, "onMenuShow");
1181     menuParam.onMenuHide = ParseMenuCallback(frameNode, menuOptions, info, "onMenuHide");
1182     menuParam.previewMenuOptions = ParsePreviewMenuOptions(menuOptions);
1183 }
1184 
ParseMenuCallback(const WeakPtr<NG::FrameNode> & frameNode,const JSRef<JSObject> & menuOptions,const JSCallbackInfo & info,const std::string & name)1185 std::function<void(int32_t, int32_t)> JSText::ParseMenuCallback(const WeakPtr<NG::FrameNode>& frameNode,
1186     const JSRef<JSObject>& menuOptions, const JSCallbackInfo& info, const std::string& name)
1187 {
1188     auto onMenuCallbackValue = menuOptions->GetProperty(name.c_str());
1189     if (onMenuCallbackValue->IsFunction()) {
1190         RefPtr<JsFunction> jsOnMenuCallbackFunc =
1191             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onMenuCallbackValue));
1192         auto onMenuCallback = [execCtx = info.GetExecutionContext(), func = std::move(jsOnMenuCallbackFunc),
1193                                   node = frameNode, eventName = name](int32_t start, int32_t end) {
1194             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1195             ACE_SCORING_EVENT(eventName);
1196 
1197             JSRef<JSVal> params[2];
1198             params[0] = JSRef<JSVal>::Make(ToJSValue(start));
1199             params[1] = JSRef<JSVal>::Make(ToJSValue(end));
1200             PipelineContext::SetCallBackNode(node);
1201             func->ExecuteJS(2, params);
1202         };
1203         return onMenuCallback;
1204     }
1205     return nullptr;
1206 }
1207 
ParsePreviewMenuOptions(const JSRef<JSObject> & menuOptions)1208 NG::PreviewMenuOptions JSText::ParsePreviewMenuOptions(const JSRef<JSObject>& menuOptions)
1209 {
1210     NG::PreviewMenuOptions previewMenuOptions;
1211     auto jsPreviewMenuOp = menuOptions->GetProperty("previewMenuOptions");
1212     CHECK_EQUAL_RETURN(jsPreviewMenuOp->IsObject(), false, previewMenuOptions);
1213     auto jsPreviewMenuOpObj = JSRef<JSObject>::Cast(jsPreviewMenuOp);
1214     CHECK_EQUAL_RETURN(jsPreviewMenuOpObj->IsUndefined(), true, previewMenuOptions);
1215     JSRef<JSVal> jsHapticFeedbackMode = jsPreviewMenuOpObj->GetProperty("hapticFeedbackMode");
1216     CHECK_EQUAL_RETURN(jsHapticFeedbackMode->IsNumber(), false, previewMenuOptions);
1217     auto hapticFeedbackMode = static_cast<HapticFeedbackMode>(jsHapticFeedbackMode->ToNumber<int32_t>());
1218     if (hapticFeedbackMode >= HapticFeedbackMode::DISABLED && hapticFeedbackMode <= HapticFeedbackMode::AUTO) {
1219         previewMenuOptions.hapticFeedbackMode = hapticFeedbackMode;
1220     }
1221     return previewMenuOptions;
1222 }
1223 
SetMarqueeOptions(const JSCallbackInfo & info)1224 void JSText::SetMarqueeOptions(const JSCallbackInfo& info)
1225 {
1226     if (info.Length() < 1) {
1227         return;
1228     }
1229 
1230     auto args = info[0];
1231     NG::TextMarqueeOptions options;
1232 
1233     if (!args->IsObject()) {
1234         TextModel::GetInstance()->SetMarqueeOptions(options);
1235         return;
1236     }
1237 
1238     auto paramObject = JSRef<JSObject>::Cast(args);
1239     ParseMarqueeParam(paramObject, options);
1240     TextModel::GetInstance()->SetMarqueeOptions(options);
1241 }
1242 
ParseMarqueeParam(const JSRef<JSObject> & paramObject,NG::TextMarqueeOptions & options)1243 void JSText::ParseMarqueeParam(const JSRef<JSObject>& paramObject, NG::TextMarqueeOptions& options)
1244 {
1245     auto getStart = paramObject->GetProperty("start");
1246     if (getStart->IsBoolean()) {
1247         options.UpdateTextMarqueeStart(getStart->ToBoolean());
1248     }
1249 
1250     auto getLoop = paramObject->GetProperty("loop");
1251     if (getLoop->IsNumber()) {
1252         int32_t loop = static_cast<int32_t>(getLoop->ToNumber<double>());
1253         if (loop == std::numeric_limits<int32_t>::max() || loop <= 0) {
1254             loop = -1;
1255         }
1256         options.UpdateTextMarqueeLoop(loop);
1257     }
1258 
1259     auto getStep = paramObject->GetProperty("step");
1260     if (getStep->IsNumber()) {
1261         auto step = getStep->ToNumber<double>();
1262         if (GreatNotEqual(step, 0.0)) {
1263             options.UpdateTextMarqueeStep(Dimension(step, DimensionUnit::VP).ConvertToPx());
1264         }
1265     }
1266 
1267     auto delay = paramObject->GetProperty("delay");
1268     if (delay->IsNumber()) {
1269         auto delayDouble = delay->ToNumber<double>();
1270         auto delayValue = static_cast<int32_t>(delayDouble);
1271         if (delayValue < 0) {
1272             delayValue = 0;
1273         }
1274         options.UpdateTextMarqueeDelay(delayValue);
1275     }
1276 
1277     auto getFromStart = paramObject->GetProperty("fromStart");
1278     if (getFromStart->IsBoolean()) {
1279         options.UpdateTextMarqueeDirection(
1280             getFromStart->ToBoolean() ? MarqueeDirection::DEFAULT : MarqueeDirection::DEFAULT_REVERSE);
1281     }
1282 
1283     auto getFadeout = paramObject->GetProperty("fadeout");
1284     if (getFadeout->IsBoolean()) {
1285         options.UpdateTextMarqueeFadeout(getFadeout->ToBoolean());
1286     }
1287 
1288     auto getStartPolicy = paramObject->GetProperty("marqueeStartPolicy");
1289     if (getStartPolicy->IsNumber()) {
1290         auto startPolicy = static_cast<MarqueeStartPolicy>(getStartPolicy->ToNumber<int32_t>());
1291         options.UpdateTextMarqueeStartPolicy(startPolicy);
1292     }
1293 }
1294 
SetOnMarqueeStateChange(const JSCallbackInfo & info)1295 void JSText::SetOnMarqueeStateChange(const JSCallbackInfo& info)
1296 {
1297     if (!info[0]->IsFunction()) {
1298         return;
1299     }
1300 
1301     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
1302     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1303     auto onMarqueeStateChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
1304                                     int32_t value) {
1305         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1306         ACE_SCORING_EVENT("Text.onMarqueeStateChange");
1307         PipelineContext::SetCallBackNode(node);
1308         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(value));
1309         func->ExecuteJS(1, &newJSVal);
1310     };
1311 
1312     TextModel::GetInstance()->SetOnMarqueeStateChange(std::move(onMarqueeStateChange));
1313 }
1314 
EditMenuOptions(const JSCallbackInfo & info)1315 void JSText::EditMenuOptions(const JSCallbackInfo& info)
1316 {
1317     NG::OnCreateMenuCallback onCreateMenuCallback;
1318     NG::OnMenuItemClickCallback onMenuItemClick;
1319     JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick);
1320     TextModel::GetInstance()->SetSelectionMenuOptions(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
1321 }
1322 } // namespace OHOS::Ace::Framework
1323