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.

LazyFont.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.net.URI;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import org.xml.sax.InputSource;
  25. import org.apache.commons.logging.Log;
  26. import org.apache.commons.logging.LogFactory;
  27. import org.apache.fop.apps.FOPException;
  28. import org.apache.fop.apps.io.InternalResourceResolver;
  29. import org.apache.fop.complexscripts.fonts.Positionable;
  30. import org.apache.fop.complexscripts.fonts.Substitutable;
  31. /**
  32. * This class is used to defer the loading of a font until it is really used.
  33. */
  34. public class LazyFont extends Typeface implements FontDescriptor, Substitutable, Positionable {
  35. private static Log log = LogFactory.getLog(LazyFont.class);
  36. private final URI metricsURI;
  37. private final URI fontEmbedURI;
  38. private final boolean useKerning;
  39. private final boolean useAdvanced;
  40. private final EncodingMode encodingMode;
  41. private EmbeddingMode embeddingMode;
  42. private final String subFontName;
  43. private final boolean embedded;
  44. private final InternalResourceResolver resourceResolver;
  45. private boolean isMetricsLoaded;
  46. private Typeface realFont;
  47. private FontDescriptor realFontDescriptor;
  48. /**
  49. * Main constructor
  50. * @param fontInfo the font info to embed
  51. * @param resourceResolver the font resolver to handle font URIs
  52. */
  53. public LazyFont(EmbedFontInfo fontInfo, InternalResourceResolver resourceResolver,
  54. boolean useComplexScripts) {
  55. this.metricsURI = fontInfo.getMetricsURI();
  56. this.fontEmbedURI = fontInfo.getEmbedURI();
  57. this.useKerning = fontInfo.getKerning();
  58. if (resourceResolver != null) {
  59. this.useAdvanced = useComplexScripts;
  60. } else {
  61. this.useAdvanced = fontInfo.getAdvanced();
  62. }
  63. this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode()
  64. : EncodingMode.AUTO;
  65. this.embeddingMode = fontInfo.getEmbeddingMode() != null ? fontInfo.getEmbeddingMode()
  66. : EmbeddingMode.AUTO;
  67. this.subFontName = fontInfo.getSubFontName();
  68. this.embedded = fontInfo.isEmbedded();
  69. this.resourceResolver = resourceResolver;
  70. }
  71. /** {@inheritDoc} */
  72. public String toString() {
  73. StringBuffer sbuf = new StringBuffer(super.toString());
  74. sbuf.append('{');
  75. sbuf.append("metrics-url=" + metricsURI);
  76. sbuf.append(",embed-url=" + fontEmbedURI);
  77. sbuf.append(",kerning=" + useKerning);
  78. sbuf.append(",advanced=" + useAdvanced);
  79. sbuf.append('}');
  80. return sbuf.toString();
  81. }
  82. private void load(boolean fail) {
  83. if (!isMetricsLoaded) {
  84. try {
  85. if (metricsURI != null) {
  86. /**@todo Possible thread problem here */
  87. FontReader reader = null;
  88. InputStream in = resourceResolver.getResource(metricsURI);
  89. InputSource src = new InputSource(in);
  90. src.setSystemId(metricsURI.toASCIIString());
  91. reader = new FontReader(src, resourceResolver);
  92. reader.setKerningEnabled(useKerning);
  93. reader.setAdvancedEnabled(useAdvanced);
  94. if (this.embedded) {
  95. reader.setFontEmbedURI(fontEmbedURI);
  96. }
  97. realFont = reader.getFont();
  98. } else {
  99. if (fontEmbedURI == null) {
  100. throw new RuntimeException("Cannot load font. No font URIs available.");
  101. }
  102. realFont = FontLoader.loadFont(fontEmbedURI, subFontName, embedded,
  103. embeddingMode, encodingMode, useKerning, useAdvanced, resourceResolver);
  104. }
  105. if (realFont instanceof FontDescriptor) {
  106. realFontDescriptor = (FontDescriptor) realFont;
  107. }
  108. } catch (FOPException fopex) {
  109. log.error("Failed to read font metrics file " + metricsURI, fopex);
  110. if (fail) {
  111. throw new RuntimeException(fopex);
  112. }
  113. } catch (IOException ioex) {
  114. log.error("Failed to read font metrics file " + metricsURI, ioex);
  115. if (fail) {
  116. throw new RuntimeException(ioex);
  117. }
  118. }
  119. realFont.setEventListener(this.eventListener);
  120. isMetricsLoaded = true;
  121. }
  122. }
  123. /**
  124. * Gets the real font.
  125. * @return the real font
  126. */
  127. public Typeface getRealFont() {
  128. load(false);
  129. return realFont;
  130. }
  131. // ---- Font ----
  132. /** {@inheritDoc} */
  133. public String getEncodingName() {
  134. load(true);
  135. return realFont.getEncodingName();
  136. }
  137. /**
  138. * {@inheritDoc}
  139. */
  140. public char mapChar(char c) {
  141. load(true);
  142. return realFont.mapChar(c);
  143. }
  144. /**
  145. * {@inheritDoc}
  146. */
  147. public boolean hadMappingOperations() {
  148. load(true);
  149. return realFont.hadMappingOperations();
  150. }
  151. /**
  152. * {@inheritDoc}
  153. */
  154. public boolean hasChar(char c) {
  155. load(true);
  156. return realFont.hasChar(c);
  157. }
  158. /**
  159. * {@inheritDoc}
  160. */
  161. public boolean isMultiByte() {
  162. load(true);
  163. return realFont.isMultiByte();
  164. }
  165. // ---- FontMetrics interface ----
  166. /** {@inheritDoc} */
  167. public String getFontName() {
  168. load(true);
  169. return realFont.getFontName();
  170. }
  171. /** {@inheritDoc} */
  172. public String getEmbedFontName() {
  173. load(true);
  174. return realFont.getEmbedFontName();
  175. }
  176. /** {@inheritDoc} */
  177. public String getFullName() {
  178. load(true);
  179. return realFont.getFullName();
  180. }
  181. /** {@inheritDoc} */
  182. public Set<String> getFamilyNames() {
  183. load(true);
  184. return realFont.getFamilyNames();
  185. }
  186. /**
  187. * {@inheritDoc}
  188. */
  189. public int getMaxAscent(int size) {
  190. load(true);
  191. return realFont.getMaxAscent(size);
  192. }
  193. /**
  194. * {@inheritDoc}
  195. */
  196. public int getAscender(int size) {
  197. load(true);
  198. return realFont.getAscender(size);
  199. }
  200. /**
  201. * {@inheritDoc}
  202. */
  203. public int getCapHeight(int size) {
  204. load(true);
  205. return realFont.getCapHeight(size);
  206. }
  207. /**
  208. * {@inheritDoc}
  209. */
  210. public int getDescender(int size) {
  211. load(true);
  212. return realFont.getDescender(size);
  213. }
  214. /**
  215. * {@inheritDoc}
  216. */
  217. public int getXHeight(int size) {
  218. load(true);
  219. return realFont.getXHeight(size);
  220. }
  221. /**
  222. * {@inheritDoc}
  223. */
  224. public int getWidth(int i, int size) {
  225. load(true);
  226. return realFont.getWidth(i, size);
  227. }
  228. /**
  229. * {@inheritDoc}
  230. */
  231. public int[] getWidths() {
  232. load(true);
  233. return realFont.getWidths();
  234. }
  235. /**
  236. * {@inheritDoc}
  237. */
  238. public boolean hasKerningInfo() {
  239. load(true);
  240. return realFont.hasKerningInfo();
  241. }
  242. /**
  243. * {@inheritDoc}
  244. */
  245. public Map<Integer, Map<Integer, Integer>> getKerningInfo() {
  246. load(true);
  247. return realFont.getKerningInfo();
  248. }
  249. // ---- FontDescriptor interface ----
  250. /**
  251. * {@inheritDoc}
  252. */
  253. public int getCapHeight() {
  254. load(true);
  255. return realFontDescriptor.getCapHeight();
  256. }
  257. /**
  258. * {@inheritDoc}
  259. */
  260. public int getDescender() {
  261. load(true);
  262. return realFontDescriptor.getDescender();
  263. }
  264. /**
  265. * {@inheritDoc}
  266. */
  267. public int getAscender() {
  268. load(true);
  269. return realFontDescriptor.getAscender();
  270. }
  271. /** {@inheritDoc} */
  272. public int getFlags() {
  273. load(true);
  274. return realFontDescriptor.getFlags();
  275. }
  276. /** {@inheritDoc} */
  277. public boolean isSymbolicFont() {
  278. load(true);
  279. return realFontDescriptor.isSymbolicFont();
  280. }
  281. /**
  282. * {@inheritDoc}
  283. */
  284. public int[] getFontBBox() {
  285. load(true);
  286. return realFontDescriptor.getFontBBox();
  287. }
  288. /**
  289. * {@inheritDoc}
  290. */
  291. public int getItalicAngle() {
  292. load(true);
  293. return realFontDescriptor.getItalicAngle();
  294. }
  295. /**
  296. * {@inheritDoc}
  297. */
  298. public int getStemV() {
  299. load(true);
  300. return realFontDescriptor.getStemV();
  301. }
  302. /**
  303. * {@inheritDoc}
  304. */
  305. public FontType getFontType() {
  306. load(true);
  307. return realFontDescriptor.getFontType();
  308. }
  309. /**
  310. * {@inheritDoc}
  311. */
  312. public boolean isEmbeddable() {
  313. load(true);
  314. return realFontDescriptor.isEmbeddable();
  315. }
  316. /**
  317. * {@inheritDoc}
  318. */
  319. public boolean performsSubstitution() {
  320. load(true);
  321. if ( realFontDescriptor instanceof Substitutable ) {
  322. return ((Substitutable)realFontDescriptor).performsSubstitution();
  323. } else {
  324. return false;
  325. }
  326. }
  327. /**
  328. * {@inheritDoc}
  329. */
  330. public CharSequence performSubstitution ( CharSequence cs, String script, String language ) {
  331. load(true);
  332. if ( realFontDescriptor instanceof Substitutable ) {
  333. return ((Substitutable)realFontDescriptor).performSubstitution(cs, script, language);
  334. } else {
  335. return cs;
  336. }
  337. }
  338. /**
  339. * {@inheritDoc}
  340. */
  341. public CharSequence reorderCombiningMarks
  342. ( CharSequence cs, int[][] gpa, String script, String language ) {
  343. load(true);
  344. if ( realFontDescriptor instanceof Substitutable ) {
  345. return ((Substitutable)realFontDescriptor)
  346. .reorderCombiningMarks(cs, gpa, script, language);
  347. } else {
  348. return cs;
  349. }
  350. }
  351. /**
  352. * {@inheritDoc}
  353. */
  354. public boolean performsPositioning() {
  355. load(true);
  356. if ( realFontDescriptor instanceof Positionable ) {
  357. return ((Positionable)realFontDescriptor).performsPositioning();
  358. } else {
  359. return false;
  360. }
  361. }
  362. /**
  363. * {@inheritDoc}
  364. */
  365. public int[][]
  366. performPositioning ( CharSequence cs, String script, String language, int fontSize ) {
  367. load(true);
  368. if ( realFontDescriptor instanceof Positionable ) {
  369. return ((Positionable)realFontDescriptor)
  370. .performPositioning(cs, script, language, fontSize);
  371. } else {
  372. return null;
  373. }
  374. }
  375. /**
  376. * {@inheritDoc}
  377. */
  378. public int[][]
  379. performPositioning ( CharSequence cs, String script, String language ) {
  380. load(true);
  381. if ( realFontDescriptor instanceof Positionable ) {
  382. return ((Positionable)realFontDescriptor)
  383. .performPositioning(cs, script, language);
  384. } else {
  385. return null;
  386. }
  387. }
  388. /**
  389. * {@inheritDoc}
  390. */
  391. public boolean isSubsetEmbedded() {
  392. load(true);
  393. return realFont.isMultiByte();
  394. }
  395. }