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