From aa504376af2246e39fd854ffa0cf5ada4cf9d566 Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Sun, 22 Apr 2018 23:35:27 +0530 Subject: [PATCH 1/9] defined model for gsub-data --- .../fontbox/ttf/GlyphSubstitutionTable.java | 10 +- .../org/apache/fontbox/ttf/TrueTypeFont.java | 11 +- .../gsub/GlyphSubstitutionDataExtractor.java | 60 ++++++++-- .../ttf/gsub/GsubWorkerForBengali.java | 25 ++-- .../apache/fontbox/ttf/model/GsubData.java | 81 +++++++++++++ .../apache/fontbox/ttf/model/Language.java | 50 ++++++++ .../fontbox/ttf/model/MapBackedGsubData.java | 82 +++++++++++++ .../ttf/model/MapBackedScriptFeature.java | 109 ++++++++++++++++++ .../fontbox/ttf/model/ScriptFeature.java | 42 +++++++ .../ttf/GlyphSubstitutionTableTest.java | 17 +-- .../pdfbox/pdmodel/PDPageContentStream.java | 18 ++- .../pdfbox/pdmodel/font/PDType0Font.java | 14 +-- 12 files changed, 461 insertions(+), 58 deletions(-) create mode 100644 fontbox/src/main/java/org/apache/fontbox/ttf/model/GsubData.java create mode 100644 fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java create mode 100644 fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedGsubData.java create mode 100644 fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedScriptFeature.java create mode 100644 fontbox/src/main/java/org/apache/fontbox/ttf/model/ScriptFeature.java diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphSubstitutionTable.java b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphSubstitutionTable.java index bdb8adc91e1..bc54f21706f 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphSubstitutionTable.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphSubstitutionTable.java @@ -31,6 +31,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.ttf.gsub.GlyphSubstitutionDataExtractor; +import org.apache.fontbox.ttf.model.GsubData; import org.apache.fontbox.ttf.table.common.CoverageTable; import org.apache.fontbox.ttf.table.common.CoverageTableFormat1; import org.apache.fontbox.ttf.table.common.CoverageTableFormat2; @@ -72,7 +73,7 @@ public class GlyphSubstitutionTable extends TTFTable private String lastUsedSupportedScript; - private Map, Integer>> rawGSubData; + private GsubData gsubData; GlyphSubstitutionTable(TrueTypeFont font) { @@ -103,9 +104,8 @@ void read(TrueTypeFont ttf, TTFDataStream data) throws IOException GlyphSubstitutionDataExtractor glyphSubstitutionDataExtractor = new GlyphSubstitutionDataExtractor(); - rawGSubData = glyphSubstitutionDataExtractor + gsubData = glyphSubstitutionDataExtractor .getGsubData(scriptList, featureListTable, lookupListTable); - LOG.debug("rawGSubData: " + rawGSubData); } private Map readScriptList(TTFDataStream data, long offset) @@ -670,9 +670,9 @@ public int getUnsubstitution(int sgid) return gid; } - public Map, Integer>> getRawGSubData() + public GsubData getGsubData() { - return rawGSubData; + return gsubData; } private RangeRecord readRangeRecord(TTFDataStream data) throws IOException diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java index 8edcc6188a2..948c1367448 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java @@ -27,11 +27,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.fontbox.FontBoxFont; -import org.apache.fontbox.util.BoundingBox; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fontbox.FontBoxFont; +import org.apache.fontbox.ttf.model.GsubData; +import org.apache.fontbox.util.BoundingBox; /** * A TrueType font file. @@ -654,15 +655,15 @@ public int nameToGID(String name) throws IOException return 0; } - public Map, Integer>> getGlyphSubstitutionMap() throws IOException + public GsubData getGsubData() throws IOException { GlyphSubstitutionTable table = getGsub(); if (table == null) { - return Collections.emptyMap(); + return GsubData.NO_DATA_FOUND; } - return table.getRawGSubData(); + return table.getGsubData(); } /** diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GlyphSubstitutionDataExtractor.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GlyphSubstitutionDataExtractor.java index 7fb2c0eeaaa..6eaec7b02c6 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GlyphSubstitutionDataExtractor.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GlyphSubstitutionDataExtractor.java @@ -26,6 +26,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fontbox.ttf.model.GsubData; +import org.apache.fontbox.ttf.model.Language; +import org.apache.fontbox.ttf.model.MapBackedGsubData; import org.apache.fontbox.ttf.table.common.CoverageTable; import org.apache.fontbox.ttf.table.common.FeatureListTable; import org.apache.fontbox.ttf.table.common.FeatureRecord; @@ -52,19 +55,19 @@ public class GlyphSubstitutionDataExtractor private static final Log LOG = LogFactory.getLog(GlyphSubstitutionDataExtractor.class); - private static final String[] SUPPORTED_LANGUAGES = { "bng2", "beng" }; - - public Map, Integer>> getGsubData(Map scriptList, + public GsubData getGsubData(Map scriptList, FeatureListTable featureListTable, LookupListTable lookupListTable) { - ScriptTable scriptTable = getSupportedLanguage(scriptList); + ScriptTableDetails scriptTableDetails = getSupportedLanguage(scriptList); - if (scriptTable == null) + if (scriptTableDetails == null) { - return Collections.emptyMap(); + return GsubData.NO_DATA_FOUND; } + ScriptTable scriptTable = scriptTableDetails.getScriptTable(); + Map, Integer>> gsubData = new LinkedHashMap<>(); // the starting point is really the scriptTags if (scriptTable.getDefaultLangSysTable() != null) @@ -76,16 +79,21 @@ public Map, Integer>> getGsubData(Map scriptList) + private ScriptTableDetails getSupportedLanguage(Map scriptList) { - for (String supportedLanguage : SUPPORTED_LANGUAGES) + for (Language lang : Language.values()) { - if (scriptList.containsKey(supportedLanguage)) + for (String scriptName : lang.getScriptNames()) { - return scriptList.get(supportedLanguage); + if (scriptList.containsKey(scriptName)) + { + return new ScriptTableDetails(lang, scriptName, scriptList.get(scriptName)); + } } } return null; @@ -232,4 +240,34 @@ private void putNewSubstitutionEntry(Map, Integer> glyphSubstituti } } + private static class ScriptTableDetails + { + private final Language language; + private final String featureName; + private final ScriptTable scriptTable; + + private ScriptTableDetails(Language language, String featureName, ScriptTable scriptTable) + { + this.language = language; + this.featureName = featureName; + this.scriptTable = scriptTable; + } + + public Language getLanguage() + { + return language; + } + + public String getFeatureName() + { + return featureName; + } + + public ScriptTable getScriptTable() + { + return scriptTable; + } + + } + } diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java index d44ba3a5078..c51b9eacff5 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java @@ -21,11 +21,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.ttf.CmapLookup; +import org.apache.fontbox.ttf.model.GsubData; +import org.apache.fontbox.ttf.model.ScriptFeature; /** * @@ -49,14 +50,13 @@ public class GsubWorkerForBengali implements GsubWorker private static final char[] BEFORE_HALF_CHARS = new char[] { '\u09BF', '\u09C7', '\u09C8' }; - private final Map, Integer>> glyphSubstitutionMap; + private final GsubData gsubData; private final List beforeHalfGlyphIds; - public GsubWorkerForBengali(CmapLookup cmapLookup, - Map, Integer>> glyphSubstitutionMap) + public GsubWorkerForBengali(CmapLookup cmapLookup, GsubData gsubData) { - this.glyphSubstitutionMap = glyphSubstitutionMap; + this.gsubData = gsubData; beforeHalfGlyphIds = getBeforeHalfGlyphIds(cmapLookup); } @@ -67,7 +67,7 @@ public List substituteGlyphs(List originalGlyphIds) for (String feature : FEATURES_IN_ORDER) { - if (!glyphSubstitutionMap.containsKey(feature)) + if (!gsubData.isFeatureSupported(feature)) { LOG.debug("the feature " + feature + " was not found"); continue; @@ -75,9 +75,10 @@ public List substituteGlyphs(List originalGlyphIds) LOG.debug("applying the feature " + feature); - Map, Integer> featureMap = glyphSubstitutionMap.get(feature); + ScriptFeature scriptFeature = gsubData.getFeature(feature); - intermediateGlyphsFromGsub = applyGsubFeature(featureMap, intermediateGlyphsFromGsub); + intermediateGlyphsFromGsub = applyGsubFeature(scriptFeature, + intermediateGlyphsFromGsub); } return intermediateGlyphsFromGsub; @@ -101,12 +102,12 @@ public List repositionGlyphs(List originalGlyphIds) return repositionedGlyphIds; } - private List applyGsubFeature(Map, Integer> featureMap, + private List applyGsubFeature(ScriptFeature scriptFeature, List originalGlyphs) { GlyphArraySplitter glyphArraySplitter = new GlyphArraySplitterRegexImpl( - featureMap.keySet()); + scriptFeature.getAllGlyphIdsForSubstitution()); List> tokens = glyphArraySplitter.split(originalGlyphs); @@ -114,10 +115,10 @@ private List applyGsubFeature(Map, Integer> featureMap, for (List chunk : tokens) { - if (featureMap.containsKey(chunk)) + if (scriptFeature.canReplaceGlyphs(chunk)) { // gsub system kicks in, you get the glyphId directly - int glyphId = featureMap.get(chunk); + int glyphId = scriptFeature.getReplacementForGlyphs(chunk); gsubProcessedGlyphs.add(glyphId); } else diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/model/GsubData.java b/fontbox/src/main/java/org/apache/fontbox/ttf/model/GsubData.java new file mode 100644 index 00000000000..8e7c45c4e8f --- /dev/null +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/model/GsubData.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package org.apache.fontbox.ttf.model; + +import java.util.Set; + +/** + * Model for data from the GSUB tables + * + * @author Palash Ray + * + */ +public interface GsubData +{ + /** + * To be used when there is no GSUB data available + */ + GsubData NO_DATA_FOUND = new GsubData() + { + + @Override + public boolean isFeatureSupported(String featureName) + { + throw new UnsupportedOperationException(); + } + + @Override + public Language getLanguage() + { + throw new UnsupportedOperationException(); + } + + @Override + public ScriptFeature getFeature(String featureName) + { + throw new UnsupportedOperationException(); + } + + @Override + public String getActiveScriptName() + { + throw new UnsupportedOperationException(); + } + + @Override + public Set getSupportedFeatures() + { + throw new UnsupportedOperationException(); + } + }; + + Language getLanguage(); + + /** + * A {@link Language} can have more than one script that is supported. However, at any given point, only one of the + * many scripts are active. This method returns the name of the script that is active. + */ + String getActiveScriptName(); + + boolean isFeatureSupported(String featureName); + + ScriptFeature getFeature(String featureName); + + Set getSupportedFeatures(); + +} diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java b/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java new file mode 100644 index 00000000000..e5fe482d8c4 --- /dev/null +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java @@ -0,0 +1,50 @@ +/* + * 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. + */ + +package org.apache.fontbox.ttf.model; + +import org.apache.fontbox.ttf.table.common.ScriptRecord; + +/** + * Enumerates the languages supported for GSUB operation + * + * @author Palash Ray + * + */ +public enum Language +{ + + BENGALI(new String[] { "bng2", "beng" }); + + private final String[] scriptNames; + + private Language(String[] scriptNames) + { + this.scriptNames = scriptNames; + } + + /** + * ScriptNames form the basis of identification of the language. This method gets the ScriptNames that the given + * Language supports, in the order of preference, Index 0 being the most preferred. These names should match the + * {@link ScriptRecord} in the GSUB system. + */ + public String[] getScriptNames() + { + return scriptNames; + } + +} diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedGsubData.java b/fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedGsubData.java new file mode 100644 index 00000000000..a795588caa3 --- /dev/null +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedGsubData.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.fontbox.ttf.model; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * + * A {@link Map} based simple implementation of the {@link GsubData} + * + * @author Palash Ray + * + */ +public class MapBackedGsubData implements GsubData +{ + + private final Language language; + private final String activeScriptName; + private final Map, Integer>> glyphSubstitutionMap; + + public MapBackedGsubData(Language language, String activeScriptName, + Map, Integer>> glyphSubstitutionMap) + { + this.language = language; + this.activeScriptName = activeScriptName; + this.glyphSubstitutionMap = glyphSubstitutionMap; + } + + @Override + public Language getLanguage() + { + return language; + } + + @Override + public String getActiveScriptName() + { + return activeScriptName; + } + + @Override + public boolean isFeatureSupported(String featureName) + { + return glyphSubstitutionMap.containsKey(featureName); + } + + @Override + public ScriptFeature getFeature(String featureName) + { + if (!isFeatureSupported(featureName)) + { + throw new UnsupportedOperationException( + "The feature " + featureName + " is not supported!"); + } + + return new MapBackedScriptFeature(featureName, glyphSubstitutionMap.get(featureName)); + } + + @Override + public Set getSupportedFeatures() + { + return glyphSubstitutionMap.keySet(); + } + +} diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedScriptFeature.java b/fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedScriptFeature.java new file mode 100644 index 00000000000..1cb705c381d --- /dev/null +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/model/MapBackedScriptFeature.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package org.apache.fontbox.ttf.model; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * + * A {@link Map} based simple implementation of the {@link ScriptFeature} + * + * @author Palash Ray + * + */ +public class MapBackedScriptFeature implements ScriptFeature +{ + + private final String name; + private final Map, Integer> featureMap; + + public MapBackedScriptFeature(String name, Map, Integer> featureMap) + { + this.name = name; + this.featureMap = featureMap; + } + + @Override + public String getName() + { + return name; + } + + @Override + public Set> getAllGlyphIdsForSubstitution() + { + return featureMap.keySet(); + } + + @Override + public boolean canReplaceGlyphs(List glyphIds) + { + return featureMap.containsKey(glyphIds); + } + + @Override + public Integer getReplacementForGlyphs(List glyphIds) + { + if (!canReplaceGlyphs(glyphIds)) + { + throw new UnsupportedOperationException( + "The glyphs " + glyphIds + " cannot be replaced"); + } + return featureMap.get(glyphIds); + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((featureMap == null) ? 0 : featureMap.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MapBackedScriptFeature other = (MapBackedScriptFeature) obj; + if (featureMap == null) + { + if (other.featureMap != null) + return false; + } + else if (!featureMap.equals(other.featureMap)) + return false; + if (name == null) + { + if (other.name != null) + return false; + } + else if (!name.equals(other.name)) + return false; + return true; + } + +} diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/model/ScriptFeature.java b/fontbox/src/main/java/org/apache/fontbox/ttf/model/ScriptFeature.java new file mode 100644 index 00000000000..1efad551b8d --- /dev/null +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/model/ScriptFeature.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package org.apache.fontbox.ttf.model; + +import java.util.List; +import java.util.Set; + +import org.apache.fontbox.ttf.table.common.FeatureRecord; + +/** + * Models a {@link FeatureRecord} + * + * @author Palash Ray + * + */ +public interface ScriptFeature +{ + + String getName(); + + Set> getAllGlyphIdsForSubstitution(); + + boolean canReplaceGlyphs(List glyphIds); + + Integer getReplacementForGlyphs(List glyphIds); + +} diff --git a/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java b/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java index d184d864d57..501f0fe7e3f 100644 --- a/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java +++ b/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java @@ -17,7 +17,7 @@ package org.apache.fontbox.ttf; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import java.io.BufferedReader; @@ -30,8 +30,10 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; +import org.apache.fontbox.ttf.model.GsubData; +import org.apache.fontbox.ttf.model.MapBackedScriptFeature; +import org.apache.fontbox.ttf.model.ScriptFeature; import org.junit.Test; public class GlyphSubstitutionTableTest @@ -56,12 +58,11 @@ public void testGetRawGSubData() throws IOException testClass.read(null, memoryTTFDataStream); // then - Map, Integer>> rawGsubData = testClass.getRawGSubData(); + GsubData rawGsubData = testClass.getGsubData(); assertNotNull(rawGsubData); - assertFalse(rawGsubData.isEmpty()); + assertNotEquals(GsubData.NO_DATA_FOUND, rawGsubData); - Set featureNames = rawGsubData.keySet(); - assertEquals(new HashSet<>(EXPECTED_FEATURE_NAMES), featureNames); + assertEquals(new HashSet<>(EXPECTED_FEATURE_NAMES), rawGsubData.getSupportedFeatures()); String templatePathToFile = "/gsub/lohit_bengali/bng2/%s.txt"; @@ -70,7 +71,9 @@ public void testGetRawGSubData() throws IOException System.out.println("******* Testing feature: " + featureName); Map, Integer> expectedGsubTableRawData = getExpectedGsubTableRawData( String.format(templatePathToFile, featureName)); - assertEquals(expectedGsubTableRawData, rawGsubData.get(featureName)); + ScriptFeature scriptFeature = new MapBackedScriptFeature(featureName, + expectedGsubTableRawData); + assertEquals(scriptFeature, rawGsubData.getFeature(featureName)); } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index 50be140c1bb..043c6a4c38c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.regex.Pattern; @@ -36,6 +35,7 @@ import org.apache.fontbox.ttf.gsub.CompoundCharacterTokenizer; import org.apache.fontbox.ttf.gsub.GsubWorker; import org.apache.fontbox.ttf.gsub.GsubWorkerForBengali; +import org.apache.fontbox.ttf.model.GsubData; import org.apache.pdfbox.contentstream.PDAbstractContentStream; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; @@ -330,12 +330,11 @@ protected void showTextInternal(String text) throws IOException if (font instanceof PDType0Font) { PDType0Font pdType0Font = (PDType0Font) font; - Map, Integer>> glyphSubstitutionMap = pdType0Font - .getGlyphSubstitutionMap(); - if (!glyphSubstitutionMap.isEmpty()) + GsubData gsubData = pdType0Font.getGsubData(); + if (gsubData != GsubData.NO_DATA_FOUND) { Set glyphIds = new HashSet<>(); - encodedText = encodeForGsub(glyphSubstitutionMap, glyphIds, pdType0Font, text); + encodedText = encodeForGsub(gsubData, glyphIds, pdType0Font, text); if (pdType0Font.willBeSubset()) { pdType0Font.addGlyphsToSubset(glyphIds); @@ -1177,7 +1176,7 @@ public void setTextRise(float rise) throws IOException writeOperator("Ts"); } - private byte[] encodeForGsub(Map, Integer>> glyphSubstitutionMap, + private byte[] encodeForGsub(GsubData gsubData, Set glyphIds, PDType0Font font, String text) throws IOException { @@ -1197,7 +1196,7 @@ private byte[] encodeForGsub(Map, Integer>> glyphSubst } else { - glyphIds.addAll(applyGSUBRules(out, font, glyphSubstitutionMap, word)); + glyphIds.addAll(applyGSUBRules(out, font, gsubData, word)); } } @@ -1205,8 +1204,7 @@ private byte[] encodeForGsub(Map, Integer>> glyphSubst } private List applyGSUBRules(ByteArrayOutputStream out, PDType0Font font, - Map, Integer>> glyphSubstitutionMap, String word) - throws IOException + GsubData gsubData, String word) throws IOException { List originalGlyphIds = new ArrayList<>(); CmapLookup cmapLookup = font.getCmapLookup(); @@ -1224,7 +1222,7 @@ private List applyGSUBRules(ByteArrayOutputStream out, PDType0Font font } // TODO: figure out how to get this language-specific detail up here - GsubWorker gsubWorker = new GsubWorkerForBengali(cmapLookup, glyphSubstitutionMap); + GsubWorker gsubWorker = new GsubWorkerForBengali(cmapLookup, gsubData); List repositionedGlyphIds = gsubWorker.repositionGlyphs(originalGlyphIds); List glyphIdsAfterGsub = gsubWorker.substituteGlyphs(repositionedGlyphIds); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java index cd205868e6d..f0e62393118 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType0Font.java @@ -20,10 +20,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; @@ -32,6 +29,7 @@ import org.apache.fontbox.ttf.CmapLookup; import org.apache.fontbox.ttf.TTFParser; import org.apache.fontbox.ttf.TrueTypeFont; +import org.apache.fontbox.ttf.model.GsubData; import org.apache.fontbox.util.BoundingBox; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; @@ -52,7 +50,7 @@ public class PDType0Font extends PDFont implements PDVectorFont private final PDCIDFont descendantFont; private final Set noUnicode = new HashSet<>(); - private final Map, Integer>> glyphSubstitutionMap; + private final GsubData gsubData; private final CmapLookup cmapLookup; private CMap cMap, cMapUCS2; private boolean isCMapPredefined; @@ -70,7 +68,7 @@ public PDType0Font(COSDictionary fontDictionary) throws IOException { super(fontDictionary); - glyphSubstitutionMap = Collections.emptyMap(); + gsubData = GsubData.NO_DATA_FOUND; cmapLookup = null; COSBase base = dict.getDictionaryObject(COSName.DESCENDANT_FONTS); @@ -104,7 +102,7 @@ private PDType0Font(PDDocument document, TrueTypeFont ttf, boolean embedSubset, ttf.enableVerticalSubstitutions(); } - glyphSubstitutionMap = ttf.getGlyphSubstitutionMap(); + gsubData = ttf.getGsubData(); cmapLookup = ttf.getUnicodeCmapLookup(); embedder = new PDCIDFontType2Embedder(document, dict, ttf, embedSubset, this, vertical); @@ -599,9 +597,9 @@ public boolean hasGlyph(int code) throws IOException return descendantFont.hasGlyph(code); } - public Map, Integer>> getGlyphSubstitutionMap() + public GsubData getGsubData() { - return glyphSubstitutionMap; + return gsubData; } public byte[] encodeGlyphId(int glyphId) From 253940e89e2d9af2957175a697cd42bf35388e80 Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Sun, 22 Apr 2018 23:37:00 +0530 Subject: [PATCH 2/9] javadoc --- .../org/apache/fontbox/ttf/model/package.html | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 fontbox/src/main/java/org/apache/fontbox/ttf/model/package.html diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/model/package.html b/fontbox/src/main/java/org/apache/fontbox/ttf/model/package.html new file mode 100644 index 00000000000..4878a8b2f06 --- /dev/null +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/model/package.html @@ -0,0 +1,25 @@ + + + + + + + +This package contains a more logical model for the various font tables like GSUB. + + From 5bebb0c13ca1fab5872bce3b926281fe4f386b3e Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Sun, 22 Apr 2018 23:57:23 +0530 Subject: [PATCH 3/9] use the factory pattern to get language-specific implementation --- .../fontbox/ttf/gsub/GsubWorkerFactory.java | 46 +++++++++++++++++++ .../ttf/gsub/GsubWorkerForBengali.java | 2 +- .../apache/fontbox/ttf/model/Language.java | 6 ++- .../pdfbox/pdmodel/PDPageContentStream.java | 7 +-- 4 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java new file mode 100644 index 00000000000..872ccfd9a93 --- /dev/null +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.fontbox.ttf.gsub; + +import org.apache.fontbox.ttf.CmapLookup; +import org.apache.fontbox.ttf.model.GsubData; +import org.apache.fontbox.ttf.model.Language; + +/** + * Gets a {@link Language} specific instance of a {@link GsubWorker} + * + * @author Palash Ray + * + */ +public class GsubWorkerFactory +{ + + public GsubWorker getGsubWorker(CmapLookup cmapLookup, GsubData gsubData) + { + switch (gsubData.getLanguage()) + { + case BENGALI: + return new GsubWorkerForBengali(cmapLookup, gsubData); + default: + throw new UnsupportedOperationException( + "The language " + gsubData.getLanguage() + " is not yet supported"); + } + + } + +} diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java index c51b9eacff5..1e5a916574d 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java @@ -54,7 +54,7 @@ public class GsubWorkerForBengali implements GsubWorker private final List beforeHalfGlyphIds; - public GsubWorkerForBengali(CmapLookup cmapLookup, GsubData gsubData) + GsubWorkerForBengali(CmapLookup cmapLookup, GsubData gsubData) { this.gsubData = gsubData; beforeHalfGlyphIds = getBeforeHalfGlyphIds(cmapLookup); diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java b/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java index e5fe482d8c4..3a52ce7a2d7 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java @@ -17,10 +17,14 @@ package org.apache.fontbox.ttf.model; +import org.apache.fontbox.ttf.gsub.GsubWorker; +import org.apache.fontbox.ttf.gsub.GsubWorkerFactory; import org.apache.fontbox.ttf.table.common.ScriptRecord; /** - * Enumerates the languages supported for GSUB operation + * Enumerates the languages supported for GSUB operation. In order to support a new language, you need to add it here + * and then implement the {@link GsubWorker} for the given language and return the same from the + * {@link GsubWorkerFactory#getGsubWorker(org.apache.fontbox.ttf.CmapLookup, GsubData)} * * @author Palash Ray * diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index 043c6a4c38c..e4c117245f4 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -34,7 +34,7 @@ import org.apache.fontbox.ttf.CmapLookup; import org.apache.fontbox.ttf.gsub.CompoundCharacterTokenizer; import org.apache.fontbox.ttf.gsub.GsubWorker; -import org.apache.fontbox.ttf.gsub.GsubWorkerForBengali; +import org.apache.fontbox.ttf.gsub.GsubWorkerFactory; import org.apache.fontbox.ttf.model.GsubData; import org.apache.pdfbox.contentstream.PDAbstractContentStream; import org.apache.pdfbox.cos.COSArray; @@ -1221,8 +1221,9 @@ private List applyGSUBRules(ByteArrayOutputStream out, PDType0Font font originalGlyphIds.add(glyphId); } - // TODO: figure out how to get this language-specific detail up here - GsubWorker gsubWorker = new GsubWorkerForBengali(cmapLookup, gsubData); + GsubWorkerFactory gsubWorkerFactory = new GsubWorkerFactory(); + + GsubWorker gsubWorker = gsubWorkerFactory.getGsubWorker(cmapLookup, gsubData); List repositionedGlyphIds = gsubWorker.repositionGlyphs(originalGlyphIds); List glyphIdsAfterGsub = gsubWorker.substituteGlyphs(repositionedGlyphIds); From 41520852188225f4a4d7f34cf4d6db0795dd5dbc Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Mon, 23 Apr 2018 01:16:15 +0530 Subject: [PATCH 4/9] handle o-kar, ou-kar --- .../ttf/gsub/GsubWorkerForBengali.java | 92 +++++++++++++++++-- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java index 1e5a916574d..95dbd732fe5 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java @@ -20,7 +20,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -49,15 +51,23 @@ public class GsubWorkerForBengali implements GsubWorker "haln", "calt"); private static final char[] BEFORE_HALF_CHARS = new char[] { '\u09BF', '\u09C7', '\u09C8' }; + private static final BeforeAndAfterSpanComponent[] BEFORE_AND_AFTER_SPAN_CHARS = new BeforeAndAfterSpanComponent[] { + new BeforeAndAfterSpanComponent('\u09CB', '\u09C7', '\u09BE'), + new BeforeAndAfterSpanComponent('\u09CC', '\u09C7', '\u09D7') }; + private final CmapLookup cmapLookup; private final GsubData gsubData; private final List beforeHalfGlyphIds; + private final Map beforeAndAfterSpanGlyphIds; + GsubWorkerForBengali(CmapLookup cmapLookup, GsubData gsubData) { + this.cmapLookup = cmapLookup; this.gsubData = gsubData; - beforeHalfGlyphIds = getBeforeHalfGlyphIds(cmapLookup); + beforeHalfGlyphIds = getBeforeHalfGlyphIds(); + beforeAndAfterSpanGlyphIds = getBeforeAndAfterSpanGlyphIds(); } @Override @@ -86,6 +96,13 @@ public List substituteGlyphs(List originalGlyphIds) @Override public List repositionGlyphs(List originalGlyphIds) + { + List glyphsRepositionedByBeforeHalf = repositionBeforeHalfGlyphIds( + originalGlyphIds); + return repositionBeforeAndAfterSpanGlyphIds(glyphsRepositionedByBeforeHalf); + } + + private List repositionBeforeHalfGlyphIds(List originalGlyphIds) { List repositionedGlyphIds = new ArrayList<>(originalGlyphIds); @@ -102,6 +119,28 @@ public List repositionGlyphs(List originalGlyphIds) return repositionedGlyphIds; } + private List repositionBeforeAndAfterSpanGlyphIds(List originalGlyphIds) + { + List repositionedGlyphIds = new ArrayList<>(originalGlyphIds); + + for (int index = 1; index < originalGlyphIds.size(); index++) + { + int glyphId = originalGlyphIds.get(index); + if (beforeAndAfterSpanGlyphIds.containsKey(glyphId)) + { + BeforeAndAfterSpanComponent beforeAndAfterSpanComponent = beforeAndAfterSpanGlyphIds + .get(glyphId); + int previousGlyphId = originalGlyphIds.get(index - 1); + repositionedGlyphIds.set(index, previousGlyphId); + repositionedGlyphIds.set(index - 1, + getGlyphId(beforeAndAfterSpanComponent.beforeComponentCharacter)); + repositionedGlyphIds.add(index + 1, + getGlyphId(beforeAndAfterSpanComponent.afterComponentCharacter)); + } + } + return repositionedGlyphIds; + } + private List applyGsubFeature(ScriptFeature scriptFeature, List originalGlyphs) { @@ -133,16 +172,57 @@ private List applyGsubFeature(ScriptFeature scriptFeature, return gsubProcessedGlyphs; } - private static List getBeforeHalfGlyphIds(CmapLookup cmapLookup) + private List getBeforeHalfGlyphIds() { - List beforeHalfGlyphIds = new ArrayList<>(); + List glyphIds = new ArrayList<>(); - for (char beforeHalfChar : BEFORE_HALF_CHARS) + for (char character : BEFORE_HALF_CHARS) { - beforeHalfGlyphIds.add(cmapLookup.getGlyphId(beforeHalfChar)); + glyphIds.add(getGlyphId(character)); } - return Collections.unmodifiableList(beforeHalfGlyphIds); + return Collections.unmodifiableList(glyphIds); + + } + + private Integer getGlyphId(char character) + { + return cmapLookup.getGlyphId(character); + } + + private Map getBeforeAndAfterSpanGlyphIds() + { + Map beforeAndAfterSpanGlyphIds = new HashMap<>(); + + for (BeforeAndAfterSpanComponent beforeAndAfterSpanComponent : BEFORE_AND_AFTER_SPAN_CHARS) + { + beforeAndAfterSpanGlyphIds.put( + getGlyphId(beforeAndAfterSpanComponent.originalCharacter), + beforeAndAfterSpanComponent); + } + + return Collections.unmodifiableMap(beforeAndAfterSpanGlyphIds); + } + + /** + * Models characters like O-kar (\u09CB) and OU-kar (\u09CC). Since these 2 characters is represented by 2 + * components, one before and one after the Vyanjan Varna on which this is used, this glyph has to be replaced by + * these 2 glyphs. For O-kar, it has to be replaced by E-kar (\u09C7) and AA-kar (\u09BE). For OU-kar, it has be + * replaced by E-kar (\u09C7) and \u09D7. + * + */ + private static class BeforeAndAfterSpanComponent { + private final char originalCharacter; + private final char beforeComponentCharacter; + private final char afterComponentCharacter; + + BeforeAndAfterSpanComponent(char originalCharacter, char beforeComponentCharacter, + char afterComponentCharacter) + { + this.originalCharacter = originalCharacter; + this.beforeComponentCharacter = beforeComponentCharacter; + this.afterComponentCharacter = afterComponentCharacter; + } } From 80c84da18231907747b283703386fd68eb9028fa Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Mon, 23 Apr 2018 01:30:04 +0530 Subject: [PATCH 5/9] feature complete Bengali --- .../apache/fontbox/ttf/gsub/GsubWorker.java | 4 +--- .../ttf/gsub/GsubWorkerForBengali.java | 22 ++++++++++++++----- .../pdfbox/pdmodel/PDPageContentStream.java | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java index 8e3287ed7a6..76f6220f403 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java @@ -28,8 +28,6 @@ */ public interface GsubWorker { - List substituteGlyphs(List originalGlyphIds); - - List repositionGlyphs(List originalGlyphIds); + List preProcessAndApplyGsubTransfs(List originalGlyphIds); } diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java index 95dbd732fe5..112c143e593 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java @@ -42,13 +42,15 @@ public class GsubWorkerForBengali implements GsubWorker private static final Log LOG = LogFactory.getLog(GsubWorkerForBengali.class); + private static final String INIT_FEATURE = "init"; + /** * This sequence is very important. This has been taken from https://docs.microsoft.com/en-us/typography/script-development/bengali */ private static final List FEATURES_IN_ORDER = Arrays.asList("locl", "nukt", "akhn", - "rphf", "blwf", "half", "pstf", "vatu", "cjct", "init", "pres", "abvs", "blws", "psts", - "haln", "calt"); + "rphf", "blwf", "half", "pstf", "vatu", "cjct", INIT_FEATURE, "pres", "abvs", "blws", + "psts", "haln", "calt"); private static final char[] BEFORE_HALF_CHARS = new char[] { '\u09BF', '\u09C7', '\u09C8' }; private static final BeforeAndAfterSpanComponent[] BEFORE_AND_AFTER_SPAN_CHARS = new BeforeAndAfterSpanComponent[] { @@ -71,7 +73,7 @@ public class GsubWorkerForBengali implements GsubWorker } @Override - public List substituteGlyphs(List originalGlyphIds) + public List preProcessAndApplyGsubTransfs(List originalGlyphIds) { List intermediateGlyphsFromGsub = originalGlyphIds; @@ -91,11 +93,10 @@ public List substituteGlyphs(List originalGlyphIds) intermediateGlyphsFromGsub); } - return intermediateGlyphsFromGsub; + return Collections.unmodifiableList(repositionGlyphs(intermediateGlyphsFromGsub)); } - @Override - public List repositionGlyphs(List originalGlyphIds) + private List repositionGlyphs(List originalGlyphIds) { List glyphsRepositionedByBeforeHalf = repositionBeforeHalfGlyphIds( originalGlyphIds); @@ -181,6 +182,15 @@ private List getBeforeHalfGlyphIds() glyphIds.add(getGlyphId(character)); } + if (gsubData.isFeatureSupported(INIT_FEATURE)) + { + ScriptFeature feature = gsubData.getFeature(INIT_FEATURE); + for (List glyphCluster : feature.getAllGlyphIdsForSubstitution()) + { + glyphIds.add(feature.getReplacementForGlyphs(glyphCluster)); + } + } + return Collections.unmodifiableList(glyphIds); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index e4c117245f4..86107289762 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -1225,8 +1225,8 @@ private List applyGSUBRules(ByteArrayOutputStream out, PDType0Font font GsubWorker gsubWorker = gsubWorkerFactory.getGsubWorker(cmapLookup, gsubData); - List repositionedGlyphIds = gsubWorker.repositionGlyphs(originalGlyphIds); - List glyphIdsAfterGsub = gsubWorker.substituteGlyphs(repositionedGlyphIds); + List glyphIdsAfterGsub = gsubWorker + .preProcessAndApplyGsubTransfs(originalGlyphIds); for (Integer glyphId : glyphIdsAfterGsub) { From 880af0550fd52832526888e335bc464d11f24faf Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Mon, 23 Apr 2018 01:55:02 +0530 Subject: [PATCH 6/9] minor refactoring: renamed method in GsubWorker --- .../main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java | 7 ++++++- .../org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java | 2 +- .../org/apache/pdfbox/pdmodel/PDPageContentStream.java | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java index 76f6220f403..10019ad0ad5 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java @@ -28,6 +28,11 @@ */ public interface GsubWorker { - List preProcessAndApplyGsubTransfs(List originalGlyphIds); + /** + * Applis language-specific transforms including GSUB and any other pre or post-processing necessary for displaying + * Glyphs correctly. + * + */ + List applyTransforms(List originalGlyphIds); } diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java index 112c143e593..c338b317d7c 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForBengali.java @@ -73,7 +73,7 @@ public class GsubWorkerForBengali implements GsubWorker } @Override - public List preProcessAndApplyGsubTransfs(List originalGlyphIds) + public List applyTransforms(List originalGlyphIds) { List intermediateGlyphsFromGsub = originalGlyphIds; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index 86107289762..36f2eedeba3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -1226,7 +1226,7 @@ private List applyGSUBRules(ByteArrayOutputStream out, PDType0Font font GsubWorker gsubWorker = gsubWorkerFactory.getGsubWorker(cmapLookup, gsubData); List glyphIdsAfterGsub = gsubWorker - .preProcessAndApplyGsubTransfs(originalGlyphIds); + .applyTransforms(originalGlyphIds); for (Integer glyphId : glyphIdsAfterGsub) { From 11cecc73d6c073d7dcd2a7388ddb8b83717392a2 Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Mon, 23 Apr 2018 01:56:13 +0530 Subject: [PATCH 7/9] typo --- .../src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java index 10019ad0ad5..23060ed519a 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorker.java @@ -29,7 +29,7 @@ public interface GsubWorker { /** - * Applis language-specific transforms including GSUB and any other pre or post-processing necessary for displaying + * Applies language-specific transforms including GSUB and any other pre or post-processing necessary for displaying * Glyphs correctly. * */ From ceb00522f8980e4fd12846f53bbd6d4337677051 Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Mon, 23 Apr 2018 01:59:57 +0530 Subject: [PATCH 8/9] put some more asserts --- .../fontbox/ttf/GlyphSubstitutionTableTest.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java b/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java index 501f0fe7e3f..6cb6fefd092 100644 --- a/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java +++ b/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java @@ -32,6 +32,7 @@ import java.util.Map; import org.apache.fontbox.ttf.model.GsubData; +import org.apache.fontbox.ttf.model.Language; import org.apache.fontbox.ttf.model.MapBackedScriptFeature; import org.apache.fontbox.ttf.model.ScriptFeature; import org.junit.Test; @@ -58,11 +59,13 @@ public void testGetRawGSubData() throws IOException testClass.read(null, memoryTTFDataStream); // then - GsubData rawGsubData = testClass.getGsubData(); - assertNotNull(rawGsubData); - assertNotEquals(GsubData.NO_DATA_FOUND, rawGsubData); + GsubData gsubData = testClass.getGsubData(); + assertNotNull(gsubData); + assertNotEquals(GsubData.NO_DATA_FOUND, gsubData); + assertEquals(Language.BENGALI, gsubData.getLanguage()); + assertEquals("bng2", gsubData.getActiveScriptName()); - assertEquals(new HashSet<>(EXPECTED_FEATURE_NAMES), rawGsubData.getSupportedFeatures()); + assertEquals(new HashSet<>(EXPECTED_FEATURE_NAMES), gsubData.getSupportedFeatures()); String templatePathToFile = "/gsub/lohit_bengali/bng2/%s.txt"; @@ -73,7 +76,7 @@ public void testGetRawGSubData() throws IOException String.format(templatePathToFile, featureName)); ScriptFeature scriptFeature = new MapBackedScriptFeature(featureName, expectedGsubTableRawData); - assertEquals(scriptFeature, rawGsubData.getFeature(featureName)); + assertEquals(scriptFeature, gsubData.getFeature(featureName)); } } From 1e98b4ebf8d56911461a94ec50cedd0cbaaf1406 Mon Sep 17 00:00:00 2001 From: Palash Ray Date: Mon, 23 Apr 2018 02:04:58 +0530 Subject: [PATCH 9/9] rename test case --- .../java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java b/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java index 6cb6fefd092..f3acae7e510 100644 --- a/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java +++ b/fontbox/src/test/java/org/apache/fontbox/ttf/GlyphSubstitutionTableTest.java @@ -46,7 +46,7 @@ public class GlyphSubstitutionTableTest "blwf", "blws", "half", "haln", "init", "nukt", "pres", "pstf", "rphf", "vatu"); @Test - public void testGetRawGSubData() throws IOException + public void testGetGsubData() throws IOException { // given MemoryTTFDataStream memoryTTFDataStream = new MemoryTTFDataStream(