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 ga...@apache.org on 2012/02/26 03:29:29 UTC

svn commit: r1293736 [3/38] - in /xmlgraphics/fop/trunk: ./ src/codegen/java/org/apache/fop/tools/ src/codegen/unicode/java/org/apache/fop/complexscripts/ src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/ src/documentation/content/xdocs/trun...

Added: xmlgraphics/fop/trunk/src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java (added)
+++ xmlgraphics/fop/trunk/src/codegen/unicode/java/org/apache/fop/complexscripts/bidi/GenerateBidiTestData.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,1269 @@
+/*
+ * 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.text.bidi;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+
+import java.net.URL;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.fop.complexscripts.bidi.BidiConstants;
+import org.apache.fop.util.License;
+
+// CSOFF: LineLengthCheck
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: InnerAssignmentCheck
+// CSOFF: SimplifyBooleanReturnCheck
+// CSOFF: EmptyForIteratorPadCheck
+
+/**
+ * <p>Utility for generating a Java class and associated data files representing
+ * bidirectional confomance test data from the Unicode Character Database and
+ * Unicode BidiTest data files.</p>
+ *
+ * <p>This code is derived in part from GenerateBidiClassUtils.java.</p>
+ *
+ * @author Glenn Adams
+ */
+public final class GenerateBidiTestData {
+
+    // local constants
+    private static final String PFX_TYPE = "@Type:";
+    private static final String PFX_LEVELS = "@Levels:";
+    private static final String PFX_REORDER = "@Reorder:";
+
+    // command line options
+    private static boolean ignoreDeprecatedTypeData;
+    private static boolean verbose;
+
+    // instrumentation
+    private static int lineNumber;
+    private static int numTypeRanges;
+    private static int numLevelSpecs;
+    private static int numTestSpecs;
+
+    // compiled data
+    private static int[][] td;                  // types data
+    private static int[][] ld;                  // levels data
+
+    // ensure non-instantiation
+    private GenerateBidiTestData() {
+    }
+
+    /**
+     * Generate a class managing bidi test data for Unicode characters.
+     *
+     * @param ucdFileName name (as URL) of file containing unicode character database data
+     * @param bidiFileName name (as URL) of file containing bidi test data
+     * @param outFileName name of the output class file
+     * @throws Exception
+     */
+    private static void convertBidiTestData(String ucdFileName, String bidiFileName, String outFileName) throws Exception {
+
+        // read type data from UCD if ignoring deprecated type data
+        if ( ignoreDeprecatedTypeData ) {
+            readBidiTypeData(ucdFileName);
+        }
+
+        // read bidi test data
+        readBidiTestData(bidiFileName);
+
+        // generate class
+        PrintWriter out = new PrintWriter(new FileWriter(outFileName));
+        License.writeJavaLicenseId(out);
+        out.println();
+        out.println("package org.apache.fop.complexscripts.bidi;");
+        out.println();
+        out.println("import java.io.IOException;");
+        out.println("import java.io.InputStream;");
+        out.println("import java.io.ObjectInputStream;");
+        out.println();
+        out.println("// CSOFF: WhitespaceAfterCheck");
+        out.println();
+        out.println("/*");
+        out.println(" * !!! THIS IS A GENERATED FILE !!!");
+        out.println(" * If updates to the source are needed, then:");
+        out.println(" * - apply the necessary modifications to");
+        out.println(" *   'src/codegen/unicode/java/org/apache/fop/text/bidi/GenerateBidiTestData.java'");
+        out.println(" * - run 'ant codegen-unicode', which will generate a new BidiTestData.java");
+        out.println(" *   in 'test/java/org/apache/fop/complexscripts/bidi'");
+        out.println(" * - commit BOTH changed files");
+        out.println(" */");
+        out.println();
+        out.println("/** Bidirectional test data. */");
+        out.println("public final class BidiTestData {");
+        out.println();
+        out.println("    private BidiTestData() {");
+        out.println("    }");
+        out.println();
+        dumpData ( out, outFileName );
+        out.println("    public static final int NUM_TEST_SEQUENCES = " + numTestSpecs + ";");
+        out.println();
+        out.println("    public static int[] readTestData ( String prefix, int index ) {");
+        out.println("        int[] data = null;");
+        out.println("        InputStream is = null;");
+        out.println("        Class btc = BidiTestData.class;");
+        out.println("        String name = btc.getSimpleName() + \"$\" + prefix + index + \".ser\";");
+        out.println("        try {");
+        out.println("            if ( ( is = btc.getResourceAsStream ( name ) ) != null ) {");
+        out.println("                ObjectInputStream ois = new ObjectInputStream ( is );");
+        out.println("                data = (int[]) ois.readObject();");
+        out.println("                ois.close();");
+        out.println("            }");
+        out.println("        } catch ( IOException e ) {");
+        out.println("            data = null;");
+        out.println("        } catch ( ClassNotFoundException e ) {");
+        out.println("            data = null;");
+        out.println("        } finally {");
+        out.println("            if ( is != null ) {");
+        out.println("                try { is.close(); } catch ( Exception e ) {}");
+        out.println("            }");
+        out.println("        }");
+        out.println("        return data;");
+        out.println("    }");
+        out.println("}");
+        out.flush();
+        out.close();
+
+    }
+
+    /**
+     * Read bidi type data.
+     *
+     * @param ucdFileName name (as URL) of unicode character database data
+     */
+    private static void readBidiTypeData(String ucdFileName) throws Exception {
+        BufferedReader b = new BufferedReader(new InputStreamReader(new URL(ucdFileName).openStream()));
+        String line;
+        int n;
+        // singleton map - derived from single char entry
+        Map/*<Integer,List>*/ sm = new HashMap/*<Integer,List>*/();
+        // interval map - derived from pair of block endpoint entries
+        Map/*<String,int[3]>*/ im = new HashMap/*<String,int[3]>*/();
+        if ( verbose ) {
+            System.out.print("Reading bidi type data...");
+        }
+        for ( lineNumber = 0; ( line = b.readLine() ) != null; ) {
+            lineNumber++;
+            if ( line.length() == 0 ) {
+                continue;
+            } else if ( line.startsWith("#") ) {
+                continue;
+            } else {
+                parseTypeProperties ( line, sm, im );
+            }
+        }
+        // extract type data list
+        List tdl = processTypeData ( sm, im, new ArrayList() );
+        // dump instrumentation
+        if ( verbose ) {
+            System.out.println();
+            System.out.println("Read type ranges : " + numTypeRanges );
+            System.out.println("Read lines       : " + lineNumber );
+        }
+        td = (int[][]) tdl.toArray ( new int [ tdl.size() ] [] );
+    }
+
+    private static void parseTypeProperties ( String line, Map/*<Integer,List>*/ sm, Map/*<String,int[3]>*/ im ) {
+        String[] sa = line.split(";");
+        if ( sa.length >= 5 ) {
+            int uc = Integer.parseInt ( sa[0], 16 );
+            int bc = parseBidiClassAny ( sa[4] );
+            if ( bc >= 0 ) {
+                String ucName = sa[1];
+                if ( isBlockStart ( ucName ) ) {
+                    String ucBlock = getBlockName ( ucName );
+                    if ( ! im.containsKey ( ucBlock ) ) {
+                        im.put ( ucBlock, new int[] { uc, -1, bc } );
+                    } else {
+                        throw new IllegalArgumentException ( "duplicate start of block '" + ucBlock + "' at entry: " + line );
+                    }
+                } else if ( isBlockEnd ( ucName ) ) {
+                    String ucBlock = getBlockName ( ucName );
+                    if ( im.containsKey ( ucBlock ) ) {
+                        int[] ba = (int[]) im.get ( ucBlock );
+                        assert ba.length == 3;
+                        if ( ba[1] < 0 ) {
+                            ba[1] = uc;
+                        } else {
+                            throw new IllegalArgumentException ( "duplicate end of block '" + ucBlock + "' at entry: " + line );
+                        }
+                    } else {
+                        throw new IllegalArgumentException ( "missing start of block '" + ucBlock + "' at entry: " + line );
+                    }
+                } else {
+                    Integer k = Integer.valueOf ( bc );
+                    List sl;
+                    if ( ! sm.containsKey ( k ) ) {
+                        sl = new ArrayList();
+                        sm.put ( k, sl );
+                    } else {
+                        sl = (List) sm.get ( k );
+                    }
+                    assert sl != null;
+                    sl.add ( Integer.valueOf ( uc ) );
+                }
+            } else {
+                throw new IllegalArgumentException ( "invalid bidi class '" + sa[4] + "' at entry: " + line );
+            }
+        } else {
+            throw new IllegalArgumentException ( "invalid unicode character database entry: " + line );
+        }
+    }
+
+    private static boolean isBlockStart ( String s ) {
+        return s.startsWith("<") && s.endsWith("First>");
+    }
+
+    private static boolean isBlockEnd ( String s ) {
+        return s.startsWith("<") && s.endsWith("Last>");
+    }
+
+    private static String getBlockName ( String s ) {
+        String[] sa = s.substring ( 1, s.length() - 1 ).split(",");
+        assert ( sa != null ) && ( sa.length > 0 );
+        return sa[0].trim();
+    }
+
+    private static List processTypeData ( Map/*<Integer,List>*/ sm, Map/*<String,int[3]>*/ im, List tdl ) {
+        for ( int i = BidiConstants.FIRST, k = BidiConstants.LAST; i <= k; i++ ) {
+            Map/*<Integer,Integer>*/ rm = new TreeMap/*<Integer,Integer>*/();
+            // populate intervals from singleton map
+            List sl = (List) sm.get ( Integer.valueOf ( i ) );
+            if ( sl != null ) {
+                for ( Iterator it = sl.iterator(); it.hasNext(); ) {
+                    Integer s = (Integer) it.next();
+                    int uc = s.intValue();
+                    rm.put ( Integer.valueOf ( uc ), Integer.valueOf ( uc + 1 ) );
+                }
+            }
+            // populate intervals from (block) interval map
+            if ( ! im.isEmpty() ) {
+                for ( Iterator it = im.values().iterator(); it.hasNext(); ) {
+                    int[] ba = (int[]) it.next();
+                    assert ( ba != null ) && ( ba.length > 2 );
+                    if ( ba[2] == i ) {
+                        rm.put ( Integer.valueOf ( ba[0] ), Integer.valueOf ( ba[1] + 1 ) );
+                    }
+                }
+            }
+            tdl.add ( createTypeData ( i, extractRanges ( rm ) ) );
+        }
+        return tdl;
+    }
+
+    private static List extractRanges ( Map/*<Integer,Integer>*/ rm ) {
+        List ranges = new ArrayList();
+        int sLast = 0;
+        int eLast = 0;
+        for ( Iterator it = rm.entrySet().iterator(); it.hasNext(); ) {
+            Map.Entry/*<Integer,Integer>*/ me = (Map.Entry/*<Integer,Integer>*/) it.next();
+            int s = ((Integer) me.getKey()).intValue();
+            int e = ((Integer) me.getValue()).intValue();
+            if ( s > eLast ) {
+                if ( eLast > sLast ) {
+                    ranges.add ( new int[] { sLast, eLast } );
+                    if ( verbose ) {
+                        if ( ( ++numTypeRanges % 10 ) == 0 ) {
+                            System.out.print("#");
+                        }
+                    }
+                }
+                sLast = s;
+                eLast = e;
+            } else if ( ( s >= sLast ) && ( e >= eLast ) ) {
+                eLast = e;
+            }
+        }
+        if ( eLast > sLast ) {
+            ranges.add ( new int[] { sLast, eLast } );
+            if ( verbose ) {
+                if ( ( ++numTypeRanges % 10 ) == 0 ) {
+                    System.out.print("#");
+                }
+            }
+        }
+        return ranges;
+    }
+
+    /**
+     * Read biditest data.
+     *
+     * @param bidiFileName name (as URL) of bidi test data
+     */
+    private static void readBidiTestData(String bidiFileName) throws Exception {
+        BufferedReader b = new BufferedReader(new InputStreamReader(new URL(bidiFileName).openStream()));
+        String line;
+        int n;
+        List tdl = new ArrayList();
+        List ldl = new ArrayList();
+        if ( verbose ) {
+            System.out.print("Reading bidi test data...");
+        }
+        for ( lineNumber = 0; ( line = b.readLine() ) != null; ) {
+            lineNumber++;
+            if ( line.length() == 0 ) {
+                continue;
+            } else if ( line.startsWith("#") ) {
+                continue;
+            } else if ( line.startsWith(PFX_TYPE) && ! ignoreDeprecatedTypeData ) {
+                List lines = new ArrayList();
+                if ( ( n = readType ( line, b, lines ) ) < 0 ) {
+                    break;
+                } else {
+                    lineNumber += n;
+                    tdl.add ( parseType ( lines ) );
+                }
+            } else if ( line.startsWith(PFX_LEVELS) ) {
+                List lines = new ArrayList();
+                if ( ( n = readLevels ( line, b, lines ) ) < 0 ) {
+                    break;
+                } else {
+                    lineNumber += n;
+                    ldl.add ( parseLevels ( lines ) );
+                }
+            }
+        }
+        // dump instrumentation
+        if ( verbose ) {
+            System.out.println();
+            if ( ! ignoreDeprecatedTypeData ) {
+                System.out.println("Read type ranges : " + numTypeRanges );
+            }
+            System.out.println("Read level specs : " + numLevelSpecs );
+            System.out.println("Read test specs  : " + numTestSpecs );
+            System.out.println("Read lines       : " + lineNumber );
+        }
+        if ( ! ignoreDeprecatedTypeData ) {
+            td = (int[][]) tdl.toArray ( new int [ tdl.size() ] [] );
+        }
+        ld = (int[][]) ldl.toArray ( new int [ ldl.size() ] [] );
+    }
+
+    private static int readType ( String line, BufferedReader b, List lines ) throws IOException {
+        lines.add ( line );
+        return 0;
+    }
+
+    private static int readLevels ( String line, BufferedReader b, List lines ) throws IOException {
+        boolean done = false;
+        int n = 0;
+        lines.add ( line );
+        while ( ! done ) {
+            switch ( testPrefix ( b, PFX_LEVELS ) ) {
+            case 0:     // within current levels
+                if ( ( line = b.readLine() ) != null ) {
+                    n++;
+                    if ( ( line.length() > 0 ) && ! line.startsWith("#") ) {
+                        lines.add ( line );
+                    }
+                } else {
+                    done = true;
+                }
+                break;
+            case 1:     // end of current levels
+            case -1:    // eof
+            default:
+                done = true;
+                break;
+            }
+        }
+        return n;
+    }
+
+    private static int testPrefix ( BufferedReader b, String pfx ) throws IOException {
+        int rv = 0;
+        int pfxLen = pfx.length();
+        b.mark ( pfxLen );
+        for ( int i = 0, n = pfxLen; i < n; i++ ) {
+            int c = b.read();
+            if ( c < 0 ) {
+                rv = -1;
+                break;
+            } else if ( c != pfx.charAt ( i ) ) {
+                rv = 0;
+                break;
+            } else {
+                rv = 1;
+            }
+        }
+        b.reset();
+        return rv;
+    }
+
+    private static int[] parseType ( List lines ) {
+        if ( ( lines != null ) && ( lines.size() >= 1 ) ) {
+            String line = (String) lines.get(0);
+            if ( line.startsWith(PFX_TYPE) ) {
+                // @Type: BIDI_CLASS ':' LWSP CHARACTER_CLASS
+                String[] sa = line.split ( ":" );
+                if ( sa.length == 3 ) {
+                    String bcs = sa[1].trim();
+                    String crs = sa[2].trim();
+                    int bc = parseBidiClass ( bcs );
+                    List rl = parseCharacterRanges ( crs );
+                    return createTypeData ( bc, rl );
+                }
+            }
+        }
+        return null;
+    }
+
+    private static int[] createTypeData ( int bc, List ranges ) {
+        int[] data = new int [ 1 + ( 2 * ranges.size() ) ];
+        int k = 0;
+        data [ k++ ] = bc;
+        for ( Iterator it = ranges.iterator(); it.hasNext(); ) {
+            int[] r = (int[]) it.next();
+            data [ k++ ] = r [ 0 ];
+            data [ k++ ] = r [ 1 ];
+        }
+        return data;
+    }
+
+    private static int parseBidiClass ( String bidiClass ) {
+        int bc = 0;
+        if ( "L".equals ( bidiClass ) ) {
+            bc = BidiConstants.L;
+        } else if ( "LRE".equals ( bidiClass ) ) {
+            bc = BidiConstants.LRE;
+        } else if ( "LRO".equals ( bidiClass ) ) {
+            bc = BidiConstants.LRO;
+        } else if ( "R".equals ( bidiClass ) ) {
+            bc = BidiConstants.R;
+        } else if ( "AL".equals ( bidiClass ) ) {
+            bc = BidiConstants.AL;
+        } else if ( "RLE".equals ( bidiClass ) ) {
+            bc = BidiConstants.RLE;
+        } else if ( "RLO".equals ( bidiClass ) ) {
+            bc = BidiConstants.RLO;
+        } else if ( "PDF".equals ( bidiClass ) ) {
+            bc = BidiConstants.PDF;
+        } else if ( "EN".equals ( bidiClass ) ) {
+            bc = BidiConstants.EN;
+        } else if ( "ES".equals ( bidiClass ) ) {
+            bc = BidiConstants.ES;
+        } else if ( "ET".equals ( bidiClass ) ) {
+            bc = BidiConstants.ET;
+        } else if ( "AN".equals ( bidiClass ) ) {
+            bc = BidiConstants.AN;
+        } else if ( "CS".equals ( bidiClass ) ) {
+            bc = BidiConstants.CS;
+        } else if ( "NSM".equals ( bidiClass ) ) {
+            bc = BidiConstants.NSM;
+        } else if ( "BN".equals ( bidiClass ) ) {
+            bc = BidiConstants.BN;
+        } else if ( "B".equals ( bidiClass ) ) {
+            bc = BidiConstants.B;
+        } else if ( "S".equals ( bidiClass ) ) {
+            bc = BidiConstants.S;
+        } else if ( "WS".equals ( bidiClass ) ) {
+            bc = BidiConstants.WS;
+        } else if ( "ON".equals ( bidiClass ) ) {
+            bc = BidiConstants.ON;
+        } else {
+            throw new IllegalArgumentException ( "unknown bidi class: " + bidiClass );
+        }
+        return bc;
+    }
+
+    private static int parseBidiClassAny ( String bidiClass ) {
+        try {
+            return parseBidiClass ( bidiClass );
+        } catch ( IllegalArgumentException e ) {
+            return -1;
+        }
+    }
+
+    private static List parseCharacterRanges ( String charRanges ) {
+        List ranges = new ArrayList();
+        CharacterIterator ci = new StringCharacterIterator ( charRanges );
+        // read initial list delimiter
+        skipSpace ( ci );
+        if ( ! readStartOfList ( ci ) ) {
+            badRangeSpec ( "missing initial list delimiter", charRanges );
+        }
+        // read negation token if present
+        boolean negated = false;
+        skipSpace ( ci );
+        if ( maybeReadNext ( ci, '^' ) ) {
+            negated = true;
+        }
+        // read item
+        int[] r;
+        skipSpace ( ci );
+        if ( ( r = maybeReadItem ( ci ) ) != null ) {
+            ranges.add ( r );
+            if ( verbose ) {
+                if ( ( ++numTypeRanges % 10 ) == 0 ) {
+                    System.out.print("#");
+                }
+            }
+        } else {
+            badRangeSpec ( "must contain at least one item", charRanges );
+        }
+        // read more items if present
+        boolean more = true;
+        while ( more ) {
+            // read separator if present
+            String s;
+            skipSpace ( ci );
+            if ( ( s = maybeReadSeparator ( ci ) ) != null ) {
+                if ( ( s.length() != 0 ) && ! s.equals("||") ) {
+                    badRangeSpec ( "invalid item separator \"" + s + "\"", charRanges );
+                }
+            }
+            // read item
+            skipSpace ( ci );
+            if ( ( r = maybeReadItem ( ci ) ) != null ) {
+                ranges.add ( r );
+                if ( verbose ) {
+                    if ( ( ++numTypeRanges % 10 ) == 0 ) {
+                        System.out.print("#");
+                    }
+                }
+            } else {
+                more = false;
+            }
+        }
+        // read terminating list delimiter
+        skipSpace ( ci );
+        if ( ! readEndOfList ( ci ) ) {
+            badRangeSpec ( "missing terminating list delimiter", charRanges );
+        }
+        if ( ! atEnd ( ci ) ) {
+            badRangeSpec ( "extraneous content prior to end of line", ci );
+        }
+        if ( negated ) {
+            ranges = complementRanges ( ranges );
+        }
+        return removeSurrogates ( ranges );
+    }
+
+    private static boolean atEnd ( CharacterIterator ci ) {
+        return ci.getIndex() >= ci.getEndIndex();
+    }
+
+    private static boolean readStartOfList ( CharacterIterator ci ) {
+        return maybeReadNext ( ci, '[' );
+    }
+
+    private static void skipSpace ( CharacterIterator ci ) {
+        while ( ! atEnd ( ci ) ) {
+            char c = ci.current();
+            if ( ! Character.isWhitespace ( c ) ) {
+                break;
+            } else {
+                ci.next();
+            }
+        }
+    }
+
+    private static boolean maybeReadNext ( CharacterIterator ci, char next ) {
+        while ( ! atEnd ( ci ) ) {
+            char c = ci.current();
+            if ( c == next ) {
+                ci.next();
+                return true;
+            } else {
+                break;
+            }
+        }
+        return false;
+    }
+
+    private static int[] maybeReadItem ( CharacterIterator ci ) {
+        // read first code point
+        int p1 = -1;
+        skipSpace ( ci );
+        if ( ( p1 = maybeReadCodePoint ( ci ) ) < 0 ) {
+            return null;
+        }
+        // read second code point if present
+        int p2 = -1;
+        skipSpace ( ci );
+        if ( maybeReadNext ( ci, '-' ) ) {
+            skipSpace ( ci );
+            if ( ( p2 = maybeReadCodePoint ( ci ) ) < 0 ) {
+                badRangeSpec ( "incomplete item range, requires second item", ci );
+            }
+        }
+        if ( p2 < 0 ) {
+            return new int[] { p1, p1 + 1 };    // convert to half open interval [ P1, P1+1 )
+        } else if ( p1 <= p2 ) {
+            return new int[] { p1, p2 + 1 };    // convert to half open interval [ P1, P2+2 )
+        } else {
+            badRangeSpec ( "invalid item range, second item must be greater than or equal to first item", ci );
+            return null;
+        }
+    }
+
+    private static int maybeReadCodePoint ( CharacterIterator ci ) {
+        if ( maybeReadNext ( ci, '\\' ) ) {
+            if ( maybeReadNext ( ci, 'u' ) ) {
+                String s = maybeReadHexDigits ( ci, 4 );
+                if ( s != null ) {
+                    return Integer.parseInt ( s, 16 );
+                } else {
+                    badRangeSpec ( "incomplete escaped code point, requires 4 hex digits", ci );
+                }
+            } else if ( maybeReadNext ( ci, 'U' ) ) {
+                String s = maybeReadHexDigits ( ci, 8 );
+                if ( s != null ) {
+                    return Integer.parseInt ( s, 16 );
+                } else {
+                    badRangeSpec ( "incomplete escaped code point, requires 8 hex digits", ci );
+                }
+            } else {
+                char c = ci.current();
+                if ( c == CharacterIterator.DONE ) {
+                    badRangeSpec ( "incomplete escaped code point", ci );
+                } else {
+                    ci.next();
+                    return (int) c;
+                }
+            }
+        } else {
+            char c = ci.current();
+            if ( ( c == CharacterIterator.DONE ) || ( c == ']' ) ) {
+                return -1;
+            } else {
+                ci.next();
+                return (int) c;
+            }
+        }
+        return -1;
+    }
+
+    private static String maybeReadHexDigits ( CharacterIterator ci, int numDigits ) {
+        StringBuffer sb = new StringBuffer();
+        while ( ( numDigits < 0 ) || ( sb.length() < numDigits ) ) {
+            char c = ci.current();
+            if ( c != CharacterIterator.DONE ) {
+                if ( isHexDigit ( c ) ) {
+                    ci.next();
+                    sb.append ( c );
+                } else {
+                    break;
+                }
+            } else {
+                break;
+            }
+        }
+        if ( ( ( numDigits < 0 ) && ( sb.length() > 0 ) ) || ( sb.length() == numDigits ) ) {
+            return sb.toString();
+        } else {
+            return null;
+        }
+    }
+
+    private static boolean isHexDigit ( char c ) {
+        return ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'a' ) && ( c <= 'f' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) );
+    }
+
+    private static String maybeReadSeparator ( CharacterIterator ci ) {
+        if ( maybeReadNext ( ci, '|' ) ) {
+            if ( maybeReadNext ( ci, '|' ) ) {
+                return "||";
+            } else {
+                return "|";
+            }
+        } else {
+            return "";
+        }
+    }
+
+    private static boolean readEndOfList ( CharacterIterator ci ) {
+        return maybeReadNext ( ci, ']' );
+    }
+
+    private static List complementRanges ( List ranges ) {
+        Map/*<Integer,Integer>*/ rm = new TreeMap/*<Integer,Integer>*/();
+        for ( Iterator it = ranges.iterator(); it.hasNext(); ) {
+            int[] r = (int[]) it.next();
+            rm.put ( Integer.valueOf ( r[0] ), Integer.valueOf ( r[1] ) );
+        }
+        // add complement ranges save last
+        int s, e, cs = 0;
+        List compRanges = new ArrayList ( rm.size() + 1 );
+        for ( Iterator it = rm.entrySet().iterator(); it.hasNext(); ) {
+            Map.Entry/*<Integer,Integer>*/ me = (Map.Entry/*<Integer,Integer>*/) it.next();
+            s = ( (Integer) me.getKey() ).intValue();
+            e = ( (Integer) me.getValue() ).intValue();
+            if ( s > cs ) {
+                compRanges.add ( new int[] { cs, s } );
+            }
+            cs = e;
+        }
+        // add trailing complement range
+        if ( cs < 0x110000 ) {
+            compRanges.add ( new int[] { cs, 0x110000 } );
+        }
+        return compRanges;
+    }
+
+    private static final int[] SURROGATES = new int[] { 0xD800, 0xE000 };
+
+    private static List removeSurrogates ( List ranges ) {
+        List rsl = new ArrayList ( ranges.size() );
+        for ( Iterator it = ranges.iterator(); it.hasNext(); ) {
+            int[] r = (int[]) it.next();
+            if ( intersectsRange ( r, SURROGATES ) ) {
+                rsl.addAll ( removeRange ( r, SURROGATES ) );
+            } else {
+                rsl.add ( r );
+            }
+        }
+        return rsl;
+    }
+
+    /**
+     * Determine if range r2 intersects with range r1.
+     */
+    private static boolean intersectsRange ( int[] r1, int[] r2 ) {
+        if ( r1[1] <= r2[0] ) {                                 // r1 precedes r2 or abuts r2 on right
+            return false;
+        } else if ( r1[0] >= r2[1] ) {                          // r2 precedes r1 or abuts r1 on left
+            return false;
+        } else if ( ( r1[0] < r2[0] ) && ( r1[1] > r2[1] ) ) {  // r1 encloses r2
+            return true;
+        } else if ( r1[0] < r2[0] ) {                           // r1 precedes and overlaps r2
+            return true;
+        } else if ( r2[1] < r1[1] ) {                           // r2 precedes and overlaps r1
+            return true;
+        } else {                                                // r2 encloses r1
+            return true;
+        }
+    }
+
+    /**
+     * Remove range r2 from range r1, leaving zero, one, or two
+     * remaining ranges.
+     */
+    private static List removeRange ( int[] r1, int[] r2 ) {
+        List rl = new ArrayList();
+        if ( r1[1] <= r2[0] ) {                                 // r1 precedes r2 or abuts r2 on right
+            rl.add ( r1 );
+        } else if ( r1[0] >= r2[1] ) {                          // r2 precedes r1 or abuts r1 on left
+            rl.add ( r1 );
+        } else if ( ( r1[0] < r2[0] ) && ( r1[1] > r2[1] ) ) {  // r1 encloses r2
+            rl.add ( new int[] { r1[0], r2[0] } );
+            rl.add ( new int[] { r2[1], r1[1] } );
+        } else if ( r1[0] < r2[0] ) {                           // r1 precedes and overlaps r2
+            rl.add ( new int[] { r1[0], r2[0] } );
+        } else if ( r2[1] < r1[1] ) {                           // r2 precedes and overlaps r1
+            rl.add ( new int[] { r2[1], r1[1] } );
+        }
+        return rl;
+    }
+
+    private static void badRangeSpec ( String reason, String charRanges ) throws IllegalArgumentException {
+        if ( verbose ) {
+            System.out.println();
+        }
+        throw new IllegalArgumentException ( "bad range specification: " + reason + ": \"" + charRanges + "\"" );
+    }
+
+    private static void badRangeSpec ( String reason, CharacterIterator ci ) throws IllegalArgumentException {
+        if ( verbose ) {
+            System.out.println();
+        }
+        throw new IllegalArgumentException ( "bad range specification: " + reason + ": starting at \"" + remainder ( ci ) + "\"" );
+    }
+
+    private static String remainder ( CharacterIterator ci ) {
+        StringBuffer sb = new StringBuffer();
+        for ( char c; ( c = ci.current() ) != CharacterIterator.DONE; ) {
+            ci.next();
+            sb.append ( c );
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Parse levels segment, consisting of multiple lines as follows:
+     *
+     * LEVEL_SPEC \n
+     * REORDER_SPEC \n
+     * ( TEST_SPEC \n )+
+     */
+    private static int[] parseLevels ( List lines ) {
+        int[] la = null;        // levels array
+        int[] ra = null;        // reorder array
+        List tal = new ArrayList();
+        if ( ( lines != null ) && ( lines.size() >= 3 ) ) {
+            for ( Iterator it = lines.iterator(); it.hasNext(); ) {
+                String line = (String) it.next();
+                if ( line.startsWith(PFX_LEVELS) ) {
+                    if ( la == null ) {
+                        la = parseLevelSpec ( line );
+                        if ( verbose ) {
+                            if ( ( ++numLevelSpecs % 10 ) == 0 ) {
+                                System.out.print("&");
+                            }
+                        }
+                    } else {
+                        throw new IllegalArgumentException ( "redundant levels array: \"" + line + "\"" );
+                    }
+                } else if ( line.startsWith(PFX_REORDER) ) {
+                    if ( la == null ) {
+                        throw new IllegalArgumentException ( "missing levels array before: \"" + line + "\"" );
+                    } else if ( ra == null ) {
+                        ra = parseReorderSpec ( line, la );
+                    } else {
+                        throw new IllegalArgumentException ( "redundant reorder array: \"" + line + "\"" );
+                    }
+                } else if ( ( la != null ) && ( ra != null ) ) {
+                    int[] ta = parseTestSpec ( line, la );
+                    if ( ta != null ) {
+                        if ( verbose ) {
+                            if ( ( ++numTestSpecs % 100 ) == 0 ) {
+                                System.out.print("!");
+                            }
+                        }
+                        tal.add ( ta );
+                    }
+                } else if ( la == null ) {
+                    throw new IllegalArgumentException ( "missing levels array before: \"" + line + "\"" );
+                } else if ( ra == null ) {
+                    throw new IllegalArgumentException ( "missing reorder array before: \"" + line + "\"" );
+                }
+            }
+        }
+        if ( ( la != null ) && ( ra != null ) ) {
+            return createLevelData ( la, ra, tal );
+        } else {
+            return null;
+        }
+    }
+
+    private static int[] createLevelData ( int[] la, int[] ra, List tal ) {
+        int nl = la.length;
+        int[] data = new int [ 1 + nl * 2 + ( ( nl + 1 ) * tal.size() ) ];
+        int k = 0;
+        data [ k++ ] = nl;
+        for ( int i = 0, n = nl; i < n; i++ ) {
+            data [ k++ ] = la [ i ];
+        }
+        int nr = ra.length;
+        for ( int i = 0, n = nr; i < n; i++ ) {
+            data [ k++ ] = ra [ i ];
+        }
+        for ( Iterator it = tal.iterator(); it.hasNext(); ) {
+            int[] ta = (int[]) it.next();
+            if ( ta == null ) {
+                throw new IllegalStateException ( "null test array" );
+            } else if ( ta.length == ( nl + 1 ) ) {
+                for ( int i = 0, n = ta.length; i < n; i++ ) {
+                    data [ k++ ] = ta [ i ];
+                }
+            } else {
+                throw new IllegalStateException ( "test array length error, expected " + ( nl + 1 ) + " entries, got " + ta.length + " entries" );
+            }
+        }
+        assert k == data.length;
+        return data;
+    }
+
+    /**
+     * Parse level specification, which follows the following syntax:
+     *
+     * @Levels: ( LWSP ( NUMBER | 'x' ) )+
+     */
+    private static int[] parseLevelSpec ( String line ) {
+        CharacterIterator ci = new StringCharacterIterator ( line );
+        List ll = new ArrayList();
+        // read prefix
+        skipSpace ( ci );
+        if ( ! maybeReadToken ( ci, PFX_LEVELS ) ) {
+            badLevelSpec ( "missing prefix \"" + PFX_LEVELS + "\"", ci );
+        }
+        // read level values
+        boolean more = true;
+        while ( more ) {
+            Integer l;
+            skipSpace ( ci );
+            if ( ( l = maybeReadInteger ( ci ) ) != null ) {
+                ll.add ( l );
+            } else if ( maybeReadToken ( ci, "x" ) ) {
+                ll.add ( Integer.valueOf ( -1 ) );
+            } else {
+                more = false;
+            }
+        }
+        // read to end of line
+        skipSpace ( ci );
+        if ( ! atEnd ( ci ) ) {
+            badLevelSpec ( "extraneous content prior to end of line", ci );
+        }
+        if ( ll.size() == 0 ) {
+            badLevelSpec ( "must have at least one level value", ci );
+        }
+        return createLevelsArray ( ll );
+    }
+
+    private static Integer maybeReadInteger ( CharacterIterator ci ) {
+        // read optional minus sign if present
+        boolean negative;
+        if ( maybeReadNext ( ci, '-' ) ) {
+            negative = true;
+        } else {
+            negative = false;
+        }
+        // read digits
+        StringBuffer sb = new StringBuffer();
+        while ( true ) {
+            char c = ci.current();
+            if ( ( c != CharacterIterator.DONE ) && isDigit ( c ) ) {
+                ci.next();
+                sb.append ( c );
+            } else {
+                break;
+            }
+        }
+        if ( sb.length() == 0 ) {
+            return null;
+        } else {
+            int value = Integer.parseInt ( sb.toString() );
+            if ( negative ) {
+                value = -value;
+            }
+            return Integer.valueOf ( value );
+        }
+    }
+
+    private static boolean isDigit ( char c ) {
+        return ( ( c >= '0' ) && ( c <= '9' ) );
+    }
+
+    private static boolean maybeReadToken ( CharacterIterator ci, String s ) {
+        int startIndex = ci.getIndex();
+        for ( int i = 0, n = s.length(); i < n; i++ ) {
+            char c = s.charAt ( i );
+            if ( ci.current() == c ) {
+                ci.next();
+            } else {
+                ci.setIndex ( startIndex );
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static void badLevelSpec ( String reason, CharacterIterator ci ) throws IllegalArgumentException {
+        if ( verbose ) {
+            System.out.println();
+        }
+        throw new IllegalArgumentException ( "bad level specification: " + reason + ": starting at \"" + remainder ( ci ) + "\"" );
+    }
+
+    private static int[] createLevelsArray ( List levels ) {
+        int[] la = new int [ levels.size() ];
+        int k = 0;
+        for ( Iterator it = levels.iterator(); it.hasNext(); ) {
+            la [ k++ ] = ( (Integer) it.next() ).intValue(); 
+        }
+        return la;
+    }
+
+    /**
+     * Parse reorder specification, which follows the following syntax:
+     *
+     * @Reorder: ( LWSP NUMBER )*
+     */
+    private static int[] parseReorderSpec ( String line, int[] levels ) {
+        CharacterIterator ci = new StringCharacterIterator ( line );
+        List rl = new ArrayList();
+        // read prefix
+        skipSpace ( ci );
+        if ( ! maybeReadToken ( ci, PFX_REORDER ) ) {
+            badReorderSpec ( "missing prefix \"" + PFX_REORDER + "\"", ci );
+        }
+        // read reorder values
+        boolean more = true;
+        while ( more ) {
+            skipSpace ( ci );
+            Integer l;
+            if ( ( l = maybeReadInteger ( ci ) ) != null ) {
+                rl.add ( l );
+            } else {
+                more = false;
+            }
+        }
+        // read to end of line
+        skipSpace ( ci );
+        if ( ! atEnd ( ci ) ) {
+            badReorderSpec ( "extraneous content prior to end of line", ci );
+        }
+        return createReorderArray ( rl, levels );
+    }
+
+    private static void badReorderSpec ( String reason, CharacterIterator ci ) throws IllegalArgumentException {
+        if ( verbose ) {
+            System.out.println();
+        }
+        throw new IllegalArgumentException ( "bad reorder specification: " + reason + ": starting at \"" + remainder ( ci ) + "\"" );
+    }
+
+    private static int[] createReorderArray ( List reorders, int[] levels ) {
+        int nr = reorders.size();
+        int nl = levels.length;
+        if ( nr <= nl ) {
+            int[] ra = new int [ nl ];
+            Iterator it = reorders.iterator();
+            for ( int i = 0, n = nl; i < n; i++ ) {
+                int r = -1;
+                if ( levels [ i ] >= 0 ) {
+                    if ( it.hasNext() ) {
+                        r = ( (Integer) it.next() ).intValue();
+                    }
+                } 
+                ra [ i ] = r;
+            }
+            return ra;
+        } else {
+            throw new IllegalArgumentException ( "excessive number of reorder array entries, expected no more than " + nl + ", but got " + nr + " entries" );
+        }
+    }
+
+    /**
+     * Parse test specification, which follows the following syntax:
+     *
+     * BIDI_CLASS ( LWSP BIDI_CLASS )+ ';' LWSP NUMBER
+     */
+    private static int[] parseTestSpec ( String line, int[] levels ) {
+        CharacterIterator ci = new StringCharacterIterator ( line );
+        List cl = new ArrayList();
+        // read bidi class identifier sequence
+        while ( ! atEnd ( ci ) && ! maybeReadNext ( ci, ';' ) ) {
+            skipSpace ( ci );
+            int bc;
+            if ( ( bc = maybeReadBidiClass ( ci ) ) >= 0 ) {
+                cl.add ( Integer.valueOf ( bc ) );
+            } else {
+                break;
+            }
+        }
+        // read bit set
+        skipSpace ( ci );
+        String s;
+        int bs = 0;
+        if ( ( s = maybeReadHexDigits ( ci, -1 ) ) != null ) {
+            bs = Integer.parseInt ( s, 16 );
+        } else {
+            badTestSpec ( "missing bit set", ci );
+        }
+        // read to end of line
+        skipSpace ( ci );
+        if ( ! atEnd ( ci ) ) {
+            badTestSpec ( "extraneous content prior to end of line", ci );
+        }
+        return createTestArray ( cl, bs, levels );
+    }
+
+    private static String maybeReadIdentifier ( CharacterIterator ci ) {
+        // read keyword chars ([A-Z])
+        StringBuffer sb = new StringBuffer();
+        while ( true ) {
+            char c = ci.current();
+            if ( c == CharacterIterator.DONE ) {
+                break;
+            } else if ( sb.length() == 0 ) {
+                if ( Character.isUnicodeIdentifierStart ( c ) ) {
+                    ci.next();
+                    sb.append ( c );
+                } else {
+                    break;
+                }
+            } else {
+                if ( Character.isUnicodeIdentifierPart ( c ) ) {
+                    ci.next();
+                    sb.append ( c );
+                } else {
+                    break;
+                }
+            }
+        }
+        if ( sb.length() == 0 ) {
+            return null;
+        } else {
+            return sb.toString();
+        }
+    }
+
+    private static int maybeReadBidiClass ( CharacterIterator ci ) {
+        int bc = -1;
+        int i = ci.getIndex();
+        String s;
+        if ( ( s = maybeReadIdentifier ( ci ) ) != null ) {
+            try {
+                bc = parseBidiClass ( s );
+            } catch ( IllegalArgumentException e ) {
+                throw e;
+            }
+        }
+        if ( bc < 0 ) {
+            ci.setIndex ( i );
+        }
+        return bc;
+    }
+
+    private static void badTestSpec ( String reason, CharacterIterator ci ) throws IllegalArgumentException {
+        if ( verbose ) {
+            System.out.println();
+        }
+        throw new IllegalArgumentException ( "bad test specification: " + reason + ": starting at \"" + remainder ( ci ) + "\"" );
+    }
+
+    private static int[] createTestArray ( List classes, int bitset, int[] levels ) {
+        int nc = classes.size();
+        if ( nc <= levels.length ) {
+            int[] ta = new int [ 1 + nc ];
+            int k = 0;
+            ta [ k++ ] = bitset;
+            for ( Iterator it = classes.iterator(); it.hasNext(); ) {
+                ta [ k++ ] = ( (Integer) it.next() ).intValue(); 
+            }
+            return ta;
+        } else {
+            throw new IllegalArgumentException ( "excessive number of test array entries, expected no more than " + levels.length + ", but got " + nc + " entries" );
+        }
+    }
+
+    /**
+     * Dump data arrays to output and resource files.
+     * @param out - bidi test data java class file print writer
+     * @param outFileName - (full path) name of bidi test data java class file
+     */
+    private static void dumpData ( PrintWriter out, String outFileName ) throws IOException {
+        File f = new File ( outFileName );
+        File p = f.getParentFile();
+        if ( td != null ) {
+            String pfxTD = "TD";
+            dumpResourcesDescriptor ( out, pfxTD, td.length );
+            dumpResourcesData ( p, f.getName(), pfxTD, td );
+        }
+        if ( ld != null ) {
+            String pfxTD = "LD";
+            dumpResourcesDescriptor ( out, pfxTD, ld.length );
+            dumpResourcesData ( p, f.getName(), pfxTD, ld );
+        }
+    }
+
+    private static void dumpResourcesDescriptor ( PrintWriter out, String prefix, int numResources ) {
+        out.println ( "    public static final String " + prefix + "_PFX = \"" + prefix + "\";" );
+        out.println ( "    public static final int " + prefix + "_CNT = " + numResources + ";" );
+        out.println("");
+    }
+
+    private static void dumpResourcesData ( File btcDir, String btcName, String prefix, int[][] data ) throws IOException {
+        String btdName = extractDataFileName ( btcName );
+        for ( int i = 0, n = data.length; i < n; i++ ) {
+            File f = new File ( btcDir, btdName + "$" + prefix + i + ".ser" );
+            ObjectOutputStream os = new ObjectOutputStream ( new FileOutputStream ( f ) );
+            os.writeObject ( data[i] );
+            os.close();
+        }
+    }
+
+    private static final String JAVA_EXT = ".java";
+
+    private static String extractDataFileName ( String btcName ) {
+        if ( btcName.endsWith ( JAVA_EXT ) ) {
+            return btcName.substring ( 0, btcName.length() - JAVA_EXT.length() );
+        } else {
+            return btcName;
+        }
+    }
+
+    /**
+     * Main entry point for generator.
+     * @param args array of command line arguments
+     */
+    public static void main(String[] args) {
+        String bidiFileName = "http://www.unicode.org/Public/UNIDATA/BidiTest.txt";
+        String ucdFileName = "http://www.unicode.org/Public/UNIDATA/BidiTest.txt";
+        String outFileName = "BidiTestData.java";
+        boolean ok = true;
+        for (int i = 0; ok && ( i < args.length ); i++) {
+            String opt = args[i];
+            if ("-b".equals(opt)) {
+                if ( ( i + 1 ) <= args.length ) {
+                    bidiFileName = args[++i];
+                } else {
+                    ok = false;
+                }
+            } else if ("-d".equals(opt)) {
+                if ( ( i + 1 ) <= args.length ) {
+                    ucdFileName = args[++i];
+                } else {
+                    ok = false;
+                }
+            } else if ("-i".equals(opt)) {
+                ignoreDeprecatedTypeData = true;
+            } else if ("-o".equals(opt)) {
+                if ( ( i + 1 ) <= args.length ) {
+                    outFileName = args[++i];
+                } else {
+                    ok = false;
+                }
+            } else if ("-v".equals(opt)) {
+                verbose = true;
+            } else {
+                ok = false;
+            }
+        }
+        if ( ! ok ) {
+            System.out.println("Usage: GenerateBidiTestData [-v] [-i] [-d <ucdFile>] [-b <bidiFile>] [-o <outputFile>]");
+            System.out.println("  defaults:");
+            if ( ignoreDeprecatedTypeData ) {
+                System.out.println("    <ucdFile>    : " + ucdFileName);
+            }
+            System.out.println("    <bidiFile>   : " + bidiFileName);
+            System.out.println("    <outputFile> : " + outFileName);
+        } else {
+            try {
+                convertBidiTestData(ucdFileName, bidiFileName, outFileName);
+                System.out.println("Generated " + outFileName + " from");
+                if ( ignoreDeprecatedTypeData ) {
+                    System.out.println("    <ucdFile>  :     " + ucdFileName);
+                }
+                System.out.println("    <bidiFile> :     " + bidiFileName);
+            } catch (Exception e) {
+                System.out.println("An unexpected error occured at line: " + lineNumber );
+                e.printStackTrace();
+            }
+        }
+    }
+}

Modified: xmlgraphics/fop/trunk/src/documentation/content/xdocs/trunk/configuration.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/documentation/content/xdocs/trunk/configuration.xml?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/documentation/content/xdocs/trunk/configuration.xml (original)
+++ xmlgraphics/fop/trunk/src/documentation/content/xdocs/trunk/configuration.xml Sun Feb 26 02:29:01 2012
@@ -152,6 +152,21 @@
         <td>false</td>
       </tr>
       <tr>
+        <td>complex-scripts</td>
+        <td>attribute disabled (optional)</td>
+        <td>
+          If present and if an attribute 'disabled' is specified with the value 'false', then
+          complex script features are disabled. The same result can be obtained on an FOP
+          per-invocation basis by specifying a '-nocs' command line option when invoking FOP.
+          When complex script features are disabled, all bidirectional processing and complex
+          character to glyph mapping processing is disabled; in addition, the loading of
+          GDEF, GSUB, and GPOS advanced typographic tables is disabled for OpenType and
+          TrueType fonts. Unless disabled by this mechanism or by use of the '-nocs' command
+          line option, complex script features will be enabled by default.
+        </td>
+        <td>n/a</td>
+      </tr>
+      <tr>
         <td>default-page-settings</td>
         <td>n/a</td>
         <td>

Modified: xmlgraphics/fop/trunk/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd (original)
+++ xmlgraphics/fop/trunk/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd Sun Feb 26 02:29:01 2012
@@ -100,10 +100,10 @@
       <xs:element name="border-rect">
         <xs:complexType>
           <xs:attributeGroup ref="mf:rectAtts"/>
-          <xs:attribute name="start" type="mf:borderDef"/>
-          <xs:attribute name="end" type="mf:borderDef"/>
-          <xs:attribute name="before" type="mf:borderDef"/>
-          <xs:attribute name="after" type="mf:borderDef"/>
+          <xs:attribute name="left" type="mf:borderDef"/>
+          <xs:attribute name="right" type="mf:borderDef"/>
+          <xs:attribute name="top" type="mf:borderDef"/>
+          <xs:attribute name="bottom" type="mf:borderDef"/>
         </xs:complexType>
       </xs:element>
       <xs:element name="image">

Modified: xmlgraphics/fop/trunk/src/foschema/fop-configuration.xsd
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/foschema/fop-configuration.xsd?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/foschema/fop-configuration.xsd (original)
+++ xmlgraphics/fop/trunk/src/foschema/fop-configuration.xsd Sun Feb 26 02:29:01 2012
@@ -48,6 +48,11 @@
             <xsd:attribute name="height" type="xsd:string"></xsd:attribute>
           </xsd:complexType>
         </xsd:element>
+        <xsd:element name="complex-scripts" minOccurs="0"
+          <xsd:complexType>
+            <xsd:attribute name="disabled" type="xsd:boolean"/>
+          </xsd:complexType>
+        </xsd:element>
         <xsd:element name="renderers" minOccurs="0">
           <xsd:complexType>
             <xsd:sequence>

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FOUserAgent.java Sun Feb 26 02:29:01 2012
@@ -654,6 +654,24 @@ public class FOUserAgent {
     }
 
     /**
+     * Check whether complex script features are enabled.
+     *
+     * @return true if FOP is to use complex script features
+     */
+    public boolean isComplexScriptFeaturesEnabled() {
+        return factory.isComplexScriptFeaturesEnabled();
+    }
+
+    /**
+     * Control whether complex script features should be enabled
+     *
+     * @param useComplexScriptFeatures true if FOP is to use complex script features
+     */
+    public void setComplexScriptFeaturesEnabled(boolean useComplexScriptFeatures) {
+        factory.setComplexScriptFeaturesEnabled ( useComplexScriptFeatures );
+    }
+
+    /**
      * Activates accessibility (for output formats that support it).
      *
      * @param accessibility <code>true</code> to enable accessibility support

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactory.java Sun Feb 26 02:29:01 2012
@@ -143,6 +143,10 @@ public class FopFactory implements Image
     /** Page width */
     private String pageWidth = FopFactoryConfigurator.DEFAULT_PAGE_WIDTH;
 
+    /** Complex scripts support enabled */
+    private boolean useComplexScriptFeatures
+        = FopFactoryConfigurator.DEFAULT_COMPLEX_SCRIPT_FEATURES;
+
     /** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */
     private boolean breakIndentInheritanceOnReferenceAreaBoundary
         = FopFactoryConfigurator.DEFAULT_BREAK_INDENT_INHERITANCE;
@@ -212,6 +216,19 @@ public class FopFactory implements Image
     }
 
     /**
+     * Sets complex script support.
+     * @param value <code>true</code> to enable complex script features,
+     * <code>false</code> otherwise
+     */
+    void setComplexScriptFeaturesEnabled(boolean value) {
+        this.useComplexScriptFeatures = value;
+    }
+
+    boolean isComplexScriptFeaturesEnabled() {
+        return useComplexScriptFeatures;
+    }
+
+    /**
      * Returns a new {@link Fop} instance. FOP will be configured with a default user agent
      * instance.
      * <p>

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactoryConfigurator.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactoryConfigurator.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactoryConfigurator.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/apps/FopFactoryConfigurator.java Sun Feb 26 02:29:01 2012
@@ -69,6 +69,9 @@ public class FopFactoryConfigurator {
     /** Defines the default target resolution (72dpi) for FOP */
     public static final float DEFAULT_TARGET_RESOLUTION = GraphicsConstants.DEFAULT_DPI; //dpi
 
+    /** Defines the default complex script support  */
+    public static final boolean DEFAULT_COMPLEX_SCRIPT_FEATURES = true;
+
     private static final String PREFER_RENDERER = "prefer-renderer";
 
     /** logger instance */
@@ -269,6 +272,13 @@ public class FopFactoryConfigurator {
             }
         }
 
+        // configure complex script support
+        Configuration csConfig = cfg.getChild("complex-scripts");
+        if (csConfig != null) {
+            this.factory.setComplexScriptFeaturesEnabled
+                (!csConfig.getAttributeAsBoolean ( "disabled", false ));
+        }
+
         // configure font manager
         new FontManagerConfigurator(cfg, baseURI).configure(factory.getFontManager(), strict);
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Area.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Area.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Area.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Area.java Sun Feb 26 02:29:01 2012
@@ -25,6 +25,7 @@ import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fop.traits.BorderProps;
+import org.apache.fop.traits.WritingModeTraitsGetter;
 
 // If the area appears more than once in the output
 // or if the area has external data it is cached
@@ -41,27 +42,6 @@ public class Area extends AreaTreeObject
 
     private static final long serialVersionUID = 6342888466142626492L;
 
-    // stacking directions
-    /**
-     * Stacking left to right
-     */
-    public static final int LR = 0;
-
-    /**
-     * Stacking right to left
-     */
-    public static final int RL = 1;
-
-    /**
-     * Stacking top to bottom
-     */
-    public static final int TB = 2;
-
-    /**
-     * Stacking bottom to top
-     */
-    public static final int BT = 3;
-
     // orientations for reference areas
     /**
      * Normal orientation
@@ -130,16 +110,20 @@ public class Area extends AreaTreeObject
     protected int bpd;
 
     /**
+     * Resolved bidirectional level for area.
+     */
+    protected int bidiLevel = -1;
+
+    /**
      * Traits for this area stored in a HashMap
      */
-    protected Map<Integer, Object> props = null;
+    protected transient Map<Integer, Object> traits = null;
 
     /**
      * logging instance
      */
     protected static final Log log = LogFactory.getLog(Area.class);
 
-
     /**
      * Get the area class of this area.
      *
@@ -226,6 +210,32 @@ public class Area extends AreaTreeObject
     }
 
     /**
+     * Set the bidirectional embedding level.
+     *
+     * @param bidiLevel the bidirectional embedding level
+     */
+    public void setBidiLevel ( int bidiLevel ) {
+        this.bidiLevel = bidiLevel;
+    }
+
+    /**
+     * Reset the bidirectional embedding level to default
+     * value (-1).
+     */
+    public void resetBidiLevel() {
+        setBidiLevel(-1);
+    }
+
+    /**
+     * Get the bidirectional embedding level.
+     *
+     * @return the bidirectional embedding level
+     */
+    public int getBidiLevel() {
+        return bidiLevel;
+    }
+
+    /**
      * Return the sum of region border- and padding-before
      *
      * @return width in millipoints
@@ -379,10 +389,23 @@ public class Area extends AreaTreeObject
      * @param prop the value of the trait
      */
     public void addTrait(Integer traitCode, Object prop) {
-        if (props == null) {
-            props = new java.util.HashMap<Integer, Object>(20);
+        if (traits == null) {
+            traits = new java.util.HashMap<Integer, Object>(20);
+        }
+        traits.put(traitCode, prop);
+    }
+
+    /**
+     * Set traits on this area, copying from an existing traits map.
+     *
+     * @param traits the map of traits
+     */
+    public void setTraits ( Map traits ) {
+        if ( traits != null ) {
+            this.traits = new java.util.HashMap ( traits );
+        } else {
+            this.traits = null;
         }
-        props.put(traitCode, prop);
     }
 
     /**
@@ -391,12 +414,12 @@ public class Area extends AreaTreeObject
      * @return the map of traits
      */
     public Map<Integer, Object> getTraits() {
-        return this.props;
+        return this.traits;
     }
 
     /** @return true if the area has traits */
     public boolean hasTraits() {
-        return (this.props != null);
+        return (this.traits != null);
     }
 
     /**
@@ -406,7 +429,7 @@ public class Area extends AreaTreeObject
      * @return the trait value
      */
     public Object getTrait(Integer traitCode) {
-        return (props != null ? props.get(traitCode) : null);
+        return (traits != null ? traits.get(traitCode) : null);
     }
 
     /**
@@ -445,6 +468,14 @@ public class Area extends AreaTreeObject
     }
 
     /**
+     * Sets the writing mode traits for this area. Default implementation
+     * does nothing.
+     * @param wmtg a WM traits getter
+     */
+    public void setWritingModeTraits(WritingModeTraitsGetter wmtg) {
+    }
+
+    /**
      * {@inheritDoc}
      * @return ipd and bpd of area
      */
@@ -457,4 +488,3 @@ public class Area extends AreaTreeObject
         return sb.toString();
     }
 }
-

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeHandler.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeHandler.java Sun Feb 26 02:29:01 2012
@@ -73,6 +73,9 @@ public class AreaTreeHandler extends FOE
     /** The AreaTreeModel in use */
     protected AreaTreeModel model;
 
+    // Flag for controlling complex script features (default: true).
+    private boolean useComplexScriptFeatures = true;
+
     // Keeps track of all meaningful id references
     private IDTracker idTracker;
 
@@ -108,6 +111,8 @@ public class AreaTreeHandler extends FOE
 
         this.idTracker = new IDTracker();
 
+        this.useComplexScriptFeatures = userAgent.isComplexScriptFeaturesEnabled();
+
         if (log.isDebugEnabled()) {
             statistics = new Statistics();
         }
@@ -169,6 +174,15 @@ public class AreaTreeHandler extends FOE
     }
 
     /**
+     * Check whether complex script features are enabled.
+     *
+     * @return true if using complex script features
+     */
+    public boolean isComplexScriptFeaturesEnabled() {
+        return useComplexScriptFeatures;
+    }
+
+    /**
      * Prepare AreaTreeHandler for document processing This is called from
      * FOTreeBuilder.startDocument()
      *

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeParser.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeParser.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeParser.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/AreaTreeParser.java Sun Feb 26 02:29:01 2012
@@ -700,7 +700,7 @@ public class AreaTreeParser {
             public void startElement(Attributes attributes) {
                 InlineArea inl = new InlineArea();
                 transferForeignObjects(attributes, inl);
-                inl.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
+                inl.setBlockProgressionOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
                 setAreaAttributes(attributes, inl);
                 setTraits(attributes, inl, SUBSET_COMMON);
                 setTraits(attributes, inl, SUBSET_BOX);
@@ -720,7 +720,7 @@ public class AreaTreeParser {
             public void startElement(Attributes attributes) {
                 InlineParent ip = new InlineParent();
                 transferForeignObjects(attributes, ip);
-                ip.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
+                ip.setBlockProgressionOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
                 setAreaAttributes(attributes, ip);
                 setTraits(attributes, ip, SUBSET_COMMON);
                 setTraits(attributes, ip, SUBSET_BOX);
@@ -741,7 +741,7 @@ public class AreaTreeParser {
             public void startElement(Attributes attributes) {
                 InlineBlockParent ibp = new InlineBlockParent();
                 transferForeignObjects(attributes, ibp);
-                ibp.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
+                ibp.setBlockProgressionOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
                 setAreaAttributes(attributes, ibp);
                 setTraits(attributes, ibp, SUBSET_COMMON);
                 setTraits(attributes, ibp, SUBSET_BOX);
@@ -769,7 +769,7 @@ public class AreaTreeParser {
                 setTraits(attributes, text, SUBSET_COLOR);
                 setTraits(attributes, text, SUBSET_FONT);
                 text.setBaselineOffset(XMLUtil.getAttributeAsInt(attributes, "baseline", 0));
-                text.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
+                text.setBlockProgressionOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
                 text.setTextLetterSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
                         "tlsadjust", 0));
                 text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
@@ -791,8 +791,14 @@ public class AreaTreeParser {
                 int[] letterAdjust
                         = ConversionUtils.toIntArray(
                             lastAttributes.getValue("letter-adjust"), "\\s");
+                int level = XMLUtil.getAttributeAsInt(lastAttributes, "level", -1);
+                boolean reversed = XMLUtil.getAttributeAsBoolean(lastAttributes, "reversed", false);
+                int[][] gposAdjustments
+                    = XMLUtil.getAttributeAsPositionAdjustments(lastAttributes, "position-adjust");
                 content.flip();
-                WordArea word = new WordArea(content.toString().trim(), offset, letterAdjust);
+                WordArea word = new WordArea
+                    ( offset, level, content.toString().trim(), letterAdjust,
+                      null, gposAdjustments, reversed );
                 AbstractTextArea text = getCurrentText();
                 word.setParentArea(text);
                 text.addChildArea(word);
@@ -811,7 +817,8 @@ public class AreaTreeParser {
                 if (content.position() > 0) {
                     content.flip();
                     boolean adjustable = XMLUtil.getAttributeAsBoolean(lastAttributes, "adj", true);
-                    SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable);
+                    int level = XMLUtil.getAttributeAsInt(lastAttributes, "level", -1);
+                    SpaceArea space = new SpaceArea(offset, level, content.charAt(0), adjustable);
                     AbstractTextArea text = getCurrentText();
                     space.setParentArea(text);
                     text.addChildArea(space);
@@ -821,7 +828,7 @@ public class AreaTreeParser {
                     setTraits(lastAttributes, space, SUBSET_COMMON);
                     setTraits(lastAttributes, space, SUBSET_BOX);
                     setTraits(lastAttributes, space, SUBSET_COLOR);
-                    space.setOffset(offset);
+                    space.setBlockProgressionOffset(offset);
                     Area parent = (Area)areaStack.peek();
                     parent.addChildArea(space);
                 }
@@ -842,7 +849,8 @@ public class AreaTreeParser {
                 setTraits(attributes, leader, SUBSET_BOX);
                 setTraits(attributes, leader, SUBSET_COLOR);
                 setTraits(attributes, leader, SUBSET_FONT);
-                leader.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
+                leader.setBlockProgressionOffset
+                    ( XMLUtil.getAttributeAsInt(attributes, "offset", 0) );
                 String ruleStyle = attributes.getValue("ruleStyle");
                 if (ruleStyle != null) {
                     leader.setRuleStyle(ruleStyle);
@@ -857,7 +865,8 @@ public class AreaTreeParser {
         private class InlineViewportMaker extends AbstractMaker {
 
             public void startElement(Attributes attributes) {
-                InlineViewport viewport = new InlineViewport(null);
+                int level = XMLUtil.getAttributeAsInt(attributes, "level", -1);
+                InlineViewport viewport = new InlineViewport(null, level);
                 transferForeignObjects(attributes, viewport);
                 setAreaAttributes(attributes, viewport);
                 setTraits(attributes, viewport, SUBSET_COMMON);
@@ -865,7 +874,8 @@ public class AreaTreeParser {
                 setTraits(attributes, viewport, SUBSET_COLOR);
                 viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos"));
                 viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false));
-                viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
+                viewport.setBlockProgressionOffset
+                    ( XMLUtil.getAttributeAsInt(attributes, "offset", 0) );
                 Area parent = (Area)areaStack.peek();
                 parent.addChildArea(viewport);
                 areaStack.push(viewport);
@@ -1025,6 +1035,7 @@ public class AreaTreeParser {
         private void setAreaAttributes(Attributes attributes, Area area) {
             area.setIPD(Integer.parseInt(attributes.getValue("ipd")));
             area.setBPD(Integer.parseInt(attributes.getValue("bpd")));
+            area.setBidiLevel(XMLUtil.getAttributeAsInt(attributes, "level", -1));
         }
 
         private static final Object[] SUBSET_COMMON = new Object[] {

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Block.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Block.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Block.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Block.java Sun Feb 26 02:29:01 2012
@@ -58,7 +58,6 @@ public class Block extends BlockParent {
      */
     public static final int FIXED = 3;
 
-    private int stacking = TB;
     private int positioning = STACK;
 
     /** if true, allow BPD update */
@@ -133,5 +132,13 @@ public class Block extends BlockParent {
         return (startIndent != null ? startIndent : 0);
     }
 
+    /**
+     * @return the end-indent trait
+     */
+    public int getEndIndent() {
+        Integer endIndent = (Integer)getTrait(Trait.END_INDENT);
+        return (endIndent != null ? endIndent : 0);
+    }
+
 }
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/BodyRegion.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/BodyRegion.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/BodyRegion.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/BodyRegion.java Sun Feb 26 02:29:01 2012
@@ -22,6 +22,7 @@ package org.apache.fop.area;
 import java.util.List;
 
 import org.apache.fop.fo.pagination.RegionBody;
+import org.apache.fop.traits.WritingModeTraitsGetter;
 
 /**
  * This class is a container for the areas that may be generated by
@@ -140,6 +141,17 @@ public class BodyRegion extends RegionRe
     }
 
     /**
+     * Sets the writing mode traits for the main reference area of
+     * this body region area.
+     * @param wmtg a WM traits getter
+     */
+    public void setWritingModeTraits(WritingModeTraitsGetter wmtg) {
+        if ( getMainReference() != null ) {
+            getMainReference().setWritingModeTraits ( wmtg );
+        }
+    }
+
+    /**
      * Clone this object.
      *
      * @return a shallow copy of this object

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/CTM.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/CTM.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/CTM.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/CTM.java Sun Feb 26 02:29:01 2012
@@ -25,10 +25,12 @@ import java.awt.geom.Rectangle2D;
 import java.io.Serializable;
 
 import org.apache.fop.datatypes.FODimension;
+import org.apache.fop.traits.WritingMode;
 
 import static org.apache.fop.fo.Constants.EN_LR_TB;
 import static org.apache.fop.fo.Constants.EN_RL_TB;
 import static org.apache.fop.fo.Constants.EN_TB_RL;
+import static org.apache.fop.fo.Constants.EN_TB_LR;
 
 /**
  * Describe a PDF or PostScript style coordinate transformation matrix (CTM).
@@ -42,7 +44,7 @@ public class CTM implements Serializable
     private double a, b, c, d, e, f;
 
     private static final CTM CTM_LRTB = new CTM(1, 0, 0, 1, 0, 0);
-    private static final CTM CTM_RLTB = new CTM(-1, 0, 0, 1, 0, 0);
+    private static final CTM CTM_RLTB = new CTM(1, 0, 0, 1, 0, 0);
     private static final CTM CTM_TBRL = new CTM(0, 1, -1, 0, 0, 0);
 
     /**
@@ -126,28 +128,25 @@ public class CTM implements Serializable
      * Return a CTM which will transform coordinates for a particular writing-mode
      * into normalized first quandrant coordinates.
      * @param wm A writing mode constant from fo.properties.WritingMode, ie.
-     * one of LR_TB, RL_TB, TB_RL.
+     * one of LR_TB, RL_TB, TB_RL, TB_LR.
      * @param ipd The inline-progression dimension of the reference area whose
      * CTM is being set..
      * @param bpd The block-progression dimension of the reference area whose
      * CTM is being set.
      * @return a new CTM with the required transform
      */
-    public static CTM getWMctm(int wm, int ipd, int bpd) {
+    public static CTM getWMctm(WritingMode wm, int ipd, int bpd) {
         CTM wmctm;
-        switch (wm) {
+        switch (wm.getEnumValue()) {
             case EN_LR_TB:
                 return new CTM(CTM_LRTB);
             case EN_RL_TB:
-                wmctm = new CTM(CTM_RLTB);
-                wmctm.e = ipd;
-                return wmctm;
-                //return  CTM_RLTB.translate(ipd, 0);
+                return new CTM(CTM_RLTB);
             case EN_TB_RL:  // CJK
+            case EN_TB_LR:  // CJK
                 wmctm = new CTM(CTM_TBRL);
                 wmctm.e = bpd;
                 return wmctm;
-                //return CTM_TBRL.translate(0, ipd);
             default:
                 return null;
         }
@@ -284,7 +283,7 @@ public class CTM implements Serializable
      * @return CTM the coordinate transformation matrix (CTM)
      */
     public static CTM getCTMandRelDims(int absRefOrient,
-                                       int writingMode,
+                                       WritingMode writingMode,
                                        Rectangle2D absVPrect,
                                        FODimension reldims) {
         int width, height;
@@ -335,12 +334,18 @@ public class CTM implements Serializable
          * can set ipd and bpd appropriately based on the writing mode.
          */
 
-        if (writingMode == EN_LR_TB || writingMode == EN_RL_TB) {
+        switch ( writingMode.getEnumValue() ) {
+        default:
+        case EN_LR_TB:
+        case EN_RL_TB:
             reldims.ipd = width;
             reldims.bpd = height;
-        } else {
+            break;
+        case EN_TB_LR:
+        case EN_TB_RL:
             reldims.ipd = height;
             reldims.bpd = width;
+            break;
         }
         // Set a rectangle to be the writing-mode relative version???
         // Now transform for writing mode

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LineArea.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LineArea.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LineArea.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LineArea.java Sun Feb 26 02:29:01 2012
@@ -21,6 +21,7 @@ package org.apache.fop.area;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import org.apache.fop.area.inline.InlineArea;
@@ -125,6 +126,24 @@ public class LineArea extends Area {
     }
 
     /**
+     * <p>Set (en masse) the inline child areas of this line area.</p>
+     * <p> Used by bidirectional processing after line area consituent reordering.</p>
+     * @param inlineAreas the list of inline areas
+     */
+    public void setInlineAreas ( List inlineAreas ) {
+        for ( Iterator<InlineArea> it = inlineAreas.iterator(); it.hasNext();) {
+            InlineArea ia = it.next();
+            Area pa = ia.getParentArea();
+            if ( pa == null ) {
+                ia.setParentArea ( this );
+            } else {
+                assert pa == this;
+            }
+        }
+        this.inlineAreas = inlineAreas;
+    }
+
+    /**
      * Get the inline child areas of this line area.
      *
      * @return the list of inline areas
@@ -149,6 +168,21 @@ public class LineArea extends Area {
     }
 
     /**
+     * Get the end indent of this line area.
+     * The end indent is used for offsetting the end of
+     * the inline areas for alignment or other indents.
+     *
+     * @return the end indent value
+     */
+    public int getEndIndent() {
+        if (hasTrait(Trait.END_INDENT)) {
+            return getTraitAsInteger(Trait.END_INDENT);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
      * Updates the extents of the line area from its children.
      */
     public void updateExtentsFromChildren() {
@@ -178,17 +212,21 @@ public class LineArea extends Area {
      * @param ipdVariation the difference between old and new ipd
      */
     public void handleIPDVariation(int ipdVariation) {
+        int si = getStartIndent();
+        int ei = getEndIndent();
         switch (adjustingInfo.lineAlignment) {
             case EN_START:
-                // nothing to do in this case
+                // adjust end indent
+                addTrait(Trait.END_INDENT, ei - ipdVariation);
                 break;
             case EN_CENTER:
-                // re-compute indent
-                addTrait(Trait.START_INDENT, getStartIndent() - ipdVariation / 2);
+                // adjust start and end indents
+                addTrait(Trait.START_INDENT, si - ipdVariation / 2);
+                addTrait(Trait.END_INDENT, ei - ipdVariation / 2);
                 break;
             case EN_END:
-                // re-compute indent
-                addTrait(Trait.START_INDENT, getStartIndent() - ipdVariation);
+                // adjust start indent
+                addTrait(Trait.START_INDENT, si - ipdVariation);
                 break;
             case EN_JUSTIFY:
                 // compute variation factor
@@ -198,7 +236,7 @@ public class LineArea extends Area {
                 // if the LineArea has already been added to the area tree,
                 // call finalize(); otherwise, wait for the LineLM to call it
                 if (adjustingInfo.bAddedToAreaTree) {
-                    finalise();
+                    finish();
                 }
                 break;
             default:
@@ -211,7 +249,7 @@ public class LineArea extends Area {
      * and destroy the AdjustingInfo object if there are
      * no UnresolvedAreas left
      */
-    public void finalise() {
+    public void finish() {
         if (adjustingInfo.lineAlignment == EN_JUSTIFY) {
             if (log.isTraceEnabled()) {
                 log.trace("Applying variation factor to justified line: " + adjustingInfo);

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LinkResolver.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LinkResolver.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LinkResolver.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/LinkResolver.java Sun Feb 26 02:29:01 2012
@@ -20,6 +20,7 @@
 package org.apache.fop.area;
 
 // Java
+import java.util.ArrayList;
 import java.util.List;
 import java.io.Serializable;
 
@@ -33,6 +34,7 @@ public class LinkResolver implements Res
     private boolean resolved = false;
     private String idRef;
     private Area area;
+    private transient List<Resolvable> dependents = null;
 
     /**
      * Create a new link resolver.
@@ -79,8 +81,35 @@ public class LinkResolver implements Res
     public void resolveIDRef(String id, PageViewport pv) {
         if (idRef.equals(id) && pv != null) {
             resolved = true;
-            Trait.InternalLink iLink = new Trait.InternalLink(pv.getKey(), idRef);
-            area.addTrait(Trait.INTERNAL_LINK, iLink);
+            if ( area != null ) {
+                Trait.InternalLink iLink = new Trait.InternalLink(pv.getKey(), idRef);
+                area.addTrait(Trait.INTERNAL_LINK, iLink);
+                area = null; // break circular reference from basic link area to this resolver
+            }
+            resolveDependents(id, pv);
         }
     }
+
+    /**
+     * Add dependent resolvable. Used to resolve second-order resolvables that
+     * depend on resolution of this resolver.
+     * @param dependent resolvable
+     */
+    public void addDependent(Resolvable dependent) {
+        if ( dependents == null ) {
+            dependents = new ArrayList<Resolvable>();
+        }
+        dependents.add(dependent);
+    }
+
+    private void resolveDependents(String id, PageViewport pv) {
+        if ( dependents != null ) {
+            List<PageViewport> pages = new ArrayList<PageViewport>();
+            pages.add(pv);
+            for ( Resolvable r : dependents ) {
+                r.resolveIDRef(id, pages);
+            }
+        }
+    }
+
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/MainReference.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/MainReference.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/MainReference.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/MainReference.java Sun Feb 26 02:29:01 2012
@@ -19,6 +19,8 @@
 
 package org.apache.fop.area;
 
+import org.apache.fop.traits.WritingModeTraitsGetter;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -124,5 +126,16 @@ public class MainReference extends Area 
         return parent.getColumnGap();
     }
 
+    /**
+     * Sets the writing mode traits for the spans of this main
+     * reference area.
+     * @param wmtg a WM traits getter
+     */
+    public void setWritingModeTraits(WritingModeTraitsGetter wmtg) {
+        for ( Span s : (List<Span>) getSpans() ) {
+            s.setWritingModeTraits ( wmtg );
+        }
+    }
+
 }
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Page.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Page.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Page.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/Page.java Sun Feb 26 02:29:01 2012
@@ -33,6 +33,7 @@ import org.apache.fop.fo.pagination.Regi
 import org.apache.fop.fo.pagination.SimplePageMaster;
 import org.apache.fop.fo.properties.CommonMarginBlock;
 import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.traits.WritingModeTraitsGetter;
 
 import static org.apache.fop.fo.Constants.FO_REGION_AFTER;
 import static org.apache.fop.fo.Constants.FO_REGION_BEFORE;
@@ -304,6 +305,29 @@ public class Page extends AreaTreeObject
         return unresolved;
     }
 
+    /**
+     * Sets the writing mode traits for the region viewports of
+     * this page.
+     * @param wmtg a WM traits getter
+     */
+    public void setWritingModeTraits(WritingModeTraitsGetter wmtg) {
+        if (regionBefore != null) {
+            regionBefore.setWritingModeTraits(wmtg);
+        }
+        if (regionStart != null) {
+            regionStart.setWritingModeTraits(wmtg);
+        }
+        if (regionBody != null) {
+            regionBody.setWritingModeTraits(wmtg);
+        }
+        if (regionEnd != null) {
+            regionEnd.setWritingModeTraits(wmtg);
+        }
+        if (regionAfter != null) {
+            regionAfter.setWritingModeTraits(wmtg);
+        }
+    }
+
 }
 
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/area/PageViewport.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/area/PageViewport.java?rev=1293736&r1=1293735&r2=1293736&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/area/PageViewport.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/area/PageViewport.java Sun Feb 26 02:29:01 2012
@@ -34,6 +34,7 @@ import org.apache.commons.logging.LogFac
 
 import org.apache.fop.fo.flow.Marker;
 import org.apache.fop.fo.pagination.SimplePageMaster;
+import org.apache.fop.traits.WritingModeTraitsGetter;
 
 import static org.apache.fop.fo.Constants.FO_REGION_BODY;
 import static org.apache.fop.fo.Constants.EN_FSWP;
@@ -654,4 +655,15 @@ public class PageViewport extends AreaTr
     public RegionReference getRegionReference(int id) {
         return getPage().getRegionViewport(id).getRegionReference();
     }
+
+    /**
+     * Sets the writing mode traits for the page associated with this viewport.
+     * @param wmtg a WM traits getter
+     */
+    public void setWritingModeTraits(WritingModeTraitsGetter wmtg) {
+        if ( page != null ) {
+            page.setWritingModeTraits(wmtg);
+        }
+    }
+
 }



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