Title: [222887] trunk
Revision
222887
Author
n_w...@apple.com
Date
2017-10-04 16:43:13 -0700 (Wed, 04 Oct 2017)

Log Message

AX: Make video objects accessible on iOS
https://bugs.webkit.org/show_bug.cgi?id=177788
<rdar://problem/34778028>

Reviewed by Chris Fleizach.

Source/WebCore:

Exposed certain <video> elements on iOS:
1. If they have no controls attribute set and have playsinline attribute set, that means
   normally there are custom controls provided.
2. Without autoplay attribute set. From iOS 10, with the motivation to improve performace by
   replacing GIF with <video>, elements will now honor the autoplay attribute if they
   have no audio. So normally those <video> elements are not interactive.

Also provided functions to let iOS users interact with the video elements:
- Play/Pause: accessibilityActivate
- Fast forward: accessibilityIncrement
- Rewind: accessibilityDecrement

Test: accessibility/ios-simulator/video-elements-ios.html

* WebCore.xcodeproj/project.pbxproj:
* accessibility/AXObjectCache.cpp:
(WebCore::createFromRenderer):
* accessibility/AccessibilityMediaObject.cpp: Added.
(WebCore::AccessibilityMediaObject::AccessibilityMediaObject):
(WebCore::AccessibilityMediaObject::~AccessibilityMediaObject):
(WebCore::AccessibilityMediaObject::create):
(WebCore::AccessibilityMediaObject::computeAccessibilityIsIgnored const):
(WebCore::AccessibilityMediaObject::mediaElement const):
(WebCore::AccessibilityMediaObject::stringValue const):
(WebCore::AccessibilityMediaObject::interactiveVideoDuration const):
(WebCore::AccessibilityMediaObject::mediaSeek):
(WebCore::AccessibilityMediaObject::toggleMute):
(WebCore::AccessibilityMediaObject::increment):
(WebCore::AccessibilityMediaObject::decrement):
(WebCore::AccessibilityMediaObject::press):
(WebCore::AccessibilityMediaObject::hasControlsAttributeSet const):
(WebCore::AccessibilityMediaObject::isPlaying const):
(WebCore::AccessibilityMediaObject::isMuted const):
(WebCore::AccessibilityMediaObject::isAutoplayEnabled const):
(WebCore::AccessibilityMediaObject::isPlayingInline const):
(WebCore::AccessibilityMediaObject::enterFullscreen const):
* accessibility/AccessibilityMediaObject.h: Added.
* accessibility/AccessibilityObject.cpp:
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::isMediaObject const):
* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper accessibilityIsWebInteractiveVideo]):
(-[WebAccessibilityObjectWrapper interactiveVideoDescription]):
(-[WebAccessibilityObjectWrapper accessibilityIsMediaPlaying]):
(-[WebAccessibilityObjectWrapper accessibilityIsMediaMuted]):
(-[WebAccessibilityObjectWrapper accessibilityToggleMuteForMedia]):
(-[WebAccessibilityObjectWrapper accessibilityVideoEnterFullscreen]):
(-[WebAccessibilityObjectWrapper determineIsAccessibilityElement]):
(-[WebAccessibilityObjectWrapper stringValueShouldBeUsedInLabel]):
(-[WebAccessibilityObjectWrapper accessibilityLabel]):

LayoutTests:

* accessibility/ios-simulator/video-elements-ios-expected.txt: Added.
* accessibility/ios-simulator/video-elements-ios.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (222886 => 222887)


--- trunk/LayoutTests/ChangeLog	2017-10-04 23:27:45 UTC (rev 222886)
+++ trunk/LayoutTests/ChangeLog	2017-10-04 23:43:13 UTC (rev 222887)
@@ -1,3 +1,14 @@
+2017-10-04  Nan Wang  <n_w...@apple.com>
+
+        AX: Make video objects accessible on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=177788
+        <rdar://problem/34778028>
+
+        Reviewed by Chris Fleizach.
+
+        * accessibility/ios-simulator/video-elements-ios-expected.txt: Added.
+        * accessibility/ios-simulator/video-elements-ios.html: Added.
+
 2017-10-04  Wenson Hsieh  <wenson_hs...@apple.com>
 
         Add basic support for the version of DataTransferItemList.add that takes a File

Added: trunk/LayoutTests/accessibility/ios-simulator/video-elements-ios-expected.txt (0 => 222887)


--- trunk/LayoutTests/accessibility/ios-simulator/video-elements-ios-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/video-elements-ios-expected.txt	2017-10-04 23:43:13 UTC (rev 222887)
@@ -0,0 +1,20 @@
+  
+This tests the video elements on iOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS video2 is null
+AXLabel: Video label, 9 seconds
+AXValue: 0 seconds
+PASS video.description is 'AXLabel: Video label, 9 seconds'
+PASS video.stringValue is 'AXValue: 0 seconds'
+PASS vid.paused is true
+PASS vid.paused is false
+PASS vid.paused is true
+PASS video.stringValue is 'AXValue: 2 seconds'
+PASS video.stringValue is 'AXValue: 1 seconds'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/accessibility/ios-simulator/video-elements-ios.html (0 => 222887)


--- trunk/LayoutTests/accessibility/ios-simulator/video-elements-ios.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/ios-simulator/video-elements-ios.html	2017-10-04 23:43:13 UTC (rev 222887)
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body id="body">
+
+<video width="320" height="240" playsinline id="video" aria-label="Video label">
+  <source src="" type="video/mp4">
+  Your browser does not support the video tag.
+</video>
+
+<video width="320" height="240" controls id="video2" aria-label="Video label2">
+  <source src="" type="video/mp4">
+  Your browser does not support the video tag.
+</video>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+
+    description("This tests the video elements on iOS.");
+
+    if (window.accessibilityController) {
+        jsTestIsAsync = true;
+    
+        var vid = document.getElementById("video"); 
+        var video = accessibilityController.accessibleElementById("video");
+        
+        // We shouldn't expose video elements with native controls
+        var video2 = accessibilityController.accessibleElementById("video2");
+        shouldBeNull("video2");
+        
+        vid._oncanplaythrough_ = function() {
+            debug(video.description);
+            debug(video.stringValue);
+            shouldBe("video.description", "'AXLabel: Video label, 9 seconds'");
+            shouldBe("video.stringValue", "'AXValue: 0 seconds'");
+            
+            // Test play and pause.
+            shouldBeTrue("vid.paused");
+            video.press();
+            shouldBeFalse("vid.paused");
+            video.press();
+            shouldBeTrue("vid.paused");
+            
+            // Test fast forward and rewind.
+            video.increment();
+            video.increment();
+            shouldBe("video.stringValue", "'AXValue: 2 seconds'");
+            video.decrement();
+            shouldBe("video.stringValue", "'AXValue: 1 seconds'");
+            
+            finishJSTest();
+        };
+        
+    }
+    
+</script>
+
+<script src=""
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (222886 => 222887)


--- trunk/Source/WebCore/ChangeLog	2017-10-04 23:27:45 UTC (rev 222886)
+++ trunk/Source/WebCore/ChangeLog	2017-10-04 23:43:13 UTC (rev 222887)
@@ -1,3 +1,62 @@
+2017-10-04  Nan Wang  <n_w...@apple.com>
+
+        AX: Make video objects accessible on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=177788
+        <rdar://problem/34778028>
+
+        Reviewed by Chris Fleizach.
+
+        Exposed certain <video> elements on iOS:
+        1. If they have no controls attribute set and have playsinline attribute set, that means
+           normally there are custom controls provided. 
+        2. Without autoplay attribute set. From iOS 10, with the motivation to improve performace by 
+           replacing GIF with <video>, elements will now honor the autoplay attribute if they
+           have no audio. So normally those <video> elements are not interactive.
+
+        Also provided functions to let iOS users interact with the video elements:
+        - Play/Pause: accessibilityActivate
+        - Fast forward: accessibilityIncrement
+        - Rewind: accessibilityDecrement
+
+        Test: accessibility/ios-simulator/video-elements-ios.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::createFromRenderer):
+        * accessibility/AccessibilityMediaObject.cpp: Added.
+        (WebCore::AccessibilityMediaObject::AccessibilityMediaObject):
+        (WebCore::AccessibilityMediaObject::~AccessibilityMediaObject):
+        (WebCore::AccessibilityMediaObject::create):
+        (WebCore::AccessibilityMediaObject::computeAccessibilityIsIgnored const):
+        (WebCore::AccessibilityMediaObject::mediaElement const):
+        (WebCore::AccessibilityMediaObject::stringValue const):
+        (WebCore::AccessibilityMediaObject::interactiveVideoDuration const):
+        (WebCore::AccessibilityMediaObject::mediaSeek):
+        (WebCore::AccessibilityMediaObject::toggleMute):
+        (WebCore::AccessibilityMediaObject::increment):
+        (WebCore::AccessibilityMediaObject::decrement):
+        (WebCore::AccessibilityMediaObject::press):
+        (WebCore::AccessibilityMediaObject::hasControlsAttributeSet const):
+        (WebCore::AccessibilityMediaObject::isPlaying const):
+        (WebCore::AccessibilityMediaObject::isMuted const):
+        (WebCore::AccessibilityMediaObject::isAutoplayEnabled const):
+        (WebCore::AccessibilityMediaObject::isPlayingInline const):
+        (WebCore::AccessibilityMediaObject::enterFullscreen const):
+        * accessibility/AccessibilityMediaObject.h: Added.
+        * accessibility/AccessibilityObject.cpp:
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::isMediaObject const):
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper accessibilityIsWebInteractiveVideo]):
+        (-[WebAccessibilityObjectWrapper interactiveVideoDescription]):
+        (-[WebAccessibilityObjectWrapper accessibilityIsMediaPlaying]):
+        (-[WebAccessibilityObjectWrapper accessibilityIsMediaMuted]):
+        (-[WebAccessibilityObjectWrapper accessibilityToggleMuteForMedia]):
+        (-[WebAccessibilityObjectWrapper accessibilityVideoEnterFullscreen]):
+        (-[WebAccessibilityObjectWrapper determineIsAccessibilityElement]):
+        (-[WebAccessibilityObjectWrapper stringValueShouldBeUsedInLabel]):
+        (-[WebAccessibilityObjectWrapper accessibilityLabel]):
+
 2017-10-04  Wenson Hsieh  <wenson_hs...@apple.com>
 
         Add basic support for the version of DataTransferItemList.add that takes a File

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (222886 => 222887)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-10-04 23:27:45 UTC (rev 222886)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-10-04 23:43:13 UTC (rev 222887)
@@ -5012,6 +5012,7 @@
 		A91C9FBF1B6586DE00AFFD54 /* AccessibilityTree.h in Headers */ = {isa = PBXBuildFile; fileRef = A91C9FBD1B6586DE00AFFD54 /* AccessibilityTree.h */; };
 		A91C9FC21B659A6700AFFD54 /* AccessibilityTreeItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A91C9FC01B659A6700AFFD54 /* AccessibilityTreeItem.cpp */; };
 		A91C9FC31B659A6700AFFD54 /* AccessibilityTreeItem.h in Headers */ = {isa = PBXBuildFile; fileRef = A91C9FC11B659A6700AFFD54 /* AccessibilityTreeItem.h */; };
+		A9787CB41F5F5C6600C551C6 /* AccessibilityMediaObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9787CB31F5F5C6500C551C6 /* AccessibilityMediaObject.cpp */; };
 		A9C6E4E30D745E05006442E9 /* DOMMimeType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9C6E4E10D745E05006442E9 /* DOMMimeType.cpp */; };
 		A9C6E4E40D745E05006442E9 /* DOMMimeType.h in Headers */ = {isa = PBXBuildFile; fileRef = A9C6E4E20D745E05006442E9 /* DOMMimeType.h */; };
 		A9C6E4E70D745E18006442E9 /* DOMMimeTypeArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9C6E4E50D745E18006442E9 /* DOMMimeTypeArray.cpp */; };
@@ -13524,6 +13525,8 @@
 		A91C9FBD1B6586DE00AFFD54 /* AccessibilityTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityTree.h; sourceTree = "<group>"; };
 		A91C9FC01B659A6700AFFD54 /* AccessibilityTreeItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityTreeItem.cpp; sourceTree = "<group>"; };
 		A91C9FC11B659A6700AFFD54 /* AccessibilityTreeItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilityTreeItem.h; sourceTree = "<group>"; };
+		A9787CB21F5F599200C551C6 /* AccessibilityMediaObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AccessibilityMediaObject.h; sourceTree = "<group>"; };
+		A9787CB31F5F5C6500C551C6 /* AccessibilityMediaObject.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityMediaObject.cpp; sourceTree = "<group>"; };
 		A9C6E4E10D745E05006442E9 /* DOMMimeType.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DOMMimeType.cpp; sourceTree = "<group>"; };
 		A9C6E4E20D745E05006442E9 /* DOMMimeType.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DOMMimeType.h; sourceTree = "<group>"; };
 		A9C6E4E50D745E18006442E9 /* DOMMimeTypeArray.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DOMMimeTypeArray.cpp; sourceTree = "<group>"; };
@@ -17697,6 +17700,8 @@
 				07B0ABCE1032242200FBDC33 /* AccessibilityMathMLElement.h */,
 				2981CAA4131822EC00D12F2A /* AccessibilityMediaControls.cpp */,
 				07B0113E1032242200FBDC33 /* AccessibilityMediaControls.h */,
+				A9787CB21F5F599200C551C6 /* AccessibilityMediaObject.h */,
+				A9787CB31F5F5C6500C551C6 /* AccessibilityMediaObject.cpp */,
 				76CDD2EC1103DA6600680521 /* AccessibilityMenuList.cpp */,
 				76CDD2ED1103DA6600680521 /* AccessibilityMenuList.h */,
 				76CDD2F01103DA6600680521 /* AccessibilityMenuListOption.cpp */,
@@ -31201,6 +31206,7 @@
 				29A812480FBB9CA900510293 /* AccessibilityObjectMac.mm in Sources */,
 				37F57AC31A50728F00876F98 /* AccessibilityProgressIndicator.cpp in Sources */,
 				37F57AC41A50729300876F98 /* AccessibilityRenderObject.cpp in Sources */,
+				A9787CB41F5F5C6600C551C6 /* AccessibilityMediaObject.cpp in Sources */,
 				37F57AC51A50729700876F98 /* AccessibilityScrollbar.cpp in Sources */,
 				37F57AC61A50729B00876F98 /* AccessibilityScrollView.cpp in Sources */,
 				37F57AC81A5072BC00876F98 /* AccessibilitySlider.cpp in Sources */,

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (222886 => 222887)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2017-10-04 23:27:45 UTC (rev 222886)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2017-10-04 23:43:13 UTC (rev 222887)
@@ -43,6 +43,7 @@
 #include "AccessibilityListBoxOption.h"
 #include "AccessibilityMathMLElement.h"
 #include "AccessibilityMediaControls.h"
+#include "AccessibilityMediaObject.h"
 #include "AccessibilityMenuList.h"
 #include "AccessibilityMenuListOption.h"
 #include "AccessibilityMenuListPopup.h"
@@ -444,6 +445,11 @@
     if (node && is<HTMLLabelElement>(node) && nodeHasRole(node, nullAtom()))
         return AccessibilityLabel::create(renderer);
 
+#if PLATFORM(IOS)
+    if (is<HTMLMediaElement>(node) && nodeHasRole(node, nullAtom()))
+        return AccessibilityMediaObject::create(renderer);
+#endif
+
 #if ENABLE(VIDEO)
     // media controls
     if (node && node->isMediaControlElement())

Added: trunk/Source/WebCore/accessibility/AccessibilityMediaObject.cpp (0 => 222887)


--- trunk/Source/WebCore/accessibility/AccessibilityMediaObject.cpp	                        (rev 0)
+++ trunk/Source/WebCore/accessibility/AccessibilityMediaObject.cpp	2017-10-04 23:43:13 UTC (rev 222887)
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 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 PLATFORM(IOS)
+#include "AccessibilityMediaObject.h"
+
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
+#include "HTMLVideoElement.h"
+#include "LocalizedStrings.h"
+
+
+namespace WebCore {
+    
+using namespace HTMLNames;
+
+AccessibilityMediaObject::AccessibilityMediaObject(RenderObject* renderer)
+    : AccessibilityRenderObject(renderer)
+{
+}
+
+AccessibilityMediaObject::~AccessibilityMediaObject()
+{
+}
+
+Ref<AccessibilityMediaObject> AccessibilityMediaObject::create(RenderObject* renderer)
+{
+    return adoptRef(*new AccessibilityMediaObject(renderer));
+}
+
+bool AccessibilityMediaObject::computeAccessibilityIsIgnored() const
+{
+    return accessibilityIsIgnoredByDefault();
+}
+
+HTMLMediaElement* AccessibilityMediaObject::mediaElement() const
+{
+    Node* node = this->node();
+    if (!is<HTMLMediaElement>(*node))
+        return nullptr;
+    return downcast<HTMLMediaElement>(node);
+}
+
+String AccessibilityMediaObject::stringValue() const
+{
+    if (HTMLMediaElement* element = mediaElement())
+        return localizedMediaTimeDescription(element->currentTime());
+    return AccessibilityRenderObject::stringValue();
+}
+
+String AccessibilityMediaObject::interactiveVideoDuration() const
+{
+    if (HTMLMediaElement* element = mediaElement())
+        return localizedMediaTimeDescription(element->duration());
+    return String();
+}
+    
+void AccessibilityMediaObject::mediaSeek(AXSeekDirection direction)
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return;
+    
+    // Step 5% each time.
+    const double seekStep = .05;
+    double current = element->currentTime();
+    double duration = element->duration();
+    double timeDelta = ceil(duration * seekStep);
+
+    double time = direction == AXSeekForward ? std::min(current + timeDelta, duration) : std::max(current - timeDelta, 0.0);
+    element->setCurrentTime(time);
+}
+
+void AccessibilityMediaObject::toggleMute()
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return;
+    
+    element->setMuted(!element->muted());
+}
+
+void AccessibilityMediaObject::increment()
+{
+    mediaSeek(AXSeekForward);
+}
+
+void AccessibilityMediaObject::decrement()
+{
+    mediaSeek(AXSeekBackward);
+}
+
+bool AccessibilityMediaObject::press()
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return false;
+    
+    // We can safely call the internal togglePlayState method, which doesn't check restrictions,
+    // because this method is only called from user interaction.
+    element->togglePlayState();
+    return true;
+}
+
+bool AccessibilityMediaObject::hasControlsAttributeSet() const
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return false;
+    
+    return element->controls();
+}
+    
+bool AccessibilityMediaObject::isPlaying() const
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return false;
+    
+    return element->isPlaying();
+}
+
+bool AccessibilityMediaObject::isMuted() const
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return false;
+    
+    return element->muted();
+}
+
+bool AccessibilityMediaObject::isAutoplayEnabled() const
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return false;
+    
+    return element->autoplay();
+}
+
+bool AccessibilityMediaObject::isPlayingInline() const
+{
+    HTMLMediaElement* element = mediaElement();
+    if (!element)
+        return false;
+    
+    return !element->mediaSession().requiresFullscreenForVideoPlayback(*element);
+}
+
+void AccessibilityMediaObject::enterFullscreen() const
+{
+    Node* node = this->node();
+    if (!is<HTMLVideoElement>(node))
+        return;
+    
+    HTMLVideoElement* element = downcast<HTMLVideoElement>(node);
+    element->enterFullscreen();
+}
+    
+} // namespace WebCore
+
+#endif // PLATFORM(IOS)

Added: trunk/Source/WebCore/accessibility/AccessibilityMediaObject.h (0 => 222887)


--- trunk/Source/WebCore/accessibility/AccessibilityMediaObject.h	                        (rev 0)
+++ trunk/Source/WebCore/accessibility/AccessibilityMediaObject.h	2017-10-04 23:43:13 UTC (rev 222887)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#if PLATFORM(IOS)
+
+#include "AccessibilityRenderObject.h"
+
+namespace WebCore {
+    
+class AccessibilityMediaObject final : public AccessibilityRenderObject {
+public:
+    static Ref<AccessibilityMediaObject> create(RenderObject*);
+    virtual ~AccessibilityMediaObject();
+    
+    void enterFullscreen() const;
+    void toggleMute();
+    
+    bool hasControlsAttributeSet() const;
+    String interactiveVideoDuration() const;
+    bool isPlaying() const;
+    bool isAutoplayEnabled() const;
+    bool isPlayingInline() const;
+    bool isMuted() const;
+
+private:
+    enum AXSeekDirection { AXSeekForward, AXSeekBackward };
+    explicit AccessibilityMediaObject(RenderObject*);
+    bool computeAccessibilityIsIgnored() const final;
+    bool isMediaObject() const final { return true; }
+    
+    String stringValue() const override;
+    bool press() override;
+    void increment() override;
+    void decrement() override;
+    
+    HTMLMediaElement* mediaElement() const;
+    
+    void mediaSeek(AXSeekDirection);
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_ACCESSIBILITY(AccessibilityMediaObject, isMediaObject())
+#endif // PLATFORM(IOS)

Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.cpp (222886 => 222887)


--- trunk/Source/WebCore/accessibility/AccessibilityObject.cpp	2017-10-04 23:27:45 UTC (rev 222886)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.cpp	2017-10-04 23:43:13 UTC (rev 222887)
@@ -46,6 +46,7 @@
 #include "HTMLDetailsElement.h"
 #include "HTMLFormControlElement.h"
 #include "HTMLInputElement.h"
+#include "HTMLMediaElement.h"
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "HitTestResult.h"

Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.h (222886 => 222887)


--- trunk/Source/WebCore/accessibility/AccessibilityObject.h	2017-10-04 23:27:45 UTC (rev 222886)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.h	2017-10-04 23:43:13 UTC (rev 222887)
@@ -563,6 +563,7 @@
     virtual bool isSpinButtonPart() const { return false; }
     virtual bool isMockObject() const { return false; }
     virtual bool isMediaControlLabel() const { return false; }
+    virtual bool isMediaObject() const { return false; }
     bool isSwitch() const { return roleValue() == SwitchRole; }
     bool isToggleButton() const { return roleValue() == ToggleButtonRole; }
     bool isTextControl() const;

Modified: trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm (222886 => 222887)


--- trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2017-10-04 23:27:45 UTC (rev 222886)
+++ trunk/Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm	2017-10-04 23:43:13 UTC (rev 222887)
@@ -29,6 +29,7 @@
 #if HAVE(ACCESSIBILITY) && PLATFORM(IOS)
 
 #import "AccessibilityAttachment.h"
+#import "AccessibilityMediaObject.h"
 #import "AccessibilityRenderObject.h"
 #import "AccessibilityScrollView.h"
 #import "AccessibilityTable.h"
@@ -665,6 +666,70 @@
     return traits;
 }
 
+- (BOOL)accessibilityIsWebInteractiveVideo
+{
+    if (![self _prepareAccessibilityCall])
+        return NO;
+    
+    // Only make the video object interactive if it plays inline and has no native controls.
+    if (m_object->roleValue() != VideoRole || !is<AccessibilityMediaObject>(m_object))
+        return NO;
+    
+    AccessibilityMediaObject* mediaObject = downcast<AccessibilityMediaObject>(m_object);
+    return !mediaObject->isAutoplayEnabled() && mediaObject->isPlayingInline() && !downcast<AccessibilityMediaObject>(m_object)->hasControlsAttributeSet();
+}
+
+- (NSString *)interactiveVideoDescription
+{
+    if (!is<AccessibilityMediaObject>(m_object))
+        return nil;
+    return downcast<AccessibilityMediaObject>(m_object)->interactiveVideoDuration();
+}
+
+- (BOOL)accessibilityIsMediaPlaying
+{
+    if (![self _prepareAccessibilityCall])
+        return NO;
+    
+    if (!is<AccessibilityMediaObject>(m_object))
+        return NO;
+    
+    return downcast<AccessibilityMediaObject>(m_object)->isPlaying();
+}
+
+- (BOOL)accessibilityIsMediaMuted
+{
+    if (![self _prepareAccessibilityCall])
+        return NO;
+    
+    if (!is<AccessibilityMediaObject>(m_object))
+        return NO;
+    
+    return downcast<AccessibilityMediaObject>(m_object)->isMuted();
+}
+
+- (void)accessibilityToggleMuteForMedia
+{
+    if (![self _prepareAccessibilityCall])
+        return;
+    
+    if (!is<AccessibilityMediaObject>(m_object))
+        return;
+
+    downcast<AccessibilityMediaObject>(m_object)->toggleMute();
+}
+
+- (void)accessibilityVideoEnterFullscreen
+{
+    if (![self _prepareAccessibilityCall])
+        return;
+    
+    if (!is<AccessibilityMediaObject>(m_object))
+        return;
+    
+    downcast<AccessibilityMediaObject>(m_object)->enterFullscreen();
+}
+
 - (uint64_t)_accessibilityTextEntryTraits
 {
     uint64_t traits = [self _axTextEntryTrait];
@@ -828,6 +893,9 @@
                 return true;
             return false;
             
+        case VideoRole:
+            return [self accessibilityIsWebInteractiveVideo];
+            
         // Links can sometimes be elements (when they only contain static text or don't contain anything).
         // They should not be elements when containing text and other types.
         case WebCoreLinkRole:
@@ -944,7 +1012,6 @@
         case ToolbarRole:
         case UnknownRole:
         case UserInterfaceTooltipRole:
-        case VideoRole:
         case WebApplicationRole:
         case WebAreaRole:
         case WindowRole:
@@ -975,6 +1042,8 @@
         return NO;
     if (m_object->isFileUploadButton())
         return NO;
+    if ([self accessibilityIsWebInteractiveVideo])
+        return NO;
 
     return YES;
 }
@@ -1040,6 +1109,7 @@
     NSString *axTitle = [self baseAccessibilityTitle];
     NSString *axDescription = [self baseAccessibilityDescription];
     NSString *landmarkDescription = [self ariaLandmarkRoleDescription];
+    NSString *interactiveVideoDescription = [self interactiveVideoDescription];
     
     // We should expose the value of the input type date or time through AXValue instead of AXTitle.
     if (m_object->isInputTypePopupButton() && [axTitle isEqualToString:[self accessibilityValue]])
@@ -1061,6 +1131,7 @@
         appendStringToResult(result, valueLabel);
     }
     appendStringToResult(result, landmarkDescription);
+    appendStringToResult(result, interactiveVideoDescription);
     
     return [result length] ? result : nil;
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to