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