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_) {
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 (positionY > (rootSize.Height() - keyboardHeight) && offsetFix > 0.0) {
620 SetRootRect(rootSize.Width(), rootSize.Height(), -offsetFix);
621 } else if ((positionY + height > rootSize.Height() - keyboardHeight &&
622 positionY < rootSize.Height() - keyboardHeight && height < keyboardHeight / 2.0f) &&
623 NearZero(rootNode_->GetGeometryNode()->GetFrameOffset().GetY())) {
624 SetRootRect(rootSize.Width(), rootSize.Height(), -height - offsetFix / 2.0f);
625 }
626 }
627
OnBackPressed()628 bool PipelineContext::OnBackPressed()
629 {
630 LOGD("OnBackPressed");
631 CHECK_RUN_ON(PLATFORM);
632 auto frontend = weakFrontend_.Upgrade();
633 if (!frontend) {
634 // return back.
635 return false;
636 }
637
638 // If the tag of the last child of the rootnode is video, exit full screen.
639 if (fullScreenManager_->OnBackPressed()) {
640 LOGI("Exit full screen: back press accepted");
641 return true;
642 }
643
644 // if has sharedTransition, back press will stop the sharedTransition
645 if (sharedTransitionManager_->OnBackPressed()) {
646 LOGI("sharedTransition stop: back press accepted");
647 return true;
648 }
649
650 // if has popup, back press would hide popup and not trigger page back
651 auto hasOverlay = false;
652 taskExecutor_->PostSyncTask(
653 [weakOverlay = AceType::WeakClaim(AceType::RawPtr(overlayManager_)), &hasOverlay]() {
654 auto overlay = weakOverlay.Upgrade();
655 CHECK_NULL_VOID_NOLOG(overlay);
656 hasOverlay = overlay->RemoveOverlay();
657 },
658 TaskExecutor::TaskType::UI);
659 if (hasOverlay) {
660 LOGI("popup hidden: back press accepted");
661 return true;
662 }
663
664 auto result = false;
665 taskExecutor_->PostSyncTask(
666 [weakFrontend = weakFrontend_, weakPipelineContext = WeakClaim(this), &result]() {
667 auto frontend = weakFrontend.Upgrade();
668 if (!frontend) {
669 LOGW("frontend is nullptr");
670 result = false;
671 return;
672 }
673 auto context = weakPipelineContext.Upgrade();
674 if (!context) {
675 LOGW("pipelineContext is nullptr");
676 result = false;
677 return;
678 }
679 if (context->GetNavDestinationBackButtonNode()) {
680 auto navDestinationNode =
681 AceType::DynamicCast<NavDestinationGroupNode>(context->GetNavDestinationBackButtonNode());
682 if (navDestinationNode->GetNavDestinationBackButtonEvent()) {
683 GestureEvent gestureEvent;
684 navDestinationNode->GetNavDestinationBackButtonEvent()(gestureEvent);
685 result = true;
686 }
687 }
688 },
689 TaskExecutor::TaskType::UI);
690
691 if (result) {
692 // user accept
693 LOGI("CallRouterBackToPopPage(): frontend accept");
694 return true;
695 }
696
697 taskExecutor_->PostSyncTask(
698 [weakFrontend = weakFrontend_, weakPipelineContext = WeakClaim(this), &result]() {
699 auto frontend = weakFrontend.Upgrade();
700 if (!frontend) {
701 LOGW("frontend is nullptr");
702 result = false;
703 return;
704 }
705 result = frontend->OnBackPressed();
706 },
707 TaskExecutor::TaskType::JS);
708
709 if (result) {
710 // user accept
711 LOGI("CallRouterBackToPopPage(): frontend accept");
712 return true;
713 }
714 LOGI("CallRouterBackToPopPage(): return platform consumed");
715 return false;
716 }
717
GetNavDestinationBackButtonNode()718 RefPtr<FrameNode> PipelineContext::GetNavDestinationBackButtonNode()
719 {
720 auto lastPage = stageManager_->GetLastPage();
721 CHECK_NULL_RETURN(lastPage, nullptr);
722 auto navigationNode = lastPage->FindChildNodeOfClass<NavigationGroupNode>();
723 CHECK_NULL_RETURN(navigationNode, nullptr);
724 auto navigationContentNode = navigationNode->GetContentNode();
725 CHECK_NULL_RETURN(navigationContentNode, nullptr);
726 auto navDestinationNode = navigationContentNode->FindChildNodeOfClass<NavDestinationGroupNode>();
727 CHECK_NULL_RETURN(navDestinationNode, nullptr);
728 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationNode->GetTitleBarNode());
729 CHECK_NULL_RETURN(titleBarNode, nullptr);
730 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
731 CHECK_NULL_RETURN(backButtonNode, nullptr);
732 auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty<ImageLayoutProperty>();
733 if (!backButtonLayoutProperty->HasVisibility()) {
734 return nullptr;
735 }
736
737 if (backButtonLayoutProperty->GetVisibilityValue() != VisibleType::VISIBLE) {
738 return nullptr;
739 }
740 return navDestinationNode;
741 }
742
OnTouchEvent(const TouchEvent & point,bool isSubPipe)743 void PipelineContext::OnTouchEvent(const TouchEvent& point, bool isSubPipe)
744 {
745 CHECK_RUN_ON(UI);
746 HandleEtsCardTouchEvent(point);
747 auto scalePoint = point.CreateScalePoint(GetViewScale());
748 LOGD("AceTouchEvent: x = %{public}f, y = %{public}f, type = %{public}zu", scalePoint.x, scalePoint.y,
749 scalePoint.type);
750 eventManager_->SetInstanceId(GetInstanceId());
751 if (scalePoint.type == TouchType::DOWN) {
752 isNeedShowFocus_ = false;
753 CHECK_NULL_VOID_NOLOG(rootNode_);
754 auto rootFocusHub = rootNode_->GetFocusHub();
755 if (rootFocusHub) {
756 rootFocusHub->ClearAllFocusState();
757 }
758
759 LOGD("receive touch down event, first use touch test to collect touch event target");
760 TouchRestrict touchRestrict { TouchRestrict::NONE };
761 touchRestrict.sourceType = point.sourceType;
762 touchRestrict.touchEvent = point;
763 eventManager_->TouchTest(scalePoint, rootNode_, touchRestrict, GetPluginEventOffset(), viewScale_, isSubPipe);
764
765 for (const auto& weakContext : touchPluginPipelineContext_) {
766 auto pipelineContext = DynamicCast<OHOS::Ace::PipelineBase>(weakContext.Upgrade());
767 if (!pipelineContext) {
768 continue;
769 }
770 auto pluginPoint =
771 point.UpdateScalePoint(viewScale_, static_cast<float>(pipelineContext->GetPluginEventOffset().GetX()),
772 static_cast<float>(pipelineContext->GetPluginEventOffset().GetY()), point.id);
773 // eventManager_ instance Id may changed.
774 pipelineContext->OnTouchEvent(pluginPoint, true);
775 }
776
777 // restore instance Id.
778 eventManager_->SetInstanceId(GetInstanceId());
779 }
780 if (isSubPipe) {
781 return;
782 }
783
784 if (scalePoint.type == TouchType::MOVE) {
785 touchEvents_.emplace_back(point);
786 hasIdleTasks_ = true;
787 window_->RequestFrame();
788 return;
789 }
790
791 std::optional<TouchEvent> lastMoveEvent;
792 if (scalePoint.type == TouchType::UP && !touchEvents_.empty()) {
793 for (auto iter = touchEvents_.begin(); iter != touchEvents_.end(); ++iter) {
794 auto movePoint = (*iter).CreateScalePoint(GetViewScale());
795 if (scalePoint.id == movePoint.id) {
796 lastMoveEvent = movePoint;
797 touchEvents_.erase(iter++);
798 }
799 }
800 if (lastMoveEvent.has_value()) {
801 eventManager_->DispatchTouchEvent(lastMoveEvent.value());
802 }
803 }
804
805 eventManager_->DispatchTouchEvent(scalePoint);
806
807 if ((scalePoint.type == TouchType::UP) || (scalePoint.type == TouchType::CANCEL)) {
808 // need to reset touchPluginPipelineContext_ for next touch down event.
809 touchPluginPipelineContext_.clear();
810 RemoveEtsCardTouchEventCallback(point.id);
811 }
812
813 hasIdleTasks_ = true;
814 window_->RequestFrame();
815 }
816
OnSurfaceDensityChanged(double density)817 void PipelineContext::OnSurfaceDensityChanged(double density)
818 {
819 CHECK_RUN_ON(UI);
820 LOGI("OnSurfaceDensityChanged density_(%{public}lf)", density_);
821 LOGI("OnSurfaceDensityChanged dipScale_(%{public}lf)", dipScale_);
822 density_ = density;
823 if (!NearZero(viewScale_)) {
824 LOGI("OnSurfaceDensityChanged viewScale_(%{public}lf)", viewScale_);
825 dipScale_ = density_ / viewScale_;
826 }
827 }
828
OnDumpInfo(const std::vector<std::string> & params) const829 bool PipelineContext::OnDumpInfo(const std::vector<std::string>& params) const
830 {
831 ACE_DCHECK(!params.empty());
832
833 if (params[0] == "-element") {
834 if (params.size() > 1 && params[1] == "-lastpage") {
835 auto lastPage = stageManager_->GetLastPage();
836 if (lastPage) {
837 lastPage->DumpTree(0);
838 }
839 } else {
840 rootNode_->DumpTree(0);
841 }
842 } else if (params[0] == "-render") {
843 } else if (params[0] == "-focus") {
844 if (rootNode_->GetFocusHub()) {
845 rootNode_->GetFocusHub()->DumpFocusTree(0);
846 }
847 } else if (params[0] == "-layer") {
848 } else if (params[0] == "-frontend") {
849 #ifndef WEARABLE_PRODUCT
850 } else if (params[0] == "-multimodal") {
851 #endif
852 } else if (params[0] == "-accessibility" || params[0] == "-inspector") {
853 auto accessibilityManager = GetAccessibilityManager();
854 if (accessibilityManager) {
855 accessibilityManager->OnDumpInfo(params);
856 }
857 } else if (params[0] == "-rotation" && params.size() >= 2) {
858 } else if (params[0] == "-animationscale" && params.size() >= 2) {
859 } else if (params[0] == "-velocityscale" && params.size() >= 2) {
860 } else if (params[0] == "-scrollfriction" && params.size() >= 2) {
861 } else if (params[0] == "-threadstuck" && params.size() >= 3) {
862 } else {
863 return false;
864 }
865 return true;
866 }
867
FlushTouchEvents()868 void PipelineContext::FlushTouchEvents()
869 {
870 CHECK_RUN_ON(UI);
871 CHECK_NULL_VOID(rootNode_);
872 {
873 eventManager_->FlushTouchEventsBegin(touchEvents_);
874 std::unordered_set<int32_t> moveEventIds;
875 decltype(touchEvents_) touchEvents(std::move(touchEvents_));
876 if (touchEvents.empty()) {
877 return;
878 }
879 std::list<TouchEvent> touchPoints;
880 for (auto iter = touchEvents.rbegin(); iter != touchEvents.rend(); ++iter) {
881 auto scalePoint = (*iter).CreateScalePoint(GetViewScale());
882 auto result = moveEventIds.emplace(scalePoint.id);
883 if (result.second) {
884 touchPoints.emplace_front(scalePoint);
885 }
886 }
887 auto maxSize = touchPoints.size();
888 for (auto iter = touchPoints.rbegin(); iter != touchPoints.rend(); ++iter) {
889 maxSize--;
890 if (maxSize == 0) {
891 eventManager_->FlushTouchEventsEnd(touchPoints);
892 }
893 eventManager_->DispatchTouchEvent(*iter);
894 }
895 }
896 }
897
OnMouseEvent(const MouseEvent & event)898 void PipelineContext::OnMouseEvent(const MouseEvent& event)
899 {
900 CHECK_RUN_ON(UI);
901
902 if ((event.action == MouseAction::RELEASE || event.action == MouseAction::PRESS ||
903 event.action == MouseAction::MOVE) &&
904 (event.button == MouseButton::LEFT_BUTTON || event.pressedButtons == MOUSE_PRESS_LEFT)) {
905 auto touchPoint = event.CreateTouchPoint();
906 OnTouchEvent(touchPoint);
907 }
908
909 CHECK_NULL_VOID(rootNode_);
910 auto scaleEvent = event.CreateScaleEvent(viewScale_);
911 LOGD(
912 "MouseEvent (x,y): (%{public}f,%{public}f), button: %{public}d, action: %{public}d, pressedButtons: %{public}d",
913 scaleEvent.x, scaleEvent.y, scaleEvent.button, scaleEvent.action, scaleEvent.pressedButtons);
914 TouchRestrict touchRestrict { TouchRestrict::NONE };
915 touchRestrict.sourceType = event.sourceType;
916 touchRestrict.hitTestType = SourceType::MOUSE;
917 eventManager_->MouseTest(scaleEvent, rootNode_, touchRestrict);
918 eventManager_->DispatchMouseEventNG(scaleEvent);
919 eventManager_->DispatchMouseHoverEventNG(scaleEvent);
920 eventManager_->DispatchMouseHoverAnimationNG(scaleEvent);
921 window_->RequestFrame();
922 }
923
ChangeMouseStyle(int32_t nodeId,MouseFormat format)924 bool PipelineContext::ChangeMouseStyle(int32_t nodeId, MouseFormat format)
925 {
926 if (mouseStyleNodeId_ != nodeId) {
927 return false;
928 }
929 auto mouseStyle = MouseStyle::CreateMouseStyle();
930 return mouseStyle->ChangePointerStyle(GetWindowId(), format);
931 }
932
OnKeyEvent(const KeyEvent & event)933 bool PipelineContext::OnKeyEvent(const KeyEvent& event)
934 {
935 eventManager_->SetPressedKeyCodes(event.pressedCodes);
936 // Need update while key tab pressed
937 if (!isNeedShowFocus_ && event.action == KeyAction::DOWN &&
938 (event.IsKey({ KeyCode::KEY_TAB }) || event.IsDirectionalKey())) {
939 isNeedShowFocus_ = true;
940 auto rootFocusHub = rootNode_->GetFocusHub();
941 if (rootFocusHub) {
942 rootFocusHub->PaintAllFocusState();
943 }
944 return true;
945 }
946 auto lastPage = stageManager_->GetLastPage();
947 auto mainNode = lastPage ? lastPage : rootNode_;
948 CHECK_NULL_RETURN(mainNode, false);
949 if (!eventManager_->DispatchTabIndexEventNG(event, rootNode_, mainNode)) {
950 return eventManager_->DispatchKeyEventNG(event, rootNode_);
951 }
952 return true;
953 }
954
RequestDefaultFocus()955 bool PipelineContext::RequestDefaultFocus()
956 {
957 CHECK_NULL_RETURN(stageManager_, false);
958 auto lastPage = stageManager_->GetLastPage();
959 auto mainNode = lastPage ? lastPage : rootNode_;
960 CHECK_NULL_RETURN(mainNode, false);
961 auto mainFocusHub = mainNode->GetFocusHub();
962 CHECK_NULL_RETURN(mainFocusHub, false);
963 if (mainFocusHub->IsDefaultHasFocused()) {
964 LOGD("RequestDefaultFocus: %{public}s/%{public}d 's default focus node has be focused.",
965 mainNode->GetTag().c_str(), mainNode->GetId());
966 return false;
967 }
968 auto defaultFocusNode = mainFocusHub->GetChildFocusNodeByType();
969 if (!defaultFocusNode) {
970 LOGD("RequestDefaultFocus: %{public}s/%{public}d do not has default focus node.", mainNode->GetTag().c_str(),
971 mainNode->GetId());
972 return false;
973 }
974 if (!defaultFocusNode->IsFocusableWholePath()) {
975 LOGD("RequestDefaultFocus: %{public}s/%{public}d 's default focus node is not focusable.",
976 mainNode->GetTag().c_str(), mainNode->GetId());
977 return false;
978 }
979 mainFocusHub->SetIsDefaultHasFocused(true);
980 LOGD("Focus: request default focus node %{public}s", defaultFocusNode->GetFrameName().c_str());
981 return defaultFocusNode->RequestFocusImmediately();
982 }
983
RequestFocus(const std::string & targetNodeId)984 bool PipelineContext::RequestFocus(const std::string& targetNodeId)
985 {
986 CHECK_NULL_RETURN(rootNode_, false);
987 auto focusHub = rootNode_->GetFocusHub();
988 CHECK_NULL_RETURN(focusHub, false);
989 auto currentFocusChecked = focusHub->RequestFocusImmediatelyById(targetNodeId);
990 if (!isSubPipeline_ || currentFocusChecked) {
991 LOGI("Request focus in current pipeline return is %{public}d", currentFocusChecked);
992 return currentFocusChecked;
993 }
994 LOGI("Request focus in parent pipeline");
995 auto parentPipelineBase = parentPipeline_.Upgrade();
996 CHECK_NULL_RETURN(parentPipelineBase, false);
997 auto parentPipelineContext = AceType::DynamicCast<NG::PipelineContext>(parentPipelineBase);
998 CHECK_NULL_RETURN(parentPipelineContext, false);
999 return parentPipelineContext->RequestFocus(targetNodeId);
1000 }
1001
AddDirtyFocus(const RefPtr<FrameNode> & node)1002 void PipelineContext::AddDirtyFocus(const RefPtr<FrameNode>& node)
1003 {
1004 CHECK_RUN_ON(UI);
1005 CHECK_NULL_VOID(node);
1006 if (node->GetFocusType() == FocusType::NODE) {
1007 dirtyFocusNode_ = WeakClaim(RawPtr(node));
1008 } else {
1009 dirtyFocusScope_ = WeakClaim(RawPtr(node));
1010 }
1011 window_->RequestFrame();
1012 }
1013
RootLostFocus(BlurReason reason) const1014 void PipelineContext::RootLostFocus(BlurReason reason) const
1015 {
1016 CHECK_NULL_VOID(rootNode_);
1017 auto focusHub = rootNode_->GetFocusHub();
1018 CHECK_NULL_VOID(focusHub);
1019 focusHub->LostFocus(reason);
1020 CHECK_NULL_VOID(overlayManager_);
1021 overlayManager_->HideAllMenus();
1022 overlayManager_->HideAllPopups();
1023 }
1024
ConvertAxisToMouse(const AxisEvent & event)1025 MouseEvent ConvertAxisToMouse(const AxisEvent& event)
1026 {
1027 MouseEvent result;
1028 result.x = event.x;
1029 result.y = event.y;
1030 result.action = MouseAction::MOVE;
1031 result.button = MouseButton::NONE_BUTTON;
1032 result.time = event.time;
1033 result.deviceId = event.deviceId;
1034 result.sourceType = event.sourceType;
1035 return result;
1036 }
1037
OnAxisEvent(const AxisEvent & event)1038 void PipelineContext::OnAxisEvent(const AxisEvent& event)
1039 {
1040 auto scaleEvent = event.CreateScaleEvent(viewScale_);
1041 LOGD("AxisEvent (x,y): (%{public}f,%{public}f), action: %{public}d, horizontalAxis: %{public}f, verticalAxis: "
1042 "%{public}f, pinchAxisScale: %{public}f",
1043 scaleEvent.x, scaleEvent.y, scaleEvent.action, scaleEvent.horizontalAxis, scaleEvent.verticalAxis,
1044 scaleEvent.pinchAxisScale);
1045
1046 if (event.action == AxisAction::BEGIN) {
1047 TouchRestrict touchRestrict { TouchRestrict::NONE };
1048 touchRestrict.sourceType = event.sourceType;
1049 touchRestrict.hitTestType = SourceType::TOUCH;
1050 eventManager_->TouchTest(scaleEvent, rootNode_, touchRestrict);
1051 }
1052 eventManager_->DispatchTouchEvent(scaleEvent);
1053
1054 if (event.action == AxisAction::BEGIN || event.action == AxisAction::UPDATE) {
1055 eventManager_->AxisTest(scaleEvent, rootNode_);
1056 eventManager_->DispatchAxisEvent(scaleEvent);
1057 }
1058
1059 auto mouseEvent = ConvertAxisToMouse(event);
1060 OnMouseEvent(mouseEvent);
1061 }
1062
AddVisibleAreaChangeNode(const RefPtr<FrameNode> & node,double ratio,const VisibleRatioCallback & callback)1063 void PipelineContext::AddVisibleAreaChangeNode(
1064 const RefPtr<FrameNode>& node, double ratio, const VisibleRatioCallback& callback)
1065 {
1066 CHECK_NULL_VOID(node);
1067 VisibleCallbackInfo info;
1068 info.callback = callback;
1069 info.visibleRatio = ratio;
1070 info.isCurrentVisible = false;
1071 auto iter = visibleAreaChangeNodes_.find(node->GetId());
1072 if (iter != visibleAreaChangeNodes_.end()) {
1073 auto& callbackList = iter->second;
1074 callbackList.emplace_back(info);
1075 } else {
1076 std::list<VisibleCallbackInfo> callbackList;
1077 callbackList.emplace_back(info);
1078 visibleAreaChangeNodes_[node->GetId()] = callbackList;
1079 }
1080 }
1081
RemoveVisibleAreaChangeNode(int32_t nodeId)1082 void PipelineContext::RemoveVisibleAreaChangeNode(int32_t nodeId)
1083 {
1084 visibleAreaChangeNodes_.erase(nodeId);
1085 }
1086
HandleVisibleAreaChangeEvent()1087 void PipelineContext::HandleVisibleAreaChangeEvent()
1088 {
1089 if (visibleAreaChangeNodes_.empty()) {
1090 return;
1091 }
1092 for (auto& visibleChangeNode : visibleAreaChangeNodes_) {
1093 auto uiNode = ElementRegister::GetInstance()->GetUINodeById(visibleChangeNode.first);
1094 if (!uiNode) {
1095 continue;
1096 }
1097 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
1098 if (!frameNode) {
1099 continue;
1100 }
1101 frameNode->TriggerVisibleAreaChangeCallback(visibleChangeNode.second);
1102 }
1103 }
1104
AddOnAreaChangeNode(int32_t nodeId)1105 void PipelineContext::AddOnAreaChangeNode(int32_t nodeId)
1106 {
1107 onAreaChangeNodeIds_.emplace(nodeId);
1108 }
1109
RemoveOnAreaChangeNode(int32_t nodeId)1110 void PipelineContext::RemoveOnAreaChangeNode(int32_t nodeId)
1111 {
1112 onAreaChangeNodeIds_.erase(nodeId);
1113 }
1114
HandleOnAreaChangeEvent()1115 void PipelineContext::HandleOnAreaChangeEvent()
1116 {
1117 if (onAreaChangeNodeIds_.empty()) {
1118 return;
1119 }
1120 for (const auto& nodeId : onAreaChangeNodeIds_) {
1121 auto uiNode = ElementRegister::GetInstance()->GetUINodeById(nodeId);
1122 if (!uiNode) {
1123 continue;
1124 }
1125 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
1126 if (!frameNode) {
1127 continue;
1128 }
1129 frameNode->TriggerOnAreaChangeCallback();
1130 }
1131 }
1132
OnShow()1133 void PipelineContext::OnShow()
1134 {
1135 CHECK_RUN_ON(UI);
1136 onShow_ = true;
1137 window_->OnShow();
1138 window_->RequestFrame();
1139 FlushWindowStateChangedCallback(true);
1140 }
1141
OnHide()1142 void PipelineContext::OnHide()
1143 {
1144 CHECK_RUN_ON(UI);
1145 onShow_ = false;
1146 window_->RequestFrame();
1147 window_->OnHide();
1148 OnVirtualKeyboardAreaChange(Rect());
1149 FlushWindowStateChangedCallback(false);
1150 }
1151
WindowFocus(bool isFocus)1152 void PipelineContext::WindowFocus(bool isFocus)
1153 {
1154 CHECK_RUN_ON(UI);
1155 onFocus_ = isFocus;
1156 if (!isFocus) {
1157 LOGD("WindowFocus: isFocus_ is %{public}d. Lost all focus.", onFocus_);
1158 RootLostFocus(BlurReason::WINDOW_BLUR);
1159 NotifyPopupDismiss();
1160 OnVirtualKeyboardAreaChange(Rect());
1161 }
1162 if (onFocus_ && onShow_) {
1163 LOGD("WindowFocus: onFocus_ and onShow_ are both true. Do FlushFocus().");
1164 FlushFocus();
1165 } else {
1166 LOGD("WindowFocus: onFocus_ is %{public}d, onShow_ is %{public}d.", onFocus_, onShow_);
1167 }
1168 FlushWindowFocusChangedCallback(isFocus);
1169 }
1170
ShowContainerTitle(bool isShow)1171 void PipelineContext::ShowContainerTitle(bool isShow)
1172 {
1173 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1174 LOGW("ShowContainerTitle failed, Window modal is not container.");
1175 return;
1176 }
1177 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1178 CHECK_NULL_VOID(containerNode);
1179 containerNode->GetPattern<ContainerModalPattern>()->ShowTitle(isShow);
1180 }
1181
SetContainerWindow(bool isShow)1182 void PipelineContext::SetContainerWindow(bool isShow)
1183 {
1184 #ifdef ENABLE_ROSEN_BACKEND
1185 if (!IsJsCard()) {
1186 auto rsWindow = static_cast<RosenWindow*>(GetWindow());
1187 if (rsWindow) {
1188 auto rsUIDirector = rsWindow->GetRsUIDirector();
1189 if (rsUIDirector) {
1190 rsUIDirector->SetContainerWindow(isShow, density_); // set container window show state to render service
1191 }
1192 }
1193 }
1194 #endif
1195 }
1196
SetAppBgColor(const Color & color)1197 void PipelineContext::SetAppBgColor(const Color& color)
1198 {
1199 appBgColor_ = color;
1200 #ifdef ENABLE_ROSEN_BACKEND
1201 if (!IsJsCard()) {
1202 auto rsWindow = static_cast<RosenWindow*>(GetWindow());
1203 if (rsWindow) {
1204 auto rsUIDirector = rsWindow->GetRsUIDirector();
1205 if (rsUIDirector) {
1206 rsUIDirector->SetAbilityBGAlpha(appBgColor_.GetAlpha());
1207 }
1208 }
1209 }
1210 #endif
1211 CHECK_NULL_VOID(rootNode_);
1212 auto rootPattern = rootNode_->GetPattern<RootPattern>();
1213 CHECK_NULL_VOID(rootPattern);
1214 rootPattern->SetAppBgColor(appBgColor_, windowModal_ == WindowModal::CONTAINER_MODAL);
1215 }
1216
SetAppTitle(const std::string & title)1217 void PipelineContext::SetAppTitle(const std::string& title)
1218 {
1219 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1220 LOGW("SetAppTitle failed, Window modal is not container.");
1221 return;
1222 }
1223 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1224 CHECK_NULL_VOID(containerNode);
1225 containerNode->GetPattern<ContainerModalPattern>()->SetAppTitle(title);
1226 }
1227
SetAppIcon(const RefPtr<PixelMap> & icon)1228 void PipelineContext::SetAppIcon(const RefPtr<PixelMap>& icon)
1229 {
1230 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1231 LOGW("SetAppIcon failed, Window modal is not container.");
1232 return;
1233 }
1234 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1235 CHECK_NULL_VOID(containerNode);
1236 containerNode->GetPattern<ContainerModalPattern>()->SetAppIcon(icon);
1237 }
1238
FlushReload()1239 void PipelineContext::FlushReload()
1240 {
1241 LOGI("PipelineContext::FlushReload.");
1242 AnimationOption option;
1243 const int32_t duration = 400;
1244 option.SetDuration(duration);
1245 option.SetCurve(Curves::FRICTION);
1246 AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
1247 auto pipeline = weak.Upgrade();
1248 CHECK_NULL_VOID(pipeline);
1249 pipeline->stageManager_->ReloadStage();
1250 pipeline->FlushUITasks();
1251 });
1252 }
1253
Destroy()1254 void PipelineContext::Destroy()
1255 {
1256 CHECK_RUN_ON(UI);
1257 LOGI("PipelineContext::Destroy begin.");
1258 taskScheduler_.CleanUp();
1259 scheduleTasks_.clear();
1260 dirtyNodes_.clear();
1261 rootNode_.Reset();
1262 stageManager_.Reset();
1263 overlayManager_.Reset();
1264 sharedTransitionManager_.Reset();
1265 dragDropManager_.Reset();
1266 selectOverlayManager_.Reset();
1267 fullScreenManager_.Reset();
1268 touchEvents_.clear();
1269 buildFinishCallbacks_.clear();
1270 onWindowStateChangedCallbacks_.clear();
1271 onWindowFocusChangedCallbacks_.clear();
1272 nodesToNotifyMemoryLevel_.clear();
1273 dirtyFocusNode_.Reset();
1274 dirtyFocusScope_.Reset();
1275 PipelineBase::Destroy();
1276 LOGI("PipelineContext::Destroy end.");
1277 }
1278
AddBuildFinishCallBack(std::function<void ()> && callback)1279 void PipelineContext::AddBuildFinishCallBack(std::function<void()>&& callback)
1280 {
1281 buildFinishCallbacks_.emplace_back(std::move(callback));
1282 }
1283
AddWindowStateChangedCallback(int32_t nodeId)1284 void PipelineContext::AddWindowStateChangedCallback(int32_t nodeId)
1285 {
1286 onWindowStateChangedCallbacks_.emplace_back(nodeId);
1287 }
1288
RemoveWindowStateChangedCallback(int32_t nodeId)1289 void PipelineContext::RemoveWindowStateChangedCallback(int32_t nodeId)
1290 {
1291 onWindowStateChangedCallbacks_.remove(nodeId);
1292 }
1293
FlushWindowStateChangedCallback(bool isShow)1294 void PipelineContext::FlushWindowStateChangedCallback(bool isShow)
1295 {
1296 auto iter = onWindowStateChangedCallbacks_.begin();
1297 while (iter != onWindowStateChangedCallbacks_.end()) {
1298 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1299 if (!node) {
1300 iter = onWindowStateChangedCallbacks_.erase(iter);
1301 } else {
1302 if (isShow) {
1303 node->OnWindowShow();
1304 } else {
1305 node->OnWindowHide();
1306 }
1307 ++iter;
1308 }
1309 }
1310 }
1311
AddWindowFocusChangedCallback(int32_t nodeId)1312 void PipelineContext::AddWindowFocusChangedCallback(int32_t nodeId)
1313 {
1314 onWindowFocusChangedCallbacks_.emplace_back(nodeId);
1315 }
1316
RemoveWindowFocusChangedCallback(int32_t nodeId)1317 void PipelineContext::RemoveWindowFocusChangedCallback(int32_t nodeId)
1318 {
1319 onWindowFocusChangedCallbacks_.remove(nodeId);
1320 }
1321
FlushWindowFocusChangedCallback(bool isFocus)1322 void PipelineContext::FlushWindowFocusChangedCallback(bool isFocus)
1323 {
1324 auto iter = onWindowFocusChangedCallbacks_.begin();
1325 while (iter != onWindowFocusChangedCallbacks_.end()) {
1326 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1327 if (!node) {
1328 iter = onWindowFocusChangedCallbacks_.erase(iter);
1329 } else {
1330 if (isFocus) {
1331 node->OnWindowFocused();
1332 } else {
1333 node->OnWindowUnfocused();
1334 }
1335 ++iter;
1336 }
1337 }
1338 }
1339
OnDragEvent(int32_t x,int32_t y,DragEventAction action)1340 void PipelineContext::OnDragEvent(int32_t x, int32_t y, DragEventAction action)
1341 {
1342 auto manager = GetDragDropManager();
1343 CHECK_NULL_VOID(manager);
1344 if (manager->IsDragged()) {
1345 LOGI("current context is the source of drag");
1346 return;
1347 }
1348
1349 std::string extraInfo;
1350 manager->GetExtraInfoFromClipboard(extraInfo);
1351
1352 if (action == DragEventAction::DRAG_EVENT_END) {
1353 manager->OnDragEnd(static_cast<float>(x), static_cast<float>(y), extraInfo);
1354 manager->RestoreClipboardData();
1355 return;
1356 }
1357
1358 manager->OnDragMove(static_cast<float>(x), static_cast<float>(y), extraInfo);
1359 }
1360
AddNodesToNotifyMemoryLevel(int32_t nodeId)1361 void PipelineContext::AddNodesToNotifyMemoryLevel(int32_t nodeId)
1362 {
1363 nodesToNotifyMemoryLevel_.emplace_back(nodeId);
1364 }
1365
RemoveNodesToNotifyMemoryLevel(int32_t nodeId)1366 void PipelineContext::RemoveNodesToNotifyMemoryLevel(int32_t nodeId)
1367 {
1368 nodesToNotifyMemoryLevel_.remove(nodeId);
1369 }
1370
NotifyMemoryLevel(int32_t level)1371 void PipelineContext::NotifyMemoryLevel(int32_t level)
1372 {
1373 LOGI("PipelineContext: NotifyMemoryLevel called");
1374 auto iter = nodesToNotifyMemoryLevel_.begin();
1375 while (iter != nodesToNotifyMemoryLevel_.end()) {
1376 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1377 if (!node) {
1378 iter = nodesToNotifyMemoryLevel_.erase(iter);
1379 } else {
1380 node->OnNotifyMemoryLevel(level);
1381 }
1382 ++iter;
1383 }
1384 }
AddPredictTask(PredictTask && task)1385 void PipelineContext::AddPredictTask(PredictTask&& task)
1386 {
1387 taskScheduler_.AddPredictTask(std::move(task));
1388 window_->RequestFrame();
1389 }
1390
OnIdle(int64_t deadline)1391 void PipelineContext::OnIdle(int64_t deadline)
1392 {
1393 if (deadline == 0) {
1394 return;
1395 }
1396 CHECK_RUN_ON(UI);
1397 ACE_SCOPED_TRACE("OnIdle, targettime:%" PRId64 "", deadline);
1398 taskScheduler_.FlushPredictTask(deadline - TIME_THRESHOLD);
1399 }
1400
Finish(bool) const1401 void PipelineContext::Finish(bool /*autoFinish*/) const
1402 {
1403 CHECK_RUN_ON(UI);
1404 if (finishEventHandler_) {
1405 LOGI("call finishEventHandler");
1406 finishEventHandler_();
1407 } else {
1408 LOGE("fail to finish current context due to handler is nullptr");
1409 }
1410 }
1411
AddAfterLayoutTask(std::function<void ()> && task)1412 void PipelineContext::AddAfterLayoutTask(std::function<void()>&& task)
1413 {
1414 taskScheduler_.AddAfterLayoutTask(std::move(task));
1415 }
1416
1417 } // namespace OHOS::Ace::NG
1418