1/*
2 * Copyright (C) 2009-2011 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 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
30#include "config.h"
31
32#if ENABLE(VIDEO)
33
34#include "AccessibilityMediaControls.h"
35
36#include "AXObjectCache.h"
37#include "HTMLInputElement.h"
38#include "HTMLMediaElement.h"
39#include "HTMLNames.h"
40#include "LocalizedStrings.h"
41#include "MediaControlElements.h"
42#include "RenderObject.h"
43#include "RenderSlider.h"
44#include <wtf/NeverDestroyed.h>
45
46namespace WebCore {
47
48using namespace HTMLNames;
49
50
51AccessibilityMediaControl::AccessibilityMediaControl(RenderObject* renderer)
52 : AccessibilityRenderObject(renderer)
53{
54}
55
56Ref<AccessibilityObject> AccessibilityMediaControl::create(RenderObject* renderer)
57{
58 ASSERT(renderer->node());
59
60 switch (mediaControlElementType(renderer->node())) {
61 case MediaSlider:
62 return AccessibilityMediaTimeline::create(renderer);
63
64 case MediaCurrentTimeDisplay:
65 case MediaTimeRemainingDisplay:
66 return AccessibilityMediaTimeDisplay::create(renderer);
67
68 case MediaControlsPanel:
69 return AccessibilityMediaControlsContainer::create(renderer);
70
71 default:
72 return adoptRef(*new AccessibilityMediaControl(renderer));
73 }
74}
75
76MediaControlElementType AccessibilityMediaControl::controlType() const
77{
78 if (!renderer() || !renderer()->node())
79 return MediaTimelineContainer; // Timeline container is not accessible.
80
81 return mediaControlElementType(renderer()->node());
82}
83
84const String& AccessibilityMediaControl::controlTypeName() const
85{
86 static NeverDestroyed<const String> mediaEnterFullscreenButtonName(MAKE_STATIC_STRING_IMPL("EnterFullscreenButton"));
87 static NeverDestroyed<const String> mediaExitFullscreenButtonName(MAKE_STATIC_STRING_IMPL("ExitFullscreenButton"));
88 static NeverDestroyed<const String> mediaMuteButtonName(MAKE_STATIC_STRING_IMPL("MuteButton"));
89 static NeverDestroyed<const String> mediaPlayButtonName(MAKE_STATIC_STRING_IMPL("PlayButton"));
90 static NeverDestroyed<const String> mediaSeekBackButtonName(MAKE_STATIC_STRING_IMPL("SeekBackButton"));
91 static NeverDestroyed<const String> mediaSeekForwardButtonName(MAKE_STATIC_STRING_IMPL("SeekForwardButton"));
92 static NeverDestroyed<const String> mediaRewindButtonName(MAKE_STATIC_STRING_IMPL("RewindButton"));
93 static NeverDestroyed<const String> mediaReturnToRealtimeButtonName(MAKE_STATIC_STRING_IMPL("ReturnToRealtimeButton"));
94 static NeverDestroyed<const String> mediaUnMuteButtonName(MAKE_STATIC_STRING_IMPL("UnMuteButton"));
95 static NeverDestroyed<const String> mediaPauseButtonName(MAKE_STATIC_STRING_IMPL("PauseButton"));
96 static NeverDestroyed<const String> mediaStatusDisplayName(MAKE_STATIC_STRING_IMPL("StatusDisplay"));
97 static NeverDestroyed<const String> mediaCurrentTimeDisplay(MAKE_STATIC_STRING_IMPL("CurrentTimeDisplay"));
98 static NeverDestroyed<const String> mediaTimeRemainingDisplay(MAKE_STATIC_STRING_IMPL("TimeRemainingDisplay"));
99 static NeverDestroyed<const String> mediaShowClosedCaptionsButtonName(MAKE_STATIC_STRING_IMPL("ShowClosedCaptionsButton"));
100 static NeverDestroyed<const String> mediaHideClosedCaptionsButtonName(MAKE_STATIC_STRING_IMPL("HideClosedCaptionsButton"));
101
102 switch (controlType()) {
103 case MediaEnterFullscreenButton:
104 return mediaEnterFullscreenButtonName;
105 case MediaExitFullscreenButton:
106 return mediaExitFullscreenButtonName;
107 case MediaMuteButton:
108 return mediaMuteButtonName;
109 case MediaPlayButton:
110 return mediaPlayButtonName;
111 case MediaSeekBackButton:
112 return mediaSeekBackButtonName;
113 case MediaSeekForwardButton:
114 return mediaSeekForwardButtonName;
115 case MediaRewindButton:
116 return mediaRewindButtonName;
117 case MediaReturnToRealtimeButton:
118 return mediaReturnToRealtimeButtonName;
119 case MediaUnMuteButton:
120 return mediaUnMuteButtonName;
121 case MediaPauseButton:
122 return mediaPauseButtonName;
123 case MediaStatusDisplay:
124 return mediaStatusDisplayName;
125 case MediaCurrentTimeDisplay:
126 return mediaCurrentTimeDisplay;
127 case MediaTimeRemainingDisplay:
128 return mediaTimeRemainingDisplay;
129 case MediaShowClosedCaptionsButton:
130 return mediaShowClosedCaptionsButtonName;
131 case MediaHideClosedCaptionsButton:
132 return mediaHideClosedCaptionsButtonName;
133
134 default:
135 break;
136 }
137
138 return nullAtom();
139}
140
141void AccessibilityMediaControl::accessibilityText(Vector<AccessibilityText>& textOrder) const
142{
143 String description = accessibilityDescription();
144 if (!description.isEmpty())
145 textOrder.append(AccessibilityText(description, AccessibilityTextSource::Alternative));
146
147 String title = this->title();
148 if (!title.isEmpty())
149 textOrder.append(AccessibilityText(title, AccessibilityTextSource::Alternative));
150
151 String helptext = helpText();
152 if (!helptext.isEmpty())
153 textOrder.append(AccessibilityText(helptext, AccessibilityTextSource::Help));
154}
155
156
157String AccessibilityMediaControl::title() const
158{
159 static NeverDestroyed<const String> controlsPanel(MAKE_STATIC_STRING_IMPL("ControlsPanel"));
160
161 if (controlType() == MediaControlsPanel)
162 return localizedMediaControlElementString(controlsPanel);
163
164 return AccessibilityRenderObject::title();
165}
166
167String AccessibilityMediaControl::accessibilityDescription() const
168{
169 return localizedMediaControlElementString(controlTypeName());
170}
171
172String AccessibilityMediaControl::helpText() const
173{
174 return localizedMediaControlElementHelpText(controlTypeName());
175}
176
177bool AccessibilityMediaControl::computeAccessibilityIsIgnored() const
178{
179 if (!m_renderer || m_renderer->style().visibility() != Visibility::Visible || controlType() == MediaTimelineContainer)
180 return true;
181
182 return accessibilityIsIgnoredByDefault();
183}
184
185AccessibilityRole AccessibilityMediaControl::roleValue() const
186{
187 switch (controlType()) {
188 case MediaEnterFullscreenButton:
189 case MediaExitFullscreenButton:
190 case MediaMuteButton:
191 case MediaPlayButton:
192 case MediaSeekBackButton:
193 case MediaSeekForwardButton:
194 case MediaRewindButton:
195 case MediaReturnToRealtimeButton:
196 case MediaUnMuteButton:
197 case MediaPauseButton:
198 case MediaShowClosedCaptionsButton:
199 case MediaHideClosedCaptionsButton:
200 return AccessibilityRole::Button;
201
202 case MediaStatusDisplay:
203 return AccessibilityRole::StaticText;
204
205 case MediaTimelineContainer:
206 return AccessibilityRole::Group;
207
208 default:
209 break;
210 }
211
212 return AccessibilityRole::Unknown;
213}
214
215
216//
217// AccessibilityMediaControlsContainer
218
219AccessibilityMediaControlsContainer::AccessibilityMediaControlsContainer(RenderObject* renderer)
220 : AccessibilityMediaControl(renderer)
221{
222}
223
224Ref<AccessibilityObject> AccessibilityMediaControlsContainer::create(RenderObject* renderer)
225{
226 return adoptRef(*new AccessibilityMediaControlsContainer(renderer));
227}
228
229String AccessibilityMediaControlsContainer::accessibilityDescription() const
230{
231 return localizedMediaControlElementString(elementTypeName());
232}
233
234String AccessibilityMediaControlsContainer::helpText() const
235{
236 return localizedMediaControlElementHelpText(elementTypeName());
237}
238
239bool AccessibilityMediaControlsContainer::controllingVideoElement() const
240{
241 auto element = parentMediaElement(*m_renderer);
242 return !element || element->isVideo();
243}
244
245const String& AccessibilityMediaControlsContainer::elementTypeName() const
246{
247 static NeverDestroyed<const String> videoElement(MAKE_STATIC_STRING_IMPL("VideoElement"));
248 static NeverDestroyed<const String> audioElement(MAKE_STATIC_STRING_IMPL("AudioElement"));
249
250 if (controllingVideoElement())
251 return videoElement;
252 return audioElement;
253}
254
255bool AccessibilityMediaControlsContainer::computeAccessibilityIsIgnored() const
256{
257 return accessibilityIsIgnoredByDefault();
258}
259
260//
261// AccessibilityMediaTimeline
262
263AccessibilityMediaTimeline::AccessibilityMediaTimeline(RenderObject* renderer)
264 : AccessibilitySlider(renderer)
265{
266}
267
268Ref<AccessibilityObject> AccessibilityMediaTimeline::create(RenderObject* renderer)
269{
270 return adoptRef(*new AccessibilityMediaTimeline(renderer));
271}
272
273String AccessibilityMediaTimeline::valueDescription() const
274{
275 Node* node = m_renderer->node();
276 if (!is<HTMLInputElement>(*node))
277 return String();
278
279 float time = downcast<HTMLInputElement>(*node).value().toFloat();
280 return localizedMediaTimeDescription(time);
281}
282
283String AccessibilityMediaTimeline::helpText() const
284{
285 static NeverDestroyed<const String> slider(MAKE_STATIC_STRING_IMPL("Slider"));
286 return localizedMediaControlElementHelpText(slider);
287}
288
289
290//
291// AccessibilityMediaTimeDisplay
292
293AccessibilityMediaTimeDisplay::AccessibilityMediaTimeDisplay(RenderObject* renderer)
294 : AccessibilityMediaControl(renderer)
295{
296}
297
298Ref<AccessibilityObject> AccessibilityMediaTimeDisplay::create(RenderObject* renderer)
299{
300 return adoptRef(*new AccessibilityMediaTimeDisplay(renderer));
301}
302
303bool AccessibilityMediaTimeDisplay::computeAccessibilityIsIgnored() const
304{
305 if (!m_renderer || m_renderer->style().visibility() != Visibility::Visible)
306 return true;
307
308 if (!m_renderer->style().width().value())
309 return true;
310
311 return accessibilityIsIgnoredByDefault();
312}
313
314String AccessibilityMediaTimeDisplay::accessibilityDescription() const
315{
316 static NeverDestroyed<const String> currentTimeDisplay(MAKE_STATIC_STRING_IMPL("CurrentTimeDisplay"));
317 static NeverDestroyed<const String> timeRemainingDisplay(MAKE_STATIC_STRING_IMPL("TimeRemainingDisplay"));
318
319 if (controlType() == MediaCurrentTimeDisplay)
320 return localizedMediaControlElementString(currentTimeDisplay);
321
322 return localizedMediaControlElementString(timeRemainingDisplay);
323}
324
325String AccessibilityMediaTimeDisplay::stringValue() const
326{
327 if (!m_renderer || !m_renderer->node())
328 return String();
329
330 float time = static_cast<MediaControlTimeDisplayElement*>(m_renderer->node())->currentValue();
331 return localizedMediaTimeDescription(std::abs(time));
332}
333
334} // namespace WebCore
335
336#endif // ENABLE(VIDEO)
337