Skip to content

Commit ff08e8f

Browse files
SnipxiText-CI
authored andcommitted
OTF: Support GposLookupType1 - table subformat 2
DEVSIX-5160
1 parent 304ce6d commit ff08e8f

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

io/src/main/java/com/itextpdf/io/font/otf/GposLookupType1.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.io.font.otf;
2424

25+
import java.util.ArrayList;
2526
import java.util.HashMap;
2627
import java.util.List;
2728
import java.util.Map;
@@ -56,8 +57,8 @@ public boolean transformOne(GlyphLine line) {
5657
GposValueRecord valueRecord = valueRecordMap.get(glyphCode);
5758
if (valueRecord != null) {
5859
Glyph newGlyph = new Glyph(line.get(line.idx));
59-
newGlyph.xAdvance += (short)valueRecord.XAdvance;
60-
newGlyph.yAdvance += (short)valueRecord.YAdvance;
60+
newGlyph.setXAdvance((short)(newGlyph.getXAdvance() + valueRecord.XAdvance));
61+
newGlyph.setYAdvance((short)(newGlyph.getYAdvance() + valueRecord.YAdvance));
6162
line.set(line.idx, newGlyph);
6263
positionApplied = true;
6364
}
@@ -68,13 +69,28 @@ public boolean transformOne(GlyphLine line) {
6869
@Override
6970
protected void readSubTable(int subTableLocation) throws java.io.IOException {
7071
openReader.rf.seek(subTableLocation);
71-
openReader.rf.readShort();
72-
int coverage = openReader.rf.readUnsignedShort();
72+
int subTableFormat = openReader.rf.readShort();
73+
int coverageOffset = openReader.rf.readUnsignedShort();
7374
int valueFormat = openReader.rf.readUnsignedShort();
74-
GposValueRecord valueRecord = OtfReadCommon.readGposValueRecord(openReader, valueFormat);
75-
List<Integer> coverageGlyphIds = openReader.readCoverageFormat(subTableLocation + coverage);
76-
for (Integer glyphId : coverageGlyphIds) {
77-
valueRecordMap.put((int)glyphId, valueRecord);
75+
if (subTableFormat == 1) {
76+
GposValueRecord valueRecord = OtfReadCommon.readGposValueRecord(openReader, valueFormat);
77+
List<Integer> coverageGlyphIds = openReader.readCoverageFormat(subTableLocation + coverageOffset);
78+
for (Integer glyphId : coverageGlyphIds) {
79+
valueRecordMap.put((int) glyphId, valueRecord);
80+
}
81+
} else if (subTableFormat == 2) {
82+
int valueCount = openReader.rf.readUnsignedShort();
83+
List<GposValueRecord> valueRecords = new ArrayList<>();
84+
for (int i = 0; i < valueCount; i++) {
85+
GposValueRecord valueRecord = OtfReadCommon.readGposValueRecord(openReader, valueFormat);
86+
valueRecords.add(valueRecord);
87+
}
88+
List<Integer> coverageGlyphIds = openReader.readCoverageFormat(subTableLocation + coverageOffset);
89+
for (int i = 0; i < coverageGlyphIds.size(); i++) {
90+
valueRecordMap.put((int) coverageGlyphIds.get(i), valueRecords.get(i));
91+
}
92+
} else {
93+
throw new IllegalArgumentException("Bad subtable format identifier: " + subTableFormat);
7894
}
7995
}
8096
}

io/src/test/java/com/itextpdf/io/font/otf/GposLookupType1Test.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class GposLookupType1Test extends ExtendedITextTest {
3939
private static final String RESOURCE_FOLDER = "./src/test/resources/com/itextpdf/io/font/otf/GposLookupType1Test/";
4040

4141
@Test
42-
public void verifyXAdvanceIsApplied() throws IOException {
42+
public void verifyXAdvanceIsAppliedSubFormat1() throws IOException {
4343
TrueTypeFont fontProgram = (TrueTypeFont) FontProgramFactory.createFont(RESOURCE_FOLDER + "NotoSansMyanmar-Regular.ttf");
4444
GlyphPositioningTableReader gposTableReader = fontProgram.getGposTable();
4545
GposLookupType1 lookup = (GposLookupType1) gposTableReader.getLookupTable(29);
@@ -57,7 +57,7 @@ public void verifyXAdvanceIsApplied() throws IOException {
5757
}
5858

5959
@Test
60-
public void verifyPositionIsNotAppliedForIrrelevantGlyph() throws IOException {
60+
public void verifyPositionIsNotAppliedForIrrelevantGlyphSubFormat1() throws IOException {
6161
TrueTypeFont fontProgram = (TrueTypeFont) FontProgramFactory.createFont(RESOURCE_FOLDER + "NotoSansMyanmar-Regular.ttf");
6262
GlyphPositioningTableReader gposTableReader = fontProgram.getGposTable();
6363
GposLookupType1 lookup = (GposLookupType1) gposTableReader.getLookupTable(29);
@@ -74,4 +74,27 @@ public void verifyPositionIsNotAppliedForIrrelevantGlyph() throws IOException {
7474
Assert.assertEquals(0, gl.get(0).getXAdvance());
7575
}
7676

77+
@Test
78+
public void verifyDifferentXAdvanceIsAppliedSubFormat2() throws IOException {
79+
TrueTypeFont fontProgram = (TrueTypeFont) FontProgramFactory.createFont(RESOURCE_FOLDER + "NotoSansMyanmar-Regular.ttf");
80+
GlyphPositioningTableReader gposTableReader = fontProgram.getGposTable();
81+
GposLookupType1 lookup = (GposLookupType1) gposTableReader.getLookupTable(16);
82+
83+
List<Glyph> glyphs = Arrays.asList(new Glyph(fontProgram.getGlyphByCode(401)),
84+
new Glyph(fontProgram.getGlyphByCode(5)));
85+
GlyphLine gl = new GlyphLine(glyphs);
86+
Assert.assertEquals(0, gl.get(0).getXAdvance());
87+
Assert.assertTrue(lookup.transformOne(gl));
88+
Assert.assertEquals(109, gl.get(0).getXAdvance());
89+
90+
// Subtable type 2 defines different GposValueRecords for different coverage glyphs
91+
92+
glyphs = Arrays.asList(new Glyph(fontProgram.getGlyphByCode(508)),
93+
new Glyph(fontProgram.getGlyphByCode(5)));
94+
gl = new GlyphLine(glyphs);
95+
Assert.assertEquals(0, gl.get(0).getXAdvance());
96+
Assert.assertTrue(lookup.transformOne(gl));
97+
Assert.assertEquals(158, gl.get(0).getXAdvance());
98+
}
99+
77100
}

0 commit comments

Comments
 (0)