Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/mobile/shared/components/extensions/   (Android Betriebssystem Version 17©)  Datei vom 27.6.2026 mit Größe 17 kB image not shown  

Quelle  ext-android.js

  Sprache: JAVA
 

/* 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/. */

"use strict";

/**
 * NOTE: If you change the globals in this file, you must check if the globals
 * list in mobile/android/.eslintrc.js also needs updating.
 */


ChromeUtils.defineESModuleGetters(this, {
  GeckoViewTabBridge: "resource://gre/modules/GeckoViewTab.sys.mjs",
  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
  mobileWindowTracker: "resource://gre/modules/GeckoViewWebExtension.sys.mjs",
});

var { EventDispatcher } = ChromeUtils.importESModule(
  "resource://gre/modules/Messaging.sys.mjs"
);

var { ExtensionCommon } = ChromeUtils.importESModule(
  "resource://gre/modules/ExtensionCommon.sys.mjs"
);
var { ExtensionUtils } = ChromeUtils.importESModule(
  "resource://gre/modules/ExtensionUtils.sys.mjs"
);

var { DefaultWeakMap, ExtensionError } = ExtensionUtils;

var { defineLazyGetter } = ExtensionCommon;

const BrowserStatusFilter = Components.Constructor(
  "@mozilla.org/appshell/component/browser-status-filter;1",
  "nsIWebProgress",
  "addProgressListener"
);

const WINDOW_TYPE = "navigator:geckoview";

// We need let to break cyclic dependency
/* eslint-disable-next-line prefer-const */
let windowTracker;

/**
 * A nsIWebProgressListener for a specific XUL browser, which delegates the
 * events that it receives to a tab progress listener, and prepends the browser
 * to their arguments list.
 *
 * @param {XULElement} browser
 *        A XUL browser element.
 * @param {object} listener
 *        A tab progress listener object.
 * @param {integer} flags
 *        The web progress notification flags with which to filter events.
 */

class BrowserProgressListener {
  constructor(browser, listener, flags) {
    this.listener = listener;
    this.browser = browser;
    this.filter = new BrowserStatusFilter(this, flags);
    this.browser.addProgressListener(this.filter, flags);
  }

  /**
   * Destroy the listener, and perform any necessary cleanup.
   */

  destroy() {
    this.browser.removeProgressListener(this.filter);
    this.filter.removeProgressListener(this);
  }

  /**
   * Calls the appropriate listener in the wrapped tab progress listener, with
   * the wrapped XUL browser object as its first argument, and the additional
   * arguments in `args`.
   *
   * @param {string} method
   *        The name of the nsIWebProgressListener method which is being
   *        delegated.
   * @param {*} args
   *        The arguments to pass to the delegated listener.
   * @private
   */

  delegate(method, ...args) {
    if (this.listener[method]) {
      this.listener[method](this.browser, ...args);
    }
  }

  onLocationChange(webProgress, request, locationURI, flags) {
    const window = this.browser.documentGlobal;
    // GeckoView windows can become popups at any moment, so we need to check
    // here
    if (!windowTracker.isBrowserWindow(window)) {
      return;
    }

    this.delegate("onLocationChange", webProgress, request, locationURI, flags);
  }
  onStateChange(webProgress, request, stateFlags, status) {
    this.delegate("onStateChange", webProgress, request, stateFlags, status);
  }
}

const PROGRESS_LISTENER_FLAGS =
  Ci.nsIWebProgress.NOTIFY_STATE_NETWORK | Ci.nsIWebProgress.NOTIFY_LOCATION;

class ProgressListenerWrapper {
  constructor(window, listener) {
    this.listener = new BrowserProgressListener(
      window.browser,
      listener,
      PROGRESS_LISTENER_FLAGS
    );
  }

  destroy() {
    this.listener.destroy();
  }
}

class WindowTracker extends WindowTrackerBase {
  constructor(...args) {
    super(...args);

    this.progressListeners = new DefaultWeakMap(() => new WeakMap());
  }

  getCurrentWindow(context) {
    // In GeckoView the popup is on a separate window so getCurrentWindow for
    // the popup should return whatever is the topWindow.
    if (context?.viewType === "popup") {
      // TODO bug 2040609: Improve tracking of "current window" for popups.
      return this.topWindow;
    }
    return super.getCurrentWindow(context);
  }

  get topWindow() {
    return mobileWindowTracker.topWindow;
  }

  get topNonPBWindow() {
    return mobileWindowTracker.topNonPBWindow;
  }

  isBrowserWindow(window) {
    const { documentElement } = window.document;
    return documentElement.getAttribute("windowtype") === WINDOW_TYPE;
  }

  addProgressListener(window, listener) {
    const listeners = this.progressListeners.get(window);
    if (!listeners.has(listener)) {
      const wrapper = new ProgressListenerWrapper(window, listener);
      listeners.set(listener, wrapper);
    }
  }

  removeProgressListener(window, listener) {
    const listeners = this.progressListeners.get(window);
    const wrapper = listeners.get(listener);
    if (wrapper) {
      wrapper.destroy();
      listeners.delete(listener);
    }
  }
}

/**
 * Helper to create an event manager which listens for an event in the Android
 * global EventDispatcher, and calls the given listener function whenever the
 * event is received. That listener function receives a `fire` object,
 * which it can use to dispatch events to the extension, and an object
 * detailing the EventDispatcher event that was received.
 *
 * @param {BaseContext} context
 *        The extension context which the event manager belongs to.
 * @param {string} name
 *        The API name of the event manager, e.g.,"runtime.onMessage".
 * @param {string} event
 *        The name of the EventDispatcher event to listen for.
 * @param {Function} listener
 *        The listener function to call when an EventDispatcher event is
 *        recieved.
 *
 * @returns {object} An injectable api for the new event.
 */

global.makeGlobalEvent = function makeGlobalEvent(
  context,
  name,
  event,
  listener
) {
  return new EventManager({
    context,
    name,
    register: fire => {
      const listener2 = {
        onEvent(event, data) {
          listener(fire, data);
        },
      };

      EventDispatcher.instance.registerListener(listener2, [event]);
      return () => {
        EventDispatcher.instance.unregisterListener(listener2, [event]);
      };
    },
  }).api();
};

class TabTracker extends TabTrackerBase {
  init() {
    if (this.initialized) {
      return;
    }
    this.initialized = true;

    windowTracker.addOpenListener(window => {
      const nativeTab = window.tab;
      this.emit("tab-created", { nativeTab });
    });

    windowTracker.addCloseListener(window => {
      const { tab: nativeTab, browser } = window;
      const { windowId, tabId } = this.getBrowserData(browser);
      this.emit("tab-removed", {
        nativeTab,
        tabId,
        windowId,
        // In GeckoView, it is not meaningful to speak of "window closed", because a tab is a window.
        // Until we have a meaningful way to group tabs (and close multiple tabs at once),
        // let's use isWindowClosing: false
        isWindowClosing: false,
      });
    });
  }

  getId(nativeTab) {
    return nativeTab.id;
  }

  getTab(id, default_ = undefined) {
    const windowId = GeckoViewTabBridge.tabIdToWindowId(id);
    const window = windowTracker.getWindow(windowId, nullfalse);

    if (window) {
      const { tab } = window;
      if (tab) {
        return tab;
      }
    }

    if (default_ !== undefined) {
      return default_;
    }
    throw new ExtensionError(`Invalid tab ID: ${id}`);
  }

  getTabForBrowser(browser) {
    const window = browser.documentGlobal;
    // isBrowserWindow check excludes "navigator:popup" and background pages.
    if (windowTracker.isBrowserWindow(window)) {
      // There is currently a 1:1 relation between window and tab (bug 1584252).
      return window.tab;
    }
    return null;
  }

  getBrowserData(browser) {
    const window = browser.documentGlobal;
    if (!window) {
      return { tabId: -1, windowId: -1 };
    }
    const nativeTab = this.getTabForBrowser(browser);
    if (!nativeTab) {
      let wintype = window.document.documentElement.getAttribute("windowtype");
      if (wintype === "navigator:popup") {
        // TODO bug 2040609: Improve tracking of "current window" for popups.
        let currentWindow = windowTracker.topWindow;
        if (currentWindow) {
          return { tabId: -1, windowId: windowTracker.getId(currentWindow) };
        }
      }
      return { tabId: -1, windowId: -1 };
    }

    return {
      tabId: this.getId(nativeTab),
      windowId: windowTracker.getId(window),
    };
  }

  get activeTab() {
    const window = windowTracker.topWindow;
    if (window) {
      return window.tab;
    }
    return null;
  }
}

windowTracker = new WindowTracker();
const tabTracker = new TabTracker();

Object.assign(global, { tabTracker, windowTracker });

class Tab extends TabBase {
  get _favIconUrl() {
    return undefined;
  }

  get attention() {
    // Always false because the concept is not implemented on Android.
    return false;
  }

  get audible() {
    // TODO bug 2032751: Implement tabs.audible on Android.
    return undefined;
  }

  get browser() {
    return this.nativeTab.browser;
  }

  get discarded() {
    // TODO bug 1402338: Implement tabs.discard on Android.
    return false;
  }

  get cookieStoreId() {
    return getCookieStoreIdForTab(thisthis.nativeTab);
  }

  get openerTabId() {
    // TODO bug 1817806: Implement openerTabId on Android.
    return undefined;
  }

  get height() {
    return this.browser.clientHeight;
  }

  get incognito() {
    return PrivateBrowsingUtils.isBrowserPrivate(this.browser);
  }

  get index() {
    // TODO bug 1812854: Support more than one tab per window.
    return 0;
  }

  get mutedInfo() {
    return { muted: false };
  }

  get lastAccessed() {
    // TODO bug 2032927: lastAccessed is not implemented on Android.
    return undefined;
  }

  get pinned() {
    // Always false because the concept is not implemented on Android.
    return false;
  }

  get active() {
    return this.nativeTab.getActive();
  }

  get highlighted() {
    return this.active;
  }

  get status() {
    if (this.browser.webProgress.isLoadingDocument) {
      return "loading";
    }
    return "complete";
  }

  get successorTabId() {
    return -1;
  }

  get groupId() {
    // Always TAB_GROUP_ID_NONE because tab groups are not implemented.
    return -1;
  }

  get splitViewId() {
    // Always SPLIT_VIEW_ID_NONE because split views are not implemented.
    return -1;
  }

  get width() {
    return this.browser.clientWidth;
  }

  get window() {
    return this.browser.documentGlobal;
  }

  get windowId() {
    return windowTracker.getId(this.window);
  }

  get isArticle() {
    // TODO bug 1402924: implement isArticle with toggleReaderMode.
    return false;
  }

  get isInReaderMode() {
    // TODO bug 1402924: implement isInReaderMode with toggleReaderMode.
    return false;
  }

  get hidden() {
    // tabs.hide() / tabs.show() not implemented on Android.
    return false;
  }

  get autoDiscardable() {
    // This property reflects whether the browser is allowed to auto-discard.
    // Since extensions cannot do so on Android, we return true here.
    return true;
  }

  get sharingState() {
    // sharingState is undocumented on MDN but has been around forever since it
    // landed in bug 1423725. This return value is a dummy value that does not
    // reflect the true sharing state.
    return {
      screen: undefined,
      microphone: false,
      camera: false,
    };
  }
}

// Manages tab-specific context data and dispatches tab select and close events.
class TabContext extends EventEmitter {
  constructor(getDefaultPrototype) {
    super();

    windowTracker.addListener("progress"this);

    this.getDefaultPrototype = getDefaultPrototype;
    this.tabData = new Map();
  }

  onLocationChange(browser, webProgress, request, locationURI, flags) {
    if (!webProgress.isTopLevel) {
      // Only pageAction and browserAction are consuming the "location-change" event
      // to update their per-tab status, and they should only do so in response of
      // location changes related to the top level frame (See Bug 1493470 for a rationale).
      return;
    }
    const { tab } = browser.documentGlobal;
    // fromBrowse will be false in case of e.g. a hash change or history.pushState
    const fromBrowse = !(
      flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT
    );
    this.emit(
      "location-change",
      {
        id: tab.id,
        linkedBrowser: browser,
        // TODO: we don't support selected so we just alway say we are
        selected: true,
      },
      fromBrowse
    );
  }

  get(tabId) {
    if (!this.tabData.has(tabId)) {
      const data = Object.create(this.getDefaultPrototype(tabId));
      this.tabData.set(tabId, data);
    }

    return this.tabData.get(tabId);
  }

  clear(tabId) {
    this.tabData.delete(tabId);
  }

  shutdown() {
    windowTracker.removeListener("progress"this);
  }
}

class Window extends WindowBase {
  get type() {
    // The base implementation may return "popup" in some cases, but on mobile
    // all tabs are associated with "normal" windowTypes.
    return "normal";
  }

  get focused() {
    return this.window.document.hasFocus();
  }

  isCurrentFor(context) {
    // In GeckoView the popup is on a separate window so the current window for
    // the popup is whatever is the topWindow.
    if (context?.viewType === "popup") {
      // TODO bug 2040609: Improve tracking of "current window" for popups.
      return mobileWindowTracker.topWindow == this.window;
    }
    return super.isCurrentFor(context);
  }

  get top() {
    return this.window.screenY;
  }

  get left() {
    return this.window.screenX;
  }

  get width() {
    return this.window.outerWidth;
  }

  get height() {
    return this.window.outerHeight;
  }

  get incognito() {
    return PrivateBrowsingUtils.isWindowPrivate(this.window);
  }

  get alwaysOnTop() {
    return false;
  }

  get isLastFocused() {
    return this.window === windowTracker.topWindow;
  }

  get state() {
    return "fullscreen";
  }

  *getTabs() {
    yield this.activeTab;
  }

  *getHighlightedTabs() {
    yield this.activeTab;
  }

  get activeTab() {
    const { tabManager } = this.extension;
    return tabManager.getWrapper(this.window.tab);
  }

  getTabAtIndex(index) {
    if (index == 0) {
      return this.activeTab;
    }
  }
}

Object.assign(global, { Tab, TabContext, Window });

class TabManager extends TabManagerBase {
  get(tabId, default_ = undefined) {
    const nativeTab = tabTracker.getTab(tabId, default_);

    if (nativeTab) {
      return this.getWrapper(nativeTab);
    }
    return default_;
  }

  addActiveTabPermission(nativeTab = tabTracker.activeTab) {
    return super.addActiveTabPermission(nativeTab);
  }

  revokeActiveTabPermission(nativeTab = tabTracker.activeTab) {
    return super.revokeActiveTabPermission(nativeTab);
  }

  canAccessTab(nativeTab) {
    return (
      this.extension.privateBrowsingAllowed ||
      !PrivateBrowsingUtils.isBrowserPrivate(nativeTab.browser)
    );
  }

  wrapTab(nativeTab) {
    return new Tab(this.extension, nativeTab, nativeTab.id);
  }
}

class WindowManager extends WindowManagerBase {
  get(windowId, context) {
    const window = windowTracker.getWindow(windowId, context);

    return this.getWrapper(window);
  }

  *getAll(context) {
    for (const window of windowTracker.browserWindows()) {
      if (!this.canAccessWindow(window, context)) {
        continue;
      }
      const wrapped = this.getWrapper(window);
      if (wrapped) {
        yield wrapped;
      }
    }
  }

  wrapWindow(window) {
    return new Window(this.extension, window, windowTracker.getId(window));
  }
}

// eslint-disable-next-line mozilla/balanced-listeners
extensions.on("startup", (type, extension) => {
  defineLazyGetter(extension, "tabManager", () => new TabManager(extension));
  defineLazyGetter(
    extension,
    "windowManager",
    () => new WindowManager(extension)
  );
});

/* eslint-disable mozilla/balanced-listeners */
extensions.on("page-shutdown", (type, context) => {
  // The logic here aims to close extension tabs when an extension unloads, but
  // due to lazy context creation, this does not always happen (bug 1399655).
  if (context.viewType == "tab") {
    const window = context.xulBrowser.documentGlobal;
    if (!windowTracker.isBrowserWindow(window)) {
      // Content in non-browser window, e.g. ContentPage in xpcshell uses
      // chrome://extensions/content/dummy.xhtml as the window.
      return;
    }
    GeckoViewTabBridge.closeTab({
      window,
      extensionId: context.extension.id,
    });
  }
});
/* eslint-enable mozilla/balanced-listeners */

global.openOptionsPage = async extension => {
  const { optionsPageProperties } = extension;
  const extensionId = extension.id;

  if (optionsPageProperties.open_in_tab) {
    // Delegate new tab creation and open the options page in the new tab.
    const tab = await GeckoViewTabBridge.createNewTab({
      extensionId,
      createProperties: {
        url: optionsPageProperties.page,
        active: true,
      },
    });

    const { browser } = tab;
    const loadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;

    browser.fixupAndLoadURIString(optionsPageProperties.page, {
      loadFlags,
      triggeringPrincipal: extension.principal,
    });

    const newWindow = browser.documentGlobal;
    mobileWindowTracker.setTabActive(newWindow, true);
    return;
  }

  // Delegate option page handling to the app.
  return GeckoViewTabBridge.openOptionsPage(extensionId);
};

Messung V0.5 in Prozent
C=91 H=99 G=94

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.