1 /*
2  * Copyright (c) 2021 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/transition/transition_element.h"
17 
18 #include "core/components/box/render_box_base.h"
19 #include "core/components/transform/transform_element.h"
20 #include "core/components/transition/transition_component.h"
21 #include "core/components/tween/tween_component.h"
22 #include "core/components/tween/tween_element.h"
23 
24 namespace OHOS::Ace {
25 
Update()26 void TransitionElement::Update()
27 {
28     ComposedElement::Update();
29     if (!component_) {
30         LOGE("Update failed. component is null");
31         return;
32     }
33     const auto transitionComponent = AceType::DynamicCast<TransitionComponent>(component_);
34     if (!transitionComponent) {
35         LOGE("transition element update failed. transition component is null.");
36         return;
37     }
38     optionMap_[TransitionOptionType::TRANSITION_IN] = transitionComponent->GetTransitionInOption();
39     optionMap_[TransitionOptionType::TRANSITION_OUT] = transitionComponent->GetTransitionOutOption();
40 
41     if (transitionComponent->IsOptionChanged()) {
42         transitionOption_ = transitionComponent->GetTransitionOption();
43         transitionComponent->MarkOptionChanged(false);
44     }
45 
46     auto pipelineContext = context_.Upgrade();
47     if (pipelineContext) {
48         if (!controller_) {
49             controller_ = CREATE_ANIMATOR(context_);
50         } else {
51             controller_->Stop();
52             controller_->ClearInterpolators();
53         }
54     }
55 }
56 
PerformBuild()57 void TransitionElement::PerformBuild()
58 {
59     bool build = true;
60     if (!hasBuildChild_) {
61         ComposedElement::PerformBuild();
62         hasBuildChild_ = true;
63         build = false;
64     }
65 
66     if (transitionOption_.IsValid()) {
67         ReplaceAnimation(transitionOption_);
68     } else {
69         transitionOption_ = TweenOption();
70         if (build) {
71             ComposedElement::PerformBuild();
72         }
73         return;
74     }
75 
76     if (controller_) {
77         SetController(controller_);
78         ApplyAnimation(transitionOption_);
79         controller_->Play();
80     }
81     transitionOption_ = TweenOption();
82     if (build) {
83         ComposedElement::PerformBuild();
84     }
85 }
86 
ReplaceAnimation(TweenOption & transitionOption)87 void TransitionElement::ReplaceAnimation(TweenOption& transitionOption)
88 {
89     auto& propertyAnimationMap = transitionOption.GetFloatPropertyAnimation();
90     auto& colorAnimation = transitionOption.GetColorAnimation();
91     auto& opacityAnimation = transitionOption.GetOpacityAnimation();
92     auto elementBox = GetChildBox();
93     if (!elementBox) {
94         LOGE("box element get failed.");
95         return;
96     }
97     auto renderBox = AceType::DynamicCast<RenderBoxBase>(elementBox->GetRenderNode());
98     if (!renderBox) {
99         LOGE("box render get failed.");
100         return;
101     }
102     for (auto&& [propertyAnimatableType, propertyAnimation] : propertyAnimationMap) {
103         if (propertyAnimatableType == PropertyAnimatableType::PROPERTY_WIDTH) {
104             renderBox->UpdateStyleFromRenderNode(propertyAnimatableType);
105             float width = renderBox->GetWidth();
106             auto keyframeWidthBegin = AceType::MakeRefPtr<Keyframe<float>>(0.0f, width);
107             AceType::DynamicCast<KeyframeAnimation<float>>(
108                 propertyAnimationMap[PropertyAnimatableType::PROPERTY_WIDTH])->ReplaceKeyframe(keyframeWidthBegin);
109         }
110         if (propertyAnimatableType == PropertyAnimatableType::PROPERTY_HEIGHT) {
111             renderBox->UpdateStyleFromRenderNode(propertyAnimatableType);
112             float height = renderBox->GetHeight();
113             auto keyframeHeightBegin = AceType::MakeRefPtr<Keyframe<float>>(0.0f, height);
114             AceType::DynamicCast<KeyframeAnimation<float>>
115                 (propertyAnimationMap[PropertyAnimatableType::PROPERTY_HEIGHT])->ReplaceKeyframe(keyframeHeightBegin);
116         }
117     }
118     if (colorAnimation) {
119         renderBox->UpdateStyleFromRenderNode(PropertyAnimatableType::PROPERTY_BACK_DECORATION_COLOR);
120         Color color = renderBox->GetColor();
121         auto keyframeColorBegin = AceType::MakeRefPtr<Keyframe<Color>>(0.0f, color);
122         AceType::DynamicCast<KeyframeAnimation<Color>>(colorAnimation)->ReplaceKeyframe(keyframeColorBegin);
123     }
124 
125     auto display = GetChildDisplay();
126     if (display && opacityAnimation) {
127         auto renderDisplay = AceType::DynamicCast<RenderDisplay>(display->GetRenderNode());
128         if (renderDisplay) {
129             renderDisplay->UpdateOpacity();
130             auto opacity = renderDisplay->GetOpacity() * (1.0 / UINT8_MAX);
131             auto keyframeOpacityBegin = AceType::MakeRefPtr<Keyframe<float>>(0.0f, opacity);
132             AceType::DynamicCast<KeyframeAnimation<float>>(opacityAnimation)->ReplaceKeyframe(keyframeOpacityBegin);
133         }
134     }
135 }
136 
GetChildDisplay() const137 RefPtr<DisplayElement> TransitionElement::GetChildDisplay() const
138 {
139     auto tween = GetChildTween();
140     if (!tween) {
141         LOGE("transition option get failed. no tween found.");
142         return nullptr;
143     }
144     return AceType::DynamicCast<DisplayElement>(tween->GetFirstChild());
145 }
146 
GetChildTransform() const147 RefPtr<TransformElement> TransitionElement::GetChildTransform() const
148 {
149     auto display = GetChildDisplay();
150     if (!display) {
151         LOGE("transition option get failed. no display found.");
152         return nullptr;
153     }
154     return AceType::DynamicCast<TransformElement>(display->GetFirstChild());
155 }
156 
GetChildBox() const157 RefPtr<BoxBaseElement> TransitionElement::GetChildBox() const
158 {
159     auto elementDisplay = GetChildDisplay();
160     if (!elementDisplay) {
161         LOGE("display element get failed.");
162         return nullptr;
163     }
164     auto elementTransform = AceType::DynamicCast<TransformElement>(elementDisplay->GetFirstChild());
165     if (!elementTransform) {
166         LOGE("transform element get failed.");
167         return nullptr;
168     }
169     return AceType::DynamicCast<BoxBaseElement>(elementTransform->GetFirstChild());
170 }
171 
ApplyAnimation(TweenOption & transitionOption)172 void TransitionElement::ApplyAnimation(TweenOption& transitionOption)
173 {
174     auto tween = GetChildTween();
175     if (!tween) {
176         LOGE("transition option get failed. no tween found.");
177         return;
178     }
179 
180     tween->SetOption(transitionOption);
181     tween->ApplyKeyframes();
182     tween->ApplyOptions();
183 }
184 
SetController(const RefPtr<Animator> & controller)185 void TransitionElement::SetController(const RefPtr<Animator>& controller)
186 {
187     auto tween = GetChildTween();
188     if (!tween) {
189         LOGE("set controller failed. no tween found.");
190         return;
191     }
192     tween->SetController(controller);
193 }
194 
GetController() const195 RefPtr<Animator> TransitionElement::GetController() const
196 {
197     auto tween = GetChildTween();
198     if (!tween) {
199         LOGE("get controller failed. no tween found.");
200         return nullptr;
201     }
202     return tween->GetController();
203 }
204 
SetTouchable(bool enable)205 void TransitionElement::SetTouchable(bool enable)
206 {
207     auto tween = GetChildTween();
208     if (!tween) {
209         LOGE("set touchable failed. no tween found. enable: %{public}d", enable);
210         return;
211     }
212     tween->SetTouchable(enable);
213 }
214 
SwitchTransitionOption(TransitionOptionType type,bool needApplyOption)215 void TransitionElement::SwitchTransitionOption(TransitionOptionType type, bool needApplyOption)
216 {
217     auto tween = GetChildTween();
218     if (!tween) {
219         LOGE("Switch transition option failed. no tween found. direction: %{public}d", type);
220         return;
221     }
222     optionMap_[type].ClearListeners();
223     // If never set before, use empty option instead.
224     tween->SetOption(optionMap_[type]);
225     if (!tween->ApplyKeyframes()) {
226         LOGW("Apply transition option failed. tween apply option fail.");
227     }
228     if (needApplyOption) {
229         tween->ApplyOptions();
230     }
231 }
232 
BuildChild()233 RefPtr<Component> TransitionElement::BuildChild()
234 {
235     RefPtr<TransitionComponent> transition = AceType::DynamicCast<TransitionComponent>(component_);
236     if (transition) {
237         RefPtr<TweenComponent> tweenComponent =
238             AceType::MakeRefPtr<TweenComponent>(TweenComponent::AllocTweenComponentId(), transition->GetName());
239         tweenComponent->SetChild(ComposedElement::BuildChild());
240         tweenComponent->SetIsFirstFrameShow(transition->IsFirstFrameShow());
241         return tweenComponent;
242     } else {
243         LOGE("no transition component found. return empty child.");
244         return nullptr;
245     }
246 }
247 
SetWrapHidden(bool hidden)248 void TransitionElement::SetWrapHidden(bool hidden)
249 {
250     auto tween = GetChildTween();
251     if (!tween) {
252         LOGE("set wrap hidden failed. no tween found. hidden: %{public}d", hidden);
253         return;
254     }
255     tween->SetWrapHidden(hidden);
256 }
257 
AddPreFlush()258 void TransitionElement::AddPreFlush()
259 {
260     auto tween = GetChildTween();
261     if (!tween) {
262         LOGE("Add pre flush failed. no tween found.");
263         return;
264     }
265     tween->AddPreFlush();
266 }
267 
SkipPostFlush()268 void TransitionElement::SkipPostFlush()
269 {
270     auto tween = GetChildTween();
271     if (!tween) {
272         LOGE("Skip post flush failed. no tween found.");
273         return;
274     }
275     tween->SkipPostFlush();
276 }
277 
GetChildTween() const278 RefPtr<TweenElement> TransitionElement::GetChildTween() const
279 {
280     if (children_.empty()) {
281         LOGW("get child tween failed. no child yet.");
282         return nullptr;
283     }
284     const auto& child = children_.front();
285     if (!child) {
286         LOGW("get child tween failed. null child.");
287         return nullptr;
288     }
289     auto tween = AceType::DynamicCast<TweenElement>(child);
290     if (!tween) {
291         LOGW("get child tween failed. null tween.");
292         return nullptr;
293     }
294     return tween;
295 }
296 
SetTransition(const TweenOption & inOption,const TweenOption & outOption)297 void TransitionElement::SetTransition(const TweenOption& inOption, const TweenOption& outOption)
298 {
299     optionMap_[TransitionOptionType::TRANSITION_IN] = inOption;
300     optionMap_[TransitionOptionType::TRANSITION_OUT] = outOption;
301 }
302 
SetSharedTransition(const TweenOption & inOption,const TweenOption & outOption)303 void TransitionElement::SetSharedTransition(const TweenOption& inOption, const TweenOption& outOption)
304 {
305     optionMap_[TransitionOptionType::TRANSITION_SHARED_IN] = inOption;
306     optionMap_[TransitionOptionType::TRANSITION_SHARED_OUT] = outOption;
307 }
308 
GetContentElement() const309 RefPtr<Element> TransitionElement::GetContentElement() const
310 {
311     auto tween = GetChildTween();
312     if (!tween) {
313         LOGE("get content element failed. no tween found.");
314         return nullptr;
315     }
316     return tween->GetContentElement();
317 }
318 
ResetPageTransitionAnimation() const319 void TransitionElement::ResetPageTransitionAnimation() const
320 {
321     // reset opacity
322     auto display = GetChildDisplay();
323     if (display) {
324         auto renderDisplay = AceType::DynamicCast<RenderDisplay>(display->GetRenderNode());
325         if (renderDisplay) {
326             renderDisplay->UpdateOpacity(UINT8_MAX);
327         }
328     }
329     // reset transform
330     auto transform = GetChildTransform();
331     if (transform) {
332         auto renderTransform = AceType::DynamicCast<RenderTransform>(transform->GetRenderNode());
333         if (renderTransform) {
334             renderTransform->ResetTransform();
335         }
336     }
337 }
338 
339 } // namespace OHOS::Ace
340