summaryrefslogtreecommitdiffstats
path: root/layout/base
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base')
-rw-r--r--layout/base/RestyleManagerBase.cpp63
-rw-r--r--layout/base/nsCSSFrameConstructor.cpp15
-rw-r--r--layout/base/nsChangeHint.h55
-rw-r--r--layout/base/nsPresContext.cpp9
-rw-r--r--layout/base/nsPresContext.h22
5 files changed, 153 insertions, 11 deletions
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 <body> [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 <body> 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;