1 /*
2 * Copyright (c) 2021-2022 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/tween/tween_element.h"
17
18 #include "base/geometry/transform_util.h"
19 #include "core/animation/curve_animation.h"
20 #include "core/common/frontend.h"
21 #include "core/components/clip/render_clip.h"
22 #include "core/components/display/display_component.h"
23 #include "core/components/positioned/positioned_element.h"
24 #include "core/components/shared_transition/shared_transition_element.h"
25 #include "core/components/transform/transform_component.h"
26 #include "core/components/tween/tween_component.h"
27 #include "core/pipeline/base/render_element.h"
28
29 namespace OHOS::Ace {
30 namespace {
GetAnimatable(const RefPtr<Element> & contentElement)31 RefPtr<PropertyAnimatable> GetAnimatable(const RefPtr<Element>& contentElement)
32 {
33 if (!contentElement) {
34 LOGE("Get Animatable failed. content element is null.");
35 return nullptr;
36 }
37 return AceType::DynamicCast<PropertyAnimatable>(contentElement->GetRenderNode());
38 }
39
SetTranslateProperties(const RefPtr<Animation<DimensionOffset>> & translateAnimation,TweenOption & option)40 void SetTranslateProperties(const RefPtr<Animation<DimensionOffset>>& translateAnimation, TweenOption& option)
41 {
42 if (option.GetCurve()) {
43 translateAnimation->SetCurve(option.GetCurve());
44 }
45 if (!translateAnimation->HasInitValue()) {
46 DimensionOffset beginPos = DimensionOffset(Dimension(), Dimension());
47 translateAnimation->SetInitValue(beginPos);
48 }
49 }
50
SetScaleProperties(const RefPtr<Animation<float>> & scaleAnimation,TweenOption & option)51 void SetScaleProperties(const RefPtr<Animation<float>>& scaleAnimation, TweenOption& option)
52 {
53 if (option.GetCurve()) {
54 scaleAnimation->SetCurve(option.GetCurve());
55 }
56 if (!scaleAnimation->HasInitValue()) {
57 scaleAnimation->SetInitValue(1.0f);
58 }
59 }
60
SetRotateProperties(const RefPtr<Animation<float>> & rotateAnimation,TweenOption & option)61 void SetRotateProperties(const RefPtr<Animation<float>>& rotateAnimation, TweenOption& option)
62 {
63 if (option.GetCurve()) {
64 rotateAnimation->SetCurve(option.GetCurve());
65 }
66 if (!rotateAnimation->HasInitValue()) {
67 rotateAnimation->SetInitValue(0.0f);
68 }
69 }
70
ResetController(RefPtr<Animator> & controller)71 void ResetController(RefPtr<Animator>& controller)
72 {
73 if (!controller) {
74 LOGE("Reset Controller failed. controller is null.");
75 return;
76 }
77 if (controller->GetStatus() != Animator::Status::IDLE && controller->GetStatus() != Animator::Status::STOPPED) {
78 controller->Finish();
79 }
80 controller->ClearInterpolators();
81 }
82
83 template<class T>
SetAnimationProperties(const RefPtr<Animation<T>> & animation,TweenOption & option)84 void SetAnimationProperties(const RefPtr<Animation<T>>& animation, TweenOption& option)
85 {
86 if (option.GetCurve()) {
87 animation->SetCurve(option.GetCurve());
88 }
89 if (!animation->HasInitValue()) {
90 animation->SetInitValue(T {});
91 }
92 }
93
RenderTransformUpdate(WeakPtr<RenderTransform> & weakPtr,const TransformOperation & value)94 void RenderTransformUpdate(WeakPtr<RenderTransform>& weakPtr, const TransformOperation& value)
95 {
96 auto renderTransformNode = weakPtr.Upgrade();
97 if (renderTransformNode) {
98 switch (value.type_) {
99 case TransformOperationType::TRANSLATE:
100 renderTransformNode->Translate(
101 value.translateOperation_.dx, value.translateOperation_.dy, value.translateOperation_.dz);
102 break;
103 case TransformOperationType::SKEW:
104 renderTransformNode->Skew(value.skewOperation_.skewX, value.skewOperation_.skewY);
105 break;
106 case TransformOperationType::ROTATE:
107 renderTransformNode->Rotate(value.rotateOperation_.angle, value.rotateOperation_.dx,
108 value.rotateOperation_.dy, value.rotateOperation_.dz);
109 break;
110 case TransformOperationType::MATRIX:
111 renderTransformNode->Matrix3D(value.matrix4_);
112 break;
113 case TransformOperationType::SCALE:
114 renderTransformNode->Scale(
115 value.scaleOperation_.scaleX, value.scaleOperation_.scaleY, value.scaleOperation_.scaleZ);
116 break;
117 case TransformOperationType::PERSPECTIVE:
118 renderTransformNode->Perspective(value.perspectiveOperation_.distance);
119 break;
120 case TransformOperationType::UNDEFINED:
121 renderTransformNode->Translate(Dimension {}, Dimension {}, Dimension {});
122 break;
123 default:
124 LOGE("unsupported transform operation");
125 break;
126 }
127 }
128 }
129
TransformComponentUpdate(WeakPtr<TransformComponent> & transform,const TransformOperation & value)130 void TransformComponentUpdate(WeakPtr<TransformComponent>& transform, const TransformOperation& value)
131 {
132 auto transformComponent = transform.Upgrade();
133 if (transformComponent) {
134 transformComponent->ResetTransform();
135 switch (value.type_) {
136 case TransformOperationType::TRANSLATE:
137 transformComponent->Translate(
138 value.translateOperation_.dx, value.translateOperation_.dy, value.translateOperation_.dz);
139 break;
140 case TransformOperationType::SKEW:
141 transformComponent->Skew(value.skewOperation_.skewX, value.skewOperation_.skewY);
142 break;
143 case TransformOperationType::ROTATE:
144 transformComponent->Rotate(value.rotateOperation_.dx, value.rotateOperation_.dy,
145 value.rotateOperation_.dz, value.rotateOperation_.angle);
146 break;
147 case TransformOperationType::MATRIX:
148 transformComponent->Matrix3d(value.matrix4_);
149 break;
150 case TransformOperationType::SCALE:
151 transformComponent->Scale(
152 value.scaleOperation_.scaleX, value.scaleOperation_.scaleY, value.scaleOperation_.scaleZ);
153 break;
154 case TransformOperationType::PERSPECTIVE:
155 transformComponent->Perspective(value.perspectiveOperation_.distance);
156 break;
157 case TransformOperationType::UNDEFINED:
158 transformComponent->Translate(Dimension {}, Dimension {}, Dimension {});
159 break;
160 default:
161 LOGE("unsupported transform operation");
162 break;
163 }
164 }
165 }
166
RenderTransformOriginUpdate(const WeakPtr<RenderTransform> & weakPtr,const DimensionOffset & origin)167 void RenderTransformOriginUpdate(const WeakPtr<RenderTransform>& weakPtr, const DimensionOffset& origin)
168 {
169 auto renderTransformNode = weakPtr.Upgrade();
170 if (renderTransformNode) {
171 renderTransformNode->SetTransformOrigin(origin.GetX(), origin.GetY());
172 renderTransformNode->MarkNeedUpdateOrigin();
173 }
174 }
175
CreateTransformAnimation(const RefPtr<RenderTransform> & renderTransformNode,const WeakPtr<TransformComponent> & transform,TweenOption & option)176 void CreateTransformAnimation(const RefPtr<RenderTransform>& renderTransformNode,
177 const WeakPtr<TransformComponent>& transform, TweenOption& option)
178 {
179 WeakPtr<RenderTransform> weak(renderTransformNode);
180
181 for (const auto& animation : option.GetTransformAnimations()) {
182 if (animation) {
183 SetAnimationProperties(animation, option);
184 animation->AddListener(std::bind(RenderTransformUpdate, weak, std::placeholders::_1));
185 animation->AddListener(std::bind(TransformComponentUpdate, transform, std::placeholders::_1));
186 }
187 }
188 }
189
OpacityAnimationListener(const WeakPtr<RenderDisplay> & weakRender,WeakPtr<DisplayComponent> & display,float value)190 void OpacityAnimationListener(
191 const WeakPtr<RenderDisplay>& weakRender, WeakPtr<DisplayComponent>& display, float value)
192 {
193 auto opacity = static_cast<uint8_t>(Round(value * UINT8_MAX));
194 if (value < 0.0f || value > 1.0f) {
195 opacity = UINT8_MAX;
196 }
197 auto renderDisplayNode = weakRender.Upgrade();
198 auto displayComponent = display.Upgrade();
199 if (renderDisplayNode) {
200 renderDisplayNode->UpdateOpacity(opacity);
201 if (displayComponent) {
202 displayComponent->SetOpacity((double) opacity / UINT8_MAX);
203 }
204 }
205 }
206
CreateOpacityAnimation(const RefPtr<RenderDisplay> & renderDisplayNode,const WeakPtr<DisplayComponent> & display,TweenOption & option)207 void CreateOpacityAnimation(
208 const RefPtr<RenderDisplay>& renderDisplayNode, const WeakPtr<DisplayComponent>& display, TweenOption& option)
209 {
210 auto& opacityAnimation = option.GetOpacityAnimation();
211 if (!opacityAnimation) {
212 LOGD("create opacity animation with null. skip it.");
213 return;
214 }
215 if (!opacityAnimation->HasInitValue()) {
216 opacityAnimation->SetInitValue(UINT8_MAX);
217 }
218 WeakPtr<RenderDisplay> weakRender = renderDisplayNode;
219 opacityAnimation->AddListener(std::bind(OpacityAnimationListener, weakRender, display, std::placeholders::_1));
220
221 if (option.GetCurve()) {
222 opacityAnimation->SetCurve(option.GetCurve());
223 }
224 }
225
BindingTransformAnimationToController(RefPtr<Animator> & controller,TweenOption & option)226 bool BindingTransformAnimationToController(RefPtr<Animator>& controller, TweenOption& option)
227 {
228 bool needAnimation = false;
229 const auto& animations = option.GetTransformAnimations();
230 for (auto& animation : animations) {
231 if (animation) {
232 needAnimation = true;
233 controller->AddInterpolator(animation);
234 }
235 }
236 return needAnimation;
237 }
238
239 } // namespace
240
241 const LinearEnumMapNode<AnimationType,
242 void (*)(const RefPtr<Animation<float>>&, WeakPtr<RenderTransform>&, TweenOption&)>
243 TweenElement::transformFloatAnimationAddMap_[] = {
244 { AnimationType::SCALE,
245 [](const RefPtr<Animation<float>>& scaleAnimation, WeakPtr<RenderTransform>& weakRender,
__anon5900b1650202() 246 TweenOption& option) {
247 SetScaleProperties(scaleAnimation, option);
248 scaleAnimation->AddListener([weakRender, scaleAnimation](float value) {
249 auto renderTransformNode = weakRender.Upgrade();
250 if (renderTransformNode) {
251 renderTransformNode->Scale(value);
252 }
253 });
254 } },
255 { AnimationType::SCALE_X,
256 [](const RefPtr<Animation<float>>& scaleXAnimation, WeakPtr<RenderTransform>& weakRender,
__anon5900b1650402() 257 TweenOption& option) {
258 SetScaleProperties(scaleXAnimation, option);
259 double maxScaleXY = option.GetMaxScaleXY();
260 auto renderTransformNode = weakRender.Upgrade();
261 if (renderTransformNode) {
262 renderTransformNode->SetMaxScaleXY(maxScaleXY);
263 }
264 scaleXAnimation->AddListener([weakRender, scaleXAnimation](float value) {
265 auto renderTransformNode = weakRender.Upgrade();
266 if (renderTransformNode) {
267 renderTransformNode->Scale(value, 1.0f);
268 }
269 });
270 } },
271 { AnimationType::SCALE_Y,
272 [](const RefPtr<Animation<float>>& scaleYAnimation, WeakPtr<RenderTransform>& weakRender,
__anon5900b1650602() 273 TweenOption& option) {
274 SetScaleProperties(scaleYAnimation, option);
275 scaleYAnimation->AddListener([weakRender, scaleYAnimation](float value) {
276 auto renderTransformNode = weakRender.Upgrade();
277 if (renderTransformNode) {
278 renderTransformNode->Scale(1.0f, value);
279 }
280 });
281 } },
282 { AnimationType::ROTATE_Z,
283 [](const RefPtr<Animation<float>>& rotateZAnimation, WeakPtr<RenderTransform>& weakRender,
__anon5900b1650802() 284 TweenOption& option) {
285 SetRotateProperties(rotateZAnimation, option);
286 rotateZAnimation->AddListener([weakRender, rotateZAnimation](float value) {
287 auto renderTransformNode = weakRender.Upgrade();
288 if (renderTransformNode) {
289 renderTransformNode->RotateZ(value);
290 }
291 });
292 } },
293 { AnimationType::ROTATE_X,
294 [](const RefPtr<Animation<float>>& rotateXAnimation, WeakPtr<RenderTransform>& weakRender,
__anon5900b1650a02() 295 TweenOption& option) {
296 SetRotateProperties(rotateXAnimation, option);
297 rotateXAnimation->AddListener([weakRender, rotateXAnimation](float value) {
298 auto renderTransformNode = weakRender.Upgrade();
299 if (renderTransformNode) {
300 renderTransformNode->RotateX(value);
301 }
302 });
303 } },
304 { AnimationType::ROTATE_Y,
305 [](const RefPtr<Animation<float>>& rotateYAnimation, WeakPtr<RenderTransform>& weakRender,
__anon5900b1650c02() 306 TweenOption& option) {
307 SetRotateProperties(rotateYAnimation, option);
308 rotateYAnimation->AddListener([weakRender, rotateYAnimation](float value) {
309 auto renderTransformNode = weakRender.Upgrade();
310 if (renderTransformNode) {
311 renderTransformNode->RotateY(value);
312 }
313 });
314 } }
315 };
316
Update()317 void TweenElement::Update()
318 {
319 ComposedElement::Update();
320 if (!component_) {
321 return;
322 }
323 auto tweenComponent = AceType::DynamicCast<TweenComponent>(component_);
324 if (!tweenComponent) {
325 LOGE("Get TweenComponent failed.");
326 return;
327 }
328 shadow_ = tweenComponent->GetShadow();
329 positionParam_ = tweenComponent->GetPositionParam();
330
331 if (tweenComponent->IsAnimationNameUpdated()) {
332 needUpdateKeyframes_ = true;
333 tweenComponent->DisableAnimationNameUpdated();
334 }
335 if (tweenComponent->IsOptionCssChanged()) {
336 needUpdateTweenOption_ = true;
337 option_ = tweenComponent->GetTweenOption();
338 tweenComponent->SetOptionCssChanged(false);
339 }
340 if (tweenComponent->IsOptionCustomChanged()) {
341 needUpdateTweenOptionCustom_ = true;
342 optionCustom_ = tweenComponent->GetCustomTweenOption();
343 tweenComponent->SetOptionCustomChanged(false);
344 }
345 if (tweenComponent->IsOperationCssChanged()) {
346 operation_ = tweenComponent->GetAnimationOperation();
347 tweenComponent->SetOperationCssChanged(false);
348 }
349 if (tweenComponent->IsOperationCustomChanged()) {
350 operationCustom_ = tweenComponent->GetCustomAnimationOperation();
351 tweenComponent->SetOperationCustomChanged(false);
352 }
353 auto pipelineContext = context_.Upgrade();
354 if (pipelineContext) {
355 RefPtr<Animator> controller = tweenComponent->GetAnimator();
356 if (controller) {
357 isComponentController_ = true;
358 if (!controller->HasScheduler()) {
359 controller->AttachScheduler(context_);
360 }
361 controllerCustom_ = controller;
362 }
363 if (!controller_) {
364 isDelegatedController_ = false;
365 controller_ = AceType::MakeRefPtr<Animator>(context_);
366 LOGD("set animator to component when update.");
367 }
368
369 LOGD("add request to pipeline context.");
370 if (operation_ == AnimationOperation::PAUSE || operation_ == AnimationOperation::FINISH
371 || operationCustom_ == AnimationOperation::PAUSE || operationCustom_ == AnimationOperation::FINISH) {
372 pipelineContext->AddPostAnimationFlushListener(AceType::Claim(this));
373 }
374 pipelineContext->AddPostFlushListener(AceType::Claim(this));
375 }
376 }
377
~TweenElement()378 TweenElement::~TweenElement()
379 {
380 if (isComponentController_ && controllerCustom_) {
381 controllerCustom_->ClearInterpolators();
382 controllerCustom_->ClearAllListeners();
383 controllerCustom_->Stop();
384 }
385 }
386
ApplyOperation(RefPtr<Animator> & controller,AnimationOperation & operation)387 void TweenElement::ApplyOperation(RefPtr<Animator>& controller, AnimationOperation& operation)
388 {
389 LOGD("apply operation: %{public}d", operation);
390 switch (operation) {
391 case AnimationOperation::PLAY:
392 controller->Play();
393 break;
394 case AnimationOperation::RUNNING:
395 controller->Play();
396 break;
397 case AnimationOperation::PAUSE:
398 controller->Pause();
399 break;
400 case AnimationOperation::CANCEL:
401 controller->Cancel();
402 break;
403 case AnimationOperation::FINISH:
404 controller->Finish();
405 break;
406 case AnimationOperation::REVERSE:
407 controller->Reverse();
408 break;
409 case AnimationOperation::NONE:
410 default:
411 break;
412 }
413 }
414
OnPostFlush()415 void TweenElement::OnPostFlush()
416 {
417 if (skipPostFlush_) {
418 skipPostFlush_ = false;
419 return;
420 }
421 AddPreFlush();
422 }
423
OnPostAnimationFlush()424 void TweenElement::OnPostAnimationFlush()
425 {
426 if (controller_) {
427 controller_->TriggerFrame(controller_->GetPlayedTime(), true);
428 }
429 if (controllerCustom_) {
430 controllerCustom_->TriggerFrame(controllerCustom_->GetPlayedTime(), true);
431 }
432 }
433
OnPreFlush()434 void TweenElement::OnPreFlush()
435 {
436 if (!controller_ && !controllerCustom_) {
437 LOGD("empty controller, skip start tween.");
438 return;
439 }
440 SetWrapHidden(false);
441 if (isDelegatedController_ && !isComponentController_) {
442 LOGD("controller is set from outside. skip prepare animation.");
443 return;
444 }
445
446 if (needUpdateKeyframes_ || (operation_ == AnimationOperation::PLAY && needUpdateTweenOption_)) {
447 ResetController(controller_);
448 ApplyKeyframes();
449 needUpdateKeyframes_ = false;
450 }
451
452 if (needUpdateTweenOption_) {
453 ApplyOptions(controller_, option_);
454 needUpdateTweenOption_ = false;
455 }
456 if (needUpdateTweenOptionCustom_) {
457 ResetController(controllerCustom_);
458 ApplyKeyframes(controllerCustom_, optionCustom_, prepareIdCustom_);
459 ApplyOptions(controllerCustom_, optionCustom_);
460 needUpdateTweenOptionCustom_ = false;
461 }
462 if (operation_ != AnimationOperation::NONE || operationCustom_ != AnimationOperation::NONE) {
463 auto pipelineContext = context_.Upgrade();
464 if (!pipelineContext) {
465 return;
466 }
467 }
468
469 LOGD("Start tween animation with operation: %{public}d, operationCustom: %{public}d", operation_, operationCustom_);
470 if (controller_) {
471 ApplyOperation(controller_, operation_);
472 }
473 if (controllerCustom_) {
474 ApplyOperation(controllerCustom_, operationCustom_);
475 }
476
477 // reset operation to none.
478 operation_ = AnimationOperation::NONE;
479 operationCustom_ = AnimationOperation::NONE;
480 }
481
IsNeedAnimation(RefPtr<Animator> & controller,TweenOption & option)482 bool TweenElement::IsNeedAnimation(RefPtr<Animator>& controller, TweenOption& option)
483 {
484 if (!controller) {
485 LOGE("add interpolator failed. controller is null.");
486 return false;
487 }
488 bool needAnimation = false;
489 auto& transformOffsetAnimations = option.GetTranslateAnimations();
490 for (auto&& [translate, animation] : transformOffsetAnimations) {
491 if (animation) {
492 needAnimation = true;
493 LOGD("add translate animation.");
494 controller->AddInterpolator(animation);
495 }
496 }
497 auto& transformFloatAnimations = option.GetTransformFloatAnimation();
498 for (auto&& [transformFloat, animation] : transformFloatAnimations) {
499 if (animation) {
500 needAnimation = true;
501 LOGD("add transform float animation.");
502 controller->AddInterpolator(animation);
503 }
504 }
505 if (BindingTransformAnimationToController(controller, option)) {
506 needAnimation = true;
507 }
508 auto& transformOriginAnimation = option.GetTransformOriginAnimation();
509 if (transformOriginAnimation) {
510 controller->AddInterpolator(transformOriginAnimation);
511 // no need enable needAnimation, Transform Origin Animation only work when set transform animation.
512 }
513 auto& opacityAnimation = option.GetOpacityAnimation();
514 if (opacityAnimation) {
515 LOGD("add opacity animation.");
516 controller->AddInterpolator(opacityAnimation);
517 needAnimation = true;
518 }
519 auto& colorAnimation = option.GetColorAnimation();
520 if (colorAnimation) {
521 LOGD("add color animation.");
522 controller->AddInterpolator(colorAnimation);
523 needAnimation = true;
524 }
525 if (AddToAnimator(option.GetFloatPropertyAnimation(), controller, option)) {
526 needAnimation = true;
527 }
528 return needAnimation;
529 }
530
BuildChild()531 RefPtr<Component> TweenElement::BuildChild()
532 {
533 RefPtr<TweenComponent> tween = AceType::DynamicCast<TweenComponent>(component_);
534 if (tween) {
535 RefPtr<DisplayComponent> displayComponent = AceType::DynamicCast<DisplayComponent>(tween->GetChild());
536 RefPtr<TransformComponent> transformComponent;
537 if (displayComponent) {
538 transformComponent = AceType::DynamicCast<TransformComponent>(displayComponent->GetChild());
539 if (!transformComponent) {
540 transformComponent = AceType::MakeRefPtr<TransformComponent>();
541 transformComponent->SetChild(displayComponent->GetChild());
542 displayComponent->SetChild(transformComponent);
543 }
544 } else {
545 transformComponent = AceType::MakeRefPtr<TransformComponent>();
546 displayComponent = AceType::MakeRefPtr<DisplayComponent>(transformComponent);
547 transformComponent->SetChild(ComposedElement::BuildChild());
548 }
549 displayComponent->SetPositionType(positionParam_.type);
550 displayComponent->SetHasLeft(positionParam_.left.second);
551 displayComponent->SetHasRight(positionParam_.right.second);
552 displayComponent->SetHasTop(positionParam_.top.second);
553 displayComponent->SetHasBottom(positionParam_.bottom.second);
554 displayComponent->SetLeft(positionParam_.left.first);
555 displayComponent->SetRight(positionParam_.right.first);
556 displayComponent->SetTop(positionParam_.top.first);
557 displayComponent->SetBottom(positionParam_.bottom.first);
558 displayComponent->DisableLayer(tween->IsLeafNode());
559 transform_ = transformComponent;
560 display_ = displayComponent;
561 return displayComponent;
562 } else {
563 LOGE("no tween component found. return empty child.");
564 return nullptr;
565 }
566 }
567
PerformBuild()568 void TweenElement::PerformBuild()
569 {
570 ComposedElement::PerformBuild();
571 auto tweenComponent = AceType::DynamicCast<TweenComponent>(component_);
572 if (!tweenComponent) {
573 LOGE("Get TweenComponent failed.");
574 return;
575 }
576 if (!tweenComponent->GetIsFirstFrameShow()) {
577 SetWrapHidden(true);
578 }
579 }
580
CanUpdate(const RefPtr<Component> & newComponent)581 bool TweenElement::CanUpdate(const RefPtr<Component>& newComponent)
582 {
583 auto pipelineContext = context_.Upgrade();
584 if (pipelineContext && pipelineContext->GetIsDeclarative()) {
585 return ComposedElement::CanUpdate(newComponent);
586 }
587 // components of the same type are not updated.
588 return Element::CanUpdate(newComponent);
589 }
590
CreateTranslateAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)591 void TweenElement::CreateTranslateAnimation(const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
592 {
593 if (!option.HasTransformOffsetChanged()) {
594 LOGD("create translate animation with null. skip it.");
595 return;
596 }
597 auto& transformOffsetAnimations = option.GetTranslateAnimations();
598 WeakPtr<RenderTransform> weakRender = renderTransformNode;
599 static const LinearEnumMapNode<AnimationType,
600 void (*)(const RefPtr<Animation<DimensionOffset>>&, WeakPtr<RenderTransform>&, TweenOption&)>
601 translateAnimationAddMap[] = {
602 { AnimationType::TRANSLATE,
603 [](const RefPtr<Animation<DimensionOffset>>& translateAnimation,
604 WeakPtr<RenderTransform>& weakRender, TweenOption& option) {
605 SetTranslateProperties(translateAnimation, option);
606 translateAnimation->AddListener([weakRender](const DimensionOffset& value) {
607 auto renderTransformNode = weakRender.Upgrade();
608 if (renderTransformNode) {
609 renderTransformNode->Translate(value.GetX(), value.GetY());
610 }
611 });
612 } },
613 { AnimationType::TRANSLATE_X,
614 [](const RefPtr<Animation<DimensionOffset>>& translateXAnimation, WeakPtr<RenderTransform>& weakRender,
615 TweenOption& option) {
616 SetTranslateProperties(translateXAnimation, option);
617 translateXAnimation->AddListener([weakRender](const DimensionOffset& value) {
618 auto renderTransformNode = weakRender.Upgrade();
619 if (renderTransformNode) {
620 renderTransformNode->Translate(value.GetX(), 0.0_px);
621 }
622 });
623 } },
624 { AnimationType::TRANSLATE_Y,
625 [](const RefPtr<Animation<DimensionOffset>>& translateYAnimation, WeakPtr<RenderTransform>& weakRender,
626 TweenOption& option) {
627 SetTranslateProperties(translateYAnimation, option);
628 translateYAnimation->AddListener([weakRender](const DimensionOffset& value) {
629 auto renderTransformNode = weakRender.Upgrade();
630 if (renderTransformNode) {
631 renderTransformNode->Translate(0.0_px, value.GetY());
632 }
633 });
634 } }
635 };
636 size_t mapSize = ArraySize(translateAnimationAddMap);
637 auto iterTranslateAnimation = transformOffsetAnimations.find(AnimationType::TRANSLATE);
638 if (iterTranslateAnimation != transformOffsetAnimations.end()) {
639 auto translateAnimationIter =
640 BinarySearchFindIndex(translateAnimationAddMap, mapSize, AnimationType::TRANSLATE);
641 if (translateAnimationIter != -1) {
642 auto& translateAnimation = iterTranslateAnimation->second;
643 translateAnimationAddMap[translateAnimationIter].value(translateAnimation, weakRender, option);
644 }
645 }
646
647 auto iterTranslateXAnimation = transformOffsetAnimations.find(AnimationType::TRANSLATE_X);
648 if (iterTranslateXAnimation != transformOffsetAnimations.end()) {
649 auto translateXAnimationIter =
650 BinarySearchFindIndex(translateAnimationAddMap, mapSize, AnimationType::TRANSLATE_X);
651 if (translateXAnimationIter != -1) {
652 auto& translateXAnimation = iterTranslateXAnimation->second;
653 translateAnimationAddMap[translateXAnimationIter].value(translateXAnimation, weakRender, option);
654 }
655 }
656
657 auto iterTranslateYAnimation = transformOffsetAnimations.find(AnimationType::TRANSLATE_Y);
658 if (iterTranslateYAnimation != transformOffsetAnimations.end()) {
659 auto translateYAnimationIter =
660 BinarySearchFindIndex(translateAnimationAddMap, mapSize, AnimationType::TRANSLATE_Y);
661 if (translateYAnimationIter != -1) {
662 auto& translateYAnimation = iterTranslateYAnimation->second;
663 translateAnimationAddMap[translateYAnimationIter].value(translateYAnimation, weakRender, option);
664 }
665 }
666 }
667
CreateScaleAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)668 void TweenElement::CreateScaleAnimation(const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
669 {
670 if (!option.HasTransformFloatChanged()) {
671 LOGD("create scale animation with null. skip it.");
672 return;
673 }
674 auto& transformFloatAnimations = option.GetTransformFloatAnimation();
675 WeakPtr<RenderTransform> weakRender = renderTransformNode;
676 auto iterScaleAnimation = transformFloatAnimations.find(AnimationType::SCALE);
677 size_t mapSize = ArraySize(transformFloatAnimationAddMap_);
678 if (iterScaleAnimation != transformFloatAnimations.end()) {
679 auto scaleAnimationIter = BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::SCALE);
680 if (scaleAnimationIter != -1) {
681 auto& scaleAnimation = iterScaleAnimation->second;
682 transformFloatAnimationAddMap_[scaleAnimationIter].value(scaleAnimation, weakRender, option);
683 }
684 }
685
686 auto iterScaleXAnimation = transformFloatAnimations.find(AnimationType::SCALE_X);
687 if (iterScaleXAnimation != transformFloatAnimations.end()) {
688 auto scaleXAnimationIter =
689 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::SCALE_X);
690 if (scaleXAnimationIter != -1) {
691 auto& scaleXAnimation = iterScaleXAnimation->second;
692 transformFloatAnimationAddMap_[scaleXAnimationIter].value(scaleXAnimation, weakRender, option);
693 }
694 }
695
696 auto iterScaleYAnimation = transformFloatAnimations.find(AnimationType::SCALE_Y);
697 if (iterScaleYAnimation != transformFloatAnimations.end()) {
698 auto scaleYAnimationIter =
699 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::SCALE_Y);
700 if (scaleYAnimationIter != -1) {
701 auto& scaleYAnimation = iterScaleYAnimation->second;
702 transformFloatAnimationAddMap_[scaleYAnimationIter].value(scaleYAnimation, weakRender, option);
703 }
704 }
705 }
706
CreateTransformOriginAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)707 void TweenElement::CreateTransformOriginAnimation(
708 const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
709 {
710 if (option.HasTransformOriginChanged()) {
711 renderTransformNode->SetTransformOrigin(option.GetTransformOriginX(), option.GetTransformOriginY());
712 auto animation = option.GetTransformOriginAnimation();
713 if (animation) {
714 animation->AddListener([weak = AceType::WeakClaim(AceType::RawPtr(renderTransformNode))](
715 const DimensionOffset& value) { RenderTransformOriginUpdate(weak, value); });
716
717 if (option.GetCurve()) {
718 animation->SetCurve(option.GetCurve());
719 }
720 }
721 option.SetTransformOriginChanged(false);
722 } else {
723 renderTransformNode->SetTransformOrigin(HALF_PERCENT, HALF_PERCENT);
724 renderTransformNode->MarkNeedUpdateOrigin();
725 }
726 }
727
CreateRotateAnimation(const RefPtr<RenderTransform> & renderTransformNode,TweenOption & option)728 void TweenElement::CreateRotateAnimation(const RefPtr<RenderTransform>& renderTransformNode, TweenOption& option)
729 {
730 if (!option.HasTransformFloatChanged()) {
731 LOGD("create rotate animation with null. skip it.");
732 return;
733 }
734 auto& transformFloatAnimations = option.GetTransformFloatAnimation();
735 WeakPtr<RenderTransform> weakRender = renderTransformNode;
736 auto iterRotateZAnimation = transformFloatAnimations.find(AnimationType::ROTATE_Z);
737 size_t mapSize = ArraySize(transformFloatAnimationAddMap_);
738 if (iterRotateZAnimation != transformFloatAnimations.end()) {
739 auto rotateZAnimationIter =
740 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::ROTATE_Z);
741 if (rotateZAnimationIter != -1) {
742 auto& rotateZAnimation = iterRotateZAnimation->second;
743 transformFloatAnimationAddMap_[rotateZAnimationIter].value(rotateZAnimation, weakRender, option);
744 }
745 }
746
747 auto iterRotateXAnimation = transformFloatAnimations.find(AnimationType::ROTATE_X);
748 if (iterRotateXAnimation != transformFloatAnimations.end()) {
749 auto rotateXAnimationIter =
750 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::ROTATE_X);
751 if (rotateXAnimationIter != -1) {
752 auto& rotateXAnimation = iterRotateXAnimation->second;
753 transformFloatAnimationAddMap_[rotateXAnimationIter].value(rotateXAnimation, weakRender, option);
754 }
755 }
756
757 auto iterRotateYAnimation = transformFloatAnimations.find(AnimationType::ROTATE_Y);
758 if (iterRotateYAnimation != transformFloatAnimations.end()) {
759 auto rotateYAnimationIter =
760 BinarySearchFindIndex(transformFloatAnimationAddMap_, mapSize, AnimationType::ROTATE_Y);
761 if (rotateYAnimationIter != -1) {
762 auto& rotateYAnimation = iterRotateYAnimation->second;
763 transformFloatAnimationAddMap_[rotateYAnimationIter].value(rotateYAnimation, weakRender, option);
764 }
765 }
766 }
767
CreateColorAnimation(const RefPtr<PropertyAnimatable> & animatable,TweenOption & option)768 void TweenElement::CreateColorAnimation(const RefPtr<PropertyAnimatable>& animatable, TweenOption& option)
769 {
770 if (!animatable) {
771 LOGE("create color animation failed. not a animatable child.");
772 return;
773 }
774 auto& colorAnimation = option.GetColorAnimation();
775 if (!colorAnimation) {
776 LOGE("create color animation with null. skip it.");
777 return;
778 }
779 PropertyAnimatableType propertyType;
780 if (option.GetIsBackground()) {
781 propertyType = PropertyAnimatableType::PROPERTY_BACK_DECORATION_COLOR;
782 } else {
783 propertyType = PropertyAnimatableType::PROPERTY_FRONT_DECORATION_COLOR;
784 }
785 CreatePropertyAnimation<ColorPropertyAnimatable, Color>(animatable, propertyType, option, colorAnimation);
786 }
787
788 template<class U, class V>
CreatePropertyAnimation(const RefPtr<PropertyAnimatable> & propertyAnimatable,PropertyAnimatableType propertyType,const TweenOption & option,RefPtr<Animation<V>> & animation)789 bool TweenElement::CreatePropertyAnimation(const RefPtr<PropertyAnimatable>& propertyAnimatable,
790 PropertyAnimatableType propertyType, const TweenOption& option, RefPtr<Animation<V>>& animation)
791 {
792 if (!animation) {
793 LOGE("CreatePropertyAnimation failed, animation is null.");
794 return false;
795 }
796 typename U::Type initValue;
797 bool created =
798 PropertyAnimatable::AddPropertyAnimation<U, V>(propertyAnimatable, propertyType, animation, initValue);
799 if (!created) {
800 LOGE("create property animation failed. property: %{public}d", propertyType);
801 return false;
802 }
803 if (option.GetCurve()) {
804 animation->SetCurve(option.GetCurve());
805 }
806 if (!animation->HasInitValue()) {
807 animation->SetInitValue(initValue);
808 }
809 return true;
810 }
811
812 template<class U>
AddToAnimator(const std::map<PropertyAnimatableType,U> & animations,RefPtr<Animator> & controller,TweenOption & option)813 bool TweenElement::AddToAnimator(
814 const std::map<PropertyAnimatableType, U>& animations, RefPtr<Animator>& controller, TweenOption& option)
815 {
816 bool needAnimation = false;
817 for (auto&& [property, animation] : animations) {
818 if (animation) {
819 needAnimation = true;
820 LOGD("add property animation. property: %{public}d", property);
821 controller->AddInterpolator(animation);
822 }
823 }
824 return needAnimation;
825 }
826
SetController(const RefPtr<Animator> & controller)827 void TweenElement::SetController(const RefPtr<Animator>& controller)
828 {
829 if (!controller) {
830 LOGE("set controller failed. controller is empty.");
831 return;
832 }
833 LOGD("set controller");
834 if (!controller_->IsStopped()) {
835 controller_->Stop();
836 }
837 isDelegatedController_ = true;
838 controller_ = controller;
839 }
840
GetOption() const841 const TweenOption& TweenElement::GetOption() const
842 {
843 return option_;
844 }
845
SetOption(const TweenOption & option)846 void TweenElement::SetOption(const TweenOption& option)
847 {
848 LOGD("set tween option");
849 option_ = option;
850 }
851
GetController() const852 const RefPtr<Animator>& TweenElement::GetController() const
853 {
854 return controller_;
855 }
856
SetOpacity(uint8_t opacity)857 void TweenElement::SetOpacity(uint8_t opacity)
858 {
859 if (children_.empty()) {
860 LOGE("no child when set Opacity");
861 return;
862 }
863 const auto& child = children_.front();
864 if (!child) {
865 LOGE("child is null.");
866 return;
867 }
868 auto childElement = AceType::DynamicCast<RenderElement>(child);
869 if (!childElement) {
870 LOGE("child element is null.");
871 return;
872 }
873 const auto& displayRenderNode = AceType::DynamicCast<RenderDisplay>(childElement->GetRenderNode());
874 if (!displayRenderNode) {
875 LOGE("no display render node found.");
876 return;
877 }
878 LOGD("set Opacity. Opacity: %{public}d", opacity);
879 displayRenderNode->UpdateOpacity(opacity);
880 }
881
SkipPostFlush()882 void TweenElement::SkipPostFlush()
883 {
884 skipPostFlush_ = true;
885 }
886
AddPreFlush()887 void TweenElement::AddPreFlush()
888 {
889 auto pipelineContext = context_.Upgrade();
890 if (!pipelineContext) {
891 return;
892 }
893 pipelineContext->AddPreFlushListener(AceType::Claim(this));
894 }
895
SetWrapHidden(bool hidden)896 void TweenElement::SetWrapHidden(bool hidden)
897 {
898 if (children_.empty()) {
899 LOGE("no child when set visible");
900 return;
901 }
902 const auto& child = children_.front();
903 if (!child) {
904 LOGE("child is null.");
905 return;
906 }
907 auto childElement = AceType::DynamicCast<RenderElement>(child);
908 if (!childElement) {
909 LOGE("child element is null.");
910 return;
911 }
912 const auto& displayRenderNode = AceType::DynamicCast<RenderDisplay>(childElement->GetRenderNode());
913 if (!displayRenderNode) {
914 LOGE("no display render node found.");
915 return;
916 }
917 displayRenderNode->UpdateHidden(hidden);
918 }
919
SetTouchable(bool enable)920 void TweenElement::SetTouchable(bool enable)
921 {
922 LOGD("set tween touchable status: %{public}d", enable);
923
924 if (children_.empty()) {
925 LOGW("get content child failed. no child yet.");
926 return;
927 }
928 const auto& child = children_.front();
929 if (!child || child->GetType() != RENDER_ELEMENT) {
930 LOGW("get content child failed. null child or not render child.");
931 return;
932 }
933 const auto& transformElement = AceType::DynamicCast<RenderElement>(child)->GetFirstChild();
934 if (!transformElement) {
935 LOGE("Get RenderElement failed.");
936 return;
937 }
938 const auto& transformRenderNode = AceType::DynamicCast<RenderTransform>(transformElement->GetRenderNode());
939 if (transformRenderNode) {
940 transformRenderNode->SetTouchable(enable);
941 }
942 }
943
GetContentRender() const944 RefPtr<RenderNode> TweenElement::GetContentRender() const
945 {
946 auto contentElement = GetContentElement();
947 if (!contentElement) {
948 return nullptr;
949 }
950 return contentElement->GetRenderNode();
951 }
952
ApplyKeyframes()953 bool TweenElement::ApplyKeyframes()
954 {
955 return ApplyKeyframes(controller_, option_, prepareId_);
956 }
957
AddPrepareListener(RefPtr<Animator> & controller,const WeakPtr<RenderTransform> & weakTransform,BaseId::IdType & prepareId)958 void TweenElement::AddPrepareListener(
959 RefPtr<Animator>& controller, const WeakPtr<RenderTransform>& weakTransform, BaseId::IdType& prepareId)
960 {
961 if (!controller) {
962 LOGE("Add Prepare Listener failed. controller is null.");
963 return;
964 }
965 controller->RemovePrepareListener(prepareId);
966 prepareId =
967 controller->AddPrepareListener([weakTransform, weakContext = context_,
968 weakTween = AceType::WeakClaim(this),
969 needForceResetTransform =
970 controller->GetAllowRunningAsynchronously()]() {
971 // reset transform matrix at the start of every frame.
972 auto context = weakContext.Upgrade();
973 auto tween = weakTween.Upgrade();
974 auto transform = weakTransform.Upgrade();
975 if (context && tween && transform) {
976 auto currentTimestamp = context->GetTimeFromExternalTimer();
977 if (tween->currentTimestamp_ != currentTimestamp || tween->currentTimestamp_ == 0 ||
978 needForceResetTransform) {
979 transform->ResetTransform();
980 tween->currentTimestamp_ = currentTimestamp;
981 }
982 }
983 });
984 }
985
ApplyKeyframes(RefPtr<Animator> & controller,TweenOption & option,BaseId::IdType & prepareId)986 bool TweenElement::ApplyKeyframes(RefPtr<Animator>& controller, TweenOption& option, BaseId::IdType& prepareId)
987 {
988 if (!controller) {
989 LOGW("controller is null.");
990 return false;
991 }
992 if (children_.empty()) {
993 LOGW("apply option failed. no child yet.");
994 return false;
995 }
996 const auto& child = children_.front();
997 if (!child || child->GetType() != RENDER_ELEMENT) {
998 LOGW("apply option failed. null child or not render child.");
999 return false;
1000 }
1001 LOGD("TweenElement: ApplyKeyframes.");
1002
1003 const auto& displayRenderNode =
1004 AceType::DynamicCast<RenderDisplay>(AceType::DynamicCast<RenderElement>(child)->GetRenderNode());
1005 if (!displayRenderNode) {
1006 LOGE("display render node is null.");
1007 return false;
1008 }
1009 const auto& transformElement = AceType::DynamicCast<RenderElement>(child)->GetFirstChild();
1010 if (!transformElement) {
1011 LOGE("transform element node is null.");
1012 return false;
1013 }
1014 const auto& transformRenderNode = AceType::DynamicCast<RenderTransform>(transformElement->GetRenderNode());
1015 if (!transformRenderNode) {
1016 LOGE("transform render node is null.");
1017 return false;
1018 }
1019 if (shadow_.IsValid()) {
1020 displayRenderNode->SetShadow(shadow_);
1021 transformRenderNode->SetShadow(shadow_);
1022 }
1023
1024 const auto& contentElement = AceType::DynamicCast<RenderElement>(transformElement)->GetFirstChild();
1025 auto animatable = GetAnimatable(contentElement);
1026 if (animatable) {
1027 CreateColorAnimation(animatable, option);
1028 CreatePropertyAnimationFloat(animatable, option);
1029 }
1030 CreateTransformAnimation(transformRenderNode, transform_, option);
1031 CreateTranslateAnimation(transformRenderNode, option);
1032 CreateScaleAnimation(transformRenderNode, option);
1033 CreateRotateAnimation(transformRenderNode, option);
1034 CreateTransformOriginAnimation(transformRenderNode, option);
1035 if (option.HasTransformOffsetChanged() || option.HasTransformFloatChanged() || option.HasTransformChanged()) {
1036 AddPrepareListener(controller, transformRenderNode, prepareId);
1037 }
1038 CreateOpacityAnimation(displayRenderNode, display_, option);
1039 return IsNeedAnimation(controller, option);
1040 }
1041
ApplyOptions(RefPtr<Animator> & controller,TweenOption & option)1042 void TweenElement::ApplyOptions(RefPtr<Animator>& controller, TweenOption& option)
1043 {
1044 if (!controller) {
1045 LOGE("Apply Options failed. Controller is null.");
1046 return;
1047 }
1048 LOGD("apply options.");
1049 controller->SetDuration(option.GetDuration());
1050 controller->SetIteration(option.GetIteration());
1051 controller->SetStartDelay(option.GetDelay());
1052 controller->SetFillMode(option.GetFillMode());
1053 controller->SetTempo(option.GetTempo());
1054 controller->SetAnimationDirection(option.GetAnimationDirection());
1055 controller->SetAllowRunningAsynchronously(option.GetAllowRunningAsynchronously());
1056
1057 for (const auto& [type, animation] : option.GetAnimatables()) {
1058 if (option.GetCurve()) {
1059 animation->SetCurve(option.GetCurve());
1060 }
1061 controller->AddInterpolator(animation);
1062 }
1063 }
1064
ApplyOptions()1065 void TweenElement::ApplyOptions()
1066 {
1067 ApplyOptions(controller_, option_);
1068 }
1069
GetContentElement() const1070 RefPtr<Element> TweenElement::GetContentElement() const
1071 {
1072 const auto& mountParent = GetContentParent();
1073 if (!mountParent) {
1074 LOGE("Get content element failed. content parent is null.");
1075 return nullptr;
1076 }
1077 return mountParent->GetFirstChild();
1078 }
1079
GetContentParent() const1080 RefPtr<Element> TweenElement::GetContentParent() const
1081 {
1082 const auto child = GetFirstChild();
1083 if (!child) {
1084 LOGW("Get transformElement failed. null child.");
1085 return nullptr;
1086 }
1087 const auto& displayRenderNode =
1088 AceType::DynamicCast<RenderDisplay>(AceType::DynamicCast<RenderElement>(child)->GetRenderNode());
1089 if (!displayRenderNode) {
1090 LOGE("display render node is null.");
1091 return nullptr;
1092 }
1093 const auto& transformElement = AceType::DynamicCast<RenderElement>(child)->GetFirstChild();
1094 if (!transformElement) {
1095 LOGE("Get transformElement failed. transform element is null");
1096 return nullptr;
1097 }
1098 const auto& transformRenderNode = AceType::DynamicCast<RenderTransform>(transformElement->GetRenderNode());
1099 if (!transformRenderNode) {
1100 LOGE("Get transformElement failed. transform render node is null.");
1101 return nullptr;
1102 }
1103 return transformElement;
1104 }
1105
CreatePropertyAnimationFloat(const RefPtr<PropertyAnimatable> & animatable,TweenOption & option)1106 void TweenElement::CreatePropertyAnimationFloat(const RefPtr<PropertyAnimatable>& animatable, TweenOption& option)
1107 {
1108 if (!animatable) {
1109 LOGE("Create property animation for float failed. animatable is null.");
1110 return;
1111 }
1112 auto& propertyFloatMap = option.GetFloatPropertyAnimation();
1113 if (propertyFloatMap.empty()) {
1114 LOGD("No property animation float found. skip it.");
1115 return;
1116 }
1117 for (auto&& [property, animation] : propertyFloatMap) {
1118 LOGD("Create animation float for property: %{public}d", property);
1119 CreatePropertyAnimation<FloatPropertyAnimatable, float>(animatable, property, option, animation);
1120 }
1121 }
1122
1123 } // namespace OHOS::Ace
1124