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 <sstream>
19 #include <string>
20 #include <vector>
21
22 #include "base/geometry/dimension.h"
23 #include "base/log/ace_scoring_log.h"
24 #include "base/log/ace_trace.h"
25 #include "base/utils/utils.h"
26 #include "bridge/common/utils/utils.h"
27 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
28 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
29 #include "bridge/declarative_frontend/engine/functions/js_function.h"
30 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
31 #include "bridge/declarative_frontend/jsview/js_text.h"
32 #include "bridge/declarative_frontend/jsview/js_utils.h"
33 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
34 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
35 #include "bridge/declarative_frontend/jsview/models/text_model_impl.h"
36 #include "bridge/declarative_frontend/view_stack_processor.h"
37 #include "core/common/container.h"
38 #include "core/components/text/text_theme.h"
39 #include "core/components_ng/base/view_stack_processor.h"
40 #include "core/components_ng/event/gesture_event_hub.h"
41 #include "core/components_ng/pattern/text/text_model.h"
42 #include "core/components_ng/pattern/text/text_model_ng.h"
43 #include "core/event/ace_event_handler.h"
44 #include "core/pipeline/pipeline_base.h"
45
46 namespace OHOS::Ace {
47
48 std::unique_ptr<TextModel> TextModel::instance_ = nullptr;
49 std::mutex TextModel::mutex_;
50
GetInstance()51 TextModel* TextModel::GetInstance()
52 {
53 if (!instance_) {
54 std::lock_guard<std::mutex> lock(mutex_);
55 if (!instance_) {
56 #ifdef NG_BUILD
57 instance_.reset(new NG::TextModelNG());
58 #else
59 if (Container::IsCurrentUseNewPipeline()) {
60 instance_.reset(new NG::TextModelNG());
61 } else {
62 instance_.reset(new Framework::TextModelImpl());
63 }
64 #endif
65 }
66 }
67 return instance_.get();
68 }
69
70 } // namespace OHOS::Ace
71
72 namespace OHOS::Ace::Framework {
73 namespace {
74
75 const std::vector<TextCase> TEXT_CASES = { TextCase::NORMAL, TextCase::LOWERCASE, TextCase::UPPERCASE };
76 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
77 TextOverflow::MARQUEE };
78 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
79 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END, TextAlign::JUSTIFY,
80 TextAlign::LEFT, TextAlign::RIGHT };
81 const std::vector<TextHeightAdaptivePolicy> HEIGHT_ADAPTIVE_POLICY = { TextHeightAdaptivePolicy::MAX_LINES_FIRST,
82 TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST };
83 const std::vector<WordBreak> WORD_BREAK_TYPES = { WordBreak::NORMAL, WordBreak::BREAK_ALL, WordBreak::BREAK_WORD };
84 const std::vector<EllipsisMode> ELLIPSIS_MODALS = { EllipsisMode::HEAD, EllipsisMode::MIDDLE, EllipsisMode::TAIL };
85 }; // namespace
86
SetWidth(const JSCallbackInfo & info)87 void JSText::SetWidth(const JSCallbackInfo& info)
88 {
89 JSViewAbstract::JsWidth(info);
90 TextModel::GetInstance()->OnSetWidth();
91 }
92
SetHeight(const JSCallbackInfo & info)93 void JSText::SetHeight(const JSCallbackInfo& info)
94 {
95 JSViewAbstract::JsHeight(info);
96 TextModel::GetInstance()->OnSetHeight();
97 }
98
SetFont(const JSCallbackInfo & info)99 void JSText::SetFont(const JSCallbackInfo& info)
100 {
101 Font font;
102 GetFontInfo(info, font);
103 TextModel::GetInstance()->SetFont(font);
104 }
105
GetFontInfo(const JSCallbackInfo & info,Font & font)106 void JSText::GetFontInfo(const JSCallbackInfo& info, Font& font)
107 {
108 auto tmpInfo = info[0];
109 if (!tmpInfo->IsObject()) {
110 return;
111 }
112 auto paramObject = JSRef<JSObject>::Cast(tmpInfo);
113 auto fontSize = paramObject->GetProperty("size");
114 CalcDimension size;
115 if (ParseJsDimensionFpNG(fontSize, size, false) && size.IsNonNegative()) {
116 font.fontSize = size;
117 } else {
118 auto pipelineContext = PipelineContext::GetCurrentContext();
119 CHECK_NULL_VOID(pipelineContext);
120 auto theme = pipelineContext->GetTheme<TextTheme>();
121 CHECK_NULL_VOID(theme);
122 font.fontSize = theme->GetTextStyle().GetFontSize();
123 }
124 std::string weight;
125 auto fontWeight = paramObject->GetProperty("weight");
126 if (!fontWeight->IsNull()) {
127 if (fontWeight->IsNumber()) {
128 weight = std::to_string(fontWeight->ToNumber<int32_t>());
129 } else {
130 JSContainerBase::ParseJsString(fontWeight, weight);
131 }
132 font.fontWeight = ConvertStrToFontWeight(weight);
133 }
134 auto fontFamily = paramObject->GetProperty("family");
135 if (!fontFamily->IsNull()) {
136 std::vector<std::string> fontFamilies;
137 if (JSContainerBase::ParseJsFontFamilies(fontFamily, fontFamilies)) {
138 font.fontFamilies = fontFamilies;
139 }
140 }
141 auto style = paramObject->GetProperty("style");
142 if (!style->IsNull() || style->IsNumber()) {
143 font.fontStyle = static_cast<FontStyle>(style->ToNumber<int32_t>());
144 }
145 }
146
SetFontSize(const JSCallbackInfo & info)147 void JSText::SetFontSize(const JSCallbackInfo& info)
148 {
149 if (info.Length() < 1) {
150 return;
151 }
152 CalcDimension fontSize;
153 if (!ParseJsDimensionFpNG(info[0], fontSize, false) || fontSize.IsNegative()) {
154 auto pipelineContext = PipelineBase::GetCurrentContext();
155 CHECK_NULL_VOID(pipelineContext);
156 auto theme = pipelineContext->GetTheme<TextTheme>();
157 CHECK_NULL_VOID(theme);
158 fontSize = theme->GetTextStyle().GetFontSize();
159 TextModel::GetInstance()->SetFontSize(fontSize);
160 return;
161 }
162 TextModel::GetInstance()->SetFontSize(fontSize);
163 }
164
SetFontWeight(const std::string & value)165 void JSText::SetFontWeight(const std::string& value)
166 {
167 TextModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
168 }
169
SetTextColor(const JSCallbackInfo & info)170 void JSText::SetTextColor(const JSCallbackInfo& info)
171 {
172 if (info.Length() < 1) {
173 return;
174 }
175 Color textColor;
176 if (!ParseJsColor(info[0], textColor)) {
177 auto pipelineContext = PipelineBase::GetCurrentContext();
178 CHECK_NULL_VOID(pipelineContext);
179 auto theme = pipelineContext->GetTheme<TextTheme>();
180 CHECK_NULL_VOID(theme);
181 textColor = theme->GetTextStyle().GetTextColor();
182 }
183 TextModel::GetInstance()->SetTextColor(textColor);
184 }
185
SetTextShadow(const JSCallbackInfo & info)186 void JSText::SetTextShadow(const JSCallbackInfo& info)
187 {
188 if (info.Length() < 1) {
189 return;
190 }
191 std::vector<Shadow> shadows;
192 ParseTextShadowFromShadowObject(info[0], shadows);
193 TextModel::GetInstance()->SetTextShadow(shadows);
194 }
195
SetTextOverflow(const JSCallbackInfo & info)196 void JSText::SetTextOverflow(const JSCallbackInfo& info)
197 {
198 do {
199 auto tmpInfo = info[0];
200 if (!tmpInfo->IsObject()) {
201 break;
202 }
203 JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
204 JSRef<JSVal> overflowValue = obj->GetProperty("overflow");
205 if (!overflowValue->IsNumber() && !overflowValue->IsUndefined()) {
206 break;
207 }
208 auto overflow = overflowValue->ToNumber<int32_t>();
209 if(overflowValue->IsUndefined()) {
210 overflow = 0;
211 } else if (overflow < 0 || overflow >= static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
212 break;
213 }
214 TextModel::GetInstance()->SetTextOverflow(TEXT_OVERFLOWS[overflow]);
215 } while (false);
216
217 info.SetReturnValue(info.This());
218 }
219
SetWordBreak(const JSCallbackInfo & info)220 void JSText::SetWordBreak(const JSCallbackInfo& info)
221 {
222 if (info.Length() < 1) {
223 return;
224 }
225 if (!info[0]->IsNumber()) {
226 return;
227 }
228 auto index = info[0]->ToNumber<int32_t>();
229 if (index < 0 || index >= static_cast<int32_t>(WORD_BREAK_TYPES.size())) {
230 return;
231 }
232 TextModel::GetInstance()->SetWordBreak(WORD_BREAK_TYPES[index]);
233 }
234
SetEllipsisMode(const JSCallbackInfo & info)235 void JSText::SetEllipsisMode(const JSCallbackInfo& info)
236 {
237 if (info.Length() < 1) {
238 return;
239 }
240 if (!info[0]->IsNumber()) {
241 return;
242 }
243 auto index = info[0]->ToNumber<int32_t>();
244 if (index < 0 || index >= static_cast<int32_t>(ELLIPSIS_MODALS.size())) {
245 return;
246 }
247 TextModel::GetInstance()->SetEllipsisMode(ELLIPSIS_MODALS[index]);
248 }
249
SetTextSelection(const JSCallbackInfo & info)250 void JSText::SetTextSelection(const JSCallbackInfo& info)
251 {
252 if (info.Length() < 1) {
253 return;
254 }
255 if (!info[0]->IsNumber() || !info[1]->IsNumber()) {
256 return;
257 }
258 auto startIndex = info[0]->ToNumber<int32_t>();
259 auto endIndex = info[1]->ToNumber<int32_t>();
260 if (startIndex == -1 && endIndex == -1) {
261 TextModel::GetInstance()->SetTextSelection(startIndex, endIndex);
262 return;
263 }
264 if (startIndex >= endIndex) {
265 return;
266 }
267 TextModel::GetInstance()->SetTextSelection(startIndex, endIndex);
268 }
269
SetMaxLines(const JSCallbackInfo & info)270 void JSText::SetMaxLines(const JSCallbackInfo& info)
271 {
272 int32_t value = Infinity<uint32_t>();
273 if (info[0]->ToString() != "Infinity") {
274 ParseJsInt32(info[0], value);
275 }
276 TextModel::GetInstance()->SetMaxLines(value);
277 }
278
SetTextIndent(const JSCallbackInfo & info)279 void JSText::SetTextIndent(const JSCallbackInfo& info)
280 {
281 CalcDimension value;
282 if (!ParseJsDimensionFpNG(info[0], value)) {
283 value.Reset();
284 TextModel::GetInstance()->SetTextIndent(value);
285 return;
286 }
287 TextModel::GetInstance()->SetTextIndent(value);
288 }
289
SetFontStyle(int32_t value)290 void JSText::SetFontStyle(int32_t value)
291 {
292 if (value < 0 || value >= static_cast<int32_t>(FONT_STYLES.size())) {
293 return;
294 }
295 TextModel::GetInstance()->SetItalicFontStyle(FONT_STYLES[value]);
296 }
297
SetTextAlign(int32_t value)298 void JSText::SetTextAlign(int32_t value)
299 {
300 if (value < 0 || value >= static_cast<int32_t>(TEXT_ALIGNS.size())) {
301 return;
302 }
303 TextModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
304 }
305
SetAlign(const JSCallbackInfo & info)306 void JSText::SetAlign(const JSCallbackInfo& info)
307 {
308 JSViewAbstract::JsAlign(info);
309 if (!info[0]->IsNumber()) {
310 return;
311 }
312 TextModel::GetInstance()->OnSetAlign();
313 }
314
SetLineHeight(const JSCallbackInfo & info)315 void JSText::SetLineHeight(const JSCallbackInfo& info)
316 {
317 CalcDimension value;
318 if (!ParseJsDimensionFpNG(info[0], value)) {
319 value.Reset();
320 TextModel::GetInstance()->SetLineHeight(value);
321 return;
322 }
323 if (value.IsNegative()) {
324 value.Reset();
325 }
326 TextModel::GetInstance()->SetLineHeight(value);
327 }
328
SetFontFamily(const JSCallbackInfo & info)329 void JSText::SetFontFamily(const JSCallbackInfo& info)
330 {
331 std::vector<std::string> fontFamilies;
332 if (!ParseJsFontFamilies(info[0], fontFamilies)) {
333 return;
334 }
335 TextModel::GetInstance()->SetFontFamily(fontFamilies);
336 }
337
SetMinFontSize(const JSCallbackInfo & info)338 void JSText::SetMinFontSize(const JSCallbackInfo& info)
339 {
340 if (info.Length() < 1) {
341 return;
342 }
343 auto pipelineContext = PipelineBase::GetCurrentContext();
344 CHECK_NULL_VOID(pipelineContext);
345 auto theme = pipelineContext->GetTheme<TextTheme>();
346 CHECK_NULL_VOID(theme);
347 CalcDimension minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
348 if (!ParseJsDimensionFpNG(info[0], minFontSize, false)) {
349 minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
350 TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
351 return;
352 }
353 if (minFontSize.IsNegative()) {
354 minFontSize = theme->GetTextStyle().GetAdaptMinFontSize();
355 }
356 TextModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
357 }
358
SetMaxFontSize(const JSCallbackInfo & info)359 void JSText::SetMaxFontSize(const JSCallbackInfo& info)
360 {
361 if (info.Length() < 1) {
362 return;
363 }
364 auto pipelineContext = PipelineBase::GetCurrentContext();
365 CHECK_NULL_VOID(pipelineContext);
366 auto theme = pipelineContext->GetTheme<TextTheme>();
367 CHECK_NULL_VOID(theme);
368 CalcDimension maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
369 if (!ParseJsDimensionFpNG(info[0], maxFontSize, false)) {
370 maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
371 TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
372 return;
373 }
374 if (maxFontSize.IsNegative()) {
375 maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
376 }
377 TextModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
378 }
379
SetLetterSpacing(const JSCallbackInfo & info)380 void JSText::SetLetterSpacing(const JSCallbackInfo& info)
381 {
382 CalcDimension value;
383 if (!ParseJsDimensionFpNG(info[0], value, false)) {
384 value.Reset();
385 TextModel::GetInstance()->SetLetterSpacing(value);
386 return;
387 }
388 TextModel::GetInstance()->SetLetterSpacing(value);
389 }
390
SetTextCase(int32_t value)391 void JSText::SetTextCase(int32_t value)
392 {
393 if (value < 0 || value >= static_cast<int32_t>(TEXT_CASES.size())) {
394 return;
395 }
396 TextModel::GetInstance()->SetTextCase(TEXT_CASES[value]);
397 }
398
SetBaselineOffset(const JSCallbackInfo & info)399 void JSText::SetBaselineOffset(const JSCallbackInfo& info)
400 {
401 CalcDimension value;
402 if (!ParseJsDimensionFpNG(info[0], value, false)) {
403 value.Reset();
404 TextModel::GetInstance()->SetBaselineOffset(value);
405 return;
406 }
407 TextModel::GetInstance()->SetBaselineOffset(value);
408 }
409
SetDecoration(const JSCallbackInfo & info)410 void JSText::SetDecoration(const JSCallbackInfo& info)
411 {
412 auto tmpInfo = info[0];
413 if (!tmpInfo->IsObject()) {
414 info.ReturnSelf();
415 return;
416 }
417 JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
418 JSRef<JSVal> typeValue = obj->GetProperty("type");
419 JSRef<JSVal> colorValue = obj->GetProperty("color");
420 JSRef<JSVal> styleValue = obj->GetProperty("style");
421
422 TextDecoration textDecoration;
423 if (typeValue->IsNumber()) {
424 textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
425 } else {
426 auto theme = GetTheme<TextTheme>();
427 CHECK_NULL_VOID(theme);
428 textDecoration = theme->GetTextStyle().GetTextDecoration();
429 }
430 Color result;
431 if (!ParseJsColor(colorValue, result)) {
432 auto theme = GetTheme<TextTheme>();
433 CHECK_NULL_VOID(theme);
434 result = theme->GetTextStyle().GetTextDecorationColor();
435 }
436 std::optional<TextDecorationStyle> textDecorationStyle;
437 if (styleValue->IsNumber()) {
438 textDecorationStyle = static_cast<TextDecorationStyle>(styleValue->ToNumber<int32_t>());
439 }
440 TextModel::GetInstance()->SetTextDecoration(textDecoration);
441 TextModel::GetInstance()->SetTextDecorationColor(result);
442 if (textDecorationStyle) {
443 TextModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value());
444 }
445 info.ReturnSelf();
446 }
447
SetHeightAdaptivePolicy(int32_t value)448 void JSText::SetHeightAdaptivePolicy(int32_t value)
449 {
450 if (value < 0 || value >= static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICY.size())) {
451 return;
452 }
453 TextModel::GetInstance()->SetHeightAdaptivePolicy(HEIGHT_ADAPTIVE_POLICY[value]);
454 }
455
JsOnClick(const JSCallbackInfo & info)456 void JSText::JsOnClick(const JSCallbackInfo& info)
457 {
458 if (Container::IsCurrentUseNewPipeline()) {
459 if (info[0]->IsUndefined() && IsDisableEventVersion()) {
460 TextModel::GetInstance()->ClearOnClick();
461 return;
462 }
463 if (!info[0]->IsFunction()) {
464 return;
465 }
466 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
467 auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
468 auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = frameNode]
469 (const BaseEventInfo* info) {
470 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
471 const auto* clickInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
472 ACE_SCORING_EVENT("Text.onClick");
473 PipelineContext::SetCallBackNode(node);
474 func->Execute(*clickInfo);
475 };
476 TextModel::GetInstance()->SetOnClick(std::move(onClick));
477
478 auto focusHub = NG::ViewStackProcessor::GetInstance()->GetOrCreateMainFrameNodeFocusHub();
479 CHECK_NULL_VOID(focusHub);
480 focusHub->SetFocusable(true, false);
481 } else {
482 #ifndef NG_BUILD
483 if (info[0]->IsFunction()) {
484 auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
485 auto impl = inspector ? inspector->GetInspectorFunctionImpl() : nullptr;
486 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
487 RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
488 auto onClickId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl,
489 node = frameNode](const BaseEventInfo* info) {
490 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
491 const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
492 auto newInfo = *clickInfo;
493 if (impl) {
494 impl->UpdateEventInfo(newInfo);
495 }
496 ACE_SCORING_EVENT("Text.onClick");
497 PipelineContext::SetCallBackNode(node);
498 func->Execute(newInfo);
499 };
500 TextModel::GetInstance()->SetOnClick(std::move(onClickId));
501 }
502 #endif
503 }
504 }
505
JsRemoteMessage(const JSCallbackInfo & info)506 void JSText::JsRemoteMessage(const JSCallbackInfo& info)
507 {
508 JSInteractableView::JsCommonRemoteMessage(info);
509 auto callback = JSInteractableView::GetRemoteMessageEventCallback(info);
510 TextModel::GetInstance()->SetRemoteMessage(std::move(callback));
511 }
512
Create(const JSCallbackInfo & info)513 void JSText::Create(const JSCallbackInfo& info)
514 {
515 std::string data;
516 if (info.Length() > 0) {
517 ParseJsString(info[0], data);
518 }
519
520 TextModel::GetInstance()->Create(data);
521 if (info.Length() <= 1 || !info[1]->IsObject()) {
522 return;
523 }
524
525 JSTextController* jsController = nullptr;
526 auto paramObject = JSRef<JSObject>::Cast(info[1]);
527 auto controllerObj = paramObject->GetProperty("controller");
528 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
529 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextController>();
530 }
531
532 RefPtr<TextControllerBase> controller = TextModel::GetInstance()->GetTextController();
533 if (jsController) {
534 jsController->SetController(controller);
535 }
536 }
537
SetCopyOption(const JSCallbackInfo & info)538 void JSText::SetCopyOption(const JSCallbackInfo& info)
539 {
540 if (info.Length() == 0) {
541 return;
542 }
543 auto copyOptions = CopyOptions::None;
544 auto tmpInfo = info[0];
545 if (tmpInfo->IsNumber()) {
546 auto emunNumber = tmpInfo->ToNumber<int>();
547 copyOptions = static_cast<CopyOptions>(emunNumber);
548 }
549 TextModel::GetInstance()->SetCopyOption(copyOptions);
550 }
551
SetOnCopy(const JSCallbackInfo & info)552 void JSText::SetOnCopy(const JSCallbackInfo& info)
553 {
554 CHECK_NULL_VOID(info[0]->IsFunction());
555 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
556 TextModel::GetInstance()->SetOnCopy(std::move(callback));
557 }
558
JsOnDragStart(const JSCallbackInfo & info)559 void JSText::JsOnDragStart(const JSCallbackInfo& info)
560 {
561 CHECK_NULL_VOID(info[0]->IsFunction());
562 RefPtr<JsDragFunction> jsOnDragStartFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
563 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
564 auto onDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc),
565 targetNode = frameNode](
566 const RefPtr<DragEvent>& info, const std::string& extraParams) -> NG::DragDropBaseInfo {
567 NG::DragDropBaseInfo itemInfo;
568 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo);
569 PipelineContext::SetCallBackNode(targetNode);
570 auto ret = func->Execute(info, extraParams);
571 if (!ret->IsObject()) {
572 return itemInfo;
573 }
574 auto node = ParseDragNode(ret);
575 if (node) {
576 itemInfo.node = node;
577 return itemInfo;
578 }
579 auto builderObj = JSRef<JSObject>::Cast(ret);
580 #if defined(PIXEL_MAP_SUPPORTED)
581 auto pixmap = builderObj->GetProperty("pixelMap");
582 itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap);
583 #endif
584 auto extraInfo = builderObj->GetProperty("extraInfo");
585 ParseJsString(extraInfo, itemInfo.extraInfo);
586 node = ParseDragNode(builderObj->GetProperty("builder"));
587 itemInfo.node = node;
588 return itemInfo;
589 };
590
591 TextModel::GetInstance()->SetOnDragStart(std::move(onDragStart));
592 }
593
JsOnDragEnter(const JSCallbackInfo & info)594 void JSText::JsOnDragEnter(const JSCallbackInfo& info)
595 {
596 CHECK_NULL_VOID(info[0]->IsFunction());
597 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
598 RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
599 auto onDragEnterId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc), node = frameNode](
600 const RefPtr<DragEvent>& info, const std::string& extraParams) {
601 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
602 ACE_SCORING_EVENT("onDragEnter");
603 PipelineContext::SetCallBackNode(node);
604 func->Execute(info, extraParams);
605 };
606 TextModel::GetInstance()->SetOnDragEnter(std::move(onDragEnterId));
607 }
608
JsOnDragMove(const JSCallbackInfo & info)609 void JSText::JsOnDragMove(const JSCallbackInfo& info)
610 {
611 CHECK_NULL_VOID(info[0]->IsFunction());
612 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
613 RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
614 auto onDragMoveId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc), node = frameNode](
615 const RefPtr<DragEvent>& info, const std::string& extraParams) {
616 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
617 ACE_SCORING_EVENT("onDragMove");
618 PipelineContext::SetCallBackNode(node);
619 func->Execute(info, extraParams);
620 };
621 TextModel::GetInstance()->SetOnDragMove(std::move(onDragMoveId));
622 }
623
JsOnDragLeave(const JSCallbackInfo & info)624 void JSText::JsOnDragLeave(const JSCallbackInfo& info)
625 {
626 CHECK_NULL_VOID(info[0]->IsFunction());
627 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
628 RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
629 auto onDragLeaveId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc), node = frameNode](
630 const RefPtr<DragEvent>& info, const std::string& extraParams) {
631 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
632 ACE_SCORING_EVENT("onDragLeave");
633 PipelineContext::SetCallBackNode(node);
634 func->Execute(info, extraParams);
635 };
636 TextModel::GetInstance()->SetOnDragLeave(std::move(onDragLeaveId));
637 }
638
JsOnDrop(const JSCallbackInfo & info)639 void JSText::JsOnDrop(const JSCallbackInfo& info)
640 {
641 CHECK_NULL_VOID(info[0]->IsFunction());
642 RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
643 auto onDropId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
644 const RefPtr<DragEvent>& info, const std::string& extraParams) {
645 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
646 ACE_SCORING_EVENT("onDrop");
647 func->Execute(info, extraParams);
648 };
649 TextModel::GetInstance()->SetOnDrop(std::move(onDropId));
650 }
651
JsFocusable(const JSCallbackInfo & info)652 void JSText::JsFocusable(const JSCallbackInfo& info)
653 {
654 auto tmpInfo = info[0];
655 if (!tmpInfo->IsBoolean()) {
656 return;
657 }
658 JSInteractableView::SetFocusable(tmpInfo->ToBoolean());
659 JSInteractableView::SetFocusNode(false);
660 }
661
JsDraggable(const JSCallbackInfo & info)662 void JSText::JsDraggable(const JSCallbackInfo& info)
663 {
664 auto tmpInfo = info[0];
665 if (!tmpInfo->IsBoolean()) {
666 return;
667 }
668 TextModel::GetInstance()->SetDraggable(tmpInfo->ToBoolean());
669 }
670
JsMenuOptionsExtension(const JSCallbackInfo & info)671 void JSText::JsMenuOptionsExtension(const JSCallbackInfo& info)
672 {
673 if (Container::IsCurrentUseNewPipeline()) {
674 auto tmpInfo = info[0];
675 if (tmpInfo->IsArray()) {
676 std::vector<NG::MenuOptionsParam> menuOptionsItems;
677 JSViewAbstract::ParseMenuOptions(info, JSRef<JSArray>::Cast(tmpInfo), menuOptionsItems);
678 TextModel::GetInstance()->SetMenuOptionItems(std::move(menuOptionsItems));
679 }
680 }
681 }
682
JsEnableDataDetector(const JSCallbackInfo & info)683 void JSText::JsEnableDataDetector(const JSCallbackInfo& info)
684 {
685 if (info.Length() < 1) {
686 return;
687 }
688 auto tmpInfo = info[0];
689 if (!tmpInfo->IsBoolean()) {
690 TextModel::GetInstance()->SetTextDetectEnable(false);
691 return;
692 }
693 auto enable = tmpInfo->ToBoolean();
694 TextModel::GetInstance()->SetTextDetectEnable(enable);
695 }
696
JsDataDetectorConfig(const JSCallbackInfo & info)697 void JSText::JsDataDetectorConfig(const JSCallbackInfo& info)
698 {
699 if (info.Length() < 1) {
700 return;
701 }
702 if (!info[0]->IsObject()) {
703 return;
704 }
705
706 std::string textTypes;
707 std::function<void(const std::string&)> onResult;
708 if (!ParseDataDetectorConfig(info, textTypes, onResult)) {
709 return;
710 }
711 TextModel::GetInstance()->SetTextDetectConfig(textTypes, std::move(onResult));
712 }
713
BindSelectionMenu(const JSCallbackInfo & info)714 void JSText::BindSelectionMenu(const JSCallbackInfo& info)
715 {
716 // TextSpanType
717 NG::TextSpanType testSpanType = NG::TextSpanType::TEXT;
718 if (info[0]->IsNumber()) {
719 auto spanType = info[0]->ToNumber<int32_t>();
720 testSpanType = static_cast<NG::TextSpanType>(spanType);
721 }
722
723 // Builder
724 if (!info[1]->IsObject()) {
725 return;
726 }
727 JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(info[1]);
728 auto builder = menuObj->GetProperty("builder");
729 if (!builder->IsFunction()) {
730 return;
731 }
732 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
733 CHECK_NULL_VOID(builderFunc);
734
735 // TextResponseType
736 int32_t resquiredParameterCount = 3;
737 NG::TextResponseType responseType = NG::TextResponseType::LONG_PRESS;
738 if (info[resquiredParameterCount - 1]->IsNumber()) {
739 auto response = info[resquiredParameterCount - 1]->ToNumber<int32_t>();
740 responseType = static_cast<NG::TextResponseType>(response);
741 }
742
743 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
744 std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc),
745 node = frameNode]() {
746 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
747 ACE_SCORING_EVENT("BindSelectionMenu");
748 PipelineContext::SetCallBackNode(node);
749 func->Execute();
750 };
751
752 // SelectionMenuOptions
753 NG::SelectMenuParam menuParam;
754 if (info.Length() > resquiredParameterCount && info[resquiredParameterCount]->IsObject()) {
755 ParseMenuParam(info, info[resquiredParameterCount], menuParam);
756 }
757
758 TextModel::GetInstance()->BindSelectionMenu(testSpanType, responseType, buildFunc, menuParam);
759 }
760
SetOnTextSelectionChange(const JSCallbackInfo & info)761 void JSText::SetOnTextSelectionChange(const JSCallbackInfo& info)
762 {
763 CHECK_NULL_VOID(info[0]->IsFunction());
764 JsEventCallback<void(int32_t, int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
765 TextModel::GetInstance()->SetOnTextSelectionChange(std::move(callback));
766 }
767
JsClip(const JSCallbackInfo & info)768 void JSText::JsClip(const JSCallbackInfo& info)
769 {
770 JSViewAbstract::JsClip(info);
771 if (info[0]->IsBoolean()) {
772 TextModel::GetInstance()->SetClipEdge();
773 }
774 }
775
JSBind(BindingTarget globalObj)776 void JSText::JSBind(BindingTarget globalObj)
777 {
778 JSClass<JSText>::Declare("Text");
779 MethodOptions opt = MethodOptions::NONE;
780 JSClass<JSText>::StaticMethod("create", &JSText::Create, opt);
781 JSClass<JSText>::StaticMethod("width", &JSText::SetWidth);
782 JSClass<JSText>::StaticMethod("height", &JSText::SetHeight);
783 JSClass<JSText>::StaticMethod("font", &JSText::SetFont, opt);
784 JSClass<JSText>::StaticMethod("fontColor", &JSText::SetTextColor, opt);
785 JSClass<JSText>::StaticMethod("textShadow", &JSText::SetTextShadow, opt);
786 JSClass<JSText>::StaticMethod("fontSize", &JSText::SetFontSize, opt);
787 JSClass<JSText>::StaticMethod("fontWeight", &JSText::SetFontWeight, opt);
788 JSClass<JSText>::StaticMethod("wordBreak", &JSText::SetWordBreak, opt);
789 JSClass<JSText>::StaticMethod("ellipsisMode", &JSText::SetEllipsisMode, opt);
790 JSClass<JSText>::StaticMethod("selection", &JSText::SetTextSelection, opt);
791 JSClass<JSText>::StaticMethod("maxLines", &JSText::SetMaxLines, opt);
792 JSClass<JSText>::StaticMethod("textIndent", &JSText::SetTextIndent);
793 JSClass<JSText>::StaticMethod("textOverflow", &JSText::SetTextOverflow, opt);
794 JSClass<JSText>::StaticMethod("fontStyle", &JSText::SetFontStyle, opt);
795 JSClass<JSText>::StaticMethod("align", &JSText::SetAlign, opt);
796 JSClass<JSText>::StaticMethod("textAlign", &JSText::SetTextAlign, opt);
797 JSClass<JSText>::StaticMethod("lineHeight", &JSText::SetLineHeight, opt);
798 JSClass<JSText>::StaticMethod("fontFamily", &JSText::SetFontFamily, opt);
799 JSClass<JSText>::StaticMethod("minFontSize", &JSText::SetMinFontSize, opt);
800 JSClass<JSText>::StaticMethod("maxFontSize", &JSText::SetMaxFontSize, opt);
801 JSClass<JSText>::StaticMethod("letterSpacing", &JSText::SetLetterSpacing, opt);
802 JSClass<JSText>::StaticMethod("textCase", &JSText::SetTextCase, opt);
803 JSClass<JSText>::StaticMethod("baselineOffset", &JSText::SetBaselineOffset, opt);
804 JSClass<JSText>::StaticMethod("decoration", &JSText::SetDecoration);
805 JSClass<JSText>::StaticMethod("heightAdaptivePolicy", &JSText::SetHeightAdaptivePolicy);
806 JSClass<JSText>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
807 JSClass<JSText>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
808 JSClass<JSText>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
809 JSClass<JSText>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
810 JSClass<JSText>::StaticMethod("remoteMessage", &JSText::JsRemoteMessage);
811 JSClass<JSText>::StaticMethod("copyOption", &JSText::SetCopyOption);
812 JSClass<JSText>::StaticMethod("onClick", &JSText::JsOnClick);
813 JSClass<JSText>::StaticMethod("onCopy", &JSText::SetOnCopy);
814 JSClass<JSText>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
815 JSClass<JSText>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
816 JSClass<JSText>::StaticMethod("onDragStart", &JSText::JsOnDragStart);
817 JSClass<JSText>::StaticMethod("onDragEnter", &JSText::JsOnDragEnter);
818 JSClass<JSText>::StaticMethod("onDragMove", &JSText::JsOnDragMove);
819 JSClass<JSText>::StaticMethod("onDragLeave", &JSText::JsOnDragLeave);
820 JSClass<JSText>::StaticMethod("onDrop", &JSText::JsOnDrop);
821 JSClass<JSText>::StaticMethod("focusable", &JSText::JsFocusable);
822 JSClass<JSText>::StaticMethod("draggable", &JSText::JsDraggable);
823 JSClass<JSText>::StaticMethod("textMenuOptions", &JSText::JsMenuOptionsExtension);
824 JSClass<JSText>::StaticMethod("enableDataDetector", &JSText::JsEnableDataDetector);
825 JSClass<JSText>::StaticMethod("dataDetectorConfig", &JSText::JsDataDetectorConfig);
826 JSClass<JSText>::StaticMethod("bindSelectionMenu", &JSText::BindSelectionMenu);
827 JSClass<JSText>::StaticMethod("onTextSelectionChange", &JSText::SetOnTextSelectionChange);
828 JSClass<JSText>::StaticMethod("clip", &JSText::JsClip);
829 JSClass<JSText>::InheritAndBind<JSContainerBase>(globalObj);
830 }
831
CloseSelectionMenu()832 void JSTextController::CloseSelectionMenu()
833 {
834 auto controller = controllerWeak_.Upgrade();
835 CHECK_NULL_VOID(controller);
836 controller->CloseSelectionMenu();
837 }
838
JSBind(BindingTarget globalObj)839 void JSTextController::JSBind(BindingTarget globalObj)
840 {
841 JSClass<JSTextController>::Declare("TextController");
842 JSClass<JSTextController>::Method("closeSelectionMenu", &JSTextController::CloseSelectionMenu);
843 JSClass<JSTextController>::Bind(globalObj, JSTextController::Constructor, JSTextController::Destructor);
844 }
845
ParseMenuParam(const JSCallbackInfo & info,const JSRef<JSObject> & menuOptions,NG::SelectMenuParam & menuParam)846 void JSText::ParseMenuParam(
847 const JSCallbackInfo& info, const JSRef<JSObject>& menuOptions, NG::SelectMenuParam& menuParam)
848 {
849 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
850 auto onAppearValue = menuOptions->GetProperty("onAppear");
851 if (onAppearValue->IsFunction()) {
852 RefPtr<JsFunction> jsOnAppearFunc =
853 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAppearValue));
854 auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc), node = frameNode](
855 int32_t start, int32_t end) {
856 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
857 ACE_SCORING_EVENT("onAppear");
858
859 JSRef<JSVal> params[2];
860 params[0] = JSRef<JSVal>::Make(ToJSValue(start));
861 params[1] = JSRef<JSVal>::Make(ToJSValue(end));
862 PipelineContext::SetCallBackNode(node);
863 func->ExecuteJS(2, params);
864 };
865 menuParam.onAppear = std::move(onAppear);
866 }
867
868 auto onDisappearValue = menuOptions->GetProperty("onDisappear");
869 if (onDisappearValue->IsFunction()) {
870 RefPtr<JsFunction> jsOnDisAppearFunc =
871 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDisappearValue));
872 auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc),
873 node = frameNode]() {
874 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
875 ACE_SCORING_EVENT("onDisappear");
876 PipelineContext::SetCallBackNode(node);
877 func->Execute();
878 };
879 menuParam.onDisappear = std::move(onDisappear);
880 }
881 }
882 } // namespace OHOS::Ace::Framework
883