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