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