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