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