1 /*
2 * Copyright (c) 2023 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 <algorithm>
19 #include <cinttypes>
20 #include <cstdint>
21 #include <memory>
22
23 #ifdef ENABLE_ROSEN_BACKEND
24 #include "render_service_client/core/transaction/rs_transaction.h"
25 #include "render_service_client/core/ui/rs_ui_director.h"
26
27 #endif
28
29 #include "base/geometry/ng/offset_t.h"
30 #include "base/geometry/ng/rect_t.h"
31 #include "base/log/ace_trace.h"
32 #include "base/log/ace_tracker.h"
33 #include "base/log/dump_log.h"
34 #include "base/log/event_report.h"
35 #include "base/memory/ace_type.h"
36 #include "base/memory/referenced.h"
37 #include "base/ressched/ressched_report.h"
38 #include "base/thread/task_executor.h"
39 #include "base/utils/time_util.h"
40 #include "base/utils/utils.h"
41 #include "core/animation/scheduler.h"
42 #include "core/common/ace_application_info.h"
43 #include "core/common/container.h"
44 #include "core/common/font_manager.h"
45 #include "core/common/layout_inspector.h"
46 #include "core/common/text_field_manager.h"
47 #include "core/common/thread_checker.h"
48 #include "core/common/window.h"
49 #include "core/components/common/layout/screen_system_manager.h"
50 #include "core/components_ng/base/frame_node.h"
51 #include "core/components_ng/base/ui_node.h"
52 #include "core/components_ng/pattern/app_bar/app_bar_view.h"
53 #include "core/components_ng/pattern/container_modal/container_modal_pattern.h"
54 #include "core/components_ng/pattern/container_modal/container_modal_view.h"
55 #include "core/components_ng/pattern/container_modal/container_modal_view_factory.h"
56 #include "core/components_ng/pattern/custom/custom_node_base.h"
57 #include "core/components_ng/pattern/image/image_layout_property.h"
58 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
59 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
60 #include "core/components_ng/pattern/navigation/title_bar_node.h"
61 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
62 #include "core/components_ng/pattern/overlay/overlay_manager.h"
63 #include "core/components_ng/pattern/root/root_pattern.h"
64 #include "core/components_ng/pattern/stage/stage_pattern.h"
65 #include "core/components_ng/pattern/text_field/text_field_manager.h"
66 #include "core/components_ng/property/calc_length.h"
67 #include "core/components_ng/property/measure_property.h"
68 #include "core/components_ng/property/safe_area_insets.h"
69 #include "core/components_v2/inspector/inspector_constants.h"
70 #include "core/event/ace_events.h"
71 #include "core/event/touch_event.h"
72 #include "core/pipeline/base/element_register.h"
73 #include "core/pipeline/pipeline_context.h"
74 #include "core/pipeline_ng/ui_task_scheduler.h"
75
76 namespace {
77 constexpr int32_t TIME_THRESHOLD = 2 * 1000000; // 3 millisecond
78 constexpr int32_t PLATFORM_VERSION_TEN = 10;
79 constexpr int32_t MILLISECONDS_TO_NANOSECONDS = 1000000; // Milliseconds to nanoseconds
80 } // namespace
81
82 namespace OHOS::Ace::NG {
83
PipelineContext(std::shared_ptr<Window> window,RefPtr<TaskExecutor> taskExecutor,RefPtr<AssetManager> assetManager,RefPtr<PlatformResRegister> platformResRegister,const RefPtr<Frontend> & frontend,int32_t instanceId)84 PipelineContext::PipelineContext(std::shared_ptr<Window> window, RefPtr<TaskExecutor> taskExecutor,
85 RefPtr<AssetManager> assetManager, RefPtr<PlatformResRegister> platformResRegister,
86 const RefPtr<Frontend>& frontend, int32_t instanceId)
87 : PipelineBase(window, std::move(taskExecutor), std::move(assetManager), frontend, instanceId, platformResRegister)
88 {
89 window_->OnHide();
90 }
91
PipelineContext(std::shared_ptr<Window> window,RefPtr<TaskExecutor> taskExecutor,RefPtr<AssetManager> assetManager,const RefPtr<Frontend> & frontend,int32_t instanceId)92 PipelineContext::PipelineContext(std::shared_ptr<Window> window, RefPtr<TaskExecutor> taskExecutor,
93 RefPtr<AssetManager> assetManager, const RefPtr<Frontend>& frontend, int32_t instanceId)
94 : PipelineBase(window, std::move(taskExecutor), std::move(assetManager), frontend, instanceId)
95 {
96 window_->OnHide();
97 }
98
GetCurrentContext()99 RefPtr<PipelineContext> PipelineContext::GetCurrentContext()
100 {
101 auto currentContainer = Container::Current();
102 CHECK_NULL_RETURN(currentContainer, nullptr);
103 return DynamicCast<PipelineContext>(currentContainer->GetPipelineContext());
104 }
105
GetCurrentRootWidth()106 float PipelineContext::GetCurrentRootWidth()
107 {
108 auto context = GetCurrentContext();
109 CHECK_NULL_RETURN(context, 0.0f);
110 return static_cast<float>(context->rootWidth_);
111 }
112
GetCurrentRootHeight()113 float PipelineContext::GetCurrentRootHeight()
114 {
115 auto context = GetCurrentContext();
116 CHECK_NULL_RETURN(context, 0.0f);
117 return static_cast<float>(context->rootHeight_);
118 }
119
AddDirtyCustomNode(const RefPtr<UINode> & dirtyNode)120 void PipelineContext::AddDirtyCustomNode(const RefPtr<UINode>& dirtyNode)
121 {
122 CHECK_RUN_ON(UI);
123 CHECK_NULL_VOID(dirtyNode);
124 dirtyNodes_.emplace(dirtyNode);
125 hasIdleTasks_ = true;
126 RequestFrame();
127 }
128
AddDirtyLayoutNode(const RefPtr<FrameNode> & dirty)129 void PipelineContext::AddDirtyLayoutNode(const RefPtr<FrameNode>& dirty)
130 {
131 CHECK_RUN_ON(UI);
132 CHECK_NULL_VOID(dirty);
133 taskScheduler_->AddDirtyLayoutNode(dirty);
134 ForceLayoutForImplicitAnimation();
135 #ifdef UICAST_COMPONENT_SUPPORTED
136 do {
137 auto container = Container::Current();
138 CHECK_NULL_BREAK(container);
139 auto distributedUI = container->GetDistributedUI();
140 CHECK_NULL_BREAK(distributedUI);
141 distributedUI->AddDirtyLayoutNode(dirty->GetId());
142 } while (false);
143 #endif
144 hasIdleTasks_ = true;
145 RequestFrame();
146 }
147
AddDirtyRenderNode(const RefPtr<FrameNode> & dirty)148 void PipelineContext::AddDirtyRenderNode(const RefPtr<FrameNode>& dirty)
149 {
150 CHECK_RUN_ON(UI);
151 CHECK_NULL_VOID(dirty);
152 taskScheduler_->AddDirtyRenderNode(dirty);
153 ForceRenderForImplicitAnimation();
154 #ifdef UICAST_COMPONENT_SUPPORTED
155 do {
156 auto container = Container::Current();
157 CHECK_NULL_BREAK(container);
158 auto distributedUI = container->GetDistributedUI();
159 CHECK_NULL_BREAK(distributedUI);
160 distributedUI->AddDirtyRenderNode(dirty->GetId());
161 } while (false);
162 #endif
163 hasIdleTasks_ = true;
164 RequestFrame();
165 }
166
FlushDirtyNodeUpdate()167 void PipelineContext::FlushDirtyNodeUpdate()
168 {
169 CHECK_RUN_ON(UI);
170 ACE_FUNCTION_TRACE();
171 if (FrameReport::GetInstance().GetEnable()) {
172 FrameReport::GetInstance().BeginFlushBuild();
173 }
174
175 // SomeTimes, customNode->Update may add some dirty custom nodes to dirtyNodes_,
176 // use maxFlushTimes to avoid dead cycle.
177 int maxFlushTimes = 3;
178 while (!dirtyNodes_.empty() && maxFlushTimes > 0) {
179 decltype(dirtyNodes_) dirtyNodes(std::move(dirtyNodes_));
180 for (const auto& node : dirtyNodes) {
181 if (AceType::InstanceOf<NG::CustomNodeBase>(node)) {
182 auto customNode = AceType::DynamicCast<NG::CustomNodeBase>(node);
183 ACE_SCOPED_TRACE("CustomNodeUpdate %s", customNode->GetJSViewName().c_str());
184 customNode->Update();
185 }
186 }
187 --maxFlushTimes;
188 }
189 if (!dirtyNodes_.empty()) {
190 LOGW("FlushDirtyNodeUpdate 3 times, still has dirty nodes");
191 }
192
193 if (FrameReport::GetInstance().GetEnable()) {
194 FrameReport::GetInstance().EndFlushBuild();
195 }
196 }
197
AddScheduleTask(const RefPtr<ScheduleTask> & task)198 uint32_t PipelineContext::AddScheduleTask(const RefPtr<ScheduleTask>& task)
199 {
200 CHECK_RUN_ON(UI);
201 scheduleTasks_.try_emplace(++nextScheduleTaskId_, task);
202 RequestFrame();
203 return nextScheduleTaskId_;
204 }
205
RemoveScheduleTask(uint32_t id)206 void PipelineContext::RemoveScheduleTask(uint32_t id)
207 {
208 CHECK_RUN_ON(UI);
209 scheduleTasks_.erase(id);
210 }
211
FlushVsync(uint64_t nanoTimestamp,uint32_t frameCount)212 void PipelineContext::FlushVsync(uint64_t nanoTimestamp, uint32_t frameCount)
213 {
214 CHECK_RUN_ON(UI);
215 ACE_FUNCTION_TRACE();
216 auto recvTime = GetSysTimestamp();
217 static const std::string abilityName = AceApplicationInfo::GetInstance().GetProcessName().empty()
218 ? AceApplicationInfo::GetInstance().GetPackageName()
219 : AceApplicationInfo::GetInstance().GetProcessName();
220 window_->RecordFrameTime(nanoTimestamp, abilityName);
221 FlushFrameTrace();
222 #ifdef UICAST_COMPONENT_SUPPORTED
223 do {
224 auto container = Container::Current();
225 CHECK_NULL_BREAK(container);
226 auto distributedUI = container->GetDistributedUI();
227 CHECK_NULL_BREAK(distributedUI);
228 distributedUI->ApplyOneUpdate();
229 } while (false);
230 #endif
231 ProcessDelayTasks();
232 FlushAnimation(GetTimeFromExternalTimer());
233 FlushTouchEvents();
234 FlushBuild();
235 if (isFormRender_ && drawDelegate_ && rootNode_) {
236 auto renderContext = AceType::DynamicCast<NG::RenderContext>(rootNode_->GetRenderContext());
237 drawDelegate_->DrawRSFrame(renderContext);
238 drawDelegate_ = nullptr;
239 }
240 if (!taskScheduler_->isEmpty()) {
241 #if !defined(PREVIEW)
242 LayoutInspector::SupportInspector();
243 #endif
244 }
245
246 taskScheduler_->StartRecordFrameInfo(GetCurrentFrameInfo(recvTime, nanoTimestamp));
247 taskScheduler_->FlushTask();
248 taskScheduler_->FinishRecordFrameInfo();
249 FlushAnimationClosure();
250 TryCallNextFrameLayoutCallback();
251
252 #ifdef UICAST_COMPONENT_SUPPORTED
253 do {
254 auto container = Container::Current();
255 CHECK_NULL_BREAK(container);
256 auto distributedUI = container->GetDistributedUI();
257 CHECK_NULL_BREAK(distributedUI);
258 distributedUI->OnTreeUpdate();
259 } while (false);
260 #endif
261
262 bool hasAnimation = window_->FlushCustomAnimation(nanoTimestamp);
263 if (hasAnimation) {
264 RequestFrame();
265 }
266 if (dragCleanTask_) {
267 dragCleanTask_();
268 dragCleanTask_ = nullptr;
269 }
270 FlushMessages();
271 InspectDrew();
272 if (!isFormRender_ && onShow_ && onFocus_) {
273 FlushFocus();
274 }
275 HandleOnAreaChangeEvent();
276 HandleVisibleAreaChangeEvent();
277 if (isNeedFlushMouseEvent_) {
278 FlushMouseEvent();
279 isNeedFlushMouseEvent_ = false;
280 }
281 needRenderNode_.clear();
282 taskScheduler_->FlushAfterRenderTask();
283 // Keep the call sent at the end of the function
284 if (FrameReport::GetInstance().GetEnable()) {
285 FrameReport::GetInstance().FlushEnd();
286 }
287 ResSchedReport::GetInstance().LoadPageEvent(ResDefine::LOAD_PAGE_COMPLETE_EVENT);
288 }
289
InspectDrew()290 void PipelineContext::InspectDrew()
291 {
292 CHECK_RUN_ON(UI);
293 if (!needRenderNode_.empty()) {
294 auto needRenderNode = std::move(needRenderNode_);
295 for (auto&& node : needRenderNode) {
296 if (node) {
297 OnDrawCompleted(node->GetInspectorId()->c_str());
298 }
299 }
300 }
301 }
302
ProcessDelayTasks()303 void PipelineContext::ProcessDelayTasks()
304 {
305 if (delayedTasks_.empty()) {
306 return;
307 }
308 auto currentTimeStamp = GetSysTimestamp();
309 auto delayedTasks = std::move(delayedTasks_);
310 auto result = std::remove_if(delayedTasks.begin(), delayedTasks.end(), [this, currentTimeStamp](const auto& task) {
311 if (task.timeStamp + static_cast<int64_t>(task.time) * MILLISECONDS_TO_NANOSECONDS > currentTimeStamp) {
312 delayedTasks_.emplace_back(task);
313 return true;
314 }
315 return false;
316 });
317 delayedTasks.erase(result, delayedTasks.end());
318 std::for_each(delayedTasks.begin(), delayedTasks.end(), [this](auto& delayedTask) {
319 if (delayedTask.task) {
320 delayedTask.task();
321 }
322 });
323 }
324
FlushFrameTrace()325 void PipelineContext::FlushFrameTrace()
326 {
327 if (FrameReport::GetInstance().GetEnable()) {
328 FrameReport::GetInstance().FlushBegin();
329 }
330 }
331
FlushAnimation(uint64_t nanoTimestamp)332 void PipelineContext::FlushAnimation(uint64_t nanoTimestamp)
333 {
334 CHECK_RUN_ON(UI);
335 ACE_FUNCTION_TRACE();
336 if (scheduleTasks_.empty()) {
337 return;
338 }
339
340 if (FrameReport::GetInstance().GetEnable()) {
341 FrameReport::GetInstance().BeginFlushAnimation();
342 }
343
344 decltype(scheduleTasks_) temp(std::move(scheduleTasks_));
345 for (const auto& [id, weakTask] : temp) {
346 auto task = weakTask.Upgrade();
347 if (task) {
348 task->OnFrame(nanoTimestamp);
349 }
350 }
351
352 if (FrameReport::GetInstance().GetEnable()) {
353 FrameReport::GetInstance().EndFlushAnimation();
354 }
355 }
356
FlushMessages()357 void PipelineContext::FlushMessages()
358 {
359 ACE_FUNCTION_TRACE();
360 window_->FlushTasks();
361 }
362
SetNeedRenderNode(const RefPtr<FrameNode> & node)363 void PipelineContext::SetNeedRenderNode(const RefPtr<FrameNode>& node)
364 {
365 CHECK_RUN_ON(UI);
366 needRenderNode_.insert(node);
367 }
368
NotifyConfigurationChange(const OnConfigurationChange & configurationChange)369 void PipelineContext::NotifyConfigurationChange(const OnConfigurationChange& configurationChange)
370 {
371 LOGI("NotifyConfigurationChange");
372 auto rootNode = GetRootElement();
373 rootNode->UpdateConfigurationUpdate(configurationChange);
374 PipelineBase::NotifyConfigurationChange(configurationChange);
375 }
376
FlushFocus()377 void PipelineContext::FlushFocus()
378 {
379 CHECK_RUN_ON(UI);
380 ACE_FUNCTION_TRACK();
381 ACE_FUNCTION_TRACE();
382
383 auto defaultFocusNode = dirtyDefaultFocusNode_.Upgrade();
384 if (!defaultFocusNode) {
385 dirtyDefaultFocusNode_.Reset();
386 } else {
387 auto focusNodeHub = defaultFocusNode->GetFocusHub();
388 if (focusNodeHub) {
389 auto defaultFocusNode = focusNodeHub->GetChildFocusNodeByType();
390 if (defaultFocusNode && defaultFocusNode->IsFocusableWholePath()) {
391 defaultFocusNode->RequestFocusImmediately();
392 } else {
393 focusNodeHub->RequestFocusImmediately();
394 }
395 }
396 dirtyFocusNode_.Reset();
397 dirtyFocusScope_.Reset();
398 dirtyDefaultFocusNode_.Reset();
399 return;
400 }
401
402 auto focusNode = dirtyFocusNode_.Upgrade();
403 if (!focusNode || focusNode->GetFocusType() != FocusType::NODE) {
404 dirtyFocusNode_.Reset();
405 } else {
406 auto focusNodeHub = focusNode->GetFocusHub();
407 if (focusNodeHub) {
408 focusNodeHub->RequestFocusImmediately();
409 }
410 dirtyFocusNode_.Reset();
411 dirtyFocusScope_.Reset();
412 dirtyDefaultFocusNode_.Reset();
413 return;
414 }
415 auto focusScope = dirtyFocusScope_.Upgrade();
416 if (!focusScope || focusScope->GetFocusType() != FocusType::SCOPE) {
417 dirtyFocusScope_.Reset();
418 } else {
419 auto focusScopeHub = focusScope->GetFocusHub();
420 if (focusScopeHub) {
421 focusScopeHub->RequestFocusImmediately();
422 }
423 dirtyFocusNode_.Reset();
424 dirtyFocusScope_.Reset();
425 dirtyDefaultFocusNode_.Reset();
426 return;
427 }
428 if (isRootFocusNeedUpdate_ && rootNode_ && rootNode_->GetFocusHub()) {
429 auto rootFocusHub = rootNode_->GetFocusHub();
430 if (!rootFocusHub->IsCurrentFocus()) {
431 rootFocusHub->RequestFocusImmediately();
432 } else if (!rootFocusHub->IsCurrentFocusWholePath()) {
433 rootFocusHub->LostFocus();
434 rootFocusHub->RequestFocusImmediately();
435 }
436 isRootFocusNeedUpdate_ = false;
437 }
438 }
439
FlushPipelineImmediately()440 void PipelineContext::FlushPipelineImmediately()
441 {
442 CHECK_RUN_ON(UI);
443 ACE_FUNCTION_TRACE();
444 FlushPipelineWithoutAnimation();
445 }
446
FlushPipelineWithoutAnimation()447 void PipelineContext::FlushPipelineWithoutAnimation()
448 {
449 ACE_FUNCTION_TRACE();
450 FlushBuild();
451 FlushTouchEvents();
452 taskScheduler_->FlushTask();
453 FlushAnimationClosure();
454 FlushMessages();
455 FlushFocus();
456 }
457
FlushBuild()458 void PipelineContext::FlushBuild()
459 {
460 isRebuildFinished_ = false;
461 FlushDirtyNodeUpdate();
462 isRebuildFinished_ = true;
463 FlushBuildFinishCallbacks();
464 }
465
AddAnimationClosure(std::function<void ()> && animation)466 void PipelineContext::AddAnimationClosure(std::function<void()>&& animation)
467 {
468 animationClosuresList_.emplace_back(std::move(animation));
469 }
470
FlushAnimationClosure()471 void PipelineContext::FlushAnimationClosure()
472 {
473 if (animationClosuresList_.empty()) {
474 return;
475 }
476 taskScheduler_->FlushTask();
477
478 decltype(animationClosuresList_) temp(std::move(animationClosuresList_));
479 auto scheduler = std::move(taskScheduler_);
480 taskScheduler_ = std::make_unique<UITaskScheduler>();
481 for (const auto& animation : temp) {
482 animation();
483 taskScheduler_->CleanUp();
484 }
485 taskScheduler_ = std::move(scheduler);
486 }
487
FlushBuildFinishCallbacks()488 void PipelineContext::FlushBuildFinishCallbacks()
489 {
490 decltype(buildFinishCallbacks_) buildFinishCallbacks(std::move(buildFinishCallbacks_));
491 for (const auto& func : buildFinishCallbacks) {
492 if (func) {
493 func();
494 }
495 }
496 }
497
RegisterRootEvent()498 void PipelineContext::RegisterRootEvent()
499 {
500 if (!IsFormRender()) {
501 return;
502 }
503
504 // To avoid conflicts between longPress and click events on the card,
505 // use an empty longPress event placeholder in the EtsCard scenario
506 auto hub = rootNode_->GetOrCreateGestureEventHub();
507 CHECK_NULL_VOID(hub);
508 auto event = [](const GestureEvent& info) mutable { LOGD("Not Support LongPress"); };
509 auto longPress = AceType::MakeRefPtr<NG::LongPressEvent>(std::move(event));
510 hub->SetLongPressEvent(longPress, false, true);
511 }
512
SetupRootElement()513 void PipelineContext::SetupRootElement()
514 {
515 CHECK_RUN_ON(UI);
516 rootNode_ = FrameNode::CreateFrameNodeWithTree(
517 V2::ROOT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<RootPattern>());
518 rootNode_->SetHostRootId(GetInstanceId());
519 rootNode_->SetHostPageId(-1);
520 rootNode_->SetActive(true);
521 RegisterRootEvent();
522 CalcSize idealSize { CalcLength(rootWidth_), CalcLength(rootHeight_) };
523 MeasureProperty layoutConstraint;
524 layoutConstraint.selfIdealSize = idealSize;
525 layoutConstraint.maxSize = idealSize;
526 rootNode_->UpdateLayoutConstraint(layoutConstraint);
527 auto rootFocusHub = rootNode_->GetOrCreateFocusHub();
528 rootFocusHub->SetFocusType(FocusType::SCOPE);
529 rootFocusHub->SetFocusable(true);
530 window_->SetRootFrameNode(rootNode_);
531 rootNode_->AttachToMainTree();
532
533 auto stageNode = FrameNode::CreateFrameNode(
534 V2::STAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<StagePattern>());
535 auto atomicService = installationFree_ ? AppBarView::Create(stageNode) : nullptr;
536 if (windowModal_ == WindowModal::CONTAINER_MODAL) {
537 MaximizeMode maximizeMode = GetWindowManager()->GetWindowMaximizeMode();
538 rootNode_->AddChild(
539 ContainerModalViewFactory::GetView(atomicService ? atomicService : stageNode, maximizeMode));
540 } else {
541 rootNode_->AddChild(atomicService ? atomicService : stageNode);
542 }
543 #ifdef ENABLE_ROSEN_BACKEND
544 if (!IsJsCard() && !isFormRender_) {
545 auto window = GetWindow();
546 if (window) {
547 auto rsUIDirector = window->GetRSUIDirector();
548 if (rsUIDirector) {
549 rsUIDirector->SetAbilityBGAlpha(appBgColor_.GetAlpha());
550 }
551 }
552 }
553 #endif
554 stageManager_ = MakeRefPtr<StageManager>(stageNode);
555 overlayManager_ = MakeRefPtr<OverlayManager>(
556 DynamicCast<FrameNode>(installationFree_ ? stageNode->GetParent()->GetParent() : stageNode->GetParent()));
557 fullScreenManager_ = MakeRefPtr<FullScreenManager>(rootNode_);
558 selectOverlayManager_ = MakeRefPtr<SelectOverlayManager>(rootNode_);
559 dragDropManager_ = MakeRefPtr<DragDropManager>();
560 sharedTransitionManager_ = MakeRefPtr<SharedOverlayManager>(
561 DynamicCast<FrameNode>(installationFree_ ? stageNode->GetParent()->GetParent() : stageNode->GetParent()));
562
563 OnAreaChangedFunc onAreaChangedFunc = [weakOverlayManger = AceType::WeakClaim(AceType::RawPtr(overlayManager_))](
564 const RectF& /* oldRect */, const OffsetF& /* oldOrigin */,
565 const RectF& /* rect */, const OffsetF& /* origin */) {
566 auto overlay = weakOverlayManger.Upgrade();
567 CHECK_NULL_VOID(overlay);
568 overlay->HideAllMenus();
569 overlay->HideCustomPopups();
570 };
571 rootNode_->SetOnAreaChangeCallback(std::move(onAreaChangedFunc));
572 AddOnAreaChangeNode(rootNode_->GetId());
573
574 LOGI("SetupRootElement success!");
575 }
576
SetupSubRootElement()577 void PipelineContext::SetupSubRootElement()
578 {
579 CHECK_RUN_ON(UI);
580 appBgColor_ = Color::TRANSPARENT;
581 rootNode_ = FrameNode::CreateFrameNodeWithTree(
582 V2::ROOT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<RootPattern>());
583 rootNode_->SetHostRootId(GetInstanceId());
584 rootNode_->SetHostPageId(-1);
585 rootNode_->SetActive(true);
586 CalcSize idealSize { CalcLength(rootWidth_), CalcLength(rootHeight_) };
587 MeasureProperty layoutConstraint;
588 layoutConstraint.selfIdealSize = idealSize;
589 layoutConstraint.maxSize = idealSize;
590 rootNode_->UpdateLayoutConstraint(layoutConstraint);
591 auto rootFocusHub = rootNode_->GetOrCreateFocusHub();
592 rootFocusHub->SetFocusType(FocusType::SCOPE);
593 rootFocusHub->SetFocusable(true);
594 window_->SetRootFrameNode(rootNode_);
595 rootNode_->AttachToMainTree();
596
597 #ifdef ENABLE_ROSEN_BACKEND
598 if (!IsJsCard()) {
599 auto window = GetWindow();
600 if (window) {
601 auto rsUIDirector = window->GetRSUIDirector();
602 if (rsUIDirector) {
603 rsUIDirector->SetAbilityBGAlpha(appBgColor_.GetAlpha());
604 }
605 }
606 }
607 #endif
608 // the subwindow for overlay not need stage
609 stageManager_ = MakeRefPtr<StageManager>(nullptr);
610 overlayManager_ = MakeRefPtr<OverlayManager>(rootNode_);
611 fullScreenManager_ = MakeRefPtr<FullScreenManager>(rootNode_);
612 selectOverlayManager_ = MakeRefPtr<SelectOverlayManager>(rootNode_);
613 dragDropManager_ = MakeRefPtr<DragDropManager>();
614 }
615
GetStageManager()616 const RefPtr<StageManager>& PipelineContext::GetStageManager()
617 {
618 return stageManager_;
619 }
620
GetDragDropManager()621 const RefPtr<DragDropManager>& PipelineContext::GetDragDropManager()
622 {
623 return dragDropManager_;
624 }
625
GetSelectOverlayManager()626 const RefPtr<SelectOverlayManager>& PipelineContext::GetSelectOverlayManager()
627 {
628 return selectOverlayManager_;
629 }
630
GetOverlayManager()631 const RefPtr<OverlayManager>& PipelineContext::GetOverlayManager()
632 {
633 return overlayManager_;
634 }
635
GetFullScreenManager()636 const RefPtr<FullScreenManager>& PipelineContext::GetFullScreenManager()
637 {
638 return fullScreenManager_;
639 }
640
OnSurfaceChanged(int32_t width,int32_t height,WindowSizeChangeReason type,const std::shared_ptr<Rosen::RSTransaction> & rsTransaction)641 void PipelineContext::OnSurfaceChanged(int32_t width, int32_t height, WindowSizeChangeReason type,
642 const std::shared_ptr<Rosen::RSTransaction>& rsTransaction)
643 {
644 CHECK_RUN_ON(UI);
645 LOGD("PipelineContext: OnSurfaceChanged start.");
646 if (NearEqual(rootWidth_, width) && NearEqual(rootHeight_, height) &&
647 type == WindowSizeChangeReason::CUSTOM_ANIMATION) {
648 TryCallNextFrameLayoutCallback();
649 return;
650 }
651 ExecuteSurfaceChangedCallbacks(width, height, type);
652 // TODO: add adjust for textFieldManager when ime is show.
653 auto callback = [weakFrontend = weakFrontend_, width, height]() {
654 auto frontend = weakFrontend.Upgrade();
655 if (frontend) {
656 frontend->OnSurfaceChanged(width, height);
657 }
658 };
659 auto container = Container::Current();
660 if (!container) {
661 return;
662 }
663 if (container->IsUseStageModel()) {
664 callback();
665 FlushBuild();
666 } else {
667 taskExecutor_->PostTask(callback, TaskExecutor::TaskType::JS);
668 }
669
670 FlushWindowSizeChangeCallback(width, height, type);
671
672 #ifdef ENABLE_ROSEN_BACKEND
673 StartWindowSizeChangeAnimate(width, height, type, rsTransaction);
674 #else
675 SetRootRect(width, height, 0.0);
676 #endif
677 }
678
OnLayoutCompleted(const std::string & componentId)679 void PipelineContext::OnLayoutCompleted(const std::string& componentId)
680 {
681 CHECK_RUN_ON(UI);
682 auto frontend = weakFrontend_.Upgrade();
683 if (frontend) {
684 frontend->OnLayoutCompleted(componentId);
685 }
686 }
687
OnDrawCompleted(const std::string & componentId)688 void PipelineContext::OnDrawCompleted(const std::string& componentId)
689 {
690 CHECK_RUN_ON(UI);
691 auto frontend = weakFrontend_.Upgrade();
692 if (frontend) {
693 frontend->OnDrawCompleted(componentId);
694 }
695 }
696
ExecuteSurfaceChangedCallbacks(int32_t newWidth,int32_t newHeight,WindowSizeChangeReason type)697 void PipelineContext::ExecuteSurfaceChangedCallbacks(int32_t newWidth, int32_t newHeight, WindowSizeChangeReason type)
698 {
699 for (auto&& [id, callback] : surfaceChangedCallbackMap_) {
700 if (callback) {
701 callback(newWidth, newHeight, rootWidth_, rootHeight_, type);
702 }
703 }
704 }
705
OnSurfacePositionChanged(int32_t posX,int32_t posY)706 void PipelineContext::OnSurfacePositionChanged(int32_t posX, int32_t posY)
707 {
708 for (auto&& [id, callback] : surfacePositionChangedCallbackMap_) {
709 if (callback) {
710 callback(posX, posY);
711 }
712 }
713 }
714
StartWindowSizeChangeAnimate(int32_t width,int32_t height,WindowSizeChangeReason type,const std::shared_ptr<Rosen::RSTransaction> & rsTransaction)715 void PipelineContext::StartWindowSizeChangeAnimate(int32_t width, int32_t height, WindowSizeChangeReason type,
716 const std::shared_ptr<Rosen::RSTransaction>& rsTransaction)
717 {
718 static const bool IsWindowSizeAnimationEnabled = SystemProperties::IsWindowSizeAnimationEnabled();
719 if (!IsWindowSizeAnimationEnabled) {
720 LOGE("no animation configured");
721 SetRootRect(width, height, 0.0);
722 return;
723 }
724 switch (type) {
725 case WindowSizeChangeReason::RECOVER:
726 case WindowSizeChangeReason::MAXIMIZE: {
727 LOGI("PipelineContext::Root node RECOVER/MAXIMIZE animation, width = %{public}d, height = %{public}d",
728 width, height);
729 AnimationOption option;
730 constexpr int32_t duration = 400;
731 option.SetDuration(duration);
732 auto curve = MakeRefPtr<DecelerationCurve>();
733 option.SetCurve(curve);
734 auto weak = WeakClaim(this);
735 Animate(option, curve, [width, height, weak]() {
736 auto pipeline = weak.Upgrade();
737 CHECK_NULL_VOID(pipeline);
738 pipeline->SetRootRect(width, height, 0.0);
739 pipeline->FlushUITasks();
740 });
741 break;
742 }
743 case WindowSizeChangeReason::ROTATION: {
744 SetRootRect(width, height, 0.0);
745 FlushUITasks();
746 if (textFieldManager_) {
747 DynamicCast<TextFieldManagerNG>(textFieldManager_)->ScrollTextFieldToSafeArea();
748 }
749 FlushUITasks();
750 break;
751 }
752 case WindowSizeChangeReason::DRAG_START:
753 case WindowSizeChangeReason::DRAG:
754 case WindowSizeChangeReason::DRAG_END:
755 case WindowSizeChangeReason::RESIZE:
756 case WindowSizeChangeReason::UNDEFINED:
757 default: {
758 LOGD("PipelineContext::RootNodeAnimation : unsupported type, no animation added");
759 SetRootRect(width, height, 0.0f);
760 }
761 }
762 }
763
SetRootRect(double width,double height,double offset)764 void PipelineContext::SetRootRect(double width, double height, double offset)
765 {
766 LOGI("SetRootRect width %{public}f, height %{public}f, %{public}f", width, height, offset);
767 CHECK_RUN_ON(UI);
768 UpdateRootSizeAndScale(width, height);
769 CHECK_NULL_VOID(rootNode_);
770 ScreenSystemManager::GetInstance().SetWindowInfo(rootWidth_, density_, dipScale_);
771 ScreenSystemManager::GetInstance().OnSurfaceChanged(width);
772 SizeF sizeF { static_cast<float>(width), static_cast<float>(height) };
773 if (rootNode_->GetGeometryNode()->GetFrameSize() != sizeF || rootNode_->IsLayoutDirtyMarked()) {
774 CalcSize idealSize { CalcLength(width), CalcLength(height) };
775 MeasureProperty layoutConstraint;
776 layoutConstraint.selfIdealSize = idealSize;
777 layoutConstraint.maxSize = idealSize;
778 rootNode_->UpdateLayoutConstraint(layoutConstraint);
779 // reset parentLayoutConstraint to update itself when next measure task
780 rootNode_->GetGeometryNode()->ResetParentLayoutConstraint();
781 rootNode_->MarkDirtyNode();
782 }
783 if (rootNode_->GetGeometryNode()->GetFrameOffset().GetY() != offset) {
784 OffsetF newOffset = rootNode_->GetGeometryNode()->GetFrameOffset();
785 newOffset.SetY(static_cast<float>(offset));
786 rootNode_->GetGeometryNode()->SetMarginFrameOffset(newOffset);
787 auto rootContext = rootNode_->GetRenderContext();
788 rootContext->SyncGeometryProperties(RawPtr(rootNode_->GetGeometryNode()));
789 RequestFrame();
790 }
791 #if defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
792 // For cross-platform build, flush tasks when first resize, speed up for fisrt frame.
793 if (window_ && rootNode_->GetRenderContext() && !NearZero(width) && !NearZero(height)) {
794 rootNode_->GetRenderContext()->SetBounds(0.0, 0.0, width, height);
795 window_->FlushTasks();
796 FlushVsync(GetTimeFromExternalTimer(), 0);
797 }
798 #endif
799 }
800
UpdateSystemSafeArea(const SafeAreaInsets & systemSafeArea)801 void PipelineContext::UpdateSystemSafeArea(const SafeAreaInsets& systemSafeArea)
802 {
803 CHECK_NULL_VOID_NOLOG(minPlatformVersion_ >= PLATFORM_VERSION_TEN);
804 AnimationOption option;
805 CHECK_NULL_VOID_NOLOG(safeAreaManager_);
806 option.SetCurve(safeAreaManager_->GetSafeAreaCurve());
807 AnimationUtils::Animate(option, [weak = WeakClaim(this), systemSafeArea]() {
808 auto pipeline = weak.Upgrade();
809 CHECK_NULL_VOID_NOLOG(pipeline);
810 auto safeAreaManager = pipeline->GetSafeAreaManager();
811 CHECK_NULL_VOID_NOLOG(safeAreaManager);
812 if (safeAreaManager->UpdateSystemSafeArea(systemSafeArea)) {
813 pipeline->SyncSafeArea();
814 pipeline->FlushUITasks();
815 }
816 });
817 }
818
UpdateCutoutSafeArea(const SafeAreaInsets & cutoutSafeArea)819 void PipelineContext::UpdateCutoutSafeArea(const SafeAreaInsets& cutoutSafeArea)
820 {
821 CHECK_NULL_VOID_NOLOG(minPlatformVersion_ >= PLATFORM_VERSION_TEN);
822 AnimationOption option;
823 CHECK_NULL_VOID_NOLOG(safeAreaManager_);
824 option.SetCurve(safeAreaManager_->GetSafeAreaCurve());
825 AnimationUtils::Animate(option, [weak = WeakClaim(this), cutoutSafeArea]() {
826 auto pipeline = weak.Upgrade();
827 CHECK_NULL_VOID_NOLOG(pipeline);
828 auto safeAreaManager = pipeline->GetSafeAreaManager();
829 CHECK_NULL_VOID_NOLOG(safeAreaManager);
830 if (safeAreaManager->UpdateCutoutSafeArea(cutoutSafeArea)) {
831 pipeline->SyncSafeArea();
832 pipeline->FlushUITasks();
833 }
834 });
835 }
836
SetIgnoreViewSafeArea(bool value)837 void PipelineContext::SetIgnoreViewSafeArea(bool value)
838 {
839 if (safeAreaManager_->SetIgnoreSafeArea(value)) {
840 SyncSafeArea();
841 }
842 }
843
SetIsLayoutFullScreen(bool value)844 void PipelineContext::SetIsLayoutFullScreen(bool value)
845 {
846 if (safeAreaManager_->SetIsFullScreen(value)) {
847 SyncSafeArea();
848 }
849 }
850
GetSafeArea() const851 PipelineBase::SafeAreaInsets PipelineContext::GetSafeArea() const
852 {
853 return safeAreaManager_->GetSafeArea();
854 }
855
SyncSafeArea(bool onKeyboard)856 void PipelineContext::SyncSafeArea(bool onKeyboard)
857 {
858 CHECK_NULL_VOID_NOLOG(rootNode_);
859 rootNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
860 CHECK_NULL_VOID_NOLOG(stageManager_);
861 auto page = stageManager_->GetLastPage();
862 if (page) {
863 page->MarkDirtyNode(onKeyboard ? PROPERTY_UPDATE_LAYOUT : PROPERTY_UPDATE_MEASURE);
864 }
865 if (overlayManager_) {
866 overlayManager_->MarkDirty(PROPERTY_UPDATE_MEASURE);
867 }
868 if (selectOverlayManager_) {
869 selectOverlayManager_->MarkDirty(PROPERTY_UPDATE_MEASURE);
870 }
871 auto&& restoreNodes = safeAreaManager_->GetGeoRestoreNodes();
872 for (auto&& wk : restoreNodes) {
873 auto node = wk.Upgrade();
874 if (node) {
875 node->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
876 }
877 }
878 }
879
OnVirtualKeyboardHeightChange(float keyboardHeight,const std::shared_ptr<Rosen::RSTransaction> & rsTransaction)880 void PipelineContext::OnVirtualKeyboardHeightChange(
881 float keyboardHeight, const std::shared_ptr<Rosen::RSTransaction>& rsTransaction)
882 {
883 CHECK_RUN_ON(UI);
884 // prevent repeated trigger with same keyboardHeight
885 if (keyboardHeight == safeAreaManager_->GetKeyboardInset().Length()) {
886 return;
887 }
888
889 ACE_FUNCTION_TRACE();
890 #ifdef ENABLE_ROSEN_BACKEND
891 if (rsTransaction) {
892 FlushMessages();
893 rsTransaction->Begin();
894 }
895 #endif
896 safeAreaManager_->UpdateKeyboardSafeArea(keyboardHeight);
897 if (keyboardHeight > 0) {
898 // add height of navigation bar
899 keyboardHeight += safeAreaManager_->GetSystemSafeArea().bottom_.Length();
900 }
901 auto func = [this, keyboardHeight]() {
902 float positionY = 0.0f;
903 auto manager = DynamicCast<TextFieldManagerNG>(PipelineBase::GetTextFieldManager());
904 float height = 0.0f;
905 if (manager) {
906 height = manager->GetHeight();
907 positionY = static_cast<float>(manager->GetClickPosition().GetY());
908 }
909 SizeF rootSize { static_cast<float>(rootWidth_), static_cast<float>(rootHeight_) };
910 float keyboardOffset = safeAreaManager_->GetKeyboardOffset();
911 float positionYWithOffset = positionY - keyboardOffset;
912 float offsetFix = (rootSize.Height() - positionYWithOffset) > 100.0f
913 ? keyboardHeight - (rootSize.Height() - positionYWithOffset) / 2.0f
914 : keyboardHeight;
915 #if defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
916 if (offsetFix > 0.0f && positionYWithOffset < offsetFix) {
917 offsetFix = keyboardHeight - (rootSize.Height() - positionYWithOffset - height);
918 }
919 #endif
920 LOGI("OnVirtualKeyboardAreaChange positionY:%{public}f safeArea:%{public}f offsetFix:%{public}f, "
921 "keyboardHeight %{public}f",
922 positionY, (rootSize.Height() - keyboardHeight), offsetFix, keyboardHeight);
923 if (NearZero(keyboardHeight)) {
924 safeAreaManager_->UpdateKeyboardOffset(0.0f);
925 } else if (LessOrEqual(rootSize.Height() - positionYWithOffset - height, height) &&
926 LessOrEqual(rootSize.Height() - positionYWithOffset, keyboardHeight)) {
927 safeAreaManager_->UpdateKeyboardOffset(-keyboardHeight);
928 } else if (positionYWithOffset + height > (rootSize.Height() - keyboardHeight) && offsetFix > 0.0f) {
929 safeAreaManager_->UpdateKeyboardOffset(-offsetFix);
930 } else if ((positionYWithOffset + height > rootSize.Height() - keyboardHeight &&
931 positionYWithOffset < rootSize.Height() - keyboardHeight && height < keyboardHeight / 2.0f) &&
932 NearZero(rootNode_->GetGeometryNode()->GetFrameOffset().GetY())) {
933 safeAreaManager_->UpdateKeyboardOffset(-height - offsetFix / 2.0f);
934 } else {
935 safeAreaManager_->UpdateKeyboardOffset(0.0f);
936 }
937 SyncSafeArea(true);
938 // layout immediately
939 FlushUITasks();
940
941 CHECK_NULL_VOID_NOLOG(manager);
942 manager->ScrollTextFieldToSafeArea();
943 FlushUITasks();
944 };
945
946 AnimationOption option = AnimationUtil::CreateKeyboardAnimationOption(keyboardAnimationConfig_, keyboardHeight);
947 Animate(option, option.GetCurve(), func);
948
949 #ifdef ENABLE_ROSEN_BACKEND
950 if (rsTransaction) {
951 rsTransaction->Commit();
952 }
953 #endif
954 }
955
OnBackPressed()956 bool PipelineContext::OnBackPressed()
957 {
958 LOGD("OnBackPressed");
959 CHECK_RUN_ON(PLATFORM);
960 auto frontend = weakFrontend_.Upgrade();
961 if (!frontend) {
962 // return back.
963 return false;
964 }
965
966 // If the tag of the last child of the rootnode is video, exit full screen.
967 if (fullScreenManager_->OnBackPressed()) {
968 LOGI("Exit full screen: back press accepted");
969 return true;
970 }
971
972 // if has sharedTransition, back press will stop the sharedTransition
973 if (sharedTransitionManager_->OnBackPressed()) {
974 LOGI("sharedTransition stop: back press accepted");
975 return true;
976 }
977
978 auto textfieldManager = DynamicCast<TextFieldManagerNG>(PipelineBase::GetTextFieldManager());
979 if (textfieldManager && textfieldManager->OnBackPressed()) {
980 return true;
981 }
982
983 // if has popup, back press would hide popup and not trigger page back
984 auto hasOverlay = false;
985 taskExecutor_->PostSyncTask(
986 [weakOverlay = AceType::WeakClaim(AceType::RawPtr(overlayManager_)),
987 weakSelectOverlay = AceType::WeakClaim(AceType::RawPtr(selectOverlayManager_)), &hasOverlay]() {
988 // Destroy behaviour of Select Overlay shouble be adjusted.
989 auto overlay = weakOverlay.Upgrade();
990 CHECK_NULL_VOID_NOLOG(overlay);
991 auto selectOverlay = weakSelectOverlay.Upgrade();
992 CHECK_NULL_VOID_NOLOG(selectOverlay);
993 selectOverlay->DestroySelectOverlay();
994 hasOverlay = overlay->RemoveOverlay(true);
995 },
996 TaskExecutor::TaskType::UI);
997 if (hasOverlay) {
998 LOGI("popup hidden: back press accepted");
999 return true;
1000 }
1001
1002 auto result = false;
1003 taskExecutor_->PostSyncTask(
1004 [weakFrontend = weakFrontend_, weakPipelineContext = WeakClaim(this), stageManager = stageManager_, &result]() {
1005 auto frontend = weakFrontend.Upgrade();
1006 if (!frontend) {
1007 LOGW("frontend is nullptr");
1008 result = false;
1009 return;
1010 }
1011 auto context = weakPipelineContext.Upgrade();
1012 if (!context) {
1013 LOGW("pipelineContext is nullptr");
1014 result = false;
1015 return;
1016 }
1017 CHECK_NULL_VOID(stageManager);
1018 auto lastPage = stageManager->GetLastPage();
1019 CHECK_NULL_VOID(lastPage);
1020 auto navigationGroupNode =
1021 AceType::DynamicCast<NavigationGroupNode>(context->FindNavigationNodeToHandleBack(lastPage));
1022 if (navigationGroupNode) {
1023 result = true;
1024 }
1025 },
1026 TaskExecutor::TaskType::UI);
1027
1028 if (result) {
1029 // user accept
1030 LOGI("CallRouterBackToPopPage(): navDestination accept");
1031 return true;
1032 }
1033
1034 taskExecutor_->PostSyncTask(
1035 [weakFrontend = weakFrontend_, weakPipelineContext = WeakClaim(this), &result]() {
1036 auto frontend = weakFrontend.Upgrade();
1037 if (!frontend) {
1038 LOGW("frontend is nullptr");
1039 result = false;
1040 return;
1041 }
1042 result = frontend->OnBackPressed();
1043 },
1044 TaskExecutor::TaskType::JS);
1045
1046 if (result) {
1047 // user accept
1048 LOGI("CallRouterBackToPopPage(): frontend accept");
1049 return true;
1050 }
1051 LOGI("CallRouterBackToPopPage(): return platform consumed");
1052 return false;
1053 }
1054
FindNavigationNodeToHandleBack(const RefPtr<UINode> & node)1055 RefPtr<FrameNode> PipelineContext::FindNavigationNodeToHandleBack(const RefPtr<UINode>& node)
1056 {
1057 const auto& children = node->GetChildren();
1058 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1059 auto& child = *iter;
1060
1061 auto target = FindNavigationNodeToHandleBack(child);
1062 if (target) {
1063 return target;
1064 }
1065 }
1066 auto navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(node);
1067 if (navigationGroupNode && navigationGroupNode->CheckCanHandleBack()) {
1068 return navigationGroupNode;
1069 }
1070 return nullptr;
1071 }
1072
SetIsFocusActive(bool isFocusActive)1073 bool PipelineContext::SetIsFocusActive(bool isFocusActive)
1074 {
1075 if (isFocusActive_ == isFocusActive) {
1076 return false;
1077 }
1078 isFocusActive_ = isFocusActive;
1079 CHECK_NULL_RETURN_NOLOG(rootNode_, false);
1080 auto rootFocusHub = rootNode_->GetFocusHub();
1081 CHECK_NULL_RETURN_NOLOG(rootFocusHub, false);
1082 if (isFocusActive_) {
1083 return rootFocusHub->PaintAllFocusState();
1084 }
1085 rootFocusHub->ClearAllFocusState();
1086 return true;
1087 }
1088
OnTouchEvent(const TouchEvent & point,bool isSubPipe)1089 void PipelineContext::OnTouchEvent(const TouchEvent& point, bool isSubPipe)
1090 {
1091 CHECK_RUN_ON(UI);
1092
1093 #ifdef UICAST_COMPONENT_SUPPORTED
1094 do {
1095 auto container = Container::Current();
1096 CHECK_NULL_BREAK(container);
1097 auto distributedUI = container->GetDistributedUI();
1098 CHECK_NULL_BREAK(distributedUI);
1099 if (distributedUI->IsSinkMode()) {
1100 distributedUI->BypassEvent(point, isSubPipe);
1101 return;
1102 }
1103 } while (false);
1104 #endif
1105
1106 HandleEtsCardTouchEvent(point);
1107
1108 auto scalePoint = point.CreateScalePoint(GetViewScale());
1109 LOGD("AceTouchEvent: x = %{public}f, y = %{public}f, type = %{public}zu", scalePoint.x, scalePoint.y,
1110 scalePoint.type);
1111 eventManager_->SetInstanceId(GetInstanceId());
1112 if (scalePoint.type == TouchType::DOWN) {
1113 // Set focus state inactive while touch down event received
1114 SetIsFocusActive(false);
1115 LOGD("receive touch down event, first use touch test to collect touch event target");
1116 TouchRestrict touchRestrict { TouchRestrict::NONE };
1117 touchRestrict.sourceType = point.sourceType;
1118 touchRestrict.touchEvent = point;
1119 eventManager_->TouchTest(scalePoint, rootNode_, touchRestrict, GetPluginEventOffset(), viewScale_, isSubPipe);
1120 for (const auto& weakContext : touchPluginPipelineContext_) {
1121 auto pipelineContext = DynamicCast<OHOS::Ace::PipelineBase>(weakContext.Upgrade());
1122 if (!pipelineContext) {
1123 continue;
1124 }
1125 auto pluginPoint =
1126 point.UpdateScalePoint(viewScale_, static_cast<float>(pipelineContext->GetPluginEventOffset().GetX()),
1127 static_cast<float>(pipelineContext->GetPluginEventOffset().GetY()), point.id);
1128 // eventManager_ instance Id may changed.
1129 pipelineContext->OnTouchEvent(pluginPoint, true);
1130 }
1131
1132 // restore instance Id.
1133 eventManager_->SetInstanceId(GetInstanceId());
1134 }
1135
1136 auto rootOffset = GetRootRect().GetOffset();
1137 eventManager_->HandleGlobalEventNG(scalePoint, selectOverlayManager_, rootOffset);
1138
1139 if (isSubPipe) {
1140 return;
1141 }
1142
1143 if (scalePoint.type == TouchType::MOVE) {
1144 touchEvents_.emplace_back(point);
1145 auto container = Container::Current();
1146 if (container && container->IsScenceBoardWindow() && IsWindowSceneConsumed()) {
1147 FlushTouchEvents();
1148 return;
1149 } else {
1150 hasIdleTasks_ = true;
1151 RequestFrame();
1152 return;
1153 }
1154 }
1155
1156 if (scalePoint.type == TouchType::UP) {
1157 lastTouchTime_ = GetTimeFromExternalTimer();
1158 }
1159
1160 std::optional<TouchEvent> lastMoveEvent;
1161 if (scalePoint.type == TouchType::UP && !touchEvents_.empty()) {
1162 for (auto iter = touchEvents_.begin(); iter != touchEvents_.end(); ++iter) {
1163 auto movePoint = (*iter).CreateScalePoint(GetViewScale());
1164 if (scalePoint.id == movePoint.id) {
1165 lastMoveEvent = movePoint;
1166 touchEvents_.erase(iter++);
1167 }
1168 }
1169 if (lastMoveEvent.has_value()) {
1170 eventManager_->DispatchTouchEvent(lastMoveEvent.value());
1171 }
1172 }
1173
1174 eventManager_->DispatchTouchEvent(scalePoint);
1175
1176 if ((scalePoint.type == TouchType::UP) || (scalePoint.type == TouchType::CANCEL)) {
1177 // need to reset touchPluginPipelineContext_ for next touch down event.
1178 touchPluginPipelineContext_.clear();
1179 RemoveEtsCardTouchEventCallback(point.id);
1180 }
1181
1182 hasIdleTasks_ = true;
1183 RequestFrame();
1184 }
1185
OnSurfaceDensityChanged(double density)1186 void PipelineContext::OnSurfaceDensityChanged(double density)
1187 {
1188 CHECK_RUN_ON(UI);
1189 LOGD("density_(%{public}lf), dipScale_(%{public}lf)", density_, dipScale_);
1190 density_ = density;
1191 if (!NearZero(viewScale_)) {
1192 LOGD("viewScale_(%{public}lf)", viewScale_);
1193 dipScale_ = density_ / viewScale_;
1194 }
1195 }
1196
OnDumpInfo(const std::vector<std::string> & params) const1197 bool PipelineContext::OnDumpInfo(const std::vector<std::string>& params) const
1198 {
1199 ACE_DCHECK(!params.empty());
1200
1201 if (params[0] == "-element") {
1202 if (params.size() > 1 && params[1] == "-lastpage") {
1203 auto lastPage = stageManager_->GetLastPage();
1204 if (lastPage) {
1205 lastPage->DumpTree(0);
1206 }
1207 } else {
1208 rootNode_->DumpTree(0);
1209 }
1210 } else if (params[0] == "-render") {
1211 } else if (params[0] == "-focus") {
1212 if (rootNode_->GetFocusHub()) {
1213 rootNode_->GetFocusHub()->DumpFocusTree(0);
1214 }
1215 } else if (params[0] == "-layer") {
1216 } else if (params[0] == "-frontend") {
1217 #ifndef WEARABLE_PRODUCT
1218 } else if (params[0] == "-multimodal") {
1219 #endif
1220 } else if (params[0] == "-accessibility" || params[0] == "-inspector") {
1221 auto accessibilityManager = GetAccessibilityManager();
1222 if (accessibilityManager) {
1223 accessibilityManager->OnDumpInfo(params);
1224 }
1225 } else if (params[0] == "-rotation" && params.size() >= 2) {
1226 } else if (params[0] == "-animationscale" && params.size() >= 2) {
1227 } else if (params[0] == "-velocityscale" && params.size() >= 2) {
1228 } else if (params[0] == "-scrollfriction" && params.size() >= 2) {
1229 } else if (params[0] == "-threadstuck" && params.size() >= 3) {
1230 } else if (params[0] == "-pipeline") {
1231 DumpPipelineInfo();
1232 } else {
1233 return false;
1234 }
1235
1236 return true;
1237 }
1238
GetCurrentFrameInfo(uint64_t recvTime,uint64_t timeStamp)1239 FrameInfo* PipelineContext::GetCurrentFrameInfo(uint64_t recvTime, uint64_t timeStamp)
1240 {
1241 if (SystemProperties::GetDumpFrameCount() == 0) {
1242 return nullptr;
1243 }
1244 if (dumpFrameInfos_.size() >= SystemProperties::GetDumpFrameCount()) {
1245 dumpFrameInfos_.pop_front();
1246 }
1247
1248 dumpFrameInfos_.push_back({ .frameRecvTime_ = recvTime, .frameTimeStamp_ = timeStamp });
1249 return &dumpFrameInfos_.back();
1250 }
1251
DumpPipelineInfo() const1252 void PipelineContext::DumpPipelineInfo() const
1253 {
1254 DumpLog::GetInstance().Print("PipelineInfo:");
1255 if (window_) {
1256 DumpLog::GetInstance().Print(1, "DisplayRefreshRate: " + std::to_string(window_->GetRefreshRate()));
1257 DumpLog::GetInstance().Print(1, "LastRequestVsyncTime: " + std::to_string(window_->GetLastRequestVsyncTime()));
1258 }
1259 if (!dumpFrameInfos_.empty()) {
1260 DumpLog::GetInstance().Print("==================================FrameTask==================================");
1261 for (const auto& info : dumpFrameInfos_) {
1262 DumpLog::GetInstance().Print("Task: " + info.GetTimeInfo());
1263 DumpLog::GetInstance().Print(1, "LayoutTask:");
1264 for (const auto& layout : info.layoutInfos_) {
1265 DumpLog::GetInstance().Print(2, layout.ToString());
1266 }
1267 DumpLog::GetInstance().Print(1, "RenderTask:");
1268 for (const auto& layout : info.renderInfos_) {
1269 DumpLog::GetInstance().Print(2, layout.ToString());
1270 }
1271 DumpLog::GetInstance().Print(
1272 "==================================FrameTask==================================");
1273 }
1274 }
1275 }
1276
FlushTouchEvents()1277 void PipelineContext::FlushTouchEvents()
1278 {
1279 CHECK_RUN_ON(UI);
1280 CHECK_NULL_VOID(rootNode_);
1281 {
1282 std::unordered_set<int32_t> moveEventIds;
1283 decltype(touchEvents_) touchEvents(std::move(touchEvents_));
1284 if (touchEvents.empty()) {
1285 canUseLongPredictTask_ = true;
1286 return;
1287 }
1288 canUseLongPredictTask_ = false;
1289 eventManager_->FlushTouchEventsBegin(touchEvents_);
1290 std::unordered_map<int, TouchEvent> idToTouchPoints;
1291 for (auto iter = touchEvents.rbegin(); iter != touchEvents.rend(); ++iter) {
1292 auto scalePoint = (*iter).CreateScalePoint(GetViewScale());
1293 idToTouchPoints.emplace(scalePoint.id, scalePoint);
1294 idToTouchPoints[scalePoint.id].history.insert(idToTouchPoints[scalePoint.id].history.begin(), scalePoint);
1295 }
1296 std::list<TouchEvent> touchPoints;
1297 for (auto& [_, item] : idToTouchPoints) {
1298 touchPoints.emplace_back(std::move(item));
1299 }
1300 auto maxSize = touchPoints.size();
1301 for (auto iter = touchPoints.rbegin(); iter != touchPoints.rend(); ++iter) {
1302 maxSize--;
1303 if (maxSize == 0) {
1304 eventManager_->FlushTouchEventsEnd(touchPoints);
1305 }
1306 eventManager_->DispatchTouchEvent(*iter);
1307 }
1308 }
1309 }
1310
OnMouseEvent(const MouseEvent & event)1311 void PipelineContext::OnMouseEvent(const MouseEvent& event)
1312 {
1313 CHECK_RUN_ON(UI);
1314 if (!lastMouseEvent_) {
1315 lastMouseEvent_ = std::make_unique<MouseEvent>();
1316 }
1317 lastMouseEvent_->x = event.x;
1318 lastMouseEvent_->y = event.y;
1319 lastMouseEvent_->button = event.button;
1320 lastMouseEvent_->action = event.action;
1321 lastMouseEvent_->sourceType = event.sourceType;
1322 lastMouseEvent_->time = event.time;
1323
1324 if (event.button == MouseButton::RIGHT_BUTTON && event.action == MouseAction::PRESS) {
1325 // Mouse right button press event set focus inactive here.
1326 // Mouse left button press event will set focus inactive in touch process.
1327 SetIsFocusActive(false);
1328 }
1329 auto container = Container::Current();
1330 if (((event.action == MouseAction::RELEASE || event.action == MouseAction::PRESS ||
1331 event.action == MouseAction::MOVE) &&
1332 (event.button == MouseButton::LEFT_BUTTON || event.pressedButtons == MOUSE_PRESS_LEFT)) ||
1333 (container && container->IsScenceBoardWindow() &&
1334 (event.pullAction == MouseAction::PULL_MOVE || event.pullAction == MouseAction::PULL_UP))) {
1335 auto touchPoint = event.CreateTouchPoint();
1336 OnTouchEvent(touchPoint);
1337 }
1338
1339 CHECK_NULL_VOID(rootNode_);
1340 auto scaleEvent = event.CreateScaleEvent(viewScale_);
1341 LOGD(
1342 "MouseEvent (x,y): (%{public}f,%{public}f), button: %{public}d, action: %{public}d, pressedButtons: %{public}d",
1343 scaleEvent.x, scaleEvent.y, scaleEvent.button, scaleEvent.action, scaleEvent.pressedButtons);
1344 TouchRestrict touchRestrict { TouchRestrict::NONE };
1345 touchRestrict.sourceType = event.sourceType;
1346 touchRestrict.hitTestType = SourceType::MOUSE;
1347 eventManager_->MouseTest(scaleEvent, rootNode_, touchRestrict);
1348 eventManager_->DispatchMouseEventNG(scaleEvent);
1349 eventManager_->DispatchMouseHoverEventNG(scaleEvent);
1350 eventManager_->DispatchMouseHoverAnimationNG(scaleEvent);
1351 RequestFrame();
1352 }
1353
FlushMouseEvent()1354 void PipelineContext::FlushMouseEvent()
1355 {
1356 if (!lastMouseEvent_ || lastMouseEvent_->action == MouseAction::WINDOW_LEAVE) {
1357 return;
1358 }
1359 MouseEvent event;
1360 event.x = lastMouseEvent_->x;
1361 event.y = lastMouseEvent_->y;
1362 event.time = lastMouseEvent_->time;
1363 event.action = MouseAction::MOVE;
1364 event.button = MouseButton::NONE_BUTTON;
1365 event.sourceType = SourceType::MOUSE;
1366
1367 CHECK_RUN_ON(UI);
1368 CHECK_NULL_VOID(rootNode_);
1369 auto scaleEvent = event.CreateScaleEvent(viewScale_);
1370 TouchRestrict touchRestrict { TouchRestrict::NONE };
1371 touchRestrict.sourceType = event.sourceType;
1372 touchRestrict.hitTestType = SourceType::MOUSE;
1373 eventManager_->MouseTest(scaleEvent, rootNode_, touchRestrict);
1374 eventManager_->DispatchMouseEventNG(scaleEvent);
1375 eventManager_->DispatchMouseHoverEventNG(scaleEvent);
1376 eventManager_->DispatchMouseHoverAnimationNG(scaleEvent);
1377 }
1378
ChangeMouseStyle(int32_t nodeId,MouseFormat format)1379 bool PipelineContext::ChangeMouseStyle(int32_t nodeId, MouseFormat format)
1380 {
1381 if (!onFocus_) {
1382 LOGD("ChangeMouseStyle failed because the window is not on focus.");
1383 return false;
1384 }
1385 if (mouseStyleNodeId_ != nodeId) {
1386 return false;
1387 }
1388 auto mouseStyle = MouseStyle::CreateMouseStyle();
1389 CHECK_NULL_RETURN(mouseStyle, false);
1390 LOGD("ChangeMouseStyle to %{public}d on Frame %{public}d", format, nodeId);
1391 return mouseStyle->ChangePointerStyle(GetWindowId(), format);
1392 }
1393
OnKeyEvent(const KeyEvent & event)1394 bool PipelineContext::OnKeyEvent(const KeyEvent& event)
1395 {
1396 eventManager_->SetPressedKeyCodes(event.pressedCodes);
1397 CHECK_NULL_RETURN(eventManager_, false);
1398 if (event.action == KeyAction::DOWN) {
1399 eventManager_->DispatchKeyboardShortcut(event);
1400 }
1401 if (event.code == KeyCode::KEY_ESCAPE) {
1402 auto manager = GetDragDropManager();
1403 if (manager) {
1404 manager->SetIsDragCancel(true);
1405 manager->OnDragEnd({ 0.0f, 0.0f }, "");
1406 }
1407 }
1408 // TAB key set focus state from inactive to active.
1409 // If return success. This tab key will just trigger onKeyEvent process.
1410 isTabJustTriggerOnKeyEvent_ =
1411 (event.action == KeyAction::DOWN && event.IsKey({ KeyCode::KEY_TAB }) && SetIsFocusActive(true));
1412 auto lastPage = stageManager_ ? stageManager_->GetLastPage() : nullptr;
1413 auto mainNode = lastPage ? lastPage : rootNode_;
1414 CHECK_NULL_RETURN(mainNode, false);
1415 if (!eventManager_->DispatchTabIndexEventNG(event, rootNode_, mainNode)) {
1416 auto result = eventManager_->DispatchKeyEventNG(event, rootNode_);
1417 if (!result && event.code == KeyCode::KEY_ESCAPE && event.action == KeyAction::DOWN) {
1418 CHECK_NULL_RETURN(overlayManager_, false);
1419 auto currentContainer = Container::Current();
1420 if (currentContainer->IsSubContainer() || currentContainer->IsDialogContainer()) {
1421 return overlayManager_->RemoveOverlayInSubwindow();
1422 } else {
1423 return overlayManager_->RemoveOverlay(false);
1424 }
1425 } else {
1426 return result;
1427 }
1428 }
1429 return true;
1430 }
1431
RequestDefaultFocus()1432 bool PipelineContext::RequestDefaultFocus()
1433 {
1434 CHECK_NULL_RETURN(stageManager_, false);
1435 auto lastPage = stageManager_->GetLastPage();
1436 auto mainNode = lastPage ? lastPage : rootNode_;
1437 CHECK_NULL_RETURN(mainNode, false);
1438 auto mainFocusHub = mainNode->GetFocusHub();
1439 CHECK_NULL_RETURN(mainFocusHub, false);
1440 if (mainFocusHub->IsDefaultHasFocused()) {
1441 LOGD("MainNode: %{public}s/%{public}d 's default focus node has be focused.", mainNode->GetTag().c_str(),
1442 mainNode->GetId());
1443 return false;
1444 }
1445 auto defaultFocusNodeWeak = mainFocusHub->GetDefaultFocusNode();
1446 auto defaultFocusNode = defaultFocusNodeWeak.Upgrade();
1447 if (!defaultFocusNode) {
1448 return false;
1449 }
1450 if (!defaultFocusNode->IsFocusableWholePath()) {
1451 LOGD("MainNode: %{public}s/%{public}d 's default focus node is not focusable.", mainNode->GetTag().c_str(),
1452 mainNode->GetId());
1453 return false;
1454 }
1455 mainFocusHub->SetIsDefaultHasFocused(true);
1456 LOGD("MainNode: %{public}s/%{public}d request default focus node: %{public}s/%{public}d",
1457 mainNode->GetTag().c_str(), mainNode->GetId(), defaultFocusNode->GetFrameName().c_str(),
1458 defaultFocusNode->GetFrameId());
1459 return defaultFocusNode->RequestFocusImmediately();
1460 }
1461
RequestFocus(const std::string & targetNodeId)1462 bool PipelineContext::RequestFocus(const std::string& targetNodeId)
1463 {
1464 CHECK_NULL_RETURN(rootNode_, false);
1465 auto focusHub = rootNode_->GetFocusHub();
1466 CHECK_NULL_RETURN(focusHub, false);
1467 auto currentFocusChecked = focusHub->RequestFocusImmediatelyById(targetNodeId);
1468 if (!isSubPipeline_ || currentFocusChecked) {
1469 LOGI("Request focus in current pipeline return is %{public}d", currentFocusChecked);
1470 return currentFocusChecked;
1471 }
1472 LOGI("Request focus in parent pipeline");
1473 auto parentPipelineBase = parentPipeline_.Upgrade();
1474 CHECK_NULL_RETURN(parentPipelineBase, false);
1475 auto parentPipelineContext = AceType::DynamicCast<NG::PipelineContext>(parentPipelineBase);
1476 CHECK_NULL_RETURN(parentPipelineContext, false);
1477 return parentPipelineContext->RequestFocus(targetNodeId);
1478 }
1479
AddDirtyFocus(const RefPtr<FrameNode> & node)1480 void PipelineContext::AddDirtyFocus(const RefPtr<FrameNode>& node)
1481 {
1482 CHECK_RUN_ON(UI);
1483 CHECK_NULL_VOID(node);
1484 if (node->GetFocusType() == FocusType::NODE) {
1485 dirtyFocusNode_ = WeakClaim(RawPtr(node));
1486 } else {
1487 dirtyFocusScope_ = WeakClaim(RawPtr(node));
1488 }
1489 RequestFrame();
1490 }
1491
AddDirtyDefaultFocus(const RefPtr<FrameNode> & node)1492 void PipelineContext::AddDirtyDefaultFocus(const RefPtr<FrameNode>& node)
1493 {
1494 CHECK_RUN_ON(UI);
1495 CHECK_NULL_VOID(node);
1496 dirtyDefaultFocusNode_ = WeakPtr<FrameNode>(node);
1497 RequestFrame();
1498 }
1499
RootLostFocus(BlurReason reason) const1500 void PipelineContext::RootLostFocus(BlurReason reason) const
1501 {
1502 CHECK_NULL_VOID(rootNode_);
1503 auto focusHub = rootNode_->GetFocusHub();
1504 CHECK_NULL_VOID(focusHub);
1505 focusHub->LostFocus(reason);
1506 CHECK_NULL_VOID(overlayManager_);
1507 overlayManager_->HideAllMenus();
1508 overlayManager_->HideCustomPopups();
1509 }
1510
ConvertAxisToMouse(const AxisEvent & event)1511 MouseEvent ConvertAxisToMouse(const AxisEvent& event)
1512 {
1513 MouseEvent result;
1514 result.x = event.x;
1515 result.y = event.y;
1516 result.action = MouseAction::MOVE;
1517 result.button = MouseButton::NONE_BUTTON;
1518 result.time = event.time;
1519 result.deviceId = event.deviceId;
1520 result.sourceType = event.sourceType;
1521 result.pointerEvent = event.pointerEvent;
1522 return result;
1523 }
1524
OnAxisEvent(const AxisEvent & event)1525 void PipelineContext::OnAxisEvent(const AxisEvent& event)
1526 {
1527 auto scaleEvent = event.CreateScaleEvent(viewScale_);
1528 LOGD("AxisEvent (x,y): (%{public}f,%{public}f), action: %{public}d, horizontalAxis: %{public}f, verticalAxis: "
1529 "%{public}f, pinchAxisScale: %{public}f",
1530 scaleEvent.x, scaleEvent.y, scaleEvent.action, scaleEvent.horizontalAxis, scaleEvent.verticalAxis,
1531 scaleEvent.pinchAxisScale);
1532
1533 auto dragManager = GetDragDropManager();
1534 if (dragManager && !dragManager->IsDragged()) {
1535 if (event.action == AxisAction::BEGIN) {
1536 TouchRestrict touchRestrict { TouchRestrict::NONE };
1537 touchRestrict.sourceType = event.sourceType;
1538 touchRestrict.hitTestType = SourceType::TOUCH;
1539 eventManager_->TouchTest(scaleEvent, rootNode_, touchRestrict);
1540 }
1541 eventManager_->DispatchTouchEvent(scaleEvent);
1542 }
1543
1544 if (event.action == AxisAction::BEGIN || event.action == AxisAction::UPDATE) {
1545 eventManager_->AxisTest(scaleEvent, rootNode_);
1546 eventManager_->DispatchAxisEventNG(scaleEvent);
1547 }
1548
1549 auto mouseEvent = ConvertAxisToMouse(event);
1550 OnMouseEvent(mouseEvent);
1551 }
1552
AddVisibleAreaChangeNode(const RefPtr<FrameNode> & node,double ratio,const VisibleRatioCallback & callback,bool isUserCallback)1553 void PipelineContext::AddVisibleAreaChangeNode(
1554 const RefPtr<FrameNode>& node, double ratio, const VisibleRatioCallback& callback, bool isUserCallback)
1555 {
1556 CHECK_NULL_VOID(node);
1557 VisibleCallbackInfo addInfo;
1558 addInfo.callback = callback;
1559 addInfo.isCurrentVisible = false;
1560 onVisibleAreaChangeNodeIds_.emplace(node->GetId());
1561 if (isUserCallback) {
1562 node->AddVisibleAreaUserCallback(ratio, addInfo);
1563 } else {
1564 node->AddVisibleAreaInnerCallback(ratio, addInfo);
1565 }
1566 }
1567
RemoveVisibleAreaChangeNode(int32_t nodeId)1568 void PipelineContext::RemoveVisibleAreaChangeNode(int32_t nodeId)
1569 {
1570 onVisibleAreaChangeNodeIds_.erase(nodeId);
1571 }
1572
HandleVisibleAreaChangeEvent()1573 void PipelineContext::HandleVisibleAreaChangeEvent()
1574 {
1575 ACE_FUNCTION_TRACE();
1576 if (onVisibleAreaChangeNodeIds_.empty()) {
1577 return;
1578 }
1579 auto nodes = FrameNode::GetNodesById(onVisibleAreaChangeNodeIds_);
1580 for (auto&& frameNode : nodes) {
1581 frameNode->TriggerVisibleAreaChangeCallback();
1582 }
1583 }
1584
AddOnAreaChangeNode(int32_t nodeId)1585 void PipelineContext::AddOnAreaChangeNode(int32_t nodeId)
1586 {
1587 onAreaChangeNodeIds_.emplace(nodeId);
1588 }
1589
RemoveOnAreaChangeNode(int32_t nodeId)1590 void PipelineContext::RemoveOnAreaChangeNode(int32_t nodeId)
1591 {
1592 onAreaChangeNodeIds_.erase(nodeId);
1593 }
1594
HandleOnAreaChangeEvent()1595 void PipelineContext::HandleOnAreaChangeEvent()
1596 {
1597 ACE_FUNCTION_TRACE();
1598 if (onAreaChangeNodeIds_.empty()) {
1599 return;
1600 }
1601 auto nodes = FrameNode::GetNodesById(onAreaChangeNodeIds_);
1602 for (auto&& frameNode : nodes) {
1603 frameNode->TriggerOnAreaChangeCallback();
1604 }
1605 UpdateFormLinkInfos();
1606 }
1607
UpdateFormLinkInfos()1608 void PipelineContext::UpdateFormLinkInfos()
1609 {
1610 if (formLinkInfoUpdateHandler_ && !formLinkInfoMap_.empty()) {
1611 LOGI("formLinkInfoUpdateHandler called");
1612 std::vector<std::string> formLinkInfos;
1613 for (auto iter = formLinkInfoMap_.rbegin(); iter != formLinkInfoMap_.rend(); ++iter) {
1614 auto info = iter->second;
1615 formLinkInfos.push_back(info);
1616 }
1617 formLinkInfoUpdateHandler_(formLinkInfos);
1618 }
1619 }
1620
OnShow()1621 void PipelineContext::OnShow()
1622 {
1623 CHECK_RUN_ON(UI);
1624 onShow_ = true;
1625 window_->OnShow();
1626 RequestFrame();
1627 FlushWindowStateChangedCallback(true);
1628 AccessibilityEvent event;
1629 event.windowChangeTypes = WindowUpdateType::WINDOW_UPDATE_ACTIVE;
1630 event.type = AccessibilityEventType::PAGE_CHANGE;
1631 SendEventToAccessibility(event);
1632 }
1633
OnHide()1634 void PipelineContext::OnHide()
1635 {
1636 CHECK_RUN_ON(UI);
1637 onShow_ = false;
1638 window_->OnHide();
1639 RequestFrame();
1640 OnVirtualKeyboardAreaChange(Rect());
1641 FlushWindowStateChangedCallback(false);
1642 AccessibilityEvent event;
1643 event.type = AccessibilityEventType::PAGE_CHANGE;
1644 SendEventToAccessibility(event);
1645 }
1646
WindowFocus(bool isFocus)1647 void PipelineContext::WindowFocus(bool isFocus)
1648 {
1649 CHECK_RUN_ON(UI);
1650 onFocus_ = isFocus;
1651 if (!isFocus) {
1652 LOGI("WindowFocus: window - %{public}d on blur.", windowId_);
1653 auto mouseStyle = MouseStyle::CreateMouseStyle();
1654 if (mouseStyle) {
1655 mouseStyle->ChangePointerStyle(static_cast<int32_t>(GetWindowId()), MouseFormat::DEFAULT);
1656 }
1657 RootLostFocus(BlurReason::WINDOW_BLUR);
1658 NotifyPopupDismiss();
1659 OnVirtualKeyboardAreaChange(Rect());
1660 } else {
1661 LOGI("WindowFocus: window - %{public}d on focus.", windowId_);
1662 isRootFocusNeedUpdate_ = true;
1663 FlushFocus();
1664 }
1665 FlushWindowFocusChangedCallback(isFocus);
1666 }
1667
ShowContainerTitle(bool isShow,bool hasDeco)1668 void PipelineContext::ShowContainerTitle(bool isShow, bool hasDeco)
1669 {
1670 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1671 LOGW("ShowContainerTitle failed, Window modal is not container.");
1672 return;
1673 }
1674 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1675 CHECK_NULL_VOID(containerNode);
1676 auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
1677 CHECK_NULL_VOID(containerPattern);
1678 containerPattern->ShowTitle(isShow, hasDeco);
1679 }
1680
SetContainerWindow(bool isShow)1681 void PipelineContext::SetContainerWindow(bool isShow)
1682 {
1683 #ifdef ENABLE_ROSEN_BACKEND
1684 if (!IsJsCard()) {
1685 auto window = GetWindow();
1686 if (window) {
1687 auto rsUIDirector = window->GetRSUIDirector();
1688 if (rsUIDirector) {
1689 // set container window show state to render service
1690 rsUIDirector->SetContainerWindow(isShow, density_);
1691 }
1692 }
1693 }
1694 #endif
1695 }
1696
SetAppBgColor(const Color & color)1697 void PipelineContext::SetAppBgColor(const Color& color)
1698 {
1699 appBgColor_ = color;
1700 #ifdef ENABLE_ROSEN_BACKEND
1701 if (!IsJsCard()) {
1702 auto window = GetWindow();
1703 if (window) {
1704 auto rsUIDirector = window->GetRSUIDirector();
1705 if (rsUIDirector) {
1706 rsUIDirector->SetAbilityBGAlpha(appBgColor_.GetAlpha());
1707 }
1708 }
1709 }
1710 #endif
1711 CHECK_NULL_VOID(rootNode_);
1712 auto rootPattern = rootNode_->GetPattern<RootPattern>();
1713 CHECK_NULL_VOID(rootPattern);
1714 rootPattern->SetAppBgColor(appBgColor_, windowModal_ == WindowModal::CONTAINER_MODAL);
1715 }
1716
SetAppTitle(const std::string & title)1717 void PipelineContext::SetAppTitle(const std::string& title)
1718 {
1719 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1720 LOGW("SetAppTitle failed, Window modal is not container.");
1721 return;
1722 }
1723 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1724 CHECK_NULL_VOID(containerNode);
1725 auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
1726 CHECK_NULL_VOID(containerPattern);
1727 containerPattern->SetAppTitle(title);
1728 }
1729
SetAppIcon(const RefPtr<PixelMap> & icon)1730 void PipelineContext::SetAppIcon(const RefPtr<PixelMap>& icon)
1731 {
1732 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
1733 LOGW("SetAppIcon failed, Window modal is not container.");
1734 return;
1735 }
1736 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
1737 CHECK_NULL_VOID(containerNode);
1738 auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
1739 CHECK_NULL_VOID(containerPattern);
1740 containerPattern->SetAppIcon(icon);
1741 }
1742
FlushReload()1743 void PipelineContext::FlushReload()
1744 {
1745 LOGI("PipelineContext::FlushReload.");
1746 AnimationOption option;
1747 const int32_t duration = 400;
1748 option.SetDuration(duration);
1749 option.SetCurve(Curves::FRICTION);
1750 AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
1751 auto pipeline = weak.Upgrade();
1752 CHECK_NULL_VOID(pipeline);
1753 CHECK_NULL_VOID(pipeline->stageManager_);
1754 pipeline->SetIsReloading(true);
1755 pipeline->stageManager_->ReloadStage();
1756 pipeline->SetIsReloading(false);
1757 pipeline->FlushUITasks();
1758 });
1759 }
1760
Destroy()1761 void PipelineContext::Destroy()
1762 {
1763 CHECK_RUN_ON(UI);
1764 LOGI("PipelineContext::Destroy begin.");
1765 taskScheduler_->CleanUp();
1766 scheduleTasks_.clear();
1767 dirtyNodes_.clear();
1768 rootNode_.Reset();
1769 stageManager_.Reset();
1770 overlayManager_.Reset();
1771 sharedTransitionManager_.Reset();
1772 dragDropManager_.Reset();
1773 selectOverlayManager_.Reset();
1774 fullScreenManager_.Reset();
1775 touchEvents_.clear();
1776 buildFinishCallbacks_.clear();
1777 onWindowStateChangedCallbacks_.clear();
1778 onWindowFocusChangedCallbacks_.clear();
1779 nodesToNotifyMemoryLevel_.clear();
1780 dirtyFocusNode_.Reset();
1781 dirtyFocusScope_.Reset();
1782 needRenderNode_.clear();
1783 dirtyDefaultFocusNode_.Reset();
1784 PipelineBase::Destroy();
1785 LOGI("PipelineContext::Destroy end.");
1786 }
1787
AddBuildFinishCallBack(std::function<void ()> && callback)1788 void PipelineContext::AddBuildFinishCallBack(std::function<void()>&& callback)
1789 {
1790 buildFinishCallbacks_.emplace_back(std::move(callback));
1791 }
1792
AddWindowStateChangedCallback(int32_t nodeId)1793 void PipelineContext::AddWindowStateChangedCallback(int32_t nodeId)
1794 {
1795 onWindowStateChangedCallbacks_.emplace(nodeId);
1796 }
1797
RemoveWindowStateChangedCallback(int32_t nodeId)1798 void PipelineContext::RemoveWindowStateChangedCallback(int32_t nodeId)
1799 {
1800 onWindowStateChangedCallbacks_.erase(nodeId);
1801 }
1802
FlushWindowStateChangedCallback(bool isShow)1803 void PipelineContext::FlushWindowStateChangedCallback(bool isShow)
1804 {
1805 auto iter = onWindowStateChangedCallbacks_.begin();
1806 while (iter != onWindowStateChangedCallbacks_.end()) {
1807 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1808 if (!node) {
1809 iter = onWindowStateChangedCallbacks_.erase(iter);
1810 } else {
1811 if (isShow) {
1812 node->OnWindowShow();
1813 } else {
1814 node->OnWindowHide();
1815 }
1816 ++iter;
1817 }
1818 }
1819 HandleVisibleAreaChangeEvent();
1820 }
1821
AddWindowFocusChangedCallback(int32_t nodeId)1822 void PipelineContext::AddWindowFocusChangedCallback(int32_t nodeId)
1823 {
1824 onWindowFocusChangedCallbacks_.emplace_back(nodeId);
1825 }
1826
RemoveWindowFocusChangedCallback(int32_t nodeId)1827 void PipelineContext::RemoveWindowFocusChangedCallback(int32_t nodeId)
1828 {
1829 onWindowFocusChangedCallbacks_.remove(nodeId);
1830 }
1831
FlushWindowFocusChangedCallback(bool isFocus)1832 void PipelineContext::FlushWindowFocusChangedCallback(bool isFocus)
1833 {
1834 auto iter = onWindowFocusChangedCallbacks_.begin();
1835 while (iter != onWindowFocusChangedCallbacks_.end()) {
1836 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1837 if (!node) {
1838 iter = onWindowFocusChangedCallbacks_.erase(iter);
1839 } else {
1840 if (isFocus) {
1841 node->OnWindowFocused();
1842 } else {
1843 node->OnWindowUnfocused();
1844 }
1845 ++iter;
1846 }
1847 }
1848 }
1849
AddWindowSizeChangeCallback(int32_t nodeId)1850 void PipelineContext::AddWindowSizeChangeCallback(int32_t nodeId)
1851 {
1852 onWindowSizeChangeCallbacks_.emplace_back(nodeId);
1853 }
1854
RemoveWindowSizeChangeCallback(int32_t nodeId)1855 void PipelineContext::RemoveWindowSizeChangeCallback(int32_t nodeId)
1856 {
1857 onWindowSizeChangeCallbacks_.remove(nodeId);
1858 }
1859
FlushWindowSizeChangeCallback(int32_t width,int32_t height,WindowSizeChangeReason type)1860 void PipelineContext::FlushWindowSizeChangeCallback(int32_t width, int32_t height, WindowSizeChangeReason type)
1861 {
1862 auto iter = onWindowSizeChangeCallbacks_.begin();
1863 while (iter != onWindowSizeChangeCallbacks_.end()) {
1864 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1865 if (!node) {
1866 iter = onWindowSizeChangeCallbacks_.erase(iter);
1867 } else {
1868 node->OnWindowSizeChanged(width, height, type);
1869 ++iter;
1870 }
1871 }
1872 }
1873
OnDragEvent(int32_t x,int32_t y,DragEventAction action)1874 void PipelineContext::OnDragEvent(int32_t x, int32_t y, DragEventAction action)
1875 {
1876 auto manager = GetDragDropManager();
1877 CHECK_NULL_VOID(manager);
1878 #ifdef ENABLE_DRAG_FRAMEWORK
1879 auto container = Container::Current();
1880 if (container && container->IsScenceBoardWindow()) {
1881 if (!manager->IsDragged() && manager->IsWindowConsumed()) {
1882 manager->SetIsWindowConsumed(false);
1883 LOGD("The event does not need to be handled");
1884 return;
1885 }
1886 }
1887 if (action == DragEventAction::DRAG_EVENT_OUT) {
1888 manager->ClearSummary();
1889 manager->ClearExtraInfo();
1890 }
1891 #endif // ENABLE_DRAG_FRAMEWORK
1892
1893 std::string extraInfo;
1894
1895 #ifdef ENABLE_DRAG_FRAMEWORK
1896 if (action == DragEventAction::DRAG_EVENT_START) {
1897 manager->RequireSummary();
1898 manager->GetExtraInfoFromClipboard(extraInfo);
1899 manager->SetExtraInfo(extraInfo);
1900 }
1901 #else
1902 manager->GetExtraInfoFromClipboard(extraInfo);
1903 #endif // ENABLE_DRAG_FRAMEWORK
1904 if (action == DragEventAction::DRAG_EVENT_END) {
1905 #ifdef ENABLE_DRAG_FRAMEWORK
1906 manager->GetExtraInfoFromClipboard(extraInfo);
1907 manager->SetExtraInfo(extraInfo);
1908 #endif // ENABLE_DRAG_FRAMEWORK
1909 manager->OnDragEnd(Point(x, y, x, y), extraInfo);
1910 manager->RestoreClipboardData();
1911 return;
1912 }
1913 manager->OnDragMove(Point(x, y, x, y), extraInfo);
1914 }
1915
AddNodesToNotifyMemoryLevel(int32_t nodeId)1916 void PipelineContext::AddNodesToNotifyMemoryLevel(int32_t nodeId)
1917 {
1918 nodesToNotifyMemoryLevel_.emplace_back(nodeId);
1919 }
1920
RemoveNodesToNotifyMemoryLevel(int32_t nodeId)1921 void PipelineContext::RemoveNodesToNotifyMemoryLevel(int32_t nodeId)
1922 {
1923 nodesToNotifyMemoryLevel_.remove(nodeId);
1924 }
1925
NotifyMemoryLevel(int32_t level)1926 void PipelineContext::NotifyMemoryLevel(int32_t level)
1927 {
1928 LOGI("PipelineContext: NotifyMemoryLevel called");
1929 auto iter = nodesToNotifyMemoryLevel_.begin();
1930 while (iter != nodesToNotifyMemoryLevel_.end()) {
1931 auto node = ElementRegister::GetInstance()->GetUINodeById(*iter);
1932 if (!node) {
1933 iter = nodesToNotifyMemoryLevel_.erase(iter);
1934 } else {
1935 node->OnNotifyMemoryLevel(level);
1936 ++iter;
1937 }
1938 }
1939 }
AddPredictTask(PredictTask && task)1940 void PipelineContext::AddPredictTask(PredictTask&& task)
1941 {
1942 taskScheduler_->AddPredictTask(std::move(task));
1943 RequestFrame();
1944 }
1945
OnIdle(int64_t deadline)1946 void PipelineContext::OnIdle(int64_t deadline)
1947 {
1948 if (deadline == 0) {
1949 canUseLongPredictTask_ = false;
1950 return;
1951 }
1952 if (canUseLongPredictTask_) {
1953 // check new incoming event after vsync.
1954 if (!touchEvents_.empty()) {
1955 canUseLongPredictTask_ = false;
1956 }
1957 }
1958 CHECK_RUN_ON(UI);
1959 ACE_SCOPED_TRACE("OnIdle, targettime:%" PRId64 "", deadline);
1960 taskScheduler_->FlushPredictTask(deadline - TIME_THRESHOLD, canUseLongPredictTask_);
1961 canUseLongPredictTask_ = false;
1962 if (GetSysTimestamp() < deadline) {
1963 ElementRegister::GetInstance()->CallJSCleanUpIdleTaskFunc();
1964 }
1965 }
1966
Finish(bool) const1967 void PipelineContext::Finish(bool /*autoFinish*/) const
1968 {
1969 CHECK_RUN_ON(UI);
1970 if (finishEventHandler_) {
1971 LOGI("call finishEventHandler");
1972 finishEventHandler_();
1973 } else {
1974 LOGE("fail to finish current context due to handler is nullptr");
1975 }
1976 }
1977
AddAfterLayoutTask(std::function<void ()> && task)1978 void PipelineContext::AddAfterLayoutTask(std::function<void()>&& task)
1979 {
1980 taskScheduler_->AddAfterLayoutTask(std::move(task));
1981 }
1982
AddAfterRenderTask(std::function<void ()> && task)1983 void PipelineContext::AddAfterRenderTask(std::function<void()>&& task)
1984 {
1985 taskScheduler_->AddAfterRenderTask(std::move(task));
1986 }
1987
RestoreNodeInfo(std::unique_ptr<JsonValue> nodeInfo)1988 void PipelineContext::RestoreNodeInfo(std::unique_ptr<JsonValue> nodeInfo)
1989 {
1990 if (!nodeInfo->IsObject()) {
1991 LOGW("restore nodeInfo is invalid");
1992 }
1993 auto child = nodeInfo->GetChild();
1994 while (child->IsValid()) {
1995 auto key = child->GetKey();
1996 auto value = child->GetString();
1997 restoreNodeInfo_.try_emplace(StringUtils::StringToInt(key), value);
1998 child = child->GetNext();
1999 }
2000 }
2001
GetStoredNodeInfo()2002 std::unique_ptr<JsonValue> PipelineContext::GetStoredNodeInfo()
2003 {
2004 auto jsonNodeInfo = JsonUtil::Create(false);
2005 auto iter = storeNode_.begin();
2006 while (iter != storeNode_.end()) {
2007 auto node = (iter->second).Upgrade();
2008 if (node) {
2009 std::string info = node->ProvideRestoreInfo();
2010 if (!info.empty()) {
2011 jsonNodeInfo->Put(std::to_string(iter->first).c_str(), info.c_str());
2012 }
2013 }
2014 ++iter;
2015 }
2016 return jsonNodeInfo;
2017 }
2018
StoreNode(int32_t restoreId,const WeakPtr<FrameNode> & node)2019 void PipelineContext::StoreNode(int32_t restoreId, const WeakPtr<FrameNode>& node)
2020 {
2021 auto ret = storeNode_.try_emplace(restoreId, node);
2022 if (!ret.second) {
2023 LOGW("update restore node, id = %{public}d", restoreId);
2024 storeNode_[restoreId] = node;
2025 }
2026 }
2027
GetRestoreInfo(int32_t restoreId,std::string & restoreInfo)2028 bool PipelineContext::GetRestoreInfo(int32_t restoreId, std::string& restoreInfo)
2029 {
2030 auto iter = restoreNodeInfo_.find(restoreId);
2031 if (iter != restoreNodeInfo_.end()) {
2032 restoreInfo = iter->second;
2033 restoreNodeInfo_.erase(iter);
2034 return true;
2035 }
2036 return false;
2037 }
2038
SetContainerButtonHide(bool hideSplit,bool hideMaximize,bool hideMinimize)2039 void PipelineContext::SetContainerButtonHide(bool hideSplit, bool hideMaximize, bool hideMinimize)
2040 {
2041 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
2042 LOGW("SetAppIcon failed, Window modal is not container.");
2043 return;
2044 }
2045 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
2046 CHECK_NULL_VOID(containerNode);
2047 auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
2048 CHECK_NULL_VOID(containerPattern);
2049 containerPattern->SetContainerButtonHide(hideSplit, hideMaximize, hideMinimize);
2050 }
2051
AddFontNodeNG(const WeakPtr<UINode> & node)2052 void PipelineContext::AddFontNodeNG(const WeakPtr<UINode>& node)
2053 {
2054 if (fontManager_) {
2055 fontManager_->AddFontNodeNG(node);
2056 }
2057 }
2058
RemoveFontNodeNG(const WeakPtr<UINode> & node)2059 void PipelineContext::RemoveFontNodeNG(const WeakPtr<UINode>& node)
2060 {
2061 if (fontManager_) {
2062 fontManager_->RemoveFontNodeNG(node);
2063 }
2064 }
2065
SetWindowSceneConsumed(bool isConsumed)2066 void PipelineContext::SetWindowSceneConsumed(bool isConsumed)
2067 {
2068 isWindowSceneConsumed_ = isConsumed;
2069 }
2070
IsWindowSceneConsumed()2071 bool PipelineContext::IsWindowSceneConsumed()
2072 {
2073 return isWindowSceneConsumed_;
2074 }
2075
SetCloseButtonStatus(bool isEnabled)2076 void PipelineContext::SetCloseButtonStatus(bool isEnabled)
2077 {
2078 if (windowModal_ != WindowModal::CONTAINER_MODAL) {
2079 return;
2080 }
2081 auto containerNode = AceType::DynamicCast<FrameNode>(rootNode_->GetChildren().front());
2082 CHECK_NULL_VOID(containerNode);
2083 auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
2084 CHECK_NULL_VOID(containerPattern);
2085 containerPattern->SetCloseButtonStatus(isEnabled);
2086 }
2087 } // namespace OHOS::Ace::NG
2088