Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/devtools/server/actors/inspector/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 16 kB image not shown  

Quelle  utils.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";

loader.lazyRequireGetter(
  this,
  "colorUtils",
  "resource://devtools/shared/css/color.js",
  true
);
loader.lazyRequireGetter(
  this,
  "AsyncUtils",
  "resource://devtools/shared/async-utils.js"
);
loader.lazyRequireGetter(this"flags""resource://devtools/shared/flags.js");
loader.lazyRequireGetter(
  this,
  "DevToolsUtils",
  "resource://devtools/shared/DevToolsUtils.js"
);
loader.lazyRequireGetter(
  this,
  "nodeFilterConstants",
  "resource://devtools/shared/dom-node-filter-constants.js"
);
loader.lazyRequireGetter(
  this,
  ["isNativeAnonymous""getAdjustedQuads"],
  "resource://devtools/shared/layout/utils.js",
  true
);
loader.lazyRequireGetter(
  this,
  "CssLogic",
  "resource://devtools/server/actors/inspector/css-logic.js",
  true
);
loader.lazyRequireGetter(
  this,
  "getBackgroundFor",
  "resource://devtools/server/actors/accessibility/audit/contrast.js",
  true
);
loader.lazyRequireGetter(
  this,
  ["loadSheetForBackgroundCalculation""removeSheetForBackgroundCalculation"],
  "resource://devtools/server/actors/utils/accessibility.js",
  true
);
loader.lazyRequireGetter(
  this,
  "getTextProperties",
  "resource://devtools/shared/accessibility.js",
  true
);

const XHTML_NS = "http://www.w3.org/1999/xhtml";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const IMAGE_FETCHING_TIMEOUT = 500;

/**
 * Returns the properly cased version of the node's tag name, which can be
 * used when displaying said name in the UI.
 *
 * @param  {Node} rawNode
 *         Node for which we want the display name
 * @return {String}
 *         Properly cased version of the node tag name
 */

const getNodeDisplayName = function (rawNode) {
  if (rawNode.nodeName && !rawNode.localName) {
    // The localName & prefix APIs have been moved from the Node interface to the Element
    // interface. Use Node.nodeName as a fallback.
    return rawNode.nodeName;
  }
  return (rawNode.prefix ? rawNode.prefix + ":" : "") + rawNode.localName;
};

/**
 * Returns flex and grid information about a DOM node.
 * In particular is it a grid flex/container and/or item?
 *
 * @param  {DOMNode} node
 *         The node for which then information is required
 * @return {Object}
 *         An object like { grid: { isContainer, isItem }, flex: { isContainer, isItem } }
 */

function getNodeGridFlexType(node) {
  return {
    grid: getNodeGridType(node),
    flex: getNodeFlexType(node),
  };
}

function getNodeFlexType(node) {
  return {
    isContainer: node.getAsFlexContainer && !!node.getAsFlexContainer(),
    isItem: !!node.parentFlexElement,
  };
}

function getNodeGridType(node) {
  return {
    isContainer: node.hasGridFragments && node.hasGridFragments(),
    isItem: !!findGridParentContainerForNode(node),
  };
}

function nodeDocument(node) {
  if (Cu.isDeadWrapper(node)) {
    return null;
  }
  return (
    node.ownerDocument || (node.nodeType == Node.DOCUMENT_NODE ? node : null)
  );
}

function isNodeDead(node) {
  return !node || !node.rawNode || Cu.isDeadWrapper(node.rawNode);
}

function isInXULDocument(el) {
  const doc = nodeDocument(el);
  return doc?.documentElement && doc.documentElement.namespaceURI === XUL_NS;
}

/**
 * This DeepTreeWalker filter skips whitespace text nodes and anonymous
 * content with the exception of ::marker, ::before, and ::after, plus anonymous
 * content in XUL document (needed to show all elements in the browser toolbox).
 */

function standardTreeWalkerFilter(node) {
  // ::marker, ::before, and ::after are native anonymous content, but we always
  // want to show them
  if (
    node.nodeName === "_moz_generated_content_marker" ||
    node.nodeName === "_moz_generated_content_before" ||
    node.nodeName === "_moz_generated_content_after"
  ) {
    return nodeFilterConstants.FILTER_ACCEPT;
  }

  // Ignore empty whitespace text nodes that do not impact the layout.
  if (isWhitespaceTextNode(node)) {
    return nodeHasSize(node)
      ? nodeFilterConstants.FILTER_ACCEPT
      : nodeFilterConstants.FILTER_SKIP;
  }

  // Ignore all native anonymous roots inside a non-XUL document.
  // We need to do this to skip things like form controls, scrollbars,
  // video controls, etc (see bug 1187482).
  if (isNativeAnonymous(node) && !isInXULDocument(node)) {
    return nodeFilterConstants.FILTER_SKIP;
  }

  return nodeFilterConstants.FILTER_ACCEPT;
}

/**
 * This DeepTreeWalker filter ignores anonymous content.
 */

function noAnonymousContentTreeWalkerFilter(node) {
  // Ignore all native anonymous content inside a non-XUL document.
  // We need to do this to skip things like form controls, scrollbars,
  // video controls, etc (see bug 1187482).
  if (!isInXULDocument(node) && isNativeAnonymous(node)) {
    return nodeFilterConstants.FILTER_SKIP;
  }

  return nodeFilterConstants.FILTER_ACCEPT;
}
/**
 * This DeepTreeWalker filter is like standardTreeWalkerFilter except that
 * it also includes all anonymous content (like internal form controls).
 */

function allAnonymousContentTreeWalkerFilter(node) {
  // Ignore empty whitespace text nodes that do not impact the layout.
  if (isWhitespaceTextNode(node)) {
    return nodeHasSize(node)
      ? nodeFilterConstants.FILTER_ACCEPT
      : nodeFilterConstants.FILTER_SKIP;
  }
  return nodeFilterConstants.FILTER_ACCEPT;
}

/**
 * Is the given node a text node composed of whitespace only?
 * @param {DOMNode} node
 * @return {Boolean}
 */

function isWhitespaceTextNode(node) {
  return node.nodeType == Node.TEXT_NODE && !/[^\s]/.exec(node.nodeValue);
}

/**
 * Does the given node have non-0 width and height?
 * @param {DOMNode} node
 * @return {Boolean}
 */

function nodeHasSize(node) {
  if (!node.getBoxQuads) {
    return false;
  }

  const quads = node.getBoxQuads({
    createFramesForSuppressedWhitespace: false,
  });
  return quads.some(quad => {
    const bounds = quad.getBounds();
    return bounds.width && bounds.height;
  });
}

/**
 * Returns a promise that is settled once the given HTMLImageElement has
 * finished loading.
 *
 * @param {HTMLImageElement} image - The image element.
 * @param {Number} timeout - Maximum amount of time the image is allowed to load
 * before the waiting is aborted. Ignored if flags.testing is set.
 *
 * @return {Promise} that is fulfilled once the image has loaded. If the image
 * fails to load or the load takes too long, the promise is rejected.
 */

function ensureImageLoaded(image, timeout) {
  const { HTMLImageElement } = image.ownerGlobal;
  if (!(image instanceof HTMLImageElement)) {
    return Promise.reject("image must be an HTMLImageELement");
  }

  if (image.complete) {
    // The image has already finished loading.
    return Promise.resolve();
  }

  // This image is still loading.
  const onLoad = AsyncUtils.listenOnce(image, "load");

  // Reject if loading fails.
  const onError = AsyncUtils.listenOnce(image, "error").then(() => {
    return Promise.reject("Image '" + image.src + "' failed to load.");
  });

  // Don't timeout when testing. This is never settled.
  let onAbort = new Promise(() => {});

  if (!flags.testing) {
    // Tests are not running. Reject the promise after given timeout.
    onAbort = DevToolsUtils.waitForTime(timeout).then(() => {
      return Promise.reject("Image '" + image.src + "' took too long to load.");
    });
  }

  // See which happens first.
  return Promise.race([onLoad, onError, onAbort]);
}

/**
 * Given an <img> or <canvas> element, return the image data-uri. If @param node
 * is an <img> element, the method waits a while for the image to load before
 * the data is generated. If the image does not finish loading in a reasonable
 * time (IMAGE_FETCHING_TIMEOUT milliseconds) the process aborts.
 *
 * @param {HTMLImageElement|HTMLCanvasElement} node - The <img> or <canvas>
 * element, or Image() object. Other types cause the method to reject.
 * @param {Number} maxDim - Optionally pass a maximum size you want the longest
 * side of the image to be resized to before getting the image data.

 * @return {Promise} A promise that is fulfilled with an object containing the
 * data-uri and size-related information:
 * { data: "...",
 *   size: {
 *     naturalWidth: 400,
 *     naturalHeight: 300,
 *     resized: true }
 *  }.
 *
 * If something goes wrong, the promise is rejected.
 */

const imageToImageData = async function (node, maxDim) {
  const { HTMLCanvasElement, HTMLImageElement } = node.ownerGlobal;

  const isImg = node instanceof HTMLImageElement;
  const isCanvas = node instanceof HTMLCanvasElement;

  if (!isImg && !isCanvas) {
    throw new Error("node is not a or element.");
  }

  if (isImg) {
    // Ensure that the image is ready.
    await ensureImageLoaded(node, IMAGE_FETCHING_TIMEOUT);
  }

  // Get the image resize ratio if a maxDim was provided
  let resizeRatio = 1;
  const imgWidth = node.naturalWidth || node.width;
  const imgHeight = node.naturalHeight || node.height;
  const imgMax = Math.max(imgWidth, imgHeight);
  if (maxDim && imgMax > maxDim) {
    resizeRatio = maxDim / imgMax;
  }

  // Extract the image data
  let imageData;
  // The image may already be a data-uri, in which case, save ourselves the
  // trouble of converting via the canvas.drawImage.toDataURL method, but only
  // if the image doesn't need resizing
  if (isImg && node.src.startsWith("data:") && resizeRatio === 1) {
    imageData = node.src;
  } else {
    // Create a canvas to copy the rawNode into and get the imageData from
    const canvas = node.ownerDocument.createElementNS(XHTML_NS, "canvas");
    canvas.width = imgWidth * resizeRatio;
    canvas.height = imgHeight * resizeRatio;
    const ctx = canvas.getContext("2d");

    // Copy the rawNode image or canvas in the new canvas and extract data
    ctx.drawImage(node, 0, 0, canvas.width, canvas.height);
    imageData = canvas.toDataURL("image/png");
  }

  return {
    data: imageData,
    size: {
      naturalWidth: imgWidth,
      naturalHeight: imgHeight,
      resized: resizeRatio !== 1,
    },
  };
};

/**
 * Finds the computed background color of the closest parent with a set background color.
 *
 * @param  {DOMNode}  node
 *         Node for which we want to find closest background color.
 * @return {String}
 *         String with the background color of the form rgba(r, g, b, a). Defaults to
 *         rgba(255, 255, 255, 1) if no background color is found.
 */

function getClosestBackgroundColor(node) {
  let current = node;

  while (current) {
    const computedStyle = CssLogic.getComputedStyle(current);
    if (computedStyle) {
      const currentStyle = computedStyle.getPropertyValue("background-color");
      if (InspectorUtils.isValidCSSColor(currentStyle)) {
        const currentCssColor = new colorUtils.CssColor(currentStyle);
        if (!currentCssColor.isTransparent()) {
          return currentCssColor.rgba;
        }
      }
    }

    current = current.parentNode;
  }

  return "rgba(255, 255, 255, 1)";
}

/**
 * Finds the background image of the closest parent where it is set.
 *
 * @param  {DOMNode}  node
 *         Node for which we want to find the background image.
 * @return {String}
 *         String with the value of the background iamge property. Defaults to "none" if
 *         no background image is found.
 */

function getClosestBackgroundImage(node) {
  let current = node;

  while (current) {
    const computedStyle = CssLogic.getComputedStyle(current);
    if (computedStyle) {
      const currentBackgroundImage =
        computedStyle.getPropertyValue("background-image");
      if (currentBackgroundImage !== "none") {
        return currentBackgroundImage;
      }
    }

    current = current.parentNode;
  }

  return "none";
}

/**
 * If the provided node is a grid item, then return its parent grid.
 *
 * @param  {DOMNode} node
 *         The node that is supposedly a grid item.
 * @return {DOMNode|null}
 *         The parent grid if found, null otherwise.
 */

function findGridParentContainerForNode(node) {
  try {
    while ((node = node.parentNode)) {
      const display = node.ownerGlobal.getComputedStyle(node).display;

      if (display.includes("grid")) {
        return node;
      } else if (display === "contents") {
        // Continue walking up the tree since the parent node is a content element.
        continue;
      }

      break;
    }
  } catch (e) {
    // Getting the parentNode can fail when the supplied node is in shadow DOM.
  }

  return null;
}

/**
 * Finds the background color range for the parent of a single text node
 * (i.e. for multi-colored backgrounds with gradients, images) or a single
 * background color for single-colored backgrounds. Defaults to the closest
 * background color if an error is encountered.
 *
 * @param  {Object}
 *         Node actor containing the following properties:
 *         {DOMNode} rawNode
 *         Node for which we want to calculate the color contrast.
 *         {WalkerActor} walker
 *         Walker actor used to check whether the node is the parent elm of a single text node.
 * @return {Object}
 *         Object with one or more of the following properties:
 *         {Array|null} value
 *         RGBA array for single-colored background. Null for multi-colored backgrounds.
 *         {Array|null} min
 *         RGBA array for the min luminance color in a multi-colored background.
 *         Null for single-colored backgrounds.
 *         {Array|null} max
 *         RGBA array for the max luminance color in a multi-colored background.
 *         Null for single-colored backgrounds.
 */

async function getBackgroundColor({ rawNode: node, walker }) {
  // Fall back to calculating contrast against closest bg if:
  // - not element node
  // - more than one child
  // Avoid calculating bounds and creating doc walker by returning early.
  if (
    node.nodeType != Node.ELEMENT_NODE ||
    node.childNodes.length > 1 ||
    !node.firstChild
  ) {
    return {
      value: getClosestBackgroundColorInRGBA(node),
    };
  }

  const quads = getAdjustedQuads(node.ownerGlobal, node.firstChild, "content");

  // Fall back to calculating contrast against closest bg if there are no bounds for text node.
  // Avoid creating doc walker by returning early.
  if (quads.length === 0 || !quads[0].bounds) {
    return {
      value: getClosestBackgroundColorInRGBA(node),
    };
  }

  const bounds = quads[0].bounds;

  const docWalker = walker.getDocumentWalker(node);
  const firstChild = docWalker.firstChild();

  // Fall back to calculating contrast against closest bg if:
  // - more than one child
  // - unique child is not a text node
  if (
    !firstChild ||
    docWalker.nextSibling() ||
    firstChild.nodeType !== Node.TEXT_NODE
  ) {
    return {
      value: getClosestBackgroundColorInRGBA(node),
    };
  }

  // Try calculating complex backgrounds for node
  const win = node.ownerGlobal;
  loadSheetForBackgroundCalculation(win);
  const computedStyle = CssLogic.getComputedStyle(node);
  const props = computedStyle ? getTextProperties(computedStyle) : null;

  // Fall back to calculating contrast against closest bg if there are no text props.
  if (!props) {
    return {
      value: getClosestBackgroundColorInRGBA(node),
    };
  }

  const bgColor = await getBackgroundFor(node, {
    bounds,
    win,
    convertBoundsRelativeToViewport: false,
    size: props.size,
    isBoldText: props.isBoldText,
  });
  removeSheetForBackgroundCalculation(win);

  return (
    bgColor || {
      value: getClosestBackgroundColorInRGBA(node),
    }
  );
}

/**
 *
 * @param {DOMNode} node: The node we want the background color of
 * @returns {Array[r,g,b,a]}
 */

function getClosestBackgroundColorInRGBA(node) {
  const { r, g, b, a } = InspectorUtils.colorToRGBA(
    getClosestBackgroundColor(node)
  );
  return [r, g, b, a];
}
/**
 * Indicates if a document is ready (i.e. if it's not loading anymore)
 *
 * @param {HTMLDocument} document: The document we want to check
 * @returns {Boolean}
 */

function isDocumentReady(document) {
  if (!document) {
    return false;
  }

  const { readyState } = document;
  if (readyState == "interactive" || readyState == "complete") {
    return true;
  }

  // A document might stay forever in unitialized state.
  // If the target actor is not currently loading a document,
  // assume the document is ready.
  const webProgress = document.defaultView.docShell.QueryInterface(
    Ci.nsIWebProgress
  );
  return !webProgress.isLoadingDocument;
}

module.exports = {
  allAnonymousContentTreeWalkerFilter,
  isDocumentReady,
  isWhitespaceTextNode,
  findGridParentContainerForNode,
  getBackgroundColor,
  getClosestBackgroundColor,
  getClosestBackgroundImage,
  getNodeDisplayName,
  getNodeGridFlexType,
  imageToImageData,
  isNodeDead,
  nodeDocument,
  standardTreeWalkerFilter,
  noAnonymousContentTreeWalkerFilter,
};

Messung V0.5
C=89 H=96 G=92

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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.