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 if (info.Length() > 0 && info[0]->IsNumber()) {
81 auto effect = info[0]->ToNumber<int32_t>();
82
83 if (effect >= static_cast<int32_t>(SlideEffect::LEFT) && effect <= static_cast<int32_t>(SlideEffect::BOTTOM)) {
84 PageTransitionModel::GetInstance()->SetSlideEffect(static_cast<SlideEffect>(effect));
85 }
86 }
87 }
88
Translate(const JSCallbackInfo & info)89 void JSPageTransition::Translate(const JSCallbackInfo& info)
90 {
91 if (info.Length() > 0 && info[0]->IsObject()) {
92 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
93 NG::TranslateOptions option;
94 CalcDimension length;
95 if (JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty("x"), length)) {
96 option.x = length;
97 }
98 if (JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty("y"), length)) {
99 option.y = length;
100 }
101 if (JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty("z"), length)) {
102 option.z = length;
103 }
104 PageTransitionModel::GetInstance()->SetTranslateEffect(option);
105 }
106 }
107
Scale(const JSCallbackInfo & info)108 void JSPageTransition::Scale(const JSCallbackInfo& info)
109 {
110 if (info.Length() > 0 && info[0]->IsObject()) {
111 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
112 // default: x, y, z (1.0, 1.0, 1.0)
113 double scaleX = 1.0;
114 double scaleY = 1.0;
115 double scaleZ = 1.0;
116 JSViewAbstract::ParseJsDouble(jsObj->GetProperty("x"), scaleX);
117 JSViewAbstract::ParseJsDouble(jsObj->GetProperty("y"), scaleY);
118 JSViewAbstract::ParseJsDouble(jsObj->GetProperty("z"), scaleZ);
119 // default centerX, centerY 50% 50%;
120 CalcDimension centerX = 0.5_pct;
121 CalcDimension centerY = 0.5_pct;
122
123 // if specify centerX
124 CalcDimension length;
125 if (JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty("centerX"), length)) {
126 centerX = length;
127 }
128 // if specify centerY
129 if (JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty("centerY"), length)) {
130 centerY = length;
131 }
132 NG::ScaleOptions option(
133 static_cast<float>(scaleX), static_cast<float>(scaleY), static_cast<float>(scaleZ), centerX, centerY);
134 PageTransitionModel::GetInstance()->SetScaleEffect(option);
135 }
136 }
137
Opacity(const JSCallbackInfo & info)138 void JSPageTransition::Opacity(const JSCallbackInfo& info)
139 {
140 if (info.Length() < 1) {
141 return;
142 }
143 double opacity = 0.0;
144 if (!JSViewAbstract::ParseJsDouble(info[0], opacity)) {
145 return;
146 }
147 if (LessNotEqual(opacity, 0.0)) {
148 opacity = 1.0;
149 }
150 PageTransitionModel::GetInstance()->SetOpacityEffect(static_cast<float>(opacity));
151 }
152
JsHandlerOnEnter(const JSCallbackInfo & info)153 void JSPageTransition::JsHandlerOnEnter(const JSCallbackInfo& info)
154 {
155 if (info.Length() < 1 || !info[0]->IsFunction()) {
156 return;
157 }
158
159 RefPtr<JsPageTransitionFunction> function =
160 AceType::MakeRefPtr<JsPageTransitionFunction>(JSRef<JSFunc>::Cast(info[0]));
161
162 auto onEnterHandler = [execCtx = info.GetExecutionContext(), func = std::move(function)](
163 RouteType type, const float& progress) {
164 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
165 ACE_SCORING_EVENT("PageTransition.onEnter");
166 func->Execute(type, progress);
167 };
168
169 PageTransitionModel::GetInstance()->SetOnEnter(std::move(onEnterHandler));
170 }
171
JsHandlerOnExit(const JSCallbackInfo & info)172 void JSPageTransition::JsHandlerOnExit(const JSCallbackInfo& info)
173 {
174 if (info.Length() < 1 || !info[0]->IsFunction()) {
175 return;
176 }
177
178 RefPtr<JsPageTransitionFunction> function =
179 AceType::MakeRefPtr<JsPageTransitionFunction>(JSRef<JSFunc>::Cast(info[0]));
180
181 auto onExitHandler = [execCtx = info.GetExecutionContext(), func = std::move(function)](
182 RouteType type, const float& progress) {
183 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
184 ACE_SCORING_EVENT("PageTransition.onExit");
185 func->Execute(type, progress);
186 };
187
188 PageTransitionModel::GetInstance()->SetOnExit(std::move(onExitHandler));
189 }
190
Create(const JSCallbackInfo & info)191 void JSPageTransition::Create(const JSCallbackInfo& info)
192 {
193 PageTransitionModel::GetInstance()->Create();
194 }
195
Pop()196 void JSPageTransition::Pop()
197 {
198 PageTransitionModel::GetInstance()->Pop();
199 }
200
ParseTransitionOption(const JSRef<JSVal> & transitionArgs)201 PageTransitionOption JSPageTransition::ParseTransitionOption(const JSRef<JSVal>& transitionArgs)
202 {
203 PageTransitionOption option;
204 const int32_t defaultDuration = 1000;
205 option.duration = defaultDuration;
206 option.curve = Curves::LINEAR;
207 if (!transitionArgs->IsObject()) {
208 return option;
209 }
210
211 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(transitionArgs);
212 option.duration = jsObj->GetPropertyValue<int32_t>("duration", defaultDuration);
213 if (option.duration < 0) {
214 option.duration = defaultDuration;
215 }
216 option.delay = jsObj->GetPropertyValue<int32_t>("delay", 0);
217 auto routeTypeTmp = jsObj->GetPropertyValue<int32_t>("type", static_cast<int32_t>(RouteType::NONE));
218 if (routeTypeTmp >= static_cast<int32_t>(RouteType::NONE) &&
219 routeTypeTmp <= static_cast<int32_t>(RouteType::POP)) {
220 option.routeType = static_cast<RouteType>(routeTypeTmp);
221 }
222 JSRef<JSVal> curveArgs = jsObj->GetProperty("curve");
223 RefPtr<Curve> curve;
224 if (curveArgs->IsString()) {
225 curve = CreateCurve(curveArgs->ToString(), false);
226 } else if (curveArgs->IsObject()) {
227 JSRef<JSVal> curveString = JSRef<JSObject>::Cast(curveArgs)->GetProperty("__curveString");
228 if (curveString->IsString()) {
229 curve = CreateCurve(curveString->ToString(), false);
230 }
231 }
232 if (curve) {
233 option.curve = curve;
234 }
235 return option;
236 }
237
Create(const JSCallbackInfo & info)238 void JSPageTransitionEnter::Create(const JSCallbackInfo& info)
239 {
240 if (info.Length() > 0 && info[0]->IsObject()) {
241 auto option = ParseTransitionOption(info[0]);
242 PageTransitionModel::GetInstance()->CreateTransition(PageTransitionType::ENTER, option);
243 }
244 }
245
Create(const JSCallbackInfo & info)246 void JSPageTransitionExit::Create(const JSCallbackInfo& info)
247 {
248 if (info.Length() > 0 && info[0]->IsObject()) {
249 auto option = ParseTransitionOption(info[0]);
250 PageTransitionModel::GetInstance()->CreateTransition(PageTransitionType::EXIT, option);
251 }
252 }
253
254 } // namespace OHOS::Ace::Framework
255