HTMLMarkupMap.h (15153B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:expandtab:shiftwidth=2:tabstop=2: 3 */ 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 MARKUPMAP( 9 a, 10 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 11 // An anchor element without an href attribute and without a click 12 // listener should be a generic. 13 if (!aElement->HasAttr(nsGkAtoms::href) && 14 !nsCoreUtils::HasClickListener(aElement)) { 15 return new HyperTextAccessible(aElement, aContext->Document()); 16 } 17 // Only some roles truly enjoy life as HTMLLinkAccessibles, for 18 // details see closed bug 494807. 19 const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement); 20 if (roleMapEntry && roleMapEntry->role != roles::NOTHING && 21 roleMapEntry->role != roles::LINK) { 22 return new HyperTextAccessible(aElement, aContext->Document()); 23 } 24 25 return new HTMLLinkAccessible(aElement, aContext->Document()); 26 }, 27 0) 28 29 MARKUPMAP( 30 abbr, 31 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 32 return new HTMLAbbreviationAccessible(aElement, aContext->Document()); 33 }, 34 0) 35 36 MARKUPMAP( 37 acronym, 38 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 39 return new HTMLAbbreviationAccessible(aElement, aContext->Document()); 40 }, 41 0) 42 43 MARKUPMAP(address, New_HyperText, roles::GROUPING) 44 45 MARKUPMAP(article, New_HyperText, roles::ARTICLE, Attr(xmlroles, article)) 46 47 MARKUPMAP( 48 aside, 49 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 50 return new HTMLAsideAccessible(aElement, aContext->Document()); 51 }, 52 0) 53 54 MARKUPMAP(blockquote, New_HyperText, roles::BLOCKQUOTE) 55 56 MARKUPMAP( 57 button, 58 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 59 return new HTMLButtonAccessible(aElement, aContext->Document()); 60 }, 61 0) 62 63 MARKUPMAP( 64 caption, 65 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 66 if (aContext->IsTable()) { 67 dom::HTMLTableElement* tableEl = 68 dom::HTMLTableElement::FromNode(aContext->GetContent()); 69 if (tableEl && tableEl == aElement->GetParent() && 70 tableEl->GetCaption() == aElement) { 71 return new HTMLCaptionAccessible(aElement, aContext->Document()); 72 } 73 } 74 return nullptr; 75 }, 76 0) 77 78 MARKUPMAP(code, New_HyperText, roles::CODE) 79 80 MARKUPMAP(dd, New_HTMLDtOrDd<HyperTextAccessible>, roles::DEFINITION) 81 82 MARKUPMAP(del, New_HyperText, roles::CONTENT_DELETION) 83 84 MARKUPMAP(details, New_HyperText, roles::DETAILS) 85 86 MARKUPMAP(dfn, New_HyperText, roles::TERM) 87 88 MARKUPMAP(dialog, New_HyperText, roles::DIALOG) 89 90 MARKUPMAP( 91 div, 92 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 93 // Never create an accessible if we're part of an anonymous 94 // subtree. 95 if (aElement->IsInNativeAnonymousSubtree()) { 96 return nullptr; 97 } 98 // Always create an accessible if the div has an id. 99 if (aElement->HasAttr(nsGkAtoms::id)) { 100 return new HyperTextAccessible(aElement, aContext->Document()); 101 } 102 // Never create an accessible if the div is not display:block; or 103 // display:inline-block or the like. 104 nsIFrame* f = aElement->GetPrimaryFrame(); 105 if (!f || !f->IsBlockFrameOrSubclass()) { 106 return nullptr; 107 } 108 // Check for various conditions to determine if this is a block 109 // break and needs to be rendered. 110 // If its previous sibling is an inline element, we probably want 111 // to break, so render. 112 // FIXME: This looks extremely incorrect in presence of shadow DOM, 113 // display: contents, and what not. 114 nsIContent* prevSibling = aElement->GetPreviousSibling(); 115 if (prevSibling) { 116 nsIFrame* prevSiblingFrame = prevSibling->GetPrimaryFrame(); 117 if (prevSiblingFrame && prevSiblingFrame->IsInlineOutside()) { 118 return new HyperTextAccessible(aElement, aContext->Document()); 119 } 120 } 121 // Now, check the children. 122 nsIContent* firstChild = aElement->GetFirstChild(); 123 if (firstChild) { 124 nsIFrame* firstChildFrame = firstChild->GetPrimaryFrame(); 125 if (!firstChildFrame) { 126 // The first child is invisible, but this might be due to an 127 // invisible text node. Try the next. 128 firstChild = firstChild->GetNextSibling(); 129 if (!firstChild) { 130 // If there's no next sibling, there's only one child, so there's 131 // nothing more we can do. 132 return nullptr; 133 } 134 firstChildFrame = firstChild->GetPrimaryFrame(); 135 } 136 // Check to see if first child has an inline frame. 137 if (firstChildFrame && firstChildFrame->IsInlineOutside()) { 138 return new HyperTextAccessible(aElement, aContext->Document()); 139 } 140 nsIContent* lastChild = aElement->GetLastChild(); 141 MOZ_ASSERT(lastChild); 142 if (lastChild != firstChild) { 143 nsIFrame* lastChildFrame = lastChild->GetPrimaryFrame(); 144 if (!lastChildFrame) { 145 // The last child is invisible, but this might be due to an 146 // invisible text node. Try the next. 147 lastChild = lastChild->GetPreviousSibling(); 148 MOZ_ASSERT(lastChild); 149 if (lastChild == firstChild) { 150 return nullptr; 151 } 152 lastChildFrame = lastChild->GetPrimaryFrame(); 153 } 154 // Check to see if last child has an inline frame. 155 if (lastChildFrame && lastChildFrame->IsInlineOutside()) { 156 return new HyperTextAccessible(aElement, aContext->Document()); 157 } 158 } 159 } 160 return nullptr; 161 }, 162 roles::SECTION) 163 164 MARKUPMAP( 165 dl, 166 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 167 return new HTMLListAccessible(aElement, aContext->Document()); 168 }, 169 roles::DEFINITION_LIST) 170 171 MARKUPMAP(dt, New_HTMLDtOrDd<HTMLLIAccessible>, roles::TERM) 172 173 MARKUPMAP(em, New_HyperText, roles::EMPHASIS) 174 175 MARKUPMAP( 176 figcaption, 177 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 178 return new HTMLFigcaptionAccessible(aElement, aContext->Document()); 179 }, 180 roles::CAPTION) 181 182 MARKUPMAP( 183 figure, 184 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 185 return new HTMLFigureAccessible(aElement, aContext->Document()); 186 }, 187 roles::FIGURE, Attr(xmlroles, figure)) 188 189 MARKUPMAP( 190 fieldset, 191 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 192 return new HTMLGroupboxAccessible(aElement, aContext->Document()); 193 }, 194 0) 195 196 MARKUPMAP( 197 form, 198 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 199 return new HTMLFormAccessible(aElement, aContext->Document()); 200 }, 201 0) 202 203 MARKUPMAP( 204 footer, 205 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 206 return new HTMLHeaderOrFooterAccessible(aElement, aContext->Document()); 207 }, 208 0) 209 210 MARKUPMAP( 211 header, 212 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 213 return new HTMLHeaderOrFooterAccessible(aElement, aContext->Document()); 214 }, 215 0) 216 217 MARKUPMAP(h1, New_HyperText, roles::HEADING) 218 219 MARKUPMAP(h2, New_HyperText, roles::HEADING) 220 221 MARKUPMAP(h3, New_HyperText, roles::HEADING) 222 223 MARKUPMAP(h4, New_HyperText, roles::HEADING) 224 225 MARKUPMAP(h5, New_HyperText, roles::HEADING) 226 227 MARKUPMAP(h6, New_HyperText, roles::HEADING) 228 229 MARKUPMAP(hgroup, New_HyperText, roles::GROUPING) 230 231 MARKUPMAP( 232 hr, 233 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 234 return new HTMLHRAccessible(aElement, aContext->Document()); 235 }, 236 0) 237 238 MARKUPMAP( 239 input, 240 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 241 // TODO(emilio): This would be faster if it used 242 // HTMLInputElement's already-parsed representation. 243 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 244 nsGkAtoms::checkbox, eIgnoreCase)) { 245 return new CheckboxAccessible(aElement, aContext->Document()); 246 } 247 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 248 nsGkAtoms::image, eIgnoreCase)) { 249 return new HTMLButtonAccessible(aElement, aContext->Document()); 250 } 251 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 252 nsGkAtoms::radio, eIgnoreCase)) { 253 return new HTMLRadioButtonAccessible(aElement, aContext->Document()); 254 } 255 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 256 nsGkAtoms::time, eIgnoreCase)) { 257 return new HTMLDateTimeAccessible<roles::TIME_EDITOR>( 258 aElement, aContext->Document()); 259 } 260 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 261 nsGkAtoms::date, eIgnoreCase) || 262 aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 263 nsGkAtoms::datetime_local, eIgnoreCase)) { 264 return new HTMLDateTimeAccessible<roles::DATE_EDITOR>( 265 aElement, aContext->Document()); 266 } 267 return nullptr; 268 }, 269 0) 270 271 MARKUPMAP(ins, New_HyperText, roles::CONTENT_INSERTION) 272 273 MARKUPMAP( 274 label, 275 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 276 return new HTMLLabelAccessible(aElement, aContext->Document()); 277 }, 278 roles::LABEL) 279 280 MARKUPMAP( 281 legend, 282 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 283 return new HTMLLegendAccessible(aElement, aContext->Document()); 284 }, 285 roles::LABEL) 286 287 MARKUPMAP( 288 li, 289 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 290 // If list item is a child of accessible list then create an 291 // accessible for it unconditionally by tag name. nsBlockFrame 292 // creates the list item accessible for other elements styled as 293 // list items. 294 if (aContext->IsList() && 295 aContext->GetContent() == aElement->GetParent()) { 296 return new HTMLLIAccessible(aElement, aContext->Document()); 297 } 298 299 return nullptr; 300 }, 301 0) 302 303 MARKUPMAP(main, New_HyperText, roles::LANDMARK) 304 305 MARKUPMAP(map, nullptr, roles::TEXT_CONTAINER) 306 307 MARKUPMAP(mark, New_HyperText, roles::MARK, Attr(xmlroles, mark)) 308 309 MARKUPMAP( 310 menu, 311 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 312 return new HTMLListAccessible(aElement, aContext->Document()); 313 }, 314 roles::LIST) 315 316 MARKUPMAP(nav, New_HyperText, roles::LANDMARK) 317 318 MARKUPMAP( 319 ol, 320 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 321 return new HTMLListAccessible(aElement, aContext->Document()); 322 }, 323 roles::LIST) 324 325 MARKUPMAP( 326 option, 327 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 328 return new HTMLSelectOptionAccessible(aElement, aContext->Document()); 329 }, 330 0) 331 332 MARKUPMAP( 333 optgroup, 334 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 335 return new HTMLSelectOptGroupAccessible(aElement, aContext->Document()); 336 }, 337 0) 338 339 MARKUPMAP( 340 output, 341 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 342 return new HTMLOutputAccessible(aElement, aContext->Document()); 343 }, 344 roles::STATUSBAR, Attr(aria_live, polite)) 345 346 MARKUPMAP(p, nullptr, roles::PARAGRAPH) 347 348 MARKUPMAP( 349 progress, 350 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 351 return new HTMLProgressAccessible(aElement, aContext->Document()); 352 }, 353 0) 354 355 MARKUPMAP(q, New_HyperText, 0) 356 357 MARKUPMAP(s, New_HyperText, roles::CONTENT_DELETION) 358 359 MARKUPMAP( 360 section, 361 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 362 return new HTMLSectionAccessible(aElement, aContext->Document()); 363 }, 364 0) 365 366 MARKUPMAP(strong, New_HyperText, roles::STRONG) 367 368 MARKUPMAP(sub, New_HyperText, roles::SUBSCRIPT) 369 370 MARKUPMAP( 371 summary, 372 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 373 return new HTMLSummaryAccessible(aElement, aContext->Document()); 374 }, 375 roles::SUMMARY) 376 377 MARKUPMAP(sup, New_HyperText, roles::SUPERSCRIPT) 378 379 MARKUPMAP( 380 table, 381 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 382 return new HTMLTableAccessible(aElement, aContext->Document()); 383 }, 384 roles::TABLE) 385 386 MARKUPMAP(time, New_HyperText, roles::TIME, Attr(xmlroles, time), 387 AttrFromDOM(datetime, datetime)) 388 389 MARKUPMAP(tbody, nullptr, roles::ROWGROUP) 390 391 MARKUPMAP( 392 td, 393 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 394 if (!aContext->IsHTMLTableRow()) { 395 return nullptr; 396 } 397 if (aElement->HasAttr(nsGkAtoms::scope)) { 398 return new HTMLTableHeaderCellAccessible(aElement, 399 aContext->Document()); 400 } 401 return new HTMLTableCellAccessible(aElement, aContext->Document()); 402 }, 403 0) 404 405 MARKUPMAP(tfoot, nullptr, roles::ROWGROUP) 406 407 MARKUPMAP( 408 th, 409 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 410 if (!aContext->IsHTMLTableRow()) { 411 return nullptr; 412 } 413 return new HTMLTableHeaderCellAccessible(aElement, aContext->Document()); 414 }, 415 0) 416 417 MARKUPMAP(thead, nullptr, roles::ROWGROUP) 418 419 MARKUPMAP( 420 tr, 421 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 422 if (aContext->IsTableRow()) { 423 // A <tr> within a row isn't valid. 424 return nullptr; 425 } 426 const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement); 427 if (roleMapEntry && roleMapEntry->role != roles::NOTHING && 428 roleMapEntry->role != roles::ROW) { 429 // There is a valid ARIA role which isn't "row". Don't treat this as an 430 // HTML table row. 431 return nullptr; 432 } 433 // Check if this <tr> is within a table. We check the grandparent because 434 // it might be inside a rowgroup. We don't specifically check for an HTML 435 // table because there are cases where there is a <tr> inside a 436 // <div role="table"> such as Monorail. 437 if (aContext->IsTable() || 438 (aContext->LocalParent() && aContext->LocalParent()->IsTable())) { 439 return new HTMLTableRowAccessible(aElement, aContext->Document()); 440 } 441 return nullptr; 442 }, 443 roles::ROW) 444 445 MARKUPMAP( 446 ul, 447 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 448 return new HTMLListAccessible(aElement, aContext->Document()); 449 }, 450 roles::LIST) 451 452 MARKUPMAP( 453 meter, 454 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* { 455 return new HTMLMeterAccessible(aElement, aContext->Document()); 456 }, 457 roles::METER) 458 459 MARKUPMAP(search, New_HyperText, roles::LANDMARK)