[Modern Media Controls] Implement the pageScaleFactor property
[WebKit-https.git] / Source / WebCore / Modules / modern-media-controls / media / media-controller.js
1 /*
2  * Copyright (C) 2016 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 class MediaController
27 {
28
29     constructor(shadowRoot, media, host)
30     {
31         this.shadowRoot = shadowRoot;
32         this.media = media;
33         this.host = host;
34
35         this.container = shadowRoot.appendChild(document.createElement("div"));
36         this.container.className = "media-controls-container";
37
38         if (host) {
39             host.controlsDependOnPageScaleFactor = this.layoutTraits & LayoutTraits.iOS;
40             this.container.appendChild(host.textTrackContainer);
41         }
42
43         this._updateControlsIfNeeded();
44
45         shadowRoot.addEventListener("resize", this);
46
47         if (media.webkitSupportsPresentationMode)
48             media.addEventListener("webkitpresentationmodechanged", this);
49         else
50             media.addEventListener("webkitfullscreenchange", this);
51     }
52
53     get layoutTraits()
54     {
55         let traits = window.navigator.platform === "MacIntel" ? LayoutTraits.macOS : LayoutTraits.iOS;
56         if (this.media.webkitSupportsPresentationMode) {
57             if (this.media.webkitPresentationMode === "fullscreen")
58                 return traits | LayoutTraits.Fullscreen;
59         } else if (this.media.webkitDisplayingFullscreen)
60             return traits | LayoutTraits.Fullscreen;
61         return traits;
62     }
63
64     // Protected
65
66     set pageScaleFactor(pageScaleFactor)
67     {
68         this.controls.scaleFactor = pageScaleFactor;
69         this._updateControlsSize();
70     }
71
72     set usesLTRUserInterfaceLayoutDirection(flag)
73     {
74         this.controls.usesLTRUserInterfaceLayoutDirection = flag;
75     }
76
77     handleEvent(event)
78     {
79         if (event.type === "resize" && event.currentTarget === this.shadowRoot)
80             this._updateControlsSize();
81         else if (event.currentTarget === this.media) {
82             this._updateControlsIfNeeded();
83             if (event.type === "webkitpresentationmodechanged")
84                 this._returnMediaLayerToInlineIfNeeded();
85         }
86     }
87
88     // Private
89
90     _updateControlsIfNeeded()
91     {
92         const previousControls = this.controls;
93         const ControlsClass = this._controlsClass();
94         if (previousControls && previousControls.constructor === ControlsClass)
95             return;
96
97         // Before we reset the .controls property, we need to destroy the previous
98         // supporting objects so we don't leak.
99         if (this._supportingObjects) {
100             for (let supportingObject of this._supportingObjects)
101                 supportingObject.destroy();
102         }
103
104         this.controls = new ControlsClass;
105
106         if (this.shadowRoot.host && this.shadowRoot.host.dataset.autoHideDelay)
107             this.controls.controlsBar.autoHideDelay = this.shadowRoot.host.dataset.autoHideDelay;
108
109         if (previousControls) {
110             this.controls.fadeIn();
111             this.container.replaceChild(this.controls.element, previousControls.element);
112             this.controls.usesLTRUserInterfaceLayoutDirection = previousControls.usesLTRUserInterfaceLayoutDirection;
113         } else
114             this.container.appendChild(this.controls.element);        
115
116         this._updateControlsSize();
117
118         this._supportingObjects = [AirplaySupport, ControlsVisibilitySupport, ElapsedTimeSupport, FullscreenSupport, MuteSupport, PiPSupport, PlacardSupport, PlaybackSupport, RemainingTimeSupport, ScrubbingSupport, SeekBackwardSupport, SeekForwardSupport, SkipBackSupport, StartSupport, StatusSupport, TracksSupport, VolumeSupport].map(SupportClass => {
119             return new SupportClass(this);
120         }, this);
121     }
122
123     _updateControlsSize()
124     {
125         this.controls.width = Math.round(this.media.offsetWidth * this.controls.scaleFactor);
126         this.controls.height = Math.round(this.media.offsetHeight * this.controls.scaleFactor);
127     }
128
129     _returnMediaLayerToInlineIfNeeded()
130     {
131         if (this.host)
132             window.requestAnimationFrame(() => this.host.setPreparedToReturnVideoLayerToInline(this.media.webkitPresentationMode !== PiPMode));
133     }
134
135     _controlsClass()
136     {
137         const layoutTraits = this.layoutTraits;
138         if (layoutTraits & LayoutTraits.iOS)
139             return IOSInlineMediaControls;
140         if (layoutTraits & LayoutTraits.Fullscreen)
141             return MacOSFullscreenMediaControls;
142         return MacOSInlineMediaControls;
143     }
144
145 }