From 59203c63bb777a3bacec32fb8830fba33540e809 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:35:29 +0200 Subject: Adding upstream version 127.0. Signed-off-by: Daniel Baumann --- layout/generic/CSSAlignUtils.cpp | 2 +- layout/generic/ReflowInput.cpp | 80 +++++----- layout/generic/ReflowInput.h | 9 ++ layout/generic/ScrollAnchorContainer.cpp | 12 +- layout/generic/StickyScrollContainer.cpp | 6 +- layout/generic/WritingModes.h | 227 ++++++++++++--------------- layout/generic/crashtests/crashtests.list | 6 +- layout/generic/nsAbsoluteContainingBlock.cpp | 6 +- layout/generic/nsBlockFrame.cpp | 5 +- layout/generic/nsCanvasFrame.cpp | 14 +- layout/generic/nsColumnSetFrame.cpp | 6 +- layout/generic/nsContainerFrame.cpp | 2 +- layout/generic/nsContainerFrameInlines.h | 4 +- layout/generic/nsFirstLetterFrame.cpp | 10 +- layout/generic/nsFlexContainerFrame.cpp | 216 ++++++++++++++++++++----- layout/generic/nsFlexContainerFrame.h | 3 + layout/generic/nsFloatManager.cpp | 6 +- layout/generic/nsFrameSelection.cpp | 5 - layout/generic/nsGfxScrollFrame.cpp | 24 +-- layout/generic/nsGridContainerFrame.cpp | 25 +-- layout/generic/nsGridContainerFrame.h | 59 ++++--- layout/generic/nsIFrame.cpp | 87 ++++++++-- layout/generic/nsIFrame.h | 26 ++- layout/generic/nsImageFrame.cpp | 16 +- layout/generic/nsInlineFrame.cpp | 10 +- layout/generic/nsLineLayout.cpp | 2 + layout/generic/nsRubyFrame.cpp | 18 +-- layout/generic/nsSplittableFrame.cpp | 8 +- layout/generic/nsSubDocumentFrame.cpp | 54 +++---- 29 files changed, 567 insertions(+), 381 deletions(-) (limited to 'layout/generic') diff --git a/layout/generic/CSSAlignUtils.cpp b/layout/generic/CSSAlignUtils.cpp index 7dd8999563..090cba3a2a 100644 --- a/layout/generic/CSSAlignUtils.cpp +++ b/layout/generic/CSSAlignUtils.cpp @@ -56,7 +56,7 @@ nscoord CSSAlignUtils::AlignJustifySelf(const StyleAlignFlags& aAlignment, WritingMode wm = aRI.GetWritingMode(); const LogicalMargin margin = aRI.ComputedLogicalMargin(wm); const auto startSide = MakeLogicalSide( - aAxis, MOZ_LIKELY(isSameSide) ? eLogicalEdgeStart : eLogicalEdgeEnd); + aAxis, MOZ_LIKELY(isSameSide) ? LogicalEdge::Start : LogicalEdge::End); const nscoord marginStart = margin.Side(startSide, wm); const auto endSide = GetOppositeSide(startSide); const nscoord marginEnd = margin.Side(endSide, wm); diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp index c642c77b2c..bdfd39aff1 100644 --- a/layout/generic/ReflowInput.cpp +++ b/layout/generic/ReflowInput.cpp @@ -953,21 +953,10 @@ void ReflowInput::ApplyRelativePositioning(nsIFrame* aFrame, const nsStyleDisplay* display = aFrame->StyleDisplay(); if (StylePositionProperty::Relative == display->mPosition) { *aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top); - } else if (StylePositionProperty::Sticky == display->mPosition && - !aFrame->GetNextContinuation() && !aFrame->GetPrevContinuation() && - !aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) { - // Sticky positioning for elements with multiple frames needs to be - // computed all at once. We can't safely do that here because we might be - // partway through (re)positioning the frames, so leave it until the scroll - // container reflows and calls StickyScrollContainer::UpdatePositions. - // For single-frame sticky positioned elements, though, go ahead and apply - // it now to avoid unnecessary overflow updates later. - StickyScrollContainer* ssc = - StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame); - if (ssc) { - *aPosition = ssc->ComputePosition(aFrame); - } } + // For sticky positioned elements, we'll leave them until the scroll container + // reflows and calls StickyScrollContainer::UpdatePositions() to update their + // positions. } // static @@ -1123,9 +1112,9 @@ void ReflowInput::CalculateBorderPaddingMargin( nscoord* aOutsideBoxSizing) const { WritingMode wm = GetWritingMode(); mozilla::Side startSide = - wm.PhysicalSide(MakeLogicalSide(aAxis, eLogicalEdgeStart)); + wm.PhysicalSide(MakeLogicalSide(aAxis, LogicalEdge::Start)); mozilla::Side endSide = - wm.PhysicalSide(MakeLogicalSide(aAxis, eLogicalEdgeEnd)); + wm.PhysicalSide(MakeLogicalSide(aAxis, LogicalEdge::End)); nsMargin styleBorder = mStyleBorder->GetComputedBorder(); nscoord borderStartEnd = @@ -1228,9 +1217,9 @@ static bool AxisPolarityFlipped(LogicalAxis aThisAxis, WritingMode aThisWm, aThisWm.PhysicalAxis(aThisAxis) == aOtherWm.PhysicalAxis(otherAxis), "Physical axes must match!"); Side thisStartSide = - aThisWm.PhysicalSide(MakeLogicalSide(aThisAxis, eLogicalEdgeStart)); + aThisWm.PhysicalSide(MakeLogicalSide(aThisAxis, LogicalEdge::Start)); Side otherStartSide = - aOtherWm.PhysicalSide(MakeLogicalSide(otherAxis, eLogicalEdgeStart)); + aOtherWm.PhysicalSide(MakeLogicalSide(otherAxis, LogicalEdge::Start)); return thisStartSide != otherStartSide; } @@ -2549,9 +2538,9 @@ void SizeComputationInput::InitOffsets(WritingMode aCBWM, nscoord aPercentBasis, NS_ASSERTION(val != nscoord(0), "zero in this property is useless"); LogicalSide side; if (val > 0) { - side = MakeLogicalSide(aAxis, eLogicalEdgeStart); + side = MakeLogicalSide(aAxis, LogicalEdge::Start); } else { - side = MakeLogicalSide(aAxis, eLogicalEdgeEnd); + side = MakeLogicalSide(aAxis, LogicalEdge::End); val = -val; } mComputedPadding.Side(side, wm) += val; @@ -2742,27 +2731,28 @@ void ReflowInput::CalculateBlockSideMargins() { // zeros, we should compensate this by creating extra (external) leading. // This is necessary because without this compensation, normal line height might // look too tight. -constexpr float kNormalLineHeightFactor = 1.2f; static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) { MOZ_ASSERT(aFontMetrics, "no font metrics"); nscoord externalLeading = aFontMetrics->ExternalLeading(); nscoord internalLeading = aFontMetrics->InternalLeading(); nscoord emHeight = aFontMetrics->EmHeight(); if (!internalLeading && !externalLeading) { - return NSToCoordRound(emHeight * kNormalLineHeightFactor); + return NSToCoordRound(static_cast(emHeight) * + ReflowInput::kNormalLineHeightFactor); } return emHeight + internalLeading + externalLeading; } static inline nscoord ComputeLineHeight(const StyleLineHeight& aLh, - const nsStyleFont& aRelativeToFont, + const nsFont& aFont, nsAtom* aLanguage, + bool aExplicitLanguage, nsPresContext* aPresContext, bool aIsVertical, nscoord aBlockBSize, float aFontSizeInflation) { if (aLh.IsLength()) { nscoord result = aLh.AsLength().ToAppUnits(); if (aFontSizeInflation != 1.0f) { - result = NSToCoordRound(result * aFontSizeInflation); + result = NSToCoordRound(static_cast(result) * aFontSizeInflation); } return result; } @@ -2771,8 +2761,7 @@ static inline nscoord ComputeLineHeight(const StyleLineHeight& aLh, // For factor units the computed value of the line-height property // is found by multiplying the factor by the font's computed size // (adjusted for min-size prefs and text zoom). - return aRelativeToFont.mFont.size - .ScaledBy(aLh.AsNumber() * aFontSizeInflation) + return aFont.size.ScaledBy(aLh.AsNumber() * aFontSizeInflation) .ToAppUnits(); } @@ -2781,17 +2770,25 @@ static inline nscoord ComputeLineHeight(const StyleLineHeight& aLh, return aBlockBSize; } - auto size = aRelativeToFont.mFont.size; + auto size = aFont.size; size.ScaleBy(aFontSizeInflation); if (aPresContext) { - RefPtr fm = nsLayoutUtils::GetMetricsFor( - aPresContext, aIsVertical, &aRelativeToFont, size, - /* aUseUserFontSet = */ true); + nsFont font = aFont; + font.size = size; + nsFontMetrics::Params params; + params.language = aLanguage; + params.explicitLanguage = aExplicitLanguage; + params.orientation = + aIsVertical ? nsFontMetrics::eVertical : nsFontMetrics::eHorizontal; + params.userFontSet = aPresContext->GetUserFontSet(); + params.textPerf = aPresContext->GetTextPerfMetrics(); + params.featureValueLookup = aPresContext->GetFontFeatureValuesLookup(); + RefPtr fm = aPresContext->GetMetricsFor(font, params); return GetNormalLineHeight(fm); } // If we don't have a pres context, use a 1.2em fallback. - size.ScaleBy(kNormalLineHeightFactor); + size.ScaleBy(ReflowInput::kNormalLineHeightFactor); return size.ToAppUnits(); } @@ -2839,8 +2836,9 @@ nscoord ReflowInput::CalcLineHeight( nsPresContext* aPresContext, bool aIsVertical, const nsIContent* aContent, nscoord aBlockBSize, float aFontSizeInflation) { nscoord lineHeight = - ComputeLineHeight(aLh, aRelativeToFont, aPresContext, aIsVertical, - aBlockBSize, aFontSizeInflation); + ComputeLineHeight(aLh, aRelativeToFont.mFont, aRelativeToFont.mLanguage, + aRelativeToFont.mExplicitLanguage, aPresContext, + aIsVertical, aBlockBSize, aFontSizeInflation); NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up"); @@ -2850,8 +2848,9 @@ nscoord ReflowInput::CalcLineHeight( // have a line-height smaller than 'normal'. if (!aLh.IsNormal()) { nscoord normal = ComputeLineHeight( - StyleLineHeight::Normal(), aRelativeToFont, aPresContext, aIsVertical, - aBlockBSize, aFontSizeInflation); + StyleLineHeight::Normal(), aRelativeToFont.mFont, + aRelativeToFont.mLanguage, aRelativeToFont.mExplicitLanguage, + aPresContext, aIsVertical, aBlockBSize, aFontSizeInflation); if (lineHeight < normal) { lineHeight = normal; } @@ -2861,6 +2860,17 @@ nscoord ReflowInput::CalcLineHeight( return lineHeight; } +nscoord ReflowInput::CalcLineHeightForCanvas(const StyleLineHeight& aLh, + const nsFont& aRelativeToFont, + nsAtom* aLanguage, + bool aExplicitLanguage, + nsPresContext* aPresContext, + mozilla::WritingMode aWM) { + return ComputeLineHeight(aLh, aRelativeToFont, aLanguage, aExplicitLanguage, + aPresContext, aWM.IsVertical() && !aWM.IsSideways(), + NS_UNCONSTRAINEDSIZE, 1.0f); +} + bool SizeComputationInput::ComputeMargin(WritingMode aCBWM, nscoord aPercentBasis, LayoutFrameType aFrameType) { diff --git a/layout/generic/ReflowInput.h b/layout/generic/ReflowInput.h index ba49edcaf6..7bf7c4fc73 100644 --- a/layout/generic/ReflowInput.h +++ b/layout/generic/ReflowInput.h @@ -741,6 +741,15 @@ struct ReflowInput : public SizeComputationInput { const nsIContent* aContent, nscoord aBlockBSize, float aFontSizeInflation); + static nscoord CalcLineHeightForCanvas(const StyleLineHeight& aLh, + const nsFont& aRelativeToFont, + nsAtom* aLanguage, + bool aExplicitLanguage, + nsPresContext* aPresContext, + mozilla::WritingMode aWM); + + static constexpr float kNormalLineHeightFactor = 1.2f; + mozilla::LogicalSize ComputeContainingBlockRectangle( nsPresContext* aPresContext, const ReflowInput* aContainingBlockRI) const; diff --git a/layout/generic/ScrollAnchorContainer.cpp b/layout/generic/ScrollAnchorContainer.cpp index 93336480f7..9bf17ec3d5 100644 --- a/layout/generic/ScrollAnchorContainer.cpp +++ b/layout/generic/ScrollAnchorContainer.cpp @@ -178,15 +178,15 @@ static nsRect FindScrollAnchoringBoundingRect(const nsIFrame* aScrollFrame, // axis of the scroll frame WritingMode writingMode = aScrollFrame->GetWritingMode(); switch (writingMode.GetBlockDir()) { - case WritingMode::eBlockTB: { + case WritingMode::BlockDir::TB: { overflowRect.SetBoxY(borderRect.Y(), overflowRect.YMost()); break; } - case WritingMode::eBlockLR: { + case WritingMode::BlockDir::LR: { overflowRect.SetBoxX(borderRect.X(), overflowRect.XMost()); break; } - case WritingMode::eBlockRL: { + case WritingMode::BlockDir::RL: { overflowRect.SetBoxX(overflowRect.X(), borderRect.XMost()); break; } @@ -522,15 +522,15 @@ void ScrollAnchorContainer::ApplyAdjustments() { nsPoint physicalAdjustment; switch (writingMode.GetBlockDir()) { - case WritingMode::eBlockTB: { + case WritingMode::BlockDir::TB: { physicalAdjustment.y = logicalAdjustment; break; } - case WritingMode::eBlockLR: { + case WritingMode::BlockDir::LR: { physicalAdjustment.x = logicalAdjustment; break; } - case WritingMode::eBlockRL: { + case WritingMode::BlockDir::RL: { physicalAdjustment.x = -logicalAdjustment; break; } diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp index 416bbbf4c4..e16c3af585 100644 --- a/layout/generic/StickyScrollContainer.cpp +++ b/layout/generic/StickyScrollContainer.cpp @@ -200,11 +200,13 @@ void StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsLayoutUtils::TransformRect(cbFrame, aFrame->GetParent(), *aContain); } else { *aContain = nsLayoutUtils::GetAllInFlowRectsUnion( - cbFrame, aFrame->GetParent(), nsLayoutUtils::RECTS_USE_CONTENT_BOX); + cbFrame, aFrame->GetParent(), + nsLayoutUtils::GetAllInFlowRectsFlag::UseContentBox); } nsRect marginRect = nsLayoutUtils::GetAllInFlowRectsUnion( - aFrame, aFrame->GetParent(), nsLayoutUtils::RECTS_USE_MARGIN_BOX); + aFrame, aFrame->GetParent(), + nsLayoutUtils::GetAllInFlowRectsFlag::UseMarginBoxWithAutoResolvedAsZero); // Deflate aContain by the difference between the union of aFrame's // continuations' margin boxes and the union of their border boxes, so that diff --git a/layout/generic/WritingModes.h b/layout/generic/WritingModes.h index 0fcf47f1d0..4f6e9eaec1 100644 --- a/layout/generic/WritingModes.h +++ b/layout/generic/WritingModes.h @@ -11,10 +11,8 @@ #include "mozilla/intl/BidiEmbeddingLevel.h" #include "mozilla/ComputedStyle.h" -#include "mozilla/EnumeratedRange.h" - +#include "mozilla/EnumSet.h" #include "nsRect.h" -#include "nsBidiUtils.h" #include "nsStyleStruct.h" // It is the caller's responsibility to operate on logical-coordinate objects @@ -50,7 +48,7 @@ enum class LogicalAxis : uint8_t { Block, Inline, }; -enum LogicalEdge { eLogicalEdgeStart = 0x0, eLogicalEdgeEnd = 0x1 }; +enum class LogicalEdge : uint8_t { Start, End }; enum class LogicalSide : uint8_t { BStart, @@ -59,11 +57,6 @@ enum class LogicalSide : uint8_t { IEnd, }; -constexpr auto AllLogicalSides() { - return mozilla::MakeInclusiveEnumeratedRange(LogicalSide::BStart, - LogicalSide::IEnd); -} - enum class LogicalCorner : uint8_t { BStartIStart, BStartIEnd, @@ -72,7 +65,7 @@ enum class LogicalCorner : uint8_t { }; // Physical axis constants. -enum PhysicalAxis { eAxisVertical = 0x0, eAxisHorizontal = 0x1 }; +enum class PhysicalAxis : uint8_t { Vertical, Horizontal }; // Represents zero or more physical axes. enum class PhysicalAxes : uint8_t { @@ -104,38 +97,30 @@ inline LogicalAxis GetAxis(LogicalSide aSide) { } inline LogicalEdge GetEdge(LogicalSide aSide) { - return IsEnd(aSide) ? eLogicalEdgeEnd : eLogicalEdgeStart; + return IsEnd(aSide) ? LogicalEdge::End : LogicalEdge::Start; } inline LogicalEdge GetOppositeEdge(LogicalEdge aEdge) { - // This relies on the only two LogicalEdge enum values being 0 and 1. - return LogicalEdge(1 - aEdge); + return aEdge == LogicalEdge::Start ? LogicalEdge::End : LogicalEdge::Start; } inline LogicalSide MakeLogicalSide(LogicalAxis aAxis, LogicalEdge aEdge) { - return LogicalSide((uint8_t(aAxis) << 1) | aEdge); + if (aAxis == LogicalAxis::Inline) { + return aEdge == LogicalEdge::Start ? LogicalSide::IStart + : LogicalSide::IEnd; + } + return aEdge == LogicalEdge::Start ? LogicalSide::BStart : LogicalSide::BEnd; } inline LogicalSide GetOppositeSide(LogicalSide aSide) { return MakeLogicalSide(GetAxis(aSide), GetOppositeEdge(GetEdge(aSide))); } -enum LogicalSideBits { - eLogicalSideBitsNone = 0, - eLogicalSideBitsBStart = 1 << static_cast(LogicalSide::BStart), - eLogicalSideBitsBEnd = 1 << static_cast(LogicalSide::BEnd), - eLogicalSideBitsIEnd = 1 << static_cast(LogicalSide::IEnd), - eLogicalSideBitsIStart = 1 << static_cast(LogicalSide::IStart), - eLogicalSideBitsBBoth = eLogicalSideBitsBStart | eLogicalSideBitsBEnd, - eLogicalSideBitsIBoth = eLogicalSideBitsIStart | eLogicalSideBitsIEnd, - eLogicalSideBitsAll = eLogicalSideBitsBBoth | eLogicalSideBitsIBoth -}; - -enum LineRelativeDir { - eLineRelativeDirOver = static_cast(LogicalSide::BStart), - eLineRelativeDirUnder = static_cast(LogicalSide::BEnd), - eLineRelativeDirLeft = static_cast(LogicalSide::IStart), - eLineRelativeDirRight = static_cast(LogicalSide::IEnd) +enum class LineRelativeDir : uint8_t { + Over = static_cast(LogicalSide::BStart), + Under = static_cast(LogicalSide::BEnd), + Left = static_cast(LogicalSide::IStart), + Right = static_cast(LogicalSide::IEnd) }; /** @@ -155,54 +140,41 @@ class WritingMode { /** * Absolute inline flow direction */ - enum InlineDir { - eInlineLTR = 0x00, // text flows horizontally left to right - eInlineRTL = 0x02, // text flows horizontally right to left - eInlineTTB = 0x01, // text flows vertically top to bottom - eInlineBTT = 0x03, // text flows vertically bottom to top + enum class InlineDir : uint8_t { + LTR, // text flows horizontally left to right + RTL, // text flows horizontally right to left + TTB, // text flows vertically top to bottom + BTT, // text flows vertically bottom to top }; /** * Absolute block flow direction */ - enum BlockDir { - eBlockTB = 0x00, // horizontal lines stack top to bottom - eBlockRL = 0x01, // vertical lines stack right to left - eBlockLR = 0x05, // vertical lines stack left to right - }; - - /** - * Line-relative (bidi-relative) inline flow direction - */ - enum BidiDir { - eBidiLTR = 0x00, // inline flow matches bidi LTR text - eBidiRTL = 0x10, // inline flow matches bidi RTL text + enum class BlockDir : uint8_t { + TB, // horizontal lines stack top to bottom + RL, // vertical lines stack right to left + LR, // vertical lines stack left to right }; - /** - * Unknown writing mode (should never actually be stored or used anywhere). - */ - enum { eUnknownWritingMode = 0xff }; - /** * Return the absolute inline flow direction as an InlineDir */ InlineDir GetInlineDir() const { - return InlineDir(mWritingMode._0 & eInlineMask); + if (IsVertical()) { + return IsInlineReversed() ? InlineDir::BTT : InlineDir::TTB; + } + return IsInlineReversed() ? InlineDir::RTL : InlineDir::LTR; } /** * Return the absolute block flow direction as a BlockDir */ BlockDir GetBlockDir() const { - return BlockDir(mWritingMode._0 & eBlockMask); - } - - /** - * Return the line-relative inline flow direction as a BidiDir - */ - BidiDir GetBidiDir() const { - return BidiDir((mWritingMode & StyleWritingMode::RTL)._0); + if (IsVertical()) { + return mWritingMode & StyleWritingMode::VERTICAL_LR ? BlockDir::LR + : BlockDir::RL; + } + return BlockDir::TB; } /** @@ -216,14 +188,14 @@ class WritingMode { } /** - * Return true if bidi direction is LTR. (Convenience method) + * Return true if bidi direction is LTR. */ - bool IsBidiLTR() const { return eBidiLTR == GetBidiDir(); } + bool IsBidiLTR() const { return !IsBidiRTL(); } /** - * Return true if bidi direction is RTL. (Convenience method) + * Return true if bidi direction is RTL. */ - bool IsBidiRTL() const { return eBidiRTL == GetBidiDir(); } + bool IsBidiRTL() const { return !!(mWritingMode & StyleWritingMode::RTL); } /** * True if it is vertical and vertical-lr, or is horizontal and bidi LTR. @@ -242,12 +214,12 @@ class WritingMode { /** * True if vertical-mode block direction is LR (convenience method). */ - bool IsVerticalLR() const { return eBlockLR == GetBlockDir(); } + bool IsVerticalLR() const { return GetBlockDir() == BlockDir::LR; } /** * True if vertical-mode block direction is RL (convenience method). */ - bool IsVerticalRL() const { return eBlockRL == GetBlockDir(); } + bool IsVerticalRL() const { return GetBlockDir() == BlockDir::RL; } /** * True if vertical writing mode, i.e. when @@ -339,8 +311,9 @@ class WritingMode { uint8_t(StyleWritingModeProperty::VerticalRl) == 1 && uint8_t(StyleWritingModeProperty::VerticalLr) == 3 && uint8_t(LogicalAxis::Block) == 0 && - uint8_t(LogicalAxis::Inline) == 1 && eAxisVertical == 0 && - eAxisHorizontal == 1, + uint8_t(LogicalAxis::Inline) == 1 && + uint8_t(PhysicalAxis::Vertical) == 0 && + uint8_t(PhysicalAxis::Horizontal) == 1, "unexpected writing-mode, logical axis or physical axis " "constant values"); return mozilla::PhysicalAxis((aWritingModeValue ^ uint8_t(aAxis)) & 0x1); @@ -376,7 +349,7 @@ class WritingMode { // What's left of the writing-mode should be in the range 0-3: NS_ASSERTION(aWritingModeValue < 4, "invalid aWritingModeValue value"); - return kLogicalBlockSides[aWritingModeValue][aEdge]; + return kLogicalBlockSides[aWritingModeValue][static_cast(aEdge)]; } mozilla::Side PhysicalSideForInlineAxis(LogicalEdge aEdge) const { @@ -413,13 +386,13 @@ class WritingMode { // StyleWritingMode::INLINE_REVERSED, StyleWritingMode::VERTICAL_LR and // StyleWritingMode::LINE_INVERTED bits. Use these four bits to index into // kLogicalInlineSides. - MOZ_ASSERT(StyleWritingMode::VERTICAL._0 == 0x01 && - StyleWritingMode::INLINE_REVERSED._0 == 0x02 && - StyleWritingMode::VERTICAL_LR._0 == 0x04 && - StyleWritingMode::LINE_INVERTED._0 == 0x08, - "unexpected mask values"); - int index = mWritingMode._0 & 0x0F; - return kLogicalInlineSides[index][aEdge]; + static_assert(StyleWritingMode::VERTICAL._0 == 0x01 && + StyleWritingMode::INLINE_REVERSED._0 == 0x02 && + StyleWritingMode::VERTICAL_LR._0 == 0x04 && + StyleWritingMode::LINE_INVERTED._0 == 0x08, + "Unexpected values for StyleWritingMode constants!"); + uint8_t index = mWritingMode._0 & 0x0F; + return kLogicalInlineSides[index][static_cast(aEdge)]; } /** @@ -428,9 +401,9 @@ class WritingMode { */ mozilla::Side PhysicalSide(LogicalSide aSide) const { if (IsBlock(aSide)) { - MOZ_ASSERT(StyleWritingMode::VERTICAL._0 == 0x01 && - StyleWritingMode::VERTICAL_LR._0 == 0x04, - "unexpected mask values"); + static_assert(StyleWritingMode::VERTICAL._0 == 0x01 && + StyleWritingMode::VERTICAL_LR._0 == 0x04, + "Unexpected values for StyleWritingMode constants!"); const uint8_t wm = ((mWritingMode & StyleWritingMode::VERTICAL_LR)._0 >> 1) | (mWritingMode & StyleWritingMode::VERTICAL)._0; @@ -490,12 +463,12 @@ class WritingMode { }; // clang-format on - MOZ_ASSERT(StyleWritingMode::VERTICAL._0 == 0x01 && - StyleWritingMode::INLINE_REVERSED._0 == 0x02 && - StyleWritingMode::VERTICAL_LR._0 == 0x04 && - StyleWritingMode::LINE_INVERTED._0 == 0x08, - "unexpected mask values"); - int index = mWritingMode._0 & 0x0F; + static_assert(StyleWritingMode::VERTICAL._0 == 0x01 && + StyleWritingMode::INLINE_REVERSED._0 == 0x02 && + StyleWritingMode::VERTICAL_LR._0 == 0x04 && + StyleWritingMode::LINE_INVERTED._0 == 0x08, + "Unexpected values for StyleWritingMode constants!"); + uint8_t index = mWritingMode._0 & 0x0F; return kPhysicalToLogicalSides[index][aSide]; } @@ -580,7 +553,7 @@ class WritingMode { bool ParallelAxisStartsOnSameSide(LogicalAxis aLogicalAxis, const WritingMode& aOther) const { mozilla::Side myStartSide = - this->PhysicalSide(MakeLogicalSide(aLogicalAxis, eLogicalEdgeStart)); + this->PhysicalSide(MakeLogicalSide(aLogicalAxis, LogicalEdge::Start)); // Figure out which of aOther's axes is parallel to |this| WritingMode's // aLogicalAxis, and get its physical start side as well. @@ -588,7 +561,7 @@ class WritingMode { ? GetOrthogonalAxis(aLogicalAxis) : aLogicalAxis; mozilla::Side otherWMStartSide = - aOther.PhysicalSide(MakeLogicalSide(otherWMAxis, eLogicalEdgeStart)); + aOther.PhysicalSide(MakeLogicalSide(otherWMAxis, LogicalEdge::Start)); NS_ASSERTION(myStartSide % 2 == otherWMStartSide % 2, "Should end up with sides in the same physical axis"); @@ -610,11 +583,16 @@ class WritingMode { // instance from it. friend struct widget::IMENotification; + /** + * Unknown writing mode (should never actually be stored or used anywhere). + */ + static constexpr uint8_t kUnknownWritingMode = 0xff; + /** * Return a WritingMode representing an unknown value. */ static inline WritingMode Unknown() { - return WritingMode(eUnknownWritingMode); + return WritingMode(kUnknownWritingMode); } /** @@ -624,12 +602,6 @@ class WritingMode { explicit WritingMode(uint8_t aValue) : mWritingMode{aValue} {} StyleWritingMode mWritingMode; - - enum Masks { - // Masks for output enums - eInlineMask = 0x03, // VERTICAL | INLINE_REVERSED - eBlockMask = 0x05, // VERTICAL | VERTICAL_LR - }; }; inline std::ostream& operator<<(std::ostream& aStream, const WritingMode& aWM) { @@ -818,7 +790,7 @@ class LogicalPoint { LogicalPoint operator+(const LogicalPoint& aOther) const { CHECK_WRITING_MODE(aOther.GetWritingMode()); // In non-debug builds, LogicalPoint does not store the WritingMode, - // so the first parameter here (which will always be eUnknownWritingMode) + // so the first parameter here (which will always be WritingMode::Unknown()) // is ignored. return LogicalPoint(GetWritingMode(), mPoint.x + aOther.mPoint.x, mPoint.y + aOther.mPoint.y); @@ -834,7 +806,7 @@ class LogicalPoint { LogicalPoint operator-(const LogicalPoint& aOther) const { CHECK_WRITING_MODE(aOther.GetWritingMode()); // In non-debug builds, LogicalPoint does not store the WritingMode, - // so the first parameter here (which will always be eUnknownWritingMode) + // so the first parameter here (which will always be WritingMode::Unknown()) // is ignored. return LogicalPoint(GetWritingMode(), mPoint.x - aOther.mPoint.x, mPoint.y - aOther.mPoint.y); @@ -857,7 +829,7 @@ class LogicalPoint { /** * NOTE that in non-DEBUG builds, GetWritingMode() always returns - * eUnknownWritingMode, as the current mode is not stored in the logical- + * WritingMode::Unknown(), as the current mode is not stored in the logical- * geometry classes. Therefore, this method is private; it is used ONLY * by the DEBUG-mode checking macros in this class and its friends; * other code is not allowed to ask a logical point for its writing mode, @@ -1107,48 +1079,51 @@ class LogicalSize { * LogicalSides represents a set of logical sides. */ struct LogicalSides final { + static constexpr EnumSet BBoth{LogicalSide::BStart, + LogicalSide::BEnd}; + static constexpr EnumSet IBoth{LogicalSide::IStart, + LogicalSide::IEnd}; + static constexpr EnumSet All{ + LogicalSide::BStart, LogicalSide::BEnd, LogicalSide::IStart, + LogicalSide::IEnd}; + explicit LogicalSides(WritingMode aWritingMode) +#ifdef DEBUG + : mWritingMode(aWritingMode) +#endif + { + } + LogicalSides(WritingMode aWritingMode, LogicalSides aSides) : #ifdef DEBUG mWritingMode(aWritingMode), #endif - mBits(0) { + mSides(aSides.mSides) { } - LogicalSides(WritingMode aWritingMode, LogicalSideBits aSideBits) + LogicalSides(WritingMode aWritingMode, EnumSet aSides) : #ifdef DEBUG mWritingMode(aWritingMode), #endif - mBits(aSideBits) { - MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits"); - } - bool IsEmpty() const { return mBits == 0; } - bool BStart() const { return mBits & eLogicalSideBitsBStart; } - bool BEnd() const { return mBits & eLogicalSideBitsBEnd; } - bool IStart() const { return mBits & eLogicalSideBitsIStart; } - bool IEnd() const { return mBits & eLogicalSideBitsIEnd; } - bool Contains(LogicalSideBits aSideBits) const { - MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits"); - return (mBits & aSideBits) == aSideBits; - } - LogicalSides operator|(LogicalSides aOther) const { - CHECK_WRITING_MODE(aOther.GetWritingMode()); - return *this | LogicalSideBits(aOther.mBits); - } - LogicalSides operator|(LogicalSideBits aSideBits) const { - return LogicalSides(GetWritingMode(), LogicalSideBits(mBits | aSideBits)); - } - LogicalSides& operator|=(LogicalSides aOther) { - CHECK_WRITING_MODE(aOther.GetWritingMode()); - return *this |= LogicalSideBits(aOther.mBits); + mSides(aSides) { + } + bool IsEmpty() const { return mSides.isEmpty(); } + bool BStart() const { return mSides.contains(LogicalSide::BStart); } + bool BEnd() const { return mSides.contains(LogicalSide::BEnd); } + bool IStart() const { return mSides.contains(LogicalSide::IStart); } + bool IEnd() const { return mSides.contains(LogicalSide::IEnd); } + bool Contains(LogicalSide aSide) const { return mSides.contains(aSide); } + LogicalSides& operator+=(LogicalSides aOther) { + mSides += aOther.mSides; + return *this; } - LogicalSides& operator|=(LogicalSideBits aSideBits) { - mBits |= aSideBits; + LogicalSides& operator+=(LogicalSide aOther) { + mSides += aOther; return *this; } bool operator==(LogicalSides aOther) const { CHECK_WRITING_MODE(aOther.GetWritingMode()); - return mBits == aOther.mBits; + return mSides == aOther.mSides; } bool operator!=(LogicalSides aOther) const { CHECK_WRITING_MODE(aOther.GetWritingMode()); @@ -1165,7 +1140,7 @@ struct LogicalSides final { #ifdef DEBUG WritingMode mWritingMode; #endif - uint8_t mBits; + EnumSet mSides; }; /** diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 2aea090a6f..9044b12f8d 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -394,7 +394,7 @@ load 571618-1.svg asserts(0-1) load 571975-1.html # bug 574889 load 571995.xhtml load 574958.xhtml -asserts(0-6) load 578977.html # bug 757305 +asserts(0-8) load 578977.html # bug 757305 load 580504-1.xhtml load 582793-1.html load 585598-1.xhtml @@ -622,8 +622,8 @@ load flex-nested-abspos-1.html pref(dom.meta-viewport.enabled,true) test-pref(font.size.inflation.emPerLine,15) asserts(0-100) load font-inflation-762332.html # bug 762332 asserts-if(Android||cocoaWidget,0-2) load outline-on-frameset.xhtml # bug 762332, bug 1594135 load summary-position-out-of-flow.html -pref(widget.windows.window_occlusion_tracking.enabled,false) load text-overflow-bug666751-1.html # Bug 1819154 -pref(widget.windows.window_occlusion_tracking.enabled,false) load text-overflow-bug666751-2.html # Bug 1819154 +load text-overflow-bug666751-1.html +load text-overflow-bug666751-2.html load text-overflow-bug670564.xhtml load text-overflow-bug671796.xhtml load text-overflow-bug713610.html diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp index 4f561688bf..5afd9f33f2 100644 --- a/layout/generic/nsAbsoluteContainingBlock.cpp +++ b/layout/generic/nsAbsoluteContainingBlock.cpp @@ -372,8 +372,8 @@ bool nsAbsoluteContainingBlock::FrameDependsOnContainer(nsIFrame* f, // and be positioned relative to the containing block right edge. // 'left' length and 'right' auto is the only combination we can be // sure of. - if ((wm.GetInlineDir() == WritingMode::eInlineRTL || - wm.GetBlockDir() == WritingMode::eBlockRL) && + if ((wm.GetInlineDir() == WritingMode::InlineDir::RTL || + wm.GetBlockDir() == WritingMode::BlockDir::RL) && !pos->mOffset.Get(eSideRight).IsAuto()) { return true; } @@ -383,7 +383,7 @@ bool nsAbsoluteContainingBlock::FrameDependsOnContainer(nsIFrame* f, return true; } // See comment above for width changes. - if (wm.GetInlineDir() == WritingMode::eInlineBTT && + if (wm.GetInlineDir() == WritingMode::InlineDir::BTT && !pos->mOffset.Get(eSideBottom).IsAuto()) { return true; } diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 4582c29e0b..4b314bfcaf 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -1186,7 +1186,8 @@ static bool IsLineClampRoot(const nsBlockFrame* aFrame) { return false; } - if (StaticPrefs::layout_css_webkit_line_clamp_block_enabled()) { + if (StaticPrefs::layout_css_webkit_line_clamp_block_enabled() || + aFrame->PresContext()->Document()->ChromeRulesEnabled()) { return true; } @@ -7979,7 +7980,7 @@ bool nsBlockFrame::MarkerIsEmpty() const { const nsStyleList* list = marker->StyleList(); return marker->StyleContent()->mContent.IsNone() || (list->mCounterStyle.IsNone() && list->mListStyleImage.IsNone() && - marker->StyleContent()->ContentCount() == 0); + marker->StyleContent()->NonAltContentItems().IsEmpty()); } void nsBlockFrame::ReflowOutsideMarker(nsIFrame* aMarkerFrame, diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index b4b108905f..36b579ed60 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -546,6 +546,8 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, layers.mImageCount > 0 && layers.mLayers[0].mAttachment == StyleImageLayerAttachment::Fixed; + nsDisplayList list(aBuilder); + if (!hasFixedBottomLayer || needBlendContainer) { // Put a scrolled background color item in place, at the bottom of the // list. The color of this item will be filled in during @@ -557,20 +559,18 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // interleaving the two with a scrolled background color. // PresShell::AddCanvasBackgroundColorItem makes sure there always is a // non-scrolled background color item at the bottom. - aLists.BorderBackground()->AppendNewToTop( - aBuilder, this); + list.AppendNewToTop(aBuilder, this); } - aLists.BorderBackground()->AppendToTop(&layerItems); + list.AppendToTop(&layerItems); if (needBlendContainer) { const ActiveScrolledRoot* containerASR = contASRTracker.GetContainerASR(); DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder); - aLists.BorderBackground()->AppendToTop( - nsDisplayBlendContainer::CreateForBackgroundBlendMode( - aBuilder, this, nullptr, aLists.BorderBackground(), - containerASR)); + list.AppendToTop(nsDisplayBlendContainer::CreateForBackgroundBlendMode( + aBuilder, this, nullptr, &list, containerASR)); } + aLists.BorderBackground()->AppendToTop(&list); } for (nsIFrame* kid : PrincipalChildList()) { diff --git a/layout/generic/nsColumnSetFrame.cpp b/layout/generic/nsColumnSetFrame.cpp index a9d3e28138..d78a5cb992 100644 --- a/layout/generic/nsColumnSetFrame.cpp +++ b/layout/generic/nsColumnSetFrame.cpp @@ -570,17 +570,17 @@ nsColumnSetFrame::ColumnBalanceData nsColumnSetFrame::ReflowColumns( // this is a calculation that affects layout. if (!reflowChild && shrinkingBSize) { switch (wm.GetBlockDir()) { - case WritingMode::eBlockTB: + case WritingMode::BlockDir::TB: if (child->ScrollableOverflowRect().YMost() > aConfig.mColBSize) { reflowChild = true; } break; - case WritingMode::eBlockLR: + case WritingMode::BlockDir::LR: if (child->ScrollableOverflowRect().XMost() > aConfig.mColBSize) { reflowChild = true; } break; - case WritingMode::eBlockRL: + case WritingMode::BlockDir::RL: // XXX not sure how to handle this, so for now just don't attempt // the optimization reflowChild = true; diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 2c9e707830..3cebfae2e7 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -780,7 +780,7 @@ void nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext, if (!(aFlags & ReflowChildFlags::NoSizeView)) { nsViewManager* vm = aView->GetViewManager(); - vm->ResizeView(aView, aInkOverflowArea, true); + vm->ResizeView(aView, aInkOverflowArea); } } diff --git a/layout/generic/nsContainerFrameInlines.h b/layout/generic/nsContainerFrameInlines.h index f6c85d791e..bc544fa6f8 100644 --- a/layout/generic/nsContainerFrameInlines.h +++ b/layout/generic/nsContainerFrameInlines.h @@ -21,8 +21,8 @@ void nsContainerFrame::DoInlineIntrinsicISize(ISizeData* aData, if (GetPrevInFlow()) return; // Already added. WritingMode wm = GetWritingMode(); - Side startSide = wm.PhysicalSideForInlineAxis(eLogicalEdgeStart); - Side endSide = wm.PhysicalSideForInlineAxis(eLogicalEdgeEnd); + Side startSide = wm.PhysicalSideForInlineAxis(LogicalEdge::Start); + Side endSide = wm.PhysicalSideForInlineAxis(LogicalEdge::End); const nsStylePadding* stylePadding = StylePadding(); const nsStyleBorder* styleBorder = StyleBorder(); diff --git a/layout/generic/nsFirstLetterFrame.cpp b/layout/generic/nsFirstLetterFrame.cpp index 28d1b08a30..c08950121a 100644 --- a/layout/generic/nsFirstLetterFrame.cpp +++ b/layout/generic/nsFirstLetterFrame.cpp @@ -447,12 +447,12 @@ Maybe nsFirstLetterFrame::GetNaturalBaselineBOffset( LogicalSides nsFirstLetterFrame::GetLogicalSkipSides() const { if (GetPrevContinuation()) { - // We shouldn't get calls to GetSkipSides for later continuations since - // they have separate ComputedStyles with initial values for all the - // properties that could trigger a call to GetSkipSides. Then again, - // it's not really an error to call GetSkipSides on any frame, so + // We shouldn't get calls to GetLogicalSkipSides for later continuations + // since they have separate ComputedStyles with initial values for all the + // properties that could trigger a call to GetLogicalSkipSides. Then again, + // it's not really an error to call GetLogicalSkipSides on any frame, so // that's why we handle it properly. - return LogicalSides(mWritingMode, eLogicalSideBitsAll); + return LogicalSides(mWritingMode, LogicalSides::All); } return LogicalSides(mWritingMode); // first continuation displays all sides } diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 66f1e79609..4604106a4a 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -312,7 +312,7 @@ class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker { return StyleAlignFlags::START; } - MOZ_ASSERT(wm.PhysicalAxis(MainAxis()) == eAxisHorizontal, + MOZ_ASSERT(wm.PhysicalAxis(MainAxis()) == PhysicalAxis::Horizontal, "Vertical column-oriented flex container's main axis should " "be parallel to physical left <-> right axis!"); // Map 'left' or 'right' to 'start' or 'end', depending on its block flow @@ -2021,7 +2021,7 @@ const CachedBAxisMeasurement& nsFlexContainerFrame::MeasureBSizeForFlexItem( // CachedFlexItemData is stored in item's writing mode, so we pass // aChildReflowInput into ReflowOutput's constructor. ReflowOutput childReflowOutput(aChildReflowInput); - nsReflowStatus childReflowStatus; + nsReflowStatus childStatus; const ReflowChildFlags flags = ReflowChildFlags::NoMoveFrame; const WritingMode outerWM = GetWritingMode(); @@ -2032,12 +2032,12 @@ const CachedBAxisMeasurement& nsFlexContainerFrame::MeasureBSizeForFlexItem( // unimportant. ReflowChild(aItem.Frame(), PresContext(), childReflowOutput, aChildReflowInput, outerWM, dummyPosition, dummyContainerSize, - flags, childReflowStatus); + flags, childStatus); aItem.SetHadMeasuringReflow(); // We always use unconstrained available block-size to measure flex items, // which means they should always complete. - MOZ_ASSERT(childReflowStatus.IsComplete(), + MOZ_ASSERT(childStatus.IsComplete(), "We gave flex item unconstrained available block-size, so it " "should be complete"); @@ -2227,7 +2227,7 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput, float aFlexGrow, // (We'll resolve them later; until then, we want to treat them as 0-sized.) #ifdef DEBUG { - for (const auto side : AllLogicalSides()) { + for (const auto side : LogicalSides::All) { if (styleMargin->mMargin.Get(mCBWM, side).IsAuto()) { MOZ_ASSERT(GetMarginComponentForSide(side) == 0, "Someone else tried to resolve our auto margin"); @@ -2257,7 +2257,7 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput, float aFlexGrow, // (Note: this is *not* the "flex-start" side; rather, it's the *logical* // i.e. WM-relative block-start or inline-start side.) mozilla::Side containerStartSideInCrossAxis = mCBWM.PhysicalSide( - MakeLogicalSide(aAxisTracker.CrossAxis(), eLogicalEdgeStart)); + MakeLogicalSide(aAxisTracker.CrossAxis(), LogicalEdge::Start)); // We already know these two Sides (the item's block-start and the // container's 'logical start' side for its cross axis) are in the same @@ -2354,7 +2354,7 @@ nscoord FlexItem::BaselineOffsetFromOuterCrossEdge( // column-oriented flex container. We need to synthesize the item's baseline // from its border-box edge. const bool isMainAxisHorizontal = - mCBWM.PhysicalAxis(MainAxis()) == mozilla::eAxisHorizontal; + mCBWM.PhysicalAxis(MainAxis()) == PhysicalAxis::Horizontal; // When the main axis is horizontal, the synthesized baseline is the bottom // edge of the item's border-box. Otherwise, when the main axis is vertical, @@ -2448,7 +2448,7 @@ void FlexItem::ResolveFlexBaseSizeFromAspectRatio( uint32_t FlexItem::NumAutoMarginsInAxis(LogicalAxis aAxis) const { uint32_t numAutoMargins = 0; const auto& styleMargin = mFrame->StyleMargin()->mMargin; - for (const auto edge : {eLogicalEdgeStart, eLogicalEdgeEnd}) { + for (const auto edge : {LogicalEdge::Start, LogicalEdge::End}) { const auto side = MakeLogicalSide(aAxis, edge); if (styleMargin.Get(mCBWM, side).IsAuto()) { numAutoMargins++; @@ -2708,12 +2708,12 @@ class MOZ_STACK_CLASS PositionTracker { inline LogicalSide StartSide() { return MakeLogicalSide( - mAxis, mIsAxisReversed ? eLogicalEdgeEnd : eLogicalEdgeStart); + mAxis, mIsAxisReversed ? LogicalEdge::End : LogicalEdge::Start); } inline LogicalSide EndSide() { return MakeLogicalSide( - mAxis, mIsAxisReversed ? eLogicalEdgeStart : eLogicalEdgeEnd); + mAxis, mIsAxisReversed ? LogicalEdge::Start : LogicalEdge::End); } // Advances our position across the start edge of the given margin, in the @@ -4111,12 +4111,13 @@ FlexboxAxisTracker::FlexboxAxisTracker( LogicalSide FlexboxAxisTracker::MainAxisStartSide() const { return MakeLogicalSide( - MainAxis(), IsMainAxisReversed() ? eLogicalEdgeEnd : eLogicalEdgeStart); + MainAxis(), IsMainAxisReversed() ? LogicalEdge::End : LogicalEdge::Start); } LogicalSide FlexboxAxisTracker::CrossAxisStartSide() const { - return MakeLogicalSide( - CrossAxis(), IsCrossAxisReversed() ? eLogicalEdgeEnd : eLogicalEdgeStart); + return MakeLogicalSide(CrossAxis(), IsCrossAxisReversed() + ? LogicalEdge::End + : LogicalEdge::Start); } void nsFlexContainerFrame::GenerateFlexLines( @@ -4885,8 +4886,14 @@ void nsFlexContainerFrame::UnionInFlowChildOverflow( bool anyScrolledContentItem = false; // Union of normal-positioned margin boxes for all the items. nsRect itemMarginBoxes; - // Union of relative-positioned margin boxes for the relpos items only. - nsRect relPosItemMarginBoxes; + // Overflow areas containing the union of relative-positioned and + // stick-positioned margin boxes of relpos items. + // + // Note for sticky-positioned margin boxes, we only union it with the ink + // overflow to avoid circular dependencies with the scroll container. (The + // scroll position and the scroll container's size impact the sticky position, + // so we don't want the sticky position to impact them.) + OverflowAreas relPosItemMarginBoxes; const bool useMozBoxCollapseBehavior = StyleVisibility()->UseLegacyCollapseBehavior(); for (nsIFrame* f : mFrames) { @@ -4905,8 +4912,13 @@ void nsFlexContainerFrame::UnionInFlowChildOverflow( const nsRect marginRect = f->GetMarginRectRelativeToSelf(); itemMarginBoxes = itemMarginBoxes.Union(marginRect + f->GetNormalPosition()); - relPosItemMarginBoxes = - relPosItemMarginBoxes.Union(marginRect + f->GetPosition()); + if (f->IsRelativelyPositioned()) { + relPosItemMarginBoxes.UnionAllWith(marginRect + f->GetPosition()); + } else { + MOZ_ASSERT(f->IsStickyPositioned()); + relPosItemMarginBoxes.UnionWith( + OverflowAreas(marginRect + f->GetPosition(), nsRect())); + } } else { itemMarginBoxes = itemMarginBoxes.Union(f->GetMarginRect()); } @@ -4915,7 +4927,7 @@ void nsFlexContainerFrame::UnionInFlowChildOverflow( if (anyScrolledContentItem) { itemMarginBoxes.Inflate(GetUsedPadding()); aOverflowAreas.UnionAllWith(itemMarginBoxes); - aOverflowAreas.UnionAllWith(relPosItemMarginBoxes); + aOverflowAreas.UnionWith(relPosItemMarginBoxes); } } @@ -5515,14 +5527,19 @@ std::tuple nsFlexContainerFrame::ReflowChildren( const bool isSingleLine = StyleFlexWrap::Nowrap == aReflowInput.mStylePosition->mFlexWrap; - - // FINAL REFLOW: Give each child frame another chance to reflow, now that - // we know its final size and position. const FlexLine& startmostLine = StartmostLine(aFlr.mLines, aAxisTracker); + const FlexLine& endmostLine = EndmostLine(aFlr.mLines, aAxisTracker); const FlexItem* startmostItem = startmostLine.IsEmpty() ? nullptr : &startmostLine.StartmostItem(aAxisTracker); + const FlexItem* endmostItem = + endmostLine.IsEmpty() ? nullptr : &endmostLine.EndmostItem(aAxisTracker); + + bool endmostItemOrLineHasBreakAfter = false; + // If true, push all remaining flex items to the container's next-in-flow. + bool shouldPushRemainingItems = false; + // FINAL REFLOW: Give each child frame another chance to reflow. const size_t numLines = aFlr.mLines.Length(); for (size_t lineIdx = 0; lineIdx < numLines; ++lineIdx) { // Iterate flex lines from the startmost to endmost (relative to flex @@ -5533,6 +5550,11 @@ std::tuple nsFlexContainerFrame::ReflowChildren( MOZ_ASSERT(lineIdx != 0 || &line == &startmostLine, "Logic for finding startmost line should be consistent!"); + // These two variables can be set when we are a row-oriented flex container + // during fragmentation. + bool lineHasBreakBefore = false; + bool lineHasBreakAfter = false; + const size_t numItems = line.Items().Length(); for (size_t itemIdx = 0; itemIdx < numItems; ++itemIdx) { // Iterate flex items from the startmost to endmost (relative to flex @@ -5631,15 +5653,22 @@ std::tuple nsFlexContainerFrame::ReflowChildren( // (i.e. its frame rect), instead of the container's content-box: framePos += containerContentBoxOrigin; - // Check if we actually need to reflow the item -- if the item's position - // is below the available space's block-end, push it to our next-in-flow; - // if it does need a reflow, and we already reflowed it with the right - // content-box size. - const bool childBPosExceedAvailableSpaceBEnd = - availableBSizeForItem != NS_UNCONSTRAINEDSIZE && - availableBSizeForItem <= 0; + // Check if we can skip reflowing the item because it will be pushed to + // our next-in-flow -- i.e. if there was a forced break before it, or its + // position is beyond the available space's block-end. bool itemInPushedItems = false; - if (childBPosExceedAvailableSpaceBEnd) { + if (shouldPushRemainingItems) { + FLEX_ITEM_LOG( + item.Frame(), + "[frag] Item needed to be pushed to container's next-in-flow due " + "to a forced break before it"); + pushedItems.Insert(item.Frame()); + itemInPushedItems = true; + } else if (availableBSizeForItem != NS_UNCONSTRAINEDSIZE && + availableBSizeForItem <= 0) { + // The item's position is beyond the available space, so we have to push + // it. + // // Note: Even if all of our items are beyond the available space & get // pushed here, we'll be guaranteed to place at least one of them (and // make progress) in one of the flex container's *next* fragment. It's @@ -5662,17 +5691,50 @@ std::tuple nsFlexContainerFrame::ReflowChildren( availableBSizeForItem) .ConvertTo(itemWM, flexWM); - const nsReflowStatus childReflowStatus = + const bool isAdjacentWithBStart = + framePos.B(flexWM) == containerContentBoxOrigin.B(flexWM); + const nsReflowStatus childStatus = ReflowFlexItem(aAxisTracker, aReflowInput, item, framePos, - availableSize, aContainerSize); + isAdjacentWithBStart, availableSize, aContainerSize); + + if (aReflowInput.IsInFragmentedContext()) { + const bool itemHasBreakBefore = + item.Frame()->ShouldBreakBefore(aReflowInput.mBreakType) || + childStatus.IsInlineBreakBefore(); + if (itemHasBreakBefore) { + if (aAxisTracker.IsRowOriented()) { + lineHasBreakBefore = true; + } else if (isSingleLine) { + if (&item == startmostItem) { + if (!GetPrevInFlow() && !aReflowInput.mFlags.mIsTopOfPage) { + // If we are first-in-flow and not at top-of-page, early + // return here to propagate forced break-before from the + // startmost item to the flex container. + nsReflowStatus childrenStatus; + childrenStatus.SetInlineLineBreakBeforeAndReset(); + return {0, childrenStatus}; + } + } else { + shouldPushRemainingItems = true; + } + } else { + // Bug 1806717: We haven't implemented fragmentation for + // multi-line column-oriented flex container, so we just ignore + // forced breaks for now. + } + } + } const bool shouldPushItem = [&]() { + if (shouldPushRemainingItems) { + return true; + } if (availableBSizeForItem == NS_UNCONSTRAINEDSIZE) { // If the available block-size is unconstrained, then we're not // fragmenting and we don't want to push the item. return false; } - if (framePos.B(flexWM) == containerContentBoxOrigin.B(flexWM)) { + if (isAdjacentWithBStart) { // The flex item is adjacent with block-start of the container's // content-box. Don't push it, or we'll trap in an infinite loop. return false; @@ -5691,15 +5753,38 @@ std::tuple nsFlexContainerFrame::ReflowChildren( FLEX_ITEM_LOG( item.Frame(), "[frag] Item needed to be pushed to container's next-in-flow " - "because its block-size is larger than the available space"); + "because it encounters a forced break before it, or its " + "block-size is larger than the available space"); pushedItems.Insert(item.Frame()); itemInPushedItems = true; - } else if (childReflowStatus.IsIncomplete()) { + } else if (childStatus.IsIncomplete()) { incompleteItems.Insert(item.Frame()); - } else if (childReflowStatus.IsOverflowIncomplete()) { + } else if (childStatus.IsOverflowIncomplete()) { overflowIncompleteItems.Insert(item.Frame()); } + + if (aReflowInput.IsInFragmentedContext()) { + const bool itemHasBreakAfter = + item.Frame()->ShouldBreakAfter(aReflowInput.mBreakType) || + childStatus.IsInlineBreakAfter(); + if (itemHasBreakAfter) { + if (aAxisTracker.IsRowOriented()) { + lineHasBreakAfter = true; + } else if (isSingleLine) { + shouldPushRemainingItems = true; + if (&item == endmostItem) { + endmostItemOrLineHasBreakAfter = true; + } + } else { + // Bug 1806717: We haven't implemented fragmentation for + // multi-line column-oriented flex container, so we just ignore + // forced breaks for now. + } + } + } } else { + // We already reflowed the item with the right content-box size, so we + // can simply move it into place. MoveFlexItemToFinalPosition(item, framePos, aContainerSize); } @@ -5787,6 +5872,37 @@ std::tuple nsFlexContainerFrame::ReflowChildren( } } + if (aReflowInput.IsInFragmentedContext() && aAxisTracker.IsRowOriented()) { + // Propagate forced break values from the flex items to its flex line. + if (lineHasBreakBefore) { + if (&line == &startmostLine) { + if (!GetPrevInFlow() && !aReflowInput.mFlags.mIsTopOfPage) { + // If we are first-in-flow and not at top-of-page, early return here + // to propagate forced break-before from the startmost line to the + // flex container. + nsReflowStatus childrenStatus; + childrenStatus.SetInlineLineBreakBeforeAndReset(); + return {0, childrenStatus}; + } + } else { + // Current non-startmost line has forced break-before, so push all the + // items in this line. + for (const FlexItem& item : line.Items()) { + pushedItems.Insert(item.Frame()); + incompleteItems.Remove(item.Frame()); + overflowIncompleteItems.Remove(item.Frame()); + } + shouldPushRemainingItems = true; + } + } + if (lineHasBreakAfter) { + shouldPushRemainingItems = true; + if (&line == &endmostLine) { + endmostItemOrLineHasBreakAfter = true; + } + } + } + // Now we've finished processing all the items in the startmost line. // Determine the amount by which the startmost line's block-end edge has // shifted, so we can apply the same shift for the remaining lines. @@ -5808,6 +5924,8 @@ std::tuple nsFlexContainerFrame::ReflowChildren( childrenStatus.SetIncomplete(); } else if (!overflowIncompleteItems.IsEmpty()) { childrenStatus.SetOverflowIncomplete(); + } else if (endmostItemOrLineHasBreakAfter) { + childrenStatus.SetInlineLineBreakAfter(); } PushIncompleteChildren(pushedItems, incompleteItems, overflowIncompleteItems); @@ -5952,6 +6070,14 @@ void nsFlexContainerFrame::PopulateReflowOutput( return; } + // Propagate forced break values from flex items or flex lines. + if (aChildrenStatus.IsInlineBreakBefore()) { + aStatus.SetInlineLineBreakBeforeAndReset(); + } + if (aChildrenStatus.IsInlineBreakAfter()) { + aStatus.SetInlineLineBreakAfter(); + } + // If we haven't established a baseline for the container yet, i.e. if we // don't have any flex item in the startmost flex line that participates in // baseline alignment, then use the startmost flex item to derive the @@ -6067,7 +6193,8 @@ void nsFlexContainerFrame::MoveFlexItemToFinalPosition( nsReflowStatus nsFlexContainerFrame::ReflowFlexItem( const FlexboxAxisTracker& aAxisTracker, const ReflowInput& aReflowInput, const FlexItem& aItem, const LogicalPoint& aFramePos, - const LogicalSize& aAvailableSize, const nsSize& aContainerSize) { + const bool aIsAdjacentWithBStart, const LogicalSize& aAvailableSize, + const nsSize& aContainerSize) { FLEX_ITEM_LOG(aItem.Frame(), "Doing final reflow"); // Returns true if we should use 'auto' in block axis's StyleSizeOverrides to @@ -6206,6 +6333,13 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem( aItem.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE); } + if (!aIsAdjacentWithBStart) { + // mIsTopOfPage bit in childReflowInput is carried over from aReflowInput. + // However, if this item's position is not adjacent with the flex + // container's content-box block-start edge, we should clear it. + childReflowInput.mFlags.mIsTopOfPage = false; + } + // NOTE: Be very careful about doing anything else with childReflowInput // after this point, because some of its methods (e.g. SetComputedWidth) // internally call InitResizeFlags and stomp on mVResize & mHResize. @@ -6216,11 +6350,11 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem( // CachedFlexItemData is stored in item's writing mode, so we pass // aChildReflowInput into ReflowOutput's constructor. ReflowOutput childReflowOutput(childReflowInput); - nsReflowStatus childReflowStatus; + nsReflowStatus childStatus; WritingMode outerWM = aReflowInput.GetWritingMode(); ReflowChild(aItem.Frame(), PresContext(), childReflowOutput, childReflowInput, outerWM, aFramePos, aContainerSize, ReflowChildFlags::Default, - childReflowStatus); + childStatus); // XXXdholbert Perhaps we should call CheckForInterrupt here; see bug 1495532. @@ -6240,7 +6374,7 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem( aItem.Frame()->SetProperty(CachedFlexItemData::Prop(), cached); } - return childReflowStatus; + return childStatus; } void nsFlexContainerFrame::ReflowPlaceholders( @@ -6260,10 +6394,10 @@ void nsFlexContainerFrame::ReflowPlaceholders( // No need to set the -webkit-line-clamp related flags when reflowing // a placeholder. ReflowOutput childReflowOutput(outerWM); - nsReflowStatus childReflowStatus; + nsReflowStatus childStatus; ReflowChild(placeholder, PresContext(), childReflowOutput, childReflowInput, outerWM, aContentBoxOrigin, aContainerSize, - ReflowChildFlags::Default, childReflowStatus); + ReflowChildFlags::Default, childStatus); FinishReflowChild(placeholder, PresContext(), childReflowOutput, &childReflowInput, outerWM, aContentBoxOrigin, diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index 14f91ae064..2771098255 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -604,6 +604,8 @@ class nsFlexContainerFrame final : public nsContainerFrame, * @param aItem The flex item to be reflowed. * @param aFramePos The position where the flex item's frame should * be placed. (pre-relative positioning) + * @param aIsAdjacentWithBStart True if aFramePos is adjacent with the flex + * container's content-box block-start edge. * @param aAvailableSize The available size to reflow the child frame (in the * child frame's writing-mode). * @param aContainerSize The flex container's size (required by some methods @@ -614,6 +616,7 @@ class nsFlexContainerFrame final : public nsContainerFrame, const ReflowInput& aReflowInput, const FlexItem& aItem, const mozilla::LogicalPoint& aFramePos, + const bool aIsAdjacentWithBStart, const mozilla::LogicalSize& aAvailableSize, const nsSize& aContainerSize); diff --git a/layout/generic/nsFloatManager.cpp b/layout/generic/nsFloatManager.cpp index e1866b35c1..88a8b20b4c 100644 --- a/layout/generic/nsFloatManager.cpp +++ b/layout/generic/nsFloatManager.cpp @@ -2834,8 +2834,8 @@ nsFloatManager::ShapeInfo::ConvertToFloatLogical(const nscoord aRadii[8], // Get the physical side for line-left and line-right since border radii // are on the physical axis. - Side lineLeftSide = - aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft)); + Side lineLeftSide = aWM.PhysicalSide( + aWM.LogicalSideForLineRelativeDir(LineRelativeDir::Left)); logicalRadii[eCornerTopLeftX] = aRadii[SideToHalfCorner(lineLeftSide, true, false)]; logicalRadii[eCornerTopLeftY] = @@ -2846,7 +2846,7 @@ nsFloatManager::ShapeInfo::ConvertToFloatLogical(const nscoord aRadii[8], aRadii[SideToHalfCorner(lineLeftSide, false, true)]; Side lineRightSide = aWM.PhysicalSide( - aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight)); + aWM.LogicalSideForLineRelativeDir(LineRelativeDir::Right)); logicalRadii[eCornerTopRightX] = aRadii[SideToHalfCorner(lineRightSide, false, false)]; logicalRadii[eCornerTopRightY] = diff --git a/layout/generic/nsFrameSelection.cpp b/layout/generic/nsFrameSelection.cpp index ca4e3d647e..94cf368480 100644 --- a/layout/generic/nsFrameSelection.cpp +++ b/layout/generic/nsFrameSelection.cpp @@ -1441,11 +1441,6 @@ nsresult nsFrameSelection::TakeFocus(nsIContent& aNewFocus, } } - // Don't notify selection listeners if batching is on: - if (IsBatching()) { - return NS_OK; - } - // Be aware, the Selection instance may be destroyed after this call. return NotifySelectionListeners(SelectionType::eNormal); } diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 2b0c53efe1..97e6b614dc 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -964,7 +964,7 @@ void nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowInput& aState, nsRect childScrollableOverflow = childOverflow.ScrollableOverflow(); const LogicalMargin inlinePadding = - padding.ApplySkipSides(LogicalSides(wm, eLogicalSideBitsBBoth)); + padding.ApplySkipSides(LogicalSides(wm, LogicalSides::BBoth)); childScrollableOverflow.Inflate(inlinePadding.GetPhysicalMargin(wm)); nsRect& so = aMetrics->ScrollableOverflow(); @@ -5211,15 +5211,19 @@ nsSize nsHTMLScrollFrame::GetPageScrollAmount() const { } nsSize lineScrollAmount = GetLineScrollAmount(); - - // The page increment is the size of the page, minus the smaller of - // 10% of the size or 2 lines. - return nsSize(effectiveScrollPortSize.width - - std::min(effectiveScrollPortSize.width / 10, - 2 * lineScrollAmount.width), - effectiveScrollPortSize.height - - std::min(effectiveScrollPortSize.height / 10, - 2 * lineScrollAmount.height)); + const int32_t maxOverlapPercent = std::clamp( + StaticPrefs::toolkit_scrollbox_pagescroll_maxOverlapPercent(), 0, 80); + const int32_t maxOverlapLines = + std::max(StaticPrefs::toolkit_scrollbox_pagescroll_maxOverlapLines(), 0); + + // The page increment is the size of the page, minus some overlap. + return nsSize( + effectiveScrollPortSize.width - + std::min(effectiveScrollPortSize.width * maxOverlapPercent / 100, + maxOverlapLines * lineScrollAmount.width), + effectiveScrollPortSize.height - + std::min(effectiveScrollPortSize.height * maxOverlapPercent / 100, + maxOverlapLines * lineScrollAmount.height)); } /** diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index bb6e2150ce..48c70cd479 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -4317,7 +4317,7 @@ int32_t nsGridContainerFrame::Grid::ResolveLine( bool useStart = IsNameWithStartSuffix(aLine.LineName(), &index); if (useStart || IsNameWithEndSuffix(aLine.LineName(), &index)) { auto side = MakeLogicalSide( - GetAxis(aSide), useStart ? eLogicalEdgeStart : eLogicalEdgeEnd); + GetAxis(aSide), useStart ? LogicalEdge::Start : LogicalEdge::End); RefPtr name = NS_Atomize(nsDependentSubstring( nsDependentAtomString(aLine.LineName()), 0, index)); aNameMap.FindNamedAreas(name, side, implicitLines); @@ -4377,7 +4377,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper( uint32_t from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0; auto end = ResolveLine(aEnd, aEnd.line_num, from, aNameMap, - MakeLogicalSide(aAxis, eLogicalEdgeEnd), + MakeLogicalSide(aAxis, LogicalEdge::End), aExplicitGridEnd, aStyle); int32_t span = aStart.line_num == 0 ? 1 : aStart.line_num; if (end <= 1) { @@ -4387,7 +4387,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper( return LinePair(start, end); } auto start = ResolveLine(aStart, -span, end, aNameMap, - MakeLogicalSide(aAxis, eLogicalEdgeStart), + MakeLogicalSide(aAxis, LogicalEdge::Start), aExplicitGridEnd, aStyle); return LinePair(start, end); } @@ -4411,7 +4411,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper( } else { uint32_t from = aStart.line_num < 0 ? aExplicitGridEnd + 1 : 0; start = ResolveLine(aStart, aStart.line_num, from, aNameMap, - MakeLogicalSide(aAxis, eLogicalEdgeStart), + MakeLogicalSide(aAxis, LogicalEdge::Start), aExplicitGridEnd, aStyle); if (aEnd.IsAuto()) { // A "definite line / auto" should resolve the auto to 'span 1'. @@ -4441,7 +4441,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper( from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0; } auto end = ResolveLine(aEnd, nth, from, aNameMap, - MakeLogicalSide(aAxis, eLogicalEdgeEnd), + MakeLogicalSide(aAxis, LogicalEdge::End), aExplicitGridEnd, aStyle); if (start == int32_t(kAutoLine)) { // auto / definite line @@ -4527,7 +4527,7 @@ nsGridContainerFrame::Grid::ResolveAbsPosLineRange( } uint32_t from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0; int32_t end = ResolveLine(aEnd, aEnd.line_num, from, aNameMap, - MakeLogicalSide(aAxis, eLogicalEdgeEnd), + MakeLogicalSide(aAxis, LogicalEdge::End), aExplicitGridEnd, aStyle); if (aEnd.is_span) { ++end; @@ -4540,7 +4540,7 @@ nsGridContainerFrame::Grid::ResolveAbsPosLineRange( if (aEnd.IsAuto()) { uint32_t from = aStart.line_num < 0 ? aExplicitGridEnd + 1 : 0; int32_t start = ResolveLine(aStart, aStart.line_num, from, aNameMap, - MakeLogicalSide(aAxis, eLogicalEdgeStart), + MakeLogicalSide(aAxis, LogicalEdge::Start), aExplicitGridEnd, aStyle); if (aStart.is_span) { start = std::max(aGridEnd - start, aGridStart); @@ -5761,7 +5761,7 @@ static nscoord MinSize(const GridItemInfo& aGridItem, PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis)); const nsStylePosition* stylePos = child->StylePosition(); StyleSize sizeStyle = - axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight; + axis == PhysicalAxis::Horizontal ? stylePos->mWidth : stylePos->mHeight; auto ourInlineAxis = child->GetWritingMode().PhysicalAxis(LogicalAxis::Inline); @@ -5800,8 +5800,9 @@ static nscoord MinSize(const GridItemInfo& aGridItem, nsLayoutUtils::MinSizeContributionForAxis( axis, aRC, child, IntrinsicISizeType::MinISize, *aCache->mPercentageBasis); - const StyleSize& style = - axis == eAxisHorizontal ? stylePos->mMinWidth : stylePos->mMinHeight; + const StyleSize& style = axis == PhysicalAxis::Horizontal + ? stylePos->mMinWidth + : stylePos->mMinHeight; // max-content and min-content should behave as initial value in block axis. // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported // for block size dimension on sizing properties (e.g. height), so we @@ -6017,7 +6018,7 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines( // against the physical block start side of the child to determine its // baseline sharing group. auto containerBlockStartSide = - containerWM.PhysicalSide(MakeLogicalSide(mAxis, eLogicalEdgeStart)); + containerWM.PhysicalSide(MakeLogicalSide(mAxis, LogicalEdge::Start)); for (GridItemInfo& gridItem : aGridItems) { if (gridItem.IsSubgrid(mAxis)) { @@ -6124,7 +6125,7 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines( { auto childAxis = isOrthogonal ? GetOrthogonalAxis(mAxis) : mAxis; auto childBlockStartSide = childWM.PhysicalSide( - MakeLogicalSide(childAxis, eLogicalEdgeStart)); + MakeLogicalSide(childAxis, LogicalEdge::Start)); bool isFirstBaseline = (state & ItemState::eFirstBaseline) != 0; const bool containerAndChildHasEqualBaselineSide = containerBlockStartSide == childBlockStartSide; diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h index cb3eef68c3..1fa7bbe487 100644 --- a/layout/generic/nsGridContainerFrame.h +++ b/layout/generic/nsGridContainerFrame.h @@ -566,12 +566,8 @@ class nsGridContainerFrame final : public nsContainerFrame, if (aFrame->IsSubtreeDirty()) { return false; } - - if (!CanCacheMeasurement(aFrame, aCBSize)) { - return false; - } - - return mKey == Key(aFrame, aCBSize); + const mozilla::Maybe maybeKey = Key::TryHash(aFrame, aCBSize); + return maybeKey.isSome() && mKey == *maybeKey; } static bool CanCacheMeasurement(const nsIFrame* aFrame, @@ -583,55 +579,54 @@ class nsGridContainerFrame final : public nsContainerFrame, void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize, const nscoord aBSize) { - MOZ_ASSERT(CanCacheMeasurement(aFrame, aCBSize)); - mKey.mHashKey = Key::GenerateHash(aFrame, aCBSize); + mKey.UpdateHash(aFrame, aCBSize); mBSize = aBSize; } private: - struct Key { + class Key { // mHashKey is generated by combining these 2 variables together // 1. The containing block size in the item's inline axis used // for measuring reflow // 2. The item's baseline padding property uint32_t mHashKey; + explicit Key(uint32_t aHashKey) : mHashKey(aHashKey) {} + + public: Key() = default; Key(const nsIFrame* aFrame, const LogicalSize& aCBSize) { - MOZ_ASSERT(CanHash(aFrame, aCBSize)); - mHashKey = GenerateHash(aFrame, aCBSize); + UpdateHash(aFrame, aCBSize); } void UpdateHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) { - MOZ_ASSERT(CanHash(aFrame, aCBSize)); - mHashKey = GenerateHash(aFrame, aCBSize); + const mozilla::Maybe maybeKey = TryHash(aFrame, aCBSize); + MOZ_ASSERT(maybeKey.isSome()); + mHashKey = maybeKey->mHashKey; } - static uint32_t GenerateHash(const nsIFrame* aFrame, - const LogicalSize& aCBSize) { - MOZ_ASSERT(CanHash(aFrame, aCBSize)); - - nscoord gridAreaISize = aCBSize.ISize(aFrame->GetWritingMode()); - nscoord bBaselinePaddingProperty = + static mozilla::Maybe TryHash(const nsIFrame* aFrame, + const LogicalSize& aCBSize) { + const nscoord gridAreaISize = aCBSize.ISize(aFrame->GetWritingMode()); + const nscoord bBaselinePaddingProperty = abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty())); - uint_fast8_t bitsNeededForISize = mozilla::FloorLog2(gridAreaISize) + 1; - - return (gridAreaISize << (32 - bitsNeededForISize)) | - bBaselinePaddingProperty; + const uint_fast8_t bitsNeededForISize = + mozilla::FloorLog2(gridAreaISize) + 1; + + const uint_fast8_t bitsNeededForBBaselinePadding = + mozilla::FloorLog2(bBaselinePaddingProperty) + 1; + if (bitsNeededForISize + bitsNeededForBBaselinePadding > 32) { + return mozilla::Nothing(); + } + const uint32_t hashKey = (gridAreaISize << (32 - bitsNeededForISize)) | + bBaselinePaddingProperty; + return mozilla::Some(Key(hashKey)); } static bool CanHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) { - uint_fast8_t bitsNeededForISize = - mozilla::FloorLog2(aCBSize.ISize(aFrame->GetWritingMode())) + 1; - - uint_fast8_t bitsNeededForBBaselinePadding = - mozilla::FloorLog2( - abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty()))) + - 1; - - return bitsNeededForISize + bitsNeededForBBaselinePadding <= 32; + return TryHash(aFrame, aCBSize).isSome(); } bool operator==(const Key& aOther) const { diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index 27f09b84f6..28c328c9e2 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -19,6 +19,7 @@ #include "mozilla/DebugOnly.h" #include "mozilla/DisplayPortUtils.h" #include "mozilla/EventForwards.h" +#include "mozilla/FocusModel.h" #include "mozilla/dom/CSSAnimation.h" #include "mozilla/dom/CSSTransition.h" #include "mozilla/dom/ContentVisibilityAutoStateChangeEvent.h" @@ -4928,12 +4929,14 @@ bool nsIFrame::MovingCaretToEventPointAllowedIfSecondaryButtonEvent( : aContentAtEventPoint.GetClosestNativeAnonymousSubtreeRoot()); if (Selection* selection = aFrameSelection.GetSelection(SelectionType::eNormal)) { - const bool selectionIsCollapsed = selection->IsCollapsed(); - // If right click in a selection range, we should not collapse selection. - if (!selectionIsCollapsed && - nsContentUtils::IsPointInSelection( - *selection, aContentAtEventPoint, - static_cast(aOffsetAtEventPoint))) { + const bool selectionIsCollapsed = + selection->AreNormalAndCrossShadowBoundaryRangesCollapsed(); + // If right click in a selection range, we should not collapse + // selection. + if (!selectionIsCollapsed && nsContentUtils::IsPointInSelection( + *selection, aContentAtEventPoint, + static_cast(aOffsetAtEventPoint), + true /* aAllowCrossShadowBoundary */)) { return false; } const bool wantToPreventMoveCaret = @@ -7889,7 +7892,7 @@ nsRect nsIFrame::GetNormalRect() const { nsRect nsIFrame::GetBoundingClientRect() { return nsLayoutUtils::GetAllInFlowRectsUnion( this, nsLayoutUtils::GetContainingBlockForClientRect(this), - nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS); + nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms); } nsPoint nsIFrame::GetPositionIgnoringScrolling() const { @@ -7950,8 +7953,19 @@ OverflowAreas nsIFrame::GetActualAndNormalOverflowAreasRelativeToParent() } const OverflowAreas overflows = GetOverflowAreas(); - OverflowAreas actualAndNormalOverflows = overflows + GetPosition(); - actualAndNormalOverflows.UnionWith(overflows + GetNormalPosition()); + OverflowAreas actualAndNormalOverflows = overflows + GetNormalPosition(); + if (IsRelativelyPositioned()) { + actualAndNormalOverflows.UnionWith(overflows + GetPosition()); + } else { + // For sticky positioned elements, we only use the normal position for the + // scrollable overflow. This avoids circular dependencies between sticky + // positioned elements and their scroll container. (The scroll position and + // the scroll container's size impact the sticky position, so we don't want + // the sticky position to impact them.) + MOZ_ASSERT(IsStickyPositioned()); + actualAndNormalOverflows.UnionWith( + OverflowAreas(overflows.InkOverflow() + GetPosition(), nsRect())); + } return actualAndNormalOverflows; } @@ -8008,7 +8022,7 @@ bool nsIFrame::UpdateOverflow() { if (nsView* view = GetView()) { // Make sure the frame's view is properly sized. nsViewManager* vm = view->GetViewManager(); - vm->ResizeView(view, overflowAreas.InkOverflow(), true); + vm->ResizeView(view, overflowAreas.InkOverflow()); } return true; @@ -10795,7 +10809,7 @@ bool nsIFrame::IsFocusableDueToScrollFrame() { return true; } -Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) { +Focusable nsIFrame::IsFocusable(IsFocusableFlags aFlags) { // cannot focus content in print preview mode. Only the root can be focused, // but that's handled elsewhere. if (PresContext()->Type() == nsPresContext::eContext_PrintPreview) { @@ -10806,7 +10820,8 @@ Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) { return {}; } - if (aCheckVisibility && !IsVisibleConsideringAncestors()) { + if (!(aFlags & IsFocusableFlags::IgnoreVisibility) && + !IsVisibleConsideringAncestors()) { return {}; } @@ -10826,14 +10841,14 @@ Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) { // As a legacy special-case, -moz-user-focus controls focusability and // tabability of XUL elements in some circumstances (which default to // -moz-user-focus: ignore). - auto focusability = xul->GetXULFocusability(aWithMouse); + auto focusability = xul->GetXULFocusability(aFlags); focusable.mFocusable = focusability.mForcedFocusable.valueOr(uf == StyleUserFocus::Normal); if (focusable) { focusable.mTabIndex = focusability.mForcedTabIndexIfFocusable.valueOr(0); } } else { - focusable = mContent->IsFocusableWithoutStyle(aWithMouse); + focusable = mContent->IsFocusableWithoutStyle(aFlags); } if (focusable) { @@ -10841,7 +10856,8 @@ Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) { } // If we're focusing with the mouse we never focus scroll areas. - if (!aWithMouse && IsFocusableDueToScrollFrame()) { + if (!(aFlags & IsFocusableFlags::WithMouse) && + IsFocusableDueToScrollFrame()) { return {true, 0}; } @@ -11627,6 +11643,47 @@ bool nsIFrame::HasUnreflowedContainerQueryAncestor() const { return false; } +bool nsIFrame::ShouldBreakBefore( + const ReflowInput::BreakType aBreakType) const { + const auto* display = StyleDisplay(); + return ShouldBreakBetween(display, display->mBreakBefore, aBreakType); +} + +bool nsIFrame::ShouldBreakAfter(const ReflowInput::BreakType aBreakType) const { + const auto* display = StyleDisplay(); + return ShouldBreakBetween(display, display->mBreakAfter, aBreakType); +} + +bool nsIFrame::ShouldBreakBetween( + const nsStyleDisplay* aDisplay, const StyleBreakBetween aBreakBetween, + const ReflowInput::BreakType aBreakType) const { + const bool shouldBreakBetween = [&] { + switch (aBreakBetween) { + case StyleBreakBetween::Always: + return true; + case StyleBreakBetween::Auto: + case StyleBreakBetween::Avoid: + return false; + case StyleBreakBetween::Page: + case StyleBreakBetween::Left: + case StyleBreakBetween::Right: + return aBreakType == ReflowInput::BreakType::Page; + } + MOZ_ASSERT_UNREACHABLE("Unknown break-between value!"); + return false; + }(); + + if (!shouldBreakBetween) { + return false; + } + if (IsAbsolutelyPositioned(aDisplay)) { + // 'break-before' and 'break-after' properties does not apply to + // absolutely-positioned boxes. + return false; + } + return true; +} + #ifdef DEBUG static void GetTagName(nsIFrame* aFrame, nsIContent* aContent, int aResultSize, char* aResult) { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 6e55ebe1c7..801e80c7e0 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -127,6 +127,7 @@ struct CharacterDataChangeInfo; namespace mozilla { enum class CaretAssociationHint; +enum class IsFocusableFlags : uint8_t; enum class PeekOffsetOption : uint16_t; enum class PseudoStyleType : uint8_t; enum class TableSelectionMode : uint32_t; @@ -1386,7 +1387,25 @@ class nsIFrame : public nsQueryFrame { bool HasUnreflowedContainerQueryAncestor() const; + // Return True if this frame has a forced break value before it. + // + // Note: this method only checks 'break-before' property on *this* frame, and + // it doesn't handle forced break value propagation from its first child. + // Callers should handle the propagation in reflow. + bool ShouldBreakBefore(const ReflowInput::BreakType aBreakType) const; + + // Return True if this frame has a forced break value after it. + // + // Note: this method only checks 'break-after' property on *this* frame, and + // it doesn't handle forced break value propagation from its last child. + // Callers should handle the propagation in reflow. + bool ShouldBreakAfter(const ReflowInput::BreakType aBreakType) const; + private: + bool ShouldBreakBetween(const nsStyleDisplay* aDisplay, + const mozilla::StyleBreakBetween aBreakBetween, + const ReflowInput::BreakType aBreakType) const; + // The value that the CSS page-name "auto" keyword resolves to for children // of this frame. // @@ -4369,13 +4388,10 @@ class nsIFrame : public nsQueryFrame { * Also, depending on the pref accessibility.tabfocus some widgets may be * focusable but removed from the tab order. This is the default on * Mac OS X, where fewer items are focusable. - * @param [in, optional] aWithMouse, is this focus query for mouse clicking - * @param [in, optional] aCheckVisibility, whether to treat an invisible - * frame as not focusable * @return whether the frame is focusable via mouse, kbd or script. */ - [[nodiscard]] Focusable IsFocusable(bool aWithMouse = false, - bool aCheckVisibility = true); + [[nodiscard]] Focusable IsFocusable( + mozilla::IsFocusableFlags = mozilla::IsFocusableFlags(0)); protected: // Helper for IsFocusable. diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 91d8430b60..c330f1ce6b 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -645,8 +645,9 @@ const StyleImage* nsImageFrame::GetImageFromStyle() const { nonAnonymousParent->GetContent()); styleContent = nonAnonymousParent->StyleContent(); } - MOZ_RELEASE_ASSERT(contentIndex < styleContent->ContentCount()); - auto& contentItem = styleContent->ContentAt(contentIndex); + auto items = styleContent->NonAltContentItems(); + MOZ_RELEASE_ASSERT(contentIndex < items.Length()); + const auto& contentItem = items[contentIndex]; MOZ_RELEASE_ASSERT(contentItem.IsImage()); return &contentItem.AsImage(); } @@ -1055,11 +1056,8 @@ bool nsImageFrame::ShouldCreateImageFrameForContentProperty( if (aElement.IsRootOfNativeAnonymousSubtree()) { return false; } - const auto& content = aStyle.StyleContent()->mContent; - if (!content.IsItems()) { - return false; - } - Span items = content.AsItems().AsSpan(); + Span items = + aStyle.StyleContent()->NonAltContentItems(); return items.Length() == 1 && items[0].IsImage(); } @@ -2857,10 +2855,10 @@ LogicalSides nsImageFrame::GetLogicalSkipSides() const { return skip; } if (GetPrevInFlow()) { - skip |= eLogicalSideBitsBStart; + skip += LogicalSide::BStart; } if (GetNextInFlow()) { - skip |= eLogicalSideBitsBEnd; + skip += LogicalSide::BEnd; } return skip; } diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index b481c71827..44fce51931 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -797,7 +797,7 @@ LogicalSides nsInlineFrame::GetLogicalSkipSides() const { (prev && (prev->mRect.height || prev->mRect.width))) { // Prev continuation is not empty therefore we don't render our start // border edge. - skip |= eLogicalSideBitsIStart; + skip += LogicalSide::IStart; } else { // If the prev continuation is empty, then go ahead and let our start // edge border render. @@ -809,7 +809,7 @@ LogicalSides nsInlineFrame::GetLogicalSkipSides() const { (next && (next->mRect.height || next->mRect.width))) { // Next continuation is not empty therefore we don't render our end // border edge. - skip |= eLogicalSideBitsIEnd; + skip += LogicalSide::IEnd; } else { // If the next continuation is empty, then go ahead and let our end // edge border render. @@ -822,15 +822,15 @@ LogicalSides nsInlineFrame::GetLogicalSkipSides() const { // a split should skip the "start" side. But figuring out which part of // the split we are involves getting our first continuation, which might be // expensive. So don't bother if we already have the relevant bits set. - if (skip != LogicalSides(mWritingMode, eLogicalSideBitsIBoth)) { + if (skip != LogicalSides(mWritingMode, LogicalSides::IBoth)) { // We're missing one of the skip bits, so check whether we need to set it. // Only get the first continuation once, as an optimization. nsIFrame* firstContinuation = FirstContinuation(); if (firstContinuation->FrameIsNonLastInIBSplit()) { - skip |= eLogicalSideBitsIEnd; + skip += LogicalSide::IEnd; } if (firstContinuation->FrameIsNonFirstInIBSplit()) { - skip |= eLogicalSideBitsIStart; + skip += LogicalSide::IStart; } } } diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index be6f64f1fe..a452568f57 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -396,8 +396,10 @@ nsLineLayout::PerSpanData* nsLineLayout::NewPerSpanData() { psd->mFrame = nullptr; psd->mFirstFrame = nullptr; psd->mLastFrame = nullptr; + psd->mReflowInput = nullptr; psd->mContainsFloat = false; psd->mHasNonemptyContent = false; + psd->mBaseline = nullptr; #ifdef DEBUG outerLineLayout->mSpansAllocated++; diff --git a/layout/generic/nsRubyFrame.cpp b/layout/generic/nsRubyFrame.cpp index d6119f44fb..fc74ce8184 100644 --- a/layout/generic/nsRubyFrame.cpp +++ b/layout/generic/nsRubyFrame.cpp @@ -300,25 +300,25 @@ void nsRubyFrame::ReflowSegment(nsPresContext* aPresContext, Maybe lineSide; switch (textContainer->StyleText()->mRubyPosition) { case StyleRubyPosition::Over: - lineSide.emplace(eLineRelativeDirOver); + lineSide.emplace(LineRelativeDir::Over); break; case StyleRubyPosition::Under: - lineSide.emplace(eLineRelativeDirUnder); + lineSide.emplace(LineRelativeDir::Under); break; case StyleRubyPosition::AlternateOver: if (lastLineSide.isSome() && - lastLineSide.value() == eLineRelativeDirOver) { - lineSide.emplace(eLineRelativeDirUnder); + lastLineSide.value() == LineRelativeDir::Over) { + lineSide.emplace(LineRelativeDir::Under); } else { - lineSide.emplace(eLineRelativeDirOver); + lineSide.emplace(LineRelativeDir::Over); } break; case StyleRubyPosition::AlternateUnder: if (lastLineSide.isSome() && - lastLineSide.value() == eLineRelativeDirUnder) { - lineSide.emplace(eLineRelativeDirOver); + lastLineSide.value() == LineRelativeDir::Under) { + lineSide.emplace(LineRelativeDir::Over); } else { - lineSide.emplace(eLineRelativeDirUnder); + lineSide.emplace(LineRelativeDir::Under); } break; default: @@ -333,7 +333,7 @@ void nsRubyFrame::ReflowSegment(nsPresContext* aPresContext, lineWM.LogicalSideForLineRelativeDir(lineSide.value()); if (StaticPrefs::layout_css_ruby_intercharacter_enabled() && rtcWM.IsVerticalRL() && - lineWM.GetInlineDir() == WritingMode::eInlineLTR) { + lineWM.GetInlineDir() == WritingMode::InlineDir::LTR) { // Inter-character ruby annotations are only supported for vertical-rl // in ltr horizontal writing. Fall back to non-inter-character behavior // otherwise. diff --git a/layout/generic/nsSplittableFrame.cpp b/layout/generic/nsSplittableFrame.cpp index 4054e45f8c..abc3b5bf6e 100644 --- a/layout/generic/nsSplittableFrame.cpp +++ b/layout/generic/nsSplittableFrame.cpp @@ -316,7 +316,7 @@ LogicalSides nsSplittableFrame::GetBlockLevelLogicalSkipSides( bool aAfterReflow) const { LogicalSides skip(mWritingMode); if (MOZ_UNLIKELY(IsTrueOverflowContainer())) { - skip |= eLogicalSideBitsBBoth; + skip += LogicalSides(mWritingMode, LogicalSides::BBoth); return skip; } @@ -326,19 +326,19 @@ LogicalSides nsSplittableFrame::GetBlockLevelLogicalSkipSides( } if (GetPrevContinuation()) { - skip |= eLogicalSideBitsBStart; + skip += LogicalSide::BStart; } // Always skip block-end side if we have a *later* sibling across column-span // split. if (HasColumnSpanSiblings()) { - skip |= eLogicalSideBitsBEnd; + skip += LogicalSide::BEnd; } if (aAfterReflow) { nsIFrame* nif = GetNextContinuation(); if (nif && !nif->IsTrueOverflowContainer()) { - skip |= eLogicalSideBitsBEnd; + skip += LogicalSide::BEnd; } } diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 69b4042033..731d31a16f 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -322,30 +322,29 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return; } - nsFrameLoader* frameLoader = FrameLoader(); - bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame(); - - // If we are pointer-events:none then we don't need to HitTest background const bool pointerEventsNone = Style()->PointerEvents() == StylePointerEvents::None; - if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) { - nsDisplayListCollection decorations(aBuilder); - DisplayBorderBackgroundOutline(aBuilder, decorations); - if (isRemoteFrame) { - // Wrap background colors of