clip parts of stretchy chars more carefully b=427666 (also fixes b=349907) r+sr=roc a1.9=damons

This commit is contained in:
karlt+@karlt.net 2008-04-22 20:13:09 -07:00
parent 87aabef714
commit bd2e0ff50c
4 changed files with 307 additions and 184 deletions

View File

@ -1048,8 +1048,7 @@ static nscoord
ComputeSizeFromParts(nsPresContext* aPresContext,
nsGlyphCode* aGlyphs,
nscoord* aSizes,
nscoord aTargetSize,
PRUint32 aHint)
nscoord aTargetSize)
{
enum {first, middle, last, glue};
// Add the parts that cannot be left out.
@ -1060,22 +1059,26 @@ ComputeSizeFromParts(nsPresContext* aPresContext,
}
}
// Get the minimum allowable size using some flex.
const float flex = 0.901f;
nscoord minSize = NSToCoordRound(flex * sum);
if (minSize > aTargetSize)
return minSize; // settle with the minimum size
// Determine how much is used in joins
nscoord oneDevPixel = aPresContext->AppUnitsPerDevPixel();
PRInt32 joins = aGlyphs[middle] == aGlyphs[glue] ? 1 : 2;
// Pick a maximum size using a maximum number of glue glyphs that we are
// prepared to draw for one character.
const PRInt32 maxGlyphs = 1000;
// This also takes into account the fact that, if the glue has no size,
// then the character can't be lengthened.
nscoord maxSize = sum + maxGlyphs * aSizes[glue];
nscoord maxSize = sum - 2 * joins * oneDevPixel + maxGlyphs * aSizes[glue];
if (maxSize < aTargetSize)
return maxSize; // settle with the maximum size
// Get the minimum allowable size using some flex.
nscoord minSize = NSToCoordRound(NS_MATHML_DELIMITER_FACTOR * sum);
if (minSize > aTargetSize)
return minSize; // settle with the minimum size
// Fill-up the target area
return aTargetSize;
}
@ -1401,7 +1404,7 @@ nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable,
// Build by parts if we have successfully computed the
// bounding metrics of all parts.
nscoord computedSize = ComputeSizeFromParts(mPresContext, chdata, sizedata,
mTargetSize, mStretchHint);
mTargetSize);
nscoord currentSize =
isVertical ? mBoundingMetrics.ascent + mBoundingMetrics.descent
@ -2155,6 +2158,19 @@ public:
}
};
static nsPoint
SnapToDevPixels(const gfxContext* aThebesContext, PRInt32 aAppUnitsPerGfxUnit,
const nsPoint& aPt)
{
gfxPoint pt(NSAppUnitsToFloatPixels(aPt.x, aAppUnitsPerGfxUnit),
NSAppUnitsToFloatPixels(aPt.y, aAppUnitsPerGfxUnit));
pt = aThebesContext->UserToDevice(pt);
pt.Round();
pt = aThebesContext->DeviceToUser(pt);
return nsPoint(NSFloatPixelsToAppUnits(pt.x, aAppUnitsPerGfxUnit),
NSFloatPixelsToAppUnits(pt.y, aAppUnitsPerGfxUnit));
}
// paint a stretchy char by assembling glyphs vertically
nsresult
nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
@ -2165,86 +2181,126 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
nsRect& aRect)
{
nsresult rv = NS_OK;
nsRect clipRect;
nscoord dx, dy;
nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); //XXXkt device pixel may be better?
// Get the device pixel size in the vertical direction.
// (This makes no effort to optimize for non-translation transformations.)
nscoord oneDevPixel = aPresContext->AppUnitsPerDevPixel();
// get metrics data to be re-used later
PRInt32 i;
PRInt32 i = 0;
nsGlyphCode ch, chdata[4];
nsBoundingMetrics bmdata[4];
nscoord stride = 0, offset[3], start[3], end[3];
nscoord width = aRect.width;
nsGlyphCode glue = aGlyphTable->GlueOf(aPresContext, this);
for (i = 0; i < 4; i++) {
switch (i) {
case 0: ch = aGlyphTable->TopOf(aPresContext, this); break;
case 1: ch = aGlyphTable->MiddleOf(aPresContext, this); break;
case 2: ch = aGlyphTable->BottomOf(aPresContext, this); break;
case 3: ch = glue; break;
PRInt32 glue, bottom;
nsGlyphCode chGlue = aGlyphTable->GlueOf(aPresContext, this);
for (PRInt32 j = 0; j < 4; ++j) {
switch (j) {
case 0:
ch = aGlyphTable->TopOf(aPresContext, this);
break;
case 1:
ch = aGlyphTable->MiddleOf(aPresContext, this);
if (!ch.Exists())
continue; // no middle
break;
case 2:
ch = aGlyphTable->BottomOf(aPresContext, this);
bottom = i;
break;
case 3:
ch = chGlue;
glue = i;
break;
}
// empty slots are filled with the glue if it is not null
if (!ch.Exists()) ch = glue;
nsBoundingMetrics bm;
if (!ch.Exists()) ch = chGlue;
// if (!ch.Exists()) glue is null, leave bounding metrics at 0
if (ch.Exists()) {
SetFontFamily(aRenderingContext, aFont, aGlyphTable, ch, mFamily);
rv = aRenderingContext.GetBoundingMetrics(&ch.code, 1, bm);
rv = aRenderingContext.GetBoundingMetrics(&ch.code, 1, bmdata[i]);
if (NS_FAILED(rv)) {
NS_WARNING("GetBoundingMetrics failed");
return rv;
}
if (width < bm.rightBearing) width = bm.rightBearing;
}
chdata[i] = ch;
bmdata[i] = bm;
++i;
}
dx = aRect.x;
for (i = 0; i < 3; i++) {
nscoord dx = aRect.x;
nscoord offset[3], start[3], end[3];
nsRefPtr<gfxContext> ctx = aRenderingContext.ThebesContext();
for (i = 0; i <= bottom; ++i) {
ch = chdata[i];
const nsBoundingMetrics &bm = bmdata[i];
const nsBoundingMetrics& bm = bmdata[i];
nscoord dy;
if (0 == i) { // top
dy = aRect.y + bm.ascent;
}
else if (1 == i) { // middle
dy = aRect.y + bm.ascent + (aRect.height - (bm.ascent + bm.descent))/2;
}
else { // bottom
else if (bottom == i) { // bottom
dy = aRect.y + aRect.height - bm.descent;
}
else { // middle
dy = aRect.y + bm.ascent + (aRect.height - (bm.ascent + bm.descent))/2;
}
// _cairo_scaled_font_show_glyphs snaps origins to device pixels.
// Do this now so that we can get the other dimensions right.
// (This may not achieve much with non-rectangular transformations.)
dy = SnapToDevPixels(ctx, oneDevPixel, nsPoint(dx, dy)).y;
// abcissa passed to DrawString
offset[i] = dy;
// *exact* abcissa where the *top-most* pixel of the glyph is painted
start[i] = dy - bm.ascent;
// *exact* abcissa where the *bottom-most* pixel of the glyph is painted
end[i] = dy + bm.descent; // end = start + height
// _cairo_scaled_font_glyph_device_extents rounds outwards to the nearest
// pixel, so the bm values can include 1 row of faint pixels on each edge.
// Don't rely on this pixel as it can look like a gap.
start[i] = dy - bm.ascent + oneDevPixel; // top join
end[i] = dy + bm.descent - oneDevPixel; // bottom join
}
// If there are overlaps, then join at the mid point
for (i = 0; i < bottom; ++i) {
if (end[i] > start[i+1]) {
end[i] = (end[i] + start[i+1]) / 2;
start[i+1] = end[i];
}
}
nsRect unionRect = aRect;
unionRect.x += mBoundingMetrics.leftBearing;
unionRect.width =
mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing;
unionRect.Inflate(oneDevPixel, oneDevPixel);
/////////////////////////////////////
// draw top, middle, bottom
for (i = 0; i < 3; i++) {
for (i = 0; i <= bottom; ++i) {
ch = chdata[i];
// glue can be null, and other parts could have been set to glue
if (ch.Exists()) {
#ifdef SHOW_BORDERS
// bounding box of the part
aRenderingContext.SetColor(NS_RGB(0,0,0));
aRenderingContext.DrawRect(nsRect(dx,start[i],width+30*(i+1),end[i]-start[i]));
aRenderingContext.DrawRect(nsRect(dx,start[i],aRect.width+30*(i+1),end[i]-start[i]));
#endif
dy = offset[i];
// Draw a glyph in a clipped area so that we don't have hairy chars pending outside
if (0 == i) { // top
clipRect.SetRect(dx, aRect.y, width, aRect.height);
}
else if (1 == i) { // middle
clipRect.SetRect(dx, end[0], width, start[2]-end[0]);
}
else { // bottom
clipRect.SetRect(dx, start[2], width, end[2]-start[2]);
nscoord dy = offset[i];
// Draw a glyph in a clipped area so that we don't have hairy chars
// pending outside
nsRect clipRect = unionRect;
// Clip at the join to get a solid edge (without overlap or gap), when
// this won't change the glyph too much. If the glyph is too small to
// clip then we'll overlap rather than have a gap.
nscoord height = bmdata[i].ascent + bmdata[i].descent;
if (ch == chGlue ||
height * (1.0 - NS_MATHML_DELIMITER_FACTOR) > oneDevPixel) {
if (0 == i) { // top
clipRect.height = end[i] - clipRect.y;
}
else if (bottom == i) { // bottom
clipRect.height -= start[i] - clipRect.y;
clipRect.y = start[i];
}
else { // middle
clipRect.y = start[i];
clipRect.height = end[i] - start[i];
}
}
if (!clipRect.IsEmpty()) {
clipRect.Inflate(onePixel, onePixel);
AutoPushClipRect clip(aRenderingContext, clipRect);
SetFontFamily(aRenderingContext, aFont, aGlyphTable, ch, mFamily);
aRenderingContext.DrawString(&ch.code, 1, dx, dy);
@ -2254,7 +2310,7 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
///////////////
// fill the gap between top and middle, and between middle and bottom.
if (!glue.Exists()) { // null glue : draw a rule
if (!chGlue.Exists()) { // null glue : draw a rule
// figure out the dimensions of the rule to be drawn :
// set lbearing to rightmost lbearing among the two current successive parts.
// set rbearing to leftmost rbearing among the two current successive parts.
@ -2262,11 +2318,8 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
// in TeX, but also takes care of broken fonts like the stretchy integral
// in Symbol for small font sizes in unix.
nscoord lbearing, rbearing;
PRInt32 first = 0, last = 2;
if (chdata[1].Exists()) { // middle part exists
last = 1;
}
while (last <= 2) {
PRInt32 first = 0, last = 1;
while (last <= bottom) {
if (chdata[last].Exists()) {
lbearing = bmdata[last].leftBearing;
rbearing = bmdata[last].rightBearing;
@ -2286,74 +2339,63 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext,
return NS_ERROR_UNEXPECTED;
}
// paint the rule between the parts
nsRect rule(aRect.x + lbearing, end[first] - onePixel,
rbearing - lbearing, start[last] - end[first] + 2*onePixel);
nsRect rule(aRect.x + lbearing, end[first],
rbearing - lbearing, start[last] - end[first]);
if (!rule.IsEmpty())
aRenderingContext.FillRect(rule);
first = last;
last++;
}
}
else if (bmdata[3].ascent + bmdata[3].descent > 0) {
else if (bmdata[glue].ascent + bmdata[glue].descent > 0) {
// glue is present
nscoord overlap;
nsCOMPtr<nsIFontMetrics> fm;
aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
nsMathMLFrame::GetRuleThickness(fm, overlap);
overlap = 2 * PR_MAX(overlap, onePixel);
// Ensure the stride for the glue is not reduced to less than onePixel
while (overlap > 0 && bmdata[3].ascent + bmdata[3].descent <= 2*overlap + onePixel)
overlap -= onePixel;
if (overlap > 0) {
// To protect against gaps, pretend the glue is smaller than
// it says to allow a small overlap when adjoining it.
// XXXkt Does the overlap need to be this large: removing from both
// ascent and descent means the overlap between glue glyphs is 4 *
// max(ruleThickness, onePixel), while the overlap between glue and
// other glyphs is 2 * max(ruleThickness, onePixel).
// See also bug 349907.
bmdata[3].ascent -= overlap;
bmdata[3].descent -= overlap;
nsBoundingMetrics& bm = bmdata[glue];
// Ensure the stride for the glue is not reduced to less than one pixel
if (bm.ascent + bm.descent >= 3 * oneDevPixel) {
// To protect against gaps, pretend the glue is smaller than it is,
// in order to trim off ends and thus get a solid edge for the join.
bm.ascent -= oneDevPixel;
bm.descent -= oneDevPixel;
}
nscoord edge = PR_MAX(overlap, onePixel);
SetFontFamily(aRenderingContext, aFont, aGlyphTable, glue, mFamily);
for (i = 0; i < 2; i++) {
PRInt32 count = 0;
dy = offset[i];
clipRect.SetRect(dx, end[i], width, start[i+1]-end[i]);
clipRect.Inflate(edge, edge);
nsBoundingMetrics bm = bmdata[i];
SetFontFamily(aRenderingContext, aFont, aGlyphTable, chGlue, mFamily);
nsRect clipRect = unionRect;
for (i = 0; i < bottom; ++i) {
// Make sure not to draw outside the character
nscoord dy = PR_MAX(end[i], aRect.y);
nscoord fillEnd = PR_MIN(start[i+1], aRect.YMost());
#ifdef SHOW_BORDERS
// exact area to fill
aRenderingContext.SetColor(NS_RGB(255,0,0));
clipRect.y = dy;
clipRect.height = fillEnd - dy;
aRenderingContext.DrawRect(clipRect);
{
#endif
AutoPushClipRect clip(aRenderingContext, clipRect);
while (dy + bm.descent < start[i+1]) {
if (count++ < 2) {
stride = bm.descent;
bm = bmdata[3]; // glue
stride += bm.ascent;
}
dy += stride;
aRenderingContext.DrawString(&glue.code, 1, dx, dy);
while (dy < fillEnd) {
clipRect.y = dy;
clipRect.height = PR_MIN(bm.ascent + bm.descent, fillEnd - dy);
AutoPushClipRect clip(aRenderingContext, clipRect);
dy += bm.ascent;
aRenderingContext.DrawString(&chGlue.code, 1, dx, dy);
dy += bm.descent;
}
#ifdef SHOW_BORDERS
}
// last glyph that may cross past its boundary and collide with the next
nscoord height = bm.ascent + bm.descent;
aRenderingContext.SetColor(NS_RGB(0,255,0));
aRenderingContext.DrawRect(nsRect(dx, dy-bm.ascent, width, height));
aRenderingContext.DrawRect(nsRect(dx, dy-bm.ascent, aRect.width, height));
#endif
}
}
#ifdef DEBUG
else { // no glue
NS_ASSERTION(end[0] >= start[1] && end[1] >= start[2],
"gap between parts with no glue");
else {
for (i = 0; i < bottom; ++i) {
NS_ASSERTION(end[i] >= start[i+1],
"gap between parts with missing glue glyph");
}
}
#endif
return NS_OK;
@ -2369,63 +2411,92 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
nsRect& aRect)
{
nsresult rv = NS_OK;
nsRect clipRect;
nscoord dx, dy;
nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
// Get the device pixel size in the horizontal direction.
// (This makes no effort to optimize for non-translation transformations.)
nscoord oneDevPixel = aPresContext->AppUnitsPerDevPixel();
// get metrics data to be re-used later
PRInt32 i;
PRInt32 i = 0;
nsGlyphCode ch, chdata[4];
nsBoundingMetrics bmdata[4];
nscoord stride = 0, offset[3], start[3], end[3];
dy = aRect.y + mBoundingMetrics.ascent;
nsGlyphCode glue = aGlyphTable->GlueOf(aPresContext, this);
for (i = 0; i < 4; i++) {
switch (i) {
case 0: ch = aGlyphTable->LeftOf(aPresContext, this); break;
case 1: ch = aGlyphTable->MiddleOf(aPresContext, this); break;
case 2: ch = aGlyphTable->RightOf(aPresContext, this); break;
case 3: ch = glue; break;
PRInt32 glue, right;
nsGlyphCode chGlue = aGlyphTable->GlueOf(aPresContext, this);
for (PRInt32 j = 0; j < 4; ++j) {
switch (j) {
case 0:
ch = aGlyphTable->LeftOf(aPresContext, this);
break;
case 1:
ch = aGlyphTable->MiddleOf(aPresContext, this);
if (!ch.Exists())
continue; // no middle
break;
case 2:
ch = aGlyphTable->RightOf(aPresContext, this);
right = i;
break;
case 3:
ch = chGlue;
glue = i;
break;
}
// empty slots are filled with the glue if it is not null
if (!ch.Exists()) ch = glue;
nsBoundingMetrics bm;
if (!ch.Exists()) ch = chGlue;
// if (!ch.Exists()) glue is null, leave bounding metrics at 0.
if (ch.Exists()) {
SetFontFamily(aRenderingContext, aFont, aGlyphTable, ch, mFamily);
rv = aRenderingContext.GetBoundingMetrics(&ch.code, 1, bm);
rv = aRenderingContext.GetBoundingMetrics(&ch.code, 1, bmdata[i]);
if (NS_FAILED(rv)) {
NS_WARNING("GetBoundingMetrics failed");
return rv;
}
}
chdata[i] = ch;
bmdata[i] = bm;
++i;
}
for (i = 0; i < 3; i++) {
nscoord dy = aRect.y + mBoundingMetrics.ascent;
nscoord offset[3], start[3], end[3];
nsRefPtr<gfxContext> ctx = aRenderingContext.ThebesContext();
for (i = 0; i <= right; ++i) {
ch = chdata[i];
nsBoundingMetrics &bm = bmdata[i];
const nsBoundingMetrics& bm = bmdata[i];
nscoord dx;
if (0 == i) { // left
dx = aRect.x - bm.leftBearing;
}
else if (1 == i) { // middle
dx = aRect.x + (aRect.width - bm.width)/2;
}
else { // right
else if (right == i) { // right
dx = aRect.x + aRect.width - bm.rightBearing;
}
// abcissa that DrawString used
else { // middle
dx = aRect.x + (aRect.width - bm.width)/2;
}
// _cairo_scaled_font_show_glyphs snaps origins to device pixels.
// Do this now so that we can get the other dimensions right.
// (This may not achieve much with non-rectangular transformations.)
dx = SnapToDevPixels(ctx, oneDevPixel, nsPoint(dx, dy)).x;
// abcissa passed to DrawString
offset[i] = dx;
// *exact* abcissa where the *left-most* pixel of the glyph is painted
start[i] = dx + bm.leftBearing;
// *exact* abcissa where the *right-most* pixel of the glyph is painted
end[i] = dx + bm.rightBearing; // note: end = start + width
// _cairo_scaled_font_glyph_device_extents rounds outwards to the nearest
// pixel, so the bm values can include 1 row of faint pixels on each edge.
// Don't rely on this pixel as it can look like a gap.
start[i] = dx + bm.leftBearing + oneDevPixel; // left join
end[i] = dx + bm.rightBearing - oneDevPixel; // right join
}
// If there are overlaps, then join at the mid point
for (i = 0; i < right; ++i) {
if (end[i] > start[i+1]) {
end[i] = (end[i] + start[i+1]) / 2;
start[i+1] = end[i];
}
}
nsRect unionRect = aRect;
unionRect.Inflate(oneDevPixel, oneDevPixel);
///////////////////////////
// draw left, middle, right
for (i = 0; i < 3; i++) {
for (i = 0; i <= right; ++i) {
ch = chdata[i];
// glue can be null, and other parts could have been set to glue
if (ch.Exists()) {
@ -2434,18 +2505,27 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
aRenderingContext.DrawRect(nsRect(start[i], dy - bmdata[i].ascent,
end[i] - start[i], bmdata[i].ascent + bmdata[i].descent));
#endif
dx = offset[i];
if (0 == i) { // left
clipRect.SetRect(dx, aRect.y, aRect.width, aRect.height);
}
else if (1 == i) { // middle
clipRect.SetRect(end[0], aRect.y, start[2]-end[0], aRect.height);
}
else { // right
clipRect.SetRect(start[2], aRect.y, end[2]-start[2], aRect.height);
nscoord dx = offset[i];
nsRect clipRect = unionRect;
// Clip at the join to get a solid edge (without overlap or gap), when
// this won't change the glyph too much. If the glyph is too small to
// clip then we'll overlap rather than have a gap.
nscoord width = bmdata[i].rightBearing - bmdata[i].leftBearing;
if (ch == chGlue ||
width * (1.0 - NS_MATHML_DELIMITER_FACTOR) > oneDevPixel) {
if (0 == i) { // left
clipRect.width = end[i] - clipRect.x;
}
else if (right == i) { // right
clipRect.width -= start[i] - clipRect.x;
clipRect.x = start[i];
}
else { // middle
clipRect.x = start[i];
clipRect.width = end[i] - start[i];
}
}
if (!clipRect.IsEmpty()) {
clipRect.Inflate(onePixel, onePixel);
AutoPushClipRect clip(aRenderingContext, clipRect);
SetFontFamily(aRenderingContext, aFont, aGlyphTable, ch, mFamily);
aRenderingContext.DrawString(&ch.code, 1, dx, dy);
@ -2455,18 +2535,15 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
////////////////
// fill the gap between left and middle, and between middle and right.
if (!glue.Exists()) { // null glue : draw a rule
if (!chGlue.Exists()) { // null glue : draw a rule
// figure out the dimensions of the rule to be drawn :
// set ascent to lowest ascent among the two current successive parts.
// set descent to highest descent among the two current successive parts.
// this satisfies the convention used for over/underbraces, and helps
// fix broken fonts.
nscoord ascent, descent;
PRInt32 first = 0, last = 2;
if (chdata[1].Exists()) { // middle part exists
last = 1;
}
while (last <= 2) {
PRInt32 first = 0, last = 1;
while (last <= right) {
if (chdata[last].Exists()) {
ascent = bmdata[last].ascent;
descent = bmdata[last].descent;
@ -2486,55 +2563,47 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
return NS_ERROR_UNEXPECTED;
}
// paint the rule between the parts
nsRect rule(end[first] - onePixel, dy - ascent,
start[last] - end[first] + 2*onePixel, ascent + descent);
nsRect rule(end[first], dy - ascent,
start[last] - end[first], ascent + descent);
if (!rule.IsEmpty())
aRenderingContext.FillRect(rule);
first = last;
last++;
}
}
else if (bmdata[3].rightBearing - bmdata[3].leftBearing > 0) {
else if (bmdata[glue].rightBearing - bmdata[glue].leftBearing > 0) {
// glue is present
nscoord overlap;
nsCOMPtr<nsIFontMetrics> fm;
aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
nsMathMLFrame::GetRuleThickness(fm, overlap);
overlap = 2 * PR_MAX(overlap, onePixel);
// Ensure the stride for the glue is not reduced to less than onePixel
while (overlap > 0 && bmdata[3].rightBearing - bmdata[3].leftBearing <= 2*overlap + onePixel)
overlap -= onePixel;
if (overlap > 0) {
// to protect against gaps, pretend the glue is smaller than
// it says to allow a small overlap when adjoining it
bmdata[3].leftBearing += overlap;
bmdata[3].rightBearing -= overlap;
nsBoundingMetrics& bm = bmdata[glue];
// Ensure the stride for the glue is not reduced to less than one pixel
if (bm.rightBearing - bm.leftBearing >= 3 * oneDevPixel) {
// To protect against gaps, pretend the glue is smaller than it is,
// in order to trim off ends and thus get a solid edge for the join.
bm.leftBearing += oneDevPixel;
bm.rightBearing -= oneDevPixel;
}
nscoord edge = PR_MAX(overlap, onePixel);
SetFontFamily(aRenderingContext, aFont, aGlyphTable, glue, mFamily);
for (i = 0; i < 2; i++) {
PRInt32 count = 0;
dx = offset[i];
clipRect.SetRect(end[i], aRect.y, start[i+1]-end[i], aRect.height);
clipRect.Inflate(edge, edge);
nsBoundingMetrics bm = bmdata[i];
SetFontFamily(aRenderingContext, aFont, aGlyphTable, chGlue, mFamily);
nsRect clipRect = unionRect;
for (i = 0; i < right; ++i) {
// Make sure not to draw outside the character
nscoord dx = PR_MAX(end[i], aRect.x);
nscoord fillEnd = PR_MIN(start[i+1], aRect.XMost());
#ifdef SHOW_BORDERS
// rectangles in-between that are to be filled
aRenderingContext.SetColor(NS_RGB(255,0,0));
clipRect.x = dx;
clipRect.width = fillEnd - dx;
aRenderingContext.DrawRect(clipRect);
{
#endif
AutoPushClipRect clip(aRenderingContext, clipRect);
while (dx + bm.rightBearing < start[i+1]) {
if (count++ < 2) {
stride = bm.rightBearing;
bm = bmdata[3]; // glue
stride -= bm.leftBearing;
}
dx += stride;
aRenderingContext.DrawString(&glue.code, 1, dx, dy);
while (dx < fillEnd) {
clipRect.x = dx;
clipRect.width = PR_MIN(bm.rightBearing - bm.leftBearing, fillEnd - dx);
AutoPushClipRect clip(aRenderingContext, clipRect);
dx -= bm.leftBearing;
aRenderingContext.DrawString(&chGlue.code, 1, dx, dy);
dx += bm.rightBearing;
}
#ifdef SHOW_BORDERS
}
@ -2547,8 +2616,10 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
}
#ifdef DEBUG
else { // no glue
NS_ASSERTION(end[0] >= start[1] && end[1] >= start[2],
"gap between parts with no glue");
for (i = 0; i < right; ++i) {
NS_ASSERTION(end[i] >= start[i+1],
"gap between parts with missing glue glyph");
}
}
#endif
return NS_OK;

View File

@ -0,0 +1,26 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
html { background-color: grey; }
div { display: inline-block;
font-size: 30px;
line-height: 60px; /* Ensure space for overbar */
border: 1px solid white;
padding: 2px; /* 10% error allowed in char selection */
background-color: black;
color: red; }
</style>
</head>
<body>
<div>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mphantom>
<mover>
<mi>ai</mi>
<mo>&#xaf;</mo>
</mover>
</mphantom>
</math>
</div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Check width of stretchy OverBar</title>
<style type="text/css">
html { background-color: grey; }
div { display: inline-block;
font-size: 30px;
line-height: 60px; /* Ensure space for overbar */
border: 1px solid white;
padding: 2px; /* 10% error allowed in char selection */
background-color: black;
color: black; }
</style>
</head>
<body>
<div>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mover>
<mi>ai</mi>
<mo>&#xaf;</mo>
</mover>
</math>
</div>
</body>
</html>

View File

@ -1,5 +1,6 @@
== mi-mathvariant-1.xhtml mi-mathvariant-1-ref.xhtml
== mi-mathvariant-2.xhtml mi-mathvariant-2-ref.xhtml
== table-width-1.xhtml table-width-1-ref.xhtml
== overbar-width-1.xhtml overbar-width-1-ref.xhtml
!= non-spacing-accent-1.xhtml non-spacing-accent-1-ref.xhtml
!= stretchy-underbar-1.xhtml stretchy-underbar-1-ref.xhtml