Title: [203913] trunk
Revision
203913
Author
n_w...@apple.com
Date
2016-07-29 12:11:29 -0700 (Fri, 29 Jul 2016)

Log Message

AX: Media controls accessibility improvement
https://bugs.webkit.org/show_bug.cgi?id=160223
<rdar://problem/27558003>

Reviewed by Eric Carlson.

Source/WebCore:

Changes in this patch:
1. Added a change observer for volume slider so that it will handle accessibility
   increment/decrement functions correctly.
2. Update the timer div's aria-label when time changes.
3. Added a keydown handler for left/right arrow adjusting the timeline, so that the
   value increment/decrement in a reasonable way.
4. Changed the mute button's role to checkbox since it only has on/off states.

Test: media/media-controls-accessibility.html

* Modules/mediacontrols/mediaControlsApple.js:
(Controller.prototype.createControls):
(Controller.prototype.updatePictureInPictureButton):
(Controller.prototype.timelineStepFromVideoDuration):
(Controller.prototype.incrementTimelineValue):
(Controller.prototype.decrementTimelineValue):
(Controller.prototype.showInlinePlaybackPlaceholderWhenSafe):
(Controller.prototype.handleTimelineMouseUp):
(Controller.prototype.handleTimelineKeyDown):
(Controller.prototype.handleMuteButtonClicked):
(Controller.prototype.handleMinButtonClicked):
(Controller.prototype.handleMaxButtonClicked):
(Controller.prototype.updateVideoVolume):
(Controller.prototype.handleVolumeSliderInput):
(Controller.prototype.handleVolumeSliderChange):
(Controller.prototype.handleVolumeSliderMouseDown):
(Controller.prototype.updateTime):
(Controller.prototype.updateControlsWhileScrubbing):
(Controller.prototype.updateVolume):

LayoutTests:

* accessibility/mac/video-volume-slider-accessibility-expected.txt:
* accessibility/mac/video-volume-slider-accessibility.html:
* accessibility/media-emits-object-replacement-expected.txt:
* media/media-controls-accessibility-expected.txt: Added.
* media/media-controls-accessibility.html: Added.
* platform/efl/accessibility/media-element-expected.txt:
* platform/efl/accessibility/media-emits-object-replacement-expected.txt:
* platform/gtk/accessibility/media-element-expected.txt:
* platform/gtk/accessibility/media-emits-object-replacement-expected.txt:
* platform/mac/accessibility/media-element-expected.txt:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (203912 => 203913)


--- trunk/LayoutTests/ChangeLog	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/ChangeLog	2016-07-29 19:11:29 UTC (rev 203913)
@@ -1,3 +1,22 @@
+2016-07-29  Nan Wang  <n_w...@apple.com>
+
+        AX: Media controls accessibility improvement
+        https://bugs.webkit.org/show_bug.cgi?id=160223
+        <rdar://problem/27558003>
+
+        Reviewed by Eric Carlson.
+
+        * accessibility/mac/video-volume-slider-accessibility-expected.txt:
+        * accessibility/mac/video-volume-slider-accessibility.html:
+        * accessibility/media-emits-object-replacement-expected.txt:
+        * media/media-controls-accessibility-expected.txt: Added.
+        * media/media-controls-accessibility.html: Added.
+        * platform/efl/accessibility/media-element-expected.txt:
+        * platform/efl/accessibility/media-emits-object-replacement-expected.txt:
+        * platform/gtk/accessibility/media-element-expected.txt:
+        * platform/gtk/accessibility/media-emits-object-replacement-expected.txt:
+        * platform/mac/accessibility/media-element-expected.txt:
+
 2016-07-29  Daniel Bates  <daba...@apple.com>
 
         Unskip some media tests on iOS when run in WebKitTestRunner

Modified: trunk/LayoutTests/accessibility/mac/video-volume-slider-accessibility-expected.txt (203912 => 203913)


--- trunk/LayoutTests/accessibility/mac/video-volume-slider-accessibility-expected.txt	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/accessibility/mac/video-volume-slider-accessibility-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -5,7 +5,7 @@
 
 
 PASS slider.valueDescription is 'AXValueDescription: 100%'
-PASS slider.intValue.toFixed(2) is '0.95'
+PASS slider.valueDescription is 'AXValueDescription: 95%'
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/accessibility/mac/video-volume-slider-accessibility.html (203912 => 203913)


--- trunk/LayoutTests/accessibility/mac/video-volume-slider-accessibility.html	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/accessibility/mac/video-volume-slider-accessibility.html	2016-07-29 19:11:29 UTC (rev 203913)
@@ -40,7 +40,7 @@
           
           // Then decrement the slider and check the step is 0.05.
           slider.decrement();
-          shouldBe("slider.intValue.toFixed(2)", "'0.95'");
+          shouldBe("slider.valueDescription", "'AXValueDescription: 95%'");
 }
 
 </script>

Modified: trunk/LayoutTests/accessibility/media-emits-object-replacement-expected.txt (203912 => 203913)


--- trunk/LayoutTests/accessibility/media-emits-object-replacement-expected.txt	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/accessibility/media-emits-object-replacement-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -17,7 +17,7 @@
                 AXRole: AXGroup AXValue: 
                 AXRole: AXSlider AXValue: 1
                     AXRole: AXValueIndicator AXValue: 1
-                AXRole: AXButton AXValue: 
+                AXRole: AXCheckBox AXValue: 0
         AXRole: AXStaticText AXValue:  b
     AXRole: AXGroup AXValue: 
     AXRole: AXGroup AXValue: 
@@ -34,7 +34,7 @@
                 AXRole: AXGroup AXValue: 
                 AXRole: AXSlider AXValue: 1
                     AXRole: AXValueIndicator AXValue: 1
-                AXRole: AXButton AXValue: 
+                AXRole: AXCheckBox AXValue: 0
         AXRole: AXStaticText AXValue:  b
     AXRole: AXGroup AXValue: 
 This tests ensures that if video or audio tags are used, they will emit an object replacement character in a range for string operation.

Added: trunk/LayoutTests/media/media-controls-accessibility-expected.txt (0 => 203913)


--- trunk/LayoutTests/media/media-controls-accessibility-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-controls-accessibility-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -0,0 +1,27 @@
+
+This tests that media controls have correct accessibility information.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+elapsedTimer.description: AXDescription: Elapsed 00:00
+remainingTimer.description: AXDescription: Remaining -00:06
+
+muteButton.description: AXDescription: Mute
+muteButton.role: AXRole: AXCheckBox
+muteButton.stringValue: AXValue: 0
+press muteButton
+muteButton.stringValue: AXValue: 1
+
+timeline.value: 0.5
+timeline.value: 0.0
+
+RUN(video.load())
+EVENT(canplaythrough)
+EVENT(seeked)
+EVENT(seeked)
+END OF TEST
+

Added: trunk/LayoutTests/media/media-controls-accessibility.html (0 => 203913)


--- trunk/LayoutTests/media/media-controls-accessibility.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-controls-accessibility.html	2016-07-29 19:11:29 UTC (rev 203913)
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+<video id="video" controls></video>
+<p id="description"></p>
+<div id="console"></div>
+<head>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</head>
+
+<script>
+
+description("This tests that media controls have correct accessibility information.");
+
+if (window.accessibilityController) {
+    testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1); 
+    video.src = "" "content/test");
+    
+    var videoElement;
+    var elapsedTimer, remainingTimer, timeline, muteButton;
+    var rightArrow = true;
+    run("video.load()");
+    waitForEvent("canplaythrough", function () {
+        videoElement = accessibilityController.accessibleElementById("video");
+        // Elapsed and remaining timer have the right ax label.
+        elapsedTimer = videoElement.childAtIndex(0).childAtIndex(3);
+        remainingTimer = videoElement.childAtIndex(0).childAtIndex(5);
+        debug("elapsedTimer.description: " + elapsedTimer.description);
+        debug("remainingTimer.description: " + remainingTimer.description + "\n");
+              
+        // Mute button should be a checkbox with on/off state.
+        muteButton = videoElement.childAtIndex(0).childAtIndex(9);
+        debug("muteButton.description: " + muteButton.description);
+        debug("muteButton.role: " + muteButton.role);
+        debug("muteButton.stringValue: " + muteButton.stringValue);
+        debug("press muteButton");
+        muteButton.press();
+        debug("muteButton.stringValue: " + muteButton.stringValue + "\n");
+              
+        // Left/Right arrow key should have 0.5 second step on timeline. 
+        checkTimeLineValue(rightArrow);
+    }); 
+    
+    waitForEvent("seeked", function () {
+        var timeline = mediaControlsElement(internals.shadowRoot(video).firstChild.firstChild, '-webkit-media-controls-timeline');
+        if (!timeline)
+            throw "Failed to find -webkit-media-controls-timeline";
+        debug("timeline.value: " + parseFloat(timeline.value).toFixed(1));
+        if (rightArrow) {
+            rightArrow = false;
+            checkTimeLineValue(rightArrow);
+        } else {
+            debug("");
+            endTest();
+        }
+    });
+}
+     
+function checkTimeLineValue(isRightArrow)
+{
+    var timeline = mediaControlsElement(internals.shadowRoot(video).firstChild.firstChild, '-webkit-media-controls-timeline');
+    if (!timeline)
+        throw "Failed to find -webkit-media-controls-timeline";
+        
+    timeline.focus();
+    if (isRightArrow) {
+        eventSender.keyDown("rightArrow");
+    } else {
+        eventSender.keyDown("leftArrow");
+    }
+}
+
+</script>
+
+<script src=""
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/platform/efl/accessibility/media-element-expected.txt (203912 => 203913)


--- trunk/LayoutTests/platform/efl/accessibility/media-element-expected.txt	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/platform/efl/accessibility/media-element-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -21,7 +21,7 @@
             role: AXRole: AXButton
 
 
-            title: AXTitle: Elapsed
+            title: AXTitle: Elapsed 00:00
             role: AXRole: AXTimer
 
 
@@ -33,7 +33,7 @@
             role: AXRole: AXSlider
 
 
-            title: AXTitle: Remaining
+            title: AXTitle: Remaining -00:06
             role: AXRole: AXTimer
 
 
@@ -46,7 +46,7 @@
 
 
             title: AXTitle: Mute
-            role: AXRole: AXButton
+            role: AXRole: AXCheckbox
 
 
             title: AXTitle: Display Full Screen

Modified: trunk/LayoutTests/platform/efl/accessibility/media-emits-object-replacement-expected.txt (203912 => 203913)


--- trunk/LayoutTests/platform/efl/accessibility/media-emits-object-replacement-expected.txt	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/platform/efl/accessibility/media-emits-object-replacement-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -7,7 +7,7 @@
         AXRole: AXVideo 
             AXRole: AXToolbar 
                 AXRole: AXToolbar 
-                    AXRole: AXButton 
+                    AXRole: AXCheckBox 
                     AXRole: AXSlider 
     AXRole: AXGroup AXValue: <\n>
     AXRole: AXSection AXValue: a <obj> b
@@ -14,7 +14,7 @@
         AXRole: AXAudio 
             AXRole: AXToolbar 
                 AXRole: AXToolbar 
-                    AXRole: AXButton 
+                    AXRole: AXCheckBox 
                     AXRole: AXSlider 
     AXRole: AXSection AXValue: End of test
 This tests ensures that if video or audio tags are used, they will emit an object replacement character in a range for string operation.

Modified: trunk/LayoutTests/platform/gtk/accessibility/media-element-expected.txt (203912 => 203913)


--- trunk/LayoutTests/platform/gtk/accessibility/media-element-expected.txt	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/platform/gtk/accessibility/media-element-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -21,7 +21,7 @@
             role: AXRole: AXSlider
 
 
-            title: AXTitle: Remaining
+            title: AXTitle: Remaining -00:06
             role: AXRole: AXTimer
 
 
@@ -30,7 +30,7 @@
 
 
             title: AXTitle: Mute
-            role: AXRole: AXButton
+            role: AXRole: AXCheckbox
 
 
             title: AXTitle: Volume

Modified: trunk/LayoutTests/platform/gtk/accessibility/media-emits-object-replacement-expected.txt (203912 => 203913)


--- trunk/LayoutTests/platform/gtk/accessibility/media-emits-object-replacement-expected.txt	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/platform/gtk/accessibility/media-emits-object-replacement-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -6,7 +6,7 @@
     AXRole: AXSection AXValue: a <obj> b
         AXRole: AXVideo 
             AXRole: AXToolbar 
-                AXRole: AXButton 
+                AXRole: AXCheckBox 
                 AXRole: AXSlider 
                 AXRole: AXTimer AXValue: 00:00
     AXRole: AXSection AXValue: <\n>
@@ -13,7 +13,7 @@
     AXRole: AXSection AXValue: a <obj> b
         AXRole: AXAudio 
             AXRole: AXToolbar 
-                AXRole: AXButton 
+                AXRole: AXCheckBox 
                 AXRole: AXSlider 
                 AXRole: AXTimer AXValue: 00:00
     AXRole: AXSection AXValue: End of test

Modified: trunk/LayoutTests/platform/mac/accessibility/media-element-expected.txt (203912 => 203913)


--- trunk/LayoutTests/platform/mac/accessibility/media-element-expected.txt	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/LayoutTests/platform/mac/accessibility/media-element-expected.txt	2016-07-29 19:11:29 UTC (rev 203913)
@@ -34,7 +34,7 @@
             role: AXRole: AXButton
 
 
-            description: AXDescription: Elapsed
+            description: AXDescription: Elapsed 00:00
             role: AXRole: AXGroup
             subrole: AXSubrole: AXApplicationTimer
 
@@ -55,7 +55,7 @@
                 role: AXRole: AXValueIndicator
 
 
-            description: AXDescription: Remaining
+            description: AXDescription: Remaining -00:06
             role: AXRole: AXGroup
             subrole: AXSubrole: AXApplicationTimer
 
@@ -85,7 +85,7 @@
 
 
             description: AXDescription: Mute
-            role: AXRole: AXButton
+            role: AXRole: AXCheckBox
 
 
             description: AXDescription: Display Full Screen

Modified: trunk/Source/WebCore/ChangeLog (203912 => 203913)


--- trunk/Source/WebCore/ChangeLog	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/Source/WebCore/ChangeLog	2016-07-29 19:11:29 UTC (rev 203913)
@@ -1,3 +1,41 @@
+2016-07-29  Nan Wang  <n_w...@apple.com>
+
+        AX: Media controls accessibility improvement
+        https://bugs.webkit.org/show_bug.cgi?id=160223
+        <rdar://problem/27558003>
+
+        Reviewed by Eric Carlson.
+
+        Changes in this patch:
+        1. Added a change observer for volume slider so that it will handle accessibility 
+           increment/decrement functions correctly.
+        2. Update the timer div's aria-label when time changes.
+        3. Added a keydown handler for left/right arrow adjusting the timeline, so that the
+           value increment/decrement in a reasonable way.
+        4. Changed the mute button's role to checkbox since it only has on/off states.
+
+        Test: media/media-controls-accessibility.html
+
+        * Modules/mediacontrols/mediaControlsApple.js:
+        (Controller.prototype.createControls):
+        (Controller.prototype.updatePictureInPictureButton):
+        (Controller.prototype.timelineStepFromVideoDuration):
+        (Controller.prototype.incrementTimelineValue):
+        (Controller.prototype.decrementTimelineValue):
+        (Controller.prototype.showInlinePlaybackPlaceholderWhenSafe):
+        (Controller.prototype.handleTimelineMouseUp):
+        (Controller.prototype.handleTimelineKeyDown):
+        (Controller.prototype.handleMuteButtonClicked):
+        (Controller.prototype.handleMinButtonClicked):
+        (Controller.prototype.handleMaxButtonClicked):
+        (Controller.prototype.updateVideoVolume):
+        (Controller.prototype.handleVolumeSliderInput):
+        (Controller.prototype.handleVolumeSliderChange):
+        (Controller.prototype.handleVolumeSliderMouseDown):
+        (Controller.prototype.updateTime):
+        (Controller.prototype.updateControlsWhileScrubbing):
+        (Controller.prototype.updateVolume):
+
 2016-07-29  Mark Lam  <mark....@apple.com>
 
         Remove an unused line of code.

Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js (203912 => 203913)


--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js	2016-07-29 18:58:23 UTC (rev 203912)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js	2016-07-29 19:11:29 UTC (rev 203913)
@@ -421,6 +421,7 @@
         this.listenFor(timeline, 'mousemove', this.handleTimelineMouseMove);
         this.listenFor(timeline, 'mousedown', this.handleTimelineMouseDown);
         this.listenFor(timeline, 'mouseup', this.handleTimelineMouseUp);
+        this.listenFor(timeline, 'keydown', this.handleTimelineKeyDown);
         timeline.step = .01;
 
         this.timelineContextName = "_webkit-media-controls-timeline-" + this.host.generateUUID();
@@ -447,6 +448,8 @@
         var muteButton = this.controls.muteButton = document.createElement('button');
         muteButton.setAttribute('pseudo', '-webkit-media-controls-mute-button');
         muteButton.setAttribute('aria-label', this.UIString('Mute'));
+        // Make the mute button a checkbox since it only has on/off states.
+        muteButton.setAttribute('role', 'checkbox');
         this.listenFor(muteButton, 'click', this.handleMuteButtonClicked);
 
         var minButton = this.controls.minButton = document.createElement('button');
@@ -477,6 +480,7 @@
         volume.max = 1;
         volume.step = .05;
         this.listenFor(volume, 'input', this.handleVolumeSliderInput);
+        this.listenFor(volume, 'change', this.handleVolumeSliderChange);
         this.listenFor(volume, 'mousedown', this.handleVolumeSliderMouseDown);
         this.listenFor(volume, 'mouseup', this.handleVolumeSliderMouseUp);
 
@@ -863,7 +867,37 @@
         } else
             this.controls.pictureInPictureButton.classList.add(this.ClassNames.hidden);
     },
+    
+    timelineStepFromVideoDuration: function()
+    {
+        var step;
+        var duration = this.video.duration;
+        if (duration <= 10)
+            step = .5;
+        else if (duration <= 60)
+            step = 1;
+        else if (duration <= 600)
+            step = 10;
+        else if (duration <= 3600)
+            step = 30;
+        else
+            step = 60;
+        
+        return step;
+    },
+    
+    incrementTimelineValue: function()
+    {
+        var value = this.video.currentTime + this.timelineStepFromVideoDuration();
+        return value > this.video.duration ? this.video.duration : value;
+    },
 
+    decrementTimelineValue: function()
+    {
+        var value = this.video.currentTime - this.timelineStepFromVideoDuration();
+        return value < 0 ? 0 : value;
+    },
+
     showInlinePlaybackPlaceholderWhenSafe: function() {
         if (this.presentationMode() != 'picture-in-picture')
             return;
@@ -1122,12 +1156,22 @@
     {
         this.scrubbing = false;
     },
+    
+    handleTimelineKeyDown: function(event)
+    {
+        if (event.keyCode == this.KeyCodes.left)
+            this.controls.timeline.value = this.decrementTimelineValue();
+        else if (event.keyCode == this.KeyCodes.right)
+            this.controls.timeline.value = this.incrementTimelineValue();
+    },
 
     handleMuteButtonClicked: function(event)
     {
         this.video.muted = !this.video.muted;
         if (this.video.muted)
-            this.controls.muteButton.setAttribute('aria-label', this.UIString('Unmute'));
+            this.controls.muteButton.setAttribute('aria-checked', 'true');
+        else
+            this.controls.muteButton.setAttribute('aria-checked', 'false');
         this.drawVolumeBackground();
         return true;
     },
@@ -1141,7 +1185,7 @@
     {
         if (this.video.muted) {
             this.video.muted = false;
-            this.controls.muteButton.setAttribute('aria-label', this.UIString('Mute'));
+            this.controls.muteButton.setAttribute('aria-checked', 'false');
         }
         this.video.volume = 0;
         return true;
@@ -1151,21 +1195,31 @@
     {
         if (this.video.muted) {
             this.video.muted = false;
-            this.controls.muteButton.setAttribute('aria-label', this.UIString('Mute'));
+            this.controls.muteButton.setAttribute('aria-checked', 'false');
         }
         this.video.volume = 1;
     },
 
-    handleVolumeSliderInput: function(event)
+    updateVideoVolume: function()
     {
         if (this.video.muted) {
             this.video.muted = false;
-            this.controls.muteButton.setAttribute('aria-label', this.UIString('Mute'));
+            this.controls.muteButton.setAttribute('aria-checked', 'false');
         }
         this.video.volume = this.controls.volume.value;
-        this.controls.volume.setAttribute('aria-valuetext', this.controls.volume.value * 100 + '%');
+        this.controls.volume.setAttribute('aria-valuetext', `${parseInt(this.controls.volume.value * 100)}%`);
+    },
+
+    handleVolumeSliderInput: function(event)
+    {
+        this.updateVideoVolume();
         this.drawVolumeBackground();
     },
+    
+    handleVolumeSliderChange: function(event)
+    {
+        this.updateVideoVolume();
+    },
 
     handleVolumeSliderMouseDown: function(event)
     {
@@ -1709,8 +1763,10 @@
         var currentTime = this.video.currentTime;
         var timeRemaining = currentTime - this.video.duration;
         this.currentTimeClone.innerText = this.controls.currentTime.innerText = this.formatTime(currentTime);
+        this.controls.currentTime.setAttribute('aria-label', `${this.UIString('Elapsed')} ${this.formatTime(currentTime)}`);
         this.controls.timeline.value = this.video.currentTime;
         this.remainingTimeClone.innerText = this.controls.remainingTime.innerText = this.formatTime(timeRemaining);
+        this.controls.remainingTime.setAttribute('aria-label', `${this.UIString('Remaining')} ${this.formatTime(timeRemaining)}`);
     },
     
     updateControlsWhileScrubbing: function()
@@ -2084,7 +2140,7 @@
             this.controls.muteButton.classList.remove(this.ClassNames.muted);
             this.controls.volume.value = this.video.volume;
         }
-        this.controls.volume.setAttribute('aria-valuetext', this.controls.volume.value * 100 + '%');
+        this.controls.volume.setAttribute('aria-valuetext', `${parseInt(this.controls.volume.value * 100)}%`);
         this.drawVolumeBackground();
     },
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to