1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
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/. */
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(aside
, New_HyperText
, roles::LANDMARK
)
39 MARKUPMAP(blockquote
, New_HyperText
, roles::BLOCKQUOTE
)
43 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
44 return new HTMLButtonAccessible(aElement
, aContext
->Document());
50 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
51 if (aContext
->IsTable()) {
52 dom::HTMLTableElement
* tableEl
=
53 dom::HTMLTableElement::FromNode(aContext
->GetContent());
54 if (tableEl
&& tableEl
== aElement
->GetParent() &&
55 tableEl
->GetCaption() == aElement
) {
56 return new HTMLCaptionAccessible(aElement
, aContext
->Document());
63 MARKUPMAP(code
, New_HyperText
, roles::CODE
)
65 MARKUPMAP(dd
, New_HTMLDtOrDd
<HyperTextAccessible
>, roles::DEFINITION
)
67 MARKUPMAP(del
, New_HyperText
, roles::CONTENT_DELETION
)
69 MARKUPMAP(details
, New_HyperText
, roles::DETAILS
)
71 MARKUPMAP(dialog
, New_HyperText
, roles::DIALOG
)
75 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
76 // Never create an accessible if we're part of an anonymous
78 if (aElement
->IsInNativeAnonymousSubtree()) {
81 // Always create an accessible if the div has an id.
82 if (aElement
->HasAttr(nsGkAtoms::id
)) {
83 return new HyperTextAccessible(aElement
, aContext
->Document());
85 // Never create an accessible if the div is not display:block; or
86 // display:inline-block or the like.
87 nsIFrame
* f
= aElement
->GetPrimaryFrame();
88 if (!f
|| !f
->IsBlockFrameOrSubclass()) {
91 // Check for various conditions to determine if this is a block
92 // break and needs to be rendered.
93 // If its previous sibling is an inline element, we probably want
94 // to break, so render.
95 // FIXME: This looks extremely incorrect in presence of shadow DOM,
96 // display: contents, and what not.
97 nsIContent
* prevSibling
= aElement
->GetPreviousSibling();
99 nsIFrame
* prevSiblingFrame
= prevSibling
->GetPrimaryFrame();
100 if (prevSiblingFrame
&& prevSiblingFrame
->IsInlineOutside()) {
101 return new HyperTextAccessible(aElement
, aContext
->Document());
104 // Now, check the children.
105 nsIContent
* firstChild
= aElement
->GetFirstChild();
107 nsIFrame
* firstChildFrame
= firstChild
->GetPrimaryFrame();
108 if (!firstChildFrame
) {
109 // The first child is invisible, but this might be due to an
110 // invisible text node. Try the next.
111 firstChild
= firstChild
->GetNextSibling();
113 // If there's no next sibling, there's only one child, so there's
114 // nothing more we can do.
117 firstChildFrame
= firstChild
->GetPrimaryFrame();
119 // Check to see if first child has an inline frame.
120 if (firstChildFrame
&& firstChildFrame
->IsInlineOutside()) {
121 return new HyperTextAccessible(aElement
, aContext
->Document());
123 nsIContent
* lastChild
= aElement
->GetLastChild();
124 MOZ_ASSERT(lastChild
);
125 if (lastChild
!= firstChild
) {
126 nsIFrame
* lastChildFrame
= lastChild
->GetPrimaryFrame();
127 if (!lastChildFrame
) {
128 // The last child is invisible, but this might be due to an
129 // invisible text node. Try the next.
130 lastChild
= lastChild
->GetPreviousSibling();
131 MOZ_ASSERT(lastChild
);
132 if (lastChild
== firstChild
) {
135 lastChildFrame
= lastChild
->GetPrimaryFrame();
137 // Check to see if last child has an inline frame.
138 if (lastChildFrame
&& lastChildFrame
->IsInlineOutside()) {
139 return new HyperTextAccessible(aElement
, aContext
->Document());
149 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
150 return new HTMLListAccessible(aElement
, aContext
->Document());
152 roles::DEFINITION_LIST
)
154 MARKUPMAP(dt
, New_HTMLDtOrDd
<HTMLLIAccessible
>, roles::TERM
)
158 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
159 return new HTMLFigcaptionAccessible(aElement
, aContext
->Document());
165 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
166 return new HTMLFigureAccessible(aElement
, aContext
->Document());
168 roles::FIGURE
, Attr(xmlroles
, figure
))
172 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
173 return new HTMLGroupboxAccessible(aElement
, aContext
->Document());
179 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
180 return new HTMLFormAccessible(aElement
, aContext
->Document());
186 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
187 return new HTMLHeaderOrFooterAccessible(aElement
, aContext
->Document());
193 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
194 return new HTMLHeaderOrFooterAccessible(aElement
, aContext
->Document());
198 MARKUPMAP(h1
, New_HyperText
, roles::HEADING
)
200 MARKUPMAP(h2
, New_HyperText
, roles::HEADING
)
202 MARKUPMAP(h3
, New_HyperText
, roles::HEADING
)
204 MARKUPMAP(h4
, New_HyperText
, roles::HEADING
)
206 MARKUPMAP(h5
, New_HyperText
, roles::HEADING
)
208 MARKUPMAP(h6
, New_HyperText
, roles::HEADING
)
212 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
213 return new HTMLHRAccessible(aElement
, aContext
->Document());
219 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
220 // TODO(emilio): This would be faster if it used
221 // HTMLInputElement's already-parsed representation.
222 if (aElement
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::type
,
223 nsGkAtoms::checkbox
, eIgnoreCase
)) {
224 return new CheckboxAccessible(aElement
, aContext
->Document());
226 if (aElement
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::type
,
227 nsGkAtoms::image
, eIgnoreCase
)) {
228 return new HTMLButtonAccessible(aElement
, aContext
->Document());
230 if (aElement
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::type
,
231 nsGkAtoms::radio
, eIgnoreCase
)) {
232 return new HTMLRadioButtonAccessible(aElement
, aContext
->Document());
234 if (aElement
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::type
,
235 nsGkAtoms::time
, eIgnoreCase
)) {
236 return new HTMLDateTimeAccessible
<roles::TIME_EDITOR
>(
237 aElement
, aContext
->Document());
239 if (aElement
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::type
,
240 nsGkAtoms::date
, eIgnoreCase
) ||
241 aElement
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::type
,
242 nsGkAtoms::datetime_local
, eIgnoreCase
)) {
243 return new HTMLDateTimeAccessible
<roles::DATE_EDITOR
>(
244 aElement
, aContext
->Document());
250 MARKUPMAP(ins
, New_HyperText
, roles::CONTENT_INSERTION
)
254 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
255 return new HTMLLabelAccessible(aElement
, aContext
->Document());
261 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
262 return new HTMLLegendAccessible(aElement
, aContext
->Document());
268 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
269 // If list item is a child of accessible list then create an
270 // accessible for it unconditionally by tag name. nsBlockFrame
271 // creates the list item accessible for other elements styled as
273 if (aContext
->IsList() &&
274 aContext
->GetContent() == aElement
->GetParent()) {
275 return new HTMLLIAccessible(aElement
, aContext
->Document());
282 MARKUPMAP(main
, New_HyperText
, roles::LANDMARK
)
284 MARKUPMAP(map
, nullptr, roles::TEXT_CONTAINER
)
286 MARKUPMAP(mark
, New_HyperText
, roles::MARK
, Attr(xmlroles
, mark
))
290 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
291 return new HTMLListAccessible(aElement
, aContext
->Document());
295 MARKUPMAP(nav
, New_HyperText
, roles::LANDMARK
)
299 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
300 return new HTMLListAccessible(aElement
, aContext
->Document());
306 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
307 return new HTMLSelectOptionAccessible(aElement
, aContext
->Document());
313 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
314 return new HTMLSelectOptGroupAccessible(aElement
, aContext
->Document());
320 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
321 return new HTMLOutputAccessible(aElement
, aContext
->Document());
323 roles::STATUSBAR
, Attr(aria_live
, polite
))
325 MARKUPMAP(p
, nullptr, roles::PARAGRAPH
)
329 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
330 return new HTMLProgressAccessible(aElement
, aContext
->Document());
334 MARKUPMAP(q
, New_HyperText
, 0)
336 MARKUPMAP(s
, New_HyperText
, roles::CONTENT_DELETION
)
340 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
341 return new HTMLSectionAccessible(aElement
, aContext
->Document());
345 MARKUPMAP(sub
, New_HyperText
, roles::SUBSCRIPT
)
349 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
350 return new HTMLSummaryAccessible(aElement
, aContext
->Document());
354 MARKUPMAP(sup
, New_HyperText
, roles::SUPERSCRIPT
)
358 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
359 return new HTMLTableAccessible(aElement
, aContext
->Document());
363 MARKUPMAP(time
, New_HyperText
, 0, Attr(xmlroles
, time
),
364 AttrFromDOM(datetime
, datetime
))
366 MARKUPMAP(tbody
, nullptr, roles::GROUPING
)
370 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
371 if (!aContext
->IsHTMLTableRow()) {
374 if (aElement
->HasAttr(nsGkAtoms::scope
)) {
375 return new HTMLTableHeaderCellAccessible(aElement
,
376 aContext
->Document());
378 return new HTMLTableCellAccessible(aElement
, aContext
->Document());
382 MARKUPMAP(tfoot
, nullptr, roles::GROUPING
)
386 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
387 if (!aContext
->IsHTMLTableRow()) {
390 return new HTMLTableHeaderCellAccessible(aElement
, aContext
->Document());
394 MARKUPMAP(thead
, nullptr, roles::GROUPING
)
398 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
399 if (aContext
->IsTableRow()) {
400 // A <tr> within a row isn't valid.
403 const nsRoleMapEntry
* roleMapEntry
= aria::GetRoleMap(aElement
);
404 if (roleMapEntry
&& roleMapEntry
->role
!= roles::NOTHING
&&
405 roleMapEntry
->role
!= roles::ROW
) {
406 // There is a valid ARIA role which isn't "row". Don't treat this as an
410 // Check if this <tr> is within a table. We check the grandparent because
411 // it might be inside a rowgroup. We don't specifically check for an HTML
412 // table because there are cases where there is a <tr> inside a
413 // <div role="table"> such as Monorail.
414 if (aContext
->IsTable() ||
415 (aContext
->LocalParent() && aContext
->LocalParent()->IsTable())) {
416 return new HTMLTableRowAccessible(aElement
, aContext
->Document());
424 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
425 return new HTMLListAccessible(aElement
, aContext
->Document());
431 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
432 return new HTMLMeterAccessible(aElement
, aContext
->Document());
436 MARKUPMAP(search
, New_HyperText
, roles::LANDMARK
)