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