1 /*
2  * Copyright (c) 2022-2023 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_ng/pattern/image_animator/image_animator_pattern.h"
17 #include <algorithm>
18 #include <string>
19 
20 #include "base/log/ace_trace.h"
21 #include "base/utils/time_util.h"
22 #include "core/components_ng/base/inspector_filter.h"
23 #include "core/components_ng/pattern/image/image_event_hub.h"
24 #include "core/components_ng/pattern/image/image_layout_property.h"
25 #include "core/components_ng/pattern/image/image_pattern.h"
26 #include "core/components_ng/property/calc_length.h"
27 #include "core/components_ng/property/property.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 
30 namespace OHOS::Ace::NG {
31 
32 namespace {
33 
34 constexpr int32_t DEFAULT_DURATION = 1000; // ms
35 constexpr uint32_t CRITICAL_TIME = 50;      // ms. If show time of image is less than this, use more cacheImages.
36 constexpr int64_t MICROSEC_TO_MILLISEC = 1000;
37 constexpr int32_t DEFAULT_ITERATIONS = 1;
38 
39 } // namespace
40 
ImageAnimatorPattern()41 ImageAnimatorPattern::ImageAnimatorPattern()
42 {
43     animator_ = CREATE_ANIMATOR(PipelineContext::GetCurrentContext());
44     animator_->SetFillMode(FillMode::FORWARDS);
45     animator_->SetDuration(DEFAULT_DURATION);
46     ResetFormAnimationFlag();
47 }
48 
CreatePictureAnimation(int32_t size)49 RefPtr<PictureAnimation<int32_t>> ImageAnimatorPattern::CreatePictureAnimation(int32_t size)
50 {
51     auto pictureAnimation = MakeRefPtr<PictureAnimation<int32_t>>();
52 
53     if (durationTotal_ > 0) {
54         for (int32_t index = 0; index < size; ++index) {
55             pictureAnimation->AddPicture(images_[index].duration / static_cast<float>(durationTotal_), index);
56         }
57         animator_->SetDuration(durationTotal_);
58     } else {
59         for (int32_t index = 0; index < size; ++index) {
60             pictureAnimation->AddPicture(NORMALIZED_DURATION_MAX / static_cast<float>(size), index);
61         }
62     }
63 
64     pictureAnimation->AddListener([weak = WeakClaim(this)](int32_t index) {
65         auto imageAnimator = weak.Upgrade();
66         CHECK_NULL_VOID(imageAnimator);
67         imageAnimator->SetShowingIndex(index);
68     });
69     return pictureAnimation;
70 }
71 
SetShowingIndex(int32_t index)72 void ImageAnimatorPattern::SetShowingIndex(int32_t index)
73 {
74     auto host = GetHost();
75     CHECK_NULL_VOID(host);
76     auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
77     CHECK_NULL_VOID(imageFrameNode);
78     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
79     CHECK_NULL_VOID(imageLayoutProperty);
80     if (index >= static_cast<int32_t>(images_.size())) {
81         LOGW("ImageAnimator update index error, index: %{public}d, size: %{public}zu", index, images_.size());
82         return;
83     }
84     nowImageIndex_ = index;
85     bool isShowingSrc = IsShowingSrc(imageFrameNode, images_[index].src);
86     auto cacheImageIter = FindCacheImageNode(images_[index].src);
87     std::string traceTag = images_[index].src;
88     if (images_[index].pixelMap != nullptr) {
89         isShowingSrc = IsShowingSrc(imageFrameNode, images_[index].pixelMap);
90         cacheImageIter = FindCacheImageNode(images_[index].pixelMap);
91         traceTag = "PixelMap";
92     }
93     if (isShowingSrc) {
94         ACE_SCOPED_TRACE("ImageAnimator same src %s, index %d", traceTag.c_str(), index);
95         UpdateShowingImageInfo(imageFrameNode, index);
96     } else if (cacheImageIter == cacheImages_.end()) {
97         ACE_SCOPED_TRACE("ImageAnimator no cache found, src %s, index %d", traceTag.c_str(), index);
98         UpdateShowingImageInfo(imageFrameNode, index);
99     } else if (cacheImageIter->isLoaded) {
100         ACE_SCOPED_TRACE("ImageAnimator useCache src %s, index %d", traceTag.c_str(), index);
101         auto cacheImageNode = cacheImageIter->imageNode;
102         host->RemoveChild(imageFrameNode);
103         host->AddChild(cacheImageNode, DEFAULT_NODE_SLOT, true);
104         host->RebuildRenderContextTree();
105         cacheImages_.erase(cacheImageIter);
106         CacheImageStruct newCacheImageStruct(imageFrameNode);
107         newCacheImageStruct.isLoaded = true;
108         cacheImages_.emplace_back(newCacheImageStruct);
109         UpdateShowingImageInfo(cacheImageNode, index);
110     } else {
111         UpdateShowingImageInfo(imageFrameNode, index);
112         // wait for cache image loading
113         ACE_SCOPED_TRACE("ImageAnimator waitForCache src %s, index %d", traceTag.c_str(), index);
114         return;
115     }
116     // update cache images.
117     CHECK_NULL_VOID(cacheImages_.size());
118     int32_t nextIndex = GetNextIndex(index);
119     for (auto& cacheImage : cacheImages_) {
120         UpdateCacheImageInfo(cacheImage, nextIndex);
121         nextIndex = GetNextIndex(nextIndex);
122     }
123     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
124 }
125 
UpdateShowingImageInfo(const RefPtr<FrameNode> & imageFrameNode,int32_t index)126 void ImageAnimatorPattern::UpdateShowingImageInfo(const RefPtr<FrameNode>& imageFrameNode, int32_t index)
127 {
128     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
129     CHECK_NULL_VOID(imageLayoutProperty);
130     if (images_[index].pixelMap == nullptr) {
131         imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(
132             images_[index].src, images_[index].bundleName, images_[index].moduleName));
133     } else {
134         imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
135     }
136     MarginProperty margin;
137     if (!fixedSize_) {
138         margin.left = CalcLength(images_[index].left);
139         margin.top = CalcLength(images_[index].top);
140         imageLayoutProperty->UpdateMargin(margin);
141         CalcSize realSize = { CalcLength(images_[index].width), CalcLength(images_[index].height) };
142         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
143         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
144         imageFrameNode->MarkModifyDone();
145         imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
146         return;
147     }
148     margin.SetEdges(CalcLength(0.0));
149     imageLayoutProperty->UpdateMargin(margin);
150     imageLayoutProperty->ClearUserDefinedIdealSize(true, true);
151     imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
152     imageFrameNode->MarkModifyDone();
153     imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
154     ControlAnimatedImageAnimation(imageFrameNode, true);
155 }
156 
UpdateCacheImageInfo(CacheImageStruct & cacheImage,int32_t index)157 void ImageAnimatorPattern::UpdateCacheImageInfo(CacheImageStruct& cacheImage, int32_t index)
158 {
159     if (index >= static_cast<int32_t>(images_.size())) {
160         LOGW("PrepareImageInfo index error, index: %{public}d, size: %{public}zu", index, images_.size());
161         return;
162     }
163     auto imageLayoutProperty = cacheImage.imageNode->GetLayoutProperty<ImageLayoutProperty>();
164     const auto& image = images_[index];
165     if (image.pixelMap == nullptr) {
166         auto preSrc =
167             imageLayoutProperty->HasImageSourceInfo() ? imageLayoutProperty->GetImageSourceInfoValue().GetSrc() : "";
168         if (preSrc != image.src) {
169             // need to cache newImage
170             imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(image.src, image.bundleName, image.moduleName));
171             cacheImage.index = index;
172             cacheImage.isLoaded = false;
173         }
174     } else {
175         // pixelmap
176         if (imageLayoutProperty->HasImageSourceInfo()) {
177             auto preSrc = imageLayoutProperty->GetImageSourceInfoValue().GetPixmap();
178             if (preSrc != image.pixelMap) {
179                 // need to cache newImage
180                 imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(image.pixelMap));
181                 cacheImage.index = index;
182                 cacheImage.isLoaded = false;
183             }
184         } else {
185             imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(image.pixelMap));
186             cacheImage.index = index;
187             cacheImage.isLoaded = false;
188         }
189     }
190     auto host = GetHost();
191     CHECK_NULL_VOID(host);
192     auto hostSize = host->GetGeometryNode()->GetPaddingSize();
193     if (!fixedSize_) {
194         CalcSize realSize = { CalcLength(image.width), CalcLength(image.height) };
195         imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
196         cacheImage.imageNode->GetGeometryNode()->SetContentSize(
197             { image.width.ConvertToPxWithSize(hostSize.Width()), image.height.ConvertToPxWithSize(hostSize.Height()) });
198         cacheImage.imageNode->MarkModifyDone();
199         return;
200     }
201     if (!hostSize.IsPositive()) {
202         // if imageNode size is nonPositive, no pixelMap will be generated. Wait for size.
203         return;
204     }
205     imageLayoutProperty->UpdateUserDefinedIdealSize(
206         CalcSize(CalcLength(hostSize.Width()), CalcLength(hostSize.Height())));
207     cacheImage.imageNode->GetGeometryNode()->SetContentSize(hostSize);
208     cacheImage.imageNode->MarkModifyDone();
209 }
210 
FindCacheImageNode(const RefPtr<PixelMap> & src)211 std::list<ImageAnimatorPattern::CacheImageStruct>::iterator ImageAnimatorPattern::FindCacheImageNode(
212     const RefPtr<PixelMap>& src)
213 {
214     for (auto iter = cacheImages_.begin(); iter != cacheImages_.end(); ++iter) {
215         if (IsShowingSrc(iter->imageNode, src)) {
216             return iter;
217         }
218     }
219     return cacheImages_.end();
220 }
221 
FindCacheImageNode(const std::string & src)222 std::list<ImageAnimatorPattern::CacheImageStruct>::iterator ImageAnimatorPattern::FindCacheImageNode(
223     const std::string& src)
224 {
225     for (auto iter = cacheImages_.begin(); iter != cacheImages_.end(); ++iter) {
226         if (IsShowingSrc(iter->imageNode, src)) {
227             return iter;
228         }
229     }
230     return cacheImages_.end();
231 }
232 
GenerateCachedImages()233 void ImageAnimatorPattern::GenerateCachedImages()
234 {
235     CHECK_NULL_VOID(images_.size());
236     auto averageShowTime = animator_->GetDuration() / static_cast<int32_t>(images_.size());
237     size_t cacheImageNum = static_cast<uint32_t>(averageShowTime) >= CRITICAL_TIME ? 1 : 2;
238     cacheImageNum = std::min(images_.size() - 1, cacheImageNum);
239     if (cacheImages_.size() > cacheImageNum) {
240         cacheImages_.resize(cacheImageNum);
241         return;
242     }
243     while (cacheImages_.size() < cacheImageNum) {
244         auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
245         CHECK_NULL_VOID(imageNode);
246         auto imagePattern = AceType::DynamicCast<ImagePattern>(imageNode->GetPattern());
247         CHECK_NULL_VOID(imagePattern);
248         imagePattern->SetImageAnimator(true);
249         auto imageLayoutProperty = imageNode->GetLayoutProperty();
250         imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
251         imageLayoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
252         AddImageLoadSuccessEvent(imageNode);
253         cacheImages_.emplace_back(CacheImageStruct(imageNode));
254     }
255 }
256 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & wrapper,const DirtySwapConfig & config)257 bool ImageAnimatorPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& wrapper, const DirtySwapConfig& config)
258 {
259     DisablePreAnimatedImageAnimation(static_cast<uint32_t>(nowImageIndex_));
260     if (!isLayouted_) {
261         isLayouted_ = true;
262         if (fixedSize_ && images_.size()) {
263             int32_t nextIndex = GetNextIndex(nowImageIndex_);
264             for (auto& cacheImage : cacheImages_) {
265                 UpdateCacheImageInfo(cacheImage, nextIndex);
266                 nextIndex = GetNextIndex(nextIndex);
267             }
268         }
269     }
270     return false;
271 }
272 
RunAnimatorByStatus(int32_t index)273 void ImageAnimatorPattern::RunAnimatorByStatus(int32_t index)
274 {
275     switch (status_) {
276         case Animator::Status::IDLE:
277             animator_->Cancel();
278             ResetFormAnimationFlag();
279             SetShowingIndex(index);
280             break;
281         case Animator::Status::PAUSED:
282             animator_->Pause();
283             ResetFormAnimationFlag();
284             break;
285         case Animator::Status::STOPPED:
286             animator_->Finish();
287             ResetFormAnimationFlag();
288             break;
289         default:
290             ResetFormAnimationStartTime();
291             if (isFormAnimationEnd_) {
292                 ResetFormAnimationFlag();
293                 return;
294             }
295             isReverse_ ? animator_->Backward() : animator_->Forward();
296     }
297 }
298 
DisablePreAnimatedImageAnimation(uint32_t index)299 void ImageAnimatorPattern::DisablePreAnimatedImageAnimation(uint32_t index)
300 {
301     if (index >= static_cast<uint32_t>(images_.size())) {
302         TAG_LOGW(AceLogTag::ACE_IMAGE, "ImageAnimator get index error, index: %{public}d, size: %{public}zu", index,
303             images_.size());
304         return;
305     }
306     auto cacheImageIter = FindCacheImageNode(images_[index].src);
307     if (images_[index].pixelMap != nullptr) {
308         cacheImageIter = FindCacheImageNode(images_[index].pixelMap);
309     }
310     if (cacheImageIter != cacheImages_.end()) {
311         auto cacheImageNode = cacheImageIter->imageNode;
312         ControlAnimatedImageAnimation(cacheImageNode, false);
313     }
314 }
315 
OnModifyDone()316 void ImageAnimatorPattern::OnModifyDone()
317 {
318     auto host = GetHost();
319     CHECK_NULL_VOID(host);
320     Pattern::OnModifyDone();
321     auto size = static_cast<int32_t>(images_.size());
322     if (size <= 0) {
323         LOGE("image size is less than 0.");
324         return;
325     }
326     GenerateCachedImages();
327     auto index = nowImageIndex_;
328     if ((status_ == Animator::Status::IDLE || status_ == Animator::Status::STOPPED) && !firstUpdateEvent_) {
329         index = isReverse_ ? (size - 1) : 0;
330     }
331 
332     if (imagesChangedFlag_) {
333         animator_->ClearInterpolators();
334         animator_->AddInterpolator(CreatePictureAnimation(size));
335         AdaptSelfSize();
336         imagesChangedFlag_ = false;
337     }
338     animator_->SetIteration(GetIteration());
339     if (firstUpdateEvent_) {
340         UpdateEventCallback();
341         firstUpdateEvent_ = false;
342         auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
343         AddImageLoadSuccessEvent(imageFrameNode);
344     }
345     UpdateFormDurationByRemainder();
346     RunAnimatorByStatus(index);
347 }
348 
OnAttachToFrameNode()349 void ImageAnimatorPattern::OnAttachToFrameNode()
350 {
351     auto host = GetHost();
352     CHECK_NULL_VOID(host);
353     auto context = host->GetRenderContext();
354     CHECK_NULL_VOID(context);
355     context->SetClipToFrame(true);
356 }
357 
UpdateEventCallback()358 void ImageAnimatorPattern::UpdateEventCallback()
359 {
360     auto eventHub = GetEventHub<ImageAnimatorEventHub>();
361     CHECK_NULL_VOID(eventHub);
362 
363     animator_->ClearAllListeners();
364     auto startEvent = eventHub->GetStartEvent();
365     if (startEvent != nullptr) {
366         animator_->AddStartListener([startEvent] { startEvent(); });
367     }
368 
369     auto stopEvent = eventHub->GetStopEvent();
370     if (stopEvent != nullptr) {
371         animator_->AddStopListener([stopEvent] { stopEvent(); });
372     }
373 
374     auto pauseEvent = eventHub->GetPauseEvent();
375     if (pauseEvent != nullptr) {
376         animator_->AddPauseListener([pauseEvent] { pauseEvent(); });
377     }
378 
379     auto repeatEvent = eventHub->GetRepeatEvent();
380     if (repeatEvent != nullptr) {
381         animator_->AddRepeatListener([repeatEvent] { repeatEvent(); });
382     }
383 
384     auto cancelEvent = eventHub->GetCancelEvent();
385     if (cancelEvent != nullptr) {
386         animator_->AddIdleListener([cancelEvent] { cancelEvent(); });
387     }
388 }
389 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const390 void ImageAnimatorPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
391 {
392     Pattern::ToJsonValue(json, filter);
393     /* no fixed attr below, just return */
394     if (filter.IsFastFilter()) {
395         return;
396     }
397     static const char* STATUS_MODE[] = { "AnimationStatus.Initial", "AnimationStatus.Running", "AnimationStatus.Paused",
398         "AnimationStatus.Stopped" };
399     json->PutExtAttr("state", STATUS_MODE[static_cast<int32_t>(status_)], filter);
400     json->PutExtAttr("duration", std::to_string(animator_->GetDuration()).c_str(), filter);
401     json->PutExtAttr("reverse", isReverse_ ? "true" : "false", filter);
402     json->PutExtAttr("fixedSize", fixedSize_ ? "true" : "false", filter);
403     static const char* FILL_MODE[] = { "FillMode.None", "FillMode.Forwards", "FillMode.Backwards", "FillMode.Both" };
404     json->PutExtAttr("fillMode", FILL_MODE[static_cast<int32_t>(animator_->GetFillMode())], filter);
405     json->PutExtAttr("iterations", std::to_string(animator_->GetIteration()).c_str(), filter);
406     json->PutExtAttr("images", ImagesToString().c_str(), filter);
407 }
408 
ImagesToString() const409 std::string ImageAnimatorPattern::ImagesToString() const
410 {
411     auto imageArray = JsonUtil::CreateArray(true);
412     for (const auto& image : images_) {
413         auto item = JsonUtil::Create(true);
414         item->Put("src", image.src.c_str());
415         item->Put("left", image.left.ToString().c_str());
416         item->Put("top", image.top.ToString().c_str());
417         item->Put("width", image.width.ToString().c_str());
418         item->Put("height", image.height.ToString().c_str());
419         item->Put("duration", std::to_string(image.duration).c_str());
420         imageArray->Put(item);
421     }
422     return imageArray->ToString();
423 }
424 
AdaptSelfSize()425 void ImageAnimatorPattern::AdaptSelfSize()
426 {
427     auto host = GetHost();
428     CHECK_NULL_VOID(host);
429     const auto& layoutProperty = host->GetLayoutProperty();
430     CHECK_NULL_VOID(layoutProperty);
431     if (layoutProperty->GetCalcLayoutConstraint() && layoutProperty->GetCalcLayoutConstraint()->selfIdealSize &&
432         layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->IsValid()) {
433         return;
434     }
435     Dimension maxWidth;
436     Dimension maxHeight;
437     double maxWidthPx = 0.0;
438     double maxHeightPx = 0.0;
439     for (const auto& image : images_) {
440         if (image.width.Unit() != DimensionUnit::PERCENT) {
441             auto widthPx = image.width.ConvertToPx();
442             if (widthPx > maxWidthPx) {
443                 maxWidthPx = widthPx;
444                 maxWidth = image.width;
445             }
446         }
447         if (image.height.Unit() != DimensionUnit::PERCENT) {
448             auto heightPx = image.height.ConvertToPx();
449             if (heightPx > maxHeightPx) {
450                 maxHeightPx = heightPx;
451                 maxHeight = image.height;
452             }
453         }
454     }
455     if (!maxWidth.IsValid() || !maxHeight.IsValid()) {
456         return;
457     }
458     const auto& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
459     if (!layoutConstraint || !layoutConstraint->selfIdealSize) {
460         layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(maxWidth), CalcLength(maxHeight)));
461         return;
462     }
463     if (!layoutConstraint->selfIdealSize->Width()) {
464         layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(maxWidth), std::nullopt));
465         return;
466     }
467     layoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(maxHeight)));
468 }
469 
GetNextIndex(int32_t preIndex)470 int32_t ImageAnimatorPattern::GetNextIndex(int32_t preIndex)
471 {
472     if (isReverse_) {
473         return preIndex == 0 ? (static_cast<int32_t>(images_.size()) - 1) : (preIndex - 1);
474     }
475     return (preIndex + 1) % static_cast<int32_t>(images_.size());
476 }
477 
AddImageLoadSuccessEvent(const RefPtr<FrameNode> & imageFrameNode)478 void ImageAnimatorPattern::AddImageLoadSuccessEvent(const RefPtr<FrameNode>& imageFrameNode)
479 {
480     CHECK_NULL_VOID(imageFrameNode);
481     auto eventHub = imageFrameNode->GetEventHub<ImageEventHub>();
482     eventHub->SetOnComplete(
483         [weakImage = WeakPtr<FrameNode>(imageFrameNode), weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
484             if (info.GetLoadingStatus() != 1) {
485                 // status 1 means load success. Only need loadSuccess event.
486                 return;
487             }
488             auto pattern = weak.Upgrade();
489             CHECK_NULL_VOID(pattern);
490             auto cacheImageNode = weakImage.Upgrade();
491             CHECK_NULL_VOID(cacheImageNode);
492             auto imageAnimator = pattern->GetHost();
493             CHECK_NULL_VOID(imageAnimator);
494             auto cacheLayoutProperty = cacheImageNode->GetLayoutProperty<ImageLayoutProperty>();
495             auto cacheSrc = cacheLayoutProperty->GetImageSourceInfoValue(ImageSourceInfo()).GetSrc();
496             ACE_SCOPED_TRACE("ImageAnimator cache succeed. src %s", cacheSrc.c_str());
497             auto iter = std::find_if(pattern->cacheImages_.begin(), pattern->cacheImages_.end(),
498                 [&cacheImageNode](const CacheImageStruct& other) { return other.imageNode == cacheImageNode; });
499             if (iter == pattern->cacheImages_.end()) {
500                 return;
501             }
502             iter->isLoaded = true;
503             if (pattern->nowImageIndex_ >= static_cast<int32_t>(pattern->images_.size())) {
504                 LOGW("ImageAnimator showImage index is invalid");
505                 return;
506             }
507             if (pattern->images_[pattern->nowImageIndex_].pixelMap == nullptr) {
508                 if (pattern->nowImageIndex_ == iter->index &&
509                     IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].src)) {
510                     pattern->SetShowingIndex(pattern->nowImageIndex_);
511                 } else if (pattern->nowImageIndex_ == 0) {
512                     pattern->EnableFirstAnimatedImageAnimation();
513                 }
514             } else {
515                 if (pattern->nowImageIndex_ == iter->index &&
516                     IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].pixelMap)) {
517                     pattern->SetShowingIndex(pattern->nowImageIndex_);
518                 }
519             }
520         });
521 }
522 
IsShowingSrc(const RefPtr<FrameNode> & imageFrameNode,const std::string & src)523 bool ImageAnimatorPattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const std::string& src)
524 {
525     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
526     return imageLayoutProperty->HasImageSourceInfo() && imageLayoutProperty->GetImageSourceInfoValue().GetSrc() == src;
527 }
528 
IsShowingSrc(const RefPtr<FrameNode> & imageFrameNode,const RefPtr<PixelMap> & src)529 bool ImageAnimatorPattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src)
530 {
531     auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
532     return imageLayoutProperty->HasImageSourceInfo()
533         && imageLayoutProperty->GetImageSourceInfoValue().GetPixmap() == src;
534 }
535 
IsFormRender()536 bool ImageAnimatorPattern::IsFormRender()
537 {
538     auto pipeline = PipelineBase::GetCurrentContext();
539     CHECK_NULL_RETURN(pipeline, false);
540     return pipeline->IsFormRender();
541 }
542 
UpdateFormDurationByRemainder()543 void ImageAnimatorPattern::UpdateFormDurationByRemainder()
544 {
545     if (IsFormRender()) {
546         if (!isFormAnimationStart_) {
547             formAnimationRemainder_ =
548                 DEFAULT_DURATION - (GetMicroTickCount() - formAnimationStartTime_) / MICROSEC_TO_MILLISEC;
549         }
550         if ((formAnimationRemainder_ > 0) && (animator_->GetDuration() > formAnimationRemainder_)) {
551             animator_->SetDuration(formAnimationRemainder_);
552         }
553         if (formAnimationRemainder_ <= 0) {
554             isFormAnimationEnd_ = true;
555         }
556     }
557 }
558 
ResetFormAnimationStartTime()559 void ImageAnimatorPattern::ResetFormAnimationStartTime()
560 {
561     if (isFormAnimationStart_) {
562         isFormAnimationStart_ = false;
563         formAnimationStartTime_ = GetMicroTickCount();
564     }
565 }
566 
ResetFormAnimationFlag()567 void ImageAnimatorPattern::ResetFormAnimationFlag()
568 {
569     if (IsFormRender()) {
570         formAnimationRemainder_ = DEFAULT_DURATION;
571         isFormAnimationStart_ = true;
572         isFormAnimationEnd_ = false;
573     }
574 }
575 
SetIteration(int32_t iteration)576 void ImageAnimatorPattern::SetIteration(int32_t iteration)
577 {
578     if (IsFormRender()) {
579         iteration = DEFAULT_ITERATIONS;
580     }
581     iteration_ = iteration;
582 }
583 
SetDuration(int32_t duration)584 void ImageAnimatorPattern::SetDuration(int32_t duration)
585 {
586     int32_t finalDuration = durationTotal_ > 0 ? durationTotal_ : duration;
587     if (IsFormRender()) {
588         finalDuration = finalDuration < DEFAULT_DURATION ? finalDuration : DEFAULT_DURATION;
589     }
590     if (animator_->GetDuration() == finalDuration) {
591         animator_->RemoveRepeatListener(repeatCallbackId_);
592         return;
593     }
594     if (animator_->GetStatus() == Animator::Status::IDLE || animator_->GetStatus() == Animator::Status::STOPPED) {
595         animator_->SetDuration(finalDuration);
596         animator_->RemoveRepeatListener(repeatCallbackId_);
597         return;
598     }
599     // if animator is running or paused, duration will work next time
600     animator_->RemoveRepeatListener(repeatCallbackId_);
601     repeatCallbackId_ = animator_->AddRepeatListener([weak = WeakClaim(this), finalDuration]() {
602         auto imageAnimator = weak.Upgrade();
603         CHECK_NULL_VOID(imageAnimator);
604         imageAnimator->animator_->SetDuration(finalDuration);
605     });
606 }
EnableFirstAnimatedImageAnimation()607 void ImageAnimatorPattern::EnableFirstAnimatedImageAnimation()
608 {
609     auto host = GetHost();
610     CHECK_NULL_VOID(host);
611     auto children = host->GetChildren();
612     if (children.empty()) {
613         return;
614     }
615     auto imageFrameNode = AceType::DynamicCast<FrameNode>(children.front());
616     ControlAnimatedImageAnimation(imageFrameNode, true);
617 }
ControlAnimatedImageAnimation(const RefPtr<FrameNode> & imageFrameNode,bool play)618 void ImageAnimatorPattern::ControlAnimatedImageAnimation(const RefPtr<FrameNode>& imageFrameNode, bool play)
619 {
620     CHECK_NULL_VOID(imageFrameNode);
621     auto imagePattern = AceType::DynamicCast<ImagePattern>(imageFrameNode->GetPattern());
622     CHECK_NULL_VOID(imagePattern);
623     auto image = imagePattern->GetCanvasImage();
624     CHECK_NULL_VOID(image);
625     if (!image->IsStatic()) {
626         image->ControlAnimation(play);
627     }
628 }
629 } // namespace OHOS::Ace::NG
630