... |
... |
@@ -22,16 +22,110 @@ const kPrefLetterboxingTesting = |
22
|
22
|
"privacy.resistFingerprinting.letterboxing.testing";
|
23
|
23
|
const kTopicDOMWindowOpened = "domwindowopened";
|
24
|
24
|
|
25
|
|
-var logConsole;
|
26
|
|
-function log(msg) {
|
27
|
|
- if (!logConsole) {
|
28
|
|
- logConsole = console.createInstance({
|
29
|
|
- prefix: "RFPHelper.jsm",
|
30
|
|
- maxLogLevelPref: "privacy.resistFingerprinting.jsmloglevel",
|
31
|
|
- });
|
|
25
|
+const kPrefResizeWarnings = "privacy.resistFingerprinting.resizeWarnings";
|
|
26
|
+
|
|
27
|
+XPCOMUtils.defineLazyGetter(this, "logConsole", () =>
|
|
28
|
+ console.createInstance({
|
|
29
|
+ prefix: "RFPHelper.jsm",
|
|
30
|
+ maxLogLevelPref: "privacy.resistFingerprinting.jsmloglevel",
|
|
31
|
+ })
|
|
32
|
+);
|
|
33
|
+
|
|
34
|
+function log(...args) {
|
|
35
|
+ logConsole.log(...args);
|
|
36
|
+}
|
|
37
|
+
|
|
38
|
+function forEachWindow(callback) {
|
|
39
|
+ const windowList = Services.wm.getEnumerator("navigator:browser");
|
|
40
|
+ while (windowList.hasMoreElements()) {
|
|
41
|
+ const win = windowList.getNext();
|
|
42
|
+ if (win.gBrowser && !win.closed) {
|
|
43
|
+ try {
|
|
44
|
+ callback(win);
|
|
45
|
+ } catch (e) {
|
|
46
|
+ logConsole.error(e);
|
|
47
|
+ }
|
|
48
|
+ }
|
|
49
|
+ }
|
|
50
|
+}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+async function windowResizeHandler(aEvent) {
|
|
54
|
+ if (RFPHelper.letterboxingEnabled) {
|
|
55
|
+ return;
|
|
56
|
+ }
|
|
57
|
+ if (Services.prefs.getIntPref(kPrefResizeWarnings, 3) <= 0) {
|
|
58
|
+ return;
|
|
59
|
+ }
|
|
60
|
+
|
|
61
|
+ const window = aEvent.currentTarget;
|
|
62
|
+
|
|
63
|
+ // Wait for end of execution queue to ensure we have correct windowState.
|
|
64
|
+ await new Promise(resolve => window.setTimeout(resolve, 0));
|
|
65
|
+ switch (window.windowState) {
|
|
66
|
+ case window.STATE_MAXIMIZED:
|
|
67
|
+ case window.STATE_FULLSCREEN:
|
|
68
|
+ break;
|
|
69
|
+ default:
|
|
70
|
+ return;
|
|
71
|
+ }
|
|
72
|
+
|
|
73
|
+ // Do not add another notification if one is already showing.
|
|
74
|
+ const kNotificationName = "rfp-window-resize-notification";
|
|
75
|
+ let box = window.gNotificationBox;
|
|
76
|
+ if (box.getNotificationWithValue(kNotificationName)) {
|
|
77
|
+ return;
|
32
|
78
|
}
|
33
|
79
|
|
34
|
|
- logConsole.log(msg);
|
|
80
|
+ // Rate-limit showing our notification if needed.
|
|
81
|
+ if (Date.now() - (windowResizeHandler.timestamp || 0) < 1000) {
|
|
82
|
+ return;
|
|
83
|
+ }
|
|
84
|
+ windowResizeHandler.timestamp = Date.now();
|
|
85
|
+
|
|
86
|
+ const decreaseWarningsCount = () => {
|
|
87
|
+ const currentCount = Services.prefs.getIntPref(kPrefResizeWarnings);
|
|
88
|
+ if (currentCount > 0) {
|
|
89
|
+ Services.prefs.setIntPref(kPrefResizeWarnings, currentCount - 1);
|
|
90
|
+ }
|
|
91
|
+ };
|
|
92
|
+
|
|
93
|
+ const [label, accessKey] = await window.document.l10n.formatValues([
|
|
94
|
+ { id: "basebrowser-rfp-restore-window-size-button-label" },
|
|
95
|
+ { id: "basebrowser-rfp-restore-window-size-button-ak" },
|
|
96
|
+ ]);
|
|
97
|
+
|
|
98
|
+ const buttons = [
|
|
99
|
+ {
|
|
100
|
+ label,
|
|
101
|
+ accessKey,
|
|
102
|
+ popup: null,
|
|
103
|
+ callback() {
|
|
104
|
+ // reset notification timer to work-around resize race conditions
|
|
105
|
+ windowResizeHandler.timestamp = Date.now();
|
|
106
|
+ // restore the original (rounded) size we had stored on window startup
|
|
107
|
+ let { _rfpOriginalSize } = window;
|
|
108
|
+ window.setTimeout(() => {
|
|
109
|
+ window.resizeTo(_rfpOriginalSize.width, _rfpOriginalSize.height);
|
|
110
|
+ }, 0);
|
|
111
|
+ },
|
|
112
|
+ },
|
|
113
|
+ ];
|
|
114
|
+
|
|
115
|
+ box.appendNotification(
|
|
116
|
+ kNotificationName,
|
|
117
|
+ {
|
|
118
|
+ label: { "l10n-id": "basebrowser-rfp-maximize-warning-message" },
|
|
119
|
+ priority: box.PRIORITY_WARNING_LOW,
|
|
120
|
+ eventCallback(event) {
|
|
121
|
+ if (event === "dismissed") {
|
|
122
|
+ // user manually dismissed the notification
|
|
123
|
+ decreaseWarningsCount();
|
|
124
|
+ }
|
|
125
|
+ },
|
|
126
|
+ },
|
|
127
|
+ buttons
|
|
128
|
+ );
|
35
|
129
|
}
|
36
|
130
|
|
37
|
131
|
class _RFPHelper {
|
... |
... |
@@ -158,7 +252,11 @@ class _RFPHelper { |
158
|
252
|
_handleResistFingerprintingChanged() {
|
159
|
253
|
if (Services.prefs.getBoolPref(kPrefResistFingerprinting)) {
|
160
|
254
|
this._addRFPObservers();
|
|
255
|
+ Services.ww.registerNotification(this);
|
|
256
|
+ forEachWindow(win => this._attachWindow(win));
|
161
|
257
|
} else {
|
|
258
|
+ forEachWindow(win => this._detachWindow(win));
|
|
259
|
+ Services.ww.unregisterNotification(this);
|
162
|
260
|
this._removeRFPObservers();
|
163
|
261
|
}
|
164
|
262
|
}
|
... |
... |
@@ -295,13 +393,11 @@ class _RFPHelper { |
295
|
393
|
}
|
296
|
394
|
|
297
|
395
|
_handleLetterboxingPrefChanged() {
|
298
|
|
- if (Services.prefs.getBoolPref(kPrefLetterboxing, false)) {
|
299
|
|
- Services.ww.registerNotification(this);
|
300
|
|
- this._attachAllWindows();
|
301
|
|
- } else {
|
302
|
|
- this._detachAllWindows();
|
303
|
|
- Services.ww.unregisterNotification(this);
|
304
|
|
- }
|
|
396
|
+ this.letterboxingEnabled = Services.prefs.getBoolPref(
|
|
397
|
+ kPrefLetterboxing,
|
|
398
|
+ false
|
|
399
|
+ );
|
|
400
|
+ forEachWindow(win => this._updateSizeForTabsInWindow(win));
|
305
|
401
|
}
|
306
|
402
|
|
307
|
403
|
// The function to parse the dimension set from the pref value. The pref value
|
... |
... |
@@ -402,11 +498,13 @@ class _RFPHelper { |
402
|
498
|
let logPrefix = `_roundContentSize[${Math.random()}]`;
|
403
|
499
|
log(logPrefix);
|
404
|
500
|
let win = aBrowser.ownerGlobal;
|
|
501
|
+
|
405
|
502
|
let browserContainer = aBrowser
|
406
|
503
|
.getTabBrowser()
|
407
|
504
|
.getBrowserContainer(aBrowser);
|
408
|
505
|
let browserParent = aBrowser.parentElement;
|
409
|
506
|
browserParent.classList.remove("exclude-letterboxing");
|
|
507
|
+
|
410
|
508
|
let [
|
411
|
509
|
[contentWidth, contentHeight],
|
412
|
510
|
[parentWidth, parentHeight],
|
... |
... |
@@ -419,6 +517,27 @@ class _RFPHelper { |
419
|
517
|
])
|
420
|
518
|
);
|
421
|
519
|
|
|
520
|
+ if (
|
|
521
|
+ !win._rfpSizeOffset ||
|
|
522
|
+ (win._rfpOriginalSize &&
|
|
523
|
+ win.outerWidth === win._rfpOriginalSize.width &&
|
|
524
|
+ win.outerHeight === win._rfpOriginalSize.height)
|
|
525
|
+ ) {
|
|
526
|
+ const BASELINE_ROUNDING = 10;
|
|
527
|
+ const offset = s =>
|
|
528
|
+ s - Math.round(s / BASELINE_ROUNDING) * BASELINE_ROUNDING;
|
|
529
|
+
|
|
530
|
+ win._rfpSizeOffset = {
|
|
531
|
+ width: offset(parentWidth),
|
|
532
|
+ height: offset(parentHeight),
|
|
533
|
+ };
|
|
534
|
+ log(
|
|
535
|
+ `${logPrefix} Window size offsets %o (from %s, %s)`,
|
|
536
|
+ win._rfpSizeOffset,
|
|
537
|
+ parentWidth,
|
|
538
|
+ parentHeight
|
|
539
|
+ );
|
|
540
|
+ }
|
422
|
541
|
log(
|
423
|
542
|
`${logPrefix} contentWidth=${contentWidth} contentHeight=${contentHeight} parentWidth=${parentWidth} parentHeight=${parentHeight} containerWidth=${containerWidth} containerHeight=${containerHeight}${
|
424
|
543
|
isNewTab ? " (new tab)." : "."
|
... |
... |
@@ -437,6 +556,16 @@ class _RFPHelper { |
437
|
556
|
});
|
438
|
557
|
|
439
|
558
|
let result;
|
|
559
|
+
|
|
560
|
+ if (!this.letterboxingEnabled) {
|
|
561
|
+ const offset = win._rfpSizeOffset;
|
|
562
|
+ result = r(aWidth - offset.width, aHeight - offset.height);
|
|
563
|
+ log(
|
|
564
|
+ `${logPrefix} Letterboxing disabled, applying baseline rounding offsets: (${aWidth}, ${aHeight}) => ${result.width} x ${result.height})`
|
|
565
|
+ );
|
|
566
|
+ return result;
|
|
567
|
+ }
|
|
568
|
+
|
440
|
569
|
log(`${logPrefix} roundDimensions(${aWidth}, ${aHeight})`);
|
441
|
570
|
// If the set is empty, we will round the content with the default
|
442
|
571
|
// stepping size.
|
... |
... |
@@ -554,7 +683,6 @@ class _RFPHelper { |
554
|
683
|
|
555
|
684
|
_updateSizeForTabsInWindow(aWindow) {
|
556
|
685
|
let tabBrowser = aWindow.gBrowser;
|
557
|
|
-
|
558
|
686
|
tabBrowser.tabpanels?.classList.add("letterboxing");
|
559
|
687
|
|
560
|
688
|
for (let tab of tabBrowser.tabs) {
|
... |
... |
@@ -564,10 +692,18 @@ class _RFPHelper { |
564
|
692
|
// we need to add this class late because otherwise new windows get maximized
|
565
|
693
|
aWindow.setTimeout(() => {
|
566
|
694
|
tabBrowser.tabpanels?.classList.add("letterboxing-ready");
|
|
695
|
+ if (!aWindow._rfpOriginalSize) {
|
|
696
|
+ aWindow._rfpOriginalSize = {
|
|
697
|
+ width: aWindow.outerWidth,
|
|
698
|
+ height: aWindow.outerHeight,
|
|
699
|
+ };
|
|
700
|
+ log("Recording original window size", aWindow._rfpOriginalSize);
|
|
701
|
+ }
|
567
|
702
|
});
|
568
|
703
|
}
|
569
|
704
|
|
570
|
705
|
_attachWindow(aWindow) {
|
|
706
|
+ aWindow.addEventListener("sizemodechange", windowResizeHandler);
|
571
|
707
|
aWindow.gBrowser.addTabsProgressListener(this);
|
572
|
708
|
aWindow.addEventListener("TabOpen", this);
|
573
|
709
|
const resizeObserver = (aWindow._rfpResizeObserver = new aWindow.ResizeObserver(
|
... |
... |
@@ -585,19 +721,7 @@ class _RFPHelper { |
585
|
721
|
this._updateSizeForTabsInWindow(aWindow);
|
586
|
722
|
}
|
587
|
723
|
|
588
|
|
- _attachAllWindows() {
|
589
|
|
- let windowList = Services.wm.getEnumerator("navigator:browser");
|
590
|
724
|
|
591
|
|
- while (windowList.hasMoreElements()) {
|
592
|
|
- let win = windowList.getNext();
|
593
|
|
-
|
594
|
|
- if (win.closed || !win.gBrowser) {
|
595
|
|
- continue;
|
596
|
|
- }
|
597
|
|
-
|
598
|
|
- this._attachWindow(win);
|
599
|
|
- }
|
600
|
|
- }
|
601
|
725
|
|
602
|
726
|
_detachWindow(aWindow) {
|
603
|
727
|
let tabBrowser = aWindow.gBrowser;
|
... |
... |
@@ -614,20 +738,7 @@ class _RFPHelper { |
614
|
738
|
let browser = tab.linkedBrowser;
|
615
|
739
|
this._resetContentSize(browser);
|
616
|
740
|
}
|
617
|
|
- }
|
618
|
|
-
|
619
|
|
- _detachAllWindows() {
|
620
|
|
- let windowList = Services.wm.getEnumerator("navigator:browser");
|
621
|
|
-
|
622
|
|
- while (windowList.hasMoreElements()) {
|
623
|
|
- let win = windowList.getNext();
|
624
|
|
-
|
625
|
|
- if (win.closed || !win.gBrowser) {
|
626
|
|
- continue;
|
627
|
|
- }
|
628
|
|
-
|
629
|
|
- this._detachWindow(win);
|
630
|
|
- }
|
|
741
|
+ aWindow.removeEventListener("sizemodechange", windowResizeHandler);
|
631
|
742
|
}
|
632
|
743
|
|
633
|
744
|
_handleDOMWindowOpened(win) {
|