tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 2737b801d7a2b6fe99f2c24256a254521dd72bc2
parent 6597cc40fcc39ca6bd521431b5892f9308508874
Author: Nicolas Chevobbe <nchevobbe@mozilla.com>
Date:   Mon, 22 Dec 2025 15:31:19 +0000

Bug 2006508 - [devtools] Show ::backdrop node in Inspector. r=devtools-reviewers,ochameau.

Accept ::backdrop pseudo element in the walker standard filter and set the proper
parent for it in getBindingElementAndPseudo.

We also add a few test cases to make sure the node is properly displayed in the
markup view and the animations panel.

Differential Revision: https://phabricator.services.mozilla.com/D276854

Diffstat:
Mdevtools/client/inspector/animation/test/browser_animation_pseudo-element.js | 4++++
Mdevtools/client/inspector/animation/test/doc_pseudo.html | 17+++++++++++++++++
Mdevtools/client/inspector/markup/test/browser_markup_pseudo.js | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdevtools/client/inspector/markup/test/browser_markup_search_01.js | 8++++++++
Mdevtools/client/inspector/markup/test/doc_markup_pseudo.html | 8++++++++
Mdevtools/client/inspector/markup/test/doc_markup_search.css | 4++++
Mdevtools/client/inspector/markup/test/doc_markup_search.html | 4++++
Mdevtools/client/inspector/test/browser_inspector_breadcrumbs.js | 14++++++++++++++
Mdevtools/client/inspector/test/doc_inspector_breadcrumbs.html | 10++++++++++
Mdevtools/client/inspector/test/highlighter/browser_inspector_highlighter-02.js | 16++++++++++++++++
Mdevtools/client/inspector/test/highlighter/doc_inspector_highlighter.html | 13+++++++++++++
Mdevtools/server/actors/inspector/utils.js | 12++++++------
Mdevtools/shared/inspector/css-logic.js | 3++-
13 files changed, 177 insertions(+), 7 deletions(-)

diff --git a/devtools/client/inspector/animation/test/browser_animation_pseudo-element.js b/devtools/client/inspector/animation/test/browser_animation_pseudo-element.js @@ -27,6 +27,10 @@ const TEST_DATA = [ expectedAnimationNameLabel: "div-after", }, { + expectedTargetLabel: "::backdrop", + expectedAnimationNameLabel: "dialog-backdrop", + }, + { expectedTargetLabel: "::marker", expectedAnimationNameLabel: "div-marker", }, diff --git a/devtools/client/inspector/animation/test/doc_pseudo.html b/devtools/client/inspector/animation/test/doc_pseudo.html @@ -33,6 +33,10 @@ content: "div-marker"; } + dialog::backdrop { + animation: dialog-backdrop 8.5s infinite; + } + ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { @@ -86,6 +90,15 @@ opacity: 0deg; } } + + @keyframes dialog-backdrop { + from { + background-color: hotpink; + } + to { + background-color: gold; + } + } </style> </head> <body> @@ -93,6 +106,7 @@ <div class="div-after"></div> <div class="div-marker"></div> <div class="div-view-transition">Hello</div> + <dialog>My Modal</dialog> <script> "use strict"; @@ -111,6 +125,9 @@ pseudoElement: "::marker", } ); + + // show the dialog modal so the backdrop pseudo element node gets displayed + document.querySelector("dialog").showModal(); </script> </body> </html> diff --git a/devtools/client/inspector/markup/test/browser_markup_pseudo.js b/devtools/client/inspector/markup/test/browser_markup_pseudo.js @@ -93,6 +93,77 @@ add_task(async function testMarkerOnPseudo() { "hidden", "Expander button is not visible for ul::after" ); + + await selectNode("dialog", inspector); + + const dialogNodeFront = await getNodeFront("dialog", inspector); + const dialogContainer = await getContainerForNodeFront( + dialogNodeFront, + inspector + ); + is( + ulContainer.expander.style.visibility, + "visible", + "Expander button is visible for <dialog>" + ); + + info("Click on the <dialog> parent expander and wait for children"); + await toggleContainerByClick(inspector, dialogContainer); + + let tree = ` + html + head!ignore-children + body + article!ignore-children + ul!ignore-children + dialog + p + `.trim(); + await assertMarkupViewAsTree(tree, "html", inspector); + + info("Show the dialog modal and wait for mutation"); + let onMarkupMutation = inspector.once("markupmutation"); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { + content.document.querySelector("dialog").showModal(); + }); + await onMarkupMutation; + + info( + "Check that both the ::backdrop and ::before element are now displayed under <dialog>" + ); + tree = ` + html + head!ignore-children + body + article!ignore-children + ul!ignore-children + dialog + ::backdrop + ::before + p + `.trim(); + await assertMarkupViewAsTree(tree, "html", inspector); + + info("Hide the dialog modal and wait for mutation"); + onMarkupMutation = inspector.once("markupmutation"); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { + content.document.querySelector("dialog").close(); + }); + await onMarkupMutation; + + info( + "Check that both the <dialog> ::backdrop and ::before children gets removed" + ); + tree = ` + html + head!ignore-children + body + article!ignore-children + ul!ignore-children + dialog + p + `.trim(); + await assertMarkupViewAsTree(tree, "html", inspector); }); async function checkMarkupView(inspector) { diff --git a/devtools/client/inspector/markup/test/browser_markup_search_01.js b/devtools/client/inspector/markup/test/browser_markup_search_01.js @@ -241,6 +241,14 @@ add_task(async function () { ); checkHighlightedSearchResults(inspector, ["::marker"]); + await searchInMarkupView(inspector, "::backdrop"); + is( + inspector.selection.nodeFront.displayName, + "::backdrop", + "The ::backdrop element is selected" + ); + checkHighlightedSearchResults(inspector, ["::backdrop"]); + // Search by the `content` declaration of the ::before and ::after pseudo elements await searchInMarkupView(inspector, "my_before_text"); is( diff --git a/devtools/client/inspector/markup/test/doc_markup_pseudo.html b/devtools/client/inspector/markup/test/doc_markup_pseudo.html @@ -19,6 +19,13 @@ ul::before::marker { ul::after { content: "-"; } + +dialog::backdrop { + background-color: gold; +} +dialog::before { + content: "before dialog"; +} </style> <article> @@ -28,3 +35,4 @@ ul::after { <li>Dogs</li> <li>Cats</li> </ul> +<dialog><p>My Dialog</p></dialog> diff --git a/devtools/client/inspector/markup/test/doc_markup_search.css b/devtools/client/inspector/markup/test/doc_markup_search.css @@ -12,3 +12,7 @@ /* large number so the view-transition pseudo elements are available during the whole test */ animation-duration: 3600s; } + +dialog::backdrop { + background-color: rgb(from hotpink r g b / 0.2); +} diff --git a/devtools/client/inspector/markup/test/doc_markup_search.html b/devtools/client/inspector/markup/test/doc_markup_search.html @@ -22,6 +22,7 @@ </section> <section id="cropped-attribute"></section> <section class="pseudos">|</section> + <dialog>My Modal</dialog> <script> "use strict"; @@ -40,6 +41,9 @@ const middle = Math.floor(collapseAttributeLength / 2); const cls = "-".repeat(middle) + strToMatch + "-".repeat(middle); croppedAttributeEl.classList.add(cls); + + // show the dialog modal so the backdrop pseudo element node gets displayed + document.querySelector("dialog").showModal(); </script> </body> </html> diff --git a/devtools/client/inspector/test/browser_inspector_breadcrumbs.js b/devtools/client/inspector/test/browser_inspector_breadcrumbs.js @@ -145,6 +145,20 @@ async function testPseudoElements(inspector, container) { "::after shows up in breadcrumb" ); + const dialogNodeFront = await getNodeFront("dialog", inspector); + const dialogChildren = await inspector.walker.children(dialogNodeFront); + is( + dialogChildren.nodes.length, + 2, + "Expected number of children for the dialog element" + ); + const backdropElement = dialogChildren.nodes[0]; + await checkBreadcrumbContent( + backdropElement, + ["html", "body", "dialog", "::backdrop"], + ":backdrop shows up in breadcrumb" + ); + info("Check rules on ::view-transition"); const htmlNodeFront = await getNodeFront("html", inspector); const onMarkupMutation = inspector.once("markupmutation"); diff --git a/devtools/client/inspector/test/doc_inspector_breadcrumbs.html b/devtools/client/inspector/test/doc_inspector_breadcrumbs.html @@ -13,6 +13,9 @@ #pseudo-container::after { content: 'after'; } + dialog::backdrop { + background-color: rgb(from hotpink r g b / 0.2); + } ::view-transition-group(root) { /* large number so the view-transition pseudo elements are available during the whole test */ @@ -69,6 +72,7 @@ <link /> </article> <div id='pseudo-container'></div> + <dialog>My Modal</dialog> <!-- This is a comment node --> <svg id="vector" viewBox="0 0 10 10"> <clipPath id="clip"> @@ -76,5 +80,11 @@ </clipPath> <circle cx="5" cy="5" r="5" fill="blue" clip-path="url(#clip)"></circle> </svg> + <script> + "use strict"; + + // show the dialog modal so the backdrop pseudo element node gets displayed + document.querySelector("dialog").showModal(); + </script> </body> </html> diff --git a/devtools/client/inspector/test/highlighter/browser_inspector_highlighter-02.js b/devtools/client/inspector/test/highlighter/browser_inspector_highlighter-02.js @@ -93,6 +93,22 @@ add_task(async function () { `::before::marker is properly displayed (${await getHighlighterInfobarText()})` ); + info("Highlighting the dialog::backdrop node"); + const dialogNodeFront = await getNodeFront("dialog", inspector); + const { nodes: dialogChildren } = + await inspector.walker.children(dialogNodeFront); + const dialogBackdropNodeFront = dialogChildren[0]; + onHighlighterShown = waitForHighlighterTypeShown( + inspector.highlighters.TYPES.BOXMODEL + ); + await selectNode(dialogBackdropNodeFront, inspector, "test-highlight"); + await onHighlighterShown; + is( + await getHighlighterInfobarText(), + "dialog::backdrop85 × 333", + `::backdrop is properly displayed` + ); + info("Check highlighting for ::view-transition pseudo elements"); const onMarkupMutation = inspector.once("markupmutation"); await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { diff --git a/devtools/client/inspector/test/highlighter/doc_inspector_highlighter.html b/devtools/client/inspector/test/highlighter/doc_inspector_highlighter.html @@ -48,6 +48,12 @@ color: gold; } + dialog::backdrop { + background-color: rgb(from hotpink r g b / 0.2); + width: 85px; + height: 333px; + } + ::view-transition-group(root) { /* large number so the view-transition pseudo elements are available during the whole test */ animation-duration: 3600s; @@ -62,5 +68,12 @@ <li>Dogs</li> <li>Cats</li> </ul> + <dialog>My Modal</dialog> + <script> + "use strict"; + + // show the dialog modal so the backdrop pseudo element node gets displayed + document.querySelector("dialog").showModal(); + </script> </body> </html> diff --git a/devtools/server/actors/inspector/utils.js b/devtools/server/actors/inspector/utils.js @@ -140,17 +140,17 @@ function isInXULDocument(el) { } /** - * 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). + * This DeepTreeWalker filter skips whitespace text nodes and anonymous content (unless + * we want them visible in the markup view, e.g. ::before, ::after, ::marker, …), + * 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 + // There are a few native anonymous content that we want to show in markup if ( node.nodeName === "_moz_generated_content_marker" || node.nodeName === "_moz_generated_content_before" || - node.nodeName === "_moz_generated_content_after" + node.nodeName === "_moz_generated_content_after" || + node.nodeName === "_moz_generated_content_backdrop" ) { return nodeFilterConstants.FILTER_ACCEPT; } diff --git a/devtools/shared/inspector/css-logic.js b/devtools/shared/inspector/css-logic.js @@ -571,7 +571,8 @@ function getBindingElementAndPseudo(node) { if ( implementedPseudoElement === "::marker" || implementedPseudoElement === "::before" || - implementedPseudoElement === "::after" + implementedPseudoElement === "::after" || + implementedPseudoElement === "::backdrop" ) { pseudo = getNodeDisplayName(node); bindingElement = node.parentNode;