The BIG graph update
[rrdtool.git] / libraries / freetype-2.0.5 / winfnt.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  winfnt.c                                                               */
4 /*                                                                         */
5 /*    FreeType font driver for Windows FNT/FON files                       */
6 /*                                                                         */
7 /*  Copyright 1996-2001 by                                                 */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_STREAM_H
22 #include FT_INTERNAL_OBJECTS_H
23 #include FT_INTERNAL_FNT_TYPES_H
24
25 #include "winfnt.h"
26
27 #include "fnterrs.h"
28
29
30   /*************************************************************************/
31   /*                                                                       */
32   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
33   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
34   /* messages during execution.                                            */
35   /*                                                                       */
36 #undef  FT_COMPONENT
37 #define FT_COMPONENT  trace_winfnt
38
39
40   static
41   const FT_Frame_Field  winmz_header_fields[] =
42   {
43 #undef  FT_STRUCTURE
44 #define FT_STRUCTURE  WinMZ_Header
45
46     FT_FRAME_START( 64 ),
47       FT_FRAME_USHORT_LE ( magic ),
48       FT_FRAME_SKIP_BYTES( 29 * 2 ),
49       FT_FRAME_ULONG_LE  ( lfanew ),
50     FT_FRAME_END
51   };
52
53   static
54   const FT_Frame_Field  winne_header_fields[] =
55   {
56 #undef  FT_STRUCTURE
57 #define FT_STRUCTURE  WinNE_Header
58
59     FT_FRAME_START( 40 ),
60       FT_FRAME_USHORT_LE ( magic ),
61       FT_FRAME_SKIP_BYTES( 34 ),
62       FT_FRAME_USHORT_LE ( resource_tab_offset ),
63       FT_FRAME_USHORT_LE ( rname_tab_offset ),
64     FT_FRAME_END
65   };
66
67   static
68   const FT_Frame_Field  winfnt_header_fields[] =
69   {
70 #undef  FT_STRUCTURE
71 #define FT_STRUCTURE  WinFNT_Header
72
73     FT_FRAME_START( 134 ),
74       FT_FRAME_USHORT_LE( version ),
75       FT_FRAME_ULONG_LE ( file_size ),
76       FT_FRAME_BYTES    ( copyright, 60 ),
77       FT_FRAME_USHORT_LE( file_type ),
78       FT_FRAME_USHORT_LE( nominal_point_size ),
79       FT_FRAME_USHORT_LE( vertical_resolution ),
80       FT_FRAME_USHORT_LE( horizontal_resolution ),
81       FT_FRAME_USHORT_LE( ascent ),
82       FT_FRAME_USHORT_LE( internal_leading ),
83       FT_FRAME_USHORT_LE( external_leading ),
84       FT_FRAME_BYTE     ( italic ),
85       FT_FRAME_BYTE     ( underline ),
86       FT_FRAME_BYTE     ( strike_out ),
87       FT_FRAME_USHORT_LE( weight ),
88       FT_FRAME_BYTE     ( charset ),
89       FT_FRAME_USHORT_LE( pixel_width ),
90       FT_FRAME_USHORT_LE( pixel_height ),
91       FT_FRAME_BYTE     ( pitch_and_family ),
92       FT_FRAME_USHORT_LE( avg_width ),
93       FT_FRAME_USHORT_LE( max_width ),
94       FT_FRAME_BYTE     ( first_char ),
95       FT_FRAME_BYTE     ( last_char ),
96       FT_FRAME_BYTE     ( default_char ),
97       FT_FRAME_BYTE     ( break_char ),
98       FT_FRAME_USHORT_LE( bytes_per_row ),
99       FT_FRAME_ULONG_LE ( device_offset ),
100       FT_FRAME_ULONG_LE ( face_name_offset ),
101       FT_FRAME_ULONG_LE ( bits_pointer ),
102       FT_FRAME_ULONG_LE ( bits_offset ),
103       FT_FRAME_BYTE     ( reserved ),
104       FT_FRAME_ULONG_LE ( flags ),
105       FT_FRAME_USHORT_LE( A_space ),
106       FT_FRAME_USHORT_LE( B_space ),
107       FT_FRAME_USHORT_LE( C_space ),
108       FT_FRAME_USHORT_LE( color_table_offset ),
109       FT_FRAME_BYTES    ( reserved, 4 ),
110     FT_FRAME_END
111   };
112
113
114   static void
115   fnt_font_done( FNT_Font*  font,
116                  FT_Stream  stream )
117   {
118     if ( font->fnt_frame )
119       RELEASE_Frame( font->fnt_frame );
120
121     font->fnt_size  = 0;
122     font->fnt_frame = 0;
123   }
124
125
126   static FT_Error
127   fnt_font_load( FNT_Font*  font,
128                  FT_Stream  stream )
129   {
130     FT_Error        error;
131     WinFNT_Header*  header = &font->header;
132
133
134     /* first of all, read the FNT header */
135     if ( FILE_Seek( font->offset )                   ||
136          READ_Fields( winfnt_header_fields, header ) )
137       goto Exit;
138
139     /* check header */
140     if ( header->version != 0x200 &&
141          header->version != 0x300 )
142     {
143       FT_TRACE2(( "[not a valid FNT file]\n" ));
144       error = FNT_Err_Unknown_File_Format;
145       goto Exit;
146     }
147
148     if ( header->file_type & 1 )
149     {
150       FT_TRACE2(( "[can't handle vector FNT fonts]\n" ));
151       error = FNT_Err_Unknown_File_Format;
152       goto Exit;
153     }
154
155     /* small fixup -- some fonts have the `pixel_width' field set to 0 */
156     if ( header->pixel_width == 0 )
157       header->pixel_width = header->pixel_height;
158
159     /* this is a FNT file/table, we now extract its frame */
160     if ( FILE_Seek( font->offset )                           ||
161          EXTRACT_Frame( header->file_size, font->fnt_frame ) )
162       goto Exit;
163
164   Exit:
165     return error;
166   }
167
168
169   static void
170   fnt_face_done_fonts( FNT_Face  face )
171   {
172     FT_Memory  memory = FT_FACE(face)->memory;
173     FT_Stream  stream = FT_FACE(face)->stream;
174     FNT_Font*  cur    = face->fonts;
175     FNT_Font*  limit  = cur + face->num_fonts;
176
177
178     for ( ; cur < limit; cur++ )
179       fnt_font_done( cur, stream );
180
181     FREE( face->fonts );
182     face->num_fonts = 0;
183   }
184
185
186   static FT_Error
187   fnt_face_get_dll_fonts( FNT_Face  face )
188   {
189     FT_Error      error;
190     FT_Stream     stream = FT_FACE(face)->stream;
191     FT_Memory     memory = FT_FACE(face)->memory;
192     WinMZ_Header  mz_header;
193
194
195     face->fonts     = 0;
196     face->num_fonts = 0;
197
198     /* does it begin with a MZ header? */
199     if ( FILE_Seek( 0 )                                 ||
200          READ_Fields( winmz_header_fields, &mz_header ) )
201       goto Exit;
202
203     error = FNT_Err_Unknown_File_Format;
204     if ( mz_header.magic == WINFNT_MZ_MAGIC )
205     {
206       /* yes, now look for a NE header in the file */
207       WinNE_Header  ne_header;
208
209
210       if ( FILE_Seek( mz_header.lfanew )                  ||
211            READ_Fields( winne_header_fields, &ne_header ) )
212         goto Exit;
213
214       error = FNT_Err_Unknown_File_Format;
215       if ( ne_header.magic == WINFNT_NE_MAGIC )
216       {
217         /* good, now look in the resource table for each FNT resource */
218         FT_ULong   res_offset = mz_header.lfanew +
219                                 ne_header.resource_tab_offset;
220
221         FT_UShort  size_shift;
222         FT_UShort  font_count  = 0;
223         FT_ULong   font_offset = 0;
224
225
226         if ( FILE_Seek( res_offset ) ||
227              ACCESS_Frame( ne_header.rname_tab_offset -
228                            ne_header.resource_tab_offset ) )
229           goto Exit;
230
231         size_shift = GET_UShortLE();
232
233         for (;;)
234         {
235           FT_UShort  type_id, count;
236
237
238           type_id = GET_UShortLE();
239           if ( !type_id )
240             break;
241
242           count = GET_UShortLE();
243
244           if ( type_id == 0x8008 )
245           {
246             font_count  = count;
247             font_offset = (FT_ULong)( FILE_Pos() + 4 +
248                                       ( stream->cursor - stream->limit ) );
249             break;
250           }
251
252           stream->cursor += 4 + count * 12;
253         }
254         FORGET_Frame();
255
256         if ( !font_count || !font_offset )
257         {
258           FT_TRACE2(( "this file doesn't contain any FNT resources!\n" ));
259           error = FNT_Err_Unknown_File_Format;
260           goto Exit;
261         }
262
263         if ( FILE_Seek( font_offset )                         ||
264              ALLOC_ARRAY( face->fonts, font_count, FNT_Font ) )
265           goto Exit;
266
267         face->num_fonts = font_count;
268
269         if ( ACCESS_Frame( (FT_Long)font_count * 12 ) )
270           goto Exit;
271
272         /* now read the offset and position of each FNT font */
273         {
274           FNT_Font*  cur   = face->fonts;
275           FNT_Font*  limit = cur + font_count;
276
277
278           for ( ; cur < limit; cur++ )
279           {
280             cur->offset     = (FT_ULong)GET_UShortLE() << size_shift;
281             cur->fnt_size   = (FT_ULong)GET_UShortLE() << size_shift;
282             cur->size_shift = size_shift;
283             stream->cursor += 8;
284           }
285         }
286         FORGET_Frame();
287
288         /* finally, try to load each font there */
289         {
290           FNT_Font*  cur   = face->fonts;
291           FNT_Font*  limit = cur + font_count;
292
293
294           for ( ; cur < limit; cur++ )
295           {
296             error = fnt_font_load( cur, stream );
297             if ( error )
298               goto Fail;
299           }
300         }
301       }
302     }
303
304   Fail:
305     if ( error )
306       fnt_face_done_fonts( face );
307
308   Exit:
309     return error;
310   }
311
312
313   static void
314   FNT_Face_Done( FNT_Face  face )
315   {
316     FT_Memory  memory = FT_FACE_MEMORY( face );
317
318
319     fnt_face_done_fonts( face );
320
321     FREE( face->root.available_sizes );
322     face->root.num_fixed_sizes = 0;
323   }
324
325
326   static FT_Error
327   FNT_Face_Init( FT_Stream      stream,
328                  FNT_Face       face,
329                  FT_Int         face_index,
330                  FT_Int         num_params,
331                  FT_Parameter*  params )
332   {
333     FT_Error   error;
334     FT_Memory  memory = FT_FACE_MEMORY( face );
335
336     FT_UNUSED( num_params );
337     FT_UNUSED( params );
338     FT_UNUSED( face_index );
339
340
341     /* try to load several fonts from a DLL */
342     error = fnt_face_get_dll_fonts( face );
343     if ( error )
344     {
345       /* this didn't work, now try to load a single FNT font */
346       FNT_Font*  font;
347
348       if ( ALLOC( face->fonts, sizeof ( *face->fonts ) ) )
349         goto Exit;
350
351       face->num_fonts = 1;
352       font            = face->fonts;
353
354       font->offset   = 0;
355       font->fnt_size = stream->size;
356
357       error = fnt_font_load( font, stream );
358       if ( error )
359         goto Fail;
360     }
361
362     /* all right, one or more fonts were loaded; we now need to */
363     /* fill the root FT_Face fields with relevant information   */
364     {
365       FT_Face    root  = FT_FACE( face );
366       FNT_Font*  fonts = face->fonts;
367       FNT_Font*  limit = fonts + face->num_fonts;
368       FNT_Font*  cur;
369
370
371       root->num_faces  = 1;
372       root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
373                          FT_FACE_FLAG_HORIZONTAL;
374
375       if ( fonts->header.avg_width == fonts->header.max_width )
376         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
377
378       if ( fonts->header.italic )
379         root->style_flags |= FT_STYLE_FLAG_ITALIC;
380
381       if ( fonts->header.weight >= 800 )
382         root->style_flags |= FT_STYLE_FLAG_BOLD;
383
384       /* Setup the `fixed_sizes' array */
385       if ( ALLOC_ARRAY( root->available_sizes, face->num_fonts,
386                         FT_Bitmap_Size ) )
387         goto Fail;
388
389       root->num_fixed_sizes = face->num_fonts;
390
391       {
392         FT_Bitmap_Size*  size = root->available_sizes;
393
394
395         for ( cur = fonts; cur < limit; cur++, size++ )
396         {
397           size->width  = cur->header.pixel_width;
398           size->height = cur->header.pixel_height;
399         }
400       }
401
402       /* Setup the `charmaps' array */
403       root->charmaps     = &face->charmap_handle;
404       root->num_charmaps = 1;
405
406       face->charmap.encoding    = ft_encoding_unicode;
407       face->charmap.platform_id = 3;
408       face->charmap.encoding_id = 1;
409       face->charmap.face        = root;
410
411       face->charmap_handle = &face->charmap;
412
413       root->charmap = face->charmap_handle;
414
415       /* setup remaining flags */
416       root->num_glyphs = fonts->header.last_char -
417                          fonts->header.first_char + 1;
418
419       root->family_name = (FT_String*)fonts->fnt_frame +
420                           fonts->header.face_name_offset;
421       root->style_name  = (char *)"Regular";
422
423       if ( root->style_flags & FT_STYLE_FLAG_BOLD )
424       {
425         if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
426           root->style_name = (char *)"Bold Italic";
427         else
428           root->style_name = (char *)"Bold";
429       }
430       else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
431         root->style_name = (char *)"Italic";
432     }
433
434   Fail:
435     if ( error )
436       FNT_Face_Done( face );
437
438   Exit:
439     return error;
440   }
441
442
443   static FT_Error
444   FNT_Size_Set_Pixels( FNT_Size  size )
445   {
446     /* look up a font corresponding to the current pixel size */
447     FNT_Face   face  = (FNT_Face)FT_SIZE_FACE( size );
448     FNT_Font*  cur   = face->fonts;
449     FNT_Font*  limit = cur + face->num_fonts;
450
451
452     size->font = 0;
453     for ( ; cur < limit; cur++ )
454     {
455       /* we only compare the character height, as fonts used some strange */
456       /* values                                                           */
457       if ( cur->header.pixel_height == size->root.metrics.y_ppem )
458       {
459         size->font = cur;
460
461         size->root.metrics.ascender  = cur->header.ascent * 64;
462         size->root.metrics.descender = ( cur->header.pixel_height -
463                                            cur->header.ascent ) * 64;
464         size->root.metrics.height    = cur->header.pixel_height * 64;
465         break;
466       }
467     }
468
469     return ( size->font ? FNT_Err_Ok : FNT_Err_Invalid_Pixel_Size );
470   }
471
472
473   static FT_UInt
474   FNT_Get_Char_Index( FT_CharMap  charmap,
475                       FT_Long     char_code )
476   {
477     FT_Long  result = char_code;
478
479
480     if ( charmap )
481     {
482       FNT_Font*  font  = ((FNT_Face)charmap->face)->fonts;
483       FT_Long    first = font->header.first_char;
484       FT_Long    count = font->header.last_char - first + 1;
485
486
487       char_code -= first;
488       if ( char_code < count )
489         result = char_code + 1;
490       else
491         result = 0;
492     }
493
494     return result;
495   }
496
497
498   static FT_Error
499   FNT_Load_Glyph( FT_GlyphSlot  slot,
500                   FNT_Size      size,
501                   FT_UInt       glyph_index,
502                   FT_Int        load_flags )
503   {
504     FNT_Font*   font  = size->font;
505     FT_Error    error = 0;
506     FT_Byte*    p;
507     FT_Int      len;
508     FT_Bitmap*  bitmap = &slot->bitmap;
509     FT_ULong    offset;
510     FT_Bool     new_format;
511
512     FT_UNUSED( slot );
513     FT_UNUSED( load_flags );
514
515
516     if ( !font )
517     {
518       error = FNT_Err_Invalid_Argument;
519       goto Exit;
520     }
521
522     if ( glyph_index > 0 )
523       glyph_index--;
524     else
525       glyph_index = font->header.default_char - font->header.first_char;
526
527     new_format = FT_BOOL( font->header.version == 0x300 );
528     len        = new_format ? 6 : 4;
529
530     /* jump to glyph entry */
531     p = font->fnt_frame + 118 + len * glyph_index;
532
533     bitmap->width = NEXT_ShortLE(p);
534
535     if ( new_format )
536       offset = NEXT_ULongLE(p);
537     else
538       offset = NEXT_UShortLE(p);
539
540     /* jump to glyph data */
541     p = font->fnt_frame + /* font->header.bits_offset */ + offset;
542
543     /* allocate and build bitmap */
544     {
545       FT_Memory  memory = FT_FACE_MEMORY( slot->face );
546       FT_Int     pitch  = ( bitmap->width + 7 ) >> 3;
547       FT_Byte*   column;
548       FT_Byte*   write;
549
550
551       bitmap->pitch      = pitch;
552       bitmap->rows       = font->header.pixel_height;
553       bitmap->pixel_mode = ft_pixel_mode_mono;
554
555       if ( ALLOC( bitmap->buffer, pitch * bitmap->rows ) )
556         goto Exit;
557
558       column = (FT_Byte*)bitmap->buffer;
559
560       for ( ; pitch > 0; pitch--, column++ )
561       {
562         FT_Byte*  limit = p + bitmap->rows;
563
564
565         for ( write = column; p < limit; p++, write += bitmap->pitch )
566           write[0] = p[0];
567       }
568     }
569
570     slot->flags       = ft_glyph_own_bitmap;
571     slot->bitmap_left = 0;
572     slot->bitmap_top  = font->header.ascent;
573     slot->format      = ft_glyph_format_bitmap;
574
575     /* now set up metrics */
576     slot->metrics.horiAdvance  = bitmap->width << 6;
577     slot->metrics.horiBearingX = 0;
578     slot->metrics.horiBearingY = slot->bitmap_top << 6;
579
580     slot->linearHoriAdvance    = (FT_Fixed)bitmap->width << 16;
581     slot->format               = ft_glyph_format_bitmap;
582
583   Exit:
584     return error;
585   }
586
587
588   FT_CALLBACK_TABLE_DEF
589   const FT_Driver_Class  winfnt_driver_class =
590   {
591     {
592       ft_module_font_driver,
593       sizeof ( FT_DriverRec ),
594
595       "winfonts",
596       0x10000L,
597       0x20000L,
598
599       0,
600
601       (FT_Module_Constructor)0,
602       (FT_Module_Destructor) 0,
603       (FT_Module_Requester)  0
604     },
605
606     sizeof( FNT_FaceRec ),
607     sizeof( FNT_SizeRec ),
608     sizeof( FT_GlyphSlotRec ),
609
610     (FTDriver_initFace)     FNT_Face_Init,
611     (FTDriver_doneFace)     FNT_Face_Done,
612     (FTDriver_initSize)     0,
613     (FTDriver_doneSize)     0,
614     (FTDriver_initGlyphSlot)0,
615     (FTDriver_doneGlyphSlot)0,
616
617     (FTDriver_setCharSizes) FNT_Size_Set_Pixels,
618     (FTDriver_setPixelSizes)FNT_Size_Set_Pixels,
619
620     (FTDriver_loadGlyph)    FNT_Load_Glyph,
621     (FTDriver_getCharIndex) FNT_Get_Char_Index,
622
623     (FTDriver_getKerning)   0,
624     (FTDriver_attachFile)   0,
625     (FTDriver_getAdvances)  0
626   };
627
628
629 #ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
630
631
632   /*************************************************************************/
633   /*                                                                       */
634   /* <Function>                                                            */
635   /*    getDriverClass                                                     */
636   /*                                                                       */
637   /* <Description>                                                         */
638   /*    This function is used when compiling the TrueType driver as a      */
639   /*    shared library (`.DLL' or `.so').  It will be used by the          */
640   /*    high-level library of FreeType to retrieve the address of the      */
641   /*    driver's generic interface.                                        */
642   /*                                                                       */
643   /*    It shouldn't be implemented in a static build, as each driver must */
644   /*    have the same function as an exported entry point.                 */
645   /*                                                                       */
646   /* <Return>                                                              */
647   /*    The address of the TrueType's driver generic interface.  The       */
648   /*    format-specific interface can then be retrieved through the method */
649   /*    interface->get_format_interface.                                   */
650   /*                                                                       */
651   FT_EXPORT_DEF( const FT_Driver_Class* )
652   getDriverClass( void )
653   {
654     return &winfnt_driver_class;
655   }
656
657
658 #endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */
659
660
661 /* END */