Bug 1444489 - Part II, Replace touchControls with videoControls and remove touchControls draft
authorTimothy Guan-tin Chien <timdream@gmail.com>
Wed, 21 Mar 2018 15:10:20 +0800
changeset 770601 c1abda11f158873222e85e48937b83d97b12b9c1
parent 770600 8df2f500350cd36b65015a10273b6451ca88bd4e
child 770602 07ca36eb8c656d1b548e61d648a750a020fa5c99
push id103447
push usertimdream@gmail.com
push dateWed, 21 Mar 2018 15:57:15 +0000
bugs1444489
milestone61.0a1
Bug 1444489 - Part II, Replace touchControls with videoControls and remove touchControls Also migrates TouchUtils to videoControls in order to keep some interactions. Removed the casting button from TouchUtils (to be add back to Utils in the next commit; not removing the SVG images for hg annotation) MozReview-Commit-ID: DzhmjykCLzu
mobile/android/themes/geckoview/content.css
mobile/android/themes/geckoview/images/videocontrols-exitfullscreen.svg
mobile/android/themes/geckoview/images/videocontrols-fullscreen.svg
mobile/android/themes/geckoview/images/videocontrols-mute.svg
mobile/android/themes/geckoview/images/videocontrols-pause.svg
mobile/android/themes/geckoview/images/videocontrols-play.svg
mobile/android/themes/geckoview/images/videocontrols-scrubber.svg
mobile/android/themes/geckoview/images/videocontrols-unmute.svg
mobile/android/themes/geckoview/jar.mn
mobile/android/themes/geckoview/videocontrols.css
toolkit/content/jar.mn
toolkit/content/tests/widgets/mochitest.ini
toolkit/content/tests/widgets/test_videocontrols_error.html
toolkit/content/widgets/videocontrols.css
toolkit/content/widgets/videocontrols.xml
toolkit/themes/mobile/global/media/clicktoplay-bgtexture.png
toolkit/themes/mobile/global/media/videoClickToPlayButton.svg
toolkit/themes/mobile/jar.mn
--- a/mobile/android/themes/geckoview/content.css
+++ b/mobile/android/themes/geckoview/content.css
@@ -259,21 +259,16 @@ button:disabled:active {
 select:disabled > button {
   opacity: 0.6;
   padding-inline-start: 7px;
   padding-inline-end: 7px;
   padding-block-start: 1px;
   padding-block-end: 1px;
 }
 
-/* -moz-touch-enabled? media elements */
-:-moz-any(video, audio) > xul|videocontrols {
-  -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControls");
-}
-
 /* display click to play when autoplay is blocked for videos */
 video:not([controls]) > xul|videocontrols {
   visibility: visible;
   -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#noControls");
 }
 
 *:any-link:active,
 *[role=button]:active,
deleted file mode 100644
--- a/mobile/android/themes/geckoview/images/videocontrols-exitfullscreen.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<svg width="72px" height="72px" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-276.000000, -1042.000000)" fill="#FFFFFF">
-            <g transform="translate(240.000000, 1006.000000)">
-                <path d="M36.96,80.16 C35.2060427,78.316034 35.8370453,76.8 38.4,76.8 L62.4,76.8 C65.0584079,76.8 67.2,78.9469741 67.2,81.6 L67.2,105.6 C67.2,108.165446 65.6848806,108.791856 63.84,107.04 L55.2,98.4 L49.92,104.16 C47.9768607,105.92543 44.9530217,105.908123 43.2,104.16 L39.84,100.8 C38.0648585,98.9095525 38.080377,95.8763717 39.84,94.08 L45.6,88.8 L36.96,80.16 Z M107.04,63.84 C108.79397,65.6843439 108.162544,67.2 105.6,67.2 L81.6,67.2 C78.941564,67.2 76.8,65.0529486 76.8,62.4 L76.8,38.4 C76.8,35.8334252 78.3157239,35.2076163 80.16,36.96 L88.8,45.6 L94.08,39.84 C95.909525,38.1209584 98.9004381,38.0799163 100.8,39.84 L104.16,43.2 C105.923072,45.1022004 105.884206,48.0879079 104.16,49.92 L98.4,55.2 L107.04,63.84 Z"></path>
-            </g>
-        </g>
-    </g>
-</svg>
deleted file mode 100644
--- a/mobile/android/themes/geckoview/images/videocontrols-fullscreen.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<svg width="72px" height="72px" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-84.000000, -1042.000000)" fill="#FFFFFF">
-            <g transform="translate(48.000000, 1006.000000)">
-                <path d="M77.1428571,36 L102.857143,36 C105.705437,36 108,38.3003294 108,41.1428571 L108,66.8571429 C108,69.6058346 106.376658,70.276989 104.4,68.4 L95.1428571,59.1428571 L89.4857143,65.3142857 C87.4037793,67.2058174 84.1639518,67.1872741 82.2857143,65.3142857 L78.6857143,61.7142857 C76.783777,59.6888062 76.8004039,56.4389697 78.6857143,54.5142857 L84.8571429,48.8571429 L75.6,39.6 C73.7207601,37.6243221 74.3968342,36 77.1428571,36 Z M66.8571429,108 L41.1428571,108 C38.2945329,108 36,105.699588 36,102.857143 L36,77.1428571 C36,74.3929556 37.6239899,73.7224461 39.6,75.6 L48.8571429,84.8571429 L54.5142857,78.6857143 C56.474491,76.843884 59.6790408,76.7999103 61.7142857,78.6857143 L65.3142857,82.2857143 C67.2032916,84.3237862 67.1616492,87.5227585 65.3142857,89.4857143 L59.1428571,95.1428571 L68.4,104.4 C70.279254,106.376083 69.6027253,108 66.8571429,108 Z"></path>
-            </g>
-        </g>
-    </g>
-</svg>
deleted file mode 100644
--- a/mobile/android/themes/geckoview/images/videocontrols-mute.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<svg width="70px" height="60px" viewBox="0 0 70 60" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-469.000000, -1048.000000)" fill="#FFFFFF">
-            <g transform="translate(432.000000, 1006.000000)">
-                <path d="M98.3836922,53.1162172 C103.662239,57.6998888 107,64.4601112 107,71.9999094 C107,79.5397077 103.662239,86.2999301 98.3836922,90.8836016 L94.8371224,87.3370318 C99.2157236,83.6682614 102,78.1592367 102,71.9999094 C102,65.8405821 99.2157236,60.3315575 94.8371224,56.6627871 L98.3836922,53.1162172 Z M91.2831302,60.2167792 C94.7649686,62.9636534 97,67.2207716 97,71.9999094 C97,76.7790472 94.7649686,81.0361655 91.2831302,83.7830397 L87.7103386,80.210248 C90.3032555,78.4034792 92,75.3998422 92,71.9999094 C92,68.5999775 90.3032563,65.5963412 87.7103384,63.789571 L91.2831302,60.2167792 Z M37,61.9999094 C37,59.2105478 39.2364417,56.9712087 42,56.9999094 L58,56.9999094 L75.5,42.9999094 C79.1323004,40.818613 82,42.3919545 82,46.4999094 L82,97.4999094 C82,101.618951 79.1389004,103.178674 75.5,100.999909 L58,86.9999094 L42,86.9999094 C39.2362844,87.0258469 37,84.7863502 37,81.9999094 L37,61.9999094 Z"></path>
-            </g>
-        </g>
-    </g>
-</svg>
deleted file mode 100644
--- a/mobile/android/themes/geckoview/images/videocontrols-pause.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<svg width="54px" height="72px" viewBox="0 0 54 72" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-285.000000, -1234.000000)" fill="#FFFFFF">
-            <g transform="translate(240.000000, 1198.000000)">
-                <path d="M63,103.5 C63,105.9849 60.9849,108 58.5,108 L49.5,108 C47.0151,108 45,105.9849 45,103.5 L45,40.5 C45,38.0151 47.0151,36 49.5,36 L58.5,36 C60.9849,36 63,38.0151 63,40.5 L63,103.5 Z M94.5,108 L85.5,108 C83.0151,108 81,105.9849 81,103.5 L81,40.5 C81,38.0151 83.0151,36 85.5,36 L94.5,36 C96.9849,36 99,38.0151 99,40.5 L99,103.5 C99,105.9849 96.9849,108 94.5,108 Z"></path>
-            </g>
-        </g>
-    </g>
-</svg>
deleted file mode 100644
--- a/mobile/android/themes/geckoview/images/videocontrols-play.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<svg width="58px" height="72px" viewBox="0 0 58 72" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-91.000000, -1234.000000)" fill="#FFFFFF">
-            <g transform="translate(48.000000, 1198.000000)">
-                <path d="M43,40 L43,104 C43,107.688656 45.5537886,109.093408 49,107 L99,75 C101.697423,73.3130096 101.692268,70.3534356 99,69 L49,37 C45.5596797,34.9042037 43,36.3212206 43,40 Z"></path>
-            </g>
-        </g>
-    </g>
-</svg>
deleted file mode 100644
--- a/mobile/android/themes/geckoview/images/videocontrols-scrubber.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<svg width="36px" height="36px" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-486.000000, -1444.000000)" fill="#FFFFFF">
-            <g transform="translate(432.000000, 1390.000000)">
-                <circle id="Oval-17" cx="72" cy="72" r="18"></circle>
-            </g>
-        </g>
-    </g>
-</svg>
deleted file mode 100644
--- a/mobile/android/themes/geckoview/images/videocontrols-unmute.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<svg width="45px" height="60px" viewBox="0 0 45 60" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-661.000000, -1048.000000)" fill="#FFFFFF">
-            <g transform="translate(624.000000, 1006.000000)">
-                <path d="M37,61.9999094 C37,59.2105478 39.2364417,56.9712087 42,56.9999094 L58,56.9999094 L75.5,42.9999094 C79.1323004,40.818613 82,42.3919545 82,46.4999094 L82,97.4999094 C82,101.618951 79.1389004,103.178674 75.5,100.999909 L58,86.9999094 L42,86.9999094 C39.2362844,87.0258469 37,84.7863502 37,81.9999094 L37,61.9999094 Z"></path>
-            </g>
-        </g>
-    </g>
-</svg>
--- a/mobile/android/themes/geckoview/jar.mn
+++ b/mobile/android/themes/geckoview/jar.mn
@@ -4,32 +4,20 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 geckoview.jar:
 
 % skin geckoview classic/1.0 %skin/
   skin/content.css                          (content.css)
   skin/defines.css                          (defines.css)
   skin/scrollbar.css                        (scrollbar-apz.css)
-  skin/videocontrols.css                    (videocontrols.css)
 
   skin/images/accessiblecaret-normal-hdpi.png       (images/accessiblecaret-normal-hdpi.png)
   skin/images/accessiblecaret-normal-xhdpi.png      (images/accessiblecaret-normal-xhdpi.png)
   skin/images/accessiblecaret-normal-xxhdpi.png     (images/accessiblecaret-normal-xxhdpi.png)
   skin/images/accessiblecaret-tilt-left-hdpi.png    (images/accessiblecaret-tilt-left-hdpi.png)
   skin/images/accessiblecaret-tilt-left-xhdpi.png   (images/accessiblecaret-tilt-left-xhdpi.png)
   skin/images/accessiblecaret-tilt-left-xxhdpi.png  (images/accessiblecaret-tilt-left-xxhdpi.png)
   skin/images/accessiblecaret-tilt-right-hdpi.png   (images/accessiblecaret-tilt-right-hdpi.png)
   skin/images/accessiblecaret-tilt-right-xhdpi.png  (images/accessiblecaret-tilt-right-xhdpi.png)
   skin/images/accessiblecaret-tilt-right-xxhdpi.png (images/accessiblecaret-tilt-right-xxhdpi.png)
   skin/images/dropmarker.svg                        (images/dropmarker.svg)
   skin/images/dropmarker-right.svg                  (images/dropmarker-right.svg)
-  skin/images/videocontrols-cast-ready.svg          (images/videocontrols-cast-ready.svg)
-  skin/images/videocontrols-cast-active.svg         (images/videocontrols-cast-active.svg)
-  skin/images/videocontrols-exitfullscreen.svg      (images/videocontrols-exitfullscreen.svg)
-  skin/images/videocontrols-fullscreen.svg          (images/videocontrols-fullscreen.svg)
-  skin/images/videocontrols-mute.svg                (images/videocontrols-mute.svg)
-  skin/images/videocontrols-play.svg                (images/videocontrols-play.svg)
-  skin/images/videocontrols-pause.svg               (images/videocontrols-pause.svg)
-  skin/images/videocontrols-scrubber.svg            (images/videocontrols-scrubber.svg)
-  skin/images/videocontrols-unmute.svg              (images/videocontrols-unmute.svg)
-
-% override chrome://global/skin/media/videocontrols.css chrome://geckoview/skin/videocontrols.css
deleted file mode 100644
--- a/mobile/android/themes/geckoview/videocontrols.css
+++ /dev/null
@@ -1,251 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
-
-/* video controls */
-.controlsOverlay {
-  -moz-box-pack: center;
-  -moz-box-align: end;
-  -moz-box-flex: 1;
-  -moz-box-orient: horizontal;
-}
-
-.controlsOverlay[scaled] {
-  /* scaled attribute in videocontrols.css causes conflict
-     due to different -moz-box-orient values */
-  -moz-box-align: end;
-}
-
-.controlsSpacer {
-  display: none;
-  -moz-box-flex: 0;
-}
-
-.controlBar {
-  -moz-box-flex: 1;
-  width: 100%;
-  background-color: rgba(50,50,50,0.8);
-}
-
-.buttonsBar {
-  -moz-box-flex: 1;
-  -moz-box-align: center;
-}
-
-.playButton,
-.castingButton,
-.muteButton,
-.fullscreenButton {
-  -moz-appearance: none;
-  padding: 15px;
-  border: none !important;
-  width: 48px;
-  height: 48px;
-}
-
-.playButton {
-  background: url("chrome://geckoview/skin/images/videocontrols-pause.svg") no-repeat center;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-.playButton[paused="true"] {
-  background: url("chrome://geckoview/skin/images/videocontrols-play.svg") no-repeat center;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-.castingButton {
-  background: url("chrome://geckoview/skin/images/videocontrols-cast-ready.svg") no-repeat center;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-.castingButton[active="true"] {
-  background: url("chrome://geckoview/skin/images/videocontrols-cast-active.svg") no-repeat center;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-/* If the casting button is showing, there will be two buttons on the right side of the controls.
- * This shifts the play button to be centered.
- */
-.castingButton:not([hidden="true"]) + .fullscreenButton + spacer + .playButton {
-  transform: translateX(-21px);
-}
-
-.muteButton {
-  padding-left: 17.25px;
-  padding-right: 9.75px;
-  background: url("chrome://geckoview/skin/images/videocontrols-mute.svg") no-repeat left;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-.muteButton[muted="true"] {
-  background: url("chrome://geckoview/skin/images/videocontrols-unmute.svg") no-repeat left;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-.fullscreenButton {
-  background-color: transparent;
-  background: url("chrome://geckoview/skin/images/videocontrols-fullscreen.svg") no-repeat center;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-.fullscreenButton[fullscreened] {
-  background: url("chrome://geckoview/skin/images/videocontrols-exitfullscreen.svg") no-repeat center;
-  background-size: contain;
-  background-origin: content-box;
-}
-
-.controlBar[fullscreen-unavailable] .fullscreenButton {
-  display: none;
-}
-
-/* bars */
-.scrubberStack {
-  -moz-box-flex: 1;
-  padding: 0px 18px;
-}
-
-.flexibleBar,
-.flexibleBar .progress-bar,
-.bufferBar,
-.bufferBar .progress-bar,
-.progressBar,
-.progressBar .progress-bar,
-.scrubber,
-.scrubber .scale-slider,
-.scrubber .scale-thumb {
-  -moz-appearance: none;
-  border: none;
-  padding: 0px;
-  margin: 0px;
-  background-color: transparent;
-}
-
-.flexibleBar,
-.bufferBar,
-.progressBar {
-  height: 32px;
-  padding: 15px 0px;
-}
-
-.flexibleBar {
-  padding: 16px 0px;
-}
-
-.flexibleBar .progress-bar {
-  border: 1px #777777 solid;
-  border-radius: 1px;
-}
-
-.bufferBar .progress-bar {
-  border: 2px #AFB1B3 solid;
-  border-radius: 2px;
-}
-
-.progressBar .progress-bar {
-  border: 2px #0A84FF solid;
-  border-radius: 2px;
-}
-
-.scrubber {
-  margin-left: -12px;
-  margin-right: -12px;
-}
-
-.scrubber .scale-thumb {
-  display: -moz-box;
-  margin: 0px !important;
-  padding: 0px !important;
-  background: url("chrome://geckoview/skin/images/videocontrols-scrubber.svg") no-repeat center;
-  background-size: 12px 12px;
-  height: 32px;
-  width: 32px;
-}
-
-.positionLabel, .durationLabel {
-  font-family: 'Roboto', Helvetica, Arial, sans-serif;
-  font-size: 16px;
-  color: white;
-}
-
-.statusOverlay[error] {
-  -moz-box-align: center;
-  -moz-box-pack: center;
-  background-color: rgb(50,50,50);
-}
-
-.statusIcon {
-  margin-bottom: 28px;
-  width: 36px;
-  height: 36px;
-}
-
-.statusIcon[type="error"] {
-  background: url(chrome://global/skin/media/error.png) no-repeat center;
-}
-
-/* CSS Transitions */
-.controlBar:not([immediate]) {
-  transition-property: opacity;
-  transition-duration: 200ms;
-}
-
-.controlBar[fadeout] {
-  opacity: 0;
-}
-
-.statusOverlay:not([immediate]) {
-  transition-property: opacity;
-  transition-duration: 300ms;
-  transition-delay: 750ms;
-}
-
-.statusOverlay[fadeout] {
-  opacity: 0;
-}
-
-.volumeStack,
-.timeLabel {
-  display: none;
-}
-
-.controlBar[firstshow="true"] .playButton {
-  -moz-transform: none;
-}
-
-/* Error description formatting */
-.errorLabel {
-  font-family: Helvetica, Arial, sans-serif;
-  font-size: 11px;
-  color: #bbb;
-  text-shadow:
-    -1px -1px 0 #000,
-    1px -1px 0 #000,
-    -1px 1px 0 #000,
-    1px 1px 0 #000;
-  padding: 0 10px;
-  text-align: center;
-}
-
-/* Overlay Play button */
-.clickToPlay {
-  width: 64px;
-  height: 64px;
-  -moz-box-pack: center;
-  -moz-box-align: center;
-  opacity: 0.7;
-  background-image: url(chrome://global/skin/media/clicktoplay-bgtexture.png),
-                    url(chrome://global/skin/media/videoClickToPlayButton.svg);
-  background-repeat: repeat, no-repeat;
-  background-position: center, center;
-  background-size: auto, 64px 64px;
-  background-color: hsla(0,0%,10%,.5);
-}
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -100,15 +100,14 @@ toolkit.jar:
    content/global/bindings/text.xml            (widgets/text.xml)
 *  content/global/bindings/textbox.xml         (widgets/textbox.xml)
    content/global/bindings/timekeeper.js       (widgets/timekeeper.js)
    content/global/bindings/timepicker.js       (widgets/timepicker.js)
    content/global/bindings/toolbar.xml         (widgets/toolbar.xml)
    content/global/bindings/toolbarbutton.xml   (widgets/toolbarbutton.xml)
 *  content/global/bindings/tree.xml            (widgets/tree.xml)
    content/global/bindings/videocontrols.xml   (widgets/videocontrols.xml)
-   content/global/bindings/videocontrols.css   (widgets/videocontrols.css)
 *  content/global/bindings/wizard.xml          (widgets/wizard.xml)
 #ifdef XP_MACOSX
    content/global/macWindowMenu.js
 #endif
    content/global/gmp-sources/openh264.json    (gmp-sources/openh264.json)
    content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json)
--- a/toolkit/content/tests/widgets/mochitest.ini
+++ b/toolkit/content/tests/widgets/mochitest.ini
@@ -18,36 +18,31 @@ support-files =
   videocontrols_direction-2b.html
   videocontrols_direction-2c.html
   videocontrols_direction-2d.html
   videocontrols_direction-2e.html
   videocontrols_direction_test.js
   videomask.css
 
 [test_audiocontrols_dimensions.html]
-skip-if = toolkit == 'android'
 [test_mousecapture_area.html]
 [test_videocontrols.html]
 tags = fullscreen
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_videocontrols_keyhandler.html]
 skip-if = toolkit == 'android'
 [test_videocontrols_vtt.html]
-skip-if = toolkit == 'android'
 [test_videocontrols_iframe_fullscreen.html]
 [test_videocontrols_size.html]
-skip-if = toolkit == 'android'
 [test_videocontrols_audio.html]
 [test_videocontrols_audio_direction.html]
 [test_videocontrols_jsdisabled.html]
 skip-if = toolkit == 'android' # bug 1272646
 [test_videocontrols_standalone.html]
 skip-if = toolkit == 'android' # bug 1075573
 [test_videocontrols_video_direction.html]
 skip-if = os == 'win'
 [test_videocontrols_video_noaudio.html]
-skip-if = toolkit == 'android'
 [test_bug1319301.html]
-skip-if = toolkit == 'android'
 [test_bug898940.html]
 [test_videocontrols_error.html]
 [test_videocontrols_orientation.html]
 run-if = toolkit == 'android'
--- a/toolkit/content/tests/widgets/test_videocontrols_error.html
+++ b/toolkit/content/tests/widgets/test_videocontrols_error.html
@@ -27,17 +27,21 @@
   });
 
   add_task(async function check_normal_status() {
     await new Promise(resolve => {
       video.src = "seek_with_sound.ogg";
       video.addEventListener("loadedmetadata", () => SimpleTest.executeSoon(resolve));
     });
 
-    ok(statusOverlay.hidden, "statusOverlay shoud not present without error");
+    // Wait for the fade out transition to complete in case the throbber
+    // shows up on slower platforms.
+    await SimpleTest.promiseWaitForCondition(() => statusOverlay.hidden,
+      "statusOverlay should not present without error");
+
     ok(!statusOverlay.hasAttribute("error"), "statusOverlay should not in error state");
     isnot(statusIcon.getAttribute("type"), "error", "should not show error icon");
   });
 
   add_task(async function invalid_source() {
     const errorType = "errorNoSource";
 
     await new Promise(resolve => {
deleted file mode 100644
--- a/toolkit/content/widgets/videocontrols.css
+++ /dev/null
@@ -1,79 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-@namespace html url("http://www.w3.org/1999/xhtml");
-
-.scrubber,
-.volumeControl {
-  -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#suppressChangeEvent");
-}
-
-.playButton,
-.muteButton,
-.scrubber .scale-slider,
-.volumeControl .scale-slider {
-  -moz-user-focus: none;
-}
-
-.controlBar[fullscreen-unavailable] > .fullscreenButton {
-  display: none;
-}
-
-.mediaControlsFrame {
-  direction: ltr;
-  /* Prevent unwanted style inheritance. See bug 554717. */
-  text-align: left;
-  list-style-image: none !important;
-  font: normal normal normal 100%/normal sans-serif !important;
-  text-decoration: none !important;
-}
-
-.controlsOverlay[scaled] {
-  -moz-box-align: center;
-}
-
-/* CSS Transitions
- *
- * These are overriden by the default theme; the rules here just 
- * provide a fallback to drive the required transitionend event
- * (in case a 3rd party theme does not provide transitions).
- */
-.controlBar:not([immediate]) {
-  transition-property: opacity;
-  transition-duration: 1ms;
-}
-.controlBar[fadeout] {
-  opacity: 0;
-}
-.volumeStack:not([immediate]) {
-  transition-property: opacity, margin-top;
-  transition-duration: 1ms, 1ms;
-}
-.volumeStack[fadeout] {
-  opacity: 0;
-  margin-top: 0;
-}
-.statusOverlay:not([immediate]) {
-  transition-property: opacity;
-  transition-duration: 1ms;
-  transition-delay: 750ms;
-}
-.statusOverlay[fadeout] {
-  opacity: 0;
-}
-
-/* Error description formatting */
-.errorLabel {
-  display: none;
-}
-
-[error="errorAborted"]         > [anonid="errorAborted"],
-[error="errorNetwork"]         > [anonid="errorNetwork"],
-[error="errorDecode"]          > [anonid="errorDecode"],
-[error="errorSrcNotSupported"] > [anonid="errorSrcNotSupported"],
-[error="errorNoSource"]        > [anonid="errorNoSource"],
-[error="errorGeneric"]         > [anonid="errorGeneric"] {
-  display: inline;
-}
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -10,132 +10,22 @@
 
 <bindings id="videoControlBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl"
           xmlns:svg="http://www.w3.org/2000/svg"
           xmlns:html="http://www.w3.org/1999/xhtml">
 
-<binding id="suppressChangeEvent"
-         extends="chrome://global/content/bindings/scale.xml#scale">
-<implementation implements="nsIXBLAccessible">
-  <!-- nsIXBLAccessible -->
-  <property name="accessibleName" readonly="true">
-    <getter>
-      var currTime = this.positionValue;
-      var totalTime = this.durationValue;
-
-      return this.scrubberNameFormat
-                 .replace(/#1/, currTime)
-                 .replace(/#2/, totalTime);
-    </getter>
-  </property>
-
-  <constructor>
-    <![CDATA[
-    /* eslint-disable no-multi-spaces */
-    this.scrubberNameFormat = ]]>"&scrubberScale.nameFormat;"<![CDATA[;
-    /* eslint-enable no-multi-spaces */
-    this.positionValue = "";
-    this.durationValue = "";
-    this.valueBar = null;
-    this.isDragging = false;
-    this.isPausedByDragging = false;
-
-    this.type = this.getAttribute("class");
-    this.Utils = document.getBindingParent(this.parentNode).Utils;
-    this.valueBar = this.Utils.progressBar;
-    ]]>
-  </constructor>
-
-  <method name="valueChanged">
-    <parameter name="which"/>
-    <parameter name="newValue"/>
-    <parameter name="userChanged"/>
-    <body>
-      <![CDATA[
-      // This method is a copy of the base binding's valueChanged(), except that it does
-      // not dispatch a |change| event (to avoid exposing the event to web content), and
-      // just calls the videocontrol's seekToPosition() method directly.
-      switch (which) {
-        case "curpos":
-          // Update the time shown in the thumb.
-          this.positionValue = this.Utils.formatTime(newValue, this.Utils.showHours);
-          this.Utils.positionLabel.setAttribute("value", this.positionValue);
-          // Update the value bar to match the thumb position.
-          let percent = newValue / this.max;
-          if (!isNaN(percent) && percent != Infinity) {
-            this.valueBar.value = Math.round(percent * 10000); // has max=10000
-          } else {
-            this.valueBar.removeAttribute("value");
-          }
-
-          // The value of userChanged is true when changing the position with the mouse,
-          // but not when pressing an arrow key. However, the base binding sets
-          // ._userChanged in its keypress handlers, so we just need to check both.
-          if (!userChanged && !this._userChanged) {
-            return;
-          }
-          this.setAttribute("value", newValue);
-          this.Utils.seekToPosition(newValue);
-          break;
-
-        case "minpos":
-          this.setAttribute("min", newValue);
-          break;
-
-        case "maxpos":
-          // Update the value bar to match the thumb position.
-          this.valueBar.value = Math.round(this.value / newValue * 10000); // has max=10000
-          this.setAttribute("max", newValue);
-          break;
-      }
-      ]]>
-    </body>
-  </method>
-
-  <method name="dragStateChanged">
-    <parameter name="isDragging"/>
-    <body>
-      <![CDATA[
-      this.Utils.log("--- dragStateChanged: " + isDragging + " ---");
-      this.isDragging = isDragging;
-      if (this.isPausedByDragging && !isDragging) {
-        // After the drag ends, resume playing.
-        this.Utils.video.play();
-        this.isPausedByDragging = false;
-      }
-      ]]>
-    </body>
-  </method>
-
-  <method name="pauseVideoDuringDragging">
-    <body>
-      <![CDATA[
-      if (this.isDragging &&
-         !this.Utils.video.paused && !this.isPausedByDragging) {
-        this.isPausedByDragging = true;
-        this.Utils.video.pause();
-      }
-      ]]>
-    </body>
-  </method>
-
-</implementation>
-</binding>
-
 <binding id="videoControls">
   <resources>
-    <stylesheet src="chrome://global/content/bindings/videocontrols.css"/>
     <stylesheet src="chrome://global/skin/media/videocontrols.css"/>
   </resources>
 
-  <xbl:content xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-    xmlns="http://www.w3.org/1999/xhtml" class="mediaControlsFrame">
+  <xbl:content xmlns="http://www.w3.org/1999/xhtml" class="mediaControlsFrame">
     <div anonid="controlsContainer" class="controlsContainer" role="none">
       <div anonid="statusOverlay" class="statusOverlay stackItem" hidden="true">
         <div anonid="statusIcon" class="statusIcon"></div>
         <span class="errorLabel" anonid="errorAborted">&error.aborted;</span>
         <span class="errorLabel" anonid="errorNetwork">&error.network;</span>
         <span class="errorLabel" anonid="errorDecode">&error.decode;</span>
         <span class="errorLabel" anonid="errorSrcNotSupported">&error.srcNotSupported;</span>
         <span class="errorLabel" anonid="errorNoSource">&error.noSource2;</span>
@@ -186,17 +76,16 @@
       </div>
     </div>
   </xbl:content>
 
   <implementation>
 
   <constructor>
     <![CDATA[
-    this.isTouchControls = false;
     this.randomID = 0;
 
     this.Utils = {
       debug: false,
       video: null,
       videocontrols: null,
       controlBar: null,
       playButton: null,
@@ -802,20 +691,16 @@
           timeString = hours + ":" + mins + ":" + secs;
         } else {
           timeString = mins + ":" + secs;
         }
         return timeString;
       },
 
       initPositionDurationBox() {
-        if (this.videocontrols.isTouchControls) {
-          return;
-        }
-
         const positionTextNode = Array.prototype.find.call(
           this.positionDurationBox.childNodes, (n) => !!~n.textContent.search("#1"));
         const durationSpan = this.durationSpan;
         const durationFormat = durationSpan.textContent;
         const positionFormat = positionTextNode.textContent;
 
         durationSpan.classList.add("duration");
         durationSpan.setAttribute("role", "none");
@@ -846,25 +731,21 @@
           duration = this.maxCurrentTimeSeen;
         }
 
         // If the duration is over an hour, thumb should show h:mm:ss instead of mm:ss
         this.showHours = (duration >= 3600000);
 
         // Format the duration as "h:mm:ss" or "m:ss"
         let timeString = isInfinite ? "" : this.formatTime(duration);
-        if (this.videocontrols.isTouchControls) {
-          this.durationLabel.setAttribute("value", timeString);
-        } else {
-          this.positionDurationBox.duration = timeString;
+        this.positionDurationBox.duration = timeString;
 
-          if (this.showHours) {
-            this.positionDurationBox.modifier = "long";
-            this.durationSpan.modifier = "long";
-          }
+        if (this.showHours) {
+          this.positionDurationBox.modifier = "long";
+          this.durationSpan.modifier = "long";
         }
 
         // "durationValue" property is used by scale binding to
         // generate accessible name.
         this.scrubber.durationValue = timeString;
 
         this.scrubber.max = duration;
         // XXX Can't set increment here, due to bug 473103. Also, doing so causes
@@ -898,20 +779,16 @@
 
         if (this.isPausedByDragging) {
           this.video.play();
           this.isPausedByDragging = false;
         }
       },
 
       updateScrubberProgress() {
-        if (this.videocontrols.isTouchControls) {
-          return;
-        }
-
         const positionPercent = this.scrubber.value / this.scrubber.max * 100;
 
         if (!isNaN(positionPercent) && positionPercent != Infinity) {
           this.progressBar.value = positionPercent;
         } else {
           this.progressBar.value = 0;
         }
       },
@@ -937,22 +814,18 @@
         }
         this.showDuration(duration);
 
         this.log("time update @ " + currentTime + "ms of " + duration + "ms");
 
         let positionTime = this.formatTime(currentTime, this.showHours);
 
         this.scrubber.value = currentTime;
-        if (this.videocontrols.isTouchControls) {
-          this.positionLabel.setAttribute("value", positionTime);
-        } else {
-          this.positionDurationBox.position = positionTime;
-          this.updateScrubberProgress();
-        }
+        this.positionDurationBox.position = positionTime;
+        this.updateScrubberProgress();
       },
 
       showBuffered() {
         function bsearch(haystack, needle, cmp) {
           var length = haystack.length;
           var low = 0;
           var high = length;
           while (low < high) {
@@ -1105,21 +978,17 @@
       },
 
       startFade(element, fadeIn, immediate) {
         if (element.classList.contains("controlBar") && fadeIn) {
           // Bug 493523, the scrubber doesn't call valueChanged while hidden,
           // so our dependent state (eg, timestamp in the thumb) will be stale.
           // As a workaround, update it manually when it first becomes unhidden.
           if (element.hidden) {
-            if (this.videocontrols.isTouchControls) {
-              this.scrubber.valueChanged("curpos", this.video.currentTime * 1000, false);
-            } else {
-              this.scrubber.value = this.video.currentTime * 1000;
-            }
+            this.scrubber.value = this.video.currentTime * 1000;
           }
         }
 
         if (immediate) {
           element.setAttribute("immediate", true);
         } else {
           element.removeAttribute("immediate");
         }
@@ -1153,19 +1022,16 @@
 
         var element = event.originalTarget;
 
         // Nothing to do when a fade *in* finishes.
         if (!element.hasAttribute("fadeout")) {
           return;
         }
 
-        if (this.videocontrols.isTouchControls) {
-          this.scrubber.dragStateChanged(false);
-        }
         element.hidden = true;
       },
 
       _triggeredByControls: false,
 
       startPlay() {
         this._triggeredByControls = true;
         this.hideClickToPlay();
@@ -1465,17 +1331,17 @@
       },
 
       isSupportedTextTrack(textTrack) {
         return textTrack.kind == "subtitles" ||
                textTrack.kind == "captions";
       },
 
       get isClosedCaptionAvailable() {
-        return this.overlayableTextTracks.length && !this.videocontrols.isTouchControls;
+        return this.overlayableTextTracks.length;
       },
 
       get overlayableTextTracks() {
         return Array.prototype.filter.call(this.video.textTracks, this.isSupportedTextTrack);
       },
 
       get currentTextTrackIndex() {
         const showingTT = this.overlayableTextTracks.find(tt => tt.mode == "showing");
@@ -1647,20 +1513,16 @@
         let doc = this.video.ownerDocument;
         let win = doc.defaultView;
         return doc.mozSyntheticDocument && win === win.top;
       },
 
       controlBarMinHeight: 40,
       controlBarMinVisibleHeight: 28,
       adjustControlSize() {
-        if (this.videocontrols.isTouchControls) {
-          return;
-        }
-
         const minControlBarPaddingWidth = 18;
 
         this.fullscreenButton.isWanted = !this.controlBar.hasAttribute("fullscreen-unavailable");
         this.closedCaptionButton.isWanted = this.isClosedCaptionAvailable;
         this.volumeStack.isWanted = !this.muteButton.hasAttribute("noAudio");
 
         let minRequiredWidth = this.prioritizedControls
           .filter(control => control && control.isWanted)
@@ -1788,20 +1650,18 @@
           this.fullscreenButton,
           this.closedCaptionButton,
           this.positionDurationBox,
           this.scrubberStack,
           this.durationSpan,
           this.volumeStack
         ];
 
-        // XXX controlsContainer is a desktop only element. To determine whether
-        // isTouchControls or not during the whole initialization process, get
-        // this state overridden here.
-        this.videocontrols.isTouchControls = !this.controlsContainer;
+        this.videocontrols.isTouchControls =
+          navigator.appVersion.includes("Android");
         this.isAudioOnly = (this.video instanceof HTMLAudioElement);
         this.setupInitialState();
         this.setupNewLoadState();
         this.initTextTracks();
 
         // Use the handleEvent() callback for all media events.
         // Only the "error" event listener must capture, so that it can trap error
         // events from <source> children, which don't bubble. But we use capture
@@ -1832,153 +1692,57 @@
           elem.addEventListener(eventName, boundFunc, {mozSystemGroup, capture});
         }
 
         addListener(this.muteButton, "click", this.toggleMute);
         addListener(this.closedCaptionButton, "click", this.toggleClosedCaption);
         addListener(this.fullscreenButton, "click", this.toggleFullscreen);
         addListener(this.playButton, "click", this.clickToPlayClickHandler);
         addListener(this.clickToPlay, "click", this.clickToPlayClickHandler);
-        addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
-        addListener(this.controlsSpacer, "dblclick", this.toggleFullscreen);
+
+        // On touch videocontrols, tapping controlsSpacer should show/hide
+        // the control bar, instead of playing the video or toggle fullscreen.
+        if (!this.videocontrols.isTouchControls) {
+          addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
+          addListener(this.controlsSpacer, "dblclick", this.toggleFullscreen);
+        }
 
         addListener(this.videocontrols, "resizevideocontrols", this.adjustControlSize);
         addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
         addListener(this.video.ownerDocument, "mozfullscreenchange", this.onFullscreenChange);
         addListener(this.controlBar, "transitionend", this.onControlBarTransitioned);
         addListener(this.video.ownerDocument, "fullscreenchange", this.onFullscreenChange);
         addListener(this.video, "keypress", this.keyHandler, {capture: true});
         // Prevent any click event within media controls from dispatching through to video.
         addListener(this.videocontrols, "click", function(event) {
           event.stopPropagation();
         }, {mozSystemGroup: false});
         addListener(this.videocontrols, "dragstart", function(event) {
           event.preventDefault(); // prevent dragging of controls image (bug 517114)
         });
 
-        if (!this.videocontrols.isTouchControls) {
-          addListener(this.scrubber, "input", this.onScrubberInput);
-          addListener(this.scrubber, "change", this.onScrubberChange);
-          // add mouseup listener additionally to handle the case that `change` event
-          // isn't fired when the input value before/after dragging are the same. (bug 1328061)
-          addListener(this.scrubber, "mouseup", this.onScrubberChange);
-          addListener(this.volumeControl, "input", this.updateVolume);
-          addListener(this.video.textTracks, "addtrack", this.onTextTrackAdd);
-          addListener(this.video.textTracks, "removetrack", this.onTextTrackRemove);
-          addListener(this.video.textTracks, "change", this.setClosedCaptionButtonState);
-        }
+        addListener(this.scrubber, "input", this.onScrubberInput);
+        addListener(this.scrubber, "change", this.onScrubberChange);
+        // add mouseup listener additionally to handle the case that `change` event
+        // isn't fired when the input value before/after dragging are the same. (bug 1328061)
+        addListener(this.scrubber, "mouseup", this.onScrubberChange);
+        addListener(this.volumeControl, "input", this.updateVolume);
+        addListener(this.video.textTracks, "addtrack", this.onTextTrackAdd);
+        addListener(this.video.textTracks, "removetrack", this.onTextTrackRemove);
+        addListener(this.video.textTracks, "change", this.setClosedCaptionButtonState);
 
         this.log("--- videocontrols initialized ---");
       }
     };
 
-    this.Utils.init(this);
-    ]]>
-  </constructor>
-  <destructor>
-    <![CDATA[
-    this.Utils.terminateEventListeners();
-    this.Utils.updateOrientationState(false);
-    // randomID used to be a <field>, which meant that the XBL machinery
-    // undefined the property when the element was unbound. The code in
-    // this file actually depends on this, so now that randomID is an
-    // expando, we need to make sure to explicitly delete it.
-    delete this.randomID;
-    ]]>
-  </destructor>
-
-  </implementation>
-
-  <handlers>
-    <handler event="mouseover">
-      if (!this.isTouchControls) {
-        this.Utils.onMouseInOut(event);
-      }
-    </handler>
-    <handler event="mouseout">
-      if (!this.isTouchControls) {
-        this.Utils.onMouseInOut(event);
-      }
-    </handler>
-    <handler event="mousemove">
-      if (!this.isTouchControls) {
-        this.Utils.onMouseMove(event);
-      }
-    </handler>
-  </handlers>
-</binding>
-
-<binding id="touchControls" extends="chrome://global/content/bindings/videocontrols.xml#videoControls">
-
-  <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="mediaControlsFrame">
-    <stack flex="1">
-      <vbox anonid="statusOverlay" flex="1" class="statusOverlay" hidden="true">
-        <box anonid="statusIcon" class="statusIcon"/>
-        <label class="errorLabel" anonid="errorAborted">&error.aborted;</label>
-        <label class="errorLabel" anonid="errorNetwork">&error.network;</label>
-        <label class="errorLabel" anonid="errorDecode">&error.decode;</label>
-        <label class="errorLabel" anonid="errorSrcNotSupported">&error.srcNotSupported;</label>
-        <label class="errorLabel" anonid="errorNoSource">&error.noSource2;</label>
-        <label class="errorLabel" anonid="errorGeneric">&error.generic;</label>
-      </vbox>
-
-      <vbox anonid="controlsOverlay" class="controlsOverlay">
-        <spacer anonid="controlsSpacer" class="controlsSpacer" flex="1"/>
-        <box flex="1" hidden="true">
-          <box anonid="clickToPlay" class="clickToPlay" hidden="true" flex="1"/>
-          <vbox anonid="textTrackList" class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></vbox>
-        </box>
-        <vbox anonid="controlBar" class="controlBar" hidden="true">
-          <hbox class="buttonsBar">
-            <button anonid="playButton"
-                    class="playButton"
-                    playlabel="&playButton.playLabel;"
-                    pauselabel="&playButton.pauseLabel;"/>
-            <label anonid="positionLabel" class="positionLabel" role="presentation"/>
-            <stack anonid="scrubberStack" class="scrubberStack">
-              <box class="backgroundBar"/>
-              <progressmeter class="flexibleBar" value="100"/>
-              <progressmeter anonid="bufferBar" class="bufferBar"/>
-              <progressmeter anonid="progressBar" class="progressBar" max="10000"/>
-              <scale anonid="scrubber" class="scrubber" movetoclick="true"/>
-            </stack>
-            <label anonid="durationLabel" class="durationLabel" role="presentation"/>
-            <button anonid="muteButton"
-                    class="muteButton"
-                    mutelabel="&muteButton.muteLabel;"
-                    unmutelabel="&muteButton.unmuteLabel;"/>
-            <stack anonid="volumeStack" class="volumeStack">
-              <box anonid="volumeBackground" class="volumeBackground"/>
-              <box anonid="volumeForeground" class="volumeForeground"/>
-              <scale anonid="volumeControl" class="volumeControl" movetoclick="true"/>
-            </stack>
-            <button anonid="castingButton" class="castingButton" hidden="true"
-                    aria-label="&castingButton.castingLabel;"/>
-            <button anonid="closedCaptionButton" class="closedCaptionButton" hidden="true"/>
-            <button anonid="fullscreenButton"
-                    class="fullscreenButton"
-                    enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
-                    exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
-          </hbox>
-        </vbox>
-      </vbox>
-    </stack>
-  </xbl:content>
-
-  <implementation>
-  <constructor>
-    <![CDATA[
-    this.isTouchControls = true;
     this.TouchUtils = {
       videocontrols: null,
       video: null,
       controlsTimer: null,
       controlsTimeout: 5000,
-      positionLabel: null,
-      castingButton: null,
 
       get Utils() {
         return this.videocontrols.Utils;
       },
 
       get visible() {
         return !this.Utils.controlBar.hasAttribute("fadeout") &&
                !(this.Utils.controlBar.getAttribute("hidden") == "true");
@@ -2048,83 +1812,45 @@
       terminateEventListeners() {
         for (var event of this.videoEvents) {
           try {
             this.Utils.video.removeEventListener(event, this);
           } catch (ex) {}
         }
       },
 
-      isVideoCasting() {
-        return this.video.mozIsCasting;
-      },
-
-      updateCasting(eventDetail) {
-        let castingData = JSON.parse(eventDetail);
-        if ("allow" in castingData) {
-          this.video.mozAllowCasting = !!castingData.allow;
-        }
-
-        if ("active" in castingData) {
-          this.video.mozIsCasting = !!castingData.active;
-        }
-        this.setCastButtonState();
-      },
-
-      startCasting() {
-        this.videocontrols.dispatchEvent(new CustomEvent("VideoBindingCast"));
-      },
-
-      setCastButtonState() {
-        if (this.isAudioOnly || !this.video.mozAllowCasting) {
-          this.castingButton.hidden = true;
-          return;
-        }
-
-        if (this.video.mozIsCasting) {
-          this.castingButton.setAttribute("active", "true");
-        } else {
-          this.castingButton.removeAttribute("active");
-        }
-
-        this.castingButton.hidden = false;
-      },
-
       init(binding) {
         this.videocontrols = binding;
         this.video = binding.parentNode;
 
         let self = this;
-        this.Utils.playButton.addEventListener("command", function() {
+        this.Utils.playButton.addEventListener("click", function() {
           if (!self.video.paused) {
             self.delayHideControls(0);
           } else {
             self.showControls();
           }
         });
         this.Utils.scrubber.addEventListener("touchstart", function() {
           self.clearTimer();
         });
         this.Utils.scrubber.addEventListener("touchend", function() {
           self.delayHideControls(self.controlsTimeout);
         });
         this.Utils.muteButton.addEventListener("click", function() { self.delayHideControls(self.controlsTimeout); });
 
-        this.castingButton = document.getAnonymousElementByAttribute(binding, "anonid", "castingButton");
-        this.castingButton.addEventListener("command", function() {
-          self.startCasting();
+        this.Utils.controlsSpacer.addEventListener("mouseup", function(event) {
+          if (event.originalTarget == self.Utils.controlsSpacer) {
+            if (self.firstShow) {
+              self.Utils.video.play();
+            }
+            self.toggleControls();
+          }
         });
 
-        this.video.addEventListener("media-videoCasting", function(e) {
-          if (!e.isTrusted) {
-            return;
-          }
-          self.updateCasting(e.detail);
-        }, false, true);
-
         // The first time the controls appear we want to just display
         // a play button that does not fade away. The firstShow property
         // makes that happen. But because of bug 718107 this init() method
         // may be called again when we switch in or out of fullscreen
         // mode. So we only set firstShow if we're not autoplaying and
         // if we are at the beginning of the video and not already playing
         if (!this.video.autoplay && this.Utils.dynamicControls && this.video.paused &&
             this.video.currentTime === 0) {
@@ -2136,47 +1862,60 @@
         // the controls to remain visible. this.controlsTimeout is a full
         // 5s, which feels too long after the transition.
         if (this.video.currentTime !== 0) {
           this.delayHideControls(this.Utils.HIDE_CONTROLS_TIMEOUT_MS);
         }
       }
     };
 
-    this.TouchUtils.init(this);
+    this.Utils.init(this);
+    if (this.isTouchControls) {
+      this.TouchUtils.init(this);
+    }
     this.dispatchEvent(new CustomEvent("VideoBindingAttached"));
     ]]>
   </constructor>
   <destructor>
     <![CDATA[
-    // XBL destructors don't appear to be inherited properly, so we need
-    // to do this here in addition to the videoControls destructor. :-(
+    this.Utils.terminateEventListeners();
+    this.Utils.updateOrientationState(false);
+    // randomID used to be a <field>, which meant that the XBL machinery
+    // undefined the property when the element was unbound. The code in
+    // this file actually depends on this, so now that randomID is an
+    // expando, we need to make sure to explicitly delete it.
     delete this.randomID;
     ]]>
   </destructor>
 
   </implementation>
 
   <handlers>
-    <handler event="mouseup">
-      if (event.originalTarget.nodeName == "vbox") {
-        if (this.TouchUtils.firstShow) {
-          this.Utils.video.play();
-        }
-        this.TouchUtils.toggleControls();
+    <handler event="mouseover">
+      if (!this.isTouchControls) {
+        this.Utils.onMouseInOut(event);
+      }
+    </handler>
+    <handler event="mouseout">
+      if (!this.isTouchControls) {
+        this.Utils.onMouseInOut(event);
+      }
+    </handler>
+    <handler event="mousemove">
+      if (!this.isTouchControls) {
+        this.Utils.onMouseMove(event);
       }
     </handler>
   </handlers>
-
 </binding>
 
 <binding id="noControls">
 
   <resources>
-    <stylesheet src="chrome://global/skin/media/videocontrols-html.css"/>
+    <stylesheet src="chrome://global/skin/media/videocontrols.css"/>
   </resources>
 
   <xbl:content xmlns="http://www.w3.org/1999/xhtml" class="mediaControlsFrame">
     <div anonid="controlsContainer" class="controlsContainer" role="none" hidden="true">
       <div class="controlsOverlay stackItem">
         <div class="controlsSpacerStack">
           <div anonid="clickToPlay" class="clickToPlay"></div>
         </div>
deleted file mode 100644
index 2725eb5fbf30af06b71458a44c51b1a34b756bd9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/toolkit/themes/mobile/global/media/videoClickToPlayButton.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMinYMin meet" viewBox="0 0 64 64">
-  <defs>
-    <linearGradient id="whiteGradientStops">
-      <stop style="stop-color:#fff;stop-opacity:.95" offset="0"/>
-      <stop style="stop-color:#fff;stop-opacity:.75" offset=".45"/>
-      <stop style="stop-color:#fff;stop-opacity:.72" offset=".55"/>
-      <stop style="stop-color:#fff;stop-opacity:.65" offset="1"/>
-    </linearGradient>
-    <linearGradient x1="32" y1="0" x2="32" y2="62" id="whiteGradient" xlink:href="#whiteGradientStops" gradientUnits="userSpaceOnUse"/>
-    <linearGradient id="arrowGradientStops">
-      <stop style="stop-color:#333;stop-opacity:.5" offset="0"/>
-      <stop style="stop-color:#666;stop-opacity:.5" offset="1"/>
-    </linearGradient>
-    <linearGradient x1="32" y1="16" x2="32" y2="48" id="arrowGradient" xlink:href="#arrowGradientStops" gradientUnits="userSpaceOnUse"/>
-    <filter x="-0.15" y="-0.15" width="1.25" height="1.25" color-interpolation-filters="sRGB" id="dropShadow">
-      <feDropShadow dx="0" dy="1" flood-opacity="0.5"/>
-    </filter>
-    <mask id="dropShadowMask">
-      <path style="fill:#fff;" d="M47.285,30.991L23.75,17.24c-0.357-0.208-0.692-0.278-0.969-0.221 C22.32,17.115,22,17.555,22,18.252v27.499c0,1.112,0.797,1.568,1.75,1.011l23.535-13.748C48.238,32.458,48.238,31.547,47.285,30.991 z M0,0v64h64V0H0z M32,60C16.536,60,4,47.464,4,32S16.536,4,32,4s28,12.536,28,28S47.464,60,32,60z"/>
-    </mask>
-  </defs>
-  <path mask="url(#dropShadowMask)" id="playButtonShadow" style="filter:url(#dropShadow);" d="M32,4C16.536,4,4,16.536,4,32s12.536,28,28,28s28-12.536,28-28S47.464,4,32,4z M47.285,33.014 L23.75,46.762C22.797,47.319,22,46.863,22,45.751v-27.5c0-0.697,0.32-1.137,0.781-1.232c0.277-0.058,0.612,0.012,0.969,0.221 l23.535,13.751C48.238,31.546,48.238,32.458,47.285,33.014z"/>
-  <path id="playButtonArrow" style="fill:url(#arrowGradient);" d="M22.781,17.019C22.32,17.114,22,17.555,22,18.251v27.5c0,1.112,0.797,1.568,1.75,1.011 l23.535-13.748c0.953-0.556,0.953-1.467,0-2.023L23.75,17.24C23.393,17.031,23.058,16.961,22.781,17.019z"/>
-  <path id="playButton" style="fill:url(#whiteGradient);" d="M32,4C16.536,4,4,16.536,4,32s12.536,28,28,28s28-12.536,28-28S47.464,4,32,4z M47.285,33.014 L23.75,46.762C22.797,47.319,22,46.863,22,45.751v-27.5c0-0.697,0.32-1.137,0.781-1.232c0.277-0.058,0.612,0.012,0.969,0.221 l23.535,13.751C48.238,31.546,48.238,32.458,47.285,33.014z"/>
-  <path id="playButtonEdgeHighlights" style="fill:white;fill-opacity:.3;" d="M32,4C16.536,4,4,16.536,4,32s12.536,28,28,28s28-12.536,28-28S47.464,4,32,4z M32,59C17.112,59,5,46.888,5,32S17.112,5,32,5s27,12.112,27,27S46.888,59,32,59z M47.789,30.127l-23.534-13.75 C23.826,16.126,23.396,16,22.976,16c-0.135,0-0.27,0.014-0.398,0.041C21.62,16.238,21,17.106,21,18.251v27.5 C21,47.075,21.812,48,22.977,48c0.423,0,0.854-0.126,1.279-0.375L47.79,33.877c0.769-0.449,1.21-1.132,1.21-1.875 S48.559,30.576,47.789,30.127z M47.285,33.014L23.75,46.762C23.474,46.924,23.211,47,22.977,47C22.402,47,22,46.541,22,45.751v-27.5 c0-0.697,0.32-1.137,0.781-1.232L22.976,17c0.233,0,0.498,0.079,0.775,0.24l23.535,13.751 C48.238,31.546,48.238,32.458,47.285,33.014z"/>
-  <path id="playButtonTopEdgeHighlights" style="fill:white;fill-opacity:.8;" d="M32,4C16.536,4,4,16.536,4,32c0,0.167,0.01,0.333,0.013,0.5 C4.28,17.268,16.704,5,32,5c15.296,0,27.72,12.268,27.987,27.5C59.99,32.333,60,32.167,60,32C60,16.536,47.464,4,32,4z M47.285,33.014L23.75,46.762C22.797,47.319,22,46.863,22,45.751v1c0,1.112,0.797,1.568,1.75,1.011l23.535-13.748 c0.697-0.406,0.879-1.003,0.556-1.512C47.723,32.688,47.541,32.864,47.285,33.014z"/>
-</svg>
--- a/toolkit/themes/mobile/jar.mn
+++ b/toolkit/themes/mobile/jar.mn
@@ -27,27 +27,33 @@ toolkit.jar:
    skin/classic/global/tabbox.css                          (global/empty.css)
    skin/classic/global/textbox.css                         (global/empty.css)
    skin/classic/global/toolbar.css                         (global/empty.css)
    skin/classic/global/toolbarbutton.css                   (global/empty.css)
    skin/classic/global/tree.css                            (global/empty.css)
    skin/classic/global/wizard.css                          (global/empty.css)
    skin/classic/global/scrollbars.css                      (global/empty.css)
 
-   skin/classic/global/media/clicktoplay-bgtexture.png     (global/media/clicktoplay-bgtexture.png)
-   skin/classic/global/media/error.png                     (global/media/error.png)
-   skin/classic/global/media/throbber.png                  (global/media/throbber.png)
-   skin/classic/global/media/videoClickToPlayButton.svg    (global/media/videoClickToPlayButton.svg)
    skin/classic/global/media/TopLevelImageDocument.css     (global/media/TopLevelImageDocument.css)
    skin/classic/global/media/TopLevelVideoDocument.css     (global/media/TopLevelVideoDocument.css)
    skin/classic/global/media/imagedoc-lightnoise.png       (global/media/imagedoc-lightnoise.png)
    skin/classic/global/media/imagedoc-darknoise.png        (global/media/imagedoc-darknoise.png)
 
-* skin/classic/global/media/videocontrols-html.css         (../shared/media/videocontrols.css)
+* skin/classic/global/media/videocontrols.css              (../shared/media/videocontrols.css)
+  skin/classic/global/media/pauseButton.svg                (../shared/media/pauseButton.svg)
   skin/classic/global/media/playButton.svg                 (../shared/media/playButton.svg)
+  skin/classic/global/media/error.png                      (../shared/media/error.png)
+  skin/classic/global/media/throbber.png                   (../shared/media/throbber.png)
+  skin/classic/global/media/stalled.png                    (../shared/media/stalled.png)
+  skin/classic/global/media/audioMutedButton.svg           (../shared/media/audioMutedButton.svg)
+  skin/classic/global/media/audioNoAudioButton.svg         (../shared/media/audioNoAudioButton.svg)
+  skin/classic/global/media/audioUnmutedButton.svg         (../shared/media/audioUnmutedButton.svg)
+  skin/classic/global/media/closedCaptionButton-cc-off.svg (../shared/media/closedCaptionButton-cc-off.svg)
+  skin/classic/global/media/closedCaptionButton-cc-on.svg  (../shared/media/closedCaptionButton-cc-on.svg)
+  skin/classic/global/media/fullscreenEnterButton.svg      (../shared/media/fullscreenEnterButton.svg)
 
 % skin mozapps classic/1.0 %skin/classic/mozapps/
    skin/classic/mozapps/plugins/pluginProblem.css          (mozapps/plugins/pluginProblem.css)
 
    skin/classic/mozapps/plugins/contentPluginActivate.png  (mozapps/plugins/contentPluginActivate.png)
    skin/classic/mozapps/plugins/contentPluginBlocked.png   (mozapps/plugins/contentPluginBlocked.png)
    skin/classic/mozapps/plugins/contentPluginClose.png     (mozapps/plugins/contentPluginClose.png)
    skin/classic/mozapps/plugins/contentPluginCrashed.png   (mozapps/plugins/contentPluginCrashed.png)