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 [13/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/tru...
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GurmukhiScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GurmukhiScriptProcessor.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GurmukhiScriptProcessor.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GurmukhiScriptProcessor.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,543 @@
+/*
+ * 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.complexscripts.scripts;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable;
+import org.apache.fop.complexscripts.util.GlyphSequence;
+import org.apache.fop.complexscripts.util.ScriptContextTester;
+
+// CSOFF: AvoidNestedBlocksCheck
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: WhitespaceAfter
+// CSOFF: InnerAssignmentCheck
+// CSOFF: SimplifyBooleanReturnCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * <p>The <code>GurmukhiScriptProcessor</code> class implements a script processor for
+ * performing glyph substitution and positioning operations on content associated with the Gurmukhi script.</p>
+ * @author Glenn Adams
+ */
+public class GurmukhiScriptProcessor extends IndicScriptProcessor {
+
+ /** logging instance */
+ private static final Log log = LogFactory.getLog(GurmukhiScriptProcessor.class); // CSOK: ConstantNameCheck
+
+ GurmukhiScriptProcessor ( String script ) {
+ super ( script );
+ }
+
+ @Override
+ protected Class<? extends GurmukhiSyllabizer> getSyllabizerClass() {
+ return GurmukhiSyllabizer.class;
+ }
+
+ @Override
+ // find rightmost pre-base matra
+ protected int findPreBaseMatra ( GlyphSequence gs ) {
+ int ng = gs.getGlyphCount();
+ int lk = -1;
+ for ( int i = ng; i > 0; i-- ) {
+ int k = i - 1;
+ if ( containsPreBaseMatra ( gs, k ) ) {
+ lk = k;
+ break;
+ }
+ }
+ return lk;
+ }
+
+ @Override
+ // find leftmost pre-base matra target, starting from source
+ protected int findPreBaseMatraTarget ( GlyphSequence gs, int source ) {
+ int ng = gs.getGlyphCount();
+ int lk = -1;
+ for ( int i = ( source < ng ) ? source : ng; i > 0; i-- ) {
+ int k = i - 1;
+ if ( containsConsonant ( gs, k ) ) {
+ if ( containsHalfConsonant ( gs, k ) ) {
+ lk = k;
+ } else if ( lk == -1 ) {
+ lk = k;
+ } else {
+ break;
+ }
+ }
+ }
+ return lk;
+ }
+
+ private static boolean containsPreBaseMatra ( GlyphSequence gs, int k ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( k );
+ int[] ca = gs.getCharacterArray ( false );
+ for ( int i = a.getStart(), e = a.getEnd(); i < e; i++ ) {
+ if ( isPreM ( ca [ i ] ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean containsConsonant ( GlyphSequence gs, int k ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( k );
+ int[] ca = gs.getCharacterArray ( false );
+ for ( int i = a.getStart(), e = a.getEnd(); i < e; i++ ) {
+ if ( isC ( ca [ i ] ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean containsHalfConsonant ( GlyphSequence gs, int k ) {
+ Boolean half = (Boolean) gs.getAssociation ( k ) . getPredication ( "half" );
+ return ( half != null ) ? half.booleanValue() : false;
+ }
+
+ @Override
+ protected int findReph ( GlyphSequence gs ) {
+ int ng = gs.getGlyphCount();
+ int li = -1;
+ for ( int i = 0; i < ng; i++ ) {
+ if ( containsReph ( gs, i ) ) {
+ li = i;
+ break;
+ }
+ }
+ return li;
+ }
+
+ @Override
+ protected int findRephTarget ( GlyphSequence gs, int source ) {
+ int ng = gs.getGlyphCount();
+ int c1 = -1;
+ int c2 = -1;
+ // first candidate target is after first non-half consonant
+ for ( int i = 0; i < ng; i++ ) {
+ if ( ( i != source ) && containsConsonant ( gs, i ) ) {
+ if ( ! containsHalfConsonant ( gs, i ) ) {
+ c1 = i + 1;
+ break;
+ }
+ }
+ }
+ // second candidate target is after last non-prebase matra after first candidate or before first syllable or vedic mark
+ for ( int i = ( c1 >= 0 ) ? c1 : 0; i < ng; i++ ) {
+ if ( containsMatra ( gs, i ) && ! containsPreBaseMatra ( gs, i ) ) {
+ c2 = i + 1;
+ } else if ( containsOtherMark ( gs, i ) ) {
+ c2 = i;
+ break;
+ }
+ }
+ if ( c2 >= 0 ) {
+ return c2;
+ } else if ( c1 >= 0 ) {
+ return c1;
+ } else {
+ return source;
+ }
+ }
+
+ private static boolean containsReph ( GlyphSequence gs, int k ) {
+ Boolean rphf = (Boolean) gs.getAssociation ( k ) . getPredication ( "rphf" );
+ return ( rphf != null ) ? rphf.booleanValue() : false;
+ }
+
+ private static boolean containsMatra ( GlyphSequence gs, int k ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( k );
+ int[] ca = gs.getCharacterArray ( false );
+ for ( int i = a.getStart(), e = a.getEnd(); i < e; i++ ) {
+ if ( isM ( ca [ i ] ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean containsOtherMark ( GlyphSequence gs, int k ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( k );
+ int[] ca = gs.getCharacterArray ( false );
+ for ( int i = a.getStart(), e = a.getEnd(); i < e; i++ ) {
+ switch ( typeOf ( ca [ i ] ) ) {
+ case C_T: // tone (e.g., udatta, anudatta)
+ case C_A: // accent (e.g., acute, grave)
+ case C_O: // other (e.g., candrabindu, anusvara, visarga, etc)
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
+ private static class GurmukhiSyllabizer extends DefaultSyllabizer {
+ GurmukhiSyllabizer ( String script, String language ) {
+ super ( script, language );
+ }
+ @Override
+ // | C ...
+ protected int findStartOfSyllable ( int[] ca, int s, int e ) {
+ if ( ( s < 0 ) || ( s >= e ) ) {
+ return -1;
+ } else {
+ while ( s < e ) {
+ int c = ca [ s ];
+ if ( isC ( c ) ) {
+ break;
+ } else {
+ s++;
+ }
+ }
+ return s;
+ }
+ }
+ @Override
+ // D* L? | ...
+ protected int findEndOfSyllable ( int[] ca, int s, int e ) {
+ if ( ( s < 0 ) || ( s >= e ) ) {
+ return -1;
+ } else {
+ int nd = 0;
+ int nl = 0;
+ int i;
+ // consume dead consonants
+ while ( ( i = isDeadConsonant ( ca, s, e ) ) > s ) {
+ s = i; nd++;
+ }
+ // consume zero or one live consonant
+ if ( ( i = isLiveConsonant ( ca, s, e ) ) > s ) {
+ s = i; nl++;
+ }
+ return ( ( nd > 0 ) || ( nl > 0 ) ) ? s : -1;
+ }
+ }
+ // D := ( C N? H )?
+ private int isDeadConsonant ( int[] ca, int s, int e ) {
+ if ( s < 0 ) {
+ return -1;
+ } else {
+ int c, i = 0;
+ int nc = 0, nh = 0;
+ do {
+ // C
+ if ( ( s + i ) < e ) {
+ c = ca [ s + i ];
+ if ( isC ( c ) ) {
+ i++;
+ nc++;
+ } else {
+ break;
+ }
+ }
+ // N?
+ if ( ( s + i ) < e ) {
+ c = ca [ s + 1 ];
+ if ( isN ( c ) ) {
+ i++;
+ }
+ }
+ // H
+ if ( ( s + i ) < e ) {
+ c = ca [ s + i ];
+ if ( isH ( c ) ) {
+ i++;
+ nh++;
+ } else {
+ break;
+ }
+ }
+ } while ( false );
+ return ( nc > 0 ) && ( nh > 0 ) ? s + i : -1;
+ }
+ }
+ // L := ( (C|V) N? X* )?; where X = ( MATRA | ACCENT MARK | TONE MARK | OTHER MARK )
+ private int isLiveConsonant ( int[] ca, int s, int e ) {
+ if ( s < 0 ) {
+ return -1;
+ } else {
+ int c, i = 0;
+ int nc = 0, nv = 0, nx = 0;
+ do {
+ // C
+ if ( ( s + i ) < e ) {
+ c = ca [ s + i ];
+ if ( isC ( c ) ) {
+ i++;
+ nc++;
+ } else if ( isV ( c ) ) {
+ i++;
+ nv++;
+ } else {
+ break;
+ }
+ }
+ // N?
+ if ( ( s + i ) < e ) {
+ c = ca [ s + i ];
+ if ( isN ( c ) ) {
+ i++;
+ }
+ }
+ // X*
+ while ( ( s + i ) < e ) {
+ c = ca [ s + i ];
+ if ( isX ( c ) ) {
+ i++;
+ nx++;
+ } else {
+ break;
+ }
+ }
+ } while ( false );
+ // if no X but has H, then ignore C|I
+ if ( nx == 0 ) {
+ if ( ( s + i ) < e ) {
+ c = ca [ s + i ];
+ if ( isH ( c ) ) {
+ if ( nc > 0 ) {
+ nc--;
+ } else if ( nv > 0 ) {
+ nv--;
+ }
+ }
+ }
+ }
+ return ( ( nc > 0 ) || ( nv > 0 ) ) ? s + i : -1;
+ }
+ }
+ }
+
+ // gurmukhi character types
+ static final short C_U = 0; // unassigned
+ static final short C_C = 1; // consonant
+ static final short C_V = 2; // vowel
+ static final short C_M = 3; // vowel sign (matra)
+ static final short C_S = 4; // symbol or sign
+ static final short C_T = 5; // tone mark
+ static final short C_A = 6; // accent mark
+ static final short C_P = 7; // punctuation
+ static final short C_D = 8; // digit
+ static final short C_H = 9; // halant (virama)
+ static final short C_O = 10; // other signs
+ static final short C_N = 0x0100; // nukta(ized)
+ static final short C_R = 0x0200; // reph(ized)
+ static final short C_PRE = 0x0400; // pre-base
+ static final short C_M_TYPE = 0x00FF; // type mask
+ static final short C_M_FLAGS = 0x7F00; // flag mask
+ // gurmukhi block range
+ static final int ccaStart = 0x0A00; // first code point mapped by cca // CSOK: ConstantNameCheck
+ static final int ccaEnd = 0x0A80; // last code point + 1 mapped by cca // CSOK: ConstantNameCheck
+ // gurmukhi character type lookups
+ static final short[] cca = { // CSOK: ConstantNameCheck
+ C_U, // 0x0A00 // UNASSIGNED
+ C_O, // 0x0A01 // ADAK BINDI
+ C_O, // 0x0A02 // BINDI
+ C_O, // 0x0A03 // VISARGA
+ C_U, // 0x0A04 // UNASSIGNED
+ C_V, // 0x0A05 // A
+ C_V, // 0x0A06 // AA
+ C_V, // 0x0A07 // I
+ C_V, // 0x0A08 // II
+ C_V, // 0x0A09 // U
+ C_V, // 0x0A0A // UU
+ C_U, // 0x0A0B // UNASSIGNED
+ C_U, // 0x0A0C // UNASSIGNED
+ C_U, // 0x0A0D // UNASSIGNED
+ C_U, // 0x0A0E // UNASSIGNED
+ C_V, // 0x0A0F // E
+ C_V, // 0x0A10 // AI
+ C_U, // 0x0A11 // UNASSIGNED
+ C_U, // 0x0A12 // UNASSIGNED
+ C_V, // 0x0A13 // O
+ C_V, // 0x0A14 // AU
+ C_C, // 0x0A15 // KA
+ C_C, // 0x0A16 // KHA
+ C_C, // 0x0A17 // GA
+ C_C, // 0x0A18 // GHA
+ C_C, // 0x0A19 // NGA
+ C_C, // 0x0A1A // CA
+ C_C, // 0x0A1B // CHA
+ C_C, // 0x0A1C // JA
+ C_C, // 0x0A1D // JHA
+ C_C, // 0x0A1E // NYA
+ C_C, // 0x0A1F // TTA
+ C_C, // 0x0A20 // TTHA
+ C_C, // 0x0A21 // DDA
+ C_C, // 0x0A22 // DDHA
+ C_C, // 0x0A23 // NNA
+ C_C, // 0x0A24 // TA
+ C_C, // 0x0A25 // THA
+ C_C, // 0x0A26 // DA
+ C_C, // 0x0A27 // DHA
+ C_C, // 0x0A28 // NA
+ C_U, // 0x0A29 // UNASSIGNED
+ C_C, // 0x0A2A // PA
+ C_C, // 0x0A2B // PHA
+ C_C, // 0x0A2C // BA
+ C_C, // 0x0A2D // BHA
+ C_C, // 0x0A2E // MA
+ C_C, // 0x0A2F // YA
+ C_C|C_R, // 0x0A30 // RA // CSOK: WhitespaceAround
+ C_U, // 0x0A31 // UNASSIGNED
+ C_C, // 0x0A32 // LA
+ C_C, // 0x0A33 // LLA
+ C_U, // 0x0A34 // UNASSIGNED
+ C_C, // 0x0A35 // VA
+ C_C, // 0x0A36 // SHA
+ C_U, // 0x0A37 // UNASSIGNED
+ C_C, // 0x0A38 // SA
+ C_C, // 0x0A39 // HA
+ C_U, // 0x0A3A // UNASSIGNED
+ C_U, // 0x0A3B // UNASSIGNED
+ C_N, // 0x0A3C // NUKTA
+ C_U, // 0x0A3D // UNASSIGNED
+ C_M, // 0x0A3E // AA
+ C_M|C_PRE, // 0x0A3F // I // CSOK: WhitespaceAround
+ C_M, // 0x0A40 // II
+ C_M, // 0x0A41 // U
+ C_M, // 0x0A42 // UU
+ C_U, // 0x0A43 // UNASSIGNED
+ C_U, // 0x0A44 // UNASSIGNED
+ C_U, // 0x0A45 // UNASSIGNED
+ C_U, // 0x0A46 // UNASSIGNED
+ C_M, // 0x0A47 // EE
+ C_M, // 0x0A48 // AI
+ C_U, // 0x0A49 // UNASSIGNED
+ C_U, // 0x0A4A // UNASSIGNED
+ C_M, // 0x0A4B // OO
+ C_M, // 0x0A4C // AU
+ C_H, // 0x0A4D // VIRAMA (HALANT)
+ C_U, // 0x0A4E // UNASSIGNED
+ C_U, // 0x0A4F // UNASSIGNED
+ C_U, // 0x0A50 // UNASSIGNED
+ C_T, // 0x0A51 // UDATTA
+ C_U, // 0x0A52 // UNASSIGNED
+ C_U, // 0x0A53 // UNASSIGNED
+ C_U, // 0x0A54 // UNASSIGNED
+ C_U, // 0x0A55 // UNASSIGNED
+ C_U, // 0x0A56 // UNASSIGNED
+ C_U, // 0x0A57 // UNASSIGNED
+ C_U, // 0x0A58 // UNASSIGNED
+ C_C|C_N, // 0x0A59 // KHHA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x0A5A // GHHA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x0A5B // ZA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x0A5C // RRA // CSOK: WhitespaceAround
+ C_U, // 0x0A5D // UNASSIGNED
+ C_C|C_N, // 0x0A5E // FA // CSOK: WhitespaceAround
+ C_U, // 0x0A5F // UNASSIGNED
+ C_U, // 0x0A60 // UNASSIGNED
+ C_U, // 0x0A61 // UNASSIGNED
+ C_U, // 0x0A62 // UNASSIGNED
+ C_U, // 0x0A63 // UNASSIGNED
+ C_U, // 0x0A64 // UNASSIGNED
+ C_U, // 0x0A65 // UNASSIGNED
+ C_D, // 0x0A66 // ZERO
+ C_D, // 0x0A67 // ONE
+ C_D, // 0x0A68 // TWO
+ C_D, // 0x0A69 // THREE
+ C_D, // 0x0A6A // FOUR
+ C_D, // 0x0A6B // FIVE
+ C_D, // 0x0A6C // SIX
+ C_D, // 0x0A6D // SEVEN
+ C_D, // 0x0A6E // EIGHT
+ C_D, // 0x0A6F // NINE
+ C_O, // 0x0A70 // TIPPI
+ C_O, // 0x0A71 // ADDAK
+ C_V, // 0x0A72 // IRI
+ C_V, // 0x0A73 // URA
+ C_S, // 0x0A74 // EK ONKAR
+ C_O, // 0x0A75 // YAKASH
+ C_U, // 0x0A76 // UNASSIGNED
+ C_U, // 0x0A77 // UNASSIGNED
+ C_U, // 0x0A78 // UNASSIGNED
+ C_U, // 0x0A79 // UNASSIGNED
+ C_U, // 0x0A7A // UNASSIGNED
+ C_U, // 0x0A7B // UNASSIGNED
+ C_U, // 0x0A7C // UNASSIGNED
+ C_U, // 0x0A7D // UNASSIGNED
+ C_U, // 0x0A7E // UNASSIGNED
+ C_U // 0x0A7F // UNASSIGNED
+ };
+ static int typeOf(int c) {
+ if ( ( c >= ccaStart ) && ( c < ccaEnd ) ) {
+ return cca [ c - ccaStart ] & C_M_TYPE;
+ } else {
+ return C_U;
+ }
+ }
+ static boolean isType(int c, int t) {
+ return typeOf ( c ) == t;
+ }
+ static boolean hasFlag(int c, int f) {
+ if ( ( c >= ccaStart ) && ( c < ccaEnd ) ) {
+ return ( cca [ c - ccaStart ] & f ) == f;
+ } else {
+ return false;
+ }
+ }
+ static boolean isC(int c) {
+ return isType(c,C_C);
+ }
+ static boolean isR(int c) {
+ return isType(c,C_C) && hasR(c);
+ }
+ static boolean isV(int c) {
+ return isType(c,C_V);
+ }
+ static boolean isN(int c) {
+ return c == 0x0A3C;
+ }
+ static boolean isH(int c) {
+ return c == 0x0A4D;
+ }
+ static boolean isM(int c) {
+ return isType(c,C_M);
+ }
+ static boolean isPreM(int c) {
+ return isType(c,C_M) && hasFlag(c,C_PRE);
+ }
+ static boolean isX(int c) {
+ switch ( typeOf ( c ) ) {
+ case C_M: // matra (combining vowel)
+ case C_A: // accent mark
+ case C_T: // tone mark
+ case C_O: // other (modifying) mark
+ return true;
+ default:
+ return false;
+ }
+ }
+ static boolean hasR(int c) {
+ return hasFlag(c,C_R);
+ }
+ static boolean hasN(int c) {
+ return hasFlag(c,C_N);
+ }
+
+ @Override
+ public GlyphSequence reorderCombiningMarks ( GlyphDefinitionTable gdef, GlyphSequence gs, int[][] gpa, String script, String language ) {
+ return super.reorderCombiningMarks ( gdef, gs, gpa, script, language );
+ }
+
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/IndicScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/IndicScriptProcessor.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/IndicScriptProcessor.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/IndicScriptProcessor.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,589 @@
+/*
+ * 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.complexscripts.scripts;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.complexscripts.fonts.GlyphTable;
+import org.apache.fop.complexscripts.util.CharScript;
+import org.apache.fop.complexscripts.util.GlyphContextTester;
+import org.apache.fop.complexscripts.util.GlyphSequence;
+import org.apache.fop.complexscripts.util.ScriptContextTester;
+
+// CSOFF: AvoidNestedBlocksCheck
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: InnerAssignmentCheck
+// CSOFF: SimplifyBooleanReturnCheck
+// CSOFF: EmptyForIteratorPadCheck
+// CSOFF: WhitespaceAfterCheck
+// CSOFF: ParameterNumberCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * <p>The <code>IndicScriptProcessor</code> class implements a script processor for
+ * performing glyph substitution and positioning operations on content associated with the Indic script.</p>
+ * @author Glenn Adams
+ */
+public class IndicScriptProcessor extends DefaultScriptProcessor {
+
+ /** logging instance */
+ private static final Log log = LogFactory.getLog(IndicScriptProcessor.class); // CSOK: ConstantNameCheck
+
+ /** required features to use for substitutions */
+ private static final String[] gsubReqFeatures = // CSOK: ConstantNameCheck
+ {
+ "abvf", // above base forms
+ "abvs", // above base substitutions
+ "akhn", // akhand
+ "blwf", // below base forms
+ "blws", // below base substitutions
+ "ccmp", // glyph composition/decomposition
+ "cjct", // conjunct forms
+ "clig", // contextual ligatures
+ "half", // half forms
+ "haln", // halant forms
+ "locl", // localized forms
+ "nukt", // nukta forms
+ "pref", // pre-base forms
+ "pres", // pre-base substitutions
+ "pstf", // post-base forms
+ "psts", // post-base substitutions
+ "rkrf", // rakar forms
+ "rphf", // reph form
+ "vatu" // vattu variants
+ };
+
+ /** optional features to use for substitutions */
+ private static final String[] gsubOptFeatures = // CSOK: ConstantNameCheck
+ {
+ "afrc", // alternative fractions
+ "calt", // contextual alternatives
+ "dlig" // discretionary ligatures
+ };
+
+ /** required features to use for positioning */
+ private static final String[] gposReqFeatures = // CSOK: ConstantNameCheck
+ {
+ "abvm", // above base marks
+ "blwm", // below base marks
+ "dist", // distance (adjustment)
+ "kern" // kerning
+ };
+
+ /** required features to use for positioning */
+ private static final String[] gposOptFeatures = // CSOK: ConstantNameCheck
+ {
+ };
+
+ private static class SubstitutionScriptContextTester implements ScriptContextTester {
+ private static Map/*<String,GlyphContextTester>*/ testerMap = new HashMap/*<String,GlyphContextTester>*/();
+ public GlyphContextTester getTester ( String feature ) {
+ return (GlyphContextTester) testerMap.get ( feature );
+ }
+ }
+
+ private static class PositioningScriptContextTester implements ScriptContextTester {
+ private static Map/*<String,GlyphContextTester>*/ testerMap = new HashMap/*<String,GlyphContextTester>*/();
+ public GlyphContextTester getTester ( String feature ) {
+ return (GlyphContextTester) testerMap.get ( feature );
+ }
+ }
+
+ /**
+ * Make script specific flavor of Indic script processor.
+ * @param script tag
+ * @return script processor instance
+ */
+ public static ScriptProcessor makeProcessor ( String script ) {
+ switch ( CharScript.scriptCodeFromTag ( script ) ) {
+ case CharScript.SCRIPT_DEVANAGARI:
+ case CharScript.SCRIPT_DEVANAGARI_2:
+ return new DevanagariScriptProcessor ( script );
+ case CharScript.SCRIPT_GUJARATI:
+ case CharScript.SCRIPT_GUJARATI_2:
+ return new GujaratiScriptProcessor ( script );
+ case CharScript.SCRIPT_GURMUKHI:
+ case CharScript.SCRIPT_GURMUKHI_2:
+ return new GurmukhiScriptProcessor ( script );
+ // [TBD] implement other script processors
+ default:
+ return new IndicScriptProcessor ( script );
+ }
+ }
+
+ private final ScriptContextTester subContextTester;
+ private final ScriptContextTester posContextTester;
+
+ IndicScriptProcessor ( String script ) {
+ super ( script );
+ this.subContextTester = new SubstitutionScriptContextTester();
+ this.posContextTester = new PositioningScriptContextTester();
+ }
+
+ /** {@inheritDoc} */
+ public String[] getSubstitutionFeatures() {
+ return gsubReqFeatures;
+ }
+
+ /** {@inheritDoc} */
+ public String[] getOptionalSubstitutionFeatures() {
+ return gsubOptFeatures;
+ }
+
+ /** {@inheritDoc} */
+ public ScriptContextTester getSubstitutionContextTester() {
+ return subContextTester;
+ }
+
+ /** {@inheritDoc} */
+ public String[] getPositioningFeatures() {
+ return gposReqFeatures;
+ }
+
+ /** {@inheritDoc} */
+ public String[] getOptionalPositioningFeatures() {
+ return gposOptFeatures;
+ }
+
+ /** {@inheritDoc} */
+ public ScriptContextTester getPositioningContextTester() {
+ return posContextTester;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public GlyphSequence substitute ( GlyphSequence gs, String script, String language, GlyphTable.UseSpec[] usa, ScriptContextTester sct ) {
+ assert usa != null;
+ // 1. syllabize
+ GlyphSequence[] sa = syllabize ( gs, script, language );
+ // 2. process each syllable
+ for ( int i = 0, n = sa.length; i < n; i++ ) {
+ GlyphSequence s = sa [ i ];
+ // apply basic shaping subs
+ for ( int j = 0, m = usa.length; j < m; j++ ) {
+ GlyphTable.UseSpec us = usa [ j ];
+ if ( isBasicShapingUse ( us ) ) {
+ s.setPredications ( true );
+ s = us.substitute ( s, script, language, sct );
+ }
+ }
+ // reorder pre-base matra
+ s = reorderPreBaseMatra ( s );
+ // reorder reph
+ s = reorderReph ( s );
+ // apply presentation subs
+ for ( int j = 0, m = usa.length; j < m; j++ ) {
+ GlyphTable.UseSpec us = usa [ j ];
+ if ( isPresentationUse ( us ) ) {
+ s.setPredications ( true );
+ s = us.substitute ( s, script, language, sct );
+ }
+ }
+ // record result
+ sa [ i ] = s;
+ }
+ // 3. return reassembled substituted syllables
+ return unsyllabize ( gs, sa );
+ }
+
+ /**
+ * Get script specific syllabizer class.
+ * @return a syllabizer class object or null
+ */
+ protected Class<? extends Syllabizer> getSyllabizerClass() {
+ return null;
+ }
+
+ private GlyphSequence[] syllabize ( GlyphSequence gs, String script, String language ) {
+ return Syllabizer.getSyllabizer ( script, language, getSyllabizerClass() ) . syllabize ( gs );
+ }
+
+ private GlyphSequence unsyllabize ( GlyphSequence gs, GlyphSequence[] sa ) {
+ return GlyphSequence.join ( gs, sa );
+ }
+
+ private static Set<String> basicShapingFeatures;
+ private static final String[] basicShapingFeatureStrings = { // CSOK: ConstantNameCheck
+ "abvf",
+ "akhn",
+ "blwf",
+ "cjct",
+ "half",
+ "locl",
+ "nukt",
+ "pref",
+ "pstf",
+ "rkrf",
+ "rphf",
+ "vatu",
+ };
+ static {
+ basicShapingFeatures = new HashSet<String>();
+ for ( String s : basicShapingFeatureStrings ) {
+ basicShapingFeatures.add ( s );
+ }
+ }
+ private boolean isBasicShapingUse ( GlyphTable.UseSpec us ) {
+ assert us != null;
+ if ( basicShapingFeatures != null ) {
+ return basicShapingFeatures.contains ( us.getFeature() );
+ } else {
+ return false;
+ }
+ }
+
+ private static Set<String> presentationFeatures;
+ private static final String[] presentationFeatureStrings = { // CSOK: ConstantNameCheck
+ "abvs",
+ "blws",
+ "calt",
+ "haln",
+ "pres",
+ "psts",
+ };
+ static {
+ presentationFeatures = new HashSet<String>();
+ for ( String s : presentationFeatureStrings ) {
+ presentationFeatures.add ( s );
+ }
+ }
+ private boolean isPresentationUse ( GlyphTable.UseSpec us ) {
+ assert us != null;
+ if ( presentationFeatures != null ) {
+ return presentationFeatures.contains ( us.getFeature() );
+ } else {
+ return false;
+ }
+ }
+
+ private GlyphSequence reorderPreBaseMatra ( GlyphSequence gs ) {
+ int source;
+ if ( ( source = findPreBaseMatra ( gs ) ) >= 0 ) {
+ int target;
+ if ( ( target = findPreBaseMatraTarget ( gs, source ) ) >= 0 ) {
+ if ( target != source ) {
+ gs = reorder ( gs, source, target );
+ }
+ }
+ }
+ return gs;
+ }
+
+ /**
+ * Find pre-base matra in sequence.
+ * @param gs input sequence
+ * @return index of pre-base matra or -1 if not found
+ */
+ protected int findPreBaseMatra ( GlyphSequence gs ) {
+ return -1;
+ }
+
+ /**
+ * Find pre-base matra target in sequence.
+ * @param gs input sequence
+ * @param source index of pre-base matra
+ * @return index of pre-base matra target or -1
+ */
+ protected int findPreBaseMatraTarget ( GlyphSequence gs, int source ) {
+ return -1;
+ }
+
+ private GlyphSequence reorderReph ( GlyphSequence gs ) {
+ int source;
+ if ( ( source = findReph ( gs ) ) >= 0 ) {
+ int target;
+ if ( ( target = findRephTarget ( gs, source ) ) >= 0 ) {
+ if ( target != source ) {
+ gs = reorder ( gs, source, target );
+ }
+ }
+ }
+ return gs;
+ }
+
+ /**
+ * Find reph in sequence.
+ * @param gs input sequence
+ * @return index of reph or -1 if not found
+ */
+ protected int findReph ( GlyphSequence gs ) {
+ return -1;
+ }
+
+ /**
+ * Find reph target in sequence.
+ * @param gs input sequence
+ * @param source index of reph
+ * @return index of reph target or -1
+ */
+ protected int findRephTarget ( GlyphSequence gs, int source ) {
+ return -1;
+ }
+
+ private GlyphSequence reorder ( GlyphSequence gs, int source, int target ) {
+ return GlyphSequence.reorder ( gs, source, 1, target );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean position ( GlyphSequence gs, String script, String language, int fontSize, GlyphTable.UseSpec[] usa, int[] widths, int[][] adjustments, ScriptContextTester sct ) {
+ boolean adjusted = super.position ( gs, script, language, fontSize, usa, widths, adjustments, sct );
+ return adjusted;
+ }
+
+ /** Abstract syllabizer. */
+ protected abstract static class Syllabizer {
+ private String script;
+ private String language;
+ Syllabizer ( String script, String language ) {
+ this.script = script;
+ this.language = language;
+ }
+ /**
+ * Subdivide glyph sequence GS into syllabic segments each represented by a distinct
+ * output glyph sequence.
+ * @param gs input glyph sequence
+ * @return segmented syllabic glyph sequences
+ */
+ abstract GlyphSequence[] syllabize ( GlyphSequence gs );
+ /** {@inheritDoc} */
+ public int hashCode() {
+ int hc = 0;
+ hc = 7 * hc + ( hc ^ script.hashCode() );
+ hc = 11 * hc + ( hc ^ language.hashCode() );
+ return hc;
+ }
+ /** {@inheritDoc} */
+ public boolean equals ( Object o ) {
+ if ( o instanceof Syllabizer ) {
+ Syllabizer s = (Syllabizer) o;
+ if ( ! s.script.equals ( script ) ) {
+ return false;
+ } else if ( ! s.language.equals ( language ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+ /** {@inheritDoc} */
+ public int compareTo ( Object o ) {
+ int d;
+ if ( o instanceof Syllabizer ) {
+ Syllabizer s = (Syllabizer) o;
+ if ( ( d = script.compareTo ( s.script ) ) == 0 ) {
+ d = language.compareTo ( s.language );
+ }
+ } else {
+ d = -1;
+ }
+ return d;
+ }
+ private static Map<String,Syllabizer> syllabizers = new HashMap<String,Syllabizer>();
+ static Syllabizer getSyllabizer ( String script, String language, Class<? extends Syllabizer> syllabizerClass ) {
+ String sid = makeSyllabizerId ( script, language );
+ Syllabizer s = syllabizers.get ( sid );
+ if ( s == null ) {
+ if ( ( s = makeSyllabizer ( script, language, syllabizerClass ) ) == null ) {
+ s = new DefaultSyllabizer ( script, language );
+ }
+ syllabizers.put ( sid, s );
+ }
+ return s;
+ }
+ static String makeSyllabizerId ( String script, String language ) {
+ return script + ":" + language;
+ }
+ static Syllabizer makeSyllabizer ( String script, String language, Class<? extends Syllabizer> syllabizerClass ) {
+ Syllabizer s;
+ try {
+ Constructor<? extends Syllabizer> cf = syllabizerClass.getDeclaredConstructor ( new Class[] { String.class, String.class } );
+ s = (Syllabizer) cf.newInstance ( script, language );
+ } catch ( NoSuchMethodException e ) {
+ s = null;
+ } catch ( InstantiationException e ) {
+ s = null;
+ } catch ( IllegalAccessException e ) {
+ s = null;
+ } catch ( InvocationTargetException e ) {
+ s = null;
+ }
+ return s;
+ }
+ }
+
+ /** Default syllabizer. */
+ protected static class DefaultSyllabizer extends Syllabizer {
+ DefaultSyllabizer ( String script, String language ) {
+ super ( script, language );
+ }
+ /** {@inheritDoc} */
+ @Override
+ GlyphSequence[] syllabize ( GlyphSequence gs ) {
+ int[] ca = gs.getCharacterArray ( false );
+ int nc = gs.getCharacterCount();
+ if ( nc == 0 ) {
+ return new GlyphSequence[] { gs };
+ } else {
+ return segmentize ( gs, segmentize ( ca, nc ) );
+ }
+ }
+ /**
+ * Construct array of segements from original character array (associated with original glyph sequence)
+ * @param ca input character sequence
+ * @param nc number of characters in sequence
+ * @return array of syllable segments
+ */
+ protected Segment[] segmentize ( int[] ca, int nc ) {
+ Vector<Segment> sv = new Vector<Segment> ( nc );
+ for ( int s = 0, e = nc; s < e; ) {
+ int i;
+ if ( ( i = findStartOfSyllable ( ca, s, e ) ) > s ) {
+ // from s to i is non-syllable segment
+ sv.add ( new Segment ( s, i, Segment.OTHER ) );
+ s = i; // move s to start of syllable
+ } else if ( i > s ) {
+ // from s to e is non-syllable segment
+ sv.add ( new Segment ( s, e, Segment.OTHER ) );
+ s = e; // move s to end of input sequence
+ }
+ if ( ( i = findEndOfSyllable ( ca, s, e ) ) > s ) {
+ // from s to i is syllable segment
+ sv.add ( new Segment ( s, i, Segment.SYLLABLE ) );
+ s = i; // move s to end of syllable
+ } else {
+ // from s to e is non-syllable segment
+ sv.add ( new Segment ( s, e, Segment.OTHER ) );
+ s = e; // move s to end of input sequence
+ }
+ }
+ return sv.toArray ( new Segment [ sv.size() ] );
+ }
+ /**
+ * Construct array of glyph sequences from original glyph sequence and segment array.
+ * @param gs original input glyph sequence
+ * @param sa segment array
+ * @return array of glyph sequences each belonging to an (ordered) segment in SA
+ */
+ protected GlyphSequence[] segmentize ( GlyphSequence gs, Segment[] sa ) {
+ int ng = gs.getGlyphCount();
+ int[] ga = gs.getGlyphArray ( false );
+ GlyphSequence.CharAssociation[] aa = gs.getAssociations ( 0, -1 );
+ Vector<GlyphSequence> nsv = new Vector<GlyphSequence>();
+ for ( int i = 0, ns = sa.length; i < ns; i++ ) {
+ Segment s = sa [ i ];
+ Vector<Integer> ngv = new Vector<Integer> ( ng );
+ Vector<GlyphSequence.CharAssociation> nav = new Vector<GlyphSequence.CharAssociation> ( ng );
+ for ( int j = 0; j < ng; j++ ) {
+ GlyphSequence.CharAssociation ca = aa [ j ];
+ if ( ca.contained ( s.getOffset(), s.getCount() ) ) {
+ ngv.add ( ga [ j ] );
+ nav.add ( ca );
+ }
+ }
+ if ( ngv.size() > 0 ) {
+ nsv.add ( new GlyphSequence ( gs, null, toIntArray ( ngv ), null, null, nav.toArray ( new GlyphSequence.CharAssociation [ nav.size() ] ), null ) );
+ }
+ }
+ if ( nsv.size() > 0 ) {
+ return nsv.toArray ( new GlyphSequence [ nsv.size() ] );
+ } else {
+ return new GlyphSequence[] { gs };
+ }
+ }
+ /**
+ * Find start of syllable in character array, starting at S, ending at E.
+ * @param ca character array
+ * @param s start index
+ * @param e end index
+ * @return index of start or E if no start found
+ */
+ protected int findStartOfSyllable ( int[] ca, int s, int e ) {
+ return e;
+ }
+ /**
+ * Find end of syllable in character array, starting at S, ending at E.
+ * @param ca character array
+ * @param s start index
+ * @param e end index
+ * @return index of start or S if no end found
+ */
+ protected int findEndOfSyllable ( int[] ca, int s, int e ) {
+ return s;
+ }
+ private static int[] toIntArray ( Vector<Integer> iv ) {
+ int ni = iv.size();
+ int[] ia = new int [ iv.size() ];
+ for ( int i = 0, n = ni; i < n; i++ ) {
+ ia [ i ] = (int) iv.get ( i );
+ }
+ return ia;
+ }
+ }
+
+ /** Syllabic segment. */
+ protected static class Segment {
+
+ static final int OTHER = 0; // other (non-syllable) characters
+ static final int SYLLABLE = 1; // (orthographic) syllable
+
+ private int start;
+ private int end;
+ private int type;
+
+ Segment ( int start, int end, int type ) {
+ this.start = start;
+ this.end = end;
+ this.type = type;
+ }
+
+ int getStart() {
+ return start;
+ }
+
+ int getEnd() {
+ return end;
+ }
+
+ int getOffset() {
+ return start;
+ }
+
+ int getCount() {
+ return end - start;
+ }
+
+ int getType() {
+ return type;
+ }
+ }
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ScriptProcessor.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ScriptProcessor.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ScriptProcessor.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,234 @@
+/*
+ * 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.complexscripts.scripts;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable;
+import org.apache.fop.complexscripts.fonts.GlyphPositioningTable;
+import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable;
+import org.apache.fop.complexscripts.fonts.GlyphTable;
+import org.apache.fop.complexscripts.util.CharScript;
+import org.apache.fop.complexscripts.util.GlyphSequence;
+import org.apache.fop.complexscripts.util.ScriptContextTester;
+
+// CSOFF: InnerAssignmentCheck
+// CSOFF: LineLengthCheck
+// CSOFF: ParameterNumberCheck
+
+/**
+ * Abstract script processor base class for which an implementation of the substitution and positioning methods
+ * must be supplied.
+ * @author Glenn Adams
+ */
+public abstract class ScriptProcessor {
+
+ private final String script;
+
+ private static Map<String, ScriptProcessor> processors = new HashMap<String, ScriptProcessor>();
+
+ /**
+ * Instantiate a script processor.
+ * @param script a script identifier
+ */
+ protected ScriptProcessor ( String script ) {
+ if ( ( script == null ) || ( script.length() == 0 ) ) {
+ throw new IllegalArgumentException ( "script must be non-empty string" );
+ } else {
+ this.script = script;
+ }
+ }
+
+ /** @return script identifier */
+ public final String getScript() {
+ return script;
+ }
+
+ /**
+ * Obtain script specific required substitution features.
+ * @return array of suppported substitution features or null
+ */
+ public abstract String[] getSubstitutionFeatures();
+
+ /**
+ * Obtain script specific optional substitution features.
+ * @return array of suppported substitution features or null
+ */
+ public String[] getOptionalSubstitutionFeatures() {
+ return new String[0];
+ }
+
+ /**
+ * Obtain script specific substitution context tester.
+ * @return substitution context tester or null
+ */
+ public abstract ScriptContextTester getSubstitutionContextTester();
+
+ /**
+ * Perform substitution processing using a specific set of lookup tables.
+ * @param gsub the glyph substitution table that applies
+ * @param gs an input glyph sequence
+ * @param script a script identifier
+ * @param language a language identifier
+ * @param lookups a mapping from lookup specifications to glyph subtables to use for substitution processing
+ * @return the substituted (output) glyph sequence
+ */
+ public final GlyphSequence substitute ( GlyphSubstitutionTable gsub, GlyphSequence gs, String script, String language, Map/*<LookupSpec,List<LookupTable>>>*/ lookups ) {
+ return substitute ( gs, script, language, assembleLookups ( gsub, getSubstitutionFeatures(), lookups ), getSubstitutionContextTester() );
+ }
+
+ /**
+ * Perform substitution processing using a specific set of ordered glyph table use specifications.
+ * @param gs an input glyph sequence
+ * @param script a script identifier
+ * @param language a language identifier
+ * @param usa an ordered array of glyph table use specs
+ * @param sct a script specific context tester (or null)
+ * @return the substituted (output) glyph sequence
+ */
+ public GlyphSequence substitute ( GlyphSequence gs, String script, String language, GlyphTable.UseSpec[] usa, ScriptContextTester sct ) {
+ assert usa != null;
+ for ( int i = 0, n = usa.length; i < n; i++ ) {
+ GlyphTable.UseSpec us = usa [ i ];
+ gs = us.substitute ( gs, script, language, sct );
+ }
+ return gs;
+ }
+
+ /**
+ * Reorder combining marks in glyph sequence so that they precede (within the sequence) the base
+ * character to which they are applied. N.B. In the case of RTL segments, marks are not reordered by this,
+ * method since when the segment is reversed by BIDI processing, marks are automatically reordered to precede
+ * their base glyph.
+ * @param gdef the glyph definition table that applies
+ * @param gs an input glyph sequence
+ * @param gpa associated glyph position adjustments (also reordered)
+ * @param script a script identifier
+ * @param language a language identifier
+ * @return the reordered (output) glyph sequence
+ */
+ public GlyphSequence reorderCombiningMarks ( GlyphDefinitionTable gdef, GlyphSequence gs, int[][] gpa, String script, String language ) {
+ return gs;
+ }
+
+ /**
+ * Obtain script specific required positioning features.
+ * @return array of suppported positioning features or null
+ */
+ public abstract String[] getPositioningFeatures();
+
+ /**
+ * Obtain script specific optional positioning features.
+ * @return array of suppported positioning features or null
+ */
+ public String[] getOptionalPositioningFeatures() {
+ return new String[0];
+ }
+
+ /**
+ * Obtain script specific positioning context tester.
+ * @return positioning context tester or null
+ */
+ public abstract ScriptContextTester getPositioningContextTester();
+
+ /**
+ * Perform positioning processing using a specific set of lookup tables.
+ * @param gpos the glyph positioning table that applies
+ * @param gs an input glyph sequence
+ * @param script a script identifier
+ * @param language a language identifier
+ * @param fontSize size in device units
+ * @param lookups a mapping from lookup specifications to glyph subtables to use for positioning processing
+ * @param widths array of default advancements for each glyph
+ * @param adjustments accumulated adjustments array (sequence) of 4-tuples of placement [PX,PY] and advance [AX,AY] adjustments, in that order,
+ * with one 4-tuple for each element of glyph sequence
+ * @return true if some adjustment is not zero; otherwise, false
+ */
+ public final boolean position ( GlyphPositioningTable gpos, GlyphSequence gs, String script, String language, int fontSize, Map/*<LookupSpec,List<LookupTable>>*/ lookups, int[] widths, int[][] adjustments ) {
+ return position ( gs, script, language, fontSize, assembleLookups ( gpos, getPositioningFeatures(), lookups ), widths, adjustments, getPositioningContextTester() );
+ }
+
+ /**
+ * Perform positioning processing using a specific set of ordered glyph table use specifications.
+ * @param gs an input glyph sequence
+ * @param script a script identifier
+ * @param language a language identifier
+ * @param fontSize size in device units
+ * @param usa an ordered array of glyph table use specs
+ * @param widths array of default advancements for each glyph in font
+ * @param adjustments accumulated adjustments array (sequence) of 4-tuples of placement [PX,PY] and advance [AX,AY] adjustments, in that order,
+ * with one 4-tuple for each element of glyph sequence
+ * @param sct a script specific context tester (or null)
+ * @return true if some adjustment is not zero; otherwise, false
+ */
+ public boolean position ( GlyphSequence gs, String script, String language, int fontSize, GlyphTable.UseSpec[] usa, int[] widths, int[][] adjustments, ScriptContextTester sct ) {
+ assert usa != null;
+ boolean adjusted = false;
+ for ( int i = 0, n = usa.length; i < n; i++ ) {
+ GlyphTable.UseSpec us = usa [ i ];
+ if ( us.position ( gs, script, language, fontSize, widths, adjustments, sct ) ) {
+ adjusted = true;
+ }
+ }
+ return adjusted;
+ }
+
+ /**
+ * Assemble ordered array of lookup table use specifications according to the specified features and candidate lookups,
+ * where the order of the array is in accordance to the order of the applicable lookup list.
+ * @param table the governing glyph table
+ * @param features array of feature identifiers to apply
+ * @param lookups a mapping from lookup specifications to lists of look tables from which to select lookup tables according to the specified features
+ * @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 );
+ }
+
+ /**
+ * Obtain script processor instance associated with specified script.
+ * @param script a script identifier
+ * @return a script processor instance or null if none found
+ */
+ public static synchronized ScriptProcessor getInstance ( String script ) {
+ ScriptProcessor sp = null;
+ assert processors != null;
+ if ( ( sp = processors.get ( script ) ) == null ) {
+ processors.put ( script, sp = createProcessor ( script ) );
+ }
+ return sp;
+ }
+
+ // [TBD] - rework to provide more configurable binding between script name and script processor constructor
+ private static ScriptProcessor createProcessor ( String script ) {
+ ScriptProcessor sp = null;
+ int sc = CharScript.scriptCodeFromTag ( script );
+ if ( sc == CharScript.SCRIPT_ARABIC ) {
+ sp = new ArabicScriptProcessor ( script );
+ } else if ( CharScript.isIndicScript ( sc ) ) {
+ sp = IndicScriptProcessor.makeProcessor ( script );
+ } else {
+ sp = new DefaultScriptProcessor ( script );
+ }
+ return sp;
+ }
+
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/util/CharMirror.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/util/CharMirror.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/util/CharMirror.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/util/CharMirror.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,715 @@
+/*
+ * 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.complexscripts.util;
+
+import java.util.Arrays;
+
+/**
+ * Mirror related utilities.
+ * @author Glenn Adams
+ */
+public final class CharMirror {
+
+ private CharMirror() {
+ }
+
+ /**
+ * Mirror characters that are designated as having the bidi mirrorred property.
+ * @param s a string whose characters are to be mirrored
+ * @return the resulting string
+ */
+ public static String mirror ( String s ) {
+ StringBuffer sb = new StringBuffer ( s );
+ for ( int i = 0, n = sb.length(); i < n; i++ ) {
+ sb.setCharAt ( i, (char) mirror ( sb.charAt ( i ) ) );
+ }
+ return sb.toString();
+ }
+
+ private static int[] mirroredCharacters = {
+ 0x0028,
+ 0x0029,
+ 0x003C,
+ 0x003E,
+ 0x005B,
+ 0x005D,
+ 0x007B,
+ 0x007D,
+ 0x00AB,
+ 0x00BB,
+ 0x0F3A,
+ 0x0F3B,
+ 0x0F3C,
+ 0x0F3D,
+ 0x169B,
+ 0x169C,
+ 0x2039,
+ 0x203A,
+ 0x2045,
+ 0x2046,
+ 0x207D,
+ 0x207E,
+ 0x208D,
+ 0x208E,
+ 0x2208,
+ 0x2209,
+ 0x220A,
+ 0x220B,
+ 0x220C,
+ 0x220D,
+ 0x2215,
+ 0x223C,
+ 0x223D,
+ 0x2243,
+ 0x2252,
+ 0x2253,
+ 0x2254,
+ 0x2255,
+ 0x2264,
+ 0x2265,
+ 0x2266,
+ 0x2267,
+ 0x2268,
+ 0x2269,
+ 0x226A,
+ 0x226B,
+ 0x226E,
+ 0x226F,
+ 0x2270,
+ 0x2271,
+ 0x2272,
+ 0x2273,
+ 0x2274,
+ 0x2275,
+ 0x2276,
+ 0x2277,
+ 0x2278,
+ 0x2279,
+ 0x227A,
+ 0x227B,
+ 0x227C,
+ 0x227D,
+ 0x227E,
+ 0x227F,
+ 0x2280,
+ 0x2281,
+ 0x2282,
+ 0x2283,
+ 0x2284,
+ 0x2285,
+ 0x2286,
+ 0x2287,
+ 0x2288,
+ 0x2289,
+ 0x228A,
+ 0x228B,
+ 0x228F,
+ 0x2290,
+ 0x2291,
+ 0x2292,
+ 0x2298,
+ 0x22A2,
+ 0x22A3,
+ 0x22A6,
+ 0x22A8,
+ 0x22A9,
+ 0x22AB,
+ 0x22B0,
+ 0x22B1,
+ 0x22B2,
+ 0x22B3,
+ 0x22B4,
+ 0x22B5,
+ 0x22B6,
+ 0x22B7,
+ 0x22C9,
+ 0x22CA,
+ 0x22CB,
+ 0x22CC,
+ 0x22CD,
+ 0x22D0,
+ 0x22D1,
+ 0x22D6,
+ 0x22D7,
+ 0x22D8,
+ 0x22D9,
+ 0x22DA,
+ 0x22DB,
+ 0x22DC,
+ 0x22DD,
+ 0x22DE,
+ 0x22DF,
+ 0x22E0,
+ 0x22E1,
+ 0x22E2,
+ 0x22E3,
+ 0x22E4,
+ 0x22E5,
+ 0x22E6,
+ 0x22E7,
+ 0x22E8,
+ 0x22E9,
+ 0x22EA,
+ 0x22EB,
+ 0x22EC,
+ 0x22ED,
+ 0x22F0,
+ 0x22F1,
+ 0x22F2,
+ 0x22F3,
+ 0x22F4,
+ 0x22F6,
+ 0x22F7,
+ 0x22FA,
+ 0x22FB,
+ 0x22FC,
+ 0x22FD,
+ 0x22FE,
+ 0x2308,
+ 0x2309,
+ 0x230A,
+ 0x230B,
+ 0x2329,
+ 0x232A,
+ 0x2768,
+ 0x2769,
+ 0x276A,
+ 0x276B,
+ 0x276C,
+ 0x276D,
+ 0x276E,
+ 0x276F,
+ 0x2770,
+ 0x2771,
+ 0x2772,
+ 0x2773,
+ 0x2774,
+ 0x2775,
+ 0x27C3,
+ 0x27C4,
+ 0x27C5,
+ 0x27C6,
+ 0x27C8,
+ 0x27C9,
+ 0x27D5,
+ 0x27D6,
+ 0x27DD,
+ 0x27DE,
+ 0x27E2,
+ 0x27E3,
+ 0x27E4,
+ 0x27E5,
+ 0x27E6,
+ 0x27E7,
+ 0x27E8,
+ 0x27E9,
+ 0x27EA,
+ 0x27EB,
+ 0x27EC,
+ 0x27ED,
+ 0x27EE,
+ 0x27EF,
+ 0x2983,
+ 0x2984,
+ 0x2985,
+ 0x2986,
+ 0x2987,
+ 0x2988,
+ 0x2989,
+ 0x298A,
+ 0x298B,
+ 0x298C,
+ 0x298D,
+ 0x298E,
+ 0x298F,
+ 0x2990,
+ 0x2991,
+ 0x2992,
+ 0x2993,
+ 0x2994,
+ 0x2995,
+ 0x2996,
+ 0x2997,
+ 0x2998,
+ 0x29B8,
+ 0x29C0,
+ 0x29C1,
+ 0x29C4,
+ 0x29C5,
+ 0x29CF,
+ 0x29D0,
+ 0x29D1,
+ 0x29D2,
+ 0x29D4,
+ 0x29D5,
+ 0x29D8,
+ 0x29D9,
+ 0x29DA,
+ 0x29DB,
+ 0x29F5,
+ 0x29F8,
+ 0x29F9,
+ 0x29FC,
+ 0x29FD,
+ 0x2A2B,
+ 0x2A2C,
+ 0x2A2D,
+ 0x2A2E,
+ 0x2A34,
+ 0x2A35,
+ 0x2A3C,
+ 0x2A3D,
+ 0x2A64,
+ 0x2A65,
+ 0x2A79,
+ 0x2A7A,
+ 0x2A7D,
+ 0x2A7E,
+ 0x2A7F,
+ 0x2A80,
+ 0x2A81,
+ 0x2A82,
+ 0x2A83,
+ 0x2A84,
+ 0x2A8B,
+ 0x2A8C,
+ 0x2A91,
+ 0x2A92,
+ 0x2A93,
+ 0x2A94,
+ 0x2A95,
+ 0x2A96,
+ 0x2A97,
+ 0x2A98,
+ 0x2A99,
+ 0x2A9A,
+ 0x2A9B,
+ 0x2A9C,
+ 0x2AA1,
+ 0x2AA2,
+ 0x2AA6,
+ 0x2AA7,
+ 0x2AA8,
+ 0x2AA9,
+ 0x2AAA,
+ 0x2AAB,
+ 0x2AAC,
+ 0x2AAD,
+ 0x2AAF,
+ 0x2AB0,
+ 0x2AB3,
+ 0x2AB4,
+ 0x2AC3,
+ 0x2AC4,
+ 0x2AC5,
+ 0x2AC6,
+ 0x2ACD,
+ 0x2ACE,
+ 0x2ACF,
+ 0x2AD0,
+ 0x2AD1,
+ 0x2AD2,
+ 0x2AD3,
+ 0x2AD4,
+ 0x2AD5,
+ 0x2AD6,
+ 0x2ADE,
+ 0x2AE3,
+ 0x2E02,
+ 0x2E03,
+ 0x2E04,
+ 0x2E05,
+ 0x2E09,
+ 0x2E0A,
+ 0x2E0C,
+ 0x2E0D,
+ 0x2E1C,
+ 0x2E1D,
+ 0x2E20,
+ 0x2E21,
+ 0x2E22,
+ 0x2E23,
+ 0x2E24,
+ 0x2E25,
+ 0x2E26,
+ 0x300E,
+ 0x300F,
+ 0x3010,
+ 0x3011,
+ 0x3014,
+ 0x3015,
+ 0x3016,
+ 0x3017,
+ 0x3018,
+ 0x3019,
+ 0x301A,
+ 0x301B,
+ 0xFE59,
+ 0xFE5A,
+ 0xFF3B,
+ 0xFF3D,
+ 0xFF5B,
+ 0xFF5D,
+ 0xFF5F,
+ 0xFF60,
+ 0xFF62,
+ 0xFF63
+ };
+
+ private static int[] mirroredCharactersMapping = {
+ 0x0029,
+ 0x0028,
+ 0x003E,
+ 0x003C,
+ 0x005D,
+ 0x005B,
+ 0x007D,
+ 0x007B,
+ 0x00BB,
+ 0x00AB,
+ 0x0F3B,
+ 0x0F3A,
+ 0x0F3D,
+ 0x0F3C,
+ 0x169C,
+ 0x169B,
+ 0x203A,
+ 0x2039,
+ 0x2046,
+ 0x2045,
+ 0x207E,
+ 0x207D,
+ 0x208E,
+ 0x208D,
+ 0x220B,
+ 0x220C,
+ 0x220D,
+ 0x2208,
+ 0x2209,
+ 0x220A,
+ 0x29F5,
+ 0x223D,
+ 0x223C,
+ 0x22CD,
+ 0x2253,
+ 0x2252,
+ 0x2255,
+ 0x2254,
+ 0x2265,
+ 0x2264,
+ 0x2267,
+ 0x2266,
+ 0x2269,
+ 0x2268,
+ 0x226B,
+ 0x226A,
+ 0x226F,
+ 0x226E,
+ 0x2271,
+ 0x2270,
+ 0x2273,
+ 0x2272,
+ 0x2275,
+ 0x2274,
+ 0x2277,
+ 0x2276,
+ 0x2279,
+ 0x2278,
+ 0x227B,
+ 0x227A,
+ 0x227D,
+ 0x227C,
+ 0x227F,
+ 0x227E,
+ 0x2281,
+ 0x2280,
+ 0x2283,
+ 0x2282,
+ 0x2285,
+ 0x2284,
+ 0x2287,
+ 0x2286,
+ 0x2289,
+ 0x2288,
+ 0x228B,
+ 0x228A,
+ 0x2290,
+ 0x228F,
+ 0x2292,
+ 0x2291,
+ 0x29B8,
+ 0x22A3,
+ 0x22A2,
+ 0x2ADE,
+ 0x2AE4,
+ 0x2AE3,
+ 0x2AE5,
+ 0x22B1,
+ 0x22B0,
+ 0x22B3,
+ 0x22B2,
+ 0x22B5,
+ 0x22B4,
+ 0x22B7,
+ 0x22B6,
+ 0x22CA,
+ 0x22C9,
+ 0x22CC,
+ 0x22CB,
+ 0x2243,
+ 0x22D1,
+ 0x22D0,
+ 0x22D7,
+ 0x22D6,
+ 0x22D9,
+ 0x22D8,
+ 0x22DB,
+ 0x22DA,
+ 0x22DD,
+ 0x22DC,
+ 0x22DF,
+ 0x22DE,
+ 0x22E1,
+ 0x22E0,
+ 0x22E3,
+ 0x22E2,
+ 0x22E5,
+ 0x22E4,
+ 0x22E7,
+ 0x22E6,
+ 0x22E9,
+ 0x22E8,
+ 0x22EB,
+ 0x22EA,
+ 0x22ED,
+ 0x22EC,
+ 0x22F1,
+ 0x22F0,
+ 0x22FA,
+ 0x22FB,
+ 0x22FC,
+ 0x22FD,
+ 0x22FE,
+ 0x22F2,
+ 0x22F3,
+ 0x22F4,
+ 0x22F6,
+ 0x22F7,
+ 0x2309,
+ 0x2308,
+ 0x230B,
+ 0x230A,
+ 0x232A,
+ 0x2329,
+ 0x2769,
+ 0x2768,
+ 0x276B,
+ 0x276A,
+ 0x276D,
+ 0x276C,
+ 0x276F,
+ 0x276E,
+ 0x2771,
+ 0x2770,
+ 0x2773,
+ 0x2772,
+ 0x2775,
+ 0x2774,
+ 0x27C4,
+ 0x27C3,
+ 0x27C6,
+ 0x27C5,
+ 0x27C9,
+ 0x27C8,
+ 0x27D6,
+ 0x27D5,
+ 0x27DE,
+ 0x27DD,
+ 0x27E3,
+ 0x27E2,
+ 0x27E5,
+ 0x27E4,
+ 0x27E7,
+ 0x27E6,
+ 0x27E9,
+ 0x27E8,
+ 0x27EB,
+ 0x27EA,
+ 0x27ED,
+ 0x27EC,
+ 0x27EF,
+ 0x27EE,
+ 0x2984,
+ 0x2983,
+ 0x2986,
+ 0x2985,
+ 0x2988,
+ 0x2987,
+ 0x298A,
+ 0x2989,
+ 0x298C,
+ 0x298B,
+ 0x2990,
+ 0x298F,
+ 0x298E,
+ 0x298D,
+ 0x2992,
+ 0x2991,
+ 0x2994,
+ 0x2993,
+ 0x2996,
+ 0x2995,
+ 0x2998,
+ 0x2997,
+ 0x2298,
+ 0x29C1,
+ 0x29C0,
+ 0x29C5,
+ 0x29C4,
+ 0x29D0,
+ 0x29CF,
+ 0x29D2,
+ 0x29D1,
+ 0x29D5,
+ 0x29D4,
+ 0x29D9,
+ 0x29D8,
+ 0x29DB,
+ 0x29DA,
+ 0x2215,
+ 0x29F9,
+ 0x29F8,
+ 0x29FD,
+ 0x29FC,
+ 0x2A2C,
+ 0x2A2B,
+ 0x2A2E,
+ 0x2A2D,
+ 0x2A35,
+ 0x2A34,
+ 0x2A3D,
+ 0x2A3C,
+ 0x2A65,
+ 0x2A64,
+ 0x2A7A,
+ 0x2A79,
+ 0x2A7E,
+ 0x2A7D,
+ 0x2A80,
+ 0x2A7F,
+ 0x2A82,
+ 0x2A81,
+ 0x2A84,
+ 0x2A83,
+ 0x2A8C,
+ 0x2A8B,
+ 0x2A92,
+ 0x2A91,
+ 0x2A94,
+ 0x2A93,
+ 0x2A96,
+ 0x2A95,
+ 0x2A98,
+ 0x2A97,
+ 0x2A9A,
+ 0x2A99,
+ 0x2A9C,
+ 0x2A9B,
+ 0x2AA2,
+ 0x2AA1,
+ 0x2AA7,
+ 0x2AA6,
+ 0x2AA9,
+ 0x2AA8,
+ 0x2AAB,
+ 0x2AAA,
+ 0x2AAD,
+ 0x2AAC,
+ 0x2AB0,
+ 0x2AAF,
+ 0x2AB4,
+ 0x2AB3,
+ 0x2AC4,
+ 0x2AC3,
+ 0x2AC6,
+ 0x2AC5,
+ 0x2ACE,
+ 0x2ACD,
+ 0x2AD0,
+ 0x2ACF,
+ 0x2AD2,
+ 0x2AD1,
+ 0x2AD4,
+ 0x2AD3,
+ 0x2AD6,
+ 0x2AD5,
+ 0x22A6,
+ 0x22A9,
+ 0x2E03,
+ 0x2E02,
+ 0x2E05,
+ 0x2E04,
+ 0x2E0A,
+ 0x2E09,
+ 0x2E0D,
+ 0x2E0C,
+ 0x2E1D,
+ 0x2E1C,
+ 0x2E21,
+ 0x2E20,
+ 0x2E23,
+ 0x2E22,
+ 0x2E25,
+ 0x2E24,
+ 0x2E27,
+ 0x300F,
+ 0x300E,
+ 0x3011,
+ 0x3010,
+ 0x3015,
+ 0x3014,
+ 0x3017,
+ 0x3016,
+ 0x3019,
+ 0x3018,
+ 0x301B,
+ 0x301A,
+ 0xFE5A,
+ 0xFE59,
+ 0xFF3D,
+ 0xFF3B,
+ 0xFF5D,
+ 0xFF5B,
+ 0xFF60,
+ 0xFF5F,
+ 0xFF63,
+ 0xFF62
+ };
+
+ private static int mirror ( int c ) {
+ int i = Arrays.binarySearch ( mirroredCharacters, c );
+ if ( i < 0 ) {
+ return c;
+ } else {
+ return mirroredCharactersMapping [ i ];
+ }
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org