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 "core/pipeline/base/render_element.h"
17 #include <string>
18
19 #include "base/log/log.h"
20 #include "base/utils/string_utils.h"
21 #include "base/utils/utils.h"
22 #include "core/accessibility/accessibility_manager.h"
23 #include "core/components/focus_animation/render_focus_animation.h"
24 #include "core/components/shadow/render_shadow.h"
25 #include "core/components_v2/inspector/inspector_composed_element.h"
26 #include "core/event/ace_event_helper.h"
27 #include "core/pipeline/base/composed_element.h"
28 #include "core/pipeline/base/render_component.h"
29
30 namespace OHOS::Ace {
31
RenderElement()32 RenderElement::RenderElement()
33 {
34 type_ = RENDER_ELEMENT;
35 }
36
~RenderElement()37 RenderElement::~RenderElement() {}
38
Prepare(const WeakPtr<Element> & parent)39 void RenderElement::Prepare(const WeakPtr<Element>& parent)
40 {
41 if (!renderNode_) {
42 renderNode_ = CreateRenderNode();
43 }
44 if (renderNode_) {
45 renderNode_->SyncRSNodeBoundary(component_->IsHeadComponent(), component_->IsTailComponent(), component_);
46 SetAccessibilityNode(parent);
47 renderNode_->Attach(context_);
48 }
49 // register on focus move callback
50 auto focusItem = AceType::DynamicCast<FocusNode>(this);
51 if (focusItem) {
52 focusItem->SetFocusMoveCallback([weak = AceType::WeakClaim(this)] {
53 auto element = weak.Upgrade();
54 if (element && element->renderNode_) {
55 element->renderNode_->MoveWhenOutOfViewPort(true);
56 }
57 });
58 }
59 nodeMounted_ = true;
60
61 int32_t restoreId = component_->GetRestoreId();
62 if (restoreId >= 0) {
63 auto context = context_.Upgrade();
64 if (context) {
65 // store distribute node
66 context->StoreNode(restoreId, AceType::WeakClaim(this));
67 // restore distribute node info
68 if (renderNode_) {
69 renderNode_->SetRestoreInfo(context->GetRestoreInfo(restoreId));
70 }
71 }
72 }
73 }
74
SetAccessibilityNode(const WeakPtr<Element> & parent)75 void RenderElement::SetAccessibilityNode(const WeakPtr<Element>& parent)
76 {
77 auto context = context_.Upgrade();
78 if (!context) {
79 LOGE("SetAccessibilityNode context is null");
80 return;
81 }
82 bool ignoreAccessibility = false;
83 if (component_) {
84 ignoreAccessibility = component_->IsIgnoreInspector();
85 }
86 auto parentNode = parent.Upgrade();
87 while (parentNode) {
88 if (!parentNode->IsAutoAccessibility()) {
89 break;
90 }
91 if (context->GetIsDeclarative()) {
92 if (ignoreAccessibility || parentNode->IsIgnoreInspector()) {
93 break;
94 }
95 auto composedElement = AceType::DynamicCast<V2::InspectorComposedElement>(parentNode);
96 if (composedElement) {
97 composeId_ = std::to_string(composedElement->GetInspectorId());
98 SetAccessibilityNodeById(composeId_);
99 renderNode_->SetInspectorNode(composedElement);
100 break;
101 } else {
102 parentNode = parentNode->GetElementParent().Upgrade();
103 }
104 continue;
105 }
106 auto composedElement = AceType::DynamicCast<ComposedElement>(parentNode);
107 if (composedElement) {
108 composeId_ = composedElement->GetId();
109 SetAccessibilityNodeById(composeId_);
110 break;
111 } else {
112 parentNode = parentNode->GetElementParent().Upgrade();
113 }
114 }
115 }
116
SetAccessibilityNodeById(const ComposeId & id)117 void RenderElement::SetAccessibilityNodeById(const ComposeId& id)
118 {
119 auto context = context_.Upgrade();
120 if (!context) {
121 LOGE("SetAccessibilityNodeById context is null");
122 return;
123 }
124 if (!renderNode_) {
125 LOGE("RenderElement don't have a render node");
126 return;
127 }
128 auto accessibilityManager = context->GetAccessibilityManager();
129 if (!accessibilityManager) {
130 LOGE("SetAccessibilityNode accessibilityManager is null");
131 return;
132 }
133 auto nodeId = StringUtils::StringToInt(id);
134 auto accessibilityNode = accessibilityManager->GetAccessibilityNodeById(nodeId);
135 if (accessibilityNode) {
136 renderNode_->SetAccessibilityNode(accessibilityNode);
137 }
138 }
139
UpdateAccessibilityNode()140 void RenderElement::UpdateAccessibilityNode()
141 {
142 auto context = context_.Upgrade();
143 if (!context) {
144 LOGE("UpdateAccessibilityNode context is null");
145 return;
146 }
147 if (context->GetIsDeclarative()) {
148 return;
149 }
150 // fetch new composedId from component.
151 ComposeId updateId;
152 auto component = component_;
153 while (component) {
154 auto composedNode = AceType::DynamicCast<ComposedComponent>(component);
155 if (composedNode) {
156 updateId = composedNode->GetId();
157 break;
158 }
159 component = component->GetParent().Upgrade();
160 }
161
162 // Update new composedId to renderNode.
163 if (!updateId.empty() && updateId != composeId_) {
164 SetAccessibilityNodeById(updateId);
165 composeId_ = updateId;
166 }
167 }
168
Apply(const RefPtr<Element> & child)169 void RenderElement::Apply(const RefPtr<Element>& child)
170 {
171 if (!child) {
172 LOGE("Element child is null");
173 return;
174 }
175
176 if (child->GetType() == RENDER_ELEMENT) {
177 // Directly attach the RenderNode if child is RenderElement.
178 ApplyRenderChild(AceType::DynamicCast<RenderElement>(child));
179 } else if (child->GetType() == COMPOSED_ELEMENT) {
180 // If child is ComposedElement, just set apply function.
181 RefPtr<ComposedElement> composeChild = AceType::DynamicCast<ComposedElement>(child);
182 if (composeChild) {
183 composeChild->ApplyComposed([weak = AceType::WeakClaim(this)](const RefPtr<RenderElement>& renderChild) {
184 auto renderElement = weak.Upgrade();
185 if (renderElement) {
186 renderElement->ApplyRenderChild(renderChild);
187 }
188 });
189 }
190 }
191 }
192
ApplyRenderChild(const RefPtr<RenderElement> & renderChild)193 void RenderElement::ApplyRenderChild(const RefPtr<RenderElement>& renderChild)
194 {
195 if (!renderChild) {
196 LOGW("Invalid render child");
197 return;
198 }
199
200 if (!renderNode_) {
201 LOGE("RenderElement don't have a render node");
202 return;
203 }
204
205 renderNode_->AddChild(renderChild->GetRenderNode(), renderChild->GetRenderSlot());
206 }
207
Update()208 void RenderElement::Update()
209 {
210 if (renderNode_ != nullptr) {
211 UpdateAccessibilityNode();
212 renderNode_->ProcessExternalRSNode(component_);
213 renderNode_->UpdateAll(component_);
214 if (component_ && nodeMounted_) {
215 SetElementId(component_->GetElementId());
216 if (!component_->GetAppearEventMarker().IsEmpty()) {
217 auto appearCallback = AceAsyncEvent<void()>::Create(component_->GetAppearEventMarker(), context_);
218 appearCallback();
219 }
220 if (!component_->GetDisappearEventMarker().IsEmpty()) {
221 disappearCallback_ = AceAsyncEvent<void()>::Create(component_->GetDisappearEventMarker(), context_);
222 } else {
223 disappearCallback_ = nullptr;
224 }
225 nodeMounted_ = false;
226 }
227 }
228 }
229
CreateRenderNode()230 RefPtr<RenderNode> RenderElement::CreateRenderNode()
231 {
232 RefPtr<RenderComponent> renderComponent = AceType::DynamicCast<RenderComponent>(component_);
233 if (renderComponent) {
234 auto renderNode = GetCachedRenderNode();
235 if (renderNode) {
236 return renderNode;
237 } else {
238 return renderComponent->CreateRenderNode();
239 }
240 }
241 return nullptr;
242 }
243
Detached()244 void RenderElement::Detached()
245 {
246 Deactivate();
247 if (renderNode_) {
248 renderNode_ = nullptr;
249 }
250 if (disappearCallback_) {
251 disappearCallback_();
252 }
253 }
254
Deactivate()255 void RenderElement::Deactivate()
256 {
257 UmountRender();
258 }
259
UmountRender()260 void RenderElement::UmountRender()
261 {
262 if (renderNode_) {
263 auto focusAnimation = AceType::DynamicCast<RenderFocusAnimation>(renderNode_);
264 auto context = context_.Upgrade();
265 if (focusAnimation) {
266 if (context) {
267 focusAnimation->IsRoot() ? context->PopRootFocusAnimation() : context->PopFocusAnimation();
268 }
269 }
270
271 auto shadow = AceType::DynamicCast<RenderShadow>(renderNode_);
272 if (shadow) {
273 if (context) {
274 context->PopShadow();
275 }
276 }
277 if (renderNode_->NeedWindowBlur()) {
278 renderNode_->MarkNeedWindowBlur(false);
279 }
280 renderNode_->Unmount();
281 }
282 }
283
UpdateChild(const RefPtr<Element> & child,const RefPtr<Component> & newComponent)284 RefPtr<Element> RenderElement::UpdateChild(const RefPtr<Element>& child, const RefPtr<Component>& newComponent)
285 {
286 return UpdateChildWithSlot(child, newComponent, DEFAULT_ELEMENT_SLOT, DEFAULT_RENDER_SLOT);
287 }
288
289 } // namespace OHOS::Ace
290