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]