Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

Font.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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.util.Collections;
  20. import java.util.List;
  21. import java.util.Map;
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24. import org.apache.fop.complexscripts.fonts.Positionable;
  25. import org.apache.fop.complexscripts.fonts.Substitutable;
  26. /**
  27. * This class holds font state information and provides access to the font
  28. * metrics.
  29. */
  30. public class Font implements Substitutable, Positionable {
  31. /** Extra Bold font weight */
  32. public static final int WEIGHT_EXTRA_BOLD = 800;
  33. /** Bold font weight */
  34. public static final int WEIGHT_BOLD = 700;
  35. /** Normal font weight */
  36. public static final int WEIGHT_NORMAL = 400;
  37. /** Light font weight */
  38. public static final int WEIGHT_LIGHT = 200;
  39. /** Normal font style */
  40. public static final String STYLE_NORMAL = "normal";
  41. /** Italic font style */
  42. public static final String STYLE_ITALIC = "italic";
  43. /** Oblique font style */
  44. public static final String STYLE_OBLIQUE = "oblique";
  45. /** Inclined font style */
  46. public static final String STYLE_INCLINED = "inclined";
  47. /** Default selection priority */
  48. public static final int PRIORITY_DEFAULT = 0;
  49. /** Default fallback key */
  50. public static final FontTriplet DEFAULT_FONT = new FontTriplet(
  51. "any", STYLE_NORMAL, WEIGHT_NORMAL, PRIORITY_DEFAULT);
  52. /** logger */
  53. private static Log log = LogFactory.getLog(Font.class);
  54. private final String fontName;
  55. private final FontTriplet triplet;
  56. private final int fontSize;
  57. /**
  58. * normal or small-caps font
  59. */
  60. //private int fontVariant;
  61. private final FontMetrics metric;
  62. /**
  63. * Main constructor
  64. * @param key key of the font
  65. * @param triplet the font triplet that was used to lookup this font (may be null)
  66. * @param met font metrics
  67. * @param fontSize font size
  68. */
  69. public Font(String key, FontTriplet triplet, FontMetrics met, int fontSize) {
  70. this.fontName = key;
  71. this.triplet = triplet;
  72. this.metric = met;
  73. this.fontSize = fontSize;
  74. }
  75. /**
  76. * Returns the associated font metrics object.
  77. * @return the font metrics
  78. */
  79. public FontMetrics getFontMetrics() {
  80. return this.metric;
  81. }
  82. /**
  83. * Determines whether the font is a multibyte font.
  84. * @return True if it is multibyte
  85. */
  86. public boolean isMultiByte() {
  87. return getFontMetrics().isMultiByte();
  88. }
  89. /**
  90. * Returns the font's ascender.
  91. * @return the ascender
  92. */
  93. public int getAscender() {
  94. return metric.getAscender(fontSize) / 1000;
  95. }
  96. /**
  97. * Returns the font's CapHeight.
  98. * @return the capital height
  99. */
  100. public int getCapHeight() {
  101. return metric.getCapHeight(fontSize) / 1000;
  102. }
  103. /**
  104. * Returns the font's Descender.
  105. * @return the descender
  106. */
  107. public int getDescender() {
  108. return metric.getDescender(fontSize) / 1000;
  109. }
  110. /**
  111. * Returns the font's name.
  112. * @return the font name
  113. */
  114. public String getFontName() {
  115. return fontName;
  116. }
  117. /** @return the font triplet that selected this font */
  118. public FontTriplet getFontTriplet() {
  119. return this.triplet;
  120. }
  121. /**
  122. * Returns the font size
  123. * @return the font size
  124. */
  125. public int getFontSize() {
  126. return fontSize;
  127. }
  128. /**
  129. * Returns the XHeight
  130. * @return the XHeight
  131. */
  132. public int getXHeight() {
  133. return metric.getXHeight(fontSize) / 1000;
  134. }
  135. /** @return true if the font has kerning info */
  136. public boolean hasKerning() {
  137. return metric.hasKerningInfo();
  138. }
  139. /** @return true if the font has feature (i.e., at least one lookup matches) */
  140. public boolean hasFeature(int tableType, String script, String language, String feature) {
  141. return metric.hasFeature(tableType, script, language, feature);
  142. }
  143. /**
  144. * Returns the font's kerning table
  145. * @return the kerning table
  146. */
  147. public Map<Integer, Map<Integer, Integer>> getKerning() {
  148. if (metric.hasKerningInfo()) {
  149. return metric.getKerningInfo();
  150. } else {
  151. return Collections.emptyMap();
  152. }
  153. }
  154. /**
  155. * Returns the amount of kerning between two characters.
  156. *
  157. * The value returned measures in pt. So it is already adjusted for font size.
  158. *
  159. * @param ch1 first character
  160. * @param ch2 second character
  161. * @return the distance to adjust for kerning, 0 if there's no kerning
  162. */
  163. public int getKernValue(char ch1, char ch2) {
  164. Map<Integer, Integer> kernPair = getKerning().get((int) ch1);
  165. if (kernPair != null) {
  166. Integer width = kernPair.get((int) ch2);
  167. if (width != null) {
  168. return width * getFontSize() / 1000;
  169. }
  170. }
  171. return 0;
  172. }
  173. /**
  174. * Returns the amount of kerning between two characters.
  175. *
  176. * The value returned measures in pt. So it is already adjusted for font size.
  177. *
  178. * @param ch1 first character
  179. * @param ch2 second character
  180. * @return the distance to adjust for kerning, 0 if there's no kerning
  181. */
  182. public int getKernValue(int ch1, int ch2) {
  183. // TODO !BMP
  184. if (ch1 > 0x10000) {
  185. return 0;
  186. } else if ((ch1 >= 0xD800) && (ch1 <= 0xE000)) {
  187. return 0;
  188. } else if (ch2 > 0x10000) {
  189. return 0;
  190. } else if ((ch2 >= 0xD800) && (ch2 <= 0xE000)) {
  191. return 0;
  192. } else {
  193. return getKernValue((char) ch1, (char) ch2);
  194. }
  195. }
  196. /**
  197. * Returns the width of a character
  198. * @param charnum character to look up
  199. * @return width of the character
  200. */
  201. public int getWidth(int charnum) {
  202. // returns width of given character number in millipoints
  203. return (metric.getWidth(charnum, fontSize) / 1000);
  204. }
  205. /**
  206. * Map a java character (unicode) to a font character.
  207. * Default uses CodePointMapping.
  208. * @param c character to map
  209. * @return the mapped character
  210. */
  211. public char mapChar(char c) {
  212. if (metric instanceof org.apache.fop.fonts.Typeface) {
  213. return ((org.apache.fop.fonts.Typeface)metric).mapChar(c);
  214. }
  215. // Use default CodePointMapping
  216. char d = CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c);
  217. if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) {
  218. c = d;
  219. } else {
  220. log.warn("Glyph " + (int) c + " not available in font " + fontName);
  221. c = Typeface.NOT_FOUND;
  222. }
  223. return c;
  224. }
  225. /**
  226. * Determines whether this font contains a particular character/glyph.
  227. * @param c character to check
  228. * @return True if the character is supported, Falso otherwise
  229. */
  230. public boolean hasChar(char c) {
  231. if (metric instanceof org.apache.fop.fonts.Typeface) {
  232. return ((org.apache.fop.fonts.Typeface)metric).hasChar(c);
  233. } else {
  234. // Use default CodePointMapping
  235. return (CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c) > 0);
  236. }
  237. }
  238. /**
  239. * {@inheritDoc}
  240. */
  241. @Override
  242. public String toString() {
  243. StringBuffer sbuf = new StringBuffer(super.toString());
  244. sbuf.append('{');
  245. /*
  246. sbuf.append(fontFamily);
  247. sbuf.append(',');*/
  248. sbuf.append(fontName);
  249. sbuf.append(',');
  250. sbuf.append(fontSize);
  251. /*
  252. sbuf.append(',');
  253. sbuf.append(fontStyle);
  254. sbuf.append(',');
  255. sbuf.append(fontWeight);*/
  256. sbuf.append('}');
  257. return sbuf.toString();
  258. }
  259. /**
  260. * Helper method for getting the width of a unicode char
  261. * from the current fontstate.
  262. * This also performs some guessing on widths on various
  263. * versions of space that might not exists in the font.
  264. * @param c character to inspect
  265. * @return the width of the character or -1 if no width available
  266. */
  267. public int getCharWidth(char c) {
  268. int width;
  269. if ((c == '\n') || (c == '\r') || (c == '\t') || (c == '\u00A0')) {
  270. width = getCharWidth(' ');
  271. } else {
  272. if (hasChar(c)) {
  273. int mappedChar = mapChar(c);
  274. width = getWidth(mappedChar);
  275. } else {
  276. width = -1;
  277. }
  278. if (width <= 0) {
  279. // Estimate the width of spaces not represented in
  280. // the font
  281. int em = getFontSize(); //http://en.wikipedia.org/wiki/Em_(typography)
  282. int en = em / 2; //http://en.wikipedia.org/wiki/En_(typography)
  283. if (c == ' ') {
  284. width = em;
  285. } else if (c == '\u2000') {
  286. width = en;
  287. } else if (c == '\u2001') {
  288. width = em;
  289. } else if (c == '\u2002') {
  290. width = em / 2;
  291. } else if (c == '\u2003') {
  292. width = getFontSize();
  293. } else if (c == '\u2004') {
  294. width = em / 3;
  295. } else if (c == '\u2005') {
  296. width = em / 4;
  297. } else if (c == '\u2006') {
  298. width = em / 6;
  299. } else if (c == '\u2007') {
  300. width = getCharWidth('0');
  301. } else if (c == '\u2008') {
  302. width = getCharWidth('.');
  303. } else if (c == '\u2009') {
  304. width = em / 5;
  305. } else if (c == '\u200A') {
  306. width = em / 10;
  307. } else if (c == '\u200B') {
  308. width = 0;
  309. } else if (c == '\u202F') {
  310. width = getCharWidth(' ') / 2;
  311. } else if (c == '\u2060') {
  312. width = 0;
  313. } else if (c == '\u3000') {
  314. width = getCharWidth(' ') * 2;
  315. } else if (c == '\ufeff') {
  316. width = 0;
  317. } else {
  318. //Will be internally replaced by "#" if not found
  319. width = getWidth(mapChar(c));
  320. }
  321. }
  322. }
  323. return width;
  324. }
  325. /**
  326. * Helper method for getting the width of a unicode char
  327. * from the current fontstate.
  328. * This also performs some guessing on widths on various
  329. * versions of space that might not exists in the font.
  330. * @param c character to inspect
  331. * @return the width of the character or -1 if no width available
  332. */
  333. public int getCharWidth(int c) {
  334. if (c < 0x10000) {
  335. return getCharWidth((char) c);
  336. } else {
  337. // TODO !BMP
  338. return -1;
  339. }
  340. }
  341. /**
  342. * Calculates the word width.
  343. * @param word text to get width for
  344. * @return the width of the text
  345. */
  346. public int getWordWidth(String word) {
  347. if (word == null) {
  348. return 0;
  349. }
  350. int wordLength = word.length();
  351. int width = 0;
  352. char[] characters = new char[wordLength];
  353. word.getChars(0, wordLength, characters, 0);
  354. for (int i = 0; i < wordLength; i++) {
  355. width += getCharWidth(characters[i]);
  356. }
  357. return width;
  358. }
  359. /** {@inheritDoc} */
  360. public boolean performsSubstitution() {
  361. if (metric instanceof Substitutable) {
  362. Substitutable s = (Substitutable) metric;
  363. return s.performsSubstitution();
  364. } else {
  365. return false;
  366. }
  367. }
  368. /** {@inheritDoc} */
  369. public CharSequence performSubstitution(CharSequence cs,
  370. String script, String language, List associations, boolean retainControls) {
  371. if (metric instanceof Substitutable) {
  372. Substitutable s = (Substitutable) metric;
  373. return s.performSubstitution(cs, script, language, associations, retainControls);
  374. } else {
  375. throw new UnsupportedOperationException();
  376. }
  377. }
  378. /** {@inheritDoc} */
  379. public CharSequence reorderCombiningMarks(CharSequence cs, int[][] gpa,
  380. String script, String language, List associations) {
  381. if (metric instanceof Substitutable) {
  382. Substitutable s = (Substitutable) metric;
  383. return s.reorderCombiningMarks(cs, gpa, script, language, associations);
  384. } else {
  385. throw new UnsupportedOperationException();
  386. }
  387. }
  388. /** {@inheritDoc} */
  389. public boolean performsPositioning() {
  390. if (metric instanceof Positionable) {
  391. Positionable p = (Positionable) metric;
  392. return p.performsPositioning();
  393. } else {
  394. return false;
  395. }
  396. }
  397. /** {@inheritDoc} */
  398. public int[][] performPositioning(CharSequence cs, String script, String language, int fontSize) {
  399. if (metric instanceof Positionable) {
  400. Positionable p = (Positionable) metric;
  401. return p.performPositioning(cs, script, language, fontSize);
  402. } else {
  403. throw new UnsupportedOperationException();
  404. }
  405. }
  406. /** {@inheritDoc} */
  407. public int[][] performPositioning(CharSequence cs, String script, String language) {
  408. return performPositioning(cs, script, language, fontSize);
  409. }
  410. }