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

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

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. Edd Sowden

    Senior Developer 

    Government Digital Service

    @edds

    View Slide

  2. Accessibility and how to get the
    most from your screenreader
    !
    What even is a table? A quick look
    at Accessibility APIs
    GDS
    @edds

    View Slide

  3. *
    I’m from the
    Government
    GDS
    @edds

    View Slide

  4. We’re a team at the heart of
    government building digital
    public services
    GDS
    @edds

    View Slide

  5. *
    We started
    by building
    GOV.UK
    GDS
    @edds

    View Slide

  6. *
    The best
    place to find
    government
    services and
    information
    GDS
    @edds

    View Slide

  7. GDS
    @edds

    View Slide

  8. GDS
    @edds

    View Slide

  9. GDS
    @edds

    View Slide

  10. GDS
    @edds

    View Slide

  11. GDS
    @edds

    View Slide

  12. GOV.UK should work for
    everyone
    GDS
    @edds

    View Slide

  13. I wrote a blog
    post

    View Slide

  14. 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

    View Slide

  15. GDS
    @edds

    View Slide

  16. table {
    display: block;
    overflow-x: scroll;
    }
    GDS
    @edds

    View Slide

  17. GDS
    @edds

    View Slide

  18. What does this do to
    accessibility software?
    GDS
    @edds

    View Slide

  19. Listen to your
    websites

    View Slide

  20. How many of you use
    Apple products regularly?
    GDS
    @edds

    View Slide

  21. GDS
    @edds
    How many of you test your
    websites in a screenreader?

    View Slide

  22. Voiceover comes with
    OS X and iOS
    GDS
    @edds

    View Slide

  23. The Voiceover Training is really good
    GDS
    @edds

    View Slide

  24. Let’s listen to it before I
    made the change
    GDS
    @edds

    View Slide

  25. GDS
    @edds

    View Slide

  26. And once I had added the
    extra CSS…
    GDS
    @edds

    View Slide

  27. GDS
    @edds

    View Slide

  28. The CSS display property
    affects how accessibility
    tech interprets the element
    GDS
    @edds

    View Slide




  29. GDS
    @edds

    View Slide

  30. I had lunch

    View Slide

  31. “Can’t you just set an aria
    role of table?”
    @jaffathecake
    GDS
    @edds

    View Slide


  32. GDS
    @edds

    View Slide


  33. Cell

    GDS
    @edds
    Minimum viable table:

    View Slide

  34. GDS
    @edds

    View Slide

  35. GDS
    @edds

    View Slide

  36. GDS
    @edds
    chrome://flags/#enable-devtools-experiments

    View Slide

  37. GDS
    @edds

    View Slide

  38. GDS
    @edds

    View Slide

  39. GDS
    @edds

    View Slide

  40. GDS
    @edds

    View Slide

  41. GDS
    @edds

    View Slide

  42. So our minimum viable
    table isn’t a table?
    GDS
    @edds

    View Slide

  43. Let’s have a quick recap
    on Accessibility APIs
    GDS
    @edds

    View Slide

  44. GDS
    @edds

    View Slide

  45. GDS
    @edds

    View Slide

  46. Accessibility APIs!
    !
    Windows 7: MSAA/IAccessible
    OSX: NSAccessibility
    iOS: UI Accessibility
    Android: Accessibility Framework
    GDS
    @edds

    View Slide

  47. role
    name
    state
    children
    GDS
    @edds

    View Slide

  48. 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

    View Slide

  49. 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

    View Slide

  50. Browsers use the DOM and CSS
    to generate an accessibility tree.
    This is then passed onto
    accessibility APIs
    GDS
    @edds

    View Slide

  51. So what does it look like for
    a “real” table?
    GDS
    @edds

    View Slide

  52. GDS
    @edds

    View Slide

  53. What do other browsers
    think of our minimum
    viable table?
    GDS
    @edds

    View Slide

  54. GDS
    @edds

    View Slide

  55. GDS
    @edds

    View Slide

  56. GDS
    @edds

    View Slide

  57. GDS
    @edds

    View Slide

  58. GDS
    @edds

    View Slide

  59. GDS
    @edds

    View Slide

  60. GDS
    @edds

    View Slide

  61. GDS
    @edds

    View Slide

  62. JAWS
    GDS
    @edds

    View Slide

  63. JAWS advances to the
    next table with the ’t’
    shortcut
    GDS
    @edds

    View Slide

  64. GDS
    @edds

    View Slide

  65. GDS
    @edds

    View Slide

  66. GDS
    @edds

    Cell

    View Slide

  67. Browsers have heuristics
    to protect us from table
    based layouts
    GDS
    @edds

    View Slide



  68. ……


    ……


    GDS
    @edds

    View Slide

  69. GDS
    @edds


    ……


    ……


    View Slide



  70. ……


    ……

    [ … 18 more rows … ]

    GDS
    @edds

    View Slide

  71. GDS
    @edds


    ……


    ……

    [ … 18 more rows … ]

    View Slide


  72. Green

    GDS
    @edds

    View Slide

  73. GDS
    @edds

    Green

    View Slide



  74. ……


    ……


    GDS
    @edds

    View Slide

  75. GDS
    @edds


    ……


    ……


    View Slide

  76. table { display: block; }
    !


    ……


    ……


    GDS
    @edds

    View Slide

  77. GDS
    @edds
    table { display: block; }
    !


    ……


    ……


    View Slide

  78. td { border-bottom: 1px solid; }
    !


    ……


    ……


    GDS
    @edds

    View Slide

  79. GDS
    @edds
    td { border-bottom: 1px solid; }
    !


    ……


    ……


    View Slide

  80. td { background: grey; }
    !


    ……


    ……


    GDS
    @edds

    View Slide

  81. GDS
    @edds
    td { background: grey; }
    !


    ……


    ……


    View Slide

  82. table { border-collapse: collapse; }
    td { background: grey; }
    !


    ……


    ……


    GDS
    @edds

    View Slide

  83. GDS
    @edds
    table { border-collapse: collapse; }
    td { background: grey; }
    !


    ……


    ……


    View Slide

  84. Let’s have a quick look
    under the hood in Chrome
    GDS
    @edds

    View Slide

  85. 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 bodies = tableElement->tBodies();
    135. for (unsigned bodyIndex = 0; bodyIndex < bodies->length(); ++bodyIndex) {
    136. Element* bodyElement = bodies->item(bodyIndex);

    View Slide

  86. 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 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 bodies = tableElement->tBodies();
    135. for (unsigned bodyIndex = 0; bodyIndex < bodies->length(); ++bodyIndex) {
    136. Element* bodyElement = bodies->item(bodyIndex);

    View Slide

  87. 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;

    View Slide

  88. 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. }

    View Slide

  89. What about the massive
    fox in the room?
    GDS
    @edds

    View Slide

  90. GDS
    @edds

    View Slide

  91. Firefox seems to be
    different depending on
    which screen reader
    you’re using
    GDS
    @edds

    View Slide

  92. 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");

    View Slide

  93. 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");

    View Slide

  94. 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 {

    View Slide

  95. 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()

    View Slide

  96. So what does this all
    mean?
    GDS
    @edds

    View Slide

  97. Accessibility
    is more than
    just markup

    View Slide

  98. Listen to your
    websites

    View Slide




  99. GDS
    @edds

    View Slide

  100. 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

    View Slide

  101. Edd Sowden

    Senior Developer 

    Government Digital Service

    @edds

    View Slide