diff options
author | Simon Steiner <ssteiner@apache.org> | 2020-10-14 11:10:16 +0000 |
---|---|---|
committer | Simon Steiner <ssteiner@apache.org> | 2020-10-14 11:10:16 +0000 |
commit | c1a6088b2ad360cf85128ef6c106b09d6a050e5c (patch) | |
tree | f91e1ba778e44995db6b6bd05df053a78699c898 | |
parent | bb1feeb8e2c231883fa77290b1d5826906379a23 (diff) | |
download | xmlgraphics-fop-c1a6088b2ad360cf85128ef6c106b09d6a050e5c.tar.gz xmlgraphics-fop-c1a6088b2ad360cf85128ef6c106b09d6a050e5c.zip |
FOP-2978: Include composite glyphs in otf subset
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1882485 13f79535-47bb-0310-9956-ffa450edef68
3 files changed, 75 insertions, 7 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java index 7884fff85..6f8e948dd 100644 --- a/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java +++ b/fop-core/src/main/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java @@ -37,6 +37,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.cff.CFFStandardString; +import org.apache.fontbox.cff.CFFType1Font; +import org.apache.fontbox.cff.CharStringCommand; +import org.apache.fontbox.cff.Type2CharString; import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.fonts.cff.CFFDataReader; @@ -46,6 +49,7 @@ import org.apache.fop.fonts.cff.CFFDataReader.FDSelect; import org.apache.fop.fonts.cff.CFFDataReader.FontDict; import org.apache.fop.fonts.cff.CFFDataReader.Format0FDSelect; import org.apache.fop.fonts.cff.CFFDataReader.Format3FDSelect; +import org.apache.fop.fonts.type1.AdobeStandardEncoding; /** * Reads an OpenType CFF file and generates a subset @@ -105,6 +109,9 @@ public class OTFSubSetFile extends OTFSubSetWriter { private static final int LOCAL_SUBROUTINE = 10; /** The operator used to identify a global subroutine reference */ private static final int GLOBAL_SUBROUTINE = 29; + + private static final String ACCENT_CMD = "seac"; + /** The parser used to parse type2 charstring */ private Type2Parser type2Parser; @@ -129,20 +136,41 @@ public class OTFSubSetFile extends OTFSubSetWriter { Map<Integer, Integer> usedGlyphs) throws IOException { this.mbFont = mbFont; fontFile = in; - this.embeddedName = embeddedName; - - //Sort by the new GID and store in a LinkedHashMap - subsetGlyphs = sortByValue(usedGlyphs); - initializeFont(in); - cffReader = new CFFDataReader(fontFile); - + mapChars(usedGlyphs); + //Sort by the new GID and store in a LinkedHashMap + subsetGlyphs = sortByValue(usedGlyphs); //Create the CIDFontType0C data createCFF(); } + private void mapChars(Map<Integer, Integer> usedGlyphs) throws IOException { + if (fileFont instanceof CFFType1Font) { + CFFType1Font cffType1Font = (CFFType1Font) fileFont; + subsetGlyphs = sortByValue(usedGlyphs); + for (int gid : subsetGlyphs.keySet()) { + Type2CharString type2CharString = cffType1Font.getType2CharString(gid); + List<Number> stack = new ArrayList<Number>(); + for (Object obj : type2CharString.getType1Sequence()) { + if (obj instanceof CharStringCommand) { + String name = CharStringCommand.TYPE1_VOCABULARY.get(((CharStringCommand) obj).getKey()); + if (ACCENT_CMD.equals(name)) { + int first = stack.get(3).intValue(); + int second = stack.get(4).intValue(); + mbFont.mapChar(AdobeStandardEncoding.getUnicodeFromCodePoint(first)); + mbFont.mapChar(AdobeStandardEncoding.getUnicodeFromCodePoint(second)); + } + stack.clear(); + } else { + stack.add((Number) obj); + } + } + } + } + } + private Map<Integer, Integer> sortByValue(Map<Integer, Integer> map) { List<Entry<Integer, Integer>> list = new ArrayList<Entry<Integer, Integer>>(map.entrySet()); Collections.sort(list, new Comparator<Entry<Integer, Integer>>() { diff --git a/fop-core/src/main/java/org/apache/fop/fonts/type1/AdobeStandardEncoding.java b/fop-core/src/main/java/org/apache/fop/fonts/type1/AdobeStandardEncoding.java index c6dc91dc8..1738cbf65 100644 --- a/fop-core/src/main/java/org/apache/fop/fonts/type1/AdobeStandardEncoding.java +++ b/fop-core/src/main/java/org/apache/fop/fonts/type1/AdobeStandardEncoding.java @@ -416,4 +416,13 @@ public enum AdobeStandardEncoding { } return ""; } + + public static char getUnicodeFromCodePoint(int codePoint) { + for (AdobeStandardEncoding encoding : CACHE.values()) { + if (encoding.getAdobeCodePoint() == codePoint) { + return (char) encoding.getUnicodeIndex(); + } + } + return (char) -1; + } } diff --git a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java index fef8ce114..57d5d0f46 100644 --- a/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/fonts/truetype/OTFSubSetFileTestCase.java @@ -21,6 +21,7 @@ package org.apache.fop.fonts.truetype; import java.io.ByteArrayInputStream; import java.io.DataInputStream; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -42,6 +43,9 @@ import static org.mockito.Mockito.when; import org.apache.fontbox.cff.CFFFont; import org.apache.fontbox.cff.CFFParser; +import org.apache.fontbox.cff.CFFType1Font; +import org.apache.fontbox.cff.CharStringCommand; +import org.apache.fontbox.cff.Type2CharString; import org.apache.fop.fonts.MultiByteFont; import org.apache.fop.fonts.cff.CFFDataReader; @@ -699,4 +703,31 @@ public class OTFSubSetFileTestCase extends OTFFileTestCase { Assert.assertEquals(fontSubset.read(), 248); Assert.assertEquals(fontSubset.read(), (byte)(390 - 108)); } + + @Test + public void testCompositeGlyphMapping() throws IOException { + glyphs.clear(); + glyphs.put(0, 0); + OTFSubSetFile sourceSansSubset = new OTFSubSetFile() { + protected void initializeFont(FontFileReader in) { + fileFont = new CFFType1Font() { + List<Object> sequence = Arrays.asList(0, 0, 0, (int)'a', (int)'b', new CharStringCommand(12, 6)); + public Type2CharString getType2CharString(int gid) { + return new Type2CharString(null, null, null, 0, sequence, 0, 0); + } + }; + } + }; + MultiByteFont multiByteFont = new MultiByteFont(null, null) { + public void setEmbedResourceName(String name) { + super.setEmbedResourceName(name); + addPrivateUseMapping('a', 'a'); + addPrivateUseMapping('b', 'b'); + } + }; + multiByteFont.setEmbedURI(new File(".").toURI()); + multiByteFont.setEmbedResourceName(""); + sourceSansSubset.readFont(sourceSansReader, "SourceSansProBold", multiByteFont, glyphs); + Assert.assertEquals(multiByteFont.getUsedGlyphs().toString(), "{0=0, 97=1, 98=2}"); + } } |