You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by sp...@apache.org on 2010/08/19 21:46:45 UTC
svn commit: r987282 [4/9] - in
/xmlgraphics/fop/branches/Temp_ComplexScripts: ./
src/codegen/unicode/java/org/apache/fop/hyphenation/
src/codegen/unicode/java/org/apache/fop/text/bidi/
src/java/org/apache/fop/area/ src/java/org/apache/fop/area/inline/ ...
Modified: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java?rev=987282&r1=987281&r2=987282&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java (original)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/FontReader.java Thu Aug 19 19:46:41 2010
@@ -31,12 +31,15 @@ import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.fop.apps.FOPException;
import org.apache.fop.fonts.apps.TTFReader;
+// CSOFF: LineLengthCheck
+
/**
* Class for reading a metric.xml file and creating a font object.
* Typical usage:
@@ -63,6 +66,31 @@ public class FontReader extends DefaultH
private List bfranges = null;
+ /* advanced typographic (script extras) support */
+ private boolean inScriptExtras = false;
+ private int seTable = -1;
+ private Map seLookups = null;
+ private String seScript = null;
+ private String seLanguage = null;
+ private String seFeature = null;
+ private String seUseLookup = null;
+ private List seUseLookups = null;
+ private String luID = null;
+ private int luType = -1;
+ private List ltSubtables = null;
+ private int luSequence = -1;
+ private int luFlags = 0;
+ private int lstSequence = -1;
+ private int lstFormat = -1;
+ private List lstCoverage = null;
+ private List lstGIDs = null;
+ private List lstRanges = null;
+ private List lstEntries = null;
+ private List lstLIGSets = null;
+ private List lstLIGs = null;
+ private int ligGID = -1;
+ /* end of script extras parse state */
+
private void createFont(InputSource source) throws FOPException {
XMLReader parser = null;
@@ -114,6 +142,14 @@ public class FontReader extends DefaultH
}
/**
+ * Enable/disable use of advanced typographic features for the font
+ * @param enabled true to enable, false to disable
+ */
+ public void setAdvancedEnabled(boolean enabled) {
+ returnFont.setAdvancedEnabled(enabled);
+ }
+
+ /**
* Sets the font resolver. Needed for URI resolution.
* @param resolver the font resolver
*/
@@ -158,7 +194,9 @@ public class FontReader extends DefaultH
*/
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
- if (localName.equals("font-metrics")) {
+ if ( inScriptExtras ) {
+ startElementScriptExtras ( uri, localName, qName, attributes );
+ } else if (localName.equals("font-metrics")) {
if ("TYPE0".equals(attributes.getValue("type"))) {
multiFont = new MultiByteFont();
returnFont = multiFont;
@@ -208,7 +246,10 @@ public class FontReader extends DefaultH
} else if ("pair".equals(localName)) {
currentKerning.put(new Integer(attributes.getValue("kpx2")),
new Integer(attributes.getValue("kern")));
+ } else if ("script-extras".equals(localName)) {
+ inScriptExtras = true;
}
+
}
private int getInt(String str) throws SAXException {
@@ -226,7 +267,9 @@ public class FontReader extends DefaultH
*/
public void endElement(String uri, String localName, String qName) throws SAXException {
String content = text.toString().trim();
- if ("font-name".equals(localName)) {
+ if ( inScriptExtras ) {
+ endElementScriptExtras ( uri, localName, qName, content );
+ } else if ("font-name".equals(localName)) {
returnFont.setFontName(content);
} else if ("full-name".equals(localName)) {
returnFont.setFullName(content);
@@ -303,6 +346,376 @@ public class FontReader extends DefaultH
public void characters(char[] ch, int start, int length) {
text.append(ch, start, length);
}
+
+ private void validateScriptTag ( String tag )
+ throws SAXException {
+ }
+
+ private void validateLanguageTag ( String tag, String script )
+ throws SAXException {
+ }
+
+ private void validateFeatureTag ( String tag, int tableType, String script, String language )
+ throws SAXException {
+ }
+
+ private int mapLookupType ( String type, int tableType ) {
+ int t = -1;
+ if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+ t = GlyphSubstitutionTable.getLookupTypeFromName ( type );
+ } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+ t = GlyphPositioningTable.getLookupTypeFromName ( type );
+ }
+ return t;
+ }
+
+ private void validateLookupType ( String type, int tableType )
+ throws SAXException {
+ if ( mapLookupType ( type, tableType ) == -1 ) {
+ throw new SAXParseException ( "invalid lookup type \'" + type + "\'", locator );
+ }
+ }
+
+ private void startElementScriptExtras ( String uri, String localName, String qName, Attributes attributes )
+ throws SAXException {
+ if ( "gsub".equals(localName) ) {
+ assert seLookups == null;
+ seLookups = new java.util.HashMap();
+ seTable = GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION;
+ } else if ( "gpos".equals(localName) ) {
+ assert seLookups == null;
+ seLookups = new java.util.HashMap();
+ seTable = GlyphTable.GLYPH_TABLE_TYPE_POSITIONING;
+ } else if ( "script".equals(localName) ) {
+ String tag = attributes.getValue("tag");
+ if ( tag != null ) {
+ assert seScript == null;
+ validateScriptTag ( tag );
+ seScript = tag;
+ } else {
+ throw new SAXParseException ( "missing tag attribute on <script/> element", locator );
+ }
+ } else if ( "lang".equals(localName) ) {
+ String tag = attributes.getValue("tag");
+ if ( tag != null ) {
+ assert seLanguage == null;
+ validateLanguageTag ( tag, seScript );
+ seLanguage = tag;
+ } else {
+ throw new SAXParseException ( "missing tag attribute on <lang/> element", locator );
+ }
+ } else if ( "feature".equals(localName) ) {
+ String tag = attributes.getValue("tag");
+ if ( tag != null ) {
+ validateFeatureTag ( tag, seTable, seScript, seLanguage );
+ assert seFeature == null;
+ seFeature = tag;
+ } else {
+ throw new SAXParseException ( "missing tag attribute on <feature/> element", locator );
+ }
+ } else if ( "use-lookup".equals(localName) ) {
+ String ref = attributes.getValue("ref");
+ if ( ref != null ) {
+ assert seUseLookup == null;
+ seUseLookup = ref;
+ } else {
+ throw new SAXParseException ( "missing ref attribute on <use-lookup/> element", locator );
+ }
+ } else if ( "lookup".equals(localName) ) {
+ String id = attributes.getValue("id");
+ if ( id != null ) {
+ assert luID == null;
+ luID = id; luSequence++; lstSequence = -1;
+ } else {
+ throw new SAXParseException ( "missing id attribute on <lookup/> element", locator );
+ }
+ String flags = attributes.getValue("flags");
+ if ( flags != null ) {
+ try {
+ luFlags = Integer.parseInt ( flags );
+ } catch ( NumberFormatException e ) {
+ throw new SAXParseException ( "invalid flags attribute on <lookup/> element, must be integer", locator );
+ }
+ }
+ String type = attributes.getValue("type");
+ if ( type != null ) {
+ validateLookupType ( type, seTable );
+ assert luType == -1;
+ luType = mapLookupType ( type, seTable );
+ } else {
+ throw new SAXParseException ( "missing type attribute on <lookup/> element", locator );
+ }
+ } else if ( "lst".equals(localName) ) {
+ String format = attributes.getValue("format");
+ if ( format != null ) {
+ try {
+ lstSequence++;
+ lstFormat = Integer.parseInt ( format );
+ } catch ( NumberFormatException e ) {
+ throw new SAXParseException ( "invalid format attribute on <lst/> element, must be integer", locator );
+ }
+ assert lstCoverage == null;
+ assert lstEntries == null;
+ } else {
+ throw new SAXParseException ( "missing format attribute on <lst/> element", locator );
+ }
+ } else if ( "coverage".equals(localName) ) {
+ assert lstGIDs == null;
+ assert lstRanges == null;
+ lstGIDs = new java.util.ArrayList();
+ lstRanges = new java.util.ArrayList();
+ } else if ( "range".equals(localName) ) {
+ String gs = attributes.getValue("gs");
+ String ge = attributes.getValue("ge");
+ String ci = attributes.getValue("ci");
+ if ( ( gs != null ) && ( ge != null ) && ( ci != null ) ) {
+ try {
+ int s = Integer.parseInt ( gs );
+ int e = Integer.parseInt ( ge );
+ int i = Integer.parseInt ( ci );
+ lstRanges.add ( new GlyphCoverageTable.CoverageRange ( s, e, i ) );
+ } catch ( NumberFormatException e ) {
+ throw new SAXParseException ( "invalid format attribute on <lst/> element, must be integer", locator );
+ } catch ( IllegalArgumentException e ) {
+ throw new SAXParseException ( "bad gs, ge, or ci attribute on <range/> element, must be non-negative integers, with gs <= ge", locator );
+ }
+ } else {
+ throw new SAXParseException ( "missing gs, ge, or ci attribute on <range/> element", locator );
+ }
+ } else if ( "entries".equals(localName) ) {
+ initEntriesState ( seTable, luType, lstFormat );
+ } else if ( "ligs".equals(localName) ) {
+ assert lstLIGs == null;
+ lstLIGs = new java.util.ArrayList();
+ } else if ( "lig".equals(localName) ) {
+ if ( lstLIGs == null ) {
+ throw new SAXParseException ( "missing container <ligs/> element for <lig/> element", locator );
+ } else {
+ String gid = attributes.getValue("gid");
+ if ( gid != null ) {
+ try {
+ ligGID = Integer.parseInt ( gid );
+ } catch ( NumberFormatException e ) {
+ throw new SAXParseException ( "invalid gid attribute on <lig/> element, must be integer", locator );
+ }
+ } else {
+ throw new SAXParseException ( "missing gid attribute on <lig/> element", locator );
+ }
+ }
+ }
+ }
+
+ private void endElementScriptExtras ( String uri, String localName, String qName, String content )
+ throws SAXException {
+ if ( "script-extras".equals(localName) ) {
+ inScriptExtras = false;
+ } else if ( "gsub".equals(localName) ) {
+ if ( ( ltSubtables != null ) && ( ltSubtables.size() > 0 ) ) {
+ if ( multiFont.getGSUB() == null ) {
+ multiFont.setGSUB ( new GlyphSubstitutionTable ( seLookups, ltSubtables ) );
+ }
+ }
+ ltSubtables = null; seTable = -1; seLookups = null;
+ } else if ( "gpos".equals(localName) ) {
+ if ( ( ltSubtables != null ) && ( ltSubtables.size() > 0 ) ) {
+ if ( multiFont.getGPOS() == null ) {
+ multiFont.setGPOS ( new GlyphPositioningTable ( seLookups, ltSubtables ) );
+ }
+ }
+ ltSubtables = null; seTable = -1; seLookups = null;
+ } else if ( "script".equals(localName) ) {
+ assert seUseLookups == null;
+ assert seUseLookup == null;
+ assert seFeature == null;
+ assert seLanguage == null;
+ seScript = null;
+ } else if ( "lang".equals(localName) ) {
+ assert seUseLookups == null;
+ assert seUseLookup == null;
+ assert seFeature == null;
+ seLanguage = null;
+ } else if ( "feature".equals(localName) ) {
+ if ( ( seScript != null ) && ( seLanguage != null ) && ( seFeature != null ) ) {
+ if ( ( seUseLookups != null ) && ( seUseLookups.size() > 0 ) ) {
+ seLookups.put ( new GlyphTable.LookupSpec ( seScript, seLanguage, seFeature ), seUseLookups );
+ }
+ }
+ seUseLookups = null; seFeature = null;
+ } else if ( "use-lookup".equals(localName) ) {
+ if ( seUseLookup != null ) {
+ if ( seUseLookups == null ) {
+ seUseLookups = new java.util.ArrayList();
+ }
+ seUseLookups.add ( seUseLookup );
+ }
+ seUseLookup = null;
+ } else if ( "lookup".equals(localName) ) {
+ luType = -1;
+ luFlags = 0;
+ } else if ( "lst".equals(localName) ) {
+ assert lstCoverage != null;
+ assert lstEntries != null;
+ addLookupSubtable ( seTable, luType, luID, luSequence, luFlags, lstFormat, lstCoverage, lstEntries );
+ lstFormat = -1;
+ lstCoverage = null;
+ lstEntries = null;
+ } else if ( "coverage".equals(localName) ) {
+ assert lstGIDs != null;
+ assert lstRanges != null;
+ assert lstCoverage == null;
+ if ( lstGIDs.size() > 0 ) {
+ lstCoverage = lstGIDs;
+ } else if ( lstRanges.size() > 0 ) {
+ lstCoverage = lstRanges;
+ }
+ lstGIDs = null; lstRanges = null;
+ } else if ( "gid".equals(localName) ) {
+ if ( lstGIDs != null ) {
+ try {
+ lstGIDs.add ( Integer.decode ( content ) );
+ } catch ( NumberFormatException e ) {
+ throw new SAXParseException ( "invalid <gid/> element content, must be integer", locator );
+ }
+ }
+ } else if ( "entries".equals(localName) ) {
+ finishEntriesState ( seTable, luType, lstFormat );
+ } else if ( "ligs".equals(localName) ) {
+ assert lstLIGSets != null;
+ assert lstLIGs != null;
+ lstLIGSets.add ( new GlyphSubstitutionTable.LigatureSet ( lstLIGs ) );
+ lstLIGs = null;
+ } else if ( "lig".equals(localName) ) {
+ assert lstLIGs != null;
+ assert ligGID >= 0;
+ int[] ligComponents = parseLigatureComponents ( content );
+ if ( ligComponents != null ) {
+ lstLIGs.add ( new GlyphSubstitutionTable.Ligature ( ligGID, ligComponents ) );
+ }
+ ligGID = -1;
+ }
+ }
+
+ private void initEntriesState ( int tableType, int lookupType, int subtableFormat ) {
+ if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+ switch ( lookupType ) {
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_SINGLE:
+ assert lstGIDs == null;
+ lstGIDs = new java.util.ArrayList();
+ break;
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_LIGATURE:
+ assert lstLIGSets == null;
+ lstLIGSets = new java.util.ArrayList();
+ break;
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_MULTIPLE:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_ALTERNATE:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CONTEXT:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CHAINING_CONTEXT:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
+ throw new UnsupportedOperationException();
+ default:
+ break;
+ }
+ } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+ switch ( lookupType ) {
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_SINGLE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_PAIR:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CURSIVE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_BASE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_MARK:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CONTEXT:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CHAINED_CONTEXT:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING:
+ throw new UnsupportedOperationException();
+ default:
+ break;
+ }
+ }
+ }
+
+ private void finishEntriesState ( int tableType, int lookupType, int subtableFormat ) {
+ if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+ switch ( lookupType ) {
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_SINGLE:
+ assert lstGIDs != null;
+ lstEntries = lstGIDs; lstGIDs = null;
+ break;
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_LIGATURE:
+ assert lstLIGSets != null;
+ lstEntries = lstLIGSets; lstLIGSets = null;
+ break;
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_MULTIPLE:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_ALTERNATE:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CONTEXT:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_CHAINING_CONTEXT:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_EXTENSION_SUBSTITUTION:
+ case GlyphSubstitutionTable.GSUB_LOOKUP_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE:
+ throw new UnsupportedOperationException();
+ default:
+ break;
+ }
+ } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+ switch ( lookupType ) {
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_SINGLE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_PAIR:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CURSIVE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_BASE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_MARK_TO_MARK:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CONTEXT:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_CHAINED_CONTEXT:
+ case GlyphPositioningTable.GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING:
+ throw new UnsupportedOperationException();
+ default:
+ break;
+ }
+ }
+ }
+
+ private void addLookupSubtable // CSOK: ParameterNumber
+ ( int tableType, int lookupType, String lookupID, int lookupSequence, int lookupFlags, int subtableFormat, List coverage, List entries ) {
+ GlyphSubtable st = null;
+ if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION ) {
+ st = GlyphSubstitutionTable.createSubtable ( lookupType, lookupID, lookupSequence, lookupFlags, subtableFormat, coverage, entries );
+ } else if ( tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING ) {
+ st = GlyphPositioningTable.createSubtable ( lookupType, lookupID, lookupSequence, lookupFlags, subtableFormat, coverage, entries );
+ }
+ if ( st != null ) {
+ if ( ltSubtables == null ) {
+ ltSubtables = new java.util.ArrayList();
+ }
+ ltSubtables.add ( st );
+ }
+ }
+
+ private int[] parseLigatureComponents ( String s )
+ throws SAXParseException {
+ String[] csa = s.split ( "\\s" );
+ if ( ( csa == null ) || ( csa.length == 0 ) ) {
+ throw new SAXParseException ( "invalid <lig/> element, must specify at least one component", locator );
+ } else {
+ int nc = csa.length;
+ int[] components = new int [ nc ];
+ for ( int i = 0, n = nc; i < n; i++ ) {
+ String cs = csa [ i ];
+ int c;
+ try {
+ c = Integer.parseInt ( cs );
+ if ( ( c < 0 ) || ( c > 65535 ) ) {
+ throw new SAXParseException ( "invalid component value (" + c + ") in <lig/> element, out of range", locator );
+ } else {
+ components [ i ] = c;
+ }
+ } catch ( NumberFormatException e ) {
+ throw new SAXParseException ( "invalid component \"" + cs + "\" in <lig/> element, must be integer", locator );
+ }
+
+ }
+ return components;
+ }
+ }
+
}
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+/**
+ * Interface for testing the originating (source) character context of a glyph sequence.
+ * @author Glenn Adams
+ */
+public interface GlyphContextTester {
+
+ /**
+ * Perform a test on a glyph sequence in a specific (originating) character context.
+ * @param gs glyph sequence to test
+ * @param ca character association defining the context of test
+ * @return true if test is satisfied
+ */
+ boolean test ( GlyphSequence gs, GlyphSequence.CharAssociation ca );
+
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphContextTester.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,357 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Iterator;
+
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: InnerAssignmentCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * Abstract base class implementation of glyph coverage table.
+ * @author Glenn Adams
+ */
+public abstract class GlyphCoverageTable {
+
+ /** empty coverage table */
+ public static final int GLYPH_COVERAGE_TYPE_EMPTY = 0;
+
+ /** mapped coverage table */
+ public static final int GLYPH_COVERAGE_TYPE_MAPPED = 1;
+
+ /** range based coverage table */
+ public static final int GLYPH_COVERAGE_TYPE_RANGE = 2;
+
+ /**
+ * Obtain coverage type.
+ * @return coverage format type
+ */
+ public abstract int getType();
+
+ /**
+ * Obtain coverage entries.
+ * @return list of coverage entries
+ */
+ public abstract List getEntries();
+
+ /**
+ * Map glyph identifier (code) to coverge index. Returns -1 if glyph identifier is not in the domain of
+ * the coverage table.
+ * @param gid glyph identifier (code)
+ * @return non-negative glyph coverage index or -1 if glyph identifiers is not mapped by table
+ */
+ public abstract int getCoverageIndex ( int gid );
+
+ /**
+ * Create glyph coverage table.
+ * @param coverage list of mapped or ranged coverage entries, or null or empty list
+ * @return a new covera table instance
+ */
+ public static GlyphCoverageTable createCoverageTable ( List coverage ) {
+ GlyphCoverageTable ct;
+ if ( ( coverage == null ) || ( coverage.size() == 0 ) ) {
+ ct = new EmptyCoverageTable ( coverage );
+ } else if ( isMappedCoverage ( coverage ) ) {
+ ct = new MappedCoverageTable ( coverage );
+ } else if ( isRangeCoverage ( coverage ) ) {
+ ct = new RangeCoverageTable ( coverage );
+ } else {
+ ct = null;
+ }
+ assert ct != null : "unknown coverage type";
+ return ct;
+ }
+
+ private static boolean isMappedCoverage ( List coverage ) {
+ if ( ( coverage == null ) || ( coverage.size() == 0 ) ) {
+ return false;
+ } else {
+ for ( Iterator it = coverage.iterator(); it.hasNext();) {
+ Object o = it.next();
+ if ( ! ( o instanceof Integer ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private static boolean isRangeCoverage ( List coverage ) {
+ if ( ( coverage == null ) || ( coverage.size() == 0 ) ) {
+ return false;
+ } else {
+ for ( Iterator it = coverage.iterator(); it.hasNext();) {
+ Object o = it.next();
+ if ( ! ( o instanceof CoverageRange ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private static class EmptyCoverageTable extends GlyphCoverageTable {
+ public EmptyCoverageTable ( List coverage ) {
+ }
+ public int getType() {
+ return GLYPH_COVERAGE_TYPE_EMPTY;
+ }
+ public List getEntries() {
+ return new java.util.ArrayList();
+ }
+ public int getCoverageIndex ( int gid ) {
+ return -1;
+ }
+ }
+
+ private static class MappedCoverageTable extends GlyphCoverageTable {
+ private int[] map = null;
+ public MappedCoverageTable ( List coverage ) {
+ populate ( coverage );
+ }
+ public int getType() {
+ return GLYPH_COVERAGE_TYPE_MAPPED;
+ }
+ public List getEntries() {
+ List entries = new java.util.ArrayList();
+ if ( map != null ) {
+ for ( int i = 0, n = map.length; i < n; i++ ) {
+ entries.add ( Integer.valueOf ( map [ i ] ) );
+ }
+ }
+ return entries;
+ }
+ public int getCoverageIndex ( int gid ) {
+ int i;
+ if ( ( i = Arrays.binarySearch ( map, gid ) ) >= 0 ) {
+ return i;
+ } else {
+ return -1;
+ }
+ }
+ private void populate ( List coverage ) {
+ int i = 0, n = coverage.size(), gidMax = -1;
+ int[] map = new int [ n ];
+ for ( Iterator it = coverage.iterator(); it.hasNext();) {
+ Object o = it.next();
+ if ( o instanceof Integer ) {
+ int gid = ( (Integer) o ) . intValue();
+ if ( ( gid >= 0 ) && ( gid < 65536 ) ) {
+ if ( gid > gidMax ) {
+ map [ i++ ] = gidMax = gid;
+ } else {
+ throw new IllegalArgumentException ( "out of order or duplicate glyph index: " + gid );
+ }
+ } else {
+ throw new IllegalArgumentException ( "illegal glyph index: " + gid );
+ }
+ } else {
+ throw new IllegalArgumentException ( "illegal coverage entry, must be Integer: " + o );
+ }
+ }
+ assert i == n;
+ assert this.map == null;
+ this.map = map;
+ }
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append('{');
+ for ( int i = 0, n = map.length; i < n; i++ ) {
+ if ( i > 0 ) {
+ sb.append(',');
+ }
+ sb.append ( Integer.toString ( map [ i ] ) );
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ private static class RangeCoverageTable extends GlyphCoverageTable {
+ private int[] sa = null; // array of ranges starts
+ private int[] ea = null; // array of range ends
+ private int[] ca = null; // array of range coverage (start) indices
+ public RangeCoverageTable ( List coverage ) {
+ populate ( coverage );
+ }
+ public int getType() {
+ return GLYPH_COVERAGE_TYPE_RANGE;
+ }
+ public List getEntries() {
+ List entries = new java.util.ArrayList();
+ if ( sa != null ) {
+ for ( int i = 0, n = sa.length; i < n; i++ ) {
+ entries.add ( new CoverageRange ( sa [ i ], ea [ i ], ca [ i ] ) );
+ }
+ }
+ return entries;
+ }
+ public int getCoverageIndex ( int gid ) {
+ int i, ci;
+ if ( ( i = Arrays.binarySearch ( sa, gid ) ) >= 0 ) {
+ ci = ca [ i ] + gid - sa [ i ]; // matches start of (some) range
+ } else if ( ( i = - ( i + 1 ) ) == 0 ) {
+ ci = -1; // precedes first range
+ } else if ( gid > ea [ --i ] ) {
+ ci = -1; // follows preceding (or last) range
+ } else {
+ ci = ca [ i ] + gid - sa [ i ]; // intersects (some) range
+ }
+ return ci;
+ }
+ private void populate ( List coverage ) {
+ int i = 0, n = coverage.size(), gidMax = -1;
+ int[] sa = new int [ n ];
+ int[] ea = new int [ n ];
+ int[] ca = new int [ n ];
+ for ( Iterator it = coverage.iterator(); it.hasNext();) {
+ Object o = it.next();
+ if ( o instanceof CoverageRange ) {
+ CoverageRange r = (CoverageRange) o;
+ int gs = r.getStart();
+ int ge = r.getEnd();
+ int ci = r.getIndex();
+ if ( ( gs < 0 ) || ( gs > 65535 ) ) {
+ throw new IllegalArgumentException ( "illegal glyph range: [" + gs + "," + ge + "]: bad start index" );
+ } else if ( ( ge < 0 ) || ( ge > 65535 ) ) {
+ throw new IllegalArgumentException ( "illegal glyph range: [" + gs + "," + ge + "]: bad end index" );
+ } else if ( gs > ge ) {
+ throw new IllegalArgumentException ( "illegal glyph range: [" + gs + "," + ge + "]: start index exceeds end index" );
+ } else if ( gs < gidMax ) {
+ throw new IllegalArgumentException ( "out of order glyph range: [" + gs + "," + ge + "]" );
+ } else if ( ci < 0 ) {
+ throw new IllegalArgumentException ( "illegal coverage index: " + ci );
+ } else {
+ sa [ i ] = gs;
+ ea [ i ] = gidMax = ge;
+ ca [ i ] = ci;
+ i++;
+ }
+ } else {
+ throw new IllegalArgumentException ( "illegal coverage entry, must be Integer: " + o );
+ }
+ }
+ assert i == n;
+ assert this.sa == null;
+ assert this.ea == null;
+ assert this.ca == null;
+ this.sa = sa;
+ this.ea = ea;
+ this.ca = ca;
+ }
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append('{');
+ for ( int i = 0, n = sa.length; i < n; i++ ) {
+ if ( i > 0 ) {
+ sb.append(',');
+ }
+ sb.append ( '[' );
+ sb.append ( Integer.toString ( sa [ i ] ) );
+ sb.append ( Integer.toString ( ea [ i ] ) );
+ sb.append ( "]:" );
+ sb.append ( Integer.toString ( ca [ i ] ) );
+ }
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ /**
+ * The <code>CoverageRange</code> class encapsulates a glyph [start,end] range and
+ * a coverage index.
+ */
+ public static class CoverageRange {
+
+ private final int gidStart; // first glyph in range (inclusive)
+ private final int gidEnd; // last glyph in range (inclusive)
+ private final int index; // coverage index;
+
+ /**
+ * Instantiate a coverage range.
+ */
+ public CoverageRange() {
+ this ( 0, 0, 0 );
+ }
+
+ /**
+ * Instantiate a specific coverage range.
+ * @param gidStart start of range
+ * @param gidEnd end of range
+ * @param index coverage index
+ */
+ public CoverageRange ( int gidStart, int gidEnd, int index ) {
+ if ( ( gidStart < 0 ) || ( gidEnd < 0 ) || ( index < 0 ) ) {
+ throw new IllegalArgumentException();
+ } else if ( gidStart > gidEnd ) {
+ throw new IllegalArgumentException();
+ } else {
+ this.gidStart = gidStart;
+ this.gidEnd = gidEnd;
+ this.index = index;
+ }
+ }
+
+ /** @return start of range */
+ public int getStart() {
+ return gidStart;
+ }
+
+ /** @return end of range */
+ public int getEnd() {
+ return gidEnd;
+ }
+
+ /** @return coverage index */
+ public int getIndex() {
+ return index;
+ }
+
+ /** @return interval as a pair of integers */
+ public int[] getInterval() {
+ return new int[] { gidStart, gidEnd };
+ }
+
+ /**
+ * Obtain interval, filled into first two elements of specified array, or returning new array.
+ * @param interval an array of length two or greater or null
+ * @return interval as a pair of integers, filled into specified array
+ */
+ public int[] getInterval ( int[] interval ) {
+ if ( ( interval == null ) || ( interval.length != 2 ) ) {
+ throw new IllegalArgumentException();
+ } else {
+ interval[0] = gidStart;
+ interval[1] = gidEnd;
+ }
+ return interval;
+ }
+
+ /** @return length of interval */
+ public int getLength() {
+ return gidStart - gidEnd;
+ }
+
+ }
+
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphCoverageTable.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphPositioning</code> interface is implemented by a font related object
+ * that supports the determination of glyph positioning information based on script and
+ * language of the corresponding character content.
+ * @author Glenn Adams
+ */
+public interface GlyphPositioning {
+
+ /**
+ * Perform glyph positioning.
+ * @param gs sequence to map to output glyph sequence
+ * @param script the script associated with the characters corresponding to the glyph sequence
+ * @param language the language associated with the characters corresponding to the glyph sequence
+ * @return array (sequence) of pairs of position [DX,DY] offsets, one pair for each element of
+ * glyph sequence, or null if no non-zero offset applies
+ */
+ int[] position ( GlyphSequence gs, String script, String language );
+
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioning.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphPositioningSubtable</code> implements an abstract base of a glyph subtable,
+ * providing a default implementation of the <code>GlyphPositioning</code> interface.
+ * @author Glenn Adams
+ */
+public abstract class GlyphPositioningSubtable extends GlyphSubtable implements GlyphPositioning {
+
+ /**
+ * Instantiate a <code>GlyphPositioningSubtable</code>.
+ * @param id subtable identifier
+ * @param sequence subtable sequence
+ * @param flags subtable flags
+ * @param format subtable format
+ * @param coverage subtable coverage table
+ */
+ protected GlyphPositioningSubtable ( String id, int sequence, int flags, int format, GlyphCoverageTable coverage ) {
+ super ( id, sequence, flags, format, coverage );
+ }
+
+ /** {@inheritDoc} */
+ public int getTableType() {
+ return GlyphTable.GLYPH_TABLE_TYPE_POSITIONING;
+ }
+
+ /** {@inheritDoc} */
+ public String getTypeName() {
+ return GlyphPositioningTable.getLookupTypeName ( getType() );
+ }
+
+ /** {@inheritDoc} */
+ public int[] position ( GlyphSequence gs, String script, String language ) {
+ if ( gs == null ) {
+ throw new IllegalArgumentException ( "invalid glyph sequence: must not be null" );
+ } else {
+ return null;
+ }
+ }
+
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningSubtable.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphPositioningTable</code> class is a glyph table that implements
+ * <code>GlyphPositioning</code> functionality.
+ * @author Glenn Adams
+ */
+public class GlyphPositioningTable extends GlyphTable implements GlyphPositioning {
+
+ /** single positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_SINGLE = 1;
+ /** multiple positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_PAIR = 2;
+ /** cursive positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_CURSIVE = 3;
+ /** mark to base positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_MARK_TO_BASE = 4;
+ /** mark to ligature positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE = 5;
+ /** mark to mark positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_MARK_TO_MARK = 6;
+ /** context positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_CONTEXT = 7;
+ /** chained context positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_CHAINED_CONTEXT = 8;
+ /** extension positioning subtable type */
+ public static final int GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING = 9;
+
+ /**
+ * Instantiate a <code>GlyphPositioningTable</code> object using the specified lookups
+ * and subtables.
+ * @param lookups a map of lookup specifications to subtable identifier strings
+ * @param subtables a list of identified subtables
+ */
+ public GlyphPositioningTable ( Map lookups, List subtables ) {
+ super ( lookups );
+ if ( ( subtables == null ) || ( subtables.size() == 0 ) ) {
+ throw new IllegalArgumentException ( "subtables must be non-empty" );
+ } else {
+ for ( Iterator it = subtables.iterator(); it.hasNext();) {
+ Object o = it.next();
+ if ( o instanceof GlyphPositioningSubtable ) {
+ addSubtable ( (GlyphSubtable) o );
+ } else {
+ throw new IllegalArgumentException ( "subtable must be a glyph positioning subtable" );
+ }
+ }
+ }
+ }
+
+ /**
+ * Map a lookup type name to its constant (integer) value.
+ * @param name lookup type name
+ * @return lookup type
+ */
+ public static int getLookupTypeFromName ( String name ) {
+ int t;
+ String s = name.toLowerCase();
+ if ( "single".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_SINGLE;
+ } else if ( "pair".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_PAIR;
+ } else if ( "cursive".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_CURSIVE;
+ } else if ( "marktobase".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_MARK_TO_BASE;
+ } else if ( "marktoligature".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE;
+ } else if ( "marktomark".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_MARK_TO_MARK;
+ } else if ( "context".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_CONTEXT;
+ } else if ( "chainedcontext".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_CHAINED_CONTEXT;
+ } else if ( "extensionpositioning".equals ( s ) ) {
+ t = GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING;
+ } else {
+ t = -1;
+ }
+ return t;
+ }
+
+ /**
+ * Map a lookup type constant (integer) value to its name.
+ * @param type lookup type
+ * @return lookup type name
+ */
+ public static String getLookupTypeName ( int type ) {
+ String tn;
+ switch ( type ) {
+ case GPOS_LOOKUP_TYPE_SINGLE:
+ tn = "single";
+ break;
+ case GPOS_LOOKUP_TYPE_PAIR:
+ tn = "pair";
+ break;
+ case GPOS_LOOKUP_TYPE_CURSIVE:
+ tn = "cursive";
+ break;
+ case GPOS_LOOKUP_TYPE_MARK_TO_BASE:
+ tn = "marktobase";
+ break;
+ case GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE:
+ tn = "marktoligature";
+ break;
+ case GPOS_LOOKUP_TYPE_MARK_TO_MARK:
+ tn = "marktomark";
+ break;
+ case GPOS_LOOKUP_TYPE_CONTEXT:
+ tn = "context";
+ break;
+ case GPOS_LOOKUP_TYPE_CHAINED_CONTEXT:
+ tn = "chainedcontext";
+ break;
+ case GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING:
+ tn = "extensionpositioning";
+ break;
+ default:
+ tn = "unknown";
+ break;
+ }
+ return tn;
+ }
+
+ /**
+ * Create a positioning subtable according to the specified arguments.
+ * @param type subtable type
+ * @param id subtable identifier
+ * @param sequence subtable sequence
+ * @param flags subtable flags
+ * @param format subtable format
+ * @param coverage subtable coverage table
+ * @param entries subtable entries
+ * @return a glyph subtable instance
+ */
+ public static GlyphSubtable createSubtable ( int type, String id, int sequence, int flags, int format, List coverage, List entries ) {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public int[] position ( GlyphSequence gs, String script, String language ) {
+ return null;
+ }
+
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphPositioningTable.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+import java.nio.CharBuffer;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+// CSOFF: NoWhitespaceAfterCheck
+// CSOFF: LineLengthCheck
+
+/**
+ * A GlyphSequence encapsulates a sequence of character codes, a sequence of glyph codes,
+ * and a sequence of character associations, where, for each glyph in the sequence of glyph
+ * codes, there is a corresponding character association. Character associations server to
+ * relate the glyph codes in a glyph sequence to the specific characters in an original
+ * character code sequence with which the glyph codes are associated.
+ * @author Glenn Adams
+ */
+public class GlyphSequence implements CharSequence {
+
+ private CharSequence characters;
+ private CharSequence glyphs;
+ private CharAssociation[] associations;
+
+ /**
+ * Instantiate a glyph sequence.
+ * @param characters a (possibly empty) sequence of associated (originating) characters
+ * @param sequences a (possibly empty) list of glyph sequences
+ * @param associations a (possibly empty) list of glyph to character associations, one for each glyph in the concatenated glyph sequences
+ * @param reverse a boolean indicating if the glyphs are in reverse order with respect to the nominal inline progression direction
+ */
+ public GlyphSequence ( CharSequence characters, List/*<GlyphSequence>*/ sequences, List/*<CharAssociation>*/ associations, boolean reverse ) {
+ this ( characters, concatenateSequences ( sequences, reverse ), concatenateAssociations ( associations, reverse ) );
+ }
+
+ /**
+ * Instantiate a glyph sequence.
+ * @param characters a (possibly empty) sequence of associated (originating) characters
+ * @param glyphs a (possibly empty) list of glyphs
+ * @param associations a (possibly empty) list of glyph to character associations, one for each glyph in the concatenated glyph sequences
+ */
+ public GlyphSequence ( CharSequence characters, CharSequence glyphs, CharAssociation[] associations ) {
+ if ( ( characters == null ) || ( glyphs == null ) ) {
+ throw new IllegalArgumentException ( "characters and glyphs must be non-null" );
+ } else if ( ( associations != null ) && ( associations.length != glyphs.length() ) ) {
+ throw new IllegalArgumentException ( "number of associations must match number of glyphs" );
+ } else {
+ this.characters = characters;
+ this.glyphs = glyphs;
+ if ( associations == null ) {
+ associations = makeIdentityAssociations ( characters, glyphs );
+ }
+ this.associations = associations;
+ }
+ }
+
+ /** @return sequence of corresponding (originating) characters */
+ public CharSequence getCharacters() {
+ return characters;
+ }
+
+ /** @return sequence of glyphs in glyph sequence */
+ public CharSequence getGlyphs() {
+ return glyphs;
+ }
+
+ /** @return glyph to character associations, one for each glyph */
+ public CharAssociation[] getAssociations() {
+ return associations;
+ }
+
+ /**
+ * Obtain the sequence of characters that corresponds to the glyph sequence at interval
+ * [offset,offset+count).
+ * @param offset to first glyph
+ * @param count of glyphs
+ * @return corresponding character sequence
+ */
+ public CharSequence getCharsForGlyphs ( int offset, int count ) throws DiscontinuousAssociationException { // CSOK: JavadocMethodCheck
+ int sFirst = -1, eLast = -1;
+ for ( int i = 0, n = count; i < n; i++ ) {
+ CharAssociation ca = associations [ offset + i ];
+ int s = ca.getStart();
+ int e = ca.getEnd();
+ if ( sFirst < 0 ) {
+ sFirst = s;
+ }
+ if ( eLast < 0 ) {
+ eLast = e;
+ } else if ( s == eLast ) {
+ eLast = e;
+ } else {
+ throw new DiscontinuousAssociationException();
+ }
+ }
+ return characters.subSequence ( sFirst, eLast );
+ }
+
+ /**
+ * Obtain the glyph subsequence corresponding to the half-open interval [start,end).
+ * @param start of subsequence
+ * @param end of subsequence
+ * @return a subsequence of this sequence
+ */
+ public GlyphSequence getGlyphSubsequence ( int start, int end ) {
+ CharAssociation[] subset = new CharAssociation[end - start];
+ System.arraycopy(associations, start, subset, 0, end - start);
+ return new GlyphSequence ( characters, glyphs.subSequence ( start, end ), subset );
+ }
+
+ /** @return the number of glyphs in this glyph sequence */
+ public int length() {
+ return glyphs.length();
+ }
+
+ /**
+ * Obtain glyph id at specified index.
+ * @param index to obtain glyph
+ * @return the glyph identifier of glyph at specified index
+ */
+ public char charAt ( int index ) {
+ return glyphs.charAt ( index );
+ }
+
+ /**
+ * Obtain glyph code subsequence over interval [start,end).
+ * @param start of subsequence
+ * @param end of subsequence
+ * @return the glyph code subsequence
+ */
+ public CharSequence subSequence ( int start, int end ) {
+ return glyphs.subSequence ( start, end );
+ }
+
+ /** {@inheritDoc} */
+ public String toString() {
+ return glyphs.toString();
+ }
+
+ private CharAssociation[] makeIdentityAssociations ( CharSequence characters, CharSequence glyphs ) {
+ int nc = characters.length();
+ int ng = glyphs.length();
+ CharAssociation[] ca = new CharAssociation [ ng ];
+ for ( int i = 0, n = ng; i < n; i++ ) {
+ int k = ( i > nc ) ? nc : i;
+ ca [ i ] = new CharAssociation ( i, ( k == nc ) ? 0 : 1 );
+ }
+ return ca;
+ }
+
+ private static CharSequence concatenateSequences ( List/*<GlyphSequence>*/ sequences, boolean reverse ) {
+ int ng = 0;
+ for ( Iterator it = sequences.iterator(); it.hasNext();) {
+ GlyphSequence gs = (GlyphSequence) it.next();
+ ng += gs.length();
+ }
+ CharBuffer cb = CharBuffer.allocate ( ng );
+ if ( ! reverse ) {
+ for ( ListIterator it = sequences.listIterator(); it.hasNext();) {
+ GlyphSequence gs = (GlyphSequence) it.next();
+ cb.append ( (CharSequence) gs );
+ }
+ } else {
+ for ( ListIterator it = sequences.listIterator ( sequences.size() ); it.hasPrevious();) {
+ GlyphSequence gs = (GlyphSequence) it.previous();
+ cb.append ( (CharSequence) gs );
+ }
+ }
+ cb.rewind();
+ return cb;
+ }
+
+ private static CharAssociation[] concatenateAssociations ( List/*<CharAssociation>*/ associations, boolean reverse ) {
+ int na = 0;
+ CharAssociation[] ca = new CharAssociation [ associations.size() ];
+ if ( ! reverse ) {
+ for ( ListIterator it = associations.listIterator(); it.hasNext();) {
+ CharAssociation a = (CharAssociation) it.next();
+ ca [ na++ ] = a;
+ }
+ } else {
+ for ( ListIterator it = associations.listIterator ( associations.size() ); it.hasPrevious();) {
+ CharAssociation a = (CharAssociation) it.previous();
+ ca [ na++ ] = a;
+ }
+ }
+ return ca;
+ }
+
+ /**
+ * A structure class encapsulating an interval of character codes (in a CharSequence)
+ * expressed as an offset and count (of code elements in a CharSequence, i.e., numbere of
+ * UTF-16 code elements. N.B. count does not necessarily designate the number of Unicode
+ * scalar values expressed by the CharSequence; in particular, it does not do so if there
+ * is one or more UTF-16 surrogate pairs present in the CharSequence.)
+ */
+ public static class CharAssociation {
+
+ private final int offset;
+ private final int count;
+
+ /**
+ * Instantiate a character association.
+ * @param offset into array of UTF-16 code elements (in associated CharSequence)
+ * @param count of UTF-16 character code elements (in associated CharSequence)
+ */
+ public CharAssociation ( int offset, int count ) {
+ this.offset = offset;
+ this.count = count;
+ }
+
+ /** @return offset (start of association interval) */
+ public int getOffset() {
+ return offset;
+ }
+
+ /** @return count (number of characer codes in association) */
+ public int getCount() {
+ return count;
+ }
+
+ /** @return start of association interval */
+ public int getStart() {
+ return getOffset();
+ }
+
+ /** @return end of association interval */
+ public int getEnd() {
+ return getOffset() + getCount();
+ }
+
+ }
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSequence.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphSubstitution</code> interface is implemented by a font related object
+ * that supports the determination of glyph substitution information based on script and
+ * language of the corresponding character content.
+ * @author Glenn Adams
+ */
+public interface GlyphSubstitution {
+
+ /**
+ * Perform glyph substitutions. If no substitution applies, then returns the unmodified input sequence.
+ * @param gs sequence to map to output glyph sequence
+ * @param script the script associated with the characters corresponding to the glyph sequence
+ * @param language the language associated with the characters corresponding to the glyph sequence
+ * @return resulting glyph sequence, where each 'glyph' in the returned sequence has been mapped
+ * (or not) by substitution
+ */
+ GlyphSequence substitute ( GlyphSequence gs, String script, String language );
+
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitution.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java?rev=987282&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java (added)
+++ xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java Thu Aug 19 19:46:41 2010
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+// CSOFF: LineLengthCheck
+
+/**
+ * The <code>GlyphSubstitutionSubtable</code> implements an abstract base of a glyph substitution subtable,
+ * providing a default implementation of the <code>GlyphSubstitution</code> interface.
+ * @author Glenn Adams
+ */
+public abstract class GlyphSubstitutionSubtable extends GlyphSubtable implements GlyphSubstitution {
+
+ /**
+ * Instantiate a <code>GlyphSubstitutionSubtable</code>.
+ * @param id subtable identifier
+ * @param sequence subtable sequence
+ * @param flags subtable flags
+ * @param format subtable format
+ * @param coverage subtable coverage table
+ */
+ protected GlyphSubstitutionSubtable ( String id, int sequence, int flags, int format, GlyphCoverageTable coverage ) {
+ super ( id, sequence, flags, format, coverage );
+ }
+
+ /** {@inheritDoc} */
+ public int getTableType() {
+ return GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION;
+ }
+
+ /** {@inheritDoc} */
+ public String getTypeName() {
+ return GlyphSubstitutionTable.getLookupTypeName ( getType() );
+ }
+
+ /** {@inheritDoc} */
+ public GlyphSequence substitute ( GlyphSequence gs, String script, String language ) {
+ if ( gs == null ) {
+ throw new IllegalArgumentException ( "invalid glyph sequence: must not be null" );
+ } else {
+ return gs;
+ }
+ }
+
+}
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: xmlgraphics/fop/branches/Temp_ComplexScripts/src/java/org/apache/fop/fonts/GlyphSubstitutionSubtable.java
------------------------------------------------------------------------------
svn:keywords = Id
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org