Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  t1afm.c                                                                */
  4. /*                                                                         */
  5. /*    AFM support for Type 1 fonts (body).                                 */
  6. /*                                                                         */
  7. /*  Copyright 1996-2011, 2013 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 "t1afm.h"
  21. #include FT_INTERNAL_DEBUG_H
  22. #include FT_INTERNAL_STREAM_H
  23. #include FT_INTERNAL_POSTSCRIPT_AUX_H
  24. #include "t1errors.h"
  25.  
  26.  
  27.   /*************************************************************************/
  28.   /*                                                                       */
  29.   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  30.   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  31.   /* messages during execution.                                            */
  32.   /*                                                                       */
  33. #undef  FT_COMPONENT
  34. #define FT_COMPONENT  trace_t1afm
  35.  
  36.  
  37.   FT_LOCAL_DEF( void )
  38.   T1_Done_Metrics( FT_Memory     memory,
  39.                    AFM_FontInfo  fi )
  40.   {
  41.     FT_FREE( fi->KernPairs );
  42.     fi->NumKernPair = 0;
  43.  
  44.     FT_FREE( fi->TrackKerns );
  45.     fi->NumTrackKern = 0;
  46.  
  47.     FT_FREE( fi );
  48.   }
  49.  
  50.  
  51.   /* read a glyph name and return the equivalent glyph index */
  52.   static FT_Int
  53.   t1_get_index( const char*  name,
  54.                 FT_Offset    len,
  55.                 void*        user_data )
  56.   {
  57.     T1_Font  type1 = (T1_Font)user_data;
  58.     FT_Int   n;
  59.  
  60.  
  61.     /* PS string/name length must be < 16-bit */
  62.     if ( len > 0xFFFFU )
  63.       return 0;
  64.  
  65.     for ( n = 0; n < type1->num_glyphs; n++ )
  66.     {
  67.       char*  gname = (char*)type1->glyph_names[n];
  68.  
  69.  
  70.       if ( gname && gname[0] == name[0]        &&
  71.            ft_strlen( gname ) == len           &&
  72.            ft_strncmp( gname, name, len ) == 0 )
  73.         return n;
  74.     }
  75.  
  76.     return 0;
  77.   }
  78.  
  79.  
  80. #undef  KERN_INDEX
  81. #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)(g1) << 16 ) | (g2) )
  82.  
  83.  
  84.   /* compare two kerning pairs */
  85.   FT_CALLBACK_DEF( int )
  86.   compare_kern_pairs( const void*  a,
  87.                       const void*  b )
  88.   {
  89.     AFM_KernPair  pair1 = (AFM_KernPair)a;
  90.     AFM_KernPair  pair2 = (AFM_KernPair)b;
  91.  
  92.     FT_ULong  index1 = KERN_INDEX( pair1->index1, pair1->index2 );
  93.     FT_ULong  index2 = KERN_INDEX( pair2->index1, pair2->index2 );
  94.  
  95.  
  96.     if ( index1 > index2 )
  97.       return 1;
  98.     else if ( index1 < index2 )
  99.       return -1;
  100.     else
  101.       return 0;
  102.   }
  103.  
  104.  
  105.   /* parse a PFM file -- for now, only read the kerning pairs */
  106.   static FT_Error
  107.   T1_Read_PFM( FT_Face       t1_face,
  108.                FT_Stream     stream,
  109.                AFM_FontInfo  fi )
  110.   {
  111.     FT_Error      error  = FT_Err_Ok;
  112.     FT_Memory     memory = stream->memory;
  113.     FT_Byte*      start;
  114.     FT_Byte*      limit;
  115.     FT_Byte*      p;
  116.     AFM_KernPair  kp;
  117.     FT_Int        width_table_length;
  118.     FT_CharMap    oldcharmap;
  119.     FT_CharMap    charmap;
  120.     FT_Int        n;
  121.  
  122.  
  123.     start = (FT_Byte*)stream->cursor;
  124.     limit = (FT_Byte*)stream->limit;
  125.  
  126.     /* Figure out how long the width table is.          */
  127.     /* This info is a little-endian short at offset 99. */
  128.     p = start + 99;
  129.     if ( p + 2 > limit )
  130.     {
  131.       error = FT_THROW( Unknown_File_Format );
  132.       goto Exit;
  133.     }
  134.     width_table_length = FT_PEEK_USHORT_LE( p );
  135.  
  136.     p += 18 + width_table_length;
  137.     if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
  138.       /* extension table is probably optional */
  139.       goto Exit;
  140.  
  141.     /* Kerning offset is 14 bytes from start of extensions table. */
  142.     p += 14;
  143.     p = start + FT_PEEK_ULONG_LE( p );
  144.  
  145.     if ( p == start )
  146.       /* zero offset means no table */
  147.       goto Exit;
  148.  
  149.     if ( p + 2 > limit )
  150.     {
  151.       error = FT_THROW( Unknown_File_Format );
  152.       goto Exit;
  153.     }
  154.  
  155.     fi->NumKernPair = FT_PEEK_USHORT_LE( p );
  156.     p += 2;
  157.     if ( p + 4 * fi->NumKernPair > limit )
  158.     {
  159.       error = FT_THROW( Unknown_File_Format );
  160.       goto Exit;
  161.     }
  162.  
  163.     /* Actually, kerning pairs are simply optional! */
  164.     if ( fi->NumKernPair == 0 )
  165.       goto Exit;
  166.  
  167.     /* allocate the pairs */
  168.     if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
  169.       goto Exit;
  170.  
  171.     /* now, read each kern pair */
  172.     kp             = fi->KernPairs;
  173.     limit          = p + 4 * fi->NumKernPair;
  174.  
  175.     /* PFM kerning data are stored by encoding rather than glyph index, */
  176.     /* so find the PostScript charmap of this font and install it       */
  177.     /* temporarily.  If we find no PostScript charmap, then just use    */
  178.     /* the default and hope it is the right one.                        */
  179.     oldcharmap = t1_face->charmap;
  180.     charmap    = NULL;
  181.  
  182.     for ( n = 0; n < t1_face->num_charmaps; n++ )
  183.     {
  184.       charmap = t1_face->charmaps[n];
  185.       /* check against PostScript pseudo platform */
  186.       if ( charmap->platform_id == 7 )
  187.       {
  188.         error = FT_Set_Charmap( t1_face, charmap );
  189.         if ( error )
  190.           goto Exit;
  191.         break;
  192.       }
  193.     }
  194.  
  195.     /* Kerning info is stored as:             */
  196.     /*                                        */
  197.     /*   encoding of first glyph (1 byte)     */
  198.     /*   encoding of second glyph (1 byte)    */
  199.     /*   offset (little-endian short)         */
  200.     for ( ; p < limit ; p += 4 )
  201.     {
  202.       kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
  203.       kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
  204.  
  205.       kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);
  206.       kp->y = 0;
  207.  
  208.       kp++;
  209.     }
  210.  
  211.     if ( oldcharmap != NULL )
  212.       error = FT_Set_Charmap( t1_face, oldcharmap );
  213.     if ( error )
  214.       goto Exit;
  215.  
  216.     /* now, sort the kern pairs according to their glyph indices */
  217.     ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
  218.               compare_kern_pairs );
  219.  
  220.   Exit:
  221.     if ( error )
  222.     {
  223.       FT_FREE( fi->KernPairs );
  224.       fi->NumKernPair = 0;
  225.     }
  226.  
  227.     return error;
  228.   }
  229.  
  230.  
  231.   /* parse a metrics file -- either AFM or PFM depending on what */
  232.   /* it turns out to be                                          */
  233.   FT_LOCAL_DEF( FT_Error )
  234.   T1_Read_Metrics( FT_Face    t1_face,
  235.                    FT_Stream  stream )
  236.   {
  237.     PSAux_Service  psaux;
  238.     FT_Memory      memory  = stream->memory;
  239.     AFM_ParserRec  parser;
  240.     AFM_FontInfo   fi      = NULL;
  241.     FT_Error       error   = FT_ERR( Unknown_File_Format );
  242.     T1_Font        t1_font = &( (T1_Face)t1_face )->type1;
  243.  
  244.  
  245.     if ( FT_NEW( fi )                   ||
  246.          FT_FRAME_ENTER( stream->size ) )
  247.       goto Exit;
  248.  
  249.     fi->FontBBox  = t1_font->font_bbox;
  250.     fi->Ascender  = t1_font->font_bbox.yMax;
  251.     fi->Descender = t1_font->font_bbox.yMin;
  252.  
  253.     psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
  254.     if ( psaux->afm_parser_funcs )
  255.     {
  256.       error = psaux->afm_parser_funcs->init( &parser,
  257.                                              stream->memory,
  258.                                              stream->cursor,
  259.                                              stream->limit );
  260.  
  261.       if ( !error )
  262.       {
  263.         parser.FontInfo  = fi;
  264.         parser.get_index = t1_get_index;
  265.         parser.user_data = t1_font;
  266.  
  267.         error = psaux->afm_parser_funcs->parse( &parser );
  268.         psaux->afm_parser_funcs->done( &parser );
  269.       }
  270.     }
  271.  
  272.     if ( FT_ERR_EQ( error, Unknown_File_Format ) )
  273.     {
  274.       FT_Byte*  start = stream->cursor;
  275.  
  276.  
  277.       /* MS Windows allows versions up to 0x3FF without complaining */
  278.       if ( stream->size > 6                              &&
  279.            start[1] < 4                                  &&
  280.            FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
  281.         error = T1_Read_PFM( t1_face, stream, fi );
  282.     }
  283.  
  284.     if ( !error )
  285.     {
  286.       t1_font->font_bbox = fi->FontBBox;
  287.  
  288.       t1_face->bbox.xMin =   fi->FontBBox.xMin            >> 16;
  289.       t1_face->bbox.yMin =   fi->FontBBox.yMin            >> 16;
  290.       /* no `U' suffix here to 0xFFFF! */
  291.       t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16;
  292.       t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16;
  293.  
  294.       /* no `U' suffix here to 0x8000! */
  295.       t1_face->ascender  = (FT_Short)( ( fi->Ascender  + 0x8000 ) >> 16 );
  296.       t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
  297.  
  298.       if ( fi->NumKernPair )
  299.       {
  300.         t1_face->face_flags |= FT_FACE_FLAG_KERNING;
  301.         ( (T1_Face)t1_face )->afm_data = fi;
  302.         fi = NULL;
  303.       }
  304.     }
  305.  
  306.     FT_FRAME_EXIT();
  307.  
  308.   Exit:
  309.     if ( fi != NULL )
  310.       T1_Done_Metrics( memory, fi );
  311.  
  312.     return error;
  313.   }
  314.  
  315.  
  316.   /* find the kerning for a given glyph pair */
  317.   FT_LOCAL_DEF( void )
  318.   T1_Get_Kerning( AFM_FontInfo  fi,
  319.                   FT_UInt       glyph1,
  320.                   FT_UInt       glyph2,
  321.                   FT_Vector*    kerning )
  322.   {
  323.     AFM_KernPair  min, mid, max;
  324.     FT_ULong      idx = KERN_INDEX( glyph1, glyph2 );
  325.  
  326.  
  327.     /* simple binary search */
  328.     min = fi->KernPairs;
  329.     max = min + fi->NumKernPair - 1;
  330.  
  331.     while ( min <= max )
  332.     {
  333.       FT_ULong  midi;
  334.  
  335.  
  336.       mid  = min + ( max - min ) / 2;
  337.       midi = KERN_INDEX( mid->index1, mid->index2 );
  338.  
  339.       if ( midi == idx )
  340.       {
  341.         kerning->x = mid->x;
  342.         kerning->y = mid->y;
  343.  
  344.         return;
  345.       }
  346.  
  347.       if ( midi < idx )
  348.         min = mid + 1;
  349.       else
  350.         max = mid - 1;
  351.     }
  352.  
  353.     kerning->x = 0;
  354.     kerning->y = 0;
  355.   }
  356.  
  357.  
  358.   FT_LOCAL_DEF( FT_Error )
  359.   T1_Get_Track_Kerning( FT_Face    face,
  360.                         FT_Fixed   ptsize,
  361.                         FT_Int     degree,
  362.                         FT_Fixed*  kerning )
  363.   {
  364.     AFM_FontInfo  fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
  365.     FT_Int        i;
  366.  
  367.  
  368.     if ( !fi )
  369.       return FT_THROW( Invalid_Argument );
  370.  
  371.     for ( i = 0; i < fi->NumTrackKern; i++ )
  372.     {
  373.       AFM_TrackKern  tk = fi->TrackKerns + i;
  374.  
  375.  
  376.       if ( tk->degree != degree )
  377.         continue;
  378.  
  379.       if ( ptsize < tk->min_ptsize )
  380.         *kerning = tk->min_kern;
  381.       else if ( ptsize > tk->max_ptsize )
  382.         *kerning = tk->max_kern;
  383.       else
  384.       {
  385.         *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
  386.                               tk->max_kern - tk->min_kern,
  387.                               tk->max_ptsize - tk->min_ptsize ) +
  388.                    tk->min_kern;
  389.       }
  390.     }
  391.  
  392.     return FT_Err_Ok;
  393.   }
  394.  
  395.  
  396. /* END */
  397.