]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-2994: Support OTF/TTF SVG fonts
authorSimon Steiner <ssteiner@apache.org>
Mon, 11 Jan 2021 15:00:20 +0000 (15:00 +0000)
committerSimon Steiner <ssteiner@apache.org>
Mon, 11 Jan 2021 15:00:20 +0000 (15:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1885366 13f79535-47bb-0310-9956-ffa450edef68

30 files changed:
fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java
fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java
fop-core/src/main/java/org/apache/fop/complexscripts/fonts/OTFAdvancedTypographicTableReader.java
fop-core/src/main/java/org/apache/fop/fonts/CustomFont.java
fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfig.java
fop-core/src/main/java/org/apache/fop/fonts/DefaultFontConfigurator.java
fop-core/src/main/java/org/apache/fop/fonts/EmbedFontInfo.java
fop-core/src/main/java/org/apache/fop/fonts/FontLoader.java
fop-core/src/main/java/org/apache/fop/fonts/LazyFont.java
fop-core/src/main/java/org/apache/fop/fonts/MultiByteFont.java
fop-core/src/main/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
fop-core/src/main/java/org/apache/fop/fonts/truetype/OFFontLoader.java
fop-core/src/main/java/org/apache/fop/fonts/truetype/OFTableName.java
fop-core/src/main/java/org/apache/fop/fonts/truetype/OpenFont.java
fop-core/src/main/java/org/apache/fop/fonts/truetype/SVGGlyphData.java [new file with mode: 0644]
fop-core/src/main/java/org/apache/fop/render/afp/AFPFontConfig.java
fop-core/src/main/java/org/apache/fop/render/intermediate/AbstractIFPainter.java
fop-core/src/main/java/org/apache/fop/render/java2d/ConfiguredFontCollection.java
fop-core/src/main/java/org/apache/fop/render/pdf/PDFPainter.java
fop-core/src/main/java/org/apache/fop/render/ps/PSImageHandlerSVG.java
fop-core/src/main/java/org/apache/fop/render/ps/PSPainter.java
fop-core/src/test/java/org/apache/fop/fonts/DejaVuLGCSerifTestCase.java
fop-core/src/test/java/org/apache/fop/fonts/EmbedFontInfoTestCase.java
fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFToType1TestCase.java
fop-core/src/test/java/org/apache/fop/fonts/truetype/TTFFontLoaderTestCase.java
fop-core/src/test/java/org/apache/fop/fonts/type1/Type1FontLoaderTestCase.java
fop-core/src/test/java/org/apache/fop/pdf/PDFFactoryTestCase.java
fop-core/src/test/java/org/apache/fop/render/pdf/PDFPainterTestCase.java
fop-core/src/test/java/org/apache/fop/render/ps/PSPainterTestCase.java
fop-core/src/test/java/org/apache/fop/svg/font/FontInfoBuilder.java

index ffb92b0276fb143628934c1427a68bdad16bfab7..159efe4aab56e9a8f07e2feccdc23d779170672e 100644 (file)
@@ -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;
index f125dc6a37290315f7f921147f5a2fa37e93e583..642b76f575c26e4f1043b056a5815c85185c5089 100644 (file)
@@ -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)
index 4b319f1c1ec26300bd79cdb567bf70233118e968..0607f998e7208147f91f6b135712560ac3197a19 100644 (file)
@@ -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;
     }
 
index 2b659f512daa6f8f3be933a51dd2a84c6053c8d5..cd026e1621a01e05f4fdb9ac0e341f7e855ae101 100644 (file)
@@ -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;
+    }
 }
index a1663756c6afa7527375d83a5505953089ab28b8..2b67dbd2e0b85a63131c7d22e1353cdc9fae6568 100644 (file)
@@ -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;
+        }
     }
 }
index c8d1c00e274ce827800b61bcc8e7b2b6de39b8c3..6e8c493cd93d8fdfc185ec27ac7db16d3b70193f 100644 (file)
@@ -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);
index 186f098fde8f04cb86bc7b7c27bf0ca3f30a2090..27a0a4db28c778232455488ce682f48ac226388c 100644 (file)
@@ -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();
index 06907f4035526f5014410b3c8a04228b46316c42..1e3d4092f4a25443fc1a3f56989e98fcfcd4fac8 100644 (file)
@@ -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();
     }
index 7b2d46584f9e3b86f691c54dfbb5c9d9301825f7..753cece8c1ef7fddb3850487ef47a7ccd20ba7ef 100644 (file)
@@ -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;
index 3fd780d4ee5acc161a53fd6975407706010753f9..4f1263ebe992f584ba8e7144a5b0245f5e4eca68 100644 (file)
@@ -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);
+    }
 }
 
index e14bb0123adabbbed4e5fc6b0531784d44825676..9e8d9e5dbc05f8ac8cd5a786cefd55d38a3e9299 100644 (file)
@@ -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);
                 }
index 0634957debf465d7372f28cc02b2595edf7e425d..895b798f7138f688b6fc996724eaae51b54470f7 100644 (file)
@@ -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);
index f6264129aebd4f524db5e1c199849ef2fa4956ab..29d0f78ee2350ac19134f745325c839b6bfbfd7c 100644 (file)
@@ -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) {
index 5076e306480c386faf801637c401838435a07c8a..0d10129f016f0167d302d8f61b8684ee55affa81 100644 (file)
@@ -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 (file)
index 0000000..e46e500
--- /dev/null
@@ -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();
+    }
+}
index 0967bd1f8fc475f6f429458e3e31cc20b3f8a7ea..eb6c4a77f0c2515bd5d49c1722407def35a180fe 100644 (file)
@@ -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,
index 45996a2f429698e3361a740b3aa4ad090095b0b3..44620ff6110a0e675908914b4ca9ca5d2da4d3c5 100644 (file)
@@ -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);
+        }
+    }
 }
index e494ed65cc81f3ebf4d6728796e9ddb00a077bf3..d019f352a91c5cbcf065f8b4eb284113bc22e299 100644 (file)
@@ -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);
                 }
 
index 985e587cbb7367cef72e9505fd95c0785a10d362..cae8973ace3505daee3ff01a03f566ebddfb699b 100644 (file)
@@ -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 {
index b034fa79ee6f1fe7be185c18b85849c2e20d2089..9c0a9028674a7a33b11438aaa59fda08eb2aa3c0 100644 (file)
@@ -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());
     }
 
index 34f57e42d6ea941b6d816d836936381cab4ebdf6..a7f0f455fe0fc890c9ce01a953682b000b014c2c 100644 (file)
@@ -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);
         }
index f692a56b4b3f2a1e97aa870f1cddc0f0f9d63972..bf3da20c1e5e3eed717d4429f4f1bc77bd89fe83 100644 (file)
@@ -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);
     }
 
     /**
index 9e0a7f1b0182299283dd92a49382835dda142383..2fb366536bc3059916947ad49b8b17f97a94c576 100644 (file)
@@ -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
index 9194d16c7a3789b2ab938133ac90572802938c0d..a3d86763fbf68fa6171860805a39cee779ce7602 100644 (file)
@@ -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;
     }
index 5201edba1551096649c501c2dd9685e4e51b653e..e291b8e88671062eff67574e61195501a19568d2 100644 (file)
@@ -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());
     }
 }
index 84b0b1ab14ddb2913cb7396f46aa745deb383e0a..db8d4a63922e4b00e11965c6af38b2963f783ac5 100644 (file)
@@ -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();
index ddbe63ee4ec4c4d143a39aaec2fde81e42cd2804..f7f8e26d156b14114c5f8bf8429c36e342e354f0 100644 (file)
@@ -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);
         }
index d0a29abcdc1ac2adc48a61aecd9f9d3268e8824c..aa0274d977720aee15e4bd47a6220f51b65c8479 100644 (file)
@@ -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"));
+    }
 }
index 7cc0fd7af188a63ab675ccfcd94a381053d300e8..f5754235e83f612757013a1cb1c207503f533d00 100644 (file)
@@ -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"));
+    }
 }
index 255bc19ed203142cbdcb2d6ac1e6ae3d361695a2..57428fbeeb6e040817125519282dd395a7954a7e 100644 (file)
@@ -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;