From c4f2c2237b7531c5549996c4d267e1f59ea4d17e Mon Sep 17 00:00:00 2001 From: David Shin Date: Mon, 15 May 2023 14:34:26 +0000 Subject: [PATCH] Bug 1809568 - Part 2: Provide `GetNaturalBaselineBOffset` with baseline export context. r=emilio Some baseline exports are context-sensitive. One example: In line-layout scenario, the last baseline of a scroll container is always the margin-end. In other (e.g. flex, grid) scenarios, it's the border-box clamped offset to the last line in the container. This enables the required 3 different behaviours for `inline-block` scroll containers for 3 different `baseline-source` values: - `auto`: Last baseline, margin-end - `first`: Border-box clamped offset to the first line - `last`: Border-box clamped offset to the last line Differential Revision: https://phabricator.services.mozilla.com/D173886 --- layout/base/Baseline.h | 6 ++ layout/base/nsLayoutUtils.cpp | 4 +- layout/forms/nsCheckboxRadioFrame.cpp | 3 +- layout/forms/nsCheckboxRadioFrame.h | 4 +- layout/forms/nsDateTimeControlFrame.cpp | 3 +- layout/forms/nsDateTimeControlFrame.h | 4 +- layout/forms/nsFieldSetFrame.cpp | 6 +- layout/forms/nsFieldSetFrame.h | 4 +- layout/forms/nsHTMLButtonControlFrame.cpp | 14 +-- layout/forms/nsHTMLButtonControlFrame.h | 4 +- layout/forms/nsListControlFrame.cpp | 3 +- layout/forms/nsListControlFrame.h | 4 +- layout/forms/nsTextControlFrame.h | 4 +- layout/generic/BRFrame.cpp | 6 +- layout/generic/ColumnSetWrapperFrame.cpp | 15 ++- layout/generic/ColumnSetWrapperFrame.h | 6 +- layout/generic/nsBlockFrame.cpp | 105 ++++++++++++-------- layout/generic/nsBlockFrame.h | 11 +- layout/generic/nsColumnSetFrame.cpp | 6 +- layout/generic/nsColumnSetFrame.h | 4 +- layout/generic/nsFirstLetterFrame.cpp | 3 +- layout/generic/nsFirstLetterFrame.h | 4 +- layout/generic/nsFlexContainerFrame.cpp | 6 +- layout/generic/nsFlexContainerFrame.h | 4 +- layout/generic/nsGfxScrollFrame.cpp | 9 +- layout/generic/nsGfxScrollFrame.h | 4 +- layout/generic/nsGridContainerFrame.cpp | 4 +- layout/generic/nsGridContainerFrame.h | 4 +- layout/generic/nsIFrame.cpp | 8 +- layout/generic/nsIFrame.h | 24 ++++- layout/generic/nsInlineFrame.cpp | 3 +- layout/generic/nsInlineFrame.h | 4 +- layout/generic/nsRubyBaseContainerFrame.cpp | 3 +- layout/generic/nsRubyBaseContainerFrame.h | 4 +- layout/generic/nsTextFrame.cpp | 3 +- layout/generic/nsTextFrame.h | 4 +- layout/tables/nsTableFrame.cpp | 3 +- layout/tables/nsTableFrame.h | 4 +- layout/tables/nsTableWrapperFrame.cpp | 6 +- layout/tables/nsTableWrapperFrame.h | 4 +- 40 files changed, 204 insertions(+), 120 deletions(-) diff --git a/layout/base/Baseline.h b/layout/base/Baseline.h index 8eae2e114062..fcb85d87b4db 100644 --- a/layout/base/Baseline.h +++ b/layout/base/Baseline.h @@ -19,6 +19,12 @@ enum class BaselineSharingGroup : uint8_t { Last = 1, }; +// Layout context under which the baseline is being exported to. +enum class BaselineExportContext : uint8_t { + LineLayout = 0, + Other = 1, +}; + class Baseline { public: /** diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 82fc9267d31b..2d60aa6c25b5 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5963,8 +5963,8 @@ bool nsLayoutUtils::GetLastLineBaseline(WritingMode aWM, const nsIFrame* aFrame, // `ColumnSetWrapperFrame` level, but this keeps it symmetric to // `GetFirstLinePosition`. if (aFrame->IsColumnSetFrame()) { - const auto baseline = - aFrame->GetNaturalBaselineBOffset(aWM, BaselineSharingGroup::Last); + const auto baseline = aFrame->GetNaturalBaselineBOffset( + aWM, BaselineSharingGroup::Last, BaselineExportContext::Other); if (!baseline) { return false; } diff --git a/layout/forms/nsCheckboxRadioFrame.cpp b/layout/forms/nsCheckboxRadioFrame.cpp index 90d30d2abfca..902b900fdd93 100644 --- a/layout/forms/nsCheckboxRadioFrame.cpp +++ b/layout/forms/nsCheckboxRadioFrame.cpp @@ -86,7 +86,8 @@ LogicalSize nsCheckboxRadioFrame::ComputeAutoSize( } Maybe nsCheckboxRadioFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { NS_ASSERTION(!IsSubtreeDirty(), "frame must not be dirty"); if (aBaselineGroup == BaselineSharingGroup::Last) { diff --git a/layout/forms/nsCheckboxRadioFrame.h b/layout/forms/nsCheckboxRadioFrame.h index d0e5dc200cef..4fc165e29dd4 100644 --- a/layout/forms/nsCheckboxRadioFrame.h +++ b/layout/forms/nsCheckboxRadioFrame.h @@ -62,8 +62,8 @@ class nsCheckboxRadioFrame final : public nsAtomicContainerFrame, nsEventStatus* aEventStatus) override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; /** * Respond to the request to resize and/or reflow diff --git a/layout/forms/nsDateTimeControlFrame.cpp b/layout/forms/nsDateTimeControlFrame.cpp index 252673b558bc..d80f4ea2cee3 100644 --- a/layout/forms/nsDateTimeControlFrame.cpp +++ b/layout/forms/nsDateTimeControlFrame.cpp @@ -65,7 +65,8 @@ nscoord nsDateTimeControlFrame::GetPrefISize(gfxContext* aRenderingContext) { } Maybe nsDateTimeControlFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { return nsTextControlFrame::GetSingleLineTextControlBaseline( this, mFirstBaseline, aWM, aBaselineGroup); } diff --git a/layout/forms/nsDateTimeControlFrame.h b/layout/forms/nsDateTimeControlFrame.h index ae1ff4ad248f..755cdd0933e6 100644 --- a/layout/forms/nsDateTimeControlFrame.h +++ b/layout/forms/nsDateTimeControlFrame.h @@ -62,8 +62,8 @@ class nsDateTimeControlFrame final : public nsContainerFrame { nsReflowStatus& aStatus) override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; nscoord mFirstBaseline = NS_INTRINSIC_ISIZE_UNKNOWN; }; diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp index 60e796aa3dcc..45108e4d9fcd 100644 --- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -851,7 +851,8 @@ nscoord nsFieldSetFrame::SynthesizeFallbackBaseline( } Maybe nsFieldSetFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { if (StyleDisplay()->IsContainLayout()) { // If we are layout-contained, our child 'inner' should not // affect how we calculate our baseline. @@ -862,7 +863,8 @@ Maybe nsFieldSetFrame::GetNaturalBaselineBOffset( return Nothing{}; } MOZ_ASSERT(!inner->GetWritingMode().IsOrthogonalTo(aWM)); - const auto result = inner->GetNaturalBaselineBOffset(aWM, aBaselineGroup); + const auto result = + inner->GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext); if (!result) { return Nothing{}; } diff --git a/layout/forms/nsFieldSetFrame.h b/layout/forms/nsFieldSetFrame.h index 0d446a147fbd..04d63a8a3fcb 100644 --- a/layout/forms/nsFieldSetFrame.h +++ b/layout/forms/nsFieldSetFrame.h @@ -41,8 +41,8 @@ class nsFieldSetFrame final : public nsContainerFrame { BaselineSharingGroup aBaselineGroup) const override; BaselineSharingGroup GetDefaultBaselineSharingGroup() const override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) override; diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp index 1df588f26be4..7fc5f403917d 100644 --- a/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/layout/forms/nsHTMLButtonControlFrame.cpp @@ -313,7 +313,8 @@ void nsHTMLButtonControlFrame::ReflowButtonContents( } Maybe nsHTMLButtonControlFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { if (StyleDisplay()->IsContainLayout()) { return Nothing{}; } @@ -322,11 +323,12 @@ Maybe nsHTMLButtonControlFrame::GetNaturalBaselineBOffset( if (MOZ_UNLIKELY(inner->GetWritingMode().IsOrthogonalTo(aWM))) { return Nothing{}; } - auto result = inner->GetNaturalBaselineBOffset(aWM, aBaselineGroup) - .valueOrFrom([inner, aWM, aBaselineGroup]() { - return Baseline::SynthesizeBOffsetFromBorderBox( - inner, aWM, aBaselineGroup); - }); + auto result = + inner->GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext) + .valueOrFrom([inner, aWM, aBaselineGroup]() { + return Baseline::SynthesizeBOffsetFromBorderBox(inner, aWM, + aBaselineGroup); + }); nscoord innerBStart = inner->BStart(aWM, GetSize()); if (aBaselineGroup == BaselineSharingGroup::First) { diff --git a/layout/forms/nsHTMLButtonControlFrame.h b/layout/forms/nsHTMLButtonControlFrame.h index 2acbb4f71c3d..b0d016f35517 100644 --- a/layout/forms/nsHTMLButtonControlFrame.h +++ b/layout/forms/nsHTMLButtonControlFrame.h @@ -39,8 +39,8 @@ class nsHTMLButtonControlFrame : public nsContainerFrame, nsReflowStatus& aStatus) override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const override; virtual nsresult HandleEvent(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent, diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index 905919ac4018..52dd85b004db 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -71,7 +71,8 @@ nsListControlFrame::nsListControlFrame(ComputedStyle* aStyle, nsListControlFrame::~nsListControlFrame() = default; Maybe nsListControlFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { // Unlike scroll frames which we inherit from, we don't export a baseline. return Nothing{}; } diff --git a/layout/forms/nsListControlFrame.h b/layout/forms/nsListControlFrame.h index 0b2a59a11a83..04b1b8003f5a 100644 --- a/layout/forms/nsListControlFrame.h +++ b/layout/forms/nsListControlFrame.h @@ -56,8 +56,8 @@ class nsListControlFrame final : public nsHTMLScrollFrame, NS_DECL_FRAMEARENA_HELPERS(nsListControlFrame) Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; // nsIFrame nsresult HandleEvent(nsPresContext* aPresContext, diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 5a76fd64e2a2..fa779851cd37 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -78,8 +78,8 @@ class nsTextControlFrame : public nsContainerFrame, nsReflowStatus& aStatus) override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override { + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override { if (!IsSingleLineTextControl()) { return Nothing{}; } diff --git a/layout/generic/BRFrame.cpp b/layout/generic/BRFrame.cpp index 4062c438939a..5cb7c104d964 100644 --- a/layout/generic/BRFrame.cpp +++ b/layout/generic/BRFrame.cpp @@ -60,7 +60,8 @@ class BRFrame final : public nsIFrame { nscoord GetPrefISize(gfxContext* aRenderingContext) override; Maybe GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const override; + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; bool IsFrameOfType(uint32_t aFlags) const override { return nsIFrame::IsFrameOfType( @@ -203,7 +204,8 @@ nscoord BRFrame::GetPrefISize(gfxContext* aRenderingContext) { } Maybe BRFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { if (aBaselineGroup == BaselineSharingGroup::Last) { return Nothing{}; } diff --git a/layout/generic/ColumnSetWrapperFrame.cpp b/layout/generic/ColumnSetWrapperFrame.cpp index de2bfcd9ddb2..b694b3f4f1e9 100644 --- a/layout/generic/ColumnSetWrapperFrame.cpp +++ b/layout/generic/ColumnSetWrapperFrame.cpp @@ -235,7 +235,8 @@ nscoord ColumnSetWrapperFrame::GetPrefISize(gfxContext* aRenderingContext) { template Maybe ColumnSetWrapperFrame::GetBaselineBOffset( Iterator aStart, Iterator aEnd, WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const { + BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { // Either forward iterator + first baseline, or reverse iterator + last // baseline MOZ_ASSERT((*aStart == PrincipalChildList().FirstChild() && @@ -251,7 +252,8 @@ Maybe ColumnSetWrapperFrame::GetBaselineBOffset( // baseline. for (auto itr = aStart; itr != aEnd; ++itr) { const nsIFrame* kid = *itr; - auto kidBaseline = kid->GetNaturalBaselineBOffset(aWM, aBaselineGroup); + auto kidBaseline = + kid->GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext); if (!kidBaseline) { continue; } @@ -270,13 +272,16 @@ Maybe ColumnSetWrapperFrame::GetBaselineBOffset( } Maybe ColumnSetWrapperFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { if (aBaselineGroup == BaselineSharingGroup::First) { return GetBaselineBOffset(PrincipalChildList().cbegin(), - PrincipalChildList().cend(), aWM, aBaselineGroup); + PrincipalChildList().cend(), aWM, aBaselineGroup, + aExportContext); } return GetBaselineBOffset(PrincipalChildList().crbegin(), - PrincipalChildList().crend(), aWM, aBaselineGroup); + PrincipalChildList().crend(), aWM, aBaselineGroup, + aExportContext); } #ifdef DEBUG diff --git a/layout/generic/ColumnSetWrapperFrame.h b/layout/generic/ColumnSetWrapperFrame.h index 0ee2b0b4eb1e..a71d72da6c05 100644 --- a/layout/generic/ColumnSetWrapperFrame.h +++ b/layout/generic/ColumnSetWrapperFrame.h @@ -60,7 +60,8 @@ class ColumnSetWrapperFrame final : public nsBlockFrame { nscoord GetPrefISize(gfxContext* aRenderingContext) override; Maybe GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const override; + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const override; private: explicit ColumnSetWrapperFrame(ComputedStyle* aStyle, @@ -78,7 +79,8 @@ class ColumnSetWrapperFrame final : public nsBlockFrame { template Maybe GetBaselineBOffset(Iterator aStart, Iterator aEnd, WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const; + BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const; }; } // namespace mozilla diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 4790acbe6e30..296010582cd7 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -603,54 +603,76 @@ nscoord nsBlockFrame::SynthesizeFallbackBaseline( return Baseline::SynthesizeBOffsetFromMarginBox(this, aWM, aBaselineGroup); } +template +Maybe nsBlockFrame::GetBaselineBOffset( + LineIteratorType aStart, LineIteratorType aEnd, WritingMode aWM, + BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { + MOZ_ASSERT((std::is_same_v && + aBaselineGroup == BaselineSharingGroup::First) || + (std::is_same_v && + aBaselineGroup == BaselineSharingGroup::Last), + "Iterator direction must match baseline sharing group."); + for (auto line = aStart; line != aEnd; ++line) { + if (!line->IsBlock()) { + // XXX Is this the right test? We have some bogus empty lines + // floating around, but IsEmpty is perhaps too weak. + if (line->BSize() != 0 || !line->IsEmpty()) { + const auto ascent = line->BStart() + line->GetLogicalAscent(); + if (aBaselineGroup == BaselineSharingGroup::Last) { + return Some(BSize(aWM) - ascent); + } + return Some(ascent); + } + continue; + } + nsIFrame* kid = line->mFirstChild; + if (aWM.IsOrthogonalTo(kid->GetWritingMode())) { + continue; + } + if (aExportContext == BaselineExportContext::LineLayout && + kid->IsTableWrapperFrame()) { + // `` in inline-block context does not export any baseline. + continue; + } + const auto kidBaselineGroup = + aExportContext == BaselineExportContext::LineLayout + ? kid->GetDefaultBaselineSharingGroup() + : aBaselineGroup; + const auto kidBaseline = + kid->GetNaturalBaselineBOffset(aWM, kidBaselineGroup, aExportContext); + if (!kidBaseline) { + continue; + } + auto result = *kidBaseline; + if (kidBaselineGroup == BaselineSharingGroup::Last) { + result = kid->BSize(aWM) - result; + } + // Ignore relative positioning for baseline calculations. + const nsSize& sz = line->mContainerSize; + result += kid->GetLogicalNormalPosition(aWM, sz).B(aWM); + if (aBaselineGroup == BaselineSharingGroup::Last) { + return Some(BSize(aWM) - result); + } + return Some(result); + } + return Nothing{}; +} + Maybe nsBlockFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { if (StyleDisplay()->IsContainLayout()) { return Nothing{}; } if (aBaselineGroup == BaselineSharingGroup::First) { - nscoord result; - if (!nsLayoutUtils::GetFirstLineBaseline(aWM, this, &result)) { - return Nothing{}; - } - return Some(result); + return GetBaselineBOffset(LinesBegin(), LinesEnd(), aWM, aBaselineGroup, + aExportContext); } - for (ConstReverseLineIterator line = LinesRBegin(), line_end = LinesREnd(); - line != line_end; ++line) { - if (line->IsBlock()) { - nsIFrame* kid = line->mFirstChild; - if (aWM.IsOrthogonalTo(kid->GetWritingMode())) { - continue; - } - if (kid->IsTableWrapperFrame()) { - // `
` in block display context does not export any baseline. - continue; - } - const auto kidBaselineGroup = kid->GetDefaultBaselineSharingGroup(); - const auto kidBaseline = - kid->GetNaturalBaselineBOffset(aWM, kidBaselineGroup); - if (!kidBaseline) { - continue; - } - auto result = *kidBaseline; - if (kidBaselineGroup == BaselineSharingGroup::Last) { - result = kid->BSize(aWM) - result; - } - // Ignore relative positioning for baseline calculations. - const nsSize& sz = line->mContainerSize; - result += kid->GetLogicalNormalPosition(aWM, sz).B(aWM); - return Some(BSize(aWM) - result); - } else { - // XXX Is this the right test? We have some bogus empty lines - // floating around, but IsEmpty is perhaps too weak. - if (line->BSize() != 0 || !line->IsEmpty()) { - return Some(BSize(aWM) - (line->BStart() + line->GetLogicalAscent())); - } - } - } - return Nothing{}; + return GetBaselineBOffset(LinesRBegin(), LinesREnd(), aWM, aBaselineGroup, + aExportContext); } nscoord nsBlockFrame::GetCaretBaseline() const { @@ -1570,7 +1592,8 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics, const auto baselineGroup = BaselineSharingGroup::First; Maybe result; if (MOZ_LIKELY(!wm.IsOrthogonalTo(marker->GetWritingMode()))) { - result = marker->GetNaturalBaselineBOffset(wm, baselineGroup); + result = marker->GetNaturalBaselineBOffset( + wm, baselineGroup, BaselineExportContext::LineLayout); } const auto markerBaseline = result.valueOrFrom([bbox, wm, marker]() { return bbox.BSize(wm) + marker->GetLogicalUsedMargin(wm).BEnd(wm); diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index 8dc18828d462..8323d0235bd0 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -133,8 +133,8 @@ class nsBlockFrame : public nsContainerFrame { return BaselineSharingGroup::Last; } Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const override; nscoord GetCaretBaseline() const override; void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override; @@ -276,6 +276,13 @@ class nsBlockFrame : public nsContainerFrame { private: void CheckIntrinsicCacheAgainstShrinkWrapState(); + template + Maybe GetBaselineBOffset(LineIteratorType aStart, + LineIteratorType aEnd, + mozilla::WritingMode aWM, + BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const; + public: nscoord GetMinISize(gfxContext* aRenderingContext) override; nscoord GetPrefISize(gfxContext* aRenderingContext) override; diff --git a/layout/generic/nsColumnSetFrame.cpp b/layout/generic/nsColumnSetFrame.cpp index 9fdd1d138ae7..bbb6e39878f7 100644 --- a/layout/generic/nsColumnSetFrame.cpp +++ b/layout/generic/nsColumnSetFrame.cpp @@ -1298,10 +1298,12 @@ void nsColumnSetFrame::AppendDirectlyOwnedAnonBoxes( } Maybe nsColumnSetFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { Maybe result; for (const auto* kid : mFrames) { - auto kidBaseline = kid->GetNaturalBaselineBOffset(aWM, aBaselineGroup); + auto kidBaseline = + kid->GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext); if (!kidBaseline) { continue; } diff --git a/layout/generic/nsColumnSetFrame.h b/layout/generic/nsColumnSetFrame.h index 210d2401fa20..a06424e5f394 100644 --- a/layout/generic/nsColumnSetFrame.h +++ b/layout/generic/nsColumnSetFrame.h @@ -75,8 +75,8 @@ class nsColumnSetFrame final : public nsContainerFrame { const nsPoint& aPt); Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const override; protected: nscoord mLastBalanceBSize; diff --git a/layout/generic/nsFirstLetterFrame.cpp b/layout/generic/nsFirstLetterFrame.cpp index 442cfcabe58e..1ce8aa9e3857 100644 --- a/layout/generic/nsFirstLetterFrame.cpp +++ b/layout/generic/nsFirstLetterFrame.cpp @@ -426,7 +426,8 @@ void nsFirstLetterFrame::DrainOverflowFrames(nsPresContext* aPresContext) { } Maybe nsFirstLetterFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { if (aBaselineGroup == BaselineSharingGroup::Last) { return Nothing{}; } diff --git a/layout/generic/nsFirstLetterFrame.h b/layout/generic/nsFirstLetterFrame.h index f17d28f8e529..4a099ebf3f6a 100644 --- a/layout/generic/nsFirstLetterFrame.h +++ b/layout/generic/nsFirstLetterFrame.h @@ -61,8 +61,8 @@ class nsFirstLetterFrame final : public nsContainerFrame { virtual bool CanContinueTextRun() const override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; virtual LogicalSides GetLogicalSkipSides() const override; // override of nsFrame method diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index ed0dac152960..c2f562339f62 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -416,7 +416,8 @@ class nsFlexContainerFrame::FlexItem final { // If the nsLayoutUtils getter fails, then ask the frame directly: auto baselineGroup = aUseFirstBaseline ? BaselineSharingGroup::First : BaselineSharingGroup::Last; - if (auto baseline = mFrame->GetNaturalBaselineBOffset(mWM, baselineGroup)) { + if (auto baseline = mFrame->GetNaturalBaselineBOffset( + mWM, baselineGroup, BaselineExportContext::Other)) { // Offset for last baseline from `GetNaturalBaselineBOffset` originates // from the frame's block end, so convert it back. mAscent = baselineGroup == BaselineSharingGroup::First @@ -4636,7 +4637,8 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext, } Maybe nsFlexContainerFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { if (StyleDisplay()->IsContainLayout() || HasAnyStateBits(NS_STATE_FLEX_SYNTHESIZE_BASELINE)) { return Nothing{}; diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index 1c097672d895..42911016d068 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -166,8 +166,8 @@ class nsFlexContainerFrame final : public nsContainerFrame, #endif Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; // Unions the child overflow from our in-flow children. void UnionInFlowChildOverflow(mozilla::OverflowAreas&); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 893f4a9870e8..5a5ec2dcab6f 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1421,7 +1421,8 @@ nscoord nsHTMLScrollFrame::SynthesizeFallbackBaseline( } Maybe nsHTMLScrollFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { // Block containers that are scrollable always have a last baseline // that are synthesized from block-end margin edge. // Note(dshin): This behaviour is really only relevant to `inline-block` @@ -1429,7 +1430,8 @@ Maybe nsHTMLScrollFrame::GetNaturalBaselineBOffset( // baselines are calculated through `GetFirstLineBaseline`, which does // calculations of its own. // https://drafts.csswg.org/css-align/#baseline-export - if (aBaselineGroup == BaselineSharingGroup::Last && + if (aExportContext == BaselineExportContext::LineLayout && + aBaselineGroup == BaselineSharingGroup::Last && mScrolledFrame->IsBlockFrameOrSubclass()) { return Some(SynthesizeFallbackBaseline(aWM, aBaselineGroup)); } @@ -1439,7 +1441,8 @@ Maybe nsHTMLScrollFrame::GetNaturalBaselineBOffset( } // OK, here's where we defer to our scrolled frame. - return mScrolledFrame->GetNaturalBaselineBOffset(aWM, aBaselineGroup) + return mScrolledFrame + ->GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext) .map([this, aWM](nscoord aBaseline) { // We have to add our border BStart thickness to whatever it returns, to // produce an offset in our frame-rect's coordinate system. (We don't diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 53736caaf167..ebedac17d5a1 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -130,8 +130,8 @@ class nsHTMLScrollFrame : public nsContainerFrame, mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup) const override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const override; // Recomputes the scrollable overflow area we store in the helper to take // children that are affected by perpsective set on the outer frame and scroll diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index bac52907dfc4..d3aaa8ee8533 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -9568,7 +9568,9 @@ nscoord nsGridContainerFrame::SynthesizeBaseline( baseline = isOrthogonal ? grid->GetIBaseline(aGroup) : grid->GetBBaseline(aGroup); } else if (!isOrthogonal && aGridOrderItem.mIsInEdgeTrack) { - baseline = child->GetNaturalBaselineBOffset(childWM, aGroup) + baseline = child + ->GetNaturalBaselineBOffset(childWM, aGroup, + BaselineExportContext::Other) .valueOrFrom([aGroup, child, childWM]() { return Baseline::SynthesizeBOffsetFromBorderBox( child, childWM, aGroup); diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h index 568331ce9a43..ab790c4e0e5d 100644 --- a/layout/generic/nsGridContainerFrame.h +++ b/layout/generic/nsGridContainerFrame.h @@ -131,8 +131,8 @@ class nsGridContainerFrame final : public nsContainerFrame, const nsDisplayListSet& aLists) override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override { + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override { if (StyleDisplay()->IsContainLayout() || HasAnyStateBits(NS_STATE_GRID_SYNTHESIZE_BASELINE)) { return Nothing{}; diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index a055d0f34fcf..c9e017f3c942 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -2086,13 +2086,15 @@ nscoord nsIFrame::SynthesizeFallbackBaseline( } nscoord nsIFrame::GetLogicalBaseline(WritingMode aWM) const { - return GetLogicalBaseline(aWM, GetDefaultBaselineSharingGroup()); + return GetLogicalBaseline(aWM, GetDefaultBaselineSharingGroup(), + BaselineExportContext::LineLayout); } nscoord nsIFrame::GetLogicalBaseline( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { const auto result = - GetNaturalBaselineBOffset(aWM, aBaselineGroup) + GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext) .valueOrFrom([this, aWM, aBaselineGroup]() { return SynthesizeFallbackBaseline(aWM, aBaselineGroup); }); diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 6b1f2b983d8d..ea68fe71917d 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -519,6 +519,7 @@ class nsIFrame : public nsQueryFrame { public: using AlignmentContext = mozilla::AlignmentContext; using BaselineSharingGroup = mozilla::BaselineSharingGroup; + using BaselineExportContext = mozilla::BaselineExportContext; template using Maybe = mozilla::Maybe; template @@ -1528,14 +1529,19 @@ class nsIFrame : public nsQueryFrame { /** * `GetNaturalBaselineBOffset`, but determines the baseline sharing group - * through `GetDefaultBaselineSharingGroup` (If not specified), and never - * fails, returning a synthesized baseline through + * through `GetDefaultBaselineSharingGroup` (If not specified), assuming line + * layout context, and never fails, returning a synthesized baseline through * `SynthesizeFallbackBaseline`. Unlike `GetNaturalBaselineBOffset`, Result is * always relative to the block start of the frame. */ nscoord GetLogicalBaseline(mozilla::WritingMode aWM) const; + /** + * Same as the above, but with baseline sharing group & export + * context specified. + */ nscoord GetLogicalBaseline(mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const; + BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const; /** * Return true if the frame has a first(last) inline-axis baseline per @@ -1543,14 +1549,21 @@ class nsIFrame : public nsQueryFrame { * the relevant block-axis border-box edge (Start for * BaselineSharingGroup::First, end for BaselineSharingGroup::Last), where * a positive value points towards the content-box. + * Some frames can export different baselines depending if it's in a line + * layout context or any other context (e.g. Flex, grid). * https://drafts.csswg.org/css-align-3/#baseline-export * @note The returned value is only valid when reflow is not needed. * @note You should only call this on frames with a WM that's parallel to aWM. + * @note We're approaching `nsLayoutUtils::Get(First|Last)LineBaseline` == + * `GetNaturalBaselineBOffset(aWM, (First|Last), Other)`. Grid relies on + * baseline synthesis behaviour in `nsLayoutUtils` implementations (bug + * 1609403), which blocks its removal. * @param aWM the writing-mode of the alignment context. * @return the baseline offset, if one exists */ virtual Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { return Nothing{}; } @@ -1657,7 +1670,8 @@ class nsIFrame : public nsQueryFrame { public: /** - * Get the suitable baseline sharing group for this element. + * Get the suitable baseline sharing group for this element, assuming line + * layout. */ virtual BaselineSharingGroup GetDefaultBaselineSharingGroup() const { return BaselineSharingGroup::First; diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 8d502b3a533a..37122545299d 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -841,7 +841,8 @@ LogicalSides nsInlineFrame::GetLogicalSkipSides() const { } Maybe nsInlineFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { if (aBaselineGroup == BaselineSharingGroup::Last) { return Nothing{}; } diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index f7156ff4d3cd..748bd546a84f 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -97,8 +97,8 @@ class nsInlineFrame : public nsContainerFrame { virtual void PullOverflowsFromPrevInFlow() override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; virtual bool DrainSelfOverflowList() override; /** diff --git a/layout/generic/nsRubyBaseContainerFrame.cpp b/layout/generic/nsRubyBaseContainerFrame.cpp index f34379faf9fa..0241792a2324 100644 --- a/layout/generic/nsRubyBaseContainerFrame.cpp +++ b/layout/generic/nsRubyBaseContainerFrame.cpp @@ -262,7 +262,8 @@ nsIFrame::SizeComputationResult nsRubyBaseContainerFrame::ComputeSize( } Maybe nsRubyBaseContainerFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { if (aBaselineGroup == BaselineSharingGroup::Last) { return Nothing{}; } diff --git a/layout/generic/nsRubyBaseContainerFrame.h b/layout/generic/nsRubyBaseContainerFrame.h index 3cb2c7d14486..79524f3abc1d 100644 --- a/layout/generic/nsRubyBaseContainerFrame.h +++ b/layout/generic/nsRubyBaseContainerFrame.h @@ -47,8 +47,8 @@ class nsRubyBaseContainerFrame final : public nsContainerFrame { nsReflowStatus& aStatus) override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override; diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 09fe2513cecc..70016accd59a 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -10058,7 +10058,8 @@ bool nsTextFrame::IsAtEndOfLine() const { } Maybe nsTextFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { if (aBaselineGroup == BaselineSharingGroup::Last) { return Nothing{}; } diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index d67819cf4a22..51cc15c6e28c 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -367,8 +367,8 @@ class nsTextFrame : public nsIFrame { bool IsEmpty() final; bool IsSelfEmpty() final { return IsEmpty(); } Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; bool HasSignificantTerminalNewline() const final; diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 726bc9bb8667..ada669f37b3c 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -3541,7 +3541,8 @@ nscoord nsTableFrame::SynthesizeFallbackBaseline( /* virtual */ Maybe nsTableFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const { if (StyleDisplay()->IsContainLayout()) { return Nothing{}; } diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index fe28abce6f4f..f5bb89c8e8cc 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -439,8 +439,8 @@ class nsTableFrame : public nsContainerFrame { mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup) const override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext) const override; /** return the row span of a cell, taking into account row span magic at the * bottom of a table. The row span equals the number of rows spanned by aCell diff --git a/layout/tables/nsTableWrapperFrame.cpp b/layout/tables/nsTableWrapperFrame.cpp index 37a4391b750f..85b4ce091851 100644 --- a/layout/tables/nsTableWrapperFrame.cpp +++ b/layout/tables/nsTableWrapperFrame.cpp @@ -41,7 +41,8 @@ nscoord nsTableWrapperFrame::SynthesizeFallbackBaseline( } Maybe nsTableWrapperFrame::GetNaturalBaselineBOffset( - WritingMode aWM, BaselineSharingGroup aBaselineGroup) const { + WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const { // Baseline is determined by row // (https://drafts.csswg.org/css-align-3/#baseline-export). If the row // direction is going to be orthogonal to the parent's writing mode, the @@ -52,7 +53,8 @@ Maybe nsTableWrapperFrame::GetNaturalBaselineBOffset( return Nothing{}; } auto* innerTable = InnerTableFrame(); - return innerTable->GetNaturalBaselineBOffset(aWM, aBaselineGroup) + return innerTable + ->GetNaturalBaselineBOffset(aWM, aBaselineGroup, aExportContext) .map([this, aWM, aBaselineGroup, innerTable](nscoord aBaseline) { auto bStart = innerTable->BStart(aWM, mRect.Size()); if (aBaselineGroup == BaselineSharingGroup::First) { diff --git a/layout/tables/nsTableWrapperFrame.h b/layout/tables/nsTableWrapperFrame.h index ef294dced74c..641ded6a5225 100644 --- a/layout/tables/nsTableWrapperFrame.h +++ b/layout/tables/nsTableWrapperFrame.h @@ -68,8 +68,8 @@ class nsTableWrapperFrame : public nsContainerFrame { mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup) const override; Maybe GetNaturalBaselineBOffset( - mozilla::WritingMode aWM, - BaselineSharingGroup aBaselineGroup) const override; + mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, + BaselineExportContext aExportContext) const override; virtual nscoord GetMinISize(gfxContext* aRenderingContext) override; virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;