Skip to content

Commit a566f4d

Browse files
committed
Bug 1908069 - Add border/padding/margin support to . r=emilio
This is the first patch of the series that actually take border/padding/margin into account for MathML layout. One subtility is that Gecko distinguishes the ink nsBoundingMetrics box and the ReflowOutput box for accurate positioning of math components contrary to the current version of MathML Core [1]. For MathML Core and the WPT tests, it is assumed that border/padding are used to inflate the content box [2] [3] and it does not really matter whether we inflate the ink bounding box, or simply adjust its offsets inside the normal bounding box. We choose the former and introduce a helper function InflateReflowAndBoundingMetrics for that purpose, which will be reused in follow-up patches. After inflating these boxes, the offsets of children and painted items must also be adjusted by the left/top border+padding. Regarding margins, MathML Core says that we should use "margin boxes" and WPT tests simply check that the layout of MathML constructions containing mspace elements with margins is not changed if we move these margins inside the mspace's width/height/depth attributes. To pass these tests, we similarly need to inflate both the ink and non-ink bounding boxes by the margin. However, the margins can be negative possibly leading to negative dimensions of "margin boxes". To make the code more generic, we simplify adjust all usages of the children's nsBoundingMetrics and ReflowOutput to include these margins. When calling FinishReflowChild at the end, the offsets of children must be adjusted by these margins. This patch also reimplements the extra one-pixel padding around a fraction using rules from MathML Core's UA stylesheet at https://w3c.github.io/mathml-core/#user-agent-stylesheet [1] w3c/mathml-core#78 [2] https://github.com/web-platform-tests/wpt/blob/27c8d234ee83a4b15f36ad10cc26c951b1782fb6/mathml/relations/css-styling/padding-border-margin/border-002.html#L25 [4] https://github.com/web-platform-tests/wpt/blob/27c8d234ee83a4b15f36ad10cc26c951b1782fb6/mathml/relations/css-styling/padding-border-margin/padding-002.html#L26 [3] https://github.com/web-platform-tests/wpt/blob/27c8d234ee83a4b15f36ad10cc26c951b1782fb6/mathml/relations/css-styling/padding-border-margin/margin-003.html#L50 Differential Revision: https://phabricator.services.mozilla.com/D216670
1 parent 298b21b commit a566f4d

File tree

8 files changed

+93
-39
lines changed

8 files changed

+93
-39
lines changed

layout/mathml/mathml.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ math[display="inline" i] {
7272
7373
*/
7474

75+
/* Fractions */
76+
mfrac {
77+
padding-inline: 1px;
78+
}
7579

7680
/**************************************************************************/
7781
/* merror */

layout/mathml/nsMathMLContainerFrame.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,46 @@ void nsMathMLContainerFrame::ClearSavedChildMetrics() {
9393
}
9494
}
9595

96+
nsMargin nsMathMLContainerFrame::GetBorderPaddingForPlace(
97+
const PlaceFlags& aFlags) {
98+
if (aFlags.contains(PlaceFlag::IgnoreBorderPadding)) {
99+
return nsMargin();
100+
}
101+
102+
if (aFlags.contains(PlaceFlag::IntrinsicSize)) {
103+
// Bug 1910859: Should we provide separate left and right border/padding?
104+
return nsMargin(0, IntrinsicISizeOffsets().BorderPadding(), 0, 0);
105+
}
106+
107+
return GetUsedBorderAndPadding();
108+
}
109+
110+
/* static */
111+
nsMargin nsMathMLContainerFrame::GetMarginForPlace(const PlaceFlags& aFlags,
112+
nsIFrame* aChild) {
113+
if (aFlags.contains(PlaceFlag::IntrinsicSize)) {
114+
// Bug 1910859: Should we provide separate left and right margin?
115+
return nsMargin(0, aChild->IntrinsicISizeOffsets().margin, 0, 0);
116+
}
117+
118+
return aChild->GetUsedMargin();
119+
}
120+
121+
void nsMathMLContainerFrame::InflateReflowAndBoundingMetrics(
122+
const nsMargin& aBorderPadding, ReflowOutput& aReflowOutput,
123+
nsBoundingMetrics& aBoundingMetrics) {
124+
// Bug 1910858: It is not really clear what is the right way to update the
125+
// ink bounding box when adding border or padding. Below, we assume that
126+
// border/padding inflate it.
127+
aBoundingMetrics.rightBearing += aBorderPadding.LeftRight();
128+
aBoundingMetrics.width += aBorderPadding.LeftRight();
129+
aReflowOutput.mBoundingMetrics = aBoundingMetrics;
130+
aReflowOutput.Width() += aBorderPadding.LeftRight();
131+
aReflowOutput.SetBlockStartAscent(aReflowOutput.BlockStartAscent() +
132+
aBorderPadding.top);
133+
aReflowOutput.Height() += aBorderPadding.TopBottom();
134+
}
135+
96136
// helper to get the preferred size that a container frame should use to fire
97137
// the stretch on its stretchy child frames.
98138
void nsMathMLContainerFrame::GetPreferredStretchSize(

layout/mathml/nsMathMLContainerFrame.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
291291
// SaveReflowAndBoundingMetricsFor() from all child frames.
292292
void ClearSavedChildMetrics();
293293

294+
nsMargin GetBorderPaddingForPlace(const PlaceFlags& aFlags);
295+
static nsMargin GetMarginForPlace(const PlaceFlags& aFlags, nsIFrame* aChild);
296+
297+
static void InflateReflowAndBoundingMetrics(
298+
const nsMargin& aBorderPadding, ReflowOutput& aReflowOutput,
299+
nsBoundingMetrics& aBoundingMetrics);
300+
294301
// helper to let the update of presentation data pass through
295302
// a subtree that may contain non-MathML container frames
296303
static void PropagatePresentationDataFor(nsIFrame* aFrame,

layout/mathml/nsMathMLmfracFrame.cpp

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
171171
GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum);
172172
GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen);
173173

174+
nsMargin numMargin = GetMarginForPlace(aFlags, frameNum),
175+
denMargin = GetMarginForPlace(aFlags, frameDen);
176+
174177
nsPresContext* presContext = PresContext();
175178
nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
176179

@@ -207,13 +210,12 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
207210

208211
mLineRect.height = mLineThickness;
209212

210-
// by default, leave at least one-pixel padding at either end, and add
211-
// lspace & rspace that may come from if we are an outermost
213+
// Add lspace & rspace that may come from if we are an outermost
212214
// embellished container (we fetch values from the core since they may use
213215
// units that depend on style data, and style changes could have occurred
214216
// in the core since our last visit there)
215-
nscoord leftSpace = onePixel;
216-
nscoord rightSpace = onePixel;
217+
nscoord leftSpace = 0;
218+
nscoord rightSpace = 0;
217219
if (outermostEmbellished) {
218220
const bool isRTL = StyleVisibility()->mDirection == StyleDirection::Rtl;
219221
nsEmbellishData coreData;
@@ -277,8 +279,8 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
277279
oneDevPixel);
278280
}
279281

280-
nscoord actualClearance =
281-
(numShift - bmNum.descent) - (bmDen.ascent - denShift);
282+
nscoord actualClearance = (numShift - bmNum.descent - numMargin.bottom) -
283+
(bmDen.ascent + denMargin.top - denShift);
282284
// actualClearance should be >= minClearance
283285
if (actualClearance < minClearance) {
284286
nscoord halfGap = (minClearance - actualClearance) / 2;
@@ -314,14 +316,14 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
314316
}
315317

316318
// adjust numShift to maintain minClearanceNum if needed
317-
nscoord actualClearanceNum =
318-
(numShift - bmNum.descent) - (axisHeight + actualRuleThickness / 2);
319+
nscoord actualClearanceNum = (numShift - bmNum.descent - numMargin.bottom) -
320+
(axisHeight + actualRuleThickness / 2);
319321
if (actualClearanceNum < minClearanceNum) {
320322
numShift += (minClearanceNum - actualClearanceNum);
321323
}
322324
// adjust denShift to maintain minClearanceDen if needed
323-
nscoord actualClearanceDen =
324-
(axisHeight - actualRuleThickness / 2) - (bmDen.ascent - denShift);
325+
nscoord actualClearanceDen = (axisHeight - actualRuleThickness / 2) -
326+
(bmDen.ascent + denMargin.top - denShift);
325327
if (actualClearanceDen < minClearanceDen) {
326328
denShift += (minClearanceDen - actualClearanceDen);
327329
}
@@ -332,40 +334,59 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
332334

333335
// XXX Need revisiting the width. TeX uses the exact width
334336
// e.g. in $$\huge\frac{\displaystyle\int}{i}$$
335-
nscoord width = std::max(bmNum.width, bmDen.width);
336-
nscoord dxNum = leftSpace + (width - sizeNum.Width()) / 2;
337-
nscoord dxDen = leftSpace + (width - sizeDen.Width()) / 2;
337+
nscoord width = std::max(bmNum.width + numMargin.LeftRight(),
338+
bmDen.width + denMargin.LeftRight());
339+
nscoord dxNum =
340+
leftSpace + (width - sizeNum.Width() - numMargin.LeftRight()) / 2;
341+
nscoord dxDen =
342+
leftSpace + (width - sizeDen.Width() - denMargin.LeftRight()) / 2;
338343
width += leftSpace + rightSpace;
339344

340345
mBoundingMetrics.rightBearing =
341-
std::max(dxNum + bmNum.rightBearing, dxDen + bmDen.rightBearing);
346+
std::max(dxNum + bmNum.rightBearing + numMargin.LeftRight(),
347+
dxDen + bmDen.rightBearing + denMargin.LeftRight());
342348
if (mBoundingMetrics.rightBearing < width - rightSpace)
343349
mBoundingMetrics.rightBearing = width - rightSpace;
344350
mBoundingMetrics.leftBearing =
345351
std::min(dxNum + bmNum.leftBearing, dxDen + bmDen.leftBearing);
346352
if (mBoundingMetrics.leftBearing > leftSpace)
347353
mBoundingMetrics.leftBearing = leftSpace;
348-
mBoundingMetrics.ascent = bmNum.ascent + numShift;
349-
mBoundingMetrics.descent = bmDen.descent + denShift;
354+
mBoundingMetrics.ascent = bmNum.ascent + numShift + numMargin.top;
355+
mBoundingMetrics.descent = bmDen.descent + denShift + denMargin.bottom;
350356
mBoundingMetrics.width = width;
351357

352-
aDesiredSize.SetBlockStartAscent(sizeNum.BlockStartAscent() + numShift);
353-
aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + sizeDen.Height() -
354-
sizeDen.BlockStartAscent() + denShift;
358+
aDesiredSize.SetBlockStartAscent(numMargin.top + sizeNum.BlockStartAscent() +
359+
numShift);
360+
aDesiredSize.Height() = aDesiredSize.BlockStartAscent() + sizeDen.Height() +
361+
denMargin.bottom - sizeDen.BlockStartAscent() +
362+
denShift;
355363
aDesiredSize.Width() = mBoundingMetrics.width;
356364
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
357365

366+
// Add padding+border.
367+
auto borderPadding = GetBorderPaddingForPlace(aFlags);
368+
InflateReflowAndBoundingMetrics(borderPadding, aDesiredSize,
369+
mBoundingMetrics);
370+
leftSpace += borderPadding.left;
371+
rightSpace += borderPadding.right;
372+
width += borderPadding.LeftRight();
373+
dxNum += borderPadding.left;
374+
dxDen += borderPadding.left;
375+
358376
mReference.x = 0;
359377
mReference.y = aDesiredSize.BlockStartAscent();
360378

361379
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
362380
nscoord dy;
363381
// place numerator
364-
dy = 0;
382+
dxNum += numMargin.left;
383+
dy = borderPadding.top + numMargin.top;
365384
FinishReflowChild(frameNum, presContext, sizeNum, nullptr, dxNum, dy,
366385
ReflowChildFlags::Default);
367386
// place denominator
368-
dy = aDesiredSize.Height() - sizeDen.Height();
387+
dxDen += denMargin.left;
388+
dy = aDesiredSize.Height() - sizeDen.Height() - denMargin.bottom -
389+
borderPadding.bottom;
369390
FinishReflowChild(frameDen, presContext, sizeDen, nullptr, dxDen, dy,
370391
ReflowChildFlags::Default);
371392
// place the fraction bar - dy is top of bar

testing/web-platform/meta/mathml/presentation-markup/fractions/default-mfrac-padding-style.html.ini

Lines changed: 0 additions & 3 deletions
This file was deleted.

testing/web-platform/meta/mathml/relations/css-styling/padding-border-margin/border-002.html.ini

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@
6262
[Border properties on mtext]
6363
expected: FAIL
6464

65-
[Border properties on mfrac]
66-
expected: FAIL
67-
6865
[Border properties on mover]
6966
expected: FAIL
7067

@@ -98,9 +95,6 @@
9895
[Border properties on mi (rtl)]
9996
expected: FAIL
10097

101-
[Border properties on mfrac (rtl)]
102-
expected: FAIL
103-
10498
[Border properties on mo (rtl)]
10599
expected: FAIL
106100

testing/web-platform/meta/mathml/relations/css-styling/padding-border-margin/margin-003.html.ini

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
[Margin properties on the children of msqrt]
2424
expected: FAIL
2525

26-
[Margin properties on the children of mfrac]
27-
expected: FAIL
28-
2926
[Margin properties on the children of mphantom]
3027
expected: FAIL
3128

testing/web-platform/meta/mathml/relations/css-styling/padding-border-margin/padding-002.html.ini

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@
5050
[Padding properties on msub]
5151
expected: FAIL
5252

53-
[Padding properties on mfrac]
54-
expected: FAIL
55-
5653
[Padding properties on mrow]
5754
expected: FAIL
5855

@@ -128,9 +125,6 @@
128125
[Padding properties on mphantom (rtl)]
129126
expected: FAIL
130127

131-
[Padding properties on mfrac (rtl)]
132-
expected: FAIL
133-
134128
[Padding properties on msqrt (rtl)]
135129
expected: FAIL
136130

0 commit comments

Comments
 (0)