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