winfnt.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  winfnt.c                                                               */
00004 /*                                                                         */
00005 /*    FreeType font driver for Windows FNT/FON files                       */
00006 /*                                                                         */
00007 /*  Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009 by       */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*  Copyright 2003 Huw D M Davies for Codeweavers                          */
00010 /*  Copyright 2007 Dmitry Timoshkov for Codeweavers                        */
00011 /*                                                                         */
00012 /*  This file is part of the FreeType project, and may only be used,       */
00013 /*  modified, and distributed under the terms of the FreeType project      */
00014 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00015 /*  this file you indicate that you have read the license and              */
00016 /*  understand and accept it fully.                                        */
00017 /*                                                                         */
00018 /***************************************************************************/
00019 
00020 
00021 #include <ft2build.h>
00022 #include FT_WINFONTS_H
00023 #include FT_INTERNAL_DEBUG_H
00024 #include FT_INTERNAL_STREAM_H
00025 #include FT_INTERNAL_OBJECTS_H
00026 
00027 #include "winfnt.h"
00028 #include "fnterrs.h"
00029 #include FT_SERVICE_WINFNT_H
00030 #include FT_SERVICE_XFREE86_NAME_H
00031 
00032   /*************************************************************************/
00033   /*                                                                       */
00034   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00035   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00036   /* messages during execution.                                            */
00037   /*                                                                       */
00038 #undef  FT_COMPONENT
00039 #define FT_COMPONENT  trace_winfnt
00040 
00041 
00042   static const FT_Frame_Field  winmz_header_fields[] =
00043   {
00044 #undef  FT_STRUCTURE
00045 #define FT_STRUCTURE  WinMZ_HeaderRec
00046 
00047     FT_FRAME_START( 64 ),
00048       FT_FRAME_USHORT_LE ( magic ),
00049       FT_FRAME_SKIP_BYTES( 29 * 2 ),
00050       FT_FRAME_ULONG_LE  ( lfanew ),
00051     FT_FRAME_END
00052   };
00053 
00054   static const FT_Frame_Field  winne_header_fields[] =
00055   {
00056 #undef  FT_STRUCTURE
00057 #define FT_STRUCTURE  WinNE_HeaderRec
00058 
00059     FT_FRAME_START( 40 ),
00060       FT_FRAME_USHORT_LE ( magic ),
00061       FT_FRAME_SKIP_BYTES( 34 ),
00062       FT_FRAME_USHORT_LE ( resource_tab_offset ),
00063       FT_FRAME_USHORT_LE ( rname_tab_offset ),
00064     FT_FRAME_END
00065   };
00066 
00067   static const FT_Frame_Field  winpe32_header_fields[] =
00068   {
00069 #undef  FT_STRUCTURE
00070 #define FT_STRUCTURE  WinPE32_HeaderRec
00071 
00072     FT_FRAME_START( 248 ),
00073       FT_FRAME_ULONG_LE  ( magic ),   /* PE00 */
00074       FT_FRAME_USHORT_LE ( machine ), /* 0x014c - i386 */
00075       FT_FRAME_USHORT_LE ( number_of_sections ),
00076       FT_FRAME_SKIP_BYTES( 12 ),
00077       FT_FRAME_USHORT_LE ( size_of_optional_header ),
00078       FT_FRAME_SKIP_BYTES( 2 ),
00079       FT_FRAME_USHORT_LE ( magic32 ), /* 0x10b */
00080       FT_FRAME_SKIP_BYTES( 110 ),
00081       FT_FRAME_ULONG_LE  ( rsrc_virtual_address ),
00082       FT_FRAME_ULONG_LE  ( rsrc_size ),
00083       FT_FRAME_SKIP_BYTES( 104 ),
00084     FT_FRAME_END
00085   };
00086 
00087   static const FT_Frame_Field  winpe32_section_fields[] =
00088   {
00089 #undef  FT_STRUCTURE
00090 #define FT_STRUCTURE  WinPE32_SectionRec
00091 
00092     FT_FRAME_START( 40 ),
00093       FT_FRAME_BYTES     ( name, 8 ),
00094       FT_FRAME_SKIP_BYTES( 4 ),
00095       FT_FRAME_ULONG_LE  ( virtual_address ),
00096       FT_FRAME_ULONG_LE  ( size_of_raw_data ),
00097       FT_FRAME_ULONG_LE  ( pointer_to_raw_data ),
00098       FT_FRAME_SKIP_BYTES( 16 ),
00099     FT_FRAME_END
00100   };
00101 
00102   static const FT_Frame_Field  winpe_rsrc_dir_fields[] =
00103   {
00104 #undef  FT_STRUCTURE
00105 #define FT_STRUCTURE  WinPE_RsrcDirRec
00106 
00107     FT_FRAME_START( 16 ),
00108       FT_FRAME_ULONG_LE ( characteristics ),
00109       FT_FRAME_ULONG_LE ( time_date_stamp ),
00110       FT_FRAME_USHORT_LE( major_version ),
00111       FT_FRAME_USHORT_LE( minor_version ),
00112       FT_FRAME_USHORT_LE( number_of_named_entries ),
00113       FT_FRAME_USHORT_LE( number_of_id_entries ),
00114     FT_FRAME_END
00115   };
00116 
00117   static const FT_Frame_Field  winpe_rsrc_dir_entry_fields[] =
00118   {
00119 #undef  FT_STRUCTURE
00120 #define FT_STRUCTURE  WinPE_RsrcDirEntryRec
00121 
00122     FT_FRAME_START( 8 ),
00123       FT_FRAME_ULONG_LE( name ),
00124       FT_FRAME_ULONG_LE( offset ),
00125     FT_FRAME_END
00126   };
00127 
00128   static const FT_Frame_Field  winpe_rsrc_data_entry_fields[] =
00129   {
00130 #undef  FT_STRUCTURE
00131 #define FT_STRUCTURE  WinPE_RsrcDataEntryRec
00132 
00133     FT_FRAME_START( 16 ),
00134       FT_FRAME_ULONG_LE( offset_to_data ),
00135       FT_FRAME_ULONG_LE( size ),
00136       FT_FRAME_ULONG_LE( code_page ),
00137       FT_FRAME_ULONG_LE( reserved ),
00138     FT_FRAME_END
00139   };
00140 
00141   static const FT_Frame_Field  winfnt_header_fields[] =
00142   {
00143 #undef  FT_STRUCTURE
00144 #define FT_STRUCTURE  FT_WinFNT_HeaderRec
00145 
00146     FT_FRAME_START( 148 ),
00147       FT_FRAME_USHORT_LE( version ),
00148       FT_FRAME_ULONG_LE ( file_size ),
00149       FT_FRAME_BYTES    ( copyright, 60 ),
00150       FT_FRAME_USHORT_LE( file_type ),
00151       FT_FRAME_USHORT_LE( nominal_point_size ),
00152       FT_FRAME_USHORT_LE( vertical_resolution ),
00153       FT_FRAME_USHORT_LE( horizontal_resolution ),
00154       FT_FRAME_USHORT_LE( ascent ),
00155       FT_FRAME_USHORT_LE( internal_leading ),
00156       FT_FRAME_USHORT_LE( external_leading ),
00157       FT_FRAME_BYTE     ( italic ),
00158       FT_FRAME_BYTE     ( underline ),
00159       FT_FRAME_BYTE     ( strike_out ),
00160       FT_FRAME_USHORT_LE( weight ),
00161       FT_FRAME_BYTE     ( charset ),
00162       FT_FRAME_USHORT_LE( pixel_width ),
00163       FT_FRAME_USHORT_LE( pixel_height ),
00164       FT_FRAME_BYTE     ( pitch_and_family ),
00165       FT_FRAME_USHORT_LE( avg_width ),
00166       FT_FRAME_USHORT_LE( max_width ),
00167       FT_FRAME_BYTE     ( first_char ),
00168       FT_FRAME_BYTE     ( last_char ),
00169       FT_FRAME_BYTE     ( default_char ),
00170       FT_FRAME_BYTE     ( break_char ),
00171       FT_FRAME_USHORT_LE( bytes_per_row ),
00172       FT_FRAME_ULONG_LE ( device_offset ),
00173       FT_FRAME_ULONG_LE ( face_name_offset ),
00174       FT_FRAME_ULONG_LE ( bits_pointer ),
00175       FT_FRAME_ULONG_LE ( bits_offset ),
00176       FT_FRAME_BYTE     ( reserved ),
00177       FT_FRAME_ULONG_LE ( flags ),
00178       FT_FRAME_USHORT_LE( A_space ),
00179       FT_FRAME_USHORT_LE( B_space ),
00180       FT_FRAME_USHORT_LE( C_space ),
00181       FT_FRAME_ULONG_LE ( color_table_offset ),
00182       FT_FRAME_BYTES    ( reserved1, 16 ),
00183     FT_FRAME_END
00184   };
00185 
00186 
00187   static void
00188   fnt_font_done( FNT_Face face )
00189   {
00190     FT_Memory  memory = FT_FACE( face )->memory;
00191     FT_Stream  stream = FT_FACE( face )->stream;
00192     FNT_Font   font   = face->font;
00193 
00194 
00195     if ( !font )
00196       return;
00197 
00198     if ( font->fnt_frame )
00199       FT_FRAME_RELEASE( font->fnt_frame );
00200     FT_FREE( font->family_name );
00201 
00202     FT_FREE( font );
00203     face->font = 0;
00204   }
00205 
00206 
00207   static FT_Error
00208   fnt_font_load( FNT_Font   font,
00209                  FT_Stream  stream )
00210   {
00211     FT_Error          error;
00212     FT_WinFNT_Header  header = &font->header;
00213     FT_Bool           new_format;
00214     FT_UInt           size;
00215 
00216 
00217     /* first of all, read the FNT header */
00218     if ( FT_STREAM_SEEK( font->offset )                        ||
00219          FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) )
00220       goto Exit;
00221 
00222     /* check header */
00223     if ( header->version != 0x200 &&
00224          header->version != 0x300 )
00225     {
00226       FT_TRACE2(( "[not a valid FNT file]\n" ));
00227       error = FNT_Err_Unknown_File_Format;
00228       goto Exit;
00229     }
00230 
00231     new_format = FT_BOOL( font->header.version == 0x300 );
00232     size       = new_format ? 148 : 118;
00233 
00234     if ( header->file_size < size )
00235     {
00236       FT_TRACE2(( "[not a valid FNT file]\n" ));
00237       error = FNT_Err_Unknown_File_Format;
00238       goto Exit;
00239     }
00240 
00241     /* Version 2 doesn't have these fields */
00242     if ( header->version == 0x200 )
00243     {
00244       header->flags   = 0;
00245       header->A_space = 0;
00246       header->B_space = 0;
00247       header->C_space = 0;
00248 
00249       header->color_table_offset = 0;
00250     }
00251 
00252     if ( header->file_type & 1 )
00253     {
00254       FT_TRACE2(( "[can't handle vector FNT fonts]\n" ));
00255       error = FNT_Err_Unknown_File_Format;
00256       goto Exit;
00257     }
00258 
00259     /* this is a FNT file/table; extract its frame */
00260     if ( FT_STREAM_SEEK( font->offset )                         ||
00261          FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) )
00262       goto Exit;
00263 
00264   Exit:
00265     return error;
00266   }
00267 
00268 
00269   static FT_Error
00270   fnt_face_get_dll_font( FNT_Face  face,
00271                          FT_Int    face_index )
00272   {
00273     FT_Error         error;
00274     FT_Stream        stream = FT_FACE( face )->stream;
00275     FT_Memory        memory = FT_FACE( face )->memory;
00276     WinMZ_HeaderRec  mz_header;
00277 
00278 
00279     face->font = 0;
00280 
00281     /* does it begin with an MZ header? */
00282     if ( FT_STREAM_SEEK( 0 )                                      ||
00283          FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) )
00284       goto Exit;
00285 
00286     error = FNT_Err_Unknown_File_Format;
00287     if ( mz_header.magic == WINFNT_MZ_MAGIC )
00288     {
00289       /* yes, now look for an NE header in the file */
00290       WinNE_HeaderRec  ne_header;
00291 
00292 
00293       FT_TRACE2(( "MZ signature found\n" ));
00294 
00295       if ( FT_STREAM_SEEK( mz_header.lfanew )                       ||
00296            FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) )
00297         goto Exit;
00298 
00299       error = FNT_Err_Unknown_File_Format;
00300       if ( ne_header.magic == WINFNT_NE_MAGIC )
00301       {
00302         /* good, now look into the resource table for each FNT resource */
00303         FT_ULong   res_offset  = mz_header.lfanew +
00304                                    ne_header.resource_tab_offset;
00305         FT_UShort  size_shift;
00306         FT_UShort  font_count  = 0;
00307         FT_ULong   font_offset = 0;
00308 
00309 
00310         FT_TRACE2(( "NE signature found\n" ));
00311 
00312         if ( FT_STREAM_SEEK( res_offset )                    ||
00313              FT_FRAME_ENTER( ne_header.rname_tab_offset -
00314                              ne_header.resource_tab_offset ) )
00315           goto Exit;
00316 
00317         size_shift = FT_GET_USHORT_LE();
00318 
00319         for (;;)
00320         {
00321           FT_UShort  type_id, count;
00322 
00323 
00324           type_id = FT_GET_USHORT_LE();
00325           if ( !type_id )
00326             break;
00327 
00328           count = FT_GET_USHORT_LE();
00329 
00330           if ( type_id == 0x8008U )
00331           {
00332             font_count  = count;
00333             font_offset = (FT_ULong)( FT_STREAM_POS() + 4 +
00334                                       ( stream->cursor - stream->limit ) );
00335             break;
00336           }
00337 
00338           stream->cursor += 4 + count * 12;
00339         }
00340 
00341         FT_FRAME_EXIT();
00342 
00343         if ( !font_count || !font_offset )
00344         {
00345           FT_TRACE2(( "this file doesn't contain any FNT resources\n" ));
00346           error = FNT_Err_Invalid_File_Format;
00347           goto Exit;
00348         }
00349 
00350         /* loading `winfnt_header_fields' needs at least 118 bytes;    */
00351         /* use this as a rough measure to check the expected font size */
00352         if ( font_count * 118UL > stream->size )
00353         {
00354           FT_TRACE2(( "invalid number of faces\n" ));
00355           error = FNT_Err_Invalid_File_Format;
00356           goto Exit;
00357         }
00358 
00359         face->root.num_faces = font_count;
00360 
00361         if ( face_index >= font_count )
00362         {
00363           error = FNT_Err_Invalid_Argument;
00364           goto Exit;
00365         }
00366         else if ( face_index < 0 )
00367           goto Exit;
00368 
00369         if ( FT_NEW( face->font ) )
00370           goto Exit;
00371 
00372         if ( FT_STREAM_SEEK( font_offset + face_index * 12 ) ||
00373              FT_FRAME_ENTER( 12 )                            )
00374           goto Fail;
00375 
00376         face->font->offset   = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
00377         face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
00378 
00379         stream->cursor += 8;
00380 
00381         FT_FRAME_EXIT();
00382 
00383         error = fnt_font_load( face->font, stream );
00384       }
00385       else if ( ne_header.magic == WINFNT_PE_MAGIC )
00386       {
00387         WinPE32_HeaderRec       pe32_header;
00388         WinPE32_SectionRec      pe32_section;
00389         WinPE_RsrcDirRec        root_dir, name_dir, lang_dir;
00390         WinPE_RsrcDirEntryRec   dir_entry1, dir_entry2, dir_entry3;
00391         WinPE_RsrcDataEntryRec  data_entry;
00392 
00393         FT_Long    root_dir_offset, name_dir_offset, lang_dir_offset;
00394         FT_UShort  i, j, k;
00395 
00396 
00397         FT_TRACE2(( "PE signature found\n" ));
00398 
00399         if ( FT_STREAM_SEEK( mz_header.lfanew )                           ||
00400              FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) )
00401           goto Exit;
00402 
00403         FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, "
00404                     "size_of_optional_header %02x\n"
00405                     "magic32 %02x, rsrc_virtual_address %04lx, "
00406                     "rsrc_size %04lx\n",
00407                     pe32_header.magic, pe32_header.machine,
00408                     pe32_header.number_of_sections,
00409                     pe32_header.size_of_optional_header,
00410                     pe32_header.magic32, pe32_header.rsrc_virtual_address,
00411                     pe32_header.rsrc_size ));
00412 
00413         if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ ||
00414              pe32_header.machine != 0x014c /* i386 */                        ||
00415              pe32_header.size_of_optional_header != 0xe0 /* FIXME */         ||
00416              pe32_header.magic32 != 0x10b                                    )
00417         {
00418           FT_TRACE2(( "this file has an invalid PE header\n" ));
00419           error = FNT_Err_Invalid_File_Format;
00420           goto Exit;
00421         }
00422 
00423         face->root.num_faces = 0;
00424 
00425         for ( i = 0; i < pe32_header.number_of_sections; i++ )
00426         {
00427           if ( FT_STREAM_READ_FIELDS( winpe32_section_fields,
00428                                       &pe32_section ) )
00429             goto Exit;
00430 
00431           FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n",
00432                       pe32_section.name, pe32_section.virtual_address,
00433                       pe32_section.size_of_raw_data,
00434                       pe32_section.pointer_to_raw_data ));
00435 
00436           if ( pe32_header.rsrc_virtual_address ==
00437                  pe32_section.virtual_address )
00438             goto Found_rsrc_section;
00439         }
00440 
00441         FT_TRACE2(( "this file doesn't contain any resources\n" ));
00442         error = FNT_Err_Invalid_File_Format;
00443         goto Exit;
00444 
00445       Found_rsrc_section:
00446         FT_TRACE2(( "found resources section %.8s\n", pe32_section.name ));
00447 
00448         if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data )        ||
00449              FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) )
00450           goto Exit;
00451 
00452         root_dir_offset = pe32_section.pointer_to_raw_data;
00453 
00454         for ( i = 0; i < root_dir.number_of_named_entries +
00455                            root_dir.number_of_id_entries; i++ )
00456         {
00457           if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 )      ||
00458                FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
00459                                       &dir_entry1 )                )
00460             goto Exit;
00461 
00462           if ( !(dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ )
00463           {
00464             error = FNT_Err_Invalid_File_Format;
00465             goto Exit;
00466           }
00467 
00468           dir_entry1.offset &= ~0x80000000UL;
00469 
00470           name_dir_offset = pe32_section.pointer_to_raw_data +
00471                             dir_entry1.offset;
00472 
00473           if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data +
00474                                dir_entry1.offset )                       ||
00475                FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) )
00476             goto Exit;
00477 
00478           for ( j = 0; j < name_dir.number_of_named_entries +
00479                              name_dir.number_of_id_entries; j++ )
00480           {
00481             if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 )      ||
00482                  FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
00483                                         &dir_entry2 )                )
00484               goto Exit;
00485 
00486             if ( !(dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ )
00487             {
00488               error = FNT_Err_Invalid_File_Format;
00489               goto Exit;
00490             }
00491 
00492             dir_entry2.offset &= ~0x80000000UL;
00493 
00494             lang_dir_offset = pe32_section.pointer_to_raw_data +
00495                                 dir_entry2.offset;
00496 
00497             if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data +
00498                                    dir_entry2.offset )                     ||
00499                  FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) )
00500               goto Exit;
00501 
00502             for ( k = 0; k < lang_dir.number_of_named_entries +
00503                                lang_dir.number_of_id_entries; k++ )
00504             {
00505               if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 )      ||
00506                    FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
00507                                           &dir_entry3 )                )
00508                 goto Exit;
00509 
00510               if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ )
00511               {
00512                 error = FNT_Err_Invalid_File_Format;
00513                 goto Exit;
00514               }
00515 
00516               if ( dir_entry1.name == 8 /* RT_FONT */ )
00517               {
00518                 if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) ||
00519                      FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields,
00520                                             &data_entry )                  )
00521                   goto Exit;
00522 
00523                 FT_TRACE2(( "found font #%lu, offset %04lx, "
00524                             "size %04lx, cp %lu\n",
00525                             dir_entry2.name,
00526                             pe32_section.pointer_to_raw_data +
00527                               data_entry.offset_to_data -
00528                               pe32_section.virtual_address,
00529                             data_entry.size, data_entry.code_page ));
00530 
00531                 if ( face_index == face->root.num_faces )
00532                 {
00533                   if ( FT_NEW( face->font ) )
00534                     goto Exit;
00535 
00536                   face->font->offset   = pe32_section.pointer_to_raw_data +
00537                                            data_entry.offset_to_data -
00538                                            pe32_section.virtual_address;
00539                   face->font->fnt_size = data_entry.size;
00540 
00541                   error = fnt_font_load( face->font, stream );
00542                   if ( error )
00543                   {
00544                     FT_TRACE2(( "font #%lu load error %d\n",
00545                                 dir_entry2.name, error ));
00546                     goto Fail;
00547                   }
00548                   else
00549                     FT_TRACE2(( "font #%lu successfully loaded\n",
00550                                 dir_entry2.name ));
00551                 }
00552 
00553                 face->root.num_faces++;
00554               }
00555             }
00556           }
00557         }
00558       }
00559 
00560       if ( !face->root.num_faces )
00561       {
00562         FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" ));
00563         error = FNT_Err_Invalid_File_Format;
00564         goto Exit;
00565       }
00566 
00567       if ( face_index >= face->root.num_faces )
00568       {
00569         error = FNT_Err_Invalid_Argument;
00570         goto Exit;
00571       }
00572     }
00573 
00574   Fail:
00575     if ( error )
00576       fnt_font_done( face );
00577 
00578   Exit:
00579     return error;
00580   }
00581 
00582 
00583   typedef struct  FNT_CMapRec_
00584   {
00585     FT_CMapRec  cmap;
00586     FT_UInt32   first;
00587     FT_UInt32   count;
00588 
00589   } FNT_CMapRec, *FNT_CMap;
00590 
00591 
00592   static FT_Error
00593   fnt_cmap_init( FNT_CMap  cmap )
00594   {
00595     FNT_Face  face = (FNT_Face)FT_CMAP_FACE( cmap );
00596     FNT_Font  font = face->font;
00597 
00598 
00599     cmap->first = (FT_UInt32)  font->header.first_char;
00600     cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 );
00601 
00602     return 0;
00603   }
00604 
00605 
00606   static FT_UInt
00607   fnt_cmap_char_index( FNT_CMap   cmap,
00608                        FT_UInt32  char_code )
00609   {
00610     FT_UInt  gindex = 0;
00611 
00612 
00613     char_code -= cmap->first;
00614     if ( char_code < cmap->count )
00615       /* we artificially increase the glyph index; */
00616       /* FNT_Load_Glyph reverts to the right one   */
00617       gindex = (FT_UInt)( char_code + 1 );
00618     return gindex;
00619   }
00620 
00621 
00622   static FT_UInt32
00623   fnt_cmap_char_next( FNT_CMap    cmap,
00624                       FT_UInt32  *pchar_code )
00625   {
00626     FT_UInt    gindex = 0;
00627     FT_UInt32  result = 0;
00628     FT_UInt32  char_code = *pchar_code + 1;
00629 
00630 
00631     if ( char_code <= cmap->first )
00632     {
00633       result = cmap->first;
00634       gindex = 1;
00635     }
00636     else
00637     {
00638       char_code -= cmap->first;
00639       if ( char_code < cmap->count )
00640       {
00641         result = cmap->first + char_code;
00642         gindex = (FT_UInt)( char_code + 1 );
00643       }
00644     }
00645 
00646     *pchar_code = result;
00647     return gindex;
00648   }
00649 
00650 
00651   static const FT_CMap_ClassRec  fnt_cmap_class_rec =
00652   {
00653     sizeof ( FNT_CMapRec ),
00654 
00655     (FT_CMap_InitFunc)     fnt_cmap_init,
00656     (FT_CMap_DoneFunc)     NULL,
00657     (FT_CMap_CharIndexFunc)fnt_cmap_char_index,
00658     (FT_CMap_CharNextFunc) fnt_cmap_char_next,
00659 
00660     NULL, NULL, NULL, NULL, NULL
00661   };
00662 
00663   static FT_CMap_Class const  fnt_cmap_class = &fnt_cmap_class_rec;
00664 
00665 
00666   static void
00667   FNT_Face_Done( FNT_Face  face )
00668   {
00669     FT_Memory  memory;
00670 
00671 
00672     if ( !face )
00673       return;
00674 
00675     memory = FT_FACE_MEMORY( face );
00676 
00677     fnt_font_done( face );
00678 
00679     FT_FREE( face->root.available_sizes );
00680     face->root.num_fixed_sizes = 0;
00681   }
00682 
00683 
00684   static FT_Error
00685   FNT_Face_Init( FT_Stream      stream,
00686                  FNT_Face       face,
00687                  FT_Int         face_index,
00688                  FT_Int         num_params,
00689                  FT_Parameter*  params )
00690   {
00691     FT_Error   error;
00692     FT_Memory  memory = FT_FACE_MEMORY( face );
00693 
00694     FT_UNUSED( num_params );
00695     FT_UNUSED( params );
00696 
00697 
00698     /* try to load font from a DLL */
00699     error = fnt_face_get_dll_font( face, face_index );
00700     if ( !error && face_index < 0 )
00701       goto Exit;
00702 
00703     if ( error == FNT_Err_Unknown_File_Format )
00704     {
00705       /* this didn't work; try to load a single FNT font */
00706       FNT_Font  font;
00707 
00708       if ( FT_NEW( face->font ) )
00709         goto Exit;
00710 
00711       face->root.num_faces = 1;
00712 
00713       font           = face->font;
00714       font->offset   = 0;
00715       font->fnt_size = stream->size;
00716 
00717       error = fnt_font_load( font, stream );
00718 
00719       if ( !error )
00720       {
00721         if ( face_index > 0 )
00722           error = FNT_Err_Invalid_Argument;
00723         else if ( face_index < 0 )
00724           goto Exit;
00725       }
00726     }
00727 
00728     if ( error )
00729       goto Fail;
00730 
00731     /* we now need to fill the root FT_Face fields */
00732     /* with relevant information                   */
00733     {
00734       FT_Face     root = FT_FACE( face );
00735       FNT_Font    font = face->font;
00736       FT_PtrDist  family_size;
00737 
00738 
00739       root->face_index = face_index;
00740 
00741       root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
00742                          FT_FACE_FLAG_HORIZONTAL;
00743 
00744       if ( font->header.avg_width == font->header.max_width )
00745         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
00746 
00747       if ( font->header.italic )
00748         root->style_flags |= FT_STYLE_FLAG_ITALIC;
00749 
00750       if ( font->header.weight >= 800 )
00751         root->style_flags |= FT_STYLE_FLAG_BOLD;
00752 
00753       /* set up the `fixed_sizes' array */
00754       if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
00755         goto Fail;
00756 
00757       root->num_fixed_sizes = 1;
00758 
00759       {
00760         FT_Bitmap_Size*  bsize = root->available_sizes;
00761         FT_UShort        x_res, y_res;
00762 
00763 
00764         bsize->width  = font->header.avg_width;
00765         bsize->height = (FT_Short)(
00766           font->header.pixel_height + font->header.external_leading );
00767         bsize->size   = font->header.nominal_point_size << 6;
00768 
00769         x_res = font->header.horizontal_resolution;
00770         if ( !x_res )
00771           x_res = 72;
00772 
00773         y_res = font->header.vertical_resolution;
00774         if ( !y_res )
00775           y_res = 72;
00776 
00777         bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 );
00778         bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem );
00779 
00780         /*
00781          * this reads:
00782          *
00783          * the nominal height is larger than the bbox's height
00784          *
00785          * => nominal_point_size contains incorrect value;
00786          *    use pixel_height as the nominal height
00787          */
00788         if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) )
00789         {
00790           FT_TRACE2(( "use pixel_height as the nominal height\n" ));
00791 
00792           bsize->y_ppem = font->header.pixel_height << 6;
00793           bsize->size   = FT_MulDiv( bsize->y_ppem, 72, y_res );
00794         }
00795 
00796         bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 );
00797         bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem );
00798       }
00799 
00800       {
00801         FT_CharMapRec  charmap;
00802 
00803 
00804         charmap.encoding    = FT_ENCODING_NONE;
00805         charmap.platform_id = 0;
00806         charmap.encoding_id = 0;
00807         charmap.face        = root;
00808 
00809         if ( font->header.charset == FT_WinFNT_ID_MAC )
00810         {
00811           charmap.encoding    = FT_ENCODING_APPLE_ROMAN;
00812           charmap.platform_id = 1;
00813 /*        charmap.encoding_id = 0; */
00814         }
00815 
00816         error = FT_CMap_New( fnt_cmap_class,
00817                              NULL,
00818                              &charmap,
00819                              NULL );
00820         if ( error )
00821           goto Fail;
00822 
00823         /* Select default charmap */
00824         if ( root->num_charmaps )
00825           root->charmap = root->charmaps[0];
00826       }
00827 
00828       /* setup remaining flags */
00829 
00830       /* reserve one slot for the .notdef glyph at index 0 */
00831       root->num_glyphs = font->header.last_char -
00832                          font->header.first_char + 1 + 1;
00833 
00834       if ( font->header.face_name_offset >= font->header.file_size )
00835       {
00836         FT_TRACE2(( "invalid family name offset\n" ));
00837         error = FNT_Err_Invalid_File_Format;
00838         goto Fail;
00839       }
00840       family_size = font->header.file_size - font->header.face_name_offset;
00841       /* Some broken fonts don't delimit the face name with a final */
00842       /* NULL byte -- the frame is erroneously one byte too small.  */
00843       /* We thus allocate one more byte, setting it explicitly to   */
00844       /* zero.                                                      */
00845       if ( FT_ALLOC( font->family_name, family_size + 1 ) )
00846         goto Fail;
00847 
00848       FT_MEM_COPY( font->family_name,
00849                    font->fnt_frame + font->header.face_name_offset,
00850                    family_size );
00851 
00852       font->family_name[family_size] = '\0';
00853 
00854       if ( FT_REALLOC( font->family_name,
00855                        family_size,
00856                        ft_strlen( font->family_name ) + 1 ) )
00857         goto Fail;
00858 
00859       root->family_name = font->family_name;
00860       root->style_name  = (char *)"Regular";
00861 
00862       if ( root->style_flags & FT_STYLE_FLAG_BOLD )
00863       {
00864         if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
00865           root->style_name = (char *)"Bold Italic";
00866         else
00867           root->style_name = (char *)"Bold";
00868       }
00869       else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
00870         root->style_name = (char *)"Italic";
00871     }
00872     goto Exit;
00873 
00874   Fail:
00875     FNT_Face_Done( face );
00876 
00877   Exit:
00878     return error;
00879   }
00880 
00881 
00882   static FT_Error
00883   FNT_Size_Select( FT_Size  size )
00884   {
00885     FNT_Face          face   = (FNT_Face)size->face;
00886     FT_WinFNT_Header  header = &face->font->header;
00887 
00888 
00889     FT_Select_Metrics( size->face, 0 );
00890 
00891     size->metrics.ascender    = header->ascent * 64;
00892     size->metrics.descender   = -( header->pixel_height -
00893                                    header->ascent ) * 64;
00894     size->metrics.max_advance = header->max_width * 64;
00895 
00896     return FNT_Err_Ok;
00897   }
00898 
00899 
00900   static FT_Error
00901   FNT_Size_Request( FT_Size          size,
00902                     FT_Size_Request  req )
00903   {
00904     FNT_Face          face    = (FNT_Face)size->face;
00905     FT_WinFNT_Header  header  = &face->font->header;
00906     FT_Bitmap_Size*   bsize   = size->face->available_sizes;
00907     FT_Error          error   = FNT_Err_Invalid_Pixel_Size;
00908     FT_Long           height;
00909 
00910 
00911     height = FT_REQUEST_HEIGHT( req );
00912     height = ( height + 32 ) >> 6;
00913 
00914     switch ( req->type )
00915     {
00916     case FT_SIZE_REQUEST_TYPE_NOMINAL:
00917       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
00918         error = FNT_Err_Ok;
00919       break;
00920 
00921     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
00922       if ( height == header->pixel_height )
00923         error = FNT_Err_Ok;
00924       break;
00925 
00926     default:
00927       error = FNT_Err_Unimplemented_Feature;
00928       break;
00929     }
00930 
00931     if ( error )
00932       return error;
00933     else
00934       return FNT_Size_Select( size );
00935   }
00936 
00937 
00938   static FT_Error
00939   FNT_Load_Glyph( FT_GlyphSlot  slot,
00940                   FT_Size       size,
00941                   FT_UInt       glyph_index,
00942                   FT_Int32      load_flags )
00943   {
00944     FNT_Face    face   = (FNT_Face)FT_SIZE_FACE( size );
00945     FNT_Font    font   = face->font;
00946     FT_Error    error  = FNT_Err_Ok;
00947     FT_Byte*    p;
00948     FT_Int      len;
00949     FT_Bitmap*  bitmap = &slot->bitmap;
00950     FT_ULong    offset;
00951     FT_Bool     new_format;
00952 
00953     FT_UNUSED( load_flags );
00954 
00955 
00956     if ( !face || !font ||
00957          glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) )
00958     {
00959       error = FNT_Err_Invalid_Argument;
00960       goto Exit;
00961     }
00962 
00963     if ( glyph_index > 0 )
00964       glyph_index--;                           /* revert to real index */
00965     else
00966       glyph_index = font->header.default_char; /* the .notdef glyph */
00967 
00968     new_format = FT_BOOL( font->header.version == 0x300 );
00969     len        = new_format ? 6 : 4;
00970 
00971     /* jump to glyph entry */
00972     p = font->fnt_frame + ( new_format ? 148 : 118 ) + len * glyph_index;
00973 
00974     bitmap->width = FT_NEXT_SHORT_LE( p );
00975 
00976     if ( new_format )
00977       offset = FT_NEXT_ULONG_LE( p );
00978     else
00979       offset = FT_NEXT_USHORT_LE( p );
00980 
00981     if ( offset >= font->header.file_size )
00982     {
00983       FT_TRACE2(( "invalid FNT offset\n" ));
00984       error = FNT_Err_Invalid_File_Format;
00985       goto Exit;
00986     }
00987 
00988     /* jump to glyph data */
00989     p = font->fnt_frame + /* font->header.bits_offset */ + offset;
00990 
00991     /* allocate and build bitmap */
00992     {
00993       FT_Memory  memory = FT_FACE_MEMORY( slot->face );
00994       FT_Int     pitch  = ( bitmap->width + 7 ) >> 3;
00995       FT_Byte*   column;
00996       FT_Byte*   write;
00997 
00998 
00999       bitmap->pitch      = pitch;
01000       bitmap->rows       = font->header.pixel_height;
01001       bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
01002 
01003       if ( offset + pitch * bitmap->rows >= font->header.file_size )
01004       {
01005         FT_TRACE2(( "invalid bitmap width\n" ));
01006         error = FNT_Err_Invalid_File_Format;
01007         goto Exit;
01008       }
01009 
01010       /* note: since glyphs are stored in columns and not in rows we */
01011       /*       can't use ft_glyphslot_set_bitmap                     */
01012       if ( FT_ALLOC_MULT( bitmap->buffer, pitch, bitmap->rows ) )
01013         goto Exit;
01014 
01015       column = (FT_Byte*)bitmap->buffer;
01016 
01017       for ( ; pitch > 0; pitch--, column++ )
01018       {
01019         FT_Byte*  limit = p + bitmap->rows;
01020 
01021 
01022         for ( write = column; p < limit; p++, write += bitmap->pitch )
01023           *write = *p;
01024       }
01025     }
01026 
01027     slot->internal->flags = FT_GLYPH_OWN_BITMAP;
01028     slot->bitmap_left     = 0;
01029     slot->bitmap_top      = font->header.ascent;
01030     slot->format          = FT_GLYPH_FORMAT_BITMAP;
01031 
01032     /* now set up metrics */
01033     slot->metrics.width        = bitmap->width << 6;
01034     slot->metrics.height       = bitmap->rows << 6;
01035     slot->metrics.horiAdvance  = bitmap->width << 6;
01036     slot->metrics.horiBearingX = 0;
01037     slot->metrics.horiBearingY = slot->bitmap_top << 6;
01038 
01039     ft_synthesize_vertical_metrics( &slot->metrics,
01040                                     bitmap->rows << 6 );
01041 
01042   Exit:
01043     return error;
01044   }
01045 
01046 
01047   static FT_Error
01048   winfnt_get_header( FT_Face               face,
01049                      FT_WinFNT_HeaderRec  *aheader )
01050   {
01051     FNT_Font  font = ((FNT_Face)face)->font;
01052 
01053 
01054     *aheader = font->header;
01055 
01056     return 0;
01057   }
01058 
01059 
01060   static const FT_Service_WinFntRec  winfnt_service_rec =
01061   {
01062     winfnt_get_header
01063   };
01064 
01065  /*
01066   *  SERVICE LIST
01067   *
01068   */
01069 
01070   static const FT_ServiceDescRec  winfnt_services[] =
01071   {
01072     { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_WINFNT },
01073     { FT_SERVICE_ID_WINFNT,    &winfnt_service_rec },
01074     { NULL, NULL }
01075   };
01076 
01077 
01078   static FT_Module_Interface
01079   winfnt_get_service( FT_Driver         driver,
01080                       const FT_String*  service_id )
01081   {
01082     FT_UNUSED( driver );
01083 
01084     return ft_service_list_lookup( winfnt_services, service_id );
01085   }
01086 
01087 
01088 
01089 
01090   FT_CALLBACK_TABLE_DEF
01091   const FT_Driver_ClassRec  winfnt_driver_class =
01092   {
01093     {
01094       FT_MODULE_FONT_DRIVER        |
01095       FT_MODULE_DRIVER_NO_OUTLINES,
01096       sizeof ( FT_DriverRec ),
01097 
01098       "winfonts",
01099       0x10000L,
01100       0x20000L,
01101 
01102       0,
01103 
01104       (FT_Module_Constructor)0,
01105       (FT_Module_Destructor) 0,
01106       (FT_Module_Requester)  winfnt_get_service
01107     },
01108 
01109     sizeof( FNT_FaceRec ),
01110     sizeof( FT_SizeRec ),
01111     sizeof( FT_GlyphSlotRec ),
01112 
01113     (FT_Face_InitFunc)        FNT_Face_Init,
01114     (FT_Face_DoneFunc)        FNT_Face_Done,
01115     (FT_Size_InitFunc)        0,
01116     (FT_Size_DoneFunc)        0,
01117     (FT_Slot_InitFunc)        0,
01118     (FT_Slot_DoneFunc)        0,
01119 
01120 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
01121     ft_stub_set_char_sizes,
01122     ft_stub_set_pixel_sizes,
01123 #endif
01124     (FT_Slot_LoadFunc)        FNT_Load_Glyph,
01125 
01126     (FT_Face_GetKerningFunc)  0,
01127     (FT_Face_AttachFunc)      0,
01128     (FT_Face_GetAdvancesFunc) 0,
01129 
01130     (FT_Size_RequestFunc)     FNT_Size_Request,
01131     (FT_Size_SelectFunc)      FNT_Size_Select
01132   };
01133 
01134 
01135 /* END */

Generated on Tue Jul 5 14:13:55 2011 for ROOT_528-00b_version by  doxygen 1.5.1