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