blob: 7ebd268fe222f08279e94fbc28349607d28f4aa1 [file] [log] [blame]
/*
* 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.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// CSOFF: InnerAssignmentCheck
// CSOFF: LineLengthCheck
/**
* The <code>GlyphDefinitionTable</code> class is a glyph table that implements
* glyph definition functionality according to the OpenType GDEF table.
* @author Glenn Adams
*/
public class GlyphDefinitionTable extends GlyphTable {
/** logging instance */
private static final Log log = LogFactory.getLog(GlyphDefinitionTable.class); // CSOK: ConstantNameCheck
/** glyph class subtable type */
public static final int GDEF_LOOKUP_TYPE_GLYPH_CLASS = 1;
/** attachment point subtable type */
public static final int GDEF_LOOKUP_TYPE_ATTACHMENT_POINT = 2;
/** ligature caret subtable type */
public static final int GDEF_LOOKUP_TYPE_LIGATURE_CARET = 3;
/** mark attachment subtable type */
public static final int GDEF_LOOKUP_TYPE_MARK_ATTACHMENT = 4;
/** pre-defined glyph class - base glyph */
public static final int GLYPH_CLASS_BASE = 1;
/** pre-defined glyph class - ligature glyph */
public static final int GLYPH_CLASS_LIGATURE = 2;
/** pre-defined glyph class - mark glyph */
public static final int GLYPH_CLASS_MARK = 3;
/** pre-defined glyph class - component glyph */
public static final int GLYPH_CLASS_COMPONENT = 4;
/** singleton glyph class table */
private GlyphClassSubtable gct;
/** singleton attachment point table */
// private AttachmentPointSubtable apt;
/** singleton ligature caret table */
// private LigatureCaretSubtable lct;
/** singleton mark attachment table */
// private MarkAttachmentSubtable mat;
/**
* Instantiate a <code>GlyphDefinitionTable</code> object using the specified subtables.
* @param subtables a list of identified subtables
*/
public GlyphDefinitionTable ( List subtables ) {
super ( null, new HashMap(0) );
if ( ( subtables == null ) || ( subtables.size() == 0 ) ) {
throw new AdvancedTypographicTableFormatException ( "subtables must be non-empty" );
} else {
for ( Iterator it = subtables.iterator(); it.hasNext();) {
Object o = it.next();
if ( o instanceof GlyphDefinitionSubtable ) {
addSubtable ( (GlyphSubtable) o );
} else {
throw new AdvancedTypographicTableFormatException ( "subtable must be a glyph definition subtable" );
}
}
freezeSubtables();
}
}
/**
* Reorder combining marks in glyph sequence so that they precede (within the sequence) the base
* character to which they are applied. N.B. In the case of 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 glyph.
* @param gs an input glyph sequence
* @param gpa associated glyph position adjustments (also reordered)
* @param script a script identifier
* @param language a language identifier
* @return the reordered (output) glyph sequence
*/
public GlyphSequence reorderCombiningMarks ( GlyphSequence gs, int[][] gpa, String script, String language ) {
ScriptProcessor sp = ScriptProcessor.getInstance ( script );
return sp.reorderCombiningMarks ( this, gs, gpa, script, language );
}
/** {@inheritDoc} */
protected void addSubtable ( GlyphSubtable subtable ) {
if ( subtable instanceof GlyphClassSubtable ) {
this.gct = (GlyphClassSubtable) subtable;
} else if ( subtable instanceof AttachmentPointSubtable ) {
// TODO - not yet used
// this.apt = (AttachmentPointSubtable) subtable;
} else if ( subtable instanceof LigatureCaretSubtable ) {
// TODO - not yet used
// this.lct = (LigatureCaretSubtable) subtable;
} else if ( subtable instanceof MarkAttachmentSubtable ) {
// TODO - not yet used
// this.mat = (MarkAttachmentSubtable) subtable;
} else {
throw new UnsupportedOperationException ( "unsupported glyph definition subtable type: " + subtable );
}
}
/**
* Determine if glyph belongs to pre-defined glyph class.
* @param gid a glyph identifier (index)
* @param gc a pre-defined glyph class (GLYPH_CLASS_BASE|GLYPH_CLASS_LIGATURE|GLYPH_CLASS_MARK|GLYPH_CLASS_COMPONENT).
* @return true if glyph belongs to specified glyph class
*/
public boolean isGlyphClass ( int gid, int gc ) {
if ( gct != null ) {
return gct.isGlyphClass ( gid, gc );
} else {
return false;
}
}
/**
* Determine glyph class.
* @param gid a glyph identifier (index)
* @return a pre-defined glyph class (GLYPH_CLASS_BASE|GLYPH_CLASS_LIGATURE|GLYPH_CLASS_MARK|GLYPH_CLASS_COMPONENT).
*/
public int getGlyphClass ( int gid ) {
if ( gct != null ) {
return gct.getGlyphClass ( gid );
} else {
return -1;
}
}
/**
* 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 ( "glyphclass".equals ( s ) ) {
t = GDEF_LOOKUP_TYPE_GLYPH_CLASS;
} else if ( "attachmentpoint".equals ( s ) ) {
t = GDEF_LOOKUP_TYPE_ATTACHMENT_POINT;
} else if ( "ligaturecaret".equals ( s ) ) {
t = GDEF_LOOKUP_TYPE_LIGATURE_CARET;
} else if ( "markattachment".equals ( s ) ) {
t = GDEF_LOOKUP_TYPE_MARK_ATTACHMENT;
} 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 = null;
switch ( type ) {
case GDEF_LOOKUP_TYPE_GLYPH_CLASS:
tn = "glyphclass";
break;
case GDEF_LOOKUP_TYPE_ATTACHMENT_POINT:
tn = "attachmentpoint";
break;
case GDEF_LOOKUP_TYPE_LIGATURE_CARET:
tn = "ligaturecaret";
break;
case GDEF_LOOKUP_TYPE_MARK_ATTACHMENT:
tn = "markattachment";
break;
default:
tn = "unknown";
break;
}
return tn;
}
/**
* Create a definition subtable according to the specified arguments.
* @param type subtable type
* @param id subtable identifier
* @param sequence subtable sequence
* @param flags subtable flags (must be zero)
* @param format subtable format
* @param mapping subtable mapping table
* @param entries subtable entries
* @return a glyph subtable instance
*/
public static GlyphSubtable createSubtable ( int type, String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
GlyphSubtable st = null;
switch ( type ) {
case GDEF_LOOKUP_TYPE_GLYPH_CLASS:
st = GlyphClassSubtable.create ( id, sequence, flags, format, mapping, entries );
break;
case GDEF_LOOKUP_TYPE_ATTACHMENT_POINT:
st = AttachmentPointSubtable.create ( id, sequence, flags, format, mapping, entries );
break;
case GDEF_LOOKUP_TYPE_LIGATURE_CARET:
st = LigatureCaretSubtable.create ( id, sequence, flags, format, mapping, entries );
break;
case GDEF_LOOKUP_TYPE_MARK_ATTACHMENT:
st = MarkAttachmentSubtable.create ( id, sequence, flags, format, mapping, entries );
break;
default:
break;
}
return st;
}
private abstract static class GlyphClassSubtable extends GlyphDefinitionSubtable {
GlyphClassSubtable ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping );
}
/** {@inheritDoc} */
public int getType() {
return GDEF_LOOKUP_TYPE_GLYPH_CLASS;
}
/**
* Determine if glyph belongs to pre-defined glyph class.
* @param gid a glyph identifier (index)
* @param gc a pre-defined glyph class (GLYPH_CLASS_BASE|GLYPH_CLASS_LIGATURE|GLYPH_CLASS_MARK|GLYPH_CLASS_COMPONENT).
* @return true if glyph belongs to specified glyph class
*/
public abstract boolean isGlyphClass ( int gid, int gc );
/**
* Determine glyph class.
* @param gid a glyph identifier (index)
* @return a pre-defined glyph class (GLYPH_CLASS_BASE|GLYPH_CLASS_LIGATURE|GLYPH_CLASS_MARK|GLYPH_CLASS_COMPONENT).
*/
public abstract int getGlyphClass ( int gid );
static GlyphDefinitionSubtable create ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
if ( format == 1 ) {
return new GlyphClassSubtableFormat1 ( id, sequence, flags, format, mapping, entries );
} else {
throw new UnsupportedOperationException();
}
}
}
private static class GlyphClassSubtableFormat1 extends GlyphClassSubtable {
GlyphClassSubtableFormat1 ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping, entries );
}
/** {@inheritDoc} */
public List getEntries() {
return null;
}
/** {@inheritDoc} */
public boolean isCompatible ( GlyphSubtable subtable ) {
return subtable instanceof GlyphClassSubtable;
}
/** {@inheritDoc} */
public boolean isGlyphClass ( int gid, int gc ) {
GlyphClassMapping cm = getClasses();
if ( cm != null ) {
return cm.getClassIndex ( gid, 0 ) == gc;
} else {
return false;
}
}
/** {@inheritDoc} */
public int getGlyphClass ( int gid ) {
GlyphClassMapping cm = getClasses();
if ( cm != null ) {
return cm.getClassIndex ( gid, 0 );
} else {
return -1;
}
}
}
private abstract static class AttachmentPointSubtable extends GlyphDefinitionSubtable {
AttachmentPointSubtable ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping );
}
/** {@inheritDoc} */
public int getType() {
return GDEF_LOOKUP_TYPE_ATTACHMENT_POINT;
}
static GlyphDefinitionSubtable create ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
if ( format == 1 ) {
return new AttachmentPointSubtableFormat1 ( id, sequence, flags, format, mapping, entries );
} else {
throw new UnsupportedOperationException();
}
}
}
private static class AttachmentPointSubtableFormat1 extends AttachmentPointSubtable {
AttachmentPointSubtableFormat1 ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping, entries );
}
/** {@inheritDoc} */
public List getEntries() {
return null;
}
/** {@inheritDoc} */
public boolean isCompatible ( GlyphSubtable subtable ) {
return subtable instanceof AttachmentPointSubtable;
}
}
private abstract static class LigatureCaretSubtable extends GlyphDefinitionSubtable {
LigatureCaretSubtable ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping );
}
/** {@inheritDoc} */
public int getType() {
return GDEF_LOOKUP_TYPE_LIGATURE_CARET;
}
static GlyphDefinitionSubtable create ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
if ( format == 1 ) {
return new LigatureCaretSubtableFormat1 ( id, sequence, flags, format, mapping, entries );
} else {
throw new UnsupportedOperationException();
}
}
}
private static class LigatureCaretSubtableFormat1 extends LigatureCaretSubtable {
LigatureCaretSubtableFormat1 ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping, entries );
}
/** {@inheritDoc} */
public List getEntries() {
return null;
}
/** {@inheritDoc} */
public boolean isCompatible ( GlyphSubtable subtable ) {
return subtable instanceof LigatureCaretSubtable;
}
}
private abstract static class MarkAttachmentSubtable extends GlyphDefinitionSubtable {
MarkAttachmentSubtable ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping );
}
/** {@inheritDoc} */
public int getType() {
return GDEF_LOOKUP_TYPE_MARK_ATTACHMENT;
}
static GlyphDefinitionSubtable create ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
if ( format == 1 ) {
return new MarkAttachmentSubtableFormat1 ( id, sequence, flags, format, mapping, entries );
} else {
throw new UnsupportedOperationException();
}
}
}
private static class MarkAttachmentSubtableFormat1 extends MarkAttachmentSubtable {
MarkAttachmentSubtableFormat1 ( String id, int sequence, int flags, int format, GlyphMappingTable mapping, List entries ) {
super ( id, sequence, flags, format, mapping, entries );
}
/** {@inheritDoc} */
public List getEntries() {
return null;
}
/** {@inheritDoc} */
public boolean isCompatible ( GlyphSubtable subtable ) {
return subtable instanceof MarkAttachmentSubtable;
}
}
}