1 /*
2  * Copyright (c) 2024 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/waterflow/layout/water_flow_layout_algorithm_base.h"
17 
18 #include "core/components_ng/pattern/waterflow/water_flow_pattern.h"
19 
20 namespace OHOS::Ace::NG {
PreloadItems(LayoutWrapper * host,const RefPtr<WaterFlowLayoutInfoBase> & info,int32_t cacheCount)21 void WaterFlowLayoutBase::PreloadItems(
22     LayoutWrapper* host, const RefPtr<WaterFlowLayoutInfoBase>& info, int32_t cacheCount)
23 {
24     if (cacheCount <= 0) {
25         return;
26     }
27     auto frameNode = host->GetHostNode();
28     CHECK_NULL_VOID(frameNode);
29     auto pattern = frameNode->GetPattern<WaterFlowPattern>();
30     CHECK_NULL_VOID(pattern);
31     const bool taskRegistered = !pattern->PreloadListEmpty();
32     pattern->SetPreloadList(GeneratePreloadList(info, host, cacheCount, false));
33     if (pattern->PreloadListEmpty()) {
34         return;
35     }
36 
37     pattern->SetCacheLayoutAlgo(Claim(this));
38     if (taskRegistered) {
39         return;
40     }
41     PostIdleTask(frameNode);
42 }
43 
SyncPreloadItems(LayoutWrapper * host,const RefPtr<WaterFlowLayoutInfoBase> & info,int32_t cacheCount)44 void WaterFlowLayoutBase::SyncPreloadItems(
45     LayoutWrapper* host, const RefPtr<WaterFlowLayoutInfoBase>& info, int32_t cacheCount)
46 {
47     auto list = GeneratePreloadList(info, host, cacheCount, true);
48     if (list.empty()) {
49         return;
50     }
51 
52     StartCacheLayout();
53     for (auto&& item : list) {
54         SyncPreloadItem(host, item);
55     }
56     EndCacheLayout();
57 }
58 
GeneratePreloadList(const RefPtr<WaterFlowLayoutInfoBase> & info,LayoutWrapper * host,int32_t cacheCount,bool force)59 std::list<int32_t> WaterFlowLayoutBase::GeneratePreloadList(
60     const RefPtr<WaterFlowLayoutInfoBase>& info, LayoutWrapper* host, int32_t cacheCount, bool force)
61 {
62     std::list<int32_t> preloadList;
63     const int32_t endBound = std::min(info->ItemCnt(host->GetTotalChildCount()) - 1, info->endIndex_ + cacheCount);
64     for (int32_t i = info->endIndex_ + 1; i <= endBound; ++i) {
65         if (force || !host->GetChildByIndex(info->NodeIdx(i), true)) {
66             preloadList.emplace_back(i);
67         }
68     }
69 
70     const int32_t startBound = std::max(0, info->startIndex_ - cacheCount);
71     for (int32_t i = info->startIndex_ - 1; i >= startBound; --i) {
72         if (force || !host->GetChildByIndex(info->NodeIdx(i), true)) {
73             preloadList.emplace_back(i);
74         }
75     }
76     return preloadList;
77 }
78 
PostIdleTask(const RefPtr<FrameNode> & frameNode)79 void WaterFlowLayoutBase::PostIdleTask(const RefPtr<FrameNode>& frameNode)
80 {
81     auto* context = frameNode->GetContext();
82     CHECK_NULL_VOID(context);
83     context->AddPredictTask([weak = WeakPtr(frameNode)](int64_t deadline, bool canUseLongPredictTask) {
84         auto host = weak.Upgrade();
85         CHECK_NULL_VOID(host);
86         auto pattern = host->GetPattern<WaterFlowPattern>();
87         CHECK_NULL_VOID(pattern);
88 
89         auto&& algo = pattern->GetCacheLayoutAlgo();
90         CHECK_NULL_VOID(algo);
91         algo->StartCacheLayout();
92 
93         bool needMarkDirty = false;
94         auto items = pattern->MovePreloadList();
95         for (auto it = items.begin(); it != items.end(); ++it) {
96             if (GetSysTimestamp() > deadline) {
97                 pattern->SetPreloadList(std::list<int32_t>(it, items.end()));
98                 PostIdleTask(host);
99                 break;
100             }
101             ACE_SCOPED_TRACE("Preload FlowItem %d", *it);
102             ScopedLayout scope(host->GetContext());
103             needMarkDirty |= algo->PreloadItem(RawPtr(host), *it, deadline);
104         }
105         if (needMarkDirty) {
106             host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
107         }
108         algo->EndCacheLayout();
109     });
110 }
111 
GetUpdateIdx(LayoutWrapper * host,int32_t footerIdx)112 int32_t WaterFlowLayoutBase::GetUpdateIdx(LayoutWrapper* host, int32_t footerIdx)
113 {
114     int32_t updateIdx = host->GetHostNode()->GetChildrenUpdated();
115     if (updateIdx > 0 && footerIdx == 0) {
116         --updateIdx;
117     }
118     return updateIdx;
119 }
120 } // namespace OHOS::Ace::NG
121