1 /*
2 * Copyright (c) 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/pipeline_ng/pipeline_context.h"
17
18 #include "base/memory/ace_type.h"
19 #include "core/components_ng/base/ui_node.h"
20 #include "core/components_ng/pattern/image/image_layout_property.h"
21 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
22 #include "core/components_ng/pattern/navigation/title_bar_node.h"
23 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
24
25 #ifdef ENABLE_ROSEN_BACKEND
26 #include "render_service_client/core/ui/rs_ui_director.h"
27
28 #include "core/components_ng/render/adapter/rosen_window.h"
29 #endif
30
31 #include <algorithm>
32 #include <cinttypes>
33 #include <cstdint>
34 #include <memory>
35
36 #include "base/geometry/ng/offset_t.h"
37 #include "base/log/ace_trace.h"
38 #include "base/log/ace_tracker.h"
39 #include "base/log/event_report.h"
40 #include "base/log/frame_report.h"
41 #include "base/memory/referenced.h"
42 #include "base/thread/task_executor.h"
43 #include "base/utils/utils.h"
44 #include "core/animation/scheduler.h"
45 #include "core/common/ace_application_info.h"
46 #include "core/common/container.h"
47 #include "core/common/layout_inspector.h"
48 #include "core/common/text_field_manager.h"
49 #include "core/common/thread_checker.h"
50 #include "core/common/window.h"
51 #include "core/components/common/layout/grid_system_manager.h"
52 #include "core/components_ng/base/frame_node.h"
53 #include "core/components_ng/pattern/app_bar/app_bar_view.h"
54 #include "core/components_ng/pattern/container_modal/container_modal_pattern.h"
55 #include "core/components_ng/pattern/container_modal/container_modal_view.h"
56 #include "core/components_ng/pattern/custom/custom_node_base.h"
57 #include "core/components_ng/pattern/overlay/overlay_manager.h"
58 #include "core/components_ng/pattern/root/root_pattern.h"
59 #include "core/components_ng/pattern/stage/stage_pattern.h"
60 #include "core/components_ng/pattern/text_field/text_field_manager.h"
61 #include "core/components_ng/property/calc_length.h"
62 #include "core/components_v2/inspector/inspector_constants.h"
63 #include "core/event/ace_events.h"
64 #include "core/event/touch_event.h"
65 #include "core/pipeline/base/element_register.h"
66 #include "core/pipeline/pipeline_context.h"
67 #include "core/pipeline_ng/ui_task_scheduler.h"
68
69 namespace {
70 constexpr int32_t TIME_THRESHOLD = 2 * 1000000; // 3 millisecond
71 } // namespace
72
73 namespace OHOS::Ace::NG {
74
PipelineContext(std::unique_ptr<Window> window,RefPtr<TaskExecutor> taskExecutor,RefPtr<AssetManager> assetManager,RefPtr<PlatformResRegister> platformResRegister,const RefPtr<Frontend> & frontend,int32_t instanceId)75 PipelineContext::PipelineContext(std::unique_ptr<Window> window, RefPtr<TaskExecutor> taskExecutor,
76 RefPtr<AssetManager> assetManager, RefPtr<PlatformResRegister> platformResRegister,
77 const RefPtr<Frontend>& frontend, int32_t instanceId)
78 : PipelineBase(std::move(window), std::move(taskExecutor), std::move(assetManager), frontend, instanceId)
79 {
80 window_->OnHide();
81 }
82
PipelineContext(std::unique_ptr<Window> window,RefPtr<TaskExecutor> taskExecutor,RefPtr<AssetManager> assetManager,const RefPtr<Frontend> & frontend,int32_t instanceId)83 PipelineContext::PipelineContext(std::unique_ptr<Window> window, RefPtr<TaskExecutor> taskExecutor,
84 RefPtr<AssetManager> assetManager, const RefPtr<Frontend>& frontend, int32_t instanceId)
85 : PipelineBase(std::move(window), std::move(taskExecutor), std::move(assetManager), frontend, instanceId)
86 {
87 window_->OnHide();
88 }
89
GetCurrentContext()90 RefPtr<PipelineContext> PipelineContext::GetCurrentContext()
91 {
92 auto currentContainer = Container::Current();
93 CHECK_NULL_RETURN(currentContainer, nullptr);
94 return DynamicCast<PipelineContext>(currentContainer->GetPipelineContext());
95 }
96
GetCurrentRootWidth()97 float PipelineContext::GetCurrentRootWidth()
98 {
99 auto context = GetCurrentContext();
100 CHECK_NULL_RETURN(context, 0.0f);
101 return static_cast<float>(context->rootWidth_);
102 }
103
GetCurrentRootHeight()104 float PipelineContext::GetCurrentRootHeight()
105 {
106 auto context = GetCurrentContext();
107 CHECK_NULL_RETURN(context, 0.0f);
108 return static_cast<float>(context->rootHeight_);
109 }
110
AddDirtyCustomNode(const RefPtr<UINode> & dirtyNode)111 void PipelineContext::AddDirtyCustomNode(const RefPtr<UINode>& dirtyNode)
112 {
113 CHECK_RUN_ON(UI);
114 CHECK_NULL_VOID(dirtyNode);
115 dirtyNodes_.emplace(dirtyNode);
116 hasIdleTasks_ = true;
117 window_->RequestFrame();
118 }
119
AddDirtyLayoutNode(const RefPtr<FrameNode> & dirty)120 void PipelineContext::AddDirtyLayoutNode(const RefPtr<FrameNode>& dirty)
121 {
122 CHECK_RUN_ON(UI);
123 CHECK_NULL_VOID(dirty);
124 taskScheduler_.AddDirtyLayoutNode(dirty);
125 ForceLayoutForImplicitAnimation();
126 hasIdleTasks_ = true;
127 window_->RequestFrame();
128 }
129
AddDirtyRenderNode(const RefPtr<FrameNode> & dirty)130 void PipelineContext::AddDirtyRenderNode(const RefPtr<FrameNode>& dirty)
131 {
132 CHECK_RUN_ON(UI);
133 CHECK_NULL_VOID(dirty);
134 taskScheduler_.AddDirtyRenderNode(dirty);
135 hasIdleTasks_ = true;
136 window_->RequestFrame();
137 }
138
FlushDirtyNodeUpdate()139 void PipelineContext::FlushDirtyNodeUpdate()
140 {
141 CHECK_RUN_ON(UI);
142 ACE_FUNCTION_TRACE();
143 if (FrameReport::GetInstance().GetEnable()) {
144 FrameReport::GetInstance().BeginFlushBuild();
145 }
146
147 // SomeTimes, customNode->Update may add some dirty custom nodes to dirtyNodes_,
148 // use maxFlushTimes to avoid dead cycle.
149 int maxFlushTimes = 3;
150 while (!dirtyNodes_.empty() && maxFlushTimes > 0) {
151 decltype(dirtyNodes_) dirtyNodes(std::move(dirtyNodes_));
152 for (const auto& node : dirtyNodes) {
153 if (AceType::InstanceOf<NG::CustomNodeBase>(node)) {
154 auto customNode = AceType::DynamicCast<NG::CustomNodeBase>(node);
155 customNode->Update();
156 }
157 }
158 --maxFlushTimes;
159 }
160 if (!dirtyNodes_.empty()) {
161 LOGW("FlushDirtyNodeUpdate 3 times, still has dirty nodes");
162 }
163
164 if (FrameReport::GetInstance().GetEnable()) {
165 FrameReport::GetInstance().EndFlushBuild();
166 }
167 }
168
AddScheduleTask(const RefPtr<ScheduleTask> & task)169 uint32_t PipelineContext::AddScheduleTask(const RefPtr<ScheduleTask>& task)
170 {
171 CHECK_RUN_ON(UI);
172 scheduleTasks_.try_emplace(++nextScheduleTaskId_, task);
173 window_->RequestFrame();
174 return nextScheduleTaskId_;
175 }
176
FlushVsync(uint64_t nanoTimestamp,uint32_t frameCount)177 void PipelineContext::FlushVsync(uint64_t nanoTimestamp, uint32_t frameCount)
178 {
179 CHECK_RUN_ON(UI);
180 ACE_FUNCTION_TRACE();
181 static const std::string abilityName = AceApplicationInfo::GetInstance().GetProcessName().empty()
182 ? AceApplicationInfo::GetInstance().GetPackageName()
183 : AceApplicationInfo::GetInstance().GetProcessName();
184 window_->RecordFrameTime(nanoTimestamp, abilityName);
185 FlushAnimation(GetTimeFromExternalTimer());
186 FlushBuild();
187 if (isFormRender_ && drawDelegate_ && rootNode_) {
188 auto renderContext = AceType::DynamicCast<NG::RenderContext>(rootNode_->GetRenderContext());
189 drawDelegate_->DrawRSFrame(renderContext);
190 drawDelegate_ = nullptr;
191 }
192 FlushTouchEvents();
193 if (!taskScheduler_.isEmpty()) {
194 #if !defined(PREVIEW)
195 LayoutInspector::SupportInspector();
196 #endif
197 }
198 taskScheduler_.FlushTask();
199 TryCallNextFrameLayoutCallback();
200 auto hasAninmation = window_->FlushCustomAnimation(nanoTimestamp);
201 if (hasAninmation) {
202 RequestFrame();
203 }
204 FlushMessages();
205 if (!isFormRender_ && onShow_ && onFocus_) {
206 FlushFocus();
207 }
208 HandleOnAreaChangeEvent();
209 HandleVisibleAreaChangeEvent();
210 }
211
FlushAnimation(uint64_t nanoTimestamp)212 void PipelineContext::FlushAnimation(uint64_t nanoTimestamp)
213 {
214 CHECK_RUN_ON(UI);
215 ACE_FUNCTION_TRACE();
216 if (scheduleTasks_.empty()) {
217 return;
218 }
219
220 if (FrameReport::GetInstance().GetEnable()) {
221 FrameReport::GetInstance().BeginFlushAnimation();
222 }
223
224 decltype(scheduleTasks_) temp(std::move(scheduleTasks_));
225 for (const auto& [id, weakTask] : temp) {
226 auto task = weakTask.Upgrade();
227 if (task) {
228 task->OnFrame(nanoTimestamp);
229 }
230 }
231
232 if (FrameReport::GetInstance().GetEnable()) {
233 FrameReport::GetInstance().EndFlushAnimation();
234 }
235 }
236
FlushMessages()237 void PipelineContext::FlushMessages()
238 {
239 ACE_FUNCTION_TRACE();
240 window_->FlushTasks();
241 }
242
FlushFocus()243 void PipelineContext::FlushFocus()
244 {
245 CHECK_RUN_ON(UI);
246 ACE_FUNCTION_TRACK();
247 ACE_FUNCTION_TRACE();
248 auto focusNode = dirtyFocusNode_.Upgrade();
249 if (!focusNode || focusNode->GetFocusType() != FocusType::NODE) {
250 dirtyFocusNode_.Reset();
251 } else {
252 auto focusNodeHub = focusNode->GetFocusHub();
253 if (focusNodeHub) {
254 focusNodeHub->RequestFocusImmediately();
255 }
256 dirtyFocusNode_.Reset();
257 dirtyFocusScope_.Reset();
258 return;
259 }
260 auto focusScope = dirtyFocusScope_.Upgrade();
261 if (!focusScope || focusScope->GetFocusType() != FocusType::SCOPE) {
262 dirtyFocusScope_.Reset();
263 } else {
264 auto focusScopeHub = focusScope->GetFocusHub();
265 if (focusScopeHub) {
266 focusScopeHub->RequestFocusImmediately();
267 }
268 dirtyFocusNode_.Reset();
269 dirtyFocusScope_.Reset();
270 return;
271 }
272 if (!RequestDefaultFocus()) {
273 if (rootNode_ && rootNode_->GetFocusHub() && !rootNode_->GetFocusHub()->IsCurrentFocus()) {
274 rootNode_->GetFocusHub()->RequestFocusImmediately();
275 }
276 }
277 }
278
FlushPipelineImmediately()279 void PipelineContext::FlushPipelineImmediately()
280 {
281 CHECK_RUN_ON(UI);
282 ACE_FUNCTION_TRACE();
283 FlushPipelineWithoutAnimation();
284 }
285
FlushPipelineWithoutAnimation()286 void PipelineContext::FlushPipelineWithoutAnimation()
287 {
288 FlushBuild();
289 FlushTouchEvents();
290 taskScheduler_.FlushTask();
291 FlushMessages();
292 FlushFocus();
293 }
294
FlushBuild()295 void PipelineContext::FlushBuild()
296 {
297 isRebuildFinished_ = false;
298 FlushDirtyNodeUpdate();
299 isRebuildFinished_ = true;
300 FlushBuildFinishCallbacks();
301 }
302
FlushBuildFinishCallbacks()303 void PipelineContext::FlushBuildFinishCallbacks()
304 {
305 decltype(buildFinishCallbacks_) buildFinishCallbacks(std::move(buildFinishCallbacks_));
306 for (const auto& func : buildFinishCallbacks) {
307 if (func) {
308 func();
309 }
310 }
311 }
312
RegisterRootEvent()313 void PipelineContext::RegisterRootEvent()
314 {
315 if (!IsFormRender()) {
316 return;
317 }
318
319 // To avoid conflicts between longPress and click events on the card,
320 // use an empty longPress event placeholder in the EtsCard scenario
321 auto hub = rootNode_->GetOrCreateGestureEventHub();
322 CHECK_NULL_VOID(hub);
323 auto event = [](const GestureEvent& info) mutable {
324 LOGD("Not Support LongPress");
325 };
326 auto longPress = AceType::MakeRefPtr<NG::LongPressEvent>(std::move(event));
327 hub->SetLongPressEvent(longPress, false, true);
328 }
329
SetupRootElement()330 void PipelineContext::SetupRootElement()
331 {
332 CHECK_RUN_ON(UI);
333 rootNode_ = FrameNode::CreateFrameNodeWithTree(
334 V2::ROOT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<RootPattern>());
335 rootNode_->SetHostRootId(GetInstanceId());
336 rootNode_->SetHostPageId(-1);
337 RegisterRootEvent();
338 CalcSize idealSize { CalcLength(rootWidth_), CalcLength(rootHeight_) };
339 MeasureProperty layoutConstraint;
340 layoutConstraint.selfIdealSize = idealSize;
341 layoutConstraint.maxSize = idealSize;
342 rootNode_->UpdateLayoutConstraint(layoutConstraint);
343 auto rootFocusHub = rootNode_->GetOrCreateFocusHub();
344 rootFocusHub->SetFocusType(FocusType::SCOPE);
345 rootFocusHub->SetFocusable(true);
346 window_->SetRootFrameNode(rootNode_);
347 rootNode_->AttachToMainTree();
348
349 auto stageNode = FrameNode::CreateFrameNode(
350 V2::STAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<StagePattern>());
351 auto appBarNode = installationFree_ ? AppBarView::Create(stageNode) : nullptr;
352 if (windowModal_ == WindowModal::CONTAINER_MODAL) {
353 rootNode_->AddChild(ContainerModalView::Create(appBarNode ? appBarNode : stageNode));
354 } else {
355 rootNode_->AddChild(appBarNode ? appBarNode : stageNode);
356 }
357 #ifdef ENABLE_ROSEN_BACKEND
358 if (!IsJsCard() && !isFormRender_) {
359 auto rsWindow = static_cast<RosenWindow*>(GetWindow());
360 if (rsWindow) {
361 auto rsUIDirector = rsWindow->GetRsUIDirector();
362 if (rsUIDirector) {
363 rsUIDirector->SetAbilityBGAlpha(appBgColor_.GetAlpha());
364 }
365 }
366 }
367 #endif
368 stageManager_ = MakeRefPtr<StageManager>(stageNode);
369 overlayManager_ = MakeRefPtr<OverlayManager>(
370 DynamicCast<FrameNode>(installationFree_ ? stageNode->GetParent()->GetParent() : stageNode->GetParent()));
371 fullScreenManager_ = MakeRefPtr<FullScreenManager>(rootNode_);
372 selectOverlayManager_ = MakeRefPtr<SelectOverlayManager>(rootNode_);
373 dragDropManager_ = MakeRefPtr<DragDropManager>();
374 sharedTransitionManager_ = MakeRefPtr<SharedOverlayManager>(
375 DynamicCast<FrameNode>(installationFree_ ? stageNode->GetParent()->GetParent() : stageNode->GetParent()));
376
377 OnAreaChangedFunc onAreaChangedFunc = [weakOverlayManger = AceType::WeakClaim(AceType::RawPtr(overlayManager_))](
378 const RectF& /* oldRect */, const OffsetF& /* oldOrigin */,
379 const RectF& /* rect */, const OffsetF& /* origin */) {
380 auto overlay = weakOverlayManger.Upgrade();
381 CHECK_NULL_VOID(overlay);
382 overlay->HideAllMenus();
383 overlay->HideAllPopups();
384 };
385 rootNode_->SetOnAreaChangeCallback(std::move(onAreaChangedFunc));
386 AddOnAreaChangeNode(rootNode_->GetId());
387
388 LOGI("SetupRootElement success!");
389 }
390
SetupSubRootElement()391 void PipelineContext::SetupSubRootElement()
392 {
393 CHECK_RUN_ON(UI);
394 appBgColor_ = Color::TRANSPARENT;
395 rootNode_ = FrameNode::CreateFrameNodeWithTree(
396 V2::ROOT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<RootPattern>());
397 rootNode_->SetHostRootId(GetInstanceId());
398 rootNode_->SetHostPageId(-1);
399 CalcSize idealSize { CalcLength(rootWidth_), CalcLength(rootHeight_) };
400 MeasureProperty layoutConstraint;
401 layoutConstraint.selfIdealSize = idealSize;
402 layoutConstraint.maxSize = idealSize;
403 rootNode_->UpdateLayoutConstraint(layoutConstraint);
404 auto rootFocusHub = rootNode_->GetOrCreateFocusHub();
405 rootFocusHub->SetFocusType(FocusType::SCOPE);
406 rootFocusHub->SetFocusable(true);
407 window_->SetRootFrameNode(rootNode_);
408 rootNode_->AttachToMainTree();
409
410 #ifdef ENABLE_ROSEN_BACKEND
411 if (!IsJsCard()) {
412 auto rsWindow = static_cast<RosenWindow*>(GetWindow());
413 if (rsWindow) {
414 auto rsUIDirector = rsWindow->GetRsUIDirector();
415 if (rsUIDirector) {
416 rsUIDirector->SetAbilityBGAlpha(appBgColor_.GetAlpha());
417 }
418 }
419 }
420 #endif
421 // the subwindow for overlay not need stage
422 stageManager_ = MakeRefPtr<StageManager>(nullptr);
423 overlayManager_ = MakeRefPtr<OverlayManager>(rootNode_);
424 fullScreenManager_ = MakeRefPtr<FullScreenManager>(rootNode_);
425 selectOverlayManager_ = MakeRefPtr<SelectOverlayManager>(rootNode_);
426 dragDropManager_ = MakeRefPtr<DragDropManager>();
427 }
428
GetStageManager()429 const RefPtr<StageManager>& PipelineContext::GetStageManager()
430 {
431 return stageManager_;
432 }
433
GetDragDropManager()434 const RefPtr<DragDropManager>& PipelineContext::GetDragDropManager()
435 {
436 return dragDropManager_;
437 }
438
GetSelectOverlayManager()439 const RefPtr<SelectOverlayManager>& PipelineContext::GetSelectOverlayManager()
440 {
441 return selectOverlayManager_;
442 }
443
GetOverlayManager()444 const RefPtr<OverlayManager>& PipelineContext::GetOverlayManager()
445 {
446 return overlayManager_;
447 }
448
GetFullScreenManager()449 const RefPtr<FullScreenManager>& PipelineContext::GetFullScreenManager()
450 {
451 return fullScreenManager_;
452 }
453
OnSurfaceChanged(int32_t width,int32_t height,WindowSizeChangeReason type)454 void PipelineContext::OnSurfaceChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
455 {
456 CHECK_RUN_ON(UI);
457 LOGD("PipelineContext: OnSurfaceChanged start.");
458 if (NearEqual(rootWidth_, width) && NearEqual(rootHeight_, height) &&
459 type == WindowSizeChangeReason::CUSTOM_ANIMATION) {
460 TryCallNextFrameLayoutCallback();
461 return;
462 }
463 ExecuteSurfaceChangedCallbacks(width, height);
464 // TODO: add adjust for textFieldManager when ime is show.
465 taskExecutor_->PostTask(
466 [weakFrontend = weakFrontend_, width, height]() {
467 auto frontend = weakFrontend.Upgrade();
468 if (frontend) {
469 frontend->OnSurfaceChanged(width, height);
470 }
471 },
472 TaskExecutor::TaskType::JS);
473
474 #ifdef ENABLE_ROSEN_BACKEND
475 StartWindowSizeChangeAnimate(width, height, type);
476 #else
477 SetRootRect(width, height, 0.0);
478 #endif
479 }
480
ExecuteSurfaceChangedCallbacks(int32_t newWidth,int32_t newHeight)481 void PipelineContext::ExecuteSurfaceChangedCallbacks(int32_t newWidth, int32_t newHeight)
482 {
483 for (auto&& [id, callback] : surfaceChangedCallbackMap_) {
484 if (callback) {
485 callback(newWidth, newHeight, rootWidth_, rootHeight_);
486 }
487 }
488 }
489
OnSurfacePositionChanged(int32_t posX,int32_t posY)490 void PipelineContext::OnSurfacePositionChanged(int32_t posX, int32_t posY)
491 {
492 for (auto&& [id, callback] : surfacePositionChangedCallbackMap_) {
493 if (callback) {
494 callback(posX, posY);
495 }
496 }
497 }
498
StartWindowSizeChangeAnimate(int32_t width,int32_t height,WindowSizeChangeReason type)499 void PipelineContext::StartWindowSizeChangeAnimate(int32_t width, int32_t height, WindowSizeChangeReason type)
500 {
501 static const bool IsWindowSizeAnimationEnabled = SystemProperties::IsWindowSizeAnimationEnabled();
502 if (!IsWindowSizeAnimationEnabled) {
503 LOGE("no animation configured");
504 SetRootRect(width, height, 0.0);
505 return;
506 }
507 switch (type) {
508 case WindowSizeChangeReason::RECOVER:
509 case WindowSizeChangeReason::MAXIMIZE: {
510 LOGI("PipelineContext::Root node RECOVER/MAXIMIZE animation, width = %{public}d, height = %{public}d",
511 width, height);
512 AnimationOption option;
513 constexpr int32_t duration = 400;
514 option.SetDuration(duration);
515 auto curve = MakeRefPtr<DecelerationCurve>();
516 option.SetCurve(curve);
517 auto weak = WeakClaim(this);
518 Animate(option, curve, [width, height, weak]() {
519 auto pipeline = weak.Upgrade();
520 CHECK_NULL_VOID(pipeline);
521 pipeline->SetRootRect(width, height, 0.0);
522 pipeline->FlushUITasks();
523 });
524 break;
525 }
526 case WindowSizeChangeReason::ROTATION: {
527 LOGI("PipelineContext::Root node ROTATION animation, width = %{public}d, height = %{public}d", width,
528 height);
529 AnimationOption option;
530 constexpr int32_t duration = 600;
531 option.SetDuration(duration);
532 auto curve = MakeRefPtr<CubicCurve>(0.2, 0.0, 0.2, 1.0); // animation curve: cubic [0.2, 0.0, 0.2, 1.0]
533 option.SetCurve(curve);
534 auto weak = WeakClaim(this);
535 Animate(
536 option, curve,
537 [width, height, weak]() {
538 auto pipeline = weak.Upgrade();
539 CHECK_NULL_VOID(pipeline);
540 pipeline->SetRootRect(width, height, 0.0);
541 pipeline->FlushUITasks();
542 },
543 [weak]() {
544 auto pipeline = weak.Upgrade();
545 CHECK_NULL_VOID(pipeline);
546 pipeline->rotationAnimationCount_--;
547 if (pipeline->rotationAnimationCount_ < 0) {
548 LOGE("PipelineContext::Root node ROTATION animation callback"
549 "rotationAnimationCount Invalid %{public}d",
550 pipeline->rotationAnimationCount_);
551 }
552 if (pipeline->rotationAnimationCount_ == 0) {
553 pipeline->window_->SetDrawTextAsBitmap(false);
554 }
555 });
556 rotationAnimationCount_++;
557 window_->SetDrawTextAsBitmap(true);
558 break;
559 }
560 case WindowSizeChangeReason::DRAG_START:
561 case WindowSizeChangeReason::DRAG:
562 case WindowSizeChangeReason::DRAG_END:
563 case WindowSizeChangeReason::RESIZE:
564 case WindowSizeChangeReason::UNDEFINED:
565 default: {
566 LOGD("PipelineContext::RootNodeAnimation : unsupported type, no animation added");
567 SetRootRect(width, height, 0.0f);
568 }
569 }
570 }
571
SetRootRect(double width,double height,double offset)572 void PipelineContext::SetRootRect(double width, double height, double offset)
573 {
574 LOGI("SetRootRect width %{public}f, height %{public}f, %{public}f", width, height, offset);
575 CHECK_RUN_ON(UI);
576 UpdateRootSizeAndScale(width, height);
577 CHECK_NULL_VOID(rootNode_);
578 GridSystemManager::GetInstance().SetWindowInfo(rootWidth_, density_, dipScale_);
579 GridSystemManager::GetInstance().OnSurfaceChanged(width);
580 SizeF sizeF { static_cast<float>(width), static_cast<float>(height) };
581 if (rootNode_->GetGeometryNode()->GetFrameSize() != sizeF || rootNode_->IsLayoutDirtyMarked()) {
582 CalcSize idealSize { CalcLength(width), CalcLength(height) };
583 MeasureProperty layoutConstraint;
584 layoutConstraint.selfIdealSize = idealSize;
585 layoutConstraint.maxSize = idealSize;
586 rootNode_->UpdateLayoutConstraint(layoutConstraint);
587 // reset parentLayoutConstraint to update itself when next measure task
588 rootNode_->GetGeometryNode()->ResetParentLayoutConstraint();
589 rootNode_->MarkDirtyNode();
590 }
591 if (rootNode_->GetGeometryNode()->GetFrameOffset().GetY() != offset) {
592 OffsetF newOffset = rootNode_->GetGeometryNode()->GetFrameOffset();
593 newOffset.SetY(static_cast<float>(offset));
594 rootNode_->GetGeometryNode()->SetMarginFrameOffset(newOffset);
595 auto rootContext = rootNode_->GetRenderContext();
596 rootContext->SyncGeometryProperties(RawPtr(rootNode_->GetGeometryNode()));
597 RequestFrame();
598 }
599 }
600
OnVirtualKeyboardHeightChange(float keyboardHeight)601 void PipelineContext::OnVirtualKeyboardHeightChange(float keyboardHeight)
602 {
603 CHECK_RUN_ON(UI);
604 float positionY = 0;
605 auto manager = DynamicCast<TextFieldManagerNG>(PipelineBase::GetTextFieldManager());
606 float height = 0.0f;
607 if (manager) {
608 height = manager->GetHeight();
609 positionY = static_cast<float>(manager->GetClickPosition().GetY());
610 }
611 SizeF rootSize { static_cast<float>(rootWidth_), static_cast<float>(rootHeight_) };
612 float offsetFix = (rootSize.Height() - positionY) > 100.0 ? keyboardHeight - (rootSize.Height() - positionY) / 2.0
613 : keyboardHeight;
614 LOGI("OnVirtualKeyboardAreaChange positionY:%{public}f safeArea:%{public}f offsetFix:%{public}f, "
615 "keyboardHeight %{public}f",
616 positionY, (rootSize.Height() - keyboardHeight), offsetFix, keyboardHeight);
617 if (NearZero(keyboardHeight)) {
618 SetRootRect(rootSize.Width(), rootSize.Height(), 0);
619 } else if (LessOrEqual(rootSize.Height() - positionY - height, height)) {
620 SetRootRect(rootSize.Width(), rootSize.Height(), -keyboardHeight);
621 } else if (positionY + height > (rootSize.Height() - keyboardHeight) && offsetFix > 0.0) {
622 SetRootRect(rootSize.Width(), rootSize.Height(), -offsetFix);
623 } else if ((positionY + height > rootSize.Height() - keyboardHeight &&
624 positionY < rootSize.Height() - keyboardHeight && height < keyboardHeight / 2.0f) &&
625 NearZero(rootNode_->GetGeometryNode()->GetFrameOffset().GetY())) {
626 SetRootRect(rootSize.Width(), rootSize.Height(), -height - offsetFix / 2.0f);
627 }
628 }
629
OnBackPressed()630 bool PipelineContext::OnBackPressed()
631 {
632 LOGD("OnBackPressed");
633 CHECK_RUN_ON(PLATFORM);
634 auto frontend = weakFrontend_.Upgrade();
635 if (!frontend) {
636 // return back.
637 return false;
638 }
639
640 // If the tag of the last child of the rootnode is video, exit full screen.
641 if (fullScreenManager_->OnBackPressed()) {
642 LOGI("Exit full screen: back press accepted");
643 return true;
644 }
645
646 // if has sharedTransition, back press will stop the sharedTransition
647 if (sharedTransitionManager_->OnBackPressed()) {
648 LOGI("sharedTransition stop: back press accepted");
649 return true;
650 }
651
652 // if has popup, back press would hide popup and not trigger page back
653 auto hasOverlay = false;
654 taskExecutor_->PostSyncTask(
655 [weakOverlay = AceType::WeakClaim(AceType::RawPtr(overlayManager_)), &hasOverlay]() {
656 auto overlay = weakOverlay.Upgrade();
657 CHECK_NULL_VOID_NOLOG(overlay);
658 hasOverlay = overlay->RemoveOverlay();
659 },
660 TaskExecutor::TaskType::UI);
661 if (hasOverlay) {
662 LOGI("popup hidden: back press accepted");
663 return true;
664 }
665
666 auto result = false;
667 taskExecutor_->PostSyncTask(
668 [weakFrontend = weakFrontend_, weakPipelineContext = WeakClaim(this), &result]() {
669 auto frontend = weakFrontend.Upgrade();
670 if (!frontend) {
671 LOGW("frontend is nullptr");
672 result = false;
673 return;
674 }
675 auto context = weakPipelineContext.Upgrade();
676 if (!context) {
677 LOGW("pipelineContext is nullptr");
678 result = false;
679 return;
680 }
681 if (context->GetNavDestinationBackButtonNode()) {
682 auto navDestinationNode =
683 AceType::DynamicCast<NavDestinationGroupNode>(context->GetNavDestinationBackButtonNode());
684 if (navDestinationNode->GetNavDestinationBackButtonEvent()) {
685 GestureEvent gestureEvent;
686 navDestinationNode->GetNavDestinationBackButtonEvent()(gestureEvent);
687 result = true;
688 }
689 }
690 },
691 TaskExecutor::TaskType::UI);
692
693 if (result) {
694 // user accept
695 LOGI("CallRouterBackToPopPage(): frontend accept");
696 return true;
697 }
698
699 taskExecutor_->PostSyncTask(
700 [weakFrontend = weakFrontend_, weakPipelineContext = WeakClaim(this), &result]() {
701 auto frontend = weakFrontend.Upgrade();
702 if (!frontend) {
703 LOGW("frontend is nullptr");
704 result = false;
705 return;
706 }
707 result = frontend->OnBackPressed();
708 },
709 TaskExecutor::TaskType::JS);
710
711 if (result) {
712 // user accept
713 LOGI("CallRouterBackToPopPage(): frontend accept");
714 return true;
715 }
716 LOGI("CallRouterBackToPopPage(): return platform consumed");
717 return false;
718 }
719
GetNavDestinationBackButtonNode()720 RefPtr<FrameNode> PipelineContext::GetNavDestinationBackButtonNode()
721 {
722 auto lastPage = stageManager_->GetLastPage();
723 CHECK_NULL_RETURN(lastPage, nullptr);
724 auto navigationNode = lastPage->FindChildNodeOfClass<NavigationGroupNode>();
725 CHECK_NULL_RETURN(navigationNode, nullptr);
726 auto navigationContentNode = navigationNode->GetContentNode();
727 CHECK_NULL_RETURN(navigationContentNode, nullptr);
728 auto navDestinationNode = navigationContentNode->FindChildNodeOfClass<NavDestinationGroupNode>();
729 CHECK_NULL_RETURN(navDestinationNode, nullptr);
730 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationNode->GetTitleBarNode());
731 CHECK_NULL_RETURN(titleBarNode, nullptr);
732 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
733 CHECK_NULL_RETURN(backButtonNode, nullptr);
734 auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty<ImageLayoutProperty>();
735 if (!backButtonLayoutProperty->HasVisibility()) {
736 return nullptr;
737 }
738
739 if (backButtonLayoutProperty->GetVisibilityValue() != VisibleType::VISIBLE) {
740 return nullptr;
741 }
742 return navDestinationNode;
743 }
744
OnTouchEvent(const TouchEvent & point,bool isSubPipe)745 void PipelineContext::OnTouchEvent(const TouchEvent& point, bool isSubPipe)
746 {
747 CHECK_RUN_ON(UI);
748 HandleEtsCardTouchEvent(point);
749 auto scalePoint = point.CreateScalePoint(GetViewScale());
750 LOGD("AceTouchEvent: x = %{public}f, y = %{public}f, type = %{public}zu", scalePoint.x, scalePoint.y,
751 scalePoint.type);
752 eventManager_->SetInstanceId(GetInstanceId());
753 if (scalePoint.type == TouchType::DOWN) {
754 isNeedShowFocus_ = false;
755 CHECK_NULL_VOID_NOLOG(rootNode_);
756 auto rootFocusHub = rootNode_->GetFocusHub();
757 if (rootFocusHub) {
758 rootFocusHub->ClearAllFocusState();
759 }
760
761 LOGD("receive touch down event, first use touch test to collect touch event target");
762 TouchRestrict touchRestrict { TouchRestrict::NONE };
763 touchRestrict.sourceType = point.sourceType;
764 touchRestrict.touchEvent = point;
765 eventManager_->TouchTest(scalePoint, rootNode_, touchRestrict, GetPluginEventOffset(), viewScale_, isSubPipe);
766
767 for (const auto& weakContext : touchPluginPipelineContext_) {
768 auto pipelineContext = DynamicCast<OHOS::Ace::PipelineBase>(weakContext.Upgrade());
769 if (!pipelineContext) {
770 continue;
771 }
772 auto pluginPoint =
773 point.UpdateScalePoint(viewScale_, static_cast<float>(pipelineContext->GetPluginEventOffset().GetX()),
774 static_cast<float>(pipelineContext->GetPluginEventOffset().GetY()), point.id);
775 // eventManager_ instance Id may changed.
776 pipelineContext->OnTouchEvent(pluginPoint, true);
777 }
778
779 // restore instance Id.
780 eventManager_->SetInstanceId(GetInstanceId());
781 }
782 if (isSubPipe) {
783 return;
784 }
785
786 if (scalePoint.type == TouchType::MOVE) {
787 touchEvents_.emplace_back(point);
788 hasIdleTasks_ = true;
789 window_->RequestFrame();
790 return;
791 }
792
793 std::optional<TouchEvent> lastMoveEvent;
794 if (scalePoint.type == TouchType::UP && !touchEvents_.empty()) {
795 for (auto iter = touchEvents_.begin(); iter != touchEvents_.end(); ++iter) {
796 auto movePoint = (*iter).CreateScalePoint(GetViewScale());
797 if (scalePoint.id == movePoint.id) {
798 lastMoveEvent = movePoint;
799 touchEvents_.erase(iter++);
800 }
801 }
802 if (lastMoveEvent.has_value()) {
803 eventManager_->DispatchTouchEvent(lastMoveEvent.value());
804 }
805 }
806
807 eventManager_->DispatchTouchEvent(scalePoint);
808
809 if ((scalePoint.type == TouchType::UP) || (scalePoint.type == TouchType::CANCEL)) {
810 // need to reset touchPluginPipelineContext_ for next touch down event.
811 touchPluginPipelineContext_.clear();
812 RemoveEtsCardTouchEventCallback(point.id);
813 }
814
815 hasIdleTasks_ = true;
816 window_->RequestFrame();
817 }
818
OnSurfaceDensityChanged(double density)819 void PipelineContext::OnSurfaceDensityChanged(double density)
820 {
821 CHECK_RUN_ON(UI);
822 LOGI("OnSurfaceDensityChanged density_(%{public}lf)", density_);
823 LOGI("OnSurfaceDensityChanged dipScale_(%{public}lf)", dipScale_);
824 density_ = density;
825 if (!NearZero(viewScale_)) {
826 LOGI("OnSurfaceDensityChanged viewScale_(%{public}lf)", viewScale_);
827 dipScale_ = density_ / viewScale_;
828 }
829 }
830
OnDumpInfo(const std::vector<std::string> & params) const831 bool PipelineContext::OnDumpInfo(const std::vector<std::string>& params) const
832 {
833 ACE_DCHECK(!params.empty());
834
835 if (params[0] == "-element") {
836 if (params.size() > 1 && params[1] == "-lastpage") {
837 auto lastPage = stageManager_->GetLastPage();
838 if (lastPage) {
839 lastPage->DumpTree(0);
840 }
841 } else {
842 rootNode_->DumpTree(0);
843 }
844 } else if (params[0] == "-render") {
845 } else if (params[0] == "-focus") {
846 if (rootNode_->GetFocusHub()) {
847 rootNode_->GetFocusHub()->DumpFocusTree(0);
848 }
849 } else if (params[0] == "-layer") {
850 } else if (params[0] == "-frontend") {
851 #ifndef WEARABLE_PRODUCT
852 } else if (params[0] == "-multimodal") {
853 #endif
854 } else if (params[0] == "-accessibility" || params[0] == "-inspector") {
855 auto accessibilityManager = GetAccessibilityManager();
856 if (accessibilityManager) {
857 accessibilityManager->OnDumpInfo(params);
858 }
859 } else if (params[0] == "-rotation" && params.size() >= 2) {
860 } else if (params[0] == "-animationscale" && params.size() >= 2) {
861 } else if (params[0] == "-velocityscale" && params.size() >= 2) {
862 } else if (params[0] == "-scrollfriction" && params.size() >= 2) {
863 } else if (params[0] == "-threadstuck" && params.size() >= 3) {
864 } else {
865 return false;
866 }
867 return true;
868 }
869
FlushTouchEvents()870 void PipelineContext::FlushTouchEvents()
871 {
872 CHECK_RUN_ON(UI);
873 CHECK_NULL_VOID(rootNode_);
874 {
875 eventManager_->FlushTouchEventsBegin(touchEvents_);
876 std::unordered_set<int32_t> moveEventIds;
877 decltype(touchEvents_) touchEvents(std::move(touchEvents_));
878 if (touchEvents.empty()) {
879 return;
880 }
881 std::list<TouchEvent> touchPoints;
882 for (auto iter = touchEvents.rbegin(); iter != touchEvents.rend(); ++iter) {
883 auto scalePoint = (*iter).CreateScalePoint(GetViewScale());
884 auto result = moveEventIds.emplace(scalePoint.id);
885 if (result.second) {
886 touchPoints.emplace_front(scalePoint);
887 }
888 }
889 auto maxSize = touchPoints.size();
890 for (auto iter = touchPoints.rbegin(); iter != touchPoints.rend(); ++iter) {
891 maxSize--;
892 if (maxSize == 0) {
893 eventManager_->FlushTouchEventsEnd(touchPoints);
894 }
895 eventManager_->DispatchTouchEvent(*iter);
896 }
897 }
898 }
899
OnMouseEvent(const MouseEvent & event)900 void PipelineContext::OnMouseEvent(const MouseEvent& event)
901 {
902 CHECK_RUN_ON(UI);
903
904 if ((event.action == MouseAction::RELEASE || event.action == MouseAction::PRESS ||
905 event.action == MouseAction::MOVE) &&
906 (event.button == MouseButton::LEFT_BUTTON || event.pressedButtons == MOUSE_PRESS_LEFT)) {
907 auto touchPoint = event.CreateTouchPoint();
908 OnTouchEvent(touchPoint);
909 }
910
911 CHECK_NULL_VOID(rootNode_);
912 auto scaleEvent = event.CreateScaleEvent(viewScale_);
913 LOGD(
914 "MouseEvent (x,y): (%{public}f,%{public}f), button: %{public}d, action: %{public}d, pressedButtons: %{public}d",
915 scaleEvent.x, scaleEvent.y, scaleEvent.button, scaleEvent.action, scaleEvent.pressedButtons);
916 TouchRestrict touchRestrict { TouchRestrict::NONE };
917 touchRestrict.sourceType = event.sourceType;
918 touchRestrict.hitTestType = SourceType::MOUSE;
919 eventManager_->MouseTest(scaleEvent, rootNode_, touchRestrict);
920 eventManager_->DispatchMouseEventNG(scaleEvent);
921 eventManager_->DispatchMouseHoverEventNG(scaleEvent);
922 eventManager_->DispatchMouseHoverAnimationNG(scaleEvent);
923 window_->RequestFrame();
924 }
925
ChangeMouseStyle(int32_t nodeId,MouseFormat format)926 bool PipelineContext::ChangeMouseStyle(int32_t nodeId, MouseFormat format)
927 {
928 if (mouseStyleNodeId_ != nodeId) {
929 return false;
930 }
931 auto mouseStyle = MouseStyle::CreateMouseStyle();
932 return mouseStyle->ChangePointerStyle(GetWindowId(), format);
933 }
934
OnKeyEvent(const KeyEvent & event)935 bool PipelineContext::OnKeyEvent(const KeyEvent& event)
936 {
937 eventManager_->SetPressedKeyCodes(event.pressedCodes);
938 // Need update while key tab pressed
939 if (!isNeedShowFocus_ && event.action == KeyAction::DOWN &&
940 (event.IsKey({ KeyCode::KEY_TAB }) || event.IsDirectionalKey())) {
941 isNeedShowFocus_ = true;
942 auto rootFocusHub = rootNode_->GetFocusHub();
943 if (rootFocusHub) {
944 rootFocusHub->PaintAllFocusState();
945 }
946 return true;
947 }
948 auto lastPage = stageManager_->GetLastPage();
949 auto mainNode = lastPage ? lastPage : rootNode_;
950 CHECK_NULL_RETURN(mainNode, false);
951 if (!eventManager_->DispatchTabIndexEventNG(event, rootNode_, mainNode)) {
952 return eventManager_->DispatchKeyEventNG(event, rootNode_);
953 }
954 return true;
955 }
956
RequestDefaultFocus()957 bool PipelineContext::RequestDefaultFocus()
958 {
959 CHECK_NULL_RETURN(stageManager_, false);
960 auto lastPage = stageManager_->GetLastPage();
961 auto mainNode = lastPage ? lastPage : rootNode_;
962 CHECK_NULL_RETURN(mainNode, false);
963 auto mainFocusHub = mainNode->GetFocusHub();
964 CHECK_NULL_RETURN(mainFocusHub, false);
965 if (mainFocusHub->IsDefaultHasFocused()) {
966 LOGD("RequestDefaultFocus: %{public}s/%{public}d 's default focus node has be focused.",
967 mainNode->GetTag().c_str(), mainNode->GetId());
968 return false;
969 }
970 auto defaultFocusNode = mainFocusHub->GetChildFocusNodeByType();
971 if (!defaultFocusNode) {
972 LOGD("RequestDefaultFocus: %{public}s/%{public}d do not has default focus node.", mainNode->GetTag().c_str(),
973 mainNode->GetId());
974 return false;
975 }
976 if (!defaultFocusNode->IsFocusableWholePath()) {
977 LOGD("RequestDefaultFocus: %{public}s/%{public}d 's default focus node is not focusable.",
978 mainNode->GetTag().c_str(), mainNode->GetId());
979 return false;
980 }
981 mainFocusHub->SetIsDefaultHasFocused(true);
982 LOGD("Focus: request default focus node %{public}s", defaultFocusNode->GetFrameName().c_str());
983 return defaultFocusNode->RequestFocusImmediately();
984 }
985
RequestFocus(const std::string & targetNodeId)986 bool PipelineContext::RequestFocus(const std::string& targetNodeId)
987 {
988 CHECK_NULL_RETURN(rootNode_, false);
989 auto focusHub = rootNode_->GetFocusHub();
990 CHECK_NULL_RETURN(focusHub, false);
991 auto currentFocusChecked = focusHub->RequestFocusImmediatelyById(targetNodeId);
992 if (!isSubPipeline_ || currentFocusChecked) {
993 LOGI("Request focus in current pipeline return is %{public}d", currentFocusChecked);
994 return currentFocusChecked;
995 }
996 LOGI("Request focus in parent pipeline");
997 auto parentPipelineBase = parentPipeline_.Upgrade();
998 CHECK_NULL_RETURN(parentPipelineBase, false);
999 auto parentPipelineContext = AceType::DynamicCast<NG::PipelineContext>(parentPipelineBase);
1000 CHECK_NULL_RETURN(parentPipelineContext, false);
1001 return parentPipelineContext->RequestFocus(targetNodeId);
1002 }
1003
AddDirtyFocus(const RefPtr<FrameNode> & node)1004 void PipelineContext::AddDirtyFocus(const RefPtr<FrameNode>& node)
1005 {
1006 CHECK_RUN_ON(UI);
1007 CHECK_NULL_VOID(node);
1008 if (node->GetFocusType() == FocusType::NODE) {
1009 dirtyFocusNode_ = WeakClaim(RawPtr(node));
1010 } else {
1011 dirtyFocusScope_ = WeakClaim(RawPtr(node));
1012 }
1013 window_->RequestFrame();
1014 }
1015
RootLostFocus(BlurReason reason) const1016 void PipelineContext::RootLostFocus(BlurReason reason) const
1017 {
1018 CHECK_NULL_VOID(rootNode_);
1019 auto focusHub = rootNode_->GetFocusHub();
1020 CHECK_NULL_VOID(focusHub);
1021 focusHub->LostFocus(reason);
1022 CHECK_NULL_VOID(overlayManager_);
1023 overlayManager_->HideAllMenus();
1024 overlayManager_->HideAllPopups();
1025 }
1026
ConvertAxisToMouse(const AxisEvent & event)1027 MouseEvent ConvertAxisToMouse(const AxisEvent& event)
1028 {
1029 MouseEvent result;
1030 result.x = event.x;
1031 result.y = event.y;
1032 result.action = MouseAction::MOVE;
1033 result.button = MouseButton::NONE_BUTTON;
1034 result.time = event.time;
1035 result.deviceId = event.deviceId;
1036 result.sourceType = event.sourceType;
1037 return result;
1038 }
1039
OnAxisEvent(const AxisEvent & event)1040 void PipelineContext::OnAxisEvent(const AxisEvent& event)
1041 {
1042 auto scaleEvent = event.CreateScaleEvent(viewScale_);
1043 LOGD("AxisEvent (x,y): (%{public}f,%{public}f), action: %{public}d, horizontalAxis: %{public}f, verticalAxis: "
1044 "%{public}f, pinchAxisScale: %{public}f",
1045 scaleEvent.x, scaleEvent.y, scaleEvent.action, scaleEvent.horizontalAxis, scaleEvent.verticalAxis,
1046 scaleEvent.pinchAxisScale);
1047
1048 if (event.action == AxisAction::BEGIN) {
1049 TouchRestrict touchRestrict { TouchRestrict::NONE };
1050 touchRestrict.sourceType = event.sourceType;
1051 touchRestrict.hitTestType = SourceType::TOUCH;
1052 eventManager_->TouchTest(scaleEvent, rootNode_, touchRestrict);
1053 }
1054 eventManager_->DispatchTouchEvent(scaleEvent);
1055
1056 if (event.action == AxisAction::BEGIN || event.action == AxisAction::UPDATE) {
1057 eventManager_->AxisTest(scaleEvent, rootNode_);
1058 eventManager_->DispatchAxisEvent(scaleEvent);
1059 }
1060
1061 auto mouseEvent = ConvertAxisToMouse(event);
1062 OnMouseEvent(mouseEvent);
1063 }
1064
AddVisibleAreaChangeNode(const RefPtr<FrameNode> & node,double ratio,const VisibleRatioCallback & callback)1065 void PipelineContext::AddVisibleAreaChangeNode(
1066 const RefPtr<FrameNode>& node, double ratio, const VisibleRatioCallback& callback)
1067 {
1068 CHECK_NULL_VOID(node);
1069 VisibleCallbackInfo info;
1070 info.callback = callback;
1071 info.visibleRatio = ratio;
1072 info.isCurrentVisible = false;
1073 auto iter = visibleAreaChangeNodes_.find(node->GetId());
1074 if (iter != visibleAreaChangeNodes_.end()) {
1075 auto& callbackList = iter->second;
1076 callbackList.emplace_back(info);
1077 } else {
1078 std::list<VisibleCallbackInfo> callbackList;
1079 callbackList.emplace_back(info);
1080 visibleAreaChangeNodes_[node->GetId()] = callbackList;
1081 }
1082 }
1083
RemoveVisibleAreaChangeNode(int32_t nodeId)1084 void PipelineContext::RemoveVisibleAreaChangeNode(int32_t nodeId)
1085 {
1086 visibleAreaChangeNodes_.erase(nodeId);
1087 }
1088
HandleVisibleAreaChangeEvent()1089 void PipelineContext::HandleVisibleAreaChangeEvent()
1090 {
1091 if (visibleAreaChangeNodes_.empty()) {
1092 return;
1093 }
1094 for (auto& visibleChangeNode : visibleAreaChangeNodes_) {
1095 auto uiNode = ElementRegister::GetInstance()->GetUINodeById(visibleChangeNode.first);
1096 if (!uiNode) {
1097 continue;
1098 }
1099 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
1100 if (!frameNode) {
1101 continue;
1102 }
1103 frameNode->TriggerVisibleAreaChangeCallback(visibleChangeNode.second);
1104 }
1105 }
1106
AddOnAreaChangeNode(int32_t nodeId)1107 void PipelineContext::AddOnAreaChangeNode(int32_t nodeId)
1108 {
1109 onAreaChangeNodeIds_.emplace(nodeId);
1110 }
1111
RemoveOnAreaChangeNode(int32_t nodeId)1112 void PipelineContext::RemoveOnAreaChangeNode(int32_t nodeId)
1113 {
1114 onAreaChangeNodeIds_.erase(nodeId);
1115 }
1116
HandleOnAreaChangeEvent()1117 void PipelineContext::HandleOnAreaChangeEvent()
1118 {
1119 if (onAreaChangeNodeIds_.empty()) {
1120 return;
1121 }
1122 for (const auto& nodeId : onAreaChangeNodeIds_) {
1123 auto uiNode = ElementRegister::GetInstance()->GetUINodeById(nodeId);
1124 if (!uiNode) {
1125 continue;
1126 }
1127 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
1128 if (!frameNode) {
1129 continue;
1130 }
1131 frameNode->TriggerOnAreaChangeCallback();
1132 }
1133 }
1134
OnShow()1135 void PipelineContext::OnShow()
1136 {
1137 CHECK_RUN_ON(UI);
1138 onShow_ = true;
1139 window_->OnShow();
1140 window_->RequestFrame();
1141 FlushWindowStateChangedCallback(true);
1142 }
1143
OnHide()1144 void PipelineContext::OnHide()
1145 {
1146 CHECK_RUN_ON(UI);
1147 onShow_ = false;
1148 window_->RequestFrame();
1149 window_->OnHide();
1150 OnVirtualKeyboardAreaChange(Rect());
1151 FlushWindowStateChangedCallback(false);
1152 }
1153
WindowFocus(bool isFocus)1154 void PipelineContext::WindowFocus(bool isFocus)
1155 {
1156 CHECK_RUN_ON(UI);
1157 onFocus_ = isFocus;
1158 if (!isFocus) {
1159 LOGD("WindowFocus: isFocus_ is %{public}d. Lost all focus.", onFocus_);
1160 RootLostFocus(BlurReason::WINDOW_BLUR);
1161 NotifyPopupDismiss();
1162 OnVirtualKeyboardAreaChange(Rect());
1163 }
1164 if (onFocus_ && onShow_) {
1165 LOGD("WindowFocus: onFocus_ and onShow_ are both true. Do FlushFocus().");
1166 FlushFocus();
1167 } else {
1168 LOGD("WindowFocus: onFocus_ is %{public}d, onShow_ is %{public}d.", onFocus_, onShow_);
1169 }
1170 FlushWindowFocusChangedCallback(isFocus);
1171 }
1172
ShowContainerTitle(bool isShow)1173 void PipelineContext::ShowContainerTitle(bool isShow)
1174 {
1175 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1176 LOGW("ShowContainerTitle failed, Window modal is not container.");
1177 return;
1178 }
1179 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1180 CHECK_NULL_VOID(containerNode);
1181 containerNode->GetPattern<ContainerModalPattern>()->ShowTitle(isShow);
1182 }
1183
SetContainerWindow(bool isShow)1184 void PipelineContext::SetContainerWindow(bool isShow)
1185 {
1186 #ifdef ENABLE_ROSEN_BACKEND
1187 if (!IsJsCard()) {
1188 auto rsWindow = static_cast<RosenWindow*>(GetWindow());
1189 if (rsWindow) {
1190 auto rsUIDirector = rsWindow->GetRsUIDirector();
1191 if (rsUIDirector) {
1192 rsUIDirector->SetContainerWindow(isShow, density_); // set container window show state to render service
1193 }
1194 }
1195 }
1196 #endif
1197 }
1198
SetAppBgColor(const Color & color)1199 void PipelineContext::SetAppBgColor(const Color& color)
1200 {
1201 appBgColor_ = color;
1202 #ifdef ENABLE_ROSEN_BACKEND
1203 if (!IsJsCard()) {
1204 auto rsWindow = static_cast<RosenWindow*>(GetWindow());
1205 if (rsWindow) {
1206 auto rsUIDirector = rsWindow->GetRsUIDirector();
1207 if (rsUIDirector) {
1208 rsUIDirector->SetAbilityBGAlpha(appBgColor_.GetAlpha());
1209 }
1210 }
1211 }
1212 #endif
1213 CHECK_NULL_VOID(rootNode_);
1214 auto rootPattern = rootNode_->GetPattern<RootPattern>();
1215 CHECK_NULL_VOID(rootPattern);
1216 rootPattern->SetAppBgColor(appBgColor_, windowModal_ == WindowModal::CONTAINER_MODAL);
1217 }
1218
SetAppTitle(const std::string & title)1219 void PipelineContext::SetAppTitle(const std::string& title)
1220 {
1221 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1222 LOGW("SetAppTitle failed, Window modal is not container.");
1223 return;
1224 }
1225 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1226 CHECK_NULL_VOID(containerNode);
1227 containerNode->GetPattern<ContainerModalPattern>()->SetAppTitle(title);
1228 }
1229
SetAppIcon(const RefPtr<PixelMap> & icon)1230 void PipelineContext::SetAppIcon(const RefPtr<PixelMap>& icon)
1231 {
1232 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1233 LOGW("SetAppIcon failed, Window modal is not container.");
1234 return;
1235 }
1236 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1237 CHECK_NULL_VOID(containerNode);
1238 containerNode->GetPattern<ContainerModalPattern>()->SetAppIcon(icon);
1239 }
1240
FlushReload()1241 void PipelineContext::FlushReload()
1242 {
1243 LOGI("PipelineContext::FlushReload.");
1244 AnimationOption option;
1245 const int32_t duration = 400;
1246 option.SetDuration(duration);
1247 option.SetCurve(Curves::FRICTION);
1248 AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
1249 auto pipeline = weak.Upgrade();
1250 CHECK_NULL_VOID(pipeline);
1251 pipeline->stageManager_->ReloadStage();
1252 pipeline->FlushUITasks();
1253 });
1254 }
1255
Destroy()1256 void PipelineContext::Destroy()
1257 {
1258 CHECK_RUN_ON(UI);
1259 LOGI("PipelineContext::Destroy begin.");
1260 taskScheduler_.CleanUp();
1261 scheduleTasks_.clear();
1262 dirtyNodes_.clear();
1263 rootNode_.Reset();
1264 stageManager_.Reset();
1265 overlayManager_.Reset();
1266 sharedTransitionManager_.Reset();
1267 dragDropManager_.Reset();
1268 selectOverlayManager_.Reset();
1269 fullScreenManager_.Reset();
1270 touchEvents_.clear();
1271 buildFinishCallbacks_.clear();
1272 onWindowStateChangedCallbacks_.clear();
1273 onWindowFocusChangedCallbacks_.clear();
1274 nodesToNotifyMemoryLevel_.clear();
1275 dirtyFocusNode_.Reset();
1276 dirtyFocusScope_.Reset();
1277 PipelineBase::Destroy();
1278 LOGI("PipelineContext::Destroy end.");
1279 }
1280
AddBuildFinishCallBack(std::function<void ()> && callback)1281 void PipelineContext::AddBuildFinishCallBack(std::function<void()>&& callback)
1282 {
1283 buildFinishCallbacks_.emplace_back(std::move(callback));
1284 }
1285
AddWindowStateChangedCallback(int32_t nodeId)1286 void PipelineContext::AddWindowStateChangedCallback(int32_t nodeId)
1287 {
1288 onWindowStateChangedCallbacks_.emplace(nodeId);
1289 }
1290
RemoveWindowStateChangedCallback(int32_t nodeId)1291 void PipelineContext::RemoveWindowStateChangedCallback(int32_t nodeId)
1292 {
1293 onWindowStateChangedCallbacks_.erase(nodeId);
1294 }
1295
FlushWindowStateChangedCallback(bool isShow)1296 void PipelineContext::FlushWindowStateChangedCallback(bool isShow)
1297 {
1298 auto iter = onWindowStateChangedCallbacks_.begin();
1299 while (iter != onWindowStateChangedCallbacks_.end()) {
1300 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1301 if (!node) {
1302 iter = onWindowStateChangedCallbacks_.erase(iter);
1303 } else {
1304 if (isShow) {
1305 node->OnWindowShow();
1306 } else {
1307 node->OnWindowHide();
1308 }
1309 ++iter;
1310 }
1311 }
1312 }
1313
AddWindowFocusChangedCallback(int32_t nodeId)1314 void PipelineContext::AddWindowFocusChangedCallback(int32_t nodeId)
1315 {
1316 onWindowFocusChangedCallbacks_.emplace_back(nodeId);
1317 }
1318
RemoveWindowFocusChangedCallback(int32_t nodeId)1319 void PipelineContext::RemoveWindowFocusChangedCallback(int32_t nodeId)
1320 {
1321 onWindowFocusChangedCallbacks_.remove(nodeId);
1322 }
1323
FlushWindowFocusChangedCallback(bool isFocus)1324 void PipelineContext::FlushWindowFocusChangedCallback(bool isFocus)
1325 {
1326 auto iter = onWindowFocusChangedCallbacks_.begin();
1327 while (iter != onWindowFocusChangedCallbacks_.end()) {
1328 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1329 if (!node) {
1330 iter = onWindowFocusChangedCallbacks_.erase(iter);
1331 } else {
1332 if (isFocus) {
1333 node->OnWindowFocused();
1334 } else {
1335 node->OnWindowUnfocused();
1336 }
1337 ++iter;
1338 }
1339 }
1340 }
1341
OnDragEvent(int32_t x,int32_t y,DragEventAction action)1342 void PipelineContext::OnDragEvent(int32_t x, int32_t y, DragEventAction action)
1343 {
1344 auto manager = GetDragDropManager();
1345 CHECK_NULL_VOID(manager);
1346 if (manager->IsDragged()) {
1347 LOGI("current context is the source of drag");
1348 return;
1349 }
1350
1351 std::string extraInfo;
1352 manager->GetExtraInfoFromClipboard(extraInfo);
1353
1354 if (action == DragEventAction::DRAG_EVENT_END) {
1355 manager->OnDragEnd(static_cast<float>(x), static_cast<float>(y), extraInfo);
1356 manager->RestoreClipboardData();
1357 return;
1358 }
1359
1360 manager->OnDragMove(static_cast<float>(x), static_cast<float>(y), extraInfo);
1361 }
1362
AddNodesToNotifyMemoryLevel(int32_t nodeId)1363 void PipelineContext::AddNodesToNotifyMemoryLevel(int32_t nodeId)
1364 {
1365 nodesToNotifyMemoryLevel_.emplace_back(nodeId);
1366 }
1367
RemoveNodesToNotifyMemoryLevel(int32_t nodeId)1368 void PipelineContext::RemoveNodesToNotifyMemoryLevel(int32_t nodeId)
1369 {
1370 nodesToNotifyMemoryLevel_.remove(nodeId);
1371 }
1372
NotifyMemoryLevel(int32_t level)1373 void PipelineContext::NotifyMemoryLevel(int32_t level)
1374 {
1375 LOGI("PipelineContext: NotifyMemoryLevel called");
1376 auto iter = nodesToNotifyMemoryLevel_.begin();
1377 while (iter != nodesToNotifyMemoryLevel_.end()) {
1378 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1379 if (!node) {
1380 iter = nodesToNotifyMemoryLevel_.erase(iter);
1381 } else {
1382 node->OnNotifyMemoryLevel(level);
1383 }
1384 ++iter;
1385 }
1386 }
AddPredictTask(PredictTask && task)1387 void PipelineContext::AddPredictTask(PredictTask&& task)
1388 {
1389 taskScheduler_.AddPredictTask(std::move(task));
1390 window_->RequestFrame();
1391 }
1392
OnIdle(int64_t deadline)1393 void PipelineContext::OnIdle(int64_t deadline)
1394 {
1395 if (deadline == 0) {
1396 return;
1397 }
1398 CHECK_RUN_ON(UI);
1399 ACE_SCOPED_TRACE("OnIdle, targettime:%" PRId64 "", deadline);
1400 taskScheduler_.FlushPredictTask(deadline - TIME_THRESHOLD);
1401 }
1402
Finish(bool) const1403 void PipelineContext::Finish(bool /*autoFinish*/) const
1404 {
1405 CHECK_RUN_ON(UI);
1406 if (finishEventHandler_) {
1407 LOGI("call finishEventHandler");
1408 finishEventHandler_();
1409 } else {
1410 LOGE("fail to finish current context due to handler is nullptr");
1411 }
1412 }
1413
AddAfterLayoutTask(std::function<void ()> && task)1414 void PipelineContext::AddAfterLayoutTask(std::function<void()>&& task)
1415 {
1416 taskScheduler_.AddAfterLayoutTask(std::move(task));
1417 }
1418
1419 } // namespace OHOS::Ace::NG
1420