Skip to content

Commit

Permalink
Bug 1908069 - Introduce PlaceFlags parameter to MathML layout methods…
Browse files Browse the repository at this point in the history
…. r=emilio

MathML classes has a few Place*() methods  used for layout and intrinsic
size calculation. These methods have a parameter "aPlaceOrigin"
indicating whether the children and other painted objects should have
their final positions set, or if the method is only called for measuring.
This parameter is typically set to false when doing intrinsic size
calculation or when performing some non-final measurement for operator
stretching.

For intrinsic size calculation, it is generally enough to perform
placement with aPlaceOrigin=false and ignoring the vertical metrics.
Some Place*() methods also have a parameter "aWidthOnly" for special
handling. For example, msqrt stretches a radical symbol vertically to
match the height of the content but when doing intrinsic size
calculation this is approximated to nsMathMLChar::GetMaxWidth() instead.
When we implement border/padding/margin we should also be able to
choose between using IntrinsicISizeOffsets() or GetUsed*() methods.

Finally, some Place*() methods initially call a place routing of a
parent class before further tweaking the layout. For example, msqrt
uses mrow layout on children and adds some radical symbol on top of
them. When we implement border/padding, we should make sure we don't
add the border/padding before the final result.

In order to handle all these placement behaviors, a new EnumSet is
introduced. This commit does not change behavior. Handling of padding,
border and margin will be handled in follow-up patches.

Differential Revision: https://phabricator.services.mozilla.com/D216669
  • Loading branch information
fred-wang committed Jul 31, 2024
1 parent b8569b3 commit 06acefd
Show file tree
Hide file tree
Showing 17 changed files with 154 additions and 114 deletions.
35 changes: 20 additions & 15 deletions layout/mathml/nsMathMLContainerFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ void nsMathMLContainerFrame::GetPreferredStretchSize(
// when our actual size is ok, just use it
aPreferredStretchSize = mBoundingMetrics;
} else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) {
// compute our up-to-date size using Place()
// compute our up-to-date size using Place(), without border/padding.
ReflowOutput reflowOutput(GetWritingMode());
Place(aDrawTarget, false, reflowOutput);
Place(aDrawTarget,
PlaceFlags(PlaceFlag::MeasureOnly, PlaceFlag::IgnoreBorderPadding),
reflowOutput);
aPreferredStretchSize = reflowOutput.mBoundingMetrics;
} else {
// compute a size that includes embellishments iff the container stretches
Expand Down Expand Up @@ -296,7 +298,7 @@ nsMathMLContainerFrame::Stretch(DrawTarget* aDrawTarget,
}

// re-position all our children
nsresult rv = Place(aDrawTarget, true, aDesiredStretchSize);
nsresult rv = Place(aDrawTarget, PlaceFlags(), aDesiredStretchSize);
if (NS_FAILED(rv)) {
// Make sure the child frames get their DidReflow() calls.
DidReflowChildren(mFrames.FirstChild());
Expand Down Expand Up @@ -378,14 +380,16 @@ nsresult nsMathMLContainerFrame::FinalizeReflow(DrawTarget* aDrawTarget,
!NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
(mEmbellishData.coreFrame != this && !mPresentationData.baseFrame &&
mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED);
nsresult rv = Place(aDrawTarget, placeOrigin, aDesiredSize);
nsresult rv =
Place(aDrawTarget, placeOrigin ? PlaceFlags() : PlaceFlag::MeasureOnly,
aDesiredSize);

// Place() will call FinishReflowChild() when placeOrigin is true but if
// it returns before reaching FinishReflowChild() due to errors we need
// to fulfill the reflow protocol by calling DidReflow for the child frames
// that still needs it here (or we may crash - bug 366012).
// If placeOrigin is false we should reach Place() with aPlaceOrigin == true
// through Stretch() eventually.
// If placeOrigin is false we should reach Place() with
// PlaceFlag::MeasureOnly unset through Stretch() eventually.
if (NS_FAILED(rv)) {
GatherAndStoreOverflow(&aDesiredSize);
DidReflowChildren(PrincipalChildList().FirstChild());
Expand Down Expand Up @@ -865,9 +869,6 @@ void nsMathMLContainerFrame::GetIntrinsicISizeMetrics(
containerFrame->GetIntrinsicISizeMetrics(aRenderingContext,
childDesiredSize);
} else {
// XXX This includes margin while Reflow currently doesn't consider
// margin, so we may end up with too much space, but, with stretchy
// characters, this is an approximation anyway.
nscoord width = nsLayoutUtils::IntrinsicForContainer(
aRenderingContext, childFrame, IntrinsicISizeType::PrefISize);

Expand All @@ -894,7 +895,9 @@ void nsMathMLContainerFrame::GetIntrinsicISizeMetrics(
nsresult rv =
MeasureForWidth(aRenderingContext->GetDrawTarget(), aDesiredSize);
if (NS_FAILED(rv)) {
PlaceAsMrow(aRenderingContext->GetDrawTarget(), false, aDesiredSize);
PlaceAsMrow(aRenderingContext->GetDrawTarget(),
PlaceFlags(PlaceFlag::IntrinsicSize, PlaceFlag::MeasureOnly),
aDesiredSize);
}

ClearSavedChildMetrics();
Expand All @@ -903,7 +906,9 @@ void nsMathMLContainerFrame::GetIntrinsicISizeMetrics(
/* virtual */
nsresult nsMathMLContainerFrame::MeasureForWidth(DrawTarget* aDrawTarget,
ReflowOutput& aDesiredSize) {
return Place(aDrawTarget, false, aDesiredSize);
return Place(aDrawTarget,
PlaceFlags(PlaceFlag::IntrinsicSize, PlaceFlag::MeasureOnly),
aDesiredSize);
}

// see spacing table in Chapter 18, TeXBook (p.170)
Expand Down Expand Up @@ -1107,7 +1112,7 @@ class nsMathMLContainerFrame::RowChildFrameIterator {

/* virtual */
nsresult nsMathMLContainerFrame::Place(DrawTarget* aDrawTarget,
bool aPlaceOrigin,
const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) {
// This is needed in case this frame is empty (i.e., no child frames)
mBoundingMetrics = nsBoundingMetrics();
Expand Down Expand Up @@ -1139,17 +1144,17 @@ nsresult nsMathMLContainerFrame::Place(DrawTarget* aDrawTarget,
//////////////////
// Place Children

if (aPlaceOrigin) {
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
PositionRowChildFrames(0, aDesiredSize.BlockStartAscent());
}

return NS_OK;
}

nsresult nsMathMLContainerFrame::PlaceAsMrow(DrawTarget* aDrawTarget,
bool aPlaceOrigin,
const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) {
return nsMathMLContainerFrame::Place(aDrawTarget, aPlaceOrigin, aDesiredSize);
return nsMathMLContainerFrame::Place(aDrawTarget, aFlags, aDesiredSize);
}

void nsMathMLContainerFrame::PositionRowChildFrames(nscoord aOffsetX,
Expand Down
47 changes: 33 additions & 14 deletions layout/mathml/nsMathMLContainerFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,37 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
// Additional methods

protected:
enum class PlaceFlag : uint8_t {
// If MeasureOnly is set, compute your desired size using the information
// from GetReflowAndBoundingMetricsFor. However, child frames or other
// elements should not be repositioned.
// If MeasureOnly is not set, reflow is finished. You should position all
// your children, and return your desired size. You should now use
// FinishReflowChild() on your children to complete post-reflow operations.
MeasureOnly,

// If IntrinsicSize is set, the function is actually used to determine
// intrinsic size (and consequently MeasureOnly is expected to be set too).
// - It will use nsMathMLChar::GetMaxWidth instead of nsMathMLChar::Stretch.
// - It will use IntrinsicISizeOffsets() for padding/border/margin instead
// of GetUsedBorder/Padding/Margin().
// - etc
IntrinsicSize,

// If IgnoreBorderPadding is set, the function will complete without
// adding the border/padding around the math layout. This can be used for
// elements like <msqrt> that first layout their children as an <mrow>,
// place some radical symbol on top of them and finally add its
// padding/border around that radical symbol.
IgnoreBorderPadding,
};
using PlaceFlags = mozilla::EnumSet<PlaceFlag>;

/* Place :
* This method is used to measure or position child frames and other
* elements. It may be called any number of times with aPlaceOrigin
* false to measure, and the final call of the Reflow process before
* returning from Reflow() or Stretch() will have aPlaceOrigin true
* elements. It may be called any number of times with MeasureOnly
* true, and the final call of the Reflow process before
* returning from Reflow() or Stretch() will have MeasureOnly false
* to position the elements.
*
* IMPORTANT: This method uses GetReflowAndBoundingMetricsFor() which must
Expand All @@ -146,23 +172,16 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
* The Place() method will use this information to compute the desired size
* of the frame.
*
* @param aPlaceOrigin [in]
* If aPlaceOrigin is false, compute your desired size using the
* information from GetReflowAndBoundingMetricsFor. However, child
* frames or other elements should not be repositioned.
*
* If aPlaceOrigin is true, reflow is finished. You should position
* all your children, and return your desired size. You should now
* use FinishReflowChild() on your children to complete post-reflow
* operations.
* @param aFlags [in] Flags to indicate the way the Place method should
* behave. See document for PlaceFlag above.
*
* @param aDesiredSize [out] parameter where you should return your desired
* size and your ascent/descent info. Compute your desired size using
* the information from GetReflowAndBoundingMetricsFor, and include
* any space you want for border/padding in the desired size you
* return.
*/
virtual nsresult Place(DrawTarget* aDrawTarget, bool aPlaceOrigin,
virtual nsresult Place(DrawTarget* aDrawTarget, const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize);

// MeasureForWidth:
Expand Down Expand Up @@ -197,7 +216,7 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
* (typically invalid markup) was encountered during reflow. Parameters are
* the same as Place().
*/
nsresult PlaceAsMrow(DrawTarget* aDrawTarget, bool aPlaceOrigin,
nsresult PlaceAsMrow(DrawTarget* aDrawTarget, const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize);

/*
Expand Down
5 changes: 3 additions & 2 deletions layout/mathml/nsMathMLTokenFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ void nsMathMLTokenFrame::Reflow(nsPresContext* aPresContext,
// pass, it is not computed here because our children may be text frames
// that do not implement the GetBoundingMetrics() interface.
/* virtual */
nsresult nsMathMLTokenFrame::Place(DrawTarget* aDrawTarget, bool aPlaceOrigin,
nsresult nsMathMLTokenFrame::Place(DrawTarget* aDrawTarget,
const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) {
mBoundingMetrics = nsBoundingMetrics();
for (nsIFrame* childFrame : PrincipalChildList()) {
Expand All @@ -171,7 +172,7 @@ nsresult nsMathMLTokenFrame::Place(DrawTarget* aDrawTarget, bool aPlaceOrigin,
aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
std::max(mBoundingMetrics.descent, descent);

if (aPlaceOrigin) {
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
nscoord dy, dx = 0;
for (nsIFrame* childFrame : PrincipalChildList()) {
ReflowOutput childSize(aDesiredSize.GetWritingMode());
Expand Down
4 changes: 2 additions & 2 deletions layout/mathml/nsMathMLTokenFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class nsMathMLTokenFrame : public nsMathMLContainerFrame {
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;

virtual nsresult Place(DrawTarget* aDrawTarget, bool aPlaceOrigin,
ReflowOutput& aDesiredSize) override;
nsresult Place(DrawTarget* aDrawTarget, const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) override;

protected:
explicit nsMathMLTokenFrame(ComputedStyle* aStyle,
Expand Down
27 changes: 16 additions & 11 deletions layout/mathml/nsMathMLmencloseFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,26 +299,31 @@ void nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
/* virtual */
nsresult nsMathMLmencloseFrame::MeasureForWidth(DrawTarget* aDrawTarget,
ReflowOutput& aDesiredSize) {
return PlaceInternal(aDrawTarget, false, aDesiredSize, true);
return PlaceInternal(
aDrawTarget, PlaceFlags(PlaceFlag::IntrinsicSize, PlaceFlag::MeasureOnly),
aDesiredSize);
}

/* virtual */
nsresult nsMathMLmencloseFrame::Place(DrawTarget* aDrawTarget,
bool aPlaceOrigin,
const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) {
return PlaceInternal(aDrawTarget, aPlaceOrigin, aDesiredSize, false);
return PlaceInternal(aDrawTarget, aFlags, aDesiredSize);
}

/* virtual */
nsresult nsMathMLmencloseFrame::PlaceInternal(DrawTarget* aDrawTarget,
bool aPlaceOrigin,
ReflowOutput& aDesiredSize,
bool aWidthOnly) {
const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) {
///////////////
// Measure the size of our content using the base class to format like an
// inferred mrow.
// inferred mrow, without border/padding.
ReflowOutput baseSize(aDesiredSize.GetWritingMode());
nsresult rv = nsMathMLContainerFrame::Place(aDrawTarget, false, baseSize);
nsresult rv = nsMathMLContainerFrame::Place(
aDrawTarget,
aFlags +
PlaceFlags(PlaceFlag::MeasureOnly, PlaceFlag::IgnoreBorderPadding),
baseSize);

if (NS_FAILED(rv)) {
DidReflowChildren(PrincipalChildList().FirstChild());
Expand Down Expand Up @@ -461,7 +466,7 @@ nsresult nsMathMLmencloseFrame::PlaceInternal(DrawTarget* aDrawTarget,
///////////////
// longdiv notation:
if (IsToDraw(NOTATION_LONGDIV)) {
if (aWidthOnly) {
if (aFlags.contains(PlaceFlag::IntrinsicSize)) {
nscoord longdiv_width = mMathMLChar[mLongDivCharIndex].GetMaxWidth(
this, aDrawTarget, fontSizeInflation);

Expand Down Expand Up @@ -503,7 +508,7 @@ nsresult nsMathMLmencloseFrame::PlaceInternal(DrawTarget* aDrawTarget,
? &dx_right
: &dx_left;

if (aWidthOnly) {
if (aFlags.contains(PlaceFlag::IntrinsicSize)) {
nscoord radical_width = mMathMLChar[mRadicalCharIndex].GetMaxWidth(
this, aDrawTarget, fontSizeInflation);

Expand Down Expand Up @@ -627,7 +632,7 @@ nsresult nsMathMLmencloseFrame::PlaceInternal(DrawTarget* aDrawTarget,
mReference.x = 0;
mReference.y = aDesiredSize.BlockStartAscent();

if (aPlaceOrigin) {
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
//////////////////
// Set position and size of MathMLChars
if (IsToDraw(NOTATION_LONGDIV))
Expand Down
8 changes: 4 additions & 4 deletions layout/mathml/nsMathMLmencloseFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class nsMathMLmencloseFrame : public nsMathMLContainerFrame {
friend nsIFrame* NS_NewMathMLmencloseFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle);

virtual nsresult Place(DrawTarget* aDrawTarget, bool aPlaceOrigin,
ReflowOutput& aDesiredSize) override;
nsresult Place(DrawTarget* aDrawTarget, const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) override;

virtual nsresult MeasureForWidth(DrawTarget* aDrawTarget,
ReflowOutput& aDesiredSize) override;
Expand Down Expand Up @@ -86,8 +86,8 @@ class nsMathMLmencloseFrame : public nsMathMLContainerFrame {
ClassID aID = kClassID);
virtual ~nsMathMLmencloseFrame();

nsresult PlaceInternal(DrawTarget* aDrawTarget, bool aPlaceOrigin,
ReflowOutput& aDesiredSize, bool aWidthOnly);
nsresult PlaceInternal(DrawTarget* aDrawTarget, const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize);

// functions to parse the "notation" attribute.
nsresult AddNotation(const nsAString& aNotation);
Expand Down
20 changes: 11 additions & 9 deletions layout/mathml/nsMathMLmfracFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ nsresult nsMathMLmfracFrame::AttributeChanged(int32_t aNameSpaceID,
/* virtual */
nsresult nsMathMLmfracFrame::MeasureForWidth(DrawTarget* aDrawTarget,
ReflowOutput& aDesiredSize) {
return PlaceInternal(aDrawTarget, false, aDesiredSize, true);
return PlaceInternal(
aDrawTarget, PlaceFlags(PlaceFlag::IntrinsicSize, PlaceFlag::MeasureOnly),
aDesiredSize);
}

nscoord nsMathMLmfracFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize) {
Expand All @@ -142,15 +144,15 @@ nscoord nsMathMLmfracFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize) {
}

/* virtual */
nsresult nsMathMLmfracFrame::Place(DrawTarget* aDrawTarget, bool aPlaceOrigin,
nsresult nsMathMLmfracFrame::Place(DrawTarget* aDrawTarget,
const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) {
return PlaceInternal(aDrawTarget, aPlaceOrigin, aDesiredSize, false);
return PlaceInternal(aDrawTarget, aFlags, aDesiredSize);
}

nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
bool aPlaceOrigin,
ReflowOutput& aDesiredSize,
bool aWidthOnly) {
const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) {
////////////////////////////////////
// Get the children's desired sizes
nsBoundingMetrics bmNum, bmDen;
Expand All @@ -161,10 +163,10 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
if (frameNum) frameDen = frameNum->GetNextSibling();
if (!frameNum || !frameDen || frameDen->GetNextSibling()) {
// report an error, encourage people to get their markups in order
if (aPlaceOrigin) {
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
ReportChildCountError();
}
return PlaceAsMrow(aDrawTarget, aPlaceOrigin, aDesiredSize);
return PlaceAsMrow(aDrawTarget, aFlags, aDesiredSize);
}
GetReflowAndBoundingMetricsFor(frameNum, sizeNum, bmNum);
GetReflowAndBoundingMetricsFor(frameDen, sizeDen, bmDen);
Expand Down Expand Up @@ -356,7 +358,7 @@ nsresult nsMathMLmfracFrame::PlaceInternal(DrawTarget* aDrawTarget,
mReference.x = 0;
mReference.y = aDesiredSize.BlockStartAscent();

if (aPlaceOrigin) {
if (!aFlags.contains(PlaceFlag::MeasureOnly)) {
nscoord dy;
// place numerator
dy = 0;
Expand Down
8 changes: 4 additions & 4 deletions layout/mathml/nsMathMLmfracFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ class nsMathMLmfracFrame final : public nsMathMLContainerFrame {
virtual nsresult MeasureForWidth(DrawTarget* aDrawTarget,
ReflowOutput& aDesiredSize) override;

virtual nsresult Place(DrawTarget* aDrawTarget, bool aPlaceOrigin,
ReflowOutput& aDesiredSize) override;
nsresult Place(DrawTarget* aDrawTarget, const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize) override;

virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
Expand Down Expand Up @@ -98,8 +98,8 @@ class nsMathMLmfracFrame final : public nsMathMLContainerFrame {
mLineThickness(0) {}
virtual ~nsMathMLmfracFrame();

nsresult PlaceInternal(DrawTarget* aDrawTarget, bool aPlaceOrigin,
ReflowOutput& aDesiredSize, bool aWidthOnly);
nsresult PlaceInternal(DrawTarget* aDrawTarget, const PlaceFlags& aFlags,
ReflowOutput& aDesiredSize);

// Display a slash
void DisplaySlash(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
Expand Down
Loading

0 comments on commit 06acefd

Please sign in to comment.