зеркало из https://github.com/mozilla/gecko-dev.git
Rework the positioning functions of <mover>, <munder>, <munderover> to improve their behavior w.r.t italic and non-italics fonts. Also use some fuzzy arithmetic to mitigate roundoff errors that could cause accents to collide with their base, b=135940, r=bzbarsky, sr=roc+moz
This commit is contained in:
Родитель
87c2b9e2b4
Коммит
eba1c08907
|
@ -291,6 +291,10 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext,
|
|||
GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
|
||||
GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver);
|
||||
|
||||
float p2t;
|
||||
aPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
nscoord onePixel = NSIntPixelsToTwips(1, p2t);
|
||||
|
||||
////////////////////
|
||||
// Place Children
|
||||
|
||||
|
@ -310,11 +314,12 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext,
|
|||
// whether we want an accented overscript or not
|
||||
|
||||
nscoord correction = 0;
|
||||
GetItalicCorrection (bmBase, correction);
|
||||
|
||||
nscoord delta1 = 0; // gap between base and overscript
|
||||
nscoord delta2 = 0; // extra space above overscript
|
||||
if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
|
||||
// Rule 13a, App. G, TeXbook
|
||||
GetItalicCorrection (bmBase, correction);
|
||||
nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy;
|
||||
GetBigOpSpacings (fm,
|
||||
bigOpSpacing1, dummy,
|
||||
|
@ -331,7 +336,6 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext,
|
|||
}
|
||||
else {
|
||||
// Rule 12, App. G, TeXbook
|
||||
GetSkewCorrectionFromChild (aPresContext, baseFrame, correction);
|
||||
// We are going to modify this rule to make it more general.
|
||||
// The idea behind Rule 12 in the TeXBook is to keep the accent
|
||||
// as close to the base as possible, while ensuring that the
|
||||
|
@ -360,9 +364,9 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext,
|
|||
// we try to keep the *bottom* of the accent char atleast x-height
|
||||
// from the baseline of the base char. we also slap on an extra
|
||||
// padding between the accent and base chars.
|
||||
delta1 = ruleThickness; // we have atleast the padding
|
||||
delta1 = ruleThickness + onePixel/2; // we have at least the padding
|
||||
if (bmBase.ascent < xHeight) {
|
||||
// also ensure atleast x-height above the baseline of the base
|
||||
// also ensure at least x-height above the baseline of the base
|
||||
delta1 += xHeight - bmBase.ascent;
|
||||
}
|
||||
delta2 = ruleThickness;
|
||||
|
@ -370,13 +374,7 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext,
|
|||
// empty over?
|
||||
if (!(bmOver.ascent + bmOver.descent)) delta1 = 0;
|
||||
|
||||
mBoundingMetrics.ascent =
|
||||
bmOver.ascent + bmOver.descent + delta1 + bmBase.ascent;
|
||||
|
||||
mBoundingMetrics.descent = bmBase.descent;
|
||||
|
||||
nscoord dxBase, dxOver = 0;
|
||||
nscoord dyBase, dyOver;
|
||||
|
||||
// Ad-hoc - This is to override fonts which have ready-made _accent_
|
||||
// glyphs with negative lbearing and rbearing. We want to position
|
||||
|
@ -388,13 +386,22 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext,
|
|||
}
|
||||
|
||||
if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
|
||||
mBoundingMetrics.width = PR_MAX(bmBase.width, overWidth);
|
||||
mBoundingMetrics.width = bmBase.width;
|
||||
dxOver += correction + (mBoundingMetrics.width - overWidth)/2;
|
||||
}
|
||||
else {
|
||||
mBoundingMetrics.width =
|
||||
PR_MAX(bmBase.width/2,(overWidth + correction/2)/2) +
|
||||
PR_MAX(bmBase.width/2,(overWidth - correction/2)/2);
|
||||
mBoundingMetrics.width = PR_MAX(bmBase.width, overWidth);
|
||||
dxOver += correction/2 + (mBoundingMetrics.width - overWidth)/2;
|
||||
}
|
||||
dxBase = (mBoundingMetrics.width - bmBase.width) / 2;
|
||||
|
||||
mBoundingMetrics.ascent =
|
||||
bmOver.ascent + bmOver.descent + delta1 + bmBase.ascent;
|
||||
mBoundingMetrics.descent = bmBase.descent;
|
||||
mBoundingMetrics.leftBearing =
|
||||
PR_MIN(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing);
|
||||
mBoundingMetrics.rightBearing =
|
||||
PR_MAX(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing);
|
||||
|
||||
aDesiredSize.descent = baseSize.descent;
|
||||
aDesiredSize.ascent =
|
||||
|
@ -402,34 +409,19 @@ nsMathMLmoverFrame::Place(nsIPresContext* aPresContext,
|
|||
overSize.ascent + bmOver.descent + delta1 + bmBase.ascent);
|
||||
aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
|
||||
aDesiredSize.width = mBoundingMetrics.width;
|
||||
|
||||
dxBase = (mBoundingMetrics.width - bmBase.width) / 2;
|
||||
dyBase = aDesiredSize.ascent - baseSize.ascent;
|
||||
|
||||
if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
|
||||
dxOver += correction + (mBoundingMetrics.width - overWidth)/2;
|
||||
}
|
||||
else {
|
||||
dxOver += correction/2 + (mBoundingMetrics.width - overWidth)/2;
|
||||
}
|
||||
|
||||
dyOver = aDesiredSize.ascent -
|
||||
mBoundingMetrics.ascent + bmOver.ascent - overSize.ascent;
|
||||
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
||||
|
||||
mReference.x = 0;
|
||||
mReference.y = aDesiredSize.ascent;
|
||||
|
||||
mBoundingMetrics.leftBearing =
|
||||
PR_MIN(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing);
|
||||
mBoundingMetrics.rightBearing =
|
||||
PR_MAX(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing);
|
||||
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
||||
|
||||
if (aPlaceOrigin) {
|
||||
// place base
|
||||
FinishReflowChild (baseFrame, aPresContext, nsnull, baseSize, dxBase, dyBase, 0);
|
||||
nscoord dy = aDesiredSize.ascent - baseSize.ascent;
|
||||
FinishReflowChild (baseFrame, aPresContext, nsnull, baseSize, dxBase, dy, 0);
|
||||
// place overscript
|
||||
FinishReflowChild (overFrame, aPresContext, nsnull, overSize, dxOver, dyOver, 0);
|
||||
dy = aDesiredSize.ascent -
|
||||
mBoundingMetrics.ascent + bmOver.ascent - overSize.ascent;
|
||||
FinishReflowChild (overFrame, aPresContext, nsnull, overSize, dxOver, dy, 0);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -288,6 +288,10 @@ nsMathMLmunderFrame::Place(nsIPresContext* aPresContext,
|
|||
GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
|
||||
GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder);
|
||||
|
||||
float p2t;
|
||||
aPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
nscoord onePixel = NSIntPixelsToTwips(1, p2t);
|
||||
|
||||
////////////////////
|
||||
// Place Children
|
||||
|
||||
|
@ -306,12 +310,13 @@ nsMathMLmunderFrame::Place(nsIPresContext* aPresContext,
|
|||
// there are 2 different types of placement depending on
|
||||
// whether we want an accented under or not
|
||||
|
||||
nscoord italicCorrection = 0;
|
||||
nscoord correction = 0;
|
||||
GetItalicCorrection (bmBase, correction);
|
||||
|
||||
nscoord delta1 = 0; // gap between base and underscript
|
||||
nscoord delta2 = 0; // extra space beneath underscript
|
||||
if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
|
||||
// Rule 13a, App. G, TeXbook
|
||||
GetItalicCorrection (bmBase, italicCorrection);
|
||||
nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy;
|
||||
GetBigOpSpacings (fm,
|
||||
dummy, bigOpSpacing2,
|
||||
|
@ -325,22 +330,27 @@ nsMathMLmunderFrame::Place(nsIPresContext* aPresContext,
|
|||
// XXX tune the gap delta between base and underscript
|
||||
|
||||
// Should we use Rule 10 like \underline does?
|
||||
delta1 = ruleThickness;
|
||||
delta1 = ruleThickness + onePixel/2;
|
||||
delta2 = ruleThickness;
|
||||
}
|
||||
// empty under?
|
||||
if (!(bmUnder.ascent + bmUnder.descent)) delta1 = 0;
|
||||
|
||||
nscoord dxBase, dxUnder;
|
||||
nscoord maxWidth = PR_MAX(bmBase.width, bmUnder.width);
|
||||
if (NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
|
||||
dxUnder = (maxWidth - bmUnder.width)/2;
|
||||
}
|
||||
else {
|
||||
dxUnder = -correction/2 + (maxWidth - bmUnder.width)/2;
|
||||
}
|
||||
dxBase = (maxWidth - bmBase.width)/2;
|
||||
|
||||
mBoundingMetrics.width =
|
||||
PR_MAX(dxBase + bmBase.width, dxUnder + bmUnder.width);
|
||||
mBoundingMetrics.ascent = bmBase.ascent;
|
||||
mBoundingMetrics.descent =
|
||||
bmBase.descent + delta1 + bmUnder.ascent + bmUnder.descent;
|
||||
mBoundingMetrics.width =
|
||||
PR_MAX(bmBase.width/2,(bmUnder.width + italicCorrection/2)/2) +
|
||||
PR_MAX(bmBase.width/2,(bmUnder.width - italicCorrection/2)/2);
|
||||
|
||||
nscoord dxBase = (mBoundingMetrics.width - bmBase.width) / 2;
|
||||
nscoord dxUnder = (mBoundingMetrics.width - (bmUnder.width + italicCorrection/2)) / 2;
|
||||
|
||||
mBoundingMetrics.leftBearing =
|
||||
PR_MIN(dxBase + bmBase.leftBearing, dxUnder + bmUnder.leftBearing);
|
||||
mBoundingMetrics.rightBearing =
|
||||
|
@ -351,9 +361,7 @@ nsMathMLmunderFrame::Place(nsIPresContext* aPresContext,
|
|||
PR_MAX(mBoundingMetrics.descent + delta2,
|
||||
bmBase.descent + delta1 + bmUnder.ascent + underSize.descent);
|
||||
aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
|
||||
aDesiredSize.width =
|
||||
PR_MAX(baseSize.width/2,(underSize.width + italicCorrection/2)/2) +
|
||||
PR_MAX(baseSize.width/2,(underSize.width - italicCorrection/2)/2);
|
||||
aDesiredSize.width = mBoundingMetrics.width;
|
||||
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
||||
|
||||
mReference.x = 0;
|
||||
|
|
|
@ -331,6 +331,10 @@ nsMathMLmunderoverFrame::Place(nsIPresContext* aPresContext,
|
|||
GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder);
|
||||
GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver);
|
||||
|
||||
float p2t;
|
||||
aPresContext->GetScaledPixelsToTwips(&p2t);
|
||||
nscoord onePixel = NSIntPixelsToTwips(1, p2t);
|
||||
|
||||
////////////////////
|
||||
// Place Children
|
||||
|
||||
|
@ -346,16 +350,17 @@ nsMathMLmunderoverFrame::Place(nsIPresContext* aPresContext,
|
|||
nscoord ruleThickness;
|
||||
GetRuleThickness (aRenderingContext, fm, ruleThickness);
|
||||
|
||||
nscoord correction = 0;
|
||||
GetItalicCorrection (bmBase, correction);
|
||||
|
||||
// there are 2 different types of placement depending on
|
||||
// whether we want an accented under or not
|
||||
|
||||
nscoord italicCorrection = 0;
|
||||
nscoord underDelta1 = 0; // gap between base and underscript
|
||||
nscoord underDelta2 = 0; // extra space beneath underscript
|
||||
|
||||
if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
|
||||
// Rule 13a, App. G, TeXbook
|
||||
GetItalicCorrection (bmBase, italicCorrection);
|
||||
nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy;
|
||||
GetBigOpSpacings (fm,
|
||||
dummy, bigOpSpacing2,
|
||||
|
@ -369,19 +374,17 @@ nsMathMLmunderoverFrame::Place(nsIPresContext* aPresContext,
|
|||
// XXX tune the gap delta between base and underscript
|
||||
|
||||
// Should we use Rule 10 like \underline does?
|
||||
underDelta1 = ruleThickness;
|
||||
underDelta1 = ruleThickness + onePixel/2;
|
||||
underDelta2 = ruleThickness;
|
||||
}
|
||||
// empty under?
|
||||
if (!(bmUnder.ascent + bmUnder.descent)) underDelta1 = 0;
|
||||
|
||||
nscoord correction = 0;
|
||||
nscoord overDelta1 = 0; // gap between base and overscript
|
||||
nscoord overDelta2 = 0; // extra space above overscript
|
||||
|
||||
if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
|
||||
// Rule 13a, App. G, TeXbook
|
||||
GetItalicCorrection (bmBase, italicCorrection);
|
||||
nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy;
|
||||
GetBigOpSpacings (fm,
|
||||
bigOpSpacing1, dummy,
|
||||
|
@ -397,9 +400,8 @@ nsMathMLmunderoverFrame::Place(nsIPresContext* aPresContext,
|
|||
overDelta1 = PR_MAX(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent)));
|
||||
}
|
||||
else {
|
||||
// Rule 13, App. G, TeXbook
|
||||
GetSkewCorrectionFromChild (aPresContext, baseFrame, correction);
|
||||
overDelta1 = ruleThickness;
|
||||
// Rule 12, App. G, TeXbook
|
||||
overDelta1 = ruleThickness + onePixel/2;
|
||||
if (bmBase.ascent < xHeight) {
|
||||
overDelta1 += xHeight - bmBase.ascent;
|
||||
}
|
||||
|
@ -408,33 +410,78 @@ nsMathMLmunderoverFrame::Place(nsIPresContext* aPresContext,
|
|||
// empty over?
|
||||
if (!(bmOver.ascent + bmOver.descent)) overDelta1 = 0;
|
||||
|
||||
nscoord dxBase, dxOver = 0, dxUnder = 0;
|
||||
|
||||
//////////
|
||||
// pass 1, do what <mover> does: attach the overscript on the base
|
||||
|
||||
// Ad-hoc - This is to override fonts which have ready-made _accent_
|
||||
// glyphs with negative lbearing and rbearing. We want to position
|
||||
// the overscript ourselves
|
||||
nscoord overWidth = bmOver.width;
|
||||
if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) {
|
||||
overWidth = bmOver.rightBearing - bmOver.leftBearing;
|
||||
dxOver = -bmOver.leftBearing;
|
||||
}
|
||||
|
||||
if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
|
||||
mBoundingMetrics.width = bmBase.width;
|
||||
dxOver += correction + (mBoundingMetrics.width - overWidth)/2;
|
||||
}
|
||||
else {
|
||||
mBoundingMetrics.width = PR_MAX(bmBase.width, overWidth);
|
||||
dxOver += correction/2 + (mBoundingMetrics.width - overWidth)/2;
|
||||
}
|
||||
dxBase = (mBoundingMetrics.width - bmBase.width)/2;
|
||||
|
||||
mBoundingMetrics.ascent =
|
||||
bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent;
|
||||
mBoundingMetrics.descent =
|
||||
bmBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent;
|
||||
mBoundingMetrics.width =
|
||||
PR_MAX(bmBase.width/2,PR_MAX((bmUnder.width + italicCorrection/2)/2,(bmOver.width - correction/2)/2)) +
|
||||
PR_MAX(bmBase.width/2,PR_MAX((bmUnder.width - italicCorrection/2)/2,(bmOver.width + correction/2)/2));
|
||||
|
||||
nscoord dxBase = (mBoundingMetrics.width - bmBase.width) / 2;
|
||||
nscoord dxOver = (mBoundingMetrics.width - (bmOver.width - correction/2)) / 2;
|
||||
nscoord dxUnder = (mBoundingMetrics.width - (bmUnder.width + italicCorrection/2)) / 2;
|
||||
|
||||
mBoundingMetrics.leftBearing =
|
||||
PR_MIN(dxBase + bmBase.leftBearing, dxUnder + bmUnder.leftBearing);
|
||||
PR_MIN(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing);
|
||||
mBoundingMetrics.rightBearing =
|
||||
PR_MAX(dxBase + bmBase.rightBearing, dxUnder + bmUnder.rightBearing);
|
||||
mBoundingMetrics.leftBearing =
|
||||
PR_MIN(mBoundingMetrics.leftBearing, dxOver + bmOver.leftBearing);
|
||||
mBoundingMetrics.rightBearing =
|
||||
PR_MAX(mBoundingMetrics.rightBearing, dxOver + bmOver.rightBearing);
|
||||
PR_MAX(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing);
|
||||
|
||||
aDesiredSize.ascent =
|
||||
//////////
|
||||
// pass 2, do what <munder> does: attach the underscript on the previous
|
||||
// result. We conceptually view the previous result as an "anynomous base"
|
||||
// from where to attach the underscript. Hence if the underscript is empty,
|
||||
// we should end up like <mover>. If the overscript is empty, we should
|
||||
// end up like <munder>.
|
||||
|
||||
nsBoundingMetrics bmAnonymousBase = mBoundingMetrics;
|
||||
nscoord ascentAnonymousBase =
|
||||
PR_MAX(mBoundingMetrics.ascent + overDelta2,
|
||||
overSize.ascent + bmOver.descent + overDelta1 + bmBase.ascent);
|
||||
|
||||
GetItalicCorrection(bmAnonymousBase, correction);
|
||||
|
||||
nscoord maxWidth = PR_MAX(bmAnonymousBase.width, bmUnder.width);
|
||||
if (NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
|
||||
dxUnder = (maxWidth - bmUnder.width)/2;;
|
||||
}
|
||||
else {
|
||||
dxUnder = -correction/2 + (maxWidth - bmUnder.width)/2;
|
||||
}
|
||||
nscoord dxAnonymousBase = (maxWidth - bmAnonymousBase.width)/2;
|
||||
|
||||
// adjust the offsets of the real base and overscript since their
|
||||
// final offsets should be relative to us...
|
||||
dxOver += dxAnonymousBase;
|
||||
dxBase += dxAnonymousBase;
|
||||
|
||||
mBoundingMetrics.width =
|
||||
PR_MAX(dxAnonymousBase + bmAnonymousBase.width, dxUnder + bmUnder.width);
|
||||
mBoundingMetrics.leftBearing =
|
||||
PR_MIN(dxAnonymousBase + bmAnonymousBase.leftBearing, dxUnder + bmUnder.leftBearing);
|
||||
mBoundingMetrics.rightBearing =
|
||||
PR_MAX(dxAnonymousBase + bmAnonymousBase.rightBearing, dxUnder + bmUnder.rightBearing);
|
||||
|
||||
aDesiredSize.ascent = ascentAnonymousBase;
|
||||
aDesiredSize.descent =
|
||||
PR_MAX(mBoundingMetrics.descent + underDelta2,
|
||||
bmBase.descent + underDelta1 + bmUnder.ascent + underSize.descent);
|
||||
bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + underSize.descent);
|
||||
aDesiredSize.height = aDesiredSize.ascent + aDesiredSize.descent;
|
||||
aDesiredSize.width = mBoundingMetrics.width;
|
||||
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
||||
|
|
Загрузка…
Ссылка в новой задаче