• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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