/src/freetype/src/winfonts/winfnt.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 1159 lines · 840 code · 251 blank · 68 comment · 115 complexity · 8c9cf9528d00ad4f1f048ef1c887671f MD5 · raw file

  1. /***************************************************************************/
  2. /* */
  3. /* winfnt.c */
  4. /* */
  5. /* FreeType font driver for Windows FNT/FON files */
  6. /* */
  7. /* Copyright 1996-2004, 2006-2012 by */
  8. /* David Turner, Robert Wilhelm, and Werner Lemberg. */
  9. /* Copyright 2003 Huw D M Davies for Codeweavers */
  10. /* Copyright 2007 Dmitry Timoshkov for Codeweavers */
  11. /* */
  12. /* This file is part of the FreeType project, and may only be used, */
  13. /* modified, and distributed under the terms of the FreeType project */
  14. /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
  15. /* this file you indicate that you have read the license and */
  16. /* understand and accept it fully. */
  17. /* */
  18. /***************************************************************************/
  19. #include <ft2build.h>
  20. #include FT_WINFONTS_H
  21. #include FT_INTERNAL_DEBUG_H
  22. #include FT_INTERNAL_STREAM_H
  23. #include FT_INTERNAL_OBJECTS_H
  24. #include FT_TRUETYPE_IDS_H
  25. #include "winfnt.h"
  26. #include "fnterrs.h"
  27. #include FT_SERVICE_WINFNT_H
  28. #include FT_SERVICE_XFREE86_NAME_H
  29. /*************************************************************************/
  30. /* */
  31. /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
  32. /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
  33. /* messages during execution. */
  34. /* */
  35. #undef FT_COMPONENT
  36. #define FT_COMPONENT trace_winfnt
  37. static const FT_Frame_Field winmz_header_fields[] =
  38. {
  39. #undef FT_STRUCTURE
  40. #define FT_STRUCTURE WinMZ_HeaderRec
  41. FT_FRAME_START( 64 ),
  42. FT_FRAME_USHORT_LE ( magic ),
  43. FT_FRAME_SKIP_BYTES( 29 * 2 ),
  44. FT_FRAME_ULONG_LE ( lfanew ),
  45. FT_FRAME_END
  46. };
  47. static const FT_Frame_Field winne_header_fields[] =
  48. {
  49. #undef FT_STRUCTURE
  50. #define FT_STRUCTURE WinNE_HeaderRec
  51. FT_FRAME_START( 40 ),
  52. FT_FRAME_USHORT_LE ( magic ),
  53. FT_FRAME_SKIP_BYTES( 34 ),
  54. FT_FRAME_USHORT_LE ( resource_tab_offset ),
  55. FT_FRAME_USHORT_LE ( rname_tab_offset ),
  56. FT_FRAME_END
  57. };
  58. static const FT_Frame_Field winpe32_header_fields[] =
  59. {
  60. #undef FT_STRUCTURE
  61. #define FT_STRUCTURE WinPE32_HeaderRec
  62. FT_FRAME_START( 248 ),
  63. FT_FRAME_ULONG_LE ( magic ), /* PE00 */
  64. FT_FRAME_USHORT_LE ( machine ), /* 0x014c - i386 */
  65. FT_FRAME_USHORT_LE ( number_of_sections ),
  66. FT_FRAME_SKIP_BYTES( 12 ),
  67. FT_FRAME_USHORT_LE ( size_of_optional_header ),
  68. FT_FRAME_SKIP_BYTES( 2 ),
  69. FT_FRAME_USHORT_LE ( magic32 ), /* 0x10b */
  70. FT_FRAME_SKIP_BYTES( 110 ),
  71. FT_FRAME_ULONG_LE ( rsrc_virtual_address ),
  72. FT_FRAME_ULONG_LE ( rsrc_size ),
  73. FT_FRAME_SKIP_BYTES( 104 ),
  74. FT_FRAME_END
  75. };
  76. static const FT_Frame_Field winpe32_section_fields[] =
  77. {
  78. #undef FT_STRUCTURE
  79. #define FT_STRUCTURE WinPE32_SectionRec
  80. FT_FRAME_START( 40 ),
  81. FT_FRAME_BYTES ( name, 8 ),
  82. FT_FRAME_SKIP_BYTES( 4 ),
  83. FT_FRAME_ULONG_LE ( virtual_address ),
  84. FT_FRAME_ULONG_LE ( size_of_raw_data ),
  85. FT_FRAME_ULONG_LE ( pointer_to_raw_data ),
  86. FT_FRAME_SKIP_BYTES( 16 ),
  87. FT_FRAME_END
  88. };
  89. static const FT_Frame_Field winpe_rsrc_dir_fields[] =
  90. {
  91. #undef FT_STRUCTURE
  92. #define FT_STRUCTURE WinPE_RsrcDirRec
  93. FT_FRAME_START( 16 ),
  94. FT_FRAME_ULONG_LE ( characteristics ),
  95. FT_FRAME_ULONG_LE ( time_date_stamp ),
  96. FT_FRAME_USHORT_LE( major_version ),
  97. FT_FRAME_USHORT_LE( minor_version ),
  98. FT_FRAME_USHORT_LE( number_of_named_entries ),
  99. FT_FRAME_USHORT_LE( number_of_id_entries ),
  100. FT_FRAME_END
  101. };
  102. static const FT_Frame_Field winpe_rsrc_dir_entry_fields[] =
  103. {
  104. #undef FT_STRUCTURE
  105. #define FT_STRUCTURE WinPE_RsrcDirEntryRec
  106. FT_FRAME_START( 8 ),
  107. FT_FRAME_ULONG_LE( name ),
  108. FT_FRAME_ULONG_LE( offset ),
  109. FT_FRAME_END
  110. };
  111. static const FT_Frame_Field winpe_rsrc_data_entry_fields[] =
  112. {
  113. #undef FT_STRUCTURE
  114. #define FT_STRUCTURE WinPE_RsrcDataEntryRec
  115. FT_FRAME_START( 16 ),
  116. FT_FRAME_ULONG_LE( offset_to_data ),
  117. FT_FRAME_ULONG_LE( size ),
  118. FT_FRAME_ULONG_LE( code_page ),
  119. FT_FRAME_ULONG_LE( reserved ),
  120. FT_FRAME_END
  121. };
  122. static const FT_Frame_Field winfnt_header_fields[] =
  123. {
  124. #undef FT_STRUCTURE
  125. #define FT_STRUCTURE FT_WinFNT_HeaderRec
  126. FT_FRAME_START( 148 ),
  127. FT_FRAME_USHORT_LE( version ),
  128. FT_FRAME_ULONG_LE ( file_size ),
  129. FT_FRAME_BYTES ( copyright, 60 ),
  130. FT_FRAME_USHORT_LE( file_type ),
  131. FT_FRAME_USHORT_LE( nominal_point_size ),
  132. FT_FRAME_USHORT_LE( vertical_resolution ),
  133. FT_FRAME_USHORT_LE( horizontal_resolution ),
  134. FT_FRAME_USHORT_LE( ascent ),
  135. FT_FRAME_USHORT_LE( internal_leading ),
  136. FT_FRAME_USHORT_LE( external_leading ),
  137. FT_FRAME_BYTE ( italic ),
  138. FT_FRAME_BYTE ( underline ),
  139. FT_FRAME_BYTE ( strike_out ),
  140. FT_FRAME_USHORT_LE( weight ),
  141. FT_FRAME_BYTE ( charset ),
  142. FT_FRAME_USHORT_LE( pixel_width ),
  143. FT_FRAME_USHORT_LE( pixel_height ),
  144. FT_FRAME_BYTE ( pitch_and_family ),
  145. FT_FRAME_USHORT_LE( avg_width ),
  146. FT_FRAME_USHORT_LE( max_width ),
  147. FT_FRAME_BYTE ( first_char ),
  148. FT_FRAME_BYTE ( last_char ),
  149. FT_FRAME_BYTE ( default_char ),
  150. FT_FRAME_BYTE ( break_char ),
  151. FT_FRAME_USHORT_LE( bytes_per_row ),
  152. FT_FRAME_ULONG_LE ( device_offset ),
  153. FT_FRAME_ULONG_LE ( face_name_offset ),
  154. FT_FRAME_ULONG_LE ( bits_pointer ),
  155. FT_FRAME_ULONG_LE ( bits_offset ),
  156. FT_FRAME_BYTE ( reserved ),
  157. FT_FRAME_ULONG_LE ( flags ),
  158. FT_FRAME_USHORT_LE( A_space ),
  159. FT_FRAME_USHORT_LE( B_space ),
  160. FT_FRAME_USHORT_LE( C_space ),
  161. FT_FRAME_ULONG_LE ( color_table_offset ),
  162. FT_FRAME_BYTES ( reserved1, 16 ),
  163. FT_FRAME_END
  164. };
  165. static void
  166. fnt_font_done( FNT_Face face )
  167. {
  168. FT_Memory memory = FT_FACE( face )->memory;
  169. FT_Stream stream = FT_FACE( face )->stream;
  170. FNT_Font font = face->font;
  171. if ( !font )
  172. return;
  173. if ( font->fnt_frame )
  174. FT_FRAME_RELEASE( font->fnt_frame );
  175. FT_FREE( font->family_name );
  176. FT_FREE( font );
  177. face->font = 0;
  178. }
  179. static FT_Error
  180. fnt_font_load( FNT_Font font,
  181. FT_Stream stream )
  182. {
  183. FT_Error error;
  184. FT_WinFNT_Header header = &font->header;
  185. FT_Bool new_format;
  186. FT_UInt size;
  187. /* first of all, read the FNT header */
  188. if ( FT_STREAM_SEEK( font->offset ) ||
  189. FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) )
  190. goto Exit;
  191. /* check header */
  192. if ( header->version != 0x200 &&
  193. header->version != 0x300 )
  194. {
  195. FT_TRACE2(( " not a Windows FNT file\n" ));
  196. error = FNT_Err_Unknown_File_Format;
  197. goto Exit;
  198. }
  199. new_format = FT_BOOL( font->header.version == 0x300 );
  200. size = new_format ? 148 : 118;
  201. if ( header->file_size < size )
  202. {
  203. FT_TRACE2(( " not a Windows FNT file\n" ));
  204. error = FNT_Err_Unknown_File_Format;
  205. goto Exit;
  206. }
  207. /* Version 2 doesn't have these fields */
  208. if ( header->version == 0x200 )
  209. {
  210. header->flags = 0;
  211. header->A_space = 0;
  212. header->B_space = 0;
  213. header->C_space = 0;
  214. header->color_table_offset = 0;
  215. }
  216. if ( header->file_type & 1 )
  217. {
  218. FT_TRACE2(( "[can't handle vector FNT fonts]\n" ));
  219. error = FNT_Err_Unknown_File_Format;
  220. goto Exit;
  221. }
  222. /* this is a FNT file/table; extract its frame */
  223. if ( FT_STREAM_SEEK( font->offset ) ||
  224. FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) )
  225. goto Exit;
  226. Exit:
  227. return error;
  228. }
  229. static FT_Error
  230. fnt_face_get_dll_font( FNT_Face face,
  231. FT_Int face_index )
  232. {
  233. FT_Error error;
  234. FT_Stream stream = FT_FACE( face )->stream;
  235. FT_Memory memory = FT_FACE( face )->memory;
  236. WinMZ_HeaderRec mz_header;
  237. face->font = 0;
  238. /* does it begin with an MZ header? */
  239. if ( FT_STREAM_SEEK( 0 ) ||
  240. FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) )
  241. goto Exit;
  242. error = FNT_Err_Unknown_File_Format;
  243. if ( mz_header.magic == WINFNT_MZ_MAGIC )
  244. {
  245. /* yes, now look for an NE header in the file */
  246. WinNE_HeaderRec ne_header;
  247. FT_TRACE2(( "MZ signature found\n" ));
  248. if ( FT_STREAM_SEEK( mz_header.lfanew ) ||
  249. FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) )
  250. goto Exit;
  251. error = FNT_Err_Unknown_File_Format;
  252. if ( ne_header.magic == WINFNT_NE_MAGIC )
  253. {
  254. /* good, now look into the resource table for each FNT resource */
  255. FT_ULong res_offset = mz_header.lfanew +
  256. ne_header.resource_tab_offset;
  257. FT_UShort size_shift;
  258. FT_UShort font_count = 0;
  259. FT_ULong font_offset = 0;
  260. FT_TRACE2(( "NE signature found\n" ));
  261. if ( FT_STREAM_SEEK( res_offset ) ||
  262. FT_FRAME_ENTER( ne_header.rname_tab_offset -
  263. ne_header.resource_tab_offset ) )
  264. goto Exit;
  265. size_shift = FT_GET_USHORT_LE();
  266. for (;;)
  267. {
  268. FT_UShort type_id, count;
  269. type_id = FT_GET_USHORT_LE();
  270. if ( !type_id )
  271. break;
  272. count = FT_GET_USHORT_LE();
  273. if ( type_id == 0x8008U )
  274. {
  275. font_count = count;
  276. font_offset = (FT_ULong)( FT_STREAM_POS() + 4 +
  277. ( stream->cursor - stream->limit ) );
  278. break;
  279. }
  280. stream->cursor += 4 + count * 12;
  281. }
  282. FT_FRAME_EXIT();
  283. if ( !font_count || !font_offset )
  284. {
  285. FT_TRACE2(( "this file doesn't contain any FNT resources\n" ));
  286. error = FNT_Err_Invalid_File_Format;
  287. goto Exit;
  288. }
  289. /* loading `winfnt_header_fields' needs at least 118 bytes; */
  290. /* use this as a rough measure to check the expected font size */
  291. if ( font_count * 118UL > stream->size )
  292. {
  293. FT_TRACE2(( "invalid number of faces\n" ));
  294. error = FNT_Err_Invalid_File_Format;
  295. goto Exit;
  296. }
  297. face->root.num_faces = font_count;
  298. if ( face_index >= font_count )
  299. {
  300. error = FNT_Err_Invalid_Argument;
  301. goto Exit;
  302. }
  303. else if ( face_index < 0 )
  304. goto Exit;
  305. if ( FT_NEW( face->font ) )
  306. goto Exit;
  307. if ( FT_STREAM_SEEK( font_offset + face_index * 12 ) ||
  308. FT_FRAME_ENTER( 12 ) )
  309. goto Fail;
  310. face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
  311. face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
  312. stream->cursor += 8;
  313. FT_FRAME_EXIT();
  314. error = fnt_font_load( face->font, stream );
  315. }
  316. else if ( ne_header.magic == WINFNT_PE_MAGIC )
  317. {
  318. WinPE32_HeaderRec pe32_header;
  319. WinPE32_SectionRec pe32_section;
  320. WinPE_RsrcDirRec root_dir, name_dir, lang_dir;
  321. WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3;
  322. WinPE_RsrcDataEntryRec data_entry;
  323. FT_Long root_dir_offset, name_dir_offset, lang_dir_offset;
  324. FT_UShort i, j, k;
  325. FT_TRACE2(( "PE signature found\n" ));
  326. if ( FT_STREAM_SEEK( mz_header.lfanew ) ||
  327. FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) )
  328. goto Exit;
  329. FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, "
  330. "size_of_optional_header %02x\n"
  331. "magic32 %02x, rsrc_virtual_address %04lx, "
  332. "rsrc_size %04lx\n",
  333. pe32_header.magic, pe32_header.machine,
  334. pe32_header.number_of_sections,
  335. pe32_header.size_of_optional_header,
  336. pe32_header.magic32, pe32_header.rsrc_virtual_address,
  337. pe32_header.rsrc_size ));
  338. if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ ||
  339. pe32_header.machine != 0x014c /* i386 */ ||
  340. pe32_header.size_of_optional_header != 0xe0 /* FIXME */ ||
  341. pe32_header.magic32 != 0x10b )
  342. {
  343. FT_TRACE2(( "this file has an invalid PE header\n" ));
  344. error = FNT_Err_Invalid_File_Format;
  345. goto Exit;
  346. }
  347. face->root.num_faces = 0;
  348. for ( i = 0; i < pe32_header.number_of_sections; i++ )
  349. {
  350. if ( FT_STREAM_READ_FIELDS( winpe32_section_fields,
  351. &pe32_section ) )
  352. goto Exit;
  353. FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n",
  354. pe32_section.name, pe32_section.virtual_address,
  355. pe32_section.size_of_raw_data,
  356. pe32_section.pointer_to_raw_data ));
  357. if ( pe32_header.rsrc_virtual_address ==
  358. pe32_section.virtual_address )
  359. goto Found_rsrc_section;
  360. }
  361. FT_TRACE2(( "this file doesn't contain any resources\n" ));
  362. error = FNT_Err_Invalid_File_Format;
  363. goto Exit;
  364. Found_rsrc_section:
  365. FT_TRACE2(( "found resources section %.8s\n", pe32_section.name ));
  366. if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) ||
  367. FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) )
  368. goto Exit;
  369. root_dir_offset = pe32_section.pointer_to_raw_data;
  370. for ( i = 0; i < root_dir.number_of_named_entries +
  371. root_dir.number_of_id_entries; i++ )
  372. {
  373. if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) ||
  374. FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
  375. &dir_entry1 ) )
  376. goto Exit;
  377. if ( !(dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ )
  378. {
  379. error = FNT_Err_Invalid_File_Format;
  380. goto Exit;
  381. }
  382. dir_entry1.offset &= ~0x80000000UL;
  383. name_dir_offset = pe32_section.pointer_to_raw_data +
  384. dir_entry1.offset;
  385. if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data +
  386. dir_entry1.offset ) ||
  387. FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) )
  388. goto Exit;
  389. for ( j = 0; j < name_dir.number_of_named_entries +
  390. name_dir.number_of_id_entries; j++ )
  391. {
  392. if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) ||
  393. FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
  394. &dir_entry2 ) )
  395. goto Exit;
  396. if ( !(dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ )
  397. {
  398. error = FNT_Err_Invalid_File_Format;
  399. goto Exit;
  400. }
  401. dir_entry2.offset &= ~0x80000000UL;
  402. lang_dir_offset = pe32_section.pointer_to_raw_data +
  403. dir_entry2.offset;
  404. if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data +
  405. dir_entry2.offset ) ||
  406. FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) )
  407. goto Exit;
  408. for ( k = 0; k < lang_dir.number_of_named_entries +
  409. lang_dir.number_of_id_entries; k++ )
  410. {
  411. if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) ||
  412. FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
  413. &dir_entry3 ) )
  414. goto Exit;
  415. if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ )
  416. {
  417. error = FNT_Err_Invalid_File_Format;
  418. goto Exit;
  419. }
  420. if ( dir_entry1.name == 8 /* RT_FONT */ )
  421. {
  422. if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) ||
  423. FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields,
  424. &data_entry ) )
  425. goto Exit;
  426. FT_TRACE2(( "found font #%lu, offset %04lx, "
  427. "size %04lx, cp %lu\n",
  428. dir_entry2.name,
  429. pe32_section.pointer_to_raw_data +
  430. data_entry.offset_to_data -
  431. pe32_section.virtual_address,
  432. data_entry.size, data_entry.code_page ));
  433. if ( face_index == face->root.num_faces )
  434. {
  435. if ( FT_NEW( face->font ) )
  436. goto Exit;
  437. face->font->offset = pe32_section.pointer_to_raw_data +
  438. data_entry.offset_to_data -
  439. pe32_section.virtual_address;
  440. face->font->fnt_size = data_entry.size;
  441. error = fnt_font_load( face->font, stream );
  442. if ( error )
  443. {
  444. FT_TRACE2(( "font #%lu load error %d\n",
  445. dir_entry2.name, error ));
  446. goto Fail;
  447. }
  448. else
  449. FT_TRACE2(( "font #%lu successfully loaded\n",
  450. dir_entry2.name ));
  451. }
  452. face->root.num_faces++;
  453. }
  454. }
  455. }
  456. }
  457. }
  458. if ( !face->root.num_faces )
  459. {
  460. FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" ));
  461. error = FNT_Err_Invalid_File_Format;
  462. goto Exit;
  463. }
  464. if ( face_index >= face->root.num_faces )
  465. {
  466. error = FNT_Err_Invalid_Argument;
  467. goto Exit;
  468. }
  469. }
  470. Fail:
  471. if ( error )
  472. fnt_font_done( face );
  473. Exit:
  474. return error;
  475. }
  476. typedef struct FNT_CMapRec_
  477. {
  478. FT_CMapRec cmap;
  479. FT_UInt32 first;
  480. FT_UInt32 count;
  481. } FNT_CMapRec, *FNT_CMap;
  482. static FT_Error
  483. fnt_cmap_init( FNT_CMap cmap )
  484. {
  485. FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap );
  486. FNT_Font font = face->font;
  487. cmap->first = (FT_UInt32) font->header.first_char;
  488. cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 );
  489. return 0;
  490. }
  491. static FT_UInt
  492. fnt_cmap_char_index( FNT_CMap cmap,
  493. FT_UInt32 char_code )
  494. {
  495. FT_UInt gindex = 0;
  496. char_code -= cmap->first;
  497. if ( char_code < cmap->count )
  498. /* we artificially increase the glyph index; */
  499. /* FNT_Load_Glyph reverts to the right one */
  500. gindex = (FT_UInt)( char_code + 1 );
  501. return gindex;
  502. }
  503. static FT_UInt32
  504. fnt_cmap_char_next( FNT_CMap cmap,
  505. FT_UInt32 *pchar_code )
  506. {
  507. FT_UInt gindex = 0;
  508. FT_UInt32 result = 0;
  509. FT_UInt32 char_code = *pchar_code + 1;
  510. if ( char_code <= cmap->first )
  511. {
  512. result = cmap->first;
  513. gindex = 1;
  514. }
  515. else
  516. {
  517. char_code -= cmap->first;
  518. if ( char_code < cmap->count )
  519. {
  520. result = cmap->first + char_code;
  521. gindex = (FT_UInt)( char_code + 1 );
  522. }
  523. }
  524. *pchar_code = result;
  525. return gindex;
  526. }
  527. static const FT_CMap_ClassRec fnt_cmap_class_rec =
  528. {
  529. sizeof ( FNT_CMapRec ),
  530. (FT_CMap_InitFunc) fnt_cmap_init,
  531. (FT_CMap_DoneFunc) NULL,
  532. (FT_CMap_CharIndexFunc)fnt_cmap_char_index,
  533. (FT_CMap_CharNextFunc) fnt_cmap_char_next,
  534. NULL, NULL, NULL, NULL, NULL
  535. };
  536. static FT_CMap_Class const fnt_cmap_class = &fnt_cmap_class_rec;
  537. static void
  538. FNT_Face_Done( FT_Face fntface ) /* FNT_Face */
  539. {
  540. FNT_Face face = (FNT_Face)fntface;
  541. FT_Memory memory;
  542. if ( !face )
  543. return;
  544. memory = FT_FACE_MEMORY( face );
  545. fnt_font_done( face );
  546. FT_FREE( fntface->available_sizes );
  547. fntface->num_fixed_sizes = 0;
  548. }
  549. static FT_Error
  550. FNT_Face_Init( FT_Stream stream,
  551. FT_Face fntface, /* FNT_Face */
  552. FT_Int face_index,
  553. FT_Int num_params,
  554. FT_Parameter* params )
  555. {
  556. FNT_Face face = (FNT_Face)fntface;
  557. FT_Error error;
  558. FT_Memory memory = FT_FACE_MEMORY( face );
  559. FT_UNUSED( num_params );
  560. FT_UNUSED( params );
  561. FT_TRACE2(( "Windows FNT driver\n" ));
  562. /* try to load font from a DLL */
  563. error = fnt_face_get_dll_font( face, face_index );
  564. if ( !error && face_index < 0 )
  565. goto Exit;
  566. if ( error == FNT_Err_Unknown_File_Format )
  567. {
  568. /* this didn't work; try to load a single FNT font */
  569. FNT_Font font;
  570. if ( FT_NEW( face->font ) )
  571. goto Exit;
  572. fntface->num_faces = 1;
  573. font = face->font;
  574. font->offset = 0;
  575. font->fnt_size = stream->size;
  576. error = fnt_font_load( font, stream );
  577. if ( !error )
  578. {
  579. if ( face_index > 0 )
  580. error = FNT_Err_Invalid_Argument;
  581. else if ( face_index < 0 )
  582. goto Exit;
  583. }
  584. }
  585. if ( error )
  586. goto Fail;
  587. /* we now need to fill the root FT_Face fields */
  588. /* with relevant information */
  589. {
  590. FT_Face root = FT_FACE( face );
  591. FNT_Font font = face->font;
  592. FT_PtrDist family_size;
  593. root->face_index = face_index;
  594. root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
  595. FT_FACE_FLAG_HORIZONTAL;
  596. if ( font->header.avg_width == font->header.max_width )
  597. root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
  598. if ( font->header.italic )
  599. root->style_flags |= FT_STYLE_FLAG_ITALIC;
  600. if ( font->header.weight >= 800 )
  601. root->style_flags |= FT_STYLE_FLAG_BOLD;
  602. /* set up the `fixed_sizes' array */
  603. if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
  604. goto Fail;
  605. root->num_fixed_sizes = 1;
  606. {
  607. FT_Bitmap_Size* bsize = root->available_sizes;
  608. FT_UShort x_res, y_res;
  609. bsize->width = font->header.avg_width;
  610. bsize->height = (FT_Short)(
  611. font->header.pixel_height + font->header.external_leading );
  612. bsize->size = font->header.nominal_point_size << 6;
  613. x_res = font->header.horizontal_resolution;
  614. if ( !x_res )
  615. x_res = 72;
  616. y_res = font->header.vertical_resolution;
  617. if ( !y_res )
  618. y_res = 72;
  619. bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 );
  620. bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem );
  621. /*
  622. * this reads:
  623. *
  624. * the nominal height is larger than the bbox's height
  625. *
  626. * => nominal_point_size contains incorrect value;
  627. * use pixel_height as the nominal height
  628. */
  629. if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) )
  630. {
  631. FT_TRACE2(( "use pixel_height as the nominal height\n" ));
  632. bsize->y_ppem = font->header.pixel_height << 6;
  633. bsize->size = FT_MulDiv( bsize->y_ppem, 72, y_res );
  634. }
  635. bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 );
  636. bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem );
  637. }
  638. {
  639. FT_CharMapRec charmap;
  640. charmap.encoding = FT_ENCODING_NONE;
  641. /* initial platform/encoding should indicate unset status? */
  642. charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
  643. charmap.encoding_id = TT_APPLE_ID_DEFAULT;
  644. charmap.face = root;
  645. if ( font->header.charset == FT_WinFNT_ID_MAC )
  646. {
  647. charmap.encoding = FT_ENCODING_APPLE_ROMAN;
  648. charmap.platform_id = TT_PLATFORM_MACINTOSH;
  649. /* charmap.encoding_id = TT_MAC_ID_ROMAN; */
  650. }
  651. error = FT_CMap_New( fnt_cmap_class,
  652. NULL,
  653. &charmap,
  654. NULL );
  655. if ( error )
  656. goto Fail;
  657. /* Select default charmap */
  658. if ( root->num_charmaps )
  659. root->charmap = root->charmaps[0];
  660. }
  661. /* set up remaining flags */
  662. if ( font->header.last_char < font->header.first_char )
  663. {
  664. FT_TRACE2(( "invalid number of glyphs\n" ));
  665. error = FNT_Err_Invalid_File_Format;
  666. goto Fail;
  667. }
  668. /* reserve one slot for the .notdef glyph at index 0 */
  669. root->num_glyphs = font->header.last_char -
  670. font->header.first_char + 1 + 1;
  671. if ( font->header.face_name_offset >= font->header.file_size )
  672. {
  673. FT_TRACE2(( "invalid family name offset\n" ));
  674. error = FNT_Err_Invalid_File_Format;
  675. goto Fail;
  676. }
  677. family_size = font->header.file_size - font->header.face_name_offset;
  678. /* Some broken fonts don't delimit the face name with a final */
  679. /* NULL byte -- the frame is erroneously one byte too small. */
  680. /* We thus allocate one more byte, setting it explicitly to */
  681. /* zero. */
  682. if ( FT_ALLOC( font->family_name, family_size + 1 ) )
  683. goto Fail;
  684. FT_MEM_COPY( font->family_name,
  685. font->fnt_frame + font->header.face_name_offset,
  686. family_size );
  687. font->family_name[family_size] = '\0';
  688. if ( FT_REALLOC( font->family_name,
  689. family_size,
  690. ft_strlen( font->family_name ) + 1 ) )
  691. goto Fail;
  692. root->family_name = font->family_name;
  693. root->style_name = (char *)"Regular";
  694. if ( root->style_flags & FT_STYLE_FLAG_BOLD )
  695. {
  696. if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
  697. root->style_name = (char *)"Bold Italic";
  698. else
  699. root->style_name = (char *)"Bold";
  700. }
  701. else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
  702. root->style_name = (char *)"Italic";
  703. }
  704. goto Exit;
  705. Fail:
  706. FNT_Face_Done( fntface );
  707. Exit:
  708. return error;
  709. }
  710. static FT_Error
  711. FNT_Size_Select( FT_Size size,
  712. FT_ULong strike_index )
  713. {
  714. FNT_Face face = (FNT_Face)size->face;
  715. FT_WinFNT_Header header = &face->font->header;
  716. FT_UNUSED( strike_index );
  717. FT_Select_Metrics( size->face, 0 );
  718. size->metrics.ascender = header->ascent * 64;
  719. size->metrics.descender = -( header->pixel_height -
  720. header->ascent ) * 64;
  721. size->metrics.max_advance = header->max_width * 64;
  722. return FNT_Err_Ok;
  723. }
  724. static FT_Error
  725. FNT_Size_Request( FT_Size size,
  726. FT_Size_Request req )
  727. {
  728. FNT_Face face = (FNT_Face)size->face;
  729. FT_WinFNT_Header header = &face->font->header;
  730. FT_Bitmap_Size* bsize = size->face->available_sizes;
  731. FT_Error error = FNT_Err_Invalid_Pixel_Size;
  732. FT_Long height;
  733. height = FT_REQUEST_HEIGHT( req );
  734. height = ( height + 32 ) >> 6;
  735. switch ( req->type )
  736. {
  737. case FT_SIZE_REQUEST_TYPE_NOMINAL:
  738. if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
  739. error = FNT_Err_Ok;
  740. break;
  741. case FT_SIZE_REQUEST_TYPE_REAL_DIM:
  742. if ( height == header->pixel_height )
  743. error = FNT_Err_Ok;
  744. break;
  745. default:
  746. error = FNT_Err_Unimplemented_Feature;
  747. break;
  748. }
  749. if ( error )
  750. return error;
  751. else
  752. return FNT_Size_Select( size, 0 );
  753. }
  754. static FT_Error
  755. FNT_Load_Glyph( FT_GlyphSlot slot,
  756. FT_Size size,
  757. FT_UInt glyph_index,
  758. FT_Int32 load_flags )
  759. {
  760. FNT_Face face = (FNT_Face)FT_SIZE_FACE( size );
  761. FNT_Font font;
  762. FT_Error error = FNT_Err_Ok;
  763. FT_Byte* p;
  764. FT_Int len;
  765. FT_Bitmap* bitmap = &slot->bitmap;
  766. FT_ULong offset;
  767. FT_Bool new_format;
  768. FT_UNUSED( load_flags );
  769. if ( !face )
  770. {
  771. error = FNT_Err_Invalid_Argument;
  772. goto Exit;
  773. }
  774. font = face->font;
  775. if ( !font ||
  776. glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) )
  777. {
  778. error = FNT_Err_Invalid_Argument;
  779. goto Exit;
  780. }
  781. if ( glyph_index > 0 )
  782. glyph_index--; /* revert to real index */
  783. else
  784. glyph_index = font->header.default_char; /* the .notdef glyph */
  785. new_format = FT_BOOL( font->header.version == 0x300 );
  786. len = new_format ? 6 : 4;
  787. /* jump to glyph entry */
  788. p = font->fnt_frame + ( new_format ? 148 : 118 ) + len * glyph_index;
  789. bitmap->width = FT_NEXT_SHORT_LE( p );
  790. if ( new_format )
  791. offset = FT_NEXT_ULONG_LE( p );
  792. else
  793. offset = FT_NEXT_USHORT_LE( p );
  794. if ( offset >= font->header.file_size )
  795. {
  796. FT_TRACE2(( "invalid FNT offset\n" ));
  797. error = FNT_Err_Invalid_File_Format;
  798. goto Exit;
  799. }
  800. /* jump to glyph data */
  801. p = font->fnt_frame + /* font->header.bits_offset */ + offset;
  802. /* allocate and build bitmap */
  803. {
  804. FT_Memory memory = FT_FACE_MEMORY( slot->face );
  805. FT_Int pitch = ( bitmap->width + 7 ) >> 3;
  806. FT_Byte* column;
  807. FT_Byte* write;
  808. bitmap->pitch = pitch;
  809. bitmap->rows = font->header.pixel_height;
  810. bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
  811. if ( offset + pitch * bitmap->rows >= font->header.file_size )
  812. {
  813. FT_TRACE2(( "invalid bitmap width\n" ));
  814. error = FNT_Err_Invalid_File_Format;
  815. goto Exit;
  816. }
  817. /* note: since glyphs are stored in columns and not in rows we */
  818. /* can't use ft_glyphslot_set_bitmap */
  819. if ( FT_ALLOC_MULT( bitmap->buffer, pitch, bitmap->rows ) )
  820. goto Exit;
  821. column = (FT_Byte*)bitmap->buffer;
  822. for ( ; pitch > 0; pitch--, column++ )
  823. {
  824. FT_Byte* limit = p + bitmap->rows;
  825. for ( write = column; p < limit; p++, write += bitmap->pitch )
  826. *write = *p;
  827. }
  828. }
  829. slot->internal->flags = FT_GLYPH_OWN_BITMAP;
  830. slot->bitmap_left = 0;
  831. slot->bitmap_top = font->header.ascent;
  832. slot->format = FT_GLYPH_FORMAT_BITMAP;
  833. /* now set up metrics */
  834. slot->metrics.width = bitmap->width << 6;
  835. slot->metrics.height = bitmap->rows << 6;
  836. slot->metrics.horiAdvance = bitmap->width << 6;
  837. slot->metrics.horiBearingX = 0;
  838. slot->metrics.horiBearingY = slot->bitmap_top << 6;
  839. ft_synthesize_vertical_metrics( &slot->metrics,
  840. bitmap->rows << 6 );
  841. Exit:
  842. return error;
  843. }
  844. static FT_Error
  845. winfnt_get_header( FT_Face face,
  846. FT_WinFNT_HeaderRec *aheader )
  847. {
  848. FNT_Font font = ((FNT_Face)face)->font;
  849. *aheader = font->header;
  850. return 0;
  851. }
  852. static const FT_Service_WinFntRec winfnt_service_rec =
  853. {
  854. winfnt_get_header
  855. };
  856. /*
  857. * SERVICE LIST
  858. *
  859. */
  860. static const FT_ServiceDescRec winfnt_services[] =
  861. {
  862. { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_WINFNT },
  863. { FT_SERVICE_ID_WINFNT, &winfnt_service_rec },
  864. { NULL, NULL }
  865. };
  866. static FT_Module_Interface
  867. winfnt_get_service( FT_Module module,
  868. const FT_String* service_id )
  869. {
  870. FT_UNUSED( module );
  871. return ft_service_list_lookup( winfnt_services, service_id );
  872. }
  873. FT_CALLBACK_TABLE_DEF
  874. const FT_Driver_ClassRec winfnt_driver_class =
  875. {
  876. {
  877. FT_MODULE_FONT_DRIVER |
  878. FT_MODULE_DRIVER_NO_OUTLINES,
  879. sizeof ( FT_DriverRec ),
  880. "winfonts",
  881. 0x10000L,
  882. 0x20000L,
  883. 0,
  884. 0, /* FT_Module_Constructor */
  885. 0, /* FT_Module_Destructor */
  886. winfnt_get_service
  887. },
  888. sizeof ( FNT_FaceRec ),
  889. sizeof ( FT_SizeRec ),
  890. sizeof ( FT_GlyphSlotRec ),
  891. FNT_Face_Init,
  892. FNT_Face_Done,
  893. 0, /* FT_Size_InitFunc */
  894. 0, /* FT_Size_DoneFunc */
  895. 0, /* FT_Slot_InitFunc */
  896. 0, /* FT_Slot_DoneFunc */
  897. #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
  898. ft_stub_set_char_sizes,
  899. ft_stub_set_pixel_sizes,
  900. #endif
  901. FNT_Load_Glyph,
  902. 0, /* FT_Face_GetKerningFunc */
  903. 0, /* FT_Face_AttachFunc */
  904. 0, /* FT_Face_GetAdvancesFunc */
  905. FNT_Size_Request,
  906. FNT_Size_Select
  907. };
  908. /* END */