Bug 415413 - Incorrect widths and heights of MathML with italics in table cells. r=karlt, r=roc

This commit is contained in:
Frédéric Wang 2013-11-25 09:20:20 -05:00
parent 21c334ae00
commit c3a1ac6605
17 changed files with 425 additions and 60 deletions

View File

@ -786,6 +786,67 @@ nsBlockFrame::ComputeTightBounds(gfxContext* aContext) const
return ComputeSimpleTightBounds(aContext);
}
/* virtual */ nsresult
nsBlockFrame::GetPrefWidthTightBounds(nsRenderingContext* aRenderingContext,
nscoord* aX,
nscoord* aXMost)
{
nsIFrame* firstInFlow = FirstContinuation();
if (firstInFlow != this) {
return firstInFlow->GetPrefWidthTightBounds(aRenderingContext, aX, aXMost);
}
*aX = 0;
*aXMost = 0;
nsresult rv;
InlinePrefWidthData data;
for (nsBlockFrame* curFrame = this; curFrame;
curFrame = static_cast<nsBlockFrame*>(curFrame->GetNextContinuation())) {
for (line_iterator line = curFrame->begin_lines(), line_end = curFrame->end_lines();
line != line_end; ++line)
{
nscoord childX, childXMost;
if (line->IsBlock()) {
data.ForceBreak(aRenderingContext);
rv = line->mFirstChild->GetPrefWidthTightBounds(aRenderingContext,
&childX, &childXMost);
NS_ENSURE_SUCCESS(rv, rv);
*aX = std::min(*aX, childX);
*aXMost = std::max(*aXMost, childXMost);
} else {
if (!curFrame->GetPrevContinuation() &&
line == curFrame->begin_lines()) {
// Only add text-indent if it has no percentages; using a
// percentage basis of 0 unconditionally would give strange
// behavior for calc(10%-3px).
const nsStyleCoord &indent = StyleText()->mTextIndent;
if (indent.ConvertsToLength()) {
data.currentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
}
}
// XXX Bug NNNNNN Should probably handle percentage text-indent.
data.line = &line;
data.lineContainer = curFrame;
nsIFrame *kid = line->mFirstChild;
for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
++i, kid = kid->GetNextSibling()) {
rv = kid->GetPrefWidthTightBounds(aRenderingContext, &childX,
&childXMost);
NS_ENSURE_SUCCESS(rv, rv);
*aX = std::min(*aX, data.currentLine + childX);
*aXMost = std::max(*aXMost, data.currentLine + childXMost);
kid->AddInlinePrefWidth(aRenderingContext, &data);
}
}
}
}
data.ForceBreak(aRenderingContext);
return NS_OK;
}
static bool
AvailableSpaceShrunk(const nsRect& aOldAvailableSpace,
const nsRect& aNewAvailableSpace)

View File

@ -261,6 +261,10 @@ public:
virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE;
virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext,
nscoord* aX,
nscoord* aXMost) MOZ_OVERRIDE;
/**
* Compute the final height of this frame.
*

View File

@ -4049,6 +4049,14 @@ nsFrame::ComputeSimpleTightBounds(gfxContext* aContext) const
return r;
}
/* virtual */ nsresult
nsIFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext,
nscoord* aX,
nscoord* aXMost)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* virtual */ nsSize
nsFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
nsSize aCBSize, nscoord aAvailableWidth,

View File

@ -1832,6 +1832,26 @@ public:
*/
virtual nsRect ComputeTightBounds(gfxContext* aContext) const;
/**
* This function is similar to GetPrefWidth and ComputeTightBounds: it
* computes the left and right coordinates of a preferred tight bounding
* rectangle for the frame. This is a rectangle that would enclose the pixels
* that are drawn if we lay out the element without taking any optional line
* breaks. The rectangle is in appunits and relative to the origin of this
* frame. Currently, this function is only implemented for nsBlockFrame and
* nsTextFrame and is used to determine intrinsic widths of MathML token
* elements.
* @param aContext a rendering context that can be used if we need
* to do measurement
* @param aX computed left coordinate of the tight bounding rectangle
* @param aXMost computed intrinsic width of the tight bounding rectangle
*
*/
virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext,
nscoord* aX,
nscoord* aXMost);
/**
* Pre-reflow hook. Before a frame is reflowed this method will be called.
* This call will always be invoked at least once before a subsequent Reflow

View File

@ -2609,17 +2609,20 @@ GetEndOfTrimmedText(const nsTextFragment* aFrag, const nsStyleText* aStyleText,
nsTextFrame::TrimmedOffsets
nsTextFrame::GetTrimmedOffsets(const nsTextFragment* aFrag,
bool aTrimAfter)
bool aTrimAfter, bool aPostReflow)
{
NS_ASSERTION(mTextRun, "Need textrun here");
// This should not be used during reflow. We need our TEXT_REFLOW_FLAGS
// to be set correctly. If our parent wasn't reflowed due to the frame
// tree being too deep then the return value doesn't matter.
NS_ASSERTION(!(GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
(GetParent()->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE),
"Can only call this on frames that have been reflowed");
NS_ASSERTION(!(GetStateBits() & NS_FRAME_IN_REFLOW),
"Can only call this on frames that are not being reflowed");
if (aPostReflow) {
// This should not be used during reflow. We need our TEXT_REFLOW_FLAGS
// to be set correctly. If our parent wasn't reflowed due to the frame
// tree being too deep then the return value doesn't matter.
NS_ASSERTION(!(GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
(GetParent()->GetStateBits() &
NS_FRAME_TOO_DEEP_IN_FRAME_TREE),
"Can only call this on frames that have been reflowed");
NS_ASSERTION(!(GetStateBits() & NS_FRAME_IN_REFLOW),
"Can only call this on frames that are not being reflowed");
}
TrimmedOffsets offsets = { GetContentOffset(), GetContentLength() };
const nsStyleText* textStyle = StyleText();
@ -2628,7 +2631,7 @@ nsTextFrame::GetTrimmedOffsets(const nsTextFragment* aFrag,
if (textStyle->WhiteSpaceIsSignificant())
return offsets;
if (GetStateBits() & TEXT_START_OF_LINE) {
if (!aPostReflow || (GetStateBits() & TEXT_START_OF_LINE)) {
int32_t whitespaceCount =
GetTrimmableWhitespaceCount(aFrag,
offsets.mStart, offsets.mLength, 1);
@ -2636,7 +2639,7 @@ nsTextFrame::GetTrimmedOffsets(const nsTextFragment* aFrag,
offsets.mLength -= whitespaceCount;
}
if (aTrimAfter && (GetStateBits() & TEXT_END_OF_LINE)) {
if (aTrimAfter && (!aPostReflow || (GetStateBits() & TEXT_END_OF_LINE))) {
// This treats a trailing 'pre-line' newline as trimmable. That's fine,
// it's actually what we want since we want whitespace before it to
// be trimmed.
@ -2809,6 +2812,8 @@ public:
// Call this after construction if you're not going to reflow the text
void InitializeForDisplay(bool aTrimAfter);
void InitializeForMeasure();
virtual void GetSpacing(uint32_t aStart, uint32_t aLength, Spacing* aSpacing);
virtual gfxFloat GetHyphenWidth();
virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength,
@ -3249,6 +3254,17 @@ PropertyProvider::InitializeForDisplay(bool aTrimAfter)
SetupJustificationSpacing();
}
void
PropertyProvider::InitializeForMeasure()
{
nsTextFrame::TrimmedOffsets trimmed =
mFrame->GetTrimmedOffsets(mFrag, true, false);
mStart.SetOriginalOffset(trimmed.mStart);
mLength = trimmed.mLength;
SetupJustificationSpacing();
}
static uint32_t GetSkippedDistance(const gfxSkipCharsIterator& aStart,
const gfxSkipCharsIterator& aEnd)
{
@ -7287,6 +7303,31 @@ nsTextFrame::ComputeTightBounds(gfxContext* aContext) const
return RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent);
}
/* virtual */ nsresult
nsTextFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext,
nscoord* aX,
nscoord* aXMost)
{
gfxSkipCharsIterator iter =
const_cast<nsTextFrame*>(this)->EnsureTextRun(nsTextFrame::eInflated);
if (!mTextRun)
return NS_ERROR_FAILURE;
PropertyProvider provider(const_cast<nsTextFrame*>(this), iter,
nsTextFrame::eInflated);
provider.InitializeForMeasure();
gfxTextRun::Metrics metrics =
mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(),
ComputeTransformedLength(provider),
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
aContext->ThebesContext(), &provider);
*aX = metrics.mBoundingBox.x;
*aXMost = metrics.mBoundingBox.XMost();
return NS_OK;
}
static bool
HasSoftHyphenBefore(const nsTextFragment* aFrag, gfxTextRun* aTextRun,
int32_t aStartOffset, const gfxSkipCharsIterator& aIter)

View File

@ -221,6 +221,9 @@ public:
nsSize aMargin, nsSize aBorder, nsSize aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
virtual nsRect ComputeTightBounds(gfxContext* aContext) const MOZ_OVERRIDE;
virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext,
nscoord* aX,
nscoord* aXMost) MOZ_OVERRIDE;
NS_IMETHOD Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aMetrics,
const nsHTMLReflowState& aReflowState,
@ -511,7 +514,7 @@ public:
int32_t GetEnd() const { return mStart + mLength; }
};
TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag,
bool aTrimAfter);
bool aTrimAfter, bool aPostReflow = true);
// Similar to Reflow(), but for use from nsLineLayout
void ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,

View File

@ -29,6 +29,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsMathMLContainerFrame)
NS_QUERYFRAME_HEAD(nsMathMLContainerFrame)
NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
NS_QUERYFRAME_ENTRY(nsMathMLContainerFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
// =============================================================================
@ -985,7 +986,11 @@ nsMathMLContainerFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
{
nscoord result;
DISPLAY_MIN_WIDTH(this, result);
result = GetIntrinsicWidth(aRenderingContext);
nsHTMLReflowMetrics desiredSize;
GetIntrinsicWidthMetrics(aRenderingContext, desiredSize);
nsBoundingMetrics bm = desiredSize.mBoundingMetrics;
// We include the overflow to compensate for FixInterFrameSpacing.
result = std::max(bm.width, bm.rightBearing) - std::min(0, bm.leftBearing);
return result;
}
@ -994,29 +999,46 @@ nsMathMLContainerFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
{
nscoord result;
DISPLAY_MIN_WIDTH(this, result);
result = GetIntrinsicWidth(aRenderingContext);
nsHTMLReflowMetrics desiredSize;
GetIntrinsicWidthMetrics(aRenderingContext, desiredSize);
nsBoundingMetrics bm = desiredSize.mBoundingMetrics;
// We include the overflow to compensate for FixInterFrameSpacing.
result = std::max(bm.width, bm.rightBearing) - std::min(0, bm.leftBearing);
return result;
}
/* virtual */ nscoord
nsMathMLContainerFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext)
/* virtual */ void
nsMathMLContainerFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize)
{
// Get child widths
nsIFrame* childFrame = mFrames.FirstChild();
while (childFrame) {
// 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,
nsLayoutUtils::PREF_WIDTH);
nsHTMLReflowMetrics childDesiredSize;
childDesiredSize.width = width;
childDesiredSize.mBoundingMetrics.width = width;
// TODO: we need nsIFrame::GetIntrinsicHBounds() for better values here.
childDesiredSize.mBoundingMetrics.leftBearing = 0;
childDesiredSize.mBoundingMetrics.rightBearing = width;
nsMathMLContainerFrame* containerFrame = do_QueryFrame(childFrame);
if (containerFrame) {
containerFrame->GetIntrinsicWidthMetrics(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,
nsLayoutUtils::PREF_WIDTH);
childDesiredSize.width = width;
childDesiredSize.mBoundingMetrics.width = width;
childDesiredSize.mBoundingMetrics.leftBearing = 0;
childDesiredSize.mBoundingMetrics.rightBearing = width;
nscoord x, xMost;
if (NS_SUCCEEDED(childFrame->GetPrefWidthTightBounds(aRenderingContext,
&x, &xMost))) {
childDesiredSize.mBoundingMetrics.leftBearing = x;
childDesiredSize.mBoundingMetrics.rightBearing = xMost;
}
}
SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
childDesiredSize.mBoundingMetrics);
@ -1025,15 +1047,12 @@ nsMathMLContainerFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext)
}
// Measure
nsHTMLReflowMetrics desiredSize;
nsresult rv = MeasureForWidth(*aRenderingContext, desiredSize);
nsresult rv = MeasureForWidth(*aRenderingContext, aDesiredSize);
if (NS_FAILED(rv)) {
ReflowError(*aRenderingContext, desiredSize);
ReflowError(*aRenderingContext, aDesiredSize);
}
ClearSavedChildMetrics();
return desiredSize.width;
}
/* virtual */ nsresult

View File

@ -33,6 +33,7 @@ class nsMathMLContainerFrame : public nsContainerFrame,
public:
nsMathMLContainerFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {}
NS_DECL_QUERYFRAME_TARGET(nsMathMLContainerFrame)
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS
@ -92,16 +93,18 @@ public:
nsIFrame* aOldFrame) MOZ_OVERRIDE;
/**
* Both GetMinWidth and GetPrefWidth return whatever
* GetIntrinsicWidth returns.
* Both GetMinWidth and GetPrefWidth use the intrinsic width metrics
* returned by GetIntrinsicMetrics, including ink overflow.
*/
virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
/**
* Return the intrinsic width of the frame's content area.
* Return the intrinsic horizontal metrics of the frame's content area.
*/
virtual nscoord GetIntrinsicWidth(nsRenderingContext *aRenderingContext);
virtual void
GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext,
nsHTMLReflowMetrics& aDesiredSize);
NS_IMETHOD
Reflow(nsPresContext* aPresContext,

View File

@ -564,8 +564,8 @@ GetMaxCharWidth(nsPresContext* aPresContext,
return width;
}
/* virtual */ nscoord
nsMathMLmfencedFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext)
/* virtual */ void
nsMathMLmfencedFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize)
{
nscoord width = 0;
@ -607,7 +607,10 @@ nsMathMLmfencedFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext)
NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel, em);
}
return width;
aDesiredSize.width = width;
aDesiredSize.mBoundingMetrics.width = width;
aDesiredSize.mBoundingMetrics.leftBearing = 0;
aDesiredSize.mBoundingMetrics.rightBearing = width;
}
nscoord

View File

@ -42,8 +42,9 @@ public:
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists) MOZ_OVERRIDE;
virtual nscoord
GetIntrinsicWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE;
virtual void
GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext,
nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
NS_IMETHOD
AttributeChanged(int32_t aNameSpaceID,

View File

@ -986,28 +986,36 @@ nsMathMLmoFrame::MarkIntrinsicWidthsDirty()
nsMathMLContainerFrame::MarkIntrinsicWidthsDirty();
}
/* virtual */ nscoord
nsMathMLmoFrame::GetIntrinsicWidth(nsRenderingContext *aRenderingContext)
/* virtual */ void
nsMathMLmoFrame::GetIntrinsicWidthMetrics(nsRenderingContext *aRenderingContext, nsHTMLReflowMetrics& aDesiredSize)
{
ProcessOperatorData();
nscoord width;
if (UseMathMLChar()) {
uint32_t stretchHint = GetStretchHint(mFlags, mPresentationData, true);
width = mMathMLChar.
aDesiredSize.width = mMathMLChar.
GetMaxWidth(PresContext(), *aRenderingContext,
stretchHint, mMaxSize,
NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags));
}
else {
width = nsMathMLTokenFrame::GetIntrinsicWidth(aRenderingContext);
nsMathMLTokenFrame::GetIntrinsicWidthMetrics(aRenderingContext,
aDesiredSize);
}
// leadingSpace and trailingSpace are actually applied to the outermost
// embellished container but for determining total intrinsic width it should
// be safe to include it for the core here instead.
width += mEmbellishData.leadingSpace + mEmbellishData.trailingSpace;
return width;
bool isRTL = StyleVisibility()->mDirection;
aDesiredSize.width +=
mEmbellishData.leadingSpace + mEmbellishData.trailingSpace;
aDesiredSize.mBoundingMetrics.width = aDesiredSize.width;
if (isRTL) {
aDesiredSize.mBoundingMetrics.leftBearing += mEmbellishData.trailingSpace;
aDesiredSize.mBoundingMetrics.rightBearing += mEmbellishData.trailingSpace;
} else {
aDesiredSize.mBoundingMetrics.leftBearing += mEmbellishData.leadingSpace;
aDesiredSize.mBoundingMetrics.rightBearing += mEmbellishData.leadingSpace;
}
}
NS_IMETHODIMP

View File

@ -46,8 +46,9 @@ public:
virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE;
virtual nscoord
GetIntrinsicWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
virtual void
GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext,
nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
NS_IMETHOD
AttributeChanged(int32_t aNameSpaceID,

View File

@ -350,17 +350,16 @@ nsMathMLmrootFrame::Reflow(nsPresContext* aPresContext,
return NS_OK;
}
/* virtual */ nscoord
nsMathMLmrootFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext)
/* virtual */ void
nsMathMLmrootFrame::GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext, nsHTMLReflowMetrics& aDesiredSize)
{
nsIFrame* baseFrame = mFrames.FirstChild();
nsIFrame* indexFrame = nullptr;
if (baseFrame)
indexFrame = baseFrame->GetNextSibling();
if (!indexFrame || indexFrame->GetNextSibling()) {
nsHTMLReflowMetrics desiredSize;
ReflowError(*aRenderingContext, desiredSize);
return desiredSize.width;
ReflowError(*aRenderingContext, aDesiredSize);
return;
}
nscoord baseWidth =
@ -375,7 +374,12 @@ nsMathMLmrootFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext)
GetRadicalXOffsets(indexWidth, sqrWidth, aRenderingContext->FontMetrics(),
nullptr, &dxSqr);
return dxSqr + sqrWidth + baseWidth;
nscoord width = dxSqr + sqrWidth + baseWidth;
aDesiredSize.width = width;
aDesiredSize.mBoundingMetrics.width = width;
aDesiredSize.mBoundingMetrics.leftBearing = 0;
aDesiredSize.mBoundingMetrics.rightBearing = width;
}
// ----------------------

View File

@ -40,8 +40,9 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus) MOZ_OVERRIDE;
virtual nscoord
GetIntrinsicWidth(nsRenderingContext* aRenderingContext) MOZ_OVERRIDE;
virtual void
GetIntrinsicWidthMetrics(nsRenderingContext* aRenderingContext,
nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,

View File

@ -39,6 +39,7 @@ skip-if(B2G) == quotes-1.xhtml quotes-1-ref.xhtml
!= stretchy-underbar-1.xhtml stretchy-underbar-1-ref.xhtml
== table-width-1.xhtml table-width-1-ref.xhtml
== table-width-2.html table-width-2-ref.html
fails-if(OSX||/^Windows\x20NT\x206\.[12]/.test(http.oscpu)||Android) == table-width-3.html table-width-3-ref.html
== underbar-width-1.xhtml underbar-width-1-ref.xhtml
== mathml-type-supported.xhtml mathml-type-supported-ref.xml
== mtable-align-negative-rownumber.html mtable-align-negative-rownumber-ref.html

View File

@ -0,0 +1,100 @@
<!doctype>
<html>
<head>
<title>table-width-3</title>
<meta charset="utf-8"/>
<style type="text/css">
html { background-color: grey; }
td { border: 1px solid white;
padding: 0;
background-color: black;
color: red; }
mi, mtext { font-size: 3em; }
span { font-style: italic; display: inline-block; }
</style>
</head>
<body>
<table>
<tr>
<td>
<math>
<mphantom>
<mi>f</mi>
</mphantom>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mphantom>
<mi>f</mi>
</mphantom>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mphantom>
<mi>f</mi>
<mi>f</mi>
<mi>f</mi>
</mphantom>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mphantom>
<mi style="font-style: italic;">fff</mi>
</mphantom>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mphantom>
<mtext><span>fff</span></mtext>
</mphantom>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mphantom>
<mtext><span>f</span></mtext>
<mtext><span>f</span></mtext>
<mtext><span>f</span></mtext>
</mphantom>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mphantom>
<mtext><span>f</span><span>f</span><span>f</span></mtext>
</mphantom>
</math>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,87 @@
<!doctype>
<html>
<head>
<title>table-width-3</title>
<meta charset="utf-8"/>
<style type="text/css">
html { background-color: grey; }
td { border: 1px solid white;
padding: 0;
background-color: black;
color: black; }
mi, mtext { font-size: 3em; }
span { font-style: italic; display: inline-block; }
</style>
</head>
<body>
<table>
<tr>
<td>
<math>
<mi>f</mi>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mi> f </mi>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mi>f</mi>
<mi>f</mi>
<mi>f</mi>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mi style="font-style: italic;">fff</mi>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mtext><span>fff</span></mtext>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mtext><span>f</span></mtext>
<mtext><span>f</span></mtext>
<mtext><span>f</span></mtext>
</math>
</td>
</tr>
</table>
<table>
<tr>
<td>
<math>
<mtext><span>f</span><span>f</span><span>f</span></mtext>
</math>
</td>
</tr>
</table>
</body>
</html>