summaryrefslogtreecommitdiffstats
path: root/fop-core/src/main
diff options
context:
space:
mode:
authorSimon Steiner <ssteiner@apache.org>2021-01-11 15:00:20 +0000
committerSimon Steiner <ssteiner@apache.org>2021-01-11 15:00:20 +0000
commita5fa25cf3e6fc98267fe5eaefedf466516c0bc9f (patch)
treea4c893ea8b018b6d4e56894f117cf505f42b151c /fop-core/src/main
parent1f2a414bb711508e158f9704cb6b5320cfd848e3 (diff)
downloadxmlgraphics-fop-a5fa25cf3e6fc98267fe5eaefedf466516c0bc9f.tar.gz
xmlgraphics-fop-a5fa25cf3e6fc98267fe5eaefedf466516c0bc9f.zip
FOP-2994: Support OTF/TTF SVG fonts
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1885366 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'fop-core/src/main')
-rw-r--r--fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java4
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java10
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java12
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java10
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/FontLoader.java4
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/LazyFont.java6
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java6
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java4
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java17
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/truetype/OFTableName.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/truetype/OpenFont.java30
-rw-r--r--fop-core/src/main/java/org/apache/fop/fonts/truetype/SVGGlyphData.java100
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java2
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/intermediate/AbstractIFPainter.java24
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java6
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java8
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/ps/PSImageHandlerSVG.java55
-rw-r--r--fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java33
21 files changed, 275 insertions, 64 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java b/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java
index ffb92b027..159efe4aa 100644
--- a/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java
+++ b/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java
@@ -413,7 +413,7 @@ public class FOUserAgent {
try {
// Have to do this so we can resolve data URIs
StreamSource src = new StreamSource(resourceResolver.getResource(uri));
- src.setSystemId(uri);
+ src.setSystemId(getResourceResolver().getBaseURI().toASCIIString());
return src;
} catch (URISyntaxException use) {
return null;
diff --git a/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java b/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java
index f125dc6a3..642b76f57 100644
--- a/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java
+++ b/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java
@@ -141,7 +141,7 @@ public class FopConfParser {
*/
public FopConfParser(File fopConfFile, ResourceResolver resourceResolver)
throws SAXException, IOException {
- this(new FileInputStream(fopConfFile), fopConfFile.toURI(), resourceResolver);
+ this(new FileInputStream(fopConfFile), fopConfFile.getParentFile().toURI(), resourceResolver);
}
public FopConfParser(InputStream fopConfStream, URI baseURI, EnvironmentProfile enviro)
diff --git a/fop-core/src/main/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java b/fop-core/src/main/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
index 4b319f1c1..0607f998e 100644
--- a/fop-core/src/main/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
+++ b/fop-core/src/main/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
@@ -215,7 +215,9 @@ public final class OTFAdvancedTypographicTableReader {
log.debug(tableTag + " lang sys default: " + dt);
}
}
- seScripts.put(scriptTag, new Object[] { dt, ll, seLanguages });
+ if (seLanguages != null) {
+ seScripts.put(scriptTag, new Object[]{dt, ll, seLanguages});
+ }
seLanguages = null;
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java b/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java
index 2b659f512..cd026e162 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java
@@ -32,6 +32,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.fop.apps.io.InternalResourceResolver;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
/**
@@ -80,6 +81,7 @@ public abstract class CustomFont extends Typeface
private boolean useKerning = true;
/** the character map, mapping Unicode ranges to glyph indices. */
protected List<CMapSegment> cmap = new ArrayList<CMapSegment>();
+ protected Map<Integer, SVGGlyphData> svgs;
private boolean useAdvanced = true;
private boolean simulateStyle;
protected List<SimpleSingleByteEncoding> additionalEncodings;
@@ -682,4 +684,12 @@ public abstract class CustomFont extends Typeface
}
return 0;
}
+
+ public boolean hasSVG() {
+ return svgs != null;
+ }
+
+ public void setSVG(Map<Integer, SVGGlyphData> svgs) {
+ this.svgs = svgs;
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java
index a1663756c..2b67dbd2e 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java
@@ -132,7 +132,8 @@ public final class DefaultFontConfig implements FontConfig {
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()),
fontCfg.getAttribute("embedding-mode", EncodingMode.AUTO.getName()),
fontCfg.getAttributeAsBoolean("simulate-style", false),
- fontCfg.getAttributeAsBoolean("embed-as-type1", false));
+ fontCfg.getAttributeAsBoolean("embed-as-type1", false),
+ fontCfg.getAttributeAsBoolean("svg", true));
instance.fonts.add(font);
boolean hasTriplets = false;
for (Configuration tripletCfg : fontCfg.getChildren("font-triplet")) {
@@ -322,6 +323,8 @@ public final class DefaultFontConfig implements FontConfig {
private final boolean embedAsType1;
private final boolean simulateStyle;
+ private final boolean useSVG;
+
private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>();
public List<FontTriplet> getTripletList() {
@@ -330,7 +333,7 @@ public final class DefaultFontConfig implements FontConfig {
private Font(String metrics, String embed, String afm, String pfm, String subFont, boolean kerning,
boolean advanced, String encodingMode, String embeddingMode, boolean simulateStyle,
- boolean embedAsType1) {
+ boolean embedAsType1, boolean useSVG) {
this.metrics = metrics;
this.embedUri = embed;
this.afm = afm;
@@ -342,6 +345,7 @@ public final class DefaultFontConfig implements FontConfig {
this.embeddingMode = embeddingMode;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
+ this.useSVG = useSVG;
}
/**
@@ -399,5 +403,9 @@ public final class DefaultFontConfig implements FontConfig {
public boolean getEmbedAsType1() {
return embedAsType1;
}
+
+ public boolean getUseSVG() {
+ return useSVG;
+ }
}
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java
index c8d1c00e2..6e8c493cd 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java
@@ -168,7 +168,7 @@ public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo>
EmbeddingMode embeddingMode = EmbeddingMode.getValue(font.getEmbeddingMode());
EmbedFontInfo embedFontInfo = new EmbedFontInfo(fontUris, font.isKerning(),
font.isAdvanced(), tripletList, subFont, encodingMode, embeddingMode,
- font.getSimulateStyle(), font.getEmbedAsType1());
+ font.getSimulateStyle(), font.getEmbedAsType1(), font.getUseSVG());
if (fontCache != null) {
if (!fontCache.containsFont(embedFontInfo)) {
fontCache.addFont(embedFontInfo, resourceResolver);
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java b/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java
index 186f098fd..27a0a4db2 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java
@@ -45,6 +45,7 @@ public class EmbedFontInfo implements Serializable {
/** simulates bold or italic on a regular font */
private final boolean simulateStyle;
private final boolean embedAsType1;
+ private final boolean useSVG;
/** the PostScript name of the font */
protected String postScriptName;
@@ -69,7 +70,7 @@ public class EmbedFontInfo implements Serializable {
*/
public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced,
List<FontTriplet> fontTriplets, String subFontName, EncodingMode encodingMode,
- EmbeddingMode embeddingMode, boolean simulateStyle, boolean embedAsType1) {
+ EmbeddingMode embeddingMode, boolean simulateStyle, boolean embedAsType1, boolean useSVG) {
this.kerning = kerning;
this.advanced = advanced;
this.fontTriplets = fontTriplets;
@@ -79,6 +80,7 @@ public class EmbedFontInfo implements Serializable {
this.fontUris = fontUris;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
+ this.useSVG = useSVG;
}
/**
@@ -91,7 +93,7 @@ public class EmbedFontInfo implements Serializable {
public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced,
List<FontTriplet> fontTriplets, String subFontName) {
this(fontUris, kerning, advanced, fontTriplets, subFontName, EncodingMode.AUTO,
- EmbeddingMode.AUTO, false, false);
+ EmbeddingMode.AUTO, false, false, true);
}
/**
@@ -209,6 +211,10 @@ public class EmbedFontInfo implements Serializable {
return embedAsType1;
}
+ public boolean getUseSVG() {
+ return useSVG;
+ }
+
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/FontLoader.java b/fop-core/src/main/java/org/apache/fop/fonts/FontLoader.java
index 06907f403..1e3d4092f 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/FontLoader.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/FontLoader.java
@@ -93,7 +93,7 @@ public abstract class FontLoader {
public static CustomFont loadFont(FontUris fontUris, String subFontName,
boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode,
boolean useKerning, boolean useAdvanced, InternalResourceResolver resourceResolver,
- boolean simulateStyle, boolean embedAsType1) throws IOException {
+ boolean simulateStyle, boolean embedAsType1, boolean useSVG) throws IOException {
boolean type1 = isType1(fontUris);
FontLoader loader;
if (type1) {
@@ -105,7 +105,7 @@ public abstract class FontLoader {
resourceResolver);
} else {
loader = new OFFontLoader(fontUris.getEmbed(), subFontName, embedded, embeddingMode,
- encodingMode, useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1);
+ encodingMode, useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1, useSVG);
}
return loader.getFont();
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/LazyFont.java b/fop-core/src/main/java/org/apache/fop/fonts/LazyFont.java
index 7b2d46584..753cece8c 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/LazyFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/LazyFont.java
@@ -47,6 +47,7 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable,
private final boolean useAdvanced;
private boolean simulateStyle;
private boolean embedAsType1;
+ private boolean useSVG;
private final EncodingMode encodingMode;
private final EmbeddingMode embeddingMode;
private final String subFontName;
@@ -74,6 +75,7 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable,
}
this.simulateStyle = fontInfo.getSimulateStyle();
this.embedAsType1 = fontInfo.getEmbedAsType1();
+ useSVG = fontInfo.getUseSVG();
this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode()
: EncodingMode.AUTO;
this.embeddingMode = fontInfo.getEmbeddingMode() != null ? fontInfo.getEmbeddingMode()
@@ -116,8 +118,8 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable,
if (fontUris.getEmbed() == null) {
throw new RuntimeException("Cannot load font. No font URIs available.");
}
- realFont = FontLoader.loadFont(fontUris, subFontName, embedded, embeddingMode,
- encodingMode, useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1);
+ realFont = FontLoader.loadFont(fontUris, subFontName, embedded, embeddingMode, encodingMode,
+ useKerning, useAdvanced, resourceResolver, simulateStyle, embedAsType1, useSVG);
}
if (realFont instanceof FontDescriptor) {
realFontDescriptor = (FontDescriptor) realFont;
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java b/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java
index 3fd780d4e..4f1263ebe 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java
@@ -42,6 +42,7 @@ import org.apache.fop.complexscripts.fonts.Substitutable;
import org.apache.fop.complexscripts.util.CharAssociation;
import org.apache.fop.complexscripts.util.CharNormalize;
import org.apache.fop.complexscripts.util.GlyphSequence;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
import org.apache.fop.util.CharUtilities;
/**
@@ -857,5 +858,10 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
public InputStream getCmapStream() {
return null;
}
+
+ public SVGGlyphData getSVG(char c) {
+ int gid = findGlyphIndex(c);
+ return svgs.get(gid);
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/fop-core/src/main/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
index e14bb0123..9e8d9e5db 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
@@ -223,7 +223,7 @@ public class FontInfoFinder {
try {
OFFontLoader ttfLoader = new OFFontLoader(fontURI, fontName, true,
EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced,
- resourceResolver, false, false);
+ resourceResolver, false, false, true);
customFont = ttfLoader.getFont();
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
@@ -251,7 +251,7 @@ public class FontInfoFinder {
try {
FontUris fontUris = new FontUris(fontURI, null);
customFont = FontLoader.loadFont(fontUris, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO,
- useKerning, useAdvanced, resourceResolver, false, false);
+ useKerning, useAdvanced, resourceResolver, false, false, true);
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java
index 0634957de..895b798f7 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java
@@ -55,6 +55,7 @@ public class OFFontLoader extends FontLoader {
private EmbeddingMode embeddingMode;
private boolean simulateStyle;
private boolean embedAsType1;
+ private boolean useSVG;
/**
* Default constructor
@@ -63,7 +64,7 @@ public class OFFontLoader extends FontLoader {
*/
public OFFontLoader(URI fontFileURI, InternalResourceResolver resourceResolver) {
this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resourceResolver, false,
- false);
+ false, true);
}
/**
@@ -79,15 +80,16 @@ public class OFFontLoader extends FontLoader {
* @param resolver the FontResolver for font URI resolution
* @param simulateStyle Determines whether to simulate font styles if a font does not support those by default.
*/
- public OFFontLoader(URI fontFileURI, String subFontName, boolean embedded,
- EmbeddingMode embeddingMode, EncodingMode encodingMode, boolean useKerning,
- boolean useAdvanced, InternalResourceResolver resolver, boolean simulateStyle, boolean embedAsType1) {
+ public OFFontLoader(URI fontFileURI, String subFontName, boolean embedded, EmbeddingMode embeddingMode,
+ EncodingMode encodingMode, boolean useKerning, boolean useAdvanced, InternalResourceResolver resolver,
+ boolean simulateStyle, boolean embedAsType1, boolean useSVG) {
super(fontFileURI, embedded, useKerning, useAdvanced, resolver);
this.subFontName = subFontName;
this.encodingMode = encodingMode;
this.embeddingMode = embeddingMode;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
+ this.useSVG = useSVG;
if (this.encodingMode == EncodingMode.AUTO) {
this.encodingMode = EncodingMode.CID; //Default to CID mode for TrueType
}
@@ -118,7 +120,7 @@ public class OFFontLoader extends FontLoader {
if (!supported) {
throw new IOException("The font does not have a Unicode cmap table: " + fontFileURI);
}
- buildFont(otf, ttcFontName, embedAsType1);
+ buildFont(otf, ttcFontName);
loaded = true;
} finally {
IOUtils.closeQuietly(in);
@@ -133,7 +135,7 @@ public class OFFontLoader extends FontLoader {
return null;
}
- private void buildFont(OpenFont otf, String ttcFontName, boolean embedAsType1) {
+ private void buildFont(OpenFont otf, String ttcFontName) {
boolean isCid = this.embedded;
if (this.encodingMode == EncodingMode.SINGLE_BYTE) {
isCid = false;
@@ -201,6 +203,9 @@ public class OFFontLoader extends FontLoader {
copyGlyphMetricsSingleByte(otf);
}
returnFont.setCMap(getCMap(otf));
+ if (useSVG) {
+ returnFont.setSVG(otf.svgs);
+ }
if (otf.getKerning() != null && useKerning) {
copyKerning(otf, isCid);
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFTableName.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFTableName.java
index f6264129a..29d0f78ee 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFTableName.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OFTableName.java
@@ -119,6 +119,8 @@ public final class OFTableName {
/** Vertical Metrics. */
public static final OFTableName VMTX = new OFTableName("vmtx");
+ public static final OFTableName SVG = new OFTableName("SVG ");
+
private final String name;
private OFTableName(String name) {
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OpenFont.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OpenFont.java
index 5076e3064..0d10129f0 100644
--- a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OpenFont.java
+++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OpenFont.java
@@ -31,6 +31,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -219,6 +220,7 @@ public abstract class OpenFont {
private int[] ansiWidth;
private Map<Integer, List<Integer>> ansiIndex;
+ protected Map<Integer, SVGGlyphData> svgs;
// internal mapping of glyph indexes to unicode indexes
// used for quick mappings in this class
@@ -839,6 +841,7 @@ public abstract class OpenFont {
readPostScript();
readOS2();
determineAscDesc();
+ readSVG();
readName();
boolean pcltFound = readPCLT();
@@ -1329,6 +1332,33 @@ public abstract class OpenFont {
}
}
+ private void readSVG() throws IOException {
+ OFDirTabEntry dirTab = dirTabs.get(OFTableName.SVG);
+ if (dirTab != null) {
+ svgs = new LinkedHashMap<>();
+ fontFile.seekSet(dirTab.getOffset());
+ fontFile.readTTFUShort(); //version
+ fontFile.readTTFULong(); //svgDocumentListOffset
+ fontFile.readTTFULong(); //reserved
+ int numEntries = fontFile.readTTFUShort();
+ for (int i = 0; i < numEntries; i++) {
+ int startGlyphID = fontFile.readTTFUShort();
+ fontFile.readTTFUShort(); //endGlyphID
+ SVGGlyphData svgGlyph = new SVGGlyphData();
+ svgGlyph.svgDocOffset = fontFile.readTTFULong();
+ svgGlyph.svgDocLength = fontFile.readTTFULong();
+ svgs.put(startGlyphID, svgGlyph);
+ }
+ for (SVGGlyphData entry : svgs.values()) {
+ seekTab(fontFile, OFTableName.SVG, entry.svgDocOffset);
+ fontFile.readTTFUShort(); //version
+ fontFile.readTTFULong(); //svgDocumentListOffset
+ fontFile.readTTFULong(); //reserved
+ entry.setSVG(fontFile.readTTFString((int) entry.svgDocLength));
+ }
+ }
+ }
+
/**
* Read "hmtx" table and put the horizontal metrics
* in the mtxTab array. If the number of metrics is less
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/SVGGlyphData.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/SVGGlyphData.java
new file mode 100644
index 000000000..e46e50074
--- /dev/null
+++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/SVGGlyphData.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.truetype;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import org.apache.xmlgraphics.util.uri.DataURLUtil;
+
+public class SVGGlyphData {
+ protected long svgDocOffset;
+ protected long svgDocLength;
+ private String svg;
+ public float scale = 1;
+
+ public void setSVG(String svg) {
+ this.svg = svg;
+ }
+
+ public String getDataURL(int height) {
+ try {
+ String modifiedSVG = updateTransform(svg, height);
+ return DataURLUtil.createDataURL(new ByteArrayInputStream(modifiedSVG.getBytes("UTF-8")), "image/svg");
+ } catch (IOException | TransformerException | SAXException | ParserConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String updateTransform(String svg, int height)
+ throws IOException, ParserConfigurationException, SAXException, TransformerException {
+ DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ InputSource inputSource = new InputSource();
+ inputSource.setCharacterStream(new StringReader(svg));
+ Document doc = documentBuilder.parse(inputSource);
+ NodeList nodes = doc.getElementsByTagName("g");
+ Element gElement = (Element) nodes.item(0);
+ if (gElement != null) {
+ String transform = gElement.getAttribute("transform");
+ if (transform.contains("scale(")) {
+ String scaleStr = transform.split("scale\\(")[1].split("\\)")[0].trim();
+ scale = Float.parseFloat(scaleStr);
+ gElement.removeAttribute("transform");
+ } else {
+ gElement.setAttribute("transform", "translate(0," + height + ")");
+ }
+ } else {
+ Element svgElement = (Element) doc.getElementsByTagName("svg").item(0);
+ svgElement.setAttribute("viewBox", "0 0 1000 " + height);
+ gElement = doc.createElement("g");
+ gElement.setAttribute("transform", "translate(0," + height + ")");
+ NodeList paths = doc.getElementsByTagName("path");
+ for (int i = 0; i < paths.getLength(); i++) {
+ Node path = paths.item(i);
+ if (i == 0) {
+ path.getParentNode().insertBefore(gElement, path);
+ }
+ gElement.appendChild(path);
+ }
+ }
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ StreamResult result = new StreamResult(new StringWriter());
+ DOMSource source = new DOMSource(doc);
+ transformer.transform(source, result);
+ return result.getWriter().toString();
+ }
+}
diff --git a/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java b/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java
index 0967bd1f8..eb6c4a77f 100644
--- a/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java
+++ b/fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java
@@ -384,7 +384,7 @@ public final class AFPFontConfig implements FontConfig {
try {
FontUris fontUris = new FontUris(new URI(fontUri), null);
EmbedFontInfo embedFontInfo = new EmbedFontInfo(fontUris, false, true, null, subfont, EncodingMode.AUTO,
- EmbeddingMode.FULL, false, false);
+ EmbeddingMode.FULL, false, false, true);
Typeface tf = new LazyFont(embedFontInfo, resourceResolver, false).getRealFont();
AFPResourceAccessor accessor = getAccessor(resourceResolver);
CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().build(characterset,
diff --git a/fop-core/src/main/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/fop-core/src/main/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
index 45996a2f4..44620ff61 100644
--- a/fop-core/src/main/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
+++ b/fop-core/src/main/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
@@ -46,8 +46,11 @@ import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.fop.ResourceEventProducer;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.Constants;
+import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.truetype.SVGGlyphData;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.ImageHandlerUtil;
@@ -469,4 +472,25 @@ public abstract class AbstractIFPainter<T extends IFDocumentHandler> implements
int[][] dp, String text, boolean nextIsSpace) throws IFException {
drawText(x, y, letterSpacing, wordSpacing, dp, text);
}
+
+ protected void drawSVGText(MultiByteFont multiByteFont, FontTriplet triplet, int x, int y, String text,
+ IFState state) throws IFException {
+ int sizeMillipoints = state.getFontSize();
+ Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints);
+ int newx = x;
+ for (char c : text.toCharArray()) {
+ SVGGlyphData svg = multiByteFont.getSVG(c);
+ if (svg != null) {
+ int codePoint = font.mapCodePoint(c);
+ String dataURL = svg.getDataURL(multiByteFont.getCapHeight());
+ Rectangle boundingBox = multiByteFont.getBoundingBox(codePoint, (int) (sizeMillipoints / 1000f));
+ boundingBox.y = y - boundingBox.height - boundingBox.y;
+ boundingBox.x = newx;
+ boundingBox.width = (int) (sizeMillipoints * svg.scale);
+ boundingBox.height = (int) (sizeMillipoints * svg.scale);
+ drawImage(dataURL, boundingBox);
+ }
+ newx += font.getCharWidth(c);
+ }
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java b/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
index e494ed65c..d019f352a 100644
--- a/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
+++ b/fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
@@ -83,11 +83,11 @@ public class ConfiguredFontCollection implements FontCollection {
font = new CustomFontMetricsMapper(fontMetrics, fontSource);
} else {
FontUris fontUris = configFontInfo.getFontUris();
- CustomFont fontMetrics = FontLoader.loadFont(fontUris,
- configFontInfo.getSubFontName(), true,
+ CustomFont fontMetrics = FontLoader.loadFont(fontUris, configFontInfo.getSubFontName(), true,
configFontInfo.getEmbeddingMode(), configFontInfo.getEncodingMode(),
configFontInfo.getKerning(), configFontInfo.getAdvanced(), resourceResolver,
- configFontInfo.getSimulateStyle(), configFontInfo.getEmbedAsType1());
+ configFontInfo.getSimulateStyle(), configFontInfo.getEmbedAsType1(),
+ configFontInfo.getUseSVG());
font = new CustomFontMetricsMapper(fontMetrics);
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java
index 985e587cb..cae8973ac 100644
--- a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java
+++ b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java
@@ -43,6 +43,7 @@ import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.pdf.PDFArray;
@@ -431,8 +432,11 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
FontTriplet triplet = new FontTriplet(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
-
- if ((dp == null) || IFUtil.isDPOnlyDX(dp)) {
+ String fontKey = getFontInfo().getInternalFontKey(triplet);
+ Typeface typeface = getTypeface(fontKey);
+ if (typeface instanceof MultiByteFont && ((MultiByteFont) typeface).hasSVG()) {
+ drawSVGText((MultiByteFont) typeface, triplet, x, y, text, state);
+ } else if ((dp == null) || IFUtil.isDPOnlyDX(dp)) {
drawTextWithDX(x, y, text, triplet, letterSpacing,
wordSpacing, IFUtil.convertDPToDX(dp));
} else {
diff --git a/fop-core/src/main/java/org/apache/fop/render/ps/PSImageHandlerSVG.java b/fop-core/src/main/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
index b034fa79e..9c0a90286 100644
--- a/fop-core/src/main/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
+++ b/fop-core/src/main/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
@@ -21,6 +21,7 @@ package org.apache.fop.render.ps;
import java.awt.Color;
import java.awt.Dimension;
+import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
@@ -43,14 +44,11 @@ import org.w3c.dom.NodeList;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.gvt.GraphicsNode;
-import org.apache.batik.transcoder.SVGAbstractTranscoder;
-import org.apache.batik.transcoder.TranscoderException;
-import org.apache.batik.transcoder.TranscoderInput;
-import org.apache.batik.transcoder.TranscoderOutput;
-import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.ps.ImageEncoder;
import org.apache.xmlgraphics.ps.ImageEncodingHelper;
@@ -58,6 +56,7 @@ import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.fop.image.loader.batik.BatikImageFlavors;
import org.apache.fop.image.loader.batik.BatikUtil;
+import org.apache.fop.image.loader.batik.ImageConverterSVG2G2D;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.ps.svg.PSSVGGraphics2D;
@@ -85,7 +84,7 @@ public class PSImageHandlerSVG implements ImageHandler {
ImageXMLDOM imageSVG = (ImageXMLDOM)image;
if (shouldRaster(imageSVG)) {
- InputStream is = renderSVGToInputStream(context, imageSVG);
+ InputStream is = renderSVGToInputStream(imageSVG, pos);
float x = (float) pos.getX() / 1000f;
float y = (float) pos.getY() / 1000f;
@@ -175,25 +174,35 @@ public class PSImageHandlerSVG implements ImageHandler {
}
}
- private InputStream renderSVGToInputStream(RenderingContext context, ImageXMLDOM imageSVG) throws IOException {
- PNGTranscoder png = new PNGTranscoder();
- Float width = getDimension(imageSVG.getDocument(), "width") * 8;
- png.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, width);
- Float height = getDimension(imageSVG.getDocument(), "height") * 8;
- png.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, height);
- TranscoderInput input = new TranscoderInput(imageSVG.getDocument());
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- TranscoderOutput output = new TranscoderOutput(os);
+ private InputStream renderSVGToInputStream(ImageXMLDOM imageSVG, Rectangle destinationRect)
+ throws IOException {
+ Rectangle rectangle;
+ int width;
+ int height;
+ Float widthSVG = getDimension(imageSVG.getDocument(), "width");
+ Float heightSVG = getDimension(imageSVG.getDocument(), "height");
+ if (widthSVG != null && heightSVG != null) {
+ width = (int) (widthSVG * 8);
+ height = (int) (heightSVG * 8);
+ rectangle = new Rectangle(0, 0, width, height);
+ } else {
+ int scale = 10;
+ width = destinationRect.width / scale;
+ height = destinationRect.height / scale;
+ rectangle = new Rectangle(0, 0, destinationRect.width / 100, destinationRect.height / 100);
+ destinationRect.width *= scale;
+ destinationRect.height *= scale;
+ }
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D graphics2D = image.createGraphics();
try {
- png.transcode(input, output);
- } catch (TranscoderException ex) {
- SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
- context.getUserAgent().getEventBroadcaster());
- eventProducer.svgRenderingError(this, ex, imageSVG.getInfo().getOriginalURI());
- } finally {
- os.flush();
- os.close();
+ ImageGraphics2D img = (ImageGraphics2D) new ImageConverterSVG2G2D().convert(imageSVG, new HashMap());
+ img.getGraphics2DImagePainter().paint(graphics2D, rectangle);
+ } catch (ImageException e) {
+ throw new IOException(e);
}
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ImageIO.write(image, "png", os);
return new ByteArrayInputStream(os.toByteArray());
}
diff --git a/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java b/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java
index 34f57e42d..a7f0f455f 100644
--- a/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java
+++ b/fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java
@@ -359,25 +359,28 @@ public class PSPainter extends AbstractIFPainter<PSDocumentHandler> {
}
PSGenerator generator = getGenerator();
generator.useColor(state.getTextColor());
+ FontTriplet triplet = new FontTriplet(state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
+ String fontKey = getFontKey(triplet);
+ Typeface typeface = getTypeface(fontKey);
+ if (typeface instanceof MultiByteFont && ((MultiByteFont) typeface).hasSVG()) {
+ drawSVGText((MultiByteFont) typeface, triplet, x, y, text, state);
+ return;
+ }
beginTextObject();
- FontTriplet triplet = new FontTriplet(
- state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
//TODO Ignored: state.getFontVariant()
//TODO Opportunity for font caching if font state is more heavily used
- String fontKey = getFontKey(triplet);
int sizeMillipoints = state.getFontSize();
// This assumes that *all* CIDFonts use a /ToUnicode mapping
- Typeface tf = getTypeface(fontKey);
SingleByteFont singleByteFont = null;
- if (tf instanceof SingleByteFont) {
- singleByteFont = (SingleByteFont)tf;
+ if (typeface instanceof SingleByteFont) {
+ singleByteFont = (SingleByteFont)typeface;
}
Font font = getFontInfo().getFontInstance(triplet, sizeMillipoints);
PSFontResource res = getDocumentHandler().getPSResourceForFontKey(fontKey);
- boolean otf = tf instanceof MultiByteFont && ((MultiByteFont)tf).isOTFFile();
- useFont(fontKey, sizeMillipoints, otf);
+ boolean isOpenTypeFont = typeface instanceof MultiByteFont && ((MultiByteFont)typeface).isOTFFile();
+ useFont(fontKey, sizeMillipoints, isOpenTypeFont);
if (dp != null && dp[0] != null) {
x += dp[0][0];
@@ -393,12 +396,12 @@ public class PSPainter extends AbstractIFPainter<PSDocumentHandler> {
int currentEncoding = -1;
for (int i = 0; i < textLen; i++) {
char c = text.charAt(i);
- char mapped = tf.mapChar(c);
+ char mapped = typeface.mapChar(c);
int encoding = mapped / 256;
if (currentEncoding != encoding) {
if (i > 0) {
writeText(text, start, i - start,
- letterSpacing, wordSpacing, dp, font, tf, false);
+ letterSpacing, wordSpacing, dp, font, typeface, false);
}
if (encoding == 0) {
useFont(fontKey, sizeMillipoints, false);
@@ -410,20 +413,20 @@ public class PSPainter extends AbstractIFPainter<PSDocumentHandler> {
}
}
} else {
- if (tf instanceof MultiByteFont && ((MultiByteFont)tf).isOTFFile()) {
+ if (typeface instanceof MultiByteFont && ((MultiByteFont)typeface).isOTFFile()) {
//Analyze string and split up in order to paint in different sub-fonts/encodings
int curEncoding = 0;
for (int i = start; i < textLen; i++) {
char orgChar = text.charAt(i);
- MultiByteFont mbFont = (MultiByteFont)tf;
+ MultiByteFont mbFont = (MultiByteFont)typeface;
mbFont.mapChar(orgChar);
int origGlyphIdx = mbFont.findGlyphIndex(orgChar);
int newGlyphIdx = mbFont.getUsedGlyphs().get(origGlyphIdx);
int encoding = newGlyphIdx / 256;
if (encoding != curEncoding) {
if (i != 0) {
- writeText(text, start, i - start, letterSpacing, wordSpacing, dp, font, tf,
+ writeText(text, start, i - start, letterSpacing, wordSpacing, dp, font, typeface,
true);
start = i;
}
@@ -435,8 +438,8 @@ public class PSPainter extends AbstractIFPainter<PSDocumentHandler> {
useFont(fontKey, sizeMillipoints, false);
}
}
- writeText(text, start, textLen - start, letterSpacing, wordSpacing, dp, font, tf,
- tf instanceof MultiByteFont);
+ writeText(text, start, textLen - start, letterSpacing, wordSpacing, dp, font, typeface,
+ typeface instanceof MultiByteFont);
} catch (IOException ioe) {
throw new IFException("I/O error in drawText()", ioe);
}