• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "frameworks/bridge/js_frontend/js_ace_page.h"
17 
18 #include "base/utils/system_properties.h"
19 #include "core/components/focus_collaboration/focus_collaboration_component.h"
20 #include "core/components/page/page_component.h"
21 #include "core/components/page_transition/page_transition_component.h"
22 #include "core/components_ng/base/frame_node.h"
23 #include "core/components_ng/base/ui_node.h"
24 
25 namespace OHOS::Ace::Framework {
26 
27 #ifdef NG_BUILD
JsAcePage(int32_t pageId,const std::string & url)28 JsAcePage::JsAcePage(int32_t pageId, const std::string& url) : AcePage(pageId), url_(url) {}
29 #else
30 JsAcePage::JsAcePage(int32_t pageId, const RefPtr<DOMDocument>& document, const std::string& url,
31     const WeakPtr<StageElement>& container)
32     : AcePage(pageId), domDoc_(document), url_(url), container_(container),
33       radioGroups_(std::make_shared<JsPageRadioGroups>())
34 {
35     ACE_DCHECK(domDoc_);
36 }
37 #endif
38 
~JsAcePage()39 JsAcePage::~JsAcePage()
40 {
41     LOG_DESTROY();
42 #ifndef NG_BUILD
43     auto pipelineContext = pipelineContext_.Upgrade();
44     if (!pipelineContext) {
45         return;
46     }
47 
48     auto taskExecutor = pipelineContext->GetTaskExecutor();
49     if (!taskExecutor) {
50         LOGE("taskExecutor not exists");
51         return;
52     }
53 
54     auto accessibilityManager = pipelineContext->GetAccessibilityManager();
55     RefPtr<DOMDocument> domDoc;
56     domDoc.Swap(domDoc_);
57     auto weakDom = AceType::WeakClaim(AceType::RawPtr(domDoc));
58     auto weakAcc = AceType::WeakClaim(AceType::RawPtr(accessibilityManager));
59     taskExecutor->PostTask(
60         [weakDom, weakAcc] {
61             auto domDoc = weakDom.Upgrade();
62             auto accessibilityManager = weakAcc.Upgrade();
63             if (domDoc && accessibilityManager) {
64                 accessibilityManager->ClearPageAccessibilityNodes(domDoc->GetRootNodeId());
65             }
66         },
67         TaskExecutor::TaskType::UI);
68 
69     // Release Dom and Components in UI thread
70     RefPtr<PageTransitionComponent> pageTransition;
71     pageTransition.Swap(pageTransition_);
72     RefPtr<Component> component;
73     component.Swap(component_);
74     std::shared_ptr<JsPageRadioGroups> radioGroups;
75     radioGroups.swap(radioGroups_);
76 
77     taskExecutor->PostTask(
78         [domDoc, pageTransition, component, radioGroups]() mutable {
79             LOGI("release Dom and Components on UI thread");
80             domDoc.Reset();
81             pageTransition.Reset();
82             component.Reset();
83             radioGroups.reset();
84         },
85         TaskExecutor::TaskType::UI);
86 #endif
87 }
88 
BuildPage(const std::string & url)89 RefPtr<PageComponent> JsAcePage::BuildPage(const std::string& url)
90 {
91 #ifdef NG_BUILD
92     return nullptr;
93 #else
94     CHECK_RUN_ON(UI);
95     auto pageId = GetPageId();
96     auto rootStack = domDoc_->GetRootStackComponent();
97     auto rootComposedStack = domDoc_->GetRootComposedStack();
98     auto focusCollaboration = AceType::MakeRefPtr<FocusCollaborationComponent>(true);
99 
100     if (container_.Upgrade()) {
101         if (component_) {
102             return AceType::MakeRefPtr<PageComponent>(pageId, url, component_);
103         } else if (rootComposedStack) {
104             return AceType::MakeRefPtr<PageComponent>(pageId, url, rootComposedStack);
105         }
106     }
107     if (!pageTransition_) {
108         pageTransition_ = AceType::MakeRefPtr<PageTransitionComponent>();
109     }
110     if ((!rootStack || !rootComposedStack) && !component_) {
111         LOGW("Page[%{public}d] can't be loaded. no root component.", pageId);
112         pageTransition_->SetContent(nullptr);
113     } else {
114         if (component_) {
115             focusCollaboration->InsertChild(0, component_);
116         } else if (rootComposedStack) {
117             focusCollaboration->InsertChild(0, rootComposedStack);
118         }
119         pageTransition_->SetContent(focusCollaboration);
120         if ((SystemProperties::GetDeviceType() == DeviceType::TV) && (!pageTransition_->GetIsSetOption())) {
121             pageTransition_->SetSeparation(true);
122             SwapBackgroundDecoration(pageTransition_);
123         }
124     }
125     bool isDeclarative = false;
126     auto context = pipelineContext_.Upgrade();
127     if (context && context->GetIsDeclarative()) {
128         isDeclarative = true;
129     }
130     const std::string& cardComposeId = GetCardId();
131     if (!cardComposeId.empty()) {
132         return AceType::MakeRefPtr<PageComponent>(
133             pageId, url, cardComposeId, isDeclarative ? std::move(pageTransition_) : pageTransition_);
134     }
135     return AceType::MakeRefPtr<PageComponent>(
136         pageId, url, isDeclarative ? std::move(pageTransition_) : pageTransition_);
137 #endif
138 }
139 
GetCardId() const140 std::string JsAcePage::GetCardId() const
141 {
142     std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(pageParams_);
143     if (argsValue && argsValue->IsObject()) {
144         // support old JSON structure as { "ref": value}
145         if (!argsValue->GetString(DOM_TRANSITION_CARD_COMPOSEID).empty()) {
146             return argsValue->GetString(DOM_TRANSITION_CARD_COMPOSEID);
147         }
148 
149         // support new JSON structure as { "paramsData": { "ref": value } }
150         const auto& paramsData = argsValue->GetObject(DOM_TRANSITION_CARD_PARAMS);
151         if (paramsData->IsObject() && !paramsData->GetString(DOM_TRANSITION_CARD_COMPOSEID).empty()) {
152             return paramsData->GetString(DOM_TRANSITION_CARD_COMPOSEID);
153         }
154     }
155     return "";
156 }
157 
158 #ifndef NG_BUILD
BuildPagePatch(int32_t nodeId)159 RefPtr<ComposedComponent> JsAcePage::BuildPagePatch(int32_t nodeId)
160 {
161     CHECK_RUN_ON(UI);
162     RefPtr<Component> dirtyComponent = domDoc_->GetComponentById(nodeId);
163     if (!dirtyComponent) {
164         LOGE("Node[%{public}d] can't be reached.", nodeId);
165         return nullptr;
166     }
167 
168     auto composedComponent = AceType::DynamicCast<ComposedComponent>(dirtyComponent);
169     ACE_DCHECK(composedComponent);
170     return composedComponent;
171 }
172 
SwapBackgroundDecoration(const RefPtr<PageTransitionComponent> & transition)173 void JsAcePage::SwapBackgroundDecoration(const RefPtr<PageTransitionComponent>& transition)
174 {
175     CHECK_RUN_ON(UI);
176     if (!transition) {
177         LOGW("swap background decoration failed. transition is null.");
178         return;
179     }
180 
181     auto rootNode = domDoc_->GetDOMNodeById(DOM_ROOT_NODE_ID_BASE + GetPageId());
182     if (!rootNode) {
183         LOGW("swap background decoration failed. root node is null.");
184         return;
185     }
186 
187     auto box = rootNode->GetBoxComponent();
188     if (!box) {
189         LOGW("swap background decoration failed. box is null.");
190         return;
191     }
192 
193     auto decoration = box->GetBackDecoration();
194     if (!decoration) {
195         LOGW("swap background decoration failed. decoration is null.");
196         return;
197     }
198 
199     auto backgroundBox = AceType::MakeRefPtr<BoxComponent>();
200     backgroundBox->SetBackDecoration(decoration);
201     backgroundBox->SetWidth(box->GetWidthDimension().Value(), box->GetWidthDimension().Unit());
202     backgroundBox->SetHeight(box->GetHeightDimension().Value(), box->GetHeightDimension().Unit());
203     backgroundBox->SetFlex(BoxFlex::FLEX_XY);
204     transition->SetBackground(backgroundBox);
205     box->SetBackDecoration(nullptr);
206 }
207 #endif
208 
GetBridgeById(NodeId nodeId)209 RefPtr<BaseCanvasBridge> JsAcePage::GetBridgeById(NodeId nodeId)
210 {
211     std::unique_lock<std::mutex> lock(bridgeMutex_);
212     auto iter = canvasBridges_.find(nodeId);
213     if (iter == canvasBridges_.end()) {
214         LOGE("the canvas is not in the map");
215         return nullptr;
216     }
217     return iter->second;
218 }
219 
GetOffscreenCanvasBridgeById(int32_t bridgeId)220 RefPtr<BaseCanvasBridge> JsAcePage::GetOffscreenCanvasBridgeById(int32_t bridgeId)
221 {
222     auto iter = offscreenCanvasBridges_.find(bridgeId);
223     if (iter == offscreenCanvasBridges_.end()) {
224         LOGE("the canvas is not in the map");
225         return nullptr;
226     }
227     return iter->second;
228 }
229 
GetXComponentBridgeById(NodeId nodeId)230 RefPtr<BaseXComponentBridge> JsAcePage::GetXComponentBridgeById(NodeId nodeId)
231 {
232     auto iter = xcomponentBridges_.find(nodeId);
233     if (iter == xcomponentBridges_.end()) {
234         LOGE("the XComponent is not in the map");
235         return nullptr;
236     }
237     return iter->second;
238 }
239 
GetAnimationBridge(NodeId nodeId)240 RefPtr<BaseAnimationBridge> JsAcePage::GetAnimationBridge(NodeId nodeId)
241 {
242     std::unique_lock<std::mutex> lock(bridgeMutex_);
243     auto bridge = animationBridges_.find(nodeId);
244     if (bridge == animationBridges_.end()) {
245         LOGW("the animation bridge is not in the map, nodeId: %{public}d", nodeId);
246         return nullptr;
247     }
248     return bridge->second;
249 }
250 
RemoveAnimationBridge(NodeId nodeId)251 void JsAcePage::RemoveAnimationBridge(NodeId nodeId)
252 {
253     RefPtr<BaseAnimationBridge> bridge;
254     {
255         std::unique_lock<std::mutex> lock(bridgeMutex_);
256         auto pos = animationBridges_.find(nodeId);
257         if (pos != animationBridges_.end()) {
258             bridge.Swap(pos->second);
259             animationBridges_.erase(pos);
260         }
261     }
262 
263     if (bridge) {
264         auto pipelineContext = pipelineContext_.Upgrade();
265         if (!pipelineContext) {
266             LOGE("pipelineContext is nullptr");
267             return;
268         }
269         auto taskExecutor = pipelineContext->GetTaskExecutor();
270         if (!taskExecutor) {
271             LOGE("taskExecutor is nullptr");
272             return;
273         }
274         taskExecutor->PostSyncTask([&bridge]() { bridge.Reset(); }, TaskExecutor::TaskType::JS);
275     }
276 }
277 
AddAnimationBridge(NodeId nodeId,const RefPtr<BaseAnimationBridge> & animationBridge)278 void JsAcePage::AddAnimationBridge(NodeId nodeId, const RefPtr<BaseAnimationBridge>& animationBridge)
279 {
280     if (!animationBridge) {
281         LOGE("AddAnimationBridge failed. Animation bridge is null.");
282         return;
283     }
284     std::unique_lock<std::mutex> lock(bridgeMutex_);
285     animationBridges_[nodeId] = animationBridge;
286 }
287 
AddAnimatorBridge(int32_t bridgeId,const RefPtr<BaseAnimationBridge> & animatorBridge)288 void JsAcePage::AddAnimatorBridge(int32_t bridgeId, const RefPtr<BaseAnimationBridge>& animatorBridge)
289 {
290     if (!animatorBridge) {
291         LOGE("AddAnimationBridge failed. Animation bridge is null.");
292         return;
293     }
294     auto animator = animatorBridge->JsGetAnimator();
295     if (!animator) {
296         LOGE("animator is null");
297         return;
298     }
299     animator->AttachScheduler(pipelineContext_);
300     std::unique_lock<std::mutex> lock(bridgeMutex_);
301     animatorBridges_[bridgeId] = animatorBridge;
302 }
303 
RemoveAnimatorBridge(int32_t bridgeId)304 void JsAcePage::RemoveAnimatorBridge(int32_t bridgeId)
305 {
306     std::unique_lock<std::mutex> lock(bridgeMutex_);
307     animatorBridges_.erase(bridgeId);
308 }
309 
GetAnimatorBridge(int32_t bridgeId)310 RefPtr<BaseAnimationBridge> JsAcePage::GetAnimatorBridge(int32_t bridgeId)
311 {
312     std::unique_lock<std::mutex> lock(bridgeMutex_);
313     auto bridge = animatorBridges_.find(bridgeId);
314     if (bridge == animatorBridges_.end()) {
315         LOGW("the animation bridge is not in the map, nodeId: %{public}d", bridgeId);
316         return nullptr;
317     }
318     return bridge->second;
319 }
320 
AddAnimatorInfo(const std::string & animatorId,const RefPtr<AnimatorInfo> & animatorInfo)321 void JsAcePage::AddAnimatorInfo(const std::string& animatorId, const RefPtr<AnimatorInfo>& animatorInfo)
322 {
323     if (!animatorInfo) {
324         LOGE("AddAnimation failed. Animation is null.");
325         return;
326     }
327     auto animator = animatorInfo->GetAnimator();
328     if (!animator) {
329         LOGE("animator is null");
330         return;
331     }
332     animator->AttachScheduler(pipelineContext_);
333     animatorInfos_[animatorId] = animatorInfo;
334 }
335 
RemoveAnimatorInfo(const std::string & animatorId)336 void JsAcePage::RemoveAnimatorInfo(const std::string& animatorId)
337 {
338     animatorInfos_.erase(animatorId);
339 }
340 
GetAnimatorInfo(const std::string & animatorId)341 RefPtr<AnimatorInfo> JsAcePage::GetAnimatorInfo(const std::string& animatorId)
342 {
343     auto bridge = animatorInfos_.find(animatorId);
344     if (bridge == animatorInfos_.end()) {
345         LOGW("the animation bridge is not in the map, animatorId: %{public}s", animatorId.c_str());
346         return nullptr;
347     }
348     return bridge->second;
349 }
350 
PushCanvasBridge(NodeId nodeId,const RefPtr<BaseCanvasBridge> & bridge)351 void JsAcePage::PushCanvasBridge(NodeId nodeId, const RefPtr<BaseCanvasBridge>& bridge)
352 {
353     if (!bridge) {
354         LOGE("PushCanvasBridge failed. Canvas bridge is null.");
355         return;
356     }
357     std::unique_lock<std::mutex> lock(bridgeMutex_);
358     canvasBridges_[nodeId] = bridge;
359 }
360 
PushOffscreenCanvasBridge(int32_t bridgeId,const RefPtr<BaseCanvasBridge> & bridge)361 void JsAcePage::PushOffscreenCanvasBridge(int32_t bridgeId, const RefPtr<BaseCanvasBridge>& bridge)
362 {
363     offscreenCanvasBridges_[bridgeId] = bridge;
364 }
365 
PushXComponentBridge(NodeId nodeId,const RefPtr<BaseXComponentBridge> & bridge)366 void JsAcePage::PushXComponentBridge(NodeId nodeId, const RefPtr<BaseXComponentBridge>& bridge)
367 {
368     if (!bridge) {
369         LOGE("PushXComponentBridge failed. XComponent bridge is null.");
370         return;
371     }
372     xcomponentBridges_[nodeId] = bridge;
373 }
374 
AddNodeEvent(int32_t nodeId,const std::string & actionType,const std::string & eventAction)375 void JsAcePage::AddNodeEvent(int32_t nodeId, const std::string& actionType, const std::string& eventAction)
376 {
377     std::unique_lock<std::mutex> lock(eventMutex_);
378     nodeEvent_[nodeId][actionType] = eventAction;
379 }
380 
GetNodeEventAction(int32_t nodeId,const std::string & actionType)381 std::string JsAcePage::GetNodeEventAction(int32_t nodeId, const std::string& actionType)
382 {
383     // in error case just use empty string.
384     std::unique_lock<std::mutex> lock(eventMutex_);
385     return nodeEvent_[nodeId][actionType];
386 }
387 
SetRootNode(const RefPtr<NG::UINode> & node)388 void JsAcePage::SetRootNode(const RefPtr<NG::UINode>& node)
389 {
390     pageRootNode_ = node;
391 }
392 
393 #ifndef NG_BUILD
GetRadioGroups()394 std::shared_ptr<JsPageRadioGroups> JsAcePage::GetRadioGroups()
395 {
396     return radioGroups_;
397 }
398 #endif
399 
OnJsEngineDestroy()400 void JsAcePage::OnJsEngineDestroy()
401 {
402     std::unique_lock<std::mutex> lock(bridgeMutex_);
403     for (auto&& [id, bridge] : animationBridges_) {
404         if (bridge) {
405             bridge->OnJsEngineDestroy();
406         }
407     }
408     for (auto&& [id, bridge] : canvasBridges_) {
409         if (bridge) {
410             bridge->OnJsEngineDestroy();
411         }
412     }
413     for (auto&& [id, bridge] : xcomponentBridges_) {
414         if (bridge) {
415             bridge->OnJsEngineDestroy();
416         }
417     }
418     for (auto&& [id, bridge] : animatorBridges_) {
419         if (bridge) {
420             bridge->OnJsEngineDestroy();
421         }
422     }
423     for (auto&& [id, info] : animatorInfos_) {
424         if (info) {
425             info->OnJsEngineDestroy();
426         }
427     }
428 }
429 
430 } // namespace OHOS::Ace::Framework
431