Bug 1822393 - Consume GeckoView directly in Android Components for CI builds. r=owlis...
[gecko.git] / browser / actors / DOMFullscreenChild.sys.mjs
blob4088def44b869da7bcadaa0d3b34ca826becf393
1 /* vim: set ts=2 sw=2 sts=2 et tw=80: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 export class DOMFullscreenChild extends JSWindowActorChild {
7   receiveMessage(aMessage) {
8     let window = this.contentWindow;
9     let windowUtils = window?.windowUtils;
11     switch (aMessage.name) {
12       case "DOMFullscreen:Entered": {
13         if (!windowUtils) {
14           // If we are not able to enter fullscreen, tell the parent to just
15           // exit.
16           this.sendAsyncMessage("DOMFullscreen:Exit", {});
17           break;
18         }
20         let remoteFrameBC = aMessage.data.remoteFrameBC;
21         if (remoteFrameBC) {
22           let remoteFrame = remoteFrameBC.embedderElement;
23           if (!remoteFrame) {
24             // This could happen when the page navigate away and trigger a
25             // process switching during fullscreen transition, tell the parent
26             // to just exit.
27             this.sendAsyncMessage("DOMFullscreen:Exit", {});
28             break;
29           }
30           this._isNotTheRequestSource = true;
31           windowUtils.remoteFrameFullscreenChanged(remoteFrame);
32         } else {
33           this._waitForMozAfterPaint = true;
34           this._lastTransactionId = windowUtils.lastTransactionId;
35           if (
36             !windowUtils.handleFullscreenRequests() &&
37             !this.document.fullscreenElement
38           ) {
39             // If we don't actually have any pending fullscreen request
40             // to handle, neither we have been in fullscreen, tell the
41             // parent to just exit.
42             this.sendAsyncMessage("DOMFullscreen:Exit", {});
43           }
44         }
45         break;
46       }
47       case "DOMFullscreen:CleanUp": {
48         let isNotTheRequestSource = !!aMessage.data.remoteFrameBC;
49         // If we've exited fullscreen at this point, no need to record
50         // transaction id or call exit fullscreen. This is especially
51         // important for pre-e10s, since in that case, it is possible
52         // that no more paint would be triggered after this point.
53         if (this.document.fullscreenElement) {
54           this._isNotTheRequestSource = isNotTheRequestSource;
55           // Need to wait for the MozAfterPaint after exiting fullscreen if
56           // this is the request source.
57           this._waitForMozAfterPaint = !this._isNotTheRequestSource;
58           // windowUtils could be null if the associated window is not current
59           // active window. In this case, document must be in the process of
60           // exiting fullscreen, it is okay to not ask it to exit fullscreen.
61           if (windowUtils) {
62             this._lastTransactionId = windowUtils.lastTransactionId;
63             windowUtils.exitFullscreen();
64           }
65         } else if (isNotTheRequestSource) {
66           // If we are not the request source and have exited fullscreen, reply
67           // Exited to parent as parent is waiting for our reply.
68           this.sendAsyncMessage("DOMFullscreen:Exited", {});
69         } else {
70           // If we've already exited fullscreen, it is possible that no more
71           // paint would be triggered, so don't wait for MozAfterPaint.
72           // TODO: There might be some way to move this code around a bit to
73           //       make it easier to follow. Somehow handle the "local" case in
74           //       one place and the isNotTheRequestSource case after that.
75           this.sendAsyncMessage("DOMFullscreen:Painted", {});
76         }
77         break;
78       }
79       case "DOMFullscreen:Painted": {
80         Services.obs.notifyObservers(window, "fullscreen-painted");
81         break;
82       }
83     }
84   }
86   handleEvent(aEvent) {
87     if (this.hasBeenDestroyed()) {
88       // Make sure that this actor is alive before going further because
89       // if it's not the case, any attempt to send a message or access
90       // objects such as 'contentWindow' will fail. (See bug 1590138)
91       return;
92     }
94     switch (aEvent.type) {
95       case "MozDOMFullscreen:Request": {
96         this.sendAsyncMessage("DOMFullscreen:Request", {});
97         break;
98       }
99       case "MozDOMFullscreen:NewOrigin": {
100         this.sendAsyncMessage("DOMFullscreen:NewOrigin", {
101           originNoSuffix: aEvent.target.nodePrincipal.originNoSuffix,
102         });
103         break;
104       }
105       case "MozDOMFullscreen:Exit": {
106         this.sendAsyncMessage("DOMFullscreen:Exit", {});
107         break;
108       }
109       case "MozDOMFullscreen:Entered":
110       case "MozDOMFullscreen:Exited": {
111         if (this._isNotTheRequestSource) {
112           // Fullscreen change event for a frame in the
113           // middle (content frame embedding the oop frame where the
114           // request comes from)
116           delete this._isNotTheRequestSource;
117           this.sendAsyncMessage(aEvent.type.replace("Moz", ""), {});
118           break;
119         }
121         if (this._waitForMozAfterPaint) {
122           delete this._waitForMozAfterPaint;
123           this._listeningWindow = this.contentWindow.windowRoot;
124           this._listeningWindow.addEventListener("MozAfterPaint", this);
125         }
127         if (!this.document || !this.document.fullscreenElement) {
128           // If we receive any fullscreen change event, and find we are
129           // actually not in fullscreen, also ask the parent to exit to
130           // ensure that the parent always exits fullscreen when we do.
131           this.sendAsyncMessage("DOMFullscreen:Exit", {});
132         }
133         break;
134       }
135       case "MozAfterPaint": {
136         // Only send Painted signal after we actually finish painting
137         // the transition for the fullscreen change.
138         // Note that this._lastTransactionId is not set when in pre-e10s
139         // mode, so we need to check that explicitly.
140         if (
141           !this._lastTransactionId ||
142           aEvent.transactionId > this._lastTransactionId
143         ) {
144           this._listeningWindow.removeEventListener("MozAfterPaint", this);
145           delete this._listeningWindow;
146           this.sendAsyncMessage("DOMFullscreen:Painted", {});
147         }
148         break;
149       }
150     }
151   }
153   hasBeenDestroyed() {
154     // The 'didDestroy' callback is not always getting called.
155     // So we can't rely on it here. Instead, we will try to access
156     // the browsing context to judge wether the actor has
157     // been destroyed or not.
158     try {
159       return !this.browsingContext;
160     } catch {
161       return true;
162     }
163   }