зеркало из https://github.com/mozilla/gecko-dev.git
clip parts of stretchy chars more carefully b=427666 (also fixes b=349907) r+sr=roc a1.9=damons
This commit is contained in:
Родитель
0a08f2b3e7
Коммит
6d1cc05193
|
@ -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;
|
||||
|
|
|
@ -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>¯</mo>
|
||||
</mover>
|
||||
</mphantom>
|
||||
</math>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -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>¯</mo>
|
||||
</mover>
|
||||
</math>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче