From bb1feeb8e2c231883fa77290b1d5826906379a23 Mon Sep 17 00:00:00 2001 From: Simon Steiner Date: Fri, 9 Oct 2020 10:21:46 +0000 Subject: FOP-2975: Put composite glyphs to separate font git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1882341 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/render/pcl/fonts/PCLSoftFontManager.java | 43 +++++++++++++++-- .../pcl/fonts/truetype/PCLTTFFontReader.java | 23 ++++----- .../pcl/fonts/PCLSoftFontManagerTestCase.java | 55 ++++++++++++++++++++++ 3 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManagerTestCase.java diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java index 42616581e..410971e38 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManager.java @@ -31,7 +31,12 @@ import java.util.Map.Entry; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.Typeface; +import org.apache.fop.fonts.truetype.GlyfTable; +import org.apache.fop.fonts.truetype.OFDirTabEntry; +import org.apache.fop.fonts.truetype.OFMtxEntry; +import org.apache.fop.fonts.truetype.OFTableName; import org.apache.fop.render.java2d.CustomFontMetricsMapper; +import org.apache.fop.util.CharUtilities; public class PCLSoftFontManager { private Map fontReaderMap; @@ -45,11 +50,11 @@ public class PCLSoftFontManager { } public ByteArrayOutputStream makeSoftFont(Typeface font, String text) throws IOException { - List> mappedGlyphs = mapFontGlyphs(font); if (!fontReaderMap.containsKey(font)) { fontReaderMap.put(font, PCLFontReaderFactory.createInstance(font)); } fontReader = fontReaderMap.get(font); + List> mappedGlyphs = mapFontGlyphs(font); if (mappedGlyphs.isEmpty()) { mappedGlyphs.add(new HashMap()); } @@ -95,7 +100,7 @@ public class PCLSoftFontManager { return f; } - private List> mapFontGlyphs(Typeface tf) { + private List> mapFontGlyphs(Typeface tf) throws IOException { List> mappedGlyphs = new ArrayList>(); if (tf instanceof CustomFontMetricsMapper) { CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) tf; @@ -105,10 +110,13 @@ public class PCLSoftFontManager { return mappedGlyphs; } - private List> mapGlyphs(Map usedGlyphs, CustomFont font) { + private List> mapGlyphs(Map usedGlyphs, CustomFont font) + throws IOException { int charCount = 32; + int charCountComposite = 32; List> mappedGlyphs = new ArrayList>(); Map fontGlyphs = new HashMap(); + Map fontGlyphsComposite = new HashMap(); for (Entry entry : usedGlyphs.entrySet()) { int glyphID = entry.getKey(); if (glyphID == 0) { @@ -120,14 +128,38 @@ public class PCLSoftFontManager { charCount = 32; fontGlyphs = new HashMap(); } - fontGlyphs.put(unicode, charCount++); + if (isComposite(font, unicode)) { + fontGlyphsComposite.put(unicode, charCountComposite++); + } else { + fontGlyphs.put(unicode, charCount++); + } } if (fontGlyphs.size() > 0) { mappedGlyphs.add(fontGlyphs); } + if (fontGlyphsComposite.size() > 0) { + mappedGlyphs.add(fontGlyphsComposite); + } return mappedGlyphs; } + private boolean isComposite(CustomFont customFont, int unicode) throws IOException { + OFDirTabEntry glyfTableInfo = fontReader.getFontFile().getDirectoryEntry(OFTableName.GLYF); + if (glyfTableInfo == null) { + return false; + } + List mtx = fontReader.getFontFile().getMtx(); + Map subsetGlyphs = customFont.getUsedGlyphs(); + GlyfTable glyfTable = new GlyfTable(fontReader.getFontFileReader(), mtx.toArray(new OFMtxEntry[mtx.size()]), + glyfTableInfo, subsetGlyphs); + Map mtxCharacters = fontReader.scanMtxCharacters(); + if (mtxCharacters.containsKey(unicode)) { + int mtxChar = mtxCharacters.get(unicode); + return glyfTable.isComposite(mtxChar); + } + return false; + } + private void writeFontID(int fontID, OutputStream os) throws IOException { os.write(assignFontID(fontID)); } @@ -256,6 +288,9 @@ public class PCLSoftFontManager { int curFontID = -1; String current = ""; for (char ch : text.toCharArray()) { + if (ch == CharUtilities.NBSPACE) { + ch = ' '; + } for (PCLSoftFont softFont : fonts) { if (curFontID == -1) { curFontID = softFont.getFontID(); diff --git a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java index 6b2fc23d2..f578a9b26 100644 --- a/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java +++ b/fop-core/src/main/java/org/apache/fop/render/pcl/fonts/truetype/PCLTTFFontReader.java @@ -22,7 +22,6 @@ package org.apache.fop.render.pcl.fonts.truetype; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -553,7 +552,7 @@ public class PCLTTFFontReader extends PCLFontReader { } private void writeTrueTypeTable(ByteArrayOutputStream baos, OFTableName table, - List tableOffsets) throws IOException, UnsupportedEncodingException { + List tableOffsets) throws IOException { OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(table); if (tabEntry != null) { baos.write(tabEntry.getTag()); @@ -566,7 +565,7 @@ public class PCLTTFFontReader extends PCLFontReader { } } - private void writeGDIR(ByteArrayOutputStream baos) throws UnsupportedEncodingException, IOException { + private void writeGDIR(ByteArrayOutputStream baos) throws IOException { baos.write("gdir".getBytes("ISO-8859-1")); baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Checksum baos.write(PCLByteWriterUtil.unsignedLongInt(0)); // Offset @@ -695,28 +694,24 @@ public class PCLTTFFontReader extends PCLFontReader { return (int) sum; } - protected byte[] createHmtx(Map mappedGlyphs) throws IOException { + protected byte[] createHmtx(Map mappedGlyphs) { byte[] hmtxTable = new byte[((mappedGlyphs.size() + 32) * 4)]; OFDirTabEntry entry = ttfFont.getDirectoryEntry(OFTableName.HMTX); - if (entry != null) { for (Entry glyphSubset : mappedGlyphs.entrySet()) { char unicode = glyphSubset.getKey(); - int originalIndex = 0; int softFontGlyphIndex = glyphSubset.getValue(); if (font instanceof MultiByteFont) { - originalIndex = ((MultiByteFont) font).getGIDFromChar(unicode); - - writeUShort(hmtxTable, (softFontGlyphIndex) * 4, + int originalIndex = ((MultiByteFont) font).getGIDFromChar(unicode); + writeUShort(hmtxTable, softFontGlyphIndex * 4, ttfFont.getMtx().get(originalIndex).getWx()); - writeUShort(hmtxTable, (softFontGlyphIndex) * 4 + 2, + writeUShort(hmtxTable, softFontGlyphIndex * 4 + 2, ttfFont.getMtx().get(originalIndex).getLsb()); } else { - originalIndex = ((SingleByteFont) font).getGIDFromChar(unicode); - - writeUShort(hmtxTable, (softFontGlyphIndex) * 4, + int originalIndex = ((SingleByteFont) font).getGIDFromChar(unicode); + writeUShort(hmtxTable, softFontGlyphIndex * 4, font.getWidth(originalIndex, 1)); - writeUShort(hmtxTable, (softFontGlyphIndex) * 4 + 2, 0); + writeUShort(hmtxTable, softFontGlyphIndex * 4 + 2, 0); } } } diff --git a/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManagerTestCase.java b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManagerTestCase.java new file mode 100644 index 000000000..e52fed673 --- /dev/null +++ b/fop-core/src/test/java/org/apache/fop/render/pcl/fonts/PCLSoftFontManagerTestCase.java @@ -0,0 +1,55 @@ +/* + * 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.render.pcl.fonts; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.net.URI; +import java.util.HashMap; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.fonts.CMapSegment; +import org.apache.fop.fonts.EmbeddingMode; +import org.apache.fop.fonts.FontType; +import org.apache.fop.fonts.MultiByteFont; +import org.apache.fop.render.java2d.CustomFontMetricsMapper; + +public class PCLSoftFontManagerTestCase { + @Test + public void testSplitCompositeGlyphs() throws Exception { + FOUserAgent ua = FopFactory.newInstance(new File(".").toURI()).newFOUserAgent(); + PCLSoftFontManager pclSoftFontManager = new PCLSoftFontManager(new HashMap()); + MultiByteFont mbf = new MultiByteFont(ua.getResourceResolver(), EmbeddingMode.SUBSET); + mbf.setEmbedURI(new URI("test/resources/fonts/ttf/DejaVuLGCSerif.ttf")); + mbf.setFontType(FontType.TRUETYPE); + CMapSegment cMapSegment1 = new CMapSegment('a', 'a', 1); + CMapSegment cMapSegment2 = new CMapSegment('\u00E0', '\u00E0', 2); + mbf.setCMap(new CMapSegment[] {cMapSegment1, cMapSegment2}); + mbf.mapChar('a'); + mbf.mapChar('\u00E0'); + CustomFontMetricsMapper font = new CustomFontMetricsMapper(mbf); + ByteArrayOutputStream bos = pclSoftFontManager.makeSoftFont(font, ""); + String[] fontStrings = bos.toString().split("DejaVu changes are in public domain"); + Assert.assertEquals(fontStrings.length, 3); + } +} -- cgit v1.2.3