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