deweese     02/01/24 13:35:33

  Modified:    sources/org/apache/batik/ext/awt/image/rendered
                        ProfileRed.java
               sources/org/apache/batik/gvt/renderer
                        StrokingTextPainter.java
               sources/org/apache/batik/gvt/text GlyphLayout.java
                        TextSpanLayout.java
  Added:       samples/tests/spec/text textLength.svg
  Log:
  1) Fixes for textLength with tspan (still problem when tspan first thing
     in text element).
  2) Added test for textLength with anchor.
  
  Revision  Changes    Path
  1.1                  xml-batik/samples/tests/spec/text/textLength.svg
  
  Index: textLength.svg
  ===================================================================
  <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" 
  "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd";>
  
  <!-- ====================================================================== -->
  <!-- Copyright (C) The Apache Software Foundation. All rights reserved.     -->
  <!--                                                                        -->
  <!-- This software is published under the terms of the Apache Software      -->
  <!-- License version 1.1, a copy of which has been included with this       -->
  <!-- distribution in  the LICENSE file.                                     -->
  <!-- ====================================================================== -->
  
  <!-- ====================================================================== -->
  <!-- Tests text-anchor on tspan elements                                    -->
  <!--                                                                        -->
  <!-- @author [EMAIL PROTECTED]                                             -->
  <!-- @version $Id: textLength.svg,v 1.1 2002/01/24 21:35:32 deweese Exp $    -->
  <!-- ====================================================================== -->
  <?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?>  
  
  <svg width="450" height="500" viewBox="0 0 450 500">
  
      <text class="title" x="50%" y="40">textLength with Anchor</text>
  
  
     <defs>
        <g id="fill-rgn">
           <rect x="200" y="10" width="50" height="20"
                   fill="#DDE8FF" stroke="none"/>
           <line x1="225" y1="8" x2="225" y2="32" stroke="red"/>
        </g>
  
        <g id="bg1">
           <rect x="50"  y="0" width ="350" height="50"
                 fill="lightGrey" stroke="black"/>
           <use xlink:href="#fill-rgn"/>
        </g>
  
        <g id="bg2">
           <rect x="50"  y="0" width ="350" height="50"
                 fill="white" stroke="black"/>
           <use xlink:href="#fill-rgn"/>
        </g>
     </defs>
     
     <g font-size="12" >
        <!-- no lengthadjust -->
        <g transform="translate(0,  50)">
                <use xlink:href="#bg1"/>
                <text x="225" y="24" text-anchor="middle">xml-batik</text>
                <text x="225" y="45" text-anchor="middle">No textLength</text>
        </g>
        
        <!-- With lengthAdjust spacingAndGlyphs -->
        <g transform="translate(0, 100)">
                <use xlink:href="#bg2"/>
                <text x="225" y="24" text-anchor="middle" textLength="50"
                        lengthAdjust="spacingAndGlyphs">B</text>
                <text x="225" y="45" text-anchor="middle">textLength="50" 
lengthAdjust="spacingAndGlyphs"</text>
        </g>
        
        <!-- with lengthAdjust spacing -->
        <g transform="translate(0, 150)">
                <use xlink:href="#bg1"/>
                <text x="225" y="24" text-anchor="middle" textLength="50"
                        lengthAdjust="spacing">B</text>
                <text x="225" y="45" text-anchor="middle">textLength="50" 
lengthAdjust="spacing"</text>
        </g>
        
        <!-- with lengthAdjust spacing -->
        <g transform="translate(0, 200)">
                <use xlink:href="#bg2"/>
                <text x="225" y="24" text-anchor="middle" textLength="50"
                        lengthAdjust="spacingAndGlyphs">Batik</text>
                <text x="225" y="45" text-anchor="middle">textLength="50" 
lengthAdjust="spacingAndGlyphs"</text>
        </g>
        
        <!-- with lengthAdjust spacing -->
        <g transform="translate(0, 250)">
                <use xlink:href="#bg1"/>
                <text x="225" y="24" text-anchor="middle" textLength="50"
                        lengthAdjust="spacing">Batik</text>
                <text x="225" y="45" text-anchor="middle">textLength="50" 
lengthAdjust="spacing"</text>
        </g>
        
        <!-- large number -->
        <g transform="translate(0, 300)">
                <use xlink:href="#bg2"/>
                <text x="225" y="24" text-anchor="middle" textLength="50"
                        lengthAdjust="spacingAndGlyphs">Apache Batik</text>
                <text x="225" y="45" text-anchor="middle">textLength="50" 
lengthAdjust="spacingAndGlyphs" (shrinking)</text>
        </g>
        
        <!-- large number, no anchor -->
        <g transform="translate(0, 350)">
                <use xlink:href="#bg1"/>
                <text x="200" y="24" textLength="50"
                        lengthAdjust="spacingAndGlyphs">Apache Batik</text>
                <text x="225" y="45" text-anchor="middle">textLength="50" 
lengthAdjust="spacingAndGlyphs" (no anchor)</text>
        </g>
        
        <!-- large number, tspan -->
        <g transform="translate(0, 400)">
                <use xlink:href="#bg2"/>
                <text x="225" y="24" text-anchor="middle" textLength="50" 
                      lengthAdjust="spacingAndGlyphs">Apache <tspan 
fill="red">Batik</tspan>!!</text>
                <text x="225" y="45" text-anchor="middle">textLength="50" 
lengthAdjust="spacingAndGlyphs" (tspan)</text>
        </g>
     </g>
  
     <!-- ============================================================= -->
     <!-- Batik sample mark                                             -->
     <!-- ============================================================= -->
     <use xlink:href="../../../batikLogo.svg#Batik_Tag_Box" />
  </svg>
  
  
  
  1.3       +54 -53    
xml-batik/sources/org/apache/batik/ext/awt/image/rendered/ProfileRed.java
  
  Index: ProfileRed.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/rendered/ProfileRed.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ProfileRed.java   15 Feb 2001 02:27:29 -0000      1.2
  +++ ProfileRed.java   24 Jan 2002 21:35:32 -0000      1.3
  @@ -37,7 +37,7 @@
    * on its source
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Vincent Hardy</a>
  - * @version $Id: ProfileRed.java,v 1.2 2001/02/15 02:27:29 vhardy Exp $
  + * @version $Id: ProfileRed.java,v 1.3 2002/01/24 21:35:32 deweese Exp $
    */
   public class ProfileRed extends AbstractRed {
       private static final ColorSpace sRGBCS 
  @@ -89,17 +89,19 @@
        *    Note that if the number of components in the input image and 
        *    the number of components in the replacing ColorSpace do not 
        *    match, it is not possible to apply the conversion.
  -     * d. A new BufferedImage is built, using the new ComponentColorModel 
  -     *    and the data from the original image converted to the ComponentColorModel
  -     *    built in a. The alpha channel is excluded from that new BufferedImage.
  +     * d. A new BufferedImage is built, using the new
  +     *    ComponentColorModel and the data from the original image
  +     *    converted to the ComponentColorModel built in a. The alpha
  +     *    channel is excluded from that new BufferedImage.
        * e. The BufferedImage created in d. is converted to sRGB using
        *    ColorConvertOp
        * f. The alpha channel information is integrated back into the image.
        *
  -     * IMPORTANT NOTE: The code uses a BandedSampleModel in c.) and d.) and discard 
the 
  -     * alpha channel during the color conversions (it is restored in f.)), because 
of
  -     * bugs in the interleaved model with alpha. The BandedSampleModel did not cause
  -     * any bug as of JDK 1.3.
  +     * IMPORTANT NOTE: The code uses a BandedSampleModel in c.) and
  +     * d.) and discard the alpha channel during the color conversions
  +     * (it is restored in f.)), because of bugs in the interleaved
  +     * model with alpha. The BandedSampleModel did not cause any bug
  +     * as of JDK 1.3.  
        */
       public WritableRaster copyData(WritableRaster argbWR){
           try{
  @@ -140,25 +142,27 @@
               if(!(imgCM instanceof ComponentColorModel) ||
                  !(img.getSampleModel() instanceof BandedSampleModel)){
                   ComponentColorModel imgCompCM 
  -                    = new ComponentColorModel(imgCS,                         // 
Same ColorSpace as img
  -                                              imgCM.getComponentSize(),      // 
Array of number of bits per components
  -                                              imgCM.hasAlpha(),              // 
Same alpha as img
  -                                              imgCM.isAlphaPremultiplied(),  // 
Same premultiplication as img
  -                                              imgCM.getTransparency(),       // 
Same transparency as img
  -                                              DataBuffer.TYPE_BYTE);         // 8 
bits per components.
  +                    = new ComponentColorModel
  +                        (imgCS,                      // Same ColorSpace as img
  +                         imgCM.getComponentSize(),   // Number of bits/comp
  +                         imgCM.hasAlpha(),             // Same alpha as img
  +                         imgCM.isAlphaPremultiplied(), // Same premult as img  
  +                         imgCM.getTransparency(),      // Same trans as img 
  +                         DataBuffer.TYPE_BYTE);        // 8 bit/component.
   
                   WritableRaster wr 
  -                    = Raster.createBandedRaster(DataBuffer.TYPE_BYTE,
  -                                                argbWR.getWidth(), 
argbWR.getHeight(),
  -                                                imgCompCM.getNumComponents(),
  -                                                new Point(0, 0));
  +                    = Raster.createBandedRaster
  +                    (DataBuffer.TYPE_BYTE,
  +                     argbWR.getWidth(), argbWR.getHeight(),
  +                     imgCompCM.getNumComponents(),
  +                     new Point(0, 0));
                   
  -                BufferedImage imgComp 
  -                    = new BufferedImage(imgCompCM, wr, 
imgCompCM.isAlphaPremultiplied(), null);
  +                BufferedImage imgComp = new BufferedImage
  +                    (imgCompCM, wr, imgCompCM.isAlphaPremultiplied(), null);
   
  -                BufferedImage srcImg
  -                    = new BufferedImage(imgCM, 
srcWR.createWritableTranslatedChild(0, 0),
  -                                        imgCM.isAlphaPremultiplied(), null);
  +                BufferedImage srcImg = new BufferedImage
  +                    (imgCM, srcWR.createWritableTranslatedChild(0, 0),
  +                     imgCM.isAlphaPremultiplied(), null);
                   
                   Graphics2D g = imgComp.createGraphics();
                   g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
  @@ -170,11 +174,11 @@
               }
   
               /**
  -             * Now, the input image is using a component color model. We can
  -             * therefore create an image with the new profile, using a 
ComponentColorModel
  -             * as well, because we know the number of components match (this was 
checked
  -             * at the begining of this routine).
  -             */
  +             * Now, the input image is using a component color
  +             * model. We can therefore create an image with the new
  +             * profile, using a ComponentColorModel as well, because
  +             * we know the number of components match (this was
  +             * checked at the begining of this routine).  */
               ComponentColorModel newCM 
                   = new ComponentColorModel(colorSpace,                    // ****** 
New ColorSpace ********
                                             imgCM.getComponentSize(),      // Array 
of number of bits per components
  @@ -185,34 +189,30 @@
               
               // Build a raster with bands 0, 1 and 2 of img's raster
               DataBufferByte data = (DataBufferByte)srcWR.getDataBuffer();
  -            srcWR = Raster.createBandedRaster(data, img.getWidth(), 
img.getHeight(), 
  -                                           img.getWidth(), new int[]{0, 1, 2},
  -                                           new int[]{0, 0, 0}, new Point(0, 0));
  -            BufferedImage newImg = new BufferedImage(newCM, srcWR,
  -                                                     newCM.isAlphaPremultiplied(), 
null);
  +            srcWR = Raster.createBandedRaster
  +                (data, img.getWidth(), img.getHeight(), 
  +                 img.getWidth(), new int[]{0, 1, 2},
  +                 new int[]{0, 0, 0}, new Point(0, 0));
  +            BufferedImage newImg = new BufferedImage
  +                (newCM, srcWR, newCM.isAlphaPremultiplied(), null);
   
               /**
                * Now, convert the image to sRGB
                */
  -            ComponentColorModel sRGBCompCM =
  -                new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
  -                                        new int[]{8, 8, 8},
  -                                        false,
  -                                        false,
  -                                        Transparency.OPAQUE,
  -                                        DataBuffer.TYPE_BYTE);
  -
  -            WritableRaster wr 
  -                = Raster.createBandedRaster(DataBuffer.TYPE_BYTE,
  -                                            img.getWidth(), img.getHeight(),
  -                                            sRGBCompCM.getNumComponents(),
  -                                            new Point(0, 0));
  -
  -            BufferedImage sRGBImage 
  -                = new BufferedImage(sRGBCompCM,
  -                                    wr,
  -                                    false,
  -                                    null);
  +            ComponentColorModel sRGBCompCM = new ComponentColorModel
  +                (ColorSpace.getInstance(ColorSpace.CS_sRGB),
  +                 new int[]{8, 8, 8},
  +                 false,
  +                 false,
  +                 Transparency.OPAQUE,
  +                 DataBuffer.TYPE_BYTE);
  +
  +            WritableRaster wr = Raster.createBandedRaster
  +                (DataBuffer.TYPE_BYTE, img.getWidth(), img.getHeight(),
  +                 sRGBCompCM.getNumComponents(), new Point(0, 0));
  +
  +            BufferedImage sRGBImage = new BufferedImage
  +                (sRGBCompCM, wr, false, null);
               ColorConvertOp colorConvertOp = new ColorConvertOp(null);
               colorConvertOp.filter(newImg, sRGBImage);
   
  @@ -222,7 +222,8 @@
               DataBufferByte rgbData = (DataBufferByte)wr.getDataBuffer();
               byte[][] imgBanks = data.getBankData();
               byte[][] rgbBanks = rgbData.getBankData();
  -            byte[][] argbBanks = {rgbBanks[0], rgbBanks[1], rgbBanks[2], 
imgBanks[3]};
  +            byte[][] argbBanks = {rgbBanks[0], rgbBanks[1], 
  +                                  rgbBanks[2], imgBanks[3]};
               DataBufferByte argbData = new DataBufferByte(argbBanks, 
imgBanks[0].length);
               srcWR = Raster.createBandedRaster(argbData, img.getWidth(), 
img.getHeight(),
                                              img.getWidth(), new int[]{0, 1, 2, 3},
  
  
  
  1.27      +119 -19   
xml-batik/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java
  
  Index: StrokingTextPainter.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- StrokingTextPainter.java  23 Jan 2002 14:14:09 -0000      1.26
  +++ StrokingTextPainter.java  24 Jan 2002 21:35:32 -0000      1.27
  @@ -40,6 +40,7 @@
   import org.apache.batik.gvt.font.FontFamilyResolver;
   import org.apache.batik.gvt.font.GVTFont;
   import org.apache.batik.gvt.font.GVTFontFamily;
  +import org.apache.batik.gvt.font.GVTGlyphMetrics;
   import org.apache.batik.gvt.font.UnresolvedFontFamily;
   import org.apache.batik.gvt.text.AttributedCharacterSpanIterator;
   import org.apache.batik.gvt.text.BidiAttributedCharacterIterator;
  @@ -60,7 +61,7 @@
    * @see org.apache.batik.gvt.text.GVTAttributedCharacterIterator
    *
    * @author <a href="[EMAIL PROTECTED]>Bill Haneman</a>
  - * @version $Id: StrokingTextPainter.java,v 1.26 2002/01/23 14:14:09 deweese Exp $
  + * @version $Id: StrokingTextPainter.java,v 1.27 2002/01/24 21:35:32 deweese Exp $
    */
   public class StrokingTextPainter extends BasicTextPainter {
   
  @@ -96,6 +97,11 @@
           AttributedCharacterIterator.Attribute ANCHOR_TYPE
           = GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE;
   
  +    public static final Integer ADJUST_SPACING =
  +        GVTAttributedCharacterIterator.TextAttribute.ADJUST_SPACING;
  +    public static final Integer ADJUST_ALL =
  +        GVTAttributedCharacterIterator.TextAttribute.ADJUST_ALL;
  +
       static Set extendedAtts = new HashSet();
   
       static {
  @@ -179,8 +185,8 @@
           TextChunk chunk, prevChunk=null;
           int currentChunk = 0;
           do {
  -         // Text Chunks contain one or more TextRuns, which they create from
  -         // the ACI.
  +         // Text Chunks contain one or more TextRuns, which they
  +         // create from the ACI.
               chunkACIs[currentChunk].first();
   
               chunk = getTextChunk(node, 
  @@ -192,8 +198,7 @@
               // Adjust according to text-anchor property value
               chunkACIs[currentChunk].first();
               if (chunk != null) {
  -                adjustChunkOffsets(textRuns, chunk.advance, 
  -                                   chunk.begin, chunk.end);
  +                adjustChunkOffsets(textRuns, chunk);
               }
               prevChunk = chunk;
               currentChunk++;
  @@ -595,15 +600,85 @@
        * to account for any text anchor properties.
        */
       private void adjustChunkOffsets(List textRuns, 
  -                                    Point2D advance,
  -                                    int beginChunk, 
  -                                    int endChunk) {
  -
  -        TextRun r = (TextRun) textRuns.get(beginChunk);
  +                                    TextChunk chunk) {
  +        TextRun r          = (TextRun) textRuns.get(chunk.begin);
               int anchorType = r.getAnchorType();
  +        Float   length     = r.getLength();
  +        Integer lengthAdj  = r.getLengthAdjust();
  +        Point2D advance = chunk.advance;
  +
               float dx = 0f;
               float dy = 0f;
   
  +        boolean doAdjust = true;
  +        if ((length == null) || length.isNaN())
  +            doAdjust = false;
  +        
  +        int numChars = 0;
  +        for (int n=chunk.begin; n<chunk.end; ++n) {
  +            r = (TextRun) textRuns.get(n);
  +            AttributedCharacterIterator aci = r.getACI();
  +            numChars += aci.getEndIndex()-aci.getBeginIndex();
  +        }
  +        if ((lengthAdj == 
  +             GVTAttributedCharacterIterator.TextAttribute.ADJUST_SPACING) &&
  +            (numChars == 1)) 
  +            doAdjust = false;
  +
  +        float xScale = 1;
  +        float yScale = 1;
  +        if (doAdjust) {
  +            if (lengthAdj == 
  +                GVTAttributedCharacterIterator.TextAttribute.ADJUST_SPACING) {
  +                
  +            }
  +            if (lengthAdj ==
  +                GVTAttributedCharacterIterator.TextAttribute.ADJUST_ALL) {
  +            }
  +
  +            float delta = 0;
  +            r = (TextRun)textRuns.get(chunk.end-1);
  +            TextSpanLayout  layout          = r.getLayout();
  +            GVTGlyphMetrics lastCharMetrics = 
  +                layout.getGlyphMetrics(layout.getGlyphCount()-1);
  +            Rectangle2D     lastCharBounds  = lastCharMetrics.getBounds2D();
  +
  +            if (r.getLayout().isVertical()) {
  +                if (lengthAdj == ADJUST_SPACING) {
  +                    yScale = (float)
  +                        ((length.floatValue()-lastCharBounds.getHeight())/
  +                         (advance.getY()-lastCharBounds.getHeight()));
  +                } else {
  +                    yScale = (float)(length.floatValue()/advance.getY());
  +                }
  +                dy = delta;
  +            } else {
  +                if (lengthAdj == ADJUST_SPACING) {
  +                    xScale = (float)
  +                        ((length.floatValue()-lastCharBounds.getWidth())/
  +                         (advance.getX()-lastCharBounds.getWidth()));
  +                } else {
  +                    xScale = (float)(length.floatValue()/advance.getX());
  +                }
  +                dx = delta;
  +            }
  +
  +            // System.out.println("Adv: " + advance + " Len: " + length +
  +            //                    " scale: [" + xScale + ", " + yScale + "]");
  +            Point2D.Float adv = new Point2D.Float(0,0);
  +            for (int n=chunk.begin; n<chunk.end; ++n) {
  +                r = (TextRun) textRuns.get(n);
  +                layout = r.getLayout();
  +                layout.setScale(xScale, yScale, lengthAdj==ADJUST_SPACING);
  +                Point2D lAdv = layout.getAdvance2D();
  +                adv.x += lAdv.getX();
  +                adv.y += lAdv.getY();
  +            }
  +            chunk.advance = adv;
  +        }
  +
  +        advance = chunk.advance;
  +
               switch(anchorType){
               case TextNode.Anchor.ANCHOR_MIDDLE:
                   dx = (float) (-advance.getX()/2d);
  @@ -618,17 +693,26 @@
                   // leave untouched
               }
   
  -        for (int n=beginChunk; n<endChunk; ++n) {
  -            r = (TextRun) textRuns.get(n);
  +        
  +        r = (TextRun) textRuns.get(chunk.begin);
               TextSpanLayout layout = r.getLayout();
               Point2D        offset = layout.getOffset();
  +        float initX = (float)offset.getX();
  +        float initY = (float)offset.getY();
   
  -            if (layout.isVertical())
  +        for (int n=chunk.begin; n<chunk.end; ++n) {
  +            r = (TextRun) textRuns.get(n);
  +            layout = r.getLayout();
  +            offset = layout.getOffset();
  +            if (layout.isVertical()) {
  +                float adj = (float)((offset.getY()-initY)*yScale);
                   offset = new Point2D.Float((float) offset.getX(),
  -                                           (float) offset.getY()+dy);
  -            else
  -                offset = new Point2D.Float((float) offset.getX()+dx,
  +                                           (float)initY+adj+dy);
  +            } else {
  +                float adj = (float)((offset.getX()-initX)*xScale);
  +                offset = new Point2D.Float((float)initX+adj+dx,
                                              (float) offset.getY());
  +            }
               layout.setOffset(offset);
           }
       }
  @@ -1416,6 +1500,8 @@
           private TextSpanLayout layout;
           private int anchorType;
           private boolean firstRunInChunk;
  +        private Float length;
  +        private Integer lengthAdjust;
   
           public TextRun(TextSpanLayout layout, 
                       AttributedCharacterIterator aci, 
  @@ -1425,13 +1511,14 @@
               this.aci = aci;
               this.aci.first();
               this.firstRunInChunk = firstRunInChunk;
  +            this.anchorType = TextNode.Anchor.ANCHOR_START;
  +
               TextNode.Anchor anchor = (TextNode.Anchor) aci.getAttribute
                (GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
  -            anchorType = TextNode.Anchor.ANCHOR_START;
  -
               if (anchor != null) {
  -                anchorType = anchor.getType();
  +                this.anchorType = anchor.getType();
               }
  +
               // if writing mode is right to left, then need to reverse the
               // text anchor positions
               if 
(aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE)
  @@ -1443,6 +1530,11 @@
                   }
                   // leave middle as is
               }
  +
  +            length = (Float) aci.getAttribute
  +                (GVTAttributedCharacterIterator.TextAttribute.BBOX_WIDTH);
  +            lengthAdjust = (Integer) aci.getAttribute
  +                (GVTAttributedCharacterIterator.TextAttribute.LENGTH_ADJUST);
           }
   
           public AttributedCharacterIterator getACI() {
  @@ -1455,6 +1547,14 @@
   
           public int getAnchorType() {
               return anchorType;
  +        }
  +
  +        public Float getLength() {
  +            return length;
  +        }
  +
  +        public Integer getLengthAdjust() {
  +            return lengthAdjust;
           }
   
           public boolean isFirstRunInChunk() {
  
  
  
  1.34      +110 -126  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.33
  retrieving revision 1.34
  diff -u -r1.33 -r1.34
  --- GlyphLayout.java  23 Jan 2002 14:14:09 -0000      1.33
  +++ GlyphLayout.java  24 Jan 2002 21:35:32 -0000      1.34
  @@ -42,7 +42,7 @@
    * @see org.apache.batik.gvt.text.TextSpanLayout
    *
    * @author <a href="[EMAIL PROTECTED]>Bill Haneman</a>
  - * @version $Id: GlyphLayout.java,v 1.33 2002/01/23 14:14:09 deweese Exp $
  + * @version $Id: GlyphLayout.java,v 1.34 2002/01/24 21:35:32 deweese Exp $
    */
   public class GlyphLayout implements TextSpanLayout {
   
  @@ -54,11 +54,13 @@
       private AffineTransform transform;
       private Point2D advance;
       private Point2D offset;
  +    private float   xScale=1;
  +    private float   yScale=1;
       private Point2D prevCharPosition;
       private TextPath textPath;
       private Point2D textPathAdvance;
       private int []  charMap;
  -    private boolean vertical;
  +    private boolean vertical, adjSpacing=true;
   
       private static final AttributedCharacterIterator.Attribute X
           = GVTAttributedCharacterIterator.TextAttribute.X;
  @@ -142,7 +144,7 @@
           // do the glyph layout
           this.gv.performDefaultLayout();
           doExplicitGlyphLayout(false);
  -        adjustTextSpacing();
  +        adjustTextSpacing(false);
           doPathLayout(false);
       }
   
  @@ -185,6 +187,25 @@
       }
   
       /**
  +     * Sets the scaling factor to use for string.  if ajdSpacing is
  +     * true then only the spacing between glyphs will be adjusted
  +     * otherwise the glyphs and the spaces between them will be
  +     * adjusted.
  +     * @param xScale Scale factor to apply in X direction.
  +     * @param yScale Scale factor to apply in Y direction.
  +     * @param adjSpacing True if only spaces should be adjusted.
  +     */
  +    public void setScale(float xScale, float yScale, boolean adjSpacing) {
  +        this.xScale = xScale;
  +        this.yScale = yScale;
  +        this.adjSpacing = adjSpacing;
  +        this.gv.performDefaultLayout();
  +        doExplicitGlyphLayout(false);
  +        adjustTextSpacing(true);
  +        doPathLayout(true);
  +    }
  +
  +    /**
        * Sets the text position used for the implicit origin
        * of glyph layout. Ignored if multiple explicit glyph
        * positioning attributes are present in ACI
  @@ -194,7 +215,7 @@
           this.offset = offset;
           this.gv.performDefaultLayout();
           doExplicitGlyphLayout(true);
  -        adjustTextSpacing();
  +        adjustTextSpacing(true);
           doPathLayout(true);
       }
   
  @@ -251,6 +272,11 @@
           return advance;
       }
   
  +
  +    public GVTGlyphMetrics getGlyphMetrics(int glyphIndex) {
  +        return gv.getGlyphMetrics(glyphIndex);
  +    }
  +
       /**
        * 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.
  @@ -1077,28 +1103,28 @@
       /**
        * Does any spacing adjustments that may have been specified.
        */
  -    protected void adjustTextSpacing() {
  +    protected void adjustTextSpacing(boolean applyScaling) {
   
           aci.first();
           Boolean customSpacing =  (Boolean) aci.getAttribute(
                  GVTAttributedCharacterIterator.TextAttribute.CUSTOM_SPACING);
  -        Float length = (Float) aci.getAttribute(
  -               GVTAttributedCharacterIterator.TextAttribute.BBOX_WIDTH);
  -        Integer lengthAdjust = (Integer) aci.getAttribute(
  -              GVTAttributedCharacterIterator.TextAttribute.LENGTH_ADJUST);
           if ((customSpacing != null) && customSpacing.booleanValue()) {
  -            applySpacingParams(length, lengthAdjust,
  -               (Float) aci.getAttribute(
  -               GVTAttributedCharacterIterator.TextAttribute.KERNING),
  -               (Float) aci.getAttribute(
  -               GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING),
  -               (Float) aci.getAttribute(
  -               GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING));
  +            advance = doSpacing
  +                ((Float) aci.getAttribute
  +                 (GVTAttributedCharacterIterator.TextAttribute.KERNING),
  +                 (Float) aci.getAttribute
  +                 (GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING),
  +                 (Float) aci.getAttribute
  +                 (GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING));
           }
   
  -        if (lengthAdjust ==
  -            GVTAttributedCharacterIterator.TextAttribute.ADJUST_ALL) {
  -             applyStretchTransform(length);
  +        if (!applyScaling)
  +            return;
  +
  +        if (adjSpacing) {
  +            rescaleSpacing();
  +        } else {
  +            applyStretchTransform();
           }
       }
   
  @@ -1107,90 +1133,78 @@
        *
        * @param length The required length of the text.
        */
  -    protected void applyStretchTransform(Float length) {
  -        if (length!= null && !length.isNaN()) {
  -            double xscale = 1d;
  -            double yscale = 1d;
  -            if (vertical) {
  -                yscale = length.floatValue()/gv.getVisualBounds().getHeight();
  -            } else {
  -                xscale = length.floatValue()/gv.getVisualBounds().getWidth();
  -            }
  -            Point2D startPos = gv.getGlyphPosition(0);
  -            for (int i = 0; i < gv.getNumGlyphs(); i++) {
  -                // transform the glyph position
  -                Point2D glyphPos = gv.getGlyphPosition(i);
  -                AffineTransform t = AffineTransform.getTranslateInstance
  -                    (startPos.getX(), startPos.getY());
  -                t.scale(xscale,yscale);
  -                t.translate(-startPos.getX(), -startPos.getY());
  -                Point2D newGlyphPos = new Point2D.Float();
  -                t.transform(glyphPos, newGlyphPos);
  -                gv.setGlyphPosition(i, newGlyphPos);
  +    protected void applyStretchTransform() {
  +        if (vertical) {
  +            xScale = 1;
  +        } else {
  +            yScale = 1;
  +        }
   
  -                // stretch the glyph
  -                AffineTransform glyphTransform = gv.getGlyphTransform(i);
  -                if (glyphTransform != null) {
  -                    glyphTransform.preConcatenate
  -                        (AffineTransform.getScaleInstance(xscale, yscale));
  -                    gv.setGlyphTransform(i, glyphTransform);
  -                } else {
  -                    gv.setGlyphTransform
  -                        (i, AffineTransform.getScaleInstance(xscale, yscale));
  -                }
  +        if ((xScale == 1) && (yScale==1)) 
  +            return;
  +
  +        // System.out.println("Scale: [" + xScale + ", " + yScale + "]");
  +
  +        Point2D startPos = gv.getGlyphPosition(0);
  +        for (int i = 0; i < gv.getNumGlyphs(); i++) {
  +            // transform the glyph position
  +            Point2D glyphPos = gv.getGlyphPosition(i);
  +            AffineTransform t = AffineTransform.getTranslateInstance
  +                (startPos.getX(), startPos.getY());
  +            t.scale(xScale,yScale);
  +            t.translate(-startPos.getX(), -startPos.getY());
  +            Point2D newGlyphPos = new Point2D.Float();
  +            t.transform(glyphPos, newGlyphPos);
  +            gv.setGlyphPosition(i, newGlyphPos);
  +
  +            // stretch the glyph
  +            AffineTransform glyphTransform = gv.getGlyphTransform(i);
  +            if (glyphTransform != null) {
  +                glyphTransform.preConcatenate
  +                    (AffineTransform.getScaleInstance(xScale, yScale));
  +                gv.setGlyphTransform(i, glyphTransform);
  +            } else {
  +                gv.setGlyphTransform
  +                    (i, AffineTransform.getScaleInstance(xScale, yScale));
               }
  -            advance = new Point2D.Float((float)(advance.getX()*xscale),
  -                                        (float)(advance.getY()*yscale));
           }
  +        advance = new Point2D.Float((float)(advance.getX()*xScale),
  +                                    (float)(advance.getY()*yScale));
       }
   
  -
       /**
  -     * 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,
  -                                      Float letterSpacing,
  -                                      Float wordSpacing) {
  -
  -       /**
  -        * Two passes required when textLength is specified:
  -        * First, apply spacing properties,
  -        * then adjust spacing with new advances based on ratio
  -        * of expected length to actual advance.
  -        */
  -
  -        advance = doSpacing(kern, letterSpacing, wordSpacing);
  -        if ((lengthAdjust ==
  -             GVTAttributedCharacterIterator.TextAttribute.ADJUST_SPACING) &&
  -                 length!= null && !length.isNaN()) { // adjust if necessary
  -            float xscale = 1f;
  -            float yscale = 1f;
  -            if (!vertical) {
  -                float gvWidth = (float)gv.getVisualBounds().getWidth();
  -                float lastCharWidth = (float)gv.getGlyphMetrics
  -                    (gv.getNumGlyphs()-1).getBounds2D().getWidth();
  -                if (gvWidth > lastCharWidth) {
  -                    // System.out.println("Len: " + length.floatValue() +
  -                    //                    " LCW: " + lastCharWidth + 
  -                    //                    " Wid: " + gvWidth);
  -                    xscale = ((length.floatValue()-lastCharWidth)/
  -                              (gvWidth-lastCharWidth));
  -                }
  -            } else {
  -                yscale = (length.floatValue()/
  -                          (float) gv.getVisualBounds().getHeight());
  -            }
  -            rescaleSpacing(xscale, yscale);
  +     * Rescales the spacing between each char by the specified scale factors.
  +     */
  +    protected void rescaleSpacing() {
  +        if (vertical) {
  +            xScale = 1;
  +        } else {
  +            yScale = 1;
  +        }
  +        if ((xScale == 1) && (yScale==1)) 
  +            return;
  +        Rectangle2D bounds = gv.getVisualBounds();
  +        float initX = (float) bounds.getX();
  +        float initY = (float) bounds.getY();
  +        int numGlyphs = gv.getNumGlyphs();
  +        float dx = 0f;
  +        float dy = 0f;
  +        for (int i = 0; i < numGlyphs; i++) {
  +            Point2D gpos = gv.getGlyphPosition(i);
  +            dx = (float)gpos.getX()-initX;
  +            dy = (float)gpos.getY()-initY;
  +            gv.setGlyphPosition(i, new Point2D.Float(initX+dx*xScale,
  +                                                     initY+dy*yScale));
           }
  +        Rectangle2D glyphB = gv.getGlyphMetrics(numGlyphs-1).getBounds2D();
  +        float xAdj = 0;
  +        float yAdj = 0;
  +        if (vertical) yAdj = (float)glyphB.getHeight();
  +        else          xAdj = (float)glyphB.getWidth();
  +
  +        advance = new Point2D.Float
  +            ((float)(initX+dx*xScale-offset.getX()+xAdj),
  +             (float)(initY+dy*yScale-offset.getY()+yAdj));
       }
   
       /**
  @@ -1376,36 +1390,6 @@
           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();
  -        float initY = (float) bounds.getY();
  -        int numGlyphs = gv.getNumGlyphs();
  -        float dx = 0f;
  -        float dy = 0f;
  -        for (int i = 0; i < numGlyphs; i++) {
  -            Point2D gpos = gv.getGlyphPosition(i);
  -            dx = (float)gpos.getX()-initX;
  -            dy = (float)gpos.getY()-initY;
  -            gv.setGlyphPosition(i, new Point2D.Float(initX+dx*xscale,
  -                                                     initY+dy*yscale));
  -        }
  -        Rectangle2D glyphB = gv.getGlyphMetrics(numGlyphs-1).getBounds2D();
  -        float xAdj = 0;
  -        float yAdj = 0;
  -        if (vertical) yAdj = (float)glyphB.getHeight();
  -        else          xAdj = (float)glyphB.getWidth();
  -
  -        advance = new Point2D.Float
  -            ((float)(initX+dx*xscale-offset.getX()+xAdj),
  -             (float)(initY+dy*yscale-offset.getY()+yAdj));
  -    }
   
       /**
        * Returns true if the specified character is within one of the Latin
  
  
  
  1.12      +19 -1     xml-batik/sources/org/apache/batik/gvt/text/TextSpanLayout.java
  
  Index: TextSpanLayout.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/TextSpanLayout.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- TextSpanLayout.java       18 Sep 2001 21:19:01 -0000      1.11
  +++ TextSpanLayout.java       24 Jan 2002 21:35:32 -0000      1.12
  @@ -14,6 +14,8 @@
   import java.awt.geom.Point2D;
   import java.awt.geom.AffineTransform;
   
  +import org.apache.batik.gvt.font.GVTGlyphMetrics;
  +
   /**
    * Class that performs layout of attributed text strings into
    * glyph sets paintable by TextPainter instances.
  @@ -25,7 +27,7 @@
    * @see org.apache.batik.gvt.TextPainter
    *
    * @author <a href="[EMAIL PROTECTED]>Bill Haneman</a>
  - * @version $Id: TextSpanLayout.java,v 1.11 2001/09/18 21:19:01 deweese Exp $
  + * @version $Id: TextSpanLayout.java,v 1.12 2002/01/24 21:35:32 deweese Exp $
    */
   public interface TextSpanLayout {
   
  @@ -78,6 +80,11 @@
        */
       public Point2D getAdvance2D();
   
  +    /**
  +     * Returns the Metrics for a particular glyph.
  +     */
  +    public GVTGlyphMetrics getGlyphMetrics(int glyphIndex);
  +
       public Point2D getTextPathAdvance();
   
       /**
  @@ -86,6 +93,17 @@
        * glyph positioning attributes.
        */
       public Point2D getOffset();
  +
  +    /**
  +     * Sets the scaling factor to use for string.  if ajdSpacing is
  +     * true then only the spacing between glyphs will be adjusted
  +     * otherwise the glyphs and the spaces between them will be
  +     * adjusted.
  +     * @param xScale Scale factor to apply in X direction.
  +     * @param yScale Scale factor to apply in Y direction.
  +     * @param adjSpacing True if only spaces should be adjusted.
  +     */
  +    public void setScale(float xScale, float yScale, boolean adjSpacing);
   
       /**
        * Sets the text position used for the implicit origin
  
  
  

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

Reply via email to