• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "core/components/image/image_animator_element.h"
17 
18 #include "base/utils/string_utils.h"
19 #include "core/event/ace_event_helper.h"
20 
21 namespace OHOS::Ace {
22 
~ImageAnimatorElement()23 ImageAnimatorElement::~ImageAnimatorElement()
24 {
25     auto pageElement = pageElement_.Upgrade();
26     if (pageElement && callbackId_ >= 0) {
27         pageElement->CancelHiddenCallback(callbackId_);
28     }
29 }
30 
Update()31 void Ace::ImageAnimatorElement::Update()
32 {
33     const auto imageAnimatorComponent = AceType::DynamicCast<ImageAnimatorComponent>(component_);
34     if (!imageAnimatorComponent) {
35         LOGE("ImageAnimator element update failed. imageAnimatorComponent is null.");
36         return;
37     }
38     SetElementId(imageAnimatorComponent->GetElementId());
39 
40     if (!animator_) {
41         animator_ = CREATE_ANIMATOR();
42     }
43     UpdateCallbackAndFunc(imageAnimatorComponent);
44     if (!animator_->HasScheduler()) {
45         animator_->AttachScheduler(context_);
46     }
47     animator_->SetFillMode(imageAnimatorComponent->GetFillMode());
48     animator_->SetIteration(imageAnimatorComponent->GetIteration());
49     status_ = imageAnimatorComponent->GetStatus();
50     preDecode_ = imageAnimatorComponent->GetPreDecode();
51     duration_ = imageAnimatorComponent->GetDuration();
52     isReverse_ = imageAnimatorComponent->GetIsReverse();
53     images_ = imageAnimatorComponent->GetImageProperties();
54     isFixedSize_ = imageAnimatorComponent->GetIsFixedSize();
55     border_ = imageAnimatorComponent->GetBorder();
56     fillMode_ = imageAnimatorComponent->GetFillMode();
57     iteration_ = imageAnimatorComponent->GetIteration();
58     UpdateFilterImages();
59 
60     if (!pageElement_.Invalid()) {
61         return;
62     }
63 
64     auto pageElement = GetPageElement();
65     if (!pageElement) {
66         return;
67     }
68     pageElement_ = pageElement;
69     callbackId_ = pageElement->RegisterHiddenCallback([weak = AceType::WeakClaim(this)](bool hidden) {
70         auto element = weak.Upgrade();
71         if (!element || !element->animator_) {
72             return;
73         }
74 
75         if (hidden) {
76             if (element->animator_->GetStatus() == Animator::Status::RUNNING) {
77                 element->animator_->Pause();
78                 element->isPaused_ = true;
79             }
80         } else {
81             if (element->isPaused_) {
82                 if (element->isReverse_) {
83                     element->animator_->Backward();
84                 } else {
85                     element->animator_->Forward();
86                 }
87                 element->isPaused_ = false;
88             }
89         }
90     });
91 }
92 
PerformBuild()93 void ImageAnimatorElement::PerformBuild()
94 {
95     int32_t size = static_cast<int32_t>(images_.size());
96     if (size <= 0) {
97         LOGE("image size is less than 0.");
98         return;
99     }
100     if (children_.empty()) {
101         // first time to set image child.
102         childComponent_ = BuildChild();
103         ComposedElement::PerformBuild();
104     }
105     if (preDecode_ > 1) {
106         auto boxComponent = DynamicCast<BoxComponent>(childComponent_);
107         UpdatePreLoadImages(boxComponent);
108     }
109     CreatePictureAnimation(size);
110     if (!animator_) {
111         LOGE("animator is null, need to get animator first.");
112         return;
113     }
114     // update duration after a loop of animation.
115     if (!isSetDuration_) {
116         durationTotal_ > 0 ? animator_->SetDuration(durationTotal_) : animator_->SetDuration(duration_);
117         isSetDuration_ = true;
118     }
119     animator_->ClearInterpolators();
120     animator_->AddInterpolator(pictureAnimation_);
121     animator_->RemoveRepeatListener(repeatCallbackId_);
122     repeatCallbackId_ = static_cast<int64_t>(animator_->AddRepeatListener([weak = WeakClaim(this)]() {
123         auto imageAnimator = weak.Upgrade();
124         if (!imageAnimator) {
125             return;
126         }
127         if (imageAnimator->durationTotal_ > 0) {
128             imageAnimator->animator_->SetDuration(imageAnimator->durationTotal_);
129         } else {
130             imageAnimator->animator_->SetDuration(imageAnimator->duration_);
131         }
132     }));
133     animator_->RemoveStopListener(stopCallbackId_);
134     stopCallbackId_ = static_cast<int64_t>(animator_->AddStopListener([weak = WeakClaim(this)]() {
135         auto imageAnimator = weak.Upgrade();
136         if (imageAnimator) {
137             imageAnimator->isSetDuration_ = false;
138         }
139     }));
140 
141     // for declarative frontend.
142     if (context_.Upgrade() && context_.Upgrade()->GetIsDeclarative()) {
143         if (status_ == Animator::Status::IDLE) {
144             CallAnimatorMethod(CANCEL);
145         } else if (status_ == Animator::Status::PAUSED) {
146             CallAnimatorMethod(PAUSE);
147         } else if (status_ == Animator::Status::STOPPED) {
148             CallAnimatorMethod(STOP);
149         } else {
150             CallAnimatorMethod(START);
151         }
152         return;
153     }
154     isReverse_ ? animator_->Backward() : animator_->Forward();
155 }
156 
BuildChild()157 RefPtr<Component> ImageAnimatorElement::BuildChild()
158 {
159     uint32_t size = images_.size();
160     if (size == 0) {
161         LOGE("image size is 0.");
162         return nullptr;
163     }
164     auto boxComponent = AceType::MakeRefPtr<BoxComponent>();
165     boxComponent->SetFlex(BoxFlex::FLEX_XY);
166     boxComponent->SetAlignment(Alignment::TOP_LEFT);
167     ImageProperties childImage;
168     if (durationTotal_ > 0) {
169         childImage = (isReverse_ ? filterImages_.back() : filterImages_.front());
170     } else {
171         childImage = (isReverse_ ? images_.back() : images_.front());
172     }
173     auto imageComponent = AceType::MakeRefPtr<ImageComponent>(childImage.src);
174     if (!isFixedSize_) {
175         UpdateImageSize(childImage, imageComponent);
176     }
177     if (!childImage.src.empty()) {
178         imageComponent->SetBorder(border_);
179         imageComponent->SetFitMaxSize(true);
180     }
181     boxComponent->SetChild(imageComponent);
182     return boxComponent;
183 }
184 
UpdatePreLoadImages(const RefPtr<BoxComponent> & box)185 void ImageAnimatorElement::UpdatePreLoadImages(const RefPtr<BoxComponent>& box)
186 {
187     if (!box) {
188         LOGE("boxComponent is null.");
189         return;
190     }
191     int32_t size = static_cast<int32_t>(images_.size());
192     for (int32_t idx = 0; (idx < preDecode_) && (idx < size); idx++) {
193         auto imageComponent = DynamicCast<ImageComponent>(box->GetChild());
194         if (!imageComponent) {
195             LOGE("imageComponent is null.");
196             return;
197         }
198         ImageProperties childImage = images_[idx];
199         if (!childImage.src.empty()) {
200             imageComponent->SetSrc(childImage.src);
201         }
202     }
203 }
204 
CreatePictureAnimation(int32_t size)205 void ImageAnimatorElement::CreatePictureAnimation(int32_t size)
206 {
207     if (!pictureAnimation_) {
208         pictureAnimation_ = MakeRefPtr<PictureAnimation<int32_t>>();
209     }
210 
211     pictureAnimation_->ClearListeners();
212     pictureAnimation_->ClearPictures();
213     if (durationTotal_ > 0) {
214         int32_t filterImagesSize = static_cast<int32_t>(filterImages_.size());
215         for (int32_t index = 0; index < filterImagesSize; ++index) {
216             int32_t imageDuration = filterImages_[index].duration;
217             pictureAnimation_->AddPicture((float)imageDuration / durationTotal_, index);
218         }
219     } else {
220         for (int32_t index = 0; index < size; ++index) {
221             pictureAnimation_->AddPicture(NORMALIZED_DURATION_MAX / size, index);
222         }
223     }
224     pictureAnimation_->AddListener([weak = WeakClaim(this)](const int32_t index) {
225         auto imageAnimator = weak.Upgrade();
226         if (imageAnimator) {
227             imageAnimator->PlayImageAnimator(index);
228         }
229     });
230 }
231 
UpdateFilterImages()232 void ImageAnimatorElement::UpdateFilterImages()
233 {
234     filterImages_.clear();
235     durationTotal_ = 0;
236     for (auto& childImage : images_) {
237         if (!childImage.src.empty() && childImage.duration > 0) {
238             durationTotal_ += childImage.duration;
239             filterImages_.emplace_back(childImage);
240         }
241     }
242 }
243 
PlayImageAnimator(int32_t index)244 void ImageAnimatorElement::PlayImageAnimator(int32_t index)
245 {
246     auto boxComponent = DynamicCast<BoxComponent>(childComponent_);
247     if (!boxComponent) {
248         LOGE("child boxComponent is null.");
249         return;
250     }
251     auto imageComponent = DynamicCast<ImageComponent>(boxComponent->GetChild());
252     if (!imageComponent) {
253         LOGE("imageComponent is null.");
254         return;
255     }
256     ImageProperties childImage;
257     if (durationTotal_ > 0) {
258         childImage = filterImages_[index];
259     } else {
260         childImage = images_[index];
261     }
262     if (!isFixedSize_) {
263         UpdateImageSize(childImage, imageComponent);
264         isResetBox_ = false;
265     } else {
266         if (!isResetBox_) {
267             imageComponent->SetLeft(Dimension());
268             imageComponent->SetTop(Dimension());
269             // Follows the size of the parent component
270             imageComponent->SetWidth(-1.0);
271             imageComponent->SetHeight(-1.0);
272             isResetBox_ = true;
273         }
274     }
275     if (!childImage.src.empty()) {
276         imageComponent->SetSrc(childImage.src);
277     }
278     UpdateChild(GetFirstChild(), boxComponent);
279 }
280 
UpdateImageSize(ImageProperties & imageProperties,const RefPtr<ImageComponent> & image)281 void ImageAnimatorElement::UpdateImageSize(ImageProperties& imageProperties, const RefPtr<ImageComponent>& image)
282 {
283     image->SetLeft(imageProperties.left);
284     image->SetTop(imageProperties.top);
285     if (imageProperties.width.IsValid()) {
286         image->SetWidth(imageProperties.width);
287     }
288     if (imageProperties.height.IsValid()) {
289         image->SetHeight(imageProperties.height);
290     }
291 }
292 
CallAnimatorMethod(const std::string & method)293 void ImageAnimatorElement::CallAnimatorMethod(const std::string& method)
294 {
295     if (!animator_) {
296         LOGE("CallAnimatorMethod failed, animator is null.");
297         return;
298     }
299     if (method == START) {
300         isReverse_ ? animator_->Backward() : animator_->Forward();
301     } else if (method == PAUSE) {
302         animator_->Pause();
303     } else if (method == STOP) {
304         animator_->Finish();
305     } else if (method == RESUME) {
306         animator_->Resume();
307     } else if (method == CANCEL) {
308         animator_->Cancel();
309     } else {
310         LOGE("Unsupported method name : %s", method.c_str());
311     }
312 }
313 
UpdateCallbackAndFunc(const RefPtr<ImageAnimatorComponent> & imageAnimatorComponent)314 void ImageAnimatorElement::UpdateCallbackAndFunc(const RefPtr<ImageAnimatorComponent>& imageAnimatorComponent)
315 {
316     const auto& imageAnimatorController = imageAnimatorComponent->GetImageAnimatorController();
317     if (!imageAnimatorController) {
318         LOGE("UpdateCallbackAndFunc failed, imageAnimatorController is null.");
319         return;
320     }
321 
322     // start / stop / pause / resume method.
323     imageAnimatorController->SetAnimationFunc([weak = WeakClaim(this)](const std::string& method) {
324         auto element = weak.Upgrade();
325         if (element) {
326             element->CallAnimatorMethod(method);
327         }
328     });
329 
330     // getStatus method.
331     imageAnimatorController->SetAnimatorGetStatusFunc([weak = WeakClaim(this)]() -> Animator::Status {
332         auto element = weak.Upgrade();
333         if (element) {
334             return element->GetAnimatorStatus();
335         }
336         return Animator::Status::IDLE;
337     });
338 
339     animator_->ClearAllListeners();
340     auto startEvent = imageAnimatorController->GetStartEvent();
341     if (!startEvent.IsEmpty()) {
342         animator_->AddStartListener(
343             [startEvent, weakContext = context_] { AceAsyncEvent<void()>::Create(startEvent, weakContext)(); });
344     }
345     auto stopEvent = imageAnimatorController->GetStopEvent();
346     if (!stopEvent.IsEmpty()) {
347         animator_->AddStopListener(
348             [stopEvent, weakContext = context_] { AceAsyncEvent<void()>::Create(stopEvent, weakContext)(); });
349     }
350     auto pauseEvent = imageAnimatorController->GetPauseEvent();
351     if (!pauseEvent.IsEmpty()) {
352         animator_->AddPauseListener(
353             [pauseEvent, weakContext = context_] { AceAsyncEvent<void()>::Create(pauseEvent, weakContext)(); });
354     }
355     auto resumeEvent = imageAnimatorController->GetResumeEvent();
356     if (!resumeEvent.IsEmpty()) {
357         animator_->AddResumeListener(
358             [resumeEvent, weakContext = context_] { AceAsyncEvent<void()>::Create(resumeEvent, weakContext)(); });
359     }
360     auto repeatEvent = imageAnimatorController->GetRepeatEvent();
361     if (!repeatEvent.IsEmpty()) {
362         animator_->AddRepeatListener(
363             [repeatEvent, weakContext = context_] { AceAsyncEvent<void()>::Create(repeatEvent, weakContext)(); });
364     }
365     auto cancelEvent = imageAnimatorController->GetCancelEvent();
366     if (!cancelEvent.IsEmpty()) {
367         animator_->AddIdleListener(
368             [cancelEvent, weakContext = context_] { AceAsyncEvent<void()>::Create(cancelEvent, weakContext)(); });
369     }
370 }
371 
GetAnimatorStatus() const372 Animator::Status ImageAnimatorElement::GetAnimatorStatus() const
373 {
374     if (animator_) {
375         return animator_->GetStatus();
376     }
377     return Animator::Status::IDLE;
378 }
379 
CanUpdate(const RefPtr<Component> & newComponent)380 bool ImageAnimatorElement::CanUpdate(const RefPtr<Component>& newComponent)
381 {
382     return Element::CanUpdate(newComponent);
383 }
384 
385 } // namespace OHOS::Ace
386