mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
540 lines
13 KiB
C++
540 lines
13 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "sdnAccessible-inl.h"
|
|
#include "ISimpleDOMNode_i.c"
|
|
|
|
#include "DocAccessibleWrap.h"
|
|
|
|
#include "nsAttrName.h"
|
|
#include "nsCoreUtils.h"
|
|
#include "nsIAccessibleTypes.h"
|
|
#include "nsIDOMHTMLElement.h"
|
|
#include "nsIDOMCSSStyleDeclaration.h"
|
|
#include "nsNameSpaceManager.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsWinUtils.h"
|
|
#include "nsRange.h"
|
|
|
|
#include "nsAutoPtr.h"
|
|
|
|
#include "mozilla/dom/Element.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::a11y;
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::QueryInterface(REFIID aREFIID, void** aInstancePtr)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aInstancePtr)
|
|
return E_FAIL;
|
|
*aInstancePtr = nullptr;
|
|
|
|
if (aREFIID == IID_ISimpleDOMNode) {
|
|
*aInstancePtr = static_cast<ISimpleDOMNode*>(this);
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
AccessibleWrap* accessible = static_cast<AccessibleWrap*>(GetAccessible());
|
|
if (accessible)
|
|
return accessible->QueryInterface(aREFIID, aInstancePtr);
|
|
|
|
// IUnknown* is the canonical one if and only if this accessible doesn't have
|
|
// an accessible.
|
|
if (aREFIID == IID_IUnknown) {
|
|
*aInstancePtr = static_cast<ISimpleDOMNode*>(this);
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_nodeInfo(BSTR __RPC_FAR* aNodeName,
|
|
short __RPC_FAR* aNameSpaceID,
|
|
BSTR __RPC_FAR* aNodeValue,
|
|
unsigned int __RPC_FAR* aNumChildren,
|
|
unsigned int __RPC_FAR* aUniqueID,
|
|
unsigned short __RPC_FAR* aNodeType)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aNodeName || !aNameSpaceID || !aNodeValue || !aNumChildren ||
|
|
!aUniqueID || !aNodeType)
|
|
return E_INVALIDARG;
|
|
|
|
*aNodeName = nullptr;
|
|
*aNameSpaceID = 0;
|
|
*aNodeValue = nullptr;
|
|
*aNumChildren = 0;
|
|
*aUniqueID = 0;
|
|
*aNodeType = 0;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mNode));
|
|
|
|
uint16_t nodeType = 0;
|
|
DOMNode->GetNodeType(&nodeType);
|
|
*aNodeType = static_cast<unsigned short>(nodeType);
|
|
|
|
if (*aNodeType != NODETYPE_TEXT) {
|
|
nsAutoString nodeName;
|
|
DOMNode->GetNodeName(nodeName);
|
|
*aNodeName = ::SysAllocString(nodeName.get());
|
|
}
|
|
|
|
nsAutoString nodeValue;
|
|
DOMNode->GetNodeValue(nodeValue);
|
|
*aNodeValue = ::SysAllocString(nodeValue.get());
|
|
|
|
*aNameSpaceID = mNode->IsNodeOfType(nsINode::eCONTENT) ?
|
|
static_cast<short>(mNode->AsContent()->GetNameSpaceID()) : 0;
|
|
|
|
// This is a unique ID for every content node. The 3rd party accessibility
|
|
// application can compare this to the childID we return for events such as
|
|
// focus events, to correlate back to data nodes in their internal object
|
|
// model.
|
|
Accessible* accessible = GetAccessible();
|
|
if (accessible) {
|
|
*aUniqueID = AccessibleWrap::GetChildIDFor(accessible);
|
|
} else {
|
|
*aUniqueID = - NS_PTR_TO_INT32(static_cast<void*>(this));
|
|
}
|
|
|
|
*aNumChildren = mNode->GetChildCount();
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_attributes(unsigned short aMaxAttribs,
|
|
BSTR __RPC_FAR* aAttribNames,
|
|
short __RPC_FAR* aNameSpaceIDs,
|
|
BSTR __RPC_FAR* aAttribValues,
|
|
unsigned short __RPC_FAR* aNumAttribs)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aAttribNames || !aNameSpaceIDs || !aAttribValues || !aNumAttribs)
|
|
return E_INVALIDARG;
|
|
|
|
*aNumAttribs = 0;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
if (!mNode->IsElement())
|
|
return S_FALSE;
|
|
|
|
dom::Element* elm = mNode->AsElement();
|
|
uint32_t numAttribs = elm->GetAttrCount();
|
|
if (numAttribs > aMaxAttribs)
|
|
numAttribs = aMaxAttribs;
|
|
|
|
*aNumAttribs = static_cast<unsigned short>(numAttribs);
|
|
|
|
for (uint32_t index = 0; index < numAttribs; index++) {
|
|
aNameSpaceIDs[index] = 0;
|
|
aAttribValues[index] = aAttribNames[index] = nullptr;
|
|
nsAutoString attributeValue;
|
|
|
|
const nsAttrName* name = elm->GetAttrNameAt(index);
|
|
aNameSpaceIDs[index] = static_cast<short>(name->NamespaceID());
|
|
aAttribNames[index] = ::SysAllocString(name->LocalName()->GetUTF16String());
|
|
elm->GetAttr(name->NamespaceID(), name->LocalName(), attributeValue);
|
|
aAttribValues[index] = ::SysAllocString(attributeValue.get());
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_attributesForNames(unsigned short aMaxAttribs,
|
|
BSTR __RPC_FAR* aAttribNames,
|
|
short __RPC_FAR* aNameSpaceID,
|
|
BSTR __RPC_FAR* aAttribValues)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aAttribNames || !aNameSpaceID || !aAttribValues)
|
|
return E_INVALIDARG;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
if (!mNode->IsElement())
|
|
return S_FALSE;
|
|
|
|
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(mNode));
|
|
nsNameSpaceManager* nameSpaceManager = nsNameSpaceManager::GetInstance();
|
|
|
|
int32_t index = 0;
|
|
for (index = 0; index < aMaxAttribs; index++) {
|
|
aAttribValues[index] = nullptr;
|
|
if (aAttribNames[index]) {
|
|
nsAutoString attributeValue, nameSpaceURI;
|
|
nsAutoString attributeName(nsDependentString(
|
|
static_cast<const wchar_t*>(aAttribNames[index])));
|
|
|
|
nsresult rv = NS_OK;
|
|
if (aNameSpaceID[index]>0 &&
|
|
NS_SUCCEEDED(nameSpaceManager->GetNameSpaceURI(aNameSpaceID[index],
|
|
nameSpaceURI))) {
|
|
rv = domElement->GetAttributeNS(nameSpaceURI, attributeName,
|
|
attributeValue);
|
|
} else {
|
|
rv = domElement->GetAttribute(attributeName, attributeValue);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
aAttribValues[index] = ::SysAllocString(attributeValue.get());
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_computedStyle(unsigned short aMaxStyleProperties,
|
|
boolean aUseAlternateView,
|
|
BSTR __RPC_FAR* aStyleProperties,
|
|
BSTR __RPC_FAR* aStyleValues,
|
|
unsigned short __RPC_FAR* aNumStyleProperties)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aStyleProperties || aStyleValues || !aNumStyleProperties)
|
|
return E_INVALIDARG;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
*aNumStyleProperties = 0;
|
|
|
|
if (mNode->IsNodeOfType(nsINode::eDOCUMENT))
|
|
return S_FALSE;
|
|
|
|
nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl =
|
|
nsWinUtils::GetComputedStyleDeclaration(mNode->AsContent());
|
|
NS_ENSURE_TRUE(cssDecl, E_FAIL);
|
|
|
|
uint32_t length = 0;
|
|
cssDecl->GetLength(&length);
|
|
|
|
uint32_t index = 0, realIndex = 0;
|
|
for (index = realIndex = 0; index < length && realIndex < aMaxStyleProperties;
|
|
index ++) {
|
|
nsAutoString property, value;
|
|
|
|
// Ignore -moz-* properties.
|
|
if (NS_SUCCEEDED(cssDecl->Item(index, property)) && property.CharAt(0) != '-')
|
|
cssDecl->GetPropertyValue(property, value); // Get property value
|
|
|
|
if (!value.IsEmpty()) {
|
|
aStyleProperties[realIndex] = ::SysAllocString(property.get());
|
|
aStyleValues[realIndex] = ::SysAllocString(value.get());
|
|
++realIndex;
|
|
}
|
|
}
|
|
|
|
*aNumStyleProperties = static_cast<unsigned short>(realIndex);
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_computedStyleForProperties(unsigned short aNumStyleProperties,
|
|
boolean aUseAlternateView,
|
|
BSTR __RPC_FAR* aStyleProperties,
|
|
BSTR __RPC_FAR* aStyleValues)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aStyleProperties || !aStyleValues)
|
|
return E_INVALIDARG;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
if (mNode->IsNodeOfType(nsINode::eDOCUMENT))
|
|
return S_FALSE;
|
|
|
|
nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl =
|
|
nsWinUtils::GetComputedStyleDeclaration(mNode->AsContent());
|
|
NS_ENSURE_TRUE(cssDecl, E_FAIL);
|
|
|
|
uint32_t index = 0;
|
|
for (index = 0; index < aNumStyleProperties; index++) {
|
|
nsAutoString value;
|
|
if (aStyleProperties[index])
|
|
cssDecl->GetPropertyValue(nsDependentString(aStyleProperties[index]), value); // Get property value
|
|
aStyleValues[index] = ::SysAllocString(value.get());
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::scrollTo(boolean aScrollTopLeft)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
DocAccessible* document = GetDocument();
|
|
if (!document) // that's IsDefunct check
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
if (!mNode->IsContent())
|
|
return S_FALSE;
|
|
|
|
uint32_t scrollType =
|
|
aScrollTopLeft ? nsIAccessibleScrollType::SCROLL_TYPE_TOP_LEFT :
|
|
nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_RIGHT;
|
|
|
|
nsCoreUtils::ScrollTo(document->PresShell(), mNode->AsContent(), scrollType);
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_parentNode(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aNode)
|
|
return E_INVALIDARG;
|
|
*aNode = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsINode* resultNode = mNode->GetParentNode();
|
|
if (resultNode) {
|
|
*aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
|
|
(*aNode)->AddRef();
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_firstChild(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aNode)
|
|
return E_INVALIDARG;
|
|
*aNode = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsINode* resultNode = mNode->GetFirstChild();
|
|
if (resultNode) {
|
|
*aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
|
|
(*aNode)->AddRef();
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_lastChild(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aNode)
|
|
return E_INVALIDARG;
|
|
*aNode = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsINode* resultNode = mNode->GetLastChild();
|
|
if (resultNode) {
|
|
*aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
|
|
(*aNode)->AddRef();
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_previousSibling(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aNode)
|
|
return E_INVALIDARG;
|
|
*aNode = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsINode* resultNode = mNode->GetPreviousSibling();
|
|
if (resultNode) {
|
|
*aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
|
|
(*aNode)->AddRef();
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_nextSibling(ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aNode)
|
|
return E_INVALIDARG;
|
|
*aNode = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsINode* resultNode = mNode->GetNextSibling();
|
|
if (resultNode) {
|
|
*aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
|
|
(*aNode)->AddRef();
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_childAt(unsigned aChildIndex,
|
|
ISimpleDOMNode __RPC_FAR *__RPC_FAR* aNode)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aNode)
|
|
return E_INVALIDARG;
|
|
*aNode = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsINode* resultNode = mNode->GetChildAt(aChildIndex);
|
|
if (resultNode) {
|
|
*aNode = static_cast<ISimpleDOMNode*>(new sdnAccessible(resultNode));
|
|
(*aNode)->AddRef();
|
|
}
|
|
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_innerHTML(BSTR __RPC_FAR* aInnerHTML)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aInnerHTML)
|
|
return E_INVALIDARG;
|
|
*aInnerHTML = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
if (!mNode->IsElement())
|
|
return S_FALSE;
|
|
|
|
nsAutoString innerHTML;
|
|
mNode->AsElement()->GetInnerHTML(innerHTML);
|
|
if (innerHTML.IsEmpty())
|
|
return S_FALSE;
|
|
|
|
*aInnerHTML = ::SysAllocStringLen(innerHTML.get(), innerHTML.Length());
|
|
if (!*aInnerHTML)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_localInterface(void __RPC_FAR *__RPC_FAR* aLocalInterface)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aLocalInterface)
|
|
return E_INVALIDARG;
|
|
*aLocalInterface = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
*aLocalInterface = this;
|
|
AddRef();
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|
|
|
|
STDMETHODIMP
|
|
sdnAccessible::get_language(BSTR __RPC_FAR* aLanguage)
|
|
{
|
|
A11Y_TRYBLOCK_BEGIN
|
|
|
|
if (!aLanguage)
|
|
return E_INVALIDARG;
|
|
*aLanguage = nullptr;
|
|
|
|
if (IsDefunct())
|
|
return CO_E_OBJNOTCONNECTED;
|
|
|
|
nsAutoString language;
|
|
if (mNode->IsContent())
|
|
nsCoreUtils::GetLanguageFor(mNode->AsContent(), nullptr, language);
|
|
if (language.IsEmpty()) { // Nothing found, so use document's language
|
|
mNode->OwnerDoc()->GetHeaderData(nsGkAtoms::headerContentLanguage,
|
|
language);
|
|
}
|
|
|
|
if (language.IsEmpty())
|
|
return S_FALSE;
|
|
|
|
*aLanguage = ::SysAllocStringLen(language.get(), language.Length());
|
|
if (!*aLanguage)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
|
|
A11Y_TRYBLOCK_END
|
|
}
|