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