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