Bug 804461, part2 - use context to build table trees, r=tbsaunde

This commit is contained in:
Alexander Surkov 2012-11-30 16:33:01 +09:00
parent 5501032117
commit d0638a4613
13 changed files with 382 additions and 189 deletions

View File

@ -87,7 +87,8 @@ TreeWalker::NextChildInternal(bool aNoWalkUp)
bool isSubtreeHidden = false;
Accessible* accessible = mWalkCache ? mDoc->GetAccessible(childNode) :
GetAccService()->GetOrCreateAccessible(childNode, mDoc, &isSubtreeHidden);
GetAccService()->GetOrCreateAccessible(childNode, mContext,
&isSubtreeHidden);
if (accessible)
return accessible;

View File

@ -110,7 +110,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoValue,
eSortAction,
eNoLiveAttr,
kGenericAccType,
Accessible::eTableCellAccessible,
kNoReqStates,
eARIASelectable,
eARIAReadonly
@ -175,7 +175,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoValue,
eNoAction,
eNoLiveAttr,
Accessible::eSelectAccessible,
Accessible::eSelectAccessible | Accessible::eTableAccessible,
states::FOCUSABLE,
eARIAMultiSelectable,
eARIAReadonly
@ -187,7 +187,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoValue,
eNoAction,
eNoLiveAttr,
kGenericAccType,
Accessible::eTableCellAccessible,
kNoReqStates,
eARIASelectable,
eARIAReadonly
@ -429,7 +429,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoValue,
eNoAction,
eNoLiveAttr,
kGenericAccType,
Accessible::eTableRowAccessible,
kNoReqStates,
eARIASelectable
},
@ -450,7 +450,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoValue,
eSortAction,
eNoLiveAttr,
kGenericAccType,
Accessible::eTableCellAccessible,
kNoReqStates,
eARIASelectable,
eARIAReadonly
@ -603,7 +603,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
eNoValue,
eNoAction,
eNoLiveAttr,
Accessible::eSelectAccessible,
Accessible::eSelectAccessible | Accessible::eTableAccessible,
kNoReqStates,
eARIAReadonly,
eARIAMultiSelectable

View File

@ -208,7 +208,7 @@ nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
already_AddRefed<Accessible>
nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
nsIContent* aContent,
DocAccessible* aDoc)
Accessible* aContext)
{
// We can have several cases here:
// 1) a text or html embedded document where the contentDocument variable in
@ -227,7 +227,8 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
nsCOMPtr<nsIDOMDocument> domDoc;
obj->GetContentDocument(getter_AddRefs(domDoc));
if (domDoc) {
Accessible* newAcc = new OuterDocAccessible(aContent, aDoc);
Accessible* newAcc =
new OuterDocAccessible(aContent, aContext->Document());
NS_ADDREF(newAcc);
return newAcc;
}
@ -244,7 +245,8 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
aFrame->GetPluginPort(&pluginPort);
Accessible* accessible =
new HTMLWin32ObjectOwnerAccessible(aContent, aDoc, pluginPort);
new HTMLWin32ObjectOwnerAccessible(aContent, aContext->Document(),
pluginPort);
NS_ADDREF(accessible);
return accessible;
@ -257,7 +259,7 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
NPPVpluginNativeAccessibleAtkPlugId, &plugId);
if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) {
AtkSocketAccessible* socketAccessible =
new AtkSocketAccessible(aContent, aDoc, plugId);
new AtkSocketAccessible(aContent, aContext->Document(), plugId);
NS_ADDREF(socketAccessible);
return socketAccessible;
@ -269,8 +271,8 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame,
// 3) for images and imagemaps, or anything else with a child frame
// we have the object frame, get the image frame
nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
return childFrame ? CreateAccessibleByFrameType(childFrame, aContent, aDoc) :
nullptr;
return childFrame ?
CreateAccessibleByFrameType(childFrame, aContent, aContext) : nullptr;
}
void
@ -678,17 +680,21 @@ nsAccessibilityService::IsLogged(const nsAString& aModule, bool* aIsLogged)
Accessible*
nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
DocAccessible* aDoc,
Accessible* aContext,
bool* aIsSubtreeHidden)
{
if (!aDoc || !aNode || gIsShutdown)
return nullptr;
NS_PRECONDITION(aContext && aNode && !gIsShutdown,
"Maybe let'd do a crash? Oh, yes, baby!");
if (aIsSubtreeHidden)
*aIsSubtreeHidden = false;
DocAccessible* document = aContext->Document();
// Check to see if we already have an accessible for this node in the cache.
Accessible* cachedAccessible = aDoc->GetAccessible(aNode);
// XXX: we don't have context check here. It doesn't really necessary until
// we have in-law children adoption.
Accessible* cachedAccessible = document->GetAccessible(aNode);
if (cachedAccessible)
return cachedAccessible;
@ -707,7 +713,7 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
return nullptr;
}
if (aNode->OwnerDoc() != aDoc->DocumentNode()) {
if (aNode->OwnerDoc() != document->DocumentNode()) {
NS_ERROR("Creating accessible for wrong document");
return nullptr;
}
@ -763,8 +769,8 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
return nullptr;
}
newAcc = CreateAccessibleByFrameType(frame, content, aDoc);
if (aDoc->BindToDocument(newAcc, nullptr)) {
newAcc = CreateAccessibleByFrameType(frame, content, aContext);
if (document->BindToDocument(newAcc, nullptr)) {
newAcc->AsTextLeaf()->SetText(text);
return newAcc;
}
@ -790,8 +796,8 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
return nullptr;
}
newAcc = new HyperTextAccessibleWrap(content, aDoc);
if (aDoc->BindToDocument(newAcc, aria::GetRoleMap(aNode)))
newAcc = new HyperTextAccessibleWrap(content, document);
if (document->BindToDocument(newAcc, aria::GetRoleMap(aNode)))
return newAcc;
return nullptr;
}
@ -802,115 +808,59 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
// it is referenced by ARIA relationship then treat role="presentation" on
// the element as the role is not there.
if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::presentation)) {
if (!MustBeAccessible(content, aDoc))
if (!MustBeAccessible(content, document))
return nullptr;
roleMapEntry = nullptr;
}
if (!newAcc && isHTML) { // HTML accessibles
nsIAtom* frameType = frame->GetType();
bool partOfHTMLTable =
frameType == nsGkAtoms::tableCaptionFrame ||
frameType == nsGkAtoms::tableCellFrame ||
frameType == nsGkAtoms::tableRowGroupFrame ||
frameType == nsGkAtoms::tableRowFrame;
bool legalPartOfHTMLTable = partOfHTMLTable;
if (partOfHTMLTable) {
// Table-related frames don't get table-related roles
// unless they are inside a table, but they may still get generic
// accessibles
nsIContent *tableContent = content;
while ((tableContent = tableContent->GetParent()) != nullptr) {
nsIFrame *tableFrame = tableContent->GetPrimaryFrame();
if (!tableFrame)
continue;
if (tableFrame->GetType() == nsGkAtoms::tableOuterFrame) {
Accessible* tableAccessible = aDoc->GetAccessible(tableContent);
if (tableAccessible) {
if (!roleMapEntry) {
roles::Role role = tableAccessible->Role();
// No ARIA role and not in table: override role. For example,
// <table role="label"><td>content</td></table>
if (role != roles::TABLE && role != roles::TREE_TABLE)
roleMapEntry = &nsARIAMap::gEmptyRoleMap;
}
break;
}
#ifdef DEBUG
nsRoleMapEntry* tableRoleMapEntry = aria::GetRoleMap(tableContent);
NS_ASSERTION(tableRoleMapEntry && tableRoleMapEntry->Is(nsGkAtoms::presentation),
"No accessible for parent table and it didn't have role of presentation");
#endif
if (!roleMapEntry && !MustBeAccessible(content, aDoc)) {
// Table-related descendants of presentation table are also
// presentation if they aren't focusable and have not explicit ARIA
// role (don't create accessibles for them unless they need to fire
// focus events).
return nullptr;
}
// otherwise create ARIA based accessible.
legalPartOfHTMLTable = false;
break;
}
if (tableContent->Tag() == nsGkAtoms::table) {
// Stop before we are fooled by any additional table ancestors
// This table cell frameis part of a separate ancestor table.
legalPartOfHTMLTable = false;
break;
}
}
if (!tableContent)
legalPartOfHTMLTable = false;
}
if (roleMapEntry) {
// Create ARIA grid/treegrid accessibles if node is not a child or legal
// child of HTML table and is not a HTML table.
if ((!partOfHTMLTable || !legalPartOfHTMLTable) &&
frameType != nsGkAtoms::tableOuterFrame) {
if (roleMapEntry->role == roles::TABLE ||
roleMapEntry->role == roles::TREE_TABLE) {
newAcc = new ARIAGridAccessibleWrap(content, aDoc);
} else if (roleMapEntry->role == roles::GRID_CELL ||
roleMapEntry->role == roles::ROWHEADER ||
roleMapEntry->role == roles::COLUMNHEADER) {
newAcc = new ARIAGridCellAccessibleWrap(content, aDoc);
// Create pure ARIA grid/treegrid related accessibles if they weren't used
// on accessible HTML table elements.
if ((roleMapEntry->accTypes & Accessible::eTableCellAccessible)) {
if (aContext->IsOfType(Accessible::eTableRowAccessible) &&
(frame->AccessibleType() != eHTMLTableCellAccessible ||
aContext->GetContent() != content->GetParent())) {
newAcc = new ARIAGridCellAccessibleWrap(content, document);
}
} else if ((roleMapEntry->accTypes & Accessible::eTableAccessible) &&
frame->AccessibleType() != eHTMLTableAccessible) {
newAcc = new ARIAGridAccessibleWrap(content, document);
}
}
if (!newAcc) {
// Prefer to use markup (mostly tag name, perhaps attributes) to
// decide if and what kind of accessible to create.
// The method creates accessibles for table related content too therefore
// we do not call it if accessibles for table related content are
// prevented above.
newAcc = CreateHTMLAccessibleByMarkup(frame, content, aDoc,
legalPartOfHTMLTable);
// Prefer to use markup (mostly tag name, perhaps attributes) to decide if
// and what kind of accessible to create.
newAcc = CreateHTMLAccessibleByMarkup(frame, content, aContext);
// Try using frame to do it.
if (!newAcc && (!partOfHTMLTable || legalPartOfHTMLTable))
newAcc = CreateAccessibleByFrameType(frame, content, aDoc);
if (!newAcc)
newAcc = CreateAccessibleByFrameType(frame, content, aContext);
// If table has strong ARIA role then all table descendants shouldn't
// expose their native roles.
if (!roleMapEntry && newAcc) {
if (frame->AccessibleType() == eHTMLTableRowAccessible) {
nsRoleMapEntry* contextRoleMap = aContext->ARIARoleMap();
if (contextRoleMap &&
!(contextRoleMap->accTypes & Accessible::eTableAccessible))
roleMapEntry = &nsARIAMap::gEmptyRoleMap;
} else if (frame->AccessibleType() == eHTMLTableCellAccessible &&
aContext->ARIARoleMap() == &nsARIAMap::gEmptyRoleMap) {
roleMapEntry = &nsARIAMap::gEmptyRoleMap;
}
}
}
}
if (!newAcc) {
// Elements may implement nsIAccessibleProvider via XBL. This allows them to
// say what kind of accessible to create.
newAcc = CreateAccessibleByType(content, aDoc);
newAcc = CreateAccessibleByType(content, document);
}
if (!newAcc) {
@ -918,37 +868,37 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
// on HTML elements
nsIAtom* tag = content->Tag();
if ((tag == nsGkAtoms::deck) || (tag == nsGkAtoms::tabpanels)) {
newAcc = new XULDeckAccessible(content, aDoc);
newAcc = new XULDeckAccessible(content, document);
} else if (content->IsSVG(nsGkAtoms::svg)) {
newAcc = new EnumRoleAccessible(content, aDoc, roles::DIAGRAM);
newAcc = new EnumRoleAccessible(content, document, roles::DIAGRAM);
} else if (content->IsMathML(nsGkAtoms::math)) {
newAcc = new EnumRoleAccessible(content, aDoc, roles::EQUATION);
newAcc = new EnumRoleAccessible(content, document, roles::EQUATION);
}
}
if (!newAcc)
newAcc = CreateAccessibleForDeckChild(frame, content, aDoc);
newAcc = CreateAccessibleForDeckChild(frame, content, document);
// If no accessible, see if we need to create a generic accessible because
// of some property that makes this object interesting
// We don't do this for <body>, <html>, <window>, <dialog> etc. which
// correspond to the doc accessible and will be created in any case
if (!newAcc && content->Tag() != nsGkAtoms::body && content->GetParent() &&
(roleMapEntry || MustBeAccessible(content, aDoc) ||
(roleMapEntry || MustBeAccessible(content, document) ||
(isHTML && nsCoreUtils::HasClickListener(content)))) {
// This content is focusable or has an interesting dynamic content accessibility property.
// If it's interesting we need it in the accessibility hierarchy so that events or
// other accessibles can point to it, or so that it can hold a state, etc.
if (isHTML) {
// Interesting HTML container which may have selectable text and/or embedded objects
newAcc = new HyperTextAccessibleWrap(content, aDoc);
newAcc = new HyperTextAccessibleWrap(content, document);
} else { // XUL, SVG, MathML etc.
// Interesting generic non-HTML container
newAcc = new AccessibleWrap(content, aDoc);
newAcc = new AccessibleWrap(content, document);
}
}
return aDoc->BindToDocument(newAcc, roleMapEntry) ? newAcc : nullptr;
return document->BindToDocument(newAcc, roleMapEntry) ? newAcc : nullptr;
}
////////////////////////////////////////////////////////////////////////////////
@ -1238,13 +1188,14 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
already_AddRefed<Accessible>
nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
nsIContent* aContent,
DocAccessible* aDoc,
bool aIsLegalPartOfHTMLTable)
Accessible* aContext)
{
if (aIsLegalPartOfHTMLTable) {
if (nsCoreUtils::IsHTMLTableHeader(aContent)) {
Accessible* accessible =
new HTMLTableHeaderCellAccessibleWrap(aContent, aDoc);
DocAccessible* document = aContext->Document();
if (aContext->IsOfType(Accessible::eTableRowAccessible)) {
if (nsCoreUtils::IsHTMLTableHeader(aContent) &&
aContext->GetContent() == aContent->GetParent()) {
Accessible* accessible = new HTMLTableHeaderCellAccessibleWrap(aContent,
document);
NS_ADDREF(accessible);
return accessible;
}
@ -1255,38 +1206,39 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
// This method assumes we're in an HTML namespace.
nsIAtom* tag = aContent->Tag();
if (tag == nsGkAtoms::figcaption) {
Accessible* accessible = new HTMLFigcaptionAccessible(aContent, aDoc);
Accessible* accessible = new HTMLFigcaptionAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::figure) {
Accessible* accessible = new HTMLFigureAccessible(aContent, aDoc);
Accessible* accessible = new HTMLFigureAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::legend) {
Accessible* accessible = new HTMLLegendAccessible(aContent, aDoc);
Accessible* accessible = new HTMLLegendAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::option) {
Accessible* accessible = new HTMLSelectOptionAccessible(aContent, aDoc);
Accessible* accessible = new HTMLSelectOptionAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::optgroup) {
Accessible* accessible = new HTMLSelectOptGroupAccessible(aContent, aDoc);
Accessible* accessible =
new HTMLSelectOptGroupAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::ul || tag == nsGkAtoms::ol ||
tag == nsGkAtoms::dl) {
Accessible* accessible = new HTMLListAccessible(aContent, aDoc);
Accessible* accessible = new HTMLListAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
@ -1297,12 +1249,12 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent);
if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
roleMapEntry->role != roles::LINK) {
Accessible* accessible = new HyperTextAccessibleWrap(aContent, aDoc);
Accessible* accessible = new HyperTextAccessibleWrap(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
Accessible* accessible = new HTMLLinkAccessible(aContent, aDoc);
Accessible* accessible = new HTMLLinkAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
@ -1310,7 +1262,7 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
if (tag == nsGkAtoms::dt || tag == nsGkAtoms::li) {
// Create list item accessible unconditionally by tag name. nsBlockFrame
// creates the list item accessible for other elements styled as list items.
Accessible* accessible = new HTMLLIAccessible(aContent, aDoc);
Accessible* accessible = new HTMLLIAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
@ -1327,20 +1279,20 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
tag == nsGkAtoms::h5 ||
tag == nsGkAtoms::h6 ||
tag == nsGkAtoms::q) {
Accessible* accessible = new HyperTextAccessibleWrap(aContent, aDoc);
Accessible* accessible = new HyperTextAccessibleWrap(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::output) {
Accessible* accessible = new HTMLOutputAccessible(aContent, aDoc);
Accessible* accessible = new HTMLOutputAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
if (tag == nsGkAtoms::progress) {
Accessible* accessible =
new HTMLProgressMeterAccessible(aContent, aDoc);
new HTMLProgressMeterAccessible(aContent, document);
NS_ADDREF(accessible);
return accessible;
}
@ -1351,86 +1303,109 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
already_AddRefed<Accessible>
nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
nsIContent* aContent,
DocAccessible* aDoc)
Accessible* aContext)
{
DocAccessible* document = aContext->Document();
nsRefPtr<Accessible> newAcc;
switch (aFrame->AccessibleType()) {
case eNoAccessible:
return nullptr;
case eHTMLBRAccessible:
newAcc = new HTMLBRAccessible(aContent, aDoc);
newAcc = new HTMLBRAccessible(aContent, document);
break;
case eHTMLButtonAccessible:
newAcc = new HTMLButtonAccessible(aContent, aDoc);
newAcc = new HTMLButtonAccessible(aContent, document);
break;
case eHTMLCanvasAccessible:
newAcc = new HTMLCanvasAccessible(aContent, aDoc);
newAcc = new HTMLCanvasAccessible(aContent, document);
break;
case eHTMLCaptionAccessible:
newAcc = new HTMLCaptionAccessible(aContent, aDoc);
if (aContext->IsOfType(Accessible::eTableAccessible) &&
aContext->GetContent() == aContent->GetParent()) {
newAcc = new HTMLCaptionAccessible(aContent, document);
}
break;
case eHTMLCheckboxAccessible:
newAcc = new HTMLCheckboxAccessible(aContent, aDoc);
newAcc = new HTMLCheckboxAccessible(aContent, document);
break;
case eHTMLComboboxAccessible:
newAcc = new HTMLComboboxAccessible(aContent, aDoc);
newAcc = new HTMLComboboxAccessible(aContent, document);
break;
case eHTMLFileInputAccessible:
newAcc = new HTMLFileInputAccessible(aContent, aDoc);
newAcc = new HTMLFileInputAccessible(aContent, document);
break;
case eHTMLGroupboxAccessible:
newAcc = new HTMLGroupboxAccessible(aContent, aDoc);
newAcc = new HTMLGroupboxAccessible(aContent, document);
break;
case eHTMLHRAccessible:
newAcc = new HTMLHRAccessible(aContent, aDoc);
newAcc = new HTMLHRAccessible(aContent, document);
break;
case eHTMLImageMapAccessible:
newAcc = new HTMLImageMapAccessible(aContent, aDoc);
newAcc = new HTMLImageMapAccessible(aContent, document);
break;
case eHTMLLabelAccessible:
newAcc = new HTMLLabelAccessible(aContent, aDoc);
newAcc = new HTMLLabelAccessible(aContent, document);
break;
case eHTMLLiAccessible:
newAcc = new HTMLLIAccessible(aContent, aDoc);
newAcc = new HTMLLIAccessible(aContent, document);
break;
case eHTMLSelectListAccessible:
newAcc = new HTMLSelectListAccessible(aContent, aDoc);
newAcc = new HTMLSelectListAccessible(aContent, document);
break;
case eHTMLMediaAccessible:
newAcc = new EnumRoleAccessible(aContent, aDoc, roles::GROUPING);
newAcc = new EnumRoleAccessible(aContent, document, roles::GROUPING);
break;
case eHTMLObjectFrameAccessible: {
nsObjectFrame* objectFrame = do_QueryFrame(aFrame);
newAcc = CreateHTMLObjectFrameAccessible(objectFrame, aContent, aDoc);
newAcc = CreateHTMLObjectFrameAccessible(objectFrame, aContent, aContext);
break;
}
case eHTMLRadioButtonAccessible:
newAcc = new HTMLRadioButtonAccessible(aContent, aDoc);
newAcc = new HTMLRadioButtonAccessible(aContent, document);
break;
case eHTMLTableAccessible:
newAcc = new HTMLTableAccessibleWrap(aContent, aDoc);
newAcc = new HTMLTableAccessibleWrap(aContent, document);
break;
case eHTMLTableCellAccessible:
newAcc = new HTMLTableCellAccessibleWrap(aContent, aDoc);
// Accessible HTML table cell must be a child of accessible HTML table row.
if (aContext->IsOfType(Accessible::eHTMLTableRowAccessible))
newAcc = new HTMLTableCellAccessibleWrap(aContent, document);
break;
case eHTMLTableRowAccessible:
newAcc = new EnumRoleAccessible(aContent, aDoc, roles::ROW);
case eHTMLTableRowAccessible: {
// Accessible HTML table row must be a child of tbody/tfoot/thead of
// accessible HTML table or must be a child of accessible of HTML table.
if (aContext->IsOfType(Accessible::eTableAccessible)) {
nsIContent* parentContent = aContent->GetParent();
nsIFrame* parentFrame = parentContent->GetPrimaryFrame();
if (parentFrame->GetType() == nsGkAtoms::tableRowGroupFrame) {
parentContent = parentContent->GetParent();
parentFrame = parentContent->GetPrimaryFrame();
}
if (parentFrame->GetType() == nsGkAtoms::tableOuterFrame &&
aContext->GetContent() == parentContent) {
newAcc = new HTMLTableRowAccessible(aContent, document);
}
}
break;
}
case eHTMLTextFieldAccessible:
newAcc = new HTMLTextFieldAccessible(aContent, aDoc);
newAcc = new HTMLTextFieldAccessible(aContent, document);
break;
case eHyperTextAccessible:
newAcc = new HyperTextAccessibleWrap(aContent, aDoc);
newAcc = new HyperTextAccessibleWrap(aContent, document);
break;
case eImageAccessible:
newAcc = new ImageAccessibleWrap(aContent, aDoc);
newAcc = new ImageAccessibleWrap(aContent, document);
break;
case eOuterDocAccessible:
newAcc = new OuterDocAccessible(aContent, aDoc);
newAcc = new OuterDocAccessible(aContent, document);
break;
case eTextLeafAccessible:
newAcc = new TextLeafAccessibleWrap(aContent, aDoc);
newAcc = new TextLeafAccessibleWrap(aContent, document);
break;
}

View File

@ -83,7 +83,7 @@ public:
bool aCanCreate);
already_AddRefed<Accessible>
CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame, nsIContent* aContent,
DocAccessible* aDoc);
Accessible* aContext);
/**
* Adds/remove ATK root accessible for gtk+ native window to/from children
@ -155,11 +155,11 @@ public:
* one.
*
* @param aNode [in] the given node
* @param aDoc [in] the doc accessible of the node
* @param aContext [in] context the accessible is created in
* @param aIsSubtreeHidden [out, optional] indicates whether the node's
* frame and its subtree is hidden
*/
Accessible* GetOrCreateAccessible(nsINode* aNode, DocAccessible* aDoc,
Accessible* GetOrCreateAccessible(nsINode* aNode, Accessible* aContext,
bool* aIsSubtreeHidden = nullptr);
private:
@ -192,15 +192,14 @@ private:
*/
already_AddRefed<Accessible>
CreateHTMLAccessibleByMarkup(nsIFrame* aFrame, nsIContent* aContent,
DocAccessible* aDoc,
bool aIsLegalPartOfHTMLTable);
Accessible* aContext);
/**
* Create an accessible whose type depends on the given frame.
*/
already_AddRefed<Accessible>
CreateAccessibleByFrameType(nsIFrame* aFrame, nsIContent* aContent,
DocAccessible* aDoc);
Accessible* aContext);
/**
* Create accessible if parent is a deck frame.

View File

@ -172,8 +172,12 @@ public:
/**
* Return true if ARIA role is specified on the element.
*/
bool HasARIARole() const
{ return mRoleMapEntry; }
bool HasARIARole() const { return mRoleMapEntry; }
/**
* Retrun ARIA role map if any.
*/
nsRoleMapEntry* ARIARoleMap() const { return mRoleMapEntry; }
/**
* Return accessible role specified by ARIA (see constants in
@ -692,6 +696,11 @@ public:
*/
bool HasOwnContent() const { return mContent && !(mFlags & eSharedNode); }
/**
* Return true if accessible is of given type.
*/
bool IsOfType(uint32_t aType) const { return mFlags & aType; }
/**
* Return true if the accessible has a numeric value.
*/
@ -778,17 +787,21 @@ public: // XXX: a small hack to make these visible for nsARIAMap
eHyperTextAccessible = 1 << 12,
eHTMLFileInputAccessible = 1 << 13,
eHTMLListItemAccessible = 1 << 14,
eImageAccessible = 1 << 15,
eImageMapAccessible = 1 << 16,
eListControlAccessible = 1 << 17,
eMenuButtonAccessible = 1 << 18,
eMenuPopupAccessible = 1 << 19,
eProgressAccessible = 1 << 20,
eRootAccessible = 1 << 21,
eSelectAccessible = 1 << 22,
eTextLeafAccessible = 1 << 23,
eXULDeckAccessible = 1 << 24,
eXULTreeAccessible = 1 << 25
eHTMLTableRowAccessible = 1 << 15,
eImageAccessible = 1 << 16,
eImageMapAccessible = 1 << 17,
eListControlAccessible = 1 << 18,
eMenuButtonAccessible = 1 << 19,
eMenuPopupAccessible = 1 << 20,
eProgressAccessible = 1 << 21,
eRootAccessible = 1 << 22,
eSelectAccessible = 1 << 23,
eTableAccessible = 1 << 24,
eTableCellAccessible = 1 << 25,
eTableRowAccessible = 1 << 26,
eTextLeafAccessible = 1 << 27,
eXULDeckAccessible = 1 << 28,
eXULTreeAccessible = 1 << 29
};
protected:

View File

@ -145,7 +145,7 @@ HTMLSelectListAccessible::CacheOptSiblings(nsIContent* aParentContent)
// Get an accessible for option or optgroup and cache it.
nsRefPtr<Accessible> accessible =
GetAccService()->GetOrCreateAccessible(childContent, mDoc);
GetAccService()->GetOrCreateAccessible(childContent, this);
if (accessible)
AppendChild(accessible);

View File

@ -321,6 +321,19 @@ HTMLTableHeaderCellAccessible::NativeRole()
return roles::COLUMNHEADER;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLTableRowAccessible
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableRowAccessible, Accessible)
role
HTMLTableRowAccessible::NativeRole()
{
return roles::ROW;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLTableAccessible
////////////////////////////////////////////////////////////////////////////////
@ -329,6 +342,7 @@ HTMLTableAccessible::
HTMLTableAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc), xpcAccessibleTable(this)
{
mFlags |= eTableAccessible;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -85,6 +85,24 @@ public:
};
/**
* HTML table row accessible (html:tr).
*/
class HTMLTableRowAccessible : public AccessibleWrap
{
public:
HTMLTableRowAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{ mFlags |= eTableRowAccessible | eHTMLTableRowAccessible; }
virtual ~HTMLTableRowAccessible() { }
NS_DECL_ISUPPORTS_INHERITED
// Accessible
virtual a11y::role NativeRole();
};
/**
* HTML table accessible (html:table).
*/

View File

@ -28,6 +28,7 @@ XULTreeGridAccessible::
XULTreeGridAccessible(nsIContent* aContent, DocAccessible* aDoc) :
XULTreeAccessible(aContent, aDoc), xpcAccessibleTable(this)
{
mFlags |= eTableAccessible;
}
////////////////////////////////////////////////////////////////////////////////
@ -279,6 +280,8 @@ XULTreeGridRowAccessible::
nsITreeView* aTreeView, int32_t aRow) :
XULTreeItemAccessibleBase(aContent, aDoc, aTreeAcc, aTree, aTreeView, aRow)
{
mFlags |= eTableRowAccessible;
mAccessibleCache.Init(kDefaultTreeCacheSize);
}

View File

@ -369,6 +369,9 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree)
testStates(acc, statesObj.states, statesObj.extraStates,
statesObj.absentStates, statesObj.absentExtraStates);
} else if (prop == "tagName") {
is(accTree[prop], acc.DOMNode.tagName, msg);
} else if (prop != "children") {
is(acc[prop], accTree[prop], msg);
}

View File

@ -115,7 +115,8 @@
//////////////////////////////////////////////////////////////////////////
// test gEmptyRoleMap
testRole("cell", ROLE_NOTHING);
testRole("buttontable_row", ROLE_NOTHING);
testRole("buttontable_cell", ROLE_NOTHING);
// abstract roles
var abstract_roles = ["composite", "landmark", "structure", "widget",
@ -275,8 +276,8 @@
<!-- test gEmptyRoleMap -->
<table role="button">
<tr>
<td id="cell">cell</td>
<tr id="buttontable_row">
<td id="buttontable_cell">cell</td>
</tr>
</table>

View File

@ -32,6 +32,124 @@
testAccessibleTree("grid", accTree);
//////////////////////////////////////////////////////////////////////////
// crazy grids (mad mix of ARIA and HTML tables)
accTree = {
role: ROLE_TABLE,
children: [
{ // div@role="row"
role: ROLE_ROW,
tagName: "DIV",
children: [
{ // caption text leaf
role: ROLE_TEXT_LEAF,
name: "caption",
children: [ ]
},
{ // th text leaf
role: ROLE_TEXT_LEAF,
name: "header1",
children: [ ]
},
{ // td@role="columnheader"
role: ROLE_COLUMNHEADER,
name: "header2",
children: [ { TEXT_LEAF: [ ] } ]
}
]
}
]
};
testAccessibleTree("crazy_grid1", accTree);
accTree = {
role: ROLE_TABLE,
children: [
{ // tr@role="row"
role: ROLE_ROW,
tagName: "TR",
children: [
{ // td text leaf
role: ROLE_TEXT_LEAF,
name: "cell1",
children: [ ]
},
{ // td@role="gridcell"
role: ROLE_GRID_CELL,
name: "cell2",
children: [ { TEXT_LEAF: [ ] } ]
}
]
}
]
};
testAccessibleTree("crazy_grid2", accTree);
accTree = {
role: ROLE_TABLE,
children: [
{ // div@role="row"
role: ROLE_ROW,
children: [
{ // div@role="gridcell"
role: ROLE_GRID_CELL,
children: [
{ // text leaf from presentational table
role: ROLE_TEXT_LEAF,
name: "cell3",
children: [ ]
},
]
}
]
}
]
};
testAccessibleTree("crazy_grid3", accTree);
accTree = {
role: ROLE_TABLE,
children: [
{ // div@role="row"
role: ROLE_ROW,
children: [
{ // div@role="gridcell"
role: ROLE_GRID_CELL,
children: [
{ // table
role: ROLE_TABLE,
children: [
{ // tr
role: ROLE_ROW,
children: [
{ // td
role: ROLE_CELL,
children: [
{ // caption text leaf of presentational table
role: ROLE_TEXT_LEAF,
name: "caption",
children: [ ]
},
{ // td text leaf of presentational table
role: ROLE_TEXT_LEAF,
name: "cell4",
children: [ ]
}
]
}
]
}
]
}
]
}
]
}
]
};
testAccessibleTree("crazy_grid4", accTree);
SimpleTest.finish();
}
@ -59,5 +177,55 @@
</div>
</div>
</div>
<div id="crazy_grid1" role="grid">
<div role="row">
<table role="presentation">
<caption>caption</caption>
<tr>
<th>header1</th>
<td role="columnheader">header2</td>
</tr>
</table>
</div>
</div>
<div id="crazy_grid2" role="grid">
<table role="presentation">
<tr role="row">
<td id="ct_cell1">cell1</td>
<td role="gridcell">cell2</td>
</tr>
</table>
</div>
<div id="crazy_grid3" role="grid">
<div role="row">
<div role="gridcell">
<table role="presentation">
<tr>
<td>cell3</td>
</tr>
</table>
</div>
</div>
</div>
<div id="crazy_grid4" role="grid">
<div role="row">
<div role="gridcell">
<table>
<tr>
<td>
<table role="presentation">
<caption>caption</caption>
<tr><td>cell4</td></tr>
</table>
</td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>

View File

@ -27,7 +27,6 @@
var tree =
{ PUSHBUTTON: [ // table
{ NOTHING: [ // tbody
{ NOTHING: [ // tr
{ NOTHING: [ // th
{ TEXT_LEAF: [ ] }
@ -35,8 +34,7 @@
{ NOTHING: [ // td
{ TEXT_LEAF: [ ] }
] }
] },
] },
] }
] };
testAccessibleTree("button_table", tree);