• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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_ng/pattern/list/list_item_group_pattern.h"
17 
18 #include "base/log/dump_log.h"
19 #include "core/components/list/list_item_theme.h"
20 #include "core/components_ng/pattern/list/list_item_group_layout_algorithm.h"
21 #include "core/components_ng/pattern/list/list_item_group_paint_method.h"
22 #include "core/components_ng/pattern/list/list_pattern.h"
23 #include "core/pipeline_ng/pipeline_context.h"
24 
25 namespace OHOS::Ace::NG {
26 
OnAttachToFrameNode()27 void ListItemGroupPattern::OnAttachToFrameNode()
28 {
29     auto host = GetHost();
30     CHECK_NULL_VOID(host);
31     if (listItemGroupStyle_ == V2::ListItemGroupStyle::CARD) {
32         SetListItemGroupDefaultAttributes(host);
33     }
34 }
35 
OnColorConfigurationUpdate()36 void ListItemGroupPattern::OnColorConfigurationUpdate()
37 {
38     if (listItemGroupStyle_ != V2::ListItemGroupStyle::CARD) {
39         return;
40     }
41     auto itemGroupNode = GetHost();
42     CHECK_NULL_VOID(itemGroupNode);
43     auto renderContext = itemGroupNode->GetRenderContext();
44     CHECK_NULL_VOID(renderContext);
45     auto pipeline = itemGroupNode->GetContext();
46     CHECK_NULL_VOID(pipeline);
47     auto listItemGroupTheme = pipeline->GetTheme<ListItemTheme>();
48     CHECK_NULL_VOID(listItemGroupTheme);
49 
50     renderContext->UpdateBackgroundColor(listItemGroupTheme->GetItemGroupDefaultColor());
51 }
52 
SetListItemGroupDefaultAttributes(const RefPtr<FrameNode> & itemGroupNode)53 void ListItemGroupPattern::SetListItemGroupDefaultAttributes(const RefPtr<FrameNode>& itemGroupNode)
54 {
55     auto renderContext = itemGroupNode->GetRenderContext();
56     CHECK_NULL_VOID(renderContext);
57     auto layoutProperty = itemGroupNode->GetLayoutProperty<ListItemGroupLayoutProperty>();
58     CHECK_NULL_VOID(layoutProperty);
59 
60     auto pipeline = GetContext();
61     CHECK_NULL_VOID(pipeline);
62     auto listItemGroupTheme = pipeline->GetTheme<ListItemTheme>();
63     CHECK_NULL_VOID(listItemGroupTheme);
64 
65     renderContext->UpdateBackgroundColor(listItemGroupTheme->GetItemGroupDefaultColor());
66 
67     MarginProperty itemGroupMargin;
68     itemGroupMargin.left = CalcLength(listItemGroupTheme->GetItemGroupDefaultLeftMargin());
69     itemGroupMargin.right = CalcLength(listItemGroupTheme->GetItemGroupDefaultRightMargin());
70     layoutProperty->UpdateMargin(itemGroupMargin);
71 
72     PaddingProperty itemGroupPadding;
73     itemGroupPadding.left = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Left());
74     itemGroupPadding.right = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Right());
75     itemGroupPadding.top = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Top());
76     itemGroupPadding.bottom = CalcLength(listItemGroupTheme->GetItemGroupDefaultPadding().Bottom());
77     layoutProperty->UpdatePadding(itemGroupPadding);
78 
79     renderContext->UpdateBorderRadius(listItemGroupTheme->GetItemGroupDefaultBorderRadius());
80 }
81 
DumpAdvanceInfo()82 void ListItemGroupPattern::DumpAdvanceInfo()
83 {
84     DumpLog::GetInstance().AddDesc("itemStartIndex:" + std::to_string(itemStartIndex_));
85     DumpLog::GetInstance().AddDesc("itemTotalCount:" + std::to_string(itemTotalCount_));
86     DumpLog::GetInstance().AddDesc("itemDisplayEndIndex:" + std::to_string(itemDisplayEndIndex_));
87     DumpLog::GetInstance().AddDesc("itemDisplayStartIndex:" + std::to_string(itemDisplayStartIndex_));
88     DumpLog::GetInstance().AddDesc("headerMainSize:" + std::to_string(headerMainSize_));
89     DumpLog::GetInstance().AddDesc("footerMainSize:" + std::to_string(footerMainSize_));
90     DumpLog::GetInstance().AddDesc("spaceWidth:" + std::to_string(spaceWidth_));
91     DumpLog::GetInstance().AddDesc("lanes:" + std::to_string(lanes_));
92     DumpLog::GetInstance().AddDesc("laneGutter:" + std::to_string(laneGutter_));
93     DumpLog::GetInstance().AddDesc("startHeaderPos:" + std::to_string(startHeaderPos_));
94     DumpLog::GetInstance().AddDesc("endFooterPos:" + std::to_string(endFooterPos_));
95 }
96 
CreateLayoutAlgorithm()97 RefPtr<LayoutAlgorithm> ListItemGroupPattern::CreateLayoutAlgorithm()
98 {
99     CalculateItemStartIndex();
100     auto layoutAlgorithm = MakeRefPtr<ListItemGroupLayoutAlgorithm>(headerIndex_, footerIndex_, itemStartIndex_);
101     layoutAlgorithm->SetItemsPosition(itemPosition_);
102     layoutAlgorithm->SetCachedItemsPosition(cachedItemPosition_);
103     layoutAlgorithm->SetCachedIndex(forwardCachedIndex_, backwardCachedIndex_);
104     layoutAlgorithm->SetLayoutedItemInfo(layoutedItemInfo_);
105     if (childrenSize_ && ListChildrenSizeExist()) {
106         if (!posMap_) {
107             posMap_ = MakeRefPtr<ListPositionMap>();
108         }
109         layoutAlgorithm->SetListChildrenMainSize(childrenSize_);
110         layoutAlgorithm->SetListPositionMap(posMap_);
111     }
112     return layoutAlgorithm;
113 }
114 
CreateNodePaintMethod()115 RefPtr<NodePaintMethod> ListItemGroupPattern::CreateNodePaintMethod()
116 {
117     auto layoutProperty = GetLayoutProperty<ListItemGroupLayoutProperty>();
118     V2::ItemDivider itemDivider;
119     auto divider = layoutProperty->GetDivider().value_or(itemDivider);
120     auto drawVertical = (axis_ == Axis::HORIZONTAL);
121     ListItemGroupPaintInfo listItemGroupPaintInfo { layoutDirection_, mainSize_, drawVertical, lanes_,
122         spaceWidth_, laneGutter_, itemTotalCount_ };
123     return MakeRefPtr<ListItemGroupPaintMethod>(
124         divider, listItemGroupPaintInfo, itemPosition_, cachedItemPosition_, pressedItem_);
125 }
126 
SyncItemsToCachedItemPosition()127 void ListItemGroupPattern::SyncItemsToCachedItemPosition()
128 {
129     itemPosition_.insert(cachedItemPosition_.begin(), cachedItemPosition_.end());
130     cachedItemPosition_.swap(itemPosition_);
131     itemPosition_.clear();
132 }
133 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)134 bool ListItemGroupPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
135 {
136     if (config.skipMeasure && config.skipLayout) {
137         return false;
138     }
139     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
140     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
141     auto layoutAlgorithm = DynamicCast<ListItemGroupLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
142     CHECK_NULL_RETURN(layoutAlgorithm, false);
143     itemTotalCount_ = layoutAlgorithm->GetTotalItemCount();
144     auto cacheParam = layoutAlgorithm->GetCacheParam();
145     if (cacheParam) {
146         forwardCachedIndex_ = cacheParam.value().forwardCachedIndex;
147         backwardCachedIndex_ = cacheParam.value().backwardCachedIndex;
148         adjustRefPos_ = layoutAlgorithm->GetAdjustReferenceDelta();
149         layoutAlgorithm->SetCacheParam(std::nullopt);
150     }
151     if (lanes_ != layoutAlgorithm->GetLanes()) {
152         lanes_ = layoutAlgorithm->GetLanes();
153         ClearCachedItemPosition();
154     }
155     itemPosition_ = layoutAlgorithm->GetItemPosition();
156     cachedItemPosition_ = layoutAlgorithm->GetCachedItemPosition();
157     spaceWidth_ = layoutAlgorithm->GetSpaceWidth();
158     axis_ = layoutAlgorithm->GetAxis();
159     layoutDirection_ = layoutAlgorithm->GetLayoutDirection();
160     mainSize_ = layoutAlgorithm->GetMainSize();
161     laneGutter_ = layoutAlgorithm->GetLaneGutter();
162     itemDisplayEndIndex_ = layoutAlgorithm->GetEndIndex();
163     itemDisplayStartIndex_ = layoutAlgorithm->GetStartIndex();
164     headerMainSize_ = layoutAlgorithm->GetHeaderMainSize();
165     footerMainSize_ = layoutAlgorithm->GetFooterMainSize();
166     layoutedItemInfo_ = layoutAlgorithm->GetLayoutedItemInfo();
167     startHeaderPos_ = layoutAlgorithm->GetStartHeaderPos();
168     endFooterPos_ = layoutAlgorithm->GetEndFooterPos();
169     adjustRefPos_ = layoutAlgorithm->GetAdjustReferenceDelta();
170     adjustTotalSize_ = layoutAlgorithm->GetAdjustTotalSize();
171     layouted_ = true;
172     CheckListDirectionInCardStyle();
173     auto host = GetHost();
174     CHECK_NULL_RETURN(host, false);
175     auto accessibilityProperty = host->GetAccessibilityProperty<ListItemGroupAccessibilityProperty>();
176     if (accessibilityProperty != nullptr) {
177         accessibilityProperty->SetCollectionItemCounts(layoutAlgorithm->GetTotalItemCount());
178     }
179     auto listLayoutProperty = host->GetLayoutProperty<ListItemGroupLayoutProperty>();
180     return listLayoutProperty && listLayoutProperty->GetDivider().has_value() && !itemPosition_.empty();
181 }
182 
GetPaddingAndMargin() const183 float ListItemGroupPattern::GetPaddingAndMargin() const
184 {
185     auto layoutProperty = GetLayoutProperty<ListItemGroupLayoutProperty>();
186     CHECK_NULL_RETURN(layoutProperty, 0.0f);
187     const auto& padding = layoutProperty->CreatePaddingAndBorder();
188     const auto& margin = layoutProperty->CreateMargin();
189     auto offsetBeforeContent = axis_ == Axis::HORIZONTAL ? padding.left.value_or(0) : padding.top.value_or(0);
190     auto offsetAfterContent = axis_ == Axis::HORIZONTAL ? padding.right.value_or(0) : padding.bottom.value_or(0);
191     offsetBeforeContent += axis_ == Axis::HORIZONTAL ? margin.left.value_or(0) : margin.top.value_or(0);
192     offsetAfterContent += axis_ == Axis::HORIZONTAL ? margin.right.value_or(0) : margin.bottom.value_or(0);
193     return offsetBeforeContent + offsetAfterContent;
194 }
195 
GetEstimateOffset(float height,const std::pair<float,float> & targetPos) const196 float ListItemGroupPattern::GetEstimateOffset(float height, const std::pair<float, float>& targetPos) const
197 {
198     if (layoutedItemInfo_.has_value() && layoutedItemInfo_.value().startIndex > 0) {
199         float averageHeight = 0.0f;
200         float estimateHeight = GetEstimateHeight(averageHeight);
201         if (layoutedItemInfo_.value().endIndex >= itemTotalCount_ - 1) {
202             return height + estimateHeight - targetPos.second;
203         } else {
204             return height - targetPos.first + layoutedItemInfo_.value().startIndex * averageHeight - spaceWidth_;
205         }
206     }
207     return height - targetPos.first;
208 }
209 
IsVisible() const210 bool ListItemGroupPattern::IsVisible() const
211 {
212     auto layoutProperty = GetLayoutProperty<ListItemGroupLayoutProperty>();
213     CHECK_NULL_RETURN(layoutProperty, false);
214     auto visible = layoutProperty->GetVisibility().value_or(VisibleType::VISIBLE);
215     if (visible == VisibleType::GONE) {
216         return false;
217     }
218     return true;
219 }
220 
GetEstimateHeight(float & averageHeight) const221 float ListItemGroupPattern::GetEstimateHeight(float& averageHeight) const
222 {
223     auto layoutProperty = GetLayoutProperty<ListItemGroupLayoutProperty>();
224     CHECK_NULL_RETURN(layoutProperty, 0.0f);
225     auto visible = layoutProperty->GetVisibility().value_or(VisibleType::VISIBLE);
226     if (visible == VisibleType::GONE) {
227         return 0.0f;
228     }
229     float paddingAndMargin = GetPaddingAndMargin();
230     if (layoutedItemInfo_.has_value()) {
231         auto totalHeight = (layoutedItemInfo_.value().endPos - layoutedItemInfo_.value().startPos + spaceWidth_);
232         auto itemCount = layoutedItemInfo_.value().endIndex - layoutedItemInfo_.value().startIndex + 1;
233         averageHeight = totalHeight / itemCount;
234     }
235     if (layouted_) {
236         if (itemTotalCount_ > 0) {
237             return itemTotalCount_ * averageHeight + headerMainSize_ + footerMainSize_ + paddingAndMargin - spaceWidth_;
238         } else {
239             return headerMainSize_ + footerMainSize_ + paddingAndMargin;
240         }
241     }
242     auto host = GetHost();
243     auto totalItem = host->GetTotalChildCount();
244     return averageHeight * totalItem + paddingAndMargin;
245 }
246 
CheckListDirectionInCardStyle()247 void ListItemGroupPattern::CheckListDirectionInCardStyle()
248 {
249     if (axis_ == Axis::HORIZONTAL && listItemGroupStyle_ == V2::ListItemGroupStyle::CARD) {
250         auto host = GetHost();
251         CHECK_NULL_VOID(host);
252         RefPtr<FrameNode> listNode = AceType::DynamicCast<FrameNode>(host->GetParent());
253         CHECK_NULL_VOID(listNode);
254         auto listPattern = listNode->GetPattern<ListPattern>();
255         CHECK_NULL_VOID(listPattern);
256         listPattern->SetNeedToUpdateListDirectionInCardStyle(true);
257     }
258 }
259 
GetListFrameNode() const260 RefPtr<FrameNode> ListItemGroupPattern::GetListFrameNode() const
261 {
262     auto host = GetHost();
263     CHECK_NULL_RETURN(host, nullptr);
264     auto parent = host->GetParent();
265     RefPtr<FrameNode> frameNode = AceType::DynamicCast<FrameNode>(parent);
266     while (parent && !frameNode) {
267         parent = parent->GetParent();
268         frameNode = AceType::DynamicCast<FrameNode>(parent);
269     }
270     return frameNode;
271 }
272 
ListChildrenSizeExist()273 bool ListItemGroupPattern::ListChildrenSizeExist()
274 {
275     RefPtr<FrameNode> listNode = GetListFrameNode();
276     CHECK_NULL_RETURN(listNode, false);
277     auto listPattern = listNode->GetPattern<ListPattern>();
278     CHECK_NULL_RETURN(listPattern, false);
279     return listPattern->ListChildrenSizeExist();
280 }
281 
GetOrCreateListChildrenMainSize()282 RefPtr<ListChildrenMainSize> ListItemGroupPattern::GetOrCreateListChildrenMainSize()
283 {
284     if (childrenSize_) {
285         return childrenSize_;
286     }
287     childrenSize_ = AceType::MakeRefPtr<ListChildrenMainSize>();
288     auto callback = [weakPattern = WeakClaim(this)](std::tuple<int32_t, int32_t, int32_t> change, ListChangeFlag flag) {
289         auto pattern = weakPattern.Upgrade();
290         CHECK_NULL_VOID(pattern);
291         auto context = PipelineContext::GetCurrentContext();
292         CHECK_NULL_VOID(context);
293         context->AddBuildFinishCallBack([weakPattern, change, flag]() {
294             auto pattern = weakPattern.Upgrade();
295             CHECK_NULL_VOID(pattern);
296             pattern->OnChildrenSizeChanged(change, flag);
297         });
298         context->RequestFrame();
299     };
300     childrenSize_->SetOnDataChange(callback);
301     return childrenSize_;
302 }
303 
SetListChildrenMainSize(float defaultSize,const std::vector<float> & mainSize)304 void ListItemGroupPattern::SetListChildrenMainSize(
305     float defaultSize, const std::vector<float>& mainSize)
306 {
307     childrenSize_ = AceType::MakeRefPtr<ListChildrenMainSize>(mainSize, defaultSize);
308     OnChildrenSizeChanged({ -1, -1, -1 }, LIST_UPDATE_CHILD_SIZE);
309 }
310 
OnChildrenSizeChanged(std::tuple<int32_t,int32_t,int32_t> change,ListChangeFlag flag)311 void ListItemGroupPattern::OnChildrenSizeChanged(std::tuple<int32_t, int32_t, int32_t> change, ListChangeFlag flag)
312 {
313     if (!posMap_) {
314         posMap_ = MakeRefPtr<ListPositionMap>();
315     }
316     posMap_->MarkDirty(flag);
317     auto host = GetHost();
318     CHECK_NULL_VOID(host);
319     host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
320 }
321 
GetStartListItemIndex()322 VisibleContentInfo ListItemGroupPattern::GetStartListItemIndex()
323 {
324     bool isHeader = false;
325     auto startHeaderMainSize = GetHeaderMainSize();
326     auto startFooterMainSize = GetFooterMainSize();
327     if (GetDisplayStartIndexInGroup() == 0) {
328         auto startHeaderPos = startHeaderPos_;
329         isHeader = (startHeaderPos + startHeaderMainSize) > 0 ? true : false;
330     }
331     auto startPositionSize = GetItemPosition().size();
332     auto startItemIndexInGroup = GetDisplayStartIndexInGroup();
333     auto startArea = ListItemGroupArea::IN_LIST_ITEM_AREA;
334     if (startPositionSize == 0 && startFooterMainSize > 0) {
335         startArea = ListItemGroupArea::IN_FOOTER_AREA;
336         startItemIndexInGroup = -1;
337     }
338     if (GetDisplayStartIndexInGroup() == 0 && isHeader && startHeaderMainSize > 0) {
339         startArea = ListItemGroupArea::IN_HEADER_AREA;
340         startItemIndexInGroup = -1;
341     }
342     if (startHeaderMainSize == 0 && startFooterMainSize == 0 && GetTotalItemCount() == 0) {
343         startArea = ListItemGroupArea::NONE_AREA;
344     }
345     VisibleContentInfo startInfo = { startArea, startItemIndexInGroup };
346     return startInfo;
347 }
348 
GetEndListItemIndex()349 VisibleContentInfo ListItemGroupPattern::GetEndListItemIndex()
350 {
351     bool isFooter = endFooterPos_ < 0 ? true : false;
352     auto endHeaderMainSize = GetHeaderMainSize();
353     auto endFooterMainSize = GetFooterMainSize();
354     auto endPositionSize = GetItemPosition().size();
355     auto endItemIndexInGroup = GetDisplayEndIndexInGroup();
356     auto endArea = ListItemGroupArea::IN_LIST_ITEM_AREA;
357     if (endPositionSize == 0 && endHeaderMainSize > 0) {
358         endArea = ListItemGroupArea::IN_HEADER_AREA;
359         endItemIndexInGroup = -1;
360     }
361     if (isFooter && endFooterMainSize > 0) {
362         endArea = ListItemGroupArea::IN_FOOTER_AREA;
363         endItemIndexInGroup = -1;
364     }
365     if (endHeaderMainSize == 0 && endFooterMainSize == 0 && GetTotalItemCount() == 0) {
366         endArea = ListItemGroupArea::NONE_AREA;
367     }
368     VisibleContentInfo endInfo = { endArea, endItemIndexInGroup };
369     return endInfo;
370 }
371 
ResetChildrenSize()372 void ListItemGroupPattern::ResetChildrenSize()
373 {
374     if (childrenSize_) {
375         childrenSize_ = nullptr;
376         auto host = GetHost();
377         CHECK_NULL_VOID(host);
378         host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
379         OnChildrenSizeChanged({ -1, -1, -1 }, LIST_UPDATE_CHILD_SIZE);
380     }
381 }
382 
ClearItemPosition()383 void ListItemGroupPattern::ClearItemPosition()
384 {
385     itemPosition_.clear();
386 }
387 
ClearCachedItemPosition()388 void ListItemGroupPattern::ClearCachedItemPosition()
389 {
390     cachedItemPosition_.clear();
391     forwardCachedIndex_ = -1;
392     backwardCachedIndex_ = INT_MAX;
393 }
394 
CalculateItemStartIndex()395 void ListItemGroupPattern::CalculateItemStartIndex()
396 {
397     int32_t headerIndex = -1;
398     int32_t footerIndex = -1;
399     int32_t itemStartIndex = 0;
400     auto header = header_.Upgrade();
401     if (header) {
402         auto count = header->FrameCount();
403         if (count > 0) {
404             headerIndex = itemStartIndex;
405             itemStartIndex += count;
406         }
407     }
408     auto footer = footer_.Upgrade();
409     if (footer) {
410         int32_t count = footer->FrameCount();
411         if (count > 0) {
412             footerIndex = itemStartIndex;
413             itemStartIndex += count;
414         }
415     }
416     headerIndex_ = headerIndex;
417     footerIndex_ = footerIndex;
418     itemStartIndex_ = itemStartIndex;
419 }
420 
UpdateActiveChildRange(bool forward,int32_t cacheCount,bool show)421 void ListItemGroupPattern::UpdateActiveChildRange(bool forward, int32_t cacheCount, bool show)
422 {
423     auto host = GetHost();
424     CHECK_NULL_VOID(host);
425     if (forward) {
426         host->SetActiveChildRange(-1, itemStartIndex_ - 1, 0, cacheCount, show);
427     } else {
428         int32_t index = itemTotalCount_ + itemStartIndex_;
429         host->SetActiveChildRange(index, index, cacheCount, 0, show);
430     }
431     if (show && headerIndex_ >= 0) {
432         host->GetOrCreateChildByIndex(headerIndex_);
433     }
434     if (show && footerIndex_ >= 0) {
435         host->GetOrCreateChildByIndex(footerIndex_);
436     }
437     if (show) {
438         host->RebuildRenderContextTree();
439     }
440 }
441 
UpdateActiveChildRange(bool show)442 void ListItemGroupPattern::UpdateActiveChildRange(bool show)
443 {
444     auto host = GetHost();
445     CHECK_NULL_VOID(host);
446     if (!itemPosition_.empty()) {
447         auto start = itemStartIndex_ + itemPosition_.begin()->first;
448         auto end = itemStartIndex_ + itemPosition_.rbegin()->first;
449         host->SetActiveChildRange(start, end);
450     } else if (headerIndex_ >= 0 || footerIndex_ >= 0) {
451         host->SetActiveChildRange(-1, itemStartIndex_ - 1);
452     } else {
453         host->SetActiveChildRange(-1, -1);
454     }
455     if (headerIndex_ >= 0) {
456         host->GetOrCreateChildByIndex(headerIndex_);
457     }
458     if (footerIndex_ >= 0) {
459         host->GetOrCreateChildByIndex(footerIndex_);
460     }
461     if (show) {
462         host->RebuildRenderContextTree();
463     }
464 }
465 
UpdateCachedIndexForward(bool outOfView,bool show,int32_t cacheCount)466 int32_t ListItemGroupPattern::UpdateCachedIndexForward(bool outOfView, bool show, int32_t cacheCount)
467 {
468     int32_t endIndex = (outOfView || itemPosition_.empty()) ? -1 : itemPosition_.rbegin()->first;
469     int32_t endLimit = std::min(endIndex + cacheCount * lanes_, itemTotalCount_ - 1);
470     int32_t forwardCachedIndex = std::clamp(forwardCachedIndex_, endIndex, endLimit);
471     auto iter = cachedItemPosition_.begin();
472     while (iter != cachedItemPosition_.end()) {
473         if (iter->first >= endIndex + 1 && iter->first <= endLimit) {
474             iter++;
475             continue;
476         }
477         iter = cachedItemPosition_.erase(iter);
478     }
479     if (cachedItemPosition_.find(forwardCachedIndex) == cachedItemPosition_.end() ||
480         cachedItemPosition_.find(endIndex + 1) == cachedItemPosition_.end()) {
481         forwardCachedIndex = endIndex;
482         cachedItemPosition_.clear();
483     }
484     if (outOfView && forwardCachedIndex < forwardCachedIndex_) {
485         UpdateActiveChildRange(true, forwardCachedIndex + 1, show);
486     }
487     return forwardCachedIndex;
488 }
489 
UpdateCachedIndexBackward(bool outOfView,bool show,int32_t cacheCount)490 int32_t ListItemGroupPattern::UpdateCachedIndexBackward(bool outOfView, bool show, int32_t cacheCount)
491 {
492     int32_t startIndex = (outOfView || itemPosition_.empty()) ? itemTotalCount_ : itemPosition_.begin()->first;
493     int32_t startLimit = std::max(startIndex - cacheCount * lanes_, 0);
494     if (startLimit % lanes_ != 0) {
495         startLimit += (lanes_ - startLimit % lanes_);
496     }
497     int32_t backwardCachedIndex = std::clamp(backwardCachedIndex_, startLimit, startIndex);
498     auto iter = cachedItemPosition_.begin();
499     while (iter != cachedItemPosition_.end()) {
500         if (iter->first >= startLimit && iter->first <= startIndex - 1) {
501             iter++;
502             continue;
503         }
504         iter = cachedItemPosition_.erase(iter);
505     }
506     if (cachedItemPosition_.find(backwardCachedIndex) == cachedItemPosition_.end() ||
507         cachedItemPosition_.find(startIndex - 1) == cachedItemPosition_.end()) {
508         backwardCachedIndex = startIndex;
509         cachedItemPosition_.clear();
510     }
511     if (outOfView && backwardCachedIndex > backwardCachedIndex_) {
512         UpdateActiveChildRange(false, itemTotalCount_ - backwardCachedIndex, show);
513     }
514     return backwardCachedIndex;
515 }
516 
UpdateCachedIndexOmni(int32_t forwardCache,int32_t backwardCache)517 std::pair<int32_t, int32_t> ListItemGroupPattern::UpdateCachedIndexOmni(int32_t forwardCache, int32_t backwardCache)
518 {
519     int32_t forwardRes = -1;
520     int32_t backwardRes = INT_MAX;
521     int32_t startIndex = itemPosition_.begin()->first;
522     int32_t startLimit = std::max(startIndex - backwardCache * lanes_, 0);
523     if (startLimit % lanes_ != 0) {
524         startLimit += (lanes_ - startLimit % lanes_);
525     }
526     int32_t backwardCachedIndex = std::clamp(backwardCachedIndex_, startLimit, startIndex);
527     int32_t endIndex = itemPosition_.rbegin()->first;
528     int32_t endLimit = std::min(endIndex + forwardCache * lanes_, itemTotalCount_ - 1);
529     int32_t forwardCachedIndex = std::clamp(forwardCachedIndex_, endIndex, endLimit);
530     auto iter = cachedItemPosition_.begin();
531     while (iter != cachedItemPosition_.end()) {
532         if ((iter->first >= startLimit && iter->first <= startIndex - 1) ||
533             (iter->first >= endIndex + 1 && iter->first <= endLimit)) {
534             iter++;
535             continue;
536         }
537         iter = cachedItemPosition_.erase(iter);
538     }
539     if (cachedItemPosition_.find(backwardCachedIndex) == cachedItemPosition_.end() ||
540         cachedItemPosition_.find(startIndex - 1) == cachedItemPosition_.end()) {
541         backwardRes = startIndex;
542     } else {
543         backwardRes = backwardCachedIndex;
544     }
545     if (cachedItemPosition_.find(forwardCachedIndex) == cachedItemPosition_.end() ||
546         cachedItemPosition_.find(endIndex + 1) == cachedItemPosition_.end()) {
547         forwardRes = endIndex;
548     } else {
549         forwardRes = forwardCachedIndex;
550     }
551     return { forwardRes, backwardRes };
552 }
553 
UpdateCachedIndex(bool outOfView,bool reCache,int32_t forwardCache,int32_t backwardCache)554 CachedIndexInfo ListItemGroupPattern::UpdateCachedIndex(
555     bool outOfView, bool reCache, int32_t forwardCache, int32_t backwardCache)
556 {
557     CachedIndexInfo res;
558     auto host = GetHost();
559     if (!host) {
560         forwardCachedIndex_ = -1;
561         backwardCachedIndex_ = INT_MAX;
562         return res;
563     }
564     auto listNode = GetListFrameNode();
565     bool show = listNode && listNode->GetLayoutProperty<ListLayoutProperty>() ?
566         listNode->GetLayoutProperty<ListLayoutProperty>()->GetShowCachedItemsValue(false) : false;
567     if (itemTotalCount_ == -1 || host->CheckNeedForceMeasureAndLayout()) {
568         CalculateItemStartIndex();
569         itemTotalCount_ = host->GetTotalChildCount() - itemStartIndex_;
570     }
571     if (outOfView) {
572         ClearItemPosition();
573     }
574     if (reCache || reCache_) {
575         ClearCachedItemPosition();
576         UpdateActiveChildRange(show);
577         reCache_ = false;
578     }
579     int32_t lanes = lanes_ > 1 ? lanes_ : 1;
580     if (forwardCache > -1 && backwardCache > -1 && !itemPosition_.empty()) {
581         auto cached = UpdateCachedIndexOmni(forwardCache, backwardCache);
582         forwardCachedIndex_ = cached.first;
583         backwardCachedIndex_ = cached.second;
584         int32_t startIndex = itemPosition_.begin()->first;
585         int32_t endIndex = itemPosition_.rbegin()->first;
586         res.forwardCachedCount = (forwardCachedIndex_ - endIndex + lanes - 1) / lanes;
587         res.forwardCacheMax = (itemTotalCount_ - 1 - endIndex + lanes - 1) / lanes;
588         res.backwardCachedCount = (startIndex - backwardCachedIndex_ + lanes - 1) / lanes;
589         res.backwardCacheMax = (startIndex + lanes - 1) / lanes;
590     } else if (forwardCache > -1) {
591         forwardCachedIndex_ = UpdateCachedIndexForward(outOfView, show, forwardCache);
592         backwardCachedIndex_ = INT_MAX;
593         int32_t endIndex = (outOfView || itemPosition_.empty()) ? -1 : itemPosition_.rbegin()->first;
594         res.forwardCachedCount = (forwardCachedIndex_ - endIndex + lanes - 1) / lanes;
595         res.forwardCacheMax = (itemTotalCount_ - 1 - endIndex + lanes - 1) / lanes;
596     } else if (backwardCache > -1) {
597         forwardCachedIndex_ = -1;
598         backwardCachedIndex_ = UpdateCachedIndexBackward(outOfView, show, backwardCache);
599         int32_t startIndex = (outOfView || itemPosition_.empty()) ? itemTotalCount_ : itemPosition_.begin()->first;
600         res.backwardCachedCount = (startIndex - backwardCachedIndex_ + lanes - 1) / lanes;
601         res.backwardCacheMax = (startIndex + lanes - 1) / lanes;
602     }
603     return res;
604 }
605 
NeedCacheForward(const LayoutWrapper * listWrapper) const606 bool ListItemGroupPattern::NeedCacheForward(const LayoutWrapper* listWrapper) const
607 {
608     auto host = GetHost();
609     CHECK_NULL_RETURN(host, true);
610     auto listProperty = AceType::DynamicCast<ListLayoutProperty>(listWrapper->GetLayoutProperty());
611     CHECK_NULL_RETURN(listProperty, true);
612     auto listPadding = listProperty->CreatePaddingAndBorder().Offset();
613     auto offset = host->GetGeometryNode()->GetMarginFrameOffset();
614     if (GreatNotEqual(GetMainAxisOffset(offset, axis_) + headerMainSize_, GetMainAxisOffset(listPadding, axis_))) {
615         return true;
616     } else {
617         return false;
618     }
619 }
620 
LayoutCache(const LayoutConstraintF & constraint,int64_t deadline,int32_t forwardCached,int32_t backwardCached,ListMainSizeValues listSizeValues)621 void ListItemGroupPattern::LayoutCache(const LayoutConstraintF& constraint, int64_t deadline,
622     int32_t forwardCached, int32_t backwardCached, ListMainSizeValues listSizeValues)
623 {
624     auto listNode = GetListFrameNode();
625     CHECK_NULL_VOID(listNode);
626     auto listPattern = listNode->GetPattern<ListPattern>();
627     CHECK_NULL_VOID(listPattern);
628     auto listLayoutProperty = listNode->GetLayoutProperty<ListLayoutProperty>();
629     CHECK_NULL_VOID(listLayoutProperty);
630     auto cacheCountForward = listLayoutProperty->GetCachedCountWithDefault() - forwardCached;
631     auto cacheCountBackward = listLayoutProperty->GetCachedCountWithDefault() - backwardCached;
632     if (cacheCountForward < 1 && cacheCountBackward < 1) {
633         return;
634     }
635     auto host = GetHost();
636     CHECK_NULL_VOID(host);
637     auto layoutAlgorithmWrapper = host->GetLayoutAlgorithm(true);
638     CHECK_NULL_VOID(layoutAlgorithmWrapper);
639     auto itemGroup = AceType::DynamicCast<ListItemGroupLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
640     CHECK_NULL_VOID(itemGroup);
641     ListItemGroupCacheParam param = {
642         .forward = listSizeValues.forward,
643         .backward = listSizeValues.backward,
644         .show = listLayoutProperty->GetShowCachedItemsValue(false),
645         .cacheCountForward = cacheCountForward,
646         .cacheCountBackward = cacheCountBackward,
647         .forwardCachedIndex = forwardCachedIndex_,
648         .backwardCachedIndex = backwardCachedIndex_,
649         .deadline = deadline,
650     };
651     itemGroup->SetContentOffset(listSizeValues.contentStartOffset, listSizeValues.contentEndOffset);
652     itemGroup->SetCacheParam(param);
653     itemGroup->SetListLayoutProperty(listLayoutProperty);
654     itemGroup->SetListMainSize(listSizeValues.startPos, listSizeValues.endPos, listSizeValues.referencePos,
655         listSizeValues.prevContentMainSize, listSizeValues.forward);
656     host->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
657     host->GetGeometryNode()->SetParentLayoutConstraint(constraint);
658     FrameNode::ProcessOffscreenNode(host);
659     if ((!NearZero(adjustRefPos_) || !NearZero(adjustTotalSize_)) && !(childrenSize_ && ListChildrenSizeExist())) {
660         listPattern->UpdateChildPosInfo(indexInList_, adjustRefPos_, adjustTotalSize_);
661         adjustRefPos_ = 0.0f;
662         adjustTotalSize_ = 0.0f;
663     }
664 }
665 
SetListItemGroupStyle(V2::ListItemGroupStyle style)666 void ListItemGroupPattern::SetListItemGroupStyle(V2::ListItemGroupStyle style)
667 {
668     auto host = GetHost();
669     CHECK_NULL_VOID(host);
670     if (listItemGroupStyle_ == V2::ListItemGroupStyle::NONE && style == V2::ListItemGroupStyle::CARD) {
671         listItemGroupStyle_ = style;
672         SetListItemGroupDefaultAttributes(host);
673     }
674 }
675 
GetListPaddingOffset(const RefPtr<FrameNode> & listNode) const676 float ListItemGroupPattern::GetListPaddingOffset(const RefPtr<FrameNode>& listNode) const
677 {
678     float offset = 0;
679     CHECK_NULL_RETURN(listNode, offset);
680     auto layoutProperty = listNode->GetLayoutProperty<ListLayoutProperty>();
681     CHECK_NULL_RETURN(layoutProperty, offset);
682     auto padding = layoutProperty->CreatePaddingAndBorder();
683     return GetMainAxisOffset(padding.Offset(), axis_);
684 }
685 
FirstItemFullVisible(const RefPtr<FrameNode> & listNode) const686 bool ListItemGroupPattern::FirstItemFullVisible(const RefPtr<FrameNode>& listNode) const
687 {
688     auto host = GetHost();
689     CHECK_NULL_RETURN(host, true);
690     auto geometryNode = host->GetGeometryNode();
691     CHECK_NULL_RETURN(geometryNode, true);
692     OffsetF selfOffset = geometryNode->GetPaddingOffset();
693     float mainPos = GetMainAxisOffset(selfOffset, axis_) + headerMainSize_;
694     float listPadding = GetListPaddingOffset(listNode);
695     return GreatNotEqual(mainPos, listPadding);
696 }
697 
CheckDataChangeOutOfStart(int32_t index,int32_t count,int32_t startIndex)698 bool ListItemGroupPattern::CheckDataChangeOutOfStart(int32_t index, int32_t count, int32_t startIndex)
699 {
700     if (count == 0 || (count > 0 && index > startIndex) ||
701         (count < 0 && index >= startIndex)) {
702         return false;
703     }
704 
705     RefPtr<FrameNode> listNode = GetListFrameNode();
706     CHECK_NULL_RETURN(listNode, false);
707     auto listPattern = listNode->GetPattern<ListPattern>();
708     CHECK_NULL_RETURN(listPattern, false);
709     if (!listPattern->GetMaintainVisibleContentPosition()) {
710         return false;
711     }
712 
713     if (startIndex == 0 && index == 0 && count > 0 && FirstItemFullVisible(listNode)) {
714         return false;
715     }
716     listPattern->MarkNeedReEstimateOffset();
717     return true;
718 }
719 
NotifyDataChange(int32_t index,int32_t count)720 void ListItemGroupPattern::NotifyDataChange(int32_t index, int32_t count)
721 {
722     if (itemPosition_.empty()) {
723         return;
724     }
725     index -= itemStartIndex_;
726     int32_t startIndex = itemPosition_.begin()->first;
727     if (!CheckDataChangeOutOfStart(index, count, startIndex)) {
728         return;
729     }
730 
731     count = std::max(count, index - startIndex);
732     int32_t mod = 0;
733     if (count < 0 && lanes_ > 1) {
734         mod = -count % lanes_;
735     }
736     auto prevPosMap = std::move(itemPosition_);
737     for (auto &pos : prevPosMap) {
738         if (mod > 0) {
739             mod--;
740         } else {
741             itemPosition_[pos.first + count] = pos.second;
742         }
743     }
744     if (layoutedItemInfo_ && layoutedItemInfo_.value().startIndex >= index) {
745         auto& info = layoutedItemInfo_.value();
746         info.startIndex = std::max(info.startIndex + count, 0);
747         info.endIndex = std::max(info.endIndex + count, 0);
748         if (lanes_ > 1) {
749             if (count < 0) {
750                 info.startIndex += -count % lanes_;
751             } else {
752                 info.endIndex -= count % lanes_;
753             }
754         }
755     }
756 }
757 } // namespace OHOS::Ace::NG
758