/* * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if ENABLE(VIDEO) #include "AccessibilityMediaControls.h" #include "AXObjectCache.h" #include "HTMLInputElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "LocalizedStrings.h" #include "MediaControlElements.h" #include "RenderObject.h" #include "RenderSlider.h" #include namespace WebCore { using namespace HTMLNames; AccessibilityMediaControl::AccessibilityMediaControl(RenderObject* renderer) : AccessibilityRenderObject(renderer) { } Ref AccessibilityMediaControl::create(RenderObject* renderer) { ASSERT(renderer->node()); switch (mediaControlElementType(renderer->node())) { case MediaSlider: return AccessibilityMediaTimeline::create(renderer); case MediaCurrentTimeDisplay: case MediaTimeRemainingDisplay: return AccessibilityMediaTimeDisplay::create(renderer); case MediaControlsPanel: return AccessibilityMediaControlsContainer::create(renderer); default: return adoptRef(*new AccessibilityMediaControl(renderer)); } } MediaControlElementType AccessibilityMediaControl::controlType() const { if (!renderer() || !renderer()->node()) return MediaTimelineContainer; // Timeline container is not accessible. return mediaControlElementType(renderer()->node()); } const String& AccessibilityMediaControl::controlTypeName() const { static NeverDestroyed mediaEnterFullscreenButtonName(ASCIILiteral("EnterFullscreenButton")); static NeverDestroyed mediaExitFullscreenButtonName(ASCIILiteral("ExitFullscreenButton")); static NeverDestroyed mediaMuteButtonName(ASCIILiteral("MuteButton")); static NeverDestroyed mediaPlayButtonName(ASCIILiteral("PlayButton")); static NeverDestroyed mediaSeekBackButtonName(ASCIILiteral("SeekBackButton")); static NeverDestroyed mediaSeekForwardButtonName(ASCIILiteral("SeekForwardButton")); static NeverDestroyed mediaRewindButtonName(ASCIILiteral("RewindButton")); static NeverDestroyed mediaReturnToRealtimeButtonName(ASCIILiteral("ReturnToRealtimeButton")); static NeverDestroyed mediaUnMuteButtonName(ASCIILiteral("UnMuteButton")); static NeverDestroyed mediaPauseButtonName(ASCIILiteral("PauseButton")); static NeverDestroyed mediaStatusDisplayName(ASCIILiteral("StatusDisplay")); static NeverDestroyed mediaCurrentTimeDisplay(ASCIILiteral("CurrentTimeDisplay")); static NeverDestroyed mediaTimeRemainingDisplay(ASCIILiteral("TimeRemainingDisplay")); static NeverDestroyed mediaShowClosedCaptionsButtonName(ASCIILiteral("ShowClosedCaptionsButton")); static NeverDestroyed mediaHideClosedCaptionsButtonName(ASCIILiteral("HideClosedCaptionsButton")); switch (controlType()) { case MediaEnterFullscreenButton: return mediaEnterFullscreenButtonName; case MediaExitFullscreenButton: return mediaExitFullscreenButtonName; case MediaMuteButton: return mediaMuteButtonName; case MediaPlayButton: return mediaPlayButtonName; case MediaSeekBackButton: return mediaSeekBackButtonName; case MediaSeekForwardButton: return mediaSeekForwardButtonName; case MediaRewindButton: return mediaRewindButtonName; case MediaReturnToRealtimeButton: return mediaReturnToRealtimeButtonName; case MediaUnMuteButton: return mediaUnMuteButtonName; case MediaPauseButton: return mediaPauseButtonName; case MediaStatusDisplay: return mediaStatusDisplayName; case MediaCurrentTimeDisplay: return mediaCurrentTimeDisplay; case MediaTimeRemainingDisplay: return mediaTimeRemainingDisplay; case MediaShowClosedCaptionsButton: return mediaShowClosedCaptionsButtonName; case MediaHideClosedCaptionsButton: return mediaHideClosedCaptionsButtonName; default: break; } return nullAtom; } void AccessibilityMediaControl::accessibilityText(Vector& textOrder) { String description = accessibilityDescription(); if (!description.isEmpty()) textOrder.append(AccessibilityText(description, AlternativeText)); String title = this->title(); if (!title.isEmpty()) textOrder.append(AccessibilityText(title, AlternativeText)); String helptext = helpText(); if (!helptext.isEmpty()) textOrder.append(AccessibilityText(helptext, HelpText)); } String AccessibilityMediaControl::title() const { static NeverDestroyed controlsPanel(ASCIILiteral("ControlsPanel")); if (controlType() == MediaControlsPanel) return localizedMediaControlElementString(controlsPanel); return AccessibilityRenderObject::title(); } String AccessibilityMediaControl::accessibilityDescription() const { return localizedMediaControlElementString(controlTypeName()); } String AccessibilityMediaControl::helpText() const { return localizedMediaControlElementHelpText(controlTypeName()); } bool AccessibilityMediaControl::computeAccessibilityIsIgnored() const { if (!m_renderer || m_renderer->style().visibility() != VISIBLE || controlType() == MediaTimelineContainer) return true; return accessibilityIsIgnoredByDefault(); } AccessibilityRole AccessibilityMediaControl::roleValue() const { switch (controlType()) { case MediaEnterFullscreenButton: case MediaExitFullscreenButton: case MediaMuteButton: case MediaPlayButton: case MediaSeekBackButton: case MediaSeekForwardButton: case MediaRewindButton: case MediaReturnToRealtimeButton: case MediaUnMuteButton: case MediaPauseButton: case MediaShowClosedCaptionsButton: case MediaHideClosedCaptionsButton: return ButtonRole; case MediaStatusDisplay: return StaticTextRole; case MediaTimelineContainer: return GroupRole; default: break; } return UnknownRole; } // // AccessibilityMediaControlsContainer AccessibilityMediaControlsContainer::AccessibilityMediaControlsContainer(RenderObject* renderer) : AccessibilityMediaControl(renderer) { } Ref AccessibilityMediaControlsContainer::create(RenderObject* renderer) { return adoptRef(*new AccessibilityMediaControlsContainer(renderer)); } String AccessibilityMediaControlsContainer::accessibilityDescription() const { return localizedMediaControlElementString(elementTypeName()); } String AccessibilityMediaControlsContainer::helpText() const { return localizedMediaControlElementHelpText(elementTypeName()); } bool AccessibilityMediaControlsContainer::controllingVideoElement() const { auto element = parentMediaElement(*m_renderer); return !element || element->isVideo(); } const String& AccessibilityMediaControlsContainer::elementTypeName() const { static NeverDestroyed videoElement(ASCIILiteral("VideoElement")); static NeverDestroyed audioElement(ASCIILiteral("AudioElement")); if (controllingVideoElement()) return videoElement; return audioElement; } bool AccessibilityMediaControlsContainer::computeAccessibilityIsIgnored() const { return accessibilityIsIgnoredByDefault(); } // // AccessibilityMediaTimeline AccessibilityMediaTimeline::AccessibilityMediaTimeline(RenderObject* renderer) : AccessibilitySlider(renderer) { } Ref AccessibilityMediaTimeline::create(RenderObject* renderer) { return adoptRef(*new AccessibilityMediaTimeline(renderer)); } String AccessibilityMediaTimeline::valueDescription() const { Node* node = m_renderer->node(); if (!is(*node)) return String(); float time = downcast(*node).value().toFloat(); return localizedMediaTimeDescription(time); } String AccessibilityMediaTimeline::helpText() const { static NeverDestroyed slider(ASCIILiteral("Slider")); return localizedMediaControlElementHelpText(slider); } // // AccessibilityMediaTimeDisplay AccessibilityMediaTimeDisplay::AccessibilityMediaTimeDisplay(RenderObject* renderer) : AccessibilityMediaControl(renderer) { } Ref AccessibilityMediaTimeDisplay::create(RenderObject* renderer) { return adoptRef(*new AccessibilityMediaTimeDisplay(renderer)); } bool AccessibilityMediaTimeDisplay::computeAccessibilityIsIgnored() const { if (!m_renderer || m_renderer->style().visibility() != VISIBLE) return true; if (!m_renderer->style().width().value()) return true; return accessibilityIsIgnoredByDefault(); } String AccessibilityMediaTimeDisplay::accessibilityDescription() const { static NeverDestroyed currentTimeDisplay(ASCIILiteral("CurrentTimeDisplay")); static NeverDestroyed timeRemainingDisplay(ASCIILiteral("TimeRemainingDisplay")); if (controlType() == MediaCurrentTimeDisplay) return localizedMediaControlElementString(currentTimeDisplay); return localizedMediaControlElementString(timeRemainingDisplay); } String AccessibilityMediaTimeDisplay::stringValue() const { if (!m_renderer || !m_renderer->node()) return String(); MediaControlTimeDisplayElement* element = static_cast(m_renderer->node()); float time = element->currentValue(); return localizedMediaTimeDescription(fabsf(time)); } } // namespace WebCore #endif // ENABLE(VIDEO)