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 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 56PassRefPtr<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(ASCIILiteral("EnterFullscreenButton")); 87 static NeverDestroyed<const String> mediaExitFullscreenButtonName(ASCIILiteral("ExitFullscreenButton")); 88 static NeverDestroyed<const String> mediaMuteButtonName(ASCIILiteral("MuteButton")); 89 static NeverDestroyed<const String> mediaPlayButtonName(ASCIILiteral("PlayButton")); 90 static NeverDestroyed<const String> mediaSeekBackButtonName(ASCIILiteral("SeekBackButton")); 91 static NeverDestroyed<const String> mediaSeekForwardButtonName(ASCIILiteral("SeekForwardButton")); 92 static NeverDestroyed<const String> mediaRewindButtonName(ASCIILiteral("RewindButton")); 93 static NeverDestroyed<const String> mediaReturnToRealtimeButtonName(ASCIILiteral("ReturnToRealtimeButton")); 94 static NeverDestroyed<const String> mediaUnMuteButtonName(ASCIILiteral("UnMuteButton")); 95 static NeverDestroyed<const String> mediaPauseButtonName(ASCIILiteral("PauseButton")); 96 static NeverDestroyed<const String> mediaStatusDisplayName(ASCIILiteral("StatusDisplay")); 97 static NeverDestroyed<const String> mediaCurrentTimeDisplay(ASCIILiteral("CurrentTimeDisplay")); 98 static NeverDestroyed<const String> mediaTimeRemainingDisplay(ASCIILiteral("TimeRemainingDisplay")); 99 static NeverDestroyed<const String> mediaShowClosedCaptionsButtonName(ASCIILiteral("ShowClosedCaptionsButton")); 100 static NeverDestroyed<const String> mediaHideClosedCaptionsButtonName(ASCIILiteral("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) 142{ 143 String description = accessibilityDescription(); 144 if (!description.isEmpty()) 145 textOrder.append(AccessibilityText(description, AlternativeText)); 146 147 String title = this->title(); 148 if (!title.isEmpty()) 149 textOrder.append(AccessibilityText(title, AlternativeText)); 150 151 String helptext = helpText(); 152 if (!helptext.isEmpty()) 153 textOrder.append(AccessibilityText(helptext, HelpText)); 154} 155 156 157String AccessibilityMediaControl::title() const 158{ 159 static NeverDestroyed<const String> controlsPanel(ASCIILiteral("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() != 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 ButtonRole; 201 202 case MediaStatusDisplay: 203 return StaticTextRole; 204 205 case MediaTimelineContainer: 206 return GroupRole; 207 208 default: 209 break; 210 } 211 212 return UnknownRole; 213} 214 215 216 217// 218// AccessibilityMediaControlsContainer 219 220AccessibilityMediaControlsContainer::AccessibilityMediaControlsContainer(RenderObject* renderer) 221 : AccessibilityMediaControl(renderer) 222{ 223} 224 225PassRefPtr<AccessibilityObject> AccessibilityMediaControlsContainer::create(RenderObject* renderer) 226{ 227 return adoptRef(new AccessibilityMediaControlsContainer(renderer)); 228} 229 230String AccessibilityMediaControlsContainer::accessibilityDescription() const 231{ 232 return localizedMediaControlElementString(elementTypeName()); 233} 234 235String AccessibilityMediaControlsContainer::helpText() const 236{ 237 return localizedMediaControlElementHelpText(elementTypeName()); 238} 239 240bool AccessibilityMediaControlsContainer::controllingVideoElement() const 241{ 242 auto element = parentMediaElement(*m_renderer); 243 return !element || element->isVideo(); 244} 245 246const String& AccessibilityMediaControlsContainer::elementTypeName() const 247{ 248 static NeverDestroyed<const String> videoElement(ASCIILiteral("VideoElement")); 249 static NeverDestroyed<const String> audioElement(ASCIILiteral("AudioElement")); 250 251 if (controllingVideoElement()) 252 return videoElement; 253 return audioElement; 254} 255 256bool AccessibilityMediaControlsContainer::computeAccessibilityIsIgnored() const 257{ 258 return accessibilityIsIgnoredByDefault(); 259} 260 261// 262// AccessibilityMediaTimeline 263 264AccessibilityMediaTimeline::AccessibilityMediaTimeline(RenderObject* renderer) 265 : AccessibilitySlider(renderer) 266{ 267} 268 269PassRefPtr<AccessibilityObject> AccessibilityMediaTimeline::create(RenderObject* renderer) 270{ 271 return adoptRef(new AccessibilityMediaTimeline(renderer)); 272} 273 274String AccessibilityMediaTimeline::valueDescription() const 275{ 276 Node* node = m_renderer->node(); 277 if (!isHTMLInputElement(node)) 278 return String(); 279 280 float time = toHTMLInputElement(node)->value().toFloat(); 281 return localizedMediaTimeDescription(time); 282} 283 284String AccessibilityMediaTimeline::helpText() const 285{ 286 static NeverDestroyed<const String> slider(ASCIILiteral("Slider")); 287 return localizedMediaControlElementHelpText(slider); 288} 289 290 291// 292// AccessibilityMediaTimeDisplay 293 294AccessibilityMediaTimeDisplay::AccessibilityMediaTimeDisplay(RenderObject* renderer) 295 : AccessibilityMediaControl(renderer) 296{ 297} 298 299PassRefPtr<AccessibilityObject> AccessibilityMediaTimeDisplay::create(RenderObject* renderer) 300{ 301 return adoptRef(new AccessibilityMediaTimeDisplay(renderer)); 302} 303 304bool AccessibilityMediaTimeDisplay::computeAccessibilityIsIgnored() const 305{ 306 if (!m_renderer || m_renderer->style().visibility() != VISIBLE) 307 return true; 308 309 if (!m_renderer->style().width().value()) 310 return true; 311 312 return accessibilityIsIgnoredByDefault(); 313} 314 315String AccessibilityMediaTimeDisplay::accessibilityDescription() const 316{ 317 static NeverDestroyed<const String> currentTimeDisplay(ASCIILiteral("CurrentTimeDisplay")); 318 static NeverDestroyed<const String> timeRemainingDisplay(ASCIILiteral("TimeRemainingDisplay")); 319 320 if (controlType() == MediaCurrentTimeDisplay) 321 return localizedMediaControlElementString(currentTimeDisplay); 322 323 return localizedMediaControlElementString(timeRemainingDisplay); 324} 325 326String AccessibilityMediaTimeDisplay::stringValue() const 327{ 328 if (!m_renderer || !m_renderer->node()) 329 return String(); 330 331 MediaControlTimeDisplayElement* element = static_cast<MediaControlTimeDisplayElement*>(m_renderer->node()); 332 float time = element->currentValue(); 333 return localizedMediaTimeDescription(fabsf(time)); 334} 335 336} // namespace WebCore 337 338#endif // ENABLE(VIDEO) 339