Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

TTFFileTestCase.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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.truetype;
  19. import java.io.ByteArrayInputStream;
  20. import java.io.ByteArrayOutputStream;
  21. import java.io.DataOutputStream;
  22. import java.io.FileInputStream;
  23. import java.io.IOException;
  24. import java.io.InputStream;
  25. import java.util.HashMap;
  26. import java.util.List;
  27. import java.util.Map;
  28. import org.junit.Assert;
  29. import org.junit.Test;
  30. import static org.junit.Assert.assertEquals;
  31. import static org.junit.Assert.assertTrue;
  32. import static org.junit.Assert.fail;
  33. import org.apache.fop.fonts.CMapSegment;
  34. import org.apache.fop.fonts.truetype.OpenFont.PostScriptVersion;
  35. /**
  36. * Class for testing org.apache.fop.fonts.truetype.TTFFile
  37. */
  38. public class TTFFileTestCase {
  39. // We only want to initialize the FontFileReader once (for performance reasons)
  40. /** The truetype font file (DejaVuLGCSerif) */
  41. protected final TTFFile dejavuTTFFile;
  42. /** The FontFileReader for ttfFile (DejaVuLGCSerif) */
  43. protected final FontFileReader dejavuReader;
  44. /** The truetype font file (DroidSansMono) */
  45. protected final TTFFile droidmonoTTFFile;
  46. /** The FontFileReader for ttfFile (DroidSansMono) */
  47. protected final FontFileReader droidmonoReader;
  48. /** The truetype font file (AndroidEmoji) fonr non-BMP codepoints */
  49. protected final TTFFile androidEmojiTTFFile;
  50. /** The FontFileReader for ttfFile (AndroidEmoji) */
  51. protected final FontFileReader androidEmojiReader;
  52. /**
  53. * Constructor initialises FileFontReader to
  54. * @throws IOException exception
  55. */
  56. public TTFFileTestCase() throws IOException {
  57. InputStream dejaStream = new FileInputStream("test/resources/fonts/ttf/DejaVuLGCSerif.ttf");
  58. dejavuTTFFile = new TTFFile();
  59. dejavuReader = new FontFileReader(dejaStream);
  60. String dejavuHeader = OFFontLoader.readHeader(dejavuReader);
  61. dejavuTTFFile.readFont(dejavuReader, dejavuHeader);
  62. dejaStream.close();
  63. InputStream droidStream = new FileInputStream("test/resources/fonts/ttf/DroidSansMono.ttf");
  64. droidmonoTTFFile = new TTFFile();
  65. droidmonoReader = new FontFileReader(droidStream);
  66. String droidmonoHeader = OFFontLoader.readHeader(droidmonoReader);
  67. droidmonoTTFFile.readFont(droidmonoReader, droidmonoHeader);
  68. droidStream.close();
  69. InputStream emojiStream = new FileInputStream("test/resources/fonts/ttf/AndroidEmoji.ttf");
  70. androidEmojiTTFFile = new TTFFile();
  71. androidEmojiReader = new FontFileReader(emojiStream);
  72. String androidEmojiHeader = OFFontLoader.readHeader(androidEmojiReader);
  73. androidEmojiTTFFile.readFont(androidEmojiReader, androidEmojiHeader);
  74. emojiStream.close();
  75. }
  76. /**
  77. * Test convertTTFUnit2PDFUnit() - The units per em retrieved reading the HEAD table from
  78. * the font file. (DroidSansMono has the same units per em as DejaVu so no point testing it)
  79. */
  80. @Test
  81. public void testConvertTTFUnit2PDFUnit() {
  82. // DejaVu has 2048 units per em (PDF works in millipts, thus the 1000)
  83. // test rational number
  84. assertEquals(1000, dejavuTTFFile.convertTTFUnit2PDFUnit(2048));
  85. // test smallest case, this should = 0.488 (round down to 0)
  86. assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(1));
  87. // this should round up, but since it's millipts...
  88. assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(2));
  89. // ensure behaviour is the same for negative numbers
  90. assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-0));
  91. assertEquals(-1000, dejavuTTFFile.convertTTFUnit2PDFUnit(-2048));
  92. assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-1));
  93. assertEquals(0, dejavuTTFFile.convertTTFUnit2PDFUnit(-2));
  94. }
  95. /**
  96. * Test checkTTC()
  97. * @throws IOException exception
  98. */
  99. @Test
  100. public void testCheckTTC() throws IOException {
  101. // DejaVu is not a TTC, thus this returns true
  102. String dejavuHeader = OFFontLoader.readHeader(dejavuReader);
  103. assertTrue(dejavuTTFFile.checkTTC(dejavuHeader, ""));
  104. String droidmonoHeader = OFFontLoader.readHeader(droidmonoReader);
  105. assertTrue(droidmonoTTFFile.checkTTC(droidmonoHeader, ""));
  106. /*
  107. * Cannot reasonably test the rest of this method without an actual truetype collection
  108. * because all methods in FontFileReader are "final" and thus mocking isn't possible.
  109. */
  110. }
  111. /**
  112. * Test getAnsiKerning() - Tests values retrieved from the kern table in the font file.
  113. */
  114. @Test
  115. public void testGetAnsiKerning() {
  116. Map<Integer, Map<Integer, Integer>> ansiKerning = dejavuTTFFile.getAnsiKerning();
  117. if (ansiKerning.isEmpty()) {
  118. fail();
  119. }
  120. Integer k1 = ansiKerning.get((int) 'A').get((int) 'T');
  121. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue());
  122. Integer k2 = ansiKerning.get((int) 'Y').get((int) 'u');
  123. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-178), k2.intValue());
  124. // DroidSansMono doens't have kerning (it's mono-spaced)
  125. ansiKerning = droidmonoTTFFile.getAnsiKerning();
  126. if (!ansiKerning.isEmpty()) {
  127. fail("DroidSansMono shouldn't have any kerning data.");
  128. }
  129. // AndroidEmoji doens't have kerning
  130. ansiKerning = androidEmojiTTFFile.getAnsiKerning();
  131. if (!ansiKerning.isEmpty()) {
  132. fail("AndroidEmoji shouldn't have any kerning data.");
  133. }
  134. }
  135. /**
  136. * Test getCapHeight - there are several paths to test:
  137. * 1) The PCLT table (if present)
  138. * 2) The yMax (3rd) value, for the bounding box, for 'H' in the glyf table.
  139. * if not the above:
  140. * 3) The caps height in the OS/2 table
  141. * Tests values retrieved from analysing the font file.
  142. */
  143. @Test
  144. public void testGetCapHeight() {
  145. // DejaVu doesn't have the PCLT table and so these have to be guessed
  146. // The height is approximated to be the height of the "H" which for
  147. // Deja = 1493 TTFunits
  148. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1493), dejavuTTFFile.getCapHeight());
  149. // DroidSansMono doesn't have a PCLT table either
  150. // height of "H" = 1462
  151. assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1462),
  152. droidmonoTTFFile.getCapHeight());
  153. // AndroidEmoji doesn't have a PCLT table either
  154. // height of "H" = 1462
  155. assertEquals(androidEmojiTTFFile.convertTTFUnit2PDFUnit(1462),
  156. androidEmojiTTFFile.getCapHeight());
  157. }
  158. /**
  159. * Test getCharSetName() - check that it returns "WinAnsiEncoding".
  160. */
  161. @Test
  162. public void testGetCharSetName() {
  163. assertTrue("WinAnsiEncoding".equals(dejavuTTFFile.getCharSetName()));
  164. assertTrue("WinAnsiEncoding".equals(droidmonoTTFFile.getCharSetName()));
  165. //Even though this pass I'm not sure whether is what we want
  166. assertTrue("WinAnsiEncoding".equals(androidEmojiTTFFile.getCharSetName()));
  167. }
  168. /**
  169. * Test getCharWidth() - Test values retrieved from the metrics in the glyf table in
  170. * the font file.
  171. */
  172. @Test
  173. public void testGetCharWidth() {
  174. // Arbitrarily test a few values:
  175. // The width of "H" (Unicode index 0x0048) is 1786
  176. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1786), dejavuTTFFile.getCharWidth(0x48));
  177. // The width of "i" (unicode index 0x0069) is 655 TTFunits
  178. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(655), dejavuTTFFile.getCharWidth(0x69));
  179. // final check, "!" (unicode index 0x0021) is 823 TTFunits
  180. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(823), dejavuTTFFile.getCharWidth(0x21));
  181. // All the glyphs should be the same width in DroidSansMono (mono-spaced)
  182. int charWidth = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229);
  183. for (int i = 0; i < 255; i++) {
  184. assertEquals(charWidth, droidmonoTTFFile.getCharWidth(i));
  185. }
  186. // All the glyphs should be the same width in EmojiAndroid (mono-spaced)
  187. charWidth = androidEmojiTTFFile.convertTTFUnit2PDFUnit(2600);
  188. for (int i = 0; i < 255; i++) {
  189. assertEquals(charWidth, androidEmojiTTFFile.getCharWidth(i));
  190. }
  191. }
  192. /**
  193. * TODO: add implementation to this test
  194. */
  195. @Test
  196. public void testGetCMaps() {
  197. List<CMapSegment> cmaps = androidEmojiTTFFile.getCMaps();
  198. for (CMapSegment seg : cmaps) {
  199. System.out.println(seg.getUnicodeStart() + "-" + seg.getUnicodeEnd() + " -> " + seg.getGlyphStartIndex());
  200. }
  201. }
  202. /**
  203. * Test getFamilyNames() - Test value retrieved from the name table in the font file.
  204. */
  205. @Test
  206. public void testGetFamilyNames() {
  207. assertEquals(1, dejavuTTFFile.getFamilyNames().size());
  208. for (String name : dejavuTTFFile.getFamilyNames()) {
  209. assertEquals("DejaVu LGC Serif", name);
  210. }
  211. assertEquals(1, droidmonoTTFFile.getFamilyNames().size());
  212. for (String name : droidmonoTTFFile.getFamilyNames()) {
  213. assertEquals("Droid Sans Mono", name);
  214. }
  215. assertEquals(1, androidEmojiTTFFile.getFamilyNames().size());
  216. for (String name : androidEmojiTTFFile.getFamilyNames()) {
  217. assertEquals("Android Emoji", name);
  218. }
  219. }
  220. /**
  221. * Test getFirstChar() - TODO: implement a more intelligent test here.
  222. */
  223. @Test
  224. public void testGetFirstChar() {
  225. // Not really sure how to test this intelligently
  226. assertEquals(0, dejavuTTFFile.getFirstChar());
  227. assertEquals(0, droidmonoTTFFile.getFirstChar());
  228. assertEquals(0, androidEmojiTTFFile.getFirstChar());
  229. }
  230. /**
  231. * Test getFlags() - Test values retrieved from the POST table in the font file.
  232. */
  233. @Test
  234. public void testGetFlags() {
  235. /* DejaVu flags are:
  236. * italic angle = 0
  237. * fixed pitch = 0
  238. * has serifs = true (default value; this font doesn't have a PCLT table)
  239. */
  240. int flags = dejavuTTFFile.getFlags();
  241. assertEquals(0, flags & 64); // Italics angle = 0
  242. assertEquals(32, flags & 32); // Adobe standard charset
  243. assertEquals(0, flags & 2); // fixed pitch = 0
  244. assertEquals(1, flags & 1); // has serifs = 1 (true)
  245. /*
  246. * Droid flags are:
  247. * italic angle = 0
  248. * fixed pitch = 1
  249. * has serifs = true (default value; this font doesn't have a PCLT table)
  250. */
  251. flags = droidmonoTTFFile.getFlags();
  252. assertEquals(0, flags & 64);
  253. assertEquals(32, flags & 32);
  254. assertEquals(2, flags & 2);
  255. assertEquals(1, flags & 1);
  256. /*
  257. * Android Emoji flags are:
  258. * italic angle = 0
  259. * fixed pitch = 0
  260. * has serifs = true (default value; this font doesn't have a PCLT table)
  261. */
  262. flags = androidEmojiTTFFile.getFlags();
  263. assertEquals(0, flags & 64);
  264. assertEquals(32, flags & 32);
  265. assertEquals(0, flags & 2);
  266. assertEquals(1, flags & 1);
  267. }
  268. /**
  269. * Test getFontBBox() - Test values retrieved from values in the HEAD table in the font file.
  270. */
  271. @Test
  272. public void testGetFontBBox() {
  273. int[] bBox = dejavuTTFFile.getFontBBox();
  274. /*
  275. * The head table has the following values(DejaVu):
  276. * xmin = -1576, ymin = -710, xmax = 3439, ymax = 2544
  277. */
  278. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-1576), bBox[0]);
  279. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-710), bBox[1]);
  280. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(3439), bBox[2]);
  281. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(2544), bBox[3]);
  282. /*
  283. * The head table has the following values (DroidSansMono):
  284. * xmin = -312, ymin= -555, xmax = 1315, ymax = 2163
  285. */
  286. bBox = droidmonoTTFFile.getFontBBox();
  287. assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-312), bBox[0]);
  288. assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(-555), bBox[1]);
  289. assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1315), bBox[2]);
  290. assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(2163), bBox[3]);
  291. /*
  292. * The head table has the following values (DroidSansMono):
  293. * xMin = -50, yMin = -733, xMax = 2550, yMax = 2181
  294. */
  295. bBox = androidEmojiTTFFile.getFontBBox();
  296. assertEquals(androidEmojiTTFFile.convertTTFUnit2PDFUnit(-50), bBox[0]);
  297. assertEquals(androidEmojiTTFFile.convertTTFUnit2PDFUnit(-733), bBox[1]);
  298. assertEquals(androidEmojiTTFFile.convertTTFUnit2PDFUnit(2550), bBox[2]);
  299. assertEquals(androidEmojiTTFFile.convertTTFUnit2PDFUnit(2181), bBox[3]);
  300. }
  301. /**
  302. * Test getFullName() - Test value retrieved from the name table in the font file.
  303. */
  304. @Test
  305. public void testGetFullName() {
  306. assertEquals("DejaVu LGC Serif", dejavuTTFFile.getFullName());
  307. assertEquals("Droid Sans Mono", droidmonoTTFFile.getFullName());
  308. assertEquals("Android Emoji", androidEmojiTTFFile.getFullName());
  309. }
  310. /**
  311. * Test getGlyphName - Test value retrieved from the POST table in the font file.
  312. */
  313. @Test
  314. public void testGetGlyphName() {
  315. assertEquals("H", dejavuTTFFile.getGlyphName(43));
  316. assertEquals("H", droidmonoTTFFile.getGlyphName(43));
  317. assertEquals("smileface", androidEmojiTTFFile.getGlyphName(64));
  318. }
  319. /**
  320. * Test getItalicAngle() - Test value retrieved from the POST table in the font file.
  321. */
  322. @Test
  323. public void testGetItalicAngle() {
  324. assertEquals("0", dejavuTTFFile.getItalicAngle());
  325. assertEquals("0", droidmonoTTFFile.getItalicAngle());
  326. assertEquals("0", androidEmojiTTFFile.getItalicAngle());
  327. }
  328. /**
  329. * Test getKerning() - Test values retrieved from the kern table in the font file.
  330. */
  331. @Test
  332. public void testGetKerning() {
  333. Map<Integer, Map<Integer, Integer>> kerning = dejavuTTFFile.getKerning();
  334. if (kerning.isEmpty()) {
  335. fail();
  336. }
  337. Integer k1 = kerning.get((int) 'A').get((int) 'T');
  338. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-112), k1.intValue());
  339. Integer k2 = kerning.get((int) 'K').get((int) 'u');
  340. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(-45), k2.intValue());
  341. // DroidSansMono has no kerning data (mono-spaced)
  342. kerning = droidmonoTTFFile.getKerning();
  343. if (!kerning.isEmpty()) {
  344. fail("DroidSansMono shouldn't have any kerning data");
  345. }
  346. // AndroidEmoji doens't have kerning
  347. kerning = androidEmojiTTFFile.getKerning();
  348. if (!kerning.isEmpty()) {
  349. fail("AndroidEmoji shouldn't have any kerning data.");
  350. }
  351. }
  352. /**
  353. * Test lastChar() - TODO: implement a more intelligent test
  354. */
  355. @Test
  356. public void testLastChar() {
  357. assertEquals(0xff, dejavuTTFFile.getLastChar());
  358. assertEquals(0xff, droidmonoTTFFile.getLastChar());
  359. assertEquals(0xae, androidEmojiTTFFile.getLastChar()); // Last ASCII mapped char is REGISTERED SIGN
  360. }
  361. /**
  362. * Test getLowerCaseAscent() - There are several paths to test:
  363. * 1) The values in the HHEA table (see code)
  364. * 2) Fall back to values from the OS/2 table
  365. * Test values retrieved from the font file.
  366. */
  367. @Test
  368. public void testGetLowerCaseAscent() {
  369. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1556),
  370. dejavuTTFFile.getLowerCaseAscent());
  371. // Curiously the same value
  372. assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1556),
  373. droidmonoTTFFile.getLowerCaseAscent());
  374. //TODO: Nedd to be fixed?
  375. // 0 because the font miss letter glyph that are used in this method to guess the ascender:
  376. // OpenFont.guessVerticalMetricsFromGlyphBBox
  377. assertEquals(androidEmojiTTFFile.convertTTFUnit2PDFUnit(0),
  378. androidEmojiTTFFile.getLowerCaseAscent());
  379. }
  380. /**
  381. * Test getPostScriptName() - Test values retrieved from the post table in the font file.
  382. */
  383. @Test
  384. public void testGetPostScriptName() {
  385. assertEquals(PostScriptVersion.V2, dejavuTTFFile.getPostScriptVersion());
  386. assertEquals(PostScriptVersion.V2, droidmonoTTFFile.getPostScriptVersion());
  387. assertEquals(PostScriptVersion.V2, androidEmojiTTFFile.getPostScriptVersion());
  388. }
  389. /**
  390. * Test getStemV() - Undefined.
  391. */
  392. @Test
  393. public void testGetStemV() {
  394. // Undefined
  395. assertEquals("0", dejavuTTFFile.getStemV());
  396. assertEquals("0", droidmonoTTFFile.getStemV());
  397. assertEquals("0", androidEmojiTTFFile.getStemV());
  398. }
  399. /**
  400. * Test getSubFamilyName() - Test values retrieved from the name table in the font file.
  401. */
  402. @Test
  403. public void testGetSubFamilyName() {
  404. assertEquals("Book", dejavuTTFFile.getSubFamilyName());
  405. assertEquals("Regular", droidmonoTTFFile.getSubFamilyName());
  406. assertEquals("Regular", androidEmojiTTFFile.getSubFamilyName());
  407. }
  408. /**
  409. * Test getTTCnames() - TODO: add implementation with TTC font.
  410. */
  411. public void testGetTTCnames() {
  412. // Can't test with with DejaVu since it's not a TrueType Collection
  413. }
  414. /**
  415. * Test getWeightClass() - Test value retrieved from the OS/2 table in the font file.
  416. */
  417. @Test
  418. public void testGetWeightClass() {
  419. // Retrieved from OS/2 table
  420. assertEquals(400, dejavuTTFFile.getWeightClass());
  421. assertEquals(400, droidmonoTTFFile.getWeightClass());
  422. assertEquals(400, androidEmojiTTFFile.getWeightClass());
  423. }
  424. /**
  425. * Test getWidths() - Test values retrieved from the hmtx table in the font file.
  426. */
  427. @Test
  428. public void testGetWidths() {
  429. int[] widths = dejavuTTFFile.getWidths();
  430. // using the width of 'A' index = 36
  431. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1479), widths[36]);
  432. // using the width of '|' index = 95
  433. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(690), widths[95]);
  434. // DroidSansMono should have all widths the same size (mono-spaced)
  435. widths = droidmonoTTFFile.getWidths();
  436. int charWidth = droidmonoTTFFile.convertTTFUnit2PDFUnit(1229);
  437. for (OpenFont.UnicodeMapping unicodeMapping : droidmonoTTFFile.unicodeMappings) {
  438. assertEquals(charWidth, widths[unicodeMapping.getGlyphIndex()]);
  439. }
  440. // All the glyphs should be the same width in EmojiAndroid (mono-spaced)
  441. charWidth = androidEmojiTTFFile.convertTTFUnit2PDFUnit(2600);
  442. widths = androidEmojiTTFFile.getWidths();
  443. for (OpenFont.UnicodeMapping unicodeMapping : androidEmojiTTFFile.unicodeMappings) {
  444. assertEquals(charWidth, widths[unicodeMapping.getGlyphIndex()]);
  445. }
  446. }
  447. @Test
  448. public void textUnicodeCoverage() {
  449. int nonBMPcount = 0;
  450. for (OpenFont.UnicodeMapping unicodeMapping : droidmonoTTFFile.unicodeMappings) {
  451. nonBMPcount += unicodeMapping.getUnicodeIndex() > 0xFFFF ? 1 : 0;
  452. }
  453. assertEquals("The font DroidSansMono is supposed to have only BMP codepoints", 0, nonBMPcount);
  454. nonBMPcount = 0;
  455. for (OpenFont.UnicodeMapping unicodeMapping : androidEmojiTTFFile.unicodeMappings) {
  456. nonBMPcount += unicodeMapping.getUnicodeIndex() > 0xFFFF ? 1 : 0;
  457. }
  458. assertTrue("The font AndroidEmoji is supposed to have non-BMP codepoints", 0 != nonBMPcount);
  459. }
  460. /**
  461. * Test getXHeight() - There are several paths to test:
  462. * 1) The PCLT table (if available)
  463. * 2) The yMax for the bounding box for 'x' in the glyf table.
  464. * Fall back:
  465. * 3) The xheight in the OS/2 table.
  466. */
  467. @Test
  468. public void testGetXHeight() {
  469. // Since there's no PCLT table, the height of 'x' is used for both DejaVu and DroidSansMono
  470. assertEquals(dejavuTTFFile.convertTTFUnit2PDFUnit(1064), dejavuTTFFile.getXHeight());
  471. assertEquals(droidmonoTTFFile.convertTTFUnit2PDFUnit(1098), droidmonoTTFFile.getXHeight());
  472. }
  473. /**
  474. * Test isCFF() - TODO: add test for a CFF font.
  475. */
  476. @Test
  477. public void testIsCFF() {
  478. // Neither DejaVu nor DroidSansMono are a compact format font
  479. assertEquals(false, dejavuTTFFile.isCFF());
  480. assertEquals(false, droidmonoTTFFile.isCFF());
  481. assertEquals(false, androidEmojiTTFFile.isCFF());
  482. }
  483. /**
  484. * Test isEmbeddable() - Test value retrieved from the OS/2 table in the font file.
  485. */
  486. @Test
  487. public void testIsEmbeddable() {
  488. // Dejavu and DroidSansMono are both embeddable
  489. assertEquals(true, dejavuTTFFile.isEmbeddable());
  490. assertEquals(true, droidmonoTTFFile.isEmbeddable());
  491. assertEquals(true, androidEmojiTTFFile.isEmbeddable());
  492. }
  493. /** Underline position and thickness. */
  494. @Test
  495. public void testUnderline() {
  496. assertEquals(-63, dejavuTTFFile.getUnderlinePosition());
  497. assertEquals(43, dejavuTTFFile.getUnderlineThickness());
  498. assertEquals(-75, droidmonoTTFFile.getUnderlinePosition());
  499. assertEquals(49, droidmonoTTFFile.getUnderlineThickness());
  500. assertEquals(-75, androidEmojiTTFFile.getUnderlinePosition());
  501. assertEquals(49, androidEmojiTTFFile.getUnderlineThickness());
  502. }
  503. /** Strikeout position and thickness. */
  504. @Test
  505. public void testStrikeout() {
  506. assertEquals(258, dejavuTTFFile.getStrikeoutPosition());
  507. assertEquals(49, dejavuTTFFile.getStrikeoutThickness());
  508. assertEquals(243, droidmonoTTFFile.getStrikeoutPosition());
  509. assertEquals(49, droidmonoTTFFile.getStrikeoutThickness());
  510. assertEquals(122, androidEmojiTTFFile.getStrikeoutPosition());
  511. assertEquals(24, androidEmojiTTFFile.getStrikeoutThickness());
  512. }
  513. /**
  514. * Test readFont() - Add implementation if necessary.
  515. */
  516. public void testReadFont() {
  517. // I'm pretty sure we've tested this with all the other tests
  518. }
  519. @Test
  520. public void testBBox() {
  521. assertEquals(dejavuTTFFile.getBBox(1)[0], 49);
  522. assertEquals(dejavuTTFFile.getBBox(2330).length, 4);
  523. }
  524. @Test
  525. public void testReservedIndex() throws IOException {
  526. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  527. DataOutputStream dos = new DataOutputStream(bos);
  528. dos.write(0);
  529. dos.write(2);
  530. for (int i = 0; i < 31; i++) {
  531. dos.write(0);
  532. }
  533. dos.write(1); //number of glyphs
  534. dos.writeShort(32768); //index value
  535. TTFFile ttfFile = new TTFFile();
  536. ttfFile.dirTabs = new HashMap<OFTableName, OFDirTabEntry>();
  537. ttfFile.fontFile = new FontFileReader(new ByteArrayInputStream(bos.toByteArray()));
  538. ttfFile.mtxTab = new OFMtxEntry[1];
  539. ttfFile.mtxTab[0] = new OFMtxEntry();
  540. ttfFile.readPostScript();
  541. }
  542. @Test
  543. public void testStopReadAtLastOffset() throws IOException {
  544. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  545. DataOutputStream dos = new DataOutputStream(bos);
  546. dos.writeShort(0);
  547. dos.writeShort(4);
  548. dos.writeShort(4);
  549. dos.writeLong(0);
  550. TTFFile ttfFile = new TTFFile();
  551. ttfFile.dirTabs = new HashMap<>();
  552. ttfFile.dirTabs.put(OFTableName.LOCA, new OFDirTabEntry());
  553. ttfFile.dirTabs.put(OFTableName.GLYF, new OFDirTabEntry());
  554. ttfFile.fontFile = new FontFileReader(new ByteArrayInputStream(bos.toByteArray()));
  555. ttfFile.numberOfGlyphs = 2;
  556. ttfFile.mtxTab = new OFMtxEntry[2];
  557. ttfFile.mtxTab[0] = new OFMtxEntry();
  558. ttfFile.mtxTab[1] = new OFMtxEntry();
  559. ttfFile.updateBBoxAndOffset();
  560. Assert.assertEquals(ttfFile.mtxTab[0].getBoundingBox()[0], 4);
  561. }
  562. @Test
  563. public void testSymbolCmap() throws Exception {
  564. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  565. DataOutputStream dos = new DataOutputStream(bos);
  566. dos.writeShort(0);
  567. dos.writeShort(1); //num tables
  568. dos.writeShort(3); //cmapPID
  569. dos.writeShort(0); //cmapEID
  570. dos.writeInt(12); //cmapOffset
  571. dos.writeShort(4); //cmapFormat
  572. dos.writeShort(0); //skip cmap length
  573. dos.writeShort(0); //skip cmap version
  574. dos.writeShort(2); //cmapSegCountX2
  575. dos.writeShort(0); //cmapSearchRange
  576. dos.writeShort(0); //cmapEntrySelector
  577. dos.writeShort(0); //cmapRangeShift
  578. dos.writeShort(0xF020); //cmapEndCounts
  579. dos.writeShort(0); //Skip reservedPad
  580. dos.writeShort(0xF020); //cmapStartCounts
  581. dos.writeShort(0); //cmapDeltas
  582. dos.writeShort(0); //cmapRangeOffsets
  583. TTFFile symbolTTFFile = new TTFFile();
  584. symbolTTFFile.mtxTab = new OFMtxEntry[0xF020 + 1];
  585. symbolTTFFile.mtxTab[0] = new OFMtxEntry();
  586. symbolTTFFile.mtxTab[0xF020] = new OFMtxEntry();
  587. symbolTTFFile.dirTabs = new HashMap<>();
  588. symbolTTFFile.dirTabs.put(OFTableName.CMAP, new OFDirTabEntry());
  589. symbolTTFFile.fontFile = new FontFileReader(new ByteArrayInputStream(bos.toByteArray()));
  590. symbolTTFFile.initAnsiWidths();
  591. symbolTTFFile.readCMAP();
  592. Assert.assertEquals(symbolTTFFile.unicodeMappings.get(0).getUnicodeIndex(), 0xF020);
  593. Assert.assertEquals(symbolTTFFile.unicodeMappings.get(0).getGlyphIndex(), 0xF020);
  594. Assert.assertEquals(symbolTTFFile.unicodeMappings.get(1).getUnicodeIndex(), 32);
  595. Assert.assertEquals(symbolTTFFile.unicodeMappings.get(1).getGlyphIndex(), 0xF020);
  596. Assert.assertEquals(symbolTTFFile.unicodeMappings.size(), 2);
  597. }
  598. }