1 /*
2 * Copyright (c) 2024 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
17 #include "cj_view_context_ffi.h"
18 #include <functional>
19 #include <memory>
20 #include <sstream>
21 #include <utility>
22 #include "cj_lambda.h"
23 #include "base/utils/system_properties.h"
24 #include "base/utils/utils.h"
25 #include "base/log/jank_frame_report.h"
26 #include "bridge/common/utils/engine_helper.h"
27 #include "bridge/common/utils/utils.h"
28 #include "core/common/ace_engine.h"
29 #include "core/components/common/properties/animation_option.h"
30 #include "core/components_ng/base/view_stack_model.h"
31 #include "core/components_ng/base/view_stack_processor.h"
32 #include "core/components_ng/pattern/view_context/view_context_model_ng.h"
33
34 using namespace OHOS::Ace;
35 using namespace OHOS::FFI;
36 using namespace OHOS::Ace::Framework;
37
38 namespace OHOS::Ace::Framework {
39 namespace {
40 constexpr uint32_t DEFAULT_DURATION = 1000; // ms
41 constexpr int64_t MICROSEC_TO_MILLISEC = 1000;
42 }
43
GetFormAnimationTimeInterval(const RefPtr<PipelineBase> & pipelineContext)44 int64_t GetFormAnimationTimeInterval(const RefPtr<PipelineBase>& pipelineContext)
45 {
46 CHECK_NULL_RETURN(pipelineContext, 0);
47 return (GetMicroTickCount() - pipelineContext->GetFormAnimationStartTime()) / MICROSEC_TO_MILLISEC;
48 }
49
CheckIfSetFormAnimationDuration(const RefPtr<PipelineBase> & pipelineContext,const AnimationOption & option)50 bool CheckIfSetFormAnimationDuration(const RefPtr<PipelineBase>& pipelineContext, const AnimationOption& option)
51 {
52 CHECK_NULL_RETURN(pipelineContext, false);
53 return pipelineContext->IsFormAnimationFinishCallback() && pipelineContext->IsFormRender() &&
54 option.GetDuration() > (DEFAULT_DURATION - GetFormAnimationTimeInterval(pipelineContext));
55 }
56
AnimateToForStageMode(const RefPtr<PipelineBase> & pipelineContext,AnimationOption & option,void (* callback)(),const std::function<void ()> & onFinishEvent,bool immediately)57 void AnimateToForStageMode(const RefPtr<PipelineBase>& pipelineContext, AnimationOption& option,
58 void (*callback)(), const std::function<void()>& onFinishEvent, bool immediately)
59 {
60 auto triggerId = Container::CurrentIdSafely();
61 AceEngine::Get().NotifyContainers([triggerId, option](const RefPtr<Container>& container) {
62 auto context = container->GetPipelineContext();
63 if (!context) {
64 // pa container do not have pipeline context.
65 return;
66 }
67
68 if (!container->IsFRSCardContainer() && !container->WindowIsShow()) {
69 return;
70 }
71 ContainerScope scope(container->GetInstanceId());
72 context->FlushBuild();
73 if (context->GetInstanceId() == triggerId) {
74 return;
75 }
76 context->PrepareOpenImplicitAnimation();
77 });
78 pipelineContext->OpenImplicitAnimation(option, option.GetCurve(), onFinishEvent);
79 auto previousOption = pipelineContext->GetSyncAnimationOption();
80 pipelineContext->SetSyncAnimationOption(option);
81 // Execute the function.
82 auto ffiCallback = CJLambda::Create(callback);
83 ffiCallback();
84 AceEngine::Get().NotifyContainers([triggerId](const RefPtr<Container>& container) {
85 auto context = container->GetPipelineContext();
86 if (!context) {
87 // pa container do not have pipeline context.
88 return;
89 }
90
91 if (!container->IsFRSCardContainer() && !container->WindowIsShow()) {
92 return;
93 }
94 ContainerScope scope(container->GetInstanceId());
95 context->FlushBuild();
96 if (context->GetInstanceId() == triggerId) {
97 return;
98 }
99 context->PrepareCloseImplicitAnimation();
100 });
101 pipelineContext->CloseImplicitAnimation();
102 pipelineContext->SetSyncAnimationOption(previousOption);
103 if (immediately) {
104 pipelineContext->FlushMessages();
105 } else {
106 pipelineContext->RequestFrame();
107 }
108 }
109
110 extern "C" {
FfiOHOSAceFrameworkViewContextAnimation(NativeOptionAnimateParam animateOptParam)111 void FfiOHOSAceFrameworkViewContextAnimation(NativeOptionAnimateParam animateOptParam)
112 {
113 ACE_FUNCTION_TRACE();
114 if (ViewStackModel::GetInstance()->CheckTopNodeFirstBuilding()) {
115 // the node sets attribute value for the first time. No animation is generated.
116 return;
117 }
118 AnimationOption animateOpt = AnimationOption();
119 auto container = Container::CurrentSafely();
120 CHECK_NULL_VOID(container);
121 auto pipelineContextBase = container->GetPipelineContext();
122 CHECK_NULL_VOID(pipelineContextBase);
123 if (pipelineContextBase->IsFormAnimationFinishCallback() && pipelineContextBase->IsFormRender() &&
124 GetFormAnimationTimeInterval(pipelineContextBase) > DEFAULT_DURATION) {
125 return;
126 }
127
128 NativeAnimateParam animateParam;
129 if (animateOptParam.hasValue) {
130 animateParam = animateOptParam.value;
131 } else {
132 ViewContextModel::GetInstance()->closeAnimation(animateOpt, true);
133 return;
134 }
135 ParseCjAnimation(animateParam, animateOpt);
136 if (pipelineContextBase->IsFormAnimationFinishCallback() && pipelineContextBase->IsFormRender() &&
137 animateOpt.GetDuration() > (DEFAULT_DURATION - GetFormAnimationTimeInterval(pipelineContextBase))) {
138 animateOpt.SetDuration(DEFAULT_DURATION - GetFormAnimationTimeInterval(pipelineContextBase));
139 TAG_LOGW(AceLogTag::ACE_FORM, "[Form animation] Form animation SetDuration: %{public}lld ms",
140 static_cast<long long>(DEFAULT_DURATION - GetFormAnimationTimeInterval(pipelineContextBase)));
141 }
142
143 if (SystemProperties::GetRosenBackendEnabled()) {
144 animateOpt.SetAllowRunningAsynchronously(true);
145 }
146 ViewContextModel::GetInstance()->openAnimation(animateOpt);
147 JankFrameReport::GetInstance().ReportJSAnimation();
148 }
149
FfiOHOSAceFrameworkViewContextAnimationTo(NativeAnimateParam animateParam,void (* callback)(),bool isImmediately)150 void FfiOHOSAceFrameworkViewContextAnimationTo(NativeAnimateParam animateParam, void (*callback)(), bool isImmediately)
151 {
152 ACE_FUNCTION_TRACE();
153 AnimationOption animateOpt;
154 ParseCjAnimation(animateParam, animateOpt);
155 auto container = Container::CurrentSafely();
156 CHECK_NULL_VOID(container);
157 auto pipelineContextBase = container->GetPipelineContext();
158 CHECK_NULL_VOID(pipelineContextBase);
159 if (pipelineContextBase->IsFormAnimationFinishCallback() && pipelineContextBase->IsFormRender() &&
160 GetFormAnimationTimeInterval(pipelineContextBase) > DEFAULT_DURATION) {
161 return;
162 }
163 if (CheckIfSetFormAnimationDuration(pipelineContextBase, animateOpt)) {
164 animateOpt.SetDuration(DEFAULT_DURATION - GetFormAnimationTimeInterval(pipelineContextBase));
165 TAG_LOGW(AceLogTag::ACE_FORM, "[Form animation] Form animation SetDuration: %{public}lld ms",
166 static_cast<long long>(DEFAULT_DURATION - GetFormAnimationTimeInterval(pipelineContextBase)));
167 }
168 if (SystemProperties::GetRosenBackendEnabled()) {
169 if (pipelineContextBase->IsLayouting()) {
170 TAG_LOGW(AceLogTag::ACE_ANIMATION,
171 "pipeline is layouting, post animateTo, duration:%{public}d, curve:%{public}s",
172 animateOpt.GetDuration(), animateOpt.GetCurve() ? animateOpt.GetCurve()->ToString().c_str() : "");
173 pipelineContextBase->GetTaskExecutor()->PostTask(
174 [id = Container::CurrentIdSafely(), animateOpt, callback, isImmediately]() mutable {
175 ContainerScope scope(id);
176 auto container = Container::CurrentSafely();
177 CHECK_NULL_VOID(container);
178 auto pipelineContext = container->GetPipelineContext();
179 CHECK_NULL_VOID(pipelineContext);
180 AnimateToForStageMode(pipelineContext, animateOpt, callback,
181 animateOpt.GetOnFinishEvent(), isImmediately);
182 },
183 TaskExecutor::TaskType::UI, "CJAnimationTo");
184 return;
185 }
186 AnimateToForStageMode(pipelineContextBase, animateOpt, callback, animateOpt.GetOnFinishEvent(), isImmediately);
187 } else {
188 pipelineContextBase->FlushBuild();
189 pipelineContextBase->SaveExplicitAnimationOption(animateOpt);
190 // Execute the function.
191 auto ffiCallback = CJLambda::Create(callback);
192 ffiCallback();
193 pipelineContextBase->FlushBuild();
194 pipelineContextBase->CreateExplicitAnimator(animateOpt.GetOnFinishEvent());
195 pipelineContextBase->ClearExplicitAnimationOption();
196 }
197 }
198 }
199 }