Bug 1242172. Invalidate intrinsic ISizes that depend on viewport BSize when the viewport is resized. r=dbaron
MozReview-Commit-ID: INEHo7ghGyz
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5157,16 +5157,42 @@ nsLayoutUtils::MarkDescendantsDirty(nsIF
stack.AppendElement(kid);
}
}
} while (stack.Length() != 0);
} while (subtrees.Length() != 0);
}
/* static */
+void
+nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(nsIFrame* aFrame)
+{
+ AutoTArray<nsIFrame*, 32> stack;
+ stack.AppendElement(aFrame);
+
+ do {
+ nsIFrame* f = stack.ElementAt(stack.Length() - 1);
+ stack.RemoveElementAt(stack.Length() - 1);
+
+ if (!f->HasAnyStateBits(
+ NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
+ continue;
+ }
+ f->MarkIntrinsicISizesDirty();
+
+ nsIFrame::ChildListIterator lists(f);
+ for (; !lists.IsDone(); lists.Next()) {
+ for (nsIFrame* kid : lists.CurrentList()) {
+ stack.AppendElement(kid);
+ }
+ }
+ } while (stack.Length() != 0);
+}
+
+/* static */
LogicalSize
nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(WritingMode aWM,
nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
const IntrinsicSize& aIntrinsicSize,
nsSize aIntrinsicRatio,
const mozilla::LogicalSize& aCBSize,
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1482,16 +1482,18 @@ public:
aCoord.GetPercentValue() == 0.0f) ||
(aCoord.IsCalcUnit() &&
nsRuleNode::ComputeCoordPercentCalc(aCoord, nscoord_MAX) == 0 &&
nsRuleNode::ComputeCoordPercentCalc(aCoord, 0) == 0);
}
static void MarkDescendantsDirty(nsIFrame *aSubtreeRoot);
+ static void MarkIntrinsicISizesDirtyIfDependentOnBSize(nsIFrame* aFrame);
+
/*
* Calculate the used values for 'width' and 'height' for a replaced element.
*
* http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
*/
static mozilla::LogicalSize
ComputeSizeWithIntrinsicDimensions(mozilla::WritingMode aWM,
nsRenderingContext* aRenderingContext, nsIFrame* aFrame,
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1834,16 +1834,22 @@ PresShell::ResizeReflowIgnoreOverride(ns
mPresContext->RestyleManager()->ProcessPendingRestyles();
}
rootFrame = mFrameConstructor->GetRootFrame();
if (!mIsDestroying && rootFrame) {
// XXX Do a full invalidate at the beginning so that invalidates along
// the way don't have region accumulation issues?
+ // For BSize changes driven by style, RestyleManager handles this.
+ // For height:auto BSizes (i.e. layout-controlled), descendant
+ // intrinsic sizes can't depend on them. So the only other case is
+ // viewport-controlled BSizes which we handle here.
+ nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(rootFrame);
+
{
nsAutoCauseReflowNotifier crNotifier(this);
WillDoReflow();
// Kick off a top-down reflow
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
nsViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -315,16 +315,20 @@ nsHTMLScrollFrame::TryLayout(ScrollReflo
(aState->mStyles.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN && aAssumeHScroll)) {
NS_ASSERTION(!aForce, "Shouldn't be forcing a hidden scrollbar to show!");
return false;
}
if (aAssumeVScroll != aState->mReflowedContentsWithVScrollbar ||
(aAssumeHScroll != aState->mReflowedContentsWithHScrollbar &&
ScrolledContentDependsOnHeight(aState))) {
+ if (aAssumeHScroll != aState->mReflowedContentsWithHScrollbar) {
+ nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize(
+ mHelper.mScrolledFrame);
+ }
ReflowScrolledFrame(aState, aAssumeHScroll, aAssumeVScroll, aKidMetrics,
false);
}
nsSize vScrollbarMinSize(0, 0);
nsSize vScrollbarPrefSize(0, 0);
if (mHelper.mVScrollbarBox) {
GetScrollbarMetrics(aState->mBoxState, mHelper.mVScrollbarBox,
@@ -418,17 +422,18 @@ nsHTMLScrollFrame::TryLayout(ScrollReflo
// XXX Height/BSize mismatch needs to be addressed here; check the caller!
// Currently this will only behave as expected for horizontal writing modes.
// (See bug 1175509.)
bool
nsHTMLScrollFrame::ScrolledContentDependsOnHeight(ScrollReflowState* aState)
{
// Return true if ReflowScrolledFrame is going to do something different
// based on the presence of a horizontal scrollbar.
- return (mHelper.mScrolledFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE) ||
+ return mHelper.mScrolledFrame->HasAnyStateBits(
+ NS_FRAME_CONTAINS_RELATIVE_BSIZE | NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE) ||
aState->mReflowState.ComputedBSize() != NS_UNCONSTRAINEDSIZE ||
aState->mReflowState.ComputedMinBSize() > 0 ||
aState->mReflowState.ComputedMaxBSize() != NS_UNCONSTRAINEDSIZE;
}
void
nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
bool aAssumeHScroll,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1242172-1-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<iframe src="1242172-1-subdoc.html" style="width:800px; height:200px; border:1px solid black"></iframe>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1242172-1-subdoc.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html style="overflow:hidden">
+<body>
+<div style='position:absolute; height:100%; display:flex; flex-direction:row'>
+ <div style="height:100%"><img src="repeatable-diagonal-gradient.png" style='height:100%'></img></div>
+ <div style="height:100%"><img src="repeatable-diagonal-gradient.png" style='height:100%'></img></div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1242172-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<body onload="doTest()">
+<iframe id="f" src="1242172-1-subdoc.html" style="width:800px; height:100px; border:1px solid black"></iframe>
+<script>
+function doTest() {
+ f.contentDocument.body.offsetTop;
+ f.style.height = "200px";
+}
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1242172-2-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<!-- The test forces scrollbars to appear. Using overflow:scroll here avoids the
+ iterative overflow:auto reflow logic. -->
+<html style="overflow:scroll">
+<body>
+<div style='position:absolute; height:100%; display:flex; flex-direction:row'>
+ <div style="height:100%"><img src="repeatable-diagonal-gradient.png" style='height:100%'></img></div>
+ <div style="height:100%"><img src="repeatable-diagonal-gradient.png" style='height:100%'></img></div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1242172-2.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style='position:absolute; height:100%; display:flex; flex-direction:row'>
+ <div style="height:100%"><img src="repeatable-diagonal-gradient.png" style='height:100%'></img></div>
+ <div style="height:100%"><img src="repeatable-diagonal-gradient.png" style='height:100%'></img></div>
+</div>
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1940,8 +1940,10 @@ fuzzy(1,74) fuzzy-if(gtkWidget,6,79) ==
== 1209994-1.html 1209994-1-ref.html
== 1209994-2.html 1209994-2-ref.html
== 1209994-3.html 1209994-3-ref.html
== 1209994-4.html 1209994-4-ref.html
== 1222226-1.html 1222226-1-ref.html
pref(layout.css.overflow-clip-box.enabled,true) == 1226278.html 1226278-ref.html
== 1230466.html about:blank
fuzzy(100,2000) == 1239564.html 1239564-ref.html
+== 1242172-1.html 1242172-1-ref.html
+== 1242172-2.html 1242172-2-ref.html