1 /*
2  * Copyright (c) 2021-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_BRIDGE_JS_FRONTEND_JS_ACE_PAGE_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_JS_ACE_PAGE_H
18 
19 #include <functional>
20 #include <mutex>
21 #include <string>
22 #include <unordered_set>
23 #include <vector>
24 
25 #include "base/utils/macros.h"
26 #include "core/animation/animator_info.h"
27 #include "core/common/ace_page.h"
28 #include "core/common/thread_checker.h"
29 #ifndef NG_BUILD
30 #include "core/components/checkable/radio_group_component.h"
31 #endif
32 #include "core/components/page/page_target.h"
33 #include "core/components/page_transition/page_transition_component.h"
34 #include "frameworks/bridge/common/utils/source_map.h"
35 #include "frameworks/bridge/common/utils/utils.h"
36 #include "frameworks/bridge/js_frontend/engine/common/base_animation_bridge.h"
37 #include "frameworks/bridge/js_frontend/engine/common/base_canvas_bridge.h"
38 #include "frameworks/bridge/js_frontend/engine/common/base_xcomponent_bridge.h"
39 #include "frameworks/bridge/js_frontend/js_command.h"
40 
41 namespace OHOS::Ace::NG {
42 
43 class UINode;
44 
45 } // namespace OHOS::Ace::NG
46 
47 namespace OHOS::Ace::Framework {
48 
49 #ifndef NG_BUILD
50 class DOMDocument;
51 using JsPageRadioGroups = std::unordered_map<std::string, RadioGroupComponent<std::string>>;
52 #endif
53 
54 const char MERGE_SOURCEMAPS_PATH[] = "sourceMaps.map";
55 
56 // One JsAcePage corresponding to a JS bundle, so it should maintain page's lifecycle.
57 class ACE_FORCE_EXPORT JsAcePage final : public AcePage {
58     DECLARE_ACE_TYPE(JsAcePage, AcePage);
59 
60 public:
61 #ifdef NG_BUILD
62     JsAcePage(int32_t pageId, const std::string& url);
63 #else
64     JsAcePage(int32_t pageId, const RefPtr<DOMDocument>& document, const std::string& url,
65         const WeakPtr<StageElement>& container = nullptr);
66 #endif
67 
68     ~JsAcePage() override;
69 
70     RefPtr<PageComponent> BuildPage(const std::string& url) override;
71 #ifndef NG_BUILD
72     RefPtr<ComposedComponent> BuildPagePatch(int32_t nodeId);
73 
GetDomDocument()74     RefPtr<DOMDocument> GetDomDocument() const
75     {
76         return domDoc_;
77     }
78 #endif
79 
GetUrl()80     const std::string& GetUrl() const
81     {
82         return url_;
83     }
84 
CheckPageCreated()85     bool CheckPageCreated() const
86     {
87         return pageCreated_;
88     }
89 
SetPageCreated()90     void SetPageCreated()
91     {
92         pageCreated_ = true;
93     }
94 
95 #ifndef NG_BUILD
SetPageTransition(const RefPtr<PageTransitionComponent> & pageTransition)96     void SetPageTransition(const RefPtr<PageTransitionComponent>& pageTransition)
97     {
98         pageTransition_ = pageTransition;
99     }
100 
PushCommand(const RefPtr<JsCommand> & jsCommand)101     void PushCommand(const RefPtr<JsCommand>& jsCommand)
102     {
103         jsCommands_.emplace_back(jsCommand);
104     }
105 
PopAllCommands(std::vector<RefPtr<JsCommand>> & jsCommands)106     void PopAllCommands(std::vector<RefPtr<JsCommand>>& jsCommands)
107     {
108         jsCommands = std::move(jsCommands_);
109     }
110 #endif
111 
PushNewNode(NodeId nodeId,NodeId parentNodeId)112     void PushNewNode(NodeId nodeId, NodeId parentNodeId)
113     {
114         CHECK_RUN_ON(UI);
115         dirtyNodes_.emplace(nodeId);
116         PushDirtyNode(parentNodeId);
117     }
118 
PushDirtyNode(NodeId nodeId)119     void PushDirtyNode(NodeId nodeId)
120     {
121         CHECK_RUN_ON(UI);
122         auto result = dirtyNodes_.emplace(nodeId);
123         if (result.second) {
124             dirtyNodesOrderedByTime_.emplace_back(nodeId);
125         }
126     }
127 
PopAllDirtyNodes(std::vector<NodeId> & dirtyNodes)128     void PopAllDirtyNodes(std::vector<NodeId>& dirtyNodes)
129     {
130         CHECK_RUN_ON(UI);
131         dirtyNodes = std::move(dirtyNodesOrderedByTime_);
132         dirtyNodes_.clear();
133     }
134 
ClearAllDirtyNodes()135     void ClearAllDirtyNodes()
136     {
137         CHECK_RUN_ON(UI);
138         dirtyNodesOrderedByTime_.clear();
139         dirtyNodes_.clear();
140     }
141 
142 #ifndef NG_BUILD
ReserveShowCommand(const RefPtr<JsCommand> & command)143     void ReserveShowCommand(const RefPtr<JsCommand>& command)
144     {
145         if (command) {
146             std::unique_lock<std::mutex> lock(cmdMutex_);
147             showCommands_.emplace_back(command);
148         }
149     }
150 
UpdateShowAttr()151     void UpdateShowAttr()
152     {
153         CHECK_RUN_ON(UI);
154         std::unique_lock<std::mutex> lock(cmdMutex_);
155         if (showCommands_.empty()) {
156             return;
157         }
158 
159         for (auto& command : showCommands_) {
160             command->Execute(AceType::Claim(this));
161         }
162         showCommandConsumed_ = true;
163     }
164 
CheckShowCommandConsumed()165     bool CheckShowCommandConsumed() const
166     {
167         return showCommandConsumed_;
168     }
169 
ClearShowCommand()170     void ClearShowCommand()
171     {
172         std::unique_lock<std::mutex> lock(cmdMutex_);
173         showCommands_.clear();
174         showCommandConsumed_ = false;
175     }
176 #endif
177 
178     RefPtr<BaseCanvasBridge> GetBridgeById(NodeId nodeId);
179     void PushCanvasBridge(NodeId nodeId, const RefPtr<BaseCanvasBridge>& bridge);
180     void PushOffscreenCanvasBridge(int32_t bridgeId, const RefPtr<BaseCanvasBridge>& bridge);
181     RefPtr<BaseCanvasBridge> GetOffscreenCanvasBridgeById(int32_t nodeId);
182 
183     RefPtr<BaseXComponentBridge> GetXComponentBridgeById(NodeId nodeId);
184     void PushXComponentBridge(NodeId nodeId, const RefPtr<BaseXComponentBridge>& bridge);
185 
186     RefPtr<BaseAnimationBridge> GetAnimationBridge(NodeId nodeId);
187     void RemoveAnimationBridge(NodeId nodeId);
188     void AddAnimationBridge(NodeId nodeId, const RefPtr<BaseAnimationBridge>& animationBridge);
189 
190     RefPtr<BaseAnimationBridge> GetAnimatorBridge(int32_t bridgeId);
191     void RemoveAnimatorBridge(int32_t bridgeId);
192     void AddAnimatorBridge(int32_t bridgeId, const RefPtr<BaseAnimationBridge>& animatorBridge);
193 
194     RefPtr<AnimatorInfo> GetAnimatorInfo(const std::string& animatorId);
195     void RemoveAnimatorInfo(const std::string& animatorId);
196     void AddAnimatorInfo(const std::string& animatorId, const RefPtr<AnimatorInfo>& animatorInfo);
197 
SetPageParams(const std::string & params)198     void SetPageParams(const std::string& params)
199     {
200         pageParams_ = params;
201     }
202 
GetPageParams()203     const std::string& GetPageParams() const
204     {
205         return pageParams_;
206     }
207 
SetFlushCallback(std::function<void (const RefPtr<JsAcePage> &)> && callback)208     void SetFlushCallback(std::function<void(const RefPtr<JsAcePage>&)>&& callback)
209     {
210         flushCallback_ = std::move(callback);
211     }
212 
FlushCommands()213     void FlushCommands()
214     {
215         if (flushCallback_) {
216             fragmentCount_++;
217             flushCallback_(AceType::Claim(this));
218         }
219     }
220 
FragmentCount()221     int32_t FragmentCount() const
222     {
223         return fragmentCount_;
224     }
225 
226 #ifndef NG_BUILD
GetCommandSize()227     size_t GetCommandSize() const
228     {
229         return jsCommands_.size();
230     }
231 #endif
232 
SetPipelineContext(const WeakPtr<PipelineBase> & pipelineContext)233     void SetPipelineContext(const WeakPtr<PipelineBase>& pipelineContext)
234     {
235         pipelineContext_ = pipelineContext;
236     }
237 
GetPipelineContext()238     WeakPtr<PipelineBase> GetPipelineContext() const
239     {
240         return pipelineContext_;
241     }
242 
IsLiteStyle()243     bool IsLiteStyle() const
244     {
245         return useLiteStyle_;
246     }
247 
SetUseLiteStyle(bool useLiteStyle)248     void SetUseLiteStyle(bool useLiteStyle)
249     {
250         useLiteStyle_ = useLiteStyle;
251     }
252 
IsUseBoxWrap()253     bool IsUseBoxWrap() const
254     {
255         return useBoxWrap_;
256     }
257 
SetUseBoxWrap(bool useBoxWrap)258     void SetUseBoxWrap(bool useBoxWrap)
259     {
260         useBoxWrap_ = useBoxWrap;
261     }
262 
GetPluginComponentJsonData()263     const std::string& GetPluginComponentJsonData() const
264     {
265         return pluginComponentJsonData_;
266     }
267 
SetPluginComponentJsonData(const std::string & pluginComponentJsonData)268     void SetPluginComponentJsonData(const std::string& pluginComponentJsonData)
269     {
270         pluginComponentJsonData_ = pluginComponentJsonData;
271     }
272 
273     void AddNodeEvent(int32_t nodeId, const std::string& actionType, const std::string& eventAction);
274 
275     std::string GetNodeEventAction(int32_t nodeId, const std::string& actionType);
276 #ifndef NG_BUILD
277     std::shared_ptr<JsPageRadioGroups> GetRadioGroups();
278 #endif
279 
SetRootComponent(const RefPtr<Component> & component)280     void SetRootComponent(const RefPtr<Component>& component)
281     {
282         component_ = component;
283     }
284 
285     void SetRootNode(const RefPtr<NG::UINode>& node);
286 
GetRootNode()287     const RefPtr<NG::UINode>& GetRootNode() const
288     {
289         return pageRootNode_;
290     }
291 
SetPageMap(const std::string & pageMap)292     void SetPageMap(const std::string& pageMap)
293     {
294         pageMap_ = AceType::MakeRefPtr<RevSourceMap>();
295         pageMap_->Init(pageMap);
296     }
297 
GetPageMap()298     RefPtr<RevSourceMap> GetPageMap() const
299     {
300         return pageMap_;
301     }
302 
SetAppMap(const std::string & appMap)303     void SetAppMap(const std::string& appMap)
304     {
305         appMap_ = AceType::MakeRefPtr<RevSourceMap>();
306         appMap_->Init(appMap);
307     }
308 
GetAppMap()309     RefPtr<RevSourceMap> GetAppMap() const
310     {
311         return appMap_;
312     }
313 
GetStageElement()314     RefPtr<StageElement> GetStageElement() const
315     {
316         return container_.Upgrade();
317     }
318 
SetDeclarativeOnPageAppearCallback(std::function<void ()> && callback)319     void SetDeclarativeOnPageAppearCallback(std::function<void()>&& callback)
320     {
321         onPageAppear_ = callback;
322     }
323 
SetDeclarativeOnPageDisAppearCallback(std::function<void ()> && callback)324     void SetDeclarativeOnPageDisAppearCallback(std::function<void()>&& callback)
325     {
326         onPageDisAppear_ = callback;
327     }
328 
SetDeclarativeOnBackPressCallback(std::function<bool ()> && callback)329     void SetDeclarativeOnBackPressCallback(std::function<bool()>&& callback)
330     {
331         onBackPress_ = callback;
332     }
333 
SetDeclarativeOnPageRefreshCallback(std::function<void ()> && callback)334     void SetDeclarativeOnPageRefreshCallback(std::function<void()>&& callback)
335     {
336         onPageRefresh_ = callback;
337     }
338 
SetDeclarativeOnUpdateWithValueParamsCallback(std::function<void (const std::string &)> && callback)339     void SetDeclarativeOnUpdateWithValueParamsCallback(std::function<void(const std::string&)>&& callback)
340     {
341         onUpdateWithValueParams_ = callback;
342     }
343 
FireDeclarativeOnPageAppearCallback()344     void FireDeclarativeOnPageAppearCallback() const
345     {
346         if (onPageAppear_) {
347             onPageAppear_();
348         }
349     }
350 
FireDeclarativeOnPageDisAppearCallback()351     void FireDeclarativeOnPageDisAppearCallback() const
352     {
353         if (onPageDisAppear_) {
354             onPageDisAppear_();
355         }
356     }
357 
FireDeclarativeOnBackPressCallback()358     bool FireDeclarativeOnBackPressCallback() const
359     {
360         if (onBackPress_) {
361             return onBackPress_();
362         }
363         return false;
364     }
365 
FireDeclarativeOnPageRefreshCallback()366     void FireDeclarativeOnPageRefreshCallback() const
367     {
368         if (onPageRefresh_) {
369             onPageRefresh_();
370         }
371     }
372 
FireDeclarativeOnUpdateWithValueParamsCallback(const std::string & params)373     void FireDeclarativeOnUpdateWithValueParamsCallback(const std::string& params) const
374     {
375         if (onUpdateWithValueParams_) {
376             onUpdateWithValueParams_(params);
377         }
378     }
379 
380     void OnJsEngineDestroy();
381 
382 private:
383 #ifndef NG_BUILD
384     void SwapBackgroundDecoration(const RefPtr<PageTransitionComponent>& transition);
385 #endif
386     std::string GetCardId() const;
387 
388     bool pageCreated_ = false;
389 #ifndef NG_BUILD
390     bool showCommandConsumed_ = false;
391 #endif
392     int32_t fragmentCount_ = 0;
393 
394     WeakPtr<PipelineBase> pipelineContext_;
395     RefPtr<PageTransitionComponent> pageTransition_;
396     RefPtr<Component> component_;
397     RefPtr<NG::UINode> pageRootNode_;
398     RefPtr<DOMDocument> domDoc_;
399     std::string url_;
400     WeakPtr<StageElement> container_;
401 
402     RefPtr<RevSourceMap> pageMap_;
403     RefPtr<RevSourceMap> appMap_;
404     bool useLiteStyle_ = false;
405     bool useBoxWrap_ = false;
406     std::string pluginComponentJsonData_;
407 
408     std::vector<RefPtr<JsCommand>> jsCommands_;
409     std::vector<NodeId> dirtyNodesOrderedByTime_;
410     std::unordered_set<NodeId> dirtyNodes_;
411     std::mutex cmdMutex_;
412     std::vector<RefPtr<JsCommand>> showCommands_;
413     std::function<void(const RefPtr<JsAcePage>&)> flushCallback_;
414     std::string pageParams_;
415     std::mutex eventMutex_;
416     std::unordered_map<NodeId, std::unordered_map<std::string, std::string>> nodeEvent_;
417     std::mutex bridgeMutex_;
418     std::unordered_map<NodeId, RefPtr<BaseAnimationBridge>> animationBridges_;
419     std::unordered_map<NodeId, RefPtr<BaseCanvasBridge>> canvasBridges_;
420     std::unordered_map<int32_t, RefPtr<BaseCanvasBridge>> offscreenCanvasBridges_;
421     std::unordered_map<NodeId, RefPtr<BaseXComponentBridge>> xcomponentBridges_;
422     std::unordered_map<int32_t, RefPtr<BaseAnimationBridge>> animatorBridges_;
423     std::unordered_map<std::string, RefPtr<AnimatorInfo>> animatorInfos_;
424 #ifndef NG_BUILD
425     std::shared_ptr<JsPageRadioGroups> radioGroups_;
426 #endif
427 
428     std::function<void()> onPageAppear_;
429     std::function<void()> onPageDisAppear_;
430     std::function<bool()> onBackPress_;
431     std::function<void()> onPageRefresh_;
432     std::function<void(const std::string&)> onUpdateWithValueParams_;
433 };
434 
435 } // namespace OHOS::Ace::Framework
436 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_JS_ACE_PAGE_H
437