• 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 "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("elmtId: ").append(std::to_string(GetElementId())));
176         DumpLog::GetInstance().AddDesc(std::string("retakeID: ").append(std::to_string(GetRetakeId())));
177         DumpLog::GetInstance().AddDesc(std::string("Active: ").append(IsActive() ? "Y" : "N"));
178         DumpLog::GetInstance().Print(depth, AceType::TypeName(this), children_.size());
179     }
180 
181     for (const auto& item : children_) {
182         item->DumpTree(depth + 1);
183     }
184 }
185 
Dump()186 void Element::Dump() {}
187 
CanUpdate(const RefPtr<Component> & newComponent)188 bool Element::CanUpdate(const RefPtr<Component>& newComponent)
189 {
190     // The raw ptr is persistent during app process.
191     return componentTypeId_ == AceType::TypeId(newComponent);
192 }
193 
DoUpdateChildWithNewComponent(const RefPtr<Element> & child,const RefPtr<Component> & newComponent,int32_t slot,int32_t renderSlot)194 inline RefPtr<Element> Element::DoUpdateChildWithNewComponent(
195     const RefPtr<Element>& child, const RefPtr<Component>& newComponent, int32_t slot, int32_t renderSlot)
196 {
197     ChangeChildSlot(child, slot);
198     // Only change render slot for itself, the descendant node will update by 'Rebuild'
199     ChangeChildRenderSlot(child, renderSlot, false);
200     child->SetNewComponent(newComponent);
201     child->Rebuild();
202     return child;
203 }
204 
UpdateChildWithSlot(const RefPtr<Element> & child,const RefPtr<Component> & newComponent,int32_t slot,int32_t renderSlot)205 RefPtr<Element> Element::UpdateChildWithSlot(
206     const RefPtr<Element>& child, const RefPtr<Component>& newComponent, int32_t slot, int32_t renderSlot)
207 {
208     LOGD("%{public}s(elmtId: %{public}d)::UpdateChildWithSlot(child: %{public}s(elmtId: %{public}d), "
209     "component: %{public}s(elmtId: %{public}d), slot: %{public}d, renderSlot: %{public}d)",
210         AceType::TypeName(this), GetElementId(), (child ? AceType::TypeName(child) : "no child Element (yet)"),
211         (child ? child->GetElementId() : -1), newComponent ? AceType::TypeName(newComponent) : "no Component",
212         newComponent ? newComponent->GetElementId() : -1, slot, renderSlot);
213     // Considering 4 cases:
214     // 1. child == null && newComponent == null  -->  do nothing
215     if (!child && !newComponent) {
216         LOGW("no child and no newComponent, likely an internal error!");
217         return nullptr;
218     }
219 
220     // 2. child == null && newComponent != null  -->  create new child configured with newComponent
221     if (!child) {
222         auto newChild = InflateComponent(newComponent, slot, renderSlot);
223         ElementRegister::GetInstance()->AddElement(newChild);
224         return newChild;
225     }
226 
227     // 3. child != null && newComponent == null  -->  remove old child
228     if (!newComponent) {
229         ElementRegister::GetInstance()->RemoveItemSilently(child->GetElementId());
230         DeactivateChild(child);
231         return nullptr;
232     }
233 
234     // 4. child != null && newComponent != null  -->  update old child with new configuration if possible(determined by
235     //    [Element::CanUpdate]), or remove the old child and create new one configured with newComponent.
236     auto context = context_.Upgrade();
237     if (!child->CanUpdate(newComponent)) {
238         // Can not update
239         auto needRebuildFocusElement = AceType::DynamicCast<Element>(GetFocusScope());
240         if (context && needRebuildFocusElement) {
241             context->AddNeedRebuildFocusElement(needRebuildFocusElement);
242         }
243         ElementRegister::GetInstance()->RemoveItemSilently(child->GetElementId());
244         DeactivateChild(child);
245         auto newChild = InflateComponent(newComponent, slot, renderSlot);
246         ElementRegister::GetInstance()->AddElement(newChild);
247         return newChild;
248     }
249 
250     if (!context || !context->GetIsDeclarative()) {
251         // Non-declarative code path
252         return DoUpdateChildWithNewComponent(child, newComponent, slot, renderSlot);
253     }
254 
255     // Declarative path
256     if (newComponent->IsStatic()) {
257         // Declarative && Component marked as static
258         ChangeChildSlot(child, slot);
259         // Not need to rebuild child, but should change render slot for all descendant
260         ChangeChildRenderSlot(child, renderSlot, true);
261         return child;
262     }
263 
264     // Non-static component
265     if (newComponent->HasElementFunction()) {
266         newComponent->CallElementFunction(child);
267     }
268 
269     ElementRegister::GetInstance()->RemoveItemSilently(child->GetElementId());
270     auto newChild = DoUpdateChildWithNewComponent(child, newComponent, slot, renderSlot);
271     if (newChild != nullptr) {
272         newChild->SetElementId(newComponent->GetElementId());
273         ElementRegister::GetInstance()->AddElement(newChild);
274     }
275     return newChild;
276 }
277 
Mount(const RefPtr<Element> & parent,int32_t slot,int32_t renderSlot)278 void Element::Mount(const RefPtr<Element>& parent, int32_t slot, int32_t renderSlot)
279 {
280     MarkActive(true);
281     Activate();
282     SetParent(parent);
283     SetDepth(parent != nullptr ? parent->GetDepth() + 1 : 1);
284     SetPipelineContext(parent != nullptr ? parent->context_ : context_);
285     SetRenderSlot(renderSlot);
286     Prepare(parent);
287     if (parent) {
288         parent->AddChild(AceType::Claim(this), slot);
289         AddToFocus();
290     }
291     Rebuild();
292     OnMount();
293 }
294 
AddToFocus()295 void Element::AddToFocus()
296 {
297     auto parent = parent_.Upgrade();
298     if (!parent) {
299         return;
300     }
301     auto focusNode = AceType::DynamicCast<FocusNode>(this);
302     if (focusNode) {
303         auto scope = parent->GetFocusScope();
304         if (scope) {
305             auto brothers = parent->GetChildren();
306             auto iter = std::find(brothers.begin(), brothers.end(), AceType::Claim(this));
307             if (iter == brothers.end()) {
308                 return;
309             }
310             ++iter;
311             while (iter != brothers.end()) {
312                 auto nextFocusNode = AceType::DynamicCast<FocusNode>(*iter);
313                 if (nextFocusNode) {
314                     break;
315                 }
316                 ++iter;
317             }
318             if (iter != brothers.end()) {
319                 scope->AddChild(AceType::Claim(focusNode), AceType::DynamicCast<FocusNode>(*iter));
320             } else {
321                 scope->AddChild(AceType::Claim(focusNode));
322             }
323             focusNode->SetParentFocusable(scope->FocusNode::IsFocusable());
324         }
325     }
326 
327     auto focusAnimation = AceType::DynamicCast<FocusAnimationElement>(this);
328     if (focusAnimation) {
329         auto context = context_.Upgrade();
330         if (context) {
331             context->PushFocusAnimation(AceType::Claim(this));
332         }
333     }
334 
335     auto shadow = AceType::DynamicCast<ShadowElement>(this);
336     if (shadow) {
337         auto context = context_.Upgrade();
338         if (context) {
339             context->PushShadow(AceType::Claim(this));
340         }
341     }
342 }
343 
MarkDirty()344 void Element::MarkDirty()
345 {
346     RefPtr<PipelineContext> context = context_.Upgrade();
347     if (context) {
348         context->AddDirtyElement(AceType::Claim(this));
349         MarkNeedRebuild();
350     }
351 }
352 
SetUpdateComponent(const RefPtr<Component> & newComponent)353 void Element::SetUpdateComponent(const RefPtr<Component>& newComponent)
354 {
355     SetNewComponent(newComponent);
356     RefPtr<PipelineContext> context = context_.Upgrade();
357     if (context) {
358         context->AddDirtyElement(AceType::Claim(this));
359     }
360 }
361 
GetChildren() const362 const std::list<RefPtr<Element>>& Element::GetChildren() const
363 {
364     return children_;
365 }
366 
GetFirstChild() const367 RefPtr<Element> Element::GetFirstChild() const
368 {
369     if (children_.empty()) {
370         return nullptr;
371     }
372     return children_.front();
373 }
374 
GetLastChild() const375 RefPtr<Element> Element::GetLastChild() const
376 {
377     if (children_.empty()) {
378         return nullptr;
379     }
380     return children_.back();
381 }
382 
SetPipelineContext(const WeakPtr<PipelineContext> & context)383 void Element::SetPipelineContext(const WeakPtr<PipelineContext>& context)
384 {
385     context_ = context;
386     OnContextAttached();
387 }
388 
InflateComponent(const RefPtr<Component> & newComponent,int32_t slot,int32_t renderSlot)389 RefPtr<Element> Element::InflateComponent(const RefPtr<Component>& newComponent, int32_t slot, int32_t renderSlot)
390 {
391     // confirm whether there is a reuseable element.
392     auto retakeElement = RetakeDeactivateElement(newComponent);
393     if (retakeElement) {
394         retakeElement->SetNewComponent(newComponent);
395         retakeElement->Mount(AceType::Claim(this), slot, renderSlot);
396         if (auto node = retakeElement->GetRenderNode()) {
397             node->SyncRSNode(node->GetRSNode());
398         }
399         return retakeElement;
400     }
401 
402     RefPtr<Element> newChild = newComponent->CreateElement();
403     if (newChild) {
404         newChild->SetNewComponent(newComponent);
405         newChild->Mount(AceType::Claim(this), slot, renderSlot);
406     }
407     return newChild;
408 }
409 
GetFocusScope()410 RefPtr<FocusGroup> Element::GetFocusScope()
411 {
412     auto rawPtrFocusGroup = AceType::DynamicCast<FocusGroup>(this);
413     if (rawPtrFocusGroup) {
414         return AceType::Claim(rawPtrFocusGroup);
415     }
416 
417     auto rawPtrFocusNode = AceType::DynamicCast<FocusNode>(this);
418     if (rawPtrFocusNode) {
419         return nullptr;
420     }
421 
422     auto parent = parent_.Upgrade();
423     if (parent) {
424         return parent->GetFocusScope();
425     }
426 
427     return nullptr;
428 }
429 
GetPageElement()430 RefPtr<PageElement> Element::GetPageElement()
431 {
432     auto pageElement = AceType::DynamicCast<PageElement>(this);
433     if (pageElement != nullptr) {
434         return AceType::Claim(pageElement);
435     }
436 
437     auto parent = parent_.Upgrade();
438 
439     if (!parent) {
440         return nullptr;
441     }
442 
443     return parent->GetPageElement();
444 }
445 
RetakeDeactivateElement(const RefPtr<Component> & newComponent)446 RefPtr<Element> Element::RetakeDeactivateElement(const RefPtr<Component>& newComponent)
447 {
448     RefPtr<PipelineContext> context = context_.Upgrade();
449     if (context != nullptr) {
450         return context->GetDeactivateElement(newComponent->GetRetakeId());
451     }
452     return nullptr;
453 }
454 
RebuildFocusTree()455 void Element::RebuildFocusTree()
456 {
457     auto focusScope = AceType::DynamicCast<FocusGroup>(this);
458     if (!focusScope) {
459         return;
460     }
461 
462     std::list<RefPtr<FocusNode>> rebuildFocusNodes;
463     for (auto& item : children_) {
464         auto tmp = item->RebuildFocusChild();
465         if (!tmp.empty()) {
466             rebuildFocusNodes.merge(std::move(tmp));
467         }
468     }
469     focusScope->RebuildChild(std::move(rebuildFocusNodes));
470 }
471 
RebuildFocusChild()472 std::list<RefPtr<FocusNode>> Element::RebuildFocusChild()
473 {
474     std::list<RefPtr<FocusNode>> list;
475     auto focusNode = AceType::DynamicCast<FocusNode>(this);
476     if (focusNode) {
477         RebuildFocusTree();
478         list.emplace_back(AceType::Claim(focusNode));
479         return list;
480     }
481     for (auto& item : children_) {
482         auto focusTmp = item->RebuildFocusChild();
483         if (!focusTmp.empty()) {
484             list.merge(std::move(focusTmp));
485         }
486     }
487     return list;
488 }
489 
MarkActive(bool active)490 void Element::MarkActive(bool active)
491 {
492     if (active_ == active) {
493         return;
494     }
495     active_ = active;
496     if (active_) {
497         OnActive();
498     } else {
499         OnInactive();
500     }
501     for (auto& item : children_) {
502         item->MarkActive(active);
503     }
504 }
505 
SetElementId(int32_t elmtId)506 void Element::SetElementId(int32_t elmtId)
507 {
508     LOGD("Setting elmtId %{public}d for %{public}s", elmtId, AceType::TypeName(this));
509     elmtId_ = elmtId;
510 }
511 
512 /*
513  *   Memebers for partial update
514  */
LocalizedUpdateWithComponent(const RefPtr<Component> & newComponent,const RefPtr<Component> & outmostWrappingComponent)515 void Element::LocalizedUpdateWithComponent(
516     const RefPtr<Component>& newComponent, const RefPtr<Component>& outmostWrappingComponent)
517 {
518     LOGD("%{public}s elmtId %{public}d  updating with %{public}s elmtId %{public}d, canUpdate(): %{public}s",
519         AceType::TypeName(this), GetElementId(), AceType::TypeName(newComponent), newComponent->GetElementId(),
520         CanUpdate(newComponent) ? "yes" : "no");
521 
522     ACE_DCHECK(CanUpdate(newComponent));
523     ACE_DCHECK(
524         (GetElementId() == ElementRegister::UndefinedElementId) || (GetElementId() == newComponent->GetElementId()));
525 
526     // update wrapping component first
527     // do not traverse further to parent if outmostWrappingComponent == newComponent, i.e. scope of local update
528     // has been reached
529     const auto newParentComponent = newComponent->GetParent().Upgrade();
530     const auto parentElement = GetElementParent().Upgrade();
531     if ((newParentComponent != nullptr) && (newParentComponent != outmostWrappingComponent) &&
532         (parentElement != nullptr)) {
533         parentElement->LocalizedUpdateWithComponent(newParentComponent, outmostWrappingComponent);
534     }
535 
536     // update Element with Component
537     SetNewComponent(newComponent); // virtual
538     LocalizedUpdate();             // virtual
539     SetNewComponent(nullptr);
540 }
541 
LocalizedUpdate()542 void Element::LocalizedUpdate()
543 {
544     LOGD("%{public}s elmtId %{public}d calling Update function", AceType::TypeName(this), GetElementId());
545     Update();
546 }
547 
UnregisterForPartialUpdates()548 void Element::UnregisterForPartialUpdates()
549 {
550     if (elmtId_ != ElementRegister::UndefinedElementId) {
551         ElementRegister::GetInstance()->RemoveItem(elmtId_);
552     }
553     UnregisterChildrenForPartialUpdates();
554 }
555 
UnregisterChildrenForPartialUpdates()556 void Element::UnregisterChildrenForPartialUpdates()
557 {
558     for (const auto& child : GetChildren()) {
559         child->UnregisterForPartialUpdates();
560     }
561 }
562 } // namespace OHOS::Ace
563