mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 395909. Should not require namespaces for ARIA role usage in text/html. r=surkov, a=dsicore
This commit is contained in:
parent
3347682055
commit
558c745412
@ -55,7 +55,7 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval
|
||||
nsIAccessible createHyperTextAccessible(in nsISupports aFrame);
|
||||
nsIAccessible createHTMLBRAccessible(in nsISupports aFrame);
|
||||
nsIAccessible createHTMLButtonAccessible(in nsISupports aFrame);
|
||||
nsIAccessible createHTMLAccessibleByMarkup(in nsIFrame aFrame, in nsIWeakReference aWeakShell, in nsIDOMNode aDOMNode, in AString aRole);
|
||||
nsIAccessible createHTMLAccessibleByMarkup(in nsIFrame aFrame, in nsIWeakReference aWeakShell, in nsIDOMNode aDOMNode);
|
||||
nsIAccessible createHTMLLIAccessible(in nsISupports aFrame, in nsISupports aBulletFrame, in AString aBulletText);
|
||||
nsIAccessible createHTMLCheckboxAccessible(in nsISupports aFrame);
|
||||
nsIAccessible createHTMLComboboxAccessible(in nsIDOMNode aNode, in nsIWeakReference aPresShell);
|
||||
|
@ -47,12 +47,14 @@
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDocumentViewer.h"
|
||||
#include "nsIDOM3Node.h"
|
||||
#include "nsIDOMCSSStyleDeclaration.h"
|
||||
#include "nsIDOMCSSPrimitiveValue.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMHTMLDocument.h"
|
||||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIDOMNSDocument.h"
|
||||
#include "nsIDOMNSHTMLElement.h"
|
||||
#include "nsIDOMViewCSS.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
@ -890,3 +892,71 @@ nsAccessNode::GetLanguage(nsAString& aLanguage)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsAccessNode::GetARIARole(nsIContent *aContent, nsString& aRole)
|
||||
{
|
||||
nsAutoString prefix;
|
||||
PRBool strictPrefixChecking = PR_TRUE;
|
||||
aRole.Truncate();
|
||||
|
||||
if (aContent->IsNodeOfType(nsINode::eHTML)) { // HTML node
|
||||
// Allow non-namespaced role attribute in HTML
|
||||
aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::role, aRole);
|
||||
// Find non-namespaced role attribute on HTML node
|
||||
nsCOMPtr<nsIDOMNSDocument> doc(do_QueryInterface(aContent->GetDocument()));
|
||||
if (doc) {
|
||||
// In text/html we are hardcoded to allow the exact prefix "wairole:" to
|
||||
// always indicate that we are using the WAI roles.
|
||||
// This allows ARIA to be used within text/html where namespaces cannot be defined.
|
||||
// We also now relax the prefix checking, which means no prefix is required to use WAI Roles
|
||||
nsAutoString mimeType;
|
||||
doc->GetContentType(mimeType);
|
||||
if (mimeType.EqualsLiteral("text/html")) {
|
||||
prefix = NS_LITERAL_STRING("wairole:");
|
||||
strictPrefixChecking = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try namespaced-role attribute (xhtml or xhtml2 namespace) -- allowed in any kind of content
|
||||
if (aRole.IsEmpty() && !aContent->GetAttr(kNameSpaceID_XHTML, nsAccessibilityAtoms::role, aRole) &&
|
||||
!aContent->GetAttr(kNameSpaceID_XHTML2_Unofficial, nsAccessibilityAtoms::role, aRole)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool hasPrefix = (aRole.Find(":") >= 0);
|
||||
|
||||
if (!hasPrefix) {
|
||||
// * No prefix* -- not a QName
|
||||
// Just return entire string as long as prefix is not currently required
|
||||
if (strictPrefixChecking) {
|
||||
// Prefix was required and we didn't have one
|
||||
aRole.Truncate();
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// * Has prefix * -- is a QName (role="prefix:rolename")
|
||||
if (strictPrefixChecking) { // Not text/html, we need to actually find the WAIRole prefix
|
||||
// QI to nsIDOM3Node causes some overhead. Unfortunately we need to do this each
|
||||
// time there is a prefixed role attribute, because the prefix to namespace mappings
|
||||
// can change within any subtree via the xmlns attribute
|
||||
nsCOMPtr<nsIDOM3Node> dom3Node(do_QueryInterface(aContent));
|
||||
if (dom3Node) {
|
||||
// Look up exact prefix name for WAI Roles
|
||||
NS_NAMED_LITERAL_STRING(kWAIRoles_Namespace, "http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#");
|
||||
dom3Node->LookupPrefix(kWAIRoles_Namespace, prefix);
|
||||
prefix += ':';
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 length = prefix.Length();
|
||||
if (length > 1 && StringBeginsWith(aRole, prefix)) {
|
||||
// Is a QName (role="prefix:rolename"), and prefix matches WAI Role prefix
|
||||
// Trim the WAI Role prefix off
|
||||
aRole.Cut(0, length);
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -71,6 +71,16 @@ class nsApplicationAccessibleWrap;
|
||||
typedef nsInterfaceHashtable<nsVoidPtrHashKey, nsIAccessNode>
|
||||
nsAccessNodeHashtable;
|
||||
|
||||
/**
|
||||
* Does the current content have this ARIA role?
|
||||
* Implemented as a compiler macro so that length can be computed at compile time.
|
||||
* @param aContent Node to get role string from
|
||||
* @param aRoleName Role string to compare with -- literal const char*
|
||||
* @return PR_TRUE if there is a match
|
||||
*/
|
||||
#define ARIARoleEquals(aContent, aRoleName) \
|
||||
nsAccessNode::ARIARoleEqualsImpl(aContent, aRoleName, NS_ARRAY_LENGTH(aRoleName) - 1)
|
||||
|
||||
class nsAccessNode: public nsIAccessNode, public nsPIAccessNode
|
||||
{
|
||||
public: // construction, destruction
|
||||
@ -114,14 +124,16 @@ class nsAccessNode: public nsIAccessNode, public nsPIAccessNode
|
||||
aContent->HasAttr(kNameSpaceID_XHTML2_Unofficial, nsAccessibilityAtoms::role);
|
||||
}
|
||||
|
||||
// Return PR_TRUE if there is a role attribute, and fill it into aRole
|
||||
static PRBool GetRoleAttribute(nsIContent *aContent, nsAString& aRole)
|
||||
{
|
||||
aRole.Truncate();
|
||||
return (aContent->IsNodeOfType(nsINode::eHTML) && aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::role, aRole)) ||
|
||||
aContent->GetAttr(kNameSpaceID_XHTML, nsAccessibilityAtoms::role, aRole) ||
|
||||
aContent->GetAttr(kNameSpaceID_XHTML2_Unofficial, nsAccessibilityAtoms::role, aRole);
|
||||
}
|
||||
/**
|
||||
* Provide the role string if there is one
|
||||
* @param aContent Node to get role string from
|
||||
* @param aRole String to fill role into
|
||||
* @return PR_TRUE if there is a role attribute, and fill it into aRole
|
||||
*/
|
||||
static PRBool GetARIARole(nsIContent *aContent, nsString& aRole);
|
||||
|
||||
static PRBool ARIARoleEqualsImpl(nsIContent* aContent, const char* aRoleName, PRUint32 aLen)
|
||||
{ nsAutoString role; return GetARIARole(aContent, role) && role.EqualsASCII(aRoleName, aLen); }
|
||||
|
||||
static void GetComputedStyleDeclaration(const nsAString& aPseudoElt,
|
||||
nsIDOMElement *aElement,
|
||||
|
@ -434,7 +434,6 @@ nsresult
|
||||
nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame *aFrame,
|
||||
nsIWeakReference *aWeakShell,
|
||||
nsIDOMNode *aNode,
|
||||
const nsAString& aRole,
|
||||
nsIAccessible **aAccessible)
|
||||
{
|
||||
// This method assumes we're in an HTML namespace.
|
||||
@ -1337,9 +1336,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
|
||||
}
|
||||
|
||||
nsAutoString role;
|
||||
if (nsAccessNode::GetRoleAttribute(content, role) &&
|
||||
StringEndsWith(role, NS_LITERAL_STRING(":presentation")) &&
|
||||
!content->IsFocusable()) {
|
||||
if (nsAccessNode::GetARIARole(content, role) && role.EqualsLiteral("presentation") && !content->IsFocusable()) {
|
||||
// Only create accessible for role=":presentation" if it is focusable --
|
||||
// in that case we need an accessible in case it gets focused, we
|
||||
// don't want focus ever to be 'lost'
|
||||
@ -1366,7 +1363,7 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
|
||||
} else if (!newAcc) { // HTML accessibles
|
||||
// Prefer to use markup (mostly tag name, perhaps attributes) to
|
||||
// decide if and what kind of accessible to create.
|
||||
CreateHTMLAccessibleByMarkup(frame, aWeakShell, aNode, role, getter_AddRefs(newAcc));
|
||||
CreateHTMLAccessibleByMarkup(frame, aWeakShell, aNode, getter_AddRefs(newAcc));
|
||||
|
||||
PRBool tryFrame = (newAcc == nsnull);
|
||||
if (!content->IsFocusable()) {
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "nsIAccessibleHyperText.h"
|
||||
#include "nsAccessibleTreeWalker.h"
|
||||
|
||||
#include "nsIDOM3Node.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMDocumentXBL.h"
|
||||
@ -53,7 +52,6 @@
|
||||
#include "nsIDOMHTMLDocument.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsIDOMNodeFilter.h"
|
||||
#include "nsIDOMNSDocument.h"
|
||||
#include "nsIDOMNSHTMLElement.h"
|
||||
#include "nsIDOMTreeWalker.h"
|
||||
#include "nsIDOMXULButtonElement.h"
|
||||
@ -475,45 +473,18 @@ NS_IMETHODIMP nsAccessible::Init()
|
||||
{
|
||||
nsIContent *content = GetRoleContent(mDOMNode);
|
||||
nsAutoString roleString;
|
||||
if (content && GetRoleAttribute(content, roleString)) {
|
||||
// QI to nsIDOM3Node causes some overhead. Unfortunately we need to do this each
|
||||
// time there is a role attribute, because the prefixe to namespace mappings
|
||||
// can change within any subtree via the xmlns attribute
|
||||
nsCOMPtr<nsIDOM3Node> dom3Node(do_QueryInterface(content));
|
||||
if (dom3Node) {
|
||||
nsAutoString prefix;
|
||||
NS_NAMED_LITERAL_STRING(kWAIRoles_Namespace, "http://www.w3.org/2005/01/wai-rdf/GUIRoleTaxonomy#");
|
||||
dom3Node->LookupPrefix(kWAIRoles_Namespace, prefix);
|
||||
if (prefix.IsEmpty()) {
|
||||
// In HTML we are hardcoded to allow the exact prefix "wairole:" to
|
||||
// always indicate that we are using the WAI roles. This allows DHTML accessibility
|
||||
// to be used within HTML
|
||||
nsCOMPtr<nsIDOMNSDocument> doc(do_QueryInterface(content->GetDocument()));
|
||||
if (doc) {
|
||||
nsAutoString mimeType;
|
||||
doc->GetContentType(mimeType);
|
||||
if (mimeType.EqualsLiteral("text/html")) {
|
||||
prefix = NS_LITERAL_STRING("wairole");
|
||||
}
|
||||
}
|
||||
}
|
||||
prefix += ':';
|
||||
PRUint32 length = prefix.Length();
|
||||
if (length > 1 && StringBeginsWith(roleString, prefix)) {
|
||||
roleString.Cut(0, length);
|
||||
nsCString utf8Role = NS_ConvertUTF16toUTF8(roleString); // For easy comparison
|
||||
ToLowerCase(utf8Role);
|
||||
PRUint32 index;
|
||||
for (index = 0; nsARIAMap::gWAIRoleMap[index].roleString; index ++) {
|
||||
if (utf8Role.Equals(nsARIAMap::gWAIRoleMap[index].roleString)) {
|
||||
break; // The dynamic role attribute maps to an entry in our table
|
||||
}
|
||||
}
|
||||
// Always use some entry if there is a role string
|
||||
// If no match, we use the last entry which maps to ROLE_NOTHING
|
||||
mRoleMapEntry = &nsARIAMap::gWAIRoleMap[index];
|
||||
if (content && GetARIARole(content, roleString)) {
|
||||
nsCString utf8Role = NS_ConvertUTF16toUTF8(roleString); // For easy comparison
|
||||
ToLowerCase(utf8Role);
|
||||
PRUint32 index;
|
||||
for (index = 0; nsARIAMap::gWAIRoleMap[index].roleString; index ++) {
|
||||
if (utf8Role.Equals(nsARIAMap::gWAIRoleMap[index].roleString)) {
|
||||
break; // The dynamic role attribute maps to an entry in our table
|
||||
}
|
||||
}
|
||||
// Always use some entry if there is a role string
|
||||
// If no match, we use the last entry which maps to ROLE_NOTHING
|
||||
mRoleMapEntry = &nsARIAMap::gWAIRoleMap[index];
|
||||
}
|
||||
|
||||
return nsAccessNodeWrap::Init();
|
||||
@ -2067,7 +2038,7 @@ nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
|
||||
// XXX In the future we may need to expose the dynamic content role inheritance chain
|
||||
// through this attribute
|
||||
nsAutoString xmlRole;
|
||||
if (GetRoleAttribute(content, xmlRole)) {
|
||||
if (GetARIARole(content, xmlRole)) {
|
||||
attributes->SetStringProperty(NS_LITERAL_CSTRING("xml-roles"), xmlRole, oldValueUnused);
|
||||
}
|
||||
|
||||
|
@ -1807,9 +1807,7 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
|
||||
eCoalesceFromSameSubtree, isAsynch);
|
||||
|
||||
// Check to see change occured in an ARIA menu, and fire an EVENT_MENUPOPUP_START if it did
|
||||
nsAutoString role;
|
||||
if (GetRoleAttribute(aChild, role) &&
|
||||
StringEndsWith(role, NS_LITERAL_STRING(":menu"), nsCaseInsensitiveStringComparator())) {
|
||||
if (ARIARoleEquals(aChild, "menu")) {
|
||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
|
||||
childNode, nsnull, eAllowDupes, isAsynch);
|
||||
}
|
||||
@ -1817,8 +1815,7 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
|
||||
// Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
|
||||
nsIContent *ancestor = aChild;
|
||||
while (ancestor) {
|
||||
if (GetRoleAttribute(ancestor, role) &&
|
||||
StringEndsWith(role, NS_LITERAL_STRING(":alert"), nsCaseInsensitiveStringComparator())) {
|
||||
if (ARIARoleEquals(ancestor, "alert")) {
|
||||
nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
|
||||
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode, nsnull,
|
||||
eRemoveDupes, isAsynch);
|
||||
|
@ -466,7 +466,7 @@ STDMETHODIMP nsAccessibleWrap::get_accRole(
|
||||
|
||||
if (content->IsNodeOfType(nsINode::eELEMENT)) {
|
||||
nsAutoString roleString;
|
||||
if (msaaRole != ROLE_SYSTEM_CLIENT && !GetRoleAttribute(content, roleString)) {
|
||||
if (msaaRole != ROLE_SYSTEM_CLIENT && !GetARIARole(content, roleString)) {
|
||||
nsINodeInfo *nodeInfo = content->NodeInfo();
|
||||
nodeInfo->GetName(roleString);
|
||||
nsAutoString nameSpaceURI;
|
||||
|
Loading…
Reference in New Issue
Block a user