protected void doExplicitGlyphLayout()

in batik-bridge/src/main/java/org/apache/batik/bridge/GlyphLayout.java [1059:1452]


    protected void doExplicitGlyphLayout() {

        this.gv.performDefaultLayout();

        float baselineAscent
            = vertical ?
            (float) gv.getLogicalBounds().getWidth() :
            (metrics.getAscent() + Math.abs(metrics.getDescent()));

        int numGlyphs = gv.getNumGlyphs();

        float[] gp = gv.getGlyphPositions(0, numGlyphs+1, null);
        float verticalFirstOffset = 0f;
        float horizontalFirstOffset = 0f;

        boolean glyphOrientationAuto = isGlyphOrientationAuto();
        int glyphOrientationAngle = 0;
        if (!glyphOrientationAuto) {
            glyphOrientationAngle = getGlyphOrientationAngle();
        }
        int i=0;
        int aciStart = aci.getBeginIndex();
        int aciIndex = 0;
        char ch = aci.first();
        int runLimit = aciIndex+aciStart;

        Float x=null, y=null, dx=null, dy=null, rotation=null;
        Object baseline=null;

        float shift_x_pos = 0;
        float shift_y_pos = 0;
        float curr_x_pos = (float)offset.getX();
        float curr_y_pos = (float)offset.getY();

        Point2D.Float pos = new Point2D.Float();
        boolean hasArabicTransparent = false;

        while (i < numGlyphs) {
            if (aciIndex+aciStart >= runLimit) {
                runLimit = aci.getRunLimit(runAtts);
                x        = (Float) aci.getAttribute(X);
                y        = (Float) aci.getAttribute(Y);
                dx       = (Float) aci.getAttribute(DX);
                dy       = (Float) aci.getAttribute(DY);
                rotation = (Float) aci.getAttribute(ROTATION);
                baseline = aci.getAttribute(BASELINE_SHIFT);
            }

            GVTGlyphMetrics gm = gv.getGlyphMetrics(i);

            if (i==0) {
                if (isVertical()) {
                    if (glyphOrientationAuto) {
                        if (isLatinChar(ch)) {
                            // it will be rotated 90
                            verticalFirstOffset = 0f;
                        } else {
                            // it won't be rotated
                            float advY = gm.getVerticalAdvance();
                            float asc  = metrics.getAscent();
                            float dsc  = metrics.getDescent();
                            verticalFirstOffset =  asc+(advY-(asc+dsc))/2;
                        }
                    } else {
                        if (glyphOrientationAngle == 0) {
                            float advY = gm.getVerticalAdvance();
                            float asc  = metrics.getAscent();
                            float dsc  = metrics.getDescent();
                            verticalFirstOffset =  asc+(advY-(asc+dsc))/2;
                        } else {
                            // 90, 180, 270
                            verticalFirstOffset = 0f;
                        }
                    }
                } else {  // not vertical
                    if ((glyphOrientationAngle == 270)) {
                        horizontalFirstOffset =
                            (float)gm.getBounds2D().getHeight();
                    } else {
                        // 0, 90, 180
                        horizontalFirstOffset = 0;
                    }
                }
            } else {  // not the first char
                if (glyphOrientationAuto        &&
                    (verticalFirstOffset == 0f) && !isLatinChar(ch)) {
                    float advY = gm.getVerticalAdvance();
                    float asc  = metrics.getAscent();
                    float dsc  = metrics.getDescent();
                    verticalFirstOffset =  asc + (advY - (asc+dsc))/2;
                }
            }

            // ox and oy are origin adjustments for each glyph,
            // computed on the basis of baseline-shifts, etc.
            float ox = 0f;
            float oy = 0f;
            float glyphOrientationRotation = 0f;
            float glyphRotation = 0f;

            if (ch != CharacterIterator.DONE) {
                if (vertical) {
                    if (glyphOrientationAuto) {
                        if (isLatinChar(ch)) {
                            // If character is Latin, then rotate by
                            // 90 degrees
                            glyphOrientationRotation = (float) (Math.PI / 2f);
                        } else {
                            glyphOrientationRotation = 0f;
                        }
                    } else {
                        glyphOrientationRotation = (float)Math.toRadians(glyphOrientationAngle);
                    }
                    if (textPath != null) {
                        // if vertical and on a path, any x's are ignored
                        x = null;
                    }
                } else {
                    glyphOrientationRotation = (float)Math.toRadians(glyphOrientationAngle);
                    if (textPath != null) {
                        // if horizontal and on a path, any y's are ignored
                        y = null;
                    }
                }

                // calculate the total rotation for this glyph
                if (rotation == null || rotation.isNaN()) {
                    glyphRotation = glyphOrientationRotation;
                } else {
                    glyphRotation = (rotation +
                                     glyphOrientationRotation);
                }

                if ((x != null) && !x.isNaN()) {
                    if (i == 0)
                        shift_x_pos = (float)(x -offset.getX());
                    curr_x_pos = x -shift_x_pos;
                }
                if (dx != null && !dx.isNaN()) {
                    curr_x_pos += dx;
                }

                if ((y != null) && !y.isNaN()) {
                    if (i == 0)
                        shift_y_pos = (float)(y -offset.getY());
                    curr_y_pos = y -shift_y_pos;
                }
                if (dy != null && !dy.isNaN()) {
                    curr_y_pos += dy;
                } else if (i > 0) {
                    curr_y_pos += gp[i*2 + 1]-gp[i*2 - 1];
                }

                float baselineAdjust = 0f;
                if (baseline != null) {
                    if (baseline instanceof Integer) {
                        if (baseline==TextAttribute.SUPERSCRIPT_SUPER) {
                            baselineAdjust = baselineAscent*0.5f;
                        } else if (baseline==TextAttribute.SUPERSCRIPT_SUB) {
                            baselineAdjust = -baselineAscent*0.5f;
                        }
                    } else if (baseline instanceof Float) {
                        baselineAdjust = (Float) baseline;
                    }
                    if (vertical) {
                        ox = baselineAdjust;
                    } else {
                        oy = -baselineAdjust;
                    }
                }

                if (vertical) {
                    // offset due to rotation of first character
                    oy += verticalFirstOffset;

                    if (glyphOrientationAuto) {
                        if (isLatinChar(ch)) {
                            ox += metrics.getStrikethroughOffset();
                        } else {
                            Rectangle2D glyphBounds
                                = gv.getGlyphVisualBounds(i).getBounds2D();
                            ox -= (float)((glyphBounds.getMaxX() - gp[2*i]) -
                                          glyphBounds.getWidth()/2);
                        }
                    } else {
                        // center the character if it's not auto orient
                        Rectangle2D glyphBounds
                            = gv.getGlyphVisualBounds(i).getBounds2D();
                        if (glyphOrientationAngle == 0) {
                            ox -= (float)((glyphBounds.getMaxX() - gp[2*i]) -
                                          glyphBounds.getWidth()/2);
                        } else if (glyphOrientationAngle == 180) {
                            ox += (float)((glyphBounds.getMaxX() - gp[2*i]) -
                                          glyphBounds.getWidth()/2);
                        } else if (glyphOrientationAngle == 90) {
                            ox += metrics.getStrikethroughOffset();
                        } else { // 270
                            ox -= metrics.getStrikethroughOffset();
                        }
                    }
                } else {
                    ox += horizontalFirstOffset;
                    if (glyphOrientationAngle == 90) {
                        oy -= gm.getHorizontalAdvance();
                    } else if (glyphOrientationAngle == 180) {
                        oy -= metrics.getAscent();
                    }
                }
            }

            // set the new glyph position
            pos.x = curr_x_pos+ox;
            pos.y = curr_y_pos+oy;
            gv.setGlyphPosition(i, pos);

            // calculate the position of the next glyph
            if (ArabicTextHandler.arabicCharTransparent(ch)) {
                hasArabicTransparent = true;
            } else {
                // Apply the advance if the current char is not transparent
                if (vertical) {
                    float advanceY = 0;
                    if (glyphOrientationAuto) {
                        if (isLatinChar(ch)) {
                            advanceY = gm.getHorizontalAdvance();
                        } else {
                            advanceY = gm.getVerticalAdvance();
                        }
                    } else {
                        if ((glyphOrientationAngle ==   0) ||
                            (glyphOrientationAngle == 180)) {
                            advanceY = gm.getVerticalAdvance();
                        } else if (glyphOrientationAngle == 90) {
                            advanceY = gm.getHorizontalAdvance();
                        } else { // 270
                            advanceY = gm.getHorizontalAdvance();
                            // need to translate so that the spacing
                            // between chars is correct
                            gv.setGlyphTransform
                                (i, AffineTransform.getTranslateInstance
                                 (0, advanceY));
                        }
                    }
                    curr_y_pos += advanceY;
                } else {
                    float advanceX = 0;
                    if (glyphOrientationAngle ==   0) {
                        advanceX = gm.getHorizontalAdvance();
                    } else if (glyphOrientationAngle == 180) {
                        advanceX = gm.getHorizontalAdvance();
                        // need to translate so that the spacing
                        // between chars is correct
                        gv.setGlyphTransform
                            (i, AffineTransform.getTranslateInstance
                             (advanceX, 0));
                    } else {
                        // 90, 270
                        advanceX = gm.getVerticalAdvance();
                    }
                    curr_x_pos += advanceX;
                }
            }

            // rotate the glyph
            if (!epsEQ(glyphRotation,0)) {
                AffineTransform glyphTransform = gv.getGlyphTransform(i);
                if (glyphTransform == null) {
                    glyphTransform = new AffineTransform();
                }
                AffineTransform rotAt;
                // Make the 90Deg rotations slightly 'snap to'.
                // Also use explicit matrix to avoid round-off.
                if (epsEQ(glyphRotation, Math.PI/2)) {
                    rotAt = new AffineTransform(0, 1, -1, 0, 0, 0);
                } else if (epsEQ(glyphRotation, Math.PI)) {
                    rotAt = new AffineTransform(-1, 0, 0, -1, 0, 0);
                } else if (epsEQ(glyphRotation, 3*Math.PI/2)) {
                    rotAt = new AffineTransform(0, -1, 1, 0, 0, 0);
                } else {
                    rotAt = AffineTransform.getRotateInstance(glyphRotation);
                }
                glyphTransform.concatenate(rotAt);
                gv.setGlyphTransform(i, glyphTransform);
            }

            aciIndex += gv.getCharacterCount(i,i);
            if (aciIndex >= charMap.length)
                aciIndex = charMap.length-1;
            ch = aci.setIndex(aciIndex+aciStart);
            i++;
        }
        // Update last glyph pos
        pos.x = curr_x_pos;
        pos.y = curr_y_pos;
        gv.setGlyphPosition(i, pos);

        advance = new Point2D.Float((float)(curr_x_pos - offset.getX()),
                                    (float)(curr_y_pos - offset.getY()));


        // Do a last pass positioning the transparent/mark glyphs on the
        // base glyphs.
        if (hasArabicTransparent) {
            ch = aci.first();
            aciIndex = 0;
            i=0;
            int transparentStart = -1;
            while (i < numGlyphs) {
                if (ArabicTextHandler.arabicCharTransparent(ch)) {
                    if (transparentStart == -1) transparentStart = i;
                } else {
                    if (transparentStart != -1) {
                        Point2D         loc   = gv.getGlyphPosition(i);
                        GVTGlyphMetrics gm    = gv.getGlyphMetrics(i);
                        int tyS=0, txS=0;      // these never changed ??     todo
                        float advX=0, advY=0;
                        if (vertical) {
                            if (glyphOrientationAuto ||
                                (glyphOrientationAngle == 90))
                                advY = gm.getHorizontalAdvance();
                            else if (glyphOrientationAngle == 270)
                                advY = 0;
                            else if (glyphOrientationAngle == 0)
                                advX = gm.getHorizontalAdvance();
                            else // 180
                                advX = -gm.getHorizontalAdvance();
                        } else {
                            if (glyphOrientationAngle ==   0)
                                advX = gm.getHorizontalAdvance();
                            else if (glyphOrientationAngle == 90)
                                advY = gm.getHorizontalAdvance();
                            else if (glyphOrientationAngle == 180)
                                advX = 0;
                            else // 270
                                advY = -gm.getHorizontalAdvance();
                        }
                        float baseX = (float)(loc.getX()+advX);
                        float baseY = (float)(loc.getY()+advY);
                        for (int j=transparentStart; j<i; j++) {
                            Point2D         locT = gv.getGlyphPosition(j);
                            GVTGlyphMetrics gmT  = gv.getGlyphMetrics(j);
                            float           locX = (float)locT.getX();
                            float           locY = (float)locT.getY();
                            float           tx=0, ty=0;
                            float           advT = gmT.getHorizontalAdvance();
                            if (vertical) {
                                if (glyphOrientationAuto ||
                                    (glyphOrientationAngle == 90))
                                    locY = baseY-advT;
                                else if (glyphOrientationAngle == 270)
                                    locY = baseY+advT;
                                else if (glyphOrientationAngle == 0)
                                    locX = baseX-advT;
                                else // 180deg
                                    locX = baseX+advT;
                            } else {
                                if (glyphOrientationAngle ==   0)
                                    locX = baseX-advT;
                                else if (glyphOrientationAngle == 90)
                                    locY = baseY-advT;
                                else if (glyphOrientationAngle == 180)
                                    locX = baseX+advT;
                                else // 270
                                    locY = baseY+advT;
                            }

                            locT = new Point2D.Double(locX, locY);
                            gv.setGlyphPosition(j, locT);
                            if ((txS != 0) || (tyS != 0)) {        // because txS, tyS are set to 0 and not
                                AffineTransform at;                // changed, this path is never used  todo
                                at = AffineTransform.getTranslateInstance
                                    (tx,ty);
                                at.concatenate(gv.getGlyphTransform(i));
                                gv.setGlyphTransform(i, at);
                            }
                        }
                        transparentStart = -1;
                    }
                }
                aciIndex += gv.getCharacterCount(i,i);
                if (aciIndex >= charMap.length)
                    aciIndex = charMap.length-1;
                ch = aci.setIndex(aciIndex+aciStart);
                i++;
            }

        }


        layoutApplied  = true;
        spacingApplied = false;
        glyphAdvances  = null;
        pathApplied    = false;
    }