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/components_v2/common/element_proxy.h"
17
18 #include <map>
19 #include <unordered_map>
20
21 #include "base/log/ace_trace.h"
22 #include "base/log/dump_log.h"
23 #include "base/log/log.h"
24 #include "base/memory/ace_type.h"
25 #include "base/utils/macros.h"
26 #include "core/common/container.h"
27 #include "core/components/box/box_element.h"
28 #include "core/components/grid_layout/grid_layout_item_component.h"
29 #include "core/components/grid_layout/grid_layout_item_element.h"
30 #include "core/components/ifelse/if_else_component.h"
31 #include "core/components_v2/foreach/lazy_foreach_component.h"
32 #include "core/components_v2/inspector/inspector_composed_component.h"
33 #include "core/components_v2/list/list_item_component.h"
34 #include "core/components_v2/tabs/tabs_helper.h"
35 #include "core/pipeline/base/component.h"
36 #include "core/pipeline/base/composed_component.h"
37 #include "frameworks/core/components_part_upd/foreach/foreach_component.h"
38 #include "frameworks/core/components_part_upd/foreach/foreach_element.h"
39 #include "frameworks/core/pipeline/base/element_register.h"
40
41 namespace OHOS::Ace::V2 {
42 namespace {
43
44 const std::string PREFIX_STEP = " ";
45 class RenderElementProxy : public ElementProxy {
46 public:
RenderElementProxy(const WeakPtr<ElementProxyHost> & host,bool forceRender=false)47 explicit RenderElementProxy(const WeakPtr<ElementProxyHost>& host, bool forceRender = false)
48 : ElementProxy(host), forceRender_(forceRender)
49 {}
~RenderElementProxy()50 ~RenderElementProxy() override
51 {
52 RemoveSelfFromElementRegistry();
53 ReleaseElement(Container::IsCurrentUsePartialUpdate());
54 }
55
Update(const RefPtr<Component> & component,size_t startIndex)56 void Update(const RefPtr<Component>& component, size_t startIndex) override
57 {
58 if (Container::IsCurrentUsePartialUpdate()) {
59 UpdateForPartialUpdate(component, startIndex);
60 return;
61 }
62 auto composedComponent = AceType::DynamicCast<ComposedComponent>(component);
63 auto inspectorComposedComponent = AceType::DynamicCast<InspectorComposedComponent>(component);
64 SetComposedId(composedComponent ? composedComponent->GetId() : "");
65
66 component_ = component;
67 while (composedComponent && !composedComponent->HasElementFunction() && !inspectorComposedComponent) {
68 component_ = composedComponent->GetChild();
69 composedComponent = AceType::DynamicCast<ComposedComponent>(component_);
70 }
71
72 auto host = host_.Upgrade();
73 if (!host) {
74 return;
75 }
76
77 if (!component_ && forceRender_) {
78 component_ = host->OnMakeEmptyComponent();
79 }
80
81 startIndex_ = startIndex;
82 count_ = component_ ? 1 : 0;
83
84 if (element_) {
85 element_ = host->OnUpdateElement(element_, component_);
86 }
87 }
88
UpdateForPartialUpdate(const RefPtr<Component> & component,size_t startIndex)89 void UpdateForPartialUpdate(const RefPtr<Component>& component, size_t startIndex)
90 {
91 auto composedComponent = AceType::DynamicCast<ComposedComponent>(component);
92 auto inspectorComposedComponent = AceType::DynamicCast<InspectorComposedComponent>(component);
93 SetComposedId(composedComponent ? composedComponent->GetId() : "");
94
95 component_ = component;
96 while (composedComponent && !composedComponent->HasElementFunction() && !inspectorComposedComponent) {
97 component_ = composedComponent->GetChild();
98 composedComponent = AceType::DynamicCast<ComposedComponent>(component_);
99 }
100
101 auto host = host_.Upgrade();
102 if (!host) {
103 return;
104 }
105
106 if (!component_ && forceRender_) {
107 component_ = host->OnMakeEmptyComponent();
108 }
109
110 startIndex_ = startIndex;
111 count_ = component_ ? 1 : 0;
112
113 if (GetElementId() == ElementRegister::UndefinedElementId) {
114 // first render case, add the ElementRegistry
115 ACE_DCHECK(element_ == nullptr);
116
117 SetElementId(component_->GetElementId());
118 AddSelfToElementRegistry();
119 realElmtId_ = ElementRegister::GetInstance()->MakeUniqueId();
120 }
121
122 if (element_) {
123 element_ = CreateElement();
124 }
125 }
126
LocalizedUpdate(const RefPtr<Component> & inwardWrappingComponent,const RefPtr<Component> & newListItemComponent)127 void LocalizedUpdate(
128 const RefPtr<Component>& inwardWrappingComponent, const RefPtr<Component>& newListItemComponent) override
129 {
130 ACE_DCHECK(
131 (component_ != nullptr) && (GetElementId() != ElementRegister::UndefinedElementId) && "Is re-render");
132
133 if (element_) {
134 // the Component (correctly) has elmtId of this ProxyElement
135 // We are updating the 'real' Lst/GridElement, need to adjust the elmtId
136 // in the Component.
137 newListItemComponent->SetElementId(realElmtId_);
138
139 // List/Grid Item do not use normal wrapping
140 auto updateElement = element_;
141 auto updateComponent = newListItemComponent;
142
143 for (;;) {
144 updateElement->SetNewComponent(updateComponent);
145 updateElement->LocalizedUpdate(); // virtual
146 updateElement->SetNewComponent(nullptr);
147
148 updateElement = updateElement->GetFirstChild();
149 auto singleChild = AceType::DynamicCast<SingleChild>(updateComponent);
150 if ((updateElement == nullptr) || (singleChild == nullptr) || (singleChild->GetChild() == nullptr)) {
151 break;
152 }
153 updateComponent = singleChild->GetChild();
154 }
155 }
156 }
157
CreateElement()158 RefPtr<Element> CreateElement()
159 {
160 auto host = host_.Upgrade();
161 if (!host) {
162 return nullptr;
163 }
164
165 auto tabContentItemComponent = TabsHelper::TraverseComponentTo<TabContentItemComponent>(component_);
166 if (tabContentItemComponent) {
167 tabContentItemComponent->SetElementId(realElmtId_);
168 } else {
169 component_->SetElementId(realElmtId_);
170 }
171 auto element = host->OnUpdateElement(element_, component_);
172 if (tabContentItemComponent) {
173 tabContentItemComponent->SetElementId(GetElementId());
174 } else {
175 component_->SetElementId(GetElementId());
176 }
177 return element;
178 }
179
UpdateIndex(size_t startIndex)180 void UpdateIndex(size_t startIndex) override
181 {
182 startIndex_ = startIndex;
183 }
184
GetComponentByIndex(size_t index)185 RefPtr<Component> GetComponentByIndex(size_t index) override
186 {
187 ACE_DCHECK(index == startIndex_);
188 return component_;
189 }
190
GetElementByIndex(size_t index)191 RefPtr<Element> GetElementByIndex(size_t index) override
192 {
193 ACE_DCHECK(index == startIndex_);
194 if (element_) {
195 return element_;
196 }
197 if (!component_) {
198 return nullptr;
199 }
200 auto host = host_.Upgrade();
201 if (!host) {
202 return nullptr;
203 }
204 if (Container::IsCurrentUsePartialUpdate()) {
205 element_ = CreateElement();
206 return element_;
207 }
208 element_ = host->OnUpdateElement(element_, component_);
209 return element_;
210 }
211
RefreshActiveComposeIds()212 void RefreshActiveComposeIds() override
213 {
214 auto host = host_.Upgrade();
215 if (!host) {
216 return;
217 }
218 host->AddActiveComposeId(composedId_);
219 };
220
ReleaseElement(bool partialUpdates)221 void ReleaseElement(bool partialUpdates)
222 {
223 if (!element_) {
224 return;
225 }
226 auto host = host_.Upgrade();
227 if (!host) {
228 return;
229 }
230 SetComposedId("");
231 if (partialUpdates) {
232 element_->UnregisterForPartialUpdates();
233 }
234 element_ = host->OnUpdateElement(element_, nullptr);
235 }
236
ReleaseElementByIndex(size_t index)237 void ReleaseElementByIndex(size_t index) override
238 {
239 ACE_DCHECK(index == startIndex_);
240 ReleaseElement(true);
241 }
242
ReleaseElementById(const ComposeId & id)243 void ReleaseElementById(const ComposeId& id) override {}
244
Dump(const std::string & prefix) const245 void Dump(const std::string& prefix) const override
246 {
247 if (!DumpLog::GetInstance().GetDumpFile()) {
248 return;
249 }
250 ElementProxy::Dump(prefix);
251 if (element_) {
252 DumpLog::GetInstance().AddDesc(prefix + std::string("[RenderElementProxy] element: ") +
253 AceType::TypeName(AceType::RawPtr(element_)) +
254 ", retakeId: " + std::to_string(element_->GetRetakeId()));
255 } else {
256 DumpLog::GetInstance().AddDesc(prefix + std::string("[RenderElementProxy] Null element."));
257 }
258 }
259
260 protected:
261 // the proxy has elmtId, the real Element element_
262 // needs to be always given a different but always same elmtId
263 int32_t realElmtId_ = ElementRegister::UndefinedElementId;
264
SetComposedId(const ComposeId & composedId)265 void SetComposedId(const ComposeId& composedId)
266 {
267 auto host = host_.Upgrade();
268 if (!host) {
269 return;
270 }
271 if (composedId_ != composedId) {
272 // Add old id to host and remove it later
273 host->AddComposeId(composedId_);
274 }
275 host->AddComposeId(composedId);
276 composedId_ = composedId;
277 }
278 bool forceRender_ = false;
279 RefPtr<Component> component_;
280 RefPtr<Element> element_;
281 };
282
283 class TabContentItemElementProxy : public RenderElementProxy {
284 public:
TabContentItemElementProxy(const WeakPtr<ElementProxyHost> & host,bool forceRender=false)285 explicit TabContentItemElementProxy(const WeakPtr<ElementProxyHost>& host, bool forceRender = false)
286 : RenderElementProxy(host, forceRender) {}
287
~TabContentItemElementProxy()288 ~TabContentItemElementProxy() override
289 {
290 auto tabContentItemComponent = TabsHelper::TraverseComponentTo<TabContentItemComponent>(component_);
291 if (tabContentItemComponent) {
292 TabsHelper::RemoveTabBarItemById(tabContentItemComponent->GetBarElementId());
293
294 if (!host_.Upgrade()) {
295 LOGE("Host_ is nullptr");
296 return;
297 }
298 auto element = AceType::DynamicCast<TabContentProxyElement>(host_.Upgrade());
299 if (!element) {
300 LOGE("DTOR host is NOT TabContentProxyElement is nullptr");
301 return;
302 }
303 TabsHelper::DecTabContentRenderCount(AceType::DynamicCast<TabContentProxyElement>(host_.Upgrade()));
304 }
305 }
306
Update(const RefPtr<Component> & component,size_t startIndex)307 void Update(const RefPtr<Component>& component, size_t startIndex) override
308 {
309 if (GetElementId() == ElementRegister::UndefinedElementId) {
310 // first render case, add the ElementRegistry
311 ACE_DCHECK(element_ == nullptr);
312
313 auto tabContentItemComponent = TabsHelper::TraverseComponentTo<TabContentItemComponent>(component);
314 if (tabContentItemComponent) {
315 SetElementId(tabContentItemComponent->GetElementId());
316 }
317 AddSelfToElementRegistry();
318 realElmtId_ = ElementRegister::GetInstance()->MakeUniqueId();
319 }
320
321 // Add Tab Bar Item
322 auto tabContentProxyElement = AceType::DynamicCast<TabContentProxyElement>(host_.Upgrade());
323 if (tabContentProxyElement && !element_) {
324 auto tabContentItemComponent = TabsHelper::TraverseComponentTo<TabContentItemComponent>(component);
325 TabsHelper::AddTabBarElement(tabContentProxyElement, tabContentItemComponent);
326 TabsHelper::IncTabContentRenderCount(tabContentProxyElement);
327 }
328
329 RenderElementProxy::Update(component, startIndex);
330 }
331
LocalizedUpdate(const RefPtr<Component> & inwardWrappingComponent,const RefPtr<Component> & newTabContentItemComponent)332 void LocalizedUpdate(
333 const RefPtr<Component>& inwardWrappingComponent, const RefPtr<Component>& newTabContentItemComponent) override
334 {
335 ACE_DCHECK(
336 (component_ != nullptr) && (GetElementId() != ElementRegister::UndefinedElementId) && "Is re-render");
337
338 // Update TabBar element
339 auto tabContentProxyElement = AceType::DynamicCast<TabContentProxyElement>(host_.Upgrade());
340 if (tabContentProxyElement) {
341 auto tabContentItemComponent = TabsHelper::TraverseComponentTo<TabContentItemComponent>(
342 inwardWrappingComponent);
343 auto oldComponent = TabsHelper::TraverseComponentTo<TabContentItemComponent>(component_);
344 tabContentItemComponent->SetBarElementId(oldComponent->GetBarElementId());
345 TabsHelper::UpdateTabBarElement(tabContentProxyElement, element_, inwardWrappingComponent);
346 }
347
348 RenderElementProxy::LocalizedUpdate(inwardWrappingComponent, newTabContentItemComponent);
349 }
350
UpdateIndex(size_t startIndex)351 void UpdateIndex(size_t startIndex) override
352 {
353 startIndex_ = startIndex;
354 TabsHelper::SetTabBarElementIndex(element_,
355 TabsHelper::TraverseComponentTo<TabContentItemComponent>(component_), startIndex);
356 RenderElementProxy::UpdateIndex(startIndex);
357 }
358 };
359
360 class ItemElementProxy : public RenderElementProxy {
361 public:
ItemElementProxy(const WeakPtr<ElementProxyHost> & host)362 explicit ItemElementProxy(const WeakPtr<ElementProxyHost>& host)
363 : RenderElementProxy(host), deepRenderignState_(DeepRenderingState::shallowTree)
364 {}
365 ~ItemElementProxy() override = default;
366
GetElementByIndex(size_t index)367 RefPtr<Element> GetElementByIndex(size_t index) override
368 {
369 if (element_) {
370 return element_;
371 }
372 if (!component_) {
373 return nullptr;
374 }
375
376 if (deepRenderignState_ == DeepRenderingState::shallowTree) {
377 // repalce ListItemcomponent with new one from deep render
378 GetDeepRenderComponent();
379 }
380 element_ = CreateElement();
381 return element_;
382 }
383
384 virtual void GetDeepRenderComponent() = 0;
385
386 protected:
387 enum class DeepRenderingState { shallowTree, deepTree };
388
389 DeepRenderingState deepRenderignState_ = DeepRenderingState::shallowTree;
390 };
391
392 class ListItemElementProxy : public ItemElementProxy {
393 public:
ListItemElementProxy(const WeakPtr<ElementProxyHost> & host)394 explicit ListItemElementProxy(const WeakPtr<ElementProxyHost>& host) : ItemElementProxy(host) {}
~ListItemElementProxy()395 ~ListItemElementProxy() override
396 {
397 if (element_) {
398 element_->UnregisterForPartialUpdates();
399 }
400 }
401
Update(const RefPtr<Component> & component,size_t startIndex)402 void Update(const RefPtr<Component>& component, size_t startIndex) override
403 {
404 auto composedComponent = AceType::DynamicCast<ComposedComponent>(component);
405 auto inspectorComposedComponent = AceType::DynamicCast<InspectorComposedComponent>(component);
406 SetComposedId(composedComponent ? composedComponent->GetId() : "");
407
408 component_ = component;
409 while (composedComponent && !composedComponent->HasElementFunction() && !inspectorComposedComponent) {
410 component_ = composedComponent->GetChild();
411 composedComponent = AceType::DynamicCast<ComposedComponent>(component_);
412 }
413
414 auto host = host_.Upgrade();
415 if (!host) {
416 LOGE("no host");
417 return;
418 }
419 startIndex_ = startIndex;
420 count_ = component_ ? 1 : 0;
421
422 if (GetElementId() == ElementRegister::UndefinedElementId) {
423 // first render case, add the ElementRegistry
424 ACE_DCHECK(element_ == nullptr);
425
426 SetElementId(component_->GetElementId());
427 AddSelfToElementRegistry();
428 realElmtId_ = ElementRegister::GetInstance()->MakeUniqueId();
429
430 auto listItemComponent = AceType::DynamicCast<V2::ListItemComponent>(component_);
431 if (listItemComponent->GetIsLazyCreating()) {
432 deepRenderignState_ = DeepRenderingState::shallowTree;
433 // continue later when GetElementByIndex is called
434 return;
435 } else {
436 deepRenderignState_ = DeepRenderingState::deepTree;
437 element_ = CreateElement();
438 return;
439 }
440 }
441
442 if (element_) {
443 element_ = CreateElement();
444 }
445 }
446
GetDeepRenderComponent()447 void GetDeepRenderComponent() override
448 {
449 auto listItemComponent = AceType::DynamicCast<V2::ListItemComponent>(component_);
450 auto newComponent = listItemComponent->ExecDeepRender();
451
452 ACE_DCHECK(newComponent != nullptr);
453 ACE_DCHECK(newComponent->GetElementId() == component_->GetElementId());
454 deepRenderignState_ = DeepRenderingState::deepTree;
455 component_ = newComponent;
456
457 auto composedComponent = AceType::DynamicCast<ComposedComponent>(newComponent);
458 while (composedComponent && !composedComponent->HasElementFunction()) {
459 LOGW("ComposedComponent case, using child as component_");
460 component_ = composedComponent->GetChild();
461 composedComponent = AceType::DynamicCast<ComposedComponent>(component_);
462 }
463
464 ACE_DCHECK(GetElementId() == component_->GetElementId());
465 }
466
ReleaseElementByIndex(size_t index)467 void ReleaseElementByIndex(size_t index) override
468 {
469 deepRenderignState_ = DeepRenderingState::shallowTree;
470
471 RenderElementProxy::ReleaseElementByIndex(index);
472
473 // release deeprender Component tree,
474 // repalce component_ with a dummy
475 auto listItem = AceType::DynamicCast<V2::ListItemComponent>(component_);
476 auto placeholder = AceType::MakeRefPtr<V2::ListItemComponent>();
477 listItem->MoveDeepRenderFunc(placeholder);
478 placeholder->SetElementId(listItem->GetElementId());
479 component_ = std::move(placeholder);
480 }
481 };
482
483 class GridItemElementProxy : public ItemElementProxy {
484 public:
GridItemElementProxy(const WeakPtr<ElementProxyHost> & host)485 explicit GridItemElementProxy(const WeakPtr<ElementProxyHost>& host) : ItemElementProxy(host) {}
~GridItemElementProxy()486 ~GridItemElementProxy() override
487 {
488 if (element_) {
489 element_->UnregisterForPartialUpdates();
490 }
491 }
492
Update(const RefPtr<Component> & component,size_t startIndex)493 void Update(const RefPtr<Component>& component, size_t startIndex) override
494 {
495 auto composedComponent = AceType::DynamicCast<ComposedComponent>(component);
496 auto inspectorComposedComponent = AceType::DynamicCast<InspectorComposedComponent>(component);
497 SetComposedId(composedComponent ? composedComponent->GetId() : "");
498
499 component_ = component;
500 while (composedComponent && !composedComponent->HasElementFunction() && !inspectorComposedComponent) {
501 component_ = composedComponent->GetChild();
502 composedComponent = AceType::DynamicCast<ComposedComponent>(component_);
503 }
504
505 auto host = host_.Upgrade();
506 if (!host) {
507 LOGE("no host");
508 return;
509 }
510 startIndex_ = startIndex;
511 count_ = component_ ? 1 : 0;
512
513 if (GetElementId() == ElementRegister::UndefinedElementId) {
514 // first render case, add the ElementRegistry
515 ACE_DCHECK(element_ == nullptr);
516
517 SetElementId(component_->GetElementId());
518 AddSelfToElementRegistry();
519 realElmtId_ = ElementRegister::GetInstance()->MakeUniqueId();
520 auto gridItemComponent = AceType::DynamicCast<GridLayoutItemComponent>(component_);
521 if (gridItemComponent->GetIsLazyCreating()) {
522 deepRenderignState_ = DeepRenderingState::shallowTree;
523 // continue later when GetElementByIndex is called
524 return;
525 } else {
526 deepRenderignState_ = DeepRenderingState::deepTree;
527 element_ = CreateElement();
528 return;
529 }
530 }
531
532 if (element_) {
533 element_ = CreateElement();
534 }
535 }
536
GetDeepRenderComponent()537 void GetDeepRenderComponent() override
538 {
539 auto gridItemComponent = AceType::DynamicCast<GridLayoutItemComponent>(component_);
540 auto newComponent = gridItemComponent->ExecDeepRender();
541
542 ACE_DCHECK(newComponent != nullptr);
543 ACE_DCHECK(newComponent->GetElementId() == component_->GetElementId());
544
545 deepRenderignState_ = DeepRenderingState::deepTree;
546 component_ = newComponent;
547
548 auto composedComponent = AceType::DynamicCast<ComposedComponent>(newComponent);
549 while (composedComponent && !composedComponent->HasElementFunction()) {
550 LOGW("ComposedComponent case, using child as component_");
551 component_ = composedComponent->GetChild();
552 composedComponent = AceType::DynamicCast<ComposedComponent>(component_);
553 }
554
555 ACE_DCHECK(GetElementId() == component_->GetElementId());
556 }
557
ReleaseElementByIndex(size_t index)558 void ReleaseElementByIndex(size_t index) override
559 {
560 deepRenderignState_ = DeepRenderingState::shallowTree;
561
562 RenderElementProxy::ReleaseElementByIndex(index);
563
564 // release deeprender Component tree,
565 // replace component_ with a dummy
566 auto gridItem = AceType::DynamicCast<GridLayoutItemComponent>(component_);
567 auto placeholder = AceType::MakeRefPtr<GridLayoutItemComponent>();
568 gridItem->MoveDeepRenderFunc(placeholder);
569 placeholder->SetElementId(gridItem->GetElementId());
570 component_ = std::move(placeholder);
571 }
572 };
573
574 class LazyForEachElementProxy : public virtual ElementProxy, public virtual DataChangeListener {
575 DECLARE_ACE_TYPE(LazyForEachElementProxy, ElementProxy, DataChangeListener)
576 public:
LazyForEachElementProxy(const WeakPtr<ElementProxyHost> & host)577 explicit LazyForEachElementProxy(const WeakPtr<ElementProxyHost>& host) : ElementProxy(host) {}
~LazyForEachElementProxy()578 ~LazyForEachElementProxy() override
579 {
580 for (auto&& item : children_) {
581 auto viewId = item.second->GetId();
582 if (lazyForEachComponent_) {
583 lazyForEachComponent_->ReleaseChildGroupByComposedId(viewId);
584 }
585 }
586 children_.clear();
587 }
588
Update(const RefPtr<Component> & component,size_t startIndex)589 void Update(const RefPtr<Component>& component, size_t startIndex) override
590 {
591 auto lazyForEachComponent = AceType::DynamicCast<LazyForEachComponent>(component);
592 ACE_DCHECK(lazyForEachComponent);
593
594 if (lazyForEachComponent_) {
595 if (count_ != lazyForEachComponent->TotalCount()) {
596 LOGW("Count of items MUST be the same while updating");
597 count_ = lazyForEachComponent->TotalCount();
598 }
599 lazyForEachComponent_->UnregisterDataChangeListener(this);
600 } else {
601 count_ = lazyForEachComponent->TotalCount();
602 }
603
604 startIndex_ = startIndex;
605 composedId_ = lazyForEachComponent->GetId();
606 lazyForEachComponent->RegisterDataChangeListener(AceType::Claim(this));
607 lazyForEachComponent_ = lazyForEachComponent;
608
609 for (const auto& item : children_) {
610 auto childComponent = lazyForEachComponent_->GetChildByIndex(item.first);
611 item.second->Update(childComponent, startIndex_ + item.first);
612 }
613 }
614
LocalizedUpdate(const RefPtr<Component> & newComponent,const RefPtr<Component> & outmostWrappingComponent)615 void LocalizedUpdate(
616 const RefPtr<Component>& newComponent, const RefPtr<Component>& outmostWrappingComponent) override
617 {
618 Update(newComponent, startIndex_);
619 }
620
UpdateIndex(size_t startIndex)621 void UpdateIndex(size_t startIndex) override
622 {
623 if (startIndex_ == startIndex) {
624 return;
625 }
626 startIndex_ = startIndex;
627
628 for (const auto& item : children_) {
629 item.second->UpdateIndex(startIndex_ + item.first);
630 }
631 }
632
GetComponentByIndex(size_t index)633 RefPtr<Component> GetComponentByIndex(size_t index) override
634 {
635 auto it = children_.find(index - startIndex_);
636 if (it != children_.end()) {
637 return it->second->GetComponentByIndex(index);
638 }
639
640 auto component = lazyForEachComponent_->GetChildByIndex(index - startIndex_);
641 ACE_DCHECK(AceType::InstanceOf<ComposedComponent>(component));
642 auto child = AceType::MakeRefPtr<RenderElementProxy>(host_.Upgrade(), true);
643 child->Update(component, index);
644 return child->GetComponentByIndex(index);
645 }
646
GetElementByIndex(size_t index)647 RefPtr<Element> GetElementByIndex(size_t index) override
648 {
649 auto it = children_.find(index - startIndex_);
650 if (it != children_.end()) {
651 return it->second->GetElementByIndex(index);
652 }
653
654 auto component = lazyForEachComponent_->GetChildByIndex(index - startIndex_);
655 auto child = ElementProxy::Create(host_, component);
656 children_.emplace(index - startIndex_, child);
657 child->Update(component, index);
658 return child->GetElementByIndex(index);
659 }
660
ReleaseElementByIndex(size_t index)661 void ReleaseElementByIndex(size_t index) override
662 {
663 auto it = children_.find(index - startIndex_);
664 if (it != children_.end()) {
665 auto viewId = it->second->GetId();
666 if (lazyForEachComponent_) {
667 lazyForEachComponent_->ReleaseChildGroupByComposedId(viewId);
668 }
669 children_.erase(it);
670 }
671 }
672
ReleaseElementById(const ComposeId & composeId)673 void ReleaseElementById(const ComposeId& composeId) override
674 {
675 if (lazyForEachComponent_) {
676 lazyForEachComponent_->ReleaseChildGroupByComposedId(composeId);
677 }
678 }
679
RefreshActiveComposeIds()680 void RefreshActiveComposeIds() override
681 {
682 auto host = host_.Upgrade();
683 if (!host) {
684 return;
685 }
686 for (auto const& child : children_) {
687 child.second->RefreshActiveComposeIds();
688 }
689 }
690
OnDataReloaded()691 void OnDataReloaded() override
692 {
693 LOGI("OnDataReloaded()");
694 ACE_SCOPED_TRACE("OnDataReloaded");
695
696 if (!lazyForEachComponent_) {
697 LOGE("lazyForEachComponent_ is nullptr");
698 return;
699 }
700 LazyForEachCache cache(lazyForEachComponent_);
701 size_t oldCount = count_;
702 count_ = cache.TotalCount();
703 auto host = host_.Upgrade();
704 if (count_ == 0) {
705 children_.clear();
706 if (host) {
707 if (oldCount != count_) {
708 host->UpdateIndex();
709 }
710 host->OnDataSourceUpdated(startIndex_);
711 }
712 return;
713 }
714
715 std::list<std::pair<size_t, RefPtr<ElementProxy>>> items(children_.begin(), children_.end());
716 children_.clear();
717 std::list<RefPtr<ElementProxy>> deletedItems;
718 auto checkRange = items.size() / 3;
719 for (const auto& [index, child] : items) {
720 size_t newIdx = cache[child->GetId()];
721 if (newIdx != INVALID_INDEX) {
722 children_.emplace(newIdx, child);
723 child->Update(cache[newIdx], startIndex_ + newIdx);
724 continue;
725 }
726
727 size_t idx = std::min(index, count_ - 1);
728 size_t range = std::max(idx, count_ - 1 - idx);
729 range = std::min(range, checkRange);
730 bool recycle = false;
731 for (size_t i = 0; i <= range; ++i) {
732 if (idx >= i && !cache.IsInCache(idx - i)) {
733 auto component = cache[idx - i];
734 if (component->GetId() == child->GetId()) {
735 children_.emplace(idx - i, child);
736 child->Update(cache[idx - i], startIndex_ + idx - i);
737 recycle = true;
738 break;
739 }
740 }
741
742 if (idx + i < count_ && !cache.IsInCache(idx + i)) {
743 auto component = cache[idx + i];
744 if (component->GetId() == child->GetId()) {
745 children_.emplace(idx + i, child);
746 child->Update(cache[idx + i], startIndex_ + idx + i);
747 recycle = true;
748 break;
749 }
750 }
751 }
752 if (!recycle) {
753 deletedItems.emplace_back(child);
754 }
755 }
756
757 if (lazyForEachComponent_) {
758 for (auto&& item : deletedItems) {
759 lazyForEachComponent_->ReleaseChildGroupByComposedId(item->GetId());
760 }
761 }
762
763 if (host) {
764 if (oldCount != count_) {
765 host->UpdateIndex();
766 }
767 host->OnDataSourceUpdated(startIndex_);
768 }
769 }
770
OnDataAdded(size_t index)771 void OnDataAdded(size_t index) override
772 {
773 LOGI("OnDataAdded(%{public}zu)", index);
774
775 if (index > count_) {
776 LOGW("Invalid index");
777 return;
778 }
779
780 if (index < count_) {
781 std::list<std::pair<size_t, RefPtr<ElementProxy>>> items;
782 auto it = children_.begin();
783 while (it != children_.end()) {
784 if (it->first < index) {
785 ++it;
786 continue;
787 }
788 items.emplace_back(it->first + 1, it->second);
789 it = children_.erase(it);
790 }
791
792 for (const auto& item : items) {
793 children_.emplace(item.first, item.second);
794 item.second->UpdateIndex(startIndex_ + item.first);
795 }
796 }
797
798 count_++;
799
800 auto host = host_.Upgrade();
801 if (host) {
802 host->UpdateIndex();
803 host->OnDataSourceUpdated(startIndex_ + index);
804 }
805 }
806
OnDataBulkAdded(size_t index,size_t count)807 void OnDataBulkAdded(size_t index, size_t count) override {};
808
OnDataDeleted(size_t index)809 void OnDataDeleted(size_t index) override
810 {
811 LOGI("OnDataDeleted(%{public}zu)", index);
812
813 if (index >= count_) {
814 LOGW("Invalid index");
815 return;
816 }
817
818 std::list<std::pair<size_t, RefPtr<ElementProxy>>> items;
819 RefPtr<ElementProxy> deleteItem;
820 auto it = children_.begin();
821 while (it != children_.end()) {
822 if (it->first < index) {
823 ++it;
824 continue;
825 }
826 if (it->first == index) {
827 deleteItem = it->second;
828 }
829
830 if (it->first > index) {
831 items.emplace_back(it->first - 1, it->second);
832 }
833 it = children_.erase(it);
834 }
835
836 if (lazyForEachComponent_ && deleteItem) {
837 lazyForEachComponent_->ReleaseChildGroupByComposedId(deleteItem->GetId());
838 }
839
840 for (const auto& item : items) {
841 children_.emplace(item.first, item.second);
842 item.second->UpdateIndex(startIndex_ + item.first);
843 }
844
845 count_--;
846
847 auto host = host_.Upgrade();
848 if (host) {
849 host->UpdateIndex();
850 host->OnDataSourceUpdated(startIndex_ + index);
851 }
852 }
853
OnDataBulkDeleted(size_t index,size_t count)854 void OnDataBulkDeleted(size_t index, size_t count) override {};
855
OnDatasetChange(const std::list<V2::Operation> & DataOperations)856 void OnDatasetChange(const std::list<V2::Operation>& DataOperations) override {};
857
OnDataChanged(size_t index)858 void OnDataChanged(size_t index) override
859 {
860 LOGI("OnDataChanged(%{public}zu)", index);
861
862 auto it = children_.find(index);
863 if (it == children_.end()) {
864 return;
865 }
866
867 auto component = lazyForEachComponent_->GetChildByIndex(index);
868 it->second->Update(component, startIndex_ + index);
869
870 auto host = host_.Upgrade();
871 if (host) {
872 host->OnDataSourceUpdated(startIndex_ + index);
873 }
874 }
875
OnDataMoved(size_t from,size_t to)876 void OnDataMoved(size_t from, size_t to) override
877 {
878 LOGI("OnDataMoved(from:%{public}zu, to:%{public}zu)", from, to);
879
880 if (from == to || from >= count_ || to >= count_) {
881 LOGW("Invalid index");
882 return;
883 }
884
885 RefPtr<ElementProxy> childFrom;
886 auto itFrom = children_.find(from);
887 if (itFrom != children_.end()) {
888 childFrom = itFrom->second;
889 children_.erase(itFrom);
890 }
891
892 std::list<std::pair<size_t, RefPtr<ElementProxy>>> items;
893
894 if (from < to) {
895 for (size_t idx = from + 1; idx <= to; ++idx) {
896 auto it = children_.find(idx);
897 if (it == children_.end()) {
898 continue;
899 }
900 items.emplace_back(idx - 1, it->second);
901 children_.erase(it);
902 }
903 } else {
904 for (size_t idx = from - 1; idx >= to; --idx) {
905 auto it = children_.find(idx);
906 if (it != children_.end()) {
907 items.emplace_back(idx + 1, it->second);
908 children_.erase(it);
909 }
910 if (idx == 0) {
911 break;
912 }
913 }
914 }
915
916 for (const auto& item : items) {
917 children_.emplace(item.first, item.second);
918 item.second->UpdateIndex(startIndex_ + item.first);
919 }
920
921 if (childFrom) {
922 children_.emplace(to, childFrom);
923 childFrom->UpdateIndex(startIndex_ + to);
924 }
925
926 auto host = host_.Upgrade();
927 if (host) {
928 host->OnDataSourceUpdated(startIndex_ + std::min(from, to));
929 }
930 }
931
Dump(const std::string & prefix) const932 void Dump(const std::string& prefix) const override
933 {
934 if (!DumpLog::GetInstance().GetDumpFile()) {
935 return;
936 }
937 ElementProxy::Dump(prefix);
938 DumpLog::GetInstance().AddDesc(
939 prefix + std::string("[LazyForEachElementProxy] childSize: ").append(std::to_string(children_.size())));
940 }
941
942 private:
943 class LazyForEachCache final {
944 public:
LazyForEachCache(const RefPtr<LazyForEachComponent> & component)945 explicit LazyForEachCache(const RefPtr<LazyForEachComponent>& component) : lazyForEachComponent_(component)
946 {
947 if (component) {
948 count_ = component->TotalCount();
949 } else {
950 count_ = 0;
951 }
952 }
953 ~LazyForEachCache() = default;
954
operator [](size_t index)955 RefPtr<ComposedComponent> operator[](size_t index)
956 {
957 if (index >= count_) {
958 return nullptr;
959 }
960
961 auto it = componentCache_.find(index);
962 if (it != componentCache_.end()) {
963 return it->second;
964 }
965
966 auto component = AceType::DynamicCast<ComposedComponent>(lazyForEachComponent_->GetChildByIndex(index));
967 ACE_DCHECK(component);
968 idCache_.emplace(component->GetId(), index);
969 componentCache_.emplace(index, component);
970 return component;
971 }
972
973 size_t operator[](const ComposeId& id) const
__anon58dd4b170202(const ComposeId& id) 974 {
975 auto it = idCache_.find(id);
976 return it == idCache_.end() ? INVALID_INDEX : it->second;
977 }
978
979 bool IsInCache(size_t index) const
__anon58dd4b170302(const ComposeId& id) 980 {
981 return componentCache_.find(index) != componentCache_.end();
982 }
983
984 size_t TotalCount() const
__anon58dd4b170402(const ComposeId& id) 985 {
986 return count_;
987 }
988
989 private:
990 RefPtr<LazyForEachComponent> lazyForEachComponent_;
991 size_t count_ = 0;
992 std::unordered_map<ComposeId, size_t> idCache_;
993 std::unordered_map<size_t, RefPtr<ComposedComponent>> componentCache_;
994 };
995
996 RefPtr<LazyForEachComponent> lazyForEachComponent_;
997 std::map<size_t, RefPtr<ElementProxy>> children_;
998 };
999
1000 class LinearElementProxy : public ElementProxy {
1001 DECLARE_ACE_TYPE(LinearElementProxy, ElementProxy);
1002
1003 public:
LinearElementProxy(const WeakPtr<ElementProxyHost> & host)1004 explicit LinearElementProxy(const WeakPtr<ElementProxyHost>& host) : ElementProxy(host) {}
1005 ~LinearElementProxy() override = default;
1006
UpdateIndex(size_t startIndex)1007 void UpdateIndex(size_t startIndex) override
1008 {
1009 count_ = 0;
1010 startIndex_ = startIndex;
1011 for (const auto& child : children_) {
1012 child->UpdateIndex(startIndex_ + count_);
1013 count_ += child->RenderCount();
1014 }
1015 }
1016
GetComponentByIndex(size_t index)1017 RefPtr<Component> GetComponentByIndex(size_t index) override
1018 {
1019 for (const auto& child : children_) {
1020 if (child->IndexInRange(index)) {
1021 return child->GetComponentByIndex(index);
1022 }
1023 }
1024 return nullptr;
1025 }
1026
GetElementByIndex(size_t index)1027 RefPtr<Element> GetElementByIndex(size_t index) override
1028 {
1029 for (const auto& child : children_) {
1030 if (child->IndexInRange(index)) {
1031 return child->GetElementByIndex(index);
1032 }
1033 }
1034 return nullptr;
1035 }
1036
ReleaseElementByIndex(size_t index)1037 void ReleaseElementByIndex(size_t index) override
1038 {
1039 for (const auto& child : children_) {
1040 if (child->IndexInRange(index)) {
1041 child->ReleaseElementByIndex(index);
1042 break;
1043 }
1044 }
1045 }
1046
ReleaseElementById(const ComposeId & composeId)1047 void ReleaseElementById(const ComposeId& composeId) override
1048 {
1049 for (const auto& child : children_) {
1050 if (!child) {
1051 continue;
1052 }
1053 child->ReleaseElementById(composeId);
1054 }
1055 }
1056
RefreshActiveComposeIds()1057 void RefreshActiveComposeIds() override
1058 {
1059 for (const auto& child : children_) {
1060 if (!child) {
1061 continue;
1062 }
1063 child->RefreshActiveComposeIds();
1064 }
1065 }
1066
Dump(const std::string & prefix) const1067 void Dump(const std::string& prefix) const override
1068 {
1069 if (!DumpLog::GetInstance().GetDumpFile()) {
1070 return;
1071 }
1072 ElementProxy::Dump(prefix);
1073 DumpLog::GetInstance().AddDesc(
1074 prefix + std::string("[LinearElementProxy] childSize: ").append(std::to_string(children_.size())));
1075 for (const auto& child : children_) {
1076 child->Dump(prefix + PREFIX_STEP);
1077 }
1078 }
1079
1080 protected:
1081 std::list<RefPtr<ElementProxy>> children_;
1082 };
1083
1084 class ForEachElementProxy : public LinearElementProxy {
1085 DECLARE_ACE_TYPE(ForEachElementProxy, LinearElementProxy);
1086
1087 public:
ForEachElementProxy(const WeakPtr<ElementProxyHost> & host)1088 explicit ForEachElementProxy(const WeakPtr<ElementProxyHost>& host) : LinearElementProxy(host) {}
1089 ~ForEachElementProxy() override = default;
1090
Update(const RefPtr<Component> & component,size_t startIndex)1091 void Update(const RefPtr<Component>& component, size_t startIndex) override
1092 {
1093 if (Container::IsCurrentUsePartialUpdate()) {
1094 UpdateForPartialUpdate(component, startIndex);
1095 return;
1096 }
1097
1098 auto forEachComponent = AceType::DynamicCast<ForEachComponent>(component);
1099 ACE_DCHECK(forEachComponent);
1100
1101 const auto& components = forEachComponent->GetChildren();
1102
1103 count_ = 0;
1104 startIndex_ = startIndex;
1105 composedId_ = forEachComponent->GetId();
1106
1107 // Child of ForEachElement MUST be ComposedComponent or MultiComposedComponent
1108 auto itChildStart = children_.begin();
1109 auto itChildEnd = children_.end();
1110 auto itComponentStart = components.begin();
1111 auto itComponentEnd = components.end();
1112
1113 // 1. Try to update children at start with new components by order
1114 while (itChildStart != itChildEnd && itComponentStart != itComponentEnd) {
1115 const auto& child = *itChildStart;
1116 const auto& childComponent = *itComponentStart;
1117 auto composedComponent = AceType::DynamicCast<BaseComposedComponent>(childComponent);
1118 ACE_DCHECK(composedComponent);
1119 if (child->GetId() != composedComponent->GetId()) {
1120 break;
1121 }
1122
1123 child->Update(childComponent, startIndex_ + count_);
1124 count_ += child->RenderCount();
1125 ++itChildStart;
1126 ++itComponentStart;
1127 }
1128
1129 // 2. Try to find children at end with new components by order
1130 while (itChildStart != itChildEnd && itComponentStart != itComponentEnd) {
1131 const auto& child = *(--itChildEnd);
1132 const auto& childComponent = *(--itComponentEnd);
1133 auto composedComponent = AceType::DynamicCast<BaseComposedComponent>(childComponent);
1134 ACE_DCHECK(composedComponent);
1135 if (child->GetId() != composedComponent->GetId()) {
1136 ++itChildEnd;
1137 ++itComponentEnd;
1138 break;
1139 }
1140 }
1141
1142 // 3. Collect children at middle
1143 std::unordered_map<ComposeId, RefPtr<ElementProxy>> proxies;
1144 while (itChildStart != itChildEnd) {
1145 const auto& child = *itChildStart;
1146 proxies.emplace(child->GetId(), child);
1147 itChildStart = children_.erase(itChildStart);
1148 }
1149
1150 // 4. Try to update children at middle with new components by order
1151 while (itComponentStart != itComponentEnd) {
1152 const auto& childComponent = *(itComponentStart++);
1153 auto composedComponent = AceType::DynamicCast<BaseComposedComponent>(childComponent);
1154 ACE_DCHECK(composedComponent);
1155
1156 RefPtr<ElementProxy> child;
1157 auto it = proxies.find(composedComponent->GetId());
1158 if (it == proxies.end()) {
1159 child = ElementProxy::Create(host_, childComponent);
1160 } else {
1161 child = it->second;
1162 proxies.erase(it);
1163 }
1164
1165 children_.insert(itChildEnd, child);
1166 child->Update(childComponent, startIndex_ + count_);
1167 count_ += child->RenderCount();
1168 }
1169
1170 // 5. Remove these useless children
1171 proxies.clear();
1172
1173 // 6. Try to update children at end with new components by order
1174 while (itChildEnd != children_.end() && itComponentEnd != components.end()) {
1175 const auto& child = *(itChildEnd++);
1176 const auto& childComponent = *(itComponentEnd++);
1177 child->Update(childComponent, startIndex_ + count_);
1178 count_ += child->RenderCount();
1179 }
1180 }
1181
1182 // In baseline Update is used on first render and also on rerender
1183 // in partial update only used fro first render
1184 // Update simplify to only support the first render case.
UpdateForPartialUpdate(const RefPtr<Component> & component,size_t startIndex)1185 void UpdateForPartialUpdate(const RefPtr<Component>& component, size_t startIndex)
1186 {
1187 if (GetElementId() != ElementRegister::UndefinedElementId) {
1188 // run this function only on first render
1189 return;
1190 }
1191
1192 auto forEachComponent = AceType::DynamicCast<OHOS::Ace::PartUpd::ForEachComponent>(component);
1193 ACE_DCHECK(forEachComponent);
1194
1195 SetElementId(forEachComponent->GetElementId());
1196 AddSelfToElementRegistry();
1197
1198 const auto& components = forEachComponent->GetChildren();
1199
1200 count_ = 0;
1201 startIndex_ = startIndex;
1202 composedId_ = forEachComponent->GetId();
1203
1204 // Child of ForEachElement MUST be ComposedComponent or MultiComposedComponent
1205 auto itChildStart = children_.begin();
1206 auto itChildEnd = children_.end();
1207 auto itComponentStart = components.begin();
1208 auto itComponentEnd = components.end();
1209
1210 // 1. Try to update children at start with new components by order
1211 while (itChildStart != itChildEnd && itComponentStart != itComponentEnd) {
1212 const auto& child = *itChildStart;
1213 const auto& childComponent = *itComponentStart;
1214 auto composedComponent = AceType::DynamicCast<BaseComposedComponent>(childComponent);
1215 ACE_DCHECK(composedComponent);
1216 if (child->GetId() != composedComponent->GetId()) {
1217 break;
1218 }
1219
1220 child->Update(childComponent, startIndex_ + count_);
1221 count_ += child->RenderCount();
1222 ++itChildStart;
1223 ++itComponentStart;
1224 }
1225
1226 // 2. Try to find children at end with new components by order
1227 while (itChildStart != itChildEnd && itComponentStart != itComponentEnd) {
1228 const auto& child = *(--itChildEnd);
1229 const auto& childComponent = *(--itComponentEnd);
1230 auto composedComponent = AceType::DynamicCast<BaseComposedComponent>(childComponent);
1231 ACE_DCHECK(composedComponent);
1232 if (child->GetId() != composedComponent->GetId()) {
1233 ++itChildEnd;
1234 ++itComponentEnd;
1235 break;
1236 }
1237 }
1238
1239 // 3. Collect children at middle
1240 std::unordered_map<ComposeId, RefPtr<ElementProxy>> proxies;
1241 while (itChildStart != itChildEnd) {
1242 const auto& child = *itChildStart;
1243 proxies.emplace(child->GetId(), child);
1244 itChildStart = children_.erase(itChildStart);
1245 }
1246
1247 // 4. Try to update children at middle with new components by order
1248 while (itComponentStart != itComponentEnd) {
1249 const auto& childComponent = *(itComponentStart++);
1250 auto composedComponent = AceType::DynamicCast<BaseComposedComponent>(childComponent);
1251 ACE_DCHECK(composedComponent);
1252
1253 RefPtr<ElementProxy> child;
1254 auto it = proxies.find(composedComponent->GetId());
1255 if (it == proxies.end()) {
1256 child = ElementProxy::Create(host_, childComponent);
1257 } else {
1258 child = it->second;
1259 proxies.erase(it);
1260 }
1261
1262 children_.insert(itChildEnd, child);
1263 child->Update(childComponent, startIndex_ + count_);
1264 count_ += child->RenderCount();
1265 }
1266
1267 // 5. Remove these useless children
1268 proxies.clear();
1269
1270 // 6. Try to update children at end with new components by order
1271 while (itChildEnd != children_.end() && itComponentEnd != components.end()) {
1272 const auto& child = *(itChildEnd++);
1273 const auto& childComponent = *(itComponentEnd++);
1274 child->Update(childComponent, startIndex_ + count_);
1275 count_ += child->RenderCount();
1276 }
1277
1278 SetIdArray(forEachComponent->GetIdArray());
1279 #ifdef ACE_DEBUG
1280 const auto& newIds = forEachComponent->GetIdArray();
1281
1282 std::string idS = "[";
1283 for (const auto& newId : newIds) {
1284 idS += newId + ", ";
1285 }
1286 idS += "]";
1287 #endif
1288 }
1289
SetIdArray(const std::list<std::string> & newIdArray)1290 void SetIdArray(const std::list<std::string>& newIdArray)
1291 {
1292 idArray_ = newIdArray;
1293 }
1294
GetIdArray() const1295 const std::list<std::string>& GetIdArray() const
1296 {
1297 return idArray_;
1298 }
1299
1300 template<typename T>
indexOf(const std::list<T> & list,T value)1301 int indexOf(const std::list<T>& list, T value)
1302 {
1303 int index = 0;
1304 for (auto it = list.begin(); it != list.end(); ++it, ++index)
1305 if ((*it) == value) {
1306 return index;
1307 }
1308 return -1;
1309 }
1310
Append(const RefPtr<ElementProxy> & existingProxyChild)1311 void Append(const RefPtr<ElementProxy>& existingProxyChild)
1312 {
1313 children_.emplace_back(existingProxyChild);
1314 existingProxyChild->UpdateIndex(startIndex_ + count_);
1315 count_ += existingProxyChild->RenderCount();
1316 }
1317
AppendNewComponent(const RefPtr<Component> & newComponent)1318 void AppendNewComponent(const RefPtr<Component>& newComponent)
1319 {
1320 auto proxyChild = ElementProxy::Create(host_, newComponent);
1321 children_.emplace_back(proxyChild);
1322 proxyChild->Update(newComponent, startIndex_ + count_);
1323 proxyChild->UpdateIndex(startIndex_ + count_);
1324 count_ += proxyChild->RenderCount();
1325 }
1326
LocalizedUpdate(const RefPtr<Component> & newComponent,const RefPtr<Component> & outmostWrappingComponent)1327 void LocalizedUpdate(
1328 const RefPtr<Component>& newComponent, const RefPtr<Component>& outmostWrappingComponent) override
1329 {
1330 auto forEachComponent = AceType::DynamicCast<OHOS::Ace::PartUpd::ForEachComponent>(newComponent);
1331 ACE_DCHECK(forEachComponent);
1332
1333 // old / previous render and new render array id's
1334 const auto& newIds = forEachComponent->GetIdArray();
1335 const auto& oldIds = GetIdArray();
1336
1337 ACE_DCHECK((oldIds.size() == children_.size()) &&
1338 "ForEachElementProxy::LocalizedUpdate:Number of IDs generated during previous render and number of "
1339 "ForEach child ElementProxy objects must match");
1340
1341 // will build children_ array from scratch
1342 // make a copy of the list
1343 std::list<RefPtr<ElementProxy>> oldChildren;
1344 std::swap(oldChildren, children_);
1345
1346 // the ForEach Component only includes the newly added children!
1347 const auto& newChildComponents = forEachComponent->GetChildren();
1348
1349 #ifdef ACE_DEBUG
1350 std::string idS = "[";
1351 for (const auto& oldId : oldIds) {
1352 idS += oldId + ", ";
1353 }
1354 idS += "]";
1355
1356 idS = "[";
1357 for (const auto& newId : newIds) {
1358 idS += newId + ", ";
1359 }
1360 idS += "]";
1361 #endif
1362
1363 size_t newChildIndex = 0;
1364 int32_t oldIndex = -1;
1365 count_ = 0;
1366 for (const auto& newId : newIds) {
1367 if ((oldIndex = indexOf(oldIds, newId)) == -1) {
1368 // found a newly added ID
1369 // insert component into 'slot'
1370 auto newCompsIter = newChildComponents.begin();
1371 std::advance(newCompsIter, newChildIndex);
1372 AppendNewComponent(*newCompsIter);
1373 newChildIndex++;
1374 } else {
1375 // the ID was used before, only need to update the child Element's slot
1376 auto oldElementIter = oldChildren.begin();
1377 std::advance(oldElementIter, oldIndex);
1378 Append(*oldElementIter);
1379 }
1380 }
1381
1382 SetIdArray(forEachComponent->GetIdArray());
1383
1384 // host is the parent List, Swiper or Grid element
1385 auto host = host_.Upgrade();
1386 if (host) {
1387 host->UpdateIndex();
1388 host->OnDataSourceUpdated(startIndex_);
1389 }
1390 }
1391
1392 private:
1393 std::list<std::string> idArray_;
1394 };
1395
1396 class MultiComposedElementProxy : public LinearElementProxy {
1397 public:
MultiComposedElementProxy(const WeakPtr<ElementProxyHost> & host)1398 explicit MultiComposedElementProxy(const WeakPtr<ElementProxyHost>& host) : LinearElementProxy(host) {}
1399 ~MultiComposedElementProxy() override = default;
1400
Update(const RefPtr<Component> & component,size_t startIndex)1401 void Update(const RefPtr<Component>& component, size_t startIndex) override
1402 {
1403 auto multiComposedComponent = AceType::DynamicCast<MultiComposedComponent>(component);
1404 ACE_DCHECK(multiComposedComponent);
1405
1406 const auto& components = multiComposedComponent->GetChildren();
1407
1408 count_ = 0;
1409 startIndex_ = startIndex;
1410 composedId_ = multiComposedComponent->GetId();
1411
1412 if (children_.empty()) {
1413 for (const auto& childComponent : components) {
1414 auto child = ElementProxy::Create(host_, childComponent);
1415 children_.emplace_back(child);
1416 child->Update(childComponent, startIndex_ + count_);
1417 count_ += child->RenderCount();
1418 }
1419 } else {
1420 ACE_DCHECK(children_.size() == components.size());
1421 auto it = components.begin();
1422 for (const auto& child : children_) {
1423 child->Update(*(it++), startIndex_ + count_);
1424 count_ += child->RenderCount();
1425 }
1426 }
1427 }
1428
LocalizedUpdate(const RefPtr<Component> & newComponent,const RefPtr<Component> & outmostWrappingComponent)1429 void LocalizedUpdate(
1430 const RefPtr<Component>& newComponent, const RefPtr<Component>& outmostWrappingComponent) override
1431 {
1432 Update(newComponent, startIndex_);
1433 }
1434 };
1435
1436 class IfElseElementProxy : public MultiComposedElementProxy {
1437 public:
IfElseElementProxy(const WeakPtr<ElementProxyHost> & host)1438 explicit IfElseElementProxy(const WeakPtr<ElementProxyHost>& host) : MultiComposedElementProxy(host) {}
1439 ~IfElseElementProxy() override = default;
1440
Update(const RefPtr<Component> & component,size_t startIndex)1441 void Update(const RefPtr<Component>& component, size_t startIndex) override
1442 {
1443 if (Container::IsCurrentUsePartialUpdate()) {
1444 UpdateForPartialUpdate(component, startIndex);
1445 return;
1446 }
1447
1448 auto ifElseComponent = AceType::DynamicCast<IfElseComponent>(component);
1449 ACE_DCHECK(ifElseComponent);
1450
1451 if (branchId_ >= 0 && ifElseComponent->GetBranchId() != branchId_) {
1452 // Clear old children while branch id mismatched
1453 children_.clear();
1454 }
1455
1456 branchId_ = ifElseComponent->GetBranchId();
1457 MultiComposedElementProxy::Update(component, startIndex);
1458 }
1459
UpdateInternal(const RefPtr<IfElseComponent> & ifElseComponent,size_t startIndex)1460 void UpdateInternal(const RefPtr<IfElseComponent>& ifElseComponent, size_t startIndex)
1461 {
1462 branchId_ = ifElseComponent->GetBranchId();
1463 MultiComposedElementProxy::Update(ifElseComponent, startIndex);
1464 }
1465
1466 // this function is wrongly named Update, we do not change its name to remain compatible with baseline
1467 // the function is only called on first render
1468 // on re-render Localupdate is called
UpdateForPartialUpdate(const RefPtr<Component> & component,size_t startIndex)1469 void UpdateForPartialUpdate(const RefPtr<Component>& component, size_t startIndex)
1470 {
1471 ACE_DCHECK(
1472 (GetElementId() == ElementRegister::UndefinedElementId) && "Update must only be called on first render");
1473
1474 auto ifElseComponent = AceType::DynamicCast<IfElseComponent>(component);
1475 ACE_DCHECK(ifElseComponent);
1476
1477 SetElementId(ifElseComponent->GetElementId());
1478 AddSelfToElementRegistry();
1479
1480 UpdateInternal(ifElseComponent, startIndex);
1481 }
1482
LocalizedUpdate(const RefPtr<Component> & newComponent,const RefPtr<Component> & outmostWrappingComponent)1483 void LocalizedUpdate(
1484 const RefPtr<Component>& newComponent, const RefPtr<Component>& outmostWrappingComponent) override
1485 {
1486 ACE_DCHECK((GetElementId() != ElementRegister::UndefinedElementId) &&
1487 "IfElseElementProxy::LocalizedUpdate must only be called on re-render");
1488
1489 auto ifElseComponent = AceType::DynamicCast<IfElseComponent>(newComponent);
1490
1491 ACE_DCHECK(ifElseComponent && "Must supply IfElseComponent");
1492 ACE_DCHECK(branchId_ >= 0 && "branchId_ must initial during frst render");
1493
1494 if (ifElseComponent->GetBranchId() == branchId_) {
1495 return;
1496 }
1497
1498 // Clear old children while branch id mismatched
1499 children_.clear();
1500
1501 UpdateInternal(ifElseComponent, 0);
1502
1503 // host is the parent List, Swiper or Gridelement
1504 auto host = host_.Upgrade();
1505 if (host) {
1506 host->UpdateIndex();
1507 host->OnDataSourceUpdated(startIndex_);
1508 }
1509 }
1510
1511 private:
1512 int32_t branchId_ = -1;
1513 };
1514
1515 } // namespace
1516
Dump(const std::string & prefix) const1517 void ElementProxy::Dump(const std::string& prefix) const
1518 {
1519 if (DumpLog::GetInstance().GetDumpFile()) {
1520 DumpLog::GetInstance().AddDesc(prefix + "[ElementProxy] composeId: " + composedId_);
1521 }
1522 }
1523
Create(const WeakPtr<ElementProxyHost> & host,const RefPtr<Component> & component)1524 RefPtr<ElementProxy> ElementProxy::Create(const WeakPtr<ElementProxyHost>& host, const RefPtr<Component>& component)
1525 {
1526 if (AceType::InstanceOf<LazyForEachComponent>(component)) {
1527 return AceType::MakeRefPtr<LazyForEachElementProxy>(host);
1528 }
1529 if (!Container::IsCurrentUsePartialUpdate()) {
1530 if (AceType::InstanceOf<ForEachComponent>(component)) {
1531 return AceType::MakeRefPtr<ForEachElementProxy>(host);
1532 }
1533 } else {
1534 if (AceType::InstanceOf<OHOS::Ace::PartUpd::ForEachComponent>(component)) {
1535 return AceType::MakeRefPtr<ForEachElementProxy>(host);
1536 }
1537 if (AceType::InstanceOf<ListItemComponent>(component)) {
1538 return AceType::MakeRefPtr<ListItemElementProxy>(host);
1539 }
1540 if (AceType::InstanceOf<GridLayoutItemComponent>(component)) {
1541 return AceType::MakeRefPtr<GridItemElementProxy>(host);
1542 }
1543 }
1544 if (AceType::InstanceOf<IfElseComponent>(component)) {
1545 return AceType::MakeRefPtr<IfElseElementProxy>(host);
1546 }
1547 if (AceType::InstanceOf<MultiComposedComponent>(component)) {
1548 return AceType::MakeRefPtr<MultiComposedElementProxy>(host);
1549 }
1550
1551 if (Container::IsCurrentUsePartialUpdate()) {
1552 auto tabContentItemComponent = TabsHelper::TraverseComponentTo<TabContentItemComponent>(component);
1553 if (tabContentItemComponent) {
1554 return AceType::MakeRefPtr<TabContentItemElementProxy>(host);
1555 }
1556 }
1557
1558 return AceType::MakeRefPtr<RenderElementProxy>(host);
1559 }
1560
TotalCount() const1561 size_t ElementProxyHost::TotalCount() const
1562 {
1563 return proxy_ ? proxy_->RenderCount() : 0;
1564 }
1565
UpdateChildren(const std::list<RefPtr<Component>> & components)1566 void ElementProxyHost::UpdateChildren(const std::list<RefPtr<Component>>& components)
1567 {
1568 auto component = AceType::MakeRefPtr<MultiComposedComponent>("", "", components);
1569 if (!proxy_) {
1570 proxy_ = ElementProxy::Create(AceType::WeakClaim(this), component);
1571 }
1572 proxy_->Update(component, 0);
1573 }
1574
UpdateIndex()1575 void ElementProxyHost::UpdateIndex()
1576 {
1577 if (proxy_) {
1578 proxy_->UpdateIndex(0);
1579 }
1580 }
1581
GetComponentByIndex(size_t index)1582 RefPtr<Component> ElementProxyHost::GetComponentByIndex(size_t index)
1583 {
1584 return proxy_ && proxy_->IndexInRange(index) ? proxy_->GetComponentByIndex(index) : nullptr;
1585 }
1586
GetElementByIndex(size_t index)1587 RefPtr<Element> ElementProxyHost::GetElementByIndex(size_t index)
1588 {
1589 return proxy_ && proxy_->IndexInRange(index) ? proxy_->GetElementByIndex(index) : nullptr;
1590 }
1591
ReleaseElementByIndex(size_t index)1592 void ElementProxyHost::ReleaseElementByIndex(size_t index)
1593 {
1594 if (proxy_ && proxy_->IndexInRange(index)) {
1595 proxy_->ReleaseElementByIndex(index);
1596 }
1597 }
1598
ReleaseElementById(const std::string & id)1599 void ElementProxyHost::ReleaseElementById(const std::string& id)
1600 {
1601 if (proxy_) {
1602 proxy_->ReleaseElementById(id);
1603 }
1604 }
1605
DumpProxy()1606 void ElementProxyHost::DumpProxy()
1607 {
1608 if (proxy_) {
1609 proxy_->Dump(PREFIX_STEP);
1610 } else {
1611 if (DumpLog::GetInstance().GetDumpFile()) {
1612 DumpLog::GetInstance().AddDesc(std::string("No Proxy"));
1613 }
1614 }
1615 }
1616
GetReloadedCheckNum()1617 size_t ElementProxyHost::GetReloadedCheckNum()
1618 {
1619 return TotalCount();
1620 }
1621
AddComposeId(const ComposeId & id)1622 void ElementProxyHost::AddComposeId(const ComposeId& id)
1623 {
1624 composeIds_.emplace(id);
1625 }
1626
AddActiveComposeId(ComposeId & id)1627 void ElementProxyHost::AddActiveComposeId(ComposeId& id)
1628 {
1629 activeComposeIds_.emplace(id);
1630 }
1631
ReleaseRedundantComposeIds()1632 void ElementProxyHost::ReleaseRedundantComposeIds()
1633 {
1634 if (!proxy_) {
1635 return;
1636 }
1637 activeComposeIds_.clear();
1638 proxy_->RefreshActiveComposeIds();
1639
1640 std::set<ComposeId> idsToRemove;
1641 std::set_difference(composeIds_.begin(), composeIds_.end(), activeComposeIds_.begin(), activeComposeIds_.end(),
1642 std::inserter(idsToRemove, idsToRemove.begin()));
1643 for (auto const& id : idsToRemove) {
1644 ReleaseElementById(id);
1645 }
1646 composeIds_ = activeComposeIds_;
1647 activeComposeIds_.clear();
1648 }
1649
AddSelfToElementRegistry()1650 void ElementProxy::AddSelfToElementRegistry()
1651 {
1652 ElementRegister::GetInstance()->AddElementProxy(AceType::WeakClaim(this));
1653 }
1654
RemoveSelfFromElementRegistry()1655 void ElementProxy::RemoveSelfFromElementRegistry()
1656 {
1657 ElementRegister::GetInstance()->RemoveItem(GetElementId());
1658 }
1659
GetIdArray(int32_t elmtId)1660 std::list<std::string> ForEachElementLookup::GetIdArray(int32_t elmtId)
1661 {
1662 auto elmt = ElementRegister::GetInstance()->GetElementById(elmtId);
1663 auto feElmt = elmt != nullptr ? AceType::DynamicCast<OHOS::Ace::PartUpd::ForEachElement>(elmt) : nullptr;
1664 if (feElmt != nullptr) {
1665 return feElmt->GetIdArray();
1666 }
1667
1668 auto elmtProxy = ElementRegister::GetInstance()->GetElementProxyById(elmtId);
1669 auto feElmtProxy =
1670 elmtProxy != nullptr ? AceType::DynamicCast<OHOS::Ace::V2::ForEachElementProxy>(elmtProxy) : nullptr;
1671 if (feElmtProxy != nullptr) {
1672 return feElmtProxy->GetIdArray();
1673 }
1674
1675 LOGW("Can not find ForEachElement or ForEachElementProxy with elmtId %{public}d. (ok on first render)", elmtId);
1676 return {};
1677 }
1678
1679 } // namespace OHOS::Ace::V2
1680