• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 
18 #include <optional>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 
23 #include "base/geometry/dimension.h"
24 #include "base/log/ace_scoring_log.h"
25 #include "base/log/ace_trace.h"
26 #include "base/utils/utils.h"
27 #include "bridge/common/utils/utils.h"
28 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
29 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
30 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
31 #include "bridge/declarative_frontend/jsview/models/span_model_impl.h"
32 #include "bridge/declarative_frontend/jsview/models/text_model_impl.h"
33 #ifndef NG_BUILD
34 #include "bridge/declarative_frontend/view_stack_processor.h"
35 #endif
36 #include "core/common/container.h"
37 #include "core/components_ng/pattern/text/span_model.h"
38 #include "core/components_ng/pattern/text/span_model_ng.h"
39 #include "core/components_ng/pattern/text/text_model.h"
40 
41 namespace OHOS::Ace {
42 
43 std::unique_ptr<SpanModel> SpanModel::instance_ = nullptr;
44 
GetInstance()45 SpanModel* SpanModel::GetInstance()
46 {
47     if (!instance_) {
48 #ifdef NG_BUILD
49         instance_.reset(new NG::SpanModelNG());
50 #else
51         if (Container::IsCurrentUseNewPipeline()) {
52             instance_.reset(new NG::SpanModelNG());
53         } else {
54             instance_.reset(new Framework::SpanModelImpl());
55         }
56 #endif
57     }
58     return instance_.get();
59 }
60 
61 } // namespace OHOS::Ace
62 
63 namespace OHOS::Ace::Framework {
64 namespace {
65 
66 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
67 const std::vector<TextCase> TEXT_CASES = { TextCase::NORMAL, TextCase::LOWERCASE, TextCase::UPPERCASE };
68 
69 } // namespace
70 
SetFontSize(const JSCallbackInfo & info)71 void JSSpan::SetFontSize(const JSCallbackInfo& info)
72 {
73     if (info.Length() < 1) {
74         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
75         return;
76     }
77     Dimension fontSize;
78     if (!ParseJsDimensionFp(info[0], fontSize)) {
79         return;
80     }
81 
82     SpanModel::GetInstance()->SetFontSize(fontSize);
83 }
84 
SetFontWeight(const std::string & value)85 void JSSpan::SetFontWeight(const std::string& value)
86 {
87     SpanModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
88 }
89 
SetTextColor(const JSCallbackInfo & info)90 void JSSpan::SetTextColor(const JSCallbackInfo& info)
91 {
92     if (info.Length() < 1) {
93         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
94         return;
95     }
96     Color textColor;
97     if (!ParseJsColor(info[0], textColor)) {
98         return;
99     }
100     SpanModel::GetInstance()->SetTextColor(textColor);
101 }
102 
SetFontStyle(int32_t value)103 void JSSpan::SetFontStyle(int32_t value)
104 {
105     if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
106         auto style = FONT_STYLES[value];
107         SpanModel::GetInstance()->SetItalicFontStyle(style);
108     } else {
109         LOGE("Text fontStyle(%{public}d) illegal value", value);
110     }
111 }
112 
SetFontFamily(const JSCallbackInfo & info)113 void JSSpan::SetFontFamily(const JSCallbackInfo& info)
114 {
115     if (info.Length() < 1) {
116         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
117         return;
118     }
119     std::vector<std::string> fontFamilies;
120     if (!ParseJsFontFamilies(info[0], fontFamilies)) {
121         LOGE("Parse FontFamilies failed");
122         return;
123     }
124     SpanModel::GetInstance()->SetFontFamily(fontFamilies);
125 }
126 
SetLetterSpacing(const JSCallbackInfo & info)127 void JSSpan::SetLetterSpacing(const JSCallbackInfo& info)
128 {
129     if (info.Length() < 1) {
130         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
131         return;
132     }
133     Dimension value;
134     if (!ParseJsDimensionFp(info[0], value)) {
135         return;
136     }
137     SpanModel::GetInstance()->SetLetterSpacing(value);
138 }
139 
SetTextCase(int32_t value)140 void JSSpan::SetTextCase(int32_t value)
141 {
142     if (value >= 0 && value < static_cast<int32_t>(TEXT_CASES.size())) {
143         auto textCase = TEXT_CASES[value];
144         SpanModel::GetInstance()->SetTextCase(textCase);
145     } else {
146         LOGE("Text textCase(%{public}d) illegal value", value);
147     }
148 }
149 
SetDecoration(const JSCallbackInfo & info)150 void JSSpan::SetDecoration(const JSCallbackInfo& info)
151 {
152     if (!info[0]->IsObject()) {
153         LOGE("info[0] not is Object");
154         return;
155     }
156     JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
157     JSRef<JSVal> typeValue = obj->GetProperty("type");
158     JSRef<JSVal> colorValue = obj->GetProperty("color");
159 
160     std::optional<TextDecoration> textDecoration;
161     if (typeValue->IsNumber()) {
162         textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
163     }
164     std::optional<Color> colorVal;
165     Color result;
166     if (ParseJsColor(colorValue, result)) {
167         colorVal = result;
168     } else {
169         // default color
170         colorVal = Color::BLACK;
171     }
172     if (textDecoration) {
173         SpanModel::GetInstance()->SetTextDecoration(textDecoration.value());
174     }
175     if (colorVal) {
176         SpanModel::GetInstance()->SetTextDecorationColor(colorVal.value());
177     }
178 }
179 
JsOnClick(const JSCallbackInfo & info)180 void JSSpan::JsOnClick(const JSCallbackInfo& info)
181 {
182     if (Container::IsCurrentUseNewPipeline()) {
183         if (!info[0]->IsFunction()) {
184             LOGW("the info is not click function");
185             return;
186         }
187         auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
188         auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc](const BaseEventInfo* info) {
189             const auto* clickInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
190             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
191             ACE_SCORING_EVENT("onClick");
192             func->Execute(*clickInfo);
193         };
194         SpanModel::GetInstance()->SetOnClick(std::move(onClick));
195         return;
196     }
197 #ifndef NG_BUILD
198     if (info[0]->IsFunction()) {
199         auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent();
200         CHECK_NULL_VOID(inspector);
201         auto impl = inspector->GetInspectorFunctionImpl();
202         RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
203         auto clickFunc = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl](
204                              const BaseEventInfo* info) {
205             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
206             LOGD("About to call onclick method on js");
207             const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
208             auto newInfo = *clickInfo;
209             if (impl) {
210                 impl->UpdateEventInfo(newInfo);
211             }
212             ACE_SCORING_EVENT("Span.onClick");
213             func->Execute(newInfo);
214         };
215         SpanModel::GetInstance()->SetOnClick(std::move(clickFunc));
216     }
217 #endif
218 }
219 
JsRemoteMessage(const JSCallbackInfo & info)220 void JSSpan::JsRemoteMessage(const JSCallbackInfo& info)
221 {
222 #ifndef NG_BUILD
223     RemoteCallback remoteCallback;
224     JSInteractableView::JsRemoteMessage(info, remoteCallback);
225     EventMarker remoteMessageEventId(std::move(remoteCallback));
226     auto* stack = ViewStackProcessor::GetInstance();
227     auto textSpanComponent = AceType::DynamicCast<TextSpanComponent>(stack->GetMainComponent());
228     textSpanComponent->SetRemoteMessageEventId(remoteMessageEventId);
229 #endif
230 }
231 
JSBind(BindingTarget globalObj)232 void JSSpan::JSBind(BindingTarget globalObj)
233 {
234     JSClass<JSSpan>::Declare("Span");
235     MethodOptions opt = MethodOptions::NONE;
236     JSClass<JSSpan>::StaticMethod("create", &JSSpan::Create, opt);
237     JSClass<JSSpan>::StaticMethod("fontColor", &JSSpan::SetTextColor, opt);
238     JSClass<JSSpan>::StaticMethod("fontSize", &JSSpan::SetFontSize, opt);
239     JSClass<JSSpan>::StaticMethod("fontWeight", &JSSpan::SetFontWeight, opt);
240     JSClass<JSSpan>::StaticMethod("fontStyle", &JSSpan::SetFontStyle, opt);
241     JSClass<JSSpan>::StaticMethod("fontFamily", &JSSpan::SetFontFamily, opt);
242     JSClass<JSSpan>::StaticMethod("letterSpacing", &JSSpan::SetLetterSpacing, opt);
243     JSClass<JSSpan>::StaticMethod("textCase", &JSSpan::SetTextCase, opt);
244     JSClass<JSSpan>::StaticMethod("decoration", &JSSpan::SetDecoration);
245     JSClass<JSSpan>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
246     JSClass<JSSpan>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
247     JSClass<JSSpan>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
248     JSClass<JSSpan>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
249     JSClass<JSSpan>::StaticMethod("remoteMessage", &JSSpan::JsRemoteMessage);
250     JSClass<JSSpan>::StaticMethod("onClick", &JSSpan::JsOnClick);
251     JSClass<JSSpan>::Inherit<JSContainerBase>();
252     JSClass<JSSpan>::Inherit<JSViewAbstract>();
253     JSClass<JSSpan>::Bind<>(globalObj);
254 }
255 
Create(const JSCallbackInfo & info)256 void JSSpan::Create(const JSCallbackInfo& info)
257 {
258     std::string label;
259     if (info.Length() > 0) {
260         ParseJsString(info[0], label);
261     }
262     SpanModel::GetInstance()->Create(label);
263 }
264 
265 } // namespace OHOS::Ace::Framework
266