-
-
Notifications
You must be signed in to change notification settings - Fork 631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support ARIA table attributes, skip layout tables, and don't get stuck on hidden cells #7410
Changes from 3 commits
4cc163c
1d4519c
e43a671
a2b10a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,11 +80,13 @@ template<typename TableType> inline void fillTableCounts(VBufStorage_controlFiel | |
long count = 0; | ||
if (paccTable->get_nRows(&count) == S_OK) { | ||
s << count; | ||
node->addAttribute(L"table-physicalrowcount", s.str()); | ||
node->addAttribute(L"table-rowcount", s.str()); | ||
s.str(L""); | ||
} | ||
if (paccTable->get_nColumns(&count) == S_OK) { | ||
s << count; | ||
node->addAttribute(L"table-physicalcolumncount", s.str()); | ||
node->addAttribute(L"table-columncount", s.str()); | ||
} | ||
} | ||
|
@@ -130,9 +132,11 @@ inline void fillTableCellInfo_IATable(VBufStorage_controlFieldNode_t* node, IAcc | |
boolean isSelected; | ||
if (paccTable->get_rowColumnExtentsAtIndex(cellIndex, &row, &column, &rowExtents, &columnExtents, &isSelected) == S_OK) { | ||
s << row + 1; | ||
node->addAttribute(L"table-physicalrownumber", s.str()); | ||
node->addAttribute(L"table-rownumber", s.str()); | ||
s.str(L""); | ||
s << column + 1; | ||
node->addAttribute(L"table-physicalcolumnnumber", s.str()); | ||
node->addAttribute(L"table-columnnumber", s.str()); | ||
if (columnExtents > 1) { | ||
s.str(L""); | ||
|
@@ -188,9 +192,11 @@ inline void GeckoVBufBackend_t::fillTableCellInfo_IATable2(VBufStorage_controlFi | |
boolean isSelected; | ||
if (paccTableCell->get_rowColumnExtents(&row, &column, &rowExtents, &columnExtents, &isSelected) == S_OK) { | ||
s << row + 1; | ||
node->addAttribute(L"table-physicalrownumber", s.str()); | ||
node->addAttribute(L"table-rownumber", s.str()); | ||
s.str(L""); | ||
s << column + 1; | ||
node->addAttribute(L"table-physicalcolumnnumber", s.str()); | ||
node->addAttribute(L"table-columnnumber", s.str()); | ||
if (columnExtents > 1) { | ||
s.str(L""); | ||
|
@@ -305,7 +311,7 @@ const wregex REGEX_PRESENTATION_ROLE(L"IAccessible2\\\\:\\\\:attribute_xml-roles | |
|
||
VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc, | ||
VBufStorage_buffer_t* buffer, VBufStorage_controlFieldNode_t* parentNode, VBufStorage_fieldNode_t* previousNode, | ||
IAccessibleTable* paccTable, IAccessibleTable2* paccTable2, long tableID, | ||
IAccessibleTable* paccTable, IAccessibleTable2* paccTable2, long tableID, const wchar_t* parentPresentationalRowNumber, | ||
bool ignoreInteractiveUnlabelledGraphics | ||
) { | ||
nhAssert(buffer); //buffer can't be NULL | ||
|
@@ -342,6 +348,9 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc, | |
return NULL; | ||
} | ||
|
||
// Save off the old parent for later propagation of some attributes | ||
VBufStorage_fieldNode_t* origParentNode=parentNode; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't seem to be used. |
||
|
||
//Add this node to the buffer | ||
parentNode=buffer->addControlFieldNode(parentNode,previousNode,docHandle,ID,TRUE); | ||
nhAssert(parentNode); //new node must have been created | ||
|
@@ -655,6 +664,23 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc, | |
} | ||
} | ||
|
||
// Add some presentational table attributes | ||
// Note these are only for reporting, the physical table attributes (table-physicalrownumber etc) for aiding in navigation etc are added later on. | ||
// propagate table-rownumber down to the cell as Gecko only includes it on the row itself | ||
if(parentPresentationalRowNumber) | ||
parentNode->addAttribute(L"table-rownumber",parentPresentationalRowNumber); | ||
const wchar_t* presentationalRowNumber=NULL; | ||
if((IA2AttribsMapIt = IA2AttribsMap.find(L"rowindex")) != IA2AttribsMap.end()) { | ||
parentNode->addAttribute(L"table-rownumber",IA2AttribsMapIt->second); | ||
presentationalRowNumber=IA2AttribsMapIt->second.c_str(); | ||
} | ||
if((IA2AttribsMapIt = IA2AttribsMap.find(L"colindex")) != IA2AttribsMap.end()) | ||
parentNode->addAttribute(L"table-columnnumber",IA2AttribsMapIt->second); | ||
if((IA2AttribsMapIt = IA2AttribsMap.find(L"rowcount")) != IA2AttribsMap.end()) | ||
parentNode->addAttribute(L"table-rowcount",IA2AttribsMapIt->second); | ||
if((IA2AttribsMapIt = IA2AttribsMap.find(L"colcount")) != IA2AttribsMap.end()) | ||
parentNode->addAttribute(L"table-columncount",IA2AttribsMapIt->second); | ||
|
||
BSTR value=NULL; | ||
if(pacc->get_accValue(varChild,&value)==S_OK) { | ||
if(value&&SysStringLen(value)==0) { | ||
|
@@ -736,7 +762,7 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc, | |
continue; | ||
} | ||
paccHyperlink->Release(); | ||
if (tempNode = this->fillVBuf(childPacc, buffer, parentNode, previousNode, paccTable, paccTable2, tableID, ignoreInteractiveUnlabelledGraphics)) { | ||
if (tempNode = this->fillVBuf(childPacc, buffer, parentNode, previousNode, paccTable, paccTable2, tableID, presentationalRowNumber, ignoreInteractiveUnlabelledGraphics)) { | ||
previousNode=tempNode; | ||
} else { | ||
LOG_DEBUG(L"Error in fillVBuf"); | ||
|
@@ -768,7 +794,7 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(IAccessible2* pacc, | |
VariantClear(&(varChildren[i])); | ||
continue; | ||
} | ||
if (tempNode = this->fillVBuf(childPacc, buffer, parentNode, previousNode, paccTable, paccTable2, tableID, ignoreInteractiveUnlabelledGraphics)) | ||
if (tempNode = this->fillVBuf(childPacc, buffer, parentNode, previousNode, paccTable, paccTable2, tableID, presentationalRowNumber, ignoreInteractiveUnlabelledGraphics)) | ||
previousNode=tempNode; | ||
else | ||
LOG_DEBUG(L"Error in calling fillVBuf"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1539,6 +1539,11 @@ def script_movePastEndOfContainer(self,gesture): | |
# Translators: Description for the Move past end of container command in browse mode. | ||
script_movePastEndOfContainer.__doc__=_("Moves past the end of the container element, such as a list or table") | ||
|
||
#: The controlField attribute name that should be used as the row number when navigating in a table. By default this is the same as the presentational attribute name | ||
navigationalTableRowNumberAttributeName="table-rownumber" | ||
#: The controlField attribute name that should be used as the column number when navigating in a table. By default this is the same as the presentational attribute name | ||
navigationalTableColumnNumberAttributeName="table-columnnumber" | ||
|
||
def _getTableCellCoords(self, info): | ||
""" | ||
Fetches information about the deepest table cell at the given position. | ||
|
@@ -1551,17 +1556,28 @@ def _getTableCellCoords(self, info): | |
if info.isCollapsed: | ||
info = info.copy() | ||
info.expand(textInfos.UNIT_CHARACTER) | ||
for field in reversed(info.getTextWithFields()): | ||
fields=list(info.getTextWithFields()) | ||
# First record the ID of all layout tables so that we can skip them when searching for the deepest table | ||
layoutIDs=set() | ||
for field in fields: | ||
if isinstance(field, textInfos.FieldCommand) and field.command == "controlStart" and field.field.get('table-layout'): | ||
tableID=field.field.get('table-id') | ||
if tableID is not None: | ||
layoutIDs.add(tableID) | ||
for field in reversed(fields): | ||
if not (isinstance(field, textInfos.FieldCommand) and field.command == "controlStart"): | ||
# Not a control field. | ||
continue | ||
attrs = field.field | ||
if "table-id" in attrs and "table-rownumber" in attrs: | ||
tableID=attrs.get('table-id') | ||
if tableID is None or tableID in layoutIDs: | ||
continue | ||
if self.navigationalTableColumnNumberAttributeName in attrs and not attrs.get('table-layout'): | ||
break | ||
else: | ||
raise LookupError("Not in a table cell") | ||
return (attrs["table-id"], | ||
attrs["table-rownumber"], attrs["table-columnnumber"], | ||
attrs[self.navigationalTableRowNumberAttributeName], attrs[self.navigationalTableColumnNumberAttributeName], | ||
attrs.get("table-rowsspanned", 1), attrs.get("table-columnsspanned", 1)) | ||
|
||
def _getTableCellAt(self,tableID,startPos,row,column): | ||
|
@@ -1576,6 +1592,7 @@ def _getTableCellAt(self,tableID,startPos,row,column): | |
@type column: int | ||
@returns: the table cell's position in the document | ||
@rtype: L{textInfos.TextInfo} | ||
@raises: L{HiddenCellFound} if the cell it founds is hidden, allowing the caller to try a different cell. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm concerned that we might not actually be able to tell the difference between a hidden cell and a cell which is out of bounds. Chrome doesn't render aria-hidden content in the tree at all, for example, and Gecko will probably do the same (eventually). Is there any reason we shouldn't just use LookupError here? |
||
""" | ||
raise NotImplementedError | ||
|
||
|
@@ -1612,19 +1629,28 @@ def _getNearestTableCell(self, tableID, startPos, origRow, origCol, origRowSpan, | |
elif axis == "column": | ||
destCol += origColSpan if movement == "next" else -1 | ||
|
||
if destCol < 1 or destRow<1: | ||
# Optimisation: We're definitely at the edge of the column or row. | ||
raise LookupError | ||
|
||
return self._getTableCellAt(tableID,startPos,destRow,destCol) | ||
# Try and fetch the cell at these coordinates, though if a hidden cell is hit, try up to 4 more times moving the coordinates on by one cell each time | ||
limit=5 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make this a constant, as it seems reasonable that something might want to tweak this. |
||
while limit>0: | ||
limit-=1 | ||
if destCol < 1 or destRow<1: | ||
# Optimisation: We're definitely at the edge of the column or row. | ||
raise LookupError | ||
try: | ||
return self._getTableCellAt(tableID,startPos,destRow,destCol) | ||
except HiddenCellFound: | ||
pass | ||
if axis=="row": | ||
destRow+=1 if movement=="next" else -1 | ||
else: | ||
destCol+=1 if movement=="next" else -1 | ||
raise LookupError | ||
|
||
def _tableMovementScriptHelper(self, movement="next", axis=None): | ||
if isScriptWaiting(): | ||
return | ||
formatConfig=config.conf["documentFormatting"].copy() | ||
formatConfig["reportTables"]=True | ||
# For now, table movement includes layout tables even if reporting of layout tables is disabled. | ||
formatConfig["includeLayoutTables"]=True | ||
try: | ||
tableID, origRow, origCol, origRowSpan, origColSpan = self._getTableCellCoords(self.selection) | ||
except LookupError: | ||
|
@@ -1702,3 +1728,7 @@ def _iterNotLinkBlock(self, direction="next", pos=None): | |
"kb:control+alt+rightArrow": "nextColumn", | ||
"kb:control+alt+leftArrow": "previousColumn", | ||
} | ||
|
||
class HiddenCellFound(LookupError): | ||
""" Raised when a table navigation method locates a cell but it is hidden, allowing the caller to possibly skip over it.""" | ||
pass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't need pass here, since the docstring counts as a statement. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be good to have a comment here explaining that although we default table-row/columncount to physical, this might be overridden by ARIA attributes later in fillVBuf.