Bug 1543599 - Don't suppress scroll anchoring adjustments when switching display to `none`. r=dholbert

Since that means that we won't suppress them when switching display back (since
we have no frame to pull the old style from).

We may want to match Chrome more exactly and don't do this any time `display`
changes (which if I'm reading their code correctly is what they do...).

But for now I've done the minimal thing and added a test.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-07-15 17:53:20 +00:00
Родитель 6ef01a0d95
Коммит 6aa7507e81
2 изменённых файлов: 90 добавлений и 5 удалений

Просмотреть файл

@ -2747,11 +2747,24 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
// XXXbholley: We should teach the frame constructor how to clear the dirty
// descendants bit to avoid the traversal here.
if (changeHint & nsChangeHint_ReconstructFrame) {
if (wasRestyled && styleFrame &&
styleFrame->StyleDisplay()->IsAbsolutelyPositionedStyle() !=
upToDateStyleIfRestyled->StyleDisplay()
->IsAbsolutelyPositionedStyle()) {
aRestyleState.AddPendingScrollAnchorSuppression(styleFrame);
if (wasRestyled && styleFrame) {
auto* oldDisp = styleFrame->StyleDisplay();
auto* newDisp = upToDateStyleIfRestyled->StyleDisplay();
// https://drafts.csswg.org/css-scroll-anchoring/#suppression-triggers
//
// We need to do the position check here rather than in
// DidSetComputedStyle because changing position reframes.
//
// Don't suppress adjustments when going back to display: none, regardless
// of whether we're abspos changes.
//
// TODO(emilio): I _think_ chrome won't suppress adjustments whenever
// `display` changes. But ICBW.
if (newDisp->mDisplay != StyleDisplay::None &&
oldDisp->IsAbsolutelyPositionedStyle() !=
newDisp->IsAbsolutelyPositionedStyle()) {
aRestyleState.AddPendingScrollAnchorSuppression(styleFrame);
}
}
ClearRestyleStateFromSubtree(aElement);
return true;

Просмотреть файл

@ -0,0 +1,72 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1543599">
<link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring/#suppression-triggers">
<style>
#hidden {
display: none;
background: red;
}
#spacer {
height: calc(100vh + 200px); /* At least 200px of scroll range */
}
</style>
<table>
<thead>
<tr>
<th>1
<th>1
<th>1
<th>1
</tr>
</thead>
<thead id="hidden">
<tr>
<th>1
<th>1
<th>1
<th>1
</tr>
</thead>
<tbody>
<tr><td>0 <td>0 <td>0 <td>0 </tr>
<tr><td>0 <td>0 <td>0 <td>0 </tr>
<tr><td>0 <td>0 <td>0 <td>0 </tr>
<tr><td>0 <td>0 <td>0 <td>0 </tr>
<tr><td>0 <td>0 <td>0 <td>0 </tr>
<tr><td>0 <td>0 <td>0 <td>0 </tr>
<tr><td>0 <td>0 <td>0 <td>0 </tr>
</tbody>
</table>
<div id="spacer"></div>
<script>
let firstEvent = true;
const targetScrollPosition = 100;
const hidden = document.querySelector("#hidden");
const t = async_test("Scroll offset doesn't change when an element goes back and forth to display: none");
window.onscroll = t.step_func(function() {
hidden.style.display = "block";
hidden.style.position = "absolute";
hidden.style.visibility = "hidden";
window.unused = hidden.offsetHeight;
hidden.style.display = "";
hidden.style.position = "";
hidden.style.visibility = "";
if (firstEvent) {
firstEvent = false;
requestAnimationFrame(t.step_func(function() {
requestAnimationFrame(t.step_func_done(function() {
assert_equals(document.scrollingElement.scrollTop, targetScrollPosition);
}));
}));
}
});
window.onload = t.step_func(function() {
window.scrollTo(0, targetScrollPosition);
});
</script>