Backed out changeset 5a4a5749f8dc (bug 1767262) for causing wpt failures.
This commit is contained in:
@@ -253,17 +253,7 @@ nsIFrame* nsIContent::GetPrimaryFrame(mozilla::FlushType aType) {
|
|||||||
doc->FlushPendingNotifications(aType);
|
doc->FlushPendingNotifications(aType);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* frame = GetPrimaryFrame();
|
return GetPrimaryFrame();
|
||||||
if (!frame) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aType == mozilla::FlushType::Layout) {
|
|
||||||
frame->PresShell()->EnsureReflowIfFrameHasHiddenContent(frame);
|
|
||||||
frame = GetPrimaryFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
return frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mozilla::dom {
|
namespace mozilla::dom {
|
||||||
|
|||||||
@@ -11821,37 +11821,3 @@ void PresShell::PingPerTickTelemetry(FlushType aFlushType) {
|
|||||||
bool PresShell::GetZoomableByAPZ() const {
|
bool PresShell::GetZoomableByAPZ() const {
|
||||||
return mZoomConstraintsClient && mZoomConstraintsClient->GetAllowZoom();
|
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;
|
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:
|
private:
|
||||||
~PresShell();
|
~PresShell();
|
||||||
|
|
||||||
@@ -3010,8 +2998,6 @@ class PresShell final : public nsStubDocumentObserver,
|
|||||||
nsTHashSet<nsIScrollableFrame*> mPendingScrollAnchorAdjustment;
|
nsTHashSet<nsIScrollableFrame*> mPendingScrollAnchorAdjustment;
|
||||||
nsTHashSet<nsIScrollableFrame*> mPendingScrollResnap;
|
nsTHashSet<nsIScrollableFrame*> mPendingScrollResnap;
|
||||||
|
|
||||||
nsTHashSet<nsIContent*> mHiddenContentInForcedLayout;
|
|
||||||
|
|
||||||
nsCallbackEventRequest* mFirstCallbackEventRequest = nullptr;
|
nsCallbackEventRequest* mFirstCallbackEventRequest = nullptr;
|
||||||
nsCallbackEventRequest* mLastCallbackEventRequest = nullptr;
|
nsCallbackEventRequest* mLastCallbackEventRequest = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -1262,11 +1262,6 @@ static bool IsLineClampItem(const ReflowInput& aReflowInput) {
|
|||||||
void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
||||||
const ReflowInput& aReflowInput,
|
const ReflowInput& aReflowInput,
|
||||||
nsReflowStatus& aStatus) {
|
nsReflowStatus& aStatus) {
|
||||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
|
||||||
FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkInReflow();
|
MarkInReflow();
|
||||||
DO_GLOBAL_REFLOW_COUNT("nsBlockFrame");
|
DO_GLOBAL_REFLOW_COUNT("nsBlockFrame");
|
||||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
|
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
|
||||||
@@ -2536,10 +2531,6 @@ static bool LinesAreEmpty(const nsLineList& aList) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
|
void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
|
||||||
if (IsContentHiddenForLayout()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool keepGoing = true;
|
bool keepGoing = true;
|
||||||
bool repositionViews = false; // should we really need this?
|
bool repositionViews = false; // should we really need this?
|
||||||
bool foundAnyClears = aState.mFloatBreakType != StyleClear::None;
|
bool foundAnyClears = aState.mFloatBreakType != StyleClear::None;
|
||||||
|
|||||||
@@ -4547,10 +4547,6 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
|
|||||||
ReflowOutput& aReflowOutput,
|
ReflowOutput& aReflowOutput,
|
||||||
const ReflowInput& aReflowInput,
|
const ReflowInput& aReflowInput,
|
||||||
nsReflowStatus& aStatus) {
|
nsReflowStatus& aStatus) {
|
||||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkInReflow();
|
MarkInReflow();
|
||||||
DO_GLOBAL_REFLOW_COUNT("nsFlexContainerFrame");
|
DO_GLOBAL_REFLOW_COUNT("nsFlexContainerFrame");
|
||||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
|
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
|
||||||
@@ -5295,10 +5291,6 @@ std::tuple<nscoord, bool> nsFlexContainerFrame::ReflowChildren(
|
|||||||
const nscoord aSumOfPrevInFlowsChildrenBlockSize,
|
const nscoord aSumOfPrevInFlowsChildrenBlockSize,
|
||||||
const FlexboxAxisTracker& aAxisTracker, bool aHasLineClampEllipsis,
|
const FlexboxAxisTracker& aAxisTracker, bool aHasLineClampEllipsis,
|
||||||
FlexLayoutResult& aFlr) {
|
FlexLayoutResult& aFlr) {
|
||||||
if (IsContentHiddenForLayout()) {
|
|
||||||
return {0, false};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before giving each child a final reflow, calculate the origin of the
|
// 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
|
// flex container's content box (with respect to its border-box), so that
|
||||||
// we can compute our flex item's final positions.
|
// we can compute our flex item's final positions.
|
||||||
@@ -5517,11 +5509,11 @@ void nsFlexContainerFrame::PopulateReflowOutput(
|
|||||||
|
|
||||||
if (aFlexContainerAscent == nscoord_MIN) {
|
if (aFlexContainerAscent == nscoord_MIN) {
|
||||||
// Still don't have our baseline set -- this happens if we have no
|
// 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
|
// children (or 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
|
// as their baseline... in which case, we'll use the wrong baseline, but no
|
||||||
// wrong baseline (but no big deal).
|
// big deal)
|
||||||
NS_WARNING_ASSERTION(
|
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 "
|
"Have flex items but didn't get an ascent - that's odd (or there are "
|
||||||
"just gigantic sizes involved)");
|
"just gigantic sizes involved)");
|
||||||
// Per spec, synthesize baseline from the flex container's content box
|
// Per spec, synthesize baseline from the flex container's content box
|
||||||
|
|||||||
@@ -8426,12 +8426,6 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aState,
|
|||||||
const nsSize& aContainerSize,
|
const nsSize& aContainerSize,
|
||||||
ReflowOutput& aDesiredSize,
|
ReflowOutput& aDesiredSize,
|
||||||
nsReflowStatus& aStatus) {
|
nsReflowStatus& aStatus) {
|
||||||
WritingMode wm = aState.mReflowInput->GetWritingMode();
|
|
||||||
nscoord bSize = aContentArea.BSize(wm);
|
|
||||||
if (IsContentHiddenForLayout()) {
|
|
||||||
return bSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(aState.mReflowInput);
|
MOZ_ASSERT(aState.mReflowInput);
|
||||||
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
|
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
|
||||||
|
|
||||||
@@ -8443,6 +8437,8 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aState,
|
|||||||
ocStatus, MergeSortedFrameListsFor);
|
ocStatus, MergeSortedFrameListsFor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WritingMode wm = aState.mReflowInput->GetWritingMode();
|
||||||
|
nscoord bSize = aContentArea.BSize(wm);
|
||||||
Maybe<Fragmentainer> fragmentainer = GetNearestFragmentainer(aState);
|
Maybe<Fragmentainer> fragmentainer = GetNearestFragmentainer(aState);
|
||||||
// MasonryLayout() can only handle fragmentation in the masonry-axis,
|
// MasonryLayout() can only handle fragmentation in the masonry-axis,
|
||||||
// so we let ReflowInFragmentainer() deal with grid-axis fragmentation
|
// so we let ReflowInFragmentainer() deal with grid-axis fragmentation
|
||||||
@@ -8536,10 +8532,6 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
|||||||
ReflowOutput& aDesiredSize,
|
ReflowOutput& aDesiredSize,
|
||||||
const ReflowInput& aReflowInput,
|
const ReflowInput& aReflowInput,
|
||||||
nsReflowStatus& aStatus) {
|
nsReflowStatus& aStatus) {
|
||||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkInReflow();
|
MarkInReflow();
|
||||||
DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame");
|
DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame");
|
||||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
|
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
|
||||||
|
|||||||
@@ -6747,10 +6747,6 @@ void nsIFrame::DidReflow(nsPresContext* aPresContext,
|
|||||||
const ReflowInput* aReflowInput) {
|
const ReflowInput* aReflowInput) {
|
||||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsIFrame::DidReflow"));
|
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("nsIFrame::DidReflow"));
|
||||||
|
|
||||||
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SVGObserverUtils::InvalidateDirectRenderingObservers(
|
SVGObserverUtils::InvalidateDirectRenderingObservers(
|
||||||
this, SVGObserverUtils::INVALIDATE_REFLOW);
|
this, SVGObserverUtils::INVALIDATE_REFLOW);
|
||||||
|
|
||||||
@@ -6863,11 +6859,6 @@ bool nsIFrame::IsContentHidden() const {
|
|||||||
return IsFrameOfType(nsIFrame::eReplaced) || !StyleDisplay()->IsInlineFlow();
|
return IsFrameOfType(nsIFrame::eReplaced) || !StyleDisplay()->IsInlineFlow();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsIFrame::IsContentHiddenForLayout() const {
|
|
||||||
return IsContentHidden() &&
|
|
||||||
!PresShell()->IsForcingLayoutForHiddenContent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nsIFrame::AncestorHidesContent() const {
|
bool nsIFrame::AncestorHidesContent() const {
|
||||||
if (!StaticPrefs::layout_css_content_visibility_enabled()) {
|
if (!StaticPrefs::layout_css_content_visibility_enabled()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3150,13 +3150,6 @@ class nsIFrame : public nsQueryFrame {
|
|||||||
*/
|
*/
|
||||||
bool IsContentHidden() const;
|
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`
|
* Returns true if this frame is entirely hidden due the `content-visibility`
|
||||||
* property on an ancestor.
|
* property on an ancestor.
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
prefs: [layout.css.content-visibility.enabled:true]
|
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>
|
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
|
<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
|
||||||
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
|
<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
|
||||||
<meta name="assert" content="if an scroller is hidden via content-visibility and then shown again, its scroll offset should be restored">
|
<meta name="assert" content="if an scroller is hidden via content-visibility and then shown again, its scroll offset should be restored">
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
|
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
|||||||
@@ -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