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
))
39 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
40 return new HTMLAsideAccessible(aElement
, aContext
->Document());
44 MARKUPMAP(blockquote
, New_HyperText
, roles::BLOCKQUOTE
)
48 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
49 return new HTMLButtonAccessible(aElement
, aContext
->Document());
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());
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
)
82 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
83 // Never create an accessible if we're part of an anonymous
85 if (aElement
->IsInNativeAnonymousSubtree()) {
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()) {
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();
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();
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();
120 // If there's no next sibling, there's only one child, so there's
121 // nothing more we can do.
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
) {
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());
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
)
167 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
168 return new HTMLFigcaptionAccessible(aElement
, aContext
->Document());
174 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
175 return new HTMLFigureAccessible(aElement
, aContext
->Document());
177 roles::FIGURE
, Attr(xmlroles
, figure
))
181 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
182 return new HTMLGroupboxAccessible(aElement
, aContext
->Document());
188 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
189 return new HTMLFormAccessible(aElement
, aContext
->Document());
195 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
196 return new HTMLHeaderOrFooterAccessible(aElement
, aContext
->Document());
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
)
223 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
224 return new HTMLHRAccessible(aElement
, aContext
->Document());
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());
261 MARKUPMAP(ins
, New_HyperText
, roles::CONTENT_INSERTION
)
265 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
266 return new HTMLLabelAccessible(aElement
, aContext
->Document());
272 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
273 return new HTMLLegendAccessible(aElement
, aContext
->Document());
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
284 if (aContext
->IsList() &&
285 aContext
->GetContent() == aElement
->GetParent()) {
286 return new HTMLLIAccessible(aElement
, aContext
->Document());
293 MARKUPMAP(main
, New_HyperText
, roles::LANDMARK
)
295 MARKUPMAP(map
, nullptr, roles::TEXT_CONTAINER
)
297 MARKUPMAP(mark
, New_HyperText
, roles::MARK
, Attr(xmlroles
, mark
))
301 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
302 return new HTMLListAccessible(aElement
, aContext
->Document());
306 MARKUPMAP(nav
, New_HyperText
, roles::LANDMARK
)
310 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
311 return new HTMLListAccessible(aElement
, aContext
->Document());
317 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
318 return new HTMLSelectOptionAccessible(aElement
, aContext
->Document());
324 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
325 return new HTMLSelectOptGroupAccessible(aElement
, aContext
->Document());
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
)
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
)
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
)
362 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
363 return new HTMLSummaryAccessible(aElement
, aContext
->Document());
367 MARKUPMAP(sup
, New_HyperText
, roles::SUPERSCRIPT
)
371 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
372 return new HTMLTableAccessible(aElement
, aContext
->Document());
376 MARKUPMAP(time
, New_HyperText
, roles::TIME
, Attr(xmlroles
, time
),
377 AttrFromDOM(datetime
, datetime
))
379 MARKUPMAP(tbody
, nullptr, roles::GROUPING
)
383 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
384 if (!aContext
->IsHTMLTableRow()) {
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
)
399 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
400 if (!aContext
->IsHTMLTableRow()) {
403 return new HTMLTableHeaderCellAccessible(aElement
, aContext
->Document());
407 MARKUPMAP(thead
, nullptr, roles::GROUPING
)
411 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
412 if (aContext
->IsTableRow()) {
413 // A <tr> within a row isn't valid.
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
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());
437 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
438 return new HTMLListAccessible(aElement
, aContext
->Document());
444 [](Element
* aElement
, LocalAccessible
* aContext
) -> LocalAccessible
* {
445 return new HTMLMeterAccessible(aElement
, aContext
->Document());
449 MARKUPMAP(search
, New_HyperText
, roles::LANDMARK
)