shithub: freetype+ttf2subf

ref: 5e4c2cb3bfdf883e5043b766eb9ee8ea00bc2b22
dir: /src/truetype/ttdriver.c/

View raw version
/***************************************************************************/
/*                                                                         */
/*  ttdriver.c                                                             */
/*                                                                         */
/*    TrueType font driver implementation (body).                          */
/*                                                                         */
/*  Copyright 1996-1999 by                                                 */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used,       */
/*  modified, and distributed under the terms of the FreeType project      */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/sfnt.h>
#include <freetype/ttnameid.h>

#include <ttdriver.h>
#include <ttgload.h>


#undef  FT_COMPONENT
#define FT_COMPONENT  trace_ttdriver



  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****                                                                 ****/
  /****                          F A C E S                              ****/
  /****                                                                 ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/


 /******************************************************************
  *
  * <Function>
  *    find_encoding
  *
  * <Description>
  *    return the FT_Encoding corresponding to a given
  *    (platform_id,encoding_id) pair, as found in TrueType charmaps
  *
  * <Input>
  *   platform_id ::
  *   encoding_id ::
  *
  * <Return>
  *   the corresponding FT_Encoding tag. ft_encoding_none by default
  *
  *****************************************************************/

  static
  FT_Encoding   find_encoding( int  platform_id,
                               int  encoding_id )
  {
    typedef struct  TEncoding
    {
      int          platform_id;
      int          encoding_id;
      FT_Encoding  encoding;

    } TEncoding;

    static
    const TEncoding   tt_encodings[] =
    {
      { TT_PLATFORM_ISO,                         -1, ft_encoding_unicode },

      { TT_PLATFORM_APPLE_UNICODE,               -1, ft_encoding_unicode },

      { TT_PLATFORM_MACINTOSH,      TT_MAC_ID_ROMAN, ft_encoding_apple_roman },

      { TT_PLATFORM_MICROSOFT,  TT_MS_ID_UNICODE_CS, ft_encoding_unicode },
      { TT_PLATFORM_MICROSOFT,  TT_MS_ID_SJIS,       ft_encoding_sjis },
      { TT_PLATFORM_MICROSOFT,  TT_MS_ID_BIG_5,      ft_encoding_big5 }
    };

    const TEncoding  *cur, *limit;

    cur   = tt_encodings;
    limit = cur + sizeof(tt_encodings)/sizeof(tt_encodings[0]);

    for ( ; cur < limit; cur++ )
    {
      if (cur->platform_id == platform_id)
      {
        if (cur->encoding_id == encoding_id ||
            cur->encoding_id == -1          )
          return cur->encoding;
      }
    }
    return ft_encoding_none;
  }




  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    Init_Face                                                          */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A driver method used to initialize a new TrueType face object.     */
  /*                                                                       */
  /* <Input>                                                               */
  /*    resource       :: A handle to the source resource.                 */
  /*                                                                       */
  /*    typeface_index :: An index of the face in the font resource.  Used */
  /*                      to access individual faces in font collections.  */
  /*                                                                       */
  /* <InOut>                                                               */
  /*    face           :: A handle to the face object.                     */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    The `typeface_index' parameter field will be set to -1 if the      */
  /*    engine only wants to test the format of the resource.  This means  */
  /*    that font drivers should simply check the font format, then return */
  /*    immediately with an error code of 0 (meaning success).  The field  */
  /*    `num_faces' should be set.                                         */
  /*                                                                       */
  /*    Done_Face() will be called subsequently, whatever the result was.  */
  /*                                                                       */
  static
  TT_Error  Init_Face( FT_Stream      stream,
                       TT_Face        face,
                       FT_Int         typeface_index,
                       FT_Int         num_params,
                       FT_Parameter*  params )
  {
    TT_Error     error;

    /* initialize the TrueType face object */
    error = TT_Init_Face( stream, face, typeface_index, num_params, params );

    /* now set up root fields */
    if ( !error && typeface_index >= 0 )
    {
      FT_Face     root = &face->root;
      FT_Int      flags;
      TT_CharMap  charmap;
      TT_Int      n;
      FT_Memory   memory;

      memory = root->memory;

      /*****************************************************************/
      /*                                                               */
      /* Compute face flags.                                           */
      /*                                                               */
      flags = FT_FACE_FLAG_SCALABLE  |    /* scalable outlines */
              FT_FACE_FLAG_SFNT      |    /* SFNT file format  */
              FT_FACE_FLAG_HORIZONTAL;    /* horizontal data   */

      /* fixed width font ? */
      if ( face->postscript.isFixedPitch )
        flags |= FT_FACE_FLAG_FIXED_WIDTH;

      /* vertical information ? */
      if ( face->vertical_info )
        flags |= FT_FACE_FLAG_VERTICAL;

      /* kerning available ? */
      if ( face->kern_pairs )
        flags |= FT_FACE_FLAG_KERNING;

      root->face_flags = flags;

      /*****************************************************************/
      /*                                                               */
      /* Compute style flags.                                          */
      /*                                                               */
      flags = 0;

      if ( face->os2.version != 0xFFFF )
      {
        /* We have an OS/2 table, use the `fsSelection' field */
        if ( face->os2.fsSelection & 1 )
          flags |= FT_STYLE_FLAG_ITALIC;

        if ( face->os2.fsSelection & 32 )
          flags |= FT_STYLE_FLAG_BOLD;
      }
      else
      {
        /* This is an old Mac font, use the header field */
        if ( face->header.Mac_Style & 1 )
          flags |= FT_STYLE_FLAG_BOLD;

        if ( face->header.Mac_Style & 2 )
          flags |= FT_STYLE_FLAG_ITALIC;
      }

      face->root.style_flags = flags;

      /*****************************************************************/
      /*                                                               */
      /* Polish the charmaps.                                          */
      /*                                                               */
      /*   Try to set the charmap encoding according to the platform & */
      /*   encoding ID of each charmap.                                */
      /*                                                               */
      charmap            = face->charmaps;
      root->num_charmaps = face->num_charmaps;

      /* allocate table of pointers */
      if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) )
        return error;

      for ( n = 0; n < root->num_charmaps; n++, charmap++ )
      {
        FT_Int  platform = charmap->cmap.platformID;
        FT_Int  encoding = charmap->cmap.platformEncodingID;

        charmap->root.face        = (FT_Face)face;
        charmap->root.platform_id = platform;
        charmap->root.encoding_id = encoding;
        charmap->root.encoding    = find_encoding(platform,encoding);

        /* now, set root->charmap with a unicode charmap wherever available */
        if (!root->charmap && charmap->root.encoding == ft_encoding_unicode)
          root->charmap = (FT_CharMap)charmap;

        root->charmaps[n] = (FT_CharMap)charmap;
      }

#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
      if ( face->num_sbit_strikes )
      {
       face->root.num_fixed_sizes = face->num_sbit_strikes;
       if ( ALLOC_ARRAY( face->root.available_sizes,
                         face->num_sbit_strikes,
                         FT_Bitmap_Size ) )
         return error;

       for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
       {
         face->root.available_sizes[n].width =
           face->sbit_strikes[n].x_ppem;
         face->root.available_sizes[n].height =
           face->sbit_strikes[n].y_ppem;
       }
      }
      else
#else
      {
       root->num_fixed_sizes = 0;
       root->available_sizes = 0;
      }
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */

      /*****************************************************************/
      /*                                                               */
      /*  Set up metrics.                                              */
      /*                                                               */
      root->bbox.xMin    = face->header.xMin;
      root->bbox.yMin    = face->header.yMin;
      root->bbox.xMax    = face->header.xMax;
      root->bbox.yMax    = face->header.yMax;
      root->units_per_EM = face->header.Units_Per_EM;

      /* The ascender/descender/height are computed from the OS/2 table   */
      /* when found.  Otherwise, they're taken from the horizontal header */
      if ( face->os2.version != 0xFFFF )
      {
        root->ascender  =  face->os2.sTypoAscender;
        root->descender = -face->os2.sTypoDescender;
        root->height    =  root->ascender + root->descender +
                           face->os2.sTypoLineGap;
      }
      else
      {
        root->ascender  = face->horizontal.Ascender;
        root->descender = face->horizontal.Descender;
        root->height    = root->ascender + root->descender +
                          face->horizontal.Line_Gap;
      }

      root->max_advance_width  = face->horizontal.advance_Width_Max;

      root->max_advance_height = root->height;
      if ( face->vertical_info )
        root->max_advance_height = face->vertical.advance_Height_Max;

      root->underline_position  = face->postscript.underlinePosition;
      root->underline_thickness = face->postscript.underlineThickness;

      /* root->max_points      - already set up */
      /* root->max_contours    - already set up */

    }
    return error;
  }


#undef  PAIR_TAG
#define PAIR_TAG( left, right )  ( ((TT_ULong)left << 16) | (TT_ULong)right )


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    Get_Kerning                                                        */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A driver method used to return the kerning vector between two      */
  /*    glyphs of the same face.                                           */
  /*                                                                       */
  /* <Input>                                                               */
  /*    face        :: A handle to the source face object.                 */
  /*                                                                       */
  /*    left_glyph  :: The index of the left glyph in the kern pair.       */
  /*                                                                       */
  /*    right_glyph :: The index of the right glyph in the kern pair.      */
  /*                                                                       */
  /* <Output>                                                              */
  /*    kerning     :: The kerning vector.  This is in font units for      */
  /*                   scalable formats, and in pixels for fixed-sizes     */
  /*                   formats.                                            */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  /* <Note>                                                                */
  /*    Only horizontal layouts (left-to-right & right-to-left) are        */
  /*    supported by this function.  Other layouts, or more sophisticated  */
  /*    kernings are out of scope of this method (the basic driver         */
  /*    interface is meant to be simple).                                  */
  /*                                                                       */
  /*    They can be implemented by format-specific interfaces.             */
  /*                                                                       */
  static
  TT_Error  Get_Kerning( TT_Face     face,
                         TT_UInt     left_glyph,
                         TT_UInt     right_glyph,
                         TT_Vector*  kerning )
  {
    TT_Kern_0_Pair*  pair;


    if ( !face )
      return TT_Err_Invalid_Face_Handle;

    kerning->x = 0;
    kerning->y = 0;

    if ( face->kern_pairs )
    {
      /* there are some kerning pairs in this font file! */
      TT_ULong  search_tag = PAIR_TAG( left_glyph, right_glyph );
      TT_Long   left, right;


      left  = 0;
      right = face->num_kern_pairs - 1;

      while ( left <= right )
      {
        TT_Int    middle   = left + ((right-left) >> 1);
        TT_ULong  cur_pair;


        pair     = face->kern_pairs + middle;
        cur_pair = PAIR_TAG( pair->left, pair->right );

        if ( cur_pair == search_tag )
          goto Found;

        if ( cur_pair < search_tag )
          left = middle+1;
        else
          right = middle-1;
      }
    }

  Exit:
    return TT_Err_Ok;

  Found:
    kerning->x = pair->value;
    goto Exit;
  }


#undef PAIR_TAG


  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****                                                                 ****/
  /****                           S I Z E S                             ****/
  /****                                                                 ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    Set_Char_Sizes                                                     */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A driver method used to reset a size's character sizes (horizontal */
  /*    and vertical) expressed in fractional points.                      */
  /*                                                                       */
  /* <Input>                                                               */
  /*    char_width  :: The character width expressed in 26.6 fractional    */
  /*                   points.                                             */
  /*    char_height :: The character height expressed in 26.6 fractional   */
  /*                   points.                                             */
  /*                                                                       */
  /* <InOut>                                                               */
  /*    size        :: A handle to the target size object.                 */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  static
  TT_Error  Set_Char_Sizes( TT_Size     size,
                            TT_F26Dot6  char_width,
                            TT_F26Dot6  char_height,
                            TT_UInt     horz_resolution,
                            TT_UInt     vert_resolution )
  {
    FT_Size_Metrics*  metrics = &size->root.metrics;
    TT_Face           face    = (TT_Face)size->root.face;
    TT_Long           dim_x, dim_y;

    /* This bit flag, when set, indicates that the pixel size must be */
    /* truncated to an integer. Nearly all TrueType fonts have this   */
    /* bit set, as hinting won't work really well otherwise.          */
    /*                                                                */
    /* However, for those rare fonts who do not set it, we override   */
    /* the default computations performed by the base layer. I really */
    /* don't know if this is useful, but hey, that's the spec :-)     */
    /*                                                                */
    if ( (face->header.Flags & 8) == 0 )
    {
      /* Compute pixel sizes in 26.6 units */
      dim_x = (char_width * horz_resolution) / 72;
      dim_y = (char_height * vert_resolution) / 72;

      metrics->x_scale = FT_DivFix( dim_x, face->root.units_per_EM );
      metrics->y_scale = FT_DivFix( dim_y, face->root.units_per_EM );

      metrics->x_ppem    = (TT_UShort)(dim_x >> 6);
      metrics->y_ppem    = (TT_UShort)(dim_y >> 6);
    }

    size->ttmetrics.valid = FALSE;

    return TT_Reset_Size( size );
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    Set_Pixel_Sizes                                                    */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A driver method used to reset a size's character sizes (horizontal */
  /*    and vertical) expressed in integer pixels.                         */
  /*                                                                       */
  /* <Input>                                                               */
  /*    pixel_width  :: The character width expressed in integer pixels.   */
  /*                                                                       */
  /*    pixel_height :: The character height expressed in integer pixels.  */
  /*                                                                       */
  /* <InOut>                                                               */
  /*    size         :: A handle to the target size object.                */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code. 0 means success                               */
  /*                                                                       */
  static
  TT_Error  Set_Pixel_Sizes( TT_Size  size,
                             TT_UInt  pixel_width,
                             TT_UInt  pixel_height )
  {
    UNUSED(pixel_width);
    UNUSED(pixel_height);

    /* many things were pre-computed by the base layer */

    size->ttmetrics.valid = FALSE;

    return TT_Reset_Size( size );
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    Load_Glyph                                                         */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A driver method used to load a glyph within a given glyph slot.    */
  /*                                                                       */
  /* <Input>                                                               */
  /*    slot        :: A handle to the target slot object where the glyph  */
  /*                   will be loaded.                                     */
  /*                                                                       */
  /*    size        :: A handle to the source face size at which the glyph */
  /*                   must be scaled/loaded/etc.                          */
  /*                                                                       */
  /*    glyph_index :: The index of the glyph in the font file.            */
  /*                                                                       */
  /*    load_flags  :: A flag indicating what to load for this glyph.  The */
  /*                   FTLOAD_??? constants can be used to control the     */
  /*                   glyph loading process (e.g., whether the outline    */
  /*                   should be scaled, whether to load bitmaps or not,   */
  /*                   whether to hint the outline, etc).                  */
  /* <Output>                                                              */
  /*    result      :: A set of bit flags indicating the type of data that */
  /*                   was loaded in the glyph slot (outline, bitmap,      */
  /*                   pixmap, etc).                                       */
  /*                                                                       */
  /* <Return>                                                              */
  /*    FreeType error code.  0 means success.                             */
  /*                                                                       */
  static
  TT_Error  Load_Glyph( TT_GlyphSlot  slot,
                        TT_Size       size,
                        TT_UShort     glyph_index,
                        TT_UInt       load_flags )
  {
    TT_Error  error;


    if ( !slot )
      return TT_Err_Invalid_Glyph_Handle;

    /* check that we want a scaled outline or bitmap */
    if ( !size )
      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;

    if ( load_flags & FT_LOAD_NO_SCALE )
      size = NULL;

    /* reset the size object if necessary */
    if ( size )
    {
      /* these two object must have the same parent */
      if ( size->root.face != slot->face )
        return TT_Err_Invalid_Face_Handle;

      if ( !size->ttmetrics.valid )
      {
        if ( FT_SET_ERROR( TT_Reset_Size( size ) ) )
          return error;
      }
    }

    /* now load the glyph outline if necessary */
    error = TT_Load_Glyph( size, slot, glyph_index, load_flags );

    /* force drop-out mode to 2 - irrelevant now */
    /* slot->outline.dropout_mode = 2; */

    return error;
  }


  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/
  /****                                                                 ****/
  /****                                                                 ****/
  /****             C H A R A C T E R   M A P P I N G S                 ****/
  /****                                                                 ****/
  /****                                                                 ****/
  /*************************************************************************/
  /*************************************************************************/
  /*************************************************************************/

  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    Get_Char_Index                                                     */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Uses a charmap to return a given character code's glyph index.     */
  /*                                                                       */
  /* <Input>                                                               */
  /*    charmap  :: A handle to the source charmap object.                 */
  /*    charcode :: The character code.                                    */
  /*                                                                       */
  /* <Return>                                                              */
  /*    Glyph index.  0 means `undefined character code'.                  */
  /*                                                                       */
  static
  FT_UInt  Get_Char_Index( TT_CharMap  charmap,
                           TT_Long     charcode )
  {
    TT_Error       error;
    TT_Face        face;
    TT_CMapTable*  cmap;

    cmap = &charmap->cmap;
    face = (TT_Face)charmap->root.face;

    /* Load table if needed */
    if ( !cmap->loaded )
    {
      SFNT_Interface*  sfnt = (SFNT_Interface*)face->sfnt;

      error = sfnt->load_charmap( face, cmap, face->root.stream );
      if (error)
        return error;

      cmap->loaded = TRUE;
    }

    if ( cmap->get_index )
      return cmap->get_index( cmap, charcode );
    else
      return 0;
  }


  static
  void*  tt_get_sfnt_table( TT_Face  face, FT_Sfnt_Tag  tag )
  {
    void*  table;

    switch (tag)
    {
      case ft_sfnt_head: table = &face->header; break;
      case ft_sfnt_hhea: table = &face->horizontal; break;
      case ft_sfnt_vhea: table = (face->vertical_info ? &face->vertical : 0 ); break;
      case ft_sfnt_os2:  table = (face->os2.version == 0xFFFF ? 0 : &face->os2 ); break;
      case ft_sfnt_post: table = &face->postscript; break;
      case ft_sfnt_maxp: table = &face->max_profile; break;
	  case ft_sfnt_pclt: table = face->pclt.Version ? &face->pclt : 0 ; break;

      default:
        table = 0;
    }
    return table;
  }


  static
  FTDriver_Interface  tt_get_interface( TT_Driver  driver, const char* interface )
  {
    UNUSED(driver);

    if (strcmp(interface,"get_sfnt")==0)
      return (FTDriver_Interface)tt_get_sfnt_table;

    return 0;
  }


  /* The FT_DriverInterface structure is defined in ftdriver.h. */

  const FT_DriverInterface  tt_driver_interface =
  {
    sizeof ( TT_DriverRec ),
    sizeof ( TT_FaceRec ),
    sizeof ( TT_SizeRec ),
    sizeof ( FT_GlyphSlotRec ),

    "truetype",      /* driver name                           */
    100,             /* driver version == 1.0                 */
    200,             /* driver requires FreeType 2.0 or above */

    (void*)0,

    (FTDriver_initDriver)        TT_Init_Driver,
    (FTDriver_doneDriver)        TT_Done_Driver,
    (FTDriver_getInterface)      tt_get_interface,

    (FTDriver_initFace)          Init_Face,
    (FTDriver_doneFace)          TT_Done_Face,
    (FTDriver_getKerning)        Get_Kerning,

    (FTDriver_initSize)          TT_Init_Size,
    (FTDriver_doneSize)          TT_Done_Size,
    (FTDriver_setCharSizes)      Set_Char_Sizes,
    (FTDriver_setPixelSizes)     Set_Pixel_Sizes,

    (FTDriver_initGlyphSlot)     TT_Init_GlyphSlot,
    (FTDriver_doneGlyphSlot)     TT_Done_GlyphSlot,
    (FTDriver_loadGlyph)         Load_Glyph,

    (FTDriver_getCharIndex)      Get_Char_Index,
  };



  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    getDriverInterface                                                 */
  /*                                                                       */
  /* <Description>                                                         */
  /*    This function is used when compiling the TrueType driver as a      */
  /*    shared library (`.DLL' or `.so').  It will be used by the          */
  /*    high-level library of FreeType to retrieve the address of the      */
  /*    driver's generic interface.                                        */
  /*                                                                       */
  /*    It shouldn't be implemented in a static build, as each driver must */
  /*    have the same function as an exported entry point.                 */
  /*                                                                       */
  /* <Return>                                                              */
  /*    The address of the TrueType's driver generic interface.  The       */
  /*    format-specific interface can then be retrieved through the method */
  /*    interface->get_format_interface.                                   */
  /*                                                                       */
#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS

  EXPORT_FUNC(FT_DriverInterface*)  getDriverInterface( void )
  {
    return &tt_driver_interface;
  }

#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */


/* END */