Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: webkit/glue/glue_accessibility_object.cc

Issue 348063: Introduce WebAccessibilityControllerImpl.... (Closed) Base URL: svn://chrome-svn.corp.google.com/chrome/trunk/src/
Patch Set: Licked clean. Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6
7 #include "AccessibilityObject.h"
8 #include "EventHandler.h"
9 #include "FrameView.h"
10 #include "PlatformKeyboardEvent.h"
11
12 #include "webkit/glue/glue_accessibility_object.h"
13
14 using WebCore::AccessibilityObject;
15 using WebCore::String;
16 using webkit_glue::WebAccessibility;
17
18 GlueAccessibilityObject::GlueAccessibilityObject(AccessibilityObject* obj)
19 : AccessibilityObjectWrapper(obj) {
20 m_object->setWrapper(this);
21 }
22
23 GlueAccessibilityObject* GlueAccessibilityObject::CreateInstance(
24 AccessibilityObject* obj) {
25 if (!obj)
26 return NULL;
27
28 return new GlueAccessibilityObject(obj);
29 }
30
31 bool GlueAccessibilityObject::DoDefaultAction(int child_id) {
32 AccessibilityObject* child_obj;
33
34 if (!GetAccessibilityObjectForChild(child_id, child_obj) ||
35 !child_obj->performDefaultAction()) {
36 return false;
37 }
38 return true;
39 }
40
41 GlueAccessibilityObject* GlueAccessibilityObject::HitTest(long x, long y) {
42 if (!m_object)
43 return NULL;
44
45 // x, y - coordinates are passed in as window coordinates, to maintain
46 // sandbox functionality.
47 WebCore::IntPoint point =
48 m_object->documentFrameView()->windowToContents(WebCore::IntPoint(x, y));
49 AccessibilityObject* child_obj = m_object->doAccessibilityHitTest(point);
50
51 if (!child_obj) {
52 // If we did not hit any child objects, test whether the point hit us, and
53 // report that.
54 if (!m_object->boundingBoxRect().contains(point))
55 return NULL;
56 child_obj = m_object;
57 }
58 // TODO(klink): simple object child?
59 ToWrapper(child_obj)->ref();
60 return ToWrapper(child_obj);
61 }
62
63 bool GlueAccessibilityObject::Location(long* left, long* top, long* width,
64 long* height, int child_id) {
65 if (!left || !top || !width || !height)
66 return false;
67
68 *left = *top = *width = *height = 0;
69
70 AccessibilityObject* child_obj;
71 if (!GetAccessibilityObjectForChild(child_id, child_obj))
72 return false;
73
74 // Returning window coordinates, to be handled and converted appropriately by
75 // the client.
76 WebCore::IntRect window_rect(child_obj->documentFrameView()->contentsToWindow(
77 child_obj->boundingBoxRect()));
78 *left = window_rect.x();
79 *top = window_rect.y();
80 *width = window_rect.width();
81 *height = window_rect.height();
82 return true;
83 }
84
85 GlueAccessibilityObject* GlueAccessibilityObject::Navigate(
86 WebAccessibility::Direction dir, int start_child_id) {
87 AccessibilityObject* child_obj = 0;
88
89 switch (dir) {
90 case WebAccessibility::DIRECTION_DOWN:
91 case WebAccessibility::DIRECTION_UP:
92 case WebAccessibility::DIRECTION_LEFT:
93 case WebAccessibility::DIRECTION_RIGHT:
94 // These directions are not implemented, matching Mozilla and IE.
95 return NULL;
96 case WebAccessibility::DIRECTION_LASTCHILD:
97 case WebAccessibility::DIRECTION_FIRSTCHILD:
98 // MSDN states that navigating to first/last child can only be from self.
99 if (start_child_id != 0 || !m_object)
100 return NULL;
101
102 if (dir == WebAccessibility::DIRECTION_FIRSTCHILD) {
103 child_obj = m_object->firstChild();
104 } else {
105 child_obj = m_object->lastChild();
106 }
107 break;
108 case WebAccessibility::DIRECTION_NEXT:
109 case WebAccessibility::DIRECTION_PREVIOUS: {
110 // Navigating to next and previous is allowed from self or any of our
111 // children.
112 if (!GetAccessibilityObjectForChild(start_child_id, child_obj))
113 return NULL;
114
115 if (dir == WebAccessibility::DIRECTION_NEXT) {
116 child_obj = child_obj->nextSibling();
117 } else {
118 child_obj = child_obj->previousSibling();
119 }
120 break;
121 }
122 default:
123 return NULL;
124 }
125
126 if (!child_obj)
127 return NULL;
128
129 // TODO(klink): simple object child?
130 ToWrapper(child_obj)->ref();
131 return ToWrapper(child_obj);
132 }
133
134 GlueAccessibilityObject* GlueAccessibilityObject::GetChild(int child_id) {
135 AccessibilityObject* child_obj;
136 if (!GetAccessibilityObjectForChild(child_id, child_obj))
137 return NULL;
138
139 // TODO(klink): simple object child?
140 ToWrapper(child_obj)->ref();
141 return ToWrapper(child_obj);
142 }
143
144 bool GlueAccessibilityObject::ChildCount(long* count) {
145 if (!m_object || !count)
146 return false;
147
148 *count = static_cast<long>(m_object->children().size());
149 return true;
150 }
151
152 bool GlueAccessibilityObject::DefaultAction(int child_id, String* action) {
153 if (!action)
154 return false;
155
156 AccessibilityObject* child_obj;
157 if (!GetAccessibilityObjectForChild(child_id, child_obj))
158 return false;
159
160 *action = child_obj->actionVerb();
161 return !action->isEmpty();
162 }
163
164 bool GlueAccessibilityObject::Description(int child_id, String* description) {
165 if (!description)
166 return false;
167
168 AccessibilityObject* child_obj;
169 if (!GetAccessibilityObjectForChild(child_id, child_obj))
170 return false;
171
172 // TODO(klink): Description, for SELECT subitems, should be a string
173 // describing the position of the item in its group and of the group in the
174 // list (see Firefox).
175 *description = ToWrapper(child_obj)->description();
176 return !description->isEmpty();
177 }
178
179 GlueAccessibilityObject* GlueAccessibilityObject::GetFocusedChild() {
180 if (!m_object)
181 return NULL;
182
183 AccessibilityObject* focused_obj = m_object->focusedUIElement();
184 if (!focused_obj)
185 return NULL;
186
187 // Only return the focused child if it's us or a child of us.
188 if (focused_obj == m_object || focused_obj->parentObject() == m_object) {
189 ToWrapper(focused_obj)->ref();
190 return ToWrapper(focused_obj);
191 }
192 return NULL;
193 }
194
195 bool GlueAccessibilityObject::HelpText(int child_id, String* help) {
196 if (!help)
197 return false;
198
199 AccessibilityObject* child_obj;
200 if (!GetAccessibilityObjectForChild(child_id, child_obj))
201 return false;
202
203 *help = child_obj->helpText();
204 return !help->isEmpty();
205 }
206
207 bool GlueAccessibilityObject::KeyboardShortcut(int child_id, String* shortcut) {
208 if (!shortcut)
209 return false;
210
211 AccessibilityObject* child_obj;
212 if (!GetAccessibilityObjectForChild(child_id, child_obj))
213 return false;
214
215 String access_key = child_obj->accessKey();
216 if (access_key.isNull())
217 return false;
218
219 static String access_key_modifiers;
220 if (access_key_modifiers.isNull()) {
221 unsigned modifiers = WebCore::EventHandler::accessKeyModifiers();
222 // Follow the same order as Mozilla MSAA implementation:
223 // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
224 // should not be localized and defines the separator as "+".
225 if (modifiers & WebCore::PlatformKeyboardEvent::CtrlKey)
226 access_key_modifiers += "Ctrl+";
227 if (modifiers & WebCore::PlatformKeyboardEvent::AltKey)
228 access_key_modifiers += "Alt+";
229 if (modifiers & WebCore::PlatformKeyboardEvent::ShiftKey)
230 access_key_modifiers += "Shift+";
231 if (modifiers & WebCore::PlatformKeyboardEvent::MetaKey)
232 access_key_modifiers += "Win+";
233 }
234 *shortcut = access_key_modifiers + access_key;
235 return !shortcut->isEmpty();
236 }
237
238 bool GlueAccessibilityObject::Name(int child_id, String* name) {
239 if (!name)
240 return false;
241
242 AccessibilityObject* child_obj;
243 if (!GetAccessibilityObjectForChild(child_id, child_obj))
244 return false;
245
246 *name = ToWrapper(child_obj)->name();
247 return !name->isEmpty();
248 }
249
250 GlueAccessibilityObject* GlueAccessibilityObject::GetParent() {
251 if (!m_object)
252 return NULL;
253
254 AccessibilityObject* parent_obj = m_object->parentObject();
255
256 if (parent_obj) {
257 ToWrapper(parent_obj)->ref();
258 return ToWrapper(parent_obj);
259 }
260 // No valid parent, or parent is the containing window.
261 return NULL;
262 }
263
264 bool GlueAccessibilityObject::Role(int child_id, long* role) {
265 if (!role)
266 return false;
267
268 AccessibilityObject* child_obj;
269 if (!GetAccessibilityObjectForChild(child_id, child_obj))
270 return false;
271
272 *role = ToWrapper(child_obj)->role();
273 return true;
274 }
275
276 bool GlueAccessibilityObject::Value(int child_id, String* value) {
277 if (!value)
278 return false;
279
280 AccessibilityObject* child_obj;
281 if (!GetAccessibilityObjectForChild(child_id, child_obj))
282 return false;
283
284 *value = ToWrapper(child_obj)->value();
285 return !value->isEmpty();
286 }
287
288 bool GlueAccessibilityObject::State(int child_id, long* state) {
289 if (!state)
290 return false;
291
292 *state = 0;
293 AccessibilityObject* child_obj;
294 if (!GetAccessibilityObjectForChild(child_id, child_obj))
295 return false;
296
297 if (child_obj->isChecked())
298 *state |= static_cast<long>(1 << WebAccessibility::STATE_CHECKED);
299
300 if (child_obj->canSetFocusAttribute())
301 *state |= static_cast<long>(1 << WebAccessibility::STATE_FOCUSABLE);
302
303 if (child_obj->isFocused())
304 *state |= static_cast<long>(1 << WebAccessibility::STATE_FOCUSED);
305
306 if (child_obj->isHovered())
307 *state |= static_cast<long>(1 << WebAccessibility::STATE_HOTTRACKED);
308
309 if (child_obj->isIndeterminate())
310 *state |= static_cast<long>(1 << WebAccessibility::STATE_INDETERMINATE);
311
312 if (child_obj->isAnchor())
313 *state |= static_cast<long>(1 << WebAccessibility::STATE_LINKED);
314
315 if (child_obj->isMultiSelect())
316 *state |= static_cast<long>(1 << WebAccessibility::STATE_MULTISELECTABLE);
317
318 if (child_obj->isOffScreen())
319 *state |= static_cast<long>(1 << WebAccessibility::STATE_OFFSCREEN);
320
321 if (child_obj->isPressed())
322 *state |= static_cast<long>(1 << WebAccessibility::STATE_PRESSED);
323
324 if (child_obj->isPasswordField())
325 *state |= static_cast<long>(1 << WebAccessibility::STATE_PROTECTED);
326
327 if (child_obj->isReadOnly())
328 *state |= static_cast<long>(1 << WebAccessibility::STATE_READONLY);
329
330 if (child_obj->isVisited())
331 *state |= static_cast<long>(1 << WebAccessibility::STATE_TRAVERSED);
332
333 if (!child_obj->isEnabled())
334 *state |= static_cast<long>(1 << WebAccessibility::STATE_UNAVAILABLE);
335
336 // TODO(klink): Add selected and selectable states.
337
338 return true;
339 }
340
341 // Helper functions
342 String GlueAccessibilityObject::name() const {
343 return m_object->title();
344 }
345
346 String GlueAccessibilityObject::value() const {
347 return m_object->stringValue();
348 }
349
350 String GlueAccessibilityObject::description() const {
351 String desc = m_object->accessibilityDescription();
352 if (desc.isNull())
353 return desc;
354
355 // From the Mozilla MSAA implementation:
356 // "Signal to screen readers that this description is speakable and is not
357 // a formatted positional information description. Don't localize the
358 // 'Description: ' part of this string, it will be parsed out by assistive
359 // technologies."
360 return "Description: " + desc;
361 }
362
363 // Provides a conversion between the WebCore::AccessibilityRole and a
364 // role supported on the Browser side. Listed alphabetically by the
365 // WebAccessibility role (except for default role). Static function.
366 static WebAccessibility::Role SupportedRole(WebCore::AccessibilityRole role) {
367 switch (role) {
368 case WebCore::LandmarkApplicationRole:
369 return WebAccessibility::ROLE_APPLICATION;
370 case WebCore::CellRole:
371 return WebAccessibility::ROLE_CELL;
372 case WebCore::CheckBoxRole:
373 return WebAccessibility::ROLE_CHECKBUTTON;
374 case WebCore::ColumnRole:
375 return WebAccessibility::ROLE_COLUMN;
376 case WebCore::ColumnHeaderRole:
377 return WebAccessibility::ROLE_COLUMNHEADER;
378 case WebCore::DocumentArticleRole:
379 case WebCore::WebAreaRole:
380 return WebAccessibility::ROLE_DOCUMENT;
381 case WebCore::ImageMapRole:
382 case WebCore::ImageRole:
383 return WebAccessibility::ROLE_GRAPHIC;
384 case WebCore::DocumentRegionRole:
385 case WebCore::RadioGroupRole:
386 case WebCore::GroupRole:
387 return WebAccessibility::ROLE_GROUPING;
388 case WebCore::LinkRole:
389 case WebCore::WebCoreLinkRole:
390 return WebAccessibility::ROLE_LINK;
391 case WebCore::ListRole:
392 return WebAccessibility::ROLE_LIST;
393 case WebCore::ListBoxRole:
394 return WebAccessibility::ROLE_LISTBOX;
395 case WebCore::ListBoxOptionRole:
396 return WebAccessibility::ROLE_LISTITEM;
397 case WebCore::MenuBarRole:
398 return WebAccessibility::ROLE_MENUBAR;
399 case WebCore::MenuButtonRole:
400 case WebCore::MenuItemRole:
401 return WebAccessibility::ROLE_MENUITEM;
402 case WebCore::MenuRole:
403 return WebAccessibility::ROLE_MENUPOPUP;
404 case WebCore::OutlineRole:
405 return WebAccessibility::ROLE_OUTLINE;
406 case WebCore::TabGroupRole:
407 return WebAccessibility::ROLE_PAGETABLIST;
408 case WebCore::ProgressIndicatorRole:
409 return WebAccessibility::ROLE_PROGRESSBAR;
410 case WebCore::ButtonRole:
411 return WebAccessibility::ROLE_PUSHBUTTON;
412 case WebCore::RadioButtonRole:
413 return WebAccessibility::ROLE_RADIOBUTTON;
414 case WebCore::RowRole:
415 return WebAccessibility::ROLE_ROW;
416 case WebCore::RowHeaderRole:
417 return WebAccessibility::ROLE_ROWHEADER;
418 case WebCore::SplitterRole:
419 return WebAccessibility::ROLE_SEPARATOR;
420 case WebCore::SliderRole:
421 return WebAccessibility::ROLE_SLIDER;
422 case WebCore::StaticTextRole:
423 return WebAccessibility::ROLE_STATICTEXT;
424 case WebCore::ApplicationStatusRole:
425 return WebAccessibility::ROLE_STATUSBAR;
426 case WebCore::TableRole:
427 return WebAccessibility::ROLE_TABLE;
428 case WebCore::ListMarkerRole:
429 case WebCore::TextFieldRole:
430 case WebCore::TextAreaRole:
431 return WebAccessibility::ROLE_TEXT;
432 case WebCore::ToolbarRole:
433 return WebAccessibility::ROLE_TOOLBAR;
434 case WebCore::UserInterfaceTooltipRole:
435 return WebAccessibility::ROLE_TOOLTIP;
436 case WebCore::DocumentRole:
437 case WebCore::UnknownRole:
438 default:
439 // This is the default role.
440 return WebAccessibility::ROLE_CLIENT;
441 }
442 }
443
444 WebAccessibility::Role GlueAccessibilityObject::role() const {
445 return SupportedRole(m_object->roleValue());
446 }
447
448 bool GlueAccessibilityObject::GetAccessibilityObjectForChild(int child_id,
449 AccessibilityObject*& child_obj) const {
450 child_obj = 0;
451
452 if (!m_object || child_id < 0)
453 return false;
454
455 if (child_id == 0) {
456 child_obj = m_object;
457 } else {
458 size_t child_index = static_cast<size_t>(child_id - 1);
459
460 if (child_index >= m_object->children().size())
461 return false;
462 child_obj = m_object->children().at(child_index).get();
463 }
464
465 if (!child_obj)
466 return false;
467
468 return true;
469 }
470
471 GlueAccessibilityObject* GlueAccessibilityObject::ToWrapper(
472 AccessibilityObject* obj) {
473 if (!obj)
474 return NULL;
475
476 GlueAccessibilityObject* result =
477 static_cast<GlueAccessibilityObject*>(obj->wrapper());
478 if (!result)
479 result = CreateInstance(obj);
480
481 return result;
482 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698