$30 off During Our Annual Pro Sale. View Details »

What even is a table? A quick look at Accessibi...

Edd S
September 12, 2015

What even is a table? A quick look at Accessibility APIs

Lets look at the tools that you have available to you today to ensure that you are doing the best job to make your site as accessible as possible. A quick dive into accessibility apis and trying to answer the question, what even is a table?

Edd S

September 12, 2015
Tweet

More Decks by Edd S

Other Decks in Technology

Transcript

  1. Accessibility and how to get the most from your screenreader

    ! What even is a table? A quick look at Accessibility APIs GDS @edds
  2. dimensions = ga:browser,ga:hour,ga:dayOfWeek metrics = ga:users filters = ga:browser==Internet Explorer

    Which would get you something like: (view with your own data in the Query Explorer) Then using the TSV export button in the Query Explorer, found at the bottom of the page, I can import the results into a Google Sheets and produce a quick graph of the data. For another example if we had a page which used a query string to let users filter by a date field. You could get back all the different dates people filtered by: Browser Hour Day of Week Users Internet Explorer 00 0 5895 Internet Explorer 00 1 6814 Internet Explorer 00 2 8115 Internet Explorer 00 3 8000 Internet Explorer 00 4 8077 … … … … GDS @edds
  3. Accessibility APIs! ! Windows 7: MSAA/IAccessible OSX: NSAccessibility iOS: UI

    Accessibility Android: Accessibility Framework GDS @edds
  4. GDS @edds HTML to Platform Accessibility APIs Implementation Guide W3C

    Working Draft 01 October 2013 This version: http://www.w3.org/TR/2013/WD-html-aapi-20131001/ Latest published version: http://www.w3.org/TR/html-aapi/ Latest editor's draft: http://rawgithub.com/w3c/html-api-map/master/index.html Previous version: http://www.w3.org/TR/2012/WD-html-aapi-20130901/ Editors: Steve Faulkner, The Paciello Group, [email protected] Cynthia Shelly, Microsoft, [email protected] Jason Kiss, New Zealand Government, [email protected] Alexander Surkov, Mozilla Foundation, [email protected] Copyright © 2011-2013 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C liability, trademark and document use rules apply. Select text and file a bug
  5. GDS @edds svg table table HTML4 Yes HTML5 Yes WAI-ARIA

    none MSAA + UIA Express Role: ROLE_SYSTEM_TABLE Use MSAA or UIA guidance MSAA + IAccessible2 Role: ROLE_SYSTEM_TABLE Relations: IA2_RELATION_LABELLED_BY by child caption if any Interface: IAccessibleTable2 UIA Control Type and Other Features Control Type: Data Grid Control Pattern: Table AT-SPI Role: ROLE_TABLE Relations: RELATION_LABELLED_BY by child caption if any Interface: Table AX AXRole: AXTable AXSubrole: (nil) AXRoleDescription: table tbody td
  6. Browsers use the DOM and CSS to generate an accessibility

    tree. This is then passed onto accessibility APIs GDS @edds
  7. table { display: block; } ! <table> <tr> <th>…</th><td>…</td> </tr>

    <tr> <th>…</th><td>…</td> </tr> </table> GDS @edds
  8. GDS @edds table { display: block; } ! <table> <tr>

    <th>…</th><td>…</td> </tr> <tr> <th>…</th><td>…</td> </tr> </table>
  9. td { border-bottom: 1px solid; } ! <table> <tr> <td>…</td><td>…</td>

    </tr> <tr> <td>…</td><td>…</td> </tr> </table> GDS @edds
  10. GDS @edds td { border-bottom: 1px solid; } ! <table>

    <tr> <td>…</td><td>…</td> </tr> <tr> <td>…</td><td>…</td> </tr> </table>
  11. td { background: grey; } ! <table> <tr> <td>…</td><td>…</td> </tr>

    <tr> <td>…</td><td>…</td> </tr> </table> GDS @edds
  12. GDS @edds td { background: grey; } ! <table> <tr>

    <td>…</td><td>…</td> </tr> <tr> <td>…</td><td>…</td> </tr> </table>
  13. table { border-collapse: collapse; } td { background: grey; }

    ! <table> <tr> <td>…</td><td>…</td> </tr> <tr> <td>…</td><td>…</td> </tr> </table> GDS @edds
  14. GDS @edds table { border-collapse: collapse; } td { background:

    grey; } ! <table> <tr> <td>…</td><td>…</td> </tr> <tr> <td>…</td><td>…</td> </tr> </table>
  15. GDS @edds 102. bool AXTable::isDataTable() const 103. { 104. if

    (!m_layoutObject || !node()) 105. return false; 106. 107. // Do not consider it a data table if it has an ARIA role. 108. if (hasARIARole()) 109. return false; 110. 111. // When a section of the document is contentEditable, all tables should be 112. // treated as data tables, otherwise users may not be able to work with rich 113. // text editors that allow creating and editing tables. 114. if (node() && node()->hasEditableStyle()) 115. return true; 116. 117. // This employs a heuristic to determine if this table should appear. 118. // Only "data" tables should be exposed as tables. 119. // Unfortunately, there is no good way to determine the difference 120. // between a "layout" table and a "data" table. 121. 122. LayoutTable* table = toLayoutTable(m_layoutObject); 123. Node* tableNode = table->node(); 124. if (!isHTMLTableElement(tableNode)) 125. return false; 126. 127. // Do not consider it a data table if any of its descendants have an ARIA role. 128. HTMLTableElement* tableElement = toHTMLTableElement(tableNode); 129. if (elementHasAriaRole(tableElement->tHead())) 130. return false; 131. if (elementHasAriaRole(tableElement->tFoot())) 132. return false; 133. 134. RefPtrWillBeRawPtr<HTMLCollection> bodies = tableElement->tBodies(); 135. for (unsigned bodyIndex = 0; bodyIndex < bodies->length(); ++bodyIndex) { 136. Element* bodyElement = bodies->item(bodyIndex);
  16. GDS @edds 102. bool AXTable::isDataTable() const 103. { 104. if

    (!m_layoutObject || !node()) 105. return false; 106. 107. // Do not consider it a data table if it has an ARIA role. 108. if (hasARIARole()) 109. return false; 110. 111. // When a section of the document is contentEditable, all tables should be 112. // treated as data tables, otherwise users may not be able to work with rich 113. // text editors that allow creating and editing tables. 114. if (node() && node()->hasEditableStyle()) 115. return true; 116. 117. // This employs a heuristic to determine if this table should appear. 118. // Only "data" tables should be exposed as tables. 119. // Unfortunately, there is no good way to determine the difference 120. // between a "layout" table and a "data" table. 121. 122. LayoutTable* table = toLayoutTable(m_layoutObject); 123. Node* tableNode = table->node(); 124. if (!isHTMLTableElement(tableNode)) 125. return false; 126. 127. // Do not consider it a data table if any of its descendants have an ARIA role. 128. HTMLTableElement* tableElement = toHTMLTableElement(tableNode); 129. if (elementHasAriaRole(tableElement->tHead())) 130. return false; 131. if (elementHasAriaRole(tableElement->tFoot())) 132. return false; 133. 134. RefPtrWillBeRawPtr<HTMLCollection> bodies = tableElement->tBodies(); 135. for (unsigned bodyIndex = 0; bodyIndex < bodies->length(); ++bodyIndex) { 136. Element* bodyElement = bodies->item(bodyIndex); 102. bool AXTable::isDataTable() const 103. { 104. if (!m_layoutObject || !node()) 105. return false; 106. 107. // Do not consider it a data table if it has an ARIA role. 108. if (hasARIARole()) 109. return false; 110. 111. // When a section of the document is contentEditable, all tables should be 112. // treated as data tables, otherwise users may not be able to work with rich 113. // text editors that allow creating and editing tables. 114. if (node() && node()->hasEditableStyle()) 115. return true; 116. 117. // This employs a heuristic to determine if this table should appear. 118. // Only "data" tables should be exposed as tables. 119. // Unfortunately, there is no good way to determine the difference 120. // between a "layout" table and a "data" table. 121. 122. LayoutTable* table = toLayoutTable(m_layoutObject); 123. Node* tableNode = table->node(); 124. if (!isHTMLTableElement(tableNode)) 125. return false; 126. 127. // Do not consider it a data table if any of its descendants have an ARIA role. 128. HTMLTableElement* tableElement = toHTMLTableElement(tableNode); 129. if (elementHasAriaRole(tableElement->tHead())) 130. return false; 131. if (elementHasAriaRole(tableElement->tFoot())) 132. return false; 133. 134. RefPtrWillBeRawPtr<HTMLCollection> bodies = tableElement->tBodies(); 135. for (unsigned bodyIndex = 0; bodyIndex < bodies->length(); ++bodyIndex) { 136. Element* bodyElement = bodies->item(bodyIndex);
  17. GDS @edds 167. // cells have borders, or use attributes

    like headers, abbr, scope or axis 168. table->recalcSectionsIfNeeded(); 169. LayoutTableSection* firstBody = table->firstBody(); 170. if (!firstBody) 171. return false; 172. 173. int numCols = firstBody->numColumns(); 174. int numRows = firstBody->numRows(); 175. 176. // If there's only one cell, it's not a good AXTable candidate. 177. if (numRows == 1 && numCols == 1) 178. return false; 179. 180. // If there are at least 20 rows, we'll call it a data table. 181. if (numRows >= 20) 182. return true; 183. 184. // Store the background color of the table to check against cell's background colors. 185. const ComputedStyle* tableStyle = table->style(); 186. if (!tableStyle) 187. return false; 188. Color tableBGColor = tableStyle->visitedDependentColor(CSSPropertyBackgroundColor); 189. 190. // check enough of the cells to find if the table matches our criteria 191. // Criteria: 192. // 1) must have at least one valid cell (and) 193. // 2) at least half of cells have borders (or) 194. // 3) at least half of cells have different bg colors than the table, and there is cell spacing 195. unsigned validCellCount = 0; 196. unsigned borderedCellCount = 0; 197. unsigned backgroundDifferenceCellCount = 0; 198. unsigned cellsWithTopBorder = 0; 199. unsigned cellsWithBottomBorder = 0; 200. unsigned cellsWithLeftBorder = 0; 201. unsigned cellsWithRightBorder = 0; 167. // cells have borders, or use attributes like headers, abbr, scope or axis 168. table->recalcSectionsIfNeeded(); 169. LayoutTableSection* firstBody = table->firstBody(); 170. if (!firstBody) 171. return false; 172. 173. int numCols = firstBody->numColumns(); 174. int numRows = firstBody->numRows(); 175. 176. // If there's only one cell, it's not a good AXTable candidate. 177. if (numRows == 1 && numCols == 1) 178. return false; 179. 180. // If there are at least 20 rows, we'll call it a data table. 181. if (numRows >= 20) 182. return true; 183. 184. // Store the background color of the table to check against cell's background colors. 185. const ComputedStyle* tableStyle = table->style(); 186. if (!tableStyle) 187. return false; 188. Color tableBGColor = tableStyle->visitedDependentColor(CSSPropertyBackgroundColor); 189. 190. // check enough of the cells to find if the table matches our criteria 191. // Criteria: 192. // 1) must have at least one valid cell (and) 193. // 2) at least half of cells have borders (or) 194. // 3) at least half of cells have different bg colors than the table, and there is cell spacing 195. unsigned validCellCount = 0; 196. unsigned borderedCellCount = 0; 197. unsigned backgroundDifferenceCellCount = 0; 198. unsigned cellsWithTopBorder = 0; 199. unsigned cellsWithBottomBorder = 0; 200. unsigned cellsWithLeftBorder = 0; 201. unsigned cellsWithRightBorder = 0;
  18. GDS @edds 294. return true; 295. 296. // if there

    is less than two valid cells, it's not a data table 297. if (validCellCount <= 1) 298. return false; 299. 300. // half of the cells had borders, it's a data table 301. unsigned neededCellCount = validCellCount / 2; 302. if (borderedCellCount >= neededCellCount 303. || cellsWithTopBorder >= neededCellCount 304. || cellsWithBottomBorder >= neededCellCount 305. || cellsWithLeftBorder >= neededCellCount 306. || cellsWithRightBorder >= neededCellCount) 307. return true; 308. 309. // half had different background colors, it's a data table 310. if (backgroundDifferenceCellCount >= neededCellCount) 311. return true; 312. 313. // Check if there is an alternating row background color indicating a zebra striped style pattern. 314. if (alternatingRowColorCount > 2) { 315. Color firstColor = alternatingRowColors[0]; 316. for (int k = 1; k < alternatingRowColorCount; k++) { 317. // If an odd row was the same color as the first row, its not alternating. 318. if (k % 2 == 1 && alternatingRowColors[k] == firstColor) 319. return false; 320. // If an even row is not the same as the first row, its not alternating. 321. if (!(k % 2) && alternatingRowColors[k] != firstColor) 322. return false; 323. } 324. return true; 325. } 326. 327. return false; 328. } 294. return true; 295. 296. // if there is less than two valid cells, it's not a data table 297. if (validCellCount <= 1) 298. return false; 299. 300. // half of the cells had borders, it's a data table 301. unsigned neededCellCount = validCellCount / 2; 302. if (borderedCellCount >= neededCellCount 303. || cellsWithTopBorder >= neededCellCount 304. || cellsWithBottomBorder >= neededCellCount 305. || cellsWithLeftBorder >= neededCellCount 306. || cellsWithRightBorder >= neededCellCount) 307. return true; 308. 309. // half had different background colors, it's a data table 310. if (backgroundDifferenceCellCount >= neededCellCount) 311. return true; 312. 313. // Check if there is an alternating row background color indicating a zebra striped style pattern. 314. if (alternatingRowColorCount > 2) { 315. Color firstColor = alternatingRowColors[0]; 316. for (int k = 1; k < alternatingRowColorCount; k++) { 317. // If an odd row was the same color as the first row, its not alternating. 318. if (k % 2 == 1 && alternatingRowColors[k] == firstColor) 319. return false; 320. // If an even row is not the same as the first row, its not alternating. 321. if (!(k % 2) && alternatingRowColors[k] != firstColor) 322. return false; 323. } 324. return true; 325. } 326. 327. return false; 328. }
  19. GDS @edds 922 // performance problems only. Note, currently 'aAllowEmpty'

    flag is used for 923 // caption element only. On another hand we create accessible object for 924 // the first entry of caption element (see 925 // HTMLTableAccessible::CacheChildren). 926 return !!elements->Item(1); 927 } 928 929 bool 930 HTMLTableAccessible::IsProbablyLayoutTable() 931 { 932 // Implement a heuristic to determine if table is most likely used for layout 933 // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells 934 // at the beginning or end of a row/col, and especially when they occur at the edge of a table? 935 // XXX expose this info via object attributes to AT-SPI 936 937 // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC 938 // This will allow release trunk builds to be used by testers to refine the algorithm 939 // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release 940 #ifdef SHOW_LAYOUT_HEURISTIC 941 #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \ 942 { \ 943 mLayoutHeuristic = isLayout ? \ 944 NS_LITERAL_STRING("layout table: " heuristic) : \ 945 NS_LITERAL_STRING("data table: " heuristic); \ 946 return isLayout; \ 947 } 948 #else 949 #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; } 950 #endif 951 952 DocAccessible* docAccessible = Document(); 953 if (docAccessible) { 954 uint64_t docState = docAccessible->State(); 955 if (docState & states::EDITABLE) { // Need to see all elements while document is being edited 956 RETURN_LAYOUT_ANSWER(false, "In editable document"); 957 } 958 } 959 960 // Check to see if an ARIA role overrides the role from native markup, 961 // but for which we still expose table semantics (treegrid, for example). 962 if (Role() != roles::TABLE) 963 RETURN_LAYOUT_ANSWER(false, "Has role attribute"); 964 965 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) { 966 // Role attribute is present, but overridden roles have already been dealt with. 967 // Only landmarks and other roles that don't override the role from native 968 // markup are left to deal with here. 969 RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
  20. GDS @edds 922 // performance problems only. Note, currently 'aAllowEmpty'

    flag is used for 923 // caption element only. On another hand we create accessible object for 924 // the first entry of caption element (see 925 // HTMLTableAccessible::CacheChildren). 926 return !!elements->Item(1); 927 } 928 929 bool 930 HTMLTableAccessible::IsProbablyLayoutTable() 931 { 932 // Implement a heuristic to determine if table is most likely used for layout 933 // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells 934 // at the beginning or end of a row/col, and especially when they occur at the edge of a table? 935 // XXX expose this info via object attributes to AT-SPI 936 937 // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC 938 // This will allow release trunk builds to be used by testers to refine the algorithm 939 // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release 940 #ifdef SHOW_LAYOUT_HEURISTIC 941 #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \ 942 { \ 943 mLayoutHeuristic = isLayout ? \ 944 NS_LITERAL_STRING("layout table: " heuristic) : \ 945 NS_LITERAL_STRING("data table: " heuristic); \ 946 return isLayout; \ 947 } 948 #else 949 #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; } 950 #endif 951 952 DocAccessible* docAccessible = Document(); 953 if (docAccessible) { 954 uint64_t docState = docAccessible->State(); 955 if (docState & states::EDITABLE) { // Need to see all elements while document is being edited 956 RETURN_LAYOUT_ANSWER(false, "In editable document"); 957 } 958 } 959 960 // Check to see if an ARIA role overrides the role from native markup, 961 // but for which we still expose table semantics (treegrid, for example). 962 if (Role() != roles::TABLE) 963 RETURN_LAYOUT_ANSWER(false, "Has role attribute"); 964 965 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) { 966 // Role attribute is present, but overridden roles have already been dealt with. 967 // Only landmarks and other roles that don't override the role from native 968 // markup are left to deal with here. 969 RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table"); 922 // performance problems only. Note, currently 'aAllowEmpty' flag is used for 923 // caption element only. On another hand we create accessible object for 924 // the first entry of caption element (see 925 // HTMLTableAccessible::CacheChildren). 926 return !!elements->Item(1); 927 } 928 929 bool 930 HTMLTableAccessible::IsProbablyLayoutTable() 931 { 932 // Implement a heuristic to determine if table is most likely used for layout 933 // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells 934 // at the beginning or end of a row/col, and especially when they occur at the edge of a table? 935 // XXX expose this info via object attributes to AT-SPI 936 937 // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC 938 // This will allow release trunk builds to be used by testers to refine the algorithm 939 // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release 940 #ifdef SHOW_LAYOUT_HEURISTIC 941 #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \ 942 { \ 943 mLayoutHeuristic = isLayout ? \ 944 NS_LITERAL_STRING("layout table: " heuristic) : \ 945 NS_LITERAL_STRING("data table: " heuristic); \ 946 return isLayout; \ 947 } 948 #else 949 #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; } 950 #endif 951 952 DocAccessible* docAccessible = Document(); 953 if (docAccessible) { 954 uint64_t docState = docAccessible->State(); 955 if (docState & states::EDITABLE) { // Need to see all elements while document is being edited 956 RETURN_LAYOUT_ANSWER(false, "In editable document"); 957 } 958 } 959 960 // Check to see if an ARIA role overrides the role from native markup, 961 // but for which we still expose table semantics (treegrid, for example). 962 if (Role() != roles::TABLE) 963 RETURN_LAYOUT_ANSWER(false, "Has role attribute"); 964 965 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) { 966 // Role attribute is present, but overridden roles have already been dealt with. 967 // Only landmarks and other roles that don't override the role from native 968 // markup are left to deal with here. 969 RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
  21. GDS @edds 1089 1090 if (childIdx > 0 && prevRowColor

    != rowColor) 1091 RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered"); 1092 } 1093 } 1094 1095 // Check for many rows 1096 const uint32_t kMaxLayoutRows = 20; 1097 if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data 1098 RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered"); 1099 } 1100 1101 // Check for very wide table. 1102 nsIFrame* documentFrame = Document()->GetFrame(); 1103 nsSize documentSize = documentFrame->GetSize(); 1104 if (documentSize.width > 0) { 1105 nsSize tableSize = GetFrame()->GetSize(); 1106 int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width; 1107 if (percentageOfDocWidth > 95) { 1108 // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width 1109 // Probably for layout 1110 RETURN_LAYOUT_ANSWER(true, 1111 "<= 4 columns, table width is 95% of document width"); 1112 } 1113 } 1114 1115 // Two column rules 1116 if (rowCount * colCount <= 10) { 1117 RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered"); 1118 } 1119 1120 if (HasDescendant(NS_LITERAL_STRING("embed")) || 1121 HasDescendant(NS_LITERAL_STRING("object")) || 1122 HasDescendant(NS_LITERAL_STRING("applet")) || 1123 HasDescendant(NS_LITERAL_STRING("iframe"))) { 1124 RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements"); 1125 } 1126 1127 RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data"); 1128 } 1129 1130 1131 //////////////////////////////////////////////////////////////////////////////// 1132 // HTMLCaptionAccessible 1133 //////////////////////////////////////////////////////////////////////////////// 1134 1135 Relation 1136 HTMLCaptionAccessible::RelationByType(RelationType aType) 1137 { 1089 1090 if (childIdx > 0 && prevRowColor != rowColor) 1091 RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered"); 1092 } 1093 } 1094 1095 // Check for many rows 1096 const uint32_t kMaxLayoutRows = 20; 1097 if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data 1098 RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered"); 1099 } 1100 1101 // Check for very wide table. 1102 nsIFrame* documentFrame = Document()->GetFrame(); 1103 nsSize documentSize = documentFrame->GetSize(); 1104 if (documentSize.width > 0) { 1105 nsSize tableSize = GetFrame()->GetSize(); 1106 int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width; 1107 if (percentageOfDocWidth > 95) { 1108 // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width 1109 // Probably for layout 1110 RETURN_LAYOUT_ANSWER(true, 1111 "<= 4 columns, table width is 95% of document width"); 1112 } 1113 } 1114 1115 // Two column rules 1116 if (rowCount * colCount <= 10) { 1117 RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered"); 1118 } 1119 1120 if (HasDescendant(NS_LITERAL_STRING("embed")) || 1121 HasDescendant(NS_LITERAL_STRING("object")) || 1122 HasDescendant(NS_LITERAL_STRING("applet")) || 1123 HasDescendant(NS_LITERAL_STRING("iframe"))) { 1124 RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements"); 1125 } 1126 1127 RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data"); 1128 } 1129 1130 1131 //////////////////////////////////////////////////////////////////////////////// 1132 // HTMLCaptionAccessible 1133 //////////////////////////////////////////////////////////////////////////////// 1134 1135 Relation 1136 HTMLCaptionAccessible::RelationByType(RelationType aType) 1137 {
  22. GDS @edds 1098 RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered"); 1099

    } 1100 1101 // Check for very wide table. 1102 nsIFrame* documentFrame = Document()->GetFrame(); 1103 nsSize documentSize = documentFrame->GetSize(); 1104 if (documentSize.width > 0) { 1105 nsSize tableSize = GetFrame()->GetSize(); 1106 int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width; 1107 if (percentageOfDocWidth > 95) { 1108 // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width 1109 // Probably for layout 1110 RETURN_LAYOUT_ANSWER(true, 1111 "<= 4 columns, table width is 95% of document width"); 1112 } 1113 } 1114 1115 // Two column rules 1116 if (rowCount * colCount <= 10) { 1117 RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered"); 1118 } 1119 1120 if (HasDescendant(NS_LITERAL_STRING("embed")) || 1121 HasDescendant(NS_LITERAL_STRING("object")) || 1122 HasDescendant(NS_LITERAL_STRING("applet")) || 1123 HasDescendant(NS_LITERAL_STRING("iframe"))) { 1124 RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements"); 1125 } 1126 1127 RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data"); 1128 } 1129 1130 1131 //////////////////////////////////////////////////////////////////////////////// 1132 // HTMLCaptionAccessible 1133 //////////////////////////////////////////////////////////////////////////////// 1134 1135 Relation 1136 HTMLCaptionAccessible::RelationByType(RelationType aType) 1137 { 1138 Relation rel = HyperTextAccessible::RelationByType(aType); 1139 if (aType == RelationType::LABEL_FOR) 1140 rel.AppendTarget(Parent()); 1141 1142 return rel; 1143 } 1144 1145 role 1146 HTMLCaptionAccessible::NativeRole() 1098 RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered"); 1099 } 1100 1101 // Check for very wide table. 1102 nsIFrame* documentFrame = Document()->GetFrame(); 1103 nsSize documentSize = documentFrame->GetSize(); 1104 if (documentSize.width > 0) { 1105 nsSize tableSize = GetFrame()->GetSize(); 1106 int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width; 1107 if (percentageOfDocWidth > 95) { 1108 // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width 1109 // Probably for layout 1110 RETURN_LAYOUT_ANSWER(true, 1111 "<= 4 columns, table width is 95% of document width"); 1112 } 1113 } 1114 1115 // Two column rules 1116 if (rowCount * colCount <= 10) { 1117 RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered"); 1118 } 1119 1120 if (HasDescendant(NS_LITERAL_STRING("embed")) || 1121 HasDescendant(NS_LITERAL_STRING("object")) || 1122 HasDescendant(NS_LITERAL_STRING("applet")) || 1123 HasDescendant(NS_LITERAL_STRING("iframe"))) { 1124 RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements"); 1125 } 1126 1127 RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data"); 1128 } 1129 1130 1131 //////////////////////////////////////////////////////////////////////////////// 1132 // HTMLCaptionAccessible 1133 //////////////////////////////////////////////////////////////////////////////// 1134 1135 Relation 1136 HTMLCaptionAccessible::RelationByType(RelationType aType) 1137 { 1138 Relation rel = HyperTextAccessible::RelationByType(aType); 1139 if (aType == RelationType::LABEL_FOR) 1140 rel.AppendTarget(Parent()); 1141 1142 return rel; 1143 } 1144 1145 role 1146 HTMLCaptionAccessible::NativeRole()
  23. Thank you!! ! ! Special thanks to: Alice Bartlet, Robin

    Whittleton, Tom Byers, Alex Muller, Léonie Watson, David Singleton, Gemma Leigh and Jake Archibald GDS @edds