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