From 0a9acadccafe04aa5bc3335523bb55fe52ca8e50 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 23 Apr 2018 09:16:50 +0200 Subject: moebius#121: DOM - Selection API - getSelection() should exist on XMLDocument / Selection.type https://github.com/MoonchildProductions/moebius/pull/121 --- layout/generic/Selection.h | 3 +++ layout/generic/nsSelection.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) (limited to 'layout') diff --git a/layout/generic/Selection.h b/layout/generic/Selection.h index 6f94303ca..3d5e334fc 100644 --- a/layout/generic/Selection.h +++ b/layout/generic/Selection.h @@ -179,6 +179,9 @@ public: { return mRanges.Length(); } + + void GetType(nsAString& aOutType) const; + nsRange* GetRangeAt(uint32_t aIndex, mozilla::ErrorResult& aRv); void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv); void RemoveRange(nsRange& aRange, mozilla::ErrorResult& aRv); diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index e0d65632e..a2227c39c 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -5349,6 +5349,18 @@ Selection::GetRangeCount(int32_t* aRangeCount) return NS_OK; } +void +Selection::GetType(nsAString& aOutType) const +{ + if (!RangeCount()) { + aOutType.AssignLiteral("None"); + } else if (IsCollapsed()) { + aOutType.AssignLiteral("Caret"); + } else { + aOutType.AssignLiteral("Range"); + } +} + NS_IMETHODIMP Selection::GetRangeAt(int32_t aIndex, nsIDOMRange** aReturn) { -- cgit v1.2.3 From d9d3b687b7c892b400e781dd5c57897efd7173aa Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Mon, 23 Apr 2018 11:54:06 +0200 Subject: moebius#195: DOM - PointerEvent - improvements https://github.com/MoonchildProductions/moebius/pull/195 --- layout/base/nsPresShell.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'layout') diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 63dfbd8a3..42b39c860 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -8191,6 +8191,8 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, } case eMouseDown: case eMouseUp: + case ePointerDown: + case ePointerUp: isHandlingUserInput = true; break; -- cgit v1.2.3 From 401a0e12afcaaf3aebc2e8161545ce0166e3d5bd Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Tue, 24 Apr 2018 20:17:56 +0200 Subject: Bug 1209697: Clear ancestor intrinsic sizes when our block size changes --- layout/style/nsStyleStruct.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'layout') diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 2f12d6201..eab11b80c 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1634,9 +1634,14 @@ nsStylePosition::CalcDifference(const nsStylePosition& aNewData, // also have percentage bsizes. This is handled via // nsChangeHint_UpdateComputedBSize which clears intrinsic sizes // for frames that have such replaced elements. + // + // We need to use nsChangeHint_ClearAncestorIntrinsics for + // block-size changes so we clear results of cached CSS Flex + // measuring reflows. hint |= nsChangeHint_NeedReflow | nsChangeHint_UpdateComputedBSize | - nsChangeHint_ReflowChangesSizeOrPosition; + nsChangeHint_ReflowChangesSizeOrPosition | + nsChangeHint_ClearAncestorIntrinsics; } if (isVertical ? heightChanged : widthChanged) { -- cgit v1.2.3 From 2f87463ea3c3ac36250d4028af0baddf725f6ecf Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Tue, 24 Apr 2018 20:18:05 +0200 Subject: Bug 1209697: Cache flex measuring reflows to avoid exponential behavior --- layout/generic/nsFlexContainerFrame.cpp | 138 +++++++++++++++++++++++--------- layout/generic/nsFlexContainerFrame.h | 15 ++++ 2 files changed, 114 insertions(+), 39 deletions(-) (limited to 'layout') diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index b61024324..4ecc7d877 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -33,6 +33,8 @@ typedef nsFlexContainerFrame::FlexItem FlexItem; typedef nsFlexContainerFrame::FlexLine FlexLine; typedef nsFlexContainerFrame::FlexboxAxisTracker FlexboxAxisTracker; typedef nsFlexContainerFrame::StrutInfo StrutInfo; +typedef nsFlexContainerFrame::CachedMeasuringReflowResult + CachedMeasuringReflowResult; static mozilla::LazyLogModule gFlexContainerLog("nsFlexContainerFrame"); @@ -1756,6 +1758,91 @@ nsFlexContainerFrame:: } } +/** + * A cached result for a measuring reflow. + * + * Right now we only need to cache the available size, the height and the + * ascent. This can be extended later if needed. + * + * The assumption here is that a given flex item measurement won't change until + * either the available size changes, or the flex container intrinsic size is + * marked as dirty (due to a style or DOM change). + * + * Caching it prevents us from doing exponential reflows in cases of deeply + * nested flex and scroll frames. + * + * We store them in the frame property table for simplicity. + */ +struct nsFlexContainerFrame::CachedMeasuringReflowResult +{ + LogicalSize mAvailableSize; + const nscoord mHeight; + const nscoord mAscent; + + CachedMeasuringReflowResult(const LogicalSize& aAvailableSize, + nscoord aHeight, + nscoord aAscent) + : mAvailableSize(aAvailableSize) + , mHeight(aHeight) + , mAscent(aAscent) + {} +}; + +NS_DECLARE_FRAME_PROPERTY_DELETABLE(CachedFlexMeasuringReflow, + CachedMeasuringReflowResult); + +const CachedMeasuringReflowResult& +nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem( + FlexItem& aItem, + nsPresContext* aPresContext, + ReflowInput& aChildReflowInput) +{ + const auto availableSize = aChildReflowInput.AvailableSize(); + const FrameProperties props = aItem.Frame()->Properties(); + if (const auto* cachedResult = props.Get(CachedFlexMeasuringReflow())) { + if (cachedResult->mAvailableSize == availableSize) { + return *cachedResult; + } + } + + ReflowOutput childDesiredSize(aChildReflowInput); + nsReflowStatus childReflowStatus; + + const uint32_t flags = NS_FRAME_NO_MOVE_FRAME; + ReflowChild(aItem.Frame(), aPresContext, + childDesiredSize, aChildReflowInput, + 0, 0, flags, childReflowStatus); + aItem.SetHadMeasuringReflow(); + + // XXXdholbert Once we do pagination / splitting, we'll need to actually + // handle incomplete childReflowStatuses. But for now, we give our kids + // unconstrained available height, which means they should always complete. + MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), + "We gave flex item unconstrained available height, so it " + "should be complete"); + + // Tell the child we're done with its initial reflow. + // (Necessary for e.g. GetBaseline() to work below w/out asserting) + FinishReflowChild(aItem.Frame(), aPresContext, + childDesiredSize, &aChildReflowInput, 0, 0, flags); + + auto result = + new CachedMeasuringReflowResult(availableSize, + childDesiredSize.Height(), + childDesiredSize.BlockStartAscent()); + + props.Set(CachedFlexMeasuringReflow(), result); + return *result; +} + +/* virtual */ void +nsFlexContainerFrame::MarkIntrinsicISizesDirty() +{ + for (nsIFrame* childFrame : mFrames) { + childFrame->Properties().Delete(CachedFlexMeasuringReflow()); + } +} + nscoord nsFlexContainerFrame:: MeasureFlexItemContentHeight(nsPresContext* aPresContext, @@ -1783,27 +1870,15 @@ nsFlexContainerFrame:: childRIForMeasuringHeight.SetVResize(true); } - ReflowOutput childDesiredSize(childRIForMeasuringHeight); - nsReflowStatus childReflowStatus; - const uint32_t flags = NS_FRAME_NO_MOVE_FRAME; - ReflowChild(aFlexItem.Frame(), aPresContext, - childDesiredSize, childRIForMeasuringHeight, - 0, 0, flags, childReflowStatus); + const CachedMeasuringReflowResult& reflowResult = + MeasureAscentAndHeightForFlexItem(aFlexItem, aPresContext, + childRIForMeasuringHeight); - MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), - "We gave flex item unconstrained available height, so it " - "should be complete"); - - FinishReflowChild(aFlexItem.Frame(), aPresContext, - childDesiredSize, &childRIForMeasuringHeight, - 0, 0, flags); - - aFlexItem.SetHadMeasuringReflow(); - aFlexItem.SetAscent(childDesiredSize.BlockStartAscent()); + aFlexItem.SetAscent(reflowResult.mAscent); // Subtract border/padding in vertical axis, to get _just_ // the effective computed value of the "height" property. - nscoord childDesiredHeight = childDesiredSize.Height() - + nscoord childDesiredHeight = reflowResult.mHeight - childRIForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom(); return std::max(0, childDesiredHeight); @@ -3959,25 +4034,10 @@ nsFlexContainerFrame::SizeItemInCrossAxis( // whether any of its ancestors are being resized). aChildReflowInput.SetVResize(true); } - ReflowOutput childDesiredSize(aChildReflowInput); - nsReflowStatus childReflowStatus; - const uint32_t flags = NS_FRAME_NO_MOVE_FRAME; - ReflowChild(aItem.Frame(), aPresContext, - childDesiredSize, aChildReflowInput, - 0, 0, flags, childReflowStatus); - aItem.SetHadMeasuringReflow(); - - // XXXdholbert Once we do pagination / splitting, we'll need to actually - // handle incomplete childReflowStatuses. But for now, we give our kids - // unconstrained available height, which means they should always complete. - MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus), - "We gave flex item unconstrained available height, so it " - "should be complete"); - // Tell the child we're done with its initial reflow. - // (Necessary for e.g. GetBaseline() to work below w/out asserting) - FinishReflowChild(aItem.Frame(), aPresContext, - childDesiredSize, &aChildReflowInput, 0, 0, flags); + // Potentially reflow the item, and get the sizing info. + const CachedMeasuringReflowResult& reflowResult = + MeasureAscentAndHeightForFlexItem(aItem, aPresContext, aChildReflowInput); // Save the sizing info that we learned from this reflow // ----------------------------------------------------- @@ -3989,7 +4049,7 @@ nsFlexContainerFrame::SizeItemInCrossAxis( // so we don't bother with making aAxisTracker pick the cross-axis component // for us.) nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom(); - if (childDesiredSize.Height() < crossAxisBorderPadding) { + if (reflowResult.mHeight < crossAxisBorderPadding) { // Child's requested size isn't large enough for its border/padding! // This is OK for the trivial nsFrame::Reflow() impl, but other frame // classes should know better. So, if we get here, the child had better be @@ -4002,10 +4062,10 @@ nsFlexContainerFrame::SizeItemInCrossAxis( aItem.SetCrossSize(0); } else { // (normal case) - aItem.SetCrossSize(childDesiredSize.Height() - crossAxisBorderPadding); + aItem.SetCrossSize(reflowResult.mHeight - crossAxisBorderPadding); } - aItem.SetAscent(childDesiredSize.BlockStartAscent()); + aItem.SetAscent(reflowResult.mAscent); } void @@ -4295,7 +4355,7 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext, LogicalSize availSize = aReflowInput.ComputedSize(wm); availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; ReflowInput childReflowInput(aPresContext, aReflowInput, - item->Frame(), availSize); + item->Frame(), availSize); if (!sizeOverride) { // Directly override the computed main-size, by tweaking reflow state: if (aAxisTracker.IsMainAxisHorizontal()) { diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index 22b420d85..d9cac8930 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -56,6 +56,7 @@ public: class FlexLine; class FlexboxAxisTracker; struct StrutInfo; + struct CachedMeasuringReflowResult; // nsIFrame overrides void Init(nsIContent* aContent, @@ -66,6 +67,8 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; + void MarkIntrinsicISizesDirty() override; + virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, @@ -194,6 +197,18 @@ protected: const ReflowInput& aParentReflowInput, const FlexboxAxisTracker& aAxisTracker); + /** + * This method gets a cached measuring reflow for a flex item, or does it and + * caches it. + * + * This avoids exponential reflows, see the comment on + * CachedMeasuringReflowResult. + */ + const CachedMeasuringReflowResult& MeasureAscentAndHeightForFlexItem( + FlexItem& aItem, + nsPresContext* aPresContext, + ReflowInput& aChildReflowInput); + /** * This method performs a "measuring" reflow to get the content height of * aFlexItem.Frame() (treating it as if it had auto-height), & returns the -- cgit v1.2.3 From dca75f84eb316858b2bf520d3d0cca43766ffcd2 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Tue, 24 Apr 2018 20:21:41 +0200 Subject: Bug 1336708: Don't reuse cached flex-item reflow measurements if the item's computed height has changed --- layout/generic/nsFlexContainerFrame.cpp | 60 +++++++++++++++++++++------------ layout/generic/nsFlexContainerFrame.h | 2 +- 2 files changed, 39 insertions(+), 23 deletions(-) (limited to 'layout') diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 4ecc7d877..5bc852c52 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -1761,31 +1761,50 @@ nsFlexContainerFrame:: /** * A cached result for a measuring reflow. * - * Right now we only need to cache the available size, the height and the - * ascent. This can be extended later if needed. + * Right now we only need to cache the available size and the computed height + * for checking that the reflow input is valid, and the height and the ascent + * to be used. This can be extended later if needed. * * The assumption here is that a given flex item measurement won't change until - * either the available size changes, or the flex container intrinsic size is - * marked as dirty (due to a style or DOM change). + * either the available size or computed height changes, or the flex container + * intrinsic size is marked as dirty (due to a style or DOM change). + * + * In particular the computed height may change between measuring reflows due to + * how the mIsFlexContainerMeasuringReflow flag affects size computation (see + * bug 1336708). * * Caching it prevents us from doing exponential reflows in cases of deeply * nested flex and scroll frames. * * We store them in the frame property table for simplicity. */ -struct nsFlexContainerFrame::CachedMeasuringReflowResult +class nsFlexContainerFrame::CachedMeasuringReflowResult { - LogicalSize mAvailableSize; + // Members that are part of the cache key: + const LogicalSize mAvailableSize; + const nscoord mComputedHeight; + + // Members that are part of the cache value: const nscoord mHeight; const nscoord mAscent; - CachedMeasuringReflowResult(const LogicalSize& aAvailableSize, - nscoord aHeight, - nscoord aAscent) - : mAvailableSize(aAvailableSize) - , mHeight(aHeight) - , mAscent(aAscent) +public: + CachedMeasuringReflowResult(const ReflowInput& aReflowInput, + const ReflowOutput& aDesiredSize) + : mAvailableSize(aReflowInput.AvailableSize()) + , mComputedHeight(aReflowInput.ComputedHeight()) + , mHeight(aDesiredSize.Height()) + , mAscent(aDesiredSize.BlockStartAscent()) {} + + bool IsValidFor(const ReflowInput& aReflowInput) const { + return mAvailableSize == aReflowInput.AvailableSize() && + mComputedHeight == aReflowInput.ComputedHeight(); + } + + nscoord Height() const { return mHeight; } + + nscoord Ascent() const { return mAscent; } }; NS_DECLARE_FRAME_PROPERTY_DELETABLE(CachedFlexMeasuringReflow, @@ -1797,10 +1816,9 @@ nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem( nsPresContext* aPresContext, ReflowInput& aChildReflowInput) { - const auto availableSize = aChildReflowInput.AvailableSize(); const FrameProperties props = aItem.Frame()->Properties(); if (const auto* cachedResult = props.Get(CachedFlexMeasuringReflow())) { - if (cachedResult->mAvailableSize == availableSize) { + if (cachedResult->IsValidFor(aChildReflowInput)) { return *cachedResult; } } @@ -1827,9 +1845,7 @@ nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem( childDesiredSize, &aChildReflowInput, 0, 0, flags); auto result = - new CachedMeasuringReflowResult(availableSize, - childDesiredSize.Height(), - childDesiredSize.BlockStartAscent()); + new CachedMeasuringReflowResult(aChildReflowInput, childDesiredSize); props.Set(CachedFlexMeasuringReflow(), result); return *result; @@ -1874,11 +1890,11 @@ nsFlexContainerFrame:: MeasureAscentAndHeightForFlexItem(aFlexItem, aPresContext, childRIForMeasuringHeight); - aFlexItem.SetAscent(reflowResult.mAscent); + aFlexItem.SetAscent(reflowResult.Ascent()); // Subtract border/padding in vertical axis, to get _just_ // the effective computed value of the "height" property. - nscoord childDesiredHeight = reflowResult.mHeight - + nscoord childDesiredHeight = reflowResult.Height() - childRIForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom(); return std::max(0, childDesiredHeight); @@ -4049,7 +4065,7 @@ nsFlexContainerFrame::SizeItemInCrossAxis( // so we don't bother with making aAxisTracker pick the cross-axis component // for us.) nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom(); - if (reflowResult.mHeight < crossAxisBorderPadding) { + if (reflowResult.Height() < crossAxisBorderPadding) { // Child's requested size isn't large enough for its border/padding! // This is OK for the trivial nsFrame::Reflow() impl, but other frame // classes should know better. So, if we get here, the child had better be @@ -4062,10 +4078,10 @@ nsFlexContainerFrame::SizeItemInCrossAxis( aItem.SetCrossSize(0); } else { // (normal case) - aItem.SetCrossSize(reflowResult.mHeight - crossAxisBorderPadding); + aItem.SetCrossSize(reflowResult.Height() - crossAxisBorderPadding); } - aItem.SetAscent(reflowResult.mAscent); + aItem.SetAscent(reflowResult.Ascent()); } void diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index d9cac8930..459ae8e20 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -56,7 +56,7 @@ public: class FlexLine; class FlexboxAxisTracker; struct StrutInfo; - struct CachedMeasuringReflowResult; + class CachedMeasuringReflowResult; // nsIFrame overrides void Init(nsIContent* aContent, -- cgit v1.2.3 From bf901ae222eb570746accd67744e1691809edaeb Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Tue, 24 Apr 2018 20:23:20 +0200 Subject: Bug 1336708: Reftest --- .../flexbox-align-items-center-nested-001-ref.html | 16 ++++++++ .../flexbox-align-items-center-nested-001.html | 47 ++++++++++++++++++++++ .../w3c-css/submitted/flexbox/reftest.list | 2 + 3 files changed, 65 insertions(+) create mode 100644 layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html create mode 100644 layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html (limited to 'layout') diff --git a/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html new file mode 100644 index 000000000..2473417b8 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html @@ -0,0 +1,16 @@ + +CSS Test Reference + + + +
+ diff --git a/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html new file mode 100644 index 000000000..b6e2fdff0 --- /dev/null +++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html @@ -0,0 +1,47 @@ + + +CSS Test: Flexbox nested containers with align-items: center and flexible items + + + + + +
+
+
+
+
+
+
+ diff --git a/layout/reftests/w3c-css/submitted/flexbox/reftest.list b/layout/reftests/w3c-css/submitted/flexbox/reftest.list index a623a0b59..fd8bfccc9 100644 --- a/layout/reftests/w3c-css/submitted/flexbox/reftest.list +++ b/layout/reftests/w3c-css/submitted/flexbox/reftest.list @@ -39,6 +39,8 @@ fuzzy-if(Android,158,32) == flexbox-align-self-vert-rtl-001.xhtml flexbox-align == flexbox-align-self-vert-rtl-003.xhtml flexbox-align-self-vert-rtl-003-ref.xhtml == flexbox-align-self-vert-rtl-004.xhtml flexbox-align-self-vert-rtl-004-ref.xhtml +== flexbox-align-items-center-nested-001.html flexbox-align-items-center-nested-001-ref.html + # Tests for computing the baseline of a flex container == flexbox-baseline-align-self-baseline-horiz-001.html flexbox-baseline-align-self-baseline-horiz-001-ref.html == flexbox-baseline-align-self-baseline-vert-001.html flexbox-baseline-align-self-baseline-vert-001-ref.html -- cgit v1.2.3 From d0e748cadabba2b7cbf7407c4bca665315bf00fe Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Tue, 24 Apr 2018 20:25:23 +0200 Subject: Bug 1338053: Make nsFlexContainerFrame::MarkIntrinsicISizesDirty() also call its parent class's method --- layout/generic/nsFlexContainerFrame.cpp | 1 + layout/reftests/xul/css-flex-1-ref.html | 18 ++++ layout/reftests/xul/css-flex-1.xul | 153 ++++++++++++++++++++++++++++++++ layout/reftests/xul/reftest.list | 2 + 4 files changed, 174 insertions(+) create mode 100644 layout/reftests/xul/css-flex-1-ref.html create mode 100644 layout/reftests/xul/css-flex-1.xul (limited to 'layout') diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 5bc852c52..3818d3cb7 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -1857,6 +1857,7 @@ nsFlexContainerFrame::MarkIntrinsicISizesDirty() for (nsIFrame* childFrame : mFrames) { childFrame->Properties().Delete(CachedFlexMeasuringReflow()); } + nsContainerFrame::MarkIntrinsicISizesDirty(); } nscoord diff --git a/layout/reftests/xul/css-flex-1-ref.html b/layout/reftests/xul/css-flex-1-ref.html new file mode 100644 index 000000000..a47eb8e9c --- /dev/null +++ b/layout/reftests/xul/css-flex-1-ref.html @@ -0,0 +1,18 @@ + + + + + + +
+ + diff --git a/layout/reftests/xul/css-flex-1.xul b/layout/reftests/xul/css-flex-1.xul new file mode 100644 index 000000000..7955373dd --- /dev/null +++ b/layout/reftests/xul/css-flex-1.xul @@ -0,0 +1,153 @@ + + + + + + + + + + + + +mozilla-central: layout/reftests/xul/css-flex-1.xul@67bbef772796 + + + + + + + + + +
layout/reftests/xul/css-flex-1.xul
+ +
+ + + + + + + + + + + + + + + + + + + + +
authorDaniel Holbert <dholbert@cs.stanford.edu>
Wed, 08 Feb 2017 23:08:43 -0800
changeset 34173167bbef772796
permissions-rw-r--r--
+
+ +
Bug 1338053: Make nsFlexContainerFrame::MarkIntrinsicISizesDirty() also call its parent class's method. r=emilio + +MozReview-Commit-ID: 72oIlunLcVq
+ +
+
+
+<?xml version="1.0"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        class="reftest-wait"
+        onload="tweak()">
+  <style xmlns="http://www.w3.org/1999/xhtml">
+    <![CDATA[
+    panelview {
+      border: 1px solid black;
+      background: green;
+      display: flex;
+      height: 50px;
+    }
+    ]]>
+  </style>
+  <script>
+    <![CDATA[
+    function tweak() {
+      var tweakMe = document.getElementById("tweakMe");
+      tweakMe.style.width = "100px";
+      document.documentElement.className = "";
+    }
+    ]]>
+  </script>
+  <hbox>
+    <panelview id="tweakMe"></panelview>
+  </hbox>
+</window>
+
+
+ + + + + + + diff --git a/layout/reftests/xul/reftest.list b/layout/reftests/xul/reftest.list index da09b7c81..35b9f9025 100644 --- a/layout/reftests/xul/reftest.list +++ b/layout/reftests/xul/reftest.list @@ -1,3 +1,5 @@ +== css-flex-1.xul css-flex-1-ref.html + == menuitem-key.xul menuitem-key-ref.xul # these random-if(Android) are due to differences between Android Native & Xul, see bug 732569 random-if(Android) == menulist-shrinkwrap-1.xul menulist-shrinkwrap-1-ref.xul -- cgit v1.2.3 From eae8d21428acdb3fb842df091ded0eb276bcaaaa Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Tue, 24 Apr 2018 21:39:13 +0200 Subject: moebius#138: Optimize operations on root of deeply-nested frame tree https://github.com/MoonchildProductions/moebius/pull/138 --- layout/base/RestyleManagerBase.cpp | 63 ++++++++++- layout/base/nsCSSFrameConstructor.cpp | 15 ++- layout/base/nsChangeHint.h | 55 ++++++++- layout/base/nsPresContext.cpp | 9 +- layout/base/nsPresContext.h | 22 +++- .../scrolling/propagated-overflow-style-1-ref.html | 18 +++ .../scrolling/propagated-overflow-style-1a.html | 23 ++++ .../scrolling/propagated-overflow-style-1b.html | 23 ++++ .../scrolling/propagated-overflow-style-1c.html | 19 ++++ .../scrolling/propagated-overflow-style-2-ref.html | 15 +++ .../scrolling/propagated-overflow-style-2a.html | 26 +++++ .../scrolling/propagated-overflow-style-2b.html | 26 +++++ .../scrolling/propagated-overflow-style-2c.html | 24 ++++ .../scrolling/propagated-overflow-style-2d.html | 24 ++++ .../scrolling/propagated-overflow-style-2e.html | 15 +++ layout/reftests/scrolling/reftest.list | 10 ++ layout/style/nsStyleStruct.cpp | 28 ++--- layout/style/test/mochitest.ini | 1 + .../test/test_dynamic_change_causing_reflow.html | 107 +++++++++++++++++- .../test_viewport_scrollbar_causing_reflow.html | 125 +++++++++++++++++++++ 20 files changed, 610 insertions(+), 38 deletions(-) create mode 100644 layout/reftests/scrolling/propagated-overflow-style-1-ref.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-1a.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-1b.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-1c.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-2-ref.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-2a.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-2b.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-2c.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-2d.html create mode 100644 layout/reftests/scrolling/propagated-overflow-style-2e.html create mode 100644 layout/style/test/test_viewport_scrollbar_causing_reflow.html (limited to 'layout') diff --git a/layout/base/RestyleManagerBase.cpp b/layout/base/RestyleManagerBase.cpp index 9a5ce43eb..d96d9dbbb 100644 --- a/layout/base/RestyleManagerBase.cpp +++ b/layout/base/RestyleManagerBase.cpp @@ -154,7 +154,7 @@ RestyleManagerBase::ChangeHintToString(nsChangeHint aHint) "NeutralChange", "InvalidateRenderingObservers", "ReflowChangesSizeOrPosition", "UpdateComputedBSize", "UpdateUsesOpacity", "UpdateBackgroundPosition", - "AddOrRemoveTransform" + "AddOrRemoveTransform", "CSSOverflowChange", }; static_assert(nsChangeHint_AllHints == (1 << ArrayLength(names)) - 1, "Name list doesn't match change hints."); @@ -1070,6 +1070,67 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) FramePropertyTable* propTable = presContext->PropertyTable(); nsCSSFrameConstructor* frameConstructor = presContext->FrameConstructor(); + // Handle nsChangeHint_CSSOverflowChange, by either updating the + // scrollbars on the viewport, or upgrading the change hint to frame-reconstruct. + for (nsStyleChangeData& data : aChangeList) { + if (data.mHint & nsChangeHint_CSSOverflowChange) { + data.mHint &= ~nsChangeHint_CSSOverflowChange; + bool doReconstruct = true; // assume the worst + + // Only bother with this if we're html/body, since: + // (a) It'd be *expensive* to reframe these particular nodes. They're + // at the root, so reframing would mean rebuilding the world. + // (b) It's often *unnecessary* to reframe for "overflow" changes on + // these particular nodes. In general, the only reason we reframe + // for "overflow" changes is so we can construct (or destroy) a + // scrollframe & scrollbars -- and the html/body nodes often don't + // need their own scrollframe/scrollbars because they coopt the ones + // on the viewport (which always exist). So depending on whether + // that's happening, we can skip the reframe for these nodes. + if (data.mContent->IsAnyOfHTMLElements(nsGkAtoms::body, + nsGkAtoms::html)) { + // If the restyled element provided/provides the scrollbar styles for + // the viewport before and/or after this restyle, AND it's not coopting + // that responsibility from some other element (which would need + // reconstruction to make its own scrollframe now), THEN: we don't need + // to reconstruct - we can just reflow, because no scrollframe is being + // added/removed. + nsIContent* prevOverrideNode = + presContext->GetViewportScrollbarStylesOverrideNode(); + nsIContent* newOverrideNode = + presContext->UpdateViewportScrollbarStylesOverride(); + + if (data.mContent == prevOverrideNode || + data.mContent == newOverrideNode) { + // If we get here, the restyled element provided the scrollbar styles + // for viewport before this restyle, OR it will provide them after. + if (!prevOverrideNode || !newOverrideNode || + prevOverrideNode == newOverrideNode) { + // If we get here, the restyled element is NOT replacing (or being + // replaced by) some other element as the viewport's + // scrollbar-styles provider. (If it were, we'd potentially need to + // reframe to create a dedicated scrollframe for whichever element + // is being booted from providing viewport scrollbar styles.) + // + // Under these conditions, we're OK to assume that this "overflow" + // change only impacts the root viewport's scrollframe, which + // already exists, so we can simply reflow instead of reframing. + // When requesting this reflow, we send the exact same change hints + // that "width" and "height" would send (since conceptually, + // adding/removing scrollbars is like changing the available + // space). + data.mHint |= (nsChangeHint_ReflowHintsForISizeChange | + nsChangeHint_ReflowHintsForBSizeChange); + doReconstruct = false; + } + } + } + if (doReconstruct) { + data.mHint |= nsChangeHint_ReconstructFrame; + } + } + } + // Make sure to not rebuild quote or counter lists while we're // processing restyles frameConstructor->BeginUpdate(); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index f8c7f52a9..767298b85 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -8246,11 +8246,19 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, *aDestroyedFramesFor = aChild; } + nsPresContext* presContext = mPresShell->GetPresContext(); + MOZ_ASSERT(presContext, "Our presShell should have a valid presContext"); + if (aChild->IsHTMLElement(nsGkAtoms::body) || (!aContainer && aChild->IsElement())) { - // This might be the element we propagated viewport scrollbar - // styles from. Recompute those. - mPresShell->GetPresContext()->UpdateViewportScrollbarStylesOverride(); + // We might be removing the element that we propagated viewport scrollbar + // styles from. Recompute those. (This clause covers two of the three + // possible scrollbar-propagation sources: the [as aChild or a + // descendant] and the root node. The other possible scrollbar-propagation + // source is a fullscreen element, and we have code elsewhere to update + // scrollbars after fullscreen elements are removed -- specifically, it's + // part of the fullscreen cleanup code called by Element::UnbindFromTree.) + presContext->UpdateViewportScrollbarStylesOverride(); } // XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and @@ -8316,7 +8324,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer, ClearDisplayContentsIn(aChild, aContainer); } - nsPresContext* presContext = mPresShell->GetPresContext(); #ifdef MOZ_XUL if (NotifyListBoxBody(presContext, aContainer, aChild, aOldNextSibling, childFrame, CONTENT_REMOVED)) { diff --git a/layout/base/nsChangeHint.h b/layout/base/nsChangeHint.h index 318b84840..eb2709de6 100644 --- a/layout/base/nsChangeHint.h +++ b/layout/base/nsChangeHint.h @@ -217,6 +217,16 @@ enum nsChangeHint { */ nsChangeHint_AddOrRemoveTransform = 1 << 27, + /** + * Indicates that the overflow-x and/or overflow-y property changed. + * + * In most cases, this is equivalent to nsChangeHint_ReconstructFrame. But + * in some special cases where the change is really targeting the viewport's + * scrollframe, this is instead equivalent to nsChangeHint_AllReflowHints + * (because the viewport always has an associated scrollframe). + */ + nsChangeHint_CSSOverflowChange = 1 << 28, + // IMPORTANT NOTE: When adding new hints, consider whether you need // to add them to NS_HintsNotHandledForDescendantsIn() below. Please // also add them to RestyleManager::ChangeHintToString and modify @@ -225,7 +235,7 @@ enum nsChangeHint { /** * Dummy hint value for all hints. It exists for compile time check. */ - nsChangeHint_AllHints = (1 << 28) - 1, + nsChangeHint_AllHints = (1 << 29) - 1, }; // Redefine these operators to return nothing. This will catch any use @@ -306,6 +316,7 @@ inline nsChangeHint operator^=(nsChangeHint& aLeft, nsChangeHint aRight) nsChangeHint_UpdatePostTransformOverflow | \ nsChangeHint_UpdateParentOverflow | \ nsChangeHint_ChildrenOnlyTransform | \ + nsChangeHint_CSSOverflowChange | \ nsChangeHint_RecomputePosition | \ nsChangeHint_UpdateContainingBlock | \ nsChangeHint_AddOrRemoveTransform | \ @@ -374,6 +385,48 @@ inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) nsChangeHint_ClearAncestorIntrinsics | \ nsChangeHint_ClearDescendantIntrinsics | \ nsChangeHint_NeedDirtyReflow) + +// Below are the change hints that we send for ISize & BSize changes. +// Each is similar to nsChangeHint_AllReflowHints with a few changes. + +// * For an ISize change, we send nsChangeHint_AllReflowHints, with two bits +// excluded: nsChangeHint_ClearDescendantIntrinsics (because an ancestor's +// inline-size change can't affect descendant intrinsic sizes), and +// nsChangeHint_NeedDirtyReflow (because ISize changes don't need to *force* +// all descendants to reflow). +#define nsChangeHint_ReflowHintsForISizeChange \ + nsChangeHint(nsChangeHint_AllReflowHints & \ + ~(nsChangeHint_ClearDescendantIntrinsics | \ + nsChangeHint_NeedDirtyReflow)) + +// * For a BSize change, we send almost the same hints as for ISize changes, +// with one extra: nsChangeHint_UpdateComputedBSize. We need this hint because +// BSize changes CAN affect descendant intrinsic sizes, due to replaced +// elements with percentage BSizes in descendants which also have percentage +// BSizes. nsChangeHint_UpdateComputedBSize clears intrinsic sizes for frames +// that have such replaced elements. (We could instead send +// nsChangeHint_ClearDescendantIntrinsics, but that's broader than we need.) +// +// NOTE: You might think that BSize changes could exclude +// nsChangeHint_ClearAncestorIntrinsics (which is inline-axis specific), but we +// do need to send it, to clear cached results from CSS Flex measuring reflows. +#define nsChangeHint_ReflowHintsForBSizeChange \ + nsChangeHint((nsChangeHint_AllReflowHints | \ + nsChangeHint_UpdateComputedBSize) & \ + ~(nsChangeHint_ClearDescendantIntrinsics | \ + nsChangeHint_NeedDirtyReflow)) + +// * For changes to the float area of an already-floated element, we need all +// reflow hints, but not the ones that apply to descendants. +// Our descendants aren't impacted when our float area only changes +// placement but not size/shape. (e.g. if we change which side we float to). +// But our ancestors/siblings are potentially impacted, so we need to send +// the non-descendant reflow hints. +#define nsChangeHint_ReflowHintsForFloatAreaChange \ + nsChangeHint(nsChangeHint_AllReflowHints & \ + ~(nsChangeHint_ClearDescendantIntrinsics | \ + nsChangeHint_NeedDirtyReflow)) + #define NS_STYLE_HINT_REFLOW \ nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints) diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index d9f7b368c..4a54a8432 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -208,6 +208,7 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType) mTextZoom(1.0), mFullZoom(1.0), mOverrideDPPX(0.0), mLastFontInflationScreenSize(gfxSize(-1.0, -1.0)), mPageSize(-1, -1), mPPScale(1.0f), + mViewportScrollbarOverrideNode(nullptr), mViewportStyleScrollbar(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO), mImageAnimationModePref(imgIContainer::kNormalAnimMode), mAllInvalidated(false), @@ -1423,10 +1424,10 @@ nsPresContext::UpdateViewportScrollbarStylesOverride() // Start off with our default styles, and then update them as needed. mViewportStyleScrollbar = ScrollbarStyles(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO); - nsIContent* propagatedFrom = nullptr; + mViewportScrollbarOverrideNode = nullptr; // Don't propagate the scrollbar state in printing or print preview. if (!IsPaginated()) { - propagatedFrom = + mViewportScrollbarOverrideNode = GetPropagatedScrollbarStylesForViewport(this, &mViewportStyleScrollbar); } @@ -1438,13 +1439,13 @@ nsPresContext::UpdateViewportScrollbarStylesOverride() // the styles are from, so that the state of those elements is not // affected across fullscreen change. if (fullscreenElement != document->GetRootElement() && - fullscreenElement != propagatedFrom) { + fullscreenElement != mViewportScrollbarOverrideNode) { mViewportStyleScrollbar = ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN); } } - return propagatedFrom; + return mViewportScrollbarOverrideNode; } bool diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 4fdc60a2e..d8f876291 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -719,7 +719,18 @@ public: * it was propagated from. */ nsIContent* UpdateViewportScrollbarStylesOverride(); - const ScrollbarStyles& GetViewportScrollbarStylesOverride() + + /** + * Returns the cached result from the last call to + * UpdateViewportScrollbarStylesOverride() -- i.e. return the node + * whose scrollbar styles we have propagated to the viewport (or nullptr if + * there is no such node). + */ + nsIContent* GetViewportScrollbarStylesOverrideNode() const { + return mViewportScrollbarOverrideNode; + } + + const ScrollbarStyles& GetViewportScrollbarStylesOverride() const { return mViewportStyleScrollbar; } @@ -1310,7 +1321,16 @@ protected: nscolor mBodyTextColor; + // This is a non-owning pointer. May be null. If non-null, it's guaranteed + // to be pointing to a node that's still alive, because we'll reset it in + // UpdateViewportScrollbarStylesOverride() as part of the cleanup code + // when this node is removed from the document. (For and the root node, + // this call happens in nsCSSFrameConstructor::ContentRemoved(). For + // fullscreen elements, it happens in the fullscreen-specific cleanup + // invoked by Element::UnbindFromTree().) + nsIContent* MOZ_NON_OWNING_REF mViewportScrollbarOverrideNode; ScrollbarStyles mViewportStyleScrollbar; + uint8_t mFocusRingWidth; bool mExistThrottledUpdates; diff --git a/layout/reftests/scrolling/propagated-overflow-style-1-ref.html b/layout/reftests/scrolling/propagated-overflow-style-1-ref.html new file mode 100644 index 000000000..7c2b1b315 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1-ref.html @@ -0,0 +1,18 @@ + + + + + Reference case with body and html *independently* scrollable. + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-1a.html b/layout/reftests/scrolling/propagated-overflow-style-1a.html new file mode 100644 index 000000000..b5115d36f --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1a.html @@ -0,0 +1,23 @@ + + + + + Testcase with body and html *independently* scrollable, + with body's "overflow" set dynamically. + + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-1b.html b/layout/reftests/scrolling/propagated-overflow-style-1b.html new file mode 100644 index 000000000..4608b87d6 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1b.html @@ -0,0 +1,23 @@ + + + + + Testcase with body and html *independently* scrollable, + with html's "overflow" set dynamically. + + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-1c.html b/layout/reftests/scrolling/propagated-overflow-style-1c.html new file mode 100644 index 000000000..11809915a --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-1c.html @@ -0,0 +1,19 @@ + + + + + Testcase with body and html *independently* scrollable, + with both html & body's "overflow" set dynamically. + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-2-ref.html b/layout/reftests/scrolling/propagated-overflow-style-2-ref.html new file mode 100644 index 000000000..20c3b8ae5 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2-ref.html @@ -0,0 +1,15 @@ + + + + + Reference case with the root viewport scrollable, via styles on html node. + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-2a.html b/layout/reftests/scrolling/propagated-overflow-style-2a.html new file mode 100644 index 000000000..250bedd6c --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2a.html @@ -0,0 +1,26 @@ + + + + + Testcase with only one of [html,body] being scrollable, + after body's "overflow" is reset dynamically. + + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-2b.html b/layout/reftests/scrolling/propagated-overflow-style-2b.html new file mode 100644 index 000000000..c94ddedb2 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2b.html @@ -0,0 +1,26 @@ + + + + + Testcase with only one of [html,body] being scrollable, + after html's "overflow" is reset dynamically. + + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-2c.html b/layout/reftests/scrolling/propagated-overflow-style-2c.html new file mode 100644 index 000000000..0ceb1f21a --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2c.html @@ -0,0 +1,24 @@ + + + + + Testcase with only one of [html,body] being scrollable, + with their "overflow" styles being dynamically swapped. + + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-2d.html b/layout/reftests/scrolling/propagated-overflow-style-2d.html new file mode 100644 index 000000000..3353a3374 --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2d.html @@ -0,0 +1,24 @@ + + + + + Testcase with only one of [html,body] being scrollable, + with their "overflow" styles being dynamically swapped. + + + + + + + diff --git a/layout/reftests/scrolling/propagated-overflow-style-2e.html b/layout/reftests/scrolling/propagated-overflow-style-2e.html new file mode 100644 index 000000000..f9105185b --- /dev/null +++ b/layout/reftests/scrolling/propagated-overflow-style-2e.html @@ -0,0 +1,15 @@ + + + + + Testcase with the root viewport scrollable, via styles on body node. + + + + + + diff --git a/layout/reftests/scrolling/reftest.list b/layout/reftests/scrolling/reftest.list index db1b81db6..43997ced7 100644 --- a/layout/reftests/scrolling/reftest.list +++ b/layout/reftests/scrolling/reftest.list @@ -85,3 +85,13 @@ fuzzy-if(asyncPan&&!layersGPUAccelerated,102,2420) == frame-scrolling-attr-2.htm == fractional-scroll-area.html?top=0.4&outerBottom=99.6&innerBottom=200.4&scrollBefore=999 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200&scrollBefore=999 == fractional-scroll-area.html?top=0.4&outerBottom=100.4&innerBottom=200.4&scrollBefore=999 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200&scrollBefore=999 != fractional-scroll-area-invalidation.html about:blank + +# Tests for "overflow" styles that may be propagated to the viewport: +== propagated-overflow-style-1a.html propagated-overflow-style-1-ref.html +== propagated-overflow-style-1b.html propagated-overflow-style-1-ref.html +== propagated-overflow-style-1c.html propagated-overflow-style-1-ref.html +== propagated-overflow-style-2a.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2b.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2c.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2d.html propagated-overflow-style-2-ref.html +== propagated-overflow-style-2e.html propagated-overflow-style-2-ref.html diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index eab11b80c..553239e0e 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1629,28 +1629,11 @@ nsStylePosition::CalcDifference(const nsStylePosition& aNewData, if (aOldStyleVisibility) { bool isVertical = WritingMode(aOldStyleVisibility).IsVertical(); if (isVertical ? widthChanged : heightChanged) { - // Block-size changes can affect descendant intrinsic sizes due to - // replaced elements with percentage bsizes in descendants which - // also have percentage bsizes. This is handled via - // nsChangeHint_UpdateComputedBSize which clears intrinsic sizes - // for frames that have such replaced elements. - // - // We need to use nsChangeHint_ClearAncestorIntrinsics for - // block-size changes so we clear results of cached CSS Flex - // measuring reflows. - hint |= nsChangeHint_NeedReflow | - nsChangeHint_UpdateComputedBSize | - nsChangeHint_ReflowChangesSizeOrPosition | - nsChangeHint_ClearAncestorIntrinsics; + hint |= nsChangeHint_ReflowHintsForBSizeChange; } if (isVertical ? heightChanged : widthChanged) { - // None of our inline-size differences can affect descendant - // intrinsic sizes and none of them need to force children to - // reflow. - hint |= nsChangeHint_AllReflowHints & - ~(nsChangeHint_ClearDescendantIntrinsics | - nsChangeHint_NeedDirtyReflow); + hint |= nsChangeHint_ReflowHintsForISizeChange; } } else { if (widthChanged || heightChanged) { @@ -3263,8 +3246,6 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const || mDisplay != aNewData.mDisplay || mContain != aNewData.mContain || (mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None) - || mOverflowX != aNewData.mOverflowX - || mOverflowY != aNewData.mOverflowY || mScrollBehavior != aNewData.mScrollBehavior || mScrollSnapTypeX != aNewData.mScrollSnapTypeX || mScrollSnapTypeY != aNewData.mScrollSnapTypeY @@ -3276,6 +3257,11 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const hint |= nsChangeHint_ReconstructFrame; } + if (mOverflowX != aNewData.mOverflowX + || mOverflowY != aNewData.mOverflowY) { + hint |= nsChangeHint_CSSOverflowChange; + } + /* Note: When mScrollBehavior, mScrollSnapTypeX, mScrollSnapTypeY, * mScrollSnapPointsX, mScrollSnapPointsY, or mScrollSnapDestination are * changed, nsChangeHint_NeutralChange is not sufficient to enter diff --git a/layout/style/test/mochitest.ini b/layout/style/test/mochitest.ini index 406c6f901..8182691ca 100644 --- a/layout/style/test/mochitest.ini +++ b/layout/style/test/mochitest.ini @@ -295,6 +295,7 @@ skip-if = toolkit == 'android' [test_variables.html] support-files = support/external-variable-url.css [test_video_object_fit.html] +[test_viewport_scrollbar_causing_reflow.html] [test_viewport_units.html] [test_visited_image_loading.html] skip-if = toolkit == 'android' #TIMED_OUT diff --git a/layout/style/test/test_dynamic_change_causing_reflow.html b/layout/style/test/test_dynamic_change_causing_reflow.html index a941191f6..a5bb3045c 100644 --- a/layout/style/test/test_dynamic_change_causing_reflow.html +++ b/layout/style/test/test_dynamic_change_causing_reflow.html @@ -95,6 +95,90 @@ const gTestcases = [ expectReflow: true, }, + // * Changing 'overflow' on should cause reflow, + // but not frame reconstruction + { + elem: document.body, + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: hidden", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: scroll", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: hidden", + afterStyle: "overflow: auto", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: hidden", + afterStyle: "overflow: scroll", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: hidden", + afterStyle: "overflow: visible", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: auto", + afterStyle: "overflow: hidden", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.body, + beforeStyle: "overflow: visible", + afterStyle: "overflow: hidden", + expectConstruction: false, + expectReflow: true, + }, + + // * Changing 'overflow' on should cause reflow, + // but not frame reconstruction + { + elem: document.documentElement, + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: auto", + expectConstruction: false, + expectReflow: true, + }, + { + elem: document.documentElement, + beforeStyle: "overflow: visible", + afterStyle: "overflow: auto", + expectConstruction: false, + expectReflow: true, + }, + + // * Setting 'overflow' on arbitrary node should cause reflow as well as + // frame reconstruction + { + /* beforeStyle: implicitly 'overflow:visible' */ + afterStyle: "overflow: auto", + expectConstruction: true, + expectReflow: true, + }, + { + beforeStyle: "overflow: auto", + afterStyle: "overflow: visible", + expectConstruction: true, + expectReflow: true, + }, + // * Changing 'display' should cause frame construction and reflow. { beforeStyle: "display: inline", @@ -135,23 +219,34 @@ function runOneTest(aTestcase) return; } + // Figure out which element we'll be tweaking (defaulting to gElem) + let elem = aTestcase.elem ? + aTestcase.elem : gElem; + + // Verify that 'style' attribute is unset (avoid causing ourselves trouble): + if (elem.hasAttribute("style")) { + ok(false, + "test element has 'style' attribute already set! We're going to stomp " + + "on whatever's there when we clean up..."); + } + // Set the "before" style, and compose the first part of the message // to be used in our "is"/"isnot" invocations: let msgPrefix = "Changing style "; if (aTestcase.beforeStyle) { - gElem.setAttribute("style", aTestcase.beforeStyle); + elem.setAttribute("style", aTestcase.beforeStyle); msgPrefix += "from '" + aTestcase.beforeStyle + "' "; } - msgPrefix += "to '" + aTestcase.afterStyle + "' "; + msgPrefix += "on " + elem.nodeName + " "; // Establish initial counts: - let unusedVal = gElem.offsetHeight; // flush layout + let unusedVal = elem.offsetHeight; // flush layout let origFramesConstructed = gUtils.framesConstructed; let origFramesReflowed = gUtils.framesReflowed; // Make the change and flush: - gElem.setAttribute("style", aTestcase.afterStyle); - unusedVal = gElem.offsetHeight; // flush layout + elem.setAttribute("style", aTestcase.afterStyle); + unusedVal = elem.offsetHeight; // flush layout // Make our is/isnot assertions about whether things should have changed: checkFinalCount(gUtils.framesConstructed, origFramesConstructed, @@ -162,7 +257,7 @@ function runOneTest(aTestcase) "reflow"); // Clean up! - gElem.removeAttribute("style"); + elem.removeAttribute("style"); } gTestcases.forEach(runOneTest); diff --git a/layout/style/test/test_viewport_scrollbar_causing_reflow.html b/layout/style/test/test_viewport_scrollbar_causing_reflow.html new file mode 100644 index 000000000..dfd7ec450 --- /dev/null +++ b/layout/style/test/test_viewport_scrollbar_causing_reflow.html @@ -0,0 +1,125 @@ + + + + + + Test for Bug 1367568 + + + + +Mozilla Bug 1367568 +
+ +
+ fixed-width +
(child)
+
+
+ abs-fixed-width +
(child)
+
+
+
+
+
+ + -- cgit v1.2.3