Skip to content

Commit 6a8cbc9

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 a29658e commit 6a8cbc9

File tree

9 files changed

+94
-40
lines changed

9 files changed

+94
-40
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
@@ -170,6 +170,9 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
170170
GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum);
171171
GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen);
172172

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

@@ -206,13 +209,12 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
206209

207210
mLineRect.height = mLineThickness;
208211

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

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

315317
// adjust numShift to maintain minClearanceNum if needed
316-
nscoord actualClearanceNum =
317-
(numShift - bmNum.descent) - (axisHeight + actualRuleThickness / 2);
318+
nscoord actualClearanceNum = (numShift - bmNum.descent - numMargin.bottom) -
319+
(axisHeight + actualRuleThickness / 2);
318320
if (actualClearanceNum < minClearanceNum) {
319321
numShift += (minClearanceNum - actualClearanceNum);
320322
}
321323
// adjust denShift to maintain minClearanceDen if needed
322-
nscoord actualClearanceDen =
323-
(axisHeight - actualRuleThickness / 2) - (bmDen.ascent - denShift);
324+
nscoord actualClearanceDen = (axisHeight - actualRuleThickness / 2) -
325+
(bmDen.ascent + denMargin.top - denShift);
324326
if (actualClearanceDen < minClearanceDen) {
325327
denShift += (minClearanceDen - actualClearanceDen);
326328
}
@@ -331,40 +333,59 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
331333

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

339344
mBoundingMetrics.rightBearing =
340-
std::max(dxNum + bmNum.rightBearing, dxDen + bmDen.rightBearing);
345+
std::max(dxNum + bmNum.rightBearing + numMargin.LeftRight(),
346+
dxDen + bmDen.rightBearing + denMargin.LeftRight());
341347
if (mBoundingMetrics.rightBearing < width - rightSpace)
342348
mBoundingMetrics.rightBearing = width - rightSpace;
343349
mBoundingMetrics.leftBearing =
344350
std::min(dxNum + bmNum.leftBearing, dxDen + bmDen.leftBearing);
345351
if (mBoundingMetrics.leftBearing > leftSpace)
346352
mBoundingMetrics.leftBearing = leftSpace;
347-
mBoundingMetrics.ascent = bmNum.ascent + numShift;
348-
mBoundingMetrics.descent = bmDen.descent + denShift;
353+
mBoundingMetrics.ascent = bmNum.ascent + numShift + numMargin.top;
354+
mBoundingMetrics.descent = bmDen.descent + denShift + denMargin.bottom;
349355
mBoundingMetrics.width = width;
350356

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

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

360378
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
361379
nscoord dy;
362380
// place numerator
363-
dy = 0;
381+
dxNum += numMargin.left;
382+
dy = borderPadding.top + numMargin.top;
364383
FinishReflowChild(frameNum, presContext, sizeNum, nullptr, dxNum, dy,
365384
ReflowChildFlags::Default);
366385
// place denominator
367-
dy = aDesiredSize.Height() - sizeDen.Height();
386+
dxDen += denMargin.left;
387+
dy = aDesiredSize.Height() - sizeDen.Height() - denMargin.bottom -
388+
borderPadding.bottom;
368389
FinishReflowChild(frameDen, presContext, sizeDen, nullptr, dxDen, dy,
369390
ReflowChildFlags::Default);
370391
// 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.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[frac-bar-002.html]
2-
expected: FAIL
2+
expected: [PASS, FAIL] # bug 1911053

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)