Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  RefreshBlockerChild.sys.mjs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * This file has two actors, RefreshBlockerChild js a window actor which
 * handles the refresh notifications. RefreshBlockerObserverChild is a process
 * actor that enables refresh blocking on each docshell that is created.
 */

import { setTimeout } from "resource://gre/modules/Timer.sys.mjs";

const REFRESHBLOCKING_PREF = "accessibility.blockautorefresh";

var progressListener = {
  // Bug 1247100 - When a refresh is caused by an HTTP header,
  // onRefreshAttempted will be fired before onLocationChange.
  // When a refresh is caused by a <meta> tag in the document,
  // onRefreshAttempted will be fired after onLocationChange.
  //
  // We only ever want to send a message to the parent after
  // onLocationChange has fired, since the parent uses the
  // onLocationChange update to clear transient notifications.
  // Sending the message before onLocationChange will result in
  // us creating the notification, and then clearing it very
  // soon after.
  //
  // To account for both cases (onRefreshAttempted before
  // onLocationChange, and onRefreshAttempted after onLocationChange),
  // we'll hold a mapping of DOM Windows that we see get
  // sent through both onLocationChange and onRefreshAttempted.
  // When either run, they'll check the WeakMap for the existence
  // of the DOM Window. If it doesn't exist, it'll add it. If
  // it finds it, it'll know that it's safe to send the message
  // to the parent, since we know that both have fired.
  //
  // The DOM Window is removed from blockedWindows when we notice
  // the nsIWebProgress change state to STATE_STOP for the
  // STATE_IS_WINDOW case.
  //
  // DOM Windows are mapped to a JS object that contains the data
  // to be sent to the parent to show the notification. Since that
  // data is only known when onRefreshAttempted is fired, it's only
  // ever stashed in the map if onRefreshAttempted fires first -
  // otherwise, null is set as the value of the mapping.
  blockedWindows: new WeakMap(),

  /**
   * Notices when the nsIWebProgress transitions to STATE_STOP for
   * the STATE_IS_WINDOW case, which will clear any mappings from
   * blockedWindows.
   */
  onStateChange(aWebProgress, aRequest, aStateFlags) {
    if (
      aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
      aStateFlags & Ci.nsIWebProgressListener.STATE_STOP
    ) {
      this.blockedWindows.delete(aWebProgress.DOMWindow);
    }
  },

  /**
   * Notices when the location has changed. If, when running,
   * onRefreshAttempted has already fired for this DOM Window, will
   * send the appropriate refresh blocked data to the parent.
   */
  onLocationChange(aWebProgress) {
    let win = aWebProgress.DOMWindow;
    if (this.blockedWindows.has(win)) {
      let data = this.blockedWindows.get(win);
      if (data) {
        // We saw onRefreshAttempted before onLocationChange, so
        // send the message to the parent to show the notification.
        this.send(win, data);
      }
    } else {
      this.blockedWindows.set(win, null);
    }
  },

  /**
   * Notices when a refresh / reload was attempted. If, when running,
   * onLocationChange has not yet run, will stash the appropriate data
   * into the blockedWindows map to be sent when onLocationChange fires.
   */
  onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
    let win = aWebProgress.DOMWindow;

    let data = {
      browsingContext: win.browsingContext,
      URI: aURI.spec,
      delay: aDelay,
      sameURI: aSameURI,
    };

    if (this.blockedWindows.has(win)) {
      // onLocationChange must have fired before, so we can tell the
      // parent to show the notification.
      this.send(win, data);
    } else {
      // onLocationChange hasn't fired yet, so stash the data in the
      // map so that onLocationChange can send it when it fires.
      this.blockedWindows.set(win, data);
    }

    return false;
  },

  send(win, data) {
    // Due to the |nsDocLoader| calling its |nsIWebProgressListener|s in
    // reverse order, this will occur *before* the |BrowserChild| can send its
    // |OnLocationChange| event to the parent, but we need this message to
    // arrive after to ensure that the refresh blocker notification is not
    // immediately cleared by the |OnLocationChange| from |BrowserChild|.
    setTimeout(() => {
      // An exception can occur if refresh blocking was turned off
      // during a pageload.
      try {
        let actor = win.windowGlobalChild.getActor("RefreshBlocker");
        if (actor) {
          actor.sendAsyncMessage("RefreshBlocker:Blocked", data);
        }
      } catch (ex) {}
    }, 0);
  },

  QueryInterface: ChromeUtils.generateQI([
    "nsIWebProgressListener2",
    "nsIWebProgressListener",
    "nsISupportsWeakReference",
  ]),
};

export class RefreshBlockerChild extends JSWindowActorChild {
  didDestroy() {
    // If the refresh blocking preference is turned off, all of the
    // RefreshBlockerChild actors will get destroyed, so disable
    // refresh blocking only in this case.
    if (!Services.prefs.getBoolPref(REFRESHBLOCKING_PREF)) {
      this.disable(this.docShell);
    }
  }

  enable() {
    ChromeUtils.domProcessChild
      .getActor("RefreshBlockerObserver")
      .enable(this.docShell);
  }

  disable() {
    ChromeUtils.domProcessChild
      .getActor("RefreshBlockerObserver")
      .disable(this.docShell);
  }

  receiveMessage(message) {
    let data = message.data;

    switch (message.name) {
      case "RefreshBlocker:Refresh":
        let docShell = data.browsingContext.docShell;
        let refreshURI = docShell.QueryInterface(Ci.nsIRefreshURI);
        let URI = Services.io.newURI(data.URI);
        refreshURI.forceRefreshURI(URI, null, data.delay);
        break;

      case "PreferenceChanged":
        if (data.isEnabled) {
          this.enable(this.docShell);
        } else {
          this.disable(this.docShell);
        }
    }
  }
}

export class RefreshBlockerObserverChild extends JSProcessActorChild {
  constructor() {
    super();
    this.filtersMap = new Map();
  }

  observe(subject, topic) {
    switch (topic) {
      case "webnavigation-create":
      case "chrome-webnavigation-create":
        if (Services.prefs.getBoolPref(REFRESHBLOCKING_PREF)) {
          this.enable(subject.QueryInterface(Ci.nsIDocShell));
        }
        break;

      case "webnavigation-destroy":
      case "chrome-webnavigation-destroy":
        if (Services.prefs.getBoolPref(REFRESHBLOCKING_PREF)) {
          this.disable(subject.QueryInterface(Ci.nsIDocShell));
        }
        break;
    }
  }

  enable(docShell) {
    if (this.filtersMap.has(docShell)) {
      return;
    }

    let filter = Cc[
      "@mozilla.org/appshell/component/browser-status-filter;1"
    ].createInstance(Ci.nsIWebProgress);

    filter.addProgressListener(progressListener, Ci.nsIWebProgress.NOTIFY_ALL);

    this.filtersMap.set(docShell, filter);

    let webProgress = docShell
      .QueryInterface(Ci.nsIInterfaceRequestor)
      .getInterface(Ci.nsIWebProgress);
    webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
  }

  disable(docShell) {
    let filter = this.filtersMap.get(docShell);
    if (!filter) {
      return;
    }

    let webProgress = docShell
      .QueryInterface(Ci.nsIInterfaceRequestor)
      .getInterface(Ci.nsIWebProgress);
    webProgress.removeProgressListener(filter);

    filter.removeProgressListener(progressListener);
    this.filtersMap.delete(docShell);
  }
}

[ Dauer der Verarbeitung: 0.30 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge