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 "core/pipeline/base/element.h"
17
18 #include "base/log/dump_log.h"
19 #include "base/log/log.h"
20 #include "base/memory/ace_type.h"
21 #include "core/common/frontend.h"
22 #include "core/components/focus_animation/focus_animation_element.h"
23 #include "core/components/page/page_element.h"
24 #include "core/components/shadow/shadow_element.h"
25 #include "core/pipeline/base/component.h"
26 #include "core/pipeline/base/composed_element.h"
27 #include "core/pipeline/pipeline_context.h"
28
29 namespace OHOS::Ace {
30
~Element()31 Element::~Element()
32 {
33 for (const auto& child : children_) {
34 DetachChild(child);
35 }
36 }
37
AddChild(const RefPtr<Element> & child,int32_t slot)38 void Element::AddChild(const RefPtr<Element>& child, int32_t slot)
39 {
40 if (!child) {
41 return;
42 }
43
44 auto it = std::find(children_.begin(), children_.end(), child);
45 if (it != children_.end()) {
46 LOGW("Child element is already existed");
47 return;
48 }
49
50 it = children_.begin();
51 std::advance(it, slot);
52 children_.insert(it, child);
53
54 child->SetSlot(slot);
55 Apply(child);
56 }
57
RemoveChild(const RefPtr<Element> & child)58 void Element::RemoveChild(const RefPtr<Element>& child)
59 {
60 if (child) {
61 DetachChild(child);
62 children_.remove(child);
63 }
64 }
65
GetChildBySlot(int32_t slot)66 RefPtr<Element> Element::GetChildBySlot(int32_t slot)
67 {
68 for (auto iter = children_.begin(); iter != children_.end(); iter++) {
69 if (slot == (*iter)->GetSlot()) {
70 return (*iter);
71 }
72 }
73 return nullptr;
74 }
75
ChangeChildSlot(const RefPtr<Element> & child,int32_t slot)76 void Element::ChangeChildSlot(const RefPtr<Element>& child, int32_t slot)
77 {
78 child->SetSlot(slot);
79
80 if (slot < 0) {
81 return;
82 }
83
84 auto it = children_.end();
85 if (static_cast<size_t>(slot) < children_.size()) {
86 it = children_.begin();
87 std::advance(it, slot);
88 if (*it == child) {
89 // Already at the right place
90 return;
91 }
92
93 auto itChild = std::find(it, children_.end(), child);
94 if (itChild != children_.end()) {
95 children_.erase(itChild);
96 } else {
97 LOGW("Should NOT be here");
98 children_.remove(child);
99 ++it;
100 }
101 } else {
102 children_.remove(child);
103 }
104 children_.insert(it, child);
105 }
106
ChangeChildRenderSlot(const RefPtr<Element> & child,int32_t renderSlot,bool effectDescendant)107 void Element::ChangeChildRenderSlot(const RefPtr<Element>& child, int32_t renderSlot, bool effectDescendant)
108 {
109 child->SetRenderSlot(renderSlot);
110
111 if (renderSlot < 0) {
112 return;
113 }
114
115 if (child->GetType() == RENDER_ELEMENT) {
116 auto renderNode = child->GetRenderNode();
117 renderNode->MovePosition(renderSlot);
118 } else if (child->GetType() == COMPOSED_ELEMENT && effectDescendant) {
119 int32_t newRenderSlot = renderSlot;
120 for (const auto& grandChild : child->children_) {
121 child->ChangeChildRenderSlot(grandChild, newRenderSlot, effectDescendant);
122 newRenderSlot += grandChild->CountRenderNode();
123 }
124 }
125 }
126
DeactivateChild(RefPtr<Element> child)127 void Element::DeactivateChild(RefPtr<Element> child)
128 {
129 if (child && !child->parent_.Invalid()) {
130 child->parent_ = nullptr;
131 RefPtr<PipelineContext> context = context_.Upgrade();
132 if (context) {
133 context->AddDeactivateElement(child->GetRetakeId(), child);
134 }
135 auto focusNode = AceType::DynamicCast<FocusNode>(child);
136 if (focusNode) {
137 focusNode->RemoveSelf();
138 }
139 child->Deactivate();
140 child->MarkActive(false);
141 children_.remove(child);
142 }
143 }
144
DetachChild(const RefPtr<Element> & child)145 void Element::DetachChild(const RefPtr<Element>& child)
146 {
147 auto focusNode = AceType::DynamicCast<FocusNode>(child);
148 if (focusNode) {
149 focusNode->RemoveSelf();
150 }
151 child->Detached();
152 }
153
Rebuild()154 void Element::Rebuild()
155 {
156 if (!needRebuild_) {
157 return;
158 }
159
160 needRebuild_ = false;
161
162 // When rebuild comes, newComponent_ should not be null, and will go to these 3 steps:
163 // 1. Update self using new component
164 // 2. PerformBuild will build and update child recursively
165 // 3. Finish update and release the new component
166 Update();
167 PerformBuild();
168 SetNewComponent(nullptr);
169 }
170
DumpTree(int32_t depth)171 void Element::DumpTree(int32_t depth)
172 {
173 if (DumpLog::GetInstance().GetDumpFile()) {
174 Dump();
175 DumpLog::GetInstance().AddDesc(std::string("retakeID: ").append(std::to_string(GetRetakeId())));
176 DumpLog::GetInstance().AddDesc(std::string("Active: ").append(IsActive() ? "Y" : "N"));
177 DumpLog::GetInstance().Print(depth, AceType::TypeName(this), children_.size());
178 }
179
180 for (const auto& item : children_) {
181 item->DumpTree(depth + 1);
182 }
183 }
184
DumpTree(int32_t depth,std::vector<std::string> & info)185 void Element::DumpTree(int32_t depth, std::vector<std::string>& info)
186 {
187 Dump();
188 DumpLog::GetInstance().AddDesc(std::string("retakeID: ").append(std::to_string(GetRetakeId())));
189 DumpLog::GetInstance().AddDesc(std::string("Active: ").append(IsActive() ? "Y" : "N"));
190 DumpLog::GetInstance().PrintToString(depth, AceType::TypeName(this), children_.size(), info);
191
192 for (const auto& item : children_) {
193 item->DumpTree(depth + 1, info);
194 }
195 }
196
Dump()197 void Element::Dump() {}
198
CanUpdate(const RefPtr<Component> & newComponent)199 bool Element::CanUpdate(const RefPtr<Component>& newComponent)
200 {
201 // The raw ptr is persistent during app process.
202 return componentTypeId_ == AceType::TypeId(newComponent);
203 }
204
DoUpdateChildWithNewComponent(const RefPtr<Element> & child,const RefPtr<Component> & newComponent,int32_t slot,int32_t renderSlot)205 inline RefPtr<Element> Element::DoUpdateChildWithNewComponent(
206 const RefPtr<Element>& child, const RefPtr<Component>& newComponent, int32_t slot, int32_t renderSlot)
207 {
208 ChangeChildSlot(child, slot);
209 // Only change render slot for itself, the descendant node will update by 'Rebuild'
210 ChangeChildRenderSlot(child, renderSlot, false);
211 child->SetNewComponent(newComponent);
212 child->Rebuild();
213 return child;
214 }
215
UpdateChildWithSlot(const RefPtr<Element> & child,const RefPtr<Component> & newComponent,int32_t slot,int32_t renderSlot)216 RefPtr<Element> Element::UpdateChildWithSlot(
217 const RefPtr<Element>& child, const RefPtr<Component>& newComponent, int32_t slot, int32_t renderSlot)
218 {
219 LOGD("%{public}p->%{public}s::UpdateChildWithSlot(%{public}s, %{public}s, %{public}d, %{public}d)",
220 this, AceType::TypeName(this), AceType::TypeName(child), AceType::TypeName(newComponent), slot, renderSlot);
221
222 // Considering 4 cases:
223 // 1. child == null && newComponent == null --> do nothing
224 // 2. child == null && newComponent != null --> create new child configured with newComponent
225 if (!child) {
226 return !newComponent ? nullptr : InflateComponent(newComponent, slot, renderSlot);
227 }
228
229 // 3. child != null && newComponent == null --> remove old child
230 if (!newComponent) {
231 DeactivateChild(child);
232 return nullptr;
233 }
234
235 // 4. child != null && newComponent != null --> update old child with new configuration if possible(determined by
236 // [Element::CanUpdate]), or remove the old child and create new one configured with newComponent.
237 auto context = context_.Upgrade();
238 if (!child->CanUpdate(newComponent)) {
239 // Can not update
240
241 auto needRebuildFocusElement = AceType::DynamicCast<Element>(GetFocusScope());
242 if (context && needRebuildFocusElement) {
243 context->AddNeedRebuildFocusElement(needRebuildFocusElement);
244 }
245 DeactivateChild(child);
246 return InflateComponent(newComponent, slot, renderSlot);
247 }
248
249 if (!context || !context->GetIsDeclarative()) {
250 // Non-declarative code path
251 return DoUpdateChildWithNewComponent(child, newComponent, slot, renderSlot);
252 }
253
254 // Declarative path
255 if (newComponent->IsStatic()) {
256 // Declarative && Component marked as static
257 ChangeChildSlot(child, slot);
258 // Not need to rebuild child, but should change render slot for all descendant
259 ChangeChildRenderSlot(child, renderSlot, true);
260 return child;
261 }
262
263 // Non-static component
264 if (newComponent->HasElementFunction()) {
265 newComponent->CallElementFunction(child);
266 }
267 return DoUpdateChildWithNewComponent(child, newComponent, slot, renderSlot);
268 }
269
Mount(const RefPtr<Element> & parent,int32_t slot,int32_t renderSlot)270 void Element::Mount(const RefPtr<Element>& parent, int32_t slot, int32_t renderSlot)
271 {
272 MarkActive(true);
273 Activate();
274 SetParent(parent);
275 SetDepth(parent != nullptr ? parent->GetDepth() + 1 : 1);
276 SetPipelineContext(parent != nullptr ? parent->context_ : context_);
277 SetRenderSlot(renderSlot);
278 Prepare(parent);
279 if (parent) {
280 parent->AddChild(AceType::Claim(this), slot);
281 AddToFocus();
282 }
283 Rebuild();
284 OnMount();
285 }
286
AddToFocus()287 void Element::AddToFocus()
288 {
289 auto parent = parent_.Upgrade();
290 if (!parent) {
291 return;
292 }
293 auto focusNode = AceType::DynamicCast<FocusNode>(this);
294 if (focusNode) {
295 auto scope = parent->GetFocusScope();
296 if (scope) {
297 auto brothers = parent->GetChildren();
298 auto iter = std::find(brothers.begin(), brothers.end(), AceType::Claim(this));
299 if (iter == brothers.end()) {
300 return;
301 }
302 ++iter;
303 while (iter != brothers.end()) {
304 auto nextFocusNode = AceType::DynamicCast<FocusNode>(*iter);
305 if (nextFocusNode) {
306 break;
307 }
308 ++iter;
309 }
310 if (iter != brothers.end()) {
311 scope->AddChild(AceType::Claim(focusNode), AceType::DynamicCast<FocusNode>(*iter));
312 } else {
313 scope->AddChild(AceType::Claim(focusNode));
314 }
315 focusNode->SetParentFocusable(scope->FocusNode::IsFocusable());
316 }
317 }
318
319 auto focusAnimation = AceType::DynamicCast<FocusAnimationElement>(this);
320 if (focusAnimation) {
321 auto context = context_.Upgrade();
322 if (context) {
323 context->PushFocusAnimation(AceType::Claim(this));
324 }
325 }
326
327 auto shadow = AceType::DynamicCast<ShadowElement>(this);
328 if (shadow) {
329 auto context = context_.Upgrade();
330 if (context) {
331 context->PushShadow(AceType::Claim(this));
332 }
333 }
334 }
335
MarkDirty()336 void Element::MarkDirty()
337 {
338 RefPtr<PipelineContext> context = context_.Upgrade();
339 if (context) {
340 context->AddDirtyElement(AceType::Claim(this));
341 MarkNeedRebuild();
342 }
343 }
344
SetUpdateComponent(const RefPtr<Component> & newComponent)345 void Element::SetUpdateComponent(const RefPtr<Component>& newComponent)
346 {
347 SetNewComponent(newComponent);
348 RefPtr<PipelineContext> context = context_.Upgrade();
349 if (context) {
350 context->AddDirtyElement(AceType::Claim(this));
351 }
352 }
353
GetChildren() const354 const std::list<RefPtr<Element>>& Element::GetChildren() const
355 {
356 return children_;
357 }
358
GetFirstChild() const359 RefPtr<Element> Element::GetFirstChild() const
360 {
361 if (children_.empty()) {
362 return nullptr;
363 }
364 return children_.front();
365 }
366
GetLastChild() const367 RefPtr<Element> Element::GetLastChild() const
368 {
369 if (children_.empty()) {
370 return nullptr;
371 }
372 return children_.back();
373 }
374
SetPipelineContext(const WeakPtr<PipelineContext> & context)375 void Element::SetPipelineContext(const WeakPtr<PipelineContext>& context)
376 {
377 context_ = context;
378 OnContextAttached();
379 }
380
InflateComponent(const RefPtr<Component> & newComponent,int32_t slot,int32_t renderSlot)381 RefPtr<Element> Element::InflateComponent(const RefPtr<Component>& newComponent, int32_t slot, int32_t renderSlot)
382 {
383 // confirm whether there is a reuseable element.
384 auto retakeElement = RetakeDeactivateElement(newComponent);
385 if (retakeElement) {
386 retakeElement->SetNewComponent(newComponent);
387 retakeElement->Mount(AceType::Claim(this), slot, renderSlot);
388 if (auto node = retakeElement->GetRenderNode()) {
389 node->SyncRSNode(node->GetRSNode());
390 }
391 return retakeElement;
392 }
393
394 RefPtr<Element> newChild = newComponent->CreateElement();
395 if (newChild) {
396 newChild->SetNewComponent(newComponent);
397 newChild->Mount(AceType::Claim(this), slot, renderSlot);
398 }
399 return newChild;
400 }
401
GetFocusScope()402 RefPtr<FocusGroup> Element::GetFocusScope()
403 {
404 auto rawPtrFocusGroup = AceType::DynamicCast<FocusGroup>(this);
405 if (rawPtrFocusGroup) {
406 return AceType::Claim(rawPtrFocusGroup);
407 }
408
409 auto rawPtrFocusNode = AceType::DynamicCast<FocusNode>(this);
410 if (rawPtrFocusNode) {
411 return nullptr;
412 }
413
414 auto parent = parent_.Upgrade();
415 if (parent) {
416 return parent->GetFocusScope();
417 }
418
419 return nullptr;
420 }
421
GetPageElement()422 RefPtr<PageElement> Element::GetPageElement()
423 {
424 auto pageElement = AceType::DynamicCast<PageElement>(this);
425 if (pageElement != nullptr) {
426 return AceType::Claim(pageElement);
427 }
428
429 auto parent = parent_.Upgrade();
430
431 if (!parent) {
432 return nullptr;
433 }
434
435 return parent->GetPageElement();
436 }
437
RetakeDeactivateElement(const RefPtr<Component> & newComponent)438 RefPtr<Element> Element::RetakeDeactivateElement(const RefPtr<Component>& newComponent)
439 {
440 RefPtr<PipelineContext> context = context_.Upgrade();
441 if (context != nullptr) {
442 return context->GetDeactivateElement(newComponent->GetRetakeId());
443 }
444 return nullptr;
445 }
446
RebuildFocusTree()447 void Element::RebuildFocusTree()
448 {
449 auto focusScope = AceType::DynamicCast<FocusGroup>(this);
450 if (!focusScope) {
451 return;
452 }
453
454 std::list<RefPtr<FocusNode>> rebuildFocusNodes;
455 for (auto& item : children_) {
456 auto tmp = item->RebuildFocusChild();
457 if (!tmp.empty()) {
458 rebuildFocusNodes.merge(std::move(tmp));
459 }
460 }
461 focusScope->RebuildChild(std::move(rebuildFocusNodes));
462 }
463
RebuildFocusChild()464 std::list<RefPtr<FocusNode>> Element::RebuildFocusChild()
465 {
466 std::list<RefPtr<FocusNode>> list;
467 auto focusNode = AceType::DynamicCast<FocusNode>(this);
468 if (focusNode) {
469 RebuildFocusTree();
470 list.emplace_back(AceType::Claim(focusNode));
471 return list;
472 }
473 for (auto& item : children_) {
474 auto focusTmp = item->RebuildFocusChild();
475 if (!focusTmp.empty()) {
476 list.merge(std::move(focusTmp));
477 }
478 }
479 return list;
480 }
481
MarkActive(bool active)482 void Element::MarkActive(bool active)
483 {
484 if (active_ == active) {
485 return;
486 }
487 active_ = active;
488 if (active_) {
489 OnActive();
490 } else {
491 OnInactive();
492 }
493 for (auto& item : children_) {
494 item->MarkActive(active);
495 }
496 }
497
UnregisterForElementProxy()498 void Element::UnregisterForElementProxy()
499 {
500 for (const auto& child : GetChildren()) {
501 child->UnregisterForElementProxy();
502 }
503 }
504 } // namespace OHOS::Ace
505