1 /*
2  * Copyright (c) 2021 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 #define AVERAGE_BASE 2
17 
18 #include "core/accessibility/accessibility_utils.h"
19 
20 namespace OHOS::Ace {
21 
22 const char ACCESSIBILITY_TAG_DIV[] = "div";
23 const char ACCESSIBILITY_TAG_CALENDAR[] = "calendar";
24 const char ACCESSIBILITY_TAG_TEXT[] = "text";
25 const char ACCESSIBILITY_TAG_PICKER[] = "picker";
26 const char ACCESSIBILITY_TAG_OPTION[] = "option";
27 const char ACCESSIBILITY_TAG_POPUP[] = "popup";
28 const char ACCESSIBILITY_TAG_PROGRESS[] = "progress";
29 const char ACCESSIBILITY_TAG_SELECT[] = "select";
30 const char ACCESSIBILITY_TAG_MENU[] = "menu";
31 const char ACCESSIBILITY_TAG_SLIDER[] = "slider";
32 const char ACCESSIBILITY_TAG_SPAN[] = "span";
33 const char ACCESSIBILITY_TAG_STACK[] = "stack";
34 const char ACCESSIBILITY_TAG_SWIPER[] = "swiper";
35 const char ACCESSIBILITY_TAG_SWITCH[] = "switch";
36 const char ACCESSIBILITY_TAG_TABS[] = "tabs";
37 const char ACCESSIBILITY_TAG_TAB_BAR[] = "tab-bar";
38 const char ACCESSIBILITY_TAG_TAB_CONTENT[] = "tab-content";
39 const char ACCESSIBILITY_TAG_REFRESH[] = "refresh";
40 const char ACCESSIBILITY_TAG_IMAGE[] = "image";
41 const char ACCESSIBILITY_TAG_LIST[] = "list";
42 const char ACCESSIBILITY_TAG_LIST_ITEM[] = "list-item";
43 const char ACCESSIBILITY_TAG_LIST_ITEM_GROUP[] = "list-item-group";
44 const char ACCESSIBILITY_TAG_VIDEO[] = "video";
45 const char ACCESSIBILITY_TAG_RATING[] = "rating";
46 const char ACCESSIBILITY_TAG_MARQUEE[] = "marquee";
47 const char ACCESSIBILITY_TAG_NAVIGATION_BAR[] = "navigation-bar";
48 const char ACCESSIBILITY_TAG_NAVIGATION_MENU[] = "navigation-menu";
49 const char ACCESSIBILITY_TAG_TEXTAREA[] = "textarea";
50 const char ACCESSIBILITY_TAG_INPUT[] = "input";
51 const char ACCESSIBILITY_TAG_LABEL[] = "label";
52 const char ACCESSIBILITY_TAG_DIVIDER[] = "divider";
53 const char ACCESSIBILITY_TAG_CANVAS[] = "canvas";
54 const char ACCESSIBILITY_TAG_BUTTON[] = "button";
55 const char ACCESSIBILITY_TAG_CHART[] = "chart";
56 const char ACCESSIBILITY_TAG_CLOCK[] = "clock";
57 const char ACCESSIBILITY_TAG_DIALOG[] = "dialog";
58 const char ACCESSIBILITY_TAG_SEARCH[] = "search";
59 
60 const int32_t WEIGHTED_VALUE = 13;
61 const int32_t FOCUS_DIRECTION_UP = 1;
62 const int32_t FOCUS_DIRECTION_DOWN = 1 << 1;
63 const int32_t FOCUS_DIRECTION_LEFT = 1 << 2;
64 const int32_t FOCUS_DIRECTION_RIGHT = 1 << 3;
65 const int32_t FOCUS_DIRECTION_FORWARD = 1 << 4;
66 const int32_t FOCUS_DIRECTION_BACKWARD = 1 << 5;
67 
CheckRectBeam(const Rect & nodeRect,const Rect & itemRect,const int direction)68 static bool CheckRectBeam(const Rect& nodeRect, const Rect& itemRect, const int direction)
69 {
70     switch (direction) {
71         case FOCUS_DIRECTION_LEFT:
72         case FOCUS_DIRECTION_RIGHT:
73             return nodeRect.Top() < itemRect.Bottom() && itemRect.Top() < nodeRect.Bottom();
74         case FOCUS_DIRECTION_UP:
75         case FOCUS_DIRECTION_DOWN:
76             return nodeRect.Left() < itemRect.Right() && itemRect.Left() < nodeRect.Right();
77         default:
78             break;
79     }
80     return false;
81 }
82 
IsToDirectionOf(const Rect & nodeRect,const Rect & itemRect,const int direction)83 static bool IsToDirectionOf(const Rect& nodeRect, const Rect& itemRect, const int direction)
84 {
85     switch (direction) {
86         case FOCUS_DIRECTION_LEFT:
87             return nodeRect.Left() >= itemRect.Right();
88         case FOCUS_DIRECTION_RIGHT:
89             return nodeRect.Right() <= itemRect.Left();
90         case FOCUS_DIRECTION_UP:
91             return nodeRect.Top() >= itemRect.Bottom();
92         case FOCUS_DIRECTION_DOWN:
93             return nodeRect.Bottom() <= itemRect.Top();
94         default:
95             break;
96     }
97     return false;
98 }
99 
MajorAxisDistanceToFarEdge(const Rect & nodeRect,const Rect & itemRect,const int direction)100 static double MajorAxisDistanceToFarEdge(const Rect& nodeRect, const Rect& itemRect, const int direction)
101 {
102     double distance = 0.0;
103     switch (direction) {
104         case FOCUS_DIRECTION_LEFT:
105             distance = nodeRect.Left() - itemRect.Left();
106             break;
107         case FOCUS_DIRECTION_RIGHT:
108             distance = itemRect.Right() - nodeRect.Right();
109             break;
110         case FOCUS_DIRECTION_UP:
111             distance = nodeRect.Top() - itemRect.Top();
112             break;
113         case FOCUS_DIRECTION_DOWN:
114             distance = itemRect.Bottom() - nodeRect.Bottom();
115             break;
116         default:
117             break;
118     }
119 
120     return distance > 1.0 ? distance : 1.0;
121 }
122 
MajorAxisDistance(const Rect & nodeRect,const Rect & itemRect,const int direction)123 static double MajorAxisDistance(const Rect& nodeRect, const Rect& itemRect, const int direction)
124 {
125     double distance = 0.0;
126     switch (direction) {
127         case FOCUS_DIRECTION_LEFT:
128             distance = nodeRect.Left() - itemRect.Right();
129             break;
130         case FOCUS_DIRECTION_RIGHT:
131             distance = itemRect.Left() - nodeRect.Right();
132             break;
133         case FOCUS_DIRECTION_UP:
134             distance = nodeRect.Top() - itemRect.Bottom();
135             break;
136         case FOCUS_DIRECTION_DOWN:
137             distance = itemRect.Top() - nodeRect.Bottom();
138             break;
139         default:
140             break;
141     }
142 
143     return distance > 0.0 ? distance : 0.0;
144 }
145 
MinorAxisDistance(const Rect & nodeRect,const Rect & itemRect,const int direction)146 static double MinorAxisDistance(const Rect& nodeRect, const Rect& itemRect, const int direction)
147 {
148     double distance = 0.0;
149     switch (direction) {
150         case FOCUS_DIRECTION_LEFT:
151         case FOCUS_DIRECTION_RIGHT:
152             distance = fabs((nodeRect.Top() + nodeRect.Bottom()) / AVERAGE_BASE -
153                 (itemRect.Top() + itemRect.Bottom()) / AVERAGE_BASE);
154             break;
155         case FOCUS_DIRECTION_UP:
156         case FOCUS_DIRECTION_DOWN:
157             distance = fabs((nodeRect.Left() + nodeRect.Right()) / AVERAGE_BASE -
158                 (itemRect.Left() + itemRect.Right()) / AVERAGE_BASE);
159             break;
160         default:
161             break;
162     }
163 
164     return distance > 0.0 ? distance : -distance;
165 }
166 
GetWeightedDistanceFor(double majorAxisDistance,double minorAxisDistance)167 static double GetWeightedDistanceFor(double majorAxisDistance, double minorAxisDistance)
168 {
169     return WEIGHTED_VALUE * majorAxisDistance * majorAxisDistance + minorAxisDistance * minorAxisDistance;
170 }
171 
IsCandidateRect(const Rect & nodeRect,const Rect & itemRect,const int direction)172 static bool IsCandidateRect(const Rect& nodeRect, const Rect& itemRect, const int direction)
173 {
174     switch (direction) {
175         case FOCUS_DIRECTION_LEFT:
176             return nodeRect.Left() > itemRect.Left() && nodeRect.Right() > itemRect.Right();
177         case FOCUS_DIRECTION_RIGHT:
178             return nodeRect.Left() < itemRect.Left() && nodeRect.Right() < itemRect.Right();
179         case FOCUS_DIRECTION_UP:
180             return nodeRect.Top() > itemRect.Top() && nodeRect.Bottom() > itemRect.Bottom();
181         case FOCUS_DIRECTION_DOWN:
182             return nodeRect.Top() < itemRect.Top() && nodeRect.Bottom() < itemRect.Bottom();
183         default:
184             break;
185     }
186     return false;
187 }
188 
189 // Check whether rect1 is outright better than rect2.
OutrightBetter(const Rect & nodeRect,const int direction,const Rect & Rect1,const Rect & Rect2)190 static bool OutrightBetter(const Rect& nodeRect, const int direction, const Rect& Rect1, const Rect& Rect2)
191 {
192     bool rect1InSrcBeam = CheckRectBeam(nodeRect, Rect1, direction);
193     bool rect2InSrcBeam = CheckRectBeam(nodeRect, Rect2, direction);
194     if (rect2InSrcBeam || !rect1InSrcBeam) {
195         return false;
196     }
197 
198     if (!IsToDirectionOf(nodeRect, Rect2, direction)) {
199         return true;
200     }
201 
202     // for direction left or right
203     if (direction == FOCUS_DIRECTION_LEFT || direction == FOCUS_DIRECTION_RIGHT) {
204         return true;
205     }
206 
207     return (MajorAxisDistance(nodeRect, Rect1, direction) < MajorAxisDistanceToFarEdge(nodeRect, Rect2, direction));
208 }
209 
CheckBetterRect(const Rect & nodeRect,const int direction,const Rect & itemRect,const Rect & tempBest)210 bool CheckBetterRect(const Rect& nodeRect, const int direction, const Rect& itemRect, const Rect& tempBest)
211 {
212     if (!IsCandidateRect(nodeRect, itemRect, direction)) {
213         return false;
214     }
215 
216     if (!IsCandidateRect(nodeRect, tempBest, direction)) {
217         return true;
218     }
219 
220     // now both of item and tempBest are all at the direction of node.
221     if (OutrightBetter(nodeRect, direction, itemRect, tempBest)) {
222         return true;
223     }
224 
225     if (OutrightBetter(nodeRect, direction, tempBest, itemRect)) {
226         return false;
227     }
228 
229     // otherwise, do fudge-tastic comparison of the major and minor axis
230     return (GetWeightedDistanceFor(
231                 MajorAxisDistance(nodeRect, itemRect, direction), MinorAxisDistance(nodeRect, itemRect, direction)) <
232             GetWeightedDistanceFor(
233                 MajorAxisDistance(nodeRect, tempBest, direction), MinorAxisDistance(nodeRect, tempBest, direction)));
234 }
235 
236 }  // namespace OHOS::Ace
237