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_marquee.h"
17 #include <limits>
18 #include <optional>
19 #include <string>
20 #include <vector>
21 
22 #include "base/geometry/dimension.h"
23 #include "base/log/ace_scoring_log.h"
24 #include "base/utils/utils.h"
25 #include "bridge/declarative_frontend/engine/functions/js_function.h"
26 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
27 #include "bridge/declarative_frontend/jsview/models/marquee_model_impl.h"
28 #include "core/components/text/text_theme.h"
29 #include "core/components_ng/base/view_stack_processor.h"
30 #include "core/components_ng/pattern/marquee/marquee_model.h"
31 #include "core/components_ng/pattern/marquee/marquee_model_ng.h"
32 
33 namespace OHOS::Ace {
34 
35 std::unique_ptr<MarqueeModel> MarqueeModel::instance_ = nullptr;
36 std::mutex MarqueeModel::mutex_;
GetInstance()37 MarqueeModel* MarqueeModel::GetInstance()
38 {
39 #ifdef NG_BUILD
40     static NG::MarqueeModelNG instance;
41     return &instance;
42 #else
43     if (Container::IsCurrentUseNewPipeline()) {
44         static NG::MarqueeModelNG instance;
45         return &instance;
46     } else {
47         static Framework::MarqueeModelImpl instance;
48         return &instance;
49     }
50 #endif
51 }
52 } // namespace OHOS::Ace
53 
54 namespace OHOS::Ace::Framework {
55 
56 const std::vector<MarqueeUpdateStrategy> MARQUEE_UPDATE_STRATEGYS = { MarqueeUpdateStrategy::DEFAULT,
57     MarqueeUpdateStrategy::PRESERVE_POSITION};
58 
Create(const JSCallbackInfo & info)59 void JSMarquee::Create(const JSCallbackInfo& info)
60 {
61     if (info.Length() < 1 || !info[0]->IsObject()) {
62         return;
63     }
64 
65     MarqueeModel::GetInstance()->Create();
66     auto paramObject = JSRef<JSObject>::Cast(info[0]);
67     auto src = paramObject->GetProperty("src");
68     std::optional<std::string> srcOpt;
69     if (src->IsString()) {
70         srcOpt = src->ToString();
71     }
72     MarqueeModel::GetInstance()->SetValue(srcOpt);
73 
74     auto getStart = paramObject->GetProperty("start");
75     std::optional<bool> startOpt = getStart->IsBoolean() ? getStart->ToBoolean() : false;
76     MarqueeModel::GetInstance()->SetPlayerStatus(startOpt);
77 
78     auto getStep = paramObject->GetProperty("step");
79     std::optional<double> stepOpt;
80     if (getStep->IsNumber()) {
81         auto step = getStep->ToNumber<double>();
82         if (GreatNotEqual(step, 0.0)) {
83             stepOpt = Dimension(step, DimensionUnit::VP).ConvertToPx();
84         }
85     }
86     MarqueeModel::GetInstance()->SetScrollAmount(stepOpt);
87 
88     auto getLoop = paramObject->GetProperty("loop");
89     std::optional<int32_t> loopOpt;
90     if (getLoop->IsNumber()) {
91         auto loopDouble = getLoop->ToNumber<double>();
92         int32_t loop = -1;
93         if (GreatNotEqual(loopDouble, 0.0)) {
94             loop = static_cast<int32_t>(loopDouble);
95             if (loop == std::numeric_limits<int32_t>::max() || loop < 0) {
96                 loop = -1;
97             }
98         }
99         loopOpt = loop;
100     }
101     MarqueeModel::GetInstance()->SetLoop(loopOpt);
102 
103     auto getFromStart = paramObject->GetProperty("fromStart");
104     bool fromStart = getFromStart->IsBoolean() ? getFromStart->ToBoolean() : true;
105     std::optional<MarqueeDirection> directionOpt;
106     if (fromStart) {
107         directionOpt = MarqueeDirection::LEFT;
108     } else {
109         directionOpt = MarqueeDirection::RIGHT;
110     }
111     MarqueeModel::GetInstance()->SetDirection(directionOpt);
112 }
113 
JSBind(BindingTarget globalObj)114 void JSMarquee::JSBind(BindingTarget globalObj)
115 {
116     JSClass<JSMarquee>::Declare("Marquee");
117     MethodOptions opt = MethodOptions::NONE;
118     JSClass<JSMarquee>::StaticMethod("create", &JSMarquee::Create, opt);
119     JSClass<JSMarquee>::StaticMethod("allowScale", &JSMarquee::SetAllowScale);
120     JSClass<JSMarquee>::StaticMethod("fontColor", &JSMarquee::SetTextColor);
121     JSClass<JSMarquee>::StaticMethod("fontSize", &JSMarquee::SetFontSize);
122     JSClass<JSMarquee>::StaticMethod("fontWeight", &JSMarquee::SetFontWeight);
123     JSClass<JSMarquee>::StaticMethod("fontFamily", &JSMarquee::SetFontFamily);
124     JSClass<JSMarquee>::StaticMethod("marqueeUpdateStrategy", &JSMarquee::SetMarqueeUpdateStrategy);
125     JSClass<JSMarquee>::StaticMethod("onStart", &JSMarquee::OnStart);
126     JSClass<JSMarquee>::StaticMethod("onBounce", &JSMarquee::OnBounce);
127     JSClass<JSMarquee>::StaticMethod("onFinish", &JSMarquee::OnFinish);
128     JSClass<JSMarquee>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
129     JSClass<JSMarquee>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
130     JSClass<JSMarquee>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
131     JSClass<JSMarquee>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
132     JSClass<JSMarquee>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
133     JSClass<JSMarquee>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
134     JSClass<JSMarquee>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
135     JSClass<JSMarquee>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
136     JSClass<JSMarquee>::InheritAndBind<JSViewAbstract>(globalObj);
137 }
138 
SetTextColor(const JSCallbackInfo & info)139 void JSMarquee::SetTextColor(const JSCallbackInfo& info)
140 {
141     if (info.Length() < 1) {
142         return;
143     }
144     std::optional<Color> colorOpt;
145     Color color;
146     if (ParseJsColor(info[0], color)) {
147         colorOpt = color;
148     }
149     MarqueeModel::GetInstance()->SetTextColor(colorOpt);
150 }
151 
SetFontSize(const JSCallbackInfo & info)152 void JSMarquee::SetFontSize(const JSCallbackInfo& info)
153 {
154     if (info.Length() < 1) {
155         return;
156     }
157     std::optional<Dimension> fontSizeOpt;
158     CalcDimension fontSize;
159     if (ParseJsDimensionFp(info[0], fontSize)) {
160         if (!fontSize.IsNegative() && fontSize.Unit() != DimensionUnit::PERCENT) {
161             fontSizeOpt = fontSize;
162         }
163     }
164     MarqueeModel::GetInstance()->SetFontSize(fontSizeOpt);
165 }
166 
SetAllowScale(const JSCallbackInfo & info)167 void JSMarquee::SetAllowScale(const JSCallbackInfo& info)
168 {
169     if (info.Length() < 1) {
170         return;
171     }
172     std::optional<bool> allowScaleOpt;
173     if (info[0]->IsBoolean()) {
174         allowScaleOpt = info[0]->ToBoolean();
175     }
176     MarqueeModel::GetInstance()->SetAllowScale(allowScaleOpt);
177 }
178 
SetFontWeight(const std::string & value)179 void JSMarquee::SetFontWeight(const std::string& value)
180 {
181     std::optional<FontWeight> fontWeightOpt = ConvertStrToFontWeight(value);
182     MarqueeModel::GetInstance()->SetFontWeight(fontWeightOpt);
183 }
184 
SetFontFamily(const JSCallbackInfo & info)185 void JSMarquee::SetFontFamily(const JSCallbackInfo& info)
186 {
187     if (info.Length() < 1) {
188         return;
189     }
190     std::optional<std::vector<std::string>> fontFamiliesOpt;
191     std::vector<std::string> fontFamilies;
192     if (ParseJsFontFamilies(info[0], fontFamilies)) {
193         fontFamiliesOpt = fontFamilies;
194     }
195     MarqueeModel::GetInstance()->SetFontFamily(fontFamiliesOpt);
196 }
197 
SetMarqueeUpdateStrategy(const std::string & value)198 void JSMarquee::SetMarqueeUpdateStrategy(const std::string& value)
199 {
200     static const LinearMapNode<MarqueeUpdateStrategy> marqueeUpdateStrategyTable[] = {
201         { "default", MarqueeUpdateStrategy::DEFAULT },
202         { "preserve_position", MarqueeUpdateStrategy::PRESERVE_POSITION },
203     };
204     auto marqueeUpdateStrategyIter = BinarySearchFindIndex(marqueeUpdateStrategyTable,
205         ArraySize(marqueeUpdateStrategyTable), value.c_str());
206     auto marqueeUpdateStrategyValue = marqueeUpdateStrategyIter != -1 ?
207         std::make_optional(MARQUEE_UPDATE_STRATEGYS[marqueeUpdateStrategyIter]) :
208         std::make_optional(MarqueeUpdateStrategy::DEFAULT);
209     MarqueeModel::GetInstance()->SetMarqueeUpdateStrategy(marqueeUpdateStrategyValue);
210 }
211 
OnStart(const JSCallbackInfo & info)212 void JSMarquee::OnStart(const JSCallbackInfo& info)
213 {
214     if (!info[0]->IsFunction()) {
215         return;
216     }
217 
218     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
219     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
220     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
221         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
222         ACE_SCORING_EVENT("Marquee.onStart");
223         PipelineContext::SetCallBackNode(node);
224         func->ExecuteJS();
225     };
226     MarqueeModel::GetInstance()->SetOnStart(std::move(onChange));
227 }
228 
OnBounce(const JSCallbackInfo & info)229 void JSMarquee::OnBounce(const JSCallbackInfo& info)
230 {
231     if (!info[0]->IsFunction()) {
232         return;
233     }
234 
235     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
236     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
237     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
238         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
239         ACE_SCORING_EVENT("Marquee.onBounce");
240         PipelineContext::SetCallBackNode(node);
241         func->ExecuteJS();
242     };
243     MarqueeModel::GetInstance()->SetOnBounce(std::move(onChange));
244 }
245 
OnFinish(const JSCallbackInfo & info)246 void JSMarquee::OnFinish(const JSCallbackInfo& info)
247 {
248     if (!info[0]->IsFunction()) {
249         return;
250     }
251 
252     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
253     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
254     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
255         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
256         ACE_SCORING_EVENT("Marquee.onFinish");
257         PipelineContext::SetCallBackNode(node);
258         func->ExecuteJS();
259     };
260     MarqueeModel::GetInstance()->SetOnFinish(std::move(onChange));
261 }
262 
263 } // namespace OHOS::Ace::Framework
264