]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
FOP-2191: cache matched lookups, assembled lookup spec uses; reduce glyph processing...
authorGlenn Adams <gadams@apache.org>
Fri, 18 Jan 2013 16:42:03 +0000 (16:42 +0000)
committerGlenn Adams <gadams@apache.org>
Fri, 18 Jan 2013 16:42:03 +0000 (16:42 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1435241 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/complexscripts/fonts/GlyphPositioningState.java
src/java/org/apache/fop/complexscripts/fonts/GlyphPositioningSubtable.java
src/java/org/apache/fop/complexscripts/fonts/GlyphProcessingState.java
src/java/org/apache/fop/complexscripts/fonts/GlyphSubstitutionState.java
src/java/org/apache/fop/complexscripts/fonts/GlyphSubstitutionSubtable.java
src/java/org/apache/fop/complexscripts/fonts/GlyphTable.java
src/java/org/apache/fop/complexscripts/scripts/ScriptProcessor.java
status.xml

index a865449ac16835a6353ca8b6f4f5d196f0e20f05..fafcf561440765dcc1bda8aa256db391a80e6733 100644 (file)
@@ -43,6 +43,12 @@ public class GlyphPositioningState extends GlyphProcessingState {
     /** if true, then some adjustment was applied */
     private boolean adjusted;
 
+    /**
+     * Construct default (reset) glyph positioning state.
+     */
+    public GlyphPositioningState() {
+    }
+
     /**
      * Construct glyph positioning state.
      * @param gs input glyph sequence
@@ -73,6 +79,26 @@ public class GlyphPositioningState extends GlyphProcessingState {
         this.adjustments = ps.adjustments;
     }
 
+    /**
+     * Reset glyph positioning state.
+     * @param gs input glyph sequence
+     * @param script script identifier
+     * @param language language identifier
+     * @param feature feature identifier
+     * @param fontSize font size (in micropoints)
+     * @param widths array of design advancements (in glyph index order)
+     * @param adjustments positioning adjustments to which positioning is applied
+     * @param sct script context tester (or null)
+     */
+    public GlyphPositioningState reset ( GlyphSequence gs, String script, String language, String feature, int fontSize, int[] widths, int[][] adjustments, ScriptContextTester sct ) {
+        super.reset ( gs, script, language, feature, sct );
+        this.fontSize = fontSize;
+        this.widths = widths;
+        this.adjustments = adjustments;
+        this.adjusted = false;
+        return this;
+    }
+
     /**
      * Obtain design advancement (width) of glyph at specified index.
      * @param gi glyph index
index a2e3a7fe7f96ba729aeb504274f7b2433c6fbce6..5bf073bf4123a0e7d566439449635b0f4afc6264 100644 (file)
@@ -34,6 +34,8 @@ import org.apache.fop.complexscripts.util.ScriptContextTester;
  */
 public abstract class GlyphPositioningSubtable extends GlyphSubtable implements GlyphPositioning {
 
+    private static final GlyphPositioningState state = new GlyphPositioningState();
+
     /**
      * Instantiate a <code>GlyphPositioningSubtable</code>.
      * @param id subtable identifier
@@ -122,7 +124,9 @@ public abstract class GlyphPositioningSubtable extends GlyphSubtable implements
      * @return true if a non-zero adjustment occurred
      */
     public static final boolean position ( GlyphSequence gs, String script, String language, String feature, int fontSize, GlyphPositioningSubtable[] sta, int[] widths, int[][] adjustments, ScriptContextTester sct ) {
-        return position ( new GlyphPositioningState ( gs, script, language, feature, fontSize, widths, adjustments, sct ), sta, -1 );
+        synchronized ( state ) {
+            return position ( state.reset ( gs, script, language, feature, fontSize, widths, adjustments, sct ), sta, -1 );
+        }
     }
 
 }
index c003ebbf91c3123ee939a7889940848ecab88fcb..6916e27428a327950c5a24be8ccd5614fbb41aa3 100644 (file)
@@ -75,6 +75,12 @@ public class GlyphProcessingState {
     /** current subtable */
     private GlyphSubtable subtable;
 
+    /**
+     * Construct default (reset) glyph processing state.
+     */
+    public GlyphProcessingState() {
+    }
+
     /**
      * Construct glyph processing state.
      * @param gs input glyph sequence
@@ -106,6 +112,35 @@ public class GlyphProcessingState {
         setPosition ( s.index );
     }
 
+    /**
+     * Reset glyph processing state.
+     * @param gs input glyph sequence
+     * @param script script identifier
+     * @param language language identifier
+     * @param feature feature identifier
+     * @param sct script context tester (or null)
+     */
+    protected GlyphProcessingState reset ( GlyphSequence gs, String script, String language, String feature, ScriptContextTester sct ) {
+        this.gdef = null;
+        this.script = script;
+        this.language = language;
+        this.feature = feature;
+        this.igs = gs;
+        this.index = 0;
+        this.indexLast = gs.getGlyphCount();
+        this.consumed = 0;
+        this.lookupFlags = 0;
+        this.classMatchSet = 0;
+        this.sct = sct;
+        this.gct = ( sct != null ) ? sct.getTester ( feature ) : null;
+        this.ignoreBase = new GlyphTester() { public boolean test(int gi, int flags) { return isIgnoredBase(gi, flags); } };
+        this.ignoreLigature = new GlyphTester() { public boolean test(int gi, int flags) { return isIgnoredLigature(gi, flags); } };
+        this.ignoreMark = new GlyphTester() { public boolean test(int gi, int flags) { return isIgnoredMark(gi, flags); } };
+        this.ignoreDefault = null;
+        this.subtable = null;
+        return this;
+    }
+
     /**
      * Set governing glyph definition table.
      * @param gdef glyph definition table (or null, to unset)
index c6217e3940c38dd6f1967c094a9f67f699666b86..5ff3394a221f683e3beba5d8b0e282e5e5e23d8d 100644 (file)
@@ -47,6 +47,12 @@ public class GlyphSubstitutionState extends GlyphProcessingState {
     /** character association predications */
     private boolean predications;
 
+    /**
+     * Construct default (reset) glyph substitution state.
+     */
+    public GlyphSubstitutionState() {
+    }
+
     /**
      * Construct glyph substitution state.
      * @param gs input glyph sequence
@@ -73,6 +79,23 @@ public class GlyphSubstitutionState extends GlyphProcessingState {
         this.oal = new ArrayList ( indexLast );
     }
 
+    /**
+     * Reset glyph substitution state.
+     * @param gs input glyph sequence
+     * @param script script identifier
+     * @param language language identifier
+     * @param feature feature identifier
+     * @param sct script context tester (or null)
+     */
+    public GlyphSubstitutionState reset ( GlyphSequence gs, String script, String language, String feature, ScriptContextTester sct ) {
+        super.reset ( gs, script, language, feature, sct );
+        this.alternatesIndex = null;
+        this.ogb = IntBuffer.allocate ( gs.getGlyphCount() );
+        this.oal = new ArrayList ( gs.getGlyphCount() );
+        this.predications = gs.getPredications();
+        return this;
+    }
+
     /**
      * Set alternates indices.
      * @param alternates array of alternates indices ordered by coverage index
index 2f337bc6ad27a9f2308c13ee93105409e8b82279..4468545667da5a9ae6a6a4a49980f181cfdab5ff 100644 (file)
@@ -33,6 +33,8 @@ import org.apache.fop.complexscripts.util.ScriptContextTester;
  */
 public abstract class GlyphSubstitutionSubtable extends GlyphSubtable implements GlyphSubstitution {
 
+    private static final GlyphSubstitutionState state = new GlyphSubstitutionState();
+
     /**
      * Instantiate a <code>GlyphSubstitutionSubtable</code>.
      * @param id subtable identifier
@@ -119,7 +121,9 @@ public abstract class GlyphSubstitutionSubtable extends GlyphSubtable implements
      * @return output glyph sequence
      */
     public static final GlyphSequence substitute ( GlyphSequence gs, String script, String language, String feature, GlyphSubstitutionSubtable[] sta, ScriptContextTester sct ) {
-        return substitute ( new GlyphSubstitutionState ( gs, script, language, feature, sct ), sta, -1 );
+        synchronized ( state ) {
+            return substitute ( state.reset ( gs, script, language, feature, sct ), sta, -1 );
+        }
     }
 
 }
index d7bf938cbf2672bcc128dc0d3935e8ad54e48981..1dd9d8b779044d63617a1be2f181e726327855a3 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.fop.complexscripts.fonts;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
@@ -73,6 +74,9 @@ public class GlyphTable {
     // map from lookup identifiers to lookup tables
     private Map/*<String,LookupTable>*/ lookupTables;
 
+    // cache for lookups matching
+    private Map/*<LookupSpec,Map<LookupSpec,List<LookupTable>>>*/ matchedLookups;
+
     // if true, then prevent further subtable addition
     private boolean frozen;
 
@@ -90,6 +94,7 @@ public class GlyphTable {
             this.gdef = gdef;
             this.lookups = lookups;
             this.lookupTables = new LinkedHashMap/*<String,List<LookupTable>>*/();
+            this.matchedLookups = new HashMap/*<LookupSpec,Map<LookupSpec,List<LookupTable>>>*/();
         }
     }
 
@@ -212,11 +217,16 @@ public class GlyphTable {
      * @return a (possibly empty) map from matching lookup specifications to lists of corresponding lookup tables
      */
     public Map/*<LookupSpec,List<LookupTable>>*/ matchLookups ( String script, String language, String feature ) {
-        List/*<LookupSpec>*/ lsl = matchLookupSpecs ( script, language, feature );
-        Map lm = new LinkedHashMap();
-        for ( Iterator it = lsl.iterator(); it.hasNext(); ) {
-            LookupSpec ls = (LookupSpec) it.next();
-            lm.put ( ls, findLookupTables ( ls ) );
+        LookupSpec lsm = new LookupSpec ( script, language, feature, true, true );
+        Map/*<LookupSpec,List<LookupTable>>*/ lm = (Map/*<LookupSpec,List<LookupTable>>*/) matchedLookups.get ( lsm );
+        if ( lm == null ) {
+            lm = new LinkedHashMap();
+            List/*<LookupSpec>*/ lsl = matchLookupSpecs ( script, language, feature );
+            for ( Iterator it = lsl.iterator(); it.hasNext(); ) {
+                LookupSpec ls = (LookupSpec) it.next();
+                lm.put ( ls, findLookupTables ( ls ) );
+            }
+            matchedLookups.put ( lsm, lm );
         }
         return lm;
     }
@@ -337,23 +347,34 @@ public class GlyphTable {
          * @param feature a feature identifier
          */
         public LookupSpec ( String script, String language, String feature ) {
-            if ( ( script == null ) || ( script.length() == 0 ) ) {
+            this ( script, language, feature, false, false );
+        }
+
+        /**
+         * Instantiate lookup spec.
+         * @param script a script identifier
+         * @param language a language identifier
+         * @param feature a feature identifier
+         * @param permitEmpty if true the permit empty script, language, or feature
+         * @param permitWildcard if true the permit wildcard script, language, or feature
+         */
+        LookupSpec ( String script, String language, String feature, boolean permitEmpty, boolean permitWildcard ) {
+            if ( ( script == null ) || ( ! permitEmpty && ( script.length() == 0 ) ) ) {
                 throw new AdvancedTypographicTableFormatException ( "script must be non-empty string" );
-            } else if ( ( language == null ) || ( language.length() == 0 ) ) {
+            } else if ( ( language == null ) || ( ! permitEmpty && ( language.length() == 0 ) ) ) {
                 throw new AdvancedTypographicTableFormatException ( "language must be non-empty string" );
-            } else if ( ( feature == null ) || ( feature.length() == 0 ) ) {
+            } else if ( ( feature == null ) || ( ! permitEmpty && ( feature.length() == 0 ) ) ) {
                 throw new AdvancedTypographicTableFormatException ( "feature must be non-empty string" );
-            } else if ( script.equals("*") ) {
+            } else if ( ! permitWildcard && script.equals("*") ) {
                 throw new AdvancedTypographicTableFormatException ( "script must not be wildcard" );
-            } else if ( language.equals("*") ) {
+            } else if ( ! permitWildcard && language.equals("*") ) {
                 throw new AdvancedTypographicTableFormatException ( "language must not be wildcard" );
-            } else if ( feature.equals("*") ) {
+            } else if ( ! permitWildcard && feature.equals("*") ) {
                 throw new AdvancedTypographicTableFormatException ( "feature must not be wildcard" );
-            } else {
-                this.script = script.trim();
-                this.language = language.trim();
-                this.feature = feature.trim();
             }
+            this.script = script.trim();
+            this.language = language.trim();
+            this.feature = feature.trim();
         }
 
         /** @return script identifier */
index e9397a7105931639f2a094af31dd483734eb5c32..95d9a4e0088764bec73bec3e718f6d3239fe3318 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.fop.complexscripts.scripts;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -44,6 +45,8 @@ public abstract class ScriptProcessor {
 
     private final String script;
 
+    private final Map/*<AssembledLookupsKey,GlyphTable.UseSpec[]>*/ assembledLookups;
+
     private static Map<String, ScriptProcessor> processors = new HashMap<String, ScriptProcessor>();
 
     /**
@@ -55,6 +58,7 @@ public abstract class ScriptProcessor {
             throw new IllegalArgumentException ( "script must be non-empty string" );
         } else {
             this.script = script;
+            this.assembledLookups = new HashMap/*<AssembledLookupsKey,GlyphTable.UseSpec[]>*/();
         }
     }
 
@@ -201,7 +205,22 @@ public abstract class ScriptProcessor {
      * @return ordered array of assembled lookup table use specifications
      */
     public final GlyphTable.UseSpec[] assembleLookups ( GlyphTable table, String[] features, Map/*<LookupSpec,List<LookupTable>>*/ lookups ) {
-        return table.assembleLookups ( features, lookups );
+        AssembledLookupsKey key = new AssembledLookupsKey ( table, features, lookups );
+        GlyphTable.UseSpec[] usa;
+        if ( ( usa = assembledLookupsGet ( key ) ) != null ) {
+            return usa;
+        } else {
+            return assembledLookupsPut ( key, table.assembleLookups ( features, lookups ) );
+        }
+    }
+
+    private GlyphTable.UseSpec[] assembledLookupsGet ( AssembledLookupsKey key ) {
+        return (GlyphTable.UseSpec[]) assembledLookups.get ( key );
+    }
+
+    private GlyphTable.UseSpec[]  assembledLookupsPut ( AssembledLookupsKey key, GlyphTable.UseSpec[] usa ) {
+        assembledLookups.put ( key, usa );
+        return usa;
     }
 
     /**
@@ -232,4 +251,45 @@ public abstract class ScriptProcessor {
         return sp;
     }
 
+    private static class AssembledLookupsKey {
+
+        private final GlyphTable table;
+        private final String[] features;
+        private final Map/*<LookupSpec,List<LookupTable>>*/ lookups;
+
+        AssembledLookupsKey ( GlyphTable table, String[] features, Map/*<LookupSpec,List<LookupTable>>*/ lookups ) {
+            this.table = table;
+            this.features = features;
+            this.lookups = lookups;
+        }
+
+        /** {@inheritDoc} */
+        public int hashCode() {
+            int hc = 0;
+            hc =  7 * hc + ( hc ^ table.hashCode() );
+            hc = 11 * hc + ( hc ^ Arrays.hashCode ( features ) );
+            hc = 17 * hc + ( hc ^ lookups.hashCode() );
+            return hc;
+        }
+
+        /** {@inheritDoc} */
+        public boolean equals ( Object o ) {
+            if ( o instanceof AssembledLookupsKey ) {
+                AssembledLookupsKey k = (AssembledLookupsKey) o;
+                if ( ! table.equals ( k.table ) ) {
+                    return false;
+                } else if ( ! Arrays.equals ( features, k.features ) ) {
+                    return false;
+                } else if ( ! lookups.equals ( k.lookups ) ) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else {
+                return false;
+            }
+        }
+
+    }
+
 }
index a566da0c3d3c19c1ead9d460ed48fe9bb0dc9076..caec3a862c490c2b74226a7be50d9c8b2842429b 100644 (file)
@@ -59,6 +59,9 @@
       documents. Example: the fix of marks layering will be such a case when it's done.
     -->
     <release version="FOP Trunk" date="TBD">
+      <action context="Renderers" dev="GA" type="fix" fixes-bug="FOP-2191">
+       Cache matched lookups, assembled lookup spec uses; reduce glyph processing state allocation.
+      </action>
       <action context="Renderers" dev="GA" type="fix" fixes-bug="FOP-2188">
        Optimize string allocation in PDF output processing.
       </action>