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
This commit is contained in:
David Shin
2023-05-15 14:34:26 +00:00
parent d82335fc8b
commit 6f868ef403
40 changed files with 204 additions and 120 deletions

View File

@@ -603,54 +603,76 @@ nscoord nsBlockFrame::SynthesizeFallbackBaseline(
return Baseline::SynthesizeBOffsetFromMarginBox(this, aWM, aBaselineGroup);
}
template <typename LineIteratorType>
Maybe<nscoord> nsBlockFrame::GetBaselineBOffset(
LineIteratorType aStart, LineIteratorType aEnd, WritingMode aWM,
BaselineSharingGroup aBaselineGroup,
BaselineExportContext aExportContext) const {
MOZ_ASSERT((std::is_same_v<LineIteratorType, ConstLineIterator> &&
aBaselineGroup == BaselineSharingGroup::First) ||
(std::is_same_v<LineIteratorType, ConstReverseLineIterator> &&
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()) {
// `<table>` 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<nscoord> 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()) {
// `<table>` 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<nscoord> 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);