michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "uiaRawElmProvider.h" michael@0: michael@0: #include "AccessibleWrap.h" michael@0: #include "ARIAMap.h" michael@0: #include "nsIPersistentProperties2.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // uiaRawElmProvider michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: IMPL_IUNKNOWN2(uiaRawElmProvider, michael@0: IAccessibleEx, michael@0: IRawElementProviderSimple) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // IAccessibleEx michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::GetObjectForChild(long aIdChild, michael@0: __RPC__deref_out_opt IAccessibleEx** aAccEx) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aAccEx) michael@0: return E_INVALIDARG; michael@0: michael@0: *aAccEx = nullptr; michael@0: michael@0: return mAcc->IsDefunct() ? CO_E_OBJNOTCONNECTED : S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::GetIAccessiblePair(__RPC__deref_out_opt IAccessible** aAcc, michael@0: __RPC__out long* aIdChild) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aAcc || !aIdChild) michael@0: return E_INVALIDARG; michael@0: michael@0: *aAcc = nullptr; michael@0: *aIdChild = 0; michael@0: michael@0: if (mAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: *aIdChild = CHILDID_SELF; michael@0: *aAcc = mAcc; michael@0: mAcc->AddRef(); michael@0: michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::GetRuntimeId(__RPC__deref_out_opt SAFEARRAY** aRuntimeIds) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aRuntimeIds) michael@0: return E_INVALIDARG; michael@0: michael@0: int ids[] = { UiaAppendRuntimeId, static_cast(reinterpret_cast(mAcc->UniqueID())) }; michael@0: *aRuntimeIds = SafeArrayCreateVector(VT_I4, 0, 2); michael@0: if (!*aRuntimeIds) michael@0: return E_OUTOFMEMORY; michael@0: michael@0: for (LONG i = 0; i < (LONG)ArrayLength(ids); i++) michael@0: SafeArrayPutElement(*aRuntimeIds, &i, (void*)&(ids[i])); michael@0: michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::ConvertReturnedElement(__RPC__in_opt IRawElementProviderSimple* aRawElmProvider, michael@0: __RPC__deref_out_opt IAccessibleEx** aAccEx) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aRawElmProvider || !aAccEx) michael@0: return E_INVALIDARG; michael@0: michael@0: *aAccEx = nullptr; michael@0: michael@0: void* instancePtr = nullptr; michael@0: HRESULT hr = aRawElmProvider->QueryInterface(IID_IAccessibleEx, &instancePtr); michael@0: if (SUCCEEDED(hr)) michael@0: *aAccEx = static_cast(instancePtr); michael@0: michael@0: return hr; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // IRawElementProviderSimple michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::get_ProviderOptions(__RPC__out enum ProviderOptions* aOptions) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aOptions) michael@0: return E_INVALIDARG; michael@0: michael@0: // This method is not used with IAccessibleEx implementations. michael@0: *aOptions = ProviderOptions_ServerSideProvider; michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::GetPatternProvider(PATTERNID aPatternId, michael@0: __RPC__deref_out_opt IUnknown** aPatternProvider) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aPatternProvider) michael@0: return E_INVALIDARG; michael@0: michael@0: *aPatternProvider = nullptr; michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId, michael@0: __RPC__out VARIANT* aPropertyValue) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aPropertyValue) michael@0: return E_INVALIDARG; michael@0: michael@0: if (mAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: aPropertyValue->vt = VT_EMPTY; michael@0: michael@0: switch (aPropertyId) { michael@0: // Accelerator Key / shortcut. michael@0: case UIA_AcceleratorKeyPropertyId: { michael@0: nsAutoString keyString; michael@0: michael@0: mAcc->KeyboardShortcut().ToString(keyString); michael@0: michael@0: if (!keyString.IsEmpty()) { michael@0: aPropertyValue->vt = VT_BSTR; michael@0: aPropertyValue->bstrVal = ::SysAllocString(keyString.get()); michael@0: return S_OK; michael@0: } michael@0: michael@0: break; michael@0: } michael@0: michael@0: // Access Key / mneumonic. michael@0: case UIA_AccessKeyPropertyId: { michael@0: nsAutoString keyString; michael@0: michael@0: mAcc->AccessKey().ToString(keyString); michael@0: michael@0: if (!keyString.IsEmpty()) { michael@0: aPropertyValue->vt = VT_BSTR; michael@0: aPropertyValue->bstrVal = ::SysAllocString(keyString.get()); michael@0: return S_OK; michael@0: } michael@0: michael@0: break; michael@0: } michael@0: michael@0: //ARIA Role / shortcut michael@0: case UIA_AriaRolePropertyId: { michael@0: nsAutoString xmlRoles; michael@0: michael@0: nsCOMPtr attributes = mAcc->Attributes(); michael@0: attributes->GetStringProperty(NS_LITERAL_CSTRING("xml-roles"), xmlRoles); michael@0: michael@0: if(!xmlRoles.IsEmpty()) { michael@0: aPropertyValue->vt = VT_BSTR; michael@0: aPropertyValue->bstrVal = ::SysAllocString(xmlRoles.get()); michael@0: return S_OK; michael@0: } michael@0: michael@0: break; michael@0: } michael@0: michael@0: //ARIA Properties michael@0: case UIA_AriaPropertiesPropertyId: { michael@0: nsAutoString ariaProperties; michael@0: michael@0: aria::AttrIterator attribIter(mAcc->GetContent()); michael@0: nsAutoString attribName, attribValue; michael@0: while (attribIter.Next(attribName, attribValue)) { michael@0: ariaProperties.Append(attribName); michael@0: ariaProperties.Append('='); michael@0: ariaProperties.Append(attribValue); michael@0: ariaProperties.Append(';'); michael@0: } michael@0: michael@0: if (!ariaProperties.IsEmpty()) { michael@0: //remove last delimiter: michael@0: ariaProperties.Truncate(ariaProperties.Length()-1); michael@0: aPropertyValue->vt = VT_BSTR; michael@0: aPropertyValue->bstrVal = ::SysAllocString(ariaProperties.get()); michael@0: return S_OK; michael@0: } michael@0: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: uiaRawElmProvider::get_HostRawElementProvider(__RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aRawElmProvider) michael@0: return E_INVALIDARG; michael@0: michael@0: // This method is not used with IAccessibleEx implementations. michael@0: *aRawElmProvider = nullptr; michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: }