1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "third_party/blink/renderer/modules/accessibility/ax_list_box_option.h"
30
31 #include "third_party/blink/renderer/core/aom/accessible_node.h"
32 #include "third_party/blink/renderer/core/html/forms/html_option_element.h"
33 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
34 #include "third_party/blink/renderer/core/layout/layout_object.h"
35 #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
36
37 namespace blink {
38
AXListBoxOption(LayoutObject * layout_object,AXObjectCacheImpl & ax_object_cache)39 AXListBoxOption::AXListBoxOption(LayoutObject* layout_object,
40 AXObjectCacheImpl& ax_object_cache)
41 : AXLayoutObject(layout_object, ax_object_cache) {}
42
43 AXListBoxOption::~AXListBoxOption() = default;
44
DetermineAccessibilityRole()45 ax::mojom::Role AXListBoxOption::DetermineAccessibilityRole() {
46 if ((aria_role_ = DetermineAriaRoleAttribute()) != ax::mojom::Role::kUnknown)
47 return aria_role_;
48
49 // http://www.w3.org/TR/wai-aria/complete#presentation
50 // ARIA spec says that the presentation role causes a given element to be
51 // treated as having no role or to be removed from the accessibility tree, but
52 // does not cause the content contained within the element to be removed from
53 // the accessibility tree.
54 if (IsParentPresentationalRole())
55 return ax::mojom::Role::kStaticText;
56
57 return ax::mojom::Role::kListBoxOption;
58 }
59
IsParentPresentationalRole() const60 bool AXListBoxOption::IsParentPresentationalRole() const {
61 LayoutObject* parent_layout_object = GetLayoutObject()->Parent();
62 if (!parent_layout_object)
63 return false;
64
65 AXObject* parent = AXObjectCache().GetOrCreate(parent_layout_object);
66 if (!parent)
67 return false;
68
69 if (IsListBox(parent_layout_object) &&
70 parent->HasInheritedPresentationalRole())
71 return true;
72
73 return false;
74 }
75
IsSelected() const76 AccessibilitySelectedState AXListBoxOption::IsSelected() const {
77 if (!GetNode() || !CanSetSelectedAttribute())
78 return kSelectedStateUndefined;
79
80 auto* option_element = DynamicTo<HTMLOptionElement>(GetNode());
81 return (option_element && option_element->Selected()) ? kSelectedStateTrue
82 : kSelectedStateFalse;
83 }
84
IsSelectedOptionActive() const85 bool AXListBoxOption::IsSelectedOptionActive() const {
86 HTMLSelectElement* list_box_parent_node = ListBoxOptionParentNode();
87 if (!list_box_parent_node)
88 return false;
89
90 return list_box_parent_node->ActiveSelectionEnd() == GetNode();
91 }
92
ComputeAccessibilityIsIgnored(IgnoredReasons * ignored_reasons) const93 bool AXListBoxOption::ComputeAccessibilityIsIgnored(
94 IgnoredReasons* ignored_reasons) const {
95 if (!GetNode())
96 return true;
97
98 if (AccessibilityIsIgnoredByDefault(ignored_reasons))
99 return true;
100
101 return false;
102 }
103
TextAlternative(bool recursive,bool in_aria_labelled_by_traversal,AXObjectSet & visited,ax::mojom::NameFrom & name_from,AXRelatedObjectVector * related_objects,NameSources * name_sources) const104 String AXListBoxOption::TextAlternative(bool recursive,
105 bool in_aria_labelled_by_traversal,
106 AXObjectSet& visited,
107 ax::mojom::NameFrom& name_from,
108 AXRelatedObjectVector* related_objects,
109 NameSources* name_sources) const {
110 // If nameSources is non-null, relatedObjects is used in filling it in, so it
111 // must be non-null as well.
112 if (name_sources)
113 DCHECK(related_objects);
114
115 if (!GetNode())
116 return String();
117
118 bool found_text_alternative = false;
119 String text_alternative = AriaTextAlternative(
120 recursive, in_aria_labelled_by_traversal, visited, name_from,
121 related_objects, name_sources, &found_text_alternative);
122 if (found_text_alternative && !name_sources)
123 return text_alternative;
124
125 name_from = ax::mojom::NameFrom::kContents;
126 text_alternative = To<HTMLOptionElement>(GetNode())->DisplayLabel();
127 if (name_sources) {
128 name_sources->push_back(NameSource(found_text_alternative));
129 name_sources->back().type = name_from;
130 name_sources->back().text = text_alternative;
131 found_text_alternative = true;
132 }
133
134 return text_alternative;
135 }
136
OnNativeSetSelectedAction(bool selected)137 bool AXListBoxOption::OnNativeSetSelectedAction(bool selected) {
138 HTMLSelectElement* select_element = ListBoxOptionParentNode();
139 if (!select_element)
140 return false;
141
142 if (!CanSetSelectedAttribute())
143 return false;
144
145 AccessibilitySelectedState is_option_selected = IsSelected();
146 if (is_option_selected == kSelectedStateUndefined)
147 return false;
148
149 bool is_selected = (is_option_selected == kSelectedStateTrue) ? true : false;
150 if ((is_selected && selected) || (!is_selected && !selected))
151 return false;
152
153 select_element->SelectOptionByAccessKey(To<HTMLOptionElement>(GetNode()));
154 return true;
155 }
156
ListBoxOptionParentNode() const157 HTMLSelectElement* AXListBoxOption::ListBoxOptionParentNode() const {
158 if (!GetNode())
159 return nullptr;
160
161 if (auto* option = DynamicTo<HTMLOptionElement>(GetNode()))
162 return option->OwnerSelectElement();
163
164 return nullptr;
165 }
166
167 } // namespace blink
168