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