• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
2 // 2013 The Chromium Authors. All rights reserved. Use of this source code is
3 // governed by a BSD-style license that can be found in the LICENSE file.
4 
5 // This class implements our accessible proxy object that handles moving
6 // data back and forth between MSAA clients and CefClient renderers.
7 // Sample implementation based on ui\accessibility\ax_platform_node_win.h
8 
9 #include "tests/cefclient/browser/osr_accessibility_node.h"
10 
11 #if defined(CEF_USE_ATL)
12 
13 #include <atlbase.h>
14 #include <oleacc.h>
15 #include <string>
16 
17 #include "tests/cefclient/browser/osr_accessibility_helper.h"
18 
19 namespace client {
20 
21 // Return CO_E_OBJNOTCONNECTED for accessible objects thar still exists but the
22 // window and/or object it references has been destroyed.
23 #define DATACHECK(node) (node) ? S_OK : CO_E_OBJNOTCONNECTED
24 #define VALID_CHILDID(varChild) ((varChild.vt == VT_I4))
25 
26 namespace {
27 
28 // Helper function to convert a rectangle from client coordinates to screen
29 // coordinates.
ClientToScreen(HWND hwnd,LPRECT lpRect)30 void ClientToScreen(HWND hwnd, LPRECT lpRect) {
31   if (lpRect) {
32     POINT ptTL = {lpRect->left, lpRect->top};
33     POINT ptBR = {lpRect->right, lpRect->bottom};
34     // Win32 API only provides the call for a point.
35     ClientToScreen(hwnd, &ptTL);
36     ClientToScreen(hwnd, &ptBR);
37     SetRect(lpRect, ptTL.x, ptTL.y, ptBR.x, ptBR.y);
38   }
39 }
40 
41 // Helper function to convert to MSAARole
AxRoleToMSAARole(const std::string & role_string)42 int AxRoleToMSAARole(const std::string& role_string) {
43   if (role_string == "alert")
44     return ROLE_SYSTEM_ALERT;
45   if (role_string == "application")
46     return ROLE_SYSTEM_APPLICATION;
47   if (role_string == "buttonDropDown")
48     return ROLE_SYSTEM_BUTTONDROPDOWN;
49   if (role_string == "popUpButton")
50     return ROLE_SYSTEM_BUTTONMENU;
51   if (role_string == "checkBox")
52     return ROLE_SYSTEM_CHECKBUTTON;
53   if (role_string == "comboBox")
54     return ROLE_SYSTEM_COMBOBOX;
55   if (role_string == "dialog")
56     return ROLE_SYSTEM_DIALOG;
57   if (role_string == "genericContainer")
58     return ROLE_SYSTEM_GROUPING;
59   if (role_string == "group")
60     return ROLE_SYSTEM_GROUPING;
61   if (role_string == "image")
62     return ROLE_SYSTEM_GRAPHIC;
63   if (role_string == "link")
64     return ROLE_SYSTEM_LINK;
65   if (role_string == "locationBar")
66     return ROLE_SYSTEM_GROUPING;
67   if (role_string == "menuBar")
68     return ROLE_SYSTEM_MENUBAR;
69   if (role_string == "menuItem")
70     return ROLE_SYSTEM_MENUITEM;
71   if (role_string == "menuListPopup")
72     return ROLE_SYSTEM_MENUPOPUP;
73   if (role_string == "tree")
74     return ROLE_SYSTEM_OUTLINE;
75   if (role_string == "treeItem")
76     return ROLE_SYSTEM_OUTLINEITEM;
77   if (role_string == "tab")
78     return ROLE_SYSTEM_PAGETAB;
79   if (role_string == "tabList")
80     return ROLE_SYSTEM_PAGETABLIST;
81   if (role_string == "pane")
82     return ROLE_SYSTEM_PANE;
83   if (role_string == "progressIndicator")
84     return ROLE_SYSTEM_PROGRESSBAR;
85   if (role_string == "button")
86     return ROLE_SYSTEM_PUSHBUTTON;
87   if (role_string == "radioButton")
88     return ROLE_SYSTEM_RADIOBUTTON;
89   if (role_string == "scrollBar")
90     return ROLE_SYSTEM_SCROLLBAR;
91   if (role_string == "splitter")
92     return ROLE_SYSTEM_SEPARATOR;
93   if (role_string == "slider")
94     return ROLE_SYSTEM_SLIDER;
95   if (role_string == "staticText")
96     return ROLE_SYSTEM_STATICTEXT;
97   if (role_string == "textField")
98     return ROLE_SYSTEM_TEXT;
99   if (role_string == "titleBar")
100     return ROLE_SYSTEM_TITLEBAR;
101   if (role_string == "toolbar")
102     return ROLE_SYSTEM_TOOLBAR;
103   if (role_string == "webView")
104     return ROLE_SYSTEM_GROUPING;
105   if (role_string == "window")
106     return ROLE_SYSTEM_WINDOW;
107   if (role_string == "client")
108     return ROLE_SYSTEM_CLIENT;
109   // This is the default role for MSAA.
110   return ROLE_SYSTEM_CLIENT;
111 }
112 
MiddleX(const CefRect & rect)113 static inline int MiddleX(const CefRect& rect) {
114   return rect.x + rect.width / 2;
115 }
116 
MiddleY(const CefRect & rect)117 static inline int MiddleY(const CefRect& rect) {
118   return rect.y + rect.height / 2;
119 }
120 
121 }  // namespace
122 
123 struct CefIAccessible : public IAccessible {
124  public:
125   // Implement IUnknown
126   STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override;
127   STDMETHODIMP_(ULONG) AddRef() override;
128   STDMETHODIMP_(ULONG) Release() override;
129 
130   //
131   // IAccessible methods.
132   //
133   // Retrieves the child element or child object at a given point on the screen.
134   STDMETHODIMP accHitTest(LONG x_left, LONG y_top, VARIANT* child) override;
135 
136   // Performs the object's default action.
137   STDMETHODIMP accDoDefaultAction(VARIANT var_id) override;
138 
139   // Retrieves the specified object's current screen location.
140   STDMETHODIMP accLocation(LONG* x_left,
141                            LONG* y_top,
142                            LONG* width,
143                            LONG* height,
144                            VARIANT var_id) override;
145 
146   // Traverses to another UI element and retrieves the object.
147   STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start, VARIANT* end) override;
148 
149   // Retrieves an IDispatch interface pointer for the specified child.
150   STDMETHODIMP get_accChild(VARIANT var_child, IDispatch** disp_child) override;
151 
152   // Retrieves the number of accessible children.
153   STDMETHODIMP get_accChildCount(LONG* child_count) override;
154 
155   // Retrieves a string that describes the object's default action.
156   STDMETHODIMP get_accDefaultAction(VARIANT var_id,
157                                     BSTR* default_action) override;
158 
159   // Retrieves the tooltip description.
160   STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc) override;
161 
162   // Retrieves the object that has the keyboard focus.
163   STDMETHODIMP get_accFocus(VARIANT* focus_child) override;
164 
165   // Retrieves the specified object's shortcut.
166   STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id,
167                                        BSTR* access_key) override;
168 
169   // Retrieves the name of the specified object.
170   STDMETHODIMP get_accName(VARIANT var_id, BSTR* name) override;
171 
172   // Retrieves the IDispatch interface of the object's parent.
173   STDMETHODIMP get_accParent(IDispatch** disp_parent) override;
174 
175   // Retrieves information describing the role of the specified object.
176   STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role) override;
177 
178   // Retrieves the current state of the specified object.
179   STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state) override;
180 
181   // Gets the help string for the specified object.
182   STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* help) override;
183 
184   // Retrieve or set the string value associated with the specified object.
185   // Setting the value is not typically used by screen readers, but it's
186   // used frequently by automation software.
187   STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value) override;
188   STDMETHODIMP put_accValue(VARIANT var_id, BSTR new_value) override;
189 
190   // IAccessible methods not implemented.
191   STDMETHODIMP get_accSelection(VARIANT* selected) override;
192   STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id) override;
193   STDMETHODIMP get_accHelpTopic(BSTR* help_file,
194                                 VARIANT var_id,
195                                 LONG* topic_id) override;
196   STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name) override;
197 
198   // Implement IDispatch
199   STDMETHODIMP GetTypeInfoCount(unsigned int FAR* pctinfo) override;
200   STDMETHODIMP GetTypeInfo(unsigned int iTInfo,
201                            LCID lcid,
202                            ITypeInfo FAR* FAR* ppTInfo) override;
203   STDMETHODIMP GetIDsOfNames(REFIID riid,
204                              OLECHAR FAR* FAR* rgszNames,
205                              unsigned int cNames,
206                              LCID lcid,
207                              DISPID FAR* rgDispId) override;
208   STDMETHODIMP Invoke(DISPID dispIdMember,
209                       REFIID riid,
210                       LCID lcid,
211                       WORD wFlags,
212                       DISPPARAMS FAR* pDispParams,
213                       VARIANT FAR* pVarResult,
214                       EXCEPINFO FAR* pExcepInfo,
215                       unsigned int FAR* puArgErr) override;
216 
CefIAccessibleclient::CefIAccessible217   CefIAccessible(OsrAXNode* node) : ref_count_(0), node_(node) {}
218 
219   // Remove the node reference when OsrAXNode is destroyed, so that
220   // MSAA clients get  CO_E_OBJNOTCONNECTED
MarkDestroyedclient::CefIAccessible221   void MarkDestroyed() { node_ = nullptr; }
222 
223  protected:
~CefIAccessibleclient::CefIAccessible224   virtual ~CefIAccessible() {}
225 
226   // Ref Count
227   ULONG ref_count_;
228   // OsrAXNode* proxy object
229   OsrAXNode* node_;
230 };
231 
232 // Implement IUnknown
233 // *********************
234 
235 // Handles ref counting and querying for other supported interfaces.
236 // We only support, IUnknown, IDispatch and IAccessible.
QueryInterface(REFIID riid,void ** ppvObject)237 STDMETHODIMP CefIAccessible::QueryInterface(REFIID riid, void** ppvObject) {
238   if (riid == IID_IAccessible)
239     *ppvObject = static_cast<IAccessible*>(this);
240   else if (riid == IID_IDispatch)
241     *ppvObject = static_cast<IDispatch*>(this);
242   else if (riid == IID_IUnknown)
243     *ppvObject = static_cast<IUnknown*>(this);
244   else
245     *ppvObject = nullptr;
246 
247   if (*ppvObject)
248     reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
249 
250   return (*ppvObject) ? S_OK : E_NOINTERFACE;
251 }
252 
253 // Increments COM objects refcount required by IUnknown for reference counting
STDMETHODIMP_(ULONG)254 STDMETHODIMP_(ULONG) CefIAccessible::AddRef() {
255   return InterlockedIncrement((LONG volatile*)&ref_count_);
256 }
257 
STDMETHODIMP_(ULONG)258 STDMETHODIMP_(ULONG) CefIAccessible::Release() {
259   ULONG ulRefCnt = InterlockedDecrement((LONG volatile*)&ref_count_);
260   if (ulRefCnt == 0) {
261     // Remove reference from OsrAXNode
262     if (node_)
263       node_->Destroy();
264     delete this;
265   }
266 
267   return ulRefCnt;
268 }
269 
270 // Implement IAccessible
271 // *********************
272 
273 // Returns the parent IAccessible in the form of an IDispatch interface.
get_accParent(IDispatch ** ppdispParent)274 STDMETHODIMP CefIAccessible::get_accParent(IDispatch** ppdispParent) {
275   HRESULT retCode = DATACHECK(node_);
276   if (SUCCEEDED(retCode)) {
277     if (ppdispParent) {
278       CefNativeAccessible* parent = node_->GetParentAccessibleObject();
279       if (!parent) {
280         // Find our parent window
281         HWND hWnd = ::GetParent(node_->GetWindowHandle());
282         // if we have a window attempt to get its IAccessible pointer
283         if (hWnd) {
284           AccessibleObjectFromWindow(hWnd, (DWORD)OBJID_CLIENT, IID_IAccessible,
285                                      (void**)(&parent));
286         }
287       }
288 
289       if (parent)
290         parent->AddRef();
291       *ppdispParent = parent;
292       retCode = (*ppdispParent) ? S_OK : S_FALSE;
293     }
294   } else {
295     retCode = E_INVALIDARG;
296   }
297   return retCode;
298 }
299 
300 // Returns the number of children we have for this element.
get_accChildCount(long * pcountChildren)301 STDMETHODIMP CefIAccessible::get_accChildCount(long* pcountChildren) {
302   HRESULT retCode = DATACHECK(node_);
303   if (SUCCEEDED(retCode) && pcountChildren) {
304     // Get Child node count for this from Accessibility tree
305     *pcountChildren = node_->GetChildCount();
306   } else {
307     retCode = E_INVALIDARG;
308   }
309   return retCode;
310 }
311 
312 // Returns a child IAccessible object.
get_accChild(VARIANT varChild,IDispatch ** ppdispChild)313 STDMETHODIMP CefIAccessible::get_accChild(VARIANT varChild,
314                                           IDispatch** ppdispChild) {
315   HRESULT retCode = DATACHECK(node_);
316   if (SUCCEEDED(retCode)) {
317     int numChilds = node_->GetChildCount();
318     // Mark Leaf node if there are no child
319     if (numChilds <= 0) {
320       *ppdispChild = nullptr;
321       return S_FALSE;
322     } else {
323       if (ppdispChild && VALID_CHILDID(varChild)) {
324         if (varChild.lVal == CHILDID_SELF) {
325           *ppdispChild = this;
326         } else {
327           // Convert to 0 based index and get Child Node.
328           OsrAXNode* child = node_->ChildAtIndex(varChild.lVal - 1);
329           // Fallback to focused node
330           if (!child)
331             child = node_->GetAccessibilityHelper()->GetFocusedNode();
332 
333           *ppdispChild = child->GetNativeAccessibleObject(node_);
334         }
335         if (*ppdispChild == nullptr)
336           retCode = S_FALSE;
337         else
338           (*ppdispChild)->AddRef();
339       }
340     }
341   }
342   return retCode;
343 }
344 
345 // Check and returns the accessible name for element from accessibility tree
get_accName(VARIANT varChild,BSTR * pszName)346 STDMETHODIMP CefIAccessible::get_accName(VARIANT varChild, BSTR* pszName) {
347   HRESULT retCode = DATACHECK(node_);
348   if (SUCCEEDED(retCode)) {
349     if (pszName && VALID_CHILDID(varChild)) {
350       std::wstring name = node_->AxName();
351       CComBSTR bstrResult(name.c_str());
352       *pszName = bstrResult.Detach();
353     }
354   } else {
355     retCode = E_INVALIDARG;
356   }
357   return retCode;
358 }
359 
360 // Check and returns the value for element from accessibility tree
get_accValue(VARIANT varChild,BSTR * pszValue)361 STDMETHODIMP CefIAccessible::get_accValue(VARIANT varChild, BSTR* pszValue) {
362   HRESULT retCode = DATACHECK(node_);
363   if (SUCCEEDED(retCode)) {
364     if (pszValue && VALID_CHILDID(varChild)) {
365       std::wstring name = node_->AxValue();
366       CComBSTR bstrResult(name.c_str());
367       *pszValue = bstrResult.Detach();
368     }
369   } else {
370     retCode = E_INVALIDARG;
371   }
372   return retCode;
373 }
374 
375 // Check and returns the description for element from accessibility tree
get_accDescription(VARIANT varChild,BSTR * pszDescription)376 STDMETHODIMP CefIAccessible::get_accDescription(VARIANT varChild,
377                                                 BSTR* pszDescription) {
378   HRESULT retCode = DATACHECK(node_);
379   if (SUCCEEDED(retCode)) {
380     if (pszDescription && VALID_CHILDID(varChild)) {
381       std::wstring name = node_->AxDescription();
382       CComBSTR bstrResult(name.c_str());
383       *pszDescription = bstrResult.Detach();
384     }
385   } else {
386     retCode = E_INVALIDARG;
387   }
388   return retCode;
389 }
390 
391 // Check and returns the MSAA Role for element from accessibility tree
get_accRole(VARIANT varChild,VARIANT * pvarRole)392 STDMETHODIMP CefIAccessible::get_accRole(VARIANT varChild, VARIANT* pvarRole) {
393   HRESULT retCode = DATACHECK(node_);
394   if (SUCCEEDED(retCode)) {
395     // Get the accessibilty role and Map to MSAA Role
396     if (pvarRole) {
397       pvarRole->vt = VT_I4;
398       pvarRole->lVal = AxRoleToMSAARole(node_->AxRole());
399     } else {
400       retCode = E_INVALIDARG;
401     }
402   }
403   return retCode;
404 }
405 
406 // Check and returns Accessibility State for element from accessibility tree
get_accState(VARIANT varChild,VARIANT * pvarState)407 STDMETHODIMP CefIAccessible::get_accState(VARIANT varChild,
408                                           VARIANT* pvarState) {
409   HRESULT retCode = DATACHECK(node_);
410   if (SUCCEEDED(retCode)) {
411     if (pvarState) {
412       pvarState->vt = VT_I4;
413       pvarState->lVal =
414           (GetFocus() == node_->GetWindowHandle()) ? STATE_SYSTEM_FOCUSED : 0;
415       pvarState->lVal |= STATE_SYSTEM_PRESSED;
416       pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
417 
418       // For child
419       if (varChild.lVal == CHILDID_SELF) {
420         DWORD dwStyle = GetWindowLong(node_->GetWindowHandle(), GWL_STYLE);
421         pvarState->lVal |=
422             ((dwStyle & WS_VISIBLE) == 0) ? STATE_SYSTEM_INVISIBLE : 0;
423         pvarState->lVal |=
424             ((dwStyle & WS_DISABLED) > 0) ? STATE_SYSTEM_UNAVAILABLE : 0;
425       }
426     } else {
427       retCode = E_INVALIDARG;
428     }
429   }
430   return retCode;
431 }
432 
433 // Check and returns Accessibility Shortcut if any for element
get_accKeyboardShortcut(VARIANT varChild,BSTR * pszKeyboardShortcut)434 STDMETHODIMP CefIAccessible::get_accKeyboardShortcut(
435     VARIANT varChild,
436     BSTR* pszKeyboardShortcut) {
437   HRESULT retCode = DATACHECK(node_);
438   if (SUCCEEDED(retCode)) {
439     if (pszKeyboardShortcut && VALID_CHILDID(varChild))
440       *pszKeyboardShortcut = ::SysAllocString(L"None");
441     else
442       retCode = E_INVALIDARG;
443   }
444   return retCode;
445 }
446 
447 // Return focused element from the accessibility tree
get_accFocus(VARIANT * pFocusChild)448 STDMETHODIMP CefIAccessible::get_accFocus(VARIANT* pFocusChild) {
449   HRESULT retCode = DATACHECK(node_);
450   if (SUCCEEDED(retCode)) {
451     OsrAXNode* focusedNode = node_->GetAccessibilityHelper()->GetFocusedNode();
452     CefNativeAccessible* nativeObj = nullptr;
453     if (focusedNode)
454       nativeObj = focusedNode->GetNativeAccessibleObject(nullptr);
455 
456     if (nativeObj) {
457       if (nativeObj == this) {
458         pFocusChild->vt = VT_I4;
459         pFocusChild->lVal = CHILDID_SELF;
460       } else {
461         pFocusChild->vt = VT_DISPATCH;
462         pFocusChild->pdispVal = nativeObj;
463         pFocusChild->pdispVal->AddRef();
464       }
465     } else {
466       pFocusChild->vt = VT_EMPTY;
467     }
468   }
469   return retCode;
470 }
471 
472 // Return a selection list for multiple selection items.
get_accSelection(VARIANT * pvarChildren)473 STDMETHODIMP CefIAccessible::get_accSelection(VARIANT* pvarChildren) {
474   HRESULT retCode = DATACHECK(node_);
475   if (SUCCEEDED(retCode)) {
476     if (pvarChildren)
477       pvarChildren->vt = VT_EMPTY;
478     else
479       retCode = E_INVALIDARG;
480   }
481   return retCode;
482 }
483 
484 // Return a string description of the default action of our element, eg. push
get_accDefaultAction(VARIANT varChild,BSTR * pszDefaultAction)485 STDMETHODIMP CefIAccessible::get_accDefaultAction(VARIANT varChild,
486                                                   BSTR* pszDefaultAction) {
487   HRESULT retCode = DATACHECK(node_);
488   if (SUCCEEDED(retCode)) {
489     if (pszDefaultAction && VALID_CHILDID(varChild))
490       *pszDefaultAction = ::SysAllocString(L"Push");
491     else
492       retCode = E_INVALIDARG;
493   }
494   return retCode;
495 }
496 
497 // child item selectionor for an item to take focus.
accSelect(long flagsSelect,VARIANT varChild)498 STDMETHODIMP CefIAccessible::accSelect(long flagsSelect, VARIANT varChild) {
499   HRESULT retCode = DATACHECK(node_);
500   if (SUCCEEDED(retCode)) {
501     if (VALID_CHILDID(varChild)) {
502       HWND hwnd = node_->GetWindowHandle();
503       // we only support SELFLAG_TAKEFOCUS.
504       if (((flagsSelect & SELFLAG_TAKEFOCUS) > 0) && (GetFocus() == hwnd)) {
505         RECT rcWnd;
506         GetClientRect(hwnd, &rcWnd);
507         InvalidateRect(hwnd, &rcWnd, FALSE);
508       } else {
509         retCode = S_FALSE;
510       }
511     } else {
512       retCode = E_INVALIDARG;
513     }
514   }
515 
516   return retCode;
517 }
518 
519 // Returns back the screen coordinates of our element or one of its childs
accLocation(long * pxLeft,long * pyTop,long * pcxWidth,long * pcyHeight,VARIANT varChild)520 STDMETHODIMP CefIAccessible::accLocation(long* pxLeft,
521                                          long* pyTop,
522                                          long* pcxWidth,
523                                          long* pcyHeight,
524                                          VARIANT varChild) {
525   HRESULT retCode = DATACHECK(node_);
526   if (SUCCEEDED(retCode)) {
527     if (pxLeft && pyTop && pcxWidth && pcyHeight && VALID_CHILDID(varChild)) {
528       CefRect loc = node_->AxLocation();
529       RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
530       HWND hwnd = node_->GetWindowHandle();
531       ClientToScreen(hwnd, &rcItem);
532 
533       *pxLeft = rcItem.left;
534       *pyTop = rcItem.top;
535       *pcxWidth = rcItem.right - rcItem.left;
536       *pcyHeight = rcItem.bottom - rcItem.top;
537     } else {
538       retCode = E_INVALIDARG;
539     }
540   }
541   return retCode;
542 }
543 
544 // Allow clients to move the keyboard focus within the control
545 // Deprecated
accNavigate(long navDir,VARIANT varStart,VARIANT * pvarEndUpAt)546 STDMETHODIMP CefIAccessible::accNavigate(long navDir,
547                                          VARIANT varStart,
548                                          VARIANT* pvarEndUpAt) {
549   return E_NOTIMPL;
550 }
551 
552 // Check if the coordinates provided are within our element or child items.
accHitTest(long xLeft,long yTop,VARIANT * pvarChild)553 STDMETHODIMP CefIAccessible::accHitTest(long xLeft,
554                                         long yTop,
555                                         VARIANT* pvarChild) {
556   HRESULT retCode = DATACHECK(node_);
557   if (SUCCEEDED(retCode)) {
558     if (pvarChild) {
559       pvarChild->vt = VT_EMPTY;
560 
561       CefRect loc = node_->AxLocation();
562       RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
563       POINT pt = {xLeft, yTop};
564 
565       ClientToScreen(node_->GetWindowHandle(), &rcItem);
566 
567       if (PtInRect(&rcItem, pt)) {
568         pvarChild->vt = VT_I4;
569         pvarChild->lVal = 1;
570       }
571     } else {
572       retCode = E_INVALIDARG;
573     }
574   }
575 
576   return retCode;
577 }
578 
579 // Forces the default action of our element. In simplest cases, send a click.
accDoDefaultAction(VARIANT varChild)580 STDMETHODIMP CefIAccessible::accDoDefaultAction(VARIANT varChild) {
581   HRESULT retCode = DATACHECK(node_);
582   if (SUCCEEDED(retCode) && VALID_CHILDID(varChild)) {
583     // doing our default action for out button is to simply click the button.
584     CefRefPtr<CefBrowser> browser = node_->GetBrowser();
585     if (browser) {
586       CefMouseEvent mouse_event;
587       const CefRect& rect = node_->AxLocation();
588       mouse_event.x = MiddleX(rect);
589       mouse_event.y = MiddleY(rect);
590 
591       mouse_event.modifiers = 0;
592       browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
593       browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);
594     }
595   } else {
596     retCode = E_INVALIDARG;
597   }
598 
599   return retCode;
600 }
601 
602 // Set the name for an element in the accessibility tree
put_accName(VARIANT varChild,BSTR szName)603 STDMETHODIMP CefIAccessible::put_accName(VARIANT varChild, BSTR szName) {
604   return E_NOTIMPL;
605 }
606 
607 // Set the value for an element in the accessibility tree
put_accValue(VARIANT varChild,BSTR szValue)608 STDMETHODIMP CefIAccessible::put_accValue(VARIANT varChild, BSTR szValue) {
609   return E_NOTIMPL;
610 }
611 
612 // Return E_NOTIMPL as no help file/ topic
get_accHelp(VARIANT varChild,BSTR * pszHelp)613 STDMETHODIMP CefIAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp) {
614   return E_NOTIMPL;
615 }
616 
get_accHelpTopic(BSTR * pszHelpFile,VARIANT varChild,long * pidTopic)617 STDMETHODIMP CefIAccessible::get_accHelpTopic(BSTR* pszHelpFile,
618                                               VARIANT varChild,
619                                               long* pidTopic) {
620   return E_NOTIMPL;
621 }
622 
623 // IDispatch - We are not going to return E_NOTIMPL from IDispatch methods and
624 // let Active Accessibility implement the IAccessible interface for them.
GetTypeInfoCount(unsigned int FAR * pctinfo)625 STDMETHODIMP CefIAccessible::GetTypeInfoCount(unsigned int FAR* pctinfo) {
626   return E_NOTIMPL;
627 }
628 
GetTypeInfo(unsigned int iTInfo,LCID lcid,ITypeInfo FAR * FAR * ppTInfo)629 STDMETHODIMP CefIAccessible::GetTypeInfo(unsigned int iTInfo,
630                                          LCID lcid,
631                                          ITypeInfo FAR* FAR* ppTInfo) {
632   return E_NOTIMPL;
633 }
634 
GetIDsOfNames(REFIID riid,OLECHAR FAR * FAR * rgszNames,unsigned int cNames,LCID lcid,DISPID FAR * rgDispId)635 STDMETHODIMP CefIAccessible::GetIDsOfNames(REFIID riid,
636                                            OLECHAR FAR* FAR* rgszNames,
637                                            unsigned int cNames,
638                                            LCID lcid,
639                                            DISPID FAR* rgDispId) {
640   return E_NOTIMPL;
641 }
642 
Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS FAR * pDispParams,VARIANT FAR * pVarResult,EXCEPINFO FAR * pExcepInfo,unsigned int FAR * puArgErr)643 STDMETHODIMP CefIAccessible::Invoke(DISPID dispIdMember,
644                                     REFIID riid,
645                                     LCID lcid,
646                                     WORD wFlags,
647                                     DISPPARAMS FAR* pDispParams,
648                                     VARIANT FAR* pVarResult,
649                                     EXCEPINFO FAR* pExcepInfo,
650                                     unsigned int FAR* puArgErr) {
651   return E_NOTIMPL;
652 }
653 
NotifyAccessibilityEvent(std::string event_type) const654 void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {
655   if (event_type == "focus") {
656     // Notify Screen Reader of focus change
657     ::NotifyWinEvent(EVENT_OBJECT_FOCUS, GetWindowHandle(), OBJID_CLIENT,
658                      node_id_);
659   }
660 }
661 
Destroy()662 void OsrAXNode::Destroy() {
663   CefIAccessible* ptr = static_cast<CefIAccessible*>(platform_accessibility_);
664   if (ptr)
665     ptr->MarkDestroyed();
666   platform_accessibility_ = nullptr;
667 }
668 
669 // Create and return NSAccessibility Implementation Object for Window
GetNativeAccessibleObject(OsrAXNode * parent)670 CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
671   if (!platform_accessibility_) {
672     platform_accessibility_ = new CefIAccessible(this);
673     platform_accessibility_->AddRef();
674     SetParent(parent);
675   }
676   return platform_accessibility_;
677 }
678 
679 }  // namespace client
680 
681 #else  // !defined(CEF_USE_ATL)
682 
683 namespace client {
684 
NotifyAccessibilityEvent(std::string event_type) const685 void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {}
686 
Destroy()687 void OsrAXNode::Destroy() {}
688 
GetNativeAccessibleObject(OsrAXNode * parent)689 CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
690   return nullptr;
691 }
692 
693 }  // namespace client
694 
695 #endif  // !defined(CEF_USE_ATL)
696