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

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