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 "bridge/declarative_frontend/jsview/js_image_animator.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/jsview/models/image_animator_model_impl.h"
20 #include "core/components_ng/pattern/image_animator/image_animator_model_ng.h"
21 #include "frameworks/bridge/declarative_frontend/jsview/js_utils.h"
22 
23 namespace OHOS::Ace {
24 std::unique_ptr<ImageAnimatorModel> ImageAnimatorModel::instance_ = nullptr;
25 std::mutex ImageAnimatorModel::mutex_;
GetInstance()26 ImageAnimatorModel* ImageAnimatorModel::GetInstance()
27 {
28     if (!instance_) {
29         std::lock_guard<std::mutex> lock(mutex_);
30         if (!instance_) {
31 #ifdef NG_BUILD
32             instance_.reset(new NG::ImageAnimatorModelNG());
33 #else
34             if (Container::IsCurrentUseNewPipeline()) {
35                 instance_.reset(new NG::ImageAnimatorModelNG());
36             } else {
37                 instance_.reset(new Framework::ImageAnimatorModelImpl());
38             }
39 #endif
40         }
41     }
42     return instance_.get();
43 }
44 
45 } // namespace OHOS::Ace
46 
47 namespace OHOS::Ace::Framework {
48 
49 constexpr uint32_t DEFAULT_DURATION = 1000; // ms
50 constexpr uint32_t DEFAULT_ITERATIONS = 1;
51 constexpr FillMode DEFAULT_FILL_MODE = FillMode::FORWARDS;
52 
Create()53 void JSImageAnimator::Create()
54 {
55     ImageAnimatorModel::GetInstance()->Create();
56 }
57 
JSBind(BindingTarget globalObj)58 void JSImageAnimator::JSBind(BindingTarget globalObj)
59 {
60     JSClass<JSImageAnimator>::Declare("ImageAnimator");
61     MethodOptions opt = MethodOptions::NONE;
62     JSClass<JSImageAnimator>::StaticMethod("create", &JSImageAnimator::Create, opt);
63     JSClass<JSImageAnimator>::StaticMethod("images", &JSImageAnimator::SetImages, opt);
64     JSClass<JSImageAnimator>::StaticMethod("state", &JSImageAnimator::SetState, opt);
65     JSClass<JSImageAnimator>::StaticMethod("duration", &JSImageAnimator::SetDuration, opt);
66     JSClass<JSImageAnimator>::StaticMethod("iterations", &JSImageAnimator::SetIteration, opt);
67     JSClass<JSImageAnimator>::StaticMethod("reverse", &JSImageAnimator::SetIsReverse, opt);
68     JSClass<JSImageAnimator>::StaticMethod("fixedSize", &JSImageAnimator::SetFixedSize, opt);
69     JSClass<JSImageAnimator>::StaticMethod("fillMode", &JSImageAnimator::SetFillMode, opt);
70     JSClass<JSImageAnimator>::StaticMethod("preDecode", &JSImageAnimator::SetPreDecode, opt);
71 
72     JSClass<JSImageAnimator>::StaticMethod("onStart", &JSImageAnimator::OnStart, opt);
73     JSClass<JSImageAnimator>::StaticMethod("onPause", &JSImageAnimator::OnPause, opt);
74     JSClass<JSImageAnimator>::StaticMethod("onRepeat", &JSImageAnimator::OnRepeat, opt);
75     JSClass<JSImageAnimator>::StaticMethod("onCancel", &JSImageAnimator::OnCancel, opt);
76     JSClass<JSImageAnimator>::StaticMethod("onFinish", &JSImageAnimator::OnFinish, opt);
77     JSClass<JSImageAnimator>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
78     JSClass<JSImageAnimator>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
79     JSClass<JSImageAnimator>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
80     JSClass<JSImageAnimator>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
81     JSClass<JSImageAnimator>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
82 
83     JSClass<JSImageAnimator>::InheritAndBind<JSContainerBase>(globalObj);
84 }
85 
SetImages(const JSCallbackInfo & info)86 void JSImageAnimator::SetImages(const JSCallbackInfo& info)
87 {
88     if (info.Length() < 1) {
89         return;
90     }
91     if (info[0]->IsNull()) {
92         return;
93     }
94     if (!info[0]->IsArray()) {
95         return;
96     }
97     JSRef<JSArray> imageArray = JSRef<JSArray>::Cast(info[0]);
98     std::vector<ImageProperties> images;
99     for (uint32_t i = 0; i < imageArray->Length(); ++i) {
100         ImageProperties imageProperties;
101         ParseImages(imageArray->GetValueAt(i), imageProperties);
102         images.push_back(imageProperties);
103     }
104 
105     ImageAnimatorModel::GetInstance()->SetImages(images);
106 }
107 
SetState(const JSCallbackInfo & info)108 void JSImageAnimator::SetState(const JSCallbackInfo& info)
109 {
110     if (info.Length() < 1) {
111         return;
112     }
113     int32_t state = static_cast<int32_t>(Animator::Status::IDLE);
114     if (info[0]->IsNumber()) {
115         state = info[0]->ToNumber<int32_t>();
116         if (state < static_cast<int32_t>(Animator::Status::IDLE) ||
117             state > static_cast<int32_t>(Animator::Status::STOPPED)) {
118             state = static_cast<int32_t>(Animator::Status::IDLE);
119         }
120     }
121 
122     ImageAnimatorModel::GetInstance()->SetState(state);
123 }
124 
SetDuration(const JSCallbackInfo & info)125 void JSImageAnimator::SetDuration(const JSCallbackInfo& info)
126 {
127     if (info.Length() < 1) {
128         return;
129     }
130     int32_t duration = DEFAULT_DURATION;
131     if (info[0]->IsNumber()) {
132         duration = info[0]->ToNumber<int32_t>();
133         if (duration < 0) {
134             duration = DEFAULT_DURATION;
135         }
136     }
137 
138     ImageAnimatorModel::GetInstance()->SetDuration(duration);
139 }
140 
SetIteration(const JSCallbackInfo & info)141 void JSImageAnimator::SetIteration(const JSCallbackInfo& info)
142 {
143     if (info.Length() < 1) {
144         return;
145     }
146     int32_t iteration = DEFAULT_ITERATIONS;
147     if (info[0]->IsNumber()) {
148         iteration = info[0]->ToNumber<int32_t>();
149         if (iteration < -1) {
150             iteration = DEFAULT_ITERATIONS;
151         }
152     }
153 
154     ImageAnimatorModel::GetInstance()->SetIteration(iteration);
155 }
156 
SetFillMode(const JSCallbackInfo & info)157 void JSImageAnimator::SetFillMode(const JSCallbackInfo& info)
158 {
159     if (info.Length() < 1) {
160         return;
161     }
162     int32_t fillMode = static_cast<int32_t>(DEFAULT_FILL_MODE);
163     if (info[0]->IsNumber()) {
164         fillMode = info[0]->ToNumber<int32_t>();
165         if (fillMode < static_cast<int32_t>(FillMode::NONE) || fillMode > static_cast<int32_t>(FillMode::BOTH)) {
166             fillMode = static_cast<int32_t>(DEFAULT_FILL_MODE);
167         }
168     }
169 
170     ImageAnimatorModel::GetInstance()->SetFillMode(fillMode);
171 }
172 
SetPreDecode(const JSCallbackInfo & info)173 void JSImageAnimator::SetPreDecode(const JSCallbackInfo& info)
174 {
175     if (info.Length() < 1) {
176         return;
177     }
178     int32_t preDecode = 0;
179     if (info[0]->IsNumber()) {
180         preDecode = info[0]->ToNumber<int32_t>();
181     }
182     ImageAnimatorModel::GetInstance()->SetPreDecode(preDecode);
183 }
184 
SetIsReverse(const JSCallbackInfo & info)185 void JSImageAnimator::SetIsReverse(const JSCallbackInfo& info)
186 {
187     if (info.Length() < 1) {
188         return;
189     }
190     bool isReverse = false;
191     if (info[0]->IsBoolean()) {
192         isReverse = info[0]->ToBoolean();
193     }
194     ImageAnimatorModel::GetInstance()->SetIsReverse(isReverse);
195 }
196 
SetFixedSize(const JSCallbackInfo & info)197 void JSImageAnimator::SetFixedSize(const JSCallbackInfo& info)
198 {
199     if (info.Length() < 1) {
200         return;
201     }
202     bool fixedSize = true;
203     if (info[0]->IsBoolean()) {
204         fixedSize = info[0]->ToBoolean();
205     }
206     ImageAnimatorModel::GetInstance()->SetFixedSize(fixedSize);
207 }
208 
OnStart(const JSCallbackInfo & info)209 void JSImageAnimator::OnStart(const JSCallbackInfo& info)
210 {
211     auto onStart = GetAnimatorEvent(info, "ImageAnimator.onStart");
212     ImageAnimatorModel::GetInstance()->SetOnStart(std::move(onStart));
213 }
214 
OnPause(const JSCallbackInfo & info)215 void JSImageAnimator::OnPause(const JSCallbackInfo& info)
216 {
217     auto onPause = GetAnimatorEvent(info, "ImageAnimator.onPause");
218     ImageAnimatorModel::GetInstance()->SetOnPause(std::move(onPause));
219 }
220 
OnRepeat(const JSCallbackInfo & info)221 void JSImageAnimator::OnRepeat(const JSCallbackInfo& info)
222 {
223     auto onRepeat = GetAnimatorEvent(info, "ImageAnimator.onRepeat");
224     ImageAnimatorModel::GetInstance()->SetOnRepeat(std::move(onRepeat));
225 }
226 
OnCancel(const JSCallbackInfo & info)227 void JSImageAnimator::OnCancel(const JSCallbackInfo& info)
228 {
229     auto onCancel = GetAnimatorEvent(info, "ImageAnimator.onCancel");
230     ImageAnimatorModel::GetInstance()->SetOnCancel(std::move(onCancel));
231 }
232 
OnFinish(const JSCallbackInfo & info)233 void JSImageAnimator::OnFinish(const JSCallbackInfo& info)
234 {
235     auto onFinish = GetAnimatorEvent(info, "ImageAnimator.onFinish");
236     ImageAnimatorModel::GetInstance()->SetOnFinish(std::move(onFinish));
237 }
238 
GetAnimatorEvent(const JSCallbackInfo & info,std::string && eventName)239 AnimatorEvent JSImageAnimator::GetAnimatorEvent(const JSCallbackInfo& info, std::string&& eventName)
240 {
241     if (info.Length() != 1) {
242         return {};
243     }
244     if (!info[0]->IsFunction()) {
245         return {};
246     }
247     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
248     auto animatorEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc),
249                              event = std::move(eventName)]() {
250         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
251         ACE_SCORING_EVENT(event);
252         func->Execute();
253     };
254     return animatorEvent;
255 }
256 
ParseImages(const JSRef<JSVal> & image,ImageProperties & imageProperties)257 void JSImageAnimator::ParseImages(const JSRef<JSVal>& image, ImageProperties& imageProperties)
258 {
259     if (!image->IsObject()) {
260         return;
261     }
262     JSRef<JSObject> jsObjImage = JSRef<JSObject>::Cast(image);
263     bool srcValid = ParseJsMedia(jsObjImage->GetProperty("src"), imageProperties.src);
264     GetJsMediaBundleInfo(jsObjImage->GetProperty("src"), imageProperties.bundleName, imageProperties.moduleName);
265     if (!srcValid) {
266 #if defined(PIXEL_MAP_SUPPORTED)
267         imageProperties.pixelMap = CreatePixelMapFromNapiValue(jsObjImage->GetProperty("src"));
268 #endif
269     }
270     ParseJsDimensionVp(jsObjImage->GetProperty("width"), imageProperties.width);
271     ParseJsDimensionVp(jsObjImage->GetProperty("height"), imageProperties.height);
272     ParseJsDimensionVp(jsObjImage->GetProperty("top"), imageProperties.top);
273     ParseJsDimensionVp(jsObjImage->GetProperty("left"), imageProperties.left);
274     ParseJsInt32(jsObjImage->GetProperty("duration"), imageProperties.duration);
275 }
276 
277 } // namespace OHOS::Ace::Framework
278