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 [5/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/ ...

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionTable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionTable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionTable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionTable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,609 @@
+/*
+ * 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.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+// CSOFF: InnerAssignmentCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphSubstitutionTable</code> class is a glyph table that implements
+ * <code>GlyphSubstitution</code> functionality.
+ * @author Glenn Adams
+ */
+public class GlyphSubstitutionTable extends GlyphTable implements GlyphSubstitution {
+
+    /** single substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_SINGLE = 1;
+    /** multiple substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_MULTIPLE = 2;
+    /** alternate substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_ALTERNATE = 3;
+    /** ligature substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_LIGATURE = 4;
+    /** context substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_CONTEXT = 5;
+    /** chaining context substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_CHAINING_CONTEXT = 6;
+    /** extension substitution substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION = 7;
+    /** reverse chaining context single substitution subtable type */
+    public static final int GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8;
+
+    /**
+     * Instantiate a <code>GlyphSubstitutionTable</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 GlyphSubstitutionTable ( 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 GlyphSubstitutionSubtable ) {
+                    addSubtable ( (GlyphSubtable) o );
+                } else {
+                    throw new IllegalArgumentException ( "subtable must be a glyph substitution 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 = GSUB_LOOKUP_TYPE_SINGLE;
+        } else if ( "multiple".equals ( s ) ) {
+            t = GSUB_LOOKUP_TYPE_MULTIPLE;
+        } else if ( "alternate".equals ( s ) ) {
+            t = GSUB_LOOKUP_TYPE_ALTERNATE;
+        } else if ( "ligature".equals ( s ) ) {
+            t = GSUB_LOOKUP_TYPE_LIGATURE;
+        } else if ( "context".equals ( s ) ) {
+            t = GSUB_LOOKUP_TYPE_CONTEXT;
+        } else if ( "chainingcontext".equals ( s ) ) {
+            t = GSUB_LOOKUP_TYPE_CHAINING_CONTEXT;
+        } else if ( "extensionsubstitution".equals ( s ) ) {
+            t = GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION;
+        } else if ( "reversechainiingcontextsingle".equals ( s ) ) {
+            t = GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE;
+        } 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 = null;
+        switch ( type ) {
+        case GSUB_LOOKUP_TYPE_SINGLE:
+            tn = "single";
+            break;
+        case GSUB_LOOKUP_TYPE_MULTIPLE:
+            tn = "multiple";
+            break;
+        case GSUB_LOOKUP_TYPE_ALTERNATE:
+            tn = "alternate";
+            break;
+        case GSUB_LOOKUP_TYPE_LIGATURE:
+            tn = "ligature";
+            break;
+        case GSUB_LOOKUP_TYPE_CONTEXT:
+            tn = "context";
+            break;
+        case GSUB_LOOKUP_TYPE_CHAINING_CONTEXT:
+            tn = "chainingcontext";
+            break;
+        case GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION:
+            tn = "extensionsubstitution";
+            break;
+        case GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
+            tn = "reversechainiingcontextsingle";
+            break;
+        default:
+            tn = "unknown";
+            break;
+        }
+        return tn;
+    }
+
+    /**
+     * Create a substitution 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 ) {
+        GlyphSubtable st = null;
+        switch ( type ) {
+        case GSUB_LOOKUP_TYPE_SINGLE:
+            st = new SimpleSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        case GSUB_LOOKUP_TYPE_MULTIPLE:
+            st = new MultipleSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        case GSUB_LOOKUP_TYPE_ALTERNATE:
+            st = new AlternateSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        case GSUB_LOOKUP_TYPE_LIGATURE:
+            st = new LigatureSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        case GSUB_LOOKUP_TYPE_CONTEXT:
+            st = new ContextSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        case GSUB_LOOKUP_TYPE_CHAINING_CONTEXT:
+            st = new ChainingContextSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        case GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION:
+            st = new ExtensionSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        case GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
+            st = new ReverseChainingSingleSubtable ( id, sequence, flags, format, coverage, entries );
+            break;
+        default:
+            break;
+        }
+        return st;
+    }
+
+    /** {@inheritDoc} */
+    public GlyphSequence substitute ( GlyphSequence gs, String script, String language ) {
+        GlyphSequence ogs;
+        Map/*<LookupSpec,GlyphSubtable[]>*/ lookups = matchLookups ( script, language, "*" );
+        if ( ( lookups != null ) && ( lookups.size() > 0 ) ) {
+            ScriptProcessor sp = ScriptProcessor.getInstance ( script );
+            ogs = sp.substitute ( gs, script, language, lookups );
+        } else {
+            ogs = gs;
+        }
+        return ogs;
+    }
+
+    static class SimpleSubtable extends GlyphSubstitutionSubtable {
+        private int[] map;
+        public SimpleSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+            populate ( entries );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_SINGLE;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            List entries = new ArrayList ( map.length );
+            for ( int i = 0, n = map.length; i < n; i++ ) {
+                entries.add ( Integer.valueOf ( map[i] ) );
+            }
+            return entries;
+        }
+        /** {@inheritDoc} */
+        public GlyphSequence substitute ( GlyphSequence gs, String script, String language ) {
+            CharBuffer cb = CharBuffer.allocate ( gs.length() );
+            int ng = 0;
+            for ( int i = 0; i < gs.length(); i++ ) {
+                int gi = gs.charAt ( i );
+                int ci, go = gi;
+                if ( ( ci = getCoverageIndex ( gi ) ) >= 0 ) {
+                    assert ci < map.length : "coverage index out of range";
+                    if ( ci < map.length ) {
+                        go = map [ ci ];
+                    }
+                }
+                if ( ( go < 0 ) || ( go > 65535 ) ) {
+                    go = 65535;
+                }
+                cb.put ( (char) go );
+                ng++;
+            }
+            cb.limit(ng);
+            cb.rewind();
+            return new GlyphSequence ( gs.getCharacters(), (CharSequence) cb, null );
+        }
+        private void populate ( List entries ) {
+            int i = 0, n = entries.size();
+            int[] map = new int [ n ];
+            for ( Iterator it = entries.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if ( o instanceof Integer ) {
+                    int gid = ( (Integer) o ) .intValue();
+                    if ( ( gid >= 0 ) && ( gid < 65536 ) ) {
+                        map [ i++ ] = gid;
+                    } else {
+                        throw new IllegalArgumentException ( "illegal glyph index: " + gid );
+                    }
+                } else {
+                    throw new IllegalArgumentException ( "illegal entries entry, must be Integer: " + o );
+                }
+            }
+            assert i == n;
+            assert this.map == null;
+            this.map = map;
+        }
+        /** {@inheritDoc} */
+        public String toString() {
+            StringBuffer sb = new StringBuffer(super.toString());
+            sb.append('{');
+            sb.append("coverage=");
+            sb.append(getCoverage().toString());
+            sb.append(",entries={");
+            for ( int i = 0, n = map.length; i < n; i++ ) {
+                if ( i > 0 ) {
+                    sb.append(',');
+                }
+                sb.append(Integer.toString(map[i]));
+            }
+            sb.append('}');
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    static class MultipleSubtable extends GlyphSubstitutionSubtable {
+        public MultipleSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_MULTIPLE;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            return null; // [TBD] - implement me
+        }
+    }
+
+    static class AlternateSubtable extends GlyphSubstitutionSubtable {
+        public AlternateSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_ALTERNATE;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            return null; // [TBD] - implement me
+        }
+    }
+
+    static class LigatureSubtable extends GlyphSubstitutionSubtable {
+        private LigatureSet[] map;
+        public LigatureSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+            populate ( entries );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_LIGATURE;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            List entries = new ArrayList ( map.length );
+            for ( int i = 0, n = map.length; i < n; i++ ) {
+                entries.add ( map[i] );
+            }
+            return entries;
+        }
+        /** {@inheritDoc} */
+        public GlyphSequence substitute ( GlyphSequence gs, String script, String language ) {
+            CharBuffer cb = CharBuffer.allocate ( gs.length() );
+            int ng = 0;
+            for ( int i = 0, n = gs.length(); i < n; i++ ) {
+                int gi = gs.charAt ( i );
+                int ci, go = gi;
+                LigatureSet ls = null;
+                if ( ( ci = getCoverageIndex ( gi ) ) >= 0 ) {
+                    assert ci < map.length : "coverage index out of range";
+                    if ( ci < map.length ) {
+                        ls = map [ ci ];
+                    }
+                }
+                if ( ls != null ) {
+                    Ligature l;
+                    if ( ( l = findLigature ( ls, gs, i ) ) != null ) {
+                        go = l.getLigature();
+                        i += l.getNumComponents();
+                    }
+                }
+                if ( ( go < 0 ) || ( go > 65535 ) ) {
+                    go = 65535;
+                }
+                cb.put ( (char) go );
+                ng++;
+            }
+            cb.limit(ng);
+            cb.rewind();
+            return new GlyphSequence ( gs.getCharacters(), (CharSequence) cb, null );
+        }
+        private void populate ( List entries ) {
+            int i = 0, n = entries.size();
+            LigatureSet[] map = new LigatureSet [ n ];
+            for ( Iterator it = entries.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if ( o instanceof LigatureSet ) {
+                    map [ i++ ] = (LigatureSet) o;
+                } else {
+                    throw new IllegalArgumentException ( "illegal ligatures entry, must be LigatureSet: " + o );
+                }
+            }
+            assert i == n;
+            assert this.map == null;
+            this.map = map;
+        }
+        private Ligature findLigature ( LigatureSet ls, CharSequence cs, int offset ) {
+            Ligature[] la = ls.getLigatures();
+            int k = -1;
+            int maxComponents = -1;
+            for ( int i = 0, n = la.length; i < n; i++ ) {
+                Ligature l = la [ i ];
+                if ( l.matchesComponents ( cs, offset + 1 ) ) {
+                    int nc = l.getNumComponents();
+                    if ( nc > maxComponents ) {
+                        maxComponents = nc;
+                        k = i;
+                    }
+                }
+            }
+            if ( k >= 0 ) {
+                return la [ k ];
+            } else {
+                return null;
+            }
+        }
+        /** {@inheritDoc} */
+        public String toString() {
+            StringBuffer sb = new StringBuffer(super.toString());
+            sb.append('{');
+            sb.append("coverage=");
+            sb.append(getCoverage().toString());
+            sb.append(",entries={");
+            for ( int i = 0, n = map.length; i < n; i++ ) {
+                if ( i > 0 ) {
+                    sb.append(',');
+                }
+                sb.append(map[i]);
+            }
+            sb.append('}');
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    static class ContextSubtable extends GlyphSubstitutionSubtable {
+        public ContextSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_CONTEXT;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            return null; // [TBD] - implement me
+        }
+    }
+
+    static class ChainingContextSubtable extends GlyphSubstitutionSubtable {
+        public ChainingContextSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_CHAINING_CONTEXT;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            return null; // [TBD] - implement me
+        }
+    }
+
+    static class ExtensionSubtable extends GlyphSubstitutionSubtable {
+        public ExtensionSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            return null; // [TBD] - implement me
+        }
+    }
+
+    static class ReverseChainingSingleSubtable extends GlyphSubstitutionSubtable {
+        public ReverseChainingSingleSubtable ( String id, int sequence, int flags, int format, List coverage, List entries ) {
+            super ( id, sequence, flags, format, GlyphCoverageTable.createCoverageTable ( coverage ) );
+        }
+        /** {@inheritDoc} */
+        public int getType() {
+            return GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE;
+        }
+        /** {@inheritDoc} */
+        public List getEntries() {
+            return null; // [TBD] - implement me
+        }
+    }
+
+    /**
+     * The <code>Ligature</code> class implements a ligature lookup result in terms of
+     * a ligature glyph (code) and the <emph>N+1...</emph> components that comprise the ligature,
+     * where the <emph>Nth</emph> component was consumed in the coverage table lookup mapping to
+     * this ligature instance.
+     */
+    public static class Ligature {
+
+        private final int ligature;                     // (resulting) ligature glyph 
+        private final int[] components;                 // component glyph codes (note that first component is implied)
+
+        /**
+         * Instantiate a ligature.
+         * @param ligature glyph id
+         * @param components sequence of <emph>N+1...</emph> component glyph (or character) identifiers
+         */
+        public Ligature ( int ligature, int[] components ) {
+            if ( ( ligature < 0 ) || ( ligature > 65535 ) ) {
+                throw new IllegalArgumentException ( "invalid ligature glyph index: " + ligature );
+            } else if ( ( components == null ) || ( components.length == 0 ) ) {
+                throw new IllegalArgumentException ( "invalid ligature components, must be non-empty array" );
+            } else {
+                for ( int i = 0, n = components.length; i < n; i++ ) {
+                    int c = components [ i ];
+                    if ( ( c < 0 ) || ( c > 65535 ) ) {
+                        throw new IllegalArgumentException ( "invalid component glyph index: " + c );
+                    }
+                }
+                this.ligature = ligature;
+                this.components = components;
+            }
+        }
+
+        /** @return ligature glyph id */
+        public int getLigature() {
+            return ligature;
+        }
+
+        /** @return array of <emph>N+1...</emph> components */
+        public int[] getComponents() {
+            return components;
+        }
+
+        /** @return components count */
+        public int getNumComponents() {
+            return components.length;
+        }
+
+        /**
+         * Determine of input sequence at offset matches ligature's components.
+         * @param cs glyph (or character) sequence to match this ligature against
+         * @param offset index at which to start matching the components of this ligature
+         * @return true if matches
+         */
+        public boolean matchesComponents ( CharSequence cs, int offset ) {
+            if ( ( offset + components.length ) > cs.length() ) {
+                return false;
+            } else {
+                for ( int i = 0, n = components.length; i < n; i++ ) {
+                    if ( (int) cs.charAt ( offset + i ) != components [ i ] ) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+
+        /** {@inheritDoc} */
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            sb.append("{components={");
+            for ( int i = 0, n = components.length; i < n; i++ ) {
+                if ( i > 0 ) {
+                    sb.append(',');
+                }
+                sb.append(Integer.toString(components[i]));
+            }
+            sb.append("},ligature=");
+            sb.append(Integer.toString(ligature));
+            sb.append("}");
+            return sb.toString();
+        }
+
+    }
+
+    /**
+     * The <code>LigatureSet</code> class implements a set of  ligatures.
+     */
+    public static class LigatureSet {
+
+        private final Ligature[] ligatures;                     // set of ligatures all of which share the first (implied) component
+
+        /**
+         * Instantiate a set of ligatures.
+         * @param ligatures collection of ligatures
+         */
+        public LigatureSet ( List ligatures ) {
+            this ( (Ligature[]) ligatures.toArray ( new Ligature [ ligatures.size() ] ) );
+        }
+
+        /**
+         * Instantiate a set of ligatures.
+         * @param ligatures array of ligatures
+         */
+        public LigatureSet ( Ligature[] ligatures ) {
+            if ( ( ligatures == null ) || ( ligatures.length == 0 ) ) {
+                throw new IllegalArgumentException ( "invalid ligatures, must be non-empty array" );
+            } else {
+                this.ligatures = ligatures;
+            }
+        }
+
+        /** @return array of ligatures in this ligature set */
+        public Ligature[] getLigatures() {
+            return ligatures;
+        }
+
+        /** @return count of ligatures in this ligature set */
+        public int getNumLigatures() {
+            return ligatures.length;
+        }
+
+        /** {@inheritDoc} */
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            sb.append("{ligs={");
+            for ( int i = 0, n = ligatures.length; i < n; i++ ) {
+                if ( i > 0 ) {
+                    sb.append(',');
+                }
+                sb.append(ligatures[i]);
+            }
+            sb.append("}}");
+            return sb.toString();
+        }
+
+    }
+
+}

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

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

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubtable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubtable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubtable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubtable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,108 @@
+/*
+ * 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.List;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphSubtable</code> implements an abstract glyph subtable that
+ * encapsulates identification, type, format, and coverage information.
+ * @author Glenn Adams
+ */
+public abstract class GlyphSubtable {
+
+    private String id;
+    private int sequence;
+    private int flags;
+    private int format;
+    private GlyphCoverageTable coverage;
+
+    /**
+     * Instantiate this glyph subtable.
+     * @param id subtable identifier
+     * @param sequence subtable sequence
+     * @param flags subtable flags
+     * @param format subtable format
+     * @param coverage subtable coverage table
+     */
+    protected GlyphSubtable ( String id, int sequence, int flags, int format, GlyphCoverageTable coverage )
+    {
+        if ( ( id == null ) || ( id.length() == 0 ) ) {
+            throw new IllegalArgumentException ( "invalid lookup identifier, must be non-empty string" );
+        } else if ( coverage == null ) {
+            throw new IllegalArgumentException ( "invalid coverage table, must not be null" );
+        } else {
+            this.id = id;
+            this.sequence = sequence;
+            this.flags = flags;
+            this.format = format;
+            this.coverage = coverage;
+        }
+    }
+
+    /** @return this subtable's identifer */
+    public String getID() {
+        return id;
+    }
+
+    /** @return this subtable's table type */
+    public abstract int getTableType();
+
+    /** @return this subtable's type */
+    public abstract int getType();
+
+    /** @return this subtable's type name */
+    public abstract String getTypeName();
+
+    /** @return this subtable's sequence */
+    public int getSequence() {
+        return sequence;
+    }
+
+    /** @return this subtable's flags */
+    public int getFlags() {
+        return flags;
+    }
+
+    /** @return this subtable's format */
+    public int getFormat() {
+        return format;
+    }
+
+    /** @return this subtable's coverage table */
+    public GlyphCoverageTable getCoverage() {
+        return coverage;
+    }
+
+    /** @return this subtable's lookup entries */
+    public abstract List getEntries();
+
+    /**
+     * Map glyph id to coverage index.
+     * @param gid glyph id
+     * @return the corresponding coverage index of the specified glyph id
+     */
+    public int getCoverageIndex ( int gid ) {
+        return coverage.getCoverageIndex ( gid );
+    }
+
+}

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

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

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphTable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphTable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphTable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphTable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,289 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: InnerAssignmentCheck
+// CSOFF: SimplifyBooleanReturnCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * Base class for all advanced typographic glyph tables.
+ * @author Glenn Adams
+ */
+public class GlyphTable {
+
+    /** substitution glyph table type */
+    public static final int GLYPH_TABLE_TYPE_SUBSTITUTION = 1;
+    /** positioning glyph table type */
+    public static final int GLYPH_TABLE_TYPE_POSITIONING = 2;
+    /** justification glyph table type */
+    public static final int GLYPH_TABLE_TYPE_JUSTIFICATION = 3;
+    /** baseline glyph table type */
+    public static final int GLYPH_TABLE_TYPE_BASELINE = 4;
+    /** definition glyph table type */
+    public static final int GLYPH_TABLE_TYPE_DEFINITION = 5;
+
+    // map from lookup specs to lists of strings, each naming a subtable
+    private Map /*<LookupSpec,List>*/ lookups;
+
+    // map from subtable names to glyph subtables
+    private Map /*<String,GlyphSubtable>*/ subtables;
+
+    /**
+     * Instantiate glyph table with specified lookups.
+     * @param lookups map from lookup specs to lookup tables
+     */
+    public GlyphTable ( Map /*<LookupSpec,List>*/ lookups ) {
+        if ( ( lookups == null ) || ( lookups.size() == 0 ) ) {
+            throw new IllegalArgumentException ( "lookups must be non-empty map" );
+        } else {
+            this.lookups = lookups;
+            this.subtables = new LinkedHashMap();
+        }
+    }
+
+    /**
+     * Obain array of lookup specifications.
+     * @return (possibly empty) array of all lookup specifications
+     */
+    public LookupSpec[] getLookups() {
+        return matchLookupSpecs ( "*", "*", "*" );
+    }
+
+    /**
+     * Obain array of lookup subtables.
+     * @return (possibly empty) array of all lookup subtables
+     */
+    public GlyphSubtable[] getSubtables() {
+        Collection values = subtables.values();
+        return (GlyphSubtable[]) values.toArray ( new GlyphSubtable [ values.size() ] );
+    }
+
+    /**
+     * Add a subtable.
+     * @param subtable a (non-null) glyph subtable
+     */
+    public void addSubtable ( GlyphSubtable subtable ) {
+        subtables.put ( subtable.getID(), subtable );
+    }
+
+    /**
+     * Match lookup specifications according to <script,language,feature> tuple, where
+     * '*' is a wildcard for a tuple component.
+     * @param script a script identifier
+     * @param language a language identifier
+     * @param feature a feature identifier
+     * @return a (possibly empty) array of matching lookup specifications
+     */
+    public LookupSpec[] matchLookupSpecs ( String script, String language, String feature ) {
+        Set/*<LookupSpec>*/ keys = lookups.keySet();
+        List matches = new ArrayList();
+        for ( Iterator it = keys.iterator(); it.hasNext();) {
+            LookupSpec ls = (LookupSpec) it.next();
+            if ( ! "*".equals(script) ) {
+                if ( ! ls.getScript().equals ( script ) ) {
+                    continue;
+                }
+            }
+            if ( ! "*".equals(language) ) {
+                if ( ! ls.getLanguage().equals ( language ) ) {
+                    continue;
+                }
+            }
+            if ( ! "*".equals(feature) ) {
+                if ( ! ls.getFeature().equals ( feature ) ) {
+                    continue;
+                }
+            }
+            matches.add ( ls );
+        }
+        return (LookupSpec[]) matches.toArray ( new LookupSpec [ matches.size() ] );
+    }
+
+    /**
+     * Match lookup specifications according to <script,language,feature> tuple, where
+     * '*' is a wildcard for a tuple component.
+     * @param script a script identifier
+     * @param language a language identifier
+     * @param feature a feature identifier
+     * @return a (possibly empty) map of matching lookup specifications and their corresponding subtables
+     */
+    public Map/*<LookupSpec,GlyphSubtable[]>*/ matchLookups ( String script, String language, String feature ) {
+        LookupSpec[] lsa = matchLookupSpecs ( script, language, feature );
+        Map lm = new LinkedHashMap();
+        for ( int i = 0, n = lsa.length; i < n; i++ ) {
+            lm.put ( lsa [ i ], findSubtables ( lsa [ i ] ) );
+        }
+        return lm;
+    }
+
+    /**
+     * Find glyph subtables that match a secific lookup specification.
+     * @param ls a (non-null) lookup specification
+     * @return a (possibly empty) array of subtables whose lookup specification matches the specified lookup spec
+     */
+    public GlyphSubtable[] findSubtables ( LookupSpec ls ) {
+        GlyphSubtable[] staEmpty = new GlyphSubtable [ 0 ];
+        List ids;
+        if ( ( ids = (List) lookups.get ( ls ) ) != null ) {
+            List stl = new ArrayList();
+            for ( Iterator it = ids.iterator(); it.hasNext();) {
+                String id = (String) it.next();
+                GlyphSubtable st;
+                if ( ( st = (GlyphSubtable) subtables.get ( id ) ) != null ) {
+                    stl.add ( st );
+                }
+            }
+            return (GlyphSubtable[]) stl.toArray ( staEmpty );
+        } else {
+            return staEmpty;
+        }
+    }
+
+    /**
+     * Obtain glyph table type from name.
+     * @param name of table type to map to type value
+     * @return glyph table type (as an integer constant)
+     */
+    public static int getTableTypeFromName ( String name ) {
+        int t;
+        String s = name.toLowerCase();
+        if ( "gsub".equals ( s ) ) {
+            t = GLYPH_TABLE_TYPE_SUBSTITUTION;
+        } else if ( "gpos".equals ( s ) ) {
+            t = GLYPH_TABLE_TYPE_POSITIONING;
+        } else if ( "jstf".equals ( s ) ) {
+            t = GLYPH_TABLE_TYPE_JUSTIFICATION;
+        } else if ( "base".equals ( s ) ) {
+            t = GLYPH_TABLE_TYPE_BASELINE;
+        } else if ( "gdef".equals ( s ) ) {
+            t = GLYPH_TABLE_TYPE_DEFINITION;
+        } else {
+            t = -1;
+        }
+        return t;
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        StringBuffer sb = new StringBuffer(super.toString());
+        sb.append("{");
+        sb.append("lookups={");
+        sb.append(lookups.toString());
+        sb.append("},subtables={");
+        sb.append(subtables.toString());
+        sb.append("}}");
+        return sb.toString();
+    }
+
+    /**
+     * A structure class encapsulating a lookup specification as a <script,language,feature> tuple.
+     */
+    public static class LookupSpec {
+
+        private final String script;
+        private final String language;
+        private final String feature;
+
+        /**
+         * Instantiate lookup spec.
+         * @param script a script identifier
+         * @param language a language identifier
+         * @param feature a feature identifier
+         */
+        public LookupSpec ( String script, String language, String feature ) {
+            if ( ( script == null ) || ( script.length() == 0 ) ) {
+                throw new IllegalArgumentException ( "script must be non-empty string" );
+            } else if ( ( language == null ) || ( language.length() == 0 ) ) {
+                throw new IllegalArgumentException ( "language must be non-empty string" );
+            } else if ( ( feature == null ) || ( feature.length() == 0 ) ) {
+                throw new IllegalArgumentException ( "feature must be non-empty string" );
+            } else {
+                this.script = script;
+                this.language = language;
+                this.feature = feature;
+            }
+        }
+
+        /** @return script identifier */
+        public String getScript() {
+            return script;
+        }
+
+        /** @return language identifier */
+        public String getLanguage() {
+            return language;
+        }
+
+        /** @return feature identifier  */
+        public String getFeature() {
+            return feature;
+        }
+
+        /** {@inheritDoc} */
+        public int hashCode() {
+            int h = 0;
+            h = 31 * h + script.hashCode();
+            h = 31 * h + language.hashCode();
+            h = 31 * h + feature.hashCode();
+            return h;
+        }
+
+        /** {@inheritDoc} */
+        public boolean equals ( Object o ) {
+            if ( o instanceof LookupSpec ) {
+                LookupSpec l = (LookupSpec) o;
+                if ( ! l.script.equals ( script ) ) {
+                    return false;
+                } else if ( ! l.language.equals ( language ) ) {
+                    return false;
+                } else if ( ! l.feature.equals ( feature ) ) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else {
+                return false;
+            }
+        }
+
+        /** {@inheritDoc} */
+        public String toString() {
+            StringBuffer sb = new StringBuffer(super.toString());
+            sb.append("{");
+            sb.append("<'" + script + "'");
+            sb.append(",'" + language + "'");
+            sb.append(",'" + feature + "'");
+            sb.append(">}");
+            return sb.toString();
+        }
+
+    }
+
+}

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

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

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphUtils.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphUtils.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphUtils.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphUtils.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+/**
+ * A utility class for glyphs and glyph sequences.
+ * @author Glenn Adams
+ */
+public final class GlyphUtils {
+
+    private GlyphUtils() {
+    }
+
+    /**
+     * Map a glyph (or character) code sequence to  a string, used only
+     * for debugging and logging purposes.
+     * @param cs character (glyph) id sequence
+     * @return a string representation of code sequence
+     */
+    public static String toString ( CharSequence cs ) {
+        StringBuffer sb = new StringBuffer();
+        sb.append ( '[' );
+        for ( int i = 0, n = cs.length(); i < n; i++ ) {
+            int c = cs.charAt ( i );
+            if ( i > 0 ) {
+                sb.append ( ',' );
+            }
+            sb.append ( Integer.toString ( c ) );
+        }
+        sb.append ( ']' );
+        return sb.toString();
+    }
+
+}

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

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

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/IncompatibleSubtableException.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/IncompatibleSubtableException.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/IncompatibleSubtableException.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/IncompatibleSubtableException.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+/**
+ * Exception thrown during when attempting to map glyphs to associated characters
+ * in the case that the associated characters do not represent a compact interval.
+ * @author Glenn Adams
+ */
+public class IncompatibleSubtableException extends RuntimeException {
+    /**
+     * Instantiate incompatible subtable exception
+     */
+    public IncompatibleSubtableException() {
+        super();
+    }
+    /**
+     * Instantiate incompatible subtable exception
+     * @param message a message string
+     */
+    public IncompatibleSubtableException(String message) {
+        super(message);
+    }
+}

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

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

Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/LazyFont.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/LazyFont.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/LazyFont.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/LazyFont.java Thu Aug 19 19:46:41 2010
@@ -37,22 +37,23 @@ import org.apache.fop.apps.FOPException;
 /**
  * This class is used to defer the loading of a font until it is really used.
  */
-public class LazyFont extends Typeface implements FontDescriptor {
+public class LazyFont extends Typeface implements FontDescriptor, Substitutable, Positionable {
 
     private static Log log = LogFactory.getLog(LazyFont.class);
 
-    private String metricsFileName = null;
-    private String fontEmbedPath = null;
-    private boolean useKerning = false;
+    private String metricsFileName;
+    private String fontEmbedPath;
+    private boolean useKerning;
+    private boolean useAdvanced;
     private EncodingMode encodingMode = EncodingMode.AUTO;
-    private boolean embedded = true;
-    private String subFontName = null;
+    private boolean embedded;
+    private String subFontName;
 
-    private boolean isMetricsLoaded = false;
-    private Typeface realFont = null;
-    private FontDescriptor realFontDescriptor = null;
+    private boolean isMetricsLoaded;
+    private Typeface realFont;
+    private FontDescriptor realFontDescriptor;
 
-    private FontResolver resolver = null;
+    private FontResolver resolver;
 
     /**
      * Main constructor
@@ -64,6 +65,7 @@ public class LazyFont extends Typeface i
         this.metricsFileName = fontInfo.getMetricsFile();
         this.fontEmbedPath = fontInfo.getEmbedFile();
         this.useKerning = fontInfo.getKerning();
+        this.useAdvanced = fontInfo.getAdvanced();
         this.encodingMode = fontInfo.getEncodingMode();
         this.subFontName = fontInfo.getSubFontName();
         this.embedded = fontInfo.isEmbedded();
@@ -72,9 +74,15 @@ public class LazyFont extends Typeface i
 
     /** {@inheritDoc} */
     public String toString() {
-        return ( "metrics-url=" + metricsFileName + ", embed-url=" + fontEmbedPath
-                + ", kerning=" + useKerning );
-    }
+        StringBuffer sbuf = new StringBuffer(super.toString());
+        sbuf.append('{');
+        sbuf.append("metrics-url=" + metricsFileName);
+        sbuf.append(",embed-url=" + fontEmbedPath);
+        sbuf.append(",kerning=" + useKerning);
+        sbuf.append(",advanced=" + useAdvanced);
+        sbuf.append('}');
+        return sbuf.toString();
+    }   
 
     private void load(boolean fail) {
         if (!isMetricsLoaded) {
@@ -122,6 +130,7 @@ public class LazyFont extends Typeface i
                                     new URL(metricsFileName).openStream()));
                     }
                     reader.setKerningEnabled(useKerning);
+                    reader.setAdvancedEnabled(useAdvanced);
                     if (this.embedded) {
                         reader.setFontEmbedPath(fontEmbedPath);
                     }
@@ -132,7 +141,7 @@ public class LazyFont extends Typeface i
                         throw new RuntimeException("Cannot load font. No font URIs available.");
                     }
                     realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName,
-                            this.embedded, this.encodingMode, useKerning, resolver);
+                            this.embedded, this.encodingMode, useKerning, useAdvanced, resolver);
                 }
                 if (realFont instanceof FontDescriptor) {
                     realFontDescriptor = (FontDescriptor) realFont;
@@ -375,5 +384,53 @@ public class LazyFont extends Typeface i
         return realFontDescriptor.isEmbeddable();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public boolean performsSubstitution() {
+        load(true);
+        if ( realFontDescriptor instanceof Substitutable ) {
+            return ((Substitutable)realFontDescriptor).performsSubstitution();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public CharSequence performSubstitution ( CharSequence cs, String script, String language ) {
+        load(true);
+        if ( realFontDescriptor instanceof Substitutable ) {
+            return ((Substitutable)realFontDescriptor).performSubstitution(cs, script, language);
+        } else {
+            return cs;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean performsPositioning() {
+        load(true);
+        if ( realFontDescriptor instanceof Substitutable ) {
+            return ((Positionable)realFontDescriptor).performsPositioning();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int[] performPositioning ( CharSequence cs, String script, String language ) {
+        load(true);
+        if ( realFontDescriptor instanceof Substitutable ) {
+            return ((Positionable)realFontDescriptor).performPositioning(cs, script, language);
+        } else {
+            return null;
+        }
+    }
+
 }
 

Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MultiByteFont.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MultiByteFont.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MultiByteFont.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MultiByteFont.java Thu Aug 19 19:46:41 2010
@@ -20,6 +20,7 @@
 package org.apache.fop.fonts;
 
 //Java
+import java.nio.CharBuffer;
 import java.text.DecimalFormat;
 import java.util.Map;
 
@@ -27,7 +28,7 @@ import java.util.Map;
 /**
  * Generic MultiByte (CID) font
  */
-public class MultiByteFont extends CIDFont {
+public class MultiByteFont extends CIDFont implements Substitutable, Positionable {
 
     private static int uniqueCounter = -1;
 
@@ -44,6 +45,10 @@ public class MultiByteFont extends CIDFo
     /** A map from Unicode indices to glyph indices */
     private BFEntry[] bfentries = null;
 
+    /* advanced typographic support */
+    private GlyphSubstitutionTable gsub;
+    private GlyphPositioningTable gpos;
+
     /**
      * Default constructor
      */
@@ -157,8 +162,9 @@ public class MultiByteFont extends CIDFo
      * @param c the Unicode character index
      * @return the glyph index (or 0 if the glyph is not available)
      */
-    private int findGlyphIndex(char c) {
-        int idx = (int)c;
+    // [TBD] - needs optimization
+    private int findGlyphIndex(int c) {
+        int idx = c;
         int retIdx = SingleByteEncoding.NOT_FOUND_CODE_POINT;
 
         for (int i = 0; (i < bfentries.length) && retIdx == 0; i++) {
@@ -173,6 +179,29 @@ public class MultiByteFont extends CIDFo
         return retIdx;
     }
 
+    /**
+     * Returns the Unicode scalar value that corresponds to the glyph index. If more than
+     * one correspondence exists, then the first one is returned (ordered by bfentries[]).
+     * If the glyph index is Typeface.NOT_FOUND, then returns the Unicode replacement
+     * character (0x00FFFD).
+     * @param gi glyph index
+     * @returns unicode scalar value
+     */
+    // [TBD] - needs optimization
+    private int findCharacterFromGlyphIndex ( int gi ) {
+        int cc = 0;
+        for ( int i = 0, n = bfentries.length; i < n; i++ ) {
+            BFEntry be = bfentries [ i ];
+            int s = be.getGlyphStartIndex();
+            int e = s + ( be.getUnicodeEnd() - be.getUnicodeStart() );
+            if ( ( gi >= s ) && ( gi <= e ) ) {
+                cc = be.getUnicodeStart() + ( gi - s );
+                break;
+            }
+        }
+        return cc;
+    }
+
     /** {@inheritDoc} */
     public char mapChar(char c) {
         notifyMapOperation();
@@ -248,5 +277,153 @@ public class MultiByteFont extends CIDFo
         }
         return subset.getSubsetChars();
     }
+
+    /**
+     * Establishes the glyph substitution table.
+     * @param gsub the glyph substitution table to be used by this font
+     */
+    public void setGSUB ( GlyphSubstitutionTable gsub ) {
+        if ( ( this.gsub == null ) || ( gsub == null ) ) {
+            this.gsub = gsub;
+        } else {
+            throw new IllegalStateException ( "font already associated with GSUB table" );
+        }
+    }
+
+    /**
+     * Obtain glyph substitution table.
+     * @return glyph substitution table or null if none is associated with font
+     */
+    public GlyphSubstitutionTable getGSUB() {
+        return gsub;
+    }
+
+    /**
+     * Establishes the glyph positioning table.
+     * @param gpos the glyph positioning table to be used by this font
+     */
+    public void setGPOS ( GlyphPositioningTable gpos ) {
+        if ( ( this.gpos == null ) || ( gpos == null ) ) {
+            this.gpos = gpos;
+        } else {
+            throw new IllegalStateException ( "font already associated with GPOS table" );
+        }
+    }
+
+    /**
+     * Obtain glyph positioning table.
+     * @return glyph positioning table or null if none is associated with font
+     */
+    public GlyphPositioningTable getGPOS() {
+        return gpos;
+    }
+
+    /** {@inheritDoc} */
+    public boolean performsSubstitution() {
+        return gsub != null;
+    }
+
+    /** {@inheritDoc} */
+    public CharSequence performSubstitution ( CharSequence cs, String script, String language ) {
+        if ( gsub != null ) {
+            GlyphSequence igs = mapCharsToGlyphs ( cs );
+            GlyphSequence ogs = gsub.substitute ( igs, script, language );
+            CharSequence ocs = mapGlyphsToChars ( ogs );
+            return ocs;
+        } else {
+            return cs;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public boolean performsPositioning() {
+        return gpos != null;
+    }
+
+    /** {@inheritDoc} */
+    public int[] performPositioning ( CharSequence cs, String script, String language ) {
+        if ( gpos != null ) {
+            return gpos.position ( mapCharsToGlyphs ( cs ), script, language );
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Map sequence CS, comprising a sequence of UTF-16 encoded Unicode Code Points, to
+     * an output character sequence GS, comprising a sequence of Glyph Indices. N.B. Unlike
+     * mapChar(), this method does not make use of embedded subset encodings.
+     * @param cs a CharSequence containing UTF-16 encoded Unicode characters
+     * @returns a CharSequence containing glyph indices
+     */
+    private GlyphSequence mapCharsToGlyphs ( CharSequence cs ) {
+        CharBuffer cb = CharBuffer.allocate ( cs.length() );
+        int gi, giMissing = findGlyphIndex ( Typeface.NOT_FOUND );
+        for ( int i = 0, n = cs.length(); i < n; i++ ) {
+            int cc = cs.charAt ( i );
+            if ( ( cc >= 0xD800 ) && ( cc < 0xDC00 ) ) {
+                if ( ( i + 1 ) < n ) {
+                    int sh = cc;
+                    int sl = cs.charAt ( ++i );
+                    if ( ( sl >= 0xDC00 ) && ( sl < 0xE000 ) ) {
+                        cc = 0x10000 + ( ( sh - 0xD800 ) << 10 ) + ( ( sl - 0xDC00 ) << 0 );
+                    } else {
+                        throw new IllegalArgumentException
+                            (  "ill-formed UTF-16 sequence, "
+                               + "contains isolated high surrogate at index " + i );
+                    }
+                } else {
+                    throw new IllegalArgumentException
+                        ( "ill-formed UTF-16 sequence, "
+                          + "contains isolated high surrogate at end of sequence" );
+                }
+            } else if ( ( cc >= 0xDC00 ) && ( cc < 0xE000 ) ) {
+                throw new IllegalArgumentException
+                    ( "ill-formed UTF-16 sequence, "
+                      + "contains isolated low surrogate at index " + i );
+            }
+            gi = findGlyphIndex ( cc );
+            if ( gi == SingleByteEncoding.NOT_FOUND_CODE_POINT ) {
+                gi = giMissing;
+            }
+            cb.put ( (char) gi );
+        }
+        cb.rewind();
+        return new GlyphSequence ( cs, (CharSequence) cb, null );
+    }
+
+    /**
+     * Map sequence GS, comprising a sequence of Glyph Indices, to output sequence CS,
+     * comprising a sequence of UTF-16 encoded Unicode Code Points.
+     * @param gs a CharSequence containing glyph indices
+     * @returns a CharSequence containing UTF-16 encoded Unicode characters
+     */
+    private CharSequence mapGlyphsToChars ( GlyphSequence gs ) {
+        CharBuffer cb = CharBuffer.allocate ( gs.length() );
+        int cc, ccMissing = Typeface.NOT_FOUND;
+        for ( int i = 0, n = gs.length(); i < n; i++ ) {
+            int gi = gs.charAt ( i );
+            cc = findCharacterFromGlyphIndex ( gi );
+            if ( cc == 0 ) {
+                cc = ccMissing;
+            }
+            if ( cc > 0x10FFFF ) {
+                cc = ccMissing;
+            }
+            if ( cc > 0x00FFFF ) {
+                int sh, sl;
+                cc -= 0x10000;
+                sh = ( ( cc >> 10 ) & 0x3FF ) + 0xD800;
+                sl = ( ( cc >>  0 ) & 0x3FF ) + 0xDC00;
+                cb.put ( (char) sh );
+                cb.put ( (char) sl );
+            } else {
+                cb.put ( (char) cc );
+            }
+        }
+        cb.rewind();
+        return (CharSequence) cb;
+    }
+
 }
 

Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MutableFont.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MutableFont.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MutableFont.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/MutableFont.java Thu Aug 19 19:46:41 2010
@@ -133,6 +133,12 @@ public interface MutableFont {
     void setKerningEnabled(boolean enabled);
 
     /**
+     * Enables/disabled advanced typographic features.
+     * @param enabled true if advanced typographic features should be enabled if available
+     */
+    void setAdvancedEnabled(boolean enabled);
+
+    /**
      * Adds an entry to the kerning table.
      * @param key Kerning key
      * @param value Kerning value

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Positionable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Positionable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Positionable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Positionable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,46 @@
+/*
+ * 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
+
+/**
+ * Optional interface which indicates that glyph positioning is supported and, if supported,
+ * can perform positioning.
+ * @author Glenn Adams
+ */
+public interface Positionable {
+
+    /**
+     * Determines if font performs glyph positioning.
+     * @return true if performs positioning
+     */
+    boolean performsPositioning();
+
+    /**
+     * Perform glyph positioning.
+     * @param cs character sequence to map to position offsets (advancement adjustments)
+     * @param script a script identifier
+     * @param language a language identifier
+     * @return array (sequence) of pairs of position offsets, one pair for each element of character sequence
+     */
+    int[] performPositioning ( CharSequence cs, String script, String language );
+
+}

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

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

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/ScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/ScriptProcessor.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/ScriptProcessor.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/ScriptProcessor.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,101 @@
+/*
+ * 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.HashMap;
+import java.util.Map;
+
+// CSOFF: InnerAssignmentCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * Abstract script processor base class for which an implementation of the substitution and positioning methods
+ * must be supplied.
+ * @author Glenn Adams
+ */
+public abstract class ScriptProcessor {
+
+    private final String script;
+
+    private static Map processors = new HashMap();
+
+    /**
+     * Instantiate a script processor.
+     * @param script a script identifier
+     */
+    protected ScriptProcessor ( String script ) {
+        if ( ( script == null ) || ( script.length() == 0 ) ) {
+            throw new IllegalArgumentException ( "script must be non-empty string" );
+        } else {
+            this.script = script;
+        }
+    }
+
+    /** @return script identifier */
+    public String getScript() {
+        return script;
+    }
+
+    /**
+     * Perform substitution processing using a specific set of lookup tables.
+     * @param gs an input glyph sequence
+     * @param script a script identifier
+     * @param language a language identifier
+     * @param lookups a mapping from lookup specifications to glyph subtables to use for substitution processing
+     * @return the substituted (output) glyph sequence
+     */
+    public abstract GlyphSequence substitute ( GlyphSequence gs, String script, String language, Map/*<LookupSpec,GlyphSubtable[]>*/ lookups );
+
+    /**
+     * Perform positioning processing using a specific set of lookup tables.
+     * @param gs an input glyph sequence
+     * @param script a script identifier
+     * @param language a language identifier
+     * @param lookups a mapping from lookup specifications to glyph subtables to use for positioning processing
+     * @return the substituted (output) glyph sequence
+     */
+    public abstract int[] position ( GlyphSequence gs, String script, String language, Map/*<LookupSpec,GlyphSubtable[]>*/ lookups );
+
+    /**
+     * Obtain script processor instance associated with specified script.
+     * @param script a script identifier
+     * @return a script processor instance or null if none found
+     */
+    public static synchronized ScriptProcessor getInstance ( String script ) {
+        ScriptProcessor sp = null;
+        assert processors != null;
+        if ( ( sp = (ScriptProcessor) processors.get ( script ) ) == null ) {
+            processors.put ( script, sp = createProcessor ( script ) );
+        }
+        return sp;
+    }
+
+    // [TBD] - rework to provide more configurable binding between script name and script processor constructor
+    private static ScriptProcessor createProcessor ( String script ) {
+        ScriptProcessor sp = null;
+        if ( "arab".equals ( script ) ) {
+            sp = new ArabicScriptProcessor ( script );
+        } else {
+            sp = new DefaultScriptProcessor ( script );
+        }
+        return sp;
+    }
+
+}

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

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

Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Substitutable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Substitutable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Substitutable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Substitutable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,50 @@
+/*
+ * 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
+
+/**
+ * Optional interface which indicates that glyph substitution is supported and, if supported,
+ * can perform substitution.
+ * @author Glenn Adams
+ */
+public interface Substitutable {
+
+    /**
+     * Determines if font performs glyph substitution.
+     * @return true if performs substitution.
+     */
+    boolean performsSubstitution();
+
+    /**
+     * Perform substitutions on characters to effect glyph substitution. If some substitution is performed, it
+     * entails mapping from one or more input characters denoting textual character information to one or more
+     * output character codes denoting glyphs in this font, where the output character codes may make use of
+     * private character code values that have significance only for this font.
+     * @param cs character sequence to map to output font encoding character sequence
+     * @param script a script identifier
+     * @param language a language identifier
+     * @return output sequence (represented as a character sequence, where each character in the returned sequence
+     * denotes "font characters", i.e., character codes that map directly (1-1) to their associated glyphs
+     */
+    CharSequence performSubstitution ( CharSequence cs, String script, String language );
+
+}

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

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

Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Typeface.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Typeface.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Typeface.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/Typeface.java Thu Aug 19 19:46:41 2010
@@ -142,6 +142,10 @@ public abstract class Typeface implement
     
     /** {@inheritDoc} */
     public String toString() {
-        return getFullName();
+        StringBuffer sbuf = new StringBuffer(super.toString());
+        sbuf.append('{');
+        sbuf.append(getFullName());
+        sbuf.append('}');
+        return sbuf.toString();
     }   
 }

Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/apps/TTFReader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/apps/TTFReader.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/apps/TTFReader.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/apps/TTFReader.java Thu Aug 19 19:46:41 2010
@@ -21,6 +21,7 @@ package org.apache.fop.fonts.apps;
 
 import java.io.IOException;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -29,6 +30,11 @@ import javax.xml.parsers.DocumentBuilder
 import org.apache.commons.logging.LogFactory;
 import org.apache.fop.Version;
 import org.apache.fop.fonts.FontUtil;
+import org.apache.fop.fonts.GlyphCoverageTable;
+import org.apache.fop.fonts.GlyphPositioningTable;
+import org.apache.fop.fonts.GlyphSubstitutionTable;
+import org.apache.fop.fonts.GlyphSubtable;
+import org.apache.fop.fonts.GlyphTable;
 import org.apache.fop.fonts.truetype.FontFileReader;
 import org.apache.fop.fonts.truetype.TTFCmapEntry;
 import org.apache.fop.fonts.truetype.TTFFile;
@@ -38,6 +44,9 @@ import org.w3c.dom.Element;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
+// CSOFF: InnerAssignmentCheck
+// CSOFF: LineLengthCheck
+
 /**
  * A tool which reads TTF files and generates
  * XML font metrics file for use in FOP.
@@ -350,6 +359,8 @@ public class TTFReader extends AbstractF
 
         generateDOM4Kerning(root, ttf, isCid);
 
+        generateDOM4ScriptExtensions(root, ttf, isCid);
+
         return doc;
     }
 
@@ -463,6 +474,287 @@ public class TTFReader extends AbstractF
         }
     }
 
+    private void generateDOM4LookupReferences ( Element parent, GlyphSubstitutionTable gsub, GlyphTable.LookupSpec[] lookups ) {
+        boolean usedLookup = false;
+        Document d = parent.getOwnerDocument();
+        for ( int i = 0, m = lookups.length; i < m; i++ ) {
+            GlyphTable.LookupSpec ls = lookups [ i ];
+            GlyphSubtable[] sta = gsub.findSubtables ( ls );
+            for ( int j = 0, n = sta.length; j < n; j++ ) {
+                GlyphSubtable st = sta [ j ];
+                Element e = d.createElement("use-lookup");
+                e.setAttribute ( "ref", st.getID() );
+                parent.appendChild(e);
+            }
+        }
+    }
+
+    private void generateDOM4Features ( Element parent, GlyphSubstitutionTable gsub, GlyphTable.LookupSpec[] lookups, String scriptTag, String languageTag ) {
+        Document d = parent.getOwnerDocument();
+        Set features = new java.util.LinkedHashSet();
+        for ( int i = 0, n = lookups.length; i < n; i++ ) {
+            GlyphTable.LookupSpec ls = lookups [ i ];
+            features.add ( ls.getFeature() );
+        }
+        for ( Iterator it = features.iterator(); it.hasNext();) {
+            String featureTag = (String) it.next();
+            Element e = d.createElement("feature");
+            e.setAttribute ( "tag", featureTag );
+            generateDOM4LookupReferences ( e, gsub, gsub.matchLookupSpecs ( scriptTag, languageTag, featureTag ) );
+            if ( e.hasChildNodes() ) {
+                parent.appendChild(e);
+            }
+        }
+    }
+
+    private void generateDOM4Languages ( Element parent, GlyphSubstitutionTable gsub, GlyphTable.LookupSpec[] lookups, String scriptTag ) {
+        Document d = parent.getOwnerDocument();
+        Set languages = new java.util.LinkedHashSet();
+        for ( int i = 0, n = lookups.length; i < n; i++ ) {
+            GlyphTable.LookupSpec ls = lookups [ i ];
+            languages.add ( ls.getLanguage() );
+        }
+        for ( Iterator it = languages.iterator(); it.hasNext();) {
+            String languageTag = (String) it.next();
+            Element e = d.createElement("lang");
+            e.setAttribute ( "tag", languageTag );
+            generateDOM4Features ( e, gsub, gsub.matchLookupSpecs ( scriptTag, languageTag, "*" ), scriptTag, languageTag );
+            parent.appendChild(e);
+        }
+    }
+
+    private void generateDOM4Scripts ( Element parent, GlyphSubstitutionTable gsub, GlyphTable.LookupSpec[] lookups ) {
+        Document d = parent.getOwnerDocument();
+        Set scripts = new java.util.LinkedHashSet();
+        for ( int i = 0, n = lookups.length; i < n; i++ ) {
+            GlyphTable.LookupSpec ls = lookups [ i ];
+            scripts.add ( ls.getScript() );
+        }
+        for ( Iterator it = scripts.iterator(); it.hasNext();) {
+            String scriptTag = (String) it.next();
+            Element e = d.createElement("script");
+            e.setAttribute ( "tag", scriptTag );
+            generateDOM4Languages ( e, gsub, gsub.matchLookupSpecs ( scriptTag, "*", "*" ), scriptTag );
+            parent.appendChild(e);
+        }
+    }
+
+    private void generateDOM4Coverage ( Element parent, GlyphCoverageTable coverage ) {
+        Document d = parent.getOwnerDocument();
+        Element e = d.createElement("coverage");
+        int type = coverage.getType();
+        e.setAttribute ( "format", Integer.toString ( type ) );
+        List entries = coverage.getEntries();
+        if ( type == GlyphCoverageTable.GLYPH_COVERAGE_TYPE_MAPPED ) {
+            for ( Iterator it = entries.iterator(); it.hasNext();) {
+                Integer gid = (Integer) it.next();
+                if ( gid != null ) {
+                    Element g = d.createElement("gid");
+                    g.appendChild(d.createTextNode(gid.toString()));
+                    e.appendChild(g);
+                }
+            }
+        } else if ( type == GlyphCoverageTable.GLYPH_COVERAGE_TYPE_RANGE ) {
+            for ( Iterator it = entries.iterator(); it.hasNext();) {
+                GlyphCoverageTable.CoverageRange cr = (GlyphCoverageTable.CoverageRange) it.next();
+                if ( cr != null ) {
+                    Element r = d.createElement("range");
+                    r.setAttribute ( "gs", Integer.toString(cr.getStart()) );
+                    r.setAttribute ( "ge", Integer.toString(cr.getEnd()) );
+                    r.setAttribute ( "ci", Integer.toString(cr.getIndex()) );
+                    e.appendChild(r);
+                }
+            }
+        }
+        parent.appendChild(e);
+    }
+
+    private void generateDOM4GSUBSingleEntries ( Element parent, List entries, int type, int format ) {
+        if ( entries.size() > 0 ) {
+            Document d = parent.getOwnerDocument();
+            for ( Iterator it = entries.iterator(); it.hasNext();) {
+                Integer gid = (Integer) it.next();
+                if ( gid != null ) {
+                    Element e = d.createElement("gid");
+                    e.appendChild(d.createTextNode(gid.toString()));
+                    parent.appendChild(e);
+                }
+            }
+        }
+    }
+
+    private void generateDOM4GSUBMultipleEntries ( Element parent, List entries, int type, int format ) {
+        // [TBD] - implement me
+    }
+
+    private void generateDOM4GSUBAlternateEntries ( Element parent, List entries, int type, int format ) {
+        // [TBD] - implement me
+    }
+
+    private void generateDOM4LigatureSet ( Element parent, GlyphSubstitutionTable.LigatureSet lset ) {
+        Document d = parent.getOwnerDocument();
+        Element e = d.createElement("ligs");
+        GlyphSubstitutionTable.Ligature[] la = lset.getLigatures();
+        for ( int i = 0, m = la.length; i < m; i++ ) {
+            GlyphSubstitutionTable.Ligature l = la [ i ];
+            Element le = d.createElement("lig");
+            le.setAttribute ( "gid", Integer.toString( l.getLigature() ) );
+            int[] ca = l.getComponents();
+            StringBuffer sb = new StringBuffer();
+            for ( int j = 0, n = ca.length; j < n; j++ ) {
+                if ( j > 0 ) {
+                    sb.append ( ' ' );
+                }
+                sb.append ( Integer.toString ( ca [ j ] ) );
+            }
+            if ( sb.length() > 0 ) {
+                le.appendChild ( d.createTextNode ( sb.toString() ) );
+                e.appendChild ( le );
+            }
+        }
+        parent.appendChild(e);
+    }
+
+    private void generateDOM4GSUBLigatureEntries ( Element parent, List entries, int type, int format ) {
+        if ( entries.size() > 0 ) {
+            for ( Iterator it = entries.iterator(); it.hasNext();) {
+                GlyphSubstitutionTable.LigatureSet lset = (GlyphSubstitutionTable.LigatureSet) it.next();
+                if ( lset != null ) {
+                    generateDOM4LigatureSet ( parent, lset );
+                }
+            }
+        }
+    }
+
+    private void generateDOM4GSUBContextEntries ( Element parent, List entries, int type, int format ) {
+        // [TBD] - implement me
+    }
+
+    private void generateDOM4GSUBChainingContextEntries ( Element parent, List entries, int type, int format ) {
+        // [TBD] - implement me
+    }
+
+    private void generateDOM4GSUBExtensionEntries ( Element parent, List entries, int type, int format ) {
+        // [TBD] - implement me
+    }
+
+    private void generateDOM4GSUBReverseChainingSingleEntries ( Element parent, List entries, int type, int format ) {
+        // [TBD] - implement me
+    }
+
+    private void generateDOM4GSUBEntries ( Element parent, List entries, int type, int format ) {
+        Document d = parent.getOwnerDocument();
+        Element e = d.createElement("entries");
+        switch ( type ) {
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_SINGLE:
+            generateDOM4GSUBSingleEntries ( e, entries, type, format );
+            break;
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_MULTIPLE:
+            generateDOM4GSUBMultipleEntries ( e, entries, type, format );
+            break;
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_ALTERNATE:
+            generateDOM4GSUBAlternateEntries ( e, entries, type, format );
+            break;
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_LIGATURE:
+            generateDOM4GSUBLigatureEntries ( e, entries, type, format );
+            break;
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CONTEXT:
+            generateDOM4GSUBContextEntries ( e, entries, type, format );
+            break;
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CHAINING_CONTEXT:
+            generateDOM4GSUBChainingContextEntries ( e, entries, type, format );
+            break;
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION:
+            generateDOM4GSUBExtensionEntries ( e, entries, type, format );
+            break;
+        case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
+            generateDOM4GSUBReverseChainingSingleEntries ( e, entries, type, format );
+            break;
+        default:
+            break;
+        }
+        parent.appendChild(e);
+    }
+
+    private void generateDOM4GSUBSubtable ( Element parent, GlyphSubstitutionTable gsub, GlyphSubtable st ) {
+        Document d = parent.getOwnerDocument();
+        Element e = d.createElement("lst");
+        e.setAttribute ( "format", Integer.toString ( st.getFormat() ) );
+        generateDOM4Coverage ( e, st.getCoverage() );
+        generateDOM4GSUBEntries ( e, st.getEntries(), st.getType(), st.getFormat() );
+        parent.appendChild(e);
+    }
+
+    private void generateDOM4GSUBSubtables ( Element parent, GlyphSubstitutionTable gsub, GlyphSubtable[] subtables ) {
+        if ( subtables.length > 0 ) {
+            Document d = parent.getOwnerDocument();
+            Element e = d.createElement("lookup");
+            GlyphSubtable st0 = subtables[0];
+            int st0Type = st0.getType();
+            e.setAttribute ( "id", st0.getID() );
+            e.setAttribute ( "type", st0.getTypeName() );
+            for ( int i = 0, n = subtables.length; i < n; i++ ) {
+                GlyphSubtable st = subtables[i];
+                if ( st.getType() == st0Type ) {
+                    generateDOM4GSUBSubtable ( e, gsub, st );
+                }
+            }
+            parent.appendChild(e);
+        }
+    }
+
+    private GlyphSubtable[] matchSubtables ( GlyphSubtable[] subtables, String id ) {
+        List matches = new java.util.ArrayList();
+        for ( int i = 0, n = subtables.length; i < n; i++ ) {
+            GlyphSubtable st =  subtables [ i ];
+            if ( st.getID().equals ( id ) ) {
+                matches.add ( st );
+            }
+        }
+        return (GlyphSubtable[]) matches.toArray ( new GlyphSubtable[matches.size()] );
+    }
+
+    private void generateDOM4GSUBLookups ( Element parent, GlyphSubstitutionTable gsub, GlyphSubtable[] subtables ) {
+        Set lus = new java.util.LinkedHashSet();
+        for ( int i = 0, n = subtables.length; i < n; i++ ) {
+            GlyphSubtable st =  subtables [ i ];
+            lus.add ( st.getID() );
+        }
+        for ( Iterator it = lus.iterator(); it.hasNext();) {
+            String id = (String) it.next();
+            generateDOM4GSUBSubtables ( parent, gsub, matchSubtables ( subtables, id ) );
+        }
+    }
+
+    private void generateDOM4GSUB ( Element parent, GlyphSubstitutionTable gsub ) {
+        Document d = parent.getOwnerDocument();
+        Element e = d.createElement("gsub");
+        parent.appendChild(e);
+        generateDOM4Scripts ( e, gsub, gsub.getLookups() );
+        generateDOM4GSUBLookups ( e, gsub, gsub.getSubtables() );
+    }
+
+    private void generateDOM4GPOS ( Element parent, GlyphPositioningTable gpos ) {
+        Document d = parent.getOwnerDocument();
+        Element te = d.createElement("gpos");
+        parent.appendChild(te);
+    }
+
+    private void generateDOM4ScriptExtensions(Element parent, TTFFile ttf, boolean isCid) {
+        if ( ttf.hasScriptExtension() ) {
+            Document d = parent.getOwnerDocument();
+            Element se = d.createElement("script-extras");
+            parent.appendChild(se);
+            GlyphSubstitutionTable st;
+            if ( ( st = ttf.getGSUB() ) != null ) {
+                generateDOM4GSUB ( se, st );
+            }
+            GlyphPositioningTable pt;
+            if ( ( pt = ttf.getGPOS() ) != null ) {
+                generateDOM4GPOS ( se, pt );
+            }
+        }
+    }
 
     /**
      * Bugzilla 40739, check that attr has a metrics-version attribute

Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java Thu Aug 19 19:46:41 2010
@@ -151,7 +151,7 @@ public class FontInfoFinder {
             subFontName = ((MultiByteFont)customFont).getTTCName();
         }
         EmbedFontInfo fontInfo = new EmbedFontInfo(null, customFont.isKerningEnabled(),
-                fontTripletList, embedUrl, subFontName);
+                customFont.isAdvancedEnabled(), fontTripletList, embedUrl, subFontName);
         fontInfo.setPostScriptName(customFont.getFontName());
         if (fontCache != null) {
             fontCache.addFont(fontInfo);
@@ -226,7 +226,7 @@ public class FontInfoFinder {
                 }
                 try {
                     TTFFontLoader ttfLoader = new TTFFontLoader(
-                            fontFileURI, fontName, true, EncodingMode.AUTO, true, resolver);
+                            fontFileURI, fontName, true, EncodingMode.AUTO, true, true, resolver);
                     customFont = ttfLoader.getFont();
                     if (this.eventListener != null) {
                         customFont.setEventListener(this.eventListener);



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