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 [12/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/fonts/Positionable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/fonts/Positionable.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/fonts/Positionable.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/fonts/Positionable.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,58 @@
+/*
+ * 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.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Optional interface which indicates that glyph positioning is supported and, if supported,
+ * can perform positioning.
+ * @author Glenn Adams
+ */
+public interface Positionable {
+
+ /**
+ * Determines if font performs glyph positioning.
+ * @return true if performs positioning
+ */
+ boolean performsPositioning();
+
+ /**
+ * Perform glyph positioning.
+ * @param cs character sequence to map to position offsets (advancement adjustments)
+ * @param script a script identifier
+ * @param language a language identifier
+ * @param fontSize font size
+ * @return 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, or null if no non-zero adjustment applies
+ */
+ int[][] performPositioning ( CharSequence cs, String script, String language, int fontSize );
+
+ /**
+ * Perform glyph positioning using an implied font size.
+ * @param cs character sequence to map to position offsets (advancement adjustments)
+ * @param script a script identifier
+ * @param language a language identifier
+ * @return array (sequence) of 4-tuples of placement [PX,PY] and advance [AX,AY] adjustments, in that order,
+ * with one 4-tuple for each element of glyph sequence, or null if no non-zero adjustment applies
+ */
+ int[][] performPositioning ( CharSequence cs, String script, String language );
+
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,63 @@
+/*
+ * 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.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Optional interface which indicates that glyph substitution is supported and, if supported,
+ * can perform substitution.
+ * @author Glenn Adams
+ */
+public interface Substitutable {
+
+ /**
+ * Determines if font performs glyph substitution.
+ * @return true if performs substitution.
+ */
+ boolean performsSubstitution();
+
+ /**
+ * Perform substitutions on characters to effect glyph substitution. If some substitution is performed, it
+ * entails mapping from one or more input characters denoting textual character information to one or more
+ * output character codes denoting glyphs in this font, where the output character codes may make use of
+ * private character code values that have significance only for this font.
+ * @param cs character sequence to map to output font encoding character sequence
+ * @param script a script identifier
+ * @param language a language identifier
+ * @return output sequence (represented as a character sequence, where each character in the returned sequence
+ * denotes "font characters", i.e., character codes that map directly (1-1) to their associated glyphs
+ */
+ CharSequence performSubstitution ( CharSequence cs, String script, String language );
+
+ /**
+ * Reorder combining marks in character sequence so that they precede (within the sequence) the base
+ * character to which they are applied. N.B. In the case of LTR 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 character.
+ * @param cs character sequence within which combining marks to be reordered
+ * @param gpa associated glyph position adjustments (also reordered)
+ * @param script a script identifier
+ * @param language a language identifier
+ * @return output sequence containing reordered "font characters"
+ */
+ CharSequence reorderCombiningMarks ( CharSequence cs, int[][] gpa, String script, String language );
+
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ArabicScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ArabicScriptProcessor.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ArabicScriptProcessor.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/ArabicScriptProcessor.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,522 @@
+/*
+ * 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.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.complexscripts.bidi.BidiClass;
+import org.apache.fop.complexscripts.bidi.BidiConstants;
+import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable;
+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: LineLengthCheck
+
+/**
+ * <p>The <code>ArabicScriptProcessor</code> class implements a script processor for
+ * performing glyph substitution and positioning operations on content associated with the Arabic script.</p>
+ * @author Glenn Adams
+ */
+public class ArabicScriptProcessor extends DefaultScriptProcessor {
+
+ /** logging instance */
+ private static final Log log = LogFactory.getLog(ArabicScriptProcessor.class); // CSOK: ConstantNameCheck
+
+ /** features to use for substitutions */
+ private static final String[] gsubFeatures = // CSOK: ConstantNameCheck
+ {
+ "calt", // contextual alternates
+ "ccmp", // glyph composition/decomposition
+ "fina", // final (terminal) forms
+ "init", // initial forms
+ "isol", // isolated formas
+ "liga", // standard ligatures
+ "medi", // medial forms
+ "rlig" // required ligatures
+ };
+
+ /** features to use for positioning */
+ private static final String[] gposFeatures = // CSOK: ConstantNameCheck
+ {
+ "curs", // cursive positioning
+ "kern", // kerning
+ "mark", // mark to base or ligature positioning
+ "mkmk" // mark to mark positioning
+ };
+
+ private static class SubstitutionScriptContextTester implements ScriptContextTester {
+ private static Map/*<String,GlyphContextTester>*/ testerMap = new HashMap/*<String,GlyphContextTester>*/();
+ static {
+ testerMap.put ( "fina", new GlyphContextTester() {
+ public boolean test ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ return inFinalContext ( script, language, feature, gs, index, flags );
+ }
+ } );
+ testerMap.put ( "init", new GlyphContextTester() {
+ public boolean test ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ return inInitialContext ( script, language, feature, gs, index, flags );
+ }
+ } );
+ testerMap.put ( "isol", new GlyphContextTester() {
+ public boolean test ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ return inIsolateContext ( script, language, feature, gs, index, flags );
+ }
+ } );
+ testerMap.put ( "liga", new GlyphContextTester() {
+ public boolean test ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ return inLigatureContext ( script, language, feature, gs, index, flags );
+ }
+ } );
+ testerMap.put ( "medi", new GlyphContextTester() {
+ public boolean test ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ return inMedialContext ( script, language, feature, gs, index, flags );
+ }
+ } );
+ }
+ 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 );
+ }
+ }
+
+ private final ScriptContextTester subContextTester;
+ private final ScriptContextTester posContextTester;
+
+ ArabicScriptProcessor ( String script ) {
+ super ( script );
+ this.subContextTester = new SubstitutionScriptContextTester();
+ this.posContextTester = new PositioningScriptContextTester();
+ }
+
+ /** {@inheritDoc} */
+ public String[] getSubstitutionFeatures() {
+ return gsubFeatures;
+ }
+
+ /** {@inheritDoc} */
+ public ScriptContextTester getSubstitutionContextTester() {
+ return subContextTester;
+ }
+
+ /** {@inheritDoc} */
+ public String[] getPositioningFeatures() {
+ return gposFeatures;
+ }
+
+ /** {@inheritDoc} */
+ public ScriptContextTester getPositioningContextTester() {
+ return posContextTester;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public GlyphSequence reorderCombiningMarks ( GlyphDefinitionTable gdef, GlyphSequence gs, int[][] gpa, String script, String language ) {
+ // a side effect of BIDI reordering is to order combining marks before their base, so we need to override the default here to
+ // prevent double reordering
+ return gs;
+ }
+
+ private static boolean inFinalContext ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( index );
+ int[] ca = gs.getCharacterArray ( false );
+ int nc = gs.getCharacterCount();
+ if ( nc == 0 ) {
+ return false;
+ } else {
+ int s = a.getStart();
+ int e = a.getEnd();
+ if ( ! hasFinalPrecedingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else if ( forcesFinalThisContext ( ca, nc, s, e ) ) {
+ return true;
+ } else if ( ! hasFinalFollowingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private static boolean inInitialContext ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( index );
+ int[] ca = gs.getCharacterArray ( false );
+ int nc = gs.getCharacterCount();
+ if ( nc == 0 ) {
+ return false;
+ } else {
+ int s = a.getStart();
+ int e = a.getEnd();
+ if ( ! hasInitialPrecedingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else if ( ! hasInitialFollowingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private static boolean inIsolateContext ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( index );
+ int nc = gs.getCharacterCount();
+ if ( nc == 0 ) {
+ return false;
+ } else if ( ( a.getStart() == 0 ) && ( a.getEnd() == nc ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean inLigatureContext ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( index );
+ int[] ca = gs.getCharacterArray ( false );
+ int nc = gs.getCharacterCount();
+ if ( nc == 0 ) {
+ return false;
+ } else {
+ int s = a.getStart();
+ int e = a.getEnd();
+ if ( ! hasLigaturePrecedingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else if ( ! hasLigatureFollowingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private static boolean inMedialContext ( String script, String language, String feature, GlyphSequence gs, int index, int flags ) {
+ GlyphSequence.CharAssociation a = gs.getAssociation ( index );
+ int[] ca = gs.getCharacterArray ( false );
+ int nc = gs.getCharacterCount();
+ if ( nc == 0 ) {
+ return false;
+ } else {
+ int s = a.getStart();
+ int e = a.getEnd();
+ if ( ! hasMedialPrecedingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else if ( ! hasMedialThisContext ( ca, nc, s, e ) ) {
+ return false;
+ } else if ( ! hasMedialFollowingContext ( ca, nc, s, e ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private static boolean hasFinalPrecedingContext ( int[] ca, int nc, int s, int e ) {
+ int chp = 0;
+ int clp = 0;
+ for ( int i = s; i > 0; i-- ) {
+ int k = i - 1;
+ if ( ( k >= 0 ) && ( k < nc ) ) {
+ chp = ca [ k ];
+ clp = BidiClass.getBidiClass ( chp );
+ if ( clp != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ }
+ if ( clp != BidiConstants.AL ) {
+ return false;
+ } else if ( hasIsolateInitial ( chp ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private static boolean forcesFinalThisContext ( int[] ca, int nc, int s, int e ) {
+ int chl = 0;
+ int cll = 0;
+ for ( int i = 0, n = e - s; i < n; i++ ) {
+ int k = n - i - 1;
+ int j = s + k;
+ if ( ( j >= 0 ) && ( j < nc ) ) {
+ chl = ca [ j ];
+ cll = BidiClass.getBidiClass ( chl );
+ if ( cll != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ }
+ if ( cll != BidiConstants.AL ) {
+ return false;
+ }
+ if ( hasIsolateInitial ( chl ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean hasFinalFollowingContext ( int[] ca, int nc, int s, int e ) {
+ int chf = 0;
+ int clf = 0;
+ for ( int i = e, n = nc; i < n; i++ ) {
+ chf = ca [ i ];
+ clf = BidiClass.getBidiClass ( chf );
+ if ( clf != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ if ( clf != BidiConstants.AL ) {
+ return true;
+ } else if ( hasIsolateFinal ( chf ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean hasInitialPrecedingContext ( int[] ca, int nc, int s, int e ) {
+ int chp = 0;
+ int clp = 0;
+ for ( int i = s; i > 0; i-- ) {
+ int k = i - 1;
+ if ( ( k >= 0 ) && ( k < nc ) ) {
+ chp = ca [ k ];
+ clp = BidiClass.getBidiClass ( chp );
+ if ( clp != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ }
+ if ( clp != BidiConstants.AL ) {
+ return true;
+ } else if ( hasIsolateInitial ( chp ) ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean hasInitialFollowingContext ( int[] ca, int nc, int s, int e ) {
+ int chf = 0;
+ int clf = 0;
+ for ( int i = e, n = nc; i < n; i++ ) {
+ chf = ca [ i ];
+ clf = BidiClass.getBidiClass ( chf );
+ if ( clf != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ if ( clf != BidiConstants.AL ) {
+ return false;
+ } else if ( hasIsolateFinal ( chf ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private static boolean hasMedialPrecedingContext ( int[] ca, int nc, int s, int e ) {
+ int chp = 0;
+ int clp = 0;
+ for ( int i = s; i > 0; i-- ) {
+ int k = i - 1;
+ if ( ( k >= 0 ) && ( k < nc ) ) {
+ chp = ca [ k ];
+ clp = BidiClass.getBidiClass ( chp );
+ if ( clp != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ }
+ if ( clp != BidiConstants.AL ) {
+ return false;
+ } else if ( hasIsolateInitial ( chp ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private static boolean hasMedialThisContext ( int[] ca, int nc, int s, int e ) {
+ int chf = 0; // first non-NSM char in [s,e)
+ int clf = 0;
+ for ( int i = 0, n = e - s; i < n; i++ ) {
+ int k = s + i;
+ if ( ( k >= 0 ) && ( k < nc ) ) {
+ chf = ca [ s + i ];
+ clf = BidiClass.getBidiClass ( chf );
+ if ( clf != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ }
+ if ( clf != BidiConstants.AL ) {
+ return false;
+ }
+ int chl = 0; // last non-NSM char in [s,e)
+ int cll = 0;
+ for ( int i = 0, n = e - s; i < n; i++ ) {
+ int k = n - i - 1;
+ int j = s + k;
+ if ( ( j >= 0 ) && ( j < nc ) ) {
+ chl = ca [ j ];
+ cll = BidiClass.getBidiClass ( chl );
+ if ( cll != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ }
+ if ( cll != BidiConstants.AL ) {
+ return false;
+ }
+ if ( hasIsolateFinal ( chf ) ) {
+ return false;
+ } else if ( hasIsolateInitial ( chl ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private static boolean hasMedialFollowingContext ( int[] ca, int nc, int s, int e ) {
+ int chf = 0;
+ int clf = 0;
+ for ( int i = e, n = nc; i < n; i++ ) {
+ chf = ca [ i ];
+ clf = BidiClass.getBidiClass ( chf );
+ if ( clf != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ if ( clf != BidiConstants.AL ) {
+ return false;
+ } else if ( hasIsolateFinal ( chf ) ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private static boolean hasLigaturePrecedingContext ( int[] ca, int nc, int s, int e ) {
+ return true;
+ }
+
+ private static boolean hasLigatureFollowingContext ( int[] ca, int nc, int s, int e ) {
+ int chf = 0;
+ int clf = 0;
+ for ( int i = e, n = nc; i < n; i++ ) {
+ chf = ca [ i ];
+ clf = BidiClass.getBidiClass ( chf );
+ if ( clf != BidiConstants.NSM ) {
+ break;
+ }
+ }
+ if ( clf == BidiConstants.AL ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Ordered array of Unicode scalars designating those Arabic (Script) Letters
+ * which exhibit an isolated form in word initial position.
+ */
+ private static int[] isolatedInitials = {
+ 0x0621, // HAMZA
+ 0x0622, // ALEF WITH MADDA ABOVE
+ 0x0623, // ALEF WITH HAMZA ABOVE
+ 0x0624, // WAW WITH HAMZA ABOVE
+ 0x0625, // ALEF WITH HAMZA BELOWW
+ 0x0627, // ALEF
+ 0x062F, // DAL
+ 0x0630, // THAL
+ 0x0631, // REH
+ 0x0632, // ZAIN
+ 0x0648, // WAW
+ 0x0671, // ALEF WASLA
+ 0x0672, // ALEF WITH WAVY HAMZA ABOVE
+ 0x0673, // ALEF WITH WAVY HAMZA BELOW
+ 0x0675, // HIGH HAMZA ALEF
+ 0x0676, // HIGH HAMZA WAW
+ 0x0677, // U WITH HAMZA ABOVE
+ 0x0688, // DDAL
+ 0x0689, // DAL WITH RING
+ 0x068A, // DAL WITH DOT BELOW
+ 0x068B, // DAL WITH DOT BELOW AND SMALL TAH
+ 0x068C, // DAHAL
+ 0x068D, // DDAHAL
+ 0x068E, // DUL
+ 0x068F, // DUL WITH THREE DOTS ABOVE DOWNWARDS
+ 0x0690, // DUL WITH FOUR DOTS ABOVE
+ 0x0691, // RREH
+ 0x0692, // REH WITH SMALL V
+ 0x0693, // REH WITH RING
+ 0x0694, // REH WITH DOT BELOW
+ 0x0695, // REH WITH SMALL V BELOW
+ 0x0696, // REH WITH DOT BELOW AND DOT ABOVE
+ 0x0697, // REH WITH TWO DOTS ABOVE
+ 0x0698, // JEH
+ 0x0699, // REH WITH FOUR DOTS ABOVE
+ 0x06C4, // WAW WITH RING
+ 0x06C5, // KIRGHIZ OE
+ 0x06C6, // OE
+ 0x06C7, // U
+ 0x06C8, // YU
+ 0x06C9, // KIRGHIZ YU
+ 0x06CA, // WAW WITH TWO DOTS ABOVE
+ 0x06CB, // VE
+ 0x06CF, // WAW WITH DOT ABOVE
+ 0x06EE, // DAL WITH INVERTED V
+ 0x06EF // REH WITH INVERTED V
+ };
+
+ private static boolean hasIsolateInitial ( int ch ) {
+ return Arrays.binarySearch ( isolatedInitials, ch ) >= 0;
+ }
+
+ /**
+ * Ordered array of Unicode scalars designating those Arabic (Script) Letters
+ * which exhibit an isolated form in word final position.
+ */
+ private static int[] isolatedFinals = {
+ 0x0621 // HAMZA
+ };
+
+ private static boolean hasIsolateFinal ( int ch ) {
+ return Arrays.binarySearch ( isolatedFinals, ch ) >= 0;
+ }
+
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DefaultScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DefaultScriptProcessor.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DefaultScriptProcessor.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DefaultScriptProcessor.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,144 @@
+/*
+ * 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.fop.complexscripts.fonts.GlyphDefinitionTable;
+import org.apache.fop.complexscripts.util.GlyphSequence;
+import org.apache.fop.complexscripts.util.ScriptContextTester;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * Default script processor, which enables default glyph composition/decomposition, common ligatures, localized forms
+ * and kerning.
+ *
+ * @author Glenn Adams
+ */
+public class DefaultScriptProcessor extends ScriptProcessor {
+
+ /** features to use for substitutions */
+ private static final String[] gsubFeatures = // CSOK: ConstantNameCheck
+ {
+ "ccmp", // glyph composition/decomposition
+ "liga", // common ligatures
+ "locl" // localized forms
+ };
+
+ /** features to use for positioning */
+ private static final String[] gposFeatures = // CSOK: ConstantNameCheck
+ {
+ "kern", // kerning
+ "mark", // mark to base or ligature positioning
+ "mkmk" // mark to mark positioning
+ };
+
+ DefaultScriptProcessor ( String script ) {
+ super ( script );
+ }
+
+ @Override
+ /** {@inheritDoc} */
+ public String[] getSubstitutionFeatures() {
+ return gsubFeatures;
+ }
+
+ @Override
+ /** {@inheritDoc} */
+ public ScriptContextTester getSubstitutionContextTester() {
+ return null;
+ }
+
+ @Override
+ /** {@inheritDoc} */
+ public String[] getPositioningFeatures() {
+ return gposFeatures;
+ }
+
+ @Override
+ /** {@inheritDoc} */
+ public ScriptContextTester getPositioningContextTester() {
+ return null;
+ }
+
+ @Override
+ /** {@inheritDoc} */
+ public GlyphSequence reorderCombiningMarks ( GlyphDefinitionTable gdef, GlyphSequence gs, int[][] gpa, String script, String language ) {
+ int ng = gs.getGlyphCount();
+ int[] ga = gs.getGlyphArray ( false );
+ int nm = 0;
+ // count combining marks
+ for ( int i = 0; i < ng; i++ ) {
+ int gid = ga [ i ];
+ if ( gdef.isGlyphClass ( gid, GlyphDefinitionTable.GLYPH_CLASS_MARK ) ) {
+ nm++;
+ }
+ }
+ // only reorder if there is at least one mark and at least one non-mark glyph
+ if ( ( nm > 0 ) && ( ( ng - nm ) > 0 ) ) {
+ GlyphSequence.CharAssociation[] aa = gs.getAssociations ( 0, -1 );
+ int[] nga = new int [ ng ];
+ int[][] npa = ( gpa != null ) ? new int [ ng ][] : null;
+ GlyphSequence.CharAssociation[] naa = new GlyphSequence.CharAssociation [ ng ];
+ int k = 0;
+ GlyphSequence.CharAssociation ba = null;
+ int bg = -1;
+ int[] bpa = null;
+ for ( int i = 0; i < ng; i++ ) {
+ int gid = ga [ i ];
+ int[] pa = ( gpa != null ) ? gpa [ i ] : null;
+ GlyphSequence.CharAssociation ca = aa [ i ];
+ if ( gdef.isGlyphClass ( gid, GlyphDefinitionTable.GLYPH_CLASS_MARK ) ) {
+ nga [ k ] = gid; naa [ k ] = ca;
+ if ( npa != null ) {
+ npa [ k ] = pa;
+ }
+ k++;
+ } else {
+ if ( bg != -1 ) {
+ nga [ k ] = bg; naa [ k ] = ba;
+ if ( npa != null ) {
+ npa [ k ] = bpa;
+ }
+ k++;
+ bg = -1; ba = null; bpa = null;
+ }
+ if ( bg == -1 ) {
+ bg = gid; ba = ca; bpa = pa;
+ }
+ }
+ }
+ if ( bg != -1 ) {
+ nga [ k ] = bg; naa [ k ] = ba;
+ if ( npa != null ) {
+ npa [ k ] = bpa;
+ }
+ k++;
+ }
+ assert k == ng;
+ if ( npa != null ) {
+ System.arraycopy ( npa, 0, gpa, 0, ng );
+ }
+ return new GlyphSequence ( gs, null, nga, null, null, naa, null );
+ } else {
+ return gs;
+ }
+ }
+
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DevanagariScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DevanagariScriptProcessor.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DevanagariScriptProcessor.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/DevanagariScriptProcessor.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,537 @@
+/*
+ * 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.util.GlyphSequence;
+import org.apache.fop.complexscripts.util.ScriptContextTester;
+
+// CSOFF: AvoidNestedBlocksCheck
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: WhitespaceAfter
+// CSOFF: InnerAssignmentCheck
+// CSOFF: SimplifyBooleanReturnCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * <p>The <code>DevanagariScriptProcessor</code> class implements a script processor for
+ * performing glyph substitution and positioning operations on content associated with the Devanagari script.</p>
+ * @author Glenn Adams
+ */
+public class DevanagariScriptProcessor extends IndicScriptProcessor {
+
+ /** logging instance */
+ private static final Log log = LogFactory.getLog(DevanagariScriptProcessor.class); // CSOK: ConstantNameCheck
+
+ DevanagariScriptProcessor ( String script ) {
+ super ( script );
+ }
+
+ @Override
+ protected Class<? extends DevanagariSyllabizer> getSyllabizerClass() {
+ return DevanagariSyllabizer.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 DevanagariSyllabizer extends DefaultSyllabizer {
+ DevanagariSyllabizer ( 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;
+ }
+ }
+ }
+
+ // devanagari 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
+ // devanagari block range
+ static final int ccaStart = 0x0900; // first code point mapped by cca // CSOK: ConstantNameCheck
+ static final int ccaEnd = 0x0980; // last code point + 1 mapped by cca // CSOK: ConstantNameCheck
+ // devanagari character type lookups
+ static final short[] cca = { // CSOK: ConstantNameCheck
+ C_O, // 0x0900 // INVERTED CANDRABINDU
+ C_O, // 0x0901 // CANDRABINDU
+ C_O, // 0x0902 // ANUSVARA
+ C_O, // 0x0903 // VISARGA
+ C_V, // 0x0904 // SHORT A
+ C_V, // 0x0905 // A
+ C_V, // 0x0906 // AA
+ C_V, // 0x0907 // I
+ C_V, // 0x0908 // II
+ C_V, // 0x0909 // U
+ C_V, // 0x090A // UU
+ C_V, // 0x090B // VOCALIC R
+ C_V, // 0x090C // VOCALIC L
+ C_V, // 0x090D // CANDRA E
+ C_V, // 0x090E // SHORT E
+ C_V, // 0x090F // E
+ C_V, // 0x0910 // AI
+ C_V, // 0x0911 // CANDRA O
+ C_V, // 0x0912 // SHORT O
+ C_V, // 0x0913 // O
+ C_V, // 0x0914 // AU
+ C_C, // 0x0915 // KA
+ C_C, // 0x0916 // KHA
+ C_C, // 0x0917 // GA
+ C_C, // 0x0918 // GHA
+ C_C, // 0x0919 // NGA
+ C_C, // 0x091A // CA
+ C_C, // 0x091B // CHA
+ C_C, // 0x091C // JA
+ C_C, // 0x091D // JHA
+ C_C, // 0x091E // NYA
+ C_C, // 0x091F // TTA
+ C_C, // 0x0920 // TTHA
+ C_C, // 0x0921 // DDA
+ C_C, // 0x0922 // DDHA
+ C_C, // 0x0923 // NNA
+ C_C, // 0x0924 // TA
+ C_C, // 0x0925 // THA
+ C_C, // 0x0926 // DA
+ C_C, // 0x0927 // DHA
+ C_C, // 0x0928 // NA
+ C_C, // 0x0929 // NNNA
+ C_C, // 0x092A // PA
+ C_C, // 0x092B // PHA
+ C_C, // 0x092C // BA
+ C_C, // 0x092D // BHA
+ C_C, // 0x092E // MA
+ C_C, // 0x092F // YA
+ C_C|C_R, // 0x0930 // RA // CSOK: WhitespaceAround
+ C_C|C_R|C_N, // 0x0931 // RRA = 0930+093C // CSOK: WhitespaceAround
+ C_C, // 0x0932 // LA
+ C_C, // 0x0933 // LLA
+ C_C, // 0x0934 // LLLA
+ C_C, // 0x0935 // VA
+ C_C, // 0x0936 // SHA
+ C_C, // 0x0937 // SSA
+ C_C, // 0x0938 // SA
+ C_C, // 0x0939 // HA
+ C_M, // 0x093A // OE (KASHMIRI)
+ C_M, // 0x093B // OOE (KASHMIRI)
+ C_N, // 0x093C // NUKTA
+ C_S, // 0x093D // AVAGRAHA
+ C_M, // 0x093E // AA
+ C_M|C_PRE, // 0x093F // I // CSOK: WhitespaceAround
+ C_M, // 0x0940 // II
+ C_M, // 0x0941 // U
+ C_M, // 0x0942 // UU
+ C_M, // 0x0943 // VOCALIC R
+ C_M, // 0x0944 // VOCALIC RR
+ C_M, // 0x0945 // CANDRA E
+ C_M, // 0x0946 // SHORT E
+ C_M, // 0x0947 // E
+ C_M, // 0x0948 // AI
+ C_M, // 0x0949 // CANDRA O
+ C_M, // 0x094A // SHORT O
+ C_M, // 0x094B // O
+ C_M, // 0x094C // AU
+ C_H, // 0x094D // VIRAMA (HALANT)
+ C_M, // 0x094E // PRISHTHAMATRA E
+ C_M, // 0x094F // AW
+ C_S, // 0x0950 // OM
+ C_T, // 0x0951 // UDATTA
+ C_T, // 0x0952 // ANUDATTA
+ C_A, // 0x0953 // GRAVE
+ C_A, // 0x0954 // ACUTE
+ C_M, // 0x0955 // CANDRA LONG E
+ C_M, // 0x0956 // UE
+ C_M, // 0x0957 // UUE
+ C_C|C_N, // 0x0958 // QA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x0959 // KHHA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x095A // GHHA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x095B // ZA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x095C // DDDHA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x095D // RHA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x095E // FA // CSOK: WhitespaceAround
+ C_C|C_N, // 0x095F // YYA // CSOK: WhitespaceAround
+ C_V, // 0x0960 // VOCALIC RR
+ C_V, // 0x0961 // VOCALIC LL
+ C_M, // 0x0962 // VOCALIC RR
+ C_M, // 0x0963 // VOCALIC LL
+ C_P, // 0x0964 // DANDA
+ C_P, // 0x0965 // DOUBLE DANDA
+ C_D, // 0x0966 // ZERO
+ C_D, // 0x0967 // ONE
+ C_D, // 0x0968 // TWO
+ C_D, // 0x0969 // THREE
+ C_D, // 0x096A // FOUR
+ C_D, // 0x096B // FIVE
+ C_D, // 0x096C // SIX
+ C_D, // 0x096D // SEVEN
+ C_D, // 0x096E // EIGHT
+ C_D, // 0x096F // NINE
+ C_S, // 0x0970 // ABBREVIATION SIGN
+ C_S, // 0x0971 // HIGH SPACING DOT
+ C_V, // 0x0972 // CANDRA A (MARATHI)
+ C_V, // 0x0973 // OE (KASHMIRI)
+ C_V, // 0x0974 // OOE (KASHMIRI)
+ C_V, // 0x0975 // AW (KASHMIRI)
+ C_V, // 0x0976 // UE (KASHMIRI)
+ C_V, // 0x0977 // UUE (KASHMIRI)
+ C_U, // 0x0978 // UNASSIGNED
+ C_C, // 0x0979 // ZHA
+ C_C, // 0x097A // HEAVY YA
+ C_C, // 0x097B // GGAA (SINDHI)
+ C_C, // 0x097C // JJA (SINDHI)
+ C_C, // 0x097D // GLOTTAL STOP (LIMBU)
+ C_C, // 0x097E // DDDA (SINDHI)
+ C_C // 0x097F // BBA (SINDHI)
+ };
+ 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 == 0x093C;
+ }
+ static boolean isH(int c) {
+ return c == 0x094D;
+ }
+ 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);
+ }
+
+}
Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GujaratiScriptProcessor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GujaratiScriptProcessor.java?rev=1293736&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GujaratiScriptProcessor.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/complexscripts/scripts/GujaratiScriptProcessor.java Sun Feb 26 02:29:01 2012
@@ -0,0 +1,537 @@
+/*
+ * 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.util.GlyphSequence;
+import org.apache.fop.complexscripts.util.ScriptContextTester;
+
+// CSOFF: AvoidNestedBlocksCheck
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: WhitespaceAfter
+// CSOFF: InnerAssignmentCheck
+// CSOFF: SimplifyBooleanReturnCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * <p>The <code>GujaratiScriptProcessor</code> class implements a script processor for
+ * performing glyph substitution and positioning operations on content associated with the Gujarati script.</p>
+ * @author Glenn Adams
+ */
+public class GujaratiScriptProcessor extends IndicScriptProcessor {
+
+ /** logging instance */
+ private static final Log log = LogFactory.getLog(GujaratiScriptProcessor.class); // CSOK: ConstantNameCheck
+
+ GujaratiScriptProcessor ( String script ) {
+ super ( script );
+ }
+
+ @Override
+ protected Class<? extends GujaratiSyllabizer> getSyllabizerClass() {
+ return GujaratiSyllabizer.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 GujaratiSyllabizer extends DefaultSyllabizer {
+ GujaratiSyllabizer ( 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;
+ }
+ }
+ }
+
+ // gujarati 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
+ // gujarati block range
+ static final int ccaStart = 0x0A80; // first code point mapped by cca // CSOK: ConstantNameCheck
+ static final int ccaEnd = 0x0B00; // last code point + 1 mapped by cca // CSOK: ConstantNameCheck
+ // gujarati character type lookups
+ static final short[] cca = { // CSOK: ConstantNameCheck
+ C_U, // 0x0A80 // UNASSIGNED
+ C_O, // 0x0A81 // CANDRABINDU
+ C_O, // 0x0A82 // ANUSVARA
+ C_O, // 0x0A83 // VISARGA
+ C_U, // 0x0A84 // UNASSIGNED
+ C_V, // 0x0A85 // A
+ C_V, // 0x0A86 // AA
+ C_V, // 0x0A87 // I
+ C_V, // 0x0A88 // II
+ C_V, // 0x0A89 // U
+ C_V, // 0x0A8A // UU
+ C_V, // 0x0A8B // VOCALIC R
+ C_V, // 0x0A8C // VOCALIC L
+ C_V, // 0x0A8D // CANDRA E
+ C_U, // 0x0A8E // UNASSIGNED
+ C_V, // 0x0A8F // E
+ C_V, // 0x0A90 // AI
+ C_V, // 0x0A91 // CANDRA O
+ C_U, // 0x0A92 // UNASSIGNED
+ C_V, // 0x0A93 // O
+ C_V, // 0x0A94 // AU
+ C_C, // 0x0A95 // KA
+ C_C, // 0x0A96 // KHA
+ C_C, // 0x0A97 // GA
+ C_C, // 0x0A98 // GHA
+ C_C, // 0x0A99 // NGA
+ C_C, // 0x0A9A // CA
+ C_C, // 0x0A9B // CHA
+ C_C, // 0x0A9C // JA
+ C_C, // 0x0A9D // JHA
+ C_C, // 0x0A9E // NYA
+ C_C, // 0x0A9F // TTA
+ C_C, // 0x0AA0 // TTHA
+ C_C, // 0x0AA1 // DDA
+ C_C, // 0x0AA2 // DDHA
+ C_C, // 0x0AA3 // NNA
+ C_C, // 0x0AA4 // TA
+ C_C, // 0x0AA5 // THA
+ C_C, // 0x0AA6 // DA
+ C_C, // 0x0AA7 // DHA
+ C_C, // 0x0AA8 // NA
+ C_U, // 0x0AA9 // UNASSIGNED
+ C_C, // 0x0AAA // PA
+ C_C, // 0x0AAB // PHA
+ C_C, // 0x0AAC // BA
+ C_C, // 0x0AAD // BHA
+ C_C, // 0x0AAE // MA
+ C_C, // 0x0AAF // YA
+ C_C|C_R, // 0x0AB0 // RA // CSOK: WhitespaceAround
+ C_U, // 0x0AB1 // UNASSIGNED
+ C_C, // 0x0AB2 // LA
+ C_C, // 0x0AB3 // LLA
+ C_U, // 0x0AB4 // UNASSIGNED
+ C_C, // 0x0AB5 // VA
+ C_C, // 0x0AB6 // SHA
+ C_C, // 0x0AB7 // SSA
+ C_C, // 0x0AB8 // SA
+ C_C, // 0x0AB9 // HA
+ C_U, // 0x0ABA // UNASSIGNED
+ C_U, // 0x0ABB // UNASSIGNED
+ C_N, // 0x0ABC // NUKTA
+ C_S, // 0x0ABD // AVAGRAHA
+ C_M, // 0x0ABE // AA
+ C_M|C_PRE, // 0x0ABF // I // CSOK: WhitespaceAround
+ C_M, // 0x0AC0 // II
+ C_M, // 0x0AC1 // U
+ C_M, // 0x0AC2 // UU
+ C_M, // 0x0AC3 // VOCALIC R
+ C_M, // 0x0AC4 // VOCALIC RR
+ C_M, // 0x0AC5 // CANDRA E
+ C_U, // 0x0AC6 // UNASSIGNED
+ C_M, // 0x0AC7 // E
+ C_M, // 0x0AC8 // AI
+ C_M, // 0x0AC9 // CANDRA O
+ C_U, // 0x0ACA // UNASSIGNED
+ C_M, // 0x0ACB // O
+ C_M, // 0x0ACC // AU
+ C_H, // 0x0ACD // VIRAMA (HALANT)
+ C_U, // 0x0ACE // UNASSIGNED
+ C_U, // 0x0ACF // UNASSIGNED
+ C_S, // 0x0AD0 // OM
+ C_U, // 0x0AD1 // UNASSIGNED
+ C_U, // 0x0AD2 // UNASSIGNED
+ C_U, // 0x0AD3 // UNASSIGNED
+ C_U, // 0x0AD4 // UNASSIGNED
+ C_U, // 0x0AD5 // UNASSIGNED
+ C_U, // 0x0AD6 // UNASSIGNED
+ C_U, // 0x0AD7 // UNASSIGNED
+ C_U, // 0x0AD8 // UNASSIGNED
+ C_U, // 0x0AD9 // UNASSIGNED
+ C_U, // 0x0ADA // UNASSIGNED
+ C_U, // 0x0ADB // UNASSIGNED
+ C_U, // 0x0ADC // UNASSIGNED
+ C_U, // 0x0ADD // UNASSIGNED
+ C_U, // 0x0ADE // UNASSIGNED
+ C_U, // 0x0ADF // UNASSIGNED
+ C_V, // 0x0AE0 // VOCALIC RR
+ C_V, // 0x0AE1 // VOCALIC LL
+ C_M, // 0x0AE2 // VOCALIC L
+ C_M, // 0x0AE3 // VOCALIC LL
+ C_U, // 0x0AE4 // UNASSIGNED
+ C_U, // 0x0AE5 // UNASSIGNED
+ C_D, // 0x0AE6 // ZERO
+ C_D, // 0x0AE7 // ONE
+ C_D, // 0x0AE8 // TWO
+ C_D, // 0x0AE9 // THREE
+ C_D, // 0x0AEA // FOUR
+ C_D, // 0x0AEB // FIVE
+ C_D, // 0x0AEC // SIX
+ C_D, // 0x0AED // SEVEN
+ C_D, // 0x0AEE // EIGHT
+ C_D, // 0x0AEF // NINE
+ C_U, // 0x0AF0 // UNASSIGNED
+ C_S, // 0x0AF1 // RUPEE SIGN
+ C_U, // 0x0AF2 // UNASSIGNED
+ C_U, // 0x0AF3 // UNASSIGNED
+ C_U, // 0x0AF4 // UNASSIGNED
+ C_U, // 0x0AF5 // UNASSIGNED
+ C_U, // 0x0AF6 // UNASSIGNED
+ C_U, // 0x0AF7 // UNASSIGNED
+ C_U, // 0x0AF8 // UNASSIGNED
+ C_U, // 0x0AF9 // UNASSIGNED
+ C_U, // 0x0AFA // UNASSIGNED
+ C_U, // 0x0AFB // UNASSIGNED
+ C_U, // 0x0AFC // UNASSIGNED
+ C_U, // 0x0AFD // UNASSIGNED
+ C_U, // 0x0AFE // UNASSIGNED
+ C_U // 0x0AFF // 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 == 0x0ABC;
+ }
+ static boolean isH(int c) {
+ return c == 0x0ACD;
+ }
+ 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);
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org