Skip to content

Commit c107e01

Browse files
committedMar 23, 2023
Bug 1812679 - Handle central baseline calculation in GetNaturalBaselineBOffset. r=layout-reviewers,emilio
Previously, for writing-mode using central baseline alignment (i.e. `vertical-(lr|rl)`, we simply used the center of content-box in `nsLineLayout::VerticalAlignFrames`. However, this is incorrect for e.g. a `div` with two lines of text - just like how its alphabetical baseline is the baseline of the second line of text, the central baseline should be the centerline of the second line. Differential Revision: https://phabricator.services.mozilla.com/D172165
1 parent 01e19e4 commit c107e01

26 files changed

+99
-115
lines changed
 

‎layout/base/nsLayoutUtils.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -8591,8 +8591,10 @@ void nsLayoutUtils::SetBSizeFromFontMetrics(const nsIFrame* aFrame,
85918591
// The height of our box is the sum of our font size plus the top
85928592
// and bottom border and padding. The height of children do not
85938593
// affect our height.
8594-
aMetrics.SetBlockStartAscent(aLineWM.IsLineInverted() ? fm->MaxDescent()
8595-
: fm->MaxAscent());
8594+
aMetrics.SetBlockStartAscent(
8595+
aLineWM.IsAlphabeticalBaseline()
8596+
? aLineWM.IsLineInverted() ? fm->MaxDescent() : fm->MaxAscent()
8597+
: fm->MaxHeight() / 2);
85968598
aMetrics.BSize(aLineWM) = fm->MaxHeight();
85978599
} else {
85988600
NS_WARNING("Cannot get font metrics - defaulting sizes to 0");

‎layout/forms/nsCheckboxRadioFrame.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ Maybe<nscoord> nsCheckboxRadioFrame::GetNaturalBaselineBOffset(
103103
return Nothing{};
104104
}
105105

106+
if (aWM.IsCentralBaseline()) {
107+
return Some(GetLogicalUsedBorderAndPadding(aWM).BStart(aWM) +
108+
ContentSize(aWM).BSize(aWM) / 2);
109+
}
106110
// This is for compatibility with Chrome, Safari and Edge (Dec 2016).
107111
// Treat radio buttons and checkboxes as having an intrinsic baseline
108112
// at the block-end of the control (use the block-end content edge rather

‎layout/forms/nsHTMLButtonControlFrame.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,9 @@ void nsHTMLButtonControlFrame::ReflowButtonContents(
300300
// XXX is there a better strategy? should we include border-padding?
301301
if (!aButtonReflowInput.mStyleDisplay->IsContainLayout()) {
302302
if (aButtonDesiredSize.GetWritingMode().IsOrthogonalTo(wm)) {
303-
aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.ISize(wm));
303+
aButtonDesiredSize.SetBlockStartAscent(
304+
wm.IsAlphabeticalBaseline() ? contentsDesiredSize.ISize(wm)
305+
: contentsDesiredSize.ISize(wm) / 2);
304306
} else {
305307
aButtonDesiredSize.SetBlockStartAscent(
306308
contentsDesiredSize.BlockStartAscent() + childPos.B(wm));

‎layout/generic/nsGfxScrollFrame.cpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -1456,16 +1456,32 @@ static void GetScrollableOverflowForPerspective(
14561456
}
14571457
}
14581458

1459+
BaselineSharingGroup nsHTMLScrollFrame::GetDefaultBaselineSharingGroup() const {
1460+
return mScrolledFrame->GetDefaultBaselineSharingGroup();
1461+
}
1462+
1463+
nscoord nsHTMLScrollFrame::SynthesizeFallbackBaseline(
1464+
mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup) const {
1465+
// Marign-end even for central baselines.
1466+
if (aWM.IsLineInverted()) {
1467+
return -GetLogicalUsedMargin(aWM).BStart(aWM);
1468+
}
1469+
return aBaselineGroup == BaselineSharingGroup::First
1470+
? BSize(aWM) + GetLogicalUsedMargin(aWM).BEnd(aWM)
1471+
: -GetLogicalUsedMargin(aWM).BEnd(aWM);
1472+
}
1473+
14591474
Maybe<nscoord> nsHTMLScrollFrame::GetNaturalBaselineBOffset(
14601475
WritingMode aWM, BaselineSharingGroup aBaselineGroup) const {
1461-
// Block containers that are scrollable always have a first & last baselines
1476+
// Block containers that are scrollable always have a last baseline
14621477
// that are synthesized from block-end margin edge.
14631478
// Note(dshin): This behaviour is really only relevant to `inline-block`
14641479
// alignment context. In the context of table/flex/grid alignment, first/last
14651480
// baselines are calculated through `GetFirstLineBaseline`, which does
14661481
// calculations of its own.
14671482
// https://drafts.csswg.org/css-align/#baseline-export
1468-
if (mScrolledFrame->IsBlockFrameOrSubclass()) {
1483+
if (aBaselineGroup == BaselineSharingGroup::Last &&
1484+
mScrolledFrame->IsBlockFrameOrSubclass()) {
14691485
return Some(SynthesizeFallbackBaseline(aWM, aBaselineGroup));
14701486
}
14711487

‎layout/generic/nsGfxScrollFrame.h

+4
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ class nsHTMLScrollFrame : public nsContainerFrame,
129129

130130
bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) final;
131131

132+
BaselineSharingGroup GetDefaultBaselineSharingGroup() const override;
133+
nscoord SynthesizeFallbackBaseline(
134+
mozilla::WritingMode aWM,
135+
BaselineSharingGroup aBaselineGroup) const override;
132136
Maybe<nscoord> GetNaturalBaselineBOffset(
133137
mozilla::WritingMode aWM,
134138
BaselineSharingGroup aBaselineGroup) const override;

‎layout/generic/nsIFrame.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -2113,6 +2113,9 @@ nscoord nsIFrame::SynthesizeFallbackBaseline(
21132113
WritingMode aWM, BaselineSharingGroup aBaselineGroup) const {
21142114
const auto margin = GetLogicalUsedMargin(aWM);
21152115
NS_ASSERTION(!IsSubtreeDirty(), "frame must not be dirty");
2116+
if (aWM.IsCentralBaseline()) {
2117+
return (BSize(aWM) + GetLogicalUsedMargin(aWM).BEnd(aWM)) / 2;
2118+
}
21162119
// Baseline for inverted line content is the top (block-start) margin edge,
21172120
// as the frame is in effect "flipped" for alignment purposes.
21182121
if (aWM.IsLineInverted()) {

‎layout/generic/nsLineLayout.cpp

+5-21
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,9 @@ void nsLineLayout::PlaceFrame(PerFrameData* pfd, ReflowOutput& aMetrics) {
13461346
// its ascent; instead, treat it as a block with baseline at the block-end
13471347
// edge (or block-begin in the case of an "inverted" line).
13481348
if (pfd->mWritingMode.GetBlockDir() != lineWM.GetBlockDir()) {
1349-
pfd->mAscent = lineWM.IsLineInverted() ? 0 : aMetrics.BSize(lineWM);
1349+
pfd->mAscent = lineWM.IsAlphabeticalBaseline()
1350+
? lineWM.IsLineInverted() ? 0 : aMetrics.BSize(lineWM)
1351+
: aMetrics.BSize(lineWM) / 2;
13501352
} else {
13511353
if (aMetrics.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) {
13521354
pfd->mAscent = pfd->mFrame->GetLogicalBaseline(lineWM);
@@ -2014,25 +2016,7 @@ void nsLineLayout::VerticalAlignFrames(PerSpanData* psd) {
20142016
switch (keyword) {
20152017
default:
20162018
case StyleVerticalAlignKeyword::Baseline:
2017-
if (lineWM.IsVertical() && !lineWM.IsSideways()) {
2018-
// FIXME: We should really use a central baseline from the
2019-
// baseline table of the font, rather than assuming it's in
2020-
// the middle.
2021-
if (frameSpan) {
2022-
nscoord borderBoxBSize = pfd->mBounds.BSize(lineWM);
2023-
nscoord bStartBP = pfd->mBorderPadding.BStart(lineWM);
2024-
nscoord bEndBP = pfd->mBorderPadding.BEnd(lineWM);
2025-
nscoord contentBoxBSize = borderBoxBSize - bStartBP - bEndBP;
2026-
pfd->mBounds.BStart(lineWM) =
2027-
revisedBaselineBCoord - contentBoxBSize / 2 - bStartBP;
2028-
} else {
2029-
pfd->mBounds.BStart(lineWM) = revisedBaselineBCoord -
2030-
logicalBSize / 2 +
2031-
pfd->mMargin.BStart(lineWM);
2032-
}
2033-
} else {
2034-
pfd->mBounds.BStart(lineWM) = revisedBaselineBCoord - pfd->mAscent;
2035-
}
2019+
pfd->mBounds.BStart(lineWM) = revisedBaselineBCoord - pfd->mAscent;
20362020
pfd->mBlockDirAlign = VALIGN_OTHER;
20372021
break;
20382022

@@ -2152,7 +2136,7 @@ void nsLineLayout::VerticalAlignFrames(PerSpanData* psd) {
21522136
// inverted relative to block direction.
21532137
nscoord revisedBaselineBCoord =
21542138
baselineBCoord - offset * lineWM.FlowRelativeToLineRelativeFactor();
2155-
if (lineWM.IsVertical() && !lineWM.IsSideways()) {
2139+
if (lineWM.IsCentralBaseline()) {
21562140
// If we're using a dominant center baseline, we align with the center
21572141
// of the frame being placed (bug 1133945).
21582142
pfd->mBounds.BStart(lineWM) =

‎layout/generic/nsTextFrame.cpp

+26-12
Original file line numberDiff line numberDiff line change
@@ -9292,14 +9292,21 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
92929292
finalSize.ISize(wm) =
92939293
NSToCoordCeilClamped(std::max(gfxFloat(0.0), textMetrics.mAdvanceWidth));
92949294

9295+
nscoord fontBaseline;
9296+
// Note(dshin): Baseline should tecnhically be halfway through the em box for
9297+
// a central baseline. It is simply half of the text run block size so that it
9298+
// can be easily calculated in `GetNaturalBaselineBOffset`.
92959299
if (transformedCharsFit == 0 && !usedHyphenation) {
92969300
aMetrics.SetBlockStartAscent(0);
92979301
finalSize.BSize(wm) = 0;
9302+
fontBaseline = 0;
92989303
} else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) {
9304+
fontBaseline = NSToCoordCeil(textMetrics.mAscent);
9305+
const auto size = fontBaseline + NSToCoordCeil(textMetrics.mDescent);
92999306
// Use actual text metrics for floating first letter frame.
9300-
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent));
9301-
finalSize.BSize(wm) =
9302-
aMetrics.BlockStartAscent() + NSToCoordCeil(textMetrics.mDescent);
9307+
aMetrics.SetBlockStartAscent(wm.IsAlphabeticalBaseline() ? fontBaseline
9308+
: size / 2);
9309+
finalSize.BSize(wm) = size;
93039310
} else {
93049311
// Otherwise, ascent should contain the overline drawable area.
93059312
// And also descent should contain the underline drawable area.
@@ -9309,16 +9316,18 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
93099316
wm.IsLineInverted() ? fm->MaxDescent() : fm->MaxAscent();
93109317
nscoord fontDescent =
93119318
wm.IsLineInverted() ? fm->MaxAscent() : fm->MaxDescent();
9312-
aMetrics.SetBlockStartAscent(
9313-
std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent));
9314-
nscoord descent =
9319+
fontBaseline = std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent);
9320+
const auto size =
9321+
fontBaseline +
93159322
std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent);
9316-
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
9323+
aMetrics.SetBlockStartAscent(wm.IsAlphabeticalBaseline() ? fontBaseline
9324+
: size / 2);
9325+
finalSize.BSize(wm) = size;
93179326
}
93189327
if (Style()->IsTextCombined()) {
93199328
nsFontMetrics* fm = provider.GetFontMetrics();
9320-
gfxFloat width = finalSize.ISize(wm);
9321-
gfxFloat em = fm->EmHeight();
9329+
nscoord width = finalSize.ISize(wm);
9330+
nscoord em = fm->EmHeight();
93229331
// Compress the characters in horizontal axis if necessary.
93239332
if (width <= em) {
93249333
RemoveProperty(TextCombineScaleFactorProperty());
@@ -9328,8 +9337,9 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
93289337
}
93299338
// Make the characters be in an 1em square.
93309339
if (finalSize.BSize(wm) != em) {
9331-
aMetrics.SetBlockStartAscent(aMetrics.BlockStartAscent() +
9332-
(em - finalSize.BSize(wm)) / 2);
9340+
fontBaseline =
9341+
aMetrics.BlockStartAscent() + (em - finalSize.BSize(wm)) / 2;
9342+
aMetrics.SetBlockStartAscent(fontBaseline);
93339343
finalSize.BSize(wm) = em;
93349344
}
93359345
}
@@ -9343,7 +9353,7 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
93439353
0,
93449354
"Negative descent???");
93459355

9346-
mAscent = aMetrics.BlockStartAscent();
9356+
mAscent = fontBaseline;
93479357

93489358
// Handle text that runs outside its normal bounds.
93499359
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
@@ -10021,6 +10031,10 @@ Maybe<nscoord> nsTextFrame::GetNaturalBaselineBOffset(
1002110031
}
1002210032

1002310033
if (!aWM.IsOrthogonalTo(GetWritingMode())) {
10034+
if (aWM.IsCentralBaseline()) {
10035+
return Some(GetLogicalUsedBorderAndPadding(aWM).BStart(aWM) +
10036+
ContentSize(aWM).BSize(aWM) / 2);
10037+
}
1002410038
return Some(mAscent);
1002510039
}
1002610040

‎layout/style/test/test_revert.html

-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
const kResetDiv = document.getElementById("nonInherited");
2222
const kNoAuthorStylesDiv = document.getElementById("noAuthorStyleApplied");
2323

24-
SimpleTest.expectAssertions(3, 3); // bug 1790201
25-
2624
function computedValue(node, property) {
2725
return get_computed_value(getComputedStyle(node), property);
2826
}

‎layout/tables/nsTableFrame.cpp

+13-6
Original file line numberDiff line numberDiff line change
@@ -3548,28 +3548,35 @@ Maybe<nscoord> nsTableFrame::GetNaturalBaselineBOffset(
35483548
OrderRowGroups(orderedRowGroups);
35493549
// XXX not sure if this should be the size of the containing block instead.
35503550
nsSize containerSize = mRect.Size();
3551-
auto TableBaseline = [aWM, containerSize](nsTableRowGroupFrame* aRowGroup,
3552-
nsTableRowFrame* aRow) {
3551+
auto TableBaseline = [aWM, containerSize](
3552+
nsTableRowGroupFrame* aRowGroup,
3553+
nsTableRowFrame* aRow) -> Maybe<nscoord> {
35533554
nscoord rgBStart =
35543555
LogicalRect(aWM, aRowGroup->GetNormalRect(), containerSize).BStart(aWM);
35553556
nscoord rowBStart =
3556-
LogicalRect(aWM, aRow->GetNormalRect(), containerSize).BStart(aWM);
3557-
return rgBStart + rowBStart + aRow->GetRowBaseline(aWM);
3557+
LogicalRect(aWM, aRow->GetNormalRect(), aRowGroup->GetSize())
3558+
.BStart(aWM);
3559+
return aRow->GetRowBaseline(aWM).map(
3560+
[rgBStart, rowBStart](nscoord aBaseline) {
3561+
return rgBStart + rowBStart + aBaseline;
3562+
});
35583563
};
35593564
if (aBaselineGroup == BaselineSharingGroup::First) {
35603565
for (uint32_t rgIndex = 0; rgIndex < orderedRowGroups.Length(); rgIndex++) {
35613566
nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgIndex];
35623567
nsTableRowFrame* row = rgFrame->GetFirstRow();
35633568
if (row) {
3564-
return Some(TableBaseline(rgFrame, row));
3569+
return TableBaseline(rgFrame, row);
35653570
}
35663571
}
35673572
} else {
35683573
for (uint32_t rgIndex = orderedRowGroups.Length(); rgIndex-- > 0;) {
35693574
nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgIndex];
35703575
nsTableRowFrame* row = rgFrame->GetLastRow();
35713576
if (row) {
3572-
return Some(BSize(aWM) - TableBaseline(rgFrame, row));
3577+
return TableBaseline(rgFrame, row).map([this, aWM](nscoord aBaseline) {
3578+
return BSize(aWM) - aBaseline;
3579+
});
35733580
}
35743581
}
35753582
}

‎layout/tables/nsTableRowFrame.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -398,21 +398,23 @@ void nsTableRowFrame::DidResize() {
398398
// *including* cells with rowspans
399399
nscoord nsTableRowFrame::GetMaxCellAscent() const { return mMaxCellAscent; }
400400

401-
nscoord nsTableRowFrame::GetRowBaseline(WritingMode aWM) {
401+
Maybe<nscoord> nsTableRowFrame::GetRowBaseline(WritingMode aWM) {
402402
if (mMaxCellAscent) {
403-
return mMaxCellAscent;
403+
return Some(mMaxCellAscent);
404404
}
405405

406406
// If we get here, we don't have a baseline on any of the cells in this row.
407-
407+
if (aWM.IsCentralBaseline()) {
408+
return Nothing{};
409+
}
408410
nscoord ascent = 0;
409411
for (nsIFrame* childFrame : mFrames) {
410412
MOZ_ASSERT(childFrame->IsTableCellFrame());
411413
nscoord s = Baseline::SynthesizeBOffsetFromContentBox(
412414
childFrame, aWM, BaselineSharingGroup::First);
413415
ascent = std::max(ascent, s);
414416
}
415-
return ascent;
417+
return Some(ascent);
416418
}
417419

418420
nscoord nsTableRowFrame::GetInitialBSize(nscoord aPctBasis) const {

‎layout/tables/nsTableRowFrame.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class nsTableRowFrame : public nsContainerFrame {
132132

133133
/* return the row ascent
134134
*/
135-
nscoord GetRowBaseline(mozilla::WritingMode aWritingMode);
135+
Maybe<nscoord> GetRowBaseline(mozilla::WritingMode aWM);
136136

137137
/** returns the ordinal position of this row in its table */
138138
virtual int32_t GetRowIndex() const;

‎layout/tables/nsTableWrapperFrame.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ using namespace mozilla::layout;
2828

2929
nscoord nsTableWrapperFrame::SynthesizeFallbackBaseline(
3030
mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup) const {
31+
const auto marginBlockEnd = GetLogicalUsedMargin(aWM).BEnd(aWM);
32+
if (aWM.IsCentralBaseline()) {
33+
return (BSize(aWM) + marginBlockEnd) / 2;
34+
}
3135
// Our fallback baseline is the block-end margin-edge, with respect to the
3236
// given writing mode.
33-
const auto marginBlockEnd = GetLogicalUsedMargin(aWM).BEnd(aWM);
3437
if (aBaselineGroup == BaselineSharingGroup::Last) {
3538
return -marginBlockEnd;
3639
}

‎testing/web-platform/meta/css/css-align/baseline-rules/inline-table-inline-block-baseline-vert-rl.html.ini

-2
This file was deleted.

‎testing/web-platform/meta/css/css-inline/baseline-source/baseline-source-first-002.html.ini

+4-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
[.target > * 3]
66
expected: FAIL
77

8+
[.target > * 4]
9+
expected: FAIL
10+
811
[.target > * 5]
912
expected: FAIL
1013

@@ -14,18 +17,12 @@
1417
[.target > * 9]
1518
expected: FAIL
1619

17-
[.target > * 11]
18-
expected: FAIL
19-
20-
[.target > * 13]
20+
[.target > * 10]
2121
expected: FAIL
2222

2323
[.target > * 15]
2424
expected: FAIL
2525

26-
[.target > * 17]
27-
expected: FAIL
28-
2926
[.target > * 19]
3027
expected: FAIL
3128

‎testing/web-platform/meta/css/css-inline/baseline-source/baseline-source-first-003.html.ini

-12
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,8 @@
1414
[.target > * 9]
1515
expected: FAIL
1616

17-
[.target > * 11]
18-
expected: FAIL
19-
20-
[.target > * 13]
21-
expected: FAIL
22-
2317
[.target > * 15]
2418
expected: FAIL
2519

26-
[.target > * 17]
27-
expected: FAIL
28-
29-
[.target > * 19]
30-
expected: FAIL
31-
3220
[.target > * 21]
3321
expected: FAIL

0 commit comments

Comments
 (0)
Failed to load comments.