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

Side by Side Diff: views/accessibility/native_view_accessibility_win.cc

Issue 8533010: views: Move accessibility/ directory to ui/views/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 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 | Annotate | Revision Log
« no previous file with comments | « views/accessibility/native_view_accessibility_win.h ('k') | views/view.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 <atlbase.h>
6 #include <atlcom.h>
7
8 #include <vector>
9
10 #include "views/accessibility/native_view_accessibility_win.h"
11
12 #include "third_party/iaccessible2/ia2_api_all.h"
13 #include "ui/base/accessibility/accessible_text_utils.h"
14 #include "ui/base/accessibility/accessible_view_state.h"
15 #include "ui/base/view_prop.h"
16 #include "views/widget/native_widget_win.h"
17 #include "views/widget/widget.h"
18
19 using ui::AccessibilityTypes;
20
21 // static
22 long NativeViewAccessibilityWin::next_unique_id_ = 1;
23
24 // static
25 scoped_refptr<NativeViewAccessibilityWin> NativeViewAccessibilityWin::Create(
26 views::View* view) {
27 CComObject<NativeViewAccessibilityWin>* instance = NULL;
28 HRESULT hr = CComObject<NativeViewAccessibilityWin>::CreateInstance(
29 &instance);
30 DCHECK(SUCCEEDED(hr));
31 instance->set_view(view);
32 return scoped_refptr<NativeViewAccessibilityWin>(instance);
33 }
34
35 NativeViewAccessibilityWin::NativeViewAccessibilityWin()
36 : view_(NULL),
37 unique_id_(next_unique_id_++) {
38 }
39
40 NativeViewAccessibilityWin::~NativeViewAccessibilityWin() {
41 }
42
43 // TODO(ctguil): Handle case where child View is not contained by parent.
44 STDMETHODIMP NativeViewAccessibilityWin::accHitTest(
45 LONG x_left, LONG y_top, VARIANT* child) {
46 if (!child)
47 return E_INVALIDARG;
48
49 if (!view_)
50 return E_FAIL;
51
52 gfx::Point point(x_left, y_top);
53 views::View::ConvertPointToView(NULL, view_, &point);
54
55 if (!view_->HitTest(point)) {
56 // If containing parent is not hit, return with failure.
57 child->vt = VT_EMPTY;
58 return S_FALSE;
59 }
60
61 views::View* view = view_->GetEventHandlerForPoint(point);
62 if (view == view_) {
63 // No child hit, return parent id.
64 child->vt = VT_I4;
65 child->lVal = CHILDID_SELF;
66 } else {
67 child->vt = VT_DISPATCH;
68 child->pdispVal = view->GetNativeViewAccessible();
69 child->pdispVal->AddRef();
70 }
71 return S_OK;
72 }
73
74 HRESULT NativeViewAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
75 if (!IsValidId(var_id))
76 return E_INVALIDARG;
77
78 // The object does not support the method. This value is returned for
79 // controls that do not perform actions, such as edit fields.
80 return DISP_E_MEMBERNOTFOUND;
81 }
82
83 STDMETHODIMP NativeViewAccessibilityWin::accLocation(
84 LONG* x_left, LONG* y_top, LONG* width, LONG* height, VARIANT var_id) {
85 if (!IsValidId(var_id) || !x_left || !y_top || !width || !height)
86 return E_INVALIDARG;
87
88 if (!view_)
89 return E_FAIL;
90
91 if (!view_->bounds().IsEmpty()) {
92 *width = view_->width();
93 *height = view_->height();
94 gfx::Point topleft(view_->bounds().origin());
95 views::View::ConvertPointToScreen(
96 view_->parent() ? view_->parent() : view_, &topleft);
97 *x_left = topleft.x();
98 *y_top = topleft.y();
99 } else {
100 return E_FAIL;
101 }
102 return S_OK;
103 }
104
105 STDMETHODIMP NativeViewAccessibilityWin::accNavigate(
106 LONG nav_dir, VARIANT start, VARIANT* end) {
107 if (start.vt != VT_I4 || !end)
108 return E_INVALIDARG;
109
110 if (!view_)
111 return E_FAIL;
112
113 switch (nav_dir) {
114 case NAVDIR_FIRSTCHILD:
115 case NAVDIR_LASTCHILD: {
116 if (start.lVal != CHILDID_SELF) {
117 // Start of navigation must be on the View itself.
118 return E_INVALIDARG;
119 } else if (!view_->has_children()) {
120 // No children found.
121 return S_FALSE;
122 }
123
124 // Set child_id based on first or last child.
125 int child_id = 0;
126 if (nav_dir == NAVDIR_LASTCHILD)
127 child_id = view_->child_count() - 1;
128
129 views::View* child = view_->child_at(child_id);
130 end->vt = VT_DISPATCH;
131 end->pdispVal = child->GetNativeViewAccessible();
132 end->pdispVal->AddRef();
133 return S_OK;
134 }
135 case NAVDIR_LEFT:
136 case NAVDIR_UP:
137 case NAVDIR_PREVIOUS:
138 case NAVDIR_RIGHT:
139 case NAVDIR_DOWN:
140 case NAVDIR_NEXT: {
141 // Retrieve parent to access view index and perform bounds checking.
142 views::View* parent = view_->parent();
143 if (!parent) {
144 return E_FAIL;
145 }
146
147 if (start.lVal == CHILDID_SELF) {
148 int view_index = parent->GetIndexOf(view_);
149 // Check navigation bounds, adjusting for View child indexing (MSAA
150 // child indexing starts with 1, whereas View indexing starts with 0).
151 if (!IsValidNav(nav_dir, view_index, -1,
152 parent->child_count() - 1)) {
153 // Navigation attempted to go out-of-bounds.
154 end->vt = VT_EMPTY;
155 return S_FALSE;
156 } else {
157 if (IsNavDirNext(nav_dir)) {
158 view_index += 1;
159 } else {
160 view_index -=1;
161 }
162 }
163
164 views::View* child = parent->child_at(view_index);
165 end->pdispVal = child->GetNativeViewAccessible();
166 end->vt = VT_DISPATCH;
167 end->pdispVal->AddRef();
168 return S_OK;
169 } else {
170 // Check navigation bounds, adjusting for MSAA child indexing (MSAA
171 // child indexing starts with 1, whereas View indexing starts with 0).
172 if (!IsValidNav(nav_dir, start.lVal, 0, parent->child_count() + 1)) {
173 // Navigation attempted to go out-of-bounds.
174 end->vt = VT_EMPTY;
175 return S_FALSE;
176 } else {
177 if (IsNavDirNext(nav_dir)) {
178 start.lVal += 1;
179 } else {
180 start.lVal -= 1;
181 }
182 }
183
184 HRESULT result = this->get_accChild(start, &end->pdispVal);
185 if (result == S_FALSE) {
186 // Child is a leaf.
187 end->vt = VT_I4;
188 end->lVal = start.lVal;
189 } else if (result == E_INVALIDARG) {
190 return E_INVALIDARG;
191 } else {
192 // Child is not a leaf.
193 end->vt = VT_DISPATCH;
194 }
195 }
196 break;
197 }
198 default:
199 return E_INVALIDARG;
200 }
201 // Navigation performed correctly. Global return for this function, if no
202 // error triggered an escape earlier.
203 return S_OK;
204 }
205
206 STDMETHODIMP NativeViewAccessibilityWin::get_accChild(VARIANT var_child,
207 IDispatch** disp_child) {
208 if (var_child.vt != VT_I4 || !disp_child)
209 return E_INVALIDARG;
210
211 if (!view_)
212 return E_FAIL;
213
214 LONG child_id = V_I4(&var_child);
215
216 if (child_id == CHILDID_SELF) {
217 // Remain with the same dispatch.
218 return S_OK;
219 }
220
221 views::View* child_view = NULL;
222 if (child_id > 0) {
223 int child_id_as_index = child_id - 1;
224 if (child_id_as_index < view_->child_count()) {
225 // Note: child_id is a one based index when indexing children.
226 child_view = view_->child_at(child_id_as_index);
227 } else {
228 // Attempt to retrieve a child view with the specified id.
229 child_view = view_->GetViewByID(child_id);
230 }
231 } else {
232 // Negative values are used for events fired using the view's
233 // NativeWidgetWin.
234 views::NativeWidgetWin* widget = static_cast<views::NativeWidgetWin*>(
235 view_->GetWidget()->native_widget());
236 child_view = widget->GetAccessibilityViewEventAt(child_id);
237 }
238
239 if (!child_view) {
240 // No child found.
241 *disp_child = NULL;
242 return E_FAIL;
243 }
244
245 *disp_child = child_view->GetNativeViewAccessible();
246 (*disp_child)->AddRef();
247 return S_OK;
248 }
249
250 STDMETHODIMP NativeViewAccessibilityWin::get_accChildCount(LONG* child_count) {
251 if (!child_count || !view_)
252 return E_INVALIDARG;
253
254 if (!view_)
255 return E_FAIL;
256
257 *child_count = view_->child_count();
258 return S_OK;
259 }
260
261 STDMETHODIMP NativeViewAccessibilityWin::get_accDefaultAction(
262 VARIANT var_id, BSTR* def_action) {
263 if (!IsValidId(var_id) || !def_action)
264 return E_INVALIDARG;
265
266 if (!view_)
267 return E_FAIL;
268
269 ui::AccessibleViewState state;
270 view_->GetAccessibleState(&state);
271 string16 temp_action = state.default_action;
272
273 if (!temp_action.empty()) {
274 *def_action = SysAllocString(temp_action.c_str());
275 } else {
276 return S_FALSE;
277 }
278
279 return S_OK;
280 }
281
282 STDMETHODIMP NativeViewAccessibilityWin::get_accDescription(
283 VARIANT var_id, BSTR* desc) {
284 if (!IsValidId(var_id) || !desc)
285 return E_INVALIDARG;
286
287 if (!view_)
288 return E_FAIL;
289
290 string16 temp_desc;
291
292 view_->GetTooltipText(gfx::Point(), &temp_desc);
293 if (!temp_desc.empty()) {
294 *desc = SysAllocString(temp_desc.c_str());
295 } else {
296 return S_FALSE;
297 }
298
299 return S_OK;
300 }
301
302 STDMETHODIMP NativeViewAccessibilityWin::get_accFocus(VARIANT* focus_child) {
303 if (!focus_child)
304 return E_INVALIDARG;
305
306 if (!view_)
307 return E_FAIL;
308
309 views::FocusManager* focus_manager = view_->GetFocusManager();
310 views::View* focus = focus_manager ? focus_manager->GetFocusedView() : NULL;
311 if (focus == view_) {
312 // This view has focus.
313 focus_child->vt = VT_I4;
314 focus_child->lVal = CHILDID_SELF;
315 } else if (focus && view_->Contains(focus)) {
316 // Return the child object that has the keyboard focus.
317 focus_child->pdispVal = focus->GetNativeViewAccessible();
318 focus_child->pdispVal->AddRef();
319 return S_OK;
320 } else {
321 // Neither this object nor any of its children has the keyboard focus.
322 focus_child->vt = VT_EMPTY;
323 }
324 return S_OK;
325 }
326
327 STDMETHODIMP NativeViewAccessibilityWin::get_accKeyboardShortcut(
328 VARIANT var_id, BSTR* acc_key) {
329 if (!IsValidId(var_id) || !acc_key)
330 return E_INVALIDARG;
331
332 if (!view_)
333 return E_FAIL;
334
335 ui::AccessibleViewState state;
336 view_->GetAccessibleState(&state);
337 string16 temp_key = state.keyboard_shortcut;
338
339 if (!temp_key.empty()) {
340 *acc_key = SysAllocString(temp_key.c_str());
341 } else {
342 return S_FALSE;
343 }
344
345 return S_OK;
346 }
347
348 STDMETHODIMP NativeViewAccessibilityWin::get_accName(
349 VARIANT var_id, BSTR* name) {
350 if (!IsValidId(var_id) || !name)
351 return E_INVALIDARG;
352
353 if (!view_)
354 return E_FAIL;
355
356 // Retrieve the current view's name.
357 ui::AccessibleViewState state;
358 view_->GetAccessibleState(&state);
359 string16 temp_name = state.name;
360 if (!temp_name.empty()) {
361 // Return name retrieved.
362 *name = SysAllocString(temp_name.c_str());
363 } else {
364 // If view has no name, return S_FALSE.
365 return S_FALSE;
366 }
367
368 return S_OK;
369 }
370
371 STDMETHODIMP NativeViewAccessibilityWin::get_accParent(
372 IDispatch** disp_parent) {
373 if (!disp_parent)
374 return E_INVALIDARG;
375
376 if (!view_)
377 return E_FAIL;
378
379 views::View* parent_view = view_->parent();
380
381 if (!parent_view) {
382 // This function can get called during teardown of WidetWin so we
383 // should bail out if we fail to get the HWND.
384 if (!view_->GetWidget() || !view_->GetWidget()->GetNativeView()) {
385 *disp_parent = NULL;
386 return S_FALSE;
387 }
388
389 // For a View that has no parent (e.g. root), point the accessible parent
390 // to the default implementation, to interface with Windows' hierarchy
391 // and to support calls from e.g. WindowFromAccessibleObject.
392 HRESULT hr =
393 ::AccessibleObjectFromWindow(view_->GetWidget()->GetNativeView(),
394 OBJID_WINDOW, IID_IAccessible,
395 reinterpret_cast<void**>(disp_parent));
396
397 if (!SUCCEEDED(hr)) {
398 *disp_parent = NULL;
399 return S_FALSE;
400 }
401
402 return S_OK;
403 }
404
405 *disp_parent = parent_view->GetNativeViewAccessible();
406 (*disp_parent)->AddRef();
407 return S_OK;
408 }
409
410 STDMETHODIMP NativeViewAccessibilityWin::get_accRole(
411 VARIANT var_id, VARIANT* role) {
412 if (!IsValidId(var_id) || !role)
413 return E_INVALIDARG;
414
415 if (!view_)
416 return E_FAIL;
417
418 ui::AccessibleViewState state;
419 view_->GetAccessibleState(&state);
420 role->vt = VT_I4;
421 role->lVal = MSAARole(state.role);
422 return S_OK;
423 }
424
425 STDMETHODIMP NativeViewAccessibilityWin::get_accState(
426 VARIANT var_id, VARIANT* state) {
427 // This returns MSAA states. See also the IAccessible2 interface
428 // get_states().
429
430 if (!IsValidId(var_id) || !state)
431 return E_INVALIDARG;
432
433 if (!view_)
434 return E_FAIL;
435
436 state->vt = VT_I4;
437
438 // Retrieve all currently applicable states of the parent.
439 SetState(state, view_);
440
441 // Make sure that state is not empty, and has the proper type.
442 if (state->vt == VT_EMPTY)
443 return E_FAIL;
444
445 return S_OK;
446 }
447
448 STDMETHODIMP NativeViewAccessibilityWin::get_accValue(
449 VARIANT var_id, BSTR* value) {
450 if (!IsValidId(var_id) || !value)
451 return E_INVALIDARG;
452
453 if (!view_)
454 return E_FAIL;
455
456 // Retrieve the current view's value.
457 ui::AccessibleViewState state;
458 view_->GetAccessibleState(&state);
459 string16 temp_value = state.value;
460
461 if (!temp_value.empty()) {
462 // Return value retrieved.
463 *value = SysAllocString(temp_value.c_str());
464 } else {
465 // If view has no value, fall back into the default implementation.
466 *value = NULL;
467 return E_NOTIMPL;
468 }
469
470 return S_OK;
471 }
472
473 // IAccessible functions not supported.
474
475 STDMETHODIMP NativeViewAccessibilityWin::get_accSelection(VARIANT* selected) {
476 if (selected)
477 selected->vt = VT_EMPTY;
478 return E_NOTIMPL;
479 }
480
481 STDMETHODIMP NativeViewAccessibilityWin::accSelect(
482 LONG flagsSelect, VARIANT var_id) {
483 return E_NOTIMPL;
484 }
485
486 STDMETHODIMP NativeViewAccessibilityWin::get_accHelp(
487 VARIANT var_id, BSTR* help) {
488 if (help)
489 *help = NULL;
490 return E_NOTIMPL;
491 }
492
493 STDMETHODIMP NativeViewAccessibilityWin::get_accHelpTopic(
494 BSTR* help_file, VARIANT var_id, LONG* topic_id) {
495 if (help_file) {
496 *help_file = NULL;
497 }
498 if (topic_id) {
499 *topic_id = static_cast<LONG>(-1);
500 }
501 return E_NOTIMPL;
502 }
503
504 STDMETHODIMP NativeViewAccessibilityWin::put_accName(
505 VARIANT var_id, BSTR put_name) {
506 // Deprecated.
507 return E_NOTIMPL;
508 }
509
510 STDMETHODIMP NativeViewAccessibilityWin::put_accValue(
511 VARIANT var_id, BSTR put_val) {
512 // Deprecated.
513 return E_NOTIMPL;
514 }
515
516 //
517 // IAccessible2
518 //
519
520 STDMETHODIMP NativeViewAccessibilityWin::role(LONG* role) {
521 if (!view_)
522 return E_FAIL;
523
524 if (!role)
525 return E_INVALIDARG;
526
527 ui::AccessibleViewState state;
528 view_->GetAccessibleState(&state);
529 *role = MSAARole(state.role);
530 return S_OK;
531 }
532
533 STDMETHODIMP NativeViewAccessibilityWin::get_states(AccessibleStates* states) {
534 // This returns IAccessible2 states, which supplement MSAA states.
535 // See also the MSAA interface get_accState.
536
537 if (!view_)
538 return E_FAIL;
539
540 if (!states)
541 return E_INVALIDARG;
542
543 ui::AccessibleViewState state;
544 view_->GetAccessibleState(&state);
545
546 // There are only a couple of states we need to support
547 // in IAccessible2. If any more are added, we may want to
548 // add a helper function like MSAAState.
549 *states = IA2_STATE_OPAQUE;
550 if (state.state & AccessibilityTypes::STATE_EDITABLE)
551 *states |= IA2_STATE_EDITABLE;
552
553 return S_OK;
554 }
555
556 STDMETHODIMP NativeViewAccessibilityWin::get_uniqueID(LONG* unique_id) {
557 if (!view_)
558 return E_FAIL;
559
560 if (!unique_id)
561 return E_INVALIDARG;
562
563 *unique_id = unique_id_;
564 return S_OK;
565 }
566
567 STDMETHODIMP NativeViewAccessibilityWin::get_windowHandle(HWND* window_handle) {
568 if (!view_)
569 return E_FAIL;
570
571 if (!window_handle)
572 return E_INVALIDARG;
573
574 *window_handle = view_->GetWidget()->GetNativeView();
575 return S_OK;
576 }
577
578 //
579 // IAccessibleText
580 //
581
582 STDMETHODIMP NativeViewAccessibilityWin::get_nCharacters(LONG* n_characters) {
583 if (!view_)
584 return E_FAIL;
585
586 if (!n_characters)
587 return E_INVALIDARG;
588
589 string16 text = TextForIAccessibleText();
590 *n_characters = static_cast<LONG>(text.size());
591 return S_OK;
592 }
593
594 STDMETHODIMP NativeViewAccessibilityWin::get_caretOffset(LONG* offset) {
595 if (!view_)
596 return E_FAIL;
597
598 if (!offset)
599 return E_INVALIDARG;
600
601 ui::AccessibleViewState state;
602 view_->GetAccessibleState(&state);
603 *offset = static_cast<LONG>(state.selection_end);
604 return S_OK;
605 }
606
607 STDMETHODIMP NativeViewAccessibilityWin::get_nSelections(LONG* n_selections) {
608 if (!view_)
609 return E_FAIL;
610
611 if (!n_selections)
612 return E_INVALIDARG;
613
614 ui::AccessibleViewState state;
615 view_->GetAccessibleState(&state);
616 if (state.selection_start != state.selection_end)
617 *n_selections = 1;
618 else
619 *n_selections = 0;
620 return S_OK;
621 }
622
623 STDMETHODIMP NativeViewAccessibilityWin::get_selection(LONG selection_index,
624 LONG* start_offset,
625 LONG* end_offset) {
626 if (!view_)
627 return E_FAIL;
628
629 if (!start_offset || !end_offset || selection_index != 0)
630 return E_INVALIDARG;
631
632 ui::AccessibleViewState state;
633 view_->GetAccessibleState(&state);
634 *start_offset = static_cast<LONG>(state.selection_start);
635 *end_offset = static_cast<LONG>(state.selection_end);
636 return S_OK;
637 }
638
639 STDMETHODIMP NativeViewAccessibilityWin::get_text(LONG start_offset,
640 LONG end_offset,
641 BSTR* text) {
642 if (!view_)
643 return E_FAIL;
644
645 ui::AccessibleViewState state;
646 view_->GetAccessibleState(&state);
647 string16 text_str = TextForIAccessibleText();
648 LONG len = static_cast<LONG>(text_str.size());
649
650 if (start_offset == IA2_TEXT_OFFSET_LENGTH) {
651 start_offset = len;
652 } else if (start_offset == IA2_TEXT_OFFSET_CARET) {
653 start_offset = static_cast<LONG>(state.selection_end);
654 }
655 if (end_offset == IA2_TEXT_OFFSET_LENGTH) {
656 end_offset = static_cast<LONG>(text_str.size());
657 } else if (end_offset == IA2_TEXT_OFFSET_CARET) {
658 end_offset = static_cast<LONG>(state.selection_end);
659 }
660
661 // The spec allows the arguments to be reversed.
662 if (start_offset > end_offset) {
663 LONG tmp = start_offset;
664 start_offset = end_offset;
665 end_offset = tmp;
666 }
667
668 // The spec does not allow the start or end offsets to be out or range;
669 // we must return an error if so.
670 if (start_offset < 0)
671 return E_INVALIDARG;
672 if (end_offset > len)
673 return E_INVALIDARG;
674
675 string16 substr = text_str.substr(start_offset, end_offset - start_offset);
676 if (substr.empty())
677 return S_FALSE;
678
679 *text = SysAllocString(substr.c_str());
680 DCHECK(*text);
681 return S_OK;
682 }
683
684 STDMETHODIMP NativeViewAccessibilityWin::get_textAtOffset(
685 LONG offset,
686 enum IA2TextBoundaryType boundary_type,
687 LONG* start_offset, LONG* end_offset,
688 BSTR* text) {
689 if (!start_offset || !end_offset || !text)
690 return E_INVALIDARG;
691
692 // The IAccessible2 spec says we don't have to implement the "sentence"
693 // boundary type, we can just let the screenreader handle it.
694 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
695 *start_offset = 0;
696 *end_offset = 0;
697 *text = NULL;
698 return S_FALSE;
699 }
700
701 const string16& text_str = TextForIAccessibleText();
702
703 *start_offset = FindBoundary(
704 text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
705 *end_offset = FindBoundary(
706 text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
707 return get_text(*start_offset, *end_offset, text);
708 }
709
710 STDMETHODIMP NativeViewAccessibilityWin::get_textBeforeOffset(
711 LONG offset,
712 enum IA2TextBoundaryType boundary_type,
713 LONG* start_offset, LONG* end_offset,
714 BSTR* text) {
715 if (!start_offset || !end_offset || !text)
716 return E_INVALIDARG;
717
718 // The IAccessible2 spec says we don't have to implement the "sentence"
719 // boundary type, we can just let the screenreader handle it.
720 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
721 *start_offset = 0;
722 *end_offset = 0;
723 *text = NULL;
724 return S_FALSE;
725 }
726
727 const string16& text_str = TextForIAccessibleText();
728
729 *start_offset = FindBoundary(
730 text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
731 *end_offset = offset;
732 return get_text(*start_offset, *end_offset, text);
733 }
734
735 STDMETHODIMP NativeViewAccessibilityWin::get_textAfterOffset(
736 LONG offset,
737 enum IA2TextBoundaryType boundary_type,
738 LONG* start_offset, LONG* end_offset,
739 BSTR* text) {
740 if (!start_offset || !end_offset || !text)
741 return E_INVALIDARG;
742
743 // The IAccessible2 spec says we don't have to implement the "sentence"
744 // boundary type, we can just let the screenreader handle it.
745 if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
746 *start_offset = 0;
747 *end_offset = 0;
748 *text = NULL;
749 return S_FALSE;
750 }
751
752 const string16& text_str = TextForIAccessibleText();
753
754 *start_offset = offset;
755 *end_offset = FindBoundary(
756 text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
757 return get_text(*start_offset, *end_offset, text);
758 }
759
760 STDMETHODIMP NativeViewAccessibilityWin::get_offsetAtPoint(
761 LONG x, LONG y, enum IA2CoordinateType coord_type, LONG* offset) {
762 if (!view_)
763 return E_FAIL;
764
765 if (!offset)
766 return E_INVALIDARG;
767
768 // We don't support this method, but we have to return something
769 // rather than E_NOTIMPL or screen readers will complain.
770 *offset = 0;
771 return S_OK;
772 }
773
774 //
775 // IServiceProvider methods.
776 //
777
778 STDMETHODIMP NativeViewAccessibilityWin::QueryService(
779 REFGUID guidService, REFIID riid, void** object) {
780 if (!view_)
781 return E_FAIL;
782
783 if (guidService == IID_IAccessible ||
784 guidService == IID_IAccessible2 ||
785 guidService == IID_IAccessibleText) {
786 return QueryInterface(riid, object);
787 }
788
789 *object = NULL;
790 return E_FAIL;
791 }
792
793 //
794 // Static methods.
795 //
796
797 int32 NativeViewAccessibilityWin::MSAAEvent(AccessibilityTypes::Event event) {
798 switch (event) {
799 case AccessibilityTypes::EVENT_ALERT:
800 return EVENT_SYSTEM_ALERT;
801 case AccessibilityTypes::EVENT_FOCUS:
802 return EVENT_OBJECT_FOCUS;
803 case AccessibilityTypes::EVENT_MENUSTART:
804 return EVENT_SYSTEM_MENUSTART;
805 case AccessibilityTypes::EVENT_MENUEND:
806 return EVENT_SYSTEM_MENUEND;
807 case AccessibilityTypes::EVENT_MENUPOPUPSTART:
808 return EVENT_SYSTEM_MENUPOPUPSTART;
809 case AccessibilityTypes::EVENT_MENUPOPUPEND:
810 return EVENT_SYSTEM_MENUPOPUPEND;
811 case AccessibilityTypes::EVENT_NAME_CHANGED:
812 return EVENT_OBJECT_NAMECHANGE;
813 case AccessibilityTypes::EVENT_TEXT_CHANGED:
814 return EVENT_OBJECT_VALUECHANGE;
815 case AccessibilityTypes::EVENT_SELECTION_CHANGED:
816 return IA2_EVENT_TEXT_CARET_MOVED;
817 case AccessibilityTypes::EVENT_VALUE_CHANGED:
818 return EVENT_OBJECT_VALUECHANGE;
819 default:
820 // Not supported or invalid event.
821 NOTREACHED();
822 return -1;
823 }
824 }
825
826 int32 NativeViewAccessibilityWin::MSAARole(AccessibilityTypes::Role role) {
827 switch (role) {
828 case AccessibilityTypes::ROLE_ALERT:
829 return ROLE_SYSTEM_ALERT;
830 case AccessibilityTypes::ROLE_APPLICATION:
831 return ROLE_SYSTEM_APPLICATION;
832 case AccessibilityTypes::ROLE_BUTTONDROPDOWN:
833 return ROLE_SYSTEM_BUTTONDROPDOWN;
834 case AccessibilityTypes::ROLE_BUTTONMENU:
835 return ROLE_SYSTEM_BUTTONMENU;
836 case AccessibilityTypes::ROLE_CHECKBUTTON:
837 return ROLE_SYSTEM_CHECKBUTTON;
838 case AccessibilityTypes::ROLE_COMBOBOX:
839 return ROLE_SYSTEM_COMBOBOX;
840 case AccessibilityTypes::ROLE_DIALOG:
841 return ROLE_SYSTEM_DIALOG;
842 case AccessibilityTypes::ROLE_GRAPHIC:
843 return ROLE_SYSTEM_GRAPHIC;
844 case AccessibilityTypes::ROLE_GROUPING:
845 return ROLE_SYSTEM_GROUPING;
846 case AccessibilityTypes::ROLE_LINK:
847 return ROLE_SYSTEM_LINK;
848 case AccessibilityTypes::ROLE_LOCATION_BAR:
849 return ROLE_SYSTEM_GROUPING;
850 case AccessibilityTypes::ROLE_MENUBAR:
851 return ROLE_SYSTEM_MENUBAR;
852 case AccessibilityTypes::ROLE_MENUITEM:
853 return ROLE_SYSTEM_MENUITEM;
854 case AccessibilityTypes::ROLE_MENUPOPUP:
855 return ROLE_SYSTEM_MENUPOPUP;
856 case AccessibilityTypes::ROLE_OUTLINE:
857 return ROLE_SYSTEM_OUTLINE;
858 case AccessibilityTypes::ROLE_OUTLINEITEM:
859 return ROLE_SYSTEM_OUTLINEITEM;
860 case AccessibilityTypes::ROLE_PAGETAB:
861 return ROLE_SYSTEM_PAGETAB;
862 case AccessibilityTypes::ROLE_PAGETABLIST:
863 return ROLE_SYSTEM_PAGETABLIST;
864 case AccessibilityTypes::ROLE_PANE:
865 return ROLE_SYSTEM_PANE;
866 case AccessibilityTypes::ROLE_PROGRESSBAR:
867 return ROLE_SYSTEM_PROGRESSBAR;
868 case AccessibilityTypes::ROLE_PUSHBUTTON:
869 return ROLE_SYSTEM_PUSHBUTTON;
870 case AccessibilityTypes::ROLE_RADIOBUTTON:
871 return ROLE_SYSTEM_RADIOBUTTON;
872 case AccessibilityTypes::ROLE_SCROLLBAR:
873 return ROLE_SYSTEM_SCROLLBAR;
874 case AccessibilityTypes::ROLE_SEPARATOR:
875 return ROLE_SYSTEM_SEPARATOR;
876 case AccessibilityTypes::ROLE_STATICTEXT:
877 return ROLE_SYSTEM_STATICTEXT;
878 case AccessibilityTypes::ROLE_TEXT:
879 return ROLE_SYSTEM_TEXT;
880 case AccessibilityTypes::ROLE_TITLEBAR:
881 return ROLE_SYSTEM_TITLEBAR;
882 case AccessibilityTypes::ROLE_TOOLBAR:
883 return ROLE_SYSTEM_TOOLBAR;
884 case AccessibilityTypes::ROLE_WINDOW:
885 return ROLE_SYSTEM_WINDOW;
886 case AccessibilityTypes::ROLE_CLIENT:
887 default:
888 // This is the default role for MSAA.
889 return ROLE_SYSTEM_CLIENT;
890 }
891 }
892
893 int32 NativeViewAccessibilityWin::MSAAState(AccessibilityTypes::State state) {
894 // This maps MSAA states for get_accState(). See also the IAccessible2
895 // interface get_states().
896
897 int32 msaa_state = 0;
898 if (state & AccessibilityTypes::STATE_CHECKED)
899 msaa_state |= STATE_SYSTEM_CHECKED;
900 if (state & AccessibilityTypes::STATE_COLLAPSED)
901 msaa_state |= STATE_SYSTEM_COLLAPSED;
902 if (state & AccessibilityTypes::STATE_DEFAULT)
903 msaa_state |= STATE_SYSTEM_DEFAULT;
904 if (state & AccessibilityTypes::STATE_EXPANDED)
905 msaa_state |= STATE_SYSTEM_EXPANDED;
906 if (state & AccessibilityTypes::STATE_HASPOPUP)
907 msaa_state |= STATE_SYSTEM_HASPOPUP;
908 if (state & AccessibilityTypes::STATE_HOTTRACKED)
909 msaa_state |= STATE_SYSTEM_HOTTRACKED;
910 if (state & AccessibilityTypes::STATE_INVISIBLE)
911 msaa_state |= STATE_SYSTEM_INVISIBLE;
912 if (state & AccessibilityTypes::STATE_LINKED)
913 msaa_state |= STATE_SYSTEM_LINKED;
914 if (state & AccessibilityTypes::STATE_OFFSCREEN)
915 msaa_state |= STATE_SYSTEM_OFFSCREEN;
916 if (state & AccessibilityTypes::STATE_PRESSED)
917 msaa_state |= STATE_SYSTEM_PRESSED;
918 if (state & AccessibilityTypes::STATE_PROTECTED)
919 msaa_state |= STATE_SYSTEM_PROTECTED;
920 if (state & AccessibilityTypes::STATE_READONLY)
921 msaa_state |= STATE_SYSTEM_READONLY;
922 if (state & AccessibilityTypes::STATE_SELECTED)
923 msaa_state |= STATE_SYSTEM_SELECTED;
924 if (state & AccessibilityTypes::STATE_FOCUSED)
925 msaa_state |= STATE_SYSTEM_FOCUSED;
926 if (state & AccessibilityTypes::STATE_UNAVAILABLE)
927 msaa_state |= STATE_SYSTEM_UNAVAILABLE;
928 return msaa_state;
929 }
930
931 //
932 // Private methods.
933 //
934
935 bool NativeViewAccessibilityWin::IsNavDirNext(int nav_dir) const {
936 return (nav_dir == NAVDIR_RIGHT ||
937 nav_dir == NAVDIR_DOWN ||
938 nav_dir == NAVDIR_NEXT);
939 }
940
941 bool NativeViewAccessibilityWin::IsValidNav(
942 int nav_dir, int start_id, int lower_bound, int upper_bound) const {
943 if (IsNavDirNext(nav_dir)) {
944 if ((start_id + 1) > upper_bound) {
945 return false;
946 }
947 } else {
948 if ((start_id - 1) <= lower_bound) {
949 return false;
950 }
951 }
952 return true;
953 }
954
955 bool NativeViewAccessibilityWin::IsValidId(const VARIANT& child) const {
956 // View accessibility returns an IAccessible for each view so we only support
957 // the CHILDID_SELF id.
958 return (VT_I4 == child.vt) && (CHILDID_SELF == child.lVal);
959 }
960
961 void NativeViewAccessibilityWin::SetState(
962 VARIANT* msaa_state, views::View* view) {
963 // Ensure the output param is initialized to zero.
964 msaa_state->lVal = 0;
965
966 // Default state; all views can have accessibility focus.
967 msaa_state->lVal |= STATE_SYSTEM_FOCUSABLE;
968
969 if (!view)
970 return;
971
972 if (!view->IsEnabled())
973 msaa_state->lVal |= STATE_SYSTEM_UNAVAILABLE;
974 if (!view->IsVisible())
975 msaa_state->lVal |= STATE_SYSTEM_INVISIBLE;
976 if (view->IsHotTracked())
977 msaa_state->lVal |= STATE_SYSTEM_HOTTRACKED;
978 if (view->HasFocus())
979 msaa_state->lVal |= STATE_SYSTEM_FOCUSED;
980
981 // Add on any view-specific states.
982 ui::AccessibleViewState view_state;
983 view->GetAccessibleState(&view_state);
984 msaa_state->lVal |= MSAAState(view_state.state);
985 }
986
987 string16 NativeViewAccessibilityWin::TextForIAccessibleText() {
988 ui::AccessibleViewState state;
989 view_->GetAccessibleState(&state);
990 if (state.role == AccessibilityTypes::ROLE_TEXT)
991 return state.value;
992 else
993 return state.name;
994 }
995
996 void NativeViewAccessibilityWin::HandleSpecialTextOffset(
997 const string16& text, LONG* offset) {
998 if (*offset == IA2_TEXT_OFFSET_LENGTH) {
999 *offset = static_cast<LONG>(text.size());
1000 } else if (*offset == IA2_TEXT_OFFSET_CARET) {
1001 get_caretOffset(offset);
1002 }
1003 }
1004
1005 ui::TextBoundaryType NativeViewAccessibilityWin::IA2TextBoundaryToTextBoundary(
1006 IA2TextBoundaryType ia2_boundary) {
1007 switch(ia2_boundary) {
1008 case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY;
1009 case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY;
1010 case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY;
1011 case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY;
1012 case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY;
1013 case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY;
1014 default:
1015 NOTREACHED();
1016 return ui::CHAR_BOUNDARY;
1017 }
1018 }
1019
1020 LONG NativeViewAccessibilityWin::FindBoundary(
1021 const string16& text,
1022 IA2TextBoundaryType ia2_boundary,
1023 LONG start_offset,
1024 ui::TextBoundaryDirection direction) {
1025 HandleSpecialTextOffset(text, &start_offset);
1026 ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
1027 std::vector<int32> line_breaks;
1028 return ui::FindAccessibleTextBoundary(
1029 text, line_breaks, boundary, start_offset, direction);
1030 }
OLDNEW
« no previous file with comments | « views/accessibility/native_view_accessibility_win.h ('k') | views/view.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698