Update backgrounds of sliders for inline media controls on OS X.
authorroger_fong@apple.com <roger_fong@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Mar 2015 22:54:50 +0000 (22:54 +0000)
committerroger_fong@apple.com <roger_fong@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Mar 2015 22:54:50 +0000 (22:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142188.
<rdar://problem/20012413>
Reviewed by Dean Jackson.
Don’t use CSS to draw volume and timeline slider backgrounds.
* Modules/mediacontrols/mediaControlsApple.css:
(video::-webkit-media-controls-volume-slider):
(audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb):
(audio::-webkit-media-controls-timeline):
(audio::-webkit-media-controls-timeline::-webkit-slider-thumb):
(audio::-webkit-media-controls-panel .thumbnail-track):
(audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb:active::-webkit-slider-thumb): Deleted.
(audio::-webkit-media-controls-timeline:active::-webkit-slider-thumb,): Deleted.
Draw volume and timeline slider backgrounds using 2d canvases.
* Modules/mediacontrols/mediaControlsApple.js:
(Controller.prototype.createControls):
(Controller.prototype.handleVolumeSliderInput):
(Controller.prototype.addRoundedRect):
(Controller.prototype.drawTimelineBackground):
(Controller.prototype.drawVolumeBackground):
(Controller.prototype.showControls):
* Modules/mediacontrols/mediaControlsiOS.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@180898 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/Modules/mediacontrols/mediaControlsApple.css
Source/WebCore/Modules/mediacontrols/mediaControlsApple.js
Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js

index f743792..c7cf731 100644 (file)
@@ -1,3 +1,32 @@
+2015-03-02  Roger Fong  <roger_fong@apple.com>
+
+        Update backgrounds of sliders for inline media controls on OS X.
+        https://bugs.webkit.org/show_bug.cgi?id=142188.
+        <rdar://problem/20012413>
+
+        Reviewed by Dean Jackson.
+
+        Don’t use CSS to draw volume and timeline slider backgrounds.
+        * Modules/mediacontrols/mediaControlsApple.css:
+        (video::-webkit-media-controls-volume-slider):
+        (audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb):
+        (audio::-webkit-media-controls-timeline):
+        (audio::-webkit-media-controls-timeline::-webkit-slider-thumb):
+        (audio::-webkit-media-controls-panel .thumbnail-track):
+        (audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb:active::-webkit-slider-thumb): Deleted.
+        (audio::-webkit-media-controls-timeline:active::-webkit-slider-thumb,): Deleted.
+
+        Draw volume and timeline slider backgrounds using 2d canvases.
+        * Modules/mediacontrols/mediaControlsApple.js:
+        (Controller.prototype.createControls):
+        (Controller.prototype.handleVolumeSliderInput):
+        (Controller.prototype.addRoundedRect):
+        (Controller.prototype.drawTimelineBackground):
+        (Controller.prototype.drawVolumeBackground):
+        (Controller.prototype.showControls):
+        * Modules/mediacontrols/mediaControlsiOS.js:
+        (ControllerIOS.prototype.addRoundedRect): Deleted.
+
 2015-03-01  Roger Fong  <roger_fong@apple.com>
 
         Update inline media element controls appearance Part 1.
index 58fc005..e173106 100644 (file)
@@ -206,43 +206,16 @@ video::-webkit-media-controls-volume-slider {
     margin-right: 10px !important;
 
     background-color: transparent !important;
-    background-image: -webkit-linear-gradient(
-        top,
-        rgba(15, 15, 15, .85) 0,
-        rgba(23, 23, 23, .85) 50%,
-        rgba(15, 15, 15, .85) 100%
-    ) !important;
-    border: 1px solid rgba(0, 0, 0, 0.875) !important;
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
 }
 
 video::-webkit-media-controls-volume-slider::-webkit-slider-thumb,
 audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb {
     -webkit-appearance: none !important;
-    width: 8px !important;
-    height: 8px !important;
-    border-radius: 4px !important;
-    background-color: transparent !important;
-
-    /* rotateZ() forces the layer into compositing mode.
-    Slider thumbs are small, so forcing a compositing layer is inexpensive,
-       and it keeps the slider from having to repaint while sliding. */
-    -webkit-transform: rotateZ(0) !important;
-    background-image: -webkit-linear-gradient(
-        left,
-        rgba(99, 99, 99, 1),
-        rgba(144, 144, 144, 1)
-    ) !important;
-    box-shadow: inset -1px 0 0 rgba(255, 255, 255, .5), 0 1px rgba(255, 255, 255, .14) !important;
-}
-video::-webkit-media-controls-volume-slider::-webkit-slider-thumb::-webkit-slider-thumb:active,
-video::-webkit-media-controls-volume-slider::-webkit-slider-thumb:active::-webkit-slider-thumb,
-audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb::-webkit-slider-thumb:active,
-audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb:active::-webkit-slider-thumb {
-    background-image: -webkit-linear-gradient(
-        right top,
-        rgba(160, 160, 160, 1),
-        rgba(221, 221, 221, 1)
-    ) !important;
+    width: 7px !important;
+    height: 7px !important;
+    visibility: hidden;
 }
 
 video::-webkit-media-controls-mute-button.muted,
@@ -395,47 +368,20 @@ video::-webkit-media-controls-timeline,
 audio::-webkit-media-controls-timeline {
     -webkit-appearance: none !important;
     -webkit-flex: 1 1 0 !important;
-    height: 9px !important;
+    height: 17px !important;
     margin: 0 !important;
-    background-size: 100% 9px !important;
+    background-size: 100% 100% !important;
+    background-repeat: no-repeat;
+    background-color: transparent;
 
-    border-radius: 4.5px !important;
-    background-color: rgb(74, 74, 74) !important;
-    box-shadow: inset -1px 0 0 rgba(0, 0, 0, .68), 0 1px rgba(255, 255, 255, .08) !important;
 }
 video::-webkit-media-controls-timeline::-webkit-slider-thumb,
 audio::-webkit-media-controls-timeline::-webkit-slider-thumb {
     -webkit-appearance: none !important;
-    width:6px !important;
-    height: 6px !important;
-    background-color: white !important;
-
-    /* rotateZ() forces the layer into compositing mode.
-    Slider thumbs are small, so forcing a compositing layer is inexpensive,
-       and it keeps the slider from having to repaint while sliding. */
-    -webkit-transform: translateY(1px) rotateZ(-45deg) !important;
-
-    background-image: -webkit-gradient(
-        linear,
-        left bottom,
-        right top,
-        color-stop(0, rgba(99,  99,  99,  1)),
-        color-stop(1, rgba(144, 144, 144, 1))
-    ) !important;
-}
-video::-webkit-media-controls-timeline::-webkit-slider-thumb:active,
-video::-webkit-media-controls-timeline:active::-webkit-slider-thumb,
-audio::-webkit-media-controls-timeline::-webkit-slider-thumb:active,
-audio::-webkit-media-controls-timeline:active::-webkit-slider-thumb,
- {
-    background-image: -webkit-gradient(
-        linear,
-        left bottom,
-        right top,
-        color-stop(0, rgba(160, 160, 160, 1)),
-        color-stop(1, rgba(221, 221, 221, 1))
-    ) !important;
+    width:3px !important;
+    height: 15px !important;
 }
 video::-webkit-media-controls-current-time-display,
 video::-webkit-media-controls-time-remaining-display,
 audio::-webkit-media-controls-current-time-display,
@@ -489,7 +435,7 @@ video::-webkit-media-controls-panel .thumbnail-track,
 audio::-webkit-media-controls-panel .thumbnail-track {
     position: relative;
     -webkit-flex: 1 1 0;
-    height: 9px;
+    height: 17 px;
     margin: 0 2px;
     display: -webkit-flex;
     -webkit-align-items: stretch;
index fad9452..9c83113 100644 (file)
@@ -39,6 +39,7 @@ Controller.FullScreenControls = 1;
 
 Controller.PlayAfterSeeking = 0;
 Controller.PauseAfterSeeking = 1;
+Controller.gLastTimelineId = 0;
 
 Controller.prototype = {
 
@@ -344,6 +345,9 @@ Controller.prototype = {
         this.listenFor(timeline, 'mouseup', this.handleTimelineMouseUp);
         timeline.step = .01;
 
+        this.timelineContextName = "_webkit-media-controls-timeline-" + Controller.gLastTimelineId;
+        timeline.style.backgroundImage = '-webkit-canvas(' + this.timelineContextName + ')';
+        
         var thumbnailTrack = this.controls.thumbnailTrack = document.createElement('div');
         thumbnailTrack.classList.add(this.ClassNames.thumbnailTrack);
 
@@ -389,6 +393,10 @@ Controller.prototype = {
         volume.step = .01;
         this.listenFor(volume, 'input', this.handleVolumeSliderInput);
 
+        this.volumeContextName = "_webkit-media-controls-volume-" + Controller.gLastTimelineId;
+        volume.style.backgroundImage = '-webkit-canvas(' + this.volumeContextName + ')';
+        Controller.gLastTimelineId++;
+        
         var captionButton = this.controls.captionButton = document.createElement('button');
         captionButton.setAttribute('pseudo', '-webkit-media-controls-toggle-closed-captions-button');
         captionButton.setAttribute('aria-label', this.UIString('Captions'));
@@ -853,6 +861,7 @@ Controller.prototype = {
             this.controls.muteButton.setAttribute('aria-label', this.UIString('Mute'));
         }
         this.video.volume = this.controls.volume.value;
+        this.drawVolumeBackground();
     },
 
     handleCaptionButtonClicked: function(event)
@@ -978,24 +987,149 @@ Controller.prototype = {
         this.drawTimelineBackground();
     },
 
+    addRoundedRect: function(ctx, x, y, width, height, radius) {
+        ctx.moveTo(x + radius, y);
+        ctx.arcTo(x + width, y, x + width, y + radius, radius);
+        ctx.lineTo(x + width, y + height - radius);
+        ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius);
+        ctx.lineTo(x + radius, y + height);
+        ctx.arcTo(x, y + height, x, y + height - radius, radius);
+        ctx.lineTo(x, y + radius);
+        ctx.arcTo(x, y, x + radius, y, radius);
+    },
+
     drawTimelineBackground: function() {
-        var background = 'url(\'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="none"><linearGradient id="gradient" x2="0" y2="100%" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="rgb(2, 2, 2)"/><stop offset="1" stop-color="rgb(23, 23, 23)"/></linearGradient><g style="fill:url(#gradient)">'
+        var dpr = window.devicePixelRatio;
+        var width = this.controls.timeline.offsetWidth * dpr;
+        var height = this.controls.timeline.offsetHeight * dpr;
+        
+        if (!width || !height)
+            return;
+        
+        var played = this.video.currentTime / this.video.duration;
+        var buffered = 0;
+        for (var i = 0, end = this.video.buffered.length; i < end; ++i)
+            buffered = Math.max(this.video.buffered.end(i), buffered);
+        
+        buffered /= this.video.duration;
+        
+        var ctx = document.getCSSCanvasContext('2d', this.timelineContextName, width, height);
+        
+        width /= dpr;
+        height /= dpr;
+        
+        ctx.save();
+        ctx.scale(dpr, dpr);
+        ctx.clearRect(0, 0, width, height);
+        
+        var timelineHeight = 3;
+        var trackHeight = 1;
+        var scrubberWidth = 3;
+        var scrubberHeight = 15;
+        var borderSize = 2;
+        var scrubberPosition = Math.max(0, Math.min(width - scrubberWidth, Math.round(width * played)));
+        
+        // Draw buffered section.
+        ctx.save();
+        ctx.fillStyle = "rgb(100, 100, 100)";
+        ctx.fillRect(1, 8, Math.round(width * buffered) - borderSize, trackHeight);
+        ctx.restore();
+        
+        // Draw timeline border.
+        ctx.save();
+        ctx.beginPath();
+        this.addRoundedRect(ctx, scrubberPosition, 7, width - scrubberPosition, timelineHeight, timelineHeight / 2.0);
+        this.addRoundedRect(ctx, scrubberPosition + 1, 8, width - scrubberPosition - borderSize , trackHeight, trackHeight / 2.0);
+        ctx.closePath();
+        ctx.clip("evenodd");
+        ctx.fillStyle = "rgb(30, 30, 30)";
+        ctx.fillRect(0, 0, width, height);
+        ctx.restore();
+        
+        // Draw played section.
+        ctx.save(); 
+        ctx.beginPath();
+        this.addRoundedRect(ctx, 0, 7, width, timelineHeight, timelineHeight / 2.0);
+        ctx.closePath();
+        ctx.clip();
+        ctx.fillStyle = "rgb(75, 75, 75)";
+        ctx.fillRect(0, 0, width * played, height);
+        ctx.restore();
+        
+        // Draw the scrubber.
+        ctx.save();
+        ctx.clearRect(scrubberPosition - 1, 0, scrubberWidth + borderSize, height, 0);
+        ctx.beginPath();
+        this.addRoundedRect(ctx, scrubberPosition, 1, scrubberWidth, scrubberHeight, 1);
+        ctx.closePath();
+        ctx.clip();
+        ctx.fillStyle = "rgb(140, 140, 140)";
+        ctx.fillRect(0, 0, width, height);
+        ctx.restore();
+        
+        ctx.restore();
+    },
 
-        var duration = this.video.duration;
-        var buffered = this.video.buffered;
-        for (var i = 0, end = buffered.length; i < end; ++i) {
-            var startTime = buffered.start(i);
-            var endTime = buffered.end(i);
-
-            var startX = startTime / duration;
-            var widthX = (endTime - startTime) / duration;
-            background += '<rect x="' + startX + '" y="0" width="' + widthX + '" height="1"/>';
-        }
+    drawVolumeBackground: function() {
+        var dpr = window.devicePixelRatio;
+        var width = this.controls.volume.offsetWidth * dpr;
+        var height = this.controls.volume.offsetHeight * dpr;
 
-        background += '</g></svg>\')'
-        this.controls.timeline.style.backgroundImage = background;
+        if (!width || !height)
+            return;
+            
+        var ctx = document.getCSSCanvasContext('2d', this.volumeContextName, width, height);
+        
+        width /= dpr;
+        height /= dpr;
+        
+        ctx.save();
+        ctx.scale(dpr, dpr);
+        ctx.clearRect(0, 0, width, height);
+        
+        var seekerPosition = this.controls.volume.value;
+        var trackHeight = 1;
+        var timelineHeight = 3;
+        var scrubberRadius = 3.5;
+        var scrubberDiameter = 2 * scrubberRadius;
+        var borderSize = 2;
+        
+        var scrubberPosition = Math.round(seekerPosition * (width - scrubberDiameter - borderSize));
+        
+        // Draw volume track border.
+        ctx.save();
+        ctx.beginPath();
+        this.addRoundedRect(ctx, 0, 3, width, timelineHeight, timelineHeight / 2.0);
+        this.addRoundedRect(ctx, 1, 4, width - borderSize, trackHeight, trackHeight / 2.0);
+        ctx.closePath();
+        ctx.clip("evenodd");
+        ctx.fillStyle = "rgb(30, 30, 30)";
+        ctx.fillRect(0, 0, width, height);
+        ctx.restore();
+        
+        // Clear a hole in the slider for the scrubber.
+        ctx.save();
+        ctx.beginPath();
+        this.addRoundedRect(ctx, scrubberPosition, 0, scrubberDiameter + borderSize, height, (scrubberDiameter + borderSize) / 2.0);
+        ctx.closePath();
+        ctx.clip();
+        ctx.clearRect(0, 0, width, height);
+        ctx.restore();
+        
+        // Draw scrubber.
+        ctx.save();
+        ctx.beginPath();
+        this.addRoundedRect(ctx, scrubberPosition + 1, 1, scrubberDiameter, scrubberDiameter, scrubberRadius);
+        ctx.closePath();
+        ctx.clip();
+        ctx.fillStyle = "rgb(140, 140, 140)";
+        ctx.fillRect(0, 0, width, height);
+        ctx.restore();
+        
+        ctx.restore();
+        
     },
-
+    
     formatTime: function(time)
     {
         if (isNaN(time))
@@ -1041,6 +1175,7 @@ Controller.prototype = {
 
         this.updateTime();
         this.updateProgress(true);
+        this.drawVolumeBackground();
 
         this.controls.panel.classList.add(this.ClassNames.show);
         this.controls.panel.classList.remove(this.ClassNames.hidden);
index 6e07022..f85cbef 100644 (file)
@@ -292,17 +292,6 @@ ControllerIOS.prototype = {
         this.updateProgress();
     },
 
-    addRoundedRect: function(ctx, x, y, width, height, radius) {
-        ctx.moveTo(x + radius, y);
-        ctx.arcTo(x + width, y, x + width, y + radius, radius);
-        ctx.lineTo(x + width, y + height - radius);
-        ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius);
-        ctx.lineTo(x + radius, y + height);
-        ctx.arcTo(x, y + height, x, y + height - radius, radius);
-        ctx.lineTo(x, y + radius);
-        ctx.arcTo(x, y, x + radius, y, radius);
-    },
-
     drawTimelineBackground: function() {
         var width = this.timelineWidth * window.devicePixelRatio;
         var height = this.timelineHeight * window.devicePixelRatio;