• 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_span.h"
17 #include "frameworks/bridge/declarative_frontend/jsview/js_container_span.h"
18 
19 #include <optional>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 
24 #include "base/geometry/dimension.h"
25 #include "base/log/ace_scoring_log.h"
26 #include "base/log/ace_trace.h"
27 #include "base/utils/utils.h"
28 #include "bridge/common/utils/utils.h"
29 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
30 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
31 #include "bridge/declarative_frontend/jsview/js_utils.h"
32 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
33 #include "bridge/declarative_frontend/jsview/models/span_model_impl.h"
34 #include "bridge/declarative_frontend/jsview/models/text_model_impl.h"
35 #ifndef NG_BUILD
36 #include "bridge/declarative_frontend/view_stack_processor.h"
37 #endif
38 #include "bridge/declarative_frontend/jsview/js_text.h"
39 #include "core/common/container.h"
40 #include "core/components_ng/pattern/text/span_model.h"
41 #include "core/components_ng/pattern/text/span_model_ng.h"
42 #include "core/components_ng/pattern/text/text_model.h"
43 
44 namespace OHOS::Ace {
45 
46 std::unique_ptr<SpanModel> SpanModel::instance_ = nullptr;
47 std::mutex SpanModel::mutex_;
48 
GetInstance()49 SpanModel* SpanModel::GetInstance()
50 {
51     if (!instance_) {
52         std::lock_guard<std::mutex> lock(mutex_);
53         if (!instance_) {
54 #ifdef NG_BUILD
55             instance_.reset(new NG::SpanModelNG());
56 #else
57             if (Container::IsCurrentUseNewPipeline()) {
58                 instance_.reset(new NG::SpanModelNG());
59             } else {
60                 instance_.reset(new Framework::SpanModelImpl());
61             }
62 #endif
63         }
64     }
65     return instance_.get();
66 }
67 
68 } // namespace OHOS::Ace
69 
70 namespace OHOS::Ace::Framework {
71 namespace {
72 
73 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
74 const std::vector<TextCase> TEXT_CASES = { TextCase::NORMAL, TextCase::LOWERCASE, TextCase::UPPERCASE };
75 
76 } // namespace
77 
SetFont(const JSCallbackInfo & info)78 void JSSpan::SetFont(const JSCallbackInfo& info)
79 {
80     Font font;
81     JSText::GetFontInfo(info, font);
82     SpanModel::GetInstance()->SetFont(font);
83 }
84 
SetFontSize(const JSCallbackInfo & info)85 void JSSpan::SetFontSize(const JSCallbackInfo& info)
86 {
87     if (info.Length() < 1) {
88         return;
89     }
90     CalcDimension fontSize;
91     if (!ParseJsDimensionFpNG(info[0], fontSize, false) || fontSize.IsNegative()) {
92         auto pipelineContext = PipelineBase::GetCurrentContext();
93         CHECK_NULL_VOID(pipelineContext);
94         auto theme = pipelineContext->GetTheme<TextTheme>();
95         CHECK_NULL_VOID(theme);
96         fontSize = theme->GetTextStyle().GetFontSize();
97         SpanModel::GetInstance()->SetFontSize(fontSize);
98         return;
99     }
100 
101     SpanModel::GetInstance()->SetFontSize(fontSize);
102 }
103 
SetFontWeight(const std::string & value)104 void JSSpan::SetFontWeight(const std::string& value)
105 {
106     SpanModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
107 }
108 
SetTextColor(const JSCallbackInfo & info)109 void JSSpan::SetTextColor(const JSCallbackInfo& info)
110 {
111     Color textColor;
112     if (!ParseJsColor(info[0], textColor)) {
113         auto pipelineContext = PipelineBase::GetCurrentContext();
114         CHECK_NULL_VOID(pipelineContext);
115         auto theme = pipelineContext->GetTheme<TextTheme>();
116         CHECK_NULL_VOID(theme);
117         textColor = theme->GetTextStyle().GetTextColor();
118     }
119     SpanModel::GetInstance()->SetTextColor(textColor);
120 }
121 
SetFontStyle(int32_t value)122 void JSSpan::SetFontStyle(int32_t value)
123 {
124     if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
125         auto style = FONT_STYLES[value];
126         SpanModel::GetInstance()->SetItalicFontStyle(style);
127     }
128 }
129 
SetFontFamily(const JSCallbackInfo & info)130 void JSSpan::SetFontFamily(const JSCallbackInfo& info)
131 {
132     if (info.Length() < 1) {
133         return;
134     }
135     std::vector<std::string> fontFamilies;
136     if (!ParseJsFontFamilies(info[0], fontFamilies)) {
137         return;
138     }
139     SpanModel::GetInstance()->SetFontFamily(fontFamilies);
140 }
141 
SetLetterSpacing(const JSCallbackInfo & info)142 void JSSpan::SetLetterSpacing(const JSCallbackInfo& info)
143 {
144     if (info.Length() < 1) {
145         return;
146     }
147     CalcDimension value;
148     if (!ParseJsDimensionFpNG(info[0], value, false)) {
149         value.Reset();
150         SpanModel::GetInstance()->SetLetterSpacing(value);
151         return;
152     }
153     SpanModel::GetInstance()->SetLetterSpacing(value);
154 }
155 
SetTextCase(int32_t value)156 void JSSpan::SetTextCase(int32_t value)
157 {
158     if (value >= 0 && value < static_cast<int32_t>(TEXT_CASES.size())) {
159         auto textCase = TEXT_CASES[value];
160         SpanModel::GetInstance()->SetTextCase(textCase);
161     }
162 }
163 
SetDecoration(const JSCallbackInfo & info)164 void JSSpan::SetDecoration(const JSCallbackInfo& info)
165 {
166     if (!info[0]->IsObject()) {
167         return;
168     }
169     JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
170     JSRef<JSVal> typeValue = obj->GetProperty("type");
171     JSRef<JSVal> colorValue = obj->GetProperty("color");
172     JSRef<JSVal> styleValue = obj->GetProperty("style");
173 
174     std::optional<TextDecoration> textDecoration;
175     if (typeValue->IsNumber()) {
176         textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
177     }
178     std::optional<TextDecorationStyle> textDecorationStyle;
179     if (styleValue->IsNumber()) {
180         textDecorationStyle = static_cast<TextDecorationStyle>(styleValue->ToNumber<int32_t>());
181     }
182     std::optional<Color> colorVal;
183     Color result;
184     if (ParseJsColor(colorValue, result)) {
185         colorVal = result;
186     } else {
187         // default color
188         colorVal = Color::BLACK;
189     }
190     if (textDecoration) {
191         SpanModel::GetInstance()->SetTextDecoration(textDecoration.value());
192     }
193     if (colorVal) {
194         SpanModel::GetInstance()->SetTextDecorationColor(colorVal.value());
195     }
196     if (textDecorationStyle) {
197         SpanModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value());
198     }
199 }
200 
JsOnClick(const JSCallbackInfo & info)201 void JSSpan::JsOnClick(const JSCallbackInfo& info)
202 {
203     if (Container::IsCurrentUseNewPipeline()) {
204         if (info[0]->IsUndefined() && IsDisableEventVersion()) {
205             SpanModel::GetInstance()->ClearOnClick();
206             return;
207         }
208         if (!info[0]->IsFunction()) {
209             return;
210         }
211         auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
212         WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
213         auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = targetNode](
214                            const BaseEventInfo* info) {
215             const auto* clickInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
216             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
217             ACE_SCORING_EVENT("onClick");
218             PipelineContext::SetCallBackNode(node);
219             func->Execute(*clickInfo);
220         };
221         SpanModel::GetInstance()->SetOnClick(std::move(onClick));
222         return;
223     }
224 #ifndef NG_BUILD
225     if (info[0]->IsFunction()) {
226         auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
227         CHECK_NULL_VOID(inspector);
228         auto impl = inspector->GetInspectorFunctionImpl();
229         RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
230         WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
231         auto clickFunc = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl,
232                              node = targetNode](const BaseEventInfo* info) {
233             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
234             const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
235             auto newInfo = *clickInfo;
236             if (impl) {
237                 impl->UpdateEventInfo(newInfo);
238             }
239             ACE_SCORING_EVENT("Span.onClick");
240             PipelineContext::SetCallBackNode(node);
241             func->Execute(newInfo);
242         };
243         SpanModel::GetInstance()->SetOnClick(std::move(clickFunc));
244     }
245 #endif
246 }
247 
JsRemoteMessage(const JSCallbackInfo & info)248 void JSSpan::JsRemoteMessage(const JSCallbackInfo& info)
249 {
250 #ifndef NG_BUILD
251     RemoteCallback remoteCallback;
252     JSInteractableView::JsRemoteMessage(info, remoteCallback);
253     EventMarker remoteMessageEventId(std::move(remoteCallback));
254     auto* stack = ViewStackProcessor::GetInstance();
255     auto textSpanComponent = AceType::DynamicCast<TextSpanComponent>(stack->GetMainComponent());
256     textSpanComponent->SetRemoteMessageEventId(remoteMessageEventId);
257 #endif
258 }
259 
SetLineHeight(const JSCallbackInfo & info)260 void JSSpan::SetLineHeight(const JSCallbackInfo& info)
261 {
262     CalcDimension value;
263     if (!ParseJsDimensionFpNG(info[0], value)) {
264         value.Reset();
265         SpanModel::GetInstance()->SetLineHeight(value);
266         return;
267     }
268     if (value.IsNegative()) {
269         value.Reset();
270     }
271     SpanModel::GetInstance()->SetLineHeight(value);
272 }
273 
SetTextShadow(const JSCallbackInfo & info)274 void JSSpan::SetTextShadow(const JSCallbackInfo& info)
275 {
276     if (info.Length() < 1) {
277         return;
278     }
279     std::vector<Shadow> shadows;
280     ParseTextShadowFromShadowObject(info[0], shadows);
281     SpanModel::GetInstance()->SetTextShadow(shadows);
282 }
283 
JSBind(BindingTarget globalObj)284 void JSSpan::JSBind(BindingTarget globalObj)
285 {
286     JSClass<JSSpan>::Declare("Span");
287     MethodOptions opt = MethodOptions::NONE;
288     JSClass<JSSpan>::StaticMethod("create", &JSSpan::Create, opt);
289     JSClass<JSSpan>::StaticMethod("font", &JSSpan::SetFont, opt);
290     JSClass<JSSpan>::StaticMethod("fontColor", &JSSpan::SetTextColor, opt);
291     JSClass<JSSpan>::StaticMethod("fontSize", &JSSpan::SetFontSize, opt);
292     JSClass<JSSpan>::StaticMethod("fontWeight", &JSSpan::SetFontWeight, opt);
293     JSClass<JSSpan>::StaticMethod("fontStyle", &JSSpan::SetFontStyle, opt);
294     JSClass<JSSpan>::StaticMethod("fontFamily", &JSSpan::SetFontFamily, opt);
295     JSClass<JSSpan>::StaticMethod("letterSpacing", &JSSpan::SetLetterSpacing, opt);
296     JSClass<JSSpan>::StaticMethod("textCase", &JSSpan::SetTextCase, opt);
297     JSClass<JSSpan>::StaticMethod("textShadow", &JSSpan::SetTextShadow, opt);
298     JSClass<JSSpan>::StaticMethod("decoration", &JSSpan::SetDecoration);
299     JSClass<JSSpan>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
300     JSClass<JSSpan>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
301     JSClass<JSSpan>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
302     JSClass<JSSpan>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
303     JSClass<JSSpan>::StaticMethod("remoteMessage", &JSSpan::JsRemoteMessage);
304     JSClass<JSSpan>::StaticMethod("onClick", &JSSpan::JsOnClick);
305     JSClass<JSSpan>::StaticMethod("lineHeight", &JSSpan::SetLineHeight, opt);
306     JSClass<JSSpan>::StaticMethod("textBackgroundStyle", &JSContainerSpan::SetTextBackgroundStyle, opt);
307     JSClass<JSSpan>::InheritAndBind<JSContainerBase>(globalObj);
308 }
309 
Create(const JSCallbackInfo & info)310 void JSSpan::Create(const JSCallbackInfo& info)
311 {
312     std::string label;
313     if (info.Length() > 0) {
314         ParseJsString(info[0], label);
315     }
316     SpanModel::GetInstance()->Create(label);
317 }
318 
319 } // namespace OHOS::Ace::Framework
320