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<Typeface, PCLFontReader> fontReaderMap;
}
public ByteArrayOutputStream makeSoftFont(Typeface font, String text) throws IOException {
- List<Map<Character, Integer>> mappedGlyphs = mapFontGlyphs(font);
if (!fontReaderMap.containsKey(font)) {
fontReaderMap.put(font, PCLFontReaderFactory.createInstance(font));
}
fontReader = fontReaderMap.get(font);
+ List<Map<Character, Integer>> mappedGlyphs = mapFontGlyphs(font);
if (mappedGlyphs.isEmpty()) {
mappedGlyphs.add(new HashMap<Character, Integer>());
}
return f;
}
- private List<Map<Character, Integer>> mapFontGlyphs(Typeface tf) {
+ private List<Map<Character, Integer>> mapFontGlyphs(Typeface tf) throws IOException {
List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>();
if (tf instanceof CustomFontMetricsMapper) {
CustomFontMetricsMapper fontMetrics = (CustomFontMetricsMapper) tf;
return mappedGlyphs;
}
- private List<Map<Character, Integer>> mapGlyphs(Map<Integer, Integer> usedGlyphs, CustomFont font) {
+ private List<Map<Character, Integer>> mapGlyphs(Map<Integer, Integer> usedGlyphs, CustomFont font)
+ throws IOException {
int charCount = 32;
+ int charCountComposite = 32;
List<Map<Character, Integer>> mappedGlyphs = new ArrayList<Map<Character, Integer>>();
Map<Character, Integer> fontGlyphs = new HashMap<Character, Integer>();
+ Map<Character, Integer> fontGlyphsComposite = new HashMap<Character, Integer>();
for (Entry<Integer, Integer> entry : usedGlyphs.entrySet()) {
int glyphID = entry.getKey();
if (glyphID == 0) {
charCount = 32;
fontGlyphs = new HashMap<Character, Integer>();
}
- 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<OFMtxEntry> mtx = fontReader.getFontFile().getMtx();
+ Map<Integer, Integer> subsetGlyphs = customFont.getUsedGlyphs();
+ GlyfTable glyfTable = new GlyfTable(fontReader.getFontFileReader(), mtx.toArray(new OFMtxEntry[mtx.size()]),
+ glyfTableInfo, subsetGlyphs);
+ Map<Integer, Integer> 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));
}
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();
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;
}
private void writeTrueTypeTable(ByteArrayOutputStream baos, OFTableName table,
- List<TableOffset> tableOffsets) throws IOException, UnsupportedEncodingException {
+ List<TableOffset> tableOffsets) throws IOException {
OFDirTabEntry tabEntry = ttfFont.getDirectoryEntry(table);
if (tabEntry != null) {
baos.write(tabEntry.getTag());
}
}
- 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
return (int) sum;
}
- protected byte[] createHmtx(Map<Character, Integer> mappedGlyphs) throws IOException {
+ protected byte[] createHmtx(Map<Character, Integer> mappedGlyphs) {
byte[] hmtxTable = new byte[((mappedGlyphs.size() + 32) * 4)];
OFDirTabEntry entry = ttfFont.getDirectoryEntry(OFTableName.HMTX);
-
if (entry != null) {
for (Entry<Character, Integer> 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);
}
}
}
--- /dev/null
+/*
+ * 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);
+ }
+}