123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- /*
- * 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.complexscripts.fonts;
-
- import java.io.File;
-
- import org.junit.Test;
-
- import static org.junit.Assert.assertEquals;
- import static org.junit.Assert.assertNotNull;
- import static org.junit.Assert.assertTrue;
- import static org.junit.Assert.fail;
-
- import org.apache.fop.complexscripts.fonts.GlyphTable.LookupTable;
- import org.apache.fop.complexscripts.fonts.ttx.TTXFile;
- import org.apache.fop.complexscripts.util.GlyphContextTester;
- import org.apache.fop.complexscripts.util.GlyphSequence;
- import org.apache.fop.complexscripts.util.ScriptContextTester;
-
- // CSOFF: LineLength
-
- public class GPOSTestCase implements ScriptContextTester, GlyphContextTester {
-
- private static String ttxFilesRoot = "test/resources/complexscripts";
-
- private static String[][] ttxFonts = {
- { "f0", "arab/ttx/arab-001.ttx" }, // simplified arabic
- { "f1", "arab/ttx/arab-002.ttx" }, // traditional arabic
- { "f2", "arab/ttx/arab-003.ttx" }, // lateef
- { "f3", "arab/ttx/arab-004.ttx" }, // scheherazade
- };
-
- private static Object[][] ltSingle = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_SINGLE },
- // arab-001.ttx
- { "f0", "lu1", "arab", "dflt", "mark",
- new Object[][] {
- {
- new String[] { "fathatan" },
- new int[][] {
- { 0, 0, -412, 0 }
- }
- },
- {
- new String[] { "fatha" },
- new int[][] {
- { 0, 0, -410, 0 }
- }
- },
- },
- },
- { "f0", "lu9", "arab", "*", "*",
- new Object[][] {
- {
- new String[] { "fathatan" },
- new int[][] {
- { 50, 0, 0, 0 }
- }
- },
- {
- new String[] { "fatha" },
- new int[][] {
- { 50, 0, 0, 0 }
- }
- },
- },
- },
- { "f0", "lu10", "arab", "*", "*",
- new Object[][] {
- {
- new String[] { "kasratan" },
- new int[][] {
- { 0, -200, 0, 0 }
- }
- },
- {
- new String[] { "kasra" },
- new int[][] {
- { 0, -200, 0, 0 }
- }
- },
- },
- },
- { "f0", "lu11", "arab", "*", "*",
- new Object[][] {
- {
- new String[] { "kasratan" },
- new int[][] {
- { 0, -300, 0, 0 }
- }
- },
- {
- new String[] { "kasra" },
- new int[][] {
- { 0, -300, 0, 0 }
- }
- },
- {
- new String[] { "uni0655" },
- new int[][] {
- { 0, -250, 0, 0 }
- }
- },
- },
- },
- // arab-002.ttx - maybe add tests
- // arab-003.ttx - maybe add tests
- // arab-004.ttx - maybe add tests
- };
-
- private static Object[][] ltPair = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_PAIR },
- // arab-001.ttx
- { "f0", "lu0", "arab", "dflt", "kern",
- new Object[][] {
- {
- new String[] { "wawwithhamzaabove", "hamza" },
- new int[][] {
- { -300, 0, -300, 0 }, { 0, 0, 0, 0 }
- }
- },
- {
- new String[] { "reh", "alefwithmaddaabove" },
- new int[][] {
- { -500, 0, -500, 0 }, { 0, 0, 0, 0 }
- }
- },
- {
- new String[] { "zain", "zain" },
- new int[][] {
- { -190, 0, -190, 0 }, { 0, 0, 0, 0 }
- }
- },
- {
- new String[] { "waw", "uni0649.init" },
- new int[][] {
- { -145, 0, -145, 0 }, { 0, 0, 0, 0 }
- }
- },
- {
- new String[] { "jeh", "uni06A5.init" },
- new int[][] {
- { -345, 0, -345, 0 }, { 0, 0, 0, 0 }
- }
- },
- },
- },
- // arab-002.ttx - maybe add tests
- // arab-003.ttx - maybe add tests
- // arab-004.ttx - maybe add tests
- };
-
- private static Object[][] ltCursive = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_CURSIVE },
- // arab-001.ttx - none used
- // arab-002.ttx - none used
- // arab-003.ttx - maybe add tests
- { "f2", "lu0", "arab", "dflt", "curs",
- new Object[][] {
- {
- new String[] { "uni0644.init.preAlef", "uni0622.fina.postLamIni" },
- new int[][] {
- // { 576, 0, 0, 0 }, { 0, 0, 0, 0 } - with zero widths
- { 295, 0, 0, 0 }, { 0, 0, 0, 0 }
- }
- },
- {
- new String[] { "uni0644.medi.preAlef", "uni0622.fina.postLamMed" },
- new int[][] {
- // { 550, 0, 0, 0 }, { 0, 0, 0, 0 } - with zero widths
- { 282, 0, 0, 0 }, { 0, 0, 0, 0 }
- }
- },
- },
- },
- // arab-004.ttx - none used
- };
-
- private static Object[][] ltMarkToBase = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_BASE },
- // arab-001.ttx - maybe add tests
- // arab-002.ttx
- { "f1", "lu4", "arab", "dflt", "mark",
- new Object[][] {
- {
- new String[] { "beh", "fatha" },
- new int[][] {
- // { 0, 0, 0, 0 }, { 266, -672, 0, 0 } - with zero widths
- { 0, 0, 0, 0 }, { 266, -672, -199, 0 }
- }
- },
- {
- new String[] { "alefwithhamzabelow", "kasra" },
- new int[][] {
- // { 0, 0, 0, 0 }, { -48, 344, 0, 0 } - with zero widths
- { 0, 0, 0, 0 }, { -48, 344, -199, 0 }
- }
- },
- },
- },
- // arab-003.ttx - maybe add tests
- // arab-004.ttx - maybe add tests
- };
-
- private static Object[][] ltMarkToLigature = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE },
- // arab-001.ttx
- { "f0", "lu4", "arab", "dflt", "mark",
- new Object[][] {
- {
- new String[] { "rayaleflam", "fatha", "fatha", "fatha", "fatha" },
- new int[][] {
- { 0, 0, 0, 0 }, { 1260, -1150, 0, 0 }, { 910, -1020, 0, 0 }, { 590, -630, 0, 0 }, { 110, -720, 0, 0 }
- }
- },
- {
- new String[] { "rayaleflam", "kasra", "kasra", "kasra", "kasra" },
- new int[][] {
- { 0, 0, 0, 0 }, { 1110 , 225, 0, 0 }, { 760, 275, 0, 0 }, { 520, 475, 0, 0 }, { 110, 425, 0, 0 }
- }
- },
- },
- },
- // arab-002.ttx - maybe add tests
- // arab-003.ttx - maybe add tests
- // arab-004.ttx - maybe add tests
- };
-
- private static Object[][] ltMarkToMark = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_MARK },
- // arab-001.ttx - maybe add tests
- // arab-002.ttx - maybe add tests
- // arab-003.ttx - maybe add tests
- // arab-004.ttx
- { "f3", "lu3", "arab", "dflt", "mkmk",
- new Object[][] {
- {
- new String[] { "uni064F", "uni064E" },
- new int[][] {
- { 0, 0, 0, 0 }, { -15, 495, 0, 0 }
- }
- },
- {
- new String[] { "uni0651", "uni0670" },
- new int[][] {
- { 0, 0, 0, 0 }, { -30, 705, 0, 0 }
- }
- },
- },
- },
- };
-
- private static Object[][] ltContextual = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_CONTEXTUAL },
- // arab-001.ttx - none used
- // arab-002.ttx - none used
- // arab-003.ttx - none used
- // arab-004.ttx - none used
- };
-
- private static Object[][] ltChainedContextual = {
- { GlyphPositioningTable.GPOS_LOOKUP_TYPE_CHAINED_CONTEXTUAL },
- // arab-001.ttx
- { "f0", "lu3", "arab", "dflt", "mark",
- new Object[][] {
- {
- new String[] { "behmedial", "fatha", "lam" },
- new int[][] {
- { 0, 0, 0, 0 }, { 50, 0, 0, 0 }, { 0, 0, 0, 0 }
- }
- },
- },
- },
- // arab-002.ttx
- { "f1", "lu6", "arab", "dflt", "mark",
- new Object[][] {
- {
- new String[] { "zain", "fatha", "kafinitial" },
- new int[][] {
- { 0, 250, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
- }
- },
- },
- },
- // arab-003.ttx - none used
- // arab-004.ttx
- { "f3", "lu5", "arab", "dflt", "mark",
- new Object[][] {
- {
- new String[] { "uni064D", "uni0622.fina.postLamIni", "uni0650" },
- new int[][] {
- { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 55, 424, 0, 0 }
- }
- },
- },
- },
- };
-
- @Test
- public void testGPOSSingle() throws Exception {
- performPositioning(ltSingle);
- }
-
- @Test
- public void testGPOSPair() throws Exception {
- performPositioning(ltPair);
- }
-
- @Test
- public void testGPOSCursive() throws Exception {
- performPositioning(ltCursive);
- }
-
- @Test
- public void testGPOSMarkToBase() throws Exception {
- performPositioning(ltMarkToBase);
- }
-
- @Test
- public void testGPOSMarkToLigature() throws Exception {
- performPositioning(ltMarkToLigature);
- }
-
- @Test
- public void testGPOSMarkToMark() throws Exception {
- performPositioning(ltMarkToMark);
- }
-
- @Test
- public void testGPOSContextual() throws Exception {
- performPositioning(ltContextual);
- }
-
- @Test
- public void testGPOSChainedContextual() throws Exception {
- performPositioning(ltChainedContextual);
- }
-
- /**
- * Perform positioning on all test data in test specification TS.
- * @param ts test specification
- */
- private void performPositioning(Object[][] ts) {
- assert ts.length > 0;
- Object[] tp = ts[0];
- for (int i = 1; i < ts.length; i++) {
- performPositioning(tp, ts[i]);
- }
- }
-
- /**
- * Perform positioning on all test data TD using test parameters TP.
- * @param tp test parameters
- * @param td test data
- */
- private void performPositioning(Object[] tp, Object[] td) {
- assert tp.length > 0;
- if (td.length > 5) {
- String fid = (String) td[0];
- String lid = (String) td[1];
- String script = (String) td[2];
- String language = (String) td[3];
- String feature = (String) td[4];
- TTXFile tf = findTTX(fid);
- assertTrue(tf != null);
- GlyphPositioningTable gpos = tf.getGPOS();
- assertTrue(gpos != null);
- GlyphPositioningSubtable[] sta = findGPOSSubtables(gpos, script, language, feature, lid);
- assertTrue(sta != null);
- assertTrue(sta.length > 0);
- ScriptContextTester sct = findScriptContextTester(script, language, feature);
- Object[][] tia = (Object[][]) td[5]; // test instance array
- for (Object[] ti : tia) { // test instance
- if (ti != null) {
- if (ti.length > 0) { // must have at least input glyphs
- String[] igia = (String[]) ti[0]; // input glyph id array
- int[][] ogpa = (int[][]) ti[1]; // output glyph positioning array
- GlyphSequence igs = tf.getGlyphSequence(igia);
- int[] widths = tf.getWidths();
- int[][] tgpa = new int [ igia.length ] [ 4 ];
- boolean adjusted = GlyphPositioningSubtable.position(igs, script, language, feature, 1000, sta, widths, tgpa, sct);
- assertTrue(adjusted);
- assertSamePositions(ogpa, tgpa);
- }
- }
- }
- }
- }
-
- private String findTTXPath(String fid) {
- for (String[] fs : ttxFonts) {
- if ((fs != null) && (fs.length > 1)) {
- if (fs[0].equals(fid)) {
- return ttxFilesRoot + File.separator + fs[1];
- }
- }
- }
- return null;
- }
-
- private TTXFile findTTX(String fid) {
- String pn = findTTXPath(fid);
- assertTrue(pn != null);
- try {
- TTXFile tf = TTXFile.getFromCache(pn);
- return tf;
- } catch (Exception e) {
- fail(e.getMessage());
- return null;
- }
- }
-
- private GlyphPositioningSubtable[] findGPOSSubtables(GlyphPositioningTable gpos, String script, String language, String feature, String lid) {
- LookupTable lt = gpos.getLookupTable(lid);
- if (lt != null) {
- return (GlyphPositioningSubtable[]) lt.getSubtables();
- } else {
- return null;
- }
- }
-
- private ScriptContextTester findScriptContextTester(String script, String language, String feature) {
- return this;
- }
-
- public GlyphContextTester getTester(String feature) {
- return this;
- }
-
- public boolean test(String script, String language, String feature, GlyphSequence gs, int index, int flags) {
- return true;
- }
-
- private void assertSamePositions(int[][] pa1, int[][] pa2) {
- assertNotNull(pa1);
- assertNotNull(pa2);
- assertEquals("unequal adjustment count", pa1.length, pa2.length);
- for (int i = 0; i < pa1.length; i++) {
- int[] a1 = pa1 [ i ];
- int[] a2 = pa2 [ i ];
- assertNotNull(a1);
- assertNotNull(a2);
- assertEquals("bad adjustment array length", 4, a1.length);
- assertEquals("bad adjustment array length", 4, a2.length);
- for (int k = 0; k < a1.length; k++) {
- int p1 = a1[k];
- int p2 = a2[k];
- assertEquals("bad adjustment", p1, p2);
- }
- }
- }
- }
|