Bug 1623390 - Factor out the CanBeDynamicReflowRoot bits. r=dholbert

This is cleaner and allows to reuse this logic for some experiments I have :)

Differential Revision: https://phabricator.services.mozilla.com/D67354

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2020-03-31 14:12:46 +00:00
parent 63cacb2ad9
commit eca8fd9020
3 changed files with 96 additions and 103 deletions

View File

@ -23,7 +23,6 @@
#include "nsTableCellFrame.h"
#include "nsIPercentBSizeObserver.h"
#include "nsLayoutUtils.h"
#include "mozilla/Preferences.h"
#include "nsFontInflationData.h"
#include "StickyScrollContainer.h"
#include "nsIFrameInlines.h"
@ -745,109 +744,8 @@ void ReflowInput::InitResizeFlags(nsPresContext* aPresContext,
}
}
template <typename SizeOrMaxSize>
static inline bool IsIntrinsicKeyword(const SizeOrMaxSize& aSize) {
if (!aSize.IsExtremumLength()) {
return false;
}
// All of the keywords except for '-moz-available' depend on intrinsic sizes.
return aSize.AsExtremumLength() != StyleExtremumLength::MozAvailable;
}
static bool AreDynamicReflowRootsEnabled() {
static bool sAreDynamicReflowRootsEnabled;
static bool sIsPrefCached = false;
if (!sIsPrefCached) {
sIsPrefCached = true;
Preferences::AddBoolVarCache(&sAreDynamicReflowRootsEnabled,
"layout.dynamic-reflow-roots.enabled");
}
return sAreDynamicReflowRootsEnabled;
}
void ReflowInput::InitDynamicReflowRoot() {
auto display = mStyleDisplay->mDisplay;
if (mFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
nsStyleDisplay::IsRubyDisplayType(display) ||
mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE ||
nsStyleDisplay::DisplayInside(display) == StyleDisplayInside::Table ||
(mFrame->GetParent() && mFrame->GetParent()->IsXULBoxFrame())) {
// We have a display type where 'width' and 'height' don't actually
// set the width or height (i.e., the size depends on content).
NS_ASSERTION(!(mFrame->GetStateBits() & NS_FRAME_DYNAMIC_REFLOW_ROOT),
"should not have dynamic reflow root bit");
return;
}
bool canBeDynamicReflowRoot = AreDynamicReflowRootsEnabled();
// We can't do this if our used 'width' and 'height' might be influenced by
// content.
// FIXME: For display:block, we should probably optimize inline-size
// being auto.
// FIXME: Other flex and grid cases?
const auto& width = mStylePosition->mWidth;
const auto& height = mStylePosition->mHeight;
if (canBeDynamicReflowRoot &&
(!width.IsLengthPercentage() || width.HasPercent() ||
!height.IsLengthPercentage() || height.HasPercent() ||
IsIntrinsicKeyword(mStylePosition->mMinWidth) ||
IsIntrinsicKeyword(mStylePosition->mMaxWidth) ||
IsIntrinsicKeyword(mStylePosition->mMinHeight) ||
IsIntrinsicKeyword(mStylePosition->mMaxHeight) ||
((mStylePosition->mMinWidth.IsAuto() ||
mStylePosition->mMinHeight.IsAuto()) &&
mFrame->IsFlexOrGridItem()))) {
canBeDynamicReflowRoot = false;
}
if (canBeDynamicReflowRoot && mFrame->IsFlexItem()) {
// If our flex-basis is 'auto', it'll defer to 'width' (or 'height') which
// we've already checked. Otherwise, it preempts them, so we need to
// perform the same "could-this-value-be-influenced-by-content" checks that
// we performed for 'width' and 'height' above.
const auto& flexBasis = mStylePosition->mFlexBasis;
if (!flexBasis.IsAuto()) {
if (!flexBasis.IsSize() || !flexBasis.AsSize().IsLengthPercentage() ||
flexBasis.AsSize().HasPercent()) {
canBeDynamicReflowRoot = false;
}
}
}
if (canBeDynamicReflowRoot && !mFrame->IsFixedPosContainingBlock()) {
// We can't treat this frame as a reflow root, since dynamic changes
// to absolutely-positioned frames inside of it require that we
// reflow the placeholder before we reflow the absolutely positioned
// frame.
// FIXME: Alternatively, we could sort the reflow roots in
// PresShell::ProcessReflowCommands by depth in the tree, from
// deepest to least deep. However, for performance (FIXME) we
// should really be sorting them in the opposite order!
canBeDynamicReflowRoot = false;
}
// If we participate in a container's block reflow context, or margins
// can collapse through us, we can't be a dynamic reflow root.
if (canBeDynamicReflowRoot && mFrame->IsBlockFrameOrSubclass() &&
!mFrame->HasAllStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT)) {
canBeDynamicReflowRoot = false;
}
// Subgrids are never reflow roots, but 'contain:layout/paint' prevents
// creating a subgrid in the first place.
if (canBeDynamicReflowRoot &&
(mStylePosition->mGridTemplateColumns.IsSubgrid() ||
mStylePosition->mGridTemplateRows.IsSubgrid()) &&
!(mStyleDisplay->IsContainLayout() || mStyleDisplay->IsContainPaint())) {
// NOTE: we could check that 'display' of our content's primary frame is
// '[inline-]grid' here but that's probably not worth it in practice.
canBeDynamicReflowRoot = false;
}
if (canBeDynamicReflowRoot) {
if (mFrame->CanBeDynamicReflowRoot()) {
mFrame->AddStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);
} else {
mFrame->RemoveStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT);

View File

@ -2455,6 +2455,99 @@ already_AddRefed<ComputedStyle> nsIFrame::ComputeSelectionStyle(
*element, PseudoStyleType::selection, Style());
}
template <typename SizeOrMaxSize>
static inline bool IsIntrinsicKeyword(const SizeOrMaxSize& aSize) {
if (!aSize.IsExtremumLength()) {
return false;
}
// All of the keywords except for '-moz-available' depend on intrinsic sizes.
return aSize.AsExtremumLength() != StyleExtremumLength::MozAvailable;
}
bool nsIFrame::CanBeDynamicReflowRoot() const {
if (!StaticPrefs::layout_dynamic_reflow_roots_enabled()) {
return false;
}
auto& display = *StyleDisplay();
if (IsFrameOfType(nsIFrame::eLineParticipant) ||
nsStyleDisplay::IsRubyDisplayType(display.mDisplay) ||
display.DisplayOutside() == StyleDisplayOutside::InternalTable ||
display.DisplayInside() == StyleDisplayInside::Table ||
(GetParent() && GetParent()->IsXULBoxFrame())) {
// We have a display type where 'width' and 'height' don't actually set the
// width or height (i.e., the size depends on content).
MOZ_ASSERT(!HasAnyStateBits(NS_FRAME_DYNAMIC_REFLOW_ROOT),
"should not have dynamic reflow root bit");
return false;
}
// We can't serve as a dynamic reflow root if our used 'width' and 'height'
// might be influenced by content.
//
// FIXME: For display:block, we should probably optimize inline-size: auto.
// FIXME: Other flex and grid cases?
auto& pos = *StylePosition();
const auto& width = pos.mWidth;
const auto& height = pos.mHeight;
if (!width.IsLengthPercentage() || width.HasPercent() ||
!height.IsLengthPercentage() || height.HasPercent() ||
IsIntrinsicKeyword(pos.mMinWidth) || IsIntrinsicKeyword(pos.mMaxWidth) ||
IsIntrinsicKeyword(pos.mMinHeight) ||
IsIntrinsicKeyword(pos.mMaxHeight) ||
((pos.mMinWidth.IsAuto() || pos.mMinHeight.IsAuto()) &&
IsFlexOrGridItem())) {
return false;
}
// If our flex-basis is 'auto', it'll defer to 'width' (or 'height') which
// we've already checked. Otherwise, it preempts them, so we need to
// perform the same "could-this-value-be-influenced-by-content" checks that
// we performed for 'width' and 'height' above.
if (IsFlexItem()) {
const auto& flexBasis = pos.mFlexBasis;
if (!flexBasis.IsAuto()) {
if (!flexBasis.IsSize() || !flexBasis.AsSize().IsLengthPercentage() ||
flexBasis.AsSize().HasPercent()) {
return false;
}
}
}
if (!IsFixedPosContainingBlock()) {
// We can't treat this frame as a reflow root, since dynamic changes
// to absolutely-positioned frames inside of it require that we
// reflow the placeholder before we reflow the absolutely positioned
// frame.
// FIXME: Alternatively, we could sort the reflow roots in
// PresShell::ProcessReflowCommands by depth in the tree, from
// deepest to least deep. However, for performance (FIXME) we
// should really be sorting them in the opposite order!
return false;
}
// If we participate in a container's block reflow context, or margins
// can collapse through us, we can't be a dynamic reflow root.
if (IsBlockFrameOrSubclass() &&
!HasAllStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT)) {
return false;
}
// Subgrids are never reflow roots, but 'contain:layout/paint' prevents
// creating a subgrid in the first place.
if (pos.mGridTemplateColumns.IsSubgrid() ||
pos.mGridTemplateRows.IsSubgrid()) {
// NOTE: we could check that 'display' of our parent's primary frame is
// '[inline-]grid' here but that's probably not worth it in practice.
if (!display.IsContainLayout() && !display.IsContainPaint()) {
return false;
}
}
return true;
}
/********************************************************
* Refreshes each content's frame
*********************************************************/

View File

@ -862,6 +862,8 @@ class nsIFrame : public nsQueryFrame {
*/
nsContainerFrame* GetParent() const { return mParent; }
bool CanBeDynamicReflowRoot() const;
/**
* Gets the parent of a frame, using the parent of the placeholder for
* out-of-flow frames.