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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMMON_PIPELINE_NG_UI_TASK_SCHEDULER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMMON_PIPELINE_NG_UI_TASK_SCHEDULER_H
18 
19 #include <cstdint>
20 #include <functional>
21 #include <list>
22 #include <map>
23 #include <queue>
24 #include <set>
25 
26 #include "base/log/frame_info.h"
27 #include "base/memory/referenced.h"
28 #include "base/utils/macros.h"
29 
30 namespace OHOS::Ace::NG {
31 
32 class CustomNode;
33 class FrameNode;
34 
35 using TaskThread = uint32_t;
36 constexpr TaskThread PLATFORM_TASK = 0;
37 constexpr TaskThread MAIN_TASK = 1;
38 constexpr TaskThread BACKGROUND_TASK = 1 << 1;
39 constexpr TaskThread UNDEFINED_TASK = 1 << 2;
40 
41 class UITask {
42 public:
UITask(std::function<void ()> && task)43     explicit UITask(std::function<void()>&& task) : task_(std::move(task)) {}
44 
UITask(std::function<void ()> && task,TaskThread taskThread)45     UITask(std::function<void()>&& task, TaskThread taskThread) : task_(std::move(task)), taskThread_(taskThread) {}
46 
47     ~UITask() = default;
48 
SetTaskThreadType(TaskThread taskThread)49     void SetTaskThreadType(TaskThread taskThread)
50     {
51         taskThread_ = taskThread;
52     }
53 
GetTaskThreadType()54     TaskThread GetTaskThreadType() const
55     {
56         return taskThread_;
57     }
58 
operator()59     void operator()() const
60     {
61         if (task_) {
62             task_();
63         }
64     }
65 
66 private:
67     std::function<void()> task_;
68     TaskThread taskThread_ = MAIN_TASK;
69 };
70 
71 class ACE_EXPORT UITaskScheduler final {
72 public:
73     using PredictTask = std::function<void(int64_t, bool)>;
74     UITaskScheduler();
75     ~UITaskScheduler();
76 
77     // Called on Main Thread.
78     void AddDirtyLayoutNode(const RefPtr<FrameNode>& dirty);
79     void AddLayoutNode(const RefPtr<FrameNode>& layoutNode);
80     void AddDirtyRenderNode(const RefPtr<FrameNode>& dirty);
81     void AddPredictTask(PredictTask&& task);
82     void AddAfterLayoutTask(std::function<void()>&& task, bool isFlushInImplicitAnimationTask = false);
83     void AddAfterRenderTask(std::function<void()>&& task);
84     void AddPersistAfterLayoutTask(std::function<void()>&& task);
85 
86     void FlushLayoutTask(bool forceUseMainThread = false);
87     void FlushRenderTask(bool forceUseMainThread = false);
88     void FlushTask();
89     void FlushTaskWithCheck(bool triggeredByImplicitAnimation = false);
90     void FlushPredictTask(int64_t deadline, bool canUseLongPredictTask = false);
91     void FlushAfterLayoutTask();
92     void FlushAfterLayoutCallbackInImplicitAnimationTask();
93     void FlushAfterRenderTask();
94     void FlushPersistAfterLayoutTask();
95     void ExpandSafeArea();
96 
97     void FlushDelayJsActive();
98 
UpdateCurrentPageId(uint32_t id)99     void UpdateCurrentPageId(uint32_t id)
100     {
101         currentPageId_ = id;
102     }
103 
104     void CleanUp();
105 
106     bool isEmpty();
107 
108     bool IsPredictTaskEmpty();
109 
StartRecordFrameInfo(FrameInfo * info)110     void StartRecordFrameInfo(FrameInfo* info)
111     {
112         frameInfo_ = info;
113     }
114 
FinishRecordFrameInfo()115     void FinishRecordFrameInfo()
116     {
117         frameInfo_ = nullptr;
118     }
119 
GetFrameId()120     static uint64_t GetFrameId()
121     {
122         return frameId_;
123     }
124 
IsLayouting()125     bool IsLayouting() const {
126         return isLayouting_;
127     }
128 
129     void AddSingleNodeToFlush(const RefPtr<FrameNode>& dirtyNode);
130 
131     bool RequestFrameOnLayoutCountExceeds();
132 
133     void SetJSViewActive(bool active, WeakPtr<CustomNode> custom);
134 
IsDirtyLayoutNodesEmpty()135     bool IsDirtyLayoutNodesEmpty()
136     {
137         return dirtyLayoutNodes_.empty();
138     }
139 
AddSyncGeometryNodeTask(std::function<void ()> && task)140     void AddSyncGeometryNodeTask(std::function<void()>&& task)
141     {
142         syncGeometryNodeTasks_.emplace_back(task);
143     }
144 
145     void AddSafeAreaPaddingProcessTask(FrameNode* node);
146     void RemoveSafeAreaPaddingProcessTask(FrameNode* node);
147     void FlushSafeAreaPaddingProcess();
148 
SetIsLayouting(bool layouting)149     void SetIsLayouting(bool layouting)
150     {
151         isLayouting_ = layouting;
152     }
153 
154     void FlushSyncGeometryNodeTasks();
155 
156 private:
157     bool NeedAdditionalLayout();
158     void FlushAllSingleNodeTasks();
159     void SetLayoutNodeRect();
160 
161     template<typename T>
162     struct NodeCompare {
operatorNodeCompare163         bool operator()(const T& nodeLeft, const T& nodeRight) const
164         {
165             if (!nodeLeft || !nodeRight) {
166                 return false;
167             }
168             if (nodeLeft->GetLayoutPriority() != nodeRight->GetLayoutPriority()) {
169                 return nodeLeft->GetLayoutPriority() > nodeRight->GetLayoutPriority();
170             }
171             if (nodeLeft->GetPageId() != nodeRight->GetPageId()) {
172                 return nodeLeft->GetPageId() < nodeRight->GetPageId();
173             }
174             if (nodeLeft->GetDepth() != nodeRight->GetDepth()) {
175                 return nodeLeft->GetDepth() < nodeRight->GetDepth();
176             }
177             return nodeLeft < nodeRight;
178         }
179     };
180 
181     using PageDirtySet = std::set<RefPtr<FrameNode>, NodeCompare<RefPtr<FrameNode>>>;
182     using LayoutNodesSet = std::set<RefPtr<FrameNode>, NodeCompare<RefPtr<FrameNode>>>;
183     using RootDirtyMap = std::map<uint32_t, PageDirtySet>;
184 
185     std::list<RefPtr<FrameNode>> dirtyLayoutNodes_;
186     std::list<RefPtr<FrameNode>> layoutNodes_;
187     RootDirtyMap dirtyRenderNodes_;
188     std::list<PredictTask> predictTask_;
189     std::list<std::function<void()>> afterLayoutTasks_;
190     std::list<std::function<void()>> afterLayoutCallbacksInImplicitAnimationTask_;
191     std::list<std::function<void()>> afterRenderTasks_;
192     std::list<std::function<void()>> persistAfterLayoutTasks_;
193     std::list<std::function<void()>> syncGeometryNodeTasks_;
194     std::list<RefPtr<FrameNode>> singleDirtyNodesToFlush_;
195     std::queue<bool> layoutWithImplicitAnimation_;
196     std::set<FrameNode*, NodeCompare<FrameNode*>> safeAreaPaddingProcessTasks_;
197 
198     uint32_t currentPageId_ = 0;
199     bool is64BitSystem_ = false;
200     bool isLayouting_ = false;
201     int32_t layoutedCount_ = 0;
202     int32_t multiLayoutCount_ = 0;
203 
204     FrameInfo* frameInfo_ = nullptr;
205 
206     static uint64_t frameId_;
207 
208     ACE_DISALLOW_COPY_AND_MOVE(UITaskScheduler);
209 };
210 
211 } // namespace OHOS::Ace::NG
212 
213 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMMON_PIPELINE_NG_UI_TASK_SCHEDULER_H
214