You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by sp...@apache.org on 2010/08/19 21:46:45 UTC

svn commit: r987282 [4/9] - in /xmlgraphics/fop/branches/Temp_ComplexScripts: ./ src/codegen/unicode/java/org/apache/fop/hyphenation/ src/codegen/unicode/java/org/apache/fop/text/bidi/ src/java/org/apache/fop/area/ src/java/org/apache/fop/area/inline/ ...

Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java Thu Aug 19 19:46:41 2010
@@ -31,12 +31,15 @@ import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.DefaultHandler;
 
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.fonts.apps.TTFReader;
 
+// CSOFF: LineLengthCheck
+
 /**
  * Class for reading a metric.xml file and creating a font object.
  * Typical usage:
@@ -63,6 +66,31 @@ public class FontReader extends DefaultH
 
     private List bfranges = null;
 
+    /* advanced typographic (script extras) support */
+    private boolean inScriptExtras = false;
+    private int seTable = -1;
+    private Map seLookups = null;
+    private String seScript = null;
+    private String seLanguage = null;
+    private String seFeature = null;
+    private String seUseLookup = null;
+    private List seUseLookups = null;
+    private String luID = null;
+    private int luType = -1;
+    private List ltSubtables = null;
+    private int luSequence = -1;
+    private int luFlags = 0;
+    private int lstSequence = -1;
+    private int lstFormat = -1;
+    private List lstCoverage = null;
+    private List lstGIDs = null;
+    private List lstRanges = null;
+    private List lstEntries = null;
+    private List lstLIGSets = null;
+    private List lstLIGs = null;
+    private int ligGID = -1;
+    /* end of script extras parse state */
+
     private void createFont(InputSource source) throws FOPException {
         XMLReader parser = null;
 
@@ -114,6 +142,14 @@ public class FontReader extends DefaultH
     }
 
     /**
+     * Enable/disable use of advanced typographic features for the font
+     * @param enabled true to enable, false to disable
+     */
+    public void setAdvancedEnabled(boolean enabled) {
+        returnFont.setAdvancedEnabled(enabled);
+    }
+
+    /**
      * Sets the font resolver. Needed for URI resolution.
      * @param resolver the font resolver
      */
@@ -158,7 +194,9 @@ public class FontReader extends DefaultH
      */
     public void startElement(String uri, String localName, String qName,
                              Attributes attributes) throws SAXException {
-        if (localName.equals("font-metrics")) {
+        if ( inScriptExtras ) {
+            startElementScriptExtras ( uri, localName, qName, attributes );
+        } else if (localName.equals("font-metrics")) {
             if ("TYPE0".equals(attributes.getValue("type"))) {
                 multiFont = new MultiByteFont();
                 returnFont = multiFont;
@@ -208,7 +246,10 @@ public class FontReader extends DefaultH
         } else if ("pair".equals(localName)) {
             currentKerning.put(new Integer(attributes.getValue("kpx2")),
                                new Integer(attributes.getValue("kern")));
+        } else if ("script-extras".equals(localName)) {
+            inScriptExtras = true;
         }
+
     }
 
     private int getInt(String str) throws SAXException {
@@ -226,7 +267,9 @@ public class FontReader extends DefaultH
      */
     public void endElement(String uri, String localName, String qName) throws SAXException {
         String content = text.toString().trim();
-        if ("font-name".equals(localName)) {
+        if ( inScriptExtras ) {
+            endElementScriptExtras ( uri, localName, qName, content );
+        } else if ("font-name".equals(localName)) {
             returnFont.setFontName(content);
         } else if ("full-name".equals(localName)) {
             returnFont.setFullName(content);
@@ -303,6 +346,376 @@ public class FontReader extends DefaultH
     public void characters(char[] ch, int start, int length) {
         text.append(ch, start, length);
     }
+
+    private void validateScriptTag ( String tag )
+        throws SAXException {
+    }
+
+    private void validateLanguageTag ( String tag, String script )
+        throws SAXException {
+    }
+
+    private void validateFeatureTag ( String tag, int tableType, String script, String language )
+        throws SAXException {
+    }
+
+    private int mapLookupType ( String type, int tableType ) {
+        int t = -1;
+        if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+            t = GlyphSubstitutionTable.getLookupTypeFromName ( type );
+        } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+            t = GlyphPositioningTable.getLookupTypeFromName ( type );
+        }
+        return t;
+    }
+
+    private void validateLookupType ( String type, int tableType )
+        throws SAXException {
+        if ( mapLookupType ( type, tableType ) == -1 ) {
+            throw new SAXParseException ( "invalid lookup type \'" + type + "\'", locator );
+        }
+    }
+
+    private void startElementScriptExtras ( String uri, String localName, String qName, Attributes attributes )
+        throws SAXException {
+        if ( "gsub".equals(localName) ) {
+            assert seLookups == null;
+            seLookups = new java.util.HashMap();
+            seTable = GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION;
+        } else if ( "gpos".equals(localName) ) {
+            assert seLookups == null;
+            seLookups = new java.util.HashMap();
+            seTable = GlyphTable.GLYPH_TABLE_TYPE_POSITIONING;
+        } else if ( "script".equals(localName) ) {
+            String tag = attributes.getValue("tag");
+            if ( tag != null ) {
+                assert seScript == null;
+                validateScriptTag ( tag );
+                seScript = tag;
+            } else {
+                throw new SAXParseException ( "missing tag attribute on <script/> element", locator );
+            }
+        } else if ( "lang".equals(localName) ) {
+            String tag = attributes.getValue("tag");
+            if ( tag != null ) {
+                assert seLanguage == null;
+                validateLanguageTag ( tag, seScript );
+                seLanguage = tag;
+            } else {
+                throw new SAXParseException ( "missing tag attribute on <lang/> element", locator );
+            }
+        } else if ( "feature".equals(localName) ) {
+            String tag = attributes.getValue("tag");
+            if ( tag != null ) {
+                validateFeatureTag ( tag, seTable, seScript, seLanguage );
+                assert seFeature == null;
+                seFeature = tag;
+            } else {
+                throw new SAXParseException ( "missing tag attribute on <feature/> element", locator );
+            }
+        } else if ( "use-lookup".equals(localName) ) {
+            String ref = attributes.getValue("ref");
+            if ( ref != null ) {
+                assert seUseLookup == null;
+                seUseLookup = ref;
+            } else {
+                throw new SAXParseException ( "missing ref attribute on <use-lookup/> element", locator );
+            }
+        } else if ( "lookup".equals(localName) ) {
+            String id = attributes.getValue("id");
+            if ( id != null ) {
+                assert luID == null;
+                luID = id; luSequence++; lstSequence = -1;
+            } else {
+                throw new SAXParseException ( "missing id attribute on <lookup/> element", locator );
+            }
+            String flags = attributes.getValue("flags");
+            if ( flags != null ) {
+                try {
+                    luFlags = Integer.parseInt ( flags );
+                } catch ( NumberFormatException e ) {
+                    throw new SAXParseException ( "invalid flags attribute on <lookup/> element, must be integer", locator );
+                }
+            }
+            String type = attributes.getValue("type");
+            if ( type != null ) {
+                validateLookupType ( type, seTable );
+                assert luType == -1;
+                luType = mapLookupType ( type, seTable );
+            } else {
+                throw new SAXParseException ( "missing type attribute on <lookup/> element", locator );
+            }
+        } else if ( "lst".equals(localName) ) {
+            String format = attributes.getValue("format");
+            if ( format != null ) {
+                try {
+                    lstSequence++;
+                    lstFormat = Integer.parseInt ( format );
+                } catch ( NumberFormatException e ) {
+                    throw new SAXParseException ( "invalid format attribute on <lst/> element, must be integer", locator );
+                }
+                assert lstCoverage == null;
+                assert lstEntries == null;
+            } else {
+                throw new SAXParseException ( "missing format attribute on <lst/> element", locator );
+            }
+        } else if ( "coverage".equals(localName) ) {
+            assert lstGIDs == null;
+            assert lstRanges == null;
+            lstGIDs = new java.util.ArrayList();
+            lstRanges = new java.util.ArrayList();
+        } else if ( "range".equals(localName) ) {
+            String gs = attributes.getValue("gs");
+            String ge = attributes.getValue("ge");
+            String ci = attributes.getValue("ci");
+            if ( ( gs != null ) && ( ge != null ) && ( ci != null ) ) {
+                try {
+                    int s = Integer.parseInt ( gs );
+                    int e = Integer.parseInt ( ge );
+                    int i = Integer.parseInt ( ci );
+                    lstRanges.add ( new GlyphCoverageTable.CoverageRange ( s, e, i ) );
+                } catch ( NumberFormatException e ) {
+                    throw new SAXParseException ( "invalid format attribute on <lst/> element, must be integer", locator );
+                } catch ( IllegalArgumentException e ) {
+                    throw new SAXParseException ( "bad gs, ge, or ci attribute on <range/> element, must be non-negative integers, with gs <= ge", locator );
+                }
+            } else {
+                throw new SAXParseException ( "missing gs, ge, or ci attribute on <range/> element", locator );
+            }
+        } else if ( "entries".equals(localName) ) {
+            initEntriesState ( seTable, luType, lstFormat );
+        } else if ( "ligs".equals(localName) ) {
+            assert lstLIGs == null;
+            lstLIGs = new java.util.ArrayList();
+        } else if ( "lig".equals(localName) ) {
+            if ( lstLIGs == null ) {
+                throw new SAXParseException ( "missing container <ligs/> element for <lig/> element", locator );
+            } else {
+                String gid = attributes.getValue("gid");
+                if ( gid != null ) {
+                    try {
+                        ligGID = Integer.parseInt ( gid );
+                    } catch ( NumberFormatException e ) {
+                        throw new SAXParseException ( "invalid gid attribute on <lig/> element, must be integer", locator );
+                    }
+                } else {
+                    throw new SAXParseException ( "missing gid attribute on <lig/> element", locator );
+                }
+            }
+        }
+    }
+
+    private void endElementScriptExtras ( String uri, String localName, String qName, String content )
+        throws SAXException {
+        if ( "script-extras".equals(localName) ) {
+            inScriptExtras = false;
+        } else if ( "gsub".equals(localName) ) {
+            if ( ( ltSubtables != null ) && ( ltSubtables.size() > 0 ) ) {
+                if ( multiFont.getGSUB() == null ) {
+                    multiFont.setGSUB ( new GlyphSubstitutionTable ( seLookups, ltSubtables ) );
+                }
+            }
+            ltSubtables = null; seTable = -1; seLookups = null;
+        } else if ( "gpos".equals(localName) ) {
+            if ( ( ltSubtables != null ) && ( ltSubtables.size() > 0 ) ) {
+                if ( multiFont.getGPOS() == null ) {
+                    multiFont.setGPOS ( new GlyphPositioningTable ( seLookups, ltSubtables ) );
+                }
+            }
+            ltSubtables = null; seTable = -1; seLookups = null;
+        } else if ( "script".equals(localName) ) {
+            assert seUseLookups == null;
+            assert seUseLookup == null;
+            assert seFeature == null;
+            assert seLanguage == null;
+            seScript = null;
+        } else if ( "lang".equals(localName) ) {
+            assert seUseLookups == null;
+            assert seUseLookup == null;
+            assert seFeature == null;
+            seLanguage = null;
+        } else if ( "feature".equals(localName) ) {
+            if ( ( seScript != null ) && ( seLanguage != null ) && ( seFeature != null ) ) {
+                if ( ( seUseLookups != null ) && ( seUseLookups.size() > 0 ) ) {
+                    seLookups.put ( new GlyphTable.LookupSpec ( seScript, seLanguage, seFeature ), seUseLookups );
+                }
+            }
+            seUseLookups = null; seFeature = null;
+        } else if ( "use-lookup".equals(localName) ) {
+            if ( seUseLookup != null ) {
+                if ( seUseLookups == null ) {
+                    seUseLookups = new java.util.ArrayList();
+                }
+                seUseLookups.add ( seUseLookup );
+            }
+            seUseLookup = null;
+        } else if ( "lookup".equals(localName) ) {
+            luType = -1;
+            luFlags = 0;
+        } else if ( "lst".equals(localName) ) {
+            assert lstCoverage != null;
+            assert lstEntries != null;
+            addLookupSubtable ( seTable, luType, luID, luSequence, luFlags, lstFormat, lstCoverage, lstEntries );
+            lstFormat = -1;
+            lstCoverage = null;
+            lstEntries = null;
+        } else if ( "coverage".equals(localName) ) {
+            assert lstGIDs != null;
+            assert lstRanges != null;
+            assert lstCoverage == null;
+            if ( lstGIDs.size() > 0 ) {
+                lstCoverage = lstGIDs;
+            } else if ( lstRanges.size() > 0 ) {
+                lstCoverage = lstRanges;
+            }
+            lstGIDs = null; lstRanges = null;
+        } else if ( "gid".equals(localName) ) {
+            if ( lstGIDs != null ) {
+                try {
+                    lstGIDs.add ( Integer.decode ( content ) );
+                } catch ( NumberFormatException e ) {
+                    throw new SAXParseException ( "invalid <gid/> element content, must be integer", locator );
+                }
+            }
+        } else if ( "entries".equals(localName) ) {
+            finishEntriesState ( seTable, luType, lstFormat );
+        } else if ( "ligs".equals(localName) ) {
+            assert lstLIGSets != null;
+            assert lstLIGs != null;
+            lstLIGSets.add ( new GlyphSubstitutionTable.LigatureSet ( lstLIGs ) );
+            lstLIGs = null;
+        } else if ( "lig".equals(localName) ) {
+            assert lstLIGs != null;
+            assert ligGID >= 0;
+            int[] ligComponents = parseLigatureComponents ( content );
+            if ( ligComponents != null ) {
+                lstLIGs.add ( new GlyphSubstitutionTable.Ligature ( ligGID, ligComponents ) );
+            }
+            ligGID = -1;
+        }
+    }
+
+    private void initEntriesState ( int tableType, int lookupType, int subtableFormat ) {
+        if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+            switch ( lookupType ) {
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_SINGLE:
+                assert lstGIDs == null;
+                lstGIDs = new java.util.ArrayList();
+                break;
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_LIGATURE:
+                assert lstLIGSets == null;
+                lstLIGSets = new java.util.ArrayList();
+                break;
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_MULTIPLE:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_ALTERNATE:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CONTEXT:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CHAINING_CONTEXT:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
+                throw new UnsupportedOperationException();
+            default:
+                break;
+            }
+        } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+            switch ( lookupType ) {
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_SINGLE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_PAIR:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CURSIVE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_BASE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_MARK:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CONTEXT:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CHAINED_CONTEXT:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING:
+                throw new UnsupportedOperationException();
+            default:
+                break;
+            }
+        }
+    }
+
+    private void finishEntriesState ( int tableType, int lookupType, int subtableFormat ) {
+        if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+            switch ( lookupType ) {
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_SINGLE:
+                assert lstGIDs != null;
+                lstEntries = lstGIDs; lstGIDs = null;
+                break;
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_LIGATURE:
+                assert lstLIGSets != null;
+                lstEntries = lstLIGSets; lstLIGSets = null;
+                break;
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_MULTIPLE:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_ALTERNATE:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CONTEXT:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CHAINING_CONTEXT:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION:
+            case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
+                throw new UnsupportedOperationException();
+            default:
+                break;
+            }
+        } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+            switch ( lookupType ) {
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_SINGLE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_PAIR:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CURSIVE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_BASE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_MARK:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CONTEXT:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CHAINED_CONTEXT:
+            case GlyphPositioningTable.GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING:
+                throw new UnsupportedOperationException();
+            default:
+                break;
+            }
+        }
+    }
+
+    private void addLookupSubtable                              // CSOK: ParameterNumber
+        ( int tableType, int lookupType, String lookupID, int lookupSequence, int lookupFlags, int subtableFormat, List coverage, List entries ) {
+        GlyphSubtable st = null;
+        if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+            st = GlyphSubstitutionTable.createSubtable ( lookupType, lookupID, lookupSequence, lookupFlags, subtableFormat, coverage, entries );
+        } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+            st = GlyphPositioningTable.createSubtable ( lookupType, lookupID, lookupSequence, lookupFlags, subtableFormat, coverage, entries );
+        }
+        if ( st != null ) {
+            if ( ltSubtables == null ) {
+                ltSubtables = new java.util.ArrayList();
+            }
+            ltSubtables.add ( st );
+        }
+    }
+
+    private int[] parseLigatureComponents ( String s )
+        throws SAXParseException {
+        String[] csa = s.split ( "\\s" );
+        if ( ( csa == null ) || ( csa.length == 0 ) ) {
+            throw new SAXParseException ( "invalid <lig/> element, must specify at least one component", locator );
+        } else {
+            int nc = csa.length;
+            int[] components = new int [ nc ];
+            for ( int i = 0, n = nc; i < n; i++ ) {
+                String cs = csa [ i ];
+                int c;
+                try {
+                    c = Integer.parseInt ( cs );
+                    if ( ( c < 0 ) || ( c > 65535 ) ) {
+                        throw new SAXParseException ( "invalid component value (" + c + ") in <lig/> element, out of range", locator );
+                    } else {
+                        components [ i ] = c;
+                    }
+                } catch ( NumberFormatException e ) {
+                    throw new SAXParseException ( "invalid component \"" + cs + "\" in <lig/> element, must be integer", locator );
+                }
+                
+            }
+            return components;
+        }
+    }
+
 }
 
 

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,36 @@
+/*
+ * 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.fonts;
+
+/**
+ * Interface for testing the originating (source) character context of a glyph sequence.
+ * @author Glenn Adams
+ */
+public interface GlyphContextTester {
+
+    /**
+     * Perform a test on a glyph sequence in a specific (originating) character context.
+     * @param gs glyph sequence to test
+     * @param ca character association defining the context of test
+     * @return true if test is satisfied
+     */
+    boolean test ( GlyphSequence gs, GlyphSequence.CharAssociation ca );
+
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,357 @@
+/*
+ * 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.fonts;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Iterator;
+
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: InnerAssignmentCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * Abstract base class implementation of glyph coverage table.
+ * @author Glenn Adams
+ */
+public abstract class GlyphCoverageTable {
+
+    /** empty coverage table */
+    public static final int GLYPH_COVERAGE_TYPE_EMPTY = 0;
+
+    /** mapped coverage table */
+    public static final int GLYPH_COVERAGE_TYPE_MAPPED = 1;
+
+    /** range based coverage table */
+    public static final int GLYPH_COVERAGE_TYPE_RANGE = 2;
+
+    /**
+     * Obtain coverage type.
+     * @return coverage format type
+     */
+    public abstract int getType();
+
+    /**
+     * Obtain coverage entries.
+     * @return list of coverage entries
+     */
+    public abstract List getEntries();
+
+    /**
+     * Map glyph identifier (code) to coverge index. Returns -1 if glyph identifier is not in the domain of
+     * the coverage table.
+     * @param gid glyph identifier (code)
+     * @return non-negative glyph coverage index or -1 if glyph identifiers is not mapped by table
+     */
+    public abstract int getCoverageIndex ( int gid );
+
+    /**
+     * Create glyph coverage table.
+     * @param coverage list of mapped or ranged coverage entries, or null or empty list
+     * @return a new covera table instance
+     */
+    public static GlyphCoverageTable createCoverageTable ( List coverage ) {
+        GlyphCoverageTable ct;
+        if ( ( coverage == null ) || ( coverage.size() == 0 ) ) {
+            ct = new EmptyCoverageTable ( coverage );
+        } else if ( isMappedCoverage ( coverage ) ) {
+            ct = new MappedCoverageTable ( coverage );
+        } else if ( isRangeCoverage ( coverage ) ) {
+            ct = new RangeCoverageTable ( coverage );
+        } else {
+            ct = null;
+        }
+        assert ct != null : "unknown coverage type";
+        return ct;
+    }
+
+    private static boolean isMappedCoverage ( List coverage ) {
+        if ( ( coverage == null ) || ( coverage.size() == 0 ) ) {
+            return false;
+        } else {
+            for ( Iterator it = coverage.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if ( ! ( o instanceof Integer ) ) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private static boolean isRangeCoverage ( List coverage ) {
+        if ( ( coverage == null ) || ( coverage.size() == 0 ) ) {
+            return false;
+        } else {
+            for ( Iterator it = coverage.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if ( ! ( o instanceof CoverageRange ) ) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private static class EmptyCoverageTable extends GlyphCoverageTable {
+        public EmptyCoverageTable ( List coverage ) {
+        }
+        public int getType() {
+            return GLYPH_COVERAGE_TYPE_EMPTY;
+        }
+        public List getEntries() {
+            return new java.util.ArrayList();
+        }
+        public int getCoverageIndex ( int gid ) {
+            return -1;
+        }
+    }
+
+    private static class MappedCoverageTable extends GlyphCoverageTable {
+        private int[] map = null;
+        public MappedCoverageTable ( List coverage ) {
+            populate ( coverage );
+        }
+        public int getType() {
+            return GLYPH_COVERAGE_TYPE_MAPPED;
+        }
+        public List getEntries() {
+            List entries = new java.util.ArrayList();
+            if ( map != null ) {
+                for ( int i = 0, n = map.length; i < n; i++ ) {
+                    entries.add ( Integer.valueOf ( map [ i ] ) );
+                }
+            }
+            return entries;
+        }
+        public int getCoverageIndex ( int gid ) {
+            int i;
+            if ( ( i = Arrays.binarySearch ( map, gid ) ) >= 0 ) {
+                return i;
+            } else {
+                return -1;
+            }
+        }
+        private void populate ( List coverage ) {
+            int i = 0, n = coverage.size(), gidMax = -1;
+            int[] map = new int [ n ];
+            for ( Iterator it = coverage.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if ( o instanceof Integer ) {
+                    int gid = ( (Integer) o ) . intValue();
+                    if ( ( gid >= 0 ) && ( gid < 65536 ) ) {
+                        if ( gid > gidMax ) {
+                            map [ i++ ] = gidMax = gid;
+                        } else {
+                            throw new IllegalArgumentException ( "out of order or duplicate glyph index: " + gid );
+                        }
+                    } else {
+                        throw new IllegalArgumentException ( "illegal glyph index: " + gid );
+                    }
+                } else {
+                    throw new IllegalArgumentException ( "illegal coverage entry, must be Integer: " + o );
+                }
+            }
+            assert i == n;
+            assert this.map == null;
+            this.map = map;
+        }
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            sb.append('{');
+            for ( int i = 0, n = map.length; i < n; i++ ) {
+                if ( i > 0 ) {
+                    sb.append(',');
+                }
+                sb.append ( Integer.toString ( map [ i ] ) );
+            }
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    private static class RangeCoverageTable extends GlyphCoverageTable {
+        private int[] sa = null;                                                // array of ranges starts
+        private int[] ea = null;                                                // array of range ends
+        private int[] ca = null;                                                // array of range coverage (start) indices
+        public RangeCoverageTable ( List coverage ) {
+            populate ( coverage );
+        }
+        public int getType() {
+            return GLYPH_COVERAGE_TYPE_RANGE;
+        }
+        public List getEntries() {
+            List entries = new java.util.ArrayList();
+            if ( sa != null ) {
+                for ( int i = 0, n = sa.length; i < n; i++ ) {
+                    entries.add ( new CoverageRange ( sa [ i ], ea [ i ], ca [ i ] ) );
+                }
+            }
+            return entries;
+        }
+        public int getCoverageIndex ( int gid ) {
+            int i, ci;
+            if ( ( i = Arrays.binarySearch ( sa, gid ) ) >= 0 ) {
+                ci = ca [ i ] + gid - sa [ i ];                         // matches start of (some) range
+            } else if ( ( i = - ( i + 1 ) ) == 0 ) {
+                ci = -1;                                                // precedes first range 
+            } else if ( gid > ea [ --i ] ) {
+                ci = -1;                                                // follows preceding (or last) range
+            } else {
+                ci = ca [ i ] + gid - sa [ i ];                         // intersects (some) range
+            }
+            return ci;
+        }
+        private void populate ( List coverage ) {
+            int i = 0, n = coverage.size(), gidMax = -1;
+            int[] sa = new int [ n ];
+            int[] ea = new int [ n ];
+            int[] ca = new int [ n ];
+            for ( Iterator it = coverage.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if ( o instanceof CoverageRange ) {
+                    CoverageRange r = (CoverageRange) o;
+                    int gs = r.getStart();
+                    int ge = r.getEnd();
+                    int ci = r.getIndex();
+                    if ( ( gs < 0 ) || ( gs > 65535 ) ) {
+                        throw new IllegalArgumentException ( "illegal glyph range: [" + gs + "," + ge + "]: bad start index" );
+                    } else if ( ( ge < 0 ) || ( ge > 65535 ) ) {
+                        throw new IllegalArgumentException ( "illegal glyph range: [" + gs + "," + ge + "]: bad end index" );
+                    } else if ( gs > ge ) {
+                        throw new IllegalArgumentException ( "illegal glyph range: [" + gs + "," + ge + "]: start index exceeds end index" );
+                    } else if ( gs < gidMax ) {
+                        throw new IllegalArgumentException ( "out of order glyph range: [" + gs + "," + ge + "]" );
+                    } else if ( ci < 0 ) {
+                        throw new IllegalArgumentException ( "illegal coverage index: " + ci );
+                    } else {
+                        sa [ i ] = gs;
+                        ea [ i ] = gidMax = ge;
+                        ca [ i ] = ci;
+                        i++;
+                    }
+                } else {
+                    throw new IllegalArgumentException ( "illegal coverage entry, must be Integer: " + o );
+                }
+            }
+            assert i == n;
+            assert this.sa == null;
+            assert this.ea == null;
+            assert this.ca == null;
+            this.sa = sa;
+            this.ea = ea;
+            this.ca = ca;
+        }
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            sb.append('{');
+            for ( int i = 0, n = sa.length; i < n; i++ ) {
+                if ( i > 0 ) {
+                    sb.append(',');
+                }
+                sb.append ( '[' );
+                sb.append ( Integer.toString ( sa [ i ] ) );
+                sb.append ( Integer.toString ( ea [ i ] ) );
+                sb.append ( "]:" );
+                sb.append ( Integer.toString ( ca [ i ] ) );
+            }
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    /**
+     * The <code>CoverageRange</code> class encapsulates a glyph [start,end] range and
+     * a coverage index.
+     */
+    public static class CoverageRange {
+
+        private final int gidStart;                     // first glyph in range (inclusive)
+        private final int gidEnd;                       // last glyph in range (inclusive)
+        private final int index;                        // coverage index;
+
+        /**
+         * Instantiate a coverage range.
+         */
+        public CoverageRange() {
+            this ( 0, 0, 0 );
+        }
+
+        /**
+         * Instantiate a specific coverage range.
+         * @param gidStart start of range
+         * @param gidEnd end of range
+         * @param index coverage index
+         */
+        public CoverageRange ( int gidStart, int gidEnd, int index ) {
+            if ( ( gidStart < 0 ) || ( gidEnd < 0 ) || ( index < 0 ) ) {
+                throw new IllegalArgumentException();
+            } else if ( gidStart > gidEnd ) {
+                throw new IllegalArgumentException();
+            } else {
+                this.gidStart = gidStart;
+                this.gidEnd = gidEnd;
+                this.index = index;
+            }
+        }
+
+        /** @return start of range */
+        public int getStart() {
+            return gidStart;
+        }
+
+        /** @return end of range */
+        public int getEnd() {
+            return gidEnd;
+        }
+
+        /** @return coverage index */
+        public int getIndex() {
+            return index;
+        }
+
+        /** @return interval as a pair of integers */
+        public int[] getInterval() {
+            return new int[] { gidStart, gidEnd };
+        }
+
+        /**
+         * Obtain interval, filled into first two elements of specified array, or returning new array.
+         * @param interval an array of length two or greater or null
+         * @return interval as a pair of integers, filled into specified array
+         */
+        public int[] getInterval ( int[] interval ) {
+            if ( ( interval == null ) || ( interval.length != 2 ) ) {
+                throw new IllegalArgumentException();
+            } else {
+                interval[0] = gidStart;
+                interval[1] = gidEnd;
+            }
+            return interval;
+        }
+
+        /** @return length of interval */
+        public int getLength() {
+            return gidStart - gidEnd;
+        }
+
+    }
+
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java Thu Aug 19 19:46:41 2010
@@ -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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphPositioning</code> interface is implemented by a font related object
+ * that supports the determination of glyph positioning information based on script and
+ * language of the corresponding character content.
+ * @author Glenn Adams
+ */
+public interface GlyphPositioning {
+
+    /**
+     * Perform glyph positioning.
+     * @param gs sequence to map to output glyph sequence
+     * @param script the script associated with the characters corresponding to the glyph sequence
+     * @param language the language associated with the characters corresponding to the glyph sequence
+     * @return array (sequence) of pairs of position [DX,DY] offsets, one pair for each element of
+     * glyph sequence, or null if no non-zero offset applies
+     */
+    int[] position ( GlyphSequence gs, String script, String language );
+
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,62 @@
+/*
+ * 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.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphPositioningSubtable</code> implements an abstract base of a glyph subtable,
+ * providing a default implementation of the <code>GlyphPositioning</code> interface.
+ * @author Glenn Adams
+ */
+public abstract class GlyphPositioningSubtable extends GlyphSubtable implements GlyphPositioning {
+
+    /**
+     * Instantiate a <code>GlyphPositioningSubtable</code>.
+     * @param id subtable identifier
+     * @param sequence subtable sequence
+     * @param flags subtable flags
+     * @param format subtable format
+     * @param coverage subtable coverage table
+     */
+    protected GlyphPositioningSubtable ( String id, int sequence, int flags, int format, GlyphCoverageTable coverage ) {
+        super ( id, sequence, flags, format, coverage );
+    }
+
+    /** {@inheritDoc} */
+    public int getTableType() {
+        return GlyphTable.GLYPH_TABLE_TYPE_POSITIONING;
+    }
+
+    /** {@inheritDoc} */
+    public String getTypeName() {
+        return GlyphPositioningTable.getLookupTypeName ( getType() );
+    }
+
+    /** {@inheritDoc} */
+    public int[] position ( GlyphSequence gs, String script, String language ) {
+        if ( gs == null ) {
+            throw new IllegalArgumentException ( "invalid glyph sequence: must not be null" );
+        } else {
+            return null;
+        }
+    }
+
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,170 @@
+/*
+ * 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.fonts;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphPositioningTable</code> class is a glyph table that implements
+ * <code>GlyphPositioning</code> functionality.
+ * @author Glenn Adams
+ */
+public class GlyphPositioningTable extends GlyphTable implements GlyphPositioning {
+
+    /** single positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_SINGLE = 1;
+    /** multiple positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_PAIR = 2;
+    /** cursive positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_CURSIVE = 3;
+    /** mark to base positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_MARK_TO_BASE = 4;
+    /** mark to ligature positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE = 5;
+    /** mark to mark positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_MARK_TO_MARK = 6;
+    /** context positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_CONTEXT = 7;
+    /** chained context positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_CHAINED_CONTEXT = 8;
+    /** extension positioning subtable type */
+    public static final int GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING = 9;
+
+    /**
+     * Instantiate a <code>GlyphPositioningTable</code> object using the specified lookups
+     * and subtables.
+     * @param lookups a map of lookup specifications to subtable identifier strings
+     * @param subtables a list of identified subtables
+     */
+    public GlyphPositioningTable ( Map lookups, List subtables ) {
+        super ( lookups );
+        if ( ( subtables == null ) || ( subtables.size() == 0 ) ) {
+            throw new IllegalArgumentException ( "subtables must be non-empty" );
+        } else {
+            for ( Iterator it = subtables.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if ( o instanceof GlyphPositioningSubtable ) {
+                    addSubtable ( (GlyphSubtable) o );
+                } else {
+                    throw new IllegalArgumentException ( "subtable must be a glyph positioning subtable" );
+                }
+            }
+        }
+    }
+
+    /**
+     * Map a lookup type name to its constant (integer) value.
+     * @param name lookup type name
+     * @return lookup type
+     */
+    public static int getLookupTypeFromName ( String name ) {
+        int t;
+        String s = name.toLowerCase();
+        if ( "single".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_SINGLE;
+        } else if ( "pair".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_PAIR;
+        } else if ( "cursive".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_CURSIVE;
+        } else if ( "marktobase".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_MARK_TO_BASE;
+        } else if ( "marktoligature".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE;
+        } else if ( "marktomark".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_MARK_TO_MARK;
+        } else if ( "context".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_CONTEXT;
+        } else if ( "chainedcontext".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_CHAINED_CONTEXT;
+        } else if ( "extensionpositioning".equals ( s ) ) {
+            t = GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING;
+        } else {
+            t = -1;
+        }
+        return t;
+    }
+
+    /**
+     * Map a lookup type constant (integer) value to its name.
+     * @param type lookup type
+     * @return lookup type name
+     */
+    public static String getLookupTypeName ( int type ) {
+        String tn;
+        switch ( type ) {
+        case GPOS_LOOKUP_TYPE_SINGLE:
+            tn = "single";
+            break;
+        case GPOS_LOOKUP_TYPE_PAIR:
+            tn = "pair";
+            break;
+        case GPOS_LOOKUP_TYPE_CURSIVE:
+            tn = "cursive";
+            break;
+        case GPOS_LOOKUP_TYPE_MARK_TO_BASE:
+            tn = "marktobase";
+            break;
+        case GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE:
+            tn = "marktoligature";
+            break;
+        case GPOS_LOOKUP_TYPE_MARK_TO_MARK:
+            tn = "marktomark";
+            break;
+        case GPOS_LOOKUP_TYPE_CONTEXT:
+            tn = "context";
+            break;
+        case GPOS_LOOKUP_TYPE_CHAINED_CONTEXT:
+            tn = "chainedcontext";
+            break;
+        case GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING:
+            tn = "extensionpositioning";
+            break;
+        default:
+            tn = "unknown";
+            break;
+        }
+        return tn;
+    }
+
+    /**
+     * Create a positioning subtable according to the specified arguments.
+     * @param type subtable type
+     * @param id subtable identifier
+     * @param sequence subtable sequence
+     * @param flags subtable flags
+     * @param format subtable format
+     * @param coverage subtable coverage table
+     * @param entries subtable entries
+     * @return a glyph subtable instance
+     */
+    public static GlyphSubtable createSubtable ( int type, String id, int sequence, int flags, int format, List coverage, List entries ) {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public int[] position ( GlyphSequence gs, String script, String language ) {
+        return null;
+    }
+
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,254 @@
+/*
+ * 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.fonts;
+
+import java.nio.CharBuffer;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * A GlyphSequence encapsulates a sequence of character codes, a sequence of glyph codes,
+ * and a sequence of character associations, where, for each glyph in the sequence of glyph
+ * codes, there is a corresponding character association. Character associations server to
+ * relate the glyph codes in a glyph sequence to the specific characters in an original
+ * character code sequence with which the glyph codes are associated.
+ * @author Glenn Adams
+ */
+public class GlyphSequence implements CharSequence {
+
+    private CharSequence characters;
+    private CharSequence glyphs;
+    private CharAssociation[] associations;
+
+    /**
+     * Instantiate a glyph sequence.
+     * @param characters a (possibly empty) sequence of associated (originating) characters
+     * @param sequences a (possibly empty) list of glyph sequences
+     * @param associations a (possibly empty) list of glyph to character associations, one for each glyph in the concatenated glyph sequences
+     * @param reverse a boolean indicating if the glyphs are in reverse order with respect to the nominal inline progression direction
+     */
+    public GlyphSequence ( CharSequence characters, List/*<GlyphSequence>*/ sequences, List/*<CharAssociation>*/ associations, boolean reverse ) {
+        this ( characters, concatenateSequences ( sequences, reverse ), concatenateAssociations ( associations, reverse ) );
+    }
+
+    /**
+     * Instantiate a glyph sequence.
+     * @param characters a (possibly empty) sequence of associated (originating) characters
+     * @param glyphs a (possibly empty) list of glyphs
+     * @param associations a (possibly empty) list of glyph to character associations, one for each glyph in the concatenated glyph sequences
+     */
+    public GlyphSequence ( CharSequence characters, CharSequence glyphs, CharAssociation[] associations ) {
+        if ( ( characters == null ) || ( glyphs == null ) ) {
+            throw new IllegalArgumentException ( "characters and glyphs must be non-null" );
+        } else if ( ( associations != null ) && ( associations.length != glyphs.length() ) ) {
+            throw new IllegalArgumentException ( "number of associations must match number of glyphs" );
+        } else {
+            this.characters = characters;
+            this.glyphs = glyphs;
+            if ( associations == null ) {
+                associations = makeIdentityAssociations ( characters, glyphs );
+            }
+            this.associations = associations;
+        }
+    }
+
+    /** @return sequence of corresponding (originating) characters */
+    public CharSequence getCharacters() {
+        return characters;
+    }
+
+    /** @return sequence of glyphs in glyph sequence */
+    public CharSequence getGlyphs() {
+        return glyphs;
+    }
+
+    /** @return glyph to character associations, one for each glyph */
+    public CharAssociation[] getAssociations() {
+        return associations;
+    }
+
+    /**
+     * Obtain the sequence of characters that corresponds to the glyph sequence at interval
+     * [offset,offset+count).
+     * @param offset to first glyph
+     * @param count of glyphs
+     * @return corresponding character sequence
+     */
+    public CharSequence getCharsForGlyphs ( int offset, int count ) throws DiscontinuousAssociationException {          // CSOK: JavadocMethodCheck
+        int sFirst = -1, eLast = -1;
+        for ( int i = 0, n = count; i < n; i++ ) {
+            CharAssociation ca = associations [ offset + i ];
+            int s = ca.getStart();
+            int e = ca.getEnd();
+            if ( sFirst < 0 ) {
+                sFirst = s;
+            }
+            if ( eLast < 0 ) {
+                eLast = e;
+            } else if ( s == eLast ) {
+                eLast = e;
+            } else {
+                throw new DiscontinuousAssociationException();
+            }
+        }
+        return characters.subSequence ( sFirst, eLast );
+    }
+
+    /**
+     * Obtain the glyph subsequence corresponding to the half-open interval [start,end).
+     * @param start of subsequence
+     * @param end of subsequence
+     * @return a subsequence of this sequence
+     */
+    public GlyphSequence getGlyphSubsequence ( int start, int end ) {
+        CharAssociation[] subset = new CharAssociation[end - start];
+        System.arraycopy(associations, start, subset, 0, end - start);
+        return new GlyphSequence ( characters, glyphs.subSequence ( start, end ), subset );
+    }
+
+    /** @return the number of glyphs in this glyph sequence */
+    public int length() {
+        return glyphs.length();
+    }
+
+    /**
+     * Obtain glyph id at specified index.
+     * @param index to obtain glyph
+     * @return the glyph identifier of glyph at specified index
+     */
+    public char charAt ( int index ) {
+        return glyphs.charAt ( index );
+    }
+
+    /**
+     * Obtain glyph code subsequence over interval [start,end).
+     * @param start of subsequence
+     * @param end of subsequence
+     * @return the glyph code subsequence
+     */
+    public CharSequence subSequence ( int start, int end ) {
+        return glyphs.subSequence ( start, end );
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return glyphs.toString();
+    }
+
+    private CharAssociation[] makeIdentityAssociations ( CharSequence characters, CharSequence glyphs ) {
+        int nc = characters.length();
+        int ng = glyphs.length();
+        CharAssociation[] ca = new CharAssociation [ ng ];
+        for ( int i = 0, n = ng; i < n; i++ ) {
+            int k = ( i > nc ) ? nc : i;
+            ca [ i ] = new CharAssociation ( i, ( k == nc ) ? 0 : 1 );
+        }
+        return ca;
+    }
+
+    private static CharSequence concatenateSequences ( List/*<GlyphSequence>*/ sequences, boolean reverse ) {
+        int ng = 0;
+        for ( Iterator it = sequences.iterator(); it.hasNext();) {
+            GlyphSequence gs = (GlyphSequence) it.next();
+            ng += gs.length();
+        }
+        CharBuffer cb = CharBuffer.allocate ( ng );
+        if ( ! reverse ) {
+            for ( ListIterator it = sequences.listIterator(); it.hasNext();) {
+                GlyphSequence gs = (GlyphSequence) it.next();
+                cb.append ( (CharSequence) gs );
+            }
+        } else {
+            for ( ListIterator it = sequences.listIterator ( sequences.size() ); it.hasPrevious();) {
+                GlyphSequence gs = (GlyphSequence) it.previous();
+                cb.append ( (CharSequence) gs );
+            }
+        }
+        cb.rewind();
+        return cb;
+    }
+
+    private static CharAssociation[] concatenateAssociations ( List/*<CharAssociation>*/ associations, boolean reverse ) {
+        int na = 0;
+        CharAssociation[] ca = new CharAssociation [ associations.size() ];
+        if ( ! reverse ) {
+            for ( ListIterator it = associations.listIterator(); it.hasNext();) {
+                CharAssociation a = (CharAssociation) it.next();
+                ca [ na++ ] = a;
+            }
+        } else {
+            for ( ListIterator it = associations.listIterator ( associations.size() ); it.hasPrevious();) {
+                CharAssociation a = (CharAssociation) it.previous();
+                ca [ na++ ] = a;
+            }
+        }
+        return ca;
+    }
+
+    /**
+     * A structure class encapsulating an interval of character codes (in a CharSequence)
+     * expressed as an offset and count (of code elements in a CharSequence, i.e., numbere of
+     * UTF-16 code elements. N.B. count does not necessarily designate the number of Unicode
+     * scalar values expressed by the CharSequence; in particular, it does not do so if there
+     * is one or more UTF-16 surrogate pairs present in the CharSequence.)
+     */
+    public static class CharAssociation {
+
+        private final int offset;
+        private final int count;
+
+        /**
+         * Instantiate a character association.
+         * @param offset into array of UTF-16 code elements (in associated CharSequence)
+         * @param count of UTF-16 character code elements (in associated CharSequence)
+         */
+        public CharAssociation ( int offset, int count ) {
+            this.offset = offset;
+            this.count = count;
+        }
+
+        /** @return offset (start of association interval) */
+        public int getOffset() {
+            return offset;
+        }
+
+        /** @return count (number of characer codes in association) */
+        public int getCount() {
+            return count;
+        }
+
+        /** @return start of association interval */
+        public int getStart() {
+            return getOffset();
+        }
+
+        /** @return end of association interval */
+        public int getEnd() {
+            return getOffset() + getCount();
+        }
+
+    }
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java Thu Aug 19 19:46:41 2010
@@ -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.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphSubstitution</code> interface is implemented by a font related object
+ * that supports the determination of glyph substitution information based on script and
+ * language of the corresponding character content.
+ * @author Glenn Adams
+ */
+public interface GlyphSubstitution {
+
+    /**
+     * Perform glyph substitutions. If no substitution applies, then returns the unmodified input sequence.
+     * @param gs sequence to map to output glyph sequence
+     * @param script the script associated with the characters corresponding to the glyph sequence
+     * @param language the language associated with the characters corresponding to the glyph sequence
+     * @return resulting glyph sequence, where each 'glyph' in the returned sequence has been mapped
+     * (or not) by substitution
+     */
+    GlyphSequence substitute ( GlyphSequence gs, String script, String language );
+
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,62 @@
+/*
+ * 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.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphSubstitutionSubtable</code> implements an abstract base of a glyph substitution subtable,
+ * providing a default implementation of the <code>GlyphSubstitution</code> interface.
+ * @author Glenn Adams
+ */
+public abstract class GlyphSubstitutionSubtable extends GlyphSubtable implements GlyphSubstitution {
+
+    /**
+     * Instantiate a <code>GlyphSubstitutionSubtable</code>.
+     * @param id subtable identifier
+     * @param sequence subtable sequence
+     * @param flags subtable flags
+     * @param format subtable format
+     * @param coverage subtable coverage table
+     */
+    protected GlyphSubstitutionSubtable ( String id, int sequence, int flags, int format, GlyphCoverageTable coverage ) {
+        super ( id, sequence, flags, format, coverage );
+    }
+
+    /** {@inheritDoc} */
+    public int getTableType() {
+        return GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION;
+    }
+
+    /** {@inheritDoc} */
+    public String getTypeName() {
+        return GlyphSubstitutionTable.getLookupTypeName ( getType() );
+    }
+
+    /** {@inheritDoc} */
+    public GlyphSequence substitute ( GlyphSequence gs, String script, String language ) {
+        if ( gs == null ) {
+            throw new IllegalArgumentException ( "invalid glyph sequence: must not be null" );
+        } else {
+            return gs;
+        }
+    }
+
+}

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java
------------------------------------------------------------------------------
    svn:keywords = Id



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org