morgan pushed to branch tor-browser-140.5.0esr-15.0-1 at The Tor Project / Applications / Tor Browser
Commits:
-
e891f9c2
by Henry Wilkes at 2025-11-05T14:14:01+00:00
4 changed files:
- browser/components/abouttor/AboutTorChild.sys.mjs
- browser/components/abouttor/AboutTorParent.sys.mjs
- browser/components/abouttor/content/aboutTor.js
- browser/components/tabbrowser/NewTabPagePreloading.sys.mjs
Changes:
| ... | ... | @@ -6,11 +6,9 @@ export class AboutTorChild extends JSWindowActorChild { |
| 6 | 6 | switch (event.type) {
|
| 7 | 7 | case "DOMContentLoaded":
|
| 8 | 8 | this.sendQuery("AboutTor:GetInitialData").then(data => {
|
| 9 | - const initialDataEvent = new this.contentWindow.CustomEvent(
|
|
| 10 | - "InitialData",
|
|
| 11 | - { detail: Cu.cloneInto(data, this.contentWindow) }
|
|
| 12 | - );
|
|
| 13 | - this.contentWindow.dispatchEvent(initialDataEvent);
|
|
| 9 | + if (data) {
|
|
| 10 | + this.#dispatchInitialData(data);
|
|
| 11 | + }
|
|
| 14 | 12 | });
|
| 15 | 13 | break;
|
| 16 | 14 | case "SubmitSearchOnionize":
|
| ... | ... | @@ -36,6 +34,9 @@ export class AboutTorChild extends JSWindowActorChild { |
| 36 | 34 | |
| 37 | 35 | receiveMessage(message) {
|
| 38 | 36 | switch (message.name) {
|
| 37 | + case "AboutTor:DelayedInitialData":
|
|
| 38 | + this.#dispatchInitialData(message.data);
|
|
| 39 | + break;
|
|
| 39 | 40 | case "AboutTor:DismissYEC": {
|
| 40 | 41 | this.contentWindow.dispatchEvent(
|
| 41 | 42 | new this.contentWindow.CustomEvent("DismissYEC")
|
| ... | ... | @@ -45,4 +46,16 @@ export class AboutTorChild extends JSWindowActorChild { |
| 45 | 46 | }
|
| 46 | 47 | return undefined;
|
| 47 | 48 | }
|
| 49 | + |
|
| 50 | + /**
|
|
| 51 | + * Send the initial data to the page.
|
|
| 52 | + *
|
|
| 53 | + * @param {object} data - The data to send.
|
|
| 54 | + */
|
|
| 55 | + #dispatchInitialData(data) {
|
|
| 56 | + const initialDataEvent = new this.contentWindow.CustomEvent("InitialData", {
|
|
| 57 | + detail: Cu.cloneInto(data, this.contentWindow),
|
|
| 58 | + });
|
|
| 59 | + this.contentWindow.dispatchEvent(initialDataEvent);
|
|
| 60 | + }
|
|
| 48 | 61 | } |
| ... | ... | @@ -8,6 +8,8 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 8 | 8 | });
|
| 9 | 9 | |
| 10 | 10 | const initializedActors = new Set();
|
| 11 | +const onionizePref = "torbrowser.homepage.search.onionize";
|
|
| 12 | +const surveyDismissVersionPref = "torbrowser.homepage.survey.dismiss_version";
|
|
| 11 | 13 | |
| 12 | 14 | /**
|
| 13 | 15 | * Actor parent class for the about:tor page.
|
| ... | ... | @@ -21,35 +23,76 @@ export class AboutTorParent extends JSWindowActorParent { |
| 21 | 23 | */
|
| 22 | 24 | static #dismissYEC = false;
|
| 23 | 25 | |
| 26 | + /**
|
|
| 27 | + * Whether this instance has a preloaded browser.
|
|
| 28 | + *
|
|
| 29 | + * @type {boolean}
|
|
| 30 | + */
|
|
| 31 | + #preloaded = false;
|
|
| 32 | + |
|
| 33 | + /**
|
|
| 34 | + * Method to be called when the browser corresponding to this actor has its
|
|
| 35 | + * preloadedState attribute removed.
|
|
| 36 | + */
|
|
| 37 | + preloadedRemoved() {
|
|
| 38 | + if (!this.#preloaded) {
|
|
| 39 | + return;
|
|
| 40 | + }
|
|
| 41 | + this.#preloaded = false;
|
|
| 42 | + // Send in the initial data now that the page is actually going to be
|
|
| 43 | + // visible.
|
|
| 44 | + this.sendAsyncMessage(
|
|
| 45 | + "AboutTor:DelayedInitialData",
|
|
| 46 | + this.#getInitialData()
|
|
| 47 | + );
|
|
| 48 | + }
|
|
| 49 | + |
|
| 50 | + /**
|
|
| 51 | + * Get the initial data for the page when it is about to be shown.
|
|
| 52 | + *
|
|
| 53 | + * @returns {object} - The initial data.
|
|
| 54 | + */
|
|
| 55 | + #getInitialData() {
|
|
| 56 | + let appLocale = Services.locale.appLocaleAsBCP47;
|
|
| 57 | + if (appLocale === "ja-JP-macos") {
|
|
| 58 | + appLocale = "ja";
|
|
| 59 | + }
|
|
| 60 | + |
|
| 61 | + return {
|
|
| 62 | + torConnectEnabled: lazy.TorConnect.enabled,
|
|
| 63 | + messageData: lazy.AboutTorMessage.getNext(),
|
|
| 64 | + isStable: AppConstants.MOZ_UPDATE_CHANNEL === "release",
|
|
| 65 | + searchOnionize: Services.prefs.getBoolPref(onionizePref, false),
|
|
| 66 | + surveyDismissVersion: Services.prefs.getIntPref(
|
|
| 67 | + surveyDismissVersionPref,
|
|
| 68 | + 0
|
|
| 69 | + ),
|
|
| 70 | + appLocale,
|
|
| 71 | + dismissYEC: AboutTorParent.#dismissYEC,
|
|
| 72 | + };
|
|
| 73 | + }
|
|
| 74 | + |
|
| 24 | 75 | didDestroy() {
|
| 25 | 76 | initializedActors.delete(this);
|
| 26 | 77 | }
|
| 27 | 78 | |
| 28 | 79 | receiveMessage(message) {
|
| 29 | - const onionizePref = "torbrowser.homepage.search.onionize";
|
|
| 30 | - const surveyDismissVersionPref =
|
|
| 31 | - "torbrowser.homepage.survey.dismiss_version";
|
|
| 32 | 80 | switch (message.name) {
|
| 33 | 81 | case "AboutTor:GetInitialData": {
|
| 34 | 82 | // Track this actor to send future updates.
|
| 35 | 83 | initializedActors.add(this);
|
| 36 | 84 | |
| 37 | - let appLocale = Services.locale.appLocaleAsBCP47;
|
|
| 38 | - if (appLocale === "ja-JP-macos") {
|
|
| 39 | - appLocale = "ja";
|
|
| 85 | + const browser = this.browsingContext.top.embedderElement;
|
|
| 86 | + if (browser?.getAttribute("preloadedState") === "preloaded") {
|
|
| 87 | + // Wait until the page is actually about to be shown before sending
|
|
| 88 | + // the initial data.
|
|
| 89 | + // Otherwise the preloaded page might receive data that has expired by
|
|
| 90 | + // the time the page is shown. And it will iterate
|
|
| 91 | + // AboutTorMessage.getNext too early. See tor-browser#44314.
|
|
| 92 | + this.#preloaded = true;
|
|
| 93 | + return Promise.resolve(null);
|
|
| 40 | 94 | }
|
| 41 | - return Promise.resolve({
|
|
| 42 | - torConnectEnabled: lazy.TorConnect.enabled,
|
|
| 43 | - messageData: lazy.AboutTorMessage.getNext(),
|
|
| 44 | - isStable: AppConstants.MOZ_UPDATE_CHANNEL === "release",
|
|
| 45 | - searchOnionize: Services.prefs.getBoolPref(onionizePref, false),
|
|
| 46 | - surveyDismissVersion: Services.prefs.getIntPref(
|
|
| 47 | - surveyDismissVersionPref,
|
|
| 48 | - 0
|
|
| 49 | - ),
|
|
| 50 | - appLocale,
|
|
| 51 | - dismissYEC: AboutTorParent.#dismissYEC,
|
|
| 52 | - });
|
|
| 95 | + return Promise.resolve(this.#getInitialData());
|
|
| 53 | 96 | }
|
| 54 | 97 | case "AboutTor:SetSearchOnionize":
|
| 55 | 98 | Services.prefs.setBoolPref(onionizePref, message.data);
|
| ... | ... | @@ -562,11 +562,35 @@ const YecArea = { |
| 562 | 562 | },
|
| 563 | 563 | };
|
| 564 | 564 | |
| 565 | +let gInitialData = false;
|
|
| 566 | +let gLoaded = false;
|
|
| 567 | + |
|
| 568 | +function maybeComplete() {
|
|
| 569 | + if (!gInitialData || !gLoaded) {
|
|
| 570 | + return;
|
|
| 571 | + }
|
|
| 572 | + // Wait to show the content when the l10n population has completed.
|
|
| 573 | + if (document.hasPendingL10nMutations) {
|
|
| 574 | + window.addEventListener(
|
|
| 575 | + "L10nMutationsFinished",
|
|
| 576 | + () => {
|
|
| 577 | + document.body.classList.add("initialized");
|
|
| 578 | + },
|
|
| 579 | + { once: true }
|
|
| 580 | + );
|
|
| 581 | + } else {
|
|
| 582 | + document.body.classList.add("initialized");
|
|
| 583 | + }
|
|
| 584 | +}
|
|
| 585 | + |
|
| 565 | 586 | window.addEventListener("DOMContentLoaded", () => {
|
| 566 | 587 | SearchWidget.init();
|
| 567 | 588 | MessageArea.init();
|
| 568 | 589 | SurveyArea.init();
|
| 569 | 590 | YecArea.init();
|
| 591 | + |
|
| 592 | + gLoaded = true;
|
|
| 593 | + maybeComplete();
|
|
| 570 | 594 | });
|
| 571 | 595 | |
| 572 | 596 | window.addEventListener("InitialData", event => {
|
| ... | ... | @@ -584,18 +608,8 @@ window.addEventListener("InitialData", event => { |
| 584 | 608 | SurveyArea.potentiallyShow(surveyDismissVersion, isStable, appLocale);
|
| 585 | 609 | YecArea.potentiallyShow(dismissYEC, isStable, appLocale);
|
| 586 | 610 | |
| 587 | - // Wait to show the content when the l10n population has completed.
|
|
| 588 | - if (document.hasPendingL10nMutations) {
|
|
| 589 | - window.addEventListener(
|
|
| 590 | - "L10nMutationsFinished",
|
|
| 591 | - () => {
|
|
| 592 | - document.body.classList.add("initialized");
|
|
| 593 | - },
|
|
| 594 | - { once: true }
|
|
| 595 | - );
|
|
| 596 | - } else {
|
|
| 597 | - document.body.classList.add("initialized");
|
|
| 598 | - }
|
|
| 611 | + gInitialData = true;
|
|
| 612 | + maybeComplete();
|
|
| 599 | 613 | });
|
| 600 | 614 | |
| 601 | 615 | window.addEventListener("DismissYEC", () => {
|
| ... | ... | @@ -178,6 +178,24 @@ export let NewTabPagePreloading = { |
| 178 | 178 | this.browserCounts[countKey]--;
|
| 179 | 179 | browser.removeAttribute("preloadedState");
|
| 180 | 180 | browser.setAttribute("autocompletepopup", "PopupAutoComplete");
|
| 181 | + // Let a preloaded about:tor page know that it is no longer preloaded
|
|
| 182 | + // (about to be shown). See tor-browser#44314.
|
|
| 183 | + // NOTE: We call the AboutTorParent instance directly because it is not
|
|
| 184 | + // reliable for the AboutTorParent to wait for the "preloadedState"
|
|
| 185 | + // attribute to change via a MutationObserver on the browsingContext's
|
|
| 186 | + // browser element because the AboutTorParent's browsingContext's browser
|
|
| 187 | + // element may be swapped out. E.g. see the "SwapDocShells" event.
|
|
| 188 | + // NOTE: We assume that this is the only place that removes the
|
|
| 189 | + // "preloadedState" attribute.
|
|
| 190 | + // NOTE: Alternatively, we could have the AboutTorParent wait for
|
|
| 191 | + // MozAfterPaint, but this would be slightly delayed.
|
|
| 192 | + try {
|
|
| 193 | + browser.browsingContext?.currentWindowGlobal
|
|
| 194 | + ?.getActor("AboutTor")
|
|
| 195 | + .preloadedRemoved();
|
|
| 196 | + } catch {
|
|
| 197 | + // Not an about:tor page with an AboutTorParent instance.
|
|
| 198 | + }
|
|
| 181 | 199 | }
|
| 182 | 200 | |
| 183 | 201 | return browser;
|