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