• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/declarative_frontend/jsview/js_text.h"
17 
18 #include <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