nsresult nsARIAGridCellAccessible::GetARIAState(PRUint32 *aState, PRUint32 *aExtraState) { nsresult rv = nsHyperTextAccessibleWrap::GetARIAState(aState, aExtraState); NS_ENSURE_SUCCESS(rv, rv); // Return if the gridcell has aria-selected="true". if (*aState & nsIAccessibleStates::STATE_SELECTED) return NS_OK; // Check aria-selected="true" on the row. nsCOMPtr<nsIAccessible> row; GetParent(getter_AddRefs(row)); if (nsAccUtils::Role(row) != nsIAccessibleRole::ROLE_ROW) return NS_OK; nsRefPtr<nsAccessible> acc = nsAccUtils::QueryAccessible(row); nsCOMPtr<nsIDOMNode> rowNode; acc->GetDOMNode(getter_AddRefs(rowNode)); NS_ENSURE_STATE(rowNode); nsCOMPtr<nsIContent> rowContent(do_QueryInterface(rowNode)); if (nsAccUtils::HasDefinedARIAToken(rowContent, nsAccessibilityAtoms::aria_selected) && !rowContent->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::aria_selected, nsAccessibilityAtoms::_false, eCaseMatters)) { *aState |= nsIAccessibleStates::STATE_SELECTABLE | nsIAccessibleStates::STATE_SELECTED; } return NS_OK; }
NS_IMETHODIMP nsHTMLTableAccessible::IsProbablyForLayout(PRBool *aIsProbablyForLayout) { // Implement a heuristic to determine if table is most likely used for layout // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells // at the beginning or end of a row/col, and especially when they occur at the edge of a table? // XXX expose this info via object attributes to AT-SPI // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC // This will allow release trunk builds to be used by testers to refine the algorithm // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release #ifdef SHOW_LAYOUT_HEURISTIC #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \ { *aIsProbablyForLayout = isLayout; \ mLayoutHeuristic = isLayout ? NS_LITERAL_STRING("layout table: ") : NS_LITERAL_STRING("data table: "); \ mLayoutHeuristic += NS_LITERAL_STRING(heuristic); return NS_OK; } #else #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { *aIsProbablyForLayout = isLayout; return NS_OK; } #endif *aIsProbablyForLayout = PR_FALSE; if (IsDefunct()) return NS_ERROR_FAILURE; nsDocAccessible *docAccessible = GetDocAccessible(); if (docAccessible) { PRUint32 state, extState; docAccessible->GetState(&state, &extState); if (extState & nsIAccessibleStates::EXT_STATE_EDITABLE) { // Need to see all elements while document is being edited RETURN_LAYOUT_ANSWER(PR_FALSE, "In editable document"); } } // Check to see if an ARIA role overrides the role from native markup, // but for which we still expose table semantics (treegrid, for example). PRBool hasNonTableRole = (nsAccUtils::Role(this) != nsIAccessibleRole::ROLE_TABLE); if (hasNonTableRole) { RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute"); } if (mContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) { // Role attribute is present, but overridden roles have already been dealt with. // Only landmarks and other roles that don't override the role from native // markup are left to deal with here. RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute, weak role, and role is table"); } // Check for legitimate data table elements or attributes nsAutoString summary; if ((mContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::summary, summary) && !summary.IsEmpty()) || HasDescendant(NS_LITERAL_STRING("caption"), PR_FALSE) || HasDescendant(NS_LITERAL_STRING("th")) || HasDescendant(NS_LITERAL_STRING("thead")) || HasDescendant(NS_LITERAL_STRING("tfoot")) || HasDescendant(NS_LITERAL_STRING("colgroup"))) { RETURN_LAYOUT_ANSWER(PR_FALSE, "Has caption, summary, th, thead, tfoot or colgroup -- legitimate table structures"); } if (HasDescendant(NS_LITERAL_STRING("table"))) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has a nested table within it"); } // If only 1 column or only 1 row, it's for layout PRInt32 columns, rows; GetColumnCount(&columns); if (columns <=1) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 column"); } GetRowCount(&rows); if (rows <=1) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 row"); } // Check for many columns if (columns >= 5) { RETURN_LAYOUT_ANSWER(PR_FALSE, ">=5 columns"); } // Now we know there are 2-4 columns and 2 or more rows // Check to see if there are visible borders on the cells // XXX currently, we just check the first cell -- do we really need to do more? nsCOMPtr<nsIDOMElement> cellElement; nsresult rv = GetCellAt(0, 0, *getter_AddRefs(cellElement)); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); nsCOMPtr<nsIContent> cellContent(do_QueryInterface(cellElement)); NS_ENSURE_TRUE(cellContent, NS_ERROR_FAILURE); nsIFrame *cellFrame = cellContent->GetPrimaryFrame(); if (!cellFrame) { return NS_OK; } nsMargin border; cellFrame->GetBorder(border); if (border.top && border.bottom && border.left && border.right) { RETURN_LAYOUT_ANSWER(PR_FALSE, "Has nonzero border-width on table cell"); } /** * Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward */ // Check for styled background color across the row // Alternating background color is a common way nsCOMPtr<nsIDOMNodeList> nodeList; nsCOMPtr<nsIDOMElement> tableElt(do_QueryInterface(mContent)); tableElt->GetElementsByTagName(NS_LITERAL_STRING("tr"), getter_AddRefs(nodeList)); NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE); PRUint32 length; nodeList->GetLength(&length); nsAutoString color, lastRowColor; for (PRUint32 rowCount = 0; rowCount < length; rowCount ++) { nsCOMPtr<nsIDOMNode> rowNode; nodeList->Item(rowCount, getter_AddRefs(rowNode)); nsCOMPtr<nsIContent> rowContent(do_QueryInterface(rowNode)); nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl = nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), rowContent); NS_ENSURE_TRUE(styleDecl, NS_ERROR_FAILURE); lastRowColor = color; styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"), color); if (rowCount > 0 && PR_FALSE == lastRowColor.Equals(color)) { RETURN_LAYOUT_ANSWER(PR_FALSE, "2 styles of row background color, non-bordered"); } } // Check for many rows const PRInt32 kMaxLayoutRows = 20; if (rows > kMaxLayoutRows) { // A ton of rows, this is probably for data RETURN_LAYOUT_ANSWER(PR_FALSE, ">= kMaxLayoutRows (20) and non-bordered"); } // Check for very wide table nsAutoString styledWidth; GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("width"), styledWidth); if (styledWidth.EqualsLiteral("100%")) { RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns and 100% width"); } if (styledWidth.Find(NS_LITERAL_STRING("px"))) { // Hardcoded in pixels nsIFrame *tableFrame = GetFrame(); NS_ENSURE_TRUE(tableFrame , NS_ERROR_FAILURE); nsSize tableSize = tableFrame->GetSize(); nsDocAccessible *docAccessible = GetDocAccessible(); NS_ENSURE_TRUE(docAccessible, NS_ERROR_FAILURE); nsIFrame *docFrame = docAccessible->GetFrame(); NS_ENSURE_TRUE(docFrame , NS_ERROR_FAILURE); nsSize docSize = docFrame->GetSize(); if (docSize.width > 0) { PRInt32 percentageOfDocWidth = (100 * tableSize.width) / docSize.width; if (percentageOfDocWidth > 95) { // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width // Probably for layout RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width"); } } } // Two column rules if (rows * columns <= 10) { RETURN_LAYOUT_ANSWER(PR_TRUE, "2-4 columns, 10 cells or less, non-bordered"); } if (HasDescendant(NS_LITERAL_STRING("embed")) || HasDescendant(NS_LITERAL_STRING("object")) || HasDescendant(NS_LITERAL_STRING("applet")) || HasDescendant(NS_LITERAL_STRING("iframe"))) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements"); } RETURN_LAYOUT_ANSWER(PR_FALSE, "no layout factor strong enough, so will guess data"); }