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.

FontReader.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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.fonts;
  19. //Java
  20. import java.io.IOException;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import javax.xml.parsers.SAXParserFactory;
  25. import org.xml.sax.Attributes;
  26. import org.xml.sax.InputSource;
  27. import org.xml.sax.Locator;
  28. import org.xml.sax.SAXException;
  29. import org.xml.sax.XMLReader;
  30. import org.xml.sax.helpers.DefaultHandler;
  31. import org.apache.fop.apps.FOPException;
  32. import org.apache.fop.fonts.apps.TTFReader;
  33. /**
  34. * Class for reading a metric.xml file and creating a font object.
  35. * Typical usage:
  36. * <pre>
  37. * FontReader reader = new FontReader(<path til metrics.xml>);
  38. * reader.setFontEmbedPath(<path to a .ttf or .pfb file or null to diable embedding>);
  39. * reader.useKerning(true);
  40. * Font f = reader.getFont();
  41. * </pre>
  42. */
  43. public class FontReader extends DefaultHandler {
  44. private Locator locator = null;
  45. private boolean isCID = false;
  46. private CustomFont returnFont = null;
  47. private MultiByteFont multiFont = null;
  48. private SingleByteFont singleFont = null;
  49. private StringBuffer text = new StringBuffer();
  50. private List cidWidths = null;
  51. private int cidWidthIndex = 0;
  52. private Map currentKerning = null;
  53. private List bfranges = null;
  54. private void createFont(InputSource source) throws FOPException {
  55. XMLReader parser = null;
  56. try {
  57. final SAXParserFactory factory = javax.xml.parsers.SAXParserFactory.newInstance();
  58. factory.setNamespaceAware(true);
  59. parser = factory.newSAXParser().getXMLReader();
  60. } catch (Exception e) {
  61. throw new FOPException(e);
  62. }
  63. if (parser == null) {
  64. throw new FOPException("Unable to create SAX parser");
  65. }
  66. try {
  67. parser.setFeature("http://xml.org/sax/features/namespace-prefixes",
  68. false);
  69. } catch (SAXException e) {
  70. throw new FOPException("You need a SAX parser which supports SAX version 2",
  71. e);
  72. }
  73. parser.setContentHandler(this);
  74. try {
  75. parser.parse(source);
  76. } catch (SAXException e) {
  77. throw new FOPException(e);
  78. } catch (IOException e) {
  79. throw new FOPException(e);
  80. }
  81. }
  82. /**
  83. * Sets the path to embed a font. A null value disables font embedding.
  84. * @param path URI for the embeddable file
  85. */
  86. public void setFontEmbedPath(String path) {
  87. returnFont.setEmbedFileName(path);
  88. }
  89. /**
  90. * Enable/disable use of kerning for the font
  91. * @param enabled true to enable kerning, false to disable
  92. */
  93. public void setKerningEnabled(boolean enabled) {
  94. returnFont.setKerningEnabled(enabled);
  95. }
  96. /**
  97. * Sets the font resolver. Needed for URI resolution.
  98. * @param resolver the font resolver
  99. */
  100. public void setResolver(FontResolver resolver) {
  101. returnFont.setResolver(resolver);
  102. }
  103. /**
  104. * Get the generated font object
  105. * @return the font
  106. */
  107. public Typeface getFont() {
  108. return returnFont;
  109. }
  110. /**
  111. * Construct a FontReader object from a path to a metric.xml file
  112. * and read metric data
  113. * @param source Source of the font metric file
  114. * @throws FOPException if loading the font fails
  115. */
  116. public FontReader(InputSource source) throws FOPException {
  117. createFont(source);
  118. }
  119. /**
  120. * {@inheritDoc}
  121. */
  122. public void startDocument() {
  123. }
  124. /**
  125. * {@inheritDoc}
  126. */
  127. public void setDocumentLocator(Locator locator) {
  128. this.locator = locator;
  129. }
  130. /**
  131. * {@inheritDoc}
  132. */
  133. public void startElement(String uri, String localName, String qName,
  134. Attributes attributes) throws SAXException {
  135. if (localName.equals("font-metrics")) {
  136. if ("TYPE0".equals(attributes.getValue("type"))) {
  137. multiFont = new MultiByteFont();
  138. returnFont = multiFont;
  139. isCID = true;
  140. TTFReader.checkMetricsVersion(attributes);
  141. } else if ("TRUETYPE".equals(attributes.getValue("type"))) {
  142. singleFont = new SingleByteFont();
  143. singleFont.setFontType(FontType.TRUETYPE);
  144. returnFont = singleFont;
  145. isCID = false;
  146. TTFReader.checkMetricsVersion(attributes);
  147. } else {
  148. singleFont = new SingleByteFont();
  149. singleFont.setFontType(FontType.TYPE1);
  150. returnFont = singleFont;
  151. isCID = false;
  152. }
  153. } else if ("embed".equals(localName)) {
  154. returnFont.setEmbedFileName(attributes.getValue("file"));
  155. returnFont.setEmbedResourceName(attributes.getValue("class"));
  156. } else if ("cid-widths".equals(localName)) {
  157. cidWidthIndex = getInt(attributes.getValue("start-index"));
  158. cidWidths = new java.util.ArrayList();
  159. } else if ("kerning".equals(localName)) {
  160. currentKerning = new java.util.HashMap();
  161. returnFont.putKerningEntry(new Integer(attributes.getValue("kpx1")),
  162. currentKerning);
  163. } else if ("bfranges".equals(localName)) {
  164. bfranges = new java.util.ArrayList();
  165. } else if ("bf".equals(localName)) {
  166. BFEntry entry = new BFEntry(getInt(attributes.getValue("us")),
  167. getInt(attributes.getValue("ue")),
  168. getInt(attributes.getValue("gi")));
  169. bfranges.add(entry);
  170. } else if ("wx".equals(localName)) {
  171. cidWidths.add(new Integer(attributes.getValue("w")));
  172. } else if ("widths".equals(localName)) {
  173. //singleFont.width = new int[256];
  174. } else if ("char".equals(localName)) {
  175. try {
  176. singleFont.setWidth(Integer.parseInt(attributes.getValue("idx")),
  177. Integer.parseInt(attributes.getValue("wdt")));
  178. } catch (NumberFormatException ne) {
  179. throw new SAXException("Malformed width in metric file: "
  180. + ne.getMessage(), ne);
  181. }
  182. } else if ("pair".equals(localName)) {
  183. currentKerning.put(new Integer(attributes.getValue("kpx2")),
  184. new Integer(attributes.getValue("kern")));
  185. }
  186. }
  187. private int getInt(String str) throws SAXException {
  188. int ret = 0;
  189. try {
  190. ret = Integer.parseInt(str);
  191. } catch (Exception e) {
  192. throw new SAXException("Error while parsing integer value: " + str, e);
  193. }
  194. return ret;
  195. }
  196. /**
  197. * {@inheritDoc}
  198. */
  199. public void endElement(String uri, String localName, String qName) throws SAXException {
  200. String content = text.toString().trim();
  201. if ("font-name".equals(localName)) {
  202. returnFont.setFontName(content);
  203. } else if ("full-name".equals(localName)) {
  204. returnFont.setFullName(content);
  205. } else if ("family-name".equals(localName)) {
  206. Set s = new java.util.HashSet();
  207. s.add(content);
  208. returnFont.setFamilyNames(s);
  209. } else if ("ttc-name".equals(localName) && isCID) {
  210. multiFont.setTTCName(content);
  211. } else if ("encoding".equals(localName)) {
  212. if (singleFont != null && singleFont.getFontType() == FontType.TYPE1) {
  213. singleFont.setEncoding(content);
  214. }
  215. } else if ("cap-height".equals(localName)) {
  216. returnFont.setCapHeight(getInt(content));
  217. } else if ("x-height".equals(localName)) {
  218. returnFont.setXHeight(getInt(content));
  219. } else if ("ascender".equals(localName)) {
  220. returnFont.setAscender(getInt(content));
  221. } else if ("descender".equals(localName)) {
  222. returnFont.setDescender(getInt(content));
  223. } else if ("left".equals(localName)) {
  224. int[] bbox = returnFont.getFontBBox();
  225. bbox[0] = getInt(content);
  226. returnFont.setFontBBox(bbox);
  227. } else if ("bottom".equals(localName)) {
  228. int[] bbox = returnFont.getFontBBox();
  229. bbox[1] = getInt(content);
  230. returnFont.setFontBBox(bbox);
  231. } else if ("right".equals(localName)) {
  232. int[] bbox = returnFont.getFontBBox();
  233. bbox[2] = getInt(content);
  234. returnFont.setFontBBox(bbox);
  235. } else if ("top".equals(localName)) {
  236. int[] bbox = returnFont.getFontBBox();
  237. bbox[3] = getInt(content);
  238. returnFont.setFontBBox(bbox);
  239. } else if ("first-char".equals(localName)) {
  240. returnFont.setFirstChar(getInt(content));
  241. } else if ("last-char".equals(localName)) {
  242. returnFont.setLastChar(getInt(content));
  243. } else if ("flags".equals(localName)) {
  244. returnFont.setFlags(getInt(content));
  245. } else if ("stemv".equals(localName)) {
  246. returnFont.setStemV(getInt(content));
  247. } else if ("italic-angle".equals(localName)) {
  248. returnFont.setItalicAngle(getInt(content));
  249. } else if ("missing-width".equals(localName)) {
  250. returnFont.setMissingWidth(getInt(content));
  251. } else if ("cid-type".equals(localName)) {
  252. multiFont.setCIDType(CIDFontType.byName(content));
  253. } else if ("default-width".equals(localName)) {
  254. multiFont.setDefaultWidth(getInt(content));
  255. } else if ("cid-widths".equals(localName)) {
  256. int[] wds = new int[cidWidths.size()];
  257. int j = 0;
  258. for (int count = 0; count < cidWidths.size(); count++) {
  259. Integer i = (Integer)cidWidths.get(count);
  260. wds[j++] = i.intValue();
  261. }
  262. //multiFont.addCIDWidthEntry(cidWidthIndex, wds);
  263. multiFont.setWidthArray(wds);
  264. } else if ("bfranges".equals(localName)) {
  265. multiFont.setBFEntries((BFEntry[])bfranges.toArray(new BFEntry[0]));
  266. }
  267. text.setLength(0); //Reset text buffer (see characters())
  268. }
  269. /**
  270. * {@inheritDoc}
  271. */
  272. public void characters(char[] ch, int start, int length) {
  273. text.append(ch, start, length);
  274. }
  275. }