Bug 1889091 - Part 4: Remove extra stack pointer move. r=jandem
[gecko.git] / accessible / base / HTMLMarkupMap.h
blobc607616518187468d3b6aa602691af94256b8326
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/. */
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());
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());
25 return new HTMLLinkAccessible(aElement, aContext->Document());
29 MARKUPMAP(abbr, New_HyperText, 0)
31 MARKUPMAP(acronym, New_HyperText, 0)
33 MARKUPMAP(address, New_HyperText, roles::GROUPING)
35 MARKUPMAP(article, New_HyperText, roles::ARTICLE, Attr(xmlroles, article))
37 MARKUPMAP(
38 aside,
39 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
40 return new HTMLAsideAccessible(aElement, aContext->Document());
44 MARKUPMAP(blockquote, New_HyperText, roles::BLOCKQUOTE)
46 MARKUPMAP(
47 button,
48 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
49 return new HTMLButtonAccessible(aElement, aContext->Document());
53 MARKUPMAP(
54 caption,
55 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
56 if (aContext->IsTable()) {
57 dom::HTMLTableElement* tableEl =
58 dom::HTMLTableElement::FromNode(aContext->GetContent());
59 if (tableEl && tableEl == aElement->GetParent() &&
60 tableEl->GetCaption() == aElement) {
61 return new HTMLCaptionAccessible(aElement, aContext->Document());
64 return nullptr;
68 MARKUPMAP(code, New_HyperText, roles::CODE)
70 MARKUPMAP(dd, New_HTMLDtOrDd<HyperTextAccessible>, roles::DEFINITION)
72 MARKUPMAP(del, New_HyperText, roles::CONTENT_DELETION)
74 MARKUPMAP(details, New_HyperText, roles::DETAILS)
76 MARKUPMAP(dfn, New_HyperText, roles::TERM)
78 MARKUPMAP(dialog, New_HyperText, roles::DIALOG)
80 MARKUPMAP(
81 div,
82 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
83 // Never create an accessible if we're part of an anonymous
84 // subtree.
85 if (aElement->IsInNativeAnonymousSubtree()) {
86 return nullptr;
88 // Always create an accessible if the div has an id.
89 if (aElement->HasAttr(nsGkAtoms::id)) {
90 return new HyperTextAccessible(aElement, aContext->Document());
92 // Never create an accessible if the div is not display:block; or
93 // display:inline-block or the like.
94 nsIFrame* f = aElement->GetPrimaryFrame();
95 if (!f || !f->IsBlockFrameOrSubclass()) {
96 return nullptr;
98 // Check for various conditions to determine if this is a block
99 // break and needs to be rendered.
100 // If its previous sibling is an inline element, we probably want
101 // to break, so render.
102 // FIXME: This looks extremely incorrect in presence of shadow DOM,
103 // display: contents, and what not.
104 nsIContent* prevSibling = aElement->GetPreviousSibling();
105 if (prevSibling) {
106 nsIFrame* prevSiblingFrame = prevSibling->GetPrimaryFrame();
107 if (prevSiblingFrame && prevSiblingFrame->IsInlineOutside()) {
108 return new HyperTextAccessible(aElement, aContext->Document());
111 // Now, check the children.
112 nsIContent* firstChild = aElement->GetFirstChild();
113 if (firstChild) {
114 nsIFrame* firstChildFrame = firstChild->GetPrimaryFrame();
115 if (!firstChildFrame) {
116 // The first child is invisible, but this might be due to an
117 // invisible text node. Try the next.
118 firstChild = firstChild->GetNextSibling();
119 if (!firstChild) {
120 // If there's no next sibling, there's only one child, so there's
121 // nothing more we can do.
122 return nullptr;
124 firstChildFrame = firstChild->GetPrimaryFrame();
126 // Check to see if first child has an inline frame.
127 if (firstChildFrame && firstChildFrame->IsInlineOutside()) {
128 return new HyperTextAccessible(aElement, aContext->Document());
130 nsIContent* lastChild = aElement->GetLastChild();
131 MOZ_ASSERT(lastChild);
132 if (lastChild != firstChild) {
133 nsIFrame* lastChildFrame = lastChild->GetPrimaryFrame();
134 if (!lastChildFrame) {
135 // The last child is invisible, but this might be due to an
136 // invisible text node. Try the next.
137 lastChild = lastChild->GetPreviousSibling();
138 MOZ_ASSERT(lastChild);
139 if (lastChild == firstChild) {
140 return nullptr;
142 lastChildFrame = lastChild->GetPrimaryFrame();
144 // Check to see if last child has an inline frame.
145 if (lastChildFrame && lastChildFrame->IsInlineOutside()) {
146 return new HyperTextAccessible(aElement, aContext->Document());
150 return nullptr;
152 roles::SECTION)
154 MARKUPMAP(
156 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
157 return new HTMLListAccessible(aElement, aContext->Document());
159 roles::DEFINITION_LIST)
161 MARKUPMAP(dt, New_HTMLDtOrDd<HTMLLIAccessible>, roles::TERM)
163 MARKUPMAP(em, New_HyperText, roles::EMPHASIS)
165 MARKUPMAP(
166 figcaption,
167 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
168 return new HTMLFigcaptionAccessible(aElement, aContext->Document());
170 roles::CAPTION)
172 MARKUPMAP(
173 figure,
174 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
175 return new HTMLFigureAccessible(aElement, aContext->Document());
177 roles::FIGURE, Attr(xmlroles, figure))
179 MARKUPMAP(
180 fieldset,
181 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
182 return new HTMLGroupboxAccessible(aElement, aContext->Document());
186 MARKUPMAP(
187 form,
188 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
189 return new HTMLFormAccessible(aElement, aContext->Document());
193 MARKUPMAP(
194 footer,
195 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
196 return new HTMLHeaderOrFooterAccessible(aElement, aContext->Document());
200 MARKUPMAP(
201 header,
202 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
203 return new HTMLHeaderOrFooterAccessible(aElement, aContext->Document());
207 MARKUPMAP(h1, New_HyperText, roles::HEADING)
209 MARKUPMAP(h2, New_HyperText, roles::HEADING)
211 MARKUPMAP(h3, New_HyperText, roles::HEADING)
213 MARKUPMAP(h4, New_HyperText, roles::HEADING)
215 MARKUPMAP(h5, New_HyperText, roles::HEADING)
217 MARKUPMAP(h6, New_HyperText, roles::HEADING)
219 MARKUPMAP(hgroup, New_HyperText, roles::GROUPING)
221 MARKUPMAP(
223 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
224 return new HTMLHRAccessible(aElement, aContext->Document());
228 MARKUPMAP(
229 input,
230 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
231 // TODO(emilio): This would be faster if it used
232 // HTMLInputElement's already-parsed representation.
233 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
234 nsGkAtoms::checkbox, eIgnoreCase)) {
235 return new CheckboxAccessible(aElement, aContext->Document());
237 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
238 nsGkAtoms::image, eIgnoreCase)) {
239 return new HTMLButtonAccessible(aElement, aContext->Document());
241 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
242 nsGkAtoms::radio, eIgnoreCase)) {
243 return new HTMLRadioButtonAccessible(aElement, aContext->Document());
245 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
246 nsGkAtoms::time, eIgnoreCase)) {
247 return new HTMLDateTimeAccessible<roles::TIME_EDITOR>(
248 aElement, aContext->Document());
250 if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
251 nsGkAtoms::date, eIgnoreCase) ||
252 aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
253 nsGkAtoms::datetime_local, eIgnoreCase)) {
254 return new HTMLDateTimeAccessible<roles::DATE_EDITOR>(
255 aElement, aContext->Document());
257 return nullptr;
261 MARKUPMAP(ins, New_HyperText, roles::CONTENT_INSERTION)
263 MARKUPMAP(
264 label,
265 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
266 return new HTMLLabelAccessible(aElement, aContext->Document());
268 roles::LABEL)
270 MARKUPMAP(
271 legend,
272 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
273 return new HTMLLegendAccessible(aElement, aContext->Document());
275 roles::LABEL)
277 MARKUPMAP(
279 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
280 // If list item is a child of accessible list then create an
281 // accessible for it unconditionally by tag name. nsBlockFrame
282 // creates the list item accessible for other elements styled as
283 // list items.
284 if (aContext->IsList() &&
285 aContext->GetContent() == aElement->GetParent()) {
286 return new HTMLLIAccessible(aElement, aContext->Document());
289 return nullptr;
293 MARKUPMAP(main, New_HyperText, roles::LANDMARK)
295 MARKUPMAP(map, nullptr, roles::TEXT_CONTAINER)
297 MARKUPMAP(mark, New_HyperText, roles::MARK, Attr(xmlroles, mark))
299 MARKUPMAP(
300 menu,
301 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
302 return new HTMLListAccessible(aElement, aContext->Document());
304 roles::LIST)
306 MARKUPMAP(nav, New_HyperText, roles::LANDMARK)
308 MARKUPMAP(
310 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
311 return new HTMLListAccessible(aElement, aContext->Document());
313 roles::LIST)
315 MARKUPMAP(
316 option,
317 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
318 return new HTMLSelectOptionAccessible(aElement, aContext->Document());
322 MARKUPMAP(
323 optgroup,
324 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
325 return new HTMLSelectOptGroupAccessible(aElement, aContext->Document());
329 MARKUPMAP(
330 output,
331 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
332 return new HTMLOutputAccessible(aElement, aContext->Document());
334 roles::STATUSBAR, Attr(aria_live, polite))
336 MARKUPMAP(p, nullptr, roles::PARAGRAPH)
338 MARKUPMAP(
339 progress,
340 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
341 return new HTMLProgressAccessible(aElement, aContext->Document());
345 MARKUPMAP(q, New_HyperText, 0)
347 MARKUPMAP(s, New_HyperText, roles::CONTENT_DELETION)
349 MARKUPMAP(
350 section,
351 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
352 return new HTMLSectionAccessible(aElement, aContext->Document());
356 MARKUPMAP(strong, New_HyperText, roles::STRONG)
358 MARKUPMAP(sub, New_HyperText, roles::SUBSCRIPT)
360 MARKUPMAP(
361 summary,
362 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
363 return new HTMLSummaryAccessible(aElement, aContext->Document());
365 roles::SUMMARY)
367 MARKUPMAP(sup, New_HyperText, roles::SUPERSCRIPT)
369 MARKUPMAP(
370 table,
371 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
372 return new HTMLTableAccessible(aElement, aContext->Document());
374 roles::TABLE)
376 MARKUPMAP(time, New_HyperText, roles::TIME, Attr(xmlroles, time),
377 AttrFromDOM(datetime, datetime))
379 MARKUPMAP(tbody, nullptr, roles::GROUPING)
381 MARKUPMAP(
383 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
384 if (!aContext->IsHTMLTableRow()) {
385 return nullptr;
387 if (aElement->HasAttr(nsGkAtoms::scope)) {
388 return new HTMLTableHeaderCellAccessible(aElement,
389 aContext->Document());
391 return new HTMLTableCellAccessible(aElement, aContext->Document());
395 MARKUPMAP(tfoot, nullptr, roles::GROUPING)
397 MARKUPMAP(
399 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
400 if (!aContext->IsHTMLTableRow()) {
401 return nullptr;
403 return new HTMLTableHeaderCellAccessible(aElement, aContext->Document());
407 MARKUPMAP(thead, nullptr, roles::GROUPING)
409 MARKUPMAP(
411 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
412 if (aContext->IsTableRow()) {
413 // A <tr> within a row isn't valid.
414 return nullptr;
416 const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement);
417 if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
418 roleMapEntry->role != roles::ROW) {
419 // There is a valid ARIA role which isn't "row". Don't treat this as an
420 // HTML table row.
421 return nullptr;
423 // Check if this <tr> is within a table. We check the grandparent because
424 // it might be inside a rowgroup. We don't specifically check for an HTML
425 // table because there are cases where there is a <tr> inside a
426 // <div role="table"> such as Monorail.
427 if (aContext->IsTable() ||
428 (aContext->LocalParent() && aContext->LocalParent()->IsTable())) {
429 return new HTMLTableRowAccessible(aElement, aContext->Document());
431 return nullptr;
433 roles::ROW)
435 MARKUPMAP(
437 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
438 return new HTMLListAccessible(aElement, aContext->Document());
440 roles::LIST)
442 MARKUPMAP(
443 meter,
444 [](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
445 return new HTMLMeterAccessible(aElement, aContext->Document());
447 roles::METER)
449 MARKUPMAP(search, New_HyperText, roles::LANDMARK)