diff options
Diffstat (limited to 'tests/cefclient/browser/osr_accessibility_node_win.cc')
-rw-r--r-- | tests/cefclient/browser/osr_accessibility_node_win.cc | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/tests/cefclient/browser/osr_accessibility_node_win.cc b/tests/cefclient/browser/osr_accessibility_node_win.cc new file mode 100644 index 00000000..5c5e64fb --- /dev/null +++ b/tests/cefclient/browser/osr_accessibility_node_win.cc @@ -0,0 +1,739 @@ +// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright +// 2013 The Chromium Authors. All rights reserved. Use of this source code is +// governed by a BSD-style license that can be found in the LICENSE file. + +// This class implements our accessible proxy object that handles moving +// data back and forth between MSAA clients and CefClient renderers. +// Sample implementation based on ui\accessibility\ax_platform_node_win.h + +#include "tests/cefclient/browser/osr_accessibility_node.h" + +#if defined(CEF_USE_ATL) + +#include <atlbase.h> +#include <oleacc.h> +#include <string> + +#include "tests/cefclient/browser/osr_accessibility_helper.h" + +namespace client { + +// Return CO_E_OBJNOTCONNECTED for accessible objects thar still exists but the +// window and/or object it references has been destroyed. +#define DATACHECK(node) (node) ? S_OK : CO_E_OBJNOTCONNECTED +#define VALID_CHILDID(varChild) ((varChild.vt == VT_I4)) + +namespace { + +// Helper function to convert a rectangle from client coordinates to screen +// coordinates. +void ClientToScreen(HWND hwnd, LPRECT lpRect) { + if (lpRect) { + POINT ptTL = {lpRect->left, lpRect->top}; + POINT ptBR = {lpRect->right, lpRect->bottom}; + // Win32 API only provides the call for a point. + ClientToScreen(hwnd, &ptTL); + ClientToScreen(hwnd, &ptBR); + SetRect(lpRect, ptTL.x, ptTL.y, ptBR.x, ptBR.y); + } +} + +// Helper function to convert to MSAARole +int AxRoleToMSAARole(const std::string& role_string) { + if (role_string == "alert") { + return ROLE_SYSTEM_ALERT; + } + if (role_string == "application") { + return ROLE_SYSTEM_APPLICATION; + } + if (role_string == "buttonDropDown") { + return ROLE_SYSTEM_BUTTONDROPDOWN; + } + if (role_string == "popUpButton") { + return ROLE_SYSTEM_BUTTONMENU; + } + if (role_string == "checkBox") { + return ROLE_SYSTEM_CHECKBUTTON; + } + if (role_string == "comboBox") { + return ROLE_SYSTEM_COMBOBOX; + } + if (role_string == "dialog") { + return ROLE_SYSTEM_DIALOG; + } + if (role_string == "genericContainer") { + return ROLE_SYSTEM_GROUPING; + } + if (role_string == "group") { + return ROLE_SYSTEM_GROUPING; + } + if (role_string == "image") { + return ROLE_SYSTEM_GRAPHIC; + } + if (role_string == "link") { + return ROLE_SYSTEM_LINK; + } + if (role_string == "locationBar") { + return ROLE_SYSTEM_GROUPING; + } + if (role_string == "menuBar") { + return ROLE_SYSTEM_MENUBAR; + } + if (role_string == "menuItem") { + return ROLE_SYSTEM_MENUITEM; + } + if (role_string == "menuListPopup") { + return ROLE_SYSTEM_MENUPOPUP; + } + if (role_string == "tree") { + return ROLE_SYSTEM_OUTLINE; + } + if (role_string == "treeItem") { + return ROLE_SYSTEM_OUTLINEITEM; + } + if (role_string == "tab") { + return ROLE_SYSTEM_PAGETAB; + } + if (role_string == "tabList") { + return ROLE_SYSTEM_PAGETABLIST; + } + if (role_string == "pane") { + return ROLE_SYSTEM_PANE; + } + if (role_string == "progressIndicator") { + return ROLE_SYSTEM_PROGRESSBAR; + } + if (role_string == "button") { + return ROLE_SYSTEM_PUSHBUTTON; + } + if (role_string == "radioButton") { + return ROLE_SYSTEM_RADIOBUTTON; + } + if (role_string == "scrollBar") { + return ROLE_SYSTEM_SCROLLBAR; + } + if (role_string == "splitter") { + return ROLE_SYSTEM_SEPARATOR; + } + if (role_string == "slider") { + return ROLE_SYSTEM_SLIDER; + } + if (role_string == "staticText") { + return ROLE_SYSTEM_STATICTEXT; + } + if (role_string == "textField") { + return ROLE_SYSTEM_TEXT; + } + if (role_string == "titleBar") { + return ROLE_SYSTEM_TITLEBAR; + } + if (role_string == "toolbar") { + return ROLE_SYSTEM_TOOLBAR; + } + if (role_string == "webView") { + return ROLE_SYSTEM_GROUPING; + } + if (role_string == "window") { + return ROLE_SYSTEM_WINDOW; + } + if (role_string == "client") { + return ROLE_SYSTEM_CLIENT; + } + // This is the default role for MSAA. + return ROLE_SYSTEM_CLIENT; +} + +static inline int MiddleX(const CefRect& rect) { + return rect.x + rect.width / 2; +} + +static inline int MiddleY(const CefRect& rect) { + return rect.y + rect.height / 2; +} + +} // namespace + +struct CefIAccessible : public IAccessible { + public: + // Implement IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override; + STDMETHODIMP_(ULONG) AddRef() override; + STDMETHODIMP_(ULONG) Release() override; + + // + // IAccessible methods. + // + // Retrieves the child element or child object at a given point on the screen. + STDMETHODIMP accHitTest(LONG x_left, LONG y_top, VARIANT* child) override; + + // Performs the object's default action. + STDMETHODIMP accDoDefaultAction(VARIANT var_id) override; + + // Retrieves the specified object's current screen location. + STDMETHODIMP accLocation(LONG* x_left, + LONG* y_top, + LONG* width, + LONG* height, + VARIANT var_id) override; + + // Traverses to another UI element and retrieves the object. + STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start, VARIANT* end) override; + + // Retrieves an IDispatch interface pointer for the specified child. + STDMETHODIMP get_accChild(VARIANT var_child, IDispatch** disp_child) override; + + // Retrieves the number of accessible children. + STDMETHODIMP get_accChildCount(LONG* child_count) override; + + // Retrieves a string that describes the object's default action. + STDMETHODIMP get_accDefaultAction(VARIANT var_id, + BSTR* default_action) override; + + // Retrieves the tooltip description. + STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc) override; + + // Retrieves the object that has the keyboard focus. + STDMETHODIMP get_accFocus(VARIANT* focus_child) override; + + // Retrieves the specified object's shortcut. + STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id, + BSTR* access_key) override; + + // Retrieves the name of the specified object. + STDMETHODIMP get_accName(VARIANT var_id, BSTR* name) override; + + // Retrieves the IDispatch interface of the object's parent. + STDMETHODIMP get_accParent(IDispatch** disp_parent) override; + + // Retrieves information describing the role of the specified object. + STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role) override; + + // Retrieves the current state of the specified object. + STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state) override; + + // Gets the help string for the specified object. + STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* help) override; + + // Retrieve or set the string value associated with the specified object. + // Setting the value is not typically used by screen readers, but it's + // used frequently by automation software. + STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value) override; + STDMETHODIMP put_accValue(VARIANT var_id, BSTR new_value) override; + + // IAccessible methods not implemented. + STDMETHODIMP get_accSelection(VARIANT* selected) override; + STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id) override; + STDMETHODIMP get_accHelpTopic(BSTR* help_file, + VARIANT var_id, + LONG* topic_id) override; + STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name) override; + + // Implement IDispatch + STDMETHODIMP GetTypeInfoCount(unsigned int FAR* pctinfo) override; + STDMETHODIMP GetTypeInfo(unsigned int iTInfo, + LCID lcid, + ITypeInfo FAR* FAR* ppTInfo) override; + STDMETHODIMP GetIDsOfNames(REFIID riid, + OLECHAR FAR* FAR* rgszNames, + unsigned int cNames, + LCID lcid, + DISPID FAR* rgDispId) override; + STDMETHODIMP Invoke(DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS FAR* pDispParams, + VARIANT FAR* pVarResult, + EXCEPINFO FAR* pExcepInfo, + unsigned int FAR* puArgErr) override; + + CefIAccessible(OsrAXNode* node) : ref_count_(0), node_(node) {} + + // Remove the node reference when OsrAXNode is destroyed, so that + // MSAA clients get CO_E_OBJNOTCONNECTED + void MarkDestroyed() { node_ = nullptr; } + + protected: + virtual ~CefIAccessible() {} + + // Ref Count + ULONG ref_count_; + // OsrAXNode* proxy object + OsrAXNode* node_; +}; + +// Implement IUnknown +// ********************* + +// Handles ref counting and querying for other supported interfaces. +// We only support, IUnknown, IDispatch and IAccessible. +STDMETHODIMP CefIAccessible::QueryInterface(REFIID riid, void** ppvObject) { + if (riid == IID_IAccessible) { + *ppvObject = static_cast<IAccessible*>(this); + } else if (riid == IID_IDispatch) { + *ppvObject = static_cast<IDispatch*>(this); + } else if (riid == IID_IUnknown) { + *ppvObject = static_cast<IUnknown*>(this); + } else { + *ppvObject = nullptr; + } + + if (*ppvObject) { + reinterpret_cast<IUnknown*>(*ppvObject)->AddRef(); + } + + return (*ppvObject) ? S_OK : E_NOINTERFACE; +} + +// Increments COM objects refcount required by IUnknown for reference counting +STDMETHODIMP_(ULONG) CefIAccessible::AddRef() { + return InterlockedIncrement((LONG volatile*)&ref_count_); +} + +STDMETHODIMP_(ULONG) CefIAccessible::Release() { + ULONG ulRefCnt = InterlockedDecrement((LONG volatile*)&ref_count_); + if (ulRefCnt == 0) { + // Remove reference from OsrAXNode + if (node_) { + node_->Destroy(); + } + delete this; + } + + return ulRefCnt; +} + +// Implement IAccessible +// ********************* + +// Returns the parent IAccessible in the form of an IDispatch interface. +STDMETHODIMP CefIAccessible::get_accParent(IDispatch** ppdispParent) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (ppdispParent) { + CefNativeAccessible* parent = node_->GetParentAccessibleObject(); + if (!parent) { + // Find our parent window + HWND hWnd = ::GetParent(node_->GetWindowHandle()); + // if we have a window attempt to get its IAccessible pointer + if (hWnd) { + AccessibleObjectFromWindow(hWnd, (DWORD)OBJID_CLIENT, IID_IAccessible, + (void**)(&parent)); + } + } + + if (parent) { + parent->AddRef(); + } + *ppdispParent = parent; + retCode = (*ppdispParent) ? S_OK : S_FALSE; + } + } else { + retCode = E_INVALIDARG; + } + return retCode; +} + +// Returns the number of children we have for this element. +STDMETHODIMP CefIAccessible::get_accChildCount(long* pcountChildren) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode) && pcountChildren) { + // Get Child node count for this from Accessibility tree + *pcountChildren = node_->GetChildCount(); + } else { + retCode = E_INVALIDARG; + } + return retCode; +} + +// Returns a child IAccessible object. +STDMETHODIMP CefIAccessible::get_accChild(VARIANT varChild, + IDispatch** ppdispChild) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + int numChilds = node_->GetChildCount(); + // Mark Leaf node if there are no child + if (numChilds <= 0) { + *ppdispChild = nullptr; + return S_FALSE; + } else { + if (ppdispChild && VALID_CHILDID(varChild)) { + if (varChild.lVal == CHILDID_SELF) { + *ppdispChild = this; + } else { + // Convert to 0 based index and get Child Node. + OsrAXNode* child = node_->ChildAtIndex(varChild.lVal - 1); + // Fallback to focused node + if (!child) { + child = node_->GetAccessibilityHelper()->GetFocusedNode(); + } + + *ppdispChild = child->GetNativeAccessibleObject(node_); + } + if (*ppdispChild == nullptr) { + retCode = S_FALSE; + } else { + (*ppdispChild)->AddRef(); + } + } + } + } + return retCode; +} + +// Check and returns the accessible name for element from accessibility tree +STDMETHODIMP CefIAccessible::get_accName(VARIANT varChild, BSTR* pszName) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pszName && VALID_CHILDID(varChild)) { + std::wstring name = node_->AxName(); + CComBSTR bstrResult(name.c_str()); + *pszName = bstrResult.Detach(); + } + } else { + retCode = E_INVALIDARG; + } + return retCode; +} + +// Check and returns the value for element from accessibility tree +STDMETHODIMP CefIAccessible::get_accValue(VARIANT varChild, BSTR* pszValue) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pszValue && VALID_CHILDID(varChild)) { + std::wstring name = node_->AxValue(); + CComBSTR bstrResult(name.c_str()); + *pszValue = bstrResult.Detach(); + } + } else { + retCode = E_INVALIDARG; + } + return retCode; +} + +// Check and returns the description for element from accessibility tree +STDMETHODIMP CefIAccessible::get_accDescription(VARIANT varChild, + BSTR* pszDescription) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pszDescription && VALID_CHILDID(varChild)) { + std::wstring name = node_->AxDescription(); + CComBSTR bstrResult(name.c_str()); + *pszDescription = bstrResult.Detach(); + } + } else { + retCode = E_INVALIDARG; + } + return retCode; +} + +// Check and returns the MSAA Role for element from accessibility tree +STDMETHODIMP CefIAccessible::get_accRole(VARIANT varChild, VARIANT* pvarRole) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + // Get the accessibilty role and Map to MSAA Role + if (pvarRole) { + pvarRole->vt = VT_I4; + pvarRole->lVal = AxRoleToMSAARole(node_->AxRole()); + } else { + retCode = E_INVALIDARG; + } + } + return retCode; +} + +// Check and returns Accessibility State for element from accessibility tree +STDMETHODIMP CefIAccessible::get_accState(VARIANT varChild, + VARIANT* pvarState) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pvarState) { + pvarState->vt = VT_I4; + pvarState->lVal = + (GetFocus() == node_->GetWindowHandle()) ? STATE_SYSTEM_FOCUSED : 0; + pvarState->lVal |= STATE_SYSTEM_PRESSED; + pvarState->lVal |= STATE_SYSTEM_FOCUSABLE; + + // For child + if (varChild.lVal == CHILDID_SELF) { + DWORD dwStyle = GetWindowLong(node_->GetWindowHandle(), GWL_STYLE); + pvarState->lVal |= + ((dwStyle & WS_VISIBLE) == 0) ? STATE_SYSTEM_INVISIBLE : 0; + pvarState->lVal |= + ((dwStyle & WS_DISABLED) > 0) ? STATE_SYSTEM_UNAVAILABLE : 0; + } + } else { + retCode = E_INVALIDARG; + } + } + return retCode; +} + +// Check and returns Accessibility Shortcut if any for element +STDMETHODIMP CefIAccessible::get_accKeyboardShortcut( + VARIANT varChild, + BSTR* pszKeyboardShortcut) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pszKeyboardShortcut && VALID_CHILDID(varChild)) { + *pszKeyboardShortcut = ::SysAllocString(L"None"); + } else { + retCode = E_INVALIDARG; + } + } + return retCode; +} + +// Return focused element from the accessibility tree +STDMETHODIMP CefIAccessible::get_accFocus(VARIANT* pFocusChild) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + OsrAXNode* focusedNode = node_->GetAccessibilityHelper()->GetFocusedNode(); + CefNativeAccessible* nativeObj = nullptr; + if (focusedNode) { + nativeObj = focusedNode->GetNativeAccessibleObject(nullptr); + } + + if (nativeObj) { + if (nativeObj == this) { + pFocusChild->vt = VT_I4; + pFocusChild->lVal = CHILDID_SELF; + } else { + pFocusChild->vt = VT_DISPATCH; + pFocusChild->pdispVal = nativeObj; + pFocusChild->pdispVal->AddRef(); + } + } else { + pFocusChild->vt = VT_EMPTY; + } + } + return retCode; +} + +// Return a selection list for multiple selection items. +STDMETHODIMP CefIAccessible::get_accSelection(VARIANT* pvarChildren) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pvarChildren) { + pvarChildren->vt = VT_EMPTY; + } else { + retCode = E_INVALIDARG; + } + } + return retCode; +} + +// Return a string description of the default action of our element, eg. push +STDMETHODIMP CefIAccessible::get_accDefaultAction(VARIANT varChild, + BSTR* pszDefaultAction) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pszDefaultAction && VALID_CHILDID(varChild)) { + *pszDefaultAction = ::SysAllocString(L"Push"); + } else { + retCode = E_INVALIDARG; + } + } + return retCode; +} + +// child item selectionor for an item to take focus. +STDMETHODIMP CefIAccessible::accSelect(long flagsSelect, VARIANT varChild) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (VALID_CHILDID(varChild)) { + HWND hwnd = node_->GetWindowHandle(); + // we only support SELFLAG_TAKEFOCUS. + if (((flagsSelect & SELFLAG_TAKEFOCUS) > 0) && (GetFocus() == hwnd)) { + RECT rcWnd; + GetClientRect(hwnd, &rcWnd); + InvalidateRect(hwnd, &rcWnd, FALSE); + } else { + retCode = S_FALSE; + } + } else { + retCode = E_INVALIDARG; + } + } + + return retCode; +} + +// Returns back the screen coordinates of our element or one of its childs +STDMETHODIMP CefIAccessible::accLocation(long* pxLeft, + long* pyTop, + long* pcxWidth, + long* pcyHeight, + VARIANT varChild) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pxLeft && pyTop && pcxWidth && pcyHeight && VALID_CHILDID(varChild)) { + CefRect loc = node_->AxLocation(); + RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height}; + HWND hwnd = node_->GetWindowHandle(); + ClientToScreen(hwnd, &rcItem); + + *pxLeft = rcItem.left; + *pyTop = rcItem.top; + *pcxWidth = rcItem.right - rcItem.left; + *pcyHeight = rcItem.bottom - rcItem.top; + } else { + retCode = E_INVALIDARG; + } + } + return retCode; +} + +// Allow clients to move the keyboard focus within the control +// Deprecated +STDMETHODIMP CefIAccessible::accNavigate(long navDir, + VARIANT varStart, + VARIANT* pvarEndUpAt) { + return E_NOTIMPL; +} + +// Check if the coordinates provided are within our element or child items. +STDMETHODIMP CefIAccessible::accHitTest(long xLeft, + long yTop, + VARIANT* pvarChild) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode)) { + if (pvarChild) { + pvarChild->vt = VT_EMPTY; + + CefRect loc = node_->AxLocation(); + RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height}; + POINT pt = {xLeft, yTop}; + + ClientToScreen(node_->GetWindowHandle(), &rcItem); + + if (PtInRect(&rcItem, pt)) { + pvarChild->vt = VT_I4; + pvarChild->lVal = 1; + } + } else { + retCode = E_INVALIDARG; + } + } + + return retCode; +} + +// Forces the default action of our element. In simplest cases, send a click. +STDMETHODIMP CefIAccessible::accDoDefaultAction(VARIANT varChild) { + HRESULT retCode = DATACHECK(node_); + if (SUCCEEDED(retCode) && VALID_CHILDID(varChild)) { + // doing our default action for out button is to simply click the button. + CefRefPtr<CefBrowser> browser = node_->GetBrowser(); + if (browser) { + CefMouseEvent mouse_event; + const CefRect& rect = node_->AxLocation(); + mouse_event.x = MiddleX(rect); + mouse_event.y = MiddleY(rect); + + mouse_event.modifiers = 0; + browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1); + browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1); + } + } else { + retCode = E_INVALIDARG; + } + + return retCode; +} + +// Set the name for an element in the accessibility tree +STDMETHODIMP CefIAccessible::put_accName(VARIANT varChild, BSTR szName) { + return E_NOTIMPL; +} + +// Set the value for an element in the accessibility tree +STDMETHODIMP CefIAccessible::put_accValue(VARIANT varChild, BSTR szValue) { + return E_NOTIMPL; +} + +// Return E_NOTIMPL as no help file/ topic +STDMETHODIMP CefIAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp) { + return E_NOTIMPL; +} + +STDMETHODIMP CefIAccessible::get_accHelpTopic(BSTR* pszHelpFile, + VARIANT varChild, + long* pidTopic) { + return E_NOTIMPL; +} + +// IDispatch - We are not going to return E_NOTIMPL from IDispatch methods and +// let Active Accessibility implement the IAccessible interface for them. +STDMETHODIMP CefIAccessible::GetTypeInfoCount(unsigned int FAR* pctinfo) { + return E_NOTIMPL; +} + +STDMETHODIMP CefIAccessible::GetTypeInfo(unsigned int iTInfo, + LCID lcid, + ITypeInfo FAR* FAR* ppTInfo) { + return E_NOTIMPL; +} + +STDMETHODIMP CefIAccessible::GetIDsOfNames(REFIID riid, + OLECHAR FAR* FAR* rgszNames, + unsigned int cNames, + LCID lcid, + DISPID FAR* rgDispId) { + return E_NOTIMPL; +} + +STDMETHODIMP CefIAccessible::Invoke(DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS FAR* pDispParams, + VARIANT FAR* pVarResult, + EXCEPINFO FAR* pExcepInfo, + unsigned int FAR* puArgErr) { + return E_NOTIMPL; +} + +void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const { + if (event_type == "focus") { + // Notify Screen Reader of focus change + ::NotifyWinEvent(EVENT_OBJECT_FOCUS, GetWindowHandle(), OBJID_CLIENT, + node_id_); + } +} + +void OsrAXNode::Destroy() { + CefIAccessible* ptr = static_cast<CefIAccessible*>(platform_accessibility_); + if (ptr) { + ptr->MarkDestroyed(); + } + platform_accessibility_ = nullptr; +} + +// Create and return NSAccessibility Implementation Object for Window +CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) { + if (!platform_accessibility_) { + platform_accessibility_ = new CefIAccessible(this); + platform_accessibility_->AddRef(); + SetParent(parent); + } + return platform_accessibility_; +} + +} // namespace client + +#else // !defined(CEF_USE_ATL) + +namespace client { + +void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {} + +void OsrAXNode::Destroy() {} + +CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) { + return nullptr; +} + +} // namespace client + +#endif // !defined(CEF_USE_ATL) |