Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / views / accessibility / native_view_accessibility_win.cc
1 // Copyright (c) 2012 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 "ui/views/accessibility/native_view_accessibility_win.h"
6
7 #include <oleacc.h>
8 #include <UIAutomationClient.h>
9
10 #include <set>
11 #include <vector>
12
13 #include "base/memory/singleton.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/win/scoped_comptr.h"
16 #include "base/win/windows_version.h"
17 #include "third_party/iaccessible2/ia2_api_all.h"
18 #include "ui/accessibility/ax_enums.h"
19 #include "ui/accessibility/ax_text_utils.h"
20 #include "ui/accessibility/ax_view_state.h"
21 #include "ui/base/win/accessibility_ids_win.h"
22 #include "ui/base/win/accessibility_misc_utils.h"
23 #include "ui/base/win/atl_module.h"
24 #include "ui/views/controls/button/custom_button.h"
25 #include "ui/views/focus/focus_manager.h"
26 #include "ui/views/focus/view_storage.h"
27 #include "ui/views/widget/widget.h"
28 #include "ui/views/win/hwnd_util.h"
29
30 namespace views {
31 namespace {
32
33 class AccessibleWebViewRegistry {
34  public:
35   static AccessibleWebViewRegistry* GetInstance();
36
37   void RegisterWebView(View* web_view);
38
39   void UnregisterWebView(View* web_view);
40
41   // Given the view that received the request for the accessible
42   // id in |top_view|, and the child id requested, return the native
43   // accessible object with that child id from one of the WebViews in
44   // |top_view|'s view hierarchy, if any.
45   IAccessible* GetAccessibleFromWebView(View* top_view, long child_id);
46
47   // The system uses IAccessible APIs for many purposes, but only
48   // assistive technology like screen readers uses IAccessible2.
49   // Call this method to note that the IAccessible2 interface was queried and
50   // that WebViews should be proactively notified that this interface will be
51   // used. If this is enabled for the first time, this will explicitly call
52   // QueryService with an argument of IAccessible2 on all WebViews, otherwise
53   // it will just do it from now on.
54   void EnableIAccessible2Support();
55
56  private:
57   friend struct DefaultSingletonTraits<AccessibleWebViewRegistry>;
58   AccessibleWebViewRegistry();
59   ~AccessibleWebViewRegistry() {}
60
61   IAccessible* AccessibleObjectFromChildId(View* web_view, long child_id);
62
63   void QueryIAccessible2Interface(View* web_view);
64
65   // Set of all web views. We check whether each one is contained in a
66   // top view dynamically rather than keeping track of a map.
67   std::set<View*> web_views_;
68
69   // The most recent top view used in a call to GetAccessibleFromWebView.
70   View* last_top_view_;
71
72   // The most recent web view where an accessible object was found,
73   // corresponding to |last_top_view_|.
74   View* last_web_view_;
75
76   // If IAccessible2 support is enabled, we query the IAccessible2 interface
77   // of WebViews proactively when they're registered, so that they are
78   // aware that they need to support this interface.
79   bool iaccessible2_support_enabled_;
80
81   DISALLOW_COPY_AND_ASSIGN(AccessibleWebViewRegistry);
82 };
83
84 AccessibleWebViewRegistry::AccessibleWebViewRegistry()
85     : last_top_view_(NULL),
86       last_web_view_(NULL),
87       iaccessible2_support_enabled_(false) {
88 }
89
90 AccessibleWebViewRegistry* AccessibleWebViewRegistry::GetInstance() {
91   return Singleton<AccessibleWebViewRegistry>::get();
92 }
93
94 void AccessibleWebViewRegistry::RegisterWebView(View* web_view) {
95   DCHECK(web_views_.find(web_view) == web_views_.end());
96   web_views_.insert(web_view);
97
98   if (iaccessible2_support_enabled_)
99     QueryIAccessible2Interface(web_view);
100 }
101
102 void AccessibleWebViewRegistry::UnregisterWebView(View* web_view) {
103   DCHECK(web_views_.find(web_view) != web_views_.end());
104   web_views_.erase(web_view);
105   if (last_web_view_ == web_view) {
106     last_top_view_ = NULL;
107     last_web_view_ = NULL;
108   }
109 }
110
111 IAccessible* AccessibleWebViewRegistry::GetAccessibleFromWebView(
112     View* top_view, long child_id) {
113   // This function gets called frequently, so try to avoid searching all
114   // of the web views if the notification is on the same web view that
115   // sent the last one.
116   if (last_top_view_ == top_view) {
117     IAccessible* accessible =
118         AccessibleObjectFromChildId(last_web_view_, child_id);
119     if (accessible)
120       return accessible;
121   }
122
123   // Search all web views. For each one, first ensure it's a descendant
124   // of this view where the event was posted - and if so, see if it owns
125   // an accessible object with that child id. If so, save the view to speed
126   // up the next notification.
127   for (std::set<View*>::iterator iter = web_views_.begin();
128        iter != web_views_.end(); ++iter) {
129     View* web_view = *iter;
130     if (top_view == web_view || !top_view->Contains(web_view))
131       continue;
132     IAccessible* accessible = AccessibleObjectFromChildId(web_view, child_id);
133     if (accessible) {
134       last_top_view_ = top_view;
135       last_web_view_ = web_view;
136       return accessible;
137     }
138   }
139
140   return NULL;
141 }
142
143 void AccessibleWebViewRegistry::EnableIAccessible2Support() {
144   if (iaccessible2_support_enabled_)
145     return;
146   iaccessible2_support_enabled_ = true;
147   for (std::set<View*>::iterator iter = web_views_.begin();
148        iter != web_views_.end(); ++iter) {
149     QueryIAccessible2Interface(*iter);
150   }
151 }
152
153 IAccessible* AccessibleWebViewRegistry::AccessibleObjectFromChildId(
154     View* web_view,
155     long child_id) {
156   IAccessible* web_view_accessible = web_view->GetNativeViewAccessible();
157   if (web_view_accessible == NULL)
158     return NULL;
159
160   VARIANT var_child;
161   var_child.vt = VT_I4;
162   var_child.lVal = child_id;
163   IAccessible* result = NULL;
164   if (S_OK == web_view_accessible->get_accChild(
165       var_child, reinterpret_cast<IDispatch**>(&result))) {
166     return result;
167   }
168
169   return NULL;
170 }
171
172 void AccessibleWebViewRegistry::QueryIAccessible2Interface(View* web_view) {
173   IAccessible* web_view_accessible = web_view->GetNativeViewAccessible();
174   if (!web_view_accessible)
175     return;
176
177   base::win::ScopedComPtr<IServiceProvider> service_provider;
178   if (S_OK != web_view_accessible->QueryInterface(service_provider.Receive()))
179     return;
180   base::win::ScopedComPtr<IAccessible2> iaccessible2;
181   service_provider->QueryService(
182       IID_IAccessible, IID_IAccessible2,
183       reinterpret_cast<void**>(iaccessible2.Receive()));
184 }
185
186 }  // anonymous namespace
187
188 // static
189 long NativeViewAccessibilityWin::next_unique_id_ = 1;
190 int NativeViewAccessibilityWin::view_storage_ids_[kMaxViewStorageIds] = {0};
191 int NativeViewAccessibilityWin::next_view_storage_id_index_ = 0;
192 std::vector<int> NativeViewAccessibilityWin::alert_target_view_storage_ids_;
193
194 // static
195 NativeViewAccessibility* NativeViewAccessibility::Create(View* view) {
196   // Make sure ATL is initialized in this module.
197   ui::win::CreateATLModuleIfNeeded();
198
199   CComObject<NativeViewAccessibilityWin>* instance = NULL;
200   HRESULT hr = CComObject<NativeViewAccessibilityWin>::CreateInstance(
201       &instance);
202   DCHECK(SUCCEEDED(hr));
203   instance->set_view(view);
204   instance->AddRef();
205   return instance;
206 }
207
208 NativeViewAccessibilityWin::NativeViewAccessibilityWin()
209     : unique_id_(next_unique_id_++) {
210 }
211
212 NativeViewAccessibilityWin::~NativeViewAccessibilityWin() {
213   RemoveAlertTarget();
214 }
215
216 void NativeViewAccessibilityWin::NotifyAccessibilityEvent(
217     ui::AXEvent event_type) {
218   if (!view_)
219     return;
220
221   ViewStorage* view_storage = ViewStorage::GetInstance();
222   HWND hwnd = HWNDForView(view_);
223   int view_storage_id = view_storage_ids_[next_view_storage_id_index_];
224   if (view_storage_id == 0) {
225     view_storage_id = view_storage->CreateStorageID();
226     view_storage_ids_[next_view_storage_id_index_] = view_storage_id;
227   } else {
228     view_storage->RemoveView(view_storage_id);
229   }
230   view_storage->StoreView(view_storage_id, view_);
231
232   // Positive child ids are used for enumerating direct children,
233   // negative child ids can be used as unique ids to refer to a specific
234   // descendants.  Make index into view_storage_ids_ into a negative child id.
235   int child_id =
236       base::win::kFirstViewsAccessibilityId - next_view_storage_id_index_;
237   ::NotifyWinEvent(MSAAEvent(event_type), hwnd, OBJID_CLIENT, child_id);
238   next_view_storage_id_index_ =
239       (next_view_storage_id_index_ + 1) % kMaxViewStorageIds;
240
241   // Keep track of views that are a target of an alert event.
242   if (event_type == ui::AX_EVENT_ALERT)
243     AddAlertTarget();
244 }
245
246 gfx::NativeViewAccessible NativeViewAccessibilityWin::GetNativeObject() {
247   return this;
248 }
249
250 void NativeViewAccessibilityWin::Destroy() {
251   view_ = NULL;
252   Release();
253 }
254
255 STDMETHODIMP NativeViewAccessibilityWin::accHitTest(
256     LONG x_left, LONG y_top, VARIANT* child) {
257   if (!child)
258     return E_INVALIDARG;
259
260   if (!view_ || !view_->GetWidget())
261     return E_FAIL;
262
263   // If this is a root view, our widget might have child widgets.
264   // Search child widgets first, since they're on top in the z-order.
265   if (view_->GetWidget()->GetRootView() == view_) {
266     std::vector<Widget*> child_widgets;
267     PopulateChildWidgetVector(&child_widgets);
268     for (size_t i = 0; i < child_widgets.size(); ++i) {
269       Widget* child_widget = child_widgets[i];
270       IAccessible* child_accessible =
271           child_widget->GetRootView()->GetNativeViewAccessible();
272       HRESULT result = child_accessible->accHitTest(x_left, y_top, child);
273       if (result == S_OK)
274         return result;
275     }
276   }
277
278   gfx::Point point(x_left, y_top);
279   View::ConvertPointFromScreen(view_, &point);
280
281   // If the point is not inside this view, return false.
282   if (!view_->HitTestPoint(point)) {
283     child->vt = VT_EMPTY;
284     return S_FALSE;
285   }
286
287   // Check if the point is within any of the immediate children of this
288   // view.
289   View* hit_child_view = NULL;
290   for (int i = view_->child_count() - 1; i >= 0; --i) {
291     View* child_view = view_->child_at(i);
292     if (!child_view->visible())
293       continue;
294
295     gfx::Point point_in_child_coords(point);
296     view_->ConvertPointToTarget(view_, child_view, &point_in_child_coords);
297     if (child_view->HitTestPoint(point_in_child_coords)) {
298       hit_child_view = child_view;
299       break;
300     }
301   }
302
303   // If the point was within one of this view's immediate children,
304   // call accHitTest recursively on that child's native view accessible -
305   // which may be a recursive call to this function or it may be overridden,
306   // for example in the case of a WebView.
307   if (hit_child_view) {
308     HRESULT result = hit_child_view->GetNativeViewAccessible()->accHitTest(
309         x_left, y_top, child);
310
311     // If the recursive call returned CHILDID_SELF, we have to convert that
312     // into a VT_DISPATCH for the return value to this call.
313     if (S_OK == result && child->vt == VT_I4 && child->lVal == CHILDID_SELF) {
314       child->vt = VT_DISPATCH;
315       child->pdispVal = hit_child_view->GetNativeViewAccessible();
316       // Always increment ref when returning a reference to a COM object.
317       child->pdispVal->AddRef();
318     }
319     return result;
320   }
321
322   // This object is the best match, so return CHILDID_SELF. It's tempting to
323   // simplify the logic and use VT_DISPATCH everywhere, but the Windows
324   // call AccessibleObjectFromPoint will keep calling accHitTest until some
325   // object returns CHILDID_SELF.
326   child->vt = VT_I4;
327   child->lVal = CHILDID_SELF;
328   return S_OK;
329 }
330
331 HRESULT NativeViewAccessibilityWin::accDoDefaultAction(VARIANT var_id) {
332   if (!IsValidId(var_id))
333     return E_INVALIDARG;
334
335   // The object does not support the method. This value is returned for
336   // controls that do not perform actions, such as edit fields.
337   return DISP_E_MEMBERNOTFOUND;
338 }
339
340 STDMETHODIMP NativeViewAccessibilityWin::accLocation(
341     LONG* x_left, LONG* y_top, LONG* width, LONG* height, VARIANT var_id) {
342   if (!IsValidId(var_id) || !x_left || !y_top || !width || !height)
343     return E_INVALIDARG;
344
345   if (!view_)
346     return E_FAIL;
347
348   if (!view_->bounds().IsEmpty()) {
349     *width  = view_->width();
350     *height = view_->height();
351     gfx::Point topleft(view_->bounds().origin());
352     View::ConvertPointToScreen(
353         view_->parent() ? view_->parent() : view_, &topleft);
354     *x_left = topleft.x();
355     *y_top  = topleft.y();
356   } else {
357     return E_FAIL;
358   }
359   return S_OK;
360 }
361
362 STDMETHODIMP NativeViewAccessibilityWin::accNavigate(
363     LONG nav_dir, VARIANT start, VARIANT* end) {
364   if (start.vt != VT_I4 || !end)
365     return E_INVALIDARG;
366
367   if (!view_)
368     return E_FAIL;
369
370   switch (nav_dir) {
371     case NAVDIR_FIRSTCHILD:
372     case NAVDIR_LASTCHILD: {
373       if (start.lVal != CHILDID_SELF) {
374         // Start of navigation must be on the View itself.
375         return E_INVALIDARG;
376       } else if (!view_->has_children()) {
377         // No children found.
378         return S_FALSE;
379       }
380
381       // Set child_id based on first or last child.
382       int child_id = 0;
383       if (nav_dir == NAVDIR_LASTCHILD)
384         child_id = view_->child_count() - 1;
385
386       View* child = view_->child_at(child_id);
387       end->vt = VT_DISPATCH;
388       end->pdispVal = child->GetNativeViewAccessible();
389       end->pdispVal->AddRef();
390       return S_OK;
391     }
392     case NAVDIR_LEFT:
393     case NAVDIR_UP:
394     case NAVDIR_PREVIOUS:
395     case NAVDIR_RIGHT:
396     case NAVDIR_DOWN:
397     case NAVDIR_NEXT: {
398       // Retrieve parent to access view index and perform bounds checking.
399       View* parent = view_->parent();
400       if (!parent) {
401         return E_FAIL;
402       }
403
404       if (start.lVal == CHILDID_SELF) {
405         int view_index = parent->GetIndexOf(view_);
406         // Check navigation bounds, adjusting for View child indexing (MSAA
407         // child indexing starts with 1, whereas View indexing starts with 0).
408         if (!IsValidNav(nav_dir, view_index, -1,
409                         parent->child_count() - 1)) {
410           // Navigation attempted to go out-of-bounds.
411           end->vt = VT_EMPTY;
412           return S_FALSE;
413         } else {
414           if (IsNavDirNext(nav_dir)) {
415             view_index += 1;
416           } else {
417             view_index -=1;
418           }
419         }
420
421         View* child = parent->child_at(view_index);
422         end->pdispVal = child->GetNativeViewAccessible();
423         end->vt = VT_DISPATCH;
424         end->pdispVal->AddRef();
425         return S_OK;
426       } else {
427         // Check navigation bounds, adjusting for MSAA child indexing (MSAA
428         // child indexing starts with 1, whereas View indexing starts with 0).
429         if (!IsValidNav(nav_dir, start.lVal, 0, parent->child_count() + 1)) {
430             // Navigation attempted to go out-of-bounds.
431             end->vt = VT_EMPTY;
432             return S_FALSE;
433           } else {
434             if (IsNavDirNext(nav_dir)) {
435               start.lVal += 1;
436             } else {
437               start.lVal -= 1;
438             }
439         }
440
441         HRESULT result = this->get_accChild(start, &end->pdispVal);
442         if (result == S_FALSE) {
443           // Child is a leaf.
444           end->vt = VT_I4;
445           end->lVal = start.lVal;
446         } else if (result == E_INVALIDARG) {
447           return E_INVALIDARG;
448         } else {
449           // Child is not a leaf.
450           end->vt = VT_DISPATCH;
451         }
452       }
453       break;
454     }
455     default:
456       return E_INVALIDARG;
457   }
458   // Navigation performed correctly. Global return for this function, if no
459   // error triggered an escape earlier.
460   return S_OK;
461 }
462
463 STDMETHODIMP NativeViewAccessibilityWin::get_accChild(VARIANT var_child,
464                                                       IDispatch** disp_child) {
465   if (var_child.vt != VT_I4 || !disp_child)
466     return E_INVALIDARG;
467
468   if (!view_ || !view_->GetWidget())
469     return E_FAIL;
470
471   LONG child_id = V_I4(&var_child);
472
473   if (child_id == CHILDID_SELF) {
474     // Remain with the same dispatch.
475     return S_OK;
476   }
477
478   // If this is a root view, our widget might have child widgets. Include
479   std::vector<Widget*> child_widgets;
480   if (view_->GetWidget()->GetRootView() == view_)
481     PopulateChildWidgetVector(&child_widgets);
482   int child_widget_count = static_cast<int>(child_widgets.size());
483
484   View* child_view = NULL;
485   if (child_id > 0) {
486     // Positive child ids are a 1-based child index, used by clients
487     // that want to enumerate all immediate children.
488     int child_id_as_index = child_id - 1;
489     if (child_id_as_index < view_->child_count()) {
490       child_view = view_->child_at(child_id_as_index);
491     } else if (child_id_as_index < view_->child_count() + child_widget_count) {
492       Widget* child_widget =
493           child_widgets[child_id_as_index - view_->child_count()];
494       child_view = child_widget->GetRootView();
495     }
496   } else {
497     // Negative child ids can be used to map to any descendant.
498     // Check child widget first.
499     for (int i = 0; i < child_widget_count; i++) {
500       Widget* child_widget = child_widgets[i];
501       IAccessible* child_accessible =
502           child_widget->GetRootView()->GetNativeViewAccessible();
503       HRESULT result = child_accessible->get_accChild(var_child, disp_child);
504       if (result == S_OK)
505         return result;
506     }
507
508     // We map child ids to a view storage id that can refer to a
509     // specific view (if that view still exists).
510     int view_storage_id_index =
511         base::win::kFirstViewsAccessibilityId - child_id;
512     if (view_storage_id_index >= 0 &&
513         view_storage_id_index < kMaxViewStorageIds) {
514       int view_storage_id = view_storage_ids_[view_storage_id_index];
515       ViewStorage* view_storage = ViewStorage::GetInstance();
516       child_view = view_storage->RetrieveView(view_storage_id);
517     } else {
518       *disp_child = AccessibleWebViewRegistry::GetInstance()->
519           GetAccessibleFromWebView(view_, child_id);
520       if (*disp_child)
521         return S_OK;
522     }
523   }
524
525   if (!child_view) {
526     // No child found.
527     *disp_child = NULL;
528     return E_FAIL;
529   }
530
531   *disp_child = child_view->GetNativeViewAccessible();
532   if (*disp_child) {
533     (*disp_child)->AddRef();
534     return S_OK;
535   }
536
537   return E_FAIL;
538 }
539
540 STDMETHODIMP NativeViewAccessibilityWin::get_accChildCount(LONG* child_count) {
541   if (!child_count)
542     return E_INVALIDARG;
543
544   if (!view_ || !view_->GetWidget())
545     return E_FAIL;
546
547   *child_count = view_->child_count();
548
549   // If this is a root view, our widget might have child widgets. Include
550   // them, too.
551   if (view_->GetWidget()->GetRootView() == view_) {
552     std::vector<Widget*> child_widgets;
553     PopulateChildWidgetVector(&child_widgets);
554     *child_count += child_widgets.size();
555   }
556
557   return S_OK;
558 }
559
560 STDMETHODIMP NativeViewAccessibilityWin::get_accDefaultAction(
561     VARIANT var_id, BSTR* def_action) {
562   if (!IsValidId(var_id) || !def_action)
563     return E_INVALIDARG;
564
565   if (!view_)
566     return E_FAIL;
567
568   ui::AXViewState state;
569   view_->GetAccessibleState(&state);
570   base::string16 temp_action = state.default_action;
571
572   if (!temp_action.empty()) {
573     *def_action = SysAllocString(temp_action.c_str());
574   } else {
575     return S_FALSE;
576   }
577
578   return S_OK;
579 }
580
581 STDMETHODIMP NativeViewAccessibilityWin::get_accDescription(
582     VARIANT var_id, BSTR* desc) {
583   if (!IsValidId(var_id) || !desc)
584     return E_INVALIDARG;
585
586   if (!view_)
587     return E_FAIL;
588
589   base::string16 temp_desc;
590
591   view_->GetTooltipText(gfx::Point(), &temp_desc);
592   if (!temp_desc.empty()) {
593     *desc = SysAllocString(temp_desc.c_str());
594   } else {
595     return S_FALSE;
596   }
597
598   return S_OK;
599 }
600
601 STDMETHODIMP NativeViewAccessibilityWin::get_accFocus(VARIANT* focus_child) {
602   if (!focus_child)
603     return E_INVALIDARG;
604
605   if (!view_)
606     return E_FAIL;
607
608   FocusManager* focus_manager = view_->GetFocusManager();
609   View* focus = focus_manager ? focus_manager->GetFocusedView() : NULL;
610   if (focus == view_) {
611     // This view has focus.
612     focus_child->vt = VT_I4;
613     focus_child->lVal = CHILDID_SELF;
614   } else if (focus && view_->Contains(focus)) {
615     // Return the child object that has the keyboard focus.
616     focus_child->vt = VT_DISPATCH;
617     focus_child->pdispVal = focus->GetNativeViewAccessible();
618     focus_child->pdispVal->AddRef();
619     return S_OK;
620   } else {
621     // Neither this object nor any of its children has the keyboard focus.
622     focus_child->vt = VT_EMPTY;
623   }
624   return S_OK;
625 }
626
627 STDMETHODIMP NativeViewAccessibilityWin::get_accKeyboardShortcut(
628     VARIANT var_id, BSTR* acc_key) {
629   if (!IsValidId(var_id) || !acc_key)
630     return E_INVALIDARG;
631
632   if (!view_)
633     return E_FAIL;
634
635   ui::AXViewState state;
636   view_->GetAccessibleState(&state);
637   base::string16 temp_key = state.keyboard_shortcut;
638
639   if (!temp_key.empty()) {
640     *acc_key = SysAllocString(temp_key.c_str());
641   } else {
642     return S_FALSE;
643   }
644
645   return S_OK;
646 }
647
648 STDMETHODIMP NativeViewAccessibilityWin::get_accName(
649     VARIANT var_id, BSTR* name) {
650   if (!IsValidId(var_id) || !name)
651     return E_INVALIDARG;
652
653   if (!view_)
654     return E_FAIL;
655
656   // Retrieve the current view's name.
657   ui::AXViewState state;
658   view_->GetAccessibleState(&state);
659   base::string16 temp_name = state.name;
660   if (!temp_name.empty()) {
661     // Return name retrieved.
662     *name = SysAllocString(temp_name.c_str());
663   } else {
664     // If view has no name, return S_FALSE.
665     return S_FALSE;
666   }
667
668   return S_OK;
669 }
670
671 STDMETHODIMP NativeViewAccessibilityWin::get_accParent(
672     IDispatch** disp_parent) {
673   if (!disp_parent)
674     return E_INVALIDARG;
675
676   if (!view_)
677     return E_FAIL;
678
679   *disp_parent = NULL;
680   View* parent_view = view_->parent();
681
682   if (!parent_view) {
683     HWND hwnd = HWNDForView(view_);
684     if (!hwnd)
685       return S_FALSE;
686
687     return ::AccessibleObjectFromWindow(
688         hwnd, OBJID_WINDOW, IID_IAccessible,
689         reinterpret_cast<void**>(disp_parent));
690   }
691
692   *disp_parent = parent_view->GetNativeViewAccessible();
693   (*disp_parent)->AddRef();
694   return S_OK;
695 }
696
697 STDMETHODIMP NativeViewAccessibilityWin::get_accRole(
698     VARIANT var_id, VARIANT* role) {
699   if (!IsValidId(var_id) || !role)
700     return E_INVALIDARG;
701
702   if (!view_)
703     return E_FAIL;
704
705   ui::AXViewState state;
706   view_->GetAccessibleState(&state);
707   role->vt = VT_I4;
708   role->lVal = MSAARole(state.role);
709   return S_OK;
710 }
711
712 STDMETHODIMP NativeViewAccessibilityWin::get_accState(
713     VARIANT var_id, VARIANT* state) {
714   // This returns MSAA states. See also the IAccessible2 interface
715   // get_states().
716
717   if (!IsValidId(var_id) || !state)
718     return E_INVALIDARG;
719
720   if (!view_)
721     return E_FAIL;
722
723   state->vt = VT_I4;
724
725   // Retrieve all currently applicable states of the parent.
726   SetState(state, view_);
727
728   // Make sure that state is not empty, and has the proper type.
729   if (state->vt == VT_EMPTY)
730     return E_FAIL;
731
732   return S_OK;
733 }
734
735 STDMETHODIMP NativeViewAccessibilityWin::get_accValue(VARIANT var_id,
736                                                       BSTR* value) {
737   if (!IsValidId(var_id) || !value)
738     return E_INVALIDARG;
739
740   if (!view_)
741     return E_FAIL;
742
743   // Retrieve the current view's value.
744   ui::AXViewState state;
745   view_->GetAccessibleState(&state);
746   base::string16 temp_value = state.value;
747
748   if (!temp_value.empty()) {
749     // Return value retrieved.
750     *value = SysAllocString(temp_value.c_str());
751   } else {
752     // If view has no value, fall back into the default implementation.
753     *value = NULL;
754     return E_NOTIMPL;
755   }
756
757   return S_OK;
758 }
759
760 STDMETHODIMP NativeViewAccessibilityWin::put_accValue(VARIANT var_id,
761                                                       BSTR new_value) {
762   if (!IsValidId(var_id) || !new_value)
763     return E_INVALIDARG;
764
765   if (!view_)
766     return E_FAIL;
767
768   // Return an error if the view can't set the value.
769   ui::AXViewState state;
770   view_->GetAccessibleState(&state);
771   if (state.set_value_callback.is_null())
772     return E_FAIL;
773
774   state.set_value_callback.Run(new_value);
775   return S_OK;
776 }
777
778 // IAccessible functions not supported.
779
780 STDMETHODIMP NativeViewAccessibilityWin::get_accSelection(VARIANT* selected) {
781   if (selected)
782     selected->vt = VT_EMPTY;
783   return E_NOTIMPL;
784 }
785
786 STDMETHODIMP NativeViewAccessibilityWin::accSelect(
787     LONG flagsSelect, VARIANT var_id) {
788   return E_NOTIMPL;
789 }
790
791 STDMETHODIMP NativeViewAccessibilityWin::get_accHelp(
792     VARIANT var_id, BSTR* help) {
793   base::string16 temp = base::UTF8ToUTF16(view_->GetClassName());
794   *help = SysAllocString(temp.c_str());
795   return S_OK;
796 }
797
798 STDMETHODIMP NativeViewAccessibilityWin::get_accHelpTopic(
799     BSTR* help_file, VARIANT var_id, LONG* topic_id) {
800   if (help_file) {
801     *help_file = NULL;
802   }
803   if (topic_id) {
804     *topic_id = static_cast<LONG>(-1);
805   }
806   return E_NOTIMPL;
807 }
808
809 STDMETHODIMP NativeViewAccessibilityWin::put_accName(
810     VARIANT var_id, BSTR put_name) {
811   // Deprecated.
812   return E_NOTIMPL;
813 }
814
815 //
816 // IAccessible2
817 //
818
819 STDMETHODIMP NativeViewAccessibilityWin::role(LONG* role) {
820   if (!view_)
821     return E_FAIL;
822
823   if (!role)
824     return E_INVALIDARG;
825
826   ui::AXViewState state;
827   view_->GetAccessibleState(&state);
828   *role = MSAARole(state.role);
829   return S_OK;
830 }
831
832 STDMETHODIMP NativeViewAccessibilityWin::get_states(AccessibleStates* states) {
833   // This returns IAccessible2 states, which supplement MSAA states.
834   // See also the MSAA interface get_accState.
835
836   if (!view_)
837     return E_FAIL;
838
839   if (!states)
840     return E_INVALIDARG;
841
842   ui::AXViewState state;
843   view_->GetAccessibleState(&state);
844
845   // There are only a couple of states we need to support
846   // in IAccessible2. If any more are added, we may want to
847   // add a helper function like MSAAState.
848   *states = IA2_STATE_OPAQUE;
849   if (state.HasStateFlag(ui::AX_STATE_EDITABLE))
850     *states |= IA2_STATE_EDITABLE;
851
852   return S_OK;
853 }
854
855 STDMETHODIMP NativeViewAccessibilityWin::get_uniqueID(LONG* unique_id) {
856   if (!view_)
857     return E_FAIL;
858
859   if (!unique_id)
860     return E_INVALIDARG;
861
862   *unique_id = unique_id_;
863   return S_OK;
864 }
865
866 STDMETHODIMP NativeViewAccessibilityWin::get_windowHandle(HWND* window_handle) {
867   if (!view_)
868     return E_FAIL;
869
870   if (!window_handle)
871     return E_INVALIDARG;
872
873   *window_handle = HWNDForView(view_);
874   return *window_handle ? S_OK : S_FALSE;
875 }
876
877 STDMETHODIMP NativeViewAccessibilityWin::get_relationTargetsOfType(
878     BSTR type_bstr,
879     long max_targets,
880     IUnknown ***targets,
881     long *n_targets) {
882   if (!view_)
883     return E_FAIL;
884
885   if (!targets || !n_targets)
886     return E_INVALIDARG;
887
888   *n_targets = 0;
889   *targets = NULL;
890
891   // Only respond to requests for relations of type "alerts" on the
892   // root view.
893   base::string16 type(type_bstr);
894   if (type != L"alerts" || view_->parent())
895     return S_FALSE;
896
897   // Collect all of the alert views that are still valid.
898   std::vector<View*> alert_views;
899   ViewStorage* view_storage = ViewStorage::GetInstance();
900   for (size_t i = 0; i < alert_target_view_storage_ids_.size(); ++i) {
901     int view_storage_id = alert_target_view_storage_ids_[i];
902     View* view = view_storage->RetrieveView(view_storage_id);
903     if (!view || !view_->Contains(view))
904       continue;
905     alert_views.push_back(view);
906   }
907
908   long count = alert_views.size();
909   if (count == 0)
910     return S_FALSE;
911
912   // Don't return more targets than max_targets - but note that the caller
913   // is allowed to specify max_targets=0 to mean no limit.
914   if (max_targets > 0 && count > max_targets)
915     count = max_targets;
916
917   // Return the number of targets.
918   *n_targets = count;
919
920   // Allocate COM memory for the result array and populate it.
921   *targets = static_cast<IUnknown**>(
922       CoTaskMemAlloc(count * sizeof(IUnknown*)));
923   for (long i = 0; i < count; ++i) {
924     (*targets)[i] = alert_views[i]->GetNativeViewAccessible();
925     (*targets)[i]->AddRef();
926   }
927   return S_OK;
928 }
929
930 STDMETHODIMP NativeViewAccessibilityWin::get_attributes(BSTR* attributes) {
931   if (!view_)
932     return E_FAIL;
933
934   if (!attributes)
935     return E_INVALIDARG;
936
937   base::string16 attributes_str;
938
939   // Text fields need to report the attribute "text-model:a1" to instruct
940   // screen readers to use IAccessible2 APIs to handle text editing in this
941   // object (as opposed to treating it like a native Windows text box).
942   // The text-model:a1 attribute is documented here:
943   // http://www.linuxfoundation.org/collaborate/workgroups/accessibility/ia2/ia2_implementation_guide
944   ui::AXViewState state;
945   view_->GetAccessibleState(&state);
946   if (state.role == ui::AX_ROLE_TEXT_FIELD) {
947     attributes_str = L"text-model:a1;";
948   }
949
950   *attributes = SysAllocString(attributes_str.c_str());
951   DCHECK(*attributes);
952   return S_OK;
953 }
954
955 //
956 // IAccessibleText
957 //
958
959 STDMETHODIMP NativeViewAccessibilityWin::get_nCharacters(LONG* n_characters) {
960   if (!view_)
961     return E_FAIL;
962
963   if (!n_characters)
964     return E_INVALIDARG;
965
966   base::string16 text = TextForIAccessibleText();
967   *n_characters = static_cast<LONG>(text.size());
968   return S_OK;
969 }
970
971 STDMETHODIMP NativeViewAccessibilityWin::get_caretOffset(LONG* offset) {
972   if (!view_)
973     return E_FAIL;
974
975   if (!offset)
976     return E_INVALIDARG;
977
978   ui::AXViewState state;
979   view_->GetAccessibleState(&state);
980   *offset = static_cast<LONG>(state.selection_end);
981   return S_OK;
982 }
983
984 STDMETHODIMP NativeViewAccessibilityWin::get_nSelections(LONG* n_selections) {
985   if (!view_)
986     return E_FAIL;
987
988   if (!n_selections)
989     return E_INVALIDARG;
990
991   ui::AXViewState state;
992   view_->GetAccessibleState(&state);
993   if (state.selection_start != state.selection_end)
994     *n_selections = 1;
995   else
996     *n_selections = 0;
997   return S_OK;
998 }
999
1000 STDMETHODIMP NativeViewAccessibilityWin::get_selection(LONG selection_index,
1001                                                       LONG* start_offset,
1002                                                       LONG* end_offset) {
1003   if (!view_)
1004     return E_FAIL;
1005
1006   if (!start_offset || !end_offset || selection_index != 0)
1007     return E_INVALIDARG;
1008
1009   ui::AXViewState state;
1010   view_->GetAccessibleState(&state);
1011   *start_offset = static_cast<LONG>(state.selection_start);
1012   *end_offset = static_cast<LONG>(state.selection_end);
1013   return S_OK;
1014 }
1015
1016 STDMETHODIMP NativeViewAccessibilityWin::get_text(LONG start_offset,
1017                                                   LONG end_offset,
1018                                                   BSTR* text) {
1019   if (!view_)
1020     return E_FAIL;
1021
1022   ui::AXViewState state;
1023   view_->GetAccessibleState(&state);
1024   base::string16 text_str = TextForIAccessibleText();
1025   LONG len = static_cast<LONG>(text_str.size());
1026
1027   if (start_offset == IA2_TEXT_OFFSET_LENGTH) {
1028     start_offset = len;
1029   } else if (start_offset == IA2_TEXT_OFFSET_CARET) {
1030     start_offset = static_cast<LONG>(state.selection_end);
1031   }
1032   if (end_offset == IA2_TEXT_OFFSET_LENGTH) {
1033     end_offset = static_cast<LONG>(text_str.size());
1034   } else if (end_offset == IA2_TEXT_OFFSET_CARET) {
1035     end_offset = static_cast<LONG>(state.selection_end);
1036   }
1037
1038   // The spec allows the arguments to be reversed.
1039   if (start_offset > end_offset) {
1040     LONG tmp = start_offset;
1041     start_offset = end_offset;
1042     end_offset = tmp;
1043   }
1044
1045   // The spec does not allow the start or end offsets to be out or range;
1046   // we must return an error if so.
1047   if (start_offset < 0)
1048     return E_INVALIDARG;
1049   if (end_offset > len)
1050     return E_INVALIDARG;
1051
1052   base::string16 substr =
1053       text_str.substr(start_offset, end_offset - start_offset);
1054   if (substr.empty())
1055     return S_FALSE;
1056
1057   *text = SysAllocString(substr.c_str());
1058   DCHECK(*text);
1059   return S_OK;
1060 }
1061
1062 STDMETHODIMP NativeViewAccessibilityWin::get_textAtOffset(
1063     LONG offset,
1064     enum IA2TextBoundaryType boundary_type,
1065     LONG* start_offset, LONG* end_offset,
1066     BSTR* text) {
1067   if (!start_offset || !end_offset || !text)
1068     return E_INVALIDARG;
1069
1070   // The IAccessible2 spec says we don't have to implement the "sentence"
1071   // boundary type, we can just let the screenreader handle it.
1072   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
1073     *start_offset = 0;
1074     *end_offset = 0;
1075     *text = NULL;
1076     return S_FALSE;
1077   }
1078
1079   const base::string16& text_str = TextForIAccessibleText();
1080
1081   *start_offset = FindBoundary(
1082       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
1083   *end_offset = FindBoundary(
1084       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
1085   return get_text(*start_offset, *end_offset, text);
1086 }
1087
1088 STDMETHODIMP NativeViewAccessibilityWin::get_textBeforeOffset(
1089     LONG offset,
1090     enum IA2TextBoundaryType boundary_type,
1091     LONG* start_offset, LONG* end_offset,
1092     BSTR* text) {
1093   if (!start_offset || !end_offset || !text)
1094     return E_INVALIDARG;
1095
1096   // The IAccessible2 spec says we don't have to implement the "sentence"
1097   // boundary type, we can just let the screenreader handle it.
1098   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
1099     *start_offset = 0;
1100     *end_offset = 0;
1101     *text = NULL;
1102     return S_FALSE;
1103   }
1104
1105   const base::string16& text_str = TextForIAccessibleText();
1106
1107   *start_offset = FindBoundary(
1108       text_str, boundary_type, offset, ui::BACKWARDS_DIRECTION);
1109   *end_offset = offset;
1110   return get_text(*start_offset, *end_offset, text);
1111 }
1112
1113 STDMETHODIMP NativeViewAccessibilityWin::get_textAfterOffset(
1114     LONG offset,
1115     enum IA2TextBoundaryType boundary_type,
1116     LONG* start_offset, LONG* end_offset,
1117     BSTR* text) {
1118   if (!start_offset || !end_offset || !text)
1119     return E_INVALIDARG;
1120
1121   // The IAccessible2 spec says we don't have to implement the "sentence"
1122   // boundary type, we can just let the screenreader handle it.
1123   if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) {
1124     *start_offset = 0;
1125     *end_offset = 0;
1126     *text = NULL;
1127     return S_FALSE;
1128   }
1129
1130   const base::string16& text_str = TextForIAccessibleText();
1131
1132   *start_offset = offset;
1133   *end_offset = FindBoundary(
1134       text_str, boundary_type, offset, ui::FORWARDS_DIRECTION);
1135   return get_text(*start_offset, *end_offset, text);
1136 }
1137
1138 STDMETHODIMP NativeViewAccessibilityWin::get_offsetAtPoint(
1139     LONG x, LONG y, enum IA2CoordinateType coord_type, LONG* offset) {
1140   if (!view_)
1141     return E_FAIL;
1142
1143   if (!offset)
1144     return E_INVALIDARG;
1145
1146   // We don't support this method, but we have to return something
1147   // rather than E_NOTIMPL or screen readers will complain.
1148   *offset = 0;
1149   return S_OK;
1150 }
1151
1152 //
1153 // IServiceProvider methods.
1154 //
1155
1156 STDMETHODIMP NativeViewAccessibilityWin::QueryService(
1157     REFGUID guidService, REFIID riid, void** object) {
1158   if (!view_)
1159     return E_FAIL;
1160
1161   if (riid == IID_IAccessible2 || riid == IID_IAccessible2_2)
1162     AccessibleWebViewRegistry::GetInstance()->EnableIAccessible2Support();
1163
1164   if (guidService == IID_IAccessible ||
1165       guidService == IID_IAccessible2 ||
1166       guidService == IID_IAccessible2_2 ||
1167       guidService == IID_IAccessibleText)  {
1168     return QueryInterface(riid, object);
1169   }
1170
1171   // We only support the IAccessibleEx interface on Windows 8 and above. This
1172   // is needed for the On screen Keyboard to show up in metro mode, when the
1173   // user taps an editable region in the window.
1174   // All methods in the IAccessibleEx interface are unimplemented.
1175   if (riid == IID_IAccessibleEx &&
1176       base::win::GetVersion() >= base::win::VERSION_WIN8) {
1177     return QueryInterface(riid, object);
1178   }
1179
1180   *object = NULL;
1181   return E_FAIL;
1182 }
1183
1184 STDMETHODIMP NativeViewAccessibilityWin::GetPatternProvider(
1185     PATTERNID id, IUnknown** provider) {
1186   DVLOG(1) << "In Function: "
1187            << __FUNCTION__
1188            << " for pattern id: "
1189            << id;
1190   if (id == UIA_ValuePatternId || id == UIA_TextPatternId) {
1191     ui::AXViewState state;
1192     view_->GetAccessibleState(&state);
1193     long role = MSAARole(state.role);
1194
1195     if (role == ROLE_SYSTEM_TEXT) {
1196       DVLOG(1) << "Returning UIA text provider";
1197       base::win::UIATextProvider::CreateTextProvider(
1198           state.value, true, provider);
1199       return S_OK;
1200     }
1201   }
1202   return E_NOTIMPL;
1203 }
1204
1205 STDMETHODIMP NativeViewAccessibilityWin::GetPropertyValue(PROPERTYID id,
1206                                                           VARIANT* ret) {
1207   DVLOG(1) << "In Function: "
1208            << __FUNCTION__
1209            << " for property id: "
1210            << id;
1211   if (id == UIA_ControlTypePropertyId) {
1212     ui::AXViewState state;
1213     view_->GetAccessibleState(&state);
1214     long role = MSAARole(state.role);
1215     if (role == ROLE_SYSTEM_TEXT) {
1216       V_VT(ret) = VT_I4;
1217       ret->lVal = UIA_EditControlTypeId;
1218       DVLOG(1) << "Returning Edit control type";
1219     } else {
1220       DVLOG(1) << "Returning empty control type";
1221       V_VT(ret) = VT_EMPTY;
1222     }
1223   } else {
1224     V_VT(ret) = VT_EMPTY;
1225   }
1226   return S_OK;
1227 }
1228
1229 //
1230 // Static methods.
1231 //
1232
1233 void NativeViewAccessibility::RegisterWebView(View* web_view) {
1234   AccessibleWebViewRegistry::GetInstance()->RegisterWebView(web_view);
1235 }
1236
1237 void NativeViewAccessibility::UnregisterWebView(View* web_view) {
1238   AccessibleWebViewRegistry::GetInstance()->UnregisterWebView(web_view);
1239 }
1240
1241 int32 NativeViewAccessibilityWin::MSAAEvent(ui::AXEvent event) {
1242   switch (event) {
1243     case ui::AX_EVENT_ALERT:
1244       return EVENT_SYSTEM_ALERT;
1245     case ui::AX_EVENT_FOCUS:
1246       return EVENT_OBJECT_FOCUS;
1247     case ui::AX_EVENT_MENU_START:
1248       return EVENT_SYSTEM_MENUSTART;
1249     case ui::AX_EVENT_MENU_END:
1250       return EVENT_SYSTEM_MENUEND;
1251     case ui::AX_EVENT_MENU_POPUP_START:
1252       return EVENT_SYSTEM_MENUPOPUPSTART;
1253     case ui::AX_EVENT_MENU_POPUP_END:
1254       return EVENT_SYSTEM_MENUPOPUPEND;
1255     case ui::AX_EVENT_SELECTION:
1256       return EVENT_OBJECT_SELECTION;
1257     case ui::AX_EVENT_SELECTION_ADD:
1258       return EVENT_OBJECT_SELECTIONADD;
1259     case ui::AX_EVENT_SELECTION_REMOVE:
1260       return EVENT_OBJECT_SELECTIONREMOVE;
1261     case ui::AX_EVENT_TEXT_CHANGED:
1262       return EVENT_OBJECT_NAMECHANGE;
1263     case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
1264       return IA2_EVENT_TEXT_CARET_MOVED;
1265     case ui::AX_EVENT_VALUE_CHANGED:
1266       return EVENT_OBJECT_VALUECHANGE;
1267     default:
1268       // Not supported or invalid event.
1269       NOTREACHED();
1270       return -1;
1271   }
1272 }
1273
1274 int32 NativeViewAccessibilityWin::MSAARole(ui::AXRole role) {
1275   switch (role) {
1276     case ui::AX_ROLE_ALERT:
1277       return ROLE_SYSTEM_ALERT;
1278     case ui::AX_ROLE_APPLICATION:
1279       return ROLE_SYSTEM_APPLICATION;
1280     case ui::AX_ROLE_BUTTON_DROP_DOWN:
1281       return ROLE_SYSTEM_BUTTONDROPDOWN;
1282     case ui::AX_ROLE_POP_UP_BUTTON:
1283       return ROLE_SYSTEM_BUTTONMENU;
1284     case ui::AX_ROLE_CHECK_BOX:
1285       return ROLE_SYSTEM_CHECKBUTTON;
1286     case ui::AX_ROLE_COMBO_BOX:
1287       return ROLE_SYSTEM_COMBOBOX;
1288     case ui::AX_ROLE_DIALOG:
1289       return ROLE_SYSTEM_DIALOG;
1290     case ui::AX_ROLE_GROUP:
1291       return ROLE_SYSTEM_GROUPING;
1292     case ui::AX_ROLE_IMAGE:
1293       return ROLE_SYSTEM_GRAPHIC;
1294     case ui::AX_ROLE_LINK:
1295       return ROLE_SYSTEM_LINK;
1296     case ui::AX_ROLE_LOCATION_BAR:
1297       return ROLE_SYSTEM_GROUPING;
1298     case ui::AX_ROLE_MENU_BAR:
1299       return ROLE_SYSTEM_MENUBAR;
1300     case ui::AX_ROLE_MENU_ITEM:
1301       return ROLE_SYSTEM_MENUITEM;
1302     case ui::AX_ROLE_MENU_LIST_POPUP:
1303       return ROLE_SYSTEM_MENUPOPUP;
1304     case ui::AX_ROLE_TREE:
1305       return ROLE_SYSTEM_OUTLINE;
1306     case ui::AX_ROLE_TREE_ITEM:
1307       return ROLE_SYSTEM_OUTLINEITEM;
1308     case ui::AX_ROLE_TAB:
1309       return ROLE_SYSTEM_PAGETAB;
1310     case ui::AX_ROLE_TAB_LIST:
1311       return ROLE_SYSTEM_PAGETABLIST;
1312     case ui::AX_ROLE_PANE:
1313       return ROLE_SYSTEM_PANE;
1314     case ui::AX_ROLE_PROGRESS_INDICATOR:
1315       return ROLE_SYSTEM_PROGRESSBAR;
1316     case ui::AX_ROLE_BUTTON:
1317       return ROLE_SYSTEM_PUSHBUTTON;
1318     case ui::AX_ROLE_RADIO_BUTTON:
1319       return ROLE_SYSTEM_RADIOBUTTON;
1320     case ui::AX_ROLE_SCROLL_BAR:
1321       return ROLE_SYSTEM_SCROLLBAR;
1322     case ui::AX_ROLE_SPLITTER:
1323       return ROLE_SYSTEM_SEPARATOR;
1324     case ui::AX_ROLE_SLIDER:
1325       return ROLE_SYSTEM_SLIDER;
1326     case ui::AX_ROLE_STATIC_TEXT:
1327       return ROLE_SYSTEM_STATICTEXT;
1328     case ui::AX_ROLE_TEXT_FIELD:
1329       return ROLE_SYSTEM_TEXT;
1330     case ui::AX_ROLE_TITLE_BAR:
1331       return ROLE_SYSTEM_TITLEBAR;
1332     case ui::AX_ROLE_TOOLBAR:
1333       return ROLE_SYSTEM_TOOLBAR;
1334     case ui::AX_ROLE_WEB_VIEW:
1335       return ROLE_SYSTEM_GROUPING;
1336     case ui::AX_ROLE_WINDOW:
1337       return ROLE_SYSTEM_WINDOW;
1338     case ui::AX_ROLE_CLIENT:
1339     default:
1340       // This is the default role for MSAA.
1341       return ROLE_SYSTEM_CLIENT;
1342   }
1343 }
1344
1345 int32 NativeViewAccessibilityWin::MSAAState(const ui::AXViewState& state) {
1346   // This maps MSAA states for get_accState(). See also the IAccessible2
1347   // interface get_states().
1348
1349   int32 msaa_state = 0;
1350   if (state.HasStateFlag(ui::AX_STATE_CHECKED))
1351     msaa_state |= STATE_SYSTEM_CHECKED;
1352   if (state.HasStateFlag(ui::AX_STATE_COLLAPSED))
1353     msaa_state |= STATE_SYSTEM_COLLAPSED;
1354   if (state.HasStateFlag(ui::AX_STATE_DEFAULT))
1355     msaa_state |= STATE_SYSTEM_DEFAULT;
1356   if (state.HasStateFlag(ui::AX_STATE_EXPANDED))
1357     msaa_state |= STATE_SYSTEM_EXPANDED;
1358   if (state.HasStateFlag(ui::AX_STATE_HASPOPUP))
1359     msaa_state |= STATE_SYSTEM_HASPOPUP;
1360   if (state.HasStateFlag(ui::AX_STATE_HOVERED))
1361     msaa_state |= STATE_SYSTEM_HOTTRACKED;
1362   if (state.HasStateFlag(ui::AX_STATE_INVISIBLE))
1363     msaa_state |= STATE_SYSTEM_INVISIBLE;
1364   if (state.HasStateFlag(ui::AX_STATE_LINKED))
1365     msaa_state |= STATE_SYSTEM_LINKED;
1366   if (state.HasStateFlag(ui::AX_STATE_OFFSCREEN))
1367     msaa_state |= STATE_SYSTEM_OFFSCREEN;
1368   if (state.HasStateFlag(ui::AX_STATE_PRESSED))
1369     msaa_state |= STATE_SYSTEM_PRESSED;
1370   if (state.HasStateFlag(ui::AX_STATE_PROTECTED))
1371     msaa_state |= STATE_SYSTEM_PROTECTED;
1372   if (state.HasStateFlag(ui::AX_STATE_READ_ONLY))
1373     msaa_state |= STATE_SYSTEM_READONLY;
1374   if (state.HasStateFlag(ui::AX_STATE_SELECTABLE))
1375     msaa_state |= STATE_SYSTEM_SELECTABLE;
1376   if (state.HasStateFlag(ui::AX_STATE_SELECTED))
1377     msaa_state |= STATE_SYSTEM_SELECTED;
1378   if (state.HasStateFlag(ui::AX_STATE_FOCUSED))
1379     msaa_state |= STATE_SYSTEM_FOCUSED;
1380   if (state.HasStateFlag(ui::AX_STATE_DISABLED))
1381     msaa_state |= STATE_SYSTEM_UNAVAILABLE;
1382   return msaa_state;
1383 }
1384
1385 //
1386 // Private methods.
1387 //
1388
1389 bool NativeViewAccessibilityWin::IsNavDirNext(int nav_dir) const {
1390   return (nav_dir == NAVDIR_RIGHT ||
1391           nav_dir == NAVDIR_DOWN ||
1392           nav_dir == NAVDIR_NEXT);
1393 }
1394
1395 bool NativeViewAccessibilityWin::IsValidNav(
1396     int nav_dir, int start_id, int lower_bound, int upper_bound) const {
1397   if (IsNavDirNext(nav_dir)) {
1398     if ((start_id + 1) > upper_bound) {
1399       return false;
1400     }
1401   } else {
1402     if ((start_id - 1) <= lower_bound) {
1403       return false;
1404     }
1405   }
1406   return true;
1407 }
1408
1409 bool NativeViewAccessibilityWin::IsValidId(const VARIANT& child) const {
1410   // View accessibility returns an IAccessible for each view so we only support
1411   // the CHILDID_SELF id.
1412   return (VT_I4 == child.vt) && (CHILDID_SELF == child.lVal);
1413 }
1414
1415 void NativeViewAccessibilityWin::SetState(
1416     VARIANT* msaa_state, View* view) {
1417   // Ensure the output param is initialized to zero.
1418   msaa_state->lVal = 0;
1419
1420   // Default state; all views can have accessibility focus.
1421   msaa_state->lVal |= STATE_SYSTEM_FOCUSABLE;
1422
1423   if (!view)
1424     return;
1425
1426   if (!view->enabled())
1427     msaa_state->lVal |= STATE_SYSTEM_UNAVAILABLE;
1428   if (!view->visible())
1429     msaa_state->lVal |= STATE_SYSTEM_INVISIBLE;
1430   if (!strcmp(view->GetClassName(), CustomButton::kViewClassName)) {
1431     CustomButton* button = static_cast<CustomButton*>(view);
1432     if (button->IsHotTracked())
1433       msaa_state->lVal |= STATE_SYSTEM_HOTTRACKED;
1434   }
1435   if (view->HasFocus())
1436     msaa_state->lVal |= STATE_SYSTEM_FOCUSED;
1437
1438   // Add on any view-specific states.
1439   ui::AXViewState view_state;
1440   view->GetAccessibleState(&view_state);
1441   msaa_state->lVal |= MSAAState(view_state);
1442 }
1443
1444 base::string16 NativeViewAccessibilityWin::TextForIAccessibleText() {
1445   ui::AXViewState state;
1446   view_->GetAccessibleState(&state);
1447   if (state.role == ui::AX_ROLE_TEXT_FIELD)
1448     return state.value;
1449   else
1450     return state.name;
1451 }
1452
1453 void NativeViewAccessibilityWin::HandleSpecialTextOffset(
1454     const base::string16& text, LONG* offset) {
1455   if (*offset == IA2_TEXT_OFFSET_LENGTH) {
1456     *offset = static_cast<LONG>(text.size());
1457   } else if (*offset == IA2_TEXT_OFFSET_CARET) {
1458     get_caretOffset(offset);
1459   }
1460 }
1461
1462 ui::TextBoundaryType NativeViewAccessibilityWin::IA2TextBoundaryToTextBoundary(
1463     IA2TextBoundaryType ia2_boundary) {
1464   switch(ia2_boundary) {
1465     case IA2_TEXT_BOUNDARY_CHAR: return ui::CHAR_BOUNDARY;
1466     case IA2_TEXT_BOUNDARY_WORD: return ui::WORD_BOUNDARY;
1467     case IA2_TEXT_BOUNDARY_LINE: return ui::LINE_BOUNDARY;
1468     case IA2_TEXT_BOUNDARY_SENTENCE: return ui::SENTENCE_BOUNDARY;
1469     case IA2_TEXT_BOUNDARY_PARAGRAPH: return ui::PARAGRAPH_BOUNDARY;
1470     case IA2_TEXT_BOUNDARY_ALL: return ui::ALL_BOUNDARY;
1471     default:
1472       NOTREACHED();
1473       return ui::CHAR_BOUNDARY;
1474   }
1475 }
1476
1477 LONG NativeViewAccessibilityWin::FindBoundary(
1478     const base::string16& text,
1479     IA2TextBoundaryType ia2_boundary,
1480     LONG start_offset,
1481     ui::TextBoundaryDirection direction) {
1482   HandleSpecialTextOffset(text, &start_offset);
1483   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
1484   std::vector<int32> line_breaks;
1485   return ui::FindAccessibleTextBoundary(
1486       text, line_breaks, boundary, start_offset, direction);
1487 }
1488
1489 void NativeViewAccessibilityWin::PopulateChildWidgetVector(
1490     std::vector<Widget*>* result_child_widgets) {
1491   const Widget* widget = view()->GetWidget();
1492   if (!widget)
1493     return;
1494
1495   std::set<Widget*> child_widgets;
1496   Widget::GetAllOwnedWidgets(widget->GetNativeView(), &child_widgets);
1497   for (std::set<Widget*>::const_iterator iter = child_widgets.begin();
1498            iter != child_widgets.end(); ++iter) {
1499     Widget* child_widget = *iter;
1500     DCHECK_NE(widget, child_widget);
1501
1502     if (!child_widget->IsVisible())
1503       continue;
1504
1505     if (widget->GetNativeWindowProperty(kWidgetNativeViewHostKey))
1506       continue;
1507
1508     result_child_widgets->push_back(child_widget);
1509   }
1510 }
1511
1512 void NativeViewAccessibilityWin::AddAlertTarget() {
1513   ViewStorage* view_storage = ViewStorage::GetInstance();
1514   for (size_t i = 0; i < alert_target_view_storage_ids_.size(); ++i) {
1515     int view_storage_id = alert_target_view_storage_ids_[i];
1516     View* view = view_storage->RetrieveView(view_storage_id);
1517     if (view == view_)
1518       return;
1519   }
1520   int view_storage_id = view_storage->CreateStorageID();
1521   view_storage->StoreView(view_storage_id, view_);
1522   alert_target_view_storage_ids_.push_back(view_storage_id);
1523 }
1524
1525 void NativeViewAccessibilityWin::RemoveAlertTarget() {
1526   ViewStorage* view_storage = ViewStorage::GetInstance();
1527   size_t i = 0;
1528   while (i < alert_target_view_storage_ids_.size()) {
1529     int view_storage_id = alert_target_view_storage_ids_[i];
1530     View* view = view_storage->RetrieveView(view_storage_id);
1531     if (view == NULL || view == view_) {
1532       alert_target_view_storage_ids_.erase(
1533           alert_target_view_storage_ids_.begin() + i);
1534     } else {
1535       ++i;
1536     }
1537   }
1538 }
1539
1540 }  // namespace views