You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GlyphSubtable.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.complexscripts.fonts;
  19. import java.lang.ref.WeakReference;
  20. import java.util.List;
  21. import java.util.Map;
  22. // CSOFF: InnerAssignmentCheck
  23. // CSOFF: LineLengthCheck
  24. /**
  25. * <p>The <code>GlyphSubtable</code> implements an abstract glyph subtable that
  26. * encapsulates identification, type, format, and coverage information.</p>
  27. *
  28. * <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
  29. */
  30. public abstract class GlyphSubtable implements Comparable {
  31. /** lookup flag - right to left */
  32. public static final int LF_RIGHT_TO_LEFT = 0x0001;
  33. /** lookup flag - ignore base glyphs */
  34. public static final int LF_IGNORE_BASE = 0x0002;
  35. /** lookup flag - ignore ligatures */
  36. public static final int LF_IGNORE_LIGATURE = 0x0004;
  37. /** lookup flag - ignore marks */
  38. public static final int LF_IGNORE_MARK = 0x0008;
  39. /** lookup flag - use mark filtering set */
  40. public static final int LF_USE_MARK_FILTERING_SET = 0x0010;
  41. /** lookup flag - reserved */
  42. public static final int LF_RESERVED = 0x0E00;
  43. /** lookup flag - mark attachment type */
  44. public static final int LF_MARK_ATTACHMENT_TYPE = 0xFF00;
  45. /** internal flag - use reverse scan */
  46. public static final int LF_INTERNAL_USE_REVERSE_SCAN = 0x10000;
  47. /** lookup identifier, having form of "lu%d" where %d is index of lookup in lookup list; shared by multiple subtables in a single lookup */
  48. private String lookupId;
  49. /** subtable sequence (index) number in lookup, zero based */
  50. private int sequence;
  51. /** subtable flags */
  52. private int flags;
  53. /** subtable format */
  54. private int format;
  55. /** subtable mapping table */
  56. private GlyphMappingTable mapping;
  57. /** weak reference to parent (gsub or gpos) table */
  58. private WeakReference table;
  59. /**
  60. * Instantiate this glyph subtable.
  61. * @param lookupId lookup identifier, having form of "lu%d" where %d is index of lookup in lookup list
  62. * @param sequence subtable sequence (within lookup), starting with zero
  63. * @param flags subtable flags
  64. * @param format subtable format
  65. * @param mapping subtable mapping table
  66. */
  67. protected GlyphSubtable ( String lookupId, int sequence, int flags, int format, GlyphMappingTable mapping )
  68. {
  69. if ( ( lookupId == null ) || ( lookupId.length() == 0 ) ) {
  70. throw new AdvancedTypographicTableFormatException ( "invalid lookup identifier, must be non-empty string" );
  71. } else if ( mapping == null ) {
  72. throw new AdvancedTypographicTableFormatException ( "invalid mapping table, must not be null" );
  73. } else {
  74. this.lookupId = lookupId;
  75. this.sequence = sequence;
  76. this.flags = flags;
  77. this.format = format;
  78. this.mapping = mapping;
  79. }
  80. }
  81. /** @return this subtable's lookup identifer */
  82. public String getLookupId() {
  83. return lookupId;
  84. }
  85. /** @return this subtable's table type */
  86. public abstract int getTableType();
  87. /** @return this subtable's type */
  88. public abstract int getType();
  89. /** @return this subtable's type name */
  90. public abstract String getTypeName();
  91. /**
  92. * Determine if a glyph subtable is compatible with this glyph subtable. Two glyph subtables are
  93. * compatible if the both may appear in a single lookup table.
  94. * @param subtable a glyph subtable to determine compatibility
  95. * @return true if specified subtable is compatible with this glyph subtable, where by compatible
  96. * is meant that they share the same lookup type
  97. */
  98. public abstract boolean isCompatible ( GlyphSubtable subtable );
  99. /** @return true if subtable uses reverse scanning of glyph sequence, meaning from the last glyph
  100. * in a glyph sequence to the first glyph
  101. */
  102. public abstract boolean usesReverseScan();
  103. /** @return this subtable's sequence (index) within lookup */
  104. public int getSequence() {
  105. return sequence;
  106. }
  107. /** @return this subtable's flags */
  108. public int getFlags() {
  109. return flags;
  110. }
  111. /** @return this subtable's format */
  112. public int getFormat() {
  113. return format;
  114. }
  115. /** @return this subtable's governing glyph definition table or null if none available */
  116. public GlyphDefinitionTable getGDEF() {
  117. GlyphTable gt = getTable();
  118. if ( gt != null ) {
  119. return gt.getGlyphDefinitions();
  120. } else {
  121. return null;
  122. }
  123. }
  124. /** @return this subtable's coverage mapping or null if mapping is not a coverage mapping */
  125. public GlyphCoverageMapping getCoverage() {
  126. if ( mapping instanceof GlyphCoverageMapping ) {
  127. return (GlyphCoverageMapping) mapping;
  128. } else {
  129. return null;
  130. }
  131. }
  132. /** @return this subtable's class mapping or null if mapping is not a class mapping */
  133. public GlyphClassMapping getClasses() {
  134. if ( mapping instanceof GlyphClassMapping ) {
  135. return (GlyphClassMapping) mapping;
  136. } else {
  137. return null;
  138. }
  139. }
  140. /** @return this subtable's lookup entries */
  141. public abstract List getEntries();
  142. /** @return this subtable's parent table (or null if undefined) */
  143. public synchronized GlyphTable getTable() {
  144. WeakReference r = this.table;
  145. return ( r != null ) ? (GlyphTable) r.get() : null;
  146. }
  147. /**
  148. * Establish a weak reference from this subtable to its parent
  149. * table. If table parameter is specified as <code>null</code>, then
  150. * clear and remove weak reference.
  151. * @param table the table or null
  152. * @throws IllegalStateException if table is already set to non-null
  153. */
  154. public synchronized void setTable ( GlyphTable table ) throws IllegalStateException {
  155. WeakReference r = this.table;
  156. if ( table == null ) {
  157. this.table = null;
  158. if ( r != null ) {
  159. r.clear();
  160. }
  161. } else if ( r == null ) {
  162. this.table = new WeakReference ( table );
  163. } else {
  164. throw new IllegalStateException ( "table already set" );
  165. }
  166. }
  167. /**
  168. * Resolve references to lookup tables, e.g., in RuleLookup, to the lookup tables themselves.
  169. * @param lookupTables map from lookup table identifers, e.g. "lu4", to lookup tables
  170. */
  171. public void resolveLookupReferences ( Map/*<String,GlyphTable.LookupTable>*/ lookupTables ) {
  172. }
  173. /**
  174. * Map glyph id to coverage index.
  175. * @param gid glyph id
  176. * @return the corresponding coverage index of the specified glyph id
  177. */
  178. public int getCoverageIndex ( int gid ) {
  179. if ( mapping instanceof GlyphCoverageMapping ) {
  180. return ( (GlyphCoverageMapping) mapping ) .getCoverageIndex ( gid );
  181. } else {
  182. return -1;
  183. }
  184. }
  185. /**
  186. * Map glyph id to coverage index.
  187. * @return the corresponding coverage index of the specified glyph id
  188. */
  189. public int getCoverageSize() {
  190. if ( mapping instanceof GlyphCoverageMapping ) {
  191. return ( (GlyphCoverageMapping) mapping ) .getCoverageSize();
  192. } else {
  193. return 0;
  194. }
  195. }
  196. /** {@inheritDoc} */
  197. public int hashCode() {
  198. int hc = sequence;
  199. hc = ( hc * 3 ) + ( lookupId.hashCode() ^ hc );
  200. return hc;
  201. }
  202. /**
  203. * {@inheritDoc}
  204. * @return true if the lookup identifier and the sequence number of the specified subtable is the same
  205. * as the lookup identifier and sequence number of this subtable
  206. */
  207. public boolean equals ( Object o ) {
  208. if ( o instanceof GlyphSubtable ) {
  209. GlyphSubtable st = (GlyphSubtable) o;
  210. return lookupId.equals ( st.lookupId ) && ( sequence == st.sequence );
  211. } else {
  212. return false;
  213. }
  214. }
  215. /**
  216. * {@inheritDoc}
  217. * @return the result of comparing the lookup identifier and the sequence number of the specified subtable with
  218. * the lookup identifier and sequence number of this subtable
  219. */
  220. public int compareTo ( Object o ) {
  221. int d;
  222. if ( o instanceof GlyphSubtable ) {
  223. GlyphSubtable st = (GlyphSubtable) o;
  224. if ( ( d = lookupId.compareTo ( st.lookupId ) ) == 0 ) {
  225. if ( sequence < st.sequence ) {
  226. d = -1;
  227. } else if ( sequence > st.sequence ) {
  228. d = 1;
  229. }
  230. }
  231. } else {
  232. d = -1;
  233. }
  234. return d;
  235. }
  236. /**
  237. * Determine if any of the specified subtables uses reverse scanning.
  238. * @param subtables array of glyph subtables
  239. * @return true if any of the specified subtables uses reverse scanning.
  240. */
  241. public static boolean usesReverseScan ( GlyphSubtable[] subtables ) {
  242. if ( ( subtables == null ) || ( subtables.length == 0 ) ) {
  243. return false;
  244. } else {
  245. for ( int i = 0, n = subtables.length; i < n; i++ ) {
  246. if ( subtables[i].usesReverseScan() ) {
  247. return true;
  248. }
  249. }
  250. return false;
  251. }
  252. }
  253. /**
  254. * Determine consistent flags for a set of subtables.
  255. * @param subtables array of glyph subtables
  256. * @return consistent flags
  257. * @throws IllegalStateException if inconsistent flags
  258. */
  259. public static int getFlags ( GlyphSubtable[] subtables ) throws IllegalStateException {
  260. if ( ( subtables == null ) || ( subtables.length == 0 ) ) {
  261. return 0;
  262. } else {
  263. int flags = 0;
  264. // obtain first non-zero value of flags in array of subtables
  265. for ( int i = 0, n = subtables.length; i < n; i++ ) {
  266. int f = subtables[i].getFlags();
  267. if ( flags == 0 ) {
  268. flags = f;
  269. break;
  270. }
  271. }
  272. // enforce flag consistency
  273. for ( int i = 0, n = subtables.length; i < n; i++ ) {
  274. int f = subtables[i].getFlags();
  275. if ( f != flags ) {
  276. throw new IllegalStateException ( "inconsistent lookup flags " + f + ", expected " + flags );
  277. }
  278. }
  279. return flags | ( usesReverseScan ( subtables ) ? LF_INTERNAL_USE_REVERSE_SCAN : 0 );
  280. }
  281. }
  282. }