Author: tilman
Date: Tue Nov 25 10:27:45 2025
New Revision: 1929971
Log:
PDFBOX-4213: add placeholder for Tamil
Added:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForTamil.java
- copied, changed from r1917762,
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForGujarati.java
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/gsub/GsubWorkerForTamilTest.java
- copied, changed from r1917735,
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/gsub/GsubWorkerForDevanagariTest.java
pdfbox/trunk/fontbox/src/test/resources/ttf/Lohit-Tamil.ttf (contents,
props changed)
Modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java
Modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java
==============================================================================
---
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java
Tue Nov 25 10:23:32 2025 (r1929970)
+++
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerFactory.java
Tue Nov 25 10:27:45 2025 (r1929971)
@@ -54,6 +54,8 @@ public class GsubWorkerFactory
return new GsubWorkerForLatin(gsubData);
case DFLT:
return new GsubWorkerForDflt(gsubData);
+ case TAMIL:
+ //TODO implement me
default:
return new DefaultGsubWorker();
}
Copied and modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForTamil.java
(from r1917762,
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForGujarati.java)
==============================================================================
---
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForGujarati.java
Thu May 16 07:28:38 2024 (r1917762, copy source)
+++
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/gsub/GsubWorkerForTamil.java
Tue Nov 25 10:27:45 2025 (r1929971)
@@ -31,30 +31,30 @@ import org.apache.logging.log4j.Logger;
/**
*
- * Gujarati-specific implementation of GSUB system.
+ * Tamil-specific implementation of GSUB system.
*
- * @author JAVAUSER
+ * @author TODO
*
*/
-public class GsubWorkerForGujarati implements GsubWorker
+public class GsubWorkerForTamil implements GsubWorker
{
- private static final Logger LOG =
LogManager.getLogger(GsubWorkerForGujarati.class);
-
- private static final String RKRF_FEATURE = "rkrf";
- private static final String VATU_FEATURE = "vatu";
+ private static final Logger LOG =
LogManager.getLogger(GsubWorkerForTamil.class);
+
/**
* This sequence is very important. This has been taken from <a href=
- *
"https://docs.microsoft.com/en-us/typography/script-development/gujarati">https://docs.microsoft.com/en-us/typography/script-development/gujarati</a>
+ *
"https://docs.microsoft.com/en-us/typography/script-development/tamil">https://docs.microsoft.com/en-us/typography/script-development/tamil</a>
*/
private static final List<String> FEATURES_IN_ORDER =
Arrays.asList("locl", "nukt", "akhn",
- "rphf", RKRF_FEATURE,"blwf", "half", VATU_FEATURE, "cjct", "pres",
"abvs", "blws",
+ "rphf", "pref", "half", "pres", "abvs", "blws",
"psts", "haln", "calt");
-
+
+ //TODO adjust all below this line. The existing code has been copied from
Gujarati
+
// Reph glyphs
- private static final char[] REPH_CHARS = {'\u0AB0', '\u0ACD'};
+ private static final char[] REPH_CHARS = {'\u0BB0','\u0BCD'};
// Glyphs to precede reph
- private static final char[] BEFORE_REPH_CHARS={'\u0ABE','\u0AC0'};
+ private static final char[] BEFORE_REPH_CHARS= {'\u0BB8','\u0BCD'};
// Gujarati vowel sign I
private static final char BEFORE_HALF_CHAR = '\u0ABF';
@@ -66,7 +66,7 @@ public class GsubWorkerForGujarati imple
private final List<Integer> beforeRephGlyphIds;
private final List<Integer> beforeHalfGlyphIds;
- GsubWorkerForGujarati(CmapLookup cmapLookup, GsubData gsubData)
+ GsubWorkerForTamil(CmapLookup cmapLookup, GsubData gsubData)
{
this.cmapLookup = cmapLookup;
this.gsubData = gsubData;
@@ -84,13 +84,6 @@ public class GsubWorkerForGujarati imple
{
if (!gsubData.isFeatureSupported(feature))
{
- if (feature.equals(RKRF_FEATURE) &&
gsubData.isFeatureSupported(VATU_FEATURE))
- {
- // Create your own rkrf feature from vatu feature
- intermediateGlyphsFromGsub = applyRKRFFeature(
- gsubData.getFeature(VATU_FEATURE),
- intermediateGlyphsFromGsub);
- }
LOG.debug("the feature {} was not found", feature);
continue;
}
@@ -102,49 +95,6 @@ public class GsubWorkerForGujarati imple
return Collections.unmodifiableList(intermediateGlyphsFromGsub);
}
- private List<Integer> applyRKRFFeature(ScriptFeature
rkrfGlyphsForSubstitution,
- List<Integer> originalGlyphIds)
- {
- Set<List<Integer>> rkrfGlyphIds =
rkrfGlyphsForSubstitution.getAllGlyphIdsForSubstitution();
- if (rkrfGlyphIds.isEmpty())
- {
- LOG.debug("Glyph substitution list for {} is empty.",
rkrfGlyphsForSubstitution.getName());
- return originalGlyphIds;
- }
-
- // Replace this with better implementation to get second GlyphId from
rkrfGlyphIds
- int rkrfReplacement = 0;
- for (List<Integer> firstList : rkrfGlyphIds)
- {
- if (firstList.size() > 1)
- {
- rkrfReplacement = firstList.get(1);
- break;
- }
- }
- if (rkrfReplacement == 0)
- {
- LOG.debug("Cannot find rkrf candidate. The rkrfGlyphIds doesn't
contain lists of two elements.");
- return originalGlyphIds;
- }
-
- List<Integer> rkrfList = new ArrayList<>(originalGlyphIds);
- for (int index = originalGlyphIds.size() - 1; index > 1; index--)
- {
- int raGlyph = originalGlyphIds.get(index);
- if (raGlyph == rephGlyphIds.get(0))
- {
- int viramaGlyph = originalGlyphIds.get(index - 1);
- if (viramaGlyph == rephGlyphIds.get(1))
- {
- rkrfList.set(index - 1, rkrfReplacement);
- rkrfList.remove(index);
- }
- }
- }
- return rkrfList;
- }
-
private List<Integer> repositionGlyphs(List<Integer> originalGlyphIds)
{
List<Integer> repositionedGlyphIds = new ArrayList<>(originalGlyphIds);
@@ -183,6 +133,7 @@ public class GsubWorkerForGujarati imple
int viramaGlyph = originalGlyphIds.get(index + 1);
if (raGlyph == rephGlyphIds.get(0) && viramaGlyph ==
rephGlyphIds.get(1))
{
+ // reph virama cons => cons reph virama
int nextConsonantGlyph = originalGlyphIds.get(index + 2);
rephAdjustedList.set(index, nextConsonantGlyph);
rephAdjustedList.set(index + 1, raGlyph);
@@ -190,6 +141,7 @@ public class GsubWorkerForGujarati imple
if (index + 3 < originalGlyphIds.size())
{
+ // reph virama cons matra => cons matra reph virama
int matraGlyph = originalGlyphIds.get(index + 3);
if (beforeRephGlyphIds.contains(matraGlyph))
{
Modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java
==============================================================================
---
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java
Tue Nov 25 10:23:32 2025 (r1929970)
+++
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/model/Language.java
Tue Nov 25 10:27:45 2025 (r1929971)
@@ -35,6 +35,7 @@ public enum Language
BENGALI(new String[] { "bng2", "beng" }),
DEVANAGARI(new String[] { "dev2", "deva" }),
GUJARATI(new String[] { "gjr2", "gujr" }),
+ TAMIL(new String[] { "tml2", "taml" }),
LATIN(new String[] { "latn" }),
DFLT(new String[] { "DFLT" }),
Copied and modified:
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/gsub/GsubWorkerForTamilTest.java
(from r1917735,
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/gsub/GsubWorkerForDevanagariTest.java)
==============================================================================
---
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/gsub/GsubWorkerForDevanagariTest.java
Wed May 15 08:07:36 2024 (r1917735, copy source)
+++
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/ttf/gsub/GsubWorkerForTamilTest.java
Tue Nov 25 10:27:45 2025 (r1929971)
@@ -17,263 +17,44 @@
package org.apache.fontbox.ttf.gsub;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
import org.apache.fontbox.ttf.CmapLookup;
import org.apache.fontbox.ttf.TTFParser;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
- * Integration test for {@link GsubWorkerForDevanagari}. Has various
combinations of glyphs to test
+ * Integration test for {@link GsubWorkerForTamil}. Has various combinations
of glyphs to test
* proper working of the GSUB system.
- * <p>
- * Not all tests are enabled at this time (12/2023). Please read the comment
of 10/Dec/23 in
- * PDFBOX-5729.
- *
- * @author JAVAUSER
- *
*/
-class GsubWorkerForDevanagariTest
+class GsubWorkerForTamilTest
{
- private static final String LOHIT_DEVANAGARI_TTF =
- "src/test/resources/ttf/Lohit-Devanagari.ttf";
+ private static final String LOHIT_TAMIL_TTF =
"src/test/resources/ttf/Lohit-Tamil.ttf";
private CmapLookup cmapLookup;
- private GsubWorker gsubWorkerForDevanagari;
+ private GsubWorker gsubWorkerForTamil;
@BeforeEach
public void init() throws IOException
{
- try (TrueTypeFont ttf = new TTFParser().parse(new
RandomAccessReadBufferedFile(LOHIT_DEVANAGARI_TTF)))
+ try (TrueTypeFont ttf = new TTFParser().parse(new
RandomAccessReadBufferedFile(LOHIT_TAMIL_TTF)))
{
cmapLookup = ttf.getUnicodeCmapLookup();
- gsubWorkerForDevanagari = new
GsubWorkerFactory().getGsubWorker(cmapLookup, ttf.getGsubData());
+ gsubWorkerForTamil = new
GsubWorkerFactory().getGsubWorker(cmapLookup, ttf.getGsubData());
}
}
-
- @Test
- void testApplyTransforms_locl()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(642);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("प्त"));
- System.out.println("result: " + result);
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Test
- void testApplyTransforms_nukt()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(400,396,393);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("य़ज़क़"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Test
- void testApplyTransforms_akhn()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(520,521);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("क्षज्ञ"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Test
- void testApplyTransforms_rphf()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(513);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("र्"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Disabled
- @Test
- void testApplyTransforms_rkrf()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(588,597,595,602);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("क्रब्रप्रह्र"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Test
- void testApplyTransforms_blwf()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(602,336,516);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("ह्रट्र"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Test
- void testApplyTransforms_half()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(558,557,546,537);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("ह्स्भ्त्"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Test
- void testApplyTransforms_vatu()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(517,593,601,665);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("श्रत्रस्रघ्र"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Disabled
- @Test
- void testApplyTransforms_cjct()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(638,688,636,640,639);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("द्मद्ध्र्यब्दद्वद्य"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Test
- void testApplyTransforms_pres()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(603,605,617,652);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("शृक्तज्जह्ण"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Disabled
- @Test
- void testApplyTransforms_abvs()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(353,512,353,675,353,673);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("र्रैंरौंर्रो"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Disabled
- @Test
- void testApplyTransforms_blws()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(660,663,336,584,336,583);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("दृहृट्रूट्रु"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- @Disabled
- @Test
- void testApplyTransforms_psts()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(326,704,326,582,661,662);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("किंर्कींरुरू"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
+
@Test
- void testApplyTransforms_haln()
+ void testDummy()
{
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList(539);
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds("द्"));
-
- // then
- assertEquals(glyphsAfterGsub, result);
+ System.out.println("GSUB worker: " + gsubWorkerForTamil);
+ assertTrue(gsubWorkerForTamil instanceof DefaultGsubWorker); // change
to GsubWorkerForTamil when implemented
}
- @Disabled
- void testApplyTransforms_calt()
- {
- // given
- List<Integer> glyphsAfterGsub = Arrays.asList();
-
- // when
- List<Integer> result =
gsubWorkerForDevanagari.applyTransforms(getGlyphIds(""));
-
- // then
- assertEquals(glyphsAfterGsub, result);
- }
-
- private List<Integer> getGlyphIds(String word)
- {
- List<Integer> originalGlyphIds = new ArrayList<>();
-
- for (char unicodeChar : word.toCharArray())
- {
- int glyphId = cmapLookup.getGlyphId(unicodeChar);
- assertTrue(glyphId > 0);
- originalGlyphIds.add(glyphId);
- }
-
- return originalGlyphIds;
- }
}
Added: pdfbox/trunk/fontbox/src/test/resources/ttf/Lohit-Tamil.ttf
==============================================================================
Binary file. No diff available.