diff options
author | Simon Steiner <ssteiner@apache.org> | 2021-01-11 15:00:20 +0000 |
---|---|---|
committer | Simon Steiner <ssteiner@apache.org> | 2021-01-11 15:00:20 +0000 |
commit | a5fa25cf3e6fc98267fe5eaefedf466516c0bc9f (patch) | |
tree | a4c893ea8b018b6d4e56894f117cf505f42b151c | |
parent | 1f2a414bb711508e158f9704cb6b5320cfd848e3 (diff) | |
download | xmlgraphics-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
30 files changed, 355 insertions, 72 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); } diff --git a/fop-core/src/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java index f692a56b4..bf3da20c1 100644 --- a/fop-core/src/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java @@ -49,7 +49,7 @@ public class DejaVuLGCSerifTestCase { File file = new File("test/resources/fonts/ttf/DejaVuLGCSerif.ttf"); FontUris fontUris = new FontUris(file.toURI(), null); font = FontLoader.loadFont(fontUris, "", true, EmbeddingMode.AUTO, EncodingMode.AUTO, - false, false, resolver, false, false); + false, false, resolver, false, false, true); } /** diff --git a/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java index 9e0a7f1b0..2fb366536 100644 --- a/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java @@ -54,7 +54,7 @@ public class EmbedFontInfoTestCase { triplets.add(triplet); FontUris fontUris = new FontUris(embedURI, metricsURI); sut = new EmbedFontInfo(fontUris, kerning, useAdvanced, triplets, subFontName, encMode, - embedMode, false, false); + embedMode, false, false, true); } @Test diff --git a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java index 9194d16c7..a3d86763f 100644 --- a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java +++ b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java @@ -78,7 +78,7 @@ public class OTFToType1TestCase { InternalResourceResolver rr = ResourceResolverFactory.createDefaultInternalResourceResolver( new File(".").toURI()); CustomFont realFont = FontLoader.loadFont(new FontUris(new File(s).toURI(), null), null, true, - EmbeddingMode.SUBSET, EncodingMode.AUTO, true, true, rr, false, true); + EmbeddingMode.SUBSET, EncodingMode.AUTO, true, true, rr, false, true, true); realFont.mapChar('d'); return realFont; } diff --git a/fop-core/src/test/java/org/apache/fop/fonts/truetype/TTFFontLoaderTestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/truetype/TTFFontLoaderTestCase.java index 5201edba1..e291b8e88 100644 --- a/fop-core/src/test/java/org/apache/fop/fonts/truetype/TTFFontLoaderTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/fonts/truetype/TTFFontLoaderTestCase.java @@ -51,12 +51,12 @@ public class TTFFontLoaderTestCase { OFFontLoader fontLoader = new OFFontLoader(absoluteFilePath, fontName, embedded, EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useComplexScriptFeatures, - resourceResolver, false, false); + resourceResolver, false, false, true); assertTrue(fontLoader.getFont().hasKerningInfo()); useKerning = false; fontLoader = new OFFontLoader(absoluteFilePath, fontName, embedded, EmbeddingMode.AUTO, - EncodingMode.AUTO, useKerning, useComplexScriptFeatures, resourceResolver, false, false); + EncodingMode.AUTO, useKerning, useComplexScriptFeatures, resourceResolver, false, false, true); assertFalse(fontLoader.getFont().hasKerningInfo()); } } diff --git a/fop-core/src/test/java/org/apache/fop/fonts/type1/Type1FontLoaderTestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/type1/Type1FontLoaderTestCase.java index 84b0b1ab1..db8d4a639 100644 --- a/fop-core/src/test/java/org/apache/fop/fonts/type1/Type1FontLoaderTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/fonts/type1/Type1FontLoaderTestCase.java @@ -29,6 +29,7 @@ import org.junit.Test; import org.apache.commons.io.IOUtils; +import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbeddingMode; @@ -50,8 +51,10 @@ public class Type1FontLoaderTestCase { fos.close(); FontUris fontUris = new FontUris(pfbNoAFM.toURI(), null, null, pfm.toURI()); + InternalResourceResolver resourceResolver = + ResourceResolverFactory.createDefaultInternalResourceResolver(new File(".").toURI()); CustomFont x = FontLoader.loadFont(fontUris, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, - ResourceResolverFactory.createDefaultInternalResourceResolver(new File(".").toURI()), false, false); + resourceResolver, false, false, true); Assert.assertEquals(x.getBoundingBox(0, 12).getBounds(), new Rectangle(-240, -60, 0, 60)); } finally { pfbNoAFM.delete(); diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java index ddbe63ee4..f7f8e26d1 100644 --- a/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java @@ -144,7 +144,7 @@ public class PDFFactoryTestCase { PDFFactory pdfFactory = new PDFFactory(doc); URI uri = new File("test/resources/fonts/otf/SourceSansProBold.otf").toURI(); CustomFont sb = OFFontLoader.loadFont(new FontUris(uri, null), - null, true, EmbeddingMode.SUBSET, null, false, false, rr, false, false); + null, true, EmbeddingMode.SUBSET, null, false, false, rr, false, false, true); for (char c = 0; c < 512; c++) { sb.mapChar(c); } diff --git a/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java index d0a29abcd..aa0274d97 100644 --- a/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java @@ -25,7 +25,9 @@ import java.awt.Rectangle; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import javax.xml.transform.stream.StreamResult; @@ -49,6 +51,7 @@ import org.apache.fop.fo.Constants; 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.pdf.PDFDocument; import org.apache.fop.pdf.PDFFilterList; import org.apache.fop.pdf.PDFPage; @@ -305,4 +308,37 @@ public class PDFPainterTestCase { + "\n" + "endstream"); } + + @Test + public void testSVGFont() throws IFException, IOException { + FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); + foUserAgent = fopFactory.newFOUserAgent(); + PDFDocumentHandler pdfDocumentHandler = new PDFDocumentHandler(new IFContext(foUserAgent)); + pdfDocumentHandler.setResult(new StreamResult(new ByteArrayOutputStream())); + pdfDocumentHandler.startDocument(); + pdfDocumentHandler.startPage(0, "", "", new Dimension()); + FontInfo fi = new FontInfo(); + fi.addFontProperties("f1", new FontTriplet("a", "normal", 400)); + MultiByteFont font = new MultiByteFont(null, null); + font.setWidthArray(new int[1]); + Map<Integer, SVGGlyphData> svgs = new HashMap<>(); + SVGGlyphData svgGlyph = new SVGGlyphData(); + svgGlyph.setSVG("<svg xmlns=\"http://www.w3.org/2000/svg\">\n" + + "<circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" />\n" + + "</svg>"); + svgs.put(0, svgGlyph); + font.setSVG(svgs); + font.setBBoxArray(new Rectangle[] {new Rectangle()}); + fi.addMetrics("f1", font); + pdfDocumentHandler.setFontInfo(fi); + PDFPainter pdfPainter = new PDFPainter(pdfDocumentHandler, null); + pdfPainter.setFont("a", "normal", 400, null, 12, null); + pdfPainter.drawText(0, 0, 0, 0, null, "test"); + PDFFilterList filters = pdfPainter.generator.getStream().getFilterList(); + filters.setDisableAllFilters(true); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + pdfPainter.generator.getStream().output(bos); + Assert.assertTrue(bos.toString().contains("0.00012 0 0 0.00012 0 0 cm")); + Assert.assertTrue(bos.toString().contains("1 0 0 rg")); + } } diff --git a/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java b/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java index 7cc0fd7af..f5754235e 100644 --- a/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java @@ -17,6 +17,7 @@ package org.apache.fop.render.ps; import java.awt.Color; +import java.awt.Dimension; import java.awt.Rectangle; import java.io.ByteArrayOutputStream; import java.io.File; @@ -54,6 +55,7 @@ import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.fonts.Typeface; +import org.apache.fop.fonts.truetype.SVGGlyphData; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; @@ -242,4 +244,35 @@ public class PSPainterTestCase { mbf.setIsOTFFile(otf); fi.addMetrics(name, mbf); } + + @Test + public void testSVGFont() throws IFException { + FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); + FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); + PSDocumentHandler psDocumentHandler = new PSDocumentHandler(new IFContext(foUserAgent)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + psDocumentHandler.setResult(new StreamResult(bos)); + psDocumentHandler.startDocument(); + psDocumentHandler.startPage(0, "", "", new Dimension()); + FontInfo fi = new FontInfo(); + fi.addFontProperties("f1", new FontTriplet("a", "normal", 400)); + MultiByteFont font = new MultiByteFont(null, null); + font.setWidthArray(new int[1]); + Map<Integer, SVGGlyphData> svgs = new HashMap<>(); + SVGGlyphData svgGlyph = new SVGGlyphData(); + svgGlyph.setSVG("<svg xmlns=\"http://www.w3.org/2000/svg\">\n" + + "<circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" />\n" + + "</svg>"); + svgs.put(0, svgGlyph); + font.setSVG(svgs); + font.setBBoxArray(new Rectangle[] {new Rectangle()}); + fi.addMetrics("f1", font); + psDocumentHandler.setFontInfo(fi); + PSPainter psPainter = new PSPainter(psDocumentHandler); + psPainter.setFont("a", "normal", 400, null, 12, Color.black); + psPainter.drawText(0, 0, 0, 0, null, "test"); + Assert.assertTrue(bos.toString().contains("%FOPBeginSVG")); + Assert.assertTrue(bos.toString().contains("[0.00012 0 0 0.00012 0 0] CT")); + Assert.assertTrue(bos.toString().contains("1 0 0 RC")); + } } diff --git a/fop-core/src/test/java/org/apache/fop/svg/font/FontInfoBuilder.java b/fop-core/src/test/java/org/apache/fop/svg/font/FontInfoBuilder.java index 255bc19ed..57428fbee 100644 --- a/fop-core/src/test/java/org/apache/fop/svg/font/FontInfoBuilder.java +++ b/fop-core/src/test/java/org/apache/fop/svg/font/FontInfoBuilder.java @@ -83,7 +83,7 @@ class FontInfoBuilder { URI baseURI = new File("test/resources/fonts/ttf").toURI(); InternalResourceResolver resolver = ResourceResolverFactory.createDefaultInternalResourceResolver(baseURI); OFFontLoader fontLoader = new OFFontLoader(new URI(filename), null, true, - EmbeddingMode.AUTO, EncodingMode.AUTO, true, useAdvanced, resolver, false, false); + EmbeddingMode.AUTO, EncodingMode.AUTO, true, useAdvanced, resolver, false, false, true); FontMetrics font = fontLoader.getFont(); registerFont(font, "F" + fontKey++, fontName); return this; |