diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index 14356be6aab6..dc74b83c9bfc 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -1584,6 +1584,18 @@ bool DocAccessible::PruneOrInsertSubtree(nsIContent* aRoot) { // We schedule it for reinsertion. For example, a slotted element // can change its slot attribute to a different slot. insert = true; + + // If the frame is invisible, remove it. + // Normally, layout sends explicit a11y notifications for visibility + // changes (see SendA11yNotifications in RestyleManager). However, if a + // visibility change also reconstructs the frame, we must handle it here. + if (frame && !frame->StyleVisibility()->IsVisible()) { + ContentRemoved(aRoot); + // There might be visible descendants, so we want to walk the subtree. + // However, we know we don't want to reinsert this node, so we set insert + // to false. + insert = false; + } } else { // If there is no current accessible, and the node has a frame, or is // display:contents, schedule it for insertion. diff --git a/accessible/tests/mochitest/treeupdate/test_delayed_removal.html b/accessible/tests/mochitest/treeupdate/test_delayed_removal.html index 1a3d2c887763..87bc4012a7d1 100644 --- a/accessible/tests/mochitest/treeupdate/test_delayed_removal.html +++ b/accessible/tests/mochitest/treeupdate/test_delayed_removal.html @@ -341,6 +341,40 @@ is(getAccessible("c14").name, "one two three", "subtree has correct order"); } + // Ensure that a node is removed when visibility: hidden is set but the + // layout frame is reconstructed; e.g. because of position: fixed. Also + // ensure that visible children aren't clobbered. + async function visibilityHiddenWithReframe() { + let msg = "visibilityHiddenWithReframe"; + info(msg); + + testAccessibleTree("c15", { SECTION: [ // c15 + { SECTION: [ // c15_inner + { TEXT_LEAF: [] }, // Text + { PARAGRAPH: [ + { TEXT_LEAF: [] } // Para + ] }, + { HEADING: [ // c15_visible + { TEXT_LEAF: [] } // Visible + ] }, // c15_visible + ] } // c15_inner + ] }); + + let events = waitForOrderedEvents([ + [EVENT_HIDE, "c15_inner"], + [EVENT_SHOW, "c15_visible"], + [EVENT_REORDER, "c15"], + ], msg); + getNode("c15_inner").style = "visibility: hidden; position: fixed;"; + await events; + + testAccessibleTree("c15", { SECTION: [ // c15 + { HEADING: [ // c15_visible + { TEXT_LEAF: [] } // Visible + ] }, // c15_visible + ] }); + } + async function doTest() { await hideDivFromInsideSpan(); @@ -369,6 +403,9 @@ await testCSSGeneratedContentRemovedFromButton(); await testSlack(); + + await visibilityHiddenWithReframe(); + SimpleTest.finish(); } @@ -448,6 +485,12 @@ +
+ Text +

Para

+

Visible

+
+