Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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 <ft2build.h>
  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 */
  1156.