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