| /* |
| * 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; |
| } |
| } |
| |
| } |