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 "bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h"
17 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
18 #include "core/components_ng/base/view_abstract_model_ng.h"
19 #include "frameworks/base/log/ace_scoring_log.h"
20 #include "bridge/declarative_frontend/jsview/js_accessibility.h"
21
22 namespace OHOS::Ace::Framework {
23 namespace {
24 const std::unordered_map<AccessibilityRoleType, std::string> accessibilityRoleMap {
25 { AccessibilityRoleType::ACTION_SHEET, "actionsheet" }, { AccessibilityRoleType::ALERT_DIALOG, "alertdialog" },
26 { AccessibilityRoleType::INDEXER_COMPONENT, "alphabetindexer" },
27 { AccessibilityRoleType::BADGE_COMPONENT, "badge" }, { AccessibilityRoleType::BLANK, "blank" },
28 { AccessibilityRoleType::BUTTON, "button" }, { AccessibilityRoleType::BACK_BUTTON, "backbutton" },
29 { AccessibilityRoleType::SHEET_DRAG_BAR, "sheetdragbar" },
30 { AccessibilityRoleType::CALENDAR_PICKER, "calendarpicker" }, { AccessibilityRoleType::CALENDAR, "calendar" },
31 { AccessibilityRoleType::CANVAS, "canvas" }, { AccessibilityRoleType::CANVAS_GRADIENT, "canvasgradient" },
32 { AccessibilityRoleType::CANVAS_PATTERN, "canvaspattern" }, { AccessibilityRoleType::CHECKBOX, "checkbox" },
33 { AccessibilityRoleType::CHECKBOX_GROUP, "checkboxgroup" }, { AccessibilityRoleType::CIRCLE, "circle" },
34 { AccessibilityRoleType::COLUMN_SPLIT, "columnsplit" }, { AccessibilityRoleType::COLUMN, "column" },
35 { AccessibilityRoleType::CANVAS_RENDERING_CONTEXT_2D, "canvasrenderingcontext2d" },
36 { AccessibilityRoleType::CHART, "chart" }, { AccessibilityRoleType::COUNTER, "counter" },
37 { AccessibilityRoleType::CONTAINER_MODAL, "containermodal" }, { AccessibilityRoleType::DATA_PANEL, "datapanel" },
38 { AccessibilityRoleType::DATE_PICKER, "datepicker" }, { AccessibilityRoleType::DIALOG, "dialog" },
39 { AccessibilityRoleType::DIVIDER, "divider" }, { AccessibilityRoleType::DRAG_BAR, "dragbar" },
40 { AccessibilityRoleType::EFFECT_COMPONENT, "effectcomponent" }, { AccessibilityRoleType::ELLIPSE, "ellipse" },
41 { AccessibilityRoleType::FLEX, "flex" }, { AccessibilityRoleType::FLOW_ITEM, "flowitem" },
42 { AccessibilityRoleType::FORM_COMPONENT, "formcomponent" }, { AccessibilityRoleType::FORM_LINK, "formlink" },
43 { AccessibilityRoleType::GAUGE, "gauge" }, { AccessibilityRoleType::GRID, "grid" },
44 { AccessibilityRoleType::GRID_COL, "gridcol" }, { AccessibilityRoleType::GRID_CONTAINER, "gridcontainer" },
45 { AccessibilityRoleType::GRID_ITEM, "griditem" }, { AccessibilityRoleType::GRID_ROW, "grid-row" },
46 { AccessibilityRoleType::HYPERLINK, "hyperlink" }, { AccessibilityRoleType::IMAGE, "image" },
47 { AccessibilityRoleType::IMAGE_ANIMATOR, "imageanimator" },
48 { AccessibilityRoleType::ROLE_IMAGE_BITMAP, "imagebitmap" }, { AccessibilityRoleType::IMAGE_DATA, "imagedata" },
49 { AccessibilityRoleType::IMAGE_SPAN, "imagespan" }, { AccessibilityRoleType::LABEL, "label" },
50 { AccessibilityRoleType::LINE, "line" }, { AccessibilityRoleType::LIST, "list" },
51 { AccessibilityRoleType::LIST_ITEM, "listitem" }, { AccessibilityRoleType::LIST_ITEM_GROUP, "listitemgroup" },
52 { AccessibilityRoleType::LOADING_PROGRESS, "loadingprogress" }, { AccessibilityRoleType::MARQUEE, "marquee" },
53 { AccessibilityRoleType::MATRIX2D, "matrix2d" }, { AccessibilityRoleType::MENU, "menu" },
54 { AccessibilityRoleType::MENU_ITEM, "menuitem" }, { AccessibilityRoleType::MENU_ITEM_GROUP, "menuitemgroup" },
55 { AccessibilityRoleType::NAV_DESTINATION, "navdestination" }, { AccessibilityRoleType::NAV_ROUTER, "navrouter" },
56 { AccessibilityRoleType::NAVIGATION, "navigation" }, { AccessibilityRoleType::NAVIGATION_BAR, "navigation-bar" },
57 { AccessibilityRoleType::NAVIGATION_MENU, "navigation-menu" }, { AccessibilityRoleType::NAVIGATOR, "navigator" },
58 { AccessibilityRoleType::OFFSCREEN_CANVAS, "offscreencanvas" },
59 { AccessibilityRoleType::OFFSCREEN_CANVAS_RENDERING_CONTEXT2D, "offscreencanvasrenderingcontext2d" },
60 { AccessibilityRoleType::OPTION, "option" }, { AccessibilityRoleType::PANEL, "panel" },
61 { AccessibilityRoleType::PAPER_PAGE, "paperpage" }, { AccessibilityRoleType::PATH, "path" },
62 { AccessibilityRoleType::PATH2D, "path2d" }, { AccessibilityRoleType::PATTERN_LOCK, "patternlock" },
63 { AccessibilityRoleType::PICKER, "picker" }, { AccessibilityRoleType::PICKER_VIEW, "picker-view" },
64 { AccessibilityRoleType::PLUGIN_COMPONENT, "plugincomponent" }, { AccessibilityRoleType::POLYGON, "polygon" },
65 { AccessibilityRoleType::POLYLINE, "polyline" }, { AccessibilityRoleType::POPUP, "popup" },
66 { AccessibilityRoleType::PROGRESS, "progress" }, { AccessibilityRoleType::QRCODE, "qrcode" },
67 { AccessibilityRoleType::RADIO, "radio" }, { AccessibilityRoleType::RATING, "rating" },
68 { AccessibilityRoleType::RECT, "rect" }, { AccessibilityRoleType::REFRESH, "refresh" },
69 { AccessibilityRoleType::RELATIVE_CONTAINER, "relativecontainer" },
70 { AccessibilityRoleType::REMOTE_WINDOW, "remotewindow" }, { AccessibilityRoleType::RICH_EDITOR, "richeditor" },
71 { AccessibilityRoleType::RICH_TEXT, "richtext" }, { AccessibilityRoleType::ROLE_PAGER, "rolepager" },
72 { AccessibilityRoleType::ROW, "row" }, { AccessibilityRoleType::ROW_SPLIT, "rowsplit" },
73 { AccessibilityRoleType::SCROLL, "scroll" }, { AccessibilityRoleType::SCROLL_BAR, "scrollbar" },
74 { AccessibilityRoleType::SEARCH, "search" }, { AccessibilityRoleType::SEARCH_FIELD, "searchfield" },
75 { AccessibilityRoleType::SELECT, "select" }, { AccessibilityRoleType::SHAPE, "shape" },
76 { AccessibilityRoleType::SIDEBAR_CONTAINER, "sidebarcontainer" }, { AccessibilityRoleType::SLIDER, "slider" },
77 { AccessibilityRoleType::SPAN, "span" }, { AccessibilityRoleType::STACK, "stack" },
78 { AccessibilityRoleType::STEPPER, "stepper" }, { AccessibilityRoleType::STEPPER_ITEM, "stepperitem" },
79 { AccessibilityRoleType::SWIPER, "swiper" }, { AccessibilityRoleType::SWIPER_INDICATOR, "swiperindicator" },
80 { AccessibilityRoleType::SWITCH, "switch" }, { AccessibilityRoleType::SYMBOL_GLYPH, "symbolglyph" },
81 { AccessibilityRoleType::TAB_CONTENT, "tabcontent" }, { AccessibilityRoleType::TAB_BAR, "tab-bar" },
82 { AccessibilityRoleType::TABS, "tabs" }, { AccessibilityRoleType::TEXT, "text" },
83 { AccessibilityRoleType::TEXT_CLOCK, "textclock" }, { AccessibilityRoleType::TEXT_ENTRY, "textentry" },
84 { AccessibilityRoleType::TEXT_INPUT, "textinput" }, { AccessibilityRoleType::TEXT_PICKER, "textpicker" },
85 { AccessibilityRoleType::TEXT_TIMER, "texttimer" }, { AccessibilityRoleType::TEXT_AREA, "textarea" },
86 { AccessibilityRoleType::TEXT_FIELD, "textfield" }, { AccessibilityRoleType::TIME_PICKER, "timepicker" },
87 { AccessibilityRoleType::TITLE_BAR, "titlebar" }, { AccessibilityRoleType::TOGGLER, "toggler" },
88 { AccessibilityRoleType::UI_EXTENSION_COMPONENT, "uiextensioncomponent" },
89 { AccessibilityRoleType::VIDEO, "video" }, { AccessibilityRoleType::WATER_FLOW, "waterflow" },
90 { AccessibilityRoleType::WEB, "web" }, { AccessibilityRoleType::XCOMPONENT, "xcomponent" },
91 { AccessibilityRoleType::ROLE_NONE, "NULL" }
92 };
93
94 const std::vector<AccessibilitySamePageMode> PAGE_MODE_TYPE = { AccessibilitySamePageMode::SEMI_SILENT,
95 AccessibilitySamePageMode::FULL_SILENT };
96 }
97
JsAccessibilityGroup(const JSCallbackInfo & info)98 void JSViewAbstract::JsAccessibilityGroup(const JSCallbackInfo& info)
99 {
100 bool isGroup = false;
101 if (info[0]->IsBoolean()) {
102 isGroup = info[0]->ToBoolean();
103 }
104 ViewAbstractModel::GetInstance()->SetAccessibilityGroup(isGroup);
105
106 if (info.Length() > 1 && info[1]->IsObject()) {
107 auto obj = JSRef<JSObject>::Cast(info[1]);
108
109 auto preferAccessibilityTextObj = obj->GetProperty("accessibilityPreferred");
110 auto preferAccessibilityText =
111 preferAccessibilityTextObj->IsBoolean() ? preferAccessibilityTextObj->ToBoolean() : false;
112 ViewAbstractModel::GetInstance()->SetAccessibilityTextPreferred(preferAccessibilityText);
113 }
114 }
115
JsAccessibilityText(const JSCallbackInfo & info)116 void JSViewAbstract::JsAccessibilityText(const JSCallbackInfo& info)
117 {
118 const JSRef<JSVal>& jsValue = info[0];
119 std::string text;
120 if (!ParseJsString(jsValue, text)) {
121 return;
122 }
123 ViewAbstractModel::GetInstance()->SetAccessibilityText(text);
124 }
125
JsAccessibilityTextHint(const std::string & text)126 void JSViewAbstract::JsAccessibilityTextHint(const std::string& text)
127 {
128 ViewAbstractModel::GetInstance()->SetAccessibilityTextHint(text);
129 }
130
JsAccessibilityNextFocusId(const JSCallbackInfo & info)131 void JSViewAbstract::JsAccessibilityNextFocusId(const JSCallbackInfo& info)
132 {
133 const JSRef<JSVal>& jsValue = info[0];
134 std::string nextFocusId;
135 if (!ParseJsString(jsValue, nextFocusId)) {
136 return;
137 }
138 ViewAbstractModel::GetInstance()->SetAccessibilityNextFocusId(nextFocusId);
139 }
140
JsAccessibilityDescription(const JSCallbackInfo & info)141 void JSViewAbstract::JsAccessibilityDescription(const JSCallbackInfo& info)
142 {
143 const JSRef<JSVal>& jsValue = info[0];
144 std::string description;
145 if (!ParseJsString(jsValue, description)) {
146 return;
147 }
148 std::pair<bool, std::string> autoEventPair(false, "");
149 std::pair<bool, std::string> descriptionPair(false, "");
150 ParseAccessibilityDescriptionJson(description, autoEventPair, descriptionPair);
151 if (descriptionPair.first) {
152 ViewAbstractModel::GetInstance()->SetAccessibilityDescription(descriptionPair.second);
153 } else {
154 ViewAbstractModel::GetInstance()->SetAccessibilityDescription(description);
155 }
156 if (autoEventPair.first) {
157 ViewAbstractModel::GetInstance()->SetAutoEventParam(autoEventPair.second);
158 }
159 }
160
ParseAccessibilityDescriptionJson(const std::string & description,std::pair<bool,std::string> & autoEventPair,std::pair<bool,std::string> & descriptionPair)161 void JSViewAbstract::ParseAccessibilityDescriptionJson(const std::string& description,
162 std::pair<bool, std::string>& autoEventPair, std::pair<bool, std::string>& descriptionPair)
163 {
164 if (description.empty()) {
165 return;
166 }
167 if (!StartWith(description, "{") || !EndWith(description, "}")) {
168 return;
169 }
170 auto jsonObj = JsonUtil::ParseJsonString(description);
171 if (!jsonObj || !jsonObj->IsValid() || !jsonObj->IsObject()) {
172 return;
173 }
174 if (jsonObj->Contains("$autoEventParam")) {
175 auto param = jsonObj->GetValue("$autoEventParam");
176 if (param) {
177 autoEventPair = std::make_pair(true, param->ToString());
178 }
179 }
180 if (jsonObj->Contains("$accessibilityDescription")) {
181 descriptionPair = std::make_pair(true, jsonObj->GetString("$accessibilityDescription"));
182 } else if (jsonObj->Contains("$autoEventParam")) {
183 descriptionPair = std::make_pair(true, "");
184 }
185 }
186
JsAccessibilityImportance(const std::string & importance)187 void JSViewAbstract::JsAccessibilityImportance(const std::string& importance)
188 {
189 ViewAbstractModel::GetInstance()->SetAccessibilityImportance(importance);
190 }
191
JsAccessibilityLevel(const std::string & level)192 void JSViewAbstract::JsAccessibilityLevel(const std::string& level)
193 {
194 ViewAbstractModel::GetInstance()->SetAccessibilityImportance(level);
195 }
196
JsAccessibilityVirtualNode(const JSCallbackInfo & info)197 void JSViewAbstract::JsAccessibilityVirtualNode(const JSCallbackInfo& info)
198 {
199 // parse builder
200 if (!info[0]->IsObject()) {
201 return;
202 }
203 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
204 auto builder = obj->GetProperty("builder");
205 if (builder->IsFunction()) {
206 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
207 CHECK_NULL_VOID(builderFunc);
208 auto buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc)]() {
209 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
210 ACE_SCORING_EVENT("AccessibilityVirtualNode");
211 func->Execute();
212 };
213 NG::ViewAbstractModelNG::GetInstance()->SetAccessibilityVirtualNode(std::move(buildFunc));
214 }
215 }
216
JsAccessibilitySelected(const JSCallbackInfo & info)217 void JSViewAbstract::JsAccessibilitySelected(const JSCallbackInfo& info)
218 {
219 bool selected = false;
220 bool resetValue = false;
221 JSRef<JSVal> arg = info[0];
222 if (arg->IsUndefined()) {
223 resetValue = true;
224 } else if (arg->IsBoolean()) {
225 selected = arg->ToBoolean();
226 } else {
227 return;
228 }
229
230 ViewAbstractModel::GetInstance()->SetAccessibilitySelected(selected, resetValue);
231 }
232
JsAccessibilityChecked(const JSCallbackInfo & info)233 void JSViewAbstract::JsAccessibilityChecked(const JSCallbackInfo& info)
234 {
235 bool checked = false;
236 bool resetValue = false;
237 JSRef<JSVal> arg = info[0];
238 if (arg->IsUndefined()) {
239 resetValue = true;
240 } else if (arg->IsBoolean()) {
241 checked = arg->ToBoolean();
242 } else {
243 return;
244 }
245
246 ViewAbstractModel::GetInstance()->SetAccessibilityChecked(checked, resetValue);
247 }
248
JsAccessibilityScrollTriggerable(const JSCallbackInfo & info)249 void JSViewAbstract::JsAccessibilityScrollTriggerable(const JSCallbackInfo& info)
250 {
251 bool scrollTriggerable = false;
252 bool resetValue = false;
253 JSRef<JSVal> arg = info[0];
254 if (arg->IsUndefined()) {
255 resetValue = true;
256 } else if (arg->IsBoolean()) {
257 scrollTriggerable = arg->ToBoolean();
258 } else {
259 return;
260 }
261
262 ViewAbstractModel::GetInstance()->SetAccessibilityScrollTriggerable(scrollTriggerable, resetValue);
263 }
264
JsAccessibilityRole(const JSCallbackInfo & info)265 void JSViewAbstract::JsAccessibilityRole(const JSCallbackInfo& info)
266 {
267 bool resetValue = false;
268 std::string role;
269 if (info.Length() < 1 || !info[0]->IsNumber()) {
270 ViewAbstractModel::GetInstance()->SetAccessibilityRole(role, true);
271 return;
272 }
273 auto index = info[0]->ToNumber<int32_t>();
274 AccessibilityRoleType text = static_cast<AccessibilityRoleType>(index);
275 auto it = accessibilityRoleMap.find(text);
276 if (it != accessibilityRoleMap.end()) {
277 role = it->second;
278 } else {
279 resetValue = true;
280 }
281 ViewAbstractModel::GetInstance()->SetAccessibilityRole(role, resetValue);
282 }
283
JsOnAccessibilityFocus(const JSCallbackInfo & info)284 void JSViewAbstract::JsOnAccessibilityFocus(const JSCallbackInfo& info)
285 {
286 if (info[0]->IsUndefined() || !info[0]->IsFunction()) {
287 ViewAbstractModel::GetInstance()->ResetOnAccessibilityFocus();
288 return;
289 }
290 RefPtr<JsFunction> jsFoucusFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(info[0]));
291 WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
292 auto onAccessibilityFoucus = [execCtx = info.GetExecutionContext(), func = std::move(jsFoucusFunc),
293 node = frameNode](bool isFocus) {
294 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
295 ACE_SCORING_EVENT("onAccessibilityFoucus");
296 PipelineContext::SetCallBackNode(node);
297 JSRef<JSVal> newJSVal = JSRef<JSVal>::Make(ToJSValue(isFocus));
298 func->ExecuteJS(1, &newJSVal);
299 };
300 ViewAbstractModel::GetInstance()->SetOnAccessibilityFocus(std::move(onAccessibilityFoucus));
301 }
302
JsAccessibilityDefaultFocus(const JSCallbackInfo & info)303 void JSViewAbstract::JsAccessibilityDefaultFocus(const JSCallbackInfo& info)
304 {
305 JSRef<JSVal> arg = info[0];
306 if (arg->IsBoolean()) {
307 auto isFocus = arg->ToBoolean();
308 ViewAbstractModel::GetInstance()->SetAccessibilityDefaultFocus(isFocus);
309 return;
310 }
311 ViewAbstractModel::GetInstance()->SetAccessibilityDefaultFocus(false);
312 }
313
JsAccessibilityUseSamePage(const JSCallbackInfo & info)314 void JSViewAbstract::JsAccessibilityUseSamePage(const JSCallbackInfo& info)
315 {
316 JSRef<JSVal> arg = info[0];
317 if (arg->IsNumber()) {
318 auto pageModeType = arg->ToNumber<int32_t>();
319 if (pageModeType >= 0 && pageModeType < static_cast<int32_t>(PAGE_MODE_TYPE.size())) {
320 auto pageMode = static_cast<bool>(PAGE_MODE_TYPE[pageModeType]) ? "FULL_SILENT" : "SEMI_SILENT";
321 ViewAbstractModel::GetInstance()->SetAccessibilityUseSamePage(pageMode);
322 return;
323 }
324 ViewAbstractModel::GetInstance()->SetAccessibilityUseSamePage("");
325 return;
326 }
327 ViewAbstractModel::GetInstance()->SetAccessibilityUseSamePage("");
328 }
329
GetRoleByType(AccessibilityRoleType roleType)330 std::string JSAccessibilityAbstract::GetRoleByType(AccessibilityRoleType roleType)
331 {
332 auto it = accessibilityRoleMap.find(roleType);
333 if (it != accessibilityRoleMap.end()) {
334 return it->second;
335 }
336 return "";
337 }
338
JsAccessibilityFocusDrawLevel(const JSCallbackInfo & info)339 void JSViewAbstract::JsAccessibilityFocusDrawLevel(const JSCallbackInfo& info)
340 {
341 int32_t drawLevel = 0;
342 JSRef<JSVal> arg = info[0];
343 do {
344 if (!arg->IsNumber()) {
345 break;
346 }
347 if (arg->ToNumber<int32_t>() > 1) {
348 break;
349 }
350 drawLevel = arg->ToNumber<int32_t>();
351 } while (false);
352 ViewAbstractModel::GetInstance()->SetAccessibilityFocusDrawLevel(drawLevel);
353 }
354 }