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_page_transition.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/engine/functions/js_page_transition_function.h"
20 #include "bridge/declarative_frontend/jsview/models/page_transition_model_impl.h"
21 #include "core/components_ng/pattern/stage/page_transition_model_ng.h"
22
23 namespace OHOS::Ace {
24 std::unique_ptr<PageTransitionModel> PageTransitionModel::instance_ = nullptr;
25 std::mutex PageTransitionModel::mutex_;
26
GetInstance()27 PageTransitionModel* PageTransitionModel::GetInstance()
28 {
29 if (!instance_) {
30 std::lock_guard<std::mutex> lock(mutex_);
31 if (!instance_) {
32 #ifdef NG_BUILD
33 instance_.reset(new NG::PageTransitionModelNG());
34 #else
35 if (Container::IsCurrentUseNewPipeline()) {
36 instance_.reset(new NG::PageTransitionModelNG());
37 } else {
38 instance_.reset(new Framework::PageTransitionModelImpl());
39 }
40 #endif
41 }
42 }
43 return instance_.get();
44 }
45 } // namespace OHOS::Ace
46
47 namespace OHOS::Ace::Framework {
48
JSBind(BindingTarget globalObj)49 void JSPageTransition::JSBind(BindingTarget globalObj)
50 {
51 JSClass<JSPageTransition>::Declare("PageTransition");
52 MethodOptions opt = MethodOptions::NONE;
53 JSClass<JSPageTransition>::StaticMethod("create", &JSPageTransition::Create, opt);
54 JSClass<JSPageTransition>::StaticMethod("pop", &JSPageTransition::Pop);
55 JSClass<JSPageTransition>::Bind<>(globalObj);
56
57 JSClass<JSPageTransitionEnter>::Declare("PageTransitionEnter");
58 JSClass<JSPageTransitionEnter>::StaticMethod("create", &JSPageTransitionEnter::Create, opt);
59 JSClass<JSPageTransitionEnter>::StaticMethod("slide", &JSPageTransition::Slide);
60 JSClass<JSPageTransitionEnter>::StaticMethod("translate", &JSPageTransition::Translate);
61 JSClass<JSPageTransitionEnter>::StaticMethod("scale", &JSPageTransition::Scale);
62 JSClass<JSPageTransitionEnter>::StaticMethod("opacity", &JSPageTransition::Opacity);
63 JSClass<JSPageTransitionEnter>::StaticMethod("onEnter", &JSPageTransition::JsHandlerOnEnter);
64 JSClass<JSPageTransitionEnter>::StaticMethod("pop", &JSPageTransitionEnter::Pop);
65 JSClass<JSPageTransitionEnter>::Bind<>(globalObj);
66
67 JSClass<JSPageTransitionExit>::Declare("PageTransitionExit");
68 JSClass<JSPageTransitionExit>::StaticMethod("create", &JSPageTransitionExit::Create, opt);
69 JSClass<JSPageTransitionExit>::StaticMethod("slide", &JSPageTransition::Slide);
70 JSClass<JSPageTransitionExit>::StaticMethod("translate", &JSPageTransition::Translate);
71 JSClass<JSPageTransitionExit>::StaticMethod("scale", &JSPageTransition::Scale);
72 JSClass<JSPageTransitionExit>::StaticMethod("opacity", &JSPageTransition::Opacity);
73 JSClass<JSPageTransitionExit>::StaticMethod("onExit", &JSPageTransition::JsHandlerOnExit);
74 JSClass<JSPageTransitionExit>::StaticMethod("pop", &JSPageTransitionExit::Pop);
75 JSClass<JSPageTransitionExit>::Bind<>(globalObj);
76 }
77
Slide(const JSCallbackInfo & info)78 void JSPageTransition::Slide(const JSCallbackInfo& info)
79 {
80 LOGD("JSPageTransition::Slide");
81 if (info.Length() > 0 && info[0]->IsNumber()) {
82 auto effect = info[0]->ToNumber<int32_t>();
83
84 if (effect >= static_cast<int32_t>(SlideEffect::LEFT) && effect <= static_cast<int32_t>(SlideEffect::BOTTOM)) {
85 PageTransitionModel::GetInstance()->SetSlideEffect(static_cast<SlideEffect>(effect));
86 }
87 }
88 }
89
Translate(const JSCallbackInfo & info)90 void JSPageTransition::Translate(const JSCallbackInfo& info)
91 {
92 LOGD("JSPageTransitionTranslate");
93 if (info.Length() > 0 && info[0]->IsObject()) {
94 auto args = JsonUtil::ParseJsonString(info[0]->ToString());
95 if (!args || args->IsNull()) {
96 LOGE("JSTransition Translate failed json value is nullptr or json object is null");
97 return;
98 }
99
100 NG::TranslateOptions option;
101
102 CalcDimension length;
103 if (JSViewAbstract::ParseJsonDimensionVp(args->GetValue("x"), length)) {
104 option.x = length;
105 }
106 if (JSViewAbstract::ParseJsonDimensionVp(args->GetValue("y"), length)) {
107 option.y = length;
108 }
109 if (JSViewAbstract::ParseJsonDimensionVp(args->GetValue("z"), length)) {
110 option.z = length;
111 }
112 PageTransitionModel::GetInstance()->SetTranslateEffect(option);
113 }
114 }
115
Scale(const JSCallbackInfo & info)116 void JSPageTransition::Scale(const JSCallbackInfo& info)
117 {
118 LOGD("JSPageTransition::Scale");
119 if (info.Length() > 0 && info[0]->IsObject()) {
120 auto args = JsonUtil::ParseJsonString(info[0]->ToString());
121 if (!args || args->IsNull()) {
122 LOGE("JSTransition Scale failed, json value is nullptr or json object is null");
123 return;
124 }
125
126 // default: x, y, z (1.0, 1.0, 1.0)
127 double scaleX = 1.0;
128 double scaleY = 1.0;
129 double scaleZ = 1.0;
130 JSViewAbstract::ParseJsonDouble(args->GetValue("x"), scaleX);
131 JSViewAbstract::ParseJsonDouble(args->GetValue("y"), scaleY);
132 JSViewAbstract::ParseJsonDouble(args->GetValue("z"), scaleZ);
133 // default centerX, centerY 50% 50%;
134 CalcDimension centerX = 0.5_pct;
135 CalcDimension centerY = 0.5_pct;
136
137 // if specify centerX
138 CalcDimension length;
139 if (JSViewAbstract::ParseJsonDimensionVp(args->GetValue("centerX"), length)) {
140 centerX = length;
141 }
142 // if specify centerY
143 if (JSViewAbstract::ParseJsonDimensionVp(args->GetValue("centerY"), length)) {
144 centerY = length;
145 }
146 NG::ScaleOptions option(
147 static_cast<float>(scaleX), static_cast<float>(scaleY), static_cast<float>(scaleZ), centerX, centerY);
148 PageTransitionModel::GetInstance()->SetScaleEffect(option);
149 }
150 }
151
Opacity(const JSCallbackInfo & info)152 void JSPageTransition::Opacity(const JSCallbackInfo& info)
153 {
154 LOGD("JSPageTransition::Opacity");
155 if (info.Length() < 1) {
156 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
157 return;
158 }
159 double opacity = 0.0;
160 if (!JSViewAbstract::ParseJsDouble(info[0], opacity)) {
161 return;
162 }
163 PageTransitionModel::GetInstance()->SetOpacityEffect(static_cast<float>(opacity));
164 }
165
JsHandlerOnEnter(const JSCallbackInfo & info)166 void JSPageTransition::JsHandlerOnEnter(const JSCallbackInfo& info)
167 {
168 LOGD("JSPageTransition::JsHandlerOnEnter");
169 if (info.Length() < 1 || !info[0]->IsFunction()) {
170 LOGE("JsHandlerOnEnter info.Length < 0 or info[0] is not function");
171 return;
172 }
173
174 RefPtr<JsPageTransitionFunction> function =
175 AceType::MakeRefPtr<JsPageTransitionFunction>(JSRef<JSFunc>::Cast(info[0]));
176
177 auto onEnterHandler = [execCtx = info.GetExecutionContext(), func = std::move(function)](
178 RouteType type, const float& progress) {
179 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
180 ACE_SCORING_EVENT("PageTransition.onEnter");
181 func->Execute(type, progress);
182 };
183
184 PageTransitionModel::GetInstance()->SetOnEnter(std::move(onEnterHandler));
185 }
186
JsHandlerOnExit(const JSCallbackInfo & info)187 void JSPageTransition::JsHandlerOnExit(const JSCallbackInfo& info)
188 {
189 LOGD("JSPageTransition::JsHandlerOnExit");
190 if (info.Length() < 1 || !info[0]->IsFunction()) {
191 LOGE("JsHandlerOnExit info.Length < 0 or info[0] is not function");
192 return;
193 }
194
195 RefPtr<JsPageTransitionFunction> function =
196 AceType::MakeRefPtr<JsPageTransitionFunction>(JSRef<JSFunc>::Cast(info[0]));
197
198 auto onExitHandler = [execCtx = info.GetExecutionContext(), func = std::move(function)](
199 RouteType type, const float& progress) {
200 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
201 ACE_SCORING_EVENT("PageTransition.onExit");
202 func->Execute(type, progress);
203 };
204
205 PageTransitionModel::GetInstance()->SetOnExit(std::move(onExitHandler));
206 }
207
Create(const JSCallbackInfo & info)208 void JSPageTransition::Create(const JSCallbackInfo& info)
209 {
210 LOGD("JSPageTransition::JSTransition::Create");
211 PageTransitionModel::GetInstance()->Create();
212 }
213
Pop()214 void JSPageTransition::Pop()
215 {
216 LOGD("JSPageTransition::Pop");
217 PageTransitionModel::GetInstance()->Pop();
218 }
219
ParseTransitionOption(const std::unique_ptr<JsonValue> & transitionArgs)220 PageTransitionOption JSPageTransition::ParseTransitionOption(const std::unique_ptr<JsonValue>& transitionArgs)
221 {
222 PageTransitionOption option;
223 const int32_t defaultDuration = 1000;
224 option.duration = defaultDuration;
225 option.curve = Curves::LINEAR;
226 if (transitionArgs && !transitionArgs->IsNull()) {
227 option.duration = transitionArgs->GetInt("duration", defaultDuration);
228 if (option.duration < 0) {
229 option.duration = defaultDuration;
230 }
231 option.delay = transitionArgs->GetInt("delay", 0);
232 auto routeTypeTmp = transitionArgs->GetInt("type", static_cast<int32_t>(RouteType::NONE));
233 if (routeTypeTmp >= static_cast<int32_t>(RouteType::NONE) &&
234 routeTypeTmp <= static_cast<int32_t>(RouteType::POP)) {
235 option.routeType = static_cast<RouteType>(routeTypeTmp);
236 } else {
237 LOGW("CreateTransition RouteType out of range");
238 }
239
240 auto curveArgs = transitionArgs->GetValue("curve");
241 RefPtr<Curve> curve;
242 if (curveArgs->IsString()) {
243 curve = CreateCurve(curveArgs->GetString(), false);
244 } else if (curveArgs->IsObject()) {
245 auto curveString = curveArgs->GetValue("__curveString");
246 if (curveString) {
247 curve = CreateCurve(curveString->GetString(), false);
248 }
249 }
250 if (curve) {
251 option.curve = curve;
252 }
253 }
254 return option;
255 }
256
Create(const JSCallbackInfo & info)257 void JSPageTransitionEnter::Create(const JSCallbackInfo& info)
258 {
259 LOGD("JSPageTransitionEnter::Create");
260 if (info.Length() > 0 && info[0]->IsObject()) {
261 auto transitionArgs = JsonUtil::ParseJsonString(info[0]->ToString());
262 auto option = ParseTransitionOption(transitionArgs);
263 PageTransitionModel::GetInstance()->CreateTransition(PageTransitionType::ENTER, option);
264 }
265 }
266
Create(const JSCallbackInfo & info)267 void JSPageTransitionExit::Create(const JSCallbackInfo& info)
268 {
269 LOGD("JSPageTransitionExit::Create");
270 if (info.Length() > 0 && info[0]->IsObject()) {
271 auto transitionArgs = JsonUtil::ParseJsonString(info[0]->ToString());
272 auto option = ParseTransitionOption(transitionArgs);
273 PageTransitionModel::GetInstance()->CreateTransition(PageTransitionType::EXIT, option);
274 }
275 }
276
277 } // namespace OHOS::Ace::Framework
278