Skip to content

Commit fc214d3

Browse files
committed
Bug 1916988 - Support CSS width/height properties on MathML elements. r=emilio
This patch implements support for the width/height properties on MathML elements [1]. The general algorithm from the spec is as follows: (1) The outcome of the math layout is a "math content box". (2) The content box sets its size from computed width/height values. If auto, it's the one of the "math content box". This patch ignores percentage values for now [2] [3]. (3) math content box is shifted so that its inline-start and top edges aligns with the ones of the content box. There are exceptions elements like mfrac and munder/mover/munderover which instead horizontally center the math content box within the content box. For baseline adjustment, we follow what Chromium does, see [4]. (4) Padding+border are added around the content box. Note that we ignore the box-sizing property for now [5]. The patch essentially tweaks the various MathML layout algorithms to perform steps (3) and (4) before the calls to GetBorderPaddingForPlace and InflateReflowAndBoundingMetrics. [1] https://w3c.github.io/mathml-core/#layout-algorithms [2] w3c/mathml-core#76 [3] w3c/mathml-core#77 [4] w3c/mathml-core#259 [5] w3c/mathml-core#257 Below is more information about test coverage: - width-height-001: Verify that width, height, inline-size and block-size properties sets the size of the content box. This test used to verify they are ignored, this patch fixes the `<meta name="assert">` tag. It also adds a test for the case the specified size is smaller than the content (we force non empty descendants to make sure this content is large enough) and to verify the width is used for the preferred width. - width-height-002, width-height-003: These are reftests visually checking offsets of the math content box within a larger content box (specified by width/height) for the mtext, mrow, mpadded, mfrac, msqrt, mroot, in LTR/RTL modes. In particular they allow to verify some painted elements like fraction bar and radical symbols. - width-height-004: This test more directly checks that the math content box is horizontally centered within a larger content box for munder, mover, munderover and mfrac. This patch extends the test to cover the case when the math content box is wider (i.e. overflowing outside the content box) and removes unnecessary specified height. - width-height-005: New test for other layout algorithm that don't center the math content box, checking inline-start edges of children when a width is specified. We check both LTR/RTL modes and wider/narrower content boxes. - width-height-006: Same but checking the top edges for larger/smaller height and verifying that baseline is perserved. Differential Revision: https://phabricator.services.mozilla.com/D221436 UltraBlame original commit: dc848382811227e2f040f438794da638b8792f5b
1 parent f9bcb03 commit fc214d3

24 files changed

+1208
-176
lines changed

layout/mathml/nsMathMLContainerFrame.cpp

+60-1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,59 @@ void nsMathMLContainerFrame::InflateReflowAndBoundingMetrics(
133133
aReflowOutput.Height() += aBorderPadding.TopBottom();
134134
}
135135

136+
nsMathMLContainerFrame::WidthAndHeightForPlaceAdjustment
137+
nsMathMLContainerFrame::GetWidthAndHeightForPlaceAdjustment(
138+
const PlaceFlags& aFlags) {
139+
WidthAndHeightForPlaceAdjustment sizes;
140+
if (aFlags.contains(PlaceFlag::DoNotAdjustForWidthAndHeight)) {
141+
return sizes;
142+
}
143+
const nsStylePosition* stylePos = StylePosition();
144+
const auto& width = stylePos->mWidth;
145+
146+
147+
if (width.ConvertsToLength()) {
148+
sizes.width = Some(width.ToLength());
149+
}
150+
if (!aFlags.contains(PlaceFlag::IntrinsicSize)) {
151+
152+
153+
const auto& height = stylePos->mHeight;
154+
if (height.ConvertsToLength()) {
155+
sizes.height = Some(height.ToLength());
156+
}
157+
}
158+
return sizes;
159+
}
160+
161+
nscoord nsMathMLContainerFrame::ApplyAdjustmentForWidthAndHeight(
162+
const PlaceFlags& aFlags, const WidthAndHeightForPlaceAdjustment& aSizes,
163+
ReflowOutput& aReflowOutput, nsBoundingMetrics& aBoundingMetrics) {
164+
nscoord shiftX = 0;
165+
if (aSizes.width) {
166+
MOZ_ASSERT(!aFlags.contains(PlaceFlag::DoNotAdjustForWidthAndHeight));
167+
auto width = *aSizes.width;
168+
auto oldWidth = aReflowOutput.Width();
169+
if (IsMathContentBoxHorizontallyCentered()) {
170+
shiftX = (width - oldWidth) / 2;
171+
} else if (StyleVisibility()->mDirection == StyleDirection::Rtl) {
172+
shiftX = width - oldWidth;
173+
}
174+
aBoundingMetrics.leftBearing = 0;
175+
aBoundingMetrics.rightBearing = width;
176+
aBoundingMetrics.width = width;
177+
aReflowOutput.mBoundingMetrics = aBoundingMetrics;
178+
aReflowOutput.Width() = width;
179+
}
180+
if (aSizes.height) {
181+
MOZ_ASSERT(!aFlags.contains(PlaceFlag::DoNotAdjustForWidthAndHeight));
182+
MOZ_ASSERT(!aFlags.contains(PlaceFlag::IntrinsicSize));
183+
auto height = *aSizes.height;
184+
aReflowOutput.Height() = height;
185+
}
186+
return shiftX;
187+
}
188+
136189

137190

138191
void nsMathMLContainerFrame::GetPreferredStretchSize(
@@ -1170,17 +1223,23 @@ nsresult nsMathMLContainerFrame::Place(DrawTarget* aDrawTarget,
11701223
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
11711224

11721225

1226+
auto sizes = GetWidthAndHeightForPlaceAdjustment(aFlags);
1227+
nscoord shiftX = ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
1228+
mBoundingMetrics);
1229+
1230+
11731231
auto borderPadding = GetBorderPaddingForPlace(aFlags);
11741232
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
11751233
mBoundingMetrics);
1234+
shiftX += borderPadding.left;
11761235

11771236
mReference.x = 0;
11781237
mReference.y = aDesiredSize.BlockStartAscent();
11791238

11801239

11811240

11821241
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
1183-
PositionRowChildFrames(borderPadding.left, aDesiredSize.BlockStartAscent());
1242+
PositionRowChildFrames(shiftX, aDesiredSize.BlockStartAscent());
11841243
}
11851244

11861245
return NS_OK;

layout/mathml/nsMathMLContainerFrame.h

+17
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
157157

158158

159159
IgnoreBorderPadding,
160+
161+
162+
163+
164+
DoNotAdjustForWidthAndHeight,
160165
};
161166
using PlaceFlags = mozilla::EnumSet<PlaceFlag>;
162167

@@ -247,6 +252,18 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
247252

248253
nsMargin GetBorderPaddingForPlace(const PlaceFlags& aFlags);
249254

255+
struct WidthAndHeightForPlaceAdjustment {
256+
mozilla::Maybe<nscoord> width;
257+
mozilla::Maybe<nscoord> height;
258+
};
259+
WidthAndHeightForPlaceAdjustment GetWidthAndHeightForPlaceAdjustment(
260+
const PlaceFlags& aFlags);
261+
262+
virtual bool IsMathContentBoxHorizontallyCentered() const { return false; }
263+
nscoord ApplyAdjustmentForWidthAndHeight(
264+
const PlaceFlags& aFlags, const WidthAndHeightForPlaceAdjustment& aSizes,
265+
ReflowOutput& aReflowOutput, nsBoundingMetrics& aBoundingMetrics);
266+
250267
protected:
251268

252269

layout/mathml/nsMathMLTokenFrame.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,18 @@ nsresult nsMathMLTokenFrame::Place(DrawTarget* aDrawTarget,
179179
std::max(mBoundingMetrics.descent, descent);
180180

181181

182+
auto sizes = GetWidthAndHeightForPlaceAdjustment(aFlags);
183+
auto shiftX = ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
184+
mBoundingMetrics);
185+
186+
182187
auto borderPadding = GetBorderPaddingForPlace(aFlags);
183188
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
184189
mBoundingMetrics);
185190

186191
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
187192
nscoord dx = borderPadding.left;
193+
dx += shiftX;
188194
for (nsIFrame* childFrame : PrincipalChildList()) {
189195
ReflowOutput childSize(aDesiredSize.GetWritingMode());
190196
GetReflowAndBoundingMetricsFor(childFrame, childSize,

layout/mathml/nsMathMLmencloseFrame.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,9 @@ nsresult nsMathMLmencloseFrame::Place(DrawTarget* aDrawTarget,
270270

271271

272272
ReflowOutput baseSize(aDesiredSize.GetWritingMode());
273-
PlaceFlags flags =
274-
aFlags + PlaceFlag::MeasureOnly + PlaceFlag::IgnoreBorderPadding;
273+
PlaceFlags flags = aFlags + PlaceFlag::MeasureOnly +
274+
PlaceFlag::IgnoreBorderPadding +
275+
PlaceFlag::DoNotAdjustForWidthAndHeight;
275276
nsresult rv = nsMathMLContainerFrame::Place(aDrawTarget, flags, baseSize);
276277

277278
if (NS_FAILED(rv)) {
@@ -528,6 +529,11 @@ nsresult nsMathMLmencloseFrame::Place(DrawTarget* aDrawTarget,
528529
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
529530

530531

532+
auto sizes = GetWidthAndHeightForPlaceAdjustment(aFlags);
533+
dx_left += ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
534+
mBoundingMetrics);
535+
536+
531537
auto borderPadding = GetBorderPaddingForPlace(aFlags);
532538
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
533539
mBoundingMetrics);

layout/mathml/nsMathMLmfracFrame.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,18 @@ nsresult nsMathMLmfracFrame::Place(DrawTarget* aDrawTarget,
356356
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
357357

358358

359+
auto sizes = GetWidthAndHeightForPlaceAdjustment(aFlags);
360+
auto shiftX = ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
361+
mBoundingMetrics);
362+
if (sizes.width) {
363+
364+
365+
dxNum += shiftX;
366+
dxDen += shiftX;
367+
width = *sizes.width;
368+
}
369+
370+
359371
auto borderPadding = GetBorderPaddingForPlace(aFlags);
360372
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
361373
mBoundingMetrics);

layout/mathml/nsMathMLmfracFrame.h

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class nsMathMLmfracFrame final : public nsMathMLContainerFrame {
9595
mLineThickness(0) {}
9696
virtual ~nsMathMLmfracFrame();
9797

98+
bool IsMathContentBoxHorizontallyCentered() const final { return true; }
99+
98100

99101
void DisplaySlash(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
100102
nscoord aThickness, const nsDisplayListSet& aLists);

layout/mathml/nsMathMLmmultiscriptsFrame.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,11 @@ nsresult nsMathMLmmultiscriptsFrame::PlaceMultiScript(
560560
aDesiredSize.mBoundingMetrics = boundingMetrics;
561561

562562

563+
auto sizes = aFrame->GetWidthAndHeightForPlaceAdjustment(aFlags);
564+
aFrame->ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
565+
boundingMetrics);
566+
567+
563568
auto borderPadding = aFrame->GetBorderPaddingForPlace(aFlags);
564569
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize, boundingMetrics);
565570

layout/mathml/nsMathMLmoFrame.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,8 @@ nsMathMLmoFrame::Stretch(DrawTarget* aDrawTarget,
741741

742742

743743

744-
PlaceFlags flags = PlaceFlag::IgnoreBorderPadding;
744+
PlaceFlags flags(PlaceFlag::IgnoreBorderPadding,
745+
PlaceFlag::DoNotAdjustForWidthAndHeight);
745746
nsresult rv = Place(aDrawTarget, flags, aDesiredStretchSize);
746747
if (NS_FAILED(rv)) {
747748

@@ -852,8 +853,10 @@ nsMathMLmoFrame::Stretch(DrawTarget* aDrawTarget,
852853
}
853854

854855
flags = PlaceFlags();
856+
auto sizes = GetWidthAndHeightForPlaceAdjustment(flags);
855857
auto borderPadding = GetBorderPaddingForPlace(flags);
856-
if (leadingSpace || trailingSpace || !borderPadding.IsAllZero()) {
858+
if (leadingSpace || trailingSpace || !borderPadding.IsAllZero() ||
859+
sizes.width || sizes.height) {
857860
mBoundingMetrics.width += leadingSpace + trailingSpace;
858861
aDesiredStretchSize.Width() = mBoundingMetrics.width;
859862
aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
@@ -867,6 +870,10 @@ nsMathMLmoFrame::Stretch(DrawTarget* aDrawTarget,
867870
aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;
868871

869872

873+
dx += ApplyAdjustmentForWidthAndHeight(flags, sizes, aDesiredStretchSize,
874+
mBoundingMetrics);
875+
876+
870877
InflateReflowAndBoundingMetrics(borderPadding, aDesiredStretchSize,
871878
mBoundingMetrics);
872879
dx += borderPadding.left;

layout/mathml/nsMathMLmpaddedFrame.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,9 @@ nsresult nsMathMLmpaddedFrame::Place(DrawTarget* aDrawTarget,
286286
const PlaceFlags& aFlags,
287287
ReflowOutput& aDesiredSize) {
288288

289-
PlaceFlags flags =
290-
aFlags + PlaceFlag::MeasureOnly + PlaceFlag::IgnoreBorderPadding;
289+
PlaceFlags flags = aFlags + PlaceFlag::MeasureOnly +
290+
PlaceFlag::IgnoreBorderPadding +
291+
PlaceFlag::DoNotAdjustForWidthAndHeight;
291292
nsresult rv = nsMathMLContainerFrame::Place(aDrawTarget, flags, aDesiredSize);
292293
if (NS_FAILED(rv)) {
293294
DidReflowChildren(PrincipalChildList().FirstChild());
@@ -389,6 +390,11 @@ nsresult nsMathMLmpaddedFrame::Place(DrawTarget* aDrawTarget,
389390
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
390391

391392

393+
auto sizes = GetWidthAndHeightForPlaceAdjustment(aFlags);
394+
dx += ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
395+
mBoundingMetrics);
396+
397+
392398
auto borderPadding = GetBorderPaddingForPlace(aFlags);
393399
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
394400
mBoundingMetrics);

layout/mathml/nsMathMLmrootFrame.cpp

+10-3
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,9 @@ nsresult nsMathMLmrootFrame::Place(DrawTarget* aDrawTarget,
180180
} else {
181181

182182

183-
PlaceFlags flags =
184-
aFlags + PlaceFlag::MeasureOnly + PlaceFlag::IgnoreBorderPadding;
183+
PlaceFlags flags = aFlags + PlaceFlag::MeasureOnly +
184+
PlaceFlag::IgnoreBorderPadding +
185+
PlaceFlag::DoNotAdjustForWidthAndHeight;
185186
nsresult rv = nsMathMLContainerFrame::Place(aDrawTarget, flags, baseSize);
186187
if (NS_FAILED(rv)) {
187188
DidReflowChildren(PrincipalChildList().FirstChild());
@@ -318,6 +319,12 @@ nsresult nsMathMLmrootFrame::Place(DrawTarget* aDrawTarget,
318319
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
319320

320321

322+
const PlaceFlags flags;
323+
auto sizes = GetWidthAndHeightForPlaceAdjustment(flags);
324+
nscoord shiftX = ApplyAdjustmentForWidthAndHeight(flags, sizes, aDesiredSize,
325+
mBoundingMetrics);
326+
327+
321328
auto borderPadding = GetBorderPaddingForPlace(aFlags);
322329
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
323330
mBoundingMetrics);
@@ -360,7 +367,7 @@ nsresult nsMathMLmrootFrame::Place(DrawTarget* aDrawTarget,
360367
MirrorIfRTL(aDesiredSize.Width(), baseSize.Width(), dx),
361368
dy, ReflowChildFlags::Default);
362369
} else {
363-
nscoord dx_left = borderPadding.left;
370+
nscoord dx_left = borderPadding.left + shiftX;
364371
if (!isRTL) {
365372
dx_left += bmSqr.width;
366373
}

layout/mathml/nsMathMLmspaceFrame.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ nsresult nsMathMLmspaceFrame::Place(DrawTarget* aDrawTarget,
114114
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
115115

116116

117+
const PlaceFlags flags;
118+
auto sizes = GetWidthAndHeightForPlaceAdjustment(flags);
119+
ApplyAdjustmentForWidthAndHeight(flags, sizes, aDesiredSize,
120+
mBoundingMetrics);
121+
122+
117123
auto borderPadding = GetBorderPaddingForPlace(aFlags);
118124
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
119125
mBoundingMetrics);

layout/mathml/nsMathMLmunderoverFrame.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,14 @@ nsresult nsMathMLmunderoverFrame::Place(DrawTarget* aDrawTarget,
686686
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
687687

688688

689+
auto sizes = GetWidthAndHeightForPlaceAdjustment(aFlags);
690+
auto shiftX = ApplyAdjustmentForWidthAndHeight(aFlags, sizes, aDesiredSize,
691+
mBoundingMetrics);
692+
dxOver += shiftX;
693+
dxBase += shiftX;
694+
dxUnder += shiftX;
695+
696+
689697
auto borderPadding = GetBorderPaddingForPlace(aFlags);
690698
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
691699
mBoundingMetrics);
@@ -719,3 +727,10 @@ nsresult nsMathMLmunderoverFrame::Place(DrawTarget* aDrawTarget,
719727
}
720728
return NS_OK;
721729
}
730+
731+
bool nsMathMLmunderoverFrame::IsMathContentBoxHorizontallyCentered() const {
732+
bool subsupDisplay =
733+
NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
734+
StyleFont()->mMathStyle == StyleMathStyle::Compact;
735+
return !subsupDisplay;
736+
}

layout/mathml/nsMathMLmunderoverFrame.h

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class nsMathMLmunderoverFrame final : public nsMathMLContainerFrame,
5858
virtual ~nsMathMLmunderoverFrame();
5959

6060
private:
61+
bool IsMathContentBoxHorizontallyCentered() const final;
62+
6163

6264

6365

testing/web-platform/meta/mathml/presentation-markup/fractions/frac-bar-003.html.ini

-2
This file was deleted.

testing/web-platform/meta/mathml/presentation-markup/spaces/mspace-width-height-001.html.ini

-12
This file was deleted.

testing/web-platform/meta/mathml/relations/css-styling/display-2.html.ini

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
expected: FAIL
55

66
[list display inside display block]
7-
expected: FAIL
7+
expected: [PASS, FAIL]
88

99
[flexbox display (math)]
10-
expected: FAIL
10+
expected: [PASS, FAIL]
1111

1212
[block display with column width (math)]
1313
expected: FAIL

0 commit comments

Comments
 (0)