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