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