private void computeGlyphLogicalBounds()

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() );
    }