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