Bug 875294 - Implement menclose notation "updiagonalarrow". r=karlt

This commit is contained in:
Frédéric Wang 2013-06-04 08:21:25 -04:00
parent efa209c027
commit fa7da46873
5 changed files with 94 additions and 8 deletions

View File

@ -29,6 +29,9 @@ static const PRUnichar kLongDivChar = ')';
// radical: 'SQUARE ROOT'
static const PRUnichar kRadicalChar = 0x221A;
// updiagonalstrike
static const uint8_t kArrowHeadSize = 10;
nsIFrame*
NS_NewMathMLmencloseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
@ -115,6 +118,8 @@ nsresult nsMathMLmencloseFrame::AddNotation(const nsAString& aNotation)
mNotationsToDraw |= NOTATION_BOTTOM;
} else if (aNotation.EqualsLiteral("updiagonalstrike")) {
mNotationsToDraw |= NOTATION_UPDIAGONALSTRIKE;
} else if (aNotation.EqualsLiteral("updiagonalarrow")) {
mNotationsToDraw |= NOTATION_UPDIAGONALARROW;
} else if (aNotation.EqualsLiteral("downdiagonalstrike")) {
mNotationsToDraw |= NOTATION_DOWNDIAGONALSTRIKE;
} else if (aNotation.EqualsLiteral("verticalstrike")) {
@ -146,6 +151,14 @@ void nsMathMLmencloseFrame::InitNotations()
while (tokenizer.hasMoreTokens())
AddNotation(tokenizer.nextToken());
if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
// For <menclose notation="updiagonalstrike updiagonalarrow">, if
// the two notations are drawn then the strike line may cause the point of
// the arrow to be too wide. Hence we will only draw the updiagonalarrow
// and the arrow shaft may be thought to be the updiagonalstrike.
mNotationsToDraw &= ~NOTATION_UPDIAGONALSTRIKE;
}
} else {
// default: longdiv
if (NS_FAILED(AllocateMathMLChar(NOTATION_LONGDIV)))
@ -251,6 +264,11 @@ nsMathMLmencloseFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mRuleThickness, NOTATION_UPDIAGONALSTRIKE);
}
if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
DisplayNotation(aBuilder, this, mencloseRect, aLists,
mRuleThickness, NOTATION_UPDIAGONALARROW);
}
if (IsToDraw(NOTATION_DOWNDIAGONALSTRIKE)) {
DisplayNotation(aBuilder, this, mencloseRect, aLists,
mRuleThickness, NOTATION_DOWNDIAGONALSTRIKE);
@ -370,6 +388,7 @@ nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
if (IsToDraw(NOTATION_RIGHT) ||
IsToDraw(NOTATION_LEFT) ||
IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
IsToDraw(NOTATION_UPDIAGONALARROW) ||
IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
IsToDraw(NOTATION_VERTICALSTRIKE) ||
IsToDraw(NOTATION_CIRCLE) ||
@ -398,6 +417,21 @@ nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
IsToDraw(NOTATION_CIRCLE))
mBoundingMetrics.descent += padding;
///////////////
// updiagonal arrow notation. We need enough space at the top right corner to
// draw the arrow head.
if (IsToDraw(NOTATION_UPDIAGONALARROW)) {
// This is an estimate, see nsDisplayNotation::Paint for the exact head size
nscoord arrowHeadSize = kArrowHeadSize * mRuleThickness;
// We want that the arrow shaft strikes the menclose content and that the
// arrow head does not overlap with that content. Hence we add some space
// on the right. We don't add space on the top but only ensure that the
// ascent is large enough.
dx_right = std::max(dx_right, arrowHeadSize);
mBoundingMetrics.ascent = std::max(mBoundingMetrics.ascent, arrowHeadSize);
}
///////////////
// circle notation: we don't want the ellipse to overlap the enclosed
// content. Hence, we need to increase the size of the bounding box by a
@ -568,6 +602,7 @@ nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
IsToDraw(NOTATION_RIGHT) ||
IsToDraw(NOTATION_LEFT) ||
IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
IsToDraw(NOTATION_UPDIAGONALARROW) ||
IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
IsToDraw(NOTATION_VERTICALSTRIKE) ||
IsToDraw(NOTATION_CIRCLE) ||
@ -578,6 +613,7 @@ nsMathMLmencloseFrame::PlaceInternal(nsRenderingContext& aRenderingContext,
IsToDraw(NOTATION_RIGHT) ||
IsToDraw(NOTATION_LEFT) ||
IsToDraw(NOTATION_UPDIAGONALSTRIKE) ||
IsToDraw(NOTATION_UPDIAGONALARROW) ||
IsToDraw(NOTATION_DOWNDIAGONALSTRIKE) ||
IsToDraw(NOTATION_VERTICALSTRIKE) ||
IsToDraw(NOTATION_CIRCLE) ||
@ -714,30 +750,63 @@ void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder,
// change line width to mThickness
gfxContext *gfxCtx = aCtx->ThebesContext();
gfxFloat currentLineWidth = gfxCtx->CurrentLineWidth();
gfxFloat e = presContext->AppUnitsToGfxUnits(mThickness);
gfxCtx->Save();
gfxCtx->SetLineWidth(e);
rect.Deflate(e / 2.0);
gfxCtx->NewPath();
switch(mType)
{
case NOTATION_CIRCLE:
gfxCtx->NewPath();
gfxCtx->Ellipse(rect.Center(), rect.Size());
gfxCtx->Stroke();
break;
case NOTATION_ROUNDEDBOX:
gfxCtx->NewPath();
gfxCtx->RoundedRectangle(rect, gfxCornerSizes(3 * e), true);
gfxCtx->Stroke();
break;
case NOTATION_UPDIAGONALSTRIKE:
gfxCtx->NewPath();
gfxCtx->Line(rect.BottomLeft(), rect.TopRight());
gfxCtx->Stroke();
break;
case NOTATION_DOWNDIAGONALSTRIKE:
gfxCtx->NewPath();
gfxCtx->Line(rect.TopLeft(), rect.BottomRight());
gfxCtx->Stroke();
break;
case NOTATION_UPDIAGONALARROW: {
// Compute some parameters to draw the updiagonalarrow. The values below
// are taken from MathJax's HTML-CSS output.
gfxFloat W = rect.Width(); gfxFloat H = rect.Height();
gfxFloat l = sqrt(W*W + H*H);
gfxFloat f = gfxFloat(kArrowHeadSize) * e / l;
gfxFloat w = W * f; gfxFloat h = H * f;
// Draw the arrow shaft
gfxCtx->NewPath();
gfxCtx->Line(rect.BottomLeft(), rect.TopRight() + gfxPoint(-.7*w, .7*h));
gfxCtx->Stroke();
// Draw the arrow head
gfxCtx->NewPath();
gfxPoint p[] = {
rect.TopRight(),
rect.TopRight() + gfxPoint(-w -.4*h, std::max(-e / 2.0, h - .4*w)),
rect.TopRight() + gfxPoint(-.7*w, .7*h),
rect.TopRight() + gfxPoint(std::min(e / 2.0, -w + .4*h), h + .4*w),
rect.TopRight()
};
gfxCtx->Polygon(p, sizeof(p));
gfxCtx->Fill();
}
break;
default:
@ -745,10 +814,7 @@ void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder,
break;
}
gfxCtx->Stroke();
// restore previous line width
gfxCtx->SetLineWidth(currentLineWidth);
gfxCtx->Restore();
}
void

View File

@ -38,7 +38,8 @@ enum nsMencloseNotation
NOTATION_UPDIAGONALSTRIKE = 0x100,
NOTATION_DOWNDIAGONALSTRIKE = 0x200,
NOTATION_VERTICALSTRIKE = 0x400,
NOTATION_HORIZONTALSTRIKE = 0x800
NOTATION_HORIZONTALSTRIKE = 0x800,
NOTATION_UPDIAGONALARROW = 0x1000
};
class nsMathMLmencloseFrame : public nsMathMLContainerFrame {

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head><title>Updiagonalarrow</title></head>
<body>
<p><math><menclose notation="updiagonalstrike"><mspace width="50px" height="50px"/></menclose></math></p>
</body>
</html>

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head><title>Updiagonalarrow</title></head>
<body>
<p><math><menclose><mspace width="50px" height="50px"/></menclose></math></p>
</body>
</html>

View File

@ -123,3 +123,4 @@ fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 787215
== number-size-1.xhtml number-size-1-ref.xhtml
== mathml-mmultiscript-base.html mathml-mmultiscript-base-ref.html
== mathml-mmultiscript-mprescript.html mathml-mmultiscript-mprescript-ref.html
!= menclose-1.html menclose-1-ref.html