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