Backed out changeset 7538d23ee88e (bug 1767262) for causing failures at content-visibility-081.html. CLOSED TREE
This commit is contained in:
@@ -253,17 +253,7 @@ nsIFrame* nsIContent::GetPrimaryFrame(mozilla::FlushType aType) {
|
||||
doc->FlushPendingNotifications(aType);
|
||||
}
|
||||
|
||||
auto* frame = GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aType == mozilla::FlushType::Layout) {
|
||||
frame->PresShell()->EnsureReflowIfFrameHasHiddenContent(frame);
|
||||
frame = GetPrimaryFrame();
|
||||
}
|
||||
|
||||
return frame;
|
||||
return GetPrimaryFrame();
|
||||
}
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
@@ -11821,37 +11821,3 @@ void PresShell::PingPerTickTelemetry(FlushType aFlushType) {
|
||||
bool PresShell::GetZoomableByAPZ() const {
|
||||
return mZoomConstraintsClient && mZoomConstraintsClient->GetAllowZoom();
|
||||
}
|
||||
|
||||
void PresShell::EnsureReflowIfFrameHasHiddenContent(nsIFrame* aFrame) {
|
||||
if (!aFrame || !aFrame->IsSubtreeDirty() ||
|
||||
!StaticPrefs::layout_css_content_visibility_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mHiddenContentInForcedLayout.IsEmpty());
|
||||
nsIFrame* topmostFrameWithContentHidden = nullptr;
|
||||
for (nsIFrame* cur = aFrame->GetInFlowParent(); cur;
|
||||
cur = cur->GetInFlowParent()) {
|
||||
if (cur->IsContentHidden()) {
|
||||
topmostFrameWithContentHidden = cur;
|
||||
mHiddenContentInForcedLayout.Insert(cur->GetContent());
|
||||
}
|
||||
}
|
||||
|
||||
if (mHiddenContentInForcedLayout.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Queue and immediately flush a reflow for this node.
|
||||
MOZ_ASSERT(topmostFrameWithContentHidden);
|
||||
FrameNeedsReflow(topmostFrameWithContentHidden, IntrinsicDirty::Resize,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
aFrame->PresContext()->Document()->FlushPendingNotifications(
|
||||
FlushType::Layout);
|
||||
|
||||
mHiddenContentInForcedLayout.Clear();
|
||||
}
|
||||
|
||||
bool PresShell::IsForcingLayoutForHiddenContent(const nsIFrame* aFrame) const {
|
||||
return mHiddenContentInForcedLayout.Contains(aFrame->GetContent());
|
||||
}
|
||||
|
||||
@@ -1739,18 +1739,6 @@ class PresShell final : public nsStubDocumentObserver,
|
||||
|
||||
bool GetZoomableByAPZ() const;
|
||||
|
||||
/**
|
||||
* If this frame has content hidden via `content-visibilty` that has a pending
|
||||
* reflow, force the content to reflow immediately.
|
||||
*/
|
||||
void EnsureReflowIfFrameHasHiddenContent(nsIFrame*);
|
||||
|
||||
/**
|
||||
* Whether or not this presshell is is forcing a reflow of hidden content in
|
||||
* this frame via EnsureReflowIfFrameHasHiddenContent().
|
||||
*/
|
||||
bool IsForcingLayoutForHiddenContent(const nsIFrame*) const;
|
||||
|
||||
private:
|
||||
~PresShell();
|
||||
|
||||
@@ -3010,8 +2998,6 @@ class PresShell final : public nsStubDocumentObserver,
|
||||
nsTHashSet<nsIScrollableFrame*> mPendingScrollAnchorAdjustment;
|
||||
nsTHashSet<nsIScrollableFrame*> mPendingScrollResnap;
|
||||
|
||||
nsTHashSet<nsIContent*> mHiddenContentInForcedLayout;
|
||||
|
||||
nsCallbackEventRequest* mFirstCallbackEventRequest = nullptr;
|
||||
nsCallbackEventRequest* mLastCallbackEventRequest = nullptr;
|
||||
|
||||
|
||||
@@ -1262,11 +1262,6 @@ static bool IsLineClampItem(const ReflowInput& aReflowInput) {
|
||||
void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus) {
|
||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
||||
FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
|
||||
return;
|
||||
}
|
||||
|
||||
MarkInReflow();
|
||||
DO_GLOBAL_REFLOW_COUNT("nsBlockFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
|
||||
@@ -2536,10 +2531,6 @@ static bool LinesAreEmpty(const nsLineList& aList) {
|
||||
}
|
||||
|
||||
void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
|
||||
if (IsContentHiddenForLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool keepGoing = true;
|
||||
bool repositionViews = false; // should we really need this?
|
||||
bool foundAnyClears = aState.mFloatBreakType != StyleClear::None;
|
||||
|
||||
@@ -4546,10 +4546,6 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aReflowOutput,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus) {
|
||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarkInReflow();
|
||||
DO_GLOBAL_REFLOW_COUNT("nsFlexContainerFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
|
||||
@@ -5294,10 +5290,6 @@ std::tuple<nscoord, bool> nsFlexContainerFrame::ReflowChildren(
|
||||
const nscoord aSumOfPrevInFlowsChildrenBlockSize,
|
||||
const FlexboxAxisTracker& aAxisTracker, bool aHasLineClampEllipsis,
|
||||
FlexLayoutResult& aFlr) {
|
||||
if (IsContentHiddenForLayout()) {
|
||||
return {0, false};
|
||||
}
|
||||
|
||||
// Before giving each child a final reflow, calculate the origin of the
|
||||
// flex container's content box (with respect to its border-box), so that
|
||||
// we can compute our flex item's final positions.
|
||||
@@ -5516,11 +5508,11 @@ void nsFlexContainerFrame::PopulateReflowOutput(
|
||||
|
||||
if (aFlexContainerAscent == nscoord_MIN) {
|
||||
// Still don't have our baseline set -- this happens if we have no
|
||||
// children, if our children are huge enough that they have nscoord_MIN
|
||||
// as their baseline, or our content is hidden in which case, we'll use the
|
||||
// wrong baseline (but no big deal).
|
||||
// children (or if our children are huge enough that they have nscoord_MIN
|
||||
// as their baseline... in which case, we'll use the wrong baseline, but no
|
||||
// big deal)
|
||||
NS_WARNING_ASSERTION(
|
||||
IsContentHidden() || aLines[0].IsEmpty(),
|
||||
aLines[0].IsEmpty(),
|
||||
"Have flex items but didn't get an ascent - that's odd (or there are "
|
||||
"just gigantic sizes involved)");
|
||||
// Per spec, synthesize baseline from the flex container's content box
|
||||
|
||||
@@ -8433,12 +8433,6 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aState,
|
||||
const nsSize& aContainerSize,
|
||||
ReflowOutput& aDesiredSize,
|
||||
nsReflowStatus& aStatus) {
|
||||
WritingMode wm = aState.mReflowInput->GetWritingMode();
|
||||
nscoord bSize = aContentArea.BSize(wm);
|
||||
if (IsContentHiddenForLayout()) {
|
||||
return bSize;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aState.mReflowInput);
|
||||
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
|
||||
|
||||
@@ -8450,6 +8444,8 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aState,
|
||||
ocStatus, MergeSortedFrameListsFor);
|
||||
}
|
||||
|
||||
WritingMode wm = aState.mReflowInput->GetWritingMode();
|
||||
nscoord bSize = aContentArea.BSize(wm);
|
||||
Maybe<Fragmentainer> fragmentainer = GetNearestFragmentainer(aState);
|
||||
// MasonryLayout() can only handle fragmentation in the masonry-axis,
|
||||
// so we let ReflowInFragmentainer() deal with grid-axis fragmentation
|
||||
@@ -8543,10 +8539,6 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus) {
|
||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarkInReflow();
|
||||
DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
|
||||
|
||||
@@ -6715,10 +6715,6 @@ void nsIFrame::DidReflow(nsPresContext* aPresContext,
|
||||
const ReflowInput* aReflowInput) {
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsIFrame::DidReflow"));
|
||||
|
||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SVGObserverUtils::InvalidateDirectRenderingObservers(
|
||||
this, SVGObserverUtils::INVALIDATE_REFLOW);
|
||||
|
||||
@@ -6831,11 +6827,6 @@ bool nsIFrame::IsContentHidden() const {
|
||||
return IsFrameOfType(nsIFrame::eReplaced) || !StyleDisplay()->IsInlineFlow();
|
||||
}
|
||||
|
||||
bool nsIFrame::IsContentHiddenForLayout() const {
|
||||
return IsContentHidden() &&
|
||||
!PresShell()->IsForcingLayoutForHiddenContent(this);
|
||||
}
|
||||
|
||||
bool nsIFrame::AncestorHidesContent() const {
|
||||
if (!StaticPrefs::layout_css_content_visibility_enabled()) {
|
||||
return false;
|
||||
|
||||
@@ -3150,13 +3150,6 @@ class nsIFrame : public nsQueryFrame {
|
||||
*/
|
||||
bool IsContentHidden() const;
|
||||
|
||||
/**
|
||||
* Whether the content is hidden via the `content-visibilty` property for
|
||||
* layout. Hidden content might not be hidden for layout when forcing layout
|
||||
* for size queries.
|
||||
*/
|
||||
bool IsContentHiddenForLayout() const;
|
||||
|
||||
/**
|
||||
* Returns true if this frame is entirely hidden due the `content-visibility`
|
||||
* property on an ancestor.
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
prefs: [layout.css.content-visibility.enabled:true]
|
||||
leak-threshold: [rdd:51200]
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
prefs: [layout.css.content-visibility.enabled:true]
|
||||
leak-threshold: [rdd:51200]
|
||||
@@ -1,120 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS Contain: Test content-visibility:hidden reflow counts</title>
|
||||
<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1746098">
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
content-visibility: visible;
|
||||
contain: strict;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid: repeat(2, 60px) / auto-flow 80px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="test"></div>
|
||||
|
||||
<script>
|
||||
let gUtils = SpecialPowers.getDOMWindowUtils(window);
|
||||
let gTestContainer = document.getElementById("test");
|
||||
|
||||
function setupContainerWithStrictContainment() {
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("container");
|
||||
gTestContainer.innerHTML = "";
|
||||
gTestContainer.appendChild(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
function flushLayout() {
|
||||
document.documentElement.offsetHeight;
|
||||
}
|
||||
|
||||
function getReflowCount() {
|
||||
flushLayout();
|
||||
return gUtils.framesReflowed;
|
||||
}
|
||||
|
||||
function runTestFunctionAndCountReflows(testFunction, container) {
|
||||
const beforeCount = getReflowCount();
|
||||
testFunction(container);
|
||||
const afterCount = getReflowCount();
|
||||
return afterCount - beforeCount;
|
||||
}
|
||||
|
||||
function assertContentVisibilityHiddenHasFewerReflows(testSetup, testFunction) {
|
||||
let container = setupContainerWithStrictContainment();
|
||||
testSetup(container);
|
||||
flushLayout();
|
||||
|
||||
const visibleReflows = runTestFunctionAndCountReflows(testFunction, container);
|
||||
|
||||
container = setupContainerWithStrictContainment();
|
||||
testSetup(container);
|
||||
container.style.contentVisibility = "hidden";
|
||||
flushLayout();
|
||||
|
||||
const hiddenReflows = runTestFunctionAndCountReflows(testFunction, container);
|
||||
assert_less_than(hiddenReflows, visibleReflows,
|
||||
"Style / layout changes in hidden content resulted in fewer reflows than visible content.");
|
||||
}
|
||||
|
||||
test(() => {
|
||||
assertContentVisibilityHiddenHasFewerReflows(
|
||||
(container) => {
|
||||
const div = document.createElement("div");
|
||||
div.innerText = "Test Content";
|
||||
container.appendChild(div);
|
||||
},
|
||||
(container) => {
|
||||
container.children[0].style.width = "100px";
|
||||
container.children[0].style.height = "100px";
|
||||
});
|
||||
}, `Avoiding layout while modifying a simple div's style.`);
|
||||
|
||||
test(() => {
|
||||
assertContentVisibilityHiddenHasFewerReflows(
|
||||
(container) => {
|
||||
container.classList.add("flex");
|
||||
|
||||
const flexContainer = document.createElement("div");
|
||||
flexContainer.classList.add("flex");
|
||||
container.appendChild(flexContainer);
|
||||
|
||||
container.appendChild(document.createElement("div"));
|
||||
},
|
||||
(container) => {
|
||||
container.children[0].style.flexDirection = "row-reverse";
|
||||
}
|
||||
);
|
||||
}, `Avoiding layout while modifying a div with flex display mode.`);
|
||||
|
||||
test(() => {
|
||||
assertContentVisibilityHiddenHasFewerReflows(
|
||||
(container) => {
|
||||
container.classList.add("grid");
|
||||
|
||||
const gridChild = document.createElement("div");
|
||||
gridChild.style.display = "grid";
|
||||
container.appendChild(gridChild);
|
||||
|
||||
container.appendChild(document.createElement("div"));
|
||||
},
|
||||
(container) => {
|
||||
container.children[0].style.rowGap = "30px";
|
||||
},
|
||||
);
|
||||
}, `Avoiding layout while modifying a div with grid display mode.`);
|
||||
|
||||
</script>
|
||||
</html>
|
||||
@@ -1,105 +0,0 @@
|
||||
<!doctype HTML>
|
||||
<html>
|
||||
<meta charset="utf8">
|
||||
<title>Content Visibility: nested forced layouts</title>
|
||||
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
|
||||
<meta name="assert" content="nested content-visibility items are all processed when layout is forced">
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<style>
|
||||
body, html {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.spacer {
|
||||
height: 3000px;
|
||||
}
|
||||
.target {
|
||||
width: 12px;
|
||||
height: 34px;
|
||||
|
||||
position: relative;
|
||||
left: 5px;
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
content-visibility: hidden;
|
||||
}
|
||||
|
||||
.will-hide {
|
||||
contain: style;
|
||||
contain: size;
|
||||
contain: layout;
|
||||
contain: paint;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class=spacer></div>
|
||||
|
||||
<div class="will-hide">
|
||||
<div id=one>A line of a certain length...</div>
|
||||
</div>
|
||||
|
||||
<div class="will-hide">
|
||||
<div class=target id=two></div>
|
||||
</div>
|
||||
|
||||
<div class="will-hide">
|
||||
<div class=target id=three></div>
|
||||
</div>
|
||||
|
||||
<div class="will-hide">
|
||||
<div class="will-hide">
|
||||
<div class=target id=four></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="will-hide">
|
||||
<div class="will-hide">
|
||||
<div class="will-hide">
|
||||
<div class="will-hide">
|
||||
<div class="will-hide">
|
||||
<div class=target id=five></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function hideContent() {
|
||||
document
|
||||
.querySelectorAll('.will-hide')
|
||||
.forEach(content => content.classList.add("hidden"));
|
||||
}
|
||||
|
||||
function showContent() {
|
||||
document
|
||||
.querySelectorAll('.will-hide')
|
||||
.forEach(content => content.classList.remove("hidden"));
|
||||
}
|
||||
|
||||
const ids = ["one", "two", "three", "four", "five"];
|
||||
for (let i = 0; i < ids.length; ++i) {
|
||||
test(() => {
|
||||
const expectedRect = document.getElementById(ids[i]).getClientRects()[0];
|
||||
const expectedBoundingRect = document.getElementById(ids[i]).getBoundingClientRect();
|
||||
hideContent();
|
||||
|
||||
const rect = document.getElementById(ids[i]).getClientRects()[0];
|
||||
assert_equals(rect.width, expectedRect.width, `width for "${ids[i]}"`);
|
||||
assert_equals(rect.height, expectedRect.height, `height for "${ids[i]}`);
|
||||
|
||||
const boundingRect = document.getElementById(ids[i]).getClientRects()[0];
|
||||
assert_equals(boundingRect.width, expectedBoundingRect.width, `width for "${ids[i]}"`);
|
||||
assert_equals(boundingRect.height, expectedBoundingRect.height, `height for "${ids[i]}`);
|
||||
|
||||
showContent();
|
||||
}, `${ids[i]}.getBoundingClientRect(): `);
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
Reference in New Issue
Block a user