• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2025 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/grid/grid_focus.h"
17 
18 #include "core/components_ng/base/frame_node.h"
19 #include "core/components_ng/pattern/grid/grid_item_pattern.h"
20 
21 namespace OHOS::Ace::NG {
IsFirstOrLastFocusableChild(int32_t curMainIndex,int32_t curCrossIndex)22 std::pair<bool, bool> GridFocus::IsFirstOrLastFocusableChild(int32_t curMainIndex, int32_t curCrossIndex)
23 {
24     std::unordered_set<int32_t> crossIndexSet;
25     size_t maxSize = 0;
26     for (int32_t index = curMainIndex - curFocusIndexInfo_.mainSpan + 1; index <= curMainIndex; index++) {
27         auto tempIndexSet = GetFocusableChildCrossIndexesAt(index);
28         if (tempIndexSet.size() > maxSize) {
29             maxSize = tempIndexSet.size();
30             crossIndexSet = tempIndexSet;
31         }
32     }
33     auto findLesser = std::find_if(crossIndexSet.begin(), crossIndexSet.end(),
34         [curCrossIndex](int32_t crossIndex) { return curCrossIndex > crossIndex; });
35     auto findGreater = std::find_if(crossIndexSet.begin(), crossIndexSet.end(),
36         [curCrossIndex](int32_t crossIndex) { return curCrossIndex < crossIndex; });
37     return { curCrossIndex == 0 || findLesser == crossIndexSet.end(),
38         curCrossIndex == info_.crossCount_ - 1 || findGreater == crossIndexSet.end() };
39 }
40 
GetFocusSteps(int32_t curMainIndex,int32_t curCrossIndex,FocusStep step)41 std::pair<FocusStep, FocusStep> GridFocus::GetFocusSteps(int32_t curMainIndex, int32_t curCrossIndex, FocusStep step)
42 {
43     auto firstStep = FocusStep::NONE;
44     auto secondStep = FocusStep::NONE;
45     auto isFirstOrLastFocusable = IsFirstOrLastFocusableChild(curMainIndex, curCrossIndex);
46     auto isFirstFocusable = isFirstOrLastFocusable.first;
47     auto isLastFocusable = isFirstOrLastFocusable.second;
48     auto focusWrapMode = GetFocusWrapMode();
49     if (info_.axis_ == Axis::VERTICAL) {
50         if (isFirstFocusable && (step == FocusStep::SHIFT_TAB ||
51             (focusWrapMode == FocusWrapMode::WRAP_WITH_ARROW && step == FocusStep::LEFT))) {
52             firstStep = FocusStep::UP;
53             secondStep = FocusStep::RIGHT_END;
54         } else if (isLastFocusable && (step == FocusStep::TAB || (focusWrapMode == FocusWrapMode::WRAP_WITH_ARROW &&
55             step == FocusStep::RIGHT))) {
56             firstStep = FocusStep::DOWN;
57             secondStep = FocusStep::LEFT_END;
58         }
59     } else if (info_.axis_ == Axis::HORIZONTAL) {
60         if (isFirstFocusable && (step == FocusStep::SHIFT_TAB ||
61             (focusWrapMode == FocusWrapMode::WRAP_WITH_ARROW && step == FocusStep::UP))) {
62             firstStep = FocusStep::LEFT;
63             secondStep = FocusStep::DOWN_END;
64         } else if (isLastFocusable && (step == FocusStep::TAB || (focusWrapMode == FocusWrapMode::WRAP_WITH_ARROW &&
65             step == FocusStep::DOWN))) {
66             firstStep = FocusStep::RIGHT;
67             secondStep = FocusStep::UP_END;
68         }
69     }
70     TAG_LOGI(AceLogTag::ACE_GRID, "Get focus steps. First step is %{public}d. Second step is %{public}d", firstStep,
71         secondStep);
72     return { firstStep, secondStep };
73 }
74 
GetFocusWrapMode()75 FocusWrapMode GridFocus::GetFocusWrapMode()
76 {
77     auto host = grid_.GetHost();
78     CHECK_NULL_RETURN(host, FocusWrapMode::DEFAULT);
79     auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
80     CHECK_NULL_RETURN(gridLayoutProperty, FocusWrapMode::DEFAULT);
81     return gridLayoutProperty->GetFocusWrapMode().value_or(FocusWrapMode::DEFAULT);
82 }
83 
GetNextFocusSimplified(FocusStep step,const RefPtr<FocusHub> & current)84 WeakPtr<FocusHub> GridFocus::GetNextFocusSimplified(FocusStep step, const RefPtr<FocusHub>& current)
85 {
86     CHECK_NULL_RETURN(current, nullptr);
87     auto host = grid_.GetHost();
88     CHECK_NULL_RETURN(host, nullptr);
89     auto* ctx = grid_.GetContext();
90     CHECK_NULL_RETURN(ctx, nullptr);
91 
92     int32_t diff = 0;
93     if (step == FocusStep::TAB) {
94         diff = 1;
95     } else if (step == FocusStep::SHIFT_TAB) {
96         diff = -1;
97     } else {
98         // not yet implemented
99         return nullptr;
100     }
101 
102     int32_t idx = host->GetChildTrueIndex(current->GetFrameNode()) + diff;
103     while (idx >= 0 && idx < info_.GetChildrenCount()) {
104         if (idx < info_.startIndex_ || idx > info_.endIndex_) {
105             grid_.ScrollToIndex(idx);
106             ctx->FlushUITaskWithSingleDirtyNode(host);
107         }
108         auto next = host->GetChildByIndex(idx);
109         CHECK_NULL_BREAK(next);
110         auto nextFocus = next->GetHostNode()->GetFocusHub();
111         if (nextFocus && nextFocus->IsFocusable()) {
112             return nextFocus;
113         }
114         idx += diff;
115     }
116     return nullptr;
117 }
118 
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode,bool isMainSkip)119 WeakPtr<FocusHub> GridFocus::GetNextFocusNode(
120     FocusStep step, const WeakPtr<FocusHub>& currentFocusNode, bool isMainSkip)
121 {
122     if (!isTab_) {
123         step = HandleDirectionStep(step);
124     }
125     if (!GetCurrentFocusInfo(step, currentFocusNode)) {
126         return nullptr;
127     }
128     auto focusSteps = GetFocusSteps(curFocusIndexInfo_.mainIndex, curFocusIndexInfo_.crossIndex, step);
129     if (focusSteps.first != FocusStep::NONE && focusSteps.second != FocusStep::NONE) {
130         return HandleFocusSteps(step, currentFocusNode, focusSteps);
131     }
132     ResetAllDirectionsStep();
133     auto indexes = GetNextIndexByStep(curFocusIndexInfo_.mainIndex, curFocusIndexInfo_.crossIndex,
134         curFocusIndexInfo_.mainSpan, curFocusIndexInfo_.crossSpan, step);
135     auto nextMainIndex = indexes.first;
136     auto nextCrossIndex = indexes.second;
137     while (nextMainIndex >= 0 && nextCrossIndex >= 0) {
138         if (info_.gridMatrix_.find(nextMainIndex) == info_.gridMatrix_.end()) {
139             TAG_LOGW(AceLogTag::ACE_GRID, "Can not find next main index: %{public}d", nextMainIndex);
140             return nullptr;
141         }
142         auto nextMaxCrossCount = info_.crossCount_;
143         auto flag = (step == FocusStep::LEFT_END) || (step == FocusStep::RIGHT_END);
144         auto nextMain = (step == FocusStep::RIGHT_END && curFocusIndexInfo_.mainSpan > 1)
145                             ? curFocusIndexInfo_.mainEnd
146                             : curFocusIndexInfo_.mainStart;
147         auto weakChild = info_.hasBigItem_
148                              ? (GetFocusWrapMode() == FocusWrapMode::WRAP_WITH_ARROW && CheckIsCrossDirectionFocus(step)
149                                        ? SearchBigItemFocusableChildInCross(
150                                            nextMain,
151                                            nextCrossIndex,
152                                            step,
153                                            isMainSkip)
154                                        : SearchIrregularFocusableChild(nextMainIndex, nextCrossIndex))
155                              : SearchFocusableChildInCross(nextMainIndex, nextCrossIndex, nextMaxCrossCount,
156                                  flag ? -1 : curFocusIndexInfo_.mainIndex,
157                                  curFocusIndexInfo_.crossIndex);
158         auto child = weakChild.Upgrade();
159         if (child && child->IsFocusable()) {
160             ScrollToFocusNode(weakChild);
161             return weakChild;
162         }
163         auto indexes = GetNextIndexByStep(nextMainIndex, nextCrossIndex, 1, 1, step);
164         nextMainIndex = indexes.first;
165         nextCrossIndex = indexes.second;
166     }
167     return nullptr;
168 }
169 
HandleDirectionStep(FocusStep step)170 FocusStep GridFocus::HandleDirectionStep(FocusStep step)
171 {
172     auto host = grid_.GetHost();
173     CHECK_NULL_RETURN(host, step);
174     auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
175     CHECK_NULL_RETURN(gridLayoutProperty, step);
176     bool isRtl = gridLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
177     if (isRtl) {
178         switch (step) {
179             case FocusStep::LEFT:
180                 step = FocusStep::RIGHT;
181                 break;
182             case FocusStep::RIGHT:
183                 step = FocusStep::LEFT;
184                 break;
185             default:
186                 break;
187         }
188     }
189     return step;
190 }
191 
GetCurrentFocusInfo(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)192 bool GridFocus::GetCurrentFocusInfo(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
193 {
194     auto curFocus = currentFocusNode.Upgrade();
195     CHECK_NULL_RETURN(curFocus, false);
196     auto curFrame = curFocus->GetFrameNode();
197     CHECK_NULL_RETURN(curFrame, false);
198     auto curPattern = curFrame->GetPattern();
199     CHECK_NULL_RETURN(curPattern, false);
200     auto curItemPattern = AceType::DynamicCast<GridItemPattern>(curPattern);
201     CHECK_NULL_RETURN(curItemPattern, false);
202     auto curItemProperty = curItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
203     CHECK_NULL_RETURN(curItemProperty, false);
204     auto irregularInfo = curItemPattern->GetIrregularItemInfo();
205     bool hasIrregularItemInfo = irregularInfo.has_value();
206 
207     auto curMainIndex = curItemProperty->GetMainIndex().value_or(-1);
208     auto curCrossIndex = curItemProperty->GetCrossIndex().value_or(-1);
209     auto curMainSpan =
210         hasIrregularItemInfo ? irregularInfo.value().mainSpan : curItemProperty->GetMainSpan(info_.axis_);
211     auto curCrossSpan =
212         hasIrregularItemInfo ? irregularInfo.value().crossSpan : curItemProperty->GetCrossSpan(info_.axis_);
213     auto curMainStart =
214         hasIrregularItemInfo ? irregularInfo.value().mainStart : curItemProperty->GetMainStart(info_.axis_);
215     auto curCrossStart =
216         hasIrregularItemInfo ? irregularInfo.value().crossStart : curItemProperty->GetCrossStart(info_.axis_);
217     auto curMainEnd = hasIrregularItemInfo ? irregularInfo.value().mainEnd : curItemProperty->GetMainEnd(info_.axis_);
218     auto curCrossEnd =
219         hasIrregularItemInfo ? irregularInfo.value().crossEnd : curItemProperty->GetCrossEnd(info_.axis_);
220 
221     curFocusIndexInfo_.mainIndex = curMainIndex;
222     curFocusIndexInfo_.crossIndex = curCrossIndex;
223     curFocusIndexInfo_.mainSpan = curMainSpan;
224     curFocusIndexInfo_.crossSpan = curCrossSpan;
225     curFocusIndexInfo_.mainStart = curMainStart;
226     curFocusIndexInfo_.mainEnd = curMainEnd;
227     curFocusIndexInfo_.crossStart = curCrossStart;
228     curFocusIndexInfo_.crossEnd = curCrossEnd;
229 
230     if (curMainIndex < 0 || curCrossIndex < 0) {
231         TAG_LOGW(AceLogTag::ACE_GRID, "can't find focused child.");
232         return false;
233     }
234     if (info_.gridMatrix_.find(curMainIndex) == info_.gridMatrix_.end()) {
235         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find current main index: %{public}d", curMainIndex);
236         return false;
237     }
238     TAG_LOGI(AceLogTag::ACE_GRID,
239         "GetNextFocusNode: Current:(%{public}d,%{public}d)-[%{public}d,%{public}d]. Focus: %{public}d", curMainIndex,
240         curCrossIndex, curMainSpan, curCrossSpan, step);
241 
242     return true;
243 }
244 
HandleFocusSteps(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode,std::pair<FocusStep,FocusStep> focusSteps)245 WeakPtr<FocusHub> GridFocus::HandleFocusSteps(
246     FocusStep step, const WeakPtr<FocusHub>& currentFocusNode, std::pair<FocusStep, FocusStep> focusSteps)
247 {
248     isTab_ = (step == FocusStep::TAB || step == FocusStep::SHIFT_TAB);
249     if (GetFocusWrapMode() == FocusWrapMode::WRAP_WITH_ARROW && curFocusIndexInfo_.mainSpan > 1 && !isTab_ &&
250         (info_.axis_ == Axis::VERTICAL ? (focusSteps.first == FocusStep::DOWN)
251                                        : (focusSteps.first == FocusStep::RIGHT))) {
252         auto secondStepRes = GetNextFocusNode(focusSteps.second, currentFocusNode, true);
253         if (!secondStepRes.Upgrade()) {
254             return currentFocusNode;
255         }
256         return secondStepRes;
257     } else {
258         auto firstStepRes = GetNextFocusNode(focusSteps.first, currentFocusNode);
259         if (!firstStepRes.Upgrade()) {
260             isTab_ = false;
261             return nullptr;
262         }
263         auto secondStepRes = GetNextFocusNode(focusSteps.second, firstStepRes);
264         if (!secondStepRes.Upgrade()) {
265             isTab_ = false;
266             return firstStepRes;
267         }
268         isTab_ = false;
269         return secondStepRes;
270     }
271 }
272 
CheckIsCrossDirectionFocus(FocusStep step)273 bool GridFocus::CheckIsCrossDirectionFocus(FocusStep step)
274 {
275     bool isVertical = (info_.axis_ == Axis::VERTICAL);
276 
277     bool isLeftOrRight = (step == FocusStep::LEFT) || (step == FocusStep::RIGHT) || (step == FocusStep::LEFT_END) ||
278                          (step == FocusStep::RIGHT_END);
279 
280     bool isUpOrDown = (step == FocusStep::UP) || (step == FocusStep::DOWN) || (step == FocusStep::UP_END) ||
281                       (step == FocusStep::DOWN_END);
282 
283     return !isTab_ && ((isVertical && isLeftOrRight) || (!isVertical && isUpOrDown));
284 }
285 
GetIndexByFocusHub(const WeakPtr<FocusHub> & focusNode)286 int32_t GridFocus::GetIndexByFocusHub(const WeakPtr<FocusHub>& focusNode)
287 {
288     auto focusHub = focusNode.Upgrade();
289     CHECK_NULL_RETURN(focusHub, -1);
290     auto node = focusHub->GetFrameNode();
291     CHECK_NULL_RETURN(node, -1);
292     auto property = AceType::DynamicCast<GridItemLayoutProperty>(node->GetLayoutProperty());
293     CHECK_NULL_RETURN(property, -1);
294     int32_t crossIndex = property->GetCrossIndex().value_or(-1);
295     int32_t mainIndex = property->GetMainIndex().value_or(-1);
296     return info_.FindInMatrixByMainIndexAndCrossIndex(mainIndex, crossIndex);
297 }
298 
GetNextIndexByStep(int32_t curMainIndex,int32_t curCrossIndex,int32_t curMainSpan,int32_t curCrossSpan,FocusStep step)299 std::pair<int32_t, int32_t> GridFocus::GetNextIndexByStep(
300     int32_t curMainIndex, int32_t curCrossIndex, int32_t curMainSpan, int32_t curCrossSpan, FocusStep step)
301 {
302     auto curMainStart = info_.startMainLineIndex_;
303     auto curMainEnd = info_.endMainLineIndex_;
304     auto curChildStartIndex = info_.startIndex_;
305     auto curChildEndIndex = info_.endIndex_;
306     auto childrenCount = info_.GetChildrenCount();
307     auto hasIrregularItems = info_.hasBigItem_;
308     if (info_.gridMatrix_.find(curMainIndex) == info_.gridMatrix_.end()) {
309         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find current main index: %{public}d", curMainIndex);
310         return { -1, -1 };
311     }
312     TAG_LOGI(AceLogTag::ACE_GRID,
313         "Current: (%{public}d,%{public}d)-[%{public}d,%{public}d]. axis: %{public}d, step: %{public}d", curMainIndex,
314         curCrossIndex, curMainSpan, curCrossSpan, info_.axis_, step);
315     auto curMaxCrossCount = info_.crossCount_;
316     auto nextMainIndex = curMainIndex;
317     auto nextCrossIndex = curCrossIndex;
318     if ((step == FocusStep::UP_END && info_.axis_ == Axis::HORIZONTAL) ||
319         (step == FocusStep::LEFT_END && info_.axis_ == Axis::VERTICAL)) {
320         nextMainIndex = curMainIndex;
321         nextCrossIndex = 0;
322         isLeftEndStep_ = hasIrregularItems ? true : false;
323     } else if ((step == FocusStep::DOWN_END && info_.axis_ == Axis::HORIZONTAL) ||
324                (step == FocusStep::RIGHT_END && info_.axis_ == Axis::VERTICAL)) {
325         nextMainIndex = curMainIndex;
326         nextCrossIndex = curMaxCrossCount - 1;
327         isRightEndStep_ = hasIrregularItems ? true : false;
328     } else if (((step == FocusStep::UP || step == FocusStep::SHIFT_TAB) && info_.axis_ == Axis::HORIZONTAL) ||
329                ((step == FocusStep::LEFT || step == FocusStep::SHIFT_TAB) && info_.axis_ == Axis::VERTICAL)) {
330         nextMainIndex = curMainIndex;
331         nextCrossIndex = curCrossIndex - 1;
332         isLeftStep_ = hasIrregularItems ? true : false;
333     } else if ((step == FocusStep::UP && info_.axis_ == Axis::VERTICAL) ||
334                (step == FocusStep::LEFT && info_.axis_ == Axis::HORIZONTAL)) {
335         nextMainIndex = hasIrregularItems ? curMainIndex - curMainSpan : curMainIndex - 1;
336         nextCrossIndex = curCrossIndex + static_cast<int32_t>((curCrossSpan - 1) / 2);
337         isUpStep_ = hasIrregularItems ? true : false;
338     } else if (((step == FocusStep::DOWN || step == FocusStep::TAB) && info_.axis_ == Axis::HORIZONTAL) ||
339                ((step == FocusStep::RIGHT || step == FocusStep::TAB) && info_.axis_ == Axis::VERTICAL)) {
340         nextMainIndex = curMainIndex;
341         nextCrossIndex = curCrossIndex + curCrossSpan;
342         isRightStep_ = hasIrregularItems ? true : false;
343     } else if ((step == FocusStep::DOWN && info_.axis_ == Axis::VERTICAL) ||
344                (step == FocusStep::RIGHT && info_.axis_ == Axis::HORIZONTAL)) {
345         nextMainIndex = hasIrregularItems ? curMainIndex + 1 : curMainIndex + curMainSpan;
346         nextCrossIndex = curCrossIndex + static_cast<int32_t>((curCrossSpan - 1) / 2);
347         isDownStep_ = hasIrregularItems ? true : false;
348     } else {
349         TAG_LOGW(
350             AceLogTag::ACE_GRID, "Next index return: Invalid step: %{public}d and axis: %{public}d", step, info_.axis_);
351         return { -1, -1 };
352     }
353     if (curChildStartIndex == 0 && curMainIndex == 0 && nextMainIndex < curMainIndex) {
354         nextMainIndex = curMainIndex;
355     }
356     if (curChildEndIndex == childrenCount - 1 && curMainIndex == curMainEnd && nextMainIndex > curMainIndex) {
357         nextMainIndex = curMainIndex;
358     }
359     if (nextMainIndex == curMainIndex && nextCrossIndex == curCrossIndex) {
360         TAG_LOGI(AceLogTag::ACE_GRID,
361             "Next index return: Move stoped. Next index: (%{public}d,%{public}d) is same as current.", nextMainIndex,
362             nextCrossIndex);
363         ResetAllDirectionsStep();
364         return { -1, -1 };
365     }
366     if (curChildStartIndex != 0 && curMainIndex == curMainStart && nextMainIndex < curMainIndex) {
367         // Scroll item up.
368         grid_.UpdateStartIndex(curChildStartIndex - 1);
369         auto* pipeline = grid_.GetContext();
370         if (pipeline) {
371             pipeline->FlushUITasks();
372         }
373     } else if (curChildEndIndex != childrenCount - 1 && curMainIndex == curMainEnd && nextMainIndex > curMainIndex) {
374         // Scroll item down.
375         grid_.UpdateStartIndex(curChildEndIndex + 1);
376         auto* pipeline = grid_.GetContext();
377         if (pipeline) {
378             pipeline->FlushUITasks();
379         }
380     }
381     curMainStart = info_.startMainLineIndex_;
382     curMainEnd = info_.endMainLineIndex_;
383     if (nextMainIndex < curMainStart || nextMainIndex > curMainEnd) {
384         ResetAllDirectionsStep();
385         return { -1, -1 };
386     }
387     if (nextCrossIndex < 0) {
388         ResetAllDirectionsStep();
389         return { -1, -1 };
390     }
391     if (info_.gridMatrix_.find(nextMainIndex) == info_.gridMatrix_.end()) {
392         ResetAllDirectionsStep();
393         return { -1, -1 };
394     }
395     auto nextMaxCrossCount = info_.crossCount_;
396     if (nextCrossIndex >= nextMaxCrossCount) {
397         TAG_LOGI(AceLogTag::ACE_GRID,
398             "Next index: { %{public}d,%{public}d }. Next cross index is greater than max cross count: %{public}d.",
399             nextMainIndex, nextCrossIndex, nextMaxCrossCount - 1);
400         if (nextMaxCrossCount - 1 != (curCrossIndex + curCrossSpan - 1)) {
401             TAG_LOGI(AceLogTag::ACE_GRID,
402                 "Current cross index: %{public}d is not the tail item. Return to the tail: { %{public}d,%{public}d }",
403                 curCrossIndex, nextMainIndex, nextMaxCrossCount - 1);
404             return { nextMainIndex, nextMaxCrossCount - 1 };
405         }
406         ResetAllDirectionsStep();
407         TAG_LOGI(AceLogTag::ACE_GRID, "Current cross index: %{public}d is the tail item. No next item can be found!",
408             curCrossIndex);
409         return { -1, -1 };
410     }
411     TAG_LOGI(AceLogTag::ACE_GRID, "Next index return: { %{public}d,%{public}d }.", nextMainIndex, nextCrossIndex);
412     return { nextMainIndex, nextCrossIndex };
413 }
414 
SearchBigItemFocusableChildInCross(int32_t curMainStart,int32_t tarCrossIndex,FocusStep step,bool isMainSkip)415 WeakPtr<FocusHub> GridFocus::SearchBigItemFocusableChildInCross(
416     int32_t curMainStart, int32_t tarCrossIndex, FocusStep step, bool isMainSkip)
417 {
418     auto host = grid_.GetHost();
419     CHECK_NULL_RETURN(host, nullptr);
420     if (isMainSkip) {
421         ++curMainStart;
422     }
423     auto main = info_.gridMatrix_.find(curMainStart);
424     while (main != info_.gridMatrix_.end()) {
425         auto cross = main->second.find(tarCrossIndex);
426         while (cross != main->second.end()) {
427             auto next = host->GetChildByIndex(cross->second);
428             CHECK_NULL_BREAK(next);
429             auto nextNode = next->GetHostNode();
430             CHECK_NULL_BREAK(nextNode);
431             auto nextFocus = nextNode->GetFocusHub();
432             if (nextFocus && nextFocus->IsFocusable()) {
433                 return nextFocus;
434             }
435             if (CheckStepDirection(step, false)) {
436                 tarCrossIndex--;
437             } else if (CheckStepDirection(step, true)) {
438                 tarCrossIndex++;
439             }
440             if (main->second.find(tarCrossIndex) == main->second.end()) {
441                 tarCrossIndex = main->second.size() - tarCrossIndex;
442                 break;
443             }
444             cross = main->second.find(tarCrossIndex);
445         }
446         if (CheckStepDirection(step, false)) {
447             curMainStart--;
448         } else if (CheckStepDirection(step, true)) {
449             curMainStart++;
450         }
451         if (info_.gridMatrix_.find(curMainStart) == info_.gridMatrix_.end()) {
452             break;
453         }
454         main = info_.gridMatrix_.find(curMainStart);
455     }
456     return nullptr;
457 }
458 
CheckStepDirection(FocusStep step,bool isNext)459 bool GridFocus::CheckStepDirection(FocusStep step, bool isNext)
460 {
461     if (info_.axis_ == Axis::VERTICAL) {
462         if (isNext) {
463             return step == FocusStep::LEFT_END || step == FocusStep::RIGHT;
464         } else {
465             return step == FocusStep::RIGHT_END || step == FocusStep::LEFT;
466         }
467     } else {
468         if (isNext) {
469             return step == FocusStep::UP_END || step == FocusStep::DOWN;
470         } else {
471             return step == FocusStep::DOWN_END || step == FocusStep::UP;
472         }
473     }
474 }
475 
SearchFocusableChildInCross(int32_t tarMainIndex,int32_t tarCrossIndex,int32_t maxCrossCount,int32_t curMainIndex,int32_t curCrossIndex)476 WeakPtr<FocusHub> GridFocus::SearchFocusableChildInCross(
477     int32_t tarMainIndex, int32_t tarCrossIndex, int32_t maxCrossCount, int32_t curMainIndex, int32_t curCrossIndex)
478 {
479     bool isDirectionLeft = true;
480     auto indexLeft = tarCrossIndex;
481     auto indexRight = tarCrossIndex;
482     if (curMainIndex == tarMainIndex) {
483         // Search on the same main index. Do not need search on both left and right side.
484         if (tarCrossIndex > curCrossIndex) {
485             // Only search on the right side.
486             indexLeft = -1;
487         } else if (tarCrossIndex < curCrossIndex) {
488             // Only search on the left side.
489             indexRight = maxCrossCount;
490         } else {
491             TAG_LOGW(AceLogTag::ACE_GRID, "Invalid search index: (%{public}d,%{public}d). It's same as current.",
492                 tarMainIndex, tarCrossIndex);
493             return nullptr;
494         }
495     }
496     while (indexLeft >= 0 || indexRight < maxCrossCount) {
497         int32_t curIndex = indexLeft;
498         if (indexLeft < 0) {
499             curIndex = indexRight++;
500         } else if (indexRight >= maxCrossCount) {
501             curIndex = indexLeft--;
502         } else {
503             curIndex = isDirectionLeft ? indexLeft-- : indexRight++;
504             isDirectionLeft = !isDirectionLeft;
505         }
506         auto weakChild = GetChildFocusNodeByIndex(tarMainIndex, curIndex);
507         auto child = weakChild.Upgrade();
508         if (child && child->IsFocusable()) {
509             TAG_LOGI(AceLogTag::ACE_GRID, "Found child. Index: %{public}d,%{public}d", tarMainIndex, curIndex);
510             return weakChild;
511         }
512     }
513     return nullptr;
514 }
515 
SearchIrregularFocusableChild(int32_t tarMainIndex,int32_t tarCrossIndex)516 WeakPtr<FocusHub> GridFocus::SearchIrregularFocusableChild(int32_t tarMainIndex, int32_t tarCrossIndex)
517 {
518     double minDistance = std::numeric_limits<double>::max();
519     int32_t minMainIndex = std::numeric_limits<int32_t>::max();
520     int32_t minCrossIndex = std::numeric_limits<int32_t>::max();
521     int32_t maxAreaInMainShadow = -1;
522     int32_t maxAreaInCrossShadow = -1;
523     WeakPtr<FocusHub> targetFocusHubWeak;
524 
525     auto gridFrame = grid_.GetHost();
526     CHECK_NULL_RETURN(gridFrame, nullptr);
527     auto gridFocus = gridFrame->GetFocusHub();
528     CHECK_NULL_RETURN(gridFocus, nullptr);
529     std::list<RefPtr<FocusHub>> childFocusList;
530     gridFocus->FlushChildrenFocusHub(childFocusList);
531     for (const auto& childFocus : childFocusList) {
532         if (!childFocus->IsFocusable()) {
533             continue;
534         }
535         auto childFrame = childFocus->GetFrameNode();
536         if (!childFrame) {
537             continue;
538         }
539         auto childPattern = childFrame->GetPattern<GridItemPattern>();
540         if (!childPattern) {
541             continue;
542         }
543         auto childItemProperty = childFrame->GetLayoutProperty<GridItemLayoutProperty>();
544         if (!childItemProperty) {
545             continue;
546         }
547         auto irregularInfo = childPattern->GetIrregularItemInfo();
548         bool hasIrregularItemInfo = irregularInfo.has_value();
549 
550         auto childMainIndex = childItemProperty->GetMainIndex().value_or(-1);
551         auto childCrossIndex = childItemProperty->GetCrossIndex().value_or(-1);
552         auto childMainStart =
553             hasIrregularItemInfo ? irregularInfo.value().mainStart : childItemProperty->GetMainStart(info_.axis_);
554         auto childMainEnd =
555             hasIrregularItemInfo ? irregularInfo.value().mainEnd : childItemProperty->GetMainEnd(info_.axis_);
556         auto chidCrossStart =
557             hasIrregularItemInfo ? irregularInfo.value().crossStart : childItemProperty->GetCrossStart(info_.axis_);
558         auto chidCrossEnd =
559             hasIrregularItemInfo ? irregularInfo.value().crossEnd : childItemProperty->GetCrossEnd(info_.axis_);
560         auto childCrossSpan =
561             hasIrregularItemInfo ? irregularInfo.value().crossSpan : childItemProperty->GetCrossSpan(info_.axis_);
562         auto childMainSpan =
563             hasIrregularItemInfo ? irregularInfo.value().mainSpan : childItemProperty->GetMainSpan(info_.axis_);
564 
565         GridItemIndexInfo childInfo;
566         childInfo.mainIndex = childMainIndex;
567         childInfo.crossIndex = childCrossIndex;
568         childInfo.mainStart = childMainStart;
569         childInfo.mainEnd = childMainEnd;
570         childInfo.crossStart = chidCrossStart;
571         childInfo.crossEnd = chidCrossEnd;
572 
573         if (childMainIndex < 0 || childCrossIndex < 0) {
574             continue;
575         }
576 
577         if ((isLeftStep_ && ((childCrossIndex == tarCrossIndex && childCrossSpan == 1) ||
578                                 (chidCrossEnd >= 0 && chidCrossEnd == tarCrossIndex))) ||
579             (isRightStep_ && childCrossIndex == tarCrossIndex)) {
580             double nearestDistance = GetNearestDistanceFromChildToCurFocusItemInMainAxis(tarCrossIndex, childInfo);
581             int32_t intersectAreaSize = CalcIntersectAreaInTargetDirectionShadow(childInfo, true);
582             if (LessNotEqual(nearestDistance, minDistance) ||
583                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize > maxAreaInCrossShadow) ||
584                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize == maxAreaInCrossShadow &&
585                     childMainIndex < minMainIndex)) {
586                 minDistance = nearestDistance;
587                 maxAreaInCrossShadow = intersectAreaSize;
588                 minMainIndex = childMainIndex;
589                 targetFocusHubWeak = AceType::WeakClaim(AceType::RawPtr(childFocus));
590             }
591         } else if ((isUpStep_ && childMainIndex == tarMainIndex) ||
592                    (isDownStep_ && ((childMainIndex == tarMainIndex && childMainSpan == 1) ||
593                                        (childMainStart >= 0 && childMainStart == tarMainIndex)))) {
594             double nearestDistance = GetNearestDistanceFromChildToCurFocusItemInCrossAxis(tarMainIndex, childInfo);
595             int32_t intersectAreaSize = CalcIntersectAreaInTargetDirectionShadow(childInfo, false);
596             if (LessNotEqual(nearestDistance, minDistance) ||
597                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize > maxAreaInMainShadow) ||
598                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize == maxAreaInMainShadow &&
599                     childCrossIndex < minCrossIndex)) {
600                 minDistance = nearestDistance;
601                 minCrossIndex = childCrossIndex;
602                 maxAreaInMainShadow = intersectAreaSize;
603                 targetFocusHubWeak = AceType::WeakClaim(AceType::RawPtr(childFocus));
604             }
605         } else if ((isLeftEndStep_ || isRightEndStep_) &&
606                    ((tarMainIndex == childMainIndex && tarCrossIndex == childCrossIndex) ||
607                        (childMainStart >= 0 && childMainStart <= tarMainIndex && tarMainIndex <= childMainIndex &&
608                            tarCrossIndex == childCrossIndex))) {
609             targetFocusHubWeak = AceType::WeakClaim(AceType::RawPtr(childFocus));
610         }
611     }
612     ResetAllDirectionsStep();
613     return targetFocusHubWeak;
614 }
615 
CalcIntersectAreaInTargetDirectionShadow(GridItemIndexInfo itemIndexInfo,bool isFindInMainAxis)616 int32_t GridFocus::CalcIntersectAreaInTargetDirectionShadow(GridItemIndexInfo itemIndexInfo, bool isFindInMainAxis)
617 {
618     int32_t curFocusLeftTopX = -1;
619     int32_t curFocusLeftTopY = -1;
620     int32_t curFocusRightBottonX = -1;
621     int32_t curFocusRightBottonY = -1;
622 
623     if (isFindInMainAxis) {
624         curFocusLeftTopX =
625             curFocusIndexInfo_.mainStart == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainStart;
626         curFocusLeftTopY = 0;
627         curFocusRightBottonX =
628             curFocusIndexInfo_.mainEnd == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainEnd;
629         curFocusRightBottonY = info_.crossCount_;
630     } else {
631         curFocusLeftTopX = info_.startMainLineIndex_;
632         curFocusLeftTopY =
633             curFocusIndexInfo_.crossStart == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossStart;
634         curFocusRightBottonX = info_.endMainLineIndex_;
635         curFocusRightBottonY =
636             curFocusIndexInfo_.crossEnd == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossEnd;
637     }
638     int32_t childLeftTopX = itemIndexInfo.mainStart == -1 ? itemIndexInfo.mainIndex : itemIndexInfo.mainStart;
639     int32_t childLeftTopY = itemIndexInfo.crossStart == -1 ? itemIndexInfo.crossIndex : itemIndexInfo.crossStart;
640     int32_t childRightBottonX = itemIndexInfo.mainEnd == -1 ? itemIndexInfo.mainIndex : itemIndexInfo.mainEnd;
641     int32_t childRightBottonY = itemIndexInfo.crossEnd == -1 ? itemIndexInfo.crossIndex : itemIndexInfo.crossEnd;
642 
643     int32_t intersectAreaLeftTopX = std::max(curFocusLeftTopX, childLeftTopX);
644     int32_t intersectAreaLeftTopY = std::max(curFocusLeftTopY, childLeftTopY);
645     int32_t intersectAreaRightBottonX = std::min(curFocusRightBottonX, childRightBottonX);
646     int32_t intersectAreaRightBottonY = std::min(curFocusRightBottonY, childRightBottonY);
647 
648     int32_t intersectWidth = intersectAreaRightBottonX - intersectAreaLeftTopX + 1;
649     int32_t intersectHeight = intersectAreaRightBottonY - intersectAreaLeftTopY + 1;
650 
651     return (intersectWidth < 0 || intersectHeight < 0) ? -1 : intersectWidth * intersectHeight;
652 }
653 
654 namespace {
CalcCoordinatesDistance(double curFocusMain,double curFocusCross,double childMain,double childCross)655 double CalcCoordinatesDistance(double curFocusMain, double curFocusCross, double childMain, double childCross)
656 {
657     return std::sqrt(std::pow((curFocusMain - childMain), 2) + std::pow((curFocusCross - childCross), 2));
658 }
659 } // namespace
660 
GetNearestDistanceFromChildToCurFocusItemInMainAxis(int32_t targetIndex,GridItemIndexInfo itemIndexInfo)661 double GridFocus::GetNearestDistanceFromChildToCurFocusItemInMainAxis(
662     int32_t targetIndex, GridItemIndexInfo itemIndexInfo)
663 {
664     double minDistance = std::numeric_limits<double>::max();
665     auto mainAxisIndex =
666         curFocusIndexInfo_.mainStart == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainStart;
667     auto mainAxisEndIndex =
668         curFocusIndexInfo_.mainEnd == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainEnd;
669     for (int32_t i = mainAxisIndex; i <= mainAxisEndIndex; i++) {
670         double childMainIndexDistance =
671             CalcCoordinatesDistance(i, curFocusIndexInfo_.crossIndex, itemIndexInfo.mainIndex, targetIndex);
672         double childMainStartDistance =
673             itemIndexInfo.mainStart == -1
674                 ? std::numeric_limits<double>::max()
675                 : CalcCoordinatesDistance(i, curFocusIndexInfo_.crossIndex, itemIndexInfo.mainStart, targetIndex);
676         double distance = std::min(childMainIndexDistance, childMainStartDistance);
677         if (LessNotEqual(distance, minDistance)) {
678             minDistance = distance;
679         }
680     }
681     return minDistance;
682 }
683 
GetNearestDistanceFromChildToCurFocusItemInCrossAxis(int32_t targetIndex,GridItemIndexInfo itemIndexInfo)684 double GridFocus::GetNearestDistanceFromChildToCurFocusItemInCrossAxis(
685     int32_t targetIndex, GridItemIndexInfo itemIndexInfo)
686 {
687     double minDistance = std::numeric_limits<double>::max();
688     auto crossAxisIndex =
689         curFocusIndexInfo_.crossStart == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossStart;
690     auto crossAxisEndIndex =
691         curFocusIndexInfo_.crossEnd == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossEnd;
692     for (int32_t i = crossAxisIndex; i <= crossAxisEndIndex; i++) {
693         double childCrossIndexDistance =
694             CalcCoordinatesDistance(curFocusIndexInfo_.mainIndex, i, targetIndex, itemIndexInfo.crossIndex);
695         double childCrossEndDistance =
696             itemIndexInfo.crossEnd == -1
697                 ? std::numeric_limits<double>::max()
698                 : CalcCoordinatesDistance(curFocusIndexInfo_.mainIndex, i, targetIndex, itemIndexInfo.crossEnd);
699         double distance = std::min(childCrossIndexDistance, childCrossEndDistance);
700         if (LessNotEqual(distance, minDistance)) {
701             minDistance = distance;
702         }
703     }
704     return minDistance;
705 }
706 
ResetAllDirectionsStep()707 void GridFocus::ResetAllDirectionsStep()
708 {
709     isLeftStep_ = false;
710     isRightStep_ = false;
711     isUpStep_ = false;
712     isDownStep_ = false;
713     isLeftEndStep_ = false;
714     isRightEndStep_ = false;
715 }
716 
GetChildFocusNodeByIndex(int32_t tarMainIndex,int32_t tarCrossIndex,int32_t tarIndex)717 WeakPtr<FocusHub> GridFocus::GetChildFocusNodeByIndex(int32_t tarMainIndex, int32_t tarCrossIndex, int32_t tarIndex)
718 {
719     auto gridFrame = grid_.GetHost();
720     CHECK_NULL_RETURN(gridFrame, nullptr);
721     auto gridFocus = gridFrame->GetFocusHub();
722     CHECK_NULL_RETURN(gridFocus, nullptr);
723     std::list<RefPtr<FocusHub>> childFocusList;
724     gridFocus->FlushChildrenFocusHub(childFocusList);
725     for (const auto& childFocus : childFocusList) {
726         auto childFrame = childFocus->GetFrameNode();
727         if (!childFrame) {
728             continue;
729         }
730         auto childPattern = childFrame->GetPattern();
731         if (!childPattern) {
732             continue;
733         }
734         auto childItemPattern = AceType::DynamicCast<GridItemPattern>(childPattern);
735         if (!childItemPattern) {
736             continue;
737         }
738         auto childItemProperty = childItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
739         if (!childItemProperty) {
740             continue;
741         }
742         auto curMainIndex = childItemProperty->GetMainIndex().value_or(-1);
743         auto curCrossIndex = childItemProperty->GetCrossIndex().value_or(-1);
744         if (tarIndex < 0) {
745             auto curMainSpan = childItemProperty->GetMainSpan(info_.axis_);
746             auto curCrossSpan = childItemProperty->GetCrossSpan(info_.axis_);
747             if (curMainIndex <= tarMainIndex && curMainIndex + curMainSpan > tarMainIndex &&
748                 curCrossIndex <= tarCrossIndex && curCrossIndex + curCrossSpan > tarCrossIndex) {
749                 return AceType::WeakClaim(AceType::RawPtr(childFocus));
750             }
751         } else {
752             auto row = info_.gridMatrix_.find(curMainIndex);
753             if (row == info_.gridMatrix_.end()) {
754                 TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target main index: %{public}d", curMainIndex);
755                 continue;
756             }
757             auto cell = row->second.find(curCrossIndex);
758             if (cell == row->second.end()) {
759                 TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target cross index: %{public}d", curCrossIndex);
760                 continue;
761             }
762             if (cell->second == tarIndex) {
763                 return AceType::WeakClaim(AceType::RawPtr(childFocus));
764             }
765         }
766     }
767     return nullptr;
768 }
769 
GetFocusableChildCrossIndexesAt(int32_t tarMainIndex)770 std::unordered_set<int32_t> GridFocus::GetFocusableChildCrossIndexesAt(int32_t tarMainIndex)
771 {
772     std::unordered_set<int32_t> result;
773     auto gridFrame = grid_.GetHost();
774     CHECK_NULL_RETURN(gridFrame, result);
775     auto gridFocus = gridFrame->GetFocusHub();
776     CHECK_NULL_RETURN(gridFocus, result);
777     std::list<RefPtr<FocusHub>> childFocusList;
778     gridFocus->FlushChildrenFocusHub(childFocusList);
779     for (const auto& childFocus : childFocusList) {
780         if (!childFocus->IsFocusable()) {
781             continue;
782         }
783         auto childFrame = childFocus->GetFrameNode();
784         if (!childFrame) {
785             continue;
786         }
787         auto childPattern = childFrame->GetPattern();
788         if (!childPattern) {
789             continue;
790         }
791         auto childItemPattern = AceType::DynamicCast<GridItemPattern>(childPattern);
792         if (!childItemPattern) {
793             continue;
794         }
795         auto childItemProperty = childItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
796         if (!childItemProperty) {
797             continue;
798         }
799         auto irregularInfo = childItemPattern->GetIrregularItemInfo();
800         bool hasIrregularItemInfo = irregularInfo.has_value();
801         auto curMainIndex = childItemProperty->GetMainIndex().value_or(-1);
802         auto curCrossIndex = childItemProperty->GetCrossIndex().value_or(-1);
803         auto curMainStart =
804             hasIrregularItemInfo ? irregularInfo.value().mainStart : childItemProperty->GetMainStart(info_.axis_);
805         auto curMainEnd =
806             hasIrregularItemInfo ? irregularInfo.value().mainEnd : childItemProperty->GetMainEnd(info_.axis_);
807         if ((curMainIndex == tarMainIndex) ||
808             (curMainStart >= 0 && curMainStart <= tarMainIndex && tarMainIndex <= curMainEnd)) {
809             result.emplace(curCrossIndex);
810         }
811     }
812     std::string output;
813     for (const auto& index : result) {
814         output += std::to_string(index);
815     }
816     return result;
817 }
818 
GetFocusNodeIndex(const RefPtr<FocusHub> & focusNode)819 int32_t GridFocus::GetFocusNodeIndex(const RefPtr<FocusHub>& focusNode)
820 {
821     auto tarFrame = focusNode->GetFrameNode();
822     CHECK_NULL_RETURN(tarFrame, -1);
823     auto tarPattern = tarFrame->GetPattern();
824     CHECK_NULL_RETURN(tarPattern, -1);
825     auto tarItemPattern = AceType::DynamicCast<GridItemPattern>(tarPattern);
826     CHECK_NULL_RETURN(tarItemPattern, -1);
827     auto tarItemProperty = tarItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
828     CHECK_NULL_RETURN(tarItemProperty, -1);
829     auto tarMainIndex = tarItemProperty->GetMainIndex().value_or(-1);
830     auto tarCrossIndex = tarItemProperty->GetCrossIndex().value_or(-1);
831     auto it = info_.gridMatrix_.find(tarMainIndex);
832     if (it == info_.gridMatrix_.end()) {
833         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target main index: %{public}d", tarMainIndex);
834         if (tarMainIndex == 0) {
835             return 0;
836         }
837         return info_.GetChildrenCount() - 1;
838     }
839     auto cell = it->second.find(tarCrossIndex);
840     if (cell == it->second.end()) {
841         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target cross index: %{public}d", tarCrossIndex);
842         if (tarMainIndex == 0) {
843             return 0;
844         }
845         return info_.GetChildrenCount() - 1;
846     }
847     return cell->second;
848 }
849 
ProcessFocusEvent(const KeyEvent & event,bool indexChanged)850 void GridFocus::ProcessFocusEvent(const KeyEvent& event, bool indexChanged)
851 {
852     auto host = grid_.GetHost();
853     CHECK_NULL_VOID(host);
854     auto focusHub = host->GetFocusHub();
855     CHECK_NULL_VOID(focusHub);
856     CHECK_NULL_VOID(focusHub->IsCurrentFocus());
857     if (needTriggerFocus_) {
858         if (triggerFocus_) {
859             needTriggerFocus_ = false;
860             triggerFocus_ = false;
861             focusHub->GetNextFocusByStep(event);
862         } else {
863             if (!focusIndex_.has_value()) {
864                 needTriggerFocus_ = false;
865                 return;
866             }
867             triggerFocus_ = true;
868             auto child = host->GetOrCreateChildByIndex(focusIndex_.value());
869             CHECK_NULL_VOID(child);
870             auto childNode = child->GetHostNode();
871             auto childFocusHub = childNode->GetFocusHub();
872             if (childFocusHub && !childFocusHub->IsCurrentFocus()) {
873                 childFocusHub->RequestFocusImmediately();
874             }
875             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
876         }
877         return;
878     }
879     if (indexChanged && focusIndex_.has_value()) {
880         FireFocus();
881     }
882 }
883 
FireFocus()884 void GridFocus::FireFocus()
885 {
886     auto host = grid_.GetHost();
887     CHECK_NULL_VOID(host);
888     auto* pipeline = grid_.GetContext();
889     CHECK_NULL_VOID(pipeline);
890     auto focusHub = host->GetFocusHub();
891     CHECK_NULL_VOID(focusHub);
892     CHECK_NULL_VOID(focusHub->IsCurrentFocus());
893     CHECK_NULL_VOID(focusIndex_.has_value());
894     if (IsInViewport(focusIndex_.value(), true)) {
895         auto child = host->GetChildByIndex(focusIndex_.value());
896         CHECK_NULL_VOID(child);
897         auto childNode = child->GetHostNode();
898         CHECK_NULL_VOID(childNode);
899         auto childFocusHub = childNode->GetFocusHub();
900         CHECK_NULL_VOID(childFocusHub);
901         if (!childFocusHub->IsCurrentFocus()) {
902             focusHub->SetFocusDependence(FocusDependence::AUTO);
903             childFocusHub->RequestFocusImmediately();
904             TAG_LOGI(
905                 AceLogTag::ACE_GRID, "GridItem [%{public}d] scroll into viewport, Requests focus", focusIndex_.value());
906         }
907     } else {
908         auto childFocusHub = focusHub->GetLastWeakFocusNode().Upgrade();
909         CHECK_NULL_VOID(childFocusHub);
910         if (childFocusHub->IsCurrentFocus()) {
911             focusHub->LostChildFocusToSelf();
912         }
913     }
914 }
915 
ScrollToLastFocusIndex(KeyCode keyCode)916 bool GridFocus::ScrollToLastFocusIndex(KeyCode keyCode)
917 {
918     auto* pipeline = grid_.GetContext();
919     CHECK_NULL_RETURN(pipeline, false);
920     CHECK_NULL_RETURN(pipeline->GetIsFocusActive(), false);
921     auto host = grid_.GetHost();
922     CHECK_NULL_RETURN(host, false);
923     auto focusHub = host->GetFocusHub();
924     CHECK_NULL_RETURN(focusHub, false);
925     CHECK_NULL_RETURN(focusHub->IsCurrentFocus(), false);
926     CHECK_NULL_RETURN(focusIndex_.has_value(), false);
927     auto focusIndex = focusIndex_.value();
928     if (!IsInViewport(focusIndex, false)) {
929         grid_.StopAnimate();
930         needTriggerFocus_ = true;
931 
932         // If focused item is above viewport and the current keyCode type is UP, scroll forward one more line
933         if (focusIndex < info_.startIndex_ && keyCode == KeyCode::KEY_DPAD_UP && focusIndex - info_.crossCount_ >= 0) {
934             grid_.UpdateStartIndex(focusIndex - info_.crossCount_);
935             // If focused item is below viewport and the current keyCode type is DOWN, scroll backward one more line
936         } else if (focusIndex > info_.endIndex_ && keyCode == KeyCode::KEY_DPAD_DOWN &&
937                    focusIndex + info_.crossCount_ < info_.GetChildrenCount()) {
938             grid_.UpdateStartIndex(focusIndex + info_.crossCount_);
939         } else {
940             grid_.UpdateStartIndex(focusIndex);
941         }
942         return true;
943     }
944     return false;
945 }
946 
ScrollToFocusNode(const WeakPtr<FocusHub> & focusNode)947 void GridFocus::ScrollToFocusNode(const WeakPtr<FocusHub>& focusNode)
948 {
949     grid_.StopAnimate();
950     auto nextFocus = focusNode.Upgrade();
951     CHECK_NULL_VOID(nextFocus);
952     grid_.UpdateStartIndex(GetFocusNodeIndex(nextFocus));
953 }
954 
IsInViewport(int32_t index,bool needCheckCache) const955 bool GridFocus::IsInViewport(int32_t index, bool needCheckCache) const
956 {
957     auto host = grid_.GetHost();
958     CHECK_NULL_RETURN(host, true);
959     auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
960     CHECK_NULL_RETURN(gridLayoutProperty, true);
961     int32_t cacheCount = gridLayoutProperty->GetCachedCountValue(info_.defCachedCount_) * info_.crossCount_;
962     bool showCachedItems = gridLayoutProperty->GetShowCachedItemsValue(false);
963     if (needCheckCache && showCachedItems) {
964         return index >= info_.startIndex_ - cacheCount && index <= info_.endIndex_ + cacheCount;
965     }
966     return index >= info_.startIndex_ && index <= info_.endIndex_;
967 }
968 } // namespace OHOS::Ace::NG