in batik-gvt/src/main/java/org/apache/batik/gvt/font/SVGGVTGlyphVector.java [165:351]
private void computeGlyphLogicalBounds() {
float ascent = 0;
float descent = 0;
if (font != null) {
// font will only be null if this glyph vector is for an altGlyph
GVTLineMetrics lineMetrics = font.getLineMetrics("By", frc);
ascent = lineMetrics.getAscent();
descent = lineMetrics.getDescent();
if (descent < 0) {
// make descent a positive value
descent = -descent;
}
}
if (ascent == 0) {
float maxAscent = 0;
float maxDescent = 0;
for (int i = 0; i < getNumGlyphs(); i++) {
if (!glyphVisible[i]) continue;
GVTGlyphMetrics glyphMetrics = getGlyphMetrics(i);
Rectangle2D glyphBounds = glyphMetrics.getBounds2D();
ascent = (float)(-glyphBounds.getMinY());
descent = (float)(glyphBounds.getHeight()-ascent);
if (ascent > maxAscent) maxAscent = ascent;
if (descent > maxDescent) maxDescent = descent;
}
ascent = maxAscent;
descent = maxDescent;
}
Shape[] tempLogicalBounds = new Shape[getNumGlyphs()];
boolean[] rotated = new boolean[getNumGlyphs()];
double maxWidth = -1;
double maxHeight = -1;
for (int i = 0; i < getNumGlyphs(); i++) {
if (!glyphVisible[i]) {
// the glyph is not drawn
tempLogicalBounds[i] = null;
continue;
}
AffineTransform glyphTransform = getGlyphTransform(i);
GVTGlyphMetrics glyphMetrics = getGlyphMetrics(i);
Rectangle2D glyphBounds = new Rectangle2D.Double
(0, -ascent, glyphMetrics.getHorizontalAdvance(),
ascent+descent);
if (glyphBounds.isEmpty()) {
// can't tell if rotated or not, make it
// the same as the previous glyph, if we have one...
if (i > 0) {
rotated[i] = rotated[i-1];
} else {
rotated [i] = true;
}
} else {
// get three corner points so we can determine
// whether the glyph is rotated
Point2D p1 = new Point2D.Double(glyphBounds.getMinX(),
glyphBounds.getMinY());
Point2D p2 = new Point2D.Double(glyphBounds.getMaxX(),
glyphBounds.getMinY());
Point2D p3 = new Point2D.Double(glyphBounds.getMinX(),
glyphBounds.getMaxY());
Point2D gpos = getGlyphPosition(i);
AffineTransform tr = AffineTransform.getTranslateInstance
(gpos.getX(), gpos.getY());
if (glyphTransform != null)
tr.concatenate(glyphTransform);
tempLogicalBounds[i] =
tr.createTransformedShape(glyphBounds);
Point2D tp1 = new Point2D.Double();
Point2D tp2 = new Point2D.Double();
Point2D tp3 = new Point2D.Double();
tr.transform(p1, tp1);
tr.transform(p2, tp2);
tr.transform(p3, tp3);
double tdx12 = tp1.getX()-tp2.getX();
double tdx13 = tp1.getX()-tp3.getX();
double tdy12 = tp1.getY()-tp2.getY();
double tdy13 = tp1.getY()-tp3.getY();
if ((Math.abs(tdx12) < 0.001) &&
(Math.abs(tdy13) < 0.001)) {
// If these are both zero then it is axially aligned
// on it's "side"...
rotated[i] = false;
} else if ((Math.abs(tdx13) < 0.001) &&
(Math.abs(tdy12) < 0.001)) {
// If these are both zero then it is axially aligned
// vertically.
rotated[i] = false;
} else {
rotated[i] = true;
}
Rectangle2D rectBounds;
rectBounds = tempLogicalBounds[i].getBounds2D();
if (rectBounds.getWidth() > maxWidth)
maxWidth = rectBounds.getWidth();
if (rectBounds.getHeight() > maxHeight)
maxHeight = rectBounds.getHeight();
}
}
// if appropriate, join adjacent glyph logical bounds
GeneralPath logicalBoundsPath = new GeneralPath();
for (int i = 0; i < getNumGlyphs(); i++) {
if (tempLogicalBounds[i] != null) {
logicalBoundsPath.append(tempLogicalBounds[i], false);
}
}
Rectangle2D fullBounds = logicalBoundsPath.getBounds2D();
if (fullBounds.getHeight() < maxHeight*1.5) {
// make all glyphs tops and bottoms the same as the full bounds
for (int i = 0; i < getNumGlyphs(); i++) {
// first make sure that the glyph logical bounds are
// not rotated
if (rotated[i]) continue;
if (tempLogicalBounds[i] == null) continue;
Rectangle2D glyphBounds = tempLogicalBounds[i].getBounds2D();
double x = glyphBounds.getMinX();
double width = glyphBounds.getWidth();
if ((i < getNumGlyphs()-1) &&
(tempLogicalBounds[i+1] != null)) {
// make this glyph extend to the start of the next one
Rectangle2D ngb = tempLogicalBounds[i+1].getBounds2D();
if (ngb.getX() > x) {
double nw = ngb.getX() - x;
if ((nw < width*1.15) && (nw > width*.85)) {
double delta = (nw-width)*.5;
width += delta;
ngb.setRect(ngb.getX()-delta, ngb.getY(),
ngb.getWidth()+delta, ngb.getHeight());
}
}
}
tempLogicalBounds[i] = new Rectangle2D.Double
(x, fullBounds.getMinY(),
width, fullBounds.getHeight());
}
} else if (fullBounds.getWidth() < maxWidth*1.5) {
// make all glyphs left and right edges the same as the full bounds
for (int i = 0; i < getNumGlyphs(); i++) {
// first make sure that the glyph logical bounds are
// not rotated
if (rotated[i]) continue;
if (tempLogicalBounds[i] == null) continue;
Rectangle2D glyphBounds = tempLogicalBounds[i].getBounds2D();
double y = glyphBounds.getMinY();
double height = glyphBounds.getHeight();
if ((i < getNumGlyphs()-1) &&
(tempLogicalBounds[i+1] != null)) {
// make this glyph extend to the start of the next one
Rectangle2D ngb = tempLogicalBounds[i+1].getBounds2D();
if (ngb.getY() > y) { // going top to bottom
double nh = ngb.getY() - y;
if ((nh < height*1.15) && (nh > height*.85)) {
double delta = (nh-height)*.5;
height += delta;
ngb.setRect(ngb.getX(), ngb.getY()-delta,
ngb.getWidth(), ngb.getHeight()+delta);
}
}
}
tempLogicalBounds[i] = new Rectangle2D.Double
(fullBounds.getMinX(), y,
fullBounds.getWidth(), height);
}
}
System.arraycopy( tempLogicalBounds, 0, glyphLogicalBounds, 0, getNumGlyphs() );
}