• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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