Bug 1796551 [wpt PR 36570] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / toolkit / actors / PopupBlockingChild.jsm
blob04c47bde80bd48c407ff6488faed528d93ca1e53
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
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 /* eslint no-unused-vars: ["error", {args: "none"}] */
8 var EXPORTED_SYMBOLS = ["PopupBlockingChild"];
10 // The maximum number of popup information we'll send to the parent.
11 const MAX_SENT_POPUPS = 15;
13 const { XPCOMUtils } = ChromeUtils.importESModule(
14   "resource://gre/modules/XPCOMUtils.sys.mjs"
17 class PopupBlockingChild extends JSWindowActorChild {
18   constructor() {
19     super();
20     this.weakDocStates = new WeakMap();
21   }
23   /**
24    * Returns the state for the current document referred to via
25    * this.document. If no such state exists, creates it, stores it
26    * and returns it.
27    */
28   get docState() {
29     let state = this.weakDocStates.get(this.document);
30     if (!state) {
31       state = {
32         popupData: [],
33       };
34       this.weakDocStates.set(this.document, state);
35     }
37     return state;
38   }
40   receiveMessage(msg) {
41     switch (msg.name) {
42       case "UnblockPopup": {
43         let i = msg.data.index;
44         let state = this.docState;
45         let popupData = state.popupData[i];
46         if (popupData) {
47           let dwi = popupData.requestingWindow;
49           // If we have a requesting window and the requesting document is
50           // still the current document, open the popup.
51           if (dwi && dwi.document == popupData.requestingDocument) {
52             dwi.open(
53               popupData.popupWindowURISpec,
54               popupData.popupWindowName,
55               popupData.popupWindowFeatures
56             );
57           }
58         }
59         break;
60       }
62       case "GetBlockedPopupList": {
63         let state = this.docState;
64         let length = Math.min(state.popupData.length, MAX_SENT_POPUPS);
66         let result = [];
68         for (let i = 0; i < length; ++i) {
69           let popup = state.popupData[i];
71           let popupWindowURISpec = popup.popupWindowURISpec;
73           if (this.contentWindow.location.href == popupWindowURISpec) {
74             popupWindowURISpec = "<self>";
75           } else {
76             // Limit 500 chars to be sent because the URI will be cropped
77             // by the UI anyway, and data: URIs can be significantly larger.
78             popupWindowURISpec = popupWindowURISpec.substring(0, 500);
79           }
81           result.push({
82             popupWindowURISpec,
83           });
84         }
86         return result;
87       }
88     }
90     return null;
91   }
93   handleEvent(event) {
94     switch (event.type) {
95       case "DOMPopupBlocked":
96         this.onPopupBlocked(event);
97         break;
98       case "pageshow": {
99         this.onPageShow(event);
100         break;
101       }
102     }
103   }
105   onPopupBlocked(event) {
106     if (event.target != this.document) {
107       return;
108     }
110     let state = this.docState;
112     // Avoid spamming the parent process with too many blocked popups.
113     if (state.popupData.length >= PopupBlockingChild.maxReportedPopups) {
114       return;
115     }
117     let popup = {
118       popupWindowURISpec: event.popupWindowURI
119         ? event.popupWindowURI.spec
120         : "about:blank",
121       popupWindowFeatures: event.popupWindowFeatures,
122       popupWindowName: event.popupWindowName,
123       requestingWindow: event.requestingWindow,
124       requestingDocument: event.requestingWindow.document,
125     };
127     state.popupData.push(popup);
128     this.updateBlockedPopups(true);
129   }
131   onPageShow(event) {
132     if (event.target != this.document) {
133       return;
134     }
136     this.updateBlockedPopups(false);
137   }
139   updateBlockedPopups(shouldNotify) {
140     this.sendAsyncMessage("UpdateBlockedPopups", {
141       shouldNotify,
142       count: this.docState.popupData.length,
143     });
144   }
147 XPCOMUtils.defineLazyPreferenceGetter(
148   PopupBlockingChild,
149   "maxReportedPopups",
150   "privacy.popups.maxReported"