1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 loader.lazyRequireGetter(
10 "resource://devtools/shared/DevToolsUtils.js"
13 ChromeUtils.defineESModuleGetters(lazy, {
14 NetUtil: "resource://gre/modules/NetUtil.sys.mjs",
20 author: "AUTHOR_SHEET",
23 // eslint-disable-next-line no-unused-vars
24 loader.lazyRequireGetter(
26 "setIgnoreLayoutChanges",
27 "resource://devtools/server/actors/reflow.js",
30 exports.setIgnoreLayoutChanges = (...args) =>
31 this.setIgnoreLayoutChanges(...args);
34 * Returns the `DOMWindowUtils` for the window given.
36 * @param {DOMWindow} win
37 * @returns {DOMWindowUtils}
39 const utilsCache = new WeakMap();
40 function utilsFor(win) {
41 // XXXbz Given that we now have a direct getter for the DOMWindowUtils, is
42 // this weakmap cache path any faster than just calling the getter?
43 if (!utilsCache.has(win)) {
44 utilsCache.set(win, win.windowUtils);
46 return utilsCache.get(win);
50 * Check a window is part of the boundary window given.
52 * @param {DOMWindow} boundaryWindow
53 * @param {DOMWindow} win
56 function isWindowIncluded(boundaryWindow, win) {
57 if (win === boundaryWindow) {
61 const parent = win.parent;
63 if (!parent || parent === win) {
67 return isWindowIncluded(boundaryWindow, parent);
69 exports.isWindowIncluded = isWindowIncluded;
72 * like win.frameElement, but goes through mozbrowsers and mozapps iframes.
74 * @param {DOMWindow} win
75 * The window to get the frame for
77 * The element in which the window is embedded.
79 const getFrameElement = win => {
80 const isTopWindow = win && DevToolsUtils.getTopWindow(win) === win;
81 return isTopWindow ? null : win.browsingContext.embedderElement;
83 exports.getFrameElement = getFrameElement;
86 * Get the x/y offsets for of all the parent frames of a given node, limited to
87 * the boundary window given.
89 * @param {DOMWindow} boundaryWindow
90 * The window where to stop to iterate. If `null` is given, the top
92 * @param {DOMNode} node
93 * The node for which we are to get the offset
95 * The frame offset [x, y]
97 function getFrameOffsets(boundaryWindow, node) {
101 let frameWin = getWindowFor(node);
102 const scale = getCurrentZoom(node);
104 if (boundaryWindow === null) {
105 boundaryWindow = DevToolsUtils.getTopWindow(frameWin);
106 } else if (typeof boundaryWindow === "undefined") {
107 throw new Error("No boundaryWindow given. Use null for the default one.");
110 while (frameWin !== boundaryWindow) {
111 const frameElement = getFrameElement(frameWin);
116 // We are in an iframe.
117 // We take into account the parent iframe position and its
118 // offset (borders and padding).
119 const frameRect = frameElement.getBoundingClientRect();
121 const [offsetTop, offsetLeft] = getFrameContentOffset(frameElement);
123 xOffset += frameRect.left + offsetLeft;
124 yOffset += frameRect.top + offsetTop;
126 frameWin = frameWin.parent;
129 return [xOffset * scale, yOffset * scale];
131 exports.getFrameOffsets = getFrameOffsets;
134 * Get box quads adjusted for iframes and zoom level.
136 * Warning: this function returns things that look like DOMQuad objects but
137 * aren't (they resemble an old version of the spec). Unlike the return value
138 * of node.getBoxQuads, they have a .bounds property and not a .getBounds()
141 * @param {DOMWindow} boundaryWindow
142 * The window where to stop to iterate. If `null` is given, the top
144 * @param {DOMNode} node
145 * The node for which we are to get the box model region
147 * @param {String} region
148 * The box model region to return: "content", "padding", "border" or
150 * @param {Object} [options.ignoreZoom=false]
151 * Ignore zoom used in the context of e.g. canvas.
153 * An array of objects that have the same structure as quads returned by
154 * getBoxQuads. An empty array if the node has no quads or is invalid.
156 function getAdjustedQuads(
160 { ignoreZoom, ignoreScroll } = {}
162 if (!node || !node.getBoxQuads) {
166 const quads = node.getBoxQuads({
168 relativeTo: boundaryWindow.document,
169 createFramesForSuppressedWhitespace: false,
176 const scale = ignoreZoom ? 1 : getCurrentZoom(node);
177 const { scrollX, scrollY } = ignoreScroll
178 ? { scrollX: 0, scrollY: 0 }
181 const xOffset = scrollX * scale;
182 const yOffset = scrollY * scale;
184 const adjustedQuads = [];
185 for (const quad of quads) {
186 const bounds = quad.getBounds();
189 w: quad.p1.w * scale,
190 x: quad.p1.x * scale + xOffset,
191 y: quad.p1.y * scale + yOffset,
192 z: quad.p1.z * scale,
195 w: quad.p2.w * scale,
196 x: quad.p2.x * scale + xOffset,
197 y: quad.p2.y * scale + yOffset,
198 z: quad.p2.z * scale,
201 w: quad.p3.w * scale,
202 x: quad.p3.x * scale + xOffset,
203 y: quad.p3.y * scale + yOffset,
204 z: quad.p3.z * scale,
207 w: quad.p4.w * scale,
208 x: quad.p4.x * scale + xOffset,
209 y: quad.p4.y * scale + yOffset,
210 z: quad.p4.z * scale,
213 bottom: bounds.bottom * scale + yOffset,
214 height: bounds.height * scale,
215 left: bounds.left * scale + xOffset,
216 right: bounds.right * scale + xOffset,
217 top: bounds.top * scale + yOffset,
218 width: bounds.width * scale,
219 x: bounds.x * scale + xOffset,
220 y: bounds.y * scale + yOffset,
225 return adjustedQuads;
227 exports.getAdjustedQuads = getAdjustedQuads;
230 * Compute the absolute position and the dimensions of a node, relativalely
231 * to the root window.
233 * @param {DOMWindow} boundaryWindow
234 * The window where to stop to iterate. If `null` is given, the top
236 * @param {DOMNode} node
237 * a DOM element to get the bounds for
238 * @param {DOMWindow} contentWindow
239 * the content window holding the node
241 * A rect object with the {top, left, width, height} properties
243 function getRect(boundaryWindow, node, contentWindow) {
244 let frameWin = node.ownerDocument.defaultView;
245 const clientRect = node.getBoundingClientRect();
247 if (boundaryWindow === null) {
248 boundaryWindow = DevToolsUtils.getTopWindow(frameWin);
249 } else if (typeof boundaryWindow === "undefined") {
250 throw new Error("No boundaryWindow given. Use null for the default one.");
253 // Go up in the tree of frames to determine the correct rectangle.
254 // clientRect is read-only, we need to be able to change properties.
256 top: clientRect.top + contentWindow.pageYOffset,
257 left: clientRect.left + contentWindow.pageXOffset,
258 width: clientRect.width,
259 height: clientRect.height,
262 // We iterate through all the parent windows.
263 while (frameWin !== boundaryWindow) {
264 const frameElement = getFrameElement(frameWin);
269 // We are in an iframe.
270 // We take into account the parent iframe position and its
271 // offset (borders and padding).
272 const frameRect = frameElement.getBoundingClientRect();
274 const [offsetTop, offsetLeft] = getFrameContentOffset(frameElement);
276 rect.top += frameRect.top + offsetTop;
277 rect.left += frameRect.left + offsetLeft;
279 frameWin = frameWin.parent;
284 exports.getRect = getRect;
287 * Get the 4 bounding points for a node taking iframes into account.
288 * Note that for transformed nodes, this will return the untransformed bound.
290 * @param {DOMWindow} boundaryWindow
291 * The window where to stop to iterate. If `null` is given, the top
293 * @param {DOMNode} node
295 * An object with p1,p2,p3,p4 properties being {x,y} objects
297 function getNodeBounds(boundaryWindow, node) {
301 const { scrollX, scrollY } = boundaryWindow;
302 const scale = getCurrentZoom(node);
304 // Find out the offset of the node in its current frame
308 while (el?.parentNode) {
309 offsetLeft += el.offsetLeft;
310 offsetTop += el.offsetTop;
311 el = el.offsetParent;
314 // Also take scrolled containers into account
316 while (el?.parentNode) {
318 offsetTop -= el.scrollTop;
321 offsetLeft -= el.scrollLeft;
326 // And add the potential frame offset if the node is nested
327 let [xOffset, yOffset] = getFrameOffsets(boundaryWindow, node);
328 xOffset += (offsetLeft + scrollX) * scale;
329 yOffset += (offsetTop + scrollY) * scale;
331 // Get the width and height
332 const width = node.offsetWidth * scale;
333 const height = node.offsetHeight * scale;
336 p1: { x: xOffset, y: yOffset },
337 p2: { x: xOffset + width, y: yOffset },
338 p3: { x: xOffset + width, y: yOffset + height },
339 p4: { x: xOffset, y: yOffset + height },
341 right: xOffset + width,
342 bottom: yOffset + height,
348 exports.getNodeBounds = getNodeBounds;
351 * Same as doing iframe.contentWindow but works with all types of container
352 * elements that act like frames (e.g. <embed>), where 'contentWindow' isn't a
353 * property that can be accessed.
354 * This uses the inIDeepTreeWalker instead.
355 * @param {DOMNode} frame
358 function safelyGetContentWindow(frame) {
359 if (frame.contentWindow) {
360 return frame.contentWindow;
363 const walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"].createInstance(
366 walker.showSubDocuments = true;
367 walker.showDocumentsAsNodes = true;
369 walker.currentNode = frame;
371 const document = walker.nextNode();
372 if (!document || !document.defaultView) {
373 throw new Error("Couldn't get the content window inside frame " + frame);
376 return document.defaultView;
380 * Returns a frame's content offset (frame border + padding).
381 * Note: this function shouldn't need to exist, had the platform provided a
382 * suitable API for determining the offset between the frame's content and
383 * its bounding client rect. Bug 626359 should provide us with such an API.
385 * @param {DOMNode} frame
387 * @return {Array} [offsetTop, offsetLeft]
388 * offsetTop is the distance from the top of the frame and the top of
389 * the content document.
390 * offsetLeft is the distance from the left of the frame and the left
391 * of the content document.
393 function getFrameContentOffset(frame) {
394 const style = safelyGetContentWindow(frame).getComputedStyle(frame);
396 // In some cases, the computed style is null
401 const paddingTop = parseInt(style.getPropertyValue("padding-top"), 10);
402 const paddingLeft = parseInt(style.getPropertyValue("padding-left"), 10);
404 const borderTop = parseInt(style.getPropertyValue("border-top-width"), 10);
405 const borderLeft = parseInt(style.getPropertyValue("border-left-width"), 10);
407 return [borderTop + paddingTop, borderLeft + paddingLeft];
411 * Check if a node and its document are still alive
412 * and attached to the window.
414 * @param {DOMNode} node
417 function isNodeConnected(node) {
418 if (!node.ownerDocument || !node.ownerDocument.defaultView) {
424 node.compareDocumentPosition(node.ownerDocument.documentElement) &
425 node.DOCUMENT_POSITION_DISCONNECTED
428 // "can't access dead object" error
432 exports.isNodeConnected = isNodeConnected;
435 * Determine whether a node is anonymous.
437 * @param {DOMNode} node
440 * FIXME(bug 1597411): Remove one of these (or both, as
441 * `node.isNativeAnonymous` is quite clear).
443 const isAnonymous = node => node.isNativeAnonymous;
444 exports.isAnonymous = isAnonymous;
445 exports.isNativeAnonymous = isAnonymous;
448 * Determine whether a node is a template element.
450 * @param {DOMNode} node
453 function isTemplateElement(node) {
455 node.ownerGlobal && node.ownerGlobal.HTMLTemplateElement.isInstance(node)
458 exports.isTemplateElement = isTemplateElement;
461 * Determine whether a node is a shadow root.
463 * @param {DOMNode} node
466 const isShadowRoot = node => node.containingShadowRoot == node;
467 exports.isShadowRoot = isShadowRoot;
470 * Gets the shadow root mode (open or closed).
472 * @param {DOMNode} node
473 * @return {String|null}
475 function getShadowRootMode(node) {
476 return isShadowRoot(node) ? node.mode : null;
478 exports.getShadowRootMode = getShadowRootMode;
481 * Determine whether a node is a shadow host, ie. an element that has a shadowRoot
482 * attached to itself.
484 * @param {DOMNode} node
487 function isShadowHost(node) {
488 const shadowRoot = node.openOrClosedShadowRoot;
489 return shadowRoot && shadowRoot.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
491 exports.isShadowHost = isShadowHost;
494 * Determine whether a node is a child of a shadow host. Even if the element has been
495 * assigned to a slot in the attached shadow DOM, the parent node for this element is
496 * still considered to be the "host" element, and we need to walk them differently.
498 * @param {DOMNode} node
501 function isDirectShadowHostChild(node) {
502 // Pseudo elements and native anonymous elements are always part of the anonymous tree.
504 isMarkerPseudoElement(node) ||
505 isBeforePseudoElement(node) ||
506 isAfterPseudoElement(node) ||
507 node.isNativeAnonymous
512 const parentNode = node.parentNode;
513 return parentNode && !!parentNode.openOrClosedShadowRoot;
515 exports.isDirectShadowHostChild = isDirectShadowHostChild;
518 * Determine whether a node is a ::marker pseudo.
520 * @param {DOMNode} node
523 function isMarkerPseudoElement(node) {
524 return node.nodeName === "_moz_generated_content_marker";
526 exports.isMarkerPseudoElement = isMarkerPseudoElement;
529 * Determine whether a node is a ::before pseudo.
531 * @param {DOMNode} node
534 function isBeforePseudoElement(node) {
535 return node.nodeName === "_moz_generated_content_before";
537 exports.isBeforePseudoElement = isBeforePseudoElement;
540 * Determine whether a node is a ::after pseudo.
542 * @param {DOMNode} node
545 function isAfterPseudoElement(node) {
546 return node.nodeName === "_moz_generated_content_after";
548 exports.isAfterPseudoElement = isAfterPseudoElement;
551 * Get the current zoom factor applied to the container window of a given node.
552 * @param {DOMNode|DOMWindow}
553 * The node for which the zoom factor should be calculated, or its
557 function getCurrentZoom(node) {
558 const win = getWindowFor(node);
561 throw new Error("Unable to get the zoom from the given argument.");
564 return win.browsingContext?.fullZoom || 1.0;
566 exports.getCurrentZoom = getCurrentZoom;
569 * Get the display pixel ratio for a given window.
570 * The `devicePixelRatio` property is affected by the zoom (see bug 809788), so we have to
571 * divide by the zoom value in order to get just the display density, expressed as pixel
572 * ratio (the physical display pixel compares to a pixel on a “normal” density screen).
574 * @param {DOMNode|DOMWindow}
575 * The node for which the zoom factor should be calculated, or its
579 function getDisplayPixelRatio(node) {
580 const win = getWindowFor(node);
581 return win.devicePixelRatio / getCurrentZoom(node);
583 exports.getDisplayPixelRatio = getDisplayPixelRatio;
586 * Returns the window's dimensions for the `window` given.
588 * @return {Object} An object with `width` and `height` properties, representing the
589 * number of pixels for the document's size.
591 function getWindowDimensions(window) {
592 // First we'll try without flushing layout, because it's way faster.
593 const windowUtils = utilsFor(window);
594 let { width, height } = windowUtils.getRootBounds();
596 if (!width || !height) {
597 // We need a flush after all :'(
598 width = window.innerWidth + window.scrollMaxX - window.scrollMinX;
599 height = window.innerHeight + window.scrollMaxY - window.scrollMinY;
601 const scrollbarHeight = {};
602 const scrollbarWidth = {};
603 windowUtils.getScrollbarSize(false, scrollbarWidth, scrollbarHeight);
604 width -= scrollbarWidth.value;
605 height -= scrollbarHeight.value;
608 return { width, height };
610 exports.getWindowDimensions = getWindowDimensions;
613 * Returns the viewport's dimensions for the `window` given.
615 * @return {Object} An object with `width` and `height` properties, representing the
616 * number of pixels for the viewport's size.
618 function getViewportDimensions(window) {
619 const windowUtils = utilsFor(window);
621 const scrollbarHeight = {};
622 const scrollbarWidth = {};
623 windowUtils.getScrollbarSize(false, scrollbarWidth, scrollbarHeight);
625 const width = window.innerWidth - scrollbarWidth.value;
626 const height = window.innerHeight - scrollbarHeight.value;
628 return { width, height };
630 exports.getViewportDimensions = getViewportDimensions;
633 * Return the default view for a given node, where node can be:
635 * - the document node
636 * - the window itself
637 * @param {DOMNode|DOMWindow|DOMDocument} node The node to get the window for.
638 * @return {DOMWindow}
640 function getWindowFor(node) {
641 if (Node.isInstance(node)) {
642 if (node.nodeType === node.DOCUMENT_NODE) {
643 return node.defaultView;
645 return node.ownerDocument.defaultView;
646 } else if (node instanceof Ci.nsIDOMWindow) {
653 * Synchronously loads a style sheet from `uri` and adds it to the list of
654 * additional style sheets of the document.
655 * The sheets added takes effect immediately, and only on the document of the
658 * @param {DOMWindow} window
659 * @param {String} url
660 * @param {String} [type="agent"]
662 function loadSheet(window, url, type = "agent") {
663 if (!(type in SHEET_TYPE)) {
667 const windowUtils = utilsFor(window);
669 windowUtils.loadSheetUsingURIString(url, windowUtils[SHEET_TYPE[type]]);
671 // The method fails if the url is already loaded.
674 exports.loadSheet = loadSheet;
677 * Remove the document style sheet at `sheetURI` from the list of additional
678 * style sheets of the document. The removal takes effect immediately.
680 * @param {DOMWindow} window
681 * @param {String} url
682 * @param {String} [type="agent"]
684 function removeSheet(window, url, type = "agent") {
685 if (!(type in SHEET_TYPE)) {
689 const windowUtils = utilsFor(window);
691 windowUtils.removeSheetUsingURIString(url, windowUtils[SHEET_TYPE[type]]);
693 // The method fails if the url is already removed.
696 exports.removeSheet = removeSheet;
699 * Get the untransformed coordinates for a node.
701 * @param {DOMNode} node
702 * The node for which the DOMQuad is to be returned.
703 * @param {String} region
704 * The box model region to return: "content", "padding", "border" or
707 * A DOMQuad representation of the node.
709 function getUntransformedQuad(node, region = "border") {
710 // Get the inverse transformation matrix for the node.
711 const matrix = node.getTransformToViewport();
712 const inverse = matrix.inverse();
713 const win = node.ownerGlobal;
715 // Get the adjusted quads for the node (including scroll offsets).
716 const quads = getAdjustedQuads(win, node, region, {
720 // Create DOMPoints from the transformed node position.
721 const p1 = new DOMPoint(quads[0].p1.x, quads[0].p1.y);
722 const p2 = new DOMPoint(quads[0].p2.x, quads[0].p2.y);
723 const p3 = new DOMPoint(quads[0].p3.x, quads[0].p3.y);
724 const p4 = new DOMPoint(quads[0].p4.x, quads[0].p4.y);
726 // Apply the inverse transformation matrix to the points to get the
727 // untransformed points.
728 const ip1 = inverse.transformPoint(p1);
729 const ip2 = inverse.transformPoint(p2);
730 const ip3 = inverse.transformPoint(p3);
731 const ip4 = inverse.transformPoint(p4);
733 // Save the results in a DOMQuad.
734 const quad = new DOMQuad(
735 { x: ip1.x, y: ip1.y },
736 { x: ip2.x, y: ip2.y },
737 { x: ip3.x, y: ip3.y },
738 { x: ip4.x, y: ip4.y }
741 // Remove the border offsets because we include them when calculating
742 // offsets in the while loop.
743 const style = win.getComputedStyle(node);
744 const leftAdjustment = parseInt(style.borderLeftWidth, 10) || 0;
745 const topAdjustment = parseInt(style.borderTopWidth, 10) || 0;
747 quad.p1.x -= leftAdjustment;
748 quad.p2.x -= leftAdjustment;
749 quad.p3.x -= leftAdjustment;
750 quad.p4.x -= leftAdjustment;
751 quad.p1.y -= topAdjustment;
752 quad.p2.y -= topAdjustment;
753 quad.p3.y -= topAdjustment;
754 quad.p4.y -= topAdjustment;
756 // Calculate offsets.
758 const nodeStyle = win.getComputedStyle(node);
759 const borderLeftWidth = parseInt(nodeStyle.borderLeftWidth, 10) || 0;
760 const borderTopWidth = parseInt(nodeStyle.borderTopWidth, 10) || 0;
761 const leftOffset = node.offsetLeft - node.scrollLeft + borderLeftWidth;
762 const topOffset = node.offsetTop - node.scrollTop + borderTopWidth;
764 quad.p1.x += leftOffset;
765 quad.p2.x += leftOffset;
766 quad.p3.x += leftOffset;
767 quad.p4.x += leftOffset;
768 quad.p1.y += topOffset;
769 quad.p2.y += topOffset;
770 quad.p3.y += topOffset;
771 quad.p4.y += topOffset;
773 node = node.offsetParent;
778 exports.getUntransformedQuad = getUntransformedQuad;
781 * Calculate the total of the node and all of its ancestor's scrollTop and
784 * @param {DOMNode} node
785 * The node for which the absolute scroll offsets should be calculated.
786 * @return {Object} object
787 * An object containing scrollTop and scrollLeft values.
788 * @return {Number} object.scrollLeft
789 * The total scrollLeft values of the node and all of its ancestors.
790 * @return {Number} object.scrollTop
791 * The total scrollTop values of the node and all of its ancestors.
793 function getAbsoluteScrollOffsetsForNode(node) {
794 const doc = node.ownerDocument;
796 // Our walker will only iterate up to document.body so we start by saving the
797 // scroll values for `document.documentElement`.
798 let scrollTop = doc.documentElement.scrollTop;
799 let scrollLeft = doc.documentElement.scrollLeft;
800 const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT);
801 walker.currentNode = node;
802 let currentNode = walker.currentNode;
804 // Iterate from `node` up the tree to `document.body` adding scroll offsets
806 while (currentNode) {
807 const nodeScrollTop = currentNode.scrollTop;
808 const nodeScrollLeft = currentNode.scrollLeft;
810 if (nodeScrollTop || nodeScrollLeft) {
811 scrollTop += nodeScrollTop;
812 scrollLeft += nodeScrollLeft;
815 currentNode = walker.parentNode();
823 exports.getAbsoluteScrollOffsetsForNode = getAbsoluteScrollOffsetsForNode;
826 * Check if the provided node is a <frame> or <iframe> element.
828 * @param {DOMNode} node
831 function isFrame(node) {
832 const className = ChromeUtils.getClassName(node);
833 return className == "HTMLIFrameElement" || className == "HTMLFrameElement";
837 * Check if the provided node is representing a remote <browser> element.
839 * @param {DOMNode} node
842 function isRemoteBrowserElement(node) {
844 ChromeUtils.getClassName(node) == "XULFrameElement" &&
845 !node.childNodes.length &&
846 node.getAttribute("remote") == "true"
849 exports.isRemoteBrowserElement = isRemoteBrowserElement;
852 * Check if the provided node is representing a remote frame.
854 * - In the context of the browser toolbox, a remote frame can be the <browser remote>
855 * element found inside each tab.
856 * - In the context of the content toolbox, a remote frame can be a <iframe> that contains
857 * a different origin document.
859 * @param {DOMNode} node
862 function isRemoteFrame(node) {
864 return node.frameLoader?.isRemoteFrame;
867 if (isRemoteBrowserElement(node)) {
873 exports.isRemoteFrame = isRemoteFrame;
876 * Check if the provided node is representing a frame that has its own dedicated child target.
878 * @param {BrowsingContextTargetActor} targetActor
879 * @param {DOMNode} node
882 function isFrameWithChildTarget(targetActor, node) {
883 // If the iframe is blocked because of CSP, it won't have a document (and no associated targets)
884 if (isFrameBlockedByCSP(node)) {
888 return isRemoteFrame(node) || (isFrame(node) && targetActor.ignoreSubFrames);
891 exports.isFrameWithChildTarget = isFrameWithChildTarget;
894 * Check if the provided node is representing a frame that is blocked by CSP.
896 * @param {DOMNode} node
899 function isFrameBlockedByCSP(node) {
900 if (!isFrame(node)) {
910 uri = lazy.NetUtil.newURI(node.src);
915 const res = node.ownerDocument.csp.shouldLoad(
916 Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
917 null, // nsICSPEventListener
920 null, // aOriginalURIIfRedirect
921 false // aSendViolationReports
924 return res !== Ci.nsIContentPolicy.ACCEPT;
927 exports.isFrameBlockedByCSP = isFrameBlockedByCSP;