bella       01/07/04 23:31:47

  Modified:    sources/org/apache/batik/gvt/text GlyphLayout.java
  Log:
  fixed problem with vertical alignment, improved the text selection
  
  Revision  Changes    Path
  1.16      +164 -158  xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java
  
  Index: GlyphLayout.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- GlyphLayout.java  2001/06/12 23:49:48     1.15
  +++ GlyphLayout.java  2001/07/05 06:31:46     1.16
  @@ -39,7 +39,7 @@
    * @see org.apache.batik.gvt.TextSpanLayout.
    *
    * @author <a href="[EMAIL PROTECTED]>Bill Haneman</a>
  - * @version $Id: GlyphLayout.java,v 1.15 2001/06/12 23:49:48 bella Exp $
  + * @version $Id: GlyphLayout.java,v 1.16 2001/07/05 06:31:46 bella Exp $
    */
   public class GlyphLayout implements TextSpanLayout {
   
  @@ -58,6 +58,7 @@
       /**
        * Creates the specified text layout using the
        * specified AttributedCharacterIterator and rendering context.
  +     *
        * @param aci the AttributedCharacterIterator whose text is to
        *  be laid out
        * @param offset The offset position of this text layout
  @@ -195,13 +196,15 @@
       /**
        * Returns the current text position at the completion
        * of glyph layout.
  -     * (This is the position that should be used for positioning
  -     * adjacent layouts.)
        */
       public Point2D getAdvance2D() {
           return advance;
       }
   
  +    /**
  +     * Returns the position to used when drawing a text run after this one.
  +     * It takes into account the text path layout if there is one.
  +     */
       public Point2D getTextPathAdvance() {
           if (textPath != null) {
               return textPathAdvance;
  @@ -212,14 +215,15 @@
   
   
       /**
  -     * Returns the glyph index of the glyph that has the specified char index.
  +     * Returns the index of the glyph that has the specified char index.
        *
        * @param charIndex The original index of the character in the text node's
        * text string.
        * @return The index of the matching glyph in this layout's glyph vector,
        *         or -1 if a matching glyph could not be found.
        */
  -    private int getGlyphIndex(int charIndex) {
  +    public int getGlyphIndex(int charIndex) {
  +
           int currentChar = aci.getBeginIndex();
           int numGlyphs = getGlyphCount();
           for (int i = 0; i < numGlyphs; i++) {
  @@ -234,89 +238,40 @@
           return -1;
       }
   
  -
      /**
        * Returns a Shape which encloses the currently selected glyphs
        * as specified by the character indices.
        *
        * @param beginCharIndex the index of the first char in the contiguous 
selection.
        * @param endCharIndex the index of the last char in the contiguous selection.
  -     * @param selectionLeftToRight Indicates the selection direction.
        * @return The highlight shape or null if the spacified char range does not
        * overlap with the chars in this layout.
        */
  -    public Shape getHighlightShape(int beginCharIndex, int endCharIndex,
  -                                   boolean selectionLeftToRight) {
  -
  -        Shape shape = null;
  -        int begin = getGlyphIndex(beginCharIndex);
  -        int end = getGlyphIndex(endCharIndex);
  -        aci.first();
  -        int firstGlyphCharIndex = ((Integer)aci.getAttribute(
  -            GVTAttributedCharacterIterator.TextAttribute.CHAR_INDEX)).intValue();
  +    public Shape getHighlightShape(int beginCharIndex, int endCharIndex) {
   
  -        if (begin == -1 && end == -1) {
  -            // either select all or none
  -            if (beginCharIndex > endCharIndex) { // swap
  -                int temp = endCharIndex;
  -                endCharIndex = beginCharIndex;
  -                beginCharIndex = temp;
  -            }
  -            if (firstGlyphCharIndex > beginCharIndex && firstGlyphCharIndex < 
endCharIndex) {
  -                // select all
  -                begin = 0;
  -                end = getGlyphCount()-1;
  -            } else {
  -                // select none
  -                return null;
  -            }
  +        if (beginCharIndex > endCharIndex) {
  +            int temp = beginCharIndex;
  +            beginCharIndex = endCharIndex;
  +            endCharIndex = temp;
           }
  -        if (begin < 0) {
  -            if (isLeftToRight()) {
  -                if (selectionLeftToRight) {
  -                    begin = 0;
  -                } else {
  -                    begin = getGlyphCount()-1;
  -                }
  -            } else {
  -                if (selectionLeftToRight) {
  -                    begin = getGlyphCount()-1;
  -                } else {
  -                    begin = 0;
  -                }
  -            }
  -        }
  -        if (end < 0) {
  -            if (isLeftToRight()) {
  -                if (selectionLeftToRight) {
  -                    end = getGlyphCount()-1;
  -                } else {
  -                    end = 0;
  -                }
  -            } else {
  -                if (selectionLeftToRight) {
  -                    end = 0;
  -                } else {
  -                    end = getGlyphCount()-1;
  -                }
  -            }
  -        }
  -        if (begin > end) { // swap
  -            int temp = end;
  -            end = begin;
  -            begin = temp;
  -        }
  -
  -        for (int i = begin; i <= end; i++) {
  -
  -            Shape gbounds = gv.getGlyphLogicalBounds(i);
  -            if (gbounds != null) {
  -                if (shape == null) {
  -                    shape = new GeneralPath(gbounds);
  -                } else {
  -                    ((GeneralPath) shape).append(gbounds, false);
  +        Shape shape = null;
  +        int currentChar = aci.getBeginIndex();
  +        int numGlyphs = getGlyphCount();
  +        for (int i = 0; i < numGlyphs; i++) {
  +            aci.setIndex(currentChar);
  +            int glyphCharIndex = ((Integer)aci.getAttribute(
  +                
GVTAttributedCharacterIterator.TextAttribute.CHAR_INDEX)).intValue();
  +            if (glyphCharIndex >= beginCharIndex && glyphCharIndex <= endCharIndex) 
{
  +                Shape gbounds = gv.getGlyphLogicalBounds(i);
  +                if (gbounds != null) {
  +                    if (shape == null) {
  +                        shape = new GeneralPath(gbounds);
  +                    } else {
  +                        ((GeneralPath) shape).append(gbounds, false);
  +                    }
                   }
               }
  +            currentChar += getCharacterCount(i, i);
           }
           if (transform != null && shape != null) {
               shape = transform.createTransformedShape(shape);
  @@ -330,6 +285,7 @@
        *
        * @param x the x coordinate of the point to be tested.
        * @param y the y coordinate of the point to be tested.
  +     *
        * @return a TextHit object encapsulating the character index for
        *     successful hits and whether the hit is on the character
        *     leading edge.
  @@ -350,7 +306,6 @@
   
           int currentChar = aci.getBeginIndex();
           for (int i = 0; i < gv.getNumGlyphs(); i++) {
  -
               Shape gbounds = gv.getGlyphLogicalBounds(i);
               if (gbounds != null) {
                   Rectangle2D gbounds2d = gbounds.getBounds2D();
  @@ -376,6 +331,7 @@
        */
       public boolean isVertical() {
   
  +        aci.first();
           if (aci.getAttribute(GVTAttributedCharacterIterator.
                               TextAttribute.WRITING_MODE) ==
               GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_TTB) {
  @@ -400,11 +356,14 @@
           return gv.getNumGlyphs();
       }
   
  +
       /**
        * Returns the number of chars represented by the glyphs within the
        * specified range.
  +     *
        * @param startGlyphIndex The index of the first glyph in the range.
        * @param endGlyphIndex The index of the last glyph in the range.
  +     *
        * @return The number of chars.
        */
       public int getCharacterCount(int startGlyphIndex, int endGlyphIndex) {
  @@ -449,6 +408,7 @@
        * Returns a shape describing the strikethrough line for a given ACI.
        */
       protected Shape getUnderlineShape() {
  +
           double y = metrics.getUnderlineOffset();
           float underlineThickness = metrics.getUnderlineThickness();
   
  @@ -484,6 +444,14 @@
                              logicalBounds.getMaxX() - strikethroughThickness/2.0, 
offset.getY()+y));
       }
   
  +    /**
  +     * Returns the GVTFont to use when rendering the specified character iterator.
  +     * This should already be set as an attribute on the aci.
  +     *
  +     * @param aci The character iterator to get the font attribute from.
  +     *
  +     * @return The GVTFont to use.
  +     */
       protected GVTFont getFont(AttributedCharacterIterator aci) {
           aci.first();
           GVTFont gvtFont = (GVTFont)aci.getAttributes().get(
  @@ -496,6 +464,10 @@
           }
       }
   
  +    /**
  +     * If this layout is on a text path, positions the characters along the
  +     * path.
  +     */
       protected void doPathLayout() {
   
           aci.first();
  @@ -628,6 +600,9 @@
           }
       }
   
  +    /**
  +     * Does any spacing adjustments that may have been specified.
  +     */
       protected void adjustTextSpacing() {
   
           aci.first();
  @@ -649,37 +624,15 @@
   
           if (lengthAdjust ==
               GVTAttributedCharacterIterator.TextAttribute.ADJUST_ALL) {
  -             //  transform = computeStretchTransform(length);
                applyStretchTransform(length);
           }
       }
  -
  -    protected AffineTransform computeStretchTransform(Float length) {
  -        AffineTransform t = null;
  -        if (length!= null && !length.isNaN()) {
  -            double xscale = 1d;
  -            double yscale = 1d;
  -            if (isVertical()) {
  -                yscale = length.floatValue()/gv.getVisualBounds().getHeight();
  -            } else {
  -                xscale = length.floatValue()/gv.getVisualBounds().getWidth();
  -            }
  -            try {
  -                Point2D startPos = gv.getGlyphPosition(0);
  -                AffineTransform translation =
  -                        AffineTransform.getTranslateInstance(
  -                                              startPos.getX(),
  -                                              startPos.getY());
  -                AffineTransform inverse = translation.createInverse();
  -                t = translation;
  -                t.concatenate(
  -                        AffineTransform.getScaleInstance(xscale, yscale));
  -                t.concatenate(inverse);
  -            } catch (java.awt.geom.NoninvertibleTransformException e) {;}
  -        }
  -        return t;
  -    }
   
  +    /**
  +     * Stretches the text so that it becomes the specified length.
  +     *
  +     * @param length The required length of the text.
  +     */
       protected void applyStretchTransform(Float length) {
           if (length!= null && !length.isNaN()) {
               double xscale = 1d;
  @@ -713,10 +666,17 @@
           }
       }
   
  -
  -
   
  -
  +    /**
  +     * Adjusts the spacing according to the specified parameters.
  +     *
  +     * @param length The required text length.
  +     * @param lengthAdjust Indicates the method to use when adjusting the text
  +     * length.
  +     * @param kern The kerning adjustment to apply to the space between each char.
  +     * @param letterSpacing The amount of spacing required between each char.
  +     * @param wordSpacing The amount of spacing required between each word.
  +     */
       protected void applySpacingParams(Float length,
                                         Integer lengthAdjust,
                                         Float kern,
  @@ -749,9 +709,17 @@
           }
       }
   
  +    /**
  +     * Performs any spacing adjustments required and returns the new advance
  +     * value.
  +     *
  +     * @param kern The kerning adjustment to apply to the space between each char.
  +     * @param letterSpacing The amount of spacing required between each char.
  +     * @param wordSpacing The amount of spacing required between each word.
  +     */
       protected Point2D doSpacing(Float kern,
  -                             Float letterSpacing,
  -                             Float wordSpacing) {
  +                                Float letterSpacing,
  +                                Float wordSpacing) {
   
           boolean autoKern = true;
           boolean doWordSpacing = false;
  @@ -890,6 +858,12 @@
           return newAdvance;
       }
   
  +    /**
  +     * Rescales the spacing between each char by the specified scale factors.
  +     *
  +     * @param xscale The amount to scale in the x direction.
  +     * @param yscale The amount to scale in the y direction.
  +     */
       protected void rescaleSpacing(float xscale, float yscale) {
           Rectangle2D bounds = gv.getVisualBounds();
           float initX = (float) bounds.getX();
  @@ -897,7 +871,7 @@
           int numGlyphs = gv.getNumGlyphs();
           float dx = 0f;
           float dy = 0f;
  -        for (int i=0; i<numGlyphs; ++i) {
  +        for (int i = 0; i < numGlyphs; i++) {
               Point2D gpos = gv.getGlyphPosition(i);
               dx = (float)gpos.getX()-initX;
               dy = (float)gpos.getY()-initY;
  @@ -905,10 +879,17 @@
                                                        initY+dy*yscale));
           }
           advance = new Point2D.Float((float)(initX+dx*xscale-offset.getX()),
  -                                       (float)(initY+dy*yscale-offset.getY()));
  +                                    (float)(initY+dy*yscale-offset.getY()));
       }
   
  -
  +    /**
  +     * Returns true if the specified character is within one of the Latin
  +     * unicode character blocks.
  +     *
  +     * @param c The char to test.
  +     *
  +     * @return True if c is latin.
  +     */
       protected boolean isLatinChar(char c) {
   
           Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
  @@ -925,7 +906,16 @@
   
       }
   
  +    /**
  +     * Explicitly lays out each of the glyphs in the glyph vector. This will
  +     * handle any glyph position adjustments such as dx, dy and baseline offsets.
  +     * It will also handle vertical layouts.
  +     *
  +     * @param applyOffset Specifies whether or not to add the offset position
  +     * to each of the glyph positions.
  +     */
       protected void doExplicitGlyphLayout(boolean applyOffset) {
  +
           char ch = aci.first();
           int i=0;
           float baselineAscent = isVertical() ?
  @@ -944,31 +934,39 @@
           float curr_y_pos = init_y_pos;
           boolean firstChar = true;
           float verticalFirstOffset = 0f;
  +        float largestAdvanceY = 0;
   
  -        boolean glyphOrientationAuto =
  -            
(aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION)
  -                == GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_AUTO);
  +        boolean glyphOrientationAuto = true;
           int glyphOrientationAngle = 0;
  -        if (!glyphOrientationAuto) {
  -            glyphOrientationAngle = 
(int)((Float)aci.getAttribute(GVTAttributedCharacterIterator.
  -                                           
TextAttribute.VERTICAL_ORIENTATION_ANGLE)).floatValue();
  -            // if not one of 0, 90, 180 or 270, round to nearest value
  -            if (glyphOrientationAngle != 0 || glyphOrientationAngle != 90
  -               || glyphOrientationAngle != 180 || glyphOrientationAngle != 270) {
  -                while (glyphOrientationAngle < 0) {
  -                    glyphOrientationAngle += 360;
  -                }
  -                while (glyphOrientationAngle >= 360) {
  -                    glyphOrientationAngle -= 360;
  -                }
  -                if (glyphOrientationAngle <= 45 || glyphOrientationAngle > 315) {
  -                    glyphOrientationAngle = 0;
  -                } else if (glyphOrientationAngle > 45 && glyphOrientationAngle <= 
135) {
  -                    glyphOrientationAngle = 90;
  -                } else if (glyphOrientationAngle > 135 && glyphOrientationAngle <= 
225) {
  -                    glyphOrientationAngle = 180;
  -                } else {
  -                    glyphOrientationAngle = 270;
  +
  +        if 
(aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION) 
!= null) {
  +            glyphOrientationAuto = 
(aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION)
  +                                     == 
GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_AUTO);
  +
  +            if (!glyphOrientationAuto) {
  +                Float angle = 
(Float)aci.getAttribute(GVTAttributedCharacterIterator.
  +                                           
TextAttribute.VERTICAL_ORIENTATION_ANGLE);
  +                if (angle != null) {
  +                    glyphOrientationAngle = (int)angle.floatValue();
  +                }
  +                // if not one of 0, 90, 180 or 270, round to nearest value
  +                if (glyphOrientationAngle != 0 || glyphOrientationAngle != 90
  +                    || glyphOrientationAngle != 180 || glyphOrientationAngle != 
270) {
  +                    while (glyphOrientationAngle < 0) {
  +                        glyphOrientationAngle += 360;
  +                    }
  +                    while (glyphOrientationAngle >= 360) {
  +                        glyphOrientationAngle -= 360;
  +                    }
  +                    if (glyphOrientationAngle <= 45 || glyphOrientationAngle > 315) 
{
  +                        glyphOrientationAngle = 0;
  +                    } else if (glyphOrientationAngle > 45 && glyphOrientationAngle 
<= 135) {
  +                        glyphOrientationAngle = 90;
  +                    } else if (glyphOrientationAngle > 135 && glyphOrientationAngle 
<= 225) {
  +                        glyphOrientationAngle = 180;
  +                    } else {
  +                        glyphOrientationAngle = 270;
  +                    }
                   }
               }
           }
  @@ -1136,39 +1134,47 @@
                           (double)rotation.floatValue()));
               }
   
  -            GVTGlyphMetrics gm = gv.getGlyphMetrics(i);
  -            if (isVertical()) {
  -                if (glyphOrientationAuto) {
  -                    if (isLatinChar(ch)) {
  -                        curr_y_pos += gm.getHorizontalAdvance();
  -                    } else {
  -                        curr_y_pos += gm.getVerticalAdvance();
  -                    }
  -                } else {
  -                    if (glyphOrientationAngle == 0 || glyphOrientationAngle == 180) 
{
  -                        curr_y_pos += gm.getVerticalAdvance();
  -                    } else if (glyphOrientationAngle == 90) {
  -                        curr_y_pos += gm.getHorizontalAdvance();
  -                    } else { // 270
  -                        if (i < gv.getNumGlyphs()-1) {
  -                            GVTGlyphMetrics nextGm = gv.getGlyphMetrics(i+1);
  -                            curr_y_pos += nextGm.getHorizontalAdvance();
  +            if (!ArabicTextHandler.arabicCharTransparent(ch)) {
  +                // only apply the advance if the current char is not transparent
  +                GVTGlyphMetrics gm = gv.getGlyphMetrics(i);
  +                if (isVertical()) {
  +                    float advanceY = 0;
  +                    if (glyphOrientationAuto) {
  +                        if (isLatinChar(ch)) {
  +                            advanceY = gm.getHorizontalAdvance();
                           } else {
  -                            curr_y_pos += gm.getHorizontalAdvance();
  +                            advanceY = gm.getVerticalAdvance();
                           }
  +                    } else {
  +                        if (glyphOrientationAngle == 0 || glyphOrientationAngle == 
180) {
  +                            advanceY = gm.getVerticalAdvance();
  +                        } else if (glyphOrientationAngle == 90) {
  +                            advanceY = gm.getHorizontalAdvance();
  +                        } else { // 270
  +                            if (i < gv.getNumGlyphs()-1) {
  +                                GVTGlyphMetrics nextGm = gv.getGlyphMetrics(i+1);
  +                                advanceY = nextGm.getHorizontalAdvance();
  +                            } else {
  +                                // need to estimate here, use the vertical advance
  +                                // value because it should be bigger than the
  +                                // width of any glyph that follows
  +                                advanceY = gm.getVerticalAdvance();
  +                            }
  +                        }
                       }
  +                    curr_y_pos += advanceY;
  +                } else {
  +                    curr_x_pos += gm.getHorizontalAdvance();
                   }
  -            } else {
  -                curr_x_pos += gm.getHorizontalAdvance();
               }
  -            ch = aci.next();
  -            ++i;
  +            i++;
  +            ch = aci.setIndex(aci.getBeginIndex() + i);
               firstChar = false;
   
           }
   
  -        advance = new Point2D.Float((float) (curr_x_pos-offset.getX()),
  -                                    (float) (curr_y_pos-offset.getY()));
  +        advance = new Point2D.Float((float) (curr_x_pos - offset.getX()),
  +                                    (float) (curr_y_pos - offset.getY()));
   
           offset = new Point2D.Float(init_x_pos, init_y_pos);
       }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to