aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache')
-rw-r--r--src/java/org/apache/fop/apps/FOUserAgent.java16
-rw-r--r--src/java/org/apache/fop/area/AreaTreeParser.java23
-rw-r--r--src/java/org/apache/fop/area/inline/Character.java3
-rw-r--r--src/java/org/apache/fop/area/inline/SpaceArea.java19
-rw-r--r--src/java/org/apache/fop/area/inline/TextArea.java12
-rw-r--r--src/java/org/apache/fop/area/inline/WordArea.java21
-rw-r--r--src/java/org/apache/fop/fonts/CustomFont.java29
-rw-r--r--src/java/org/apache/fop/fonts/Font.java94
-rw-r--r--src/java/org/apache/fop/fonts/FontReader.java9
-rw-r--r--src/java/org/apache/fop/fonts/FontResolver.java38
-rw-r--r--src/java/org/apache/fop/fonts/FontSetup.java56
-rw-r--r--src/java/org/apache/fop/fonts/LazyFont.java18
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java9
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java178
-rw-r--r--src/java/org/apache/fop/render/AbstractRenderer.java15
-rw-r--r--src/java/org/apache/fop/render/DefaultFontResolver.java46
-rw-r--r--src/java/org/apache/fop/render/PrintRenderer.java4
-rw-r--r--src/java/org/apache/fop/render/java2d/Java2DRenderer.java28
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java222
-rw-r--r--src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java5
-rw-r--r--src/java/org/apache/fop/render/ps/PSRenderer.java98
-rw-r--r--src/java/org/apache/fop/render/rtf/RTFHandler.java3
-rw-r--r--src/java/org/apache/fop/render/xml/XMLRenderer.java66
-rw-r--r--src/java/org/apache/fop/traits/MinOptMax.java5
-rw-r--r--src/java/org/apache/fop/traits/SpaceVal.java1
-rw-r--r--src/java/org/apache/fop/util/CharUtilities.java74
26 files changed, 659 insertions, 433 deletions
diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java
index a10692890..9612d4ae5 100644
--- a/src/java/org/apache/fop/apps/FOUserAgent.java
+++ b/src/java/org/apache/fop/apps/FOUserAgent.java
@@ -120,6 +120,9 @@ public class FOUserAgent {
/** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */
private boolean breakIndentInheritanceOnReferenceAreaBoundary = false;
+ /** Allows enabling kerning on the base 14 fonts, default is false */
+ private boolean enableBase14Kerning = false;
+
/* Additional fo.ElementMapping subclasses set by user */
private List additionalElementMappings = null;
@@ -240,6 +243,19 @@ public class FOUserAgent {
this.breakIndentInheritanceOnReferenceAreaBoundary = value;
}
+ /** @return true if kerning on base 14 fonts is enabled */
+ public boolean isBase14KerningEnabled() {
+ return this.enableBase14Kerning;
+ }
+
+ /**
+ * Controls whether kerning is activated on base 14 fonts.
+ * @param value true if kerning should be activated
+ */
+ public void setBase14KerningEnabled(boolean value) {
+ this.enableBase14Kerning = value;
+ }
+
/**
* Sets an explicit LayoutManagerMaker instance which overrides the one
* defined by the AreaTreeHandler.
diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java
index e4f1292d2..e3a291eee 100644
--- a/src/java/org/apache/fop/area/AreaTreeParser.java
+++ b/src/java/org/apache/fop/area/AreaTreeParser.java
@@ -19,6 +19,7 @@
package org.apache.fop.area;
import java.awt.geom.Rectangle2D;
+import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.StringTokenizer;
@@ -674,10 +675,27 @@ public class AreaTreeParser {
private class WordMaker extends AbstractMaker {
+ private int[] toIntArray(String s) {
+ if (s == null || s.length() == 0) {
+ return null;
+ }
+ StringTokenizer tokenizer = new StringTokenizer(s, " ");
+ List values = new java.util.ArrayList();
+ while (tokenizer.hasMoreTokens()) {
+ values.add(new Integer(tokenizer.nextToken()));
+ }
+ int[] res = new int[values.size()];
+ for (int i = 0, c = res.length; i < c; i++) {
+ res[i] = ((Integer)values.get(i)).intValue();
+ }
+ return res;
+ }
+
public void endElement() {
int offset = getAttributeAsInteger(lastAttributes, "offset", 0);
+ int[] letterAdjust = toIntArray(lastAttributes.getValue("letter-adjust"));
String txt = content.toString();
- WordArea word = new WordArea(txt, offset);
+ WordArea word = new WordArea(txt, offset, letterAdjust);
AbstractTextArea text = getCurrentText();
word.setParentArea(text);
text.addChildArea(word);
@@ -691,7 +709,8 @@ public class AreaTreeParser {
String txt = content.toString();
//TODO the isAdjustable parameter is currently not used/implemented
if (txt.length() > 0) {
- SpaceArea space = new SpaceArea(txt.charAt(0), offset, false);
+ boolean adjustable = getAttributeAsBoolean(lastAttributes, "adj", true);
+ SpaceArea space = new SpaceArea(txt.charAt(0), offset, adjustable);
AbstractTextArea text = getCurrentText();
space.setParentArea(text);
text.addChildArea(space);
diff --git a/src/java/org/apache/fop/area/inline/Character.java b/src/java/org/apache/fop/area/inline/Character.java
index f672e3632..04f73aa86 100644
--- a/src/java/org/apache/fop/area/inline/Character.java
+++ b/src/java/org/apache/fop/area/inline/Character.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2005 The Apache Software Foundation.
+ * Copyright 1999-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ package org.apache.fop.area.inline;
/**
* Single character inline area.
* This inline area holds a single character.
+ * @deprecated A TextArea with a single WordArea as its child should be used instead.
*/
public class Character extends AbstractTextArea {
// use a String instead of a character because if this character
diff --git a/src/java/org/apache/fop/area/inline/SpaceArea.java b/src/java/org/apache/fop/area/inline/SpaceArea.java
index 6ec573107..193553464 100644
--- a/src/java/org/apache/fop/area/inline/SpaceArea.java
+++ b/src/java/org/apache/fop/area/inline/SpaceArea.java
@@ -28,11 +28,6 @@ public class SpaceArea extends InlineArea {
protected String space;
/**
- * The correction offset for the next area
- */
- protected int offset = 0;
-
- /**
* Is this space adjustable?
*/
protected boolean isAdjustable;
@@ -56,16 +51,8 @@ public class SpaceArea extends InlineArea {
return new String(space);
}
- /**
- * @return Returns the offset.
- */
- public int getOffset() {
- return offset;
- }
- /**
- * @param o The offset to set.
- */
- public void setOffset(int o) {
- offset = o;
+ /** @return true if the space is adjustable (WRT word-space processing) */
+ public boolean isAdjustable() {
+ return this.isAdjustable;
}
}
diff --git a/src/java/org/apache/fop/area/inline/TextArea.java b/src/java/org/apache/fop/area/inline/TextArea.java
index 3bee4254f..a3962f457 100644
--- a/src/java/org/apache/fop/area/inline/TextArea.java
+++ b/src/java/org/apache/fop/area/inline/TextArea.java
@@ -54,7 +54,17 @@ public class TextArea extends AbstractTextArea {
* @param offset the offset for the next area
*/
public void addWord(String word, int offset) {
- WordArea wordArea = new WordArea(word, offset);
+ addWord(word, offset, null);
+ }
+
+ /**
+ * Create and add a WordArea child to this TextArea.
+ *
+ * @param word the word string
+ * @param offset the offset for the next area
+ */
+ public void addWord(String word, int offset, int[] letterAdjust) {
+ WordArea wordArea = new WordArea(word, offset, letterAdjust);
addChildArea(wordArea);
wordArea.setParentArea(this);
}
diff --git a/src/java/org/apache/fop/area/inline/WordArea.java b/src/java/org/apache/fop/area/inline/WordArea.java
index b998b819e..f62dc499f 100644
--- a/src/java/org/apache/fop/area/inline/WordArea.java
+++ b/src/java/org/apache/fop/area/inline/WordArea.java
@@ -22,24 +22,25 @@ package org.apache.fop.area.inline;
*/
public class WordArea extends InlineArea {
- /**
- * The text for this word area
- */
+ /** The text for this word area */
protected String word;
- /**
- * The correction offset for the next area
- */
+ /** The correction offset for the next area */
protected int offset = 0;
+
+ /** An array of width for adjusting the individual letters (optional) */
+ protected int[] letterAdjust;
/**
* Create a word area
* @param w the word string
* @param o the offset for the next area
+ * @param la the letter adjust array (may be null)
*/
- public WordArea(String w, int o) {
+ public WordArea(String w, int o, int[] la) {
word = w;
offset = o;
+ this.letterAdjust = la;
}
/**
@@ -61,4 +62,10 @@ public class WordArea extends InlineArea {
public void setOffset(int o) {
offset = o;
}
+
+ /** @return the array of letter adjust widths */
+ public int[] getLetterAdjustArray() {
+ return this.letterAdjust;
+ }
+
}
diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java
index f39bb108d..85c7da1ee 100644
--- a/src/java/org/apache/fop/fonts/CustomFont.java
+++ b/src/java/org/apache/fop/fonts/CustomFont.java
@@ -21,9 +21,6 @@ package org.apache.fop.fonts;
import java.util.Map;
import javax.xml.transform.Source;
-import org.apache.fop.apps.FOUserAgent;
-
-
/**
* Abstract base class for custom fonts loaded from files, for example.
*/
@@ -33,7 +30,7 @@ public abstract class CustomFont extends Typeface
private String fontName = null;
private String embedFileName = null;
private String embedResourceName = null;
- private FOUserAgent userAgent = null;
+ private FontResolver resolver = null;
private int capHeight = 0;
private int xHeight = 0;
@@ -48,7 +45,7 @@ public abstract class CustomFont extends Typeface
private int firstChar = 0;
private int lastChar = 255;
- private Map kerning = new java.util.HashMap();
+ private Map kerning;
private boolean useKerning = true;
@@ -74,10 +71,11 @@ public abstract class CustomFont extends Typeface
* @return Source for an embeddable font file or null if not available.
*/
public Source getEmbedFileSource() {
- if (userAgent != null && embedFileName != null) {
- return userAgent.resolveURI(embedFileName, userAgent.getFontBaseURL());
+ if (resolver != null && embedFileName != null) {
+ return resolver.resolve(embedFileName);
+ } else {
+ return null;
}
- return null;
}
/**
@@ -212,14 +210,14 @@ public abstract class CustomFont extends Typeface
* @see org.apache.fop.fonts.FontMetrics#hasKerningInfo()
*/
public final boolean hasKerningInfo() {
- return (isKerningEnabled() & kerning.isEmpty());
+ return (isKerningEnabled() && (kerning != null) && !kerning.isEmpty());
}
/**
* @see org.apache.fop.fonts.FontMetrics#getKerningInfo()
*/
public final Map getKerningInfo() {
- if (isKerningEnabled()) {
+ if (hasKerningInfo()) {
return kerning;
} else {
return java.util.Collections.EMPTY_MAP;
@@ -343,17 +341,20 @@ public abstract class CustomFont extends Typeface
}
/**
- * Sets the user agent environment. Needed for URI resolution
- * @param userAgent the user agent
+ * Sets the font resolver. Needed for URI resolution.
+ * @param resolver the font resolver
*/
- public void setUserAgent(FOUserAgent userAgent) {
- this.userAgent = userAgent;
+ public void setResolver(FontResolver resolver) {
+ this.resolver = resolver;
}
/**
* @see org.apache.fop.fonts.MutableFont#putKerningEntry(Integer, Map)
*/
public void putKerningEntry(Integer key, Map value) {
+ if (kerning == null) {
+ kerning = new java.util.HashMap();
+ }
this.kerning.put(key, value);
}
diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java
index cbbc81b21..1a2d39651 100644
--- a/src/java/org/apache/fop/fonts/Font.java
+++ b/src/java/org/apache/fop/fonts/Font.java
@@ -111,18 +111,39 @@ public class Font {
return metric.getXHeight(fontSize) / 1000;
}
+ /** @return true if the font has kerning info */
+ public boolean hasKerning() {
+ return metric.hasKerningInfo();
+ }
+
/**
* Returns the font's kerning table
* @return the kerning table
*/
public Map getKerning() {
- Map ret = metric.getKerningInfo();
- if (ret != null) {
- return ret;
+ if (metric.hasKerningInfo()) {
+ return metric.getKerningInfo();
} else {
return java.util.Collections.EMPTY_MAP;
}
}
+
+ /**
+ * Returns the amount of kerning between two characters.
+ * @param ch1 first character
+ * @param ch2 second character
+ * @return the distance to adjust for kerning, 0 if there's no kerning
+ */
+ public int getKernValue(char ch1, char ch2) {
+ Map kernPair = (Map)getKerning().get(new Integer(ch1));
+ if (kernPair != null) {
+ Integer width = (Integer)kernPair.get(new Integer(ch2));
+ if (width != null) {
+ return width.intValue();
+ }
+ }
+ return 0;
+ }
/**
* Returns the width of a character
@@ -206,63 +227,50 @@ public class Font {
if ((c == '\n') || (c == '\r') || (c == '\t') || (c == '\u00A0')) {
width = getCharWidth(' ');
} else {
- width = getWidth(mapChar(c));
+ if (hasChar(c)) {
+ width = getWidth(mapChar(c));
+ } else {
+ width = -1;
+ }
if (width <= 0) {
// Estimate the width of spaces not represented in
// the font
- int em = getWidth(mapChar('m'));
- int en = getWidth(mapChar('n'));
- if (em <= 0) {
- em = 500 * getFontSize();
- }
- if (en <= 0) {
- en = em - 10;
- }
+ int em = getFontSize(); //http://en.wikipedia.org/wiki/Em_(typography)
+ int en = em / 2; //http://en.wikipedia.org/wiki/En_(typography)
if (c == ' ') {
width = em;
- }
- if (c == '\u2000') {
+ } else if (c == '\u2000') {
width = en;
- }
- if (c == '\u2001') {
+ } else if (c == '\u2001') {
width = em;
- }
- if (c == '\u2002') {
+ } else if (c == '\u2002') {
width = em / 2;
- }
- if (c == '\u2003') {
+ } else if (c == '\u2003') {
width = getFontSize();
- }
- if (c == '\u2004') {
+ } else if (c == '\u2004') {
width = em / 3;
- }
- if (c == '\u2005') {
+ } else if (c == '\u2005') {
width = em / 4;
- }
- if (c == '\u2006') {
+ } else if (c == '\u2006') {
width = em / 6;
- }
- if (c == '\u2007') {
- width = getCharWidth(' ');
- }
- if (c == '\u2008') {
+ } else if (c == '\u2007') {
+ width = getCharWidth('0');
+ } else if (c == '\u2008') {
width = getCharWidth('.');
- }
- if (c == '\u2009') {
+ } else if (c == '\u2009') {
width = em / 5;
- }
- if (c == '\u200A') {
- width = 5;
- }
- if (c == '\u200B') {
- width = 100;
- }
- if (c == '\u202F') {
+ } else if (c == '\u200A') {
+ width = em / 10;
+ } else if (c == '\u200B') {
+ width = 0;
+ } else if (c == '\u202F') {
width = getCharWidth(' ') / 2;
- }
- if (c == '\u3000') {
+ } else if (c == '\u3000') {
width = getCharWidth(' ') * 2;
+ } else {
+ //Will be internally replaced by "#" if not found
+ width = getWidth(mapChar(c));
}
}
}
diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java
index 74ed06579..cc9888962 100644
--- a/src/java/org/apache/fop/fonts/FontReader.java
+++ b/src/java/org/apache/fop/fonts/FontReader.java
@@ -34,7 +34,6 @@ import org.xml.sax.helpers.DefaultHandler;
//FOP
import org.apache.fop.apps.FOPException;
-import org.apache.fop.apps.FOUserAgent;
import org.xml.sax.InputSource;
/**
@@ -114,11 +113,11 @@ public class FontReader extends DefaultHandler {
}
/**
- * Sets the user agent environment. Needed for URI resolution
- * @param userAgent the user agent
+ * Sets the font resolver. Needed for URI resolution.
+ * @param resolver the font resolver
*/
- public void setUserAgent(FOUserAgent userAgent) {
- returnFont.setUserAgent(userAgent);
+ public void setResolver(FontResolver resolver) {
+ returnFont.setResolver(resolver);
}
diff --git a/src/java/org/apache/fop/fonts/FontResolver.java b/src/java/org/apache/fop/fonts/FontResolver.java
new file mode 100644
index 000000000..7999de646
--- /dev/null
+++ b/src/java/org/apache/fop/fonts/FontResolver.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+import javax.xml.transform.Source;
+
+/**
+ * This interface is used to resolve absolute and relative font URIs.
+ */
+public interface FontResolver {
+
+ /**
+ * Called to resolve an URI to a Source instance. The base URI needed by the URIResolver's
+ * resolve() method is defined to be implicitely available in this case. If the URI cannot
+ * be resolved, null is returned and it is assumed that the FontResolver implementation
+ * already warned the user about the problem.
+ * @param href An href attribute, which may be relative or absolute.
+ * @return A Source object, or null if the href could not resolved.
+ */
+ Source resolve(String href);
+
+}
diff --git a/src/java/org/apache/fop/fonts/FontSetup.java b/src/java/org/apache/fop/fonts/FontSetup.java
index 140fcb8b8..4cab92d9d 100644
--- a/src/java/org/apache/fop/fonts/FontSetup.java
+++ b/src/java/org/apache/fop/fonts/FontSetup.java
@@ -18,8 +18,6 @@
package org.apache.fop.fonts;
-import org.apache.fop.apps.FOUserAgent;
-
// FOP (base 14 fonts)
import org.apache.fop.fonts.base14.Helvetica;
import org.apache.fop.fonts.base14.HelveticaBold;
@@ -68,22 +66,39 @@ public class FontSetup {
* triplets for lookup.
*
* @param fontInfo the font info object to set up
- * @param embedList ???
+ * @param embedList a list of EmbedFontInfo objects
+ * @param resolver the font resolver
+ */
+ public static void setup(FontInfo fontInfo, List embedList, FontResolver resolver) {
+ setup(fontInfo, embedList, resolver, false);
+ }
+
+ /**
+ * Sets up the font info object.
+ *
+ * Adds metrics for basic fonts and useful family-style-weight
+ * triplets for lookup.
+ *
+ * @param fontInfo the font info object to set up
+ * @param embedList a list of EmbedFontInfo objects
+ * @param resolver the font resolver
+ * @param enableBase14Kerning true if kerning should be enabled for base 14 fonts
*/
- public static void setup(FontInfo fontInfo, List embedList, FOUserAgent ua) {
+ public static void setup(FontInfo fontInfo, List embedList, FontResolver resolver,
+ boolean enableBase14Kerning) {
- fontInfo.addMetrics("F1", new Helvetica());
- fontInfo.addMetrics("F2", new HelveticaOblique());
- fontInfo.addMetrics("F3", new HelveticaBold());
- fontInfo.addMetrics("F4", new HelveticaBoldOblique());
- fontInfo.addMetrics("F5", new TimesRoman());
- fontInfo.addMetrics("F6", new TimesItalic());
- fontInfo.addMetrics("F7", new TimesBold());
- fontInfo.addMetrics("F8", new TimesBoldItalic());
- fontInfo.addMetrics("F9", new Courier());
- fontInfo.addMetrics("F10", new CourierOblique());
- fontInfo.addMetrics("F11", new CourierBold());
- fontInfo.addMetrics("F12", new CourierBoldOblique());
+ fontInfo.addMetrics("F1", new Helvetica(enableBase14Kerning));
+ fontInfo.addMetrics("F2", new HelveticaOblique(enableBase14Kerning));
+ fontInfo.addMetrics("F3", new HelveticaBold(enableBase14Kerning));
+ fontInfo.addMetrics("F4", new HelveticaBoldOblique(enableBase14Kerning));
+ fontInfo.addMetrics("F5", new TimesRoman(enableBase14Kerning));
+ fontInfo.addMetrics("F6", new TimesItalic(enableBase14Kerning));
+ fontInfo.addMetrics("F7", new TimesBold(enableBase14Kerning));
+ fontInfo.addMetrics("F8", new TimesBoldItalic(enableBase14Kerning));
+ fontInfo.addMetrics("F9", new Courier(enableBase14Kerning));
+ fontInfo.addMetrics("F10", new CourierOblique(enableBase14Kerning));
+ fontInfo.addMetrics("F11", new CourierBold(enableBase14Kerning));
+ fontInfo.addMetrics("F12", new CourierBoldOblique(enableBase14Kerning));
fontInfo.addMetrics("F13", new Symbol());
fontInfo.addMetrics("F14", new ZapfDingbats());
@@ -162,17 +177,18 @@ public class FontSetup {
"normal", Font.NORMAL);
/* Add configured fonts */
- addConfiguredFonts(fontInfo, embedList, 15, ua);
+ addConfiguredFonts(fontInfo, embedList, 15, resolver);
}
/**
* Add fonts from configuration file starting with internal name F<num>.
* @param fontInfo the font info object to set up
- * @param fontInfoList
+ * @param fontInfoList a list of EmbedFontInfo objects
* @param num starting index for internal font numbering
+ * @param resolver the font resolver
*/
public static void addConfiguredFonts(FontInfo fontInfo, List fontInfoList
- , int num, FOUserAgent userAgent) {
+ , int num, FontResolver resolver) {
if (fontInfoList == null) {
return; //No fonts to process
}
@@ -196,7 +212,7 @@ public class FontSetup {
LazyFont font = new LazyFont(configFontInfo.getEmbedFile(),
metricsFile,
configFontInfo.getKerning(),
- userAgent);
+ resolver);
fontInfo.addMetrics(internalName, font);
List triplets = configFontInfo.getFontTriplets();
diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java
index f8d22f3bb..ee0b47ec3 100644
--- a/src/java/org/apache/fop/fonts/LazyFont.java
+++ b/src/java/org/apache/fop/fonts/LazyFont.java
@@ -17,10 +17,8 @@
/* $Id$ */
package org.apache.fop.fonts;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import javax.xml.transform.Source;
@@ -29,7 +27,6 @@ import javax.xml.transform.stream.StreamSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.apps.FOPException;
-import org.apache.fop.apps.FOUserAgent;
import org.xml.sax.InputSource;
/**
@@ -47,21 +44,21 @@ public class LazyFont extends Typeface implements FontDescriptor {
private Typeface realFont = null;
private FontDescriptor realFontDescriptor = null;
- private FOUserAgent userAgent = null;
+ private FontResolver resolver = null;
/**
* Main constructor
* @param fontEmbedPath path to embeddable file (may be null)
* @param metricsFileName path to the metrics XML file
* @param useKerning True, if kerning should be enabled
- * @param userAgent the environment for uri resoltuion
+ * @param resolver the font resolver to handle font URIs
*/
public LazyFont(String fontEmbedPath, String metricsFileName
- , boolean useKerning, FOUserAgent userAgent) {
+ , boolean useKerning, FontResolver resolver) {
this.metricsFileName = metricsFileName;
this.fontEmbedPath = fontEmbedPath;
this.useKerning = useKerning;
- this.userAgent = userAgent;
+ this.resolver = resolver;
}
private void load(boolean fail) {
@@ -69,9 +66,8 @@ public class LazyFont extends Typeface implements FontDescriptor {
try {
/**@todo Possible thread problem here */
FontReader reader = null;
- if (userAgent != null) {
- Source source = userAgent.resolveURI(metricsFileName
- , userAgent.getFontBaseURL());
+ if (resolver != null) {
+ Source source = resolver.resolve(metricsFileName);
if (source == null) {
String err = "Cannot load font: failed to create Source from metrics file "
+ metricsFileName;
@@ -106,7 +102,7 @@ public class LazyFont extends Typeface implements FontDescriptor {
}
reader.setKerningEnabled(useKerning);
reader.setFontEmbedPath(fontEmbedPath);
- reader.setUserAgent(userAgent);
+ reader.setResolver(resolver);
realFont = reader.getFont();
if (realFont instanceof FontDescriptor) {
realFontDescriptor = (FontDescriptor) realFont;
diff --git a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
index 302e82c26..a0e198ad5 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
@@ -68,14 +68,15 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
hyphIPD = font.getCharWidth(fobj.getCommonHyphenation().hyphenationCharacter);
borderProps = fobj.getCommonBorderPaddingBackground();
setCommonBorderPaddingBackground(borderProps);
- org.apache.fop.area.inline.Character chArea = getCharacterInlineArea(fobj);
+ org.apache.fop.area.inline.TextArea chArea = getCharacterInlineArea(fobj);
chArea.setBaselineOffset(font.getAscender());
setCurrentArea(chArea);
}
- private org.apache.fop.area.inline.Character getCharacterInlineArea(Character node) {
- org.apache.fop.area.inline.Character ch
- = new org.apache.fop.area.inline.Character(node.getCharacter());
+ private org.apache.fop.area.inline.TextArea getCharacterInlineArea(Character node) {
+ org.apache.fop.area.inline.TextArea ch
+ = new org.apache.fop.area.inline.TextArea();
+ ch.addWord(String.valueOf(node.getCharacter()), 0);
TraitSetter.setProducerID(ch, node.getId());
TraitSetter.addTextDecoration(ch, fobj.getTextDecoration());
return ch;
diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
index ac8867b31..7522db6a3 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2005 The Apache Software Foundation.
+ * Copyright 1999-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -62,14 +62,16 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
private short iLScount;
private MinOptMax ipdArea;
private boolean bHyphenated;
+ private boolean isSpace;
public AreaInfo(short iSIndex, short iBIndex, short iWS, short iLS,
- MinOptMax ipd, boolean bHyph) {
+ MinOptMax ipd, boolean bHyph, boolean isSpace) {
iStartIndex = iSIndex;
iBreakIndex = iBIndex;
iWScount = iWS;
iLScount = iLS;
ipdArea = ipd;
bHyphenated = bHyph;
+ this.isSpace = isSpace;
}
public String toString() {
@@ -79,6 +81,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
+ ", sidx=" + iStartIndex
+ ", bidx=" + iBreakIndex
+ ", hyph=" + bHyphenated
+ + ", space=" + isSpace
+ "]";
}
@@ -104,14 +107,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
private FOText foText;
private char[] textArray;
+ /** Contains an array of widths to adjust for kerning and letter spacing */
+ private MinOptMax[] letterAdjustArray; //size = textArray.length + 1
+ /** The sum of all entries in the letterAdjustArray */
+ private MinOptMax totalLetterAdjust = new MinOptMax(0);
private static final char NEWLINE = '\n';
- private static final char SPACE = '\u0020'; // Normal space
- private static final char NBSPACE = '\u00A0'; // Non-breaking space
- private static final char LINEBREAK = '\u2028';
- private static final char ZERO_WIDTH_SPACE = '\u200B';
- // byte order mark
- private static final char ZERO_WIDTH_NOBREAK_SPACE = '\uFEFF';
private Font font = null;
/** Start index of first character in this parent Area */
@@ -128,8 +129,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
private MinOptMax letterSpaceIPD;
/** size of the hyphen character glyph in current font */
private int hyphIPD;
+ /** 1/1 of word-spacing value */
+ private SpaceVal ws;
/** 1/2 of word-spacing value */
private SpaceVal halfWS;
+ /** 1/2 of letter-spacing value */
+ private SpaceVal halfLS;
/** Number of space characters after previous possible break position. */
private int iNbSpacesPending;
@@ -156,6 +161,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
textArray = new char[node.endIndex - node.startIndex];
System.arraycopy(node.ca, node.startIndex, textArray, 0,
node.endIndex - node.startIndex);
+ letterAdjustArray = new MinOptMax[textArray.length + 1];
vecAreaInfo = new java.util.ArrayList();
}
@@ -168,9 +174,13 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
spaceCharIPD = font.getCharWidth(' ');
// Use hyphenationChar property
hyphIPD = font.getCharWidth(foText.getCommonHyphenation().hyphenationCharacter);
- // Make half-space: <space> on either side of a word-space)
+
SpaceVal ls = SpaceVal.makeLetterSpacing(foText.getLetterSpacing());
- SpaceVal ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, font);
+ halfLS = new SpaceVal(MinOptMax.multiply(ls.getSpace(), 0.5),
+ ls.isConditional(), ls.isForcing(), ls.getPrecedence());
+
+ ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, font);
+ // Make half-space: <space> on either side of a word-space)
halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5),
ws.isConditional(), ws.isForcing(), ws.getPrecedence());
@@ -180,6 +190,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// A<<ws>>S<ls>I<ls>M<ls>P<ls>L<ls>E<<ws>>T<ls>E<ls>S<ls>T
// there is no letter space after the last character of a word,
// nor after a space character
+ // NOTE: The above is not quite correct. Read on in XSL 1.0, 7.16.2, letter-spacing
// set letter space and word space dimension;
// the default value "normal" was converted into a MinOptMax value
@@ -288,13 +299,22 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}
if (ai == null) {
return;
- } else if (ai.iLScount == ai.iBreakIndex - ai.iStartIndex
+ }
+ int textLength = ai.iBreakIndex - ai.iStartIndex;
+ if (ai.iLScount == textLength
&& context.isLastArea()) {
// the line ends at a character like "/" or "-";
// remove the letter space after the last character
realWidth.add(MinOptMax.multiply(letterSpaceIPD, -1));
iLScount--;
}
+
+ for (int i = ai.iStartIndex + 1; i < ai.iBreakIndex + 1; i++) {
+ MinOptMax ladj = letterAdjustArray[i];
+ if (ladj != null && ladj.isElastic()) {
+ iLScount++;
+ }
+ }
// add hyphenation character if the last word is hyphenated
if (context.isLastArea() && ai.bHyphenated) {
@@ -415,9 +435,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// set the text of the TextArea, split into words and spaces
int wordStartIndex = -1;
AreaInfo areaInfo;
- for (int i = firstIndex; i <= lastIndex; i ++) {
+ for (int i = firstIndex; i <= lastIndex; i++) {
areaInfo = (AreaInfo) vecAreaInfo.get(i);
- if (areaInfo.iWScount > 0) {
+ if (areaInfo.isSpace) {
// areaInfo stores information about a space
// add a space to the TextArea
char spaceChar = textArray[areaInfo.iStartIndex];
@@ -429,17 +449,28 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// here starts a new word
wordStartIndex = areaInfo.iStartIndex;
}
- if (i == lastIndex || ((AreaInfo) vecAreaInfo.get(i + 1)).iWScount > 0) {
+ if (i == lastIndex || ((AreaInfo) vecAreaInfo.get(i + 1)).isSpace) {
// here ends a new word
// add a word to the TextArea
- String wordChars = new String(textArray, wordStartIndex, areaInfo.iBreakIndex - wordStartIndex);
+ int len = areaInfo.iBreakIndex - wordStartIndex;
+ String wordChars = new String(textArray, wordStartIndex, len);
if (isLastArea
&& i == lastIndex
&& areaInfo.bHyphenated) {
// add the hyphenation character
wordChars += foText.getCommonHyphenation().hyphenationCharacter;
}
- textArea.addWord(wordChars, 0);
+ int[] letterAdjust = new int[wordChars.length()];
+ int lsCount = areaInfo.iLScount;
+ for (int letter = 0; letter < len; letter++) {
+ MinOptMax adj = letterAdjustArray[letter + wordStartIndex + 1];
+ letterAdjust[letter] = (adj != null ? adj.opt : 0);
+ if (lsCount > 0) {
+ letterAdjust[letter] += textArea.getTextLetterSpaceAdjust();
+ lsCount--;
+ }
+ }
+ textArea.addWord(wordChars, 0, letterAdjust);
wordStartIndex = -1;
}
}
@@ -451,7 +482,40 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
return textArea;
}
+
+ private void addToLetterAdjust(int index, int width) {
+ if (letterAdjustArray[index] == null) {
+ letterAdjustArray[index] = new MinOptMax(width);
+ } else {
+ letterAdjustArray[index].add(width);
+ }
+ totalLetterAdjust.add(width);
+ }
+ private void addToLetterAdjust(int index, MinOptMax width) {
+ if (letterAdjustArray[index] == null) {
+ letterAdjustArray[index] = new MinOptMax(width);
+ } else {
+ letterAdjustArray[index].add(width);
+ }
+ totalLetterAdjust.add(width);
+ }
+
+ /**
+ * Indicates whether a character is a space in terms of this layout manager.
+ * @param ch the character
+ * @return true if it's a space
+ */
+ private static boolean isSpace(final char ch) {
+ return ch == CharUtilities.SPACE
+ || ch == CharUtilities.NBSPACE
+ || CharUtilities.isFixedWidthSpace(ch);
+ }
+
+ private static boolean isBreakChar(final char ch) {
+ return (BREAK_CHARS.indexOf(ch) >= 0);
+ }
+
/** @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int) */
public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
lineStartBAP = context.getLineStartBorderAndPaddingWidth();
@@ -464,13 +528,14 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
returnList.add(sequence);
while (iNextStart < textArray.length) {
- if (textArray[iNextStart] == SPACE
- || textArray[iNextStart] == NBSPACE) {
+ char ch = textArray[iNextStart];
+ if (ch == CharUtilities.SPACE
+ || ch == CharUtilities.NBSPACE) {
// normal space or non-breaking space:
// create the AreaInfo object
ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
- wordSpaceIPD, false);
+ wordSpaceIPD, false, true);
vecAreaInfo.add(ai);
// create the elements
@@ -479,7 +544,21 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// advance to the next character
iNextStart++;
- } else if (textArray[iNextStart] == NEWLINE) {
+ } else if (CharUtilities.isFixedWidthSpace(ch)) {
+ // create the AreaInfo object
+ MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
+ ai = new AreaInfo(iNextStart, (short) (iNextStart + 1),
+ (short) 0, (short) 0,
+ ipd, false, true);
+ vecAreaInfo.add(ai);
+
+ // create the elements
+ sequence.addAll
+ (createElementsForASpace(alignment, ai, vecAreaInfo.size() - 1));
+
+ // advance to the next character
+ iNextStart++;
+ } else if (ch == NEWLINE) {
// linefeed; this can happen when linefeed-treatment="preserve"
// add a penalty item to the list and start a new sequence
if (lineEndBAP != 0) {
@@ -497,24 +576,45 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// the beginning of a word
iThisStart = iNextStart;
iTempStart = iNextStart;
- MinOptMax wordIPD = new MinOptMax(0);
for (; iTempStart < textArray.length
- && textArray[iTempStart] != SPACE
- && textArray[iTempStart] != NBSPACE
+ && !isSpace(textArray[iTempStart])
&& textArray[iTempStart] != NEWLINE
&& !(iTempStart > iNextStart
- && BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0);
+ && isBreakChar(textArray[iTempStart - 1]));
iTempStart++) {
- wordIPD.add(font.getCharWidth(textArray[iTempStart]));
+ //nop, just find the word boundary
}
- int iLetterSpaces = iTempStart - iThisStart - 1;
+
+ //Word boundary found, process widths and kerning
+ int wordLength = iTempStart - iThisStart;
+ boolean kerning = font.hasKerning();
+ MinOptMax wordIPD = new MinOptMax(0);
+ for (int i = iThisStart; i < iTempStart; i++) {
+ char c = textArray[i];
+
+ //character width
+ int charWidth = font.getCharWidth(c);
+ wordIPD.add(charWidth);
+
+ //kerning
+ int kern = 0;
+ if (kerning && (i > iThisStart)) {
+ char previous = textArray[i - 1];
+ kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
+ if (kern != 0) {
+ addToLetterAdjust(i + 1, kern);
+ }
+ wordIPD.add(kern);
+ }
+ }
+
+ int iLetterSpaces = wordLength - 1;
// if the last character is '-' or '/' and the next one
// is not a space, it could be used as a line end;
// add one more letter space, in case other text follows
- if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0
- && iTempStart < textArray.length
- && textArray[iTempStart] != SPACE
- && textArray[iTempStart] != NBSPACE) {
+ if (isBreakChar(textArray[iTempStart - 1])
+ && iTempStart < textArray.length
+ && !isSpace(textArray[iTempStart])) {
iLetterSpaces++;
}
wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
@@ -522,12 +622,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// create the AreaInfo object
ai = new AreaInfo(iThisStart, iTempStart, (short) 0,
(short) iLetterSpaces,
- wordIPD, false);
+ wordIPD, false, false);
vecAreaInfo.add(ai);
// create the elements
- sequence.addAll
- (createElementsForAWordFragment(alignment, ai,
+ sequence.addAll(createElementsForAWordFragment(alignment, ai,
vecAreaInfo.size() - 1, letterSpaceIPD));
// advance to the next character
@@ -666,7 +765,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
(short) (bIsWordEnd
? (iStopIndex - iStartIndex - 1)
: (iStopIndex - iStartIndex)),
- newIPD, bHyphenFollows),
+ newIPD, bHyphenFollows, false),
((LeafPosition) pos).getLeafPos()));
bNothingChanged = false;
}
@@ -752,7 +851,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
LinkedList spaceElements = new LinkedList();
LeafPosition mainPosition = new LeafPosition(this, leafValue);
- if (textArray[ai.iStartIndex] == NBSPACE) {
+ if (textArray[ai.iStartIndex] == CharUtilities.NBSPACE) {
// a non-breaking space
//TODO: other kinds of non-breaking spaces
if (alignment == EN_JUSTIFY) {
@@ -784,7 +883,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
spaceElements
.add(new KnuthPenalty(
0,
- (textArray[ai.iStartIndex] == NBSPACE ? KnuthElement.INFINITE
+ (textArray[ai.iStartIndex] == CharUtilities.NBSPACE
+ ? KnuthElement.INFINITE
: 0), false,
new LeafPosition(this, -1), false));
spaceElements.add(new KnuthGlue(ai.ipdArea.opt
@@ -899,8 +999,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// the fragment could end a line; in this case, it loses one
// of its letter spaces;
boolean bSuppressibleLetterSpace
- = ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)
- && BREAK_CHARS.indexOf(textArray[ai.iBreakIndex - 1]) >= 0;
+ = /*ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)
+ &&*/ isBreakChar(textArray[ai.iBreakIndex - 1]);
if (letterSpaceWidth.min == letterSpaceWidth.max) {
// constant letter spacing
@@ -941,7 +1041,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// otherwise nothing happens
wordElements.addAll(createElementsForAHyphen(alignment, hyphIPD, new MinOptMax(0)));
} else if (bSuppressibleLetterSpace) {
- // the word framgent ends with a character that acts as a hyphen
+ // the word fragment ends with a character that acts as a hyphen
// if a break occurs the width does not increase,
// otherwise there is one more letter space
wordElements.addAll(createElementsForAHyphen(alignment, 0, letterSpaceWidth));
diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java
index 8dbaeaa20..d6c2c734f 100644
--- a/src/java/org/apache/fop/render/AbstractRenderer.java
+++ b/src/java/org/apache/fop/render/AbstractRenderer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2005 The Apache Software Foundation.
+ * Copyright 1999-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@ import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.RegionReference;
import org.apache.fop.area.Trait;
import org.apache.fop.area.OffDocumentItem;
+import org.apache.fop.area.inline.Character;
import org.apache.fop.area.inline.Container;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
@@ -59,7 +60,6 @@ import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.inline.Character;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.apps.FOUserAgent;
@@ -204,9 +204,9 @@ public abstract class AbstractRenderer
StringBuffer sb = new StringBuffer();
for (int count = 0; count < children.size(); count++) {
InlineArea inline = (InlineArea) children.get(count);
- if (inline instanceof Character) {
- sb.append(((Character) inline).getChar());
- } else if (inline instanceof TextArea) {
+ //if (inline instanceof Character) {
+ // sb.append(((Character) inline).getChar());
+ /*} else*/ if (inline instanceof TextArea) {
sb.append(((TextArea) inline).getText());
} else if (inline instanceof InlineParent) {
sb.append(convertToString(
@@ -618,8 +618,8 @@ public abstract class AbstractRenderer
protected void renderInlineArea(InlineArea inlineArea) {
if (inlineArea instanceof TextArea) {
renderText((TextArea) inlineArea);
- } else if (inlineArea instanceof Character) {
- renderCharacter((Character) inlineArea);
+ //} else if (inlineArea instanceof Character) {
+ //renderCharacter((Character) inlineArea);
} else if (inlineArea instanceof WordArea) {
renderWord((WordArea) inlineArea);
} else if (inlineArea instanceof SpaceArea) {
@@ -640,6 +640,7 @@ public abstract class AbstractRenderer
/**
* Render the given Character.
* @param ch the character to render
+ * @deprecated Only TextArea should be used. This method will be removed eventually.
*/
protected void renderCharacter(Character ch) {
currentIPPosition += ch.getAllocIPD();
diff --git a/src/java/org/apache/fop/render/DefaultFontResolver.java b/src/java/org/apache/fop/render/DefaultFontResolver.java
new file mode 100644
index 000000000..eb8a9010e
--- /dev/null
+++ b/src/java/org/apache/fop/render/DefaultFontResolver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render;
+
+import javax.xml.transform.Source;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fonts.FontResolver;
+
+/**
+ * Default FontResolver implementation which uses the FOUserAgent to resolve font URIs.
+ */
+public class DefaultFontResolver implements FontResolver {
+
+ private FOUserAgent userAgent;
+
+ /**
+ * Main constructor.
+ * @param userAgent the user agent
+ */
+ public DefaultFontResolver(FOUserAgent userAgent) {
+ this.userAgent = userAgent;
+ }
+
+ /** @see org.apache.fop.fonts.FontResolver#resolve(java.lang.String) */
+ public Source resolve(String href) {
+ return userAgent.resolveURI(href, userAgent.getFontBaseURL());
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java
index 585017a11..4de65e561 100644
--- a/src/java/org/apache/fop/render/PrintRenderer.java
+++ b/src/java/org/apache/fop/render/PrintRenderer.java
@@ -23,6 +23,7 @@ import org.apache.fop.area.Area;
import org.apache.fop.area.Trait;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontSetup;
import org.apache.fop.fonts.FontTriplet;
@@ -46,7 +47,8 @@ public abstract class PrintRenderer extends AbstractRenderer {
*/
public void setupFontInfo(FontInfo inFontInfo) {
this.fontInfo = inFontInfo;
- FontSetup.setup(fontInfo, fontList, userAgent);
+ FontResolver resolver = new DefaultFontResolver(userAgent);
+ FontSetup.setup(fontInfo, fontList, resolver, userAgent.isBase14KerningEnabled());
}
/**
diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
index 5255c7727..1dfc1b429 100644
--- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
+++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java
@@ -55,7 +55,6 @@ import org.apache.fop.area.CTM;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Trait;
-import org.apache.fop.area.inline.Character;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.InlineArea;
@@ -866,33 +865,6 @@ public abstract class Java2DRenderer extends AbstractRenderer implements Printab
}
/**
- * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character)
- */
- public void renderCharacter(Character ch) {
- renderInlineAreaBackAndBorders(ch);
-
- float x = currentIPPosition + ch.getBorderAndPaddingWidthStart();
- float y = currentBPPosition + ch.getOffset() + ch.getBaselineOffset(); // baseline
-
- Font font = getFontFromArea(ch);
- state.updateFont(font.getFontName(), font.getFontSize(), null);
-
- ColorType ct = (ColorType) ch.getTrait(Trait.COLOR);
- state.updateColor(ct, false, null);
-
- String s = ch.getChar();
- state.getGraph().drawString(s, x / 1000f, y / 1000f);
-
- // getLogger().debug( "renderCharacter(): \"" + s + "\", x: "
- // + x + ", y: " + y + state);
-
- // rendering text decorations
- renderTextDecoration(font, ch, y, x);
-
- super.renderCharacter(ch);
- }
-
- /**
* Paints the text decoration marks.
*
* @param fs Current font
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
index 33602792d..1a2994145 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
@@ -47,7 +47,7 @@ import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Trait;
import org.apache.fop.area.OffDocumentItem;
import org.apache.fop.area.BookmarkData;
-import org.apache.fop.area.inline.Character;
+import org.apache.fop.area.inline.AbstractTextArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
@@ -83,6 +83,7 @@ import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext;
+import org.apache.fop.util.CharUtilities;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
@@ -185,7 +186,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
/**
* true if a TJ command is left to be written
*/
- protected boolean textOpen = false;
+ //protected boolean textOpen = false;
/**
* true if a BT command has been written.
@@ -196,18 +197,18 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
* the previous Y coordinate of the last word written.
* Used to decide if we can draw the next word on the same line.
*/
- protected int prevWordY = 0;
+ //protected int prevWordY = 0;
/**
* the previous X coordinate of the last word written.
* used to calculate how much space between two words
*/
- protected int prevWordX = 0;
+ //protected int prevWordX = 0;
/**
* The width of the previous word. Used to calculate space between
*/
- protected int prevWordWidth = 0;
+ //protected int prevWordWidth = 0;
/**
* reusable word area string buffer to reduce memory usage
@@ -402,6 +403,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
protected void beginTextObject() {
if (!inTextMode) {
currentStream.add("BT\n");
+ currentFontName = "";
inTextMode = true;
}
}
@@ -931,79 +933,6 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
}
/**
- * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character)
- */
- public void renderCharacter(Character ch) {
- renderInlineAreaBackAndBorders(ch);
-
- beginTextObject();
- StringBuffer pdf = new StringBuffer();
-
- Font font = getFontFromArea(ch);
-
- // This assumes that *all* CIDFonts use a /ToUnicode mapping
- Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName());
- boolean useMultiByte = tf.isMultiByte();
-
- // String startText = useMultiByte ? "<FEFF" : "(";
- String startText = useMultiByte ? "<" : "(";
- String endText = useMultiByte ? "> " : ") ";
-
- updateFont(font.getFontName(), font.getFontSize(), pdf);
- ColorType ct = (ColorType) ch.getTrait(Trait.COLOR);
- if (ct != null) {
- updateColor(ct, true, pdf);
- }
-
- // word.getOffset() = only height of text itself
- // currentBlockIPPosition: 0 for beginning of line; nonzero
- // where previous line area failed to take up entire allocated space
- int rx = currentIPPosition + ch.getBorderAndPaddingWidthStart();
- int bl = currentBPPosition + ch.getOffset() + ch.getBaselineOffset();
-
-/* log.debug("Text = " + ch.getTextArea() +
- "; text width: " + ch.getWidth() +
- "; BlockIP Position: " + currentBlockIPPosition +
- "; currentBPPosition: " + currentBPPosition +
- "; offset: " + ch.getOffset());
-*/
- // Set letterSpacing
- //float ls = fs.getLetterSpacing() / this.currentFontSize;
- //pdf.append(ls).append(" Tc\n");
-
- if (!textOpen || bl != prevWordY) {
- closeText();
-
- pdf.append("1 0 0 -1 " + format(rx / 1000f) + " " + format(bl / 1000f) + " Tm "
- + format(ch.getTextLetterSpaceAdjust() / 1000f) + " Tc "
- + format(ch.getTextWordSpaceAdjust() / 1000f) + " Tw [" + startText);
- prevWordY = bl;
- textOpen = true;
- } else {
- closeText();
-
- pdf.append("1 0 0 -1 " + format(rx / 1000f) + " " + format(bl / 1000f) + " Tm "
- + format(ch.getTextLetterSpaceAdjust() / 1000f) + " Tc "
- + format(ch.getTextWordSpaceAdjust() / 1000f) + " Tw [" + startText);
- textOpen = true;
- }
- prevWordWidth = ch.getIPD();
- prevWordX = rx;
-
- String s = ch.getChar();
-
-
- escapeText(s, font, useMultiByte, pdf);
- pdf.append(endText);
-
- currentStream.add(pdf.toString());
-
- renderTextDecoration(tf, font.getFontSize(), ch, bl, rx);
-
- super.renderCharacter(ch);
- }
-
- /**
* @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
*/
public void renderText(TextArea text) {
@@ -1028,39 +957,17 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
int rx = currentIPPosition + text.getBorderAndPaddingWidthStart();
int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset();
-/* log.debug("Text = " + text.getTextArea() +
- "; text width: " + text.getWidth() +
- "; BlockIP Position: " + currentBlockIPPosition +
- "; currentBPPosition: " + currentBPPosition +
- "; offset: " + text.getOffset());
-*/
- // Set letterSpacing
- //float ls = fs.getLetterSpacing() / this.currentFontSize;
- //pdf.append(ls).append(" Tc\n");
-
- if (!textOpen || bl != prevWordY) {
- closeText();
-
- pdf.append("1 0 0 -1 " + format(rx / 1000f) + " " + format(bl / 1000f) + " Tm "
- + format(text.getTextLetterSpaceAdjust() / 1000f) + " Tc "
- + format(text.getTextWordSpaceAdjust() / 1000f) + " Tw [");
- prevWordY = bl;
- textOpen = true;
- } else {
- closeText();
-
- pdf.append("1 0 0 -1 " + format(rx / 1000f) + " " + format(bl / 1000f) + " Tm "
- + format(text.getTextLetterSpaceAdjust() / 1000f) + " Tc "
- + format(text.getTextWordSpaceAdjust() / 1000f) + " Tw [");
- textOpen = true;
- }
- prevWordWidth = text.getIPD();
- prevWordX = rx;
+ pdf.append("1 0 0 -1 " + format(rx / 1000f) + " " + format(bl / 1000f) + " Tm "
+ /*+ format(text.getTextLetterSpaceAdjust() / 1000f) + " Tc\n"*/
+ /*+ format(text.getTextWordSpaceAdjust() / 1000f) + " Tw ["*/);
+ pdf.append("[");
currentStream.add(pdf.toString());
super.renderText(text);
+ currentStream.add("] TJ\n");
+
renderTextDecoration(tf, size, text, bl, rx);
}
@@ -1072,17 +979,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName());
boolean useMultiByte = tf.isMultiByte();
- String startText = useMultiByte ? "<" : "(";
- String endText = useMultiByte ? "> " : ") ";
-
StringBuffer pdf = new StringBuffer();
- pdf.append(startText);
-
String s = word.getWord();
-
- escapeText(s, font, useMultiByte, pdf);
- pdf.append(endText);
+ escapeText(s, word.getLetterAdjustArray(),
+ font, (AbstractTextArea)word.getParentArea(), useMultiByte, pdf);
currentStream.add(pdf.toString());
@@ -1097,22 +998,21 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName());
boolean useMultiByte = tf.isMultiByte();
- String startText = useMultiByte ? "<" : "(";
- String endText = useMultiByte ? "> " : ") ";
+ String s = space.getSpace();
StringBuffer pdf = new StringBuffer();
-
- pdf.append(startText);
- String s = space.getSpace();
-
- escapeText(s, font, useMultiByte, pdf);
- pdf.append(endText);
-
- if (useMultiByte) {
- float tws = -(((TextArea) space.getParentArea()).getTextWordSpaceAdjust()
- / (font.getFontSize() / 1000f));
- pdf.append(format(tws) + " ");
+ AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
+ escapeText(s, null, font, textArea, useMultiByte, pdf);
+
+ if (space.isAdjustable()) {
+ int tws = -((TextArea) space.getParentArea()).getTextWordSpaceAdjust()
+ - 2 * textArea.getTextLetterSpaceAdjust();
+
+ if (tws != 0) {
+ pdf.append(format(tws / (font.getFontSize() / 1000f)));
+ pdf.append(" ");
+ }
}
currentStream.add(pdf.toString());
@@ -1123,15 +1023,19 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
/**
* Escapes text according to PDF rules.
* @param s Text to escape
+ * @param letterAdjust an array of widths for letter adjustment (may be null)
* @param fs Font state
+ * @param parentArea the parent text area to retrieve certain traits from
* @param useMultiByte Indicates the use of multi byte convention
* @param pdf target buffer for the escaped text
*/
- public void escapeText(String s, Font fs,
+ public void escapeText(String s, int[] letterAdjust,
+ Font fs, AbstractTextArea parentArea,
boolean useMultiByte, StringBuffer pdf) {
String startText = useMultiByte ? "<" : "(";
String endText = useMultiByte ? "> " : ") ";
+ /*
boolean kerningAvailable = false;
Map kerning = fs.getKerning();
if (kerning != null && !kerning.isEmpty()) {
@@ -1139,12 +1043,37 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
//TODO Reenable me when the layout engine supports kerning, too
log.warn("Kerning support is disabled until it is supported by the layout engine!");
}
+ */
int l = s.length();
+ float fontSize = fs.getFontSize() / 1000f;
+ boolean startPending = true;
for (int i = 0; i < l; i++) {
- char ch = fs.mapChar(s.charAt(i));
-
+ char orgChar = s.charAt(i);
+ char ch;
+ float glyphAdjust = 0;
+ if (fs.hasChar(orgChar)) {
+ ch = fs.mapChar(orgChar);
+ int tls = (i < l - 1 ? parentArea.getTextLetterSpaceAdjust() : 0);
+ glyphAdjust -= tls;
+ } else {
+ if (CharUtilities.isFixedWidthSpace(orgChar)) {
+ //Fixed width space are rendered as spaces so copy/paste works in a reader
+ ch = fs.mapChar(CharUtilities.SPACE);
+ glyphAdjust = fs.getCharWidth(ch) - fs.getCharWidth(orgChar);
+ } else {
+ ch = fs.mapChar(orgChar);
+ }
+ }
+ if (letterAdjust != null && i < l - 1) {
+ glyphAdjust -= letterAdjust[i + 1];
+ }
+
+ if (startPending) {
+ pdf.append(startText);
+ startPending = false;
+ }
if (!useMultiByte) {
if (ch > 127) {
pdf.append("\\");
@@ -1156,6 +1085,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
case '\\':
pdf.append("\\");
break;
+ default:
}
pdf.append(ch);
}
@@ -1163,24 +1093,16 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
pdf.append(PDFText.toUnicodeHex(ch));
}
- if (kerningAvailable && (i + 1) < l) {
- addKerning(pdf, (new Integer((int) ch)),
- (new Integer((int) fs.mapChar(s.charAt(i + 1)))
- ), kerning, startText, endText);
+ float adjust = glyphAdjust / fontSize;
+
+ if (adjust != 0) {
+ pdf.append(endText).append(format(adjust)).append(' ');
+ startPending = true;
}
+
}
- }
-
- private void addKerning(StringBuffer buf, Integer ch1, Integer ch2,
- Map kerning, String startText, String endText) {
- Map kernPair = (Map) kerning.get(ch1);
-
- if (kernPair != null) {
- Integer width = (Integer) kernPair.get(ch2);
- if (width != null) {
- buf.append(endText).append(-width.intValue());
- buf.append(' ').append(startText);
- }
+ if (!startPending) {
+ pdf.append(endText);
}
}
@@ -1189,13 +1111,14 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
* still and writes out the TJ command to the stream if we do
*/
protected void closeText() {
+ /*
if (textOpen) {
currentStream.add("] TJ\n");
textOpen = false;
prevWordX = 0;
prevWordY = 0;
currentFontName = "";
- }
+ }*/
}
/**
@@ -1319,6 +1242,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
fact.releaseImage(url, userAgent);
+
+ float w = (float)pos.getWidth() / 1000f;
+ float h = (float)pos.getHeight() / 1000f;
+ placeImage((float) pos.getX() / 1000,
+ (float) pos.getY() / 1000, w, h, xobj);
} else if ("image/jpeg".equals(mime) || "image/tiff".equals(mime)) {
FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
diff --git a/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java b/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java
index 90cf60ce1..b2a1c07a0 100644
--- a/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java
+++ b/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java
@@ -53,11 +53,6 @@ public class PSDocumentGraphics2D extends AbstractPSDocumentGraphics2D {
*/
PSDocumentGraphics2D(boolean textAsShapes) {
super(textAsShapes);
-
- if (!textAsShapes) {
- fontInfo = new FontInfo();
- FontSetup.setup(fontInfo, null, null);
- }
}
/**
diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java
index b786a4962..52e7c7bcb 100644
--- a/src/java/org/apache/fop/render/ps/PSRenderer.java
+++ b/src/java/org/apache/fop/render/ps/PSRenderer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2005 The Apache Software Foundation.
+ * Copyright 1999-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,18 +45,19 @@ import org.apache.fop.area.PageViewport;
import org.apache.fop.area.RegionViewport;
import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.AbstractTextArea;
-import org.apache.fop.area.inline.Character;
import org.apache.fop.area.inline.ForeignObject;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.Leader;
+import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.area.inline.WordArea;
import org.apache.fop.datatypes.ColorType;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontSetup;
-import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.image.EPSImage;
import org.apache.fop.image.FopImage;
@@ -233,6 +234,16 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " M");
}
+ /**
+ * Moves the current point by (x, y) relative to the current position,
+ * omitting any connecting line segment.
+ * @param x x coordinate
+ * @param y y coordinate
+ */
+ protected void rmoveTo(float x, float y) {
+ writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " RM");
+ }
+
/** @see org.apache.fop.render.AbstractPathOrientedRenderer#lineTo(float, float) */
protected void lineTo(float x, float y) {
writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " lineto");
@@ -310,7 +321,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
}
}
- public void paintImage(RenderedImage image, RendererContext context, int x, int y, int width, int height) throws IOException {
+ /** @see org.apache.fop.render.ImageAdapter */
+ public void paintImage(RenderedImage image, RendererContext context,
+ int x, int y, int width, int height) throws IOException {
float fx = (float)x / 1000f;
x += currentIPPosition / 1000f;
float fy = (float)y / 1000f;
@@ -822,24 +835,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
}
/**
- * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character)
- */
- public void renderCharacter(Character ch) {
- String text = ch.getChar();
- renderText(ch, text);
- super.renderCharacter(ch); //Updates IPD
- }
-
- /**
* @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
*/
public void renderText(TextArea area) {
- String text = area.getText();
- renderText(area, text);
- super.renderText(area); //Updates IPD
- }
-
- private void renderText(AbstractTextArea area, String text) {
renderInlineAreaBackAndBorders(area);
String fontname = getInternalFontNameForArea(area);
int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE);
@@ -861,24 +859,52 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
}
}
- boolean kerningAvailable = false;
- Map kerning = tf.getKerningInfo();
- if (kerning != null && !kerning.isEmpty()) {
- //kerningAvailable = true;
- //TODO Fix me when kerning is supported by the layout engine
- log.warn("Kerning info is available, but kerning is not yet implemented for"
- + " the PS renderer and not currently supported by the layout engine.");
- }
-
beginTextObject();
writeln("1 0 0 -1 " + gen.formatDouble(rx / 1000f)
+ " " + gen.formatDouble(bl / 1000f) + " Tm");
+
+ super.renderText(area); //Updates IPD
+
+ renderTextDecoration(tf, fontsize, area, bl, rx);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderWord(org.apache.fop.area.inline.WordArea)
+ */
+ protected void renderWord(WordArea word) {
+ renderText((TextArea)word.getParentArea(), word.getWord(), word.getLetterAdjustArray());
+ super.renderWord(word);
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderSpace(org.apache.fop.area.inline.SpaceArea)
+ */
+ protected void renderSpace(SpaceArea space) {
+ AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
+ String s = space.getSpace();
+ char sp = s.charAt(0);
+ Font font = getFontFromArea(textArea);
+
+ int tws = (space.isAdjustable()
+ ? ((TextArea) space.getParentArea()).getTextWordSpaceAdjust()
+ + 2 * textArea.getTextLetterSpaceAdjust()
+ : 0);
+
+ rmoveTo((font.getCharWidth(sp) + tws) / 1000f, 0);
+ super.renderSpace(space);
+ }
+
+ private void renderText(AbstractTextArea area, String text, int[] letterAdjust) {
+ Font font = getFontFromArea(area);
+ Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName());
int initialSize = text.length();
initialSize += initialSize / 2;
StringBuffer sb = new StringBuffer(initialSize);
int textLen = text.length();
- if (area.getTextLetterSpaceAdjust() == 0 && area.getTextWordSpaceAdjust() == 0) {
+ if (letterAdjust == null
+ && area.getTextLetterSpaceAdjust() == 0
+ && area.getTextWordSpaceAdjust() == 0) {
sb.append("(");
for (int i = 0; i < textLen; i++) {
final char c = text.charAt(i);
@@ -893,17 +919,16 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
final char c = text.charAt(i);
final char mapped = tf.mapChar(c);
int wordSpace;
- //TODO Synchronize word space behaviour with TextLayoutManager
- //Check the other renderers, too!
- if (CharUtilities.isAnySpace(mapped)
- && mapped != CharUtilities.ZERO_WIDTH_SPACE
- && mapped != CharUtilities.ZERO_WIDTH_NOBREAK_SPACE) {
+
+ if (CharUtilities.isAdjustableSpace(mapped)) {
wordSpace = area.getTextWordSpaceAdjust();
} else {
wordSpace = 0;
}
- int cw = tf.getWidth(mapped, fontsize) / 1000;
- offsets[i] = cw + area.getTextLetterSpaceAdjust() + wordSpace;
+ int cw = tf.getWidth(mapped, font.getFontSize()) / 1000;
+ int ladj = (letterAdjust != null && i < textLen - 1 ? letterAdjust[i + 1] : 0);
+ int tls = (i < textLen - 1 ? area.getTextLetterSpaceAdjust() : 0);
+ offsets[i] = cw + ladj + tls + wordSpace;
PSGenerator.escapeChar(mapped, sb);
}
sb.append(")" + PSGenerator.LF + "[");
@@ -921,7 +946,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
}
writeln(sb.toString());
- renderTextDecoration(tf, fontsize, area, bl, rx);
}
/** @see org.apache.fop.render.AbstractPathOrientedRenderer#breakOutOfStateStack() */
diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java
index 6e0c58be2..06764c1da 100644
--- a/src/java/org/apache/fop/render/rtf/RTFHandler.java
+++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java
@@ -66,6 +66,7 @@ import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FOText;
+import org.apache.fop.render.DefaultFontResolver;
import org.apache.fop.render.rtf.rtflib.rtfdoc.ITableAttributes;
import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfAfterContainer;
import org.apache.fop.render.rtf.rtflib.rtfdoc.IRtfBeforeContainer;
@@ -137,7 +138,7 @@ public class RTFHandler extends FOEventHandler {
this.os = os;
bDefer = true;
- FontSetup.setup(fontInfo, null, userAgent);
+ FontSetup.setup(fontInfo, null, new DefaultFontResolver(userAgent));
}
/**
diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java
index 9ef12c4c4..49df7b1b3 100644
--- a/src/java/org/apache/fop/render/xml/XMLRenderer.java
+++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java
@@ -108,6 +108,7 @@ public class XMLRenderer extends PrintRenderer {
private boolean startedSequence = false;
private RendererContext context;
+ private boolean compactFormat = false;
/** If not null, the XMLRenderer will mimic another renderer by using its font setup. */
protected Renderer mimic;
@@ -155,6 +156,10 @@ public class XMLRenderer extends PrintRenderer {
XMLHandler xmlHandler = new XMLXMLHandler();
userAgent.getXMLHandlerRegistry().addXMLHandler(xmlHandler);
+ Boolean b = (Boolean)userAgent.getRendererOptions().get("compact-format");
+ if (b != null) {
+ setCompactFormat(b.booleanValue());
+ }
}
/**
@@ -184,9 +189,12 @@ public class XMLRenderer extends PrintRenderer {
this.handler = handler;
}
- private boolean isCoarseXml() {
- return ((Boolean)
- userAgent.getRendererOptions().get("fineDetail")).booleanValue();
+ public void setCompactFormat(boolean compact) {
+ this.compactFormat = compact;
+ }
+
+ private boolean isDetailedFormat() {
+ return !this.compactFormat;
}
/**
@@ -291,16 +299,18 @@ public class XMLRenderer extends PrintRenderer {
protected void addAreaAttributes(Area area) {
addAttribute("ipd", area.getIPD());
addAttribute("bpd", area.getBPD());
- if (area.getIPD() != 0) {
- addAttribute("ipda", area.getAllocIPD());
- }
- if (area.getBPD() != 0) {
- addAttribute("bpda", area.getAllocBPD());
+ if (isDetailedFormat()) {
+ if (area.getIPD() != 0) {
+ addAttribute("ipda", area.getAllocIPD());
+ }
+ if (area.getBPD() != 0) {
+ addAttribute("bpda", area.getAllocBPD());
+ }
+ addAttribute("bap", area.getBorderAndPaddingWidthStart() + " "
+ + area.getBorderAndPaddingWidthEnd() + " "
+ + area.getBorderAndPaddingWidthBefore() + " "
+ + area.getBorderAndPaddingWidthAfter());
}
- addAttribute("bap", area.getBorderAndPaddingWidthStart() + " "
- + area.getBorderAndPaddingWidthEnd() + " "
- + area.getBorderAndPaddingWidthBefore() + " "
- + area.getBorderAndPaddingWidthAfter());
}
/**
@@ -758,20 +768,6 @@ public class XMLRenderer extends PrintRenderer {
}
/**
- * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character)
- */
- protected void renderCharacter(org.apache.fop.area.inline.Character ch) {
- atts.clear();
- addAreaAttributes(ch);
- addTraitAttributes(ch);
- addAttribute("offset", ch.getOffset());
- addAttribute("baseline", ch.getBaselineOffset());
- startElement("char", atts);
- characters(ch.getChar());
- endElement("char");
- }
-
- /**
* @see org.apache.fop.render.AbstractRenderer#renderInlineSpace(Space)
*/
protected void renderInlineSpace(Space space) {
@@ -809,6 +805,21 @@ public class XMLRenderer extends PrintRenderer {
protected void renderWord(WordArea word) {
atts.clear();
addAttribute("offset", word.getOffset());
+ int[] letterAdjust = word.getLetterAdjustArray();
+ if (letterAdjust != null) {
+ StringBuffer sb = new StringBuffer(64);
+ boolean nonZeroFound = false;
+ for (int i = 0, c = letterAdjust.length; i < c; i++) {
+ if (i > 0) {
+ sb.append(' ');
+ }
+ sb.append(letterAdjust[i]);
+ nonZeroFound |= (letterAdjust[i] != 0);
+ }
+ if (nonZeroFound) {
+ addAttribute("letter-adjust", sb.toString());
+ }
+ }
startElement("word", atts);
characters(word.getWord());
endElement("word");
@@ -821,6 +832,9 @@ public class XMLRenderer extends PrintRenderer {
protected void renderSpace(SpaceArea space) {
atts.clear();
addAttribute("offset", space.getOffset());
+ if (!space.isAdjustable()) {
+ addAttribute("adj", "false"); //default is true
+ }
startElement("space", atts);
characters(space.getSpace());
endElement("space");
diff --git a/src/java/org/apache/fop/traits/MinOptMax.java b/src/java/org/apache/fop/traits/MinOptMax.java
index 143e93ae0..981abfbf4 100644
--- a/src/java/org/apache/fop/traits/MinOptMax.java
+++ b/src/java/org/apache/fop/traits/MinOptMax.java
@@ -168,6 +168,11 @@ public class MinOptMax implements java.io.Serializable, Cloneable {
return (min != 0 || max != 0);
}
+ /** @return true if this instance allows for shrinking or stretching */
+ public boolean isElastic() {
+ return (min != opt || opt != max);
+ }
+
/** @see java.lang.Object#toString() */
public String toString() {
StringBuffer sb = new StringBuffer();
diff --git a/src/java/org/apache/fop/traits/SpaceVal.java b/src/java/org/apache/fop/traits/SpaceVal.java
index 4c9cdf5bc..d3743c88d 100644
--- a/src/java/org/apache/fop/traits/SpaceVal.java
+++ b/src/java/org/apache/fop/traits/SpaceVal.java
@@ -79,6 +79,7 @@ public class SpaceVal {
// and stretch by a half;
int spaceCharIPD = fs.getCharWidth(' ');
MinOptMax space = new MinOptMax(-spaceCharIPD / 3, 0, spaceCharIPD / 2);
+ //TODO Adding 2 letter spaces here is not 100% correct. Spaces don't have letter spacing
return new SpaceVal(
MinOptMax.add
(space, MinOptMax.multiply(letterSpacing.getSpace(), 2)),
diff --git a/src/java/org/apache/fop/util/CharUtilities.java b/src/java/org/apache/fop/util/CharUtilities.java
index 43c2c3e41..f200c3e2f 100644
--- a/src/java/org/apache/fop/util/CharUtilities.java
+++ b/src/java/org/apache/fop/util/CharUtilities.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2005 The Apache Software Foundation.
+ * Copyright 1999-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,9 +53,13 @@ public class CharUtilities {
public static final int XMLWHITESPACE = 4;
+ /** normal space */
+ public static final char SPACE = '\u0020';
+ /** non-breaking space */
+ public static final char NBSPACE = '\u00A0';
/** zero-width space */
public static final char ZERO_WIDTH_SPACE = '\u200B';
- /** zero-width no-break space */
+ /** zero-width no-break space (= byte order mark) */
public static final char ZERO_WIDTH_NOBREAK_SPACE = '\uFEFF';
@@ -89,22 +93,31 @@ public class CharUtilities {
* @return True if the character is a normal space
*/
public static boolean isBreakableSpace(char c) {
- return (c == ' '
- || (c >= '\u2000' && c <= '\u200B'));
-// c == '\u2000' // en quad
-// c == '\u2001' // em quad
-// c == '\u2002' // en space
-// c == '\u2003' // em space
-// c == '\u2004' // three-per-em space
-// c == '\u2005' // four--per-em space
-// c == '\u2006' // six-per-em space
-// c == '\u2007' // figure space
-// c == '\u2008' // punctuation space
-// c == '\u2009' // thin space
-// c == '\u200A' // hair space
-// c == '\u200B' // zero width space
+ return (c == SPACE || isFixedWidthSpace(c));
}
-
+
+ /**
+ * Method to determine if the character is a (breakable) fixed-width space.
+ * @param c the character to check
+ * @return true if the character has a fixed-width
+ */
+ public static boolean isFixedWidthSpace(char c) {
+ return (c >= '\u2000' && c <= '\u200B') || c == '\u3000';
+// c == '\u2000' // en quad
+// c == '\u2001' // em quad
+// c == '\u2002' // en space
+// c == '\u2003' // em space
+// c == '\u2004' // three-per-em space
+// c == '\u2005' // four--per-em space
+// c == '\u2006' // six-per-em space
+// c == '\u2007' // figure space
+// c == '\u2008' // punctuation space
+// c == '\u2009' // thin space
+// c == '\u200A' // hair space
+// c == '\u200B' // zero width space
+// c == '\u3000' // ideographic space
+ }
+
/**
* Method to determine if the character is a nonbreaking
* space.
@@ -113,7 +126,7 @@ public class CharUtilities {
*/
public static boolean isNonBreakableSpace(char c) {
return
- (c == '\u00A0' // no-break space
+ (c == NBSPACE // no-break space
|| c == '\u202F' // narrow no-break space
|| c == '\u3000' // ideographic space
|| c == ZERO_WIDTH_NOBREAK_SPACE); // zero width no-break space
@@ -141,5 +154,30 @@ public class CharUtilities {
boolean ret = (isBreakableSpace(c) || isNonBreakableSpace(c));
return ret;
}
+
+ /**
+ * Indicates whether a character is classified as "Alphabetic" by the Unicode standard.
+ * @param ch the character
+ * @return true if the character is "Alphabetic"
+ */
+ public static boolean isAlphabetic(char ch) {
+ //http://www.unicode.org/Public/UNIDATA/UCD.html#Alphabetic
+ //Generated from: Other_Alphabetic + Lu + Ll + Lt + Lm + Lo + Nl
+ int generalCategory = Character.getType(ch);
+ switch (generalCategory) {
+ case Character.UPPERCASE_LETTER: //Lu
+ case Character.LOWERCASE_LETTER: //Ll
+ case Character.TITLECASE_LETTER: //Lt
+ case Character.MODIFIER_LETTER: //Lm
+ case Character.OTHER_LETTER: //Lo
+ case Character.LETTER_NUMBER: //Nl
+ return true;
+ default:
+ //TODO if (ch in Other_Alphabetic) return true; (Probably need ICU4J for that)
+ //Other_Alphabetic contains mostly more exotic characters
+ return false;
+ }
+ }
+
}