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.

GlyphCoverageTable.java 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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.util.Arrays;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24. // CSOFF: LineLengthCheck
  25. /**
  26. * <p>.Base class implementation of glyph coverage table.</p>
  27. *
  28. * <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
  29. */
  30. public final class GlyphCoverageTable extends GlyphMappingTable implements GlyphCoverageMapping {
  31. /* logging instance */
  32. private static final Log log = LogFactory.getLog(GlyphCoverageTable.class);
  33. /** empty mapping table */
  34. public static final int GLYPH_COVERAGE_TYPE_EMPTY = GLYPH_MAPPING_TYPE_EMPTY;
  35. /** mapped mapping table */
  36. public static final int GLYPH_COVERAGE_TYPE_MAPPED = GLYPH_MAPPING_TYPE_MAPPED;
  37. /** range based mapping table */
  38. public static final int GLYPH_COVERAGE_TYPE_RANGE = GLYPH_MAPPING_TYPE_RANGE;
  39. private GlyphCoverageMapping cm;
  40. private GlyphCoverageTable(GlyphCoverageMapping cm) {
  41. assert cm != null;
  42. assert cm instanceof GlyphMappingTable;
  43. this.cm = cm;
  44. }
  45. /** {@inheritDoc} */
  46. public int getType() {
  47. return ((GlyphMappingTable) cm) .getType();
  48. }
  49. /** {@inheritDoc} */
  50. public List getEntries() {
  51. return ((GlyphMappingTable) cm) .getEntries();
  52. }
  53. /** {@inheritDoc} */
  54. public int getCoverageSize() {
  55. return cm.getCoverageSize();
  56. }
  57. /** {@inheritDoc} */
  58. public int getCoverageIndex(int gid) {
  59. return cm.getCoverageIndex(gid);
  60. }
  61. /**
  62. * Create glyph coverage table.
  63. * @param entries list of mapped or ranged coverage entries, or null or empty list
  64. * @return a new covera table instance
  65. */
  66. public static GlyphCoverageTable createCoverageTable(List entries) {
  67. GlyphCoverageMapping cm;
  68. if ((entries == null) || (entries.size() == 0)) {
  69. cm = new EmptyCoverageTable(entries);
  70. } else if (isMappedCoverage(entries)) {
  71. cm = new MappedCoverageTable(entries);
  72. } else if (isRangeCoverage(entries)) {
  73. cm = new RangeCoverageTable(entries);
  74. } else {
  75. cm = null;
  76. }
  77. assert cm != null : "unknown coverage type";
  78. return new GlyphCoverageTable(cm);
  79. }
  80. private static boolean isMappedCoverage(List entries) {
  81. if ((entries == null) || (entries.size() == 0)) {
  82. return false;
  83. } else {
  84. for (Iterator it = entries.iterator(); it.hasNext();) {
  85. Object o = it.next();
  86. if (!(o instanceof Integer)) {
  87. return false;
  88. }
  89. }
  90. return true;
  91. }
  92. }
  93. private static boolean isRangeCoverage(List entries) {
  94. if ((entries == null) || (entries.size() == 0)) {
  95. return false;
  96. } else {
  97. for (Iterator it = entries.iterator(); it.hasNext();) {
  98. Object o = it.next();
  99. if (!(o instanceof MappingRange)) {
  100. return false;
  101. }
  102. }
  103. return true;
  104. }
  105. }
  106. private static class EmptyCoverageTable extends GlyphMappingTable.EmptyMappingTable implements GlyphCoverageMapping {
  107. public EmptyCoverageTable(List entries) {
  108. super(entries);
  109. }
  110. /** {@inheritDoc} */
  111. public int getCoverageSize() {
  112. return 0;
  113. }
  114. /** {@inheritDoc} */
  115. public int getCoverageIndex(int gid) {
  116. return -1;
  117. }
  118. }
  119. private static class MappedCoverageTable extends GlyphMappingTable.MappedMappingTable implements GlyphCoverageMapping {
  120. private int[] map;
  121. public MappedCoverageTable(List entries) {
  122. populate(entries);
  123. }
  124. /** {@inheritDoc} */
  125. public List getEntries() {
  126. List entries = new java.util.ArrayList();
  127. if (map != null) {
  128. for (int i = 0, n = map.length; i < n; i++) {
  129. entries.add(map[i]);
  130. }
  131. }
  132. return entries;
  133. }
  134. /** {@inheritDoc} */
  135. public int getMappingSize() {
  136. return (map != null) ? map.length : 0;
  137. }
  138. public int getMappedIndex(int gid) {
  139. int i;
  140. if ((i = Arrays.binarySearch(map, gid)) >= 0) {
  141. return i;
  142. } else {
  143. return -1;
  144. }
  145. }
  146. /** {@inheritDoc} */
  147. public int getCoverageSize() {
  148. return getMappingSize();
  149. }
  150. /** {@inheritDoc} */
  151. public int getCoverageIndex(int gid) {
  152. return getMappedIndex(gid);
  153. }
  154. private void populate(List entries) {
  155. int i = 0;
  156. int skipped = 0;
  157. int n = entries.size();
  158. int gidMax = -1;
  159. int[] map = new int [ n ];
  160. for (Iterator it = entries.iterator(); it.hasNext();) {
  161. Object o = it.next();
  162. if (o instanceof Integer) {
  163. int gid = (Integer) o;
  164. if ((gid >= 0) && (gid < 65536)) {
  165. if (gid > gidMax) {
  166. map [ i++ ] = gidMax = gid;
  167. } else {
  168. log.info("ignoring out of order or duplicate glyph index: " + gid);
  169. skipped++;
  170. }
  171. } else {
  172. throw new AdvancedTypographicTableFormatException("illegal glyph index: " + gid);
  173. }
  174. } else {
  175. throw new AdvancedTypographicTableFormatException("illegal coverage entry, must be Integer: " + o);
  176. }
  177. }
  178. assert (i + skipped) == n;
  179. assert this.map == null;
  180. this.map = map;
  181. }
  182. /** {@inheritDoc} */
  183. public String toString() {
  184. StringBuffer sb = new StringBuffer();
  185. sb.append('{');
  186. for (int i = 0, n = map.length; i < n; i++) {
  187. if (i > 0) {
  188. sb.append(',');
  189. }
  190. sb.append(Integer.toString(map [ i ]));
  191. }
  192. sb.append('}');
  193. return sb.toString();
  194. }
  195. }
  196. private static class RangeCoverageTable extends GlyphMappingTable.RangeMappingTable implements GlyphCoverageMapping {
  197. public RangeCoverageTable(List entries) {
  198. super(entries);
  199. }
  200. /** {@inheritDoc} */
  201. public int getMappedIndex(int gid, int s, int m) {
  202. return m + gid - s;
  203. }
  204. /** {@inheritDoc} */
  205. public int getCoverageSize() {
  206. return getMappingSize();
  207. }
  208. /** {@inheritDoc} */
  209. public int getCoverageIndex(int gid) {
  210. return getMappedIndex(gid);
  211. }
  212. }
  213. }