Added: xmlgraphics/fop/trunk/test/java/org/apache/fop/complexscripts/fonts/GPOSTestCase.java URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/complexscripts/fonts/GPOSTestCase.java?rev=1293736&view=auto ============================================================================== --- xmlgraphics/fop/trunk/test/java/org/apache/fop/complexscripts/fonts/GPOSTestCase.java (added) +++ xmlgraphics/fop/trunk/test/java/org/apache/fop/complexscripts/fonts/GPOSTestCase.java Sun Feb 26 02:29:01 2012 @@ -0,0 +1,475 @@ +/* + * 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 java.util.List; +import java.util.Map; + +import org.apache.fop.complexscripts.fonts.GlyphSubtable; +import org.apache.fop.complexscripts.fonts.GlyphPositioningSubtable; +import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; +import org.apache.fop.complexscripts.fonts.GlyphTable.LookupSpec; +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; + +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; + +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, 0, 0, 0 }, { 0, 250, 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; + } + + @Override + public GlyphContextTester getTester ( String feature ) { + return this; + } + + @Override + 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 ); + } + } + } +}
--------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
