Edit

kc3-lang/freetype/src/base/ftglyph.c

Branch :

  • Show log

    Commit

  • Author : Werner Lemberg
    Date : 2000-07-10 00:06:22
    Hash : 97b2de58
    Message : More formatting. Synchronizing docu in include/freetype with src/base.

  • src/base/ftglyph.c
  • /***************************************************************************/
    /*                                                                         */
    /*  ftglyph.c                                                              */
    /*                                                                         */
    /*    FreeType convenience functions to handle glyphs (body).              */
    /*                                                                         */
    /*  Copyright 1996-2000 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.                                        */
    /*                                                                         */
    /***************************************************************************/
    
      /*************************************************************************/
      /*                                                                       */
      /*  This file contains the definition of several convenience functions   */
      /*  that can be used by client applications to easily retrieve glyph     */
      /*  bitmaps and outlines from a given face.                              */
      /*                                                                       */
      /*  These functions should be optional if you are writing a font server  */
      /*  or text layout engine on top of FreeType.  However, they are pretty  */
      /*  handy for many other simple uses of the library.                     */
      /*                                                                       */
      /*************************************************************************/
    
    
    #include <freetype/ftglyph.h>
    #include <freetype/ftoutln.h>
    #include <freetype/internal/ftobjs.h>
    
    
      /*************************************************************************/
      /*                                                                       */
      /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
      /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
      /* messages during execution.                                            */
      /*                                                                       */
    #undef  FT_COMPONENT
    #define FT_COMPONENT  trace_glyph
    
    
      /*************************************************************************/
      /*************************************************************************/
      /****                                                                 ****/
      /****   Convenience functions                                         ****/
      /****                                                                 ****/
      /*************************************************************************/
      /*************************************************************************/
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Matrix_Multiply                                                 */
      /*                                                                       */
      /* <Description>                                                         */
      /*    Performs the matrix operation `b = a*b'.                           */
      /*                                                                       */
      /* <Input>                                                               */
      /*    a :: A pointer to matrix `a'.                                      */
      /*                                                                       */
      /* <InOut>                                                               */
      /*    b :: A pointer to matrix `b'.                                      */
      /*                                                                       */
      /* <MT-Note>                                                             */
      /*    Yes.                                                               */
      /*                                                                       */
      /* <Note>                                                                */
      /*    The result is undefined if either `a' or `b' is zero.              */
      /*                                                                       */
      FT_EXPORT_FUNC( void )  FT_Matrix_Multiply( FT_Matrix*  a,
                                                  FT_Matrix*  b )
      {
        FT_Fixed  xx, xy, yx, yy;
    
    
        if ( !a || !b )
          return;
    
        xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx );
        xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy );
        yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx );
        yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy );
    
        b->xx = xx;  b->xy = xy;
        b->yx = yx;  b->yy = yy;
      }
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Matrix_Invert                                                   */
      /*                                                                       */
      /* <Description>                                                         */
      /*    Inverts a 2x2 matrix.  Returns an error if it can't be inverted.   */
      /*                                                                       */
      /* <InOut>                                                               */
      /*    matrix :: A pointer to the target matrix.  Remains untouched in    */
      /*              case of error.                                           */
      /*                                                                       */
      /* <Return>                                                              */
      /*    FreeType error code.  0 means success.                             */
      /*                                                                       */
      /* <MT-Note>                                                             */
      /*    Yes.                                                               */
      /*                                                                       */
      FT_EXPORT_FUNC( FT_Error )  FT_Matrix_Invert( FT_Matrix*  matrix )
      {
        FT_Pos  delta, xx, yy;
    
    
        if ( !matrix )
          return FT_Err_Invalid_Argument;
    
        /* compute discriminant */
        delta = FT_MulFix( matrix->xx, matrix->yy ) -
                FT_MulFix( matrix->xy, matrix->yx );
    
        if ( !delta )
          return FT_Err_Invalid_Argument;  /* matrix can't be inverted */
    
        matrix->xy = - FT_DivFix( matrix->xy, delta );
        matrix->yx = - FT_DivFix( matrix->yx, delta );
    
        xx = matrix->xx;
        yy = matrix->yy;
    
        matrix->xx = FT_DivFix( yy, delta );
        matrix->yy = FT_DivFix( xx, delta );
    
        return FT_Err_Ok;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /****                                                                 ****/
      /****   FT_BitmapGlyph support                                        ****/
      /****                                                                 ****/
      /*************************************************************************/
      /*************************************************************************/
    
      static
      FT_Error  ft_bitmap_copy( FT_Memory   memory,
                                FT_Bitmap*  source,
                                FT_Bitmap*  target )
      {
        FT_Error  error;
        FT_Int    pitch = source->pitch;
        FT_ULong  size;
    
    
        *target = *source;
    
        if ( pitch < 0 )
          pitch = -pitch;
    
        size = (FT_ULong)( pitch * source->rows );
    
        if ( !ALLOC( target->buffer, size ) )
          MEM_Copy( source->buffer, target->buffer, size );
    
        return error;
      }
    
    
      static
      FT_Error  ft_bitmap_glyph_init( FT_BitmapGlyph  glyph,
                                      FT_GlyphSlot    slot )
      {
        FT_Error    error   = FT_Err_Ok;
        FT_Library  library = FT_GLYPH(glyph)->library;
        FT_Memory   memory  = library->memory;
    
    
        if ( slot->format != ft_glyph_format_bitmap )
        {
          error = FT_Err_Invalid_Glyph_Format;
          goto Exit;
        }
    
        /* grab the bitmap in the slot - do lazy copying whenever possible */
        glyph->bitmap = slot->bitmap;
        glyph->left   = slot->bitmap_left;
        glyph->top    = slot->bitmap_top;
    
        if ( slot->flags & ft_glyph_own_bitmap )
          slot->flags &= ~ft_glyph_own_bitmap;
        else
        {
          /* copy the bitmap into a new buffer */
          error = ft_bitmap_copy( memory, &slot->bitmap, &glyph->bitmap );
        }
    
      Exit:
        return error;
      }
    
    
      static
      FT_Error  ft_bitmap_glyph_copy( FT_BitmapGlyph  source,
                                      FT_BitmapGlyph  target )
      {
        FT_Memory  memory = source->root.library->memory;
    
    
        target->left = source->left;
        target->top  = source->top;
    
        return ft_bitmap_copy( memory, &source->bitmap, &target->bitmap );
      }
    
    
      static
      void  ft_bitmap_glyph_done( FT_BitmapGlyph  glyph )
      {
        FT_Memory  memory = FT_GLYPH(glyph)->library->memory;
    
    
        FREE( glyph->bitmap.buffer );
      }
    
    
      static
      void  ft_bitmap_glyph_bbox( FT_BitmapGlyph  glyph,
                                  FT_BBox*        cbox )
      {
        cbox->xMin = glyph->left << 6;
        cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 );
        cbox->yMax = glyph->top << 6;
        cbox->yMin = cbox->xMax - ( glyph->bitmap.rows << 6 );
      }
    
    
      const FT_Glyph_Class  ft_bitmap_glyph_class =
      {
        sizeof( FT_BitmapGlyphRec ),
        ft_glyph_format_bitmap,
    
        (FT_Glyph_Init_Func)     ft_bitmap_glyph_init,
        (FT_Glyph_Done_Func)     ft_bitmap_glyph_done,
        (FT_Glyph_Copy_Func)     ft_bitmap_glyph_copy,
        (FT_Glyph_Transform_Func)0,
        (FT_Glyph_BBox_Func)     ft_bitmap_glyph_bbox,
        (FT_Glyph_Prepare_Func)  0
      };
    
    
      /*************************************************************************/
      /*************************************************************************/
      /****                                                                 ****/
      /****   FT_OutlineGlyph support                                       ****/
      /****                                                                 ****/
      /*************************************************************************/
      /*************************************************************************/
    
    
      static
      FT_Error  ft_outline_glyph_init( FT_OutlineGlyph  glyph,
                                       FT_GlyphSlot     slot )
      {
        FT_Error     error   = FT_Err_Ok;
        FT_Library   library = FT_GLYPH(glyph)->library;
        FT_Outline*  source  = &slot->outline;
        FT_Outline*  target  = &glyph->outline;
    
    
        /* check format in glyph slot */
        if ( slot->format != ft_glyph_format_outline )
        {
          error = FT_Err_Invalid_Glyph_Format;
          goto Exit;
        }
    
        /* allocate new outline */
        error = FT_Outline_New( library, source->n_points, source->n_contours,
                                &glyph->outline );
        if ( error )
          goto Exit;
    
        /* copy it */
        MEM_Copy( target->points, source->points,
                  source->n_points * sizeof ( FT_Vector ) );
    
        MEM_Copy( target->tags, source->tags,
                  source->n_points * sizeof ( FT_Byte ) );
    
        MEM_Copy( target->contours, source->contours,
                  source->n_contours * sizeof ( FT_Short ) );
    
        /* copy all flags, except the `ft_outline_owner' one */
        target->flags = source->flags | ft_outline_owner;
    
      Exit:
        return error;
      }
    
    
      static
      void  ft_outline_glyph_done( FT_OutlineGlyph  glyph )
      {
        FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
      }
    
    
      static
      FT_Error  ft_outline_glyph_copy( FT_OutlineGlyph  source,
                                       FT_OutlineGlyph  target )
      {
        FT_Error    error;
        FT_Library  library = FT_GLYPH( source )->library;
    
    
        error = FT_Outline_New( library, source->outline.n_points,
                                source->outline.n_contours, &target->outline );
        if ( !error )
          FT_Outline_Copy( &source->outline, &target->outline );
    
        return error;
      }
    
    
      static
      void  ft_outline_glyph_transform( FT_OutlineGlyph  glyph,
                                        FT_Matrix*       matrix,
                                        FT_Vector*       delta )
      {
        if ( matrix )
          FT_Outline_Transform( &glyph->outline, matrix );
    
        if ( delta )
          FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
      }
    
    
      static
      void  ft_outline_glyph_bbox( FT_OutlineGlyph  glyph,
                                   FT_BBox*         bbox )
      {
        FT_Outline_Get_CBox( &glyph->outline, bbox );
      }
    
    
      static
      FT_Error  ft_outline_glyph_prepare( FT_OutlineGlyph  glyph,
                                          FT_GlyphSlot     slot )
      {
        slot->format         = ft_glyph_format_outline;
        slot->outline        = glyph->outline;
        slot->outline.flags &= ~ft_outline_owner;
    
        return FT_Err_Ok;
      }
    
    
      const FT_Glyph_Class  ft_outline_glyph_class =
      {
        sizeof( FT_OutlineGlyphRec ),
        ft_glyph_format_outline,
    
        (FT_Glyph_Init_Func)     ft_outline_glyph_init,
        (FT_Glyph_Done_Func)     ft_outline_glyph_done,
        (FT_Glyph_Copy_Func)     ft_outline_glyph_copy,
        (FT_Glyph_Transform_Func)ft_outline_glyph_transform,
        (FT_Glyph_BBox_Func)     ft_outline_glyph_bbox,
        (FT_Glyph_Prepare_Func)  ft_outline_glyph_prepare
      };
    
    
      /*************************************************************************/
      /*************************************************************************/
      /****                                                                 ****/
      /****   FT_Glyph class and API                                        ****/
      /****                                                                 ****/
      /*************************************************************************/
      /*************************************************************************/
    
       static
       FT_Error  ft_new_glyph( FT_Library             library,
                               const FT_Glyph_Class*  clazz,
                               FT_Glyph*              aglyph )
       {
         FT_Memory  memory = library->memory;
         FT_Error   error;
         FT_Glyph   glyph;
    
    
         *aglyph = 0;
    
         if ( !ALLOC( glyph, clazz->glyph_size ) )
         {
           glyph->library = library;
           glyph->clazz   = clazz;
           glyph->format  = clazz->glyph_format;
    
           *aglyph = glyph;
         }
    
         return error;
       }
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Glyph_Copy                                                      */
      /*                                                                       */
      /* <Description>                                                         */
      /*    A function used to copy a glyph image.                             */
      /*                                                                       */
      /* <Input>                                                               */
      /*    source :: A handle to the source glyph object.                     */
      /*                                                                       */
      /* <Output>                                                              */
      /*    target :: A handle to the target glyph object.  0 in case of       */
      /*              error.                                                   */
      /*                                                                       */
      /* <Return>                                                              */
      /*    FreeType error code.  0 means success.                             */
      /*                                                                       */
      FT_EXPORT_FUNC( FT_Error )  FT_Glyph_Copy( FT_Glyph   source,
                                                 FT_Glyph*  target )
      {
        FT_Glyph               copy;
        FT_Error               error;
        const FT_Glyph_Class*  clazz;
    
    
        /* check arguments */
        if ( !target || !source || !source->clazz )
        {
          error = FT_Err_Invalid_Argument;
          goto Exit;
        }
    
        *target = 0;
    
        clazz = source->clazz;
        error = ft_new_glyph( source->library, clazz, &copy );
        if ( error )
          goto Exit;
    
        if ( clazz->glyph_copy )
          error = clazz->glyph_copy( source, copy );
    
        if ( error )
          FT_Done_Glyph( copy );
        else
          *target = copy;
    
      Exit:
        return error;
      }
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Get_Glyph                                                       */
      /*                                                                       */
      /* <Description>                                                         */
      /*    A function used to extract a glyph image from a slot.              */
      /*                                                                       */
      /* <Input>                                                               */
      /*    slot   :: A handle to the source glyph slot.                       */
      /*                                                                       */
      /* <Output>                                                              */
      /*    aglyph :: A handle to the glyph object.                            */
      /*                                                                       */
      /* <Return>                                                              */
      /*    FreeType error code.  0 means success.                             */
      /*                                                                       */
      FT_EXPORT_FUNC( FT_Error )  FT_Get_Glyph( FT_GlyphSlot  slot,
                                                FT_Glyph*     aglyph )
      {
        FT_Library  library = slot->library;
        FT_Error    error;
        FT_Glyph    glyph;
    
        const FT_Glyph_Class*  clazz = 0;
    
    
        if ( !slot )
          return FT_Err_Invalid_Slot_Handle;
    
        if ( !aglyph )
          return FT_Err_Invalid_Argument;
    
        /* if it is a bitmap, that's easy :-) */
        if ( slot->format == ft_glyph_format_bitmap )
          clazz = &ft_bitmap_glyph_class;
    
        /* it it is an outline too */
        else if ( slot->format == ft_glyph_format_outline )
          clazz = &ft_outline_glyph_class;
    
        else
        {
          /* try to find a renderer that supports the glyph image format */
          FT_Renderer  render = FT_Lookup_Renderer( library, slot->format, 0 );
    
    
          if ( render )
            clazz = &render->glyph_class;
        }
    
        if ( !clazz )
        {
          error = FT_Err_Invalid_Glyph_Format;
          goto Exit;
        }
    
        /* create FT_Glyph object */
        error = ft_new_glyph( library, clazz, &glyph );
        if ( error )
          goto Exit;
    
        /* copy advance while converting it to 16.16 format */
        glyph->advance.x = slot->advance.x << 10;
        glyph->advance.y = slot->advance.y << 10;
    
        /* now import the image from the glyph slot */
        error = clazz->glyph_init( glyph, slot );
    
        /* if an error occurred, destroy the glyph */
        if ( error )
          FT_Done_Glyph( glyph );
        else
          *aglyph = glyph;
    
      Exit:
        return error;
      }
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Glyph_Transform                                                 */
      /*                                                                       */
      /* <Description>                                                         */
      /*    Transforms a glyph image if its format is scalable.                */
      /*                                                                       */
      /* <Input>                                                               */
      /*    glyph  :: A handle to the target glyph object.                     */
      /*                                                                       */
      /*    matrix :: A pointer to a 2x2 matrix to apply.                      */
      /*                                                                       */
      /*    delta  :: A pointer to a 2d vector to apply.  Coordinates are      */
      /*              expressed in 1/64th of a pixel.                          */
      /*                                                                       */
      /* <Return>                                                              */
      /*    FreeType error code (the glyph format is not scalable if it is     */
      /*    not zero).                                                         */
      /*                                                                       */
      /* <Note>                                                                */
      /*    The 2x2 transformation matrix is also applied to the glyph's       */
      /*    advance vector.                                                    */
      /*                                                                       */
      FT_EXPORT_FUNC( FT_Error )  FT_Glyph_Transform( FT_Glyph    glyph,
                                                      FT_Matrix*  matrix,
                                                      FT_Vector*  delta )
      {
        const FT_Glyph_Class*  clazz;
        FT_Error               error = FT_Err_Ok;
    
    
        if ( !glyph || !glyph->clazz )
          error = FT_Err_Invalid_Argument;
        else
        {
          clazz = glyph->clazz;
          if ( clazz->glyph_transform )
          {
            /* transform glyph image */
            clazz->glyph_transform( glyph, matrix, delta );
    
            /* transform advance vector */
            if ( matrix )
              FT_Vector_Transform( &glyph->advance, matrix );
          }
          else
            error = FT_Err_Invalid_Glyph_Format;
        }
        return error;
      }
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Glyph_Get_CBox                                                  */
      /*                                                                       */
      /* <Description>                                                         */
      /*    Returns the glyph image's bounding box.                            */
      /*                                                                       */
      /* <Input>                                                               */
      /*    glyph :: A handle to the source glyph object.                      */
      /*                                                                       */
      /*    mode  :: A set of bit flags that indicate how to interpret the     */
      /*             returned bounding box values.                             */
      /*                                                                       */
      /* <Output>                                                              */
      /*    box   :: The glyph bounding box.  Coordinates are expressed in     */
      /*             1/64th of pixels if it is grid-fitted.                    */
      /*                                                                       */
      /* <Note>                                                                */
      /*    Coordinates are relative to the glyph origin, using the Y-upwards  */
      /*    convention.                                                        */
      /*                                                                       */
      /*    If `ft_glyph_bbox_subpixels' is set in `mode', the bbox            */
      /*    coordinates are returned in 26.6 pixels (i.e. 1/64th of pixels).   */
      /*    Otherwise, coordinates are expressed in integer pixels.            */
      /*                                                                       */
      /*    Note that the maximum coordinates are exclusive, which means that  */
      /*    one can compute the width and height of the glyph image (be it in  */
      /*    integer or 26.6 pixels) as:                                        */
      /*                                                                       */
      /*      width  = bbox.xMax - bbox.xMin;                                  */
      /*      height = bbox.yMax - bbox.yMin;                                  */
      /*                                                                       */
      /*    Note also that for 26.6 coordinates, if the                        */
      /*    `ft_glyph_bbox_gridfit' flag is set in `mode;, the coordinates     */
      /*    will also be grid-fitted, which corresponds to:                    */
      /*                                                                       */
      /*      bbox.xMin = FLOOR(bbox.xMin);                                    */
      /*      bbox.yMin = FLOOR(bbox.yMin);                                    */
      /*      bbox.xMax = CEILING(bbox.xMax);                                  */
      /*      bbox.yMax = CEILING(bbox.yMax);                                  */
      /*                                                                       */
      /*    The default value (0) for `bbox_mode' is `ft_glyph_bbox_pixels'.   */
      /*                                                                       */
      FT_EXPORT_FUNC( void )  FT_Glyph_Get_CBox( FT_Glyph  glyph,
                                                 FT_UInt   bbox_mode,
                                                 FT_BBox*  cbox )
      {
        const FT_Glyph_Class*  clazz;
        FT_Error               error = FT_Err_Ok;
    
    
        if ( !cbox || !glyph || !glyph->clazz )
          error = FT_Err_Invalid_Argument;
        else
        {
          clazz = glyph->clazz;
          if ( !clazz->glyph_bbox )
            error = FT_Err_Invalid_Glyph_Format;
          else
          {
            /* retrieve bbox in 26.6 coordinates */
            clazz->glyph_bbox( glyph, cbox );
    
            /* perform grid fitting if needed */
            if ( bbox_mode & ft_glyph_bbox_gridfit )
            {
              cbox->xMin &= -64;
              cbox->yMin &= -64;
              cbox->xMax  = ( cbox->xMax + 63 ) & -64;
              cbox->yMax  = ( cbox->yMax + 63 ) & -64;
            }
    
            /* convert to integer pixels if needed */
            if ( !( bbox_mode & ft_glyph_bbox_subpixels ) )
            {
              cbox->xMin >>= 6;
              cbox->yMin >>= 6;
              cbox->xMax >>= 6;
              cbox->yMax >>= 6;
            }
          }
        }
        return;
      }
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Glyph_To_Bitmap                                                 */
      /*                                                                       */
      /* <Description>                                                         */
      /*    Converts a given glyph object to a bitmap glyph object.            */
      /*                                                                       */
      /* <InOut>                                                               */
      /*    glyph       :: A pointer to a handle to the target glyph.          */
      /*                                                                       */
      /* <Input>                                                               */
      /*    render_mode :: A set of bit flags that describe how the data is    */
      /*                                                                       */
      /*                                                                       */
      /*    origin      :: A pointer to a vector used to translate the glyph   */
      /*                   image before rendering.  Can be 0 (if no            */
      /*                   translation).  The origin is expressed in           */
      /*                   26.6 pixels.                                        */
      /*                                                                       */
      /*    destroy     :: A boolean that indicates that the original glyph    */
      /*                   image should be destroyed by this function.  It is  */
      /*                   never destroyed in case of error.                   */
      /*                                                                       */
      /* <Return>                                                              */
      /*    FreeType error code.  0 means success.                             */
      /*                                                                       */
      /* <Note>                                                                */
      /*    The glyph image is translated with the `origin' vector before      */
      /*    rendering.  In case of error, it it translated back to its         */
      /*    original position and the glyph is left untouched.                 */
      /*                                                                       */
      /*    The first parameter is a pointer to a FT_Glyph handle, that will   */
      /*    be replaced by this function.  Typically, you would use (omitting  */
      /*    error handling):                                                   */
      /*                                                                       */
      /*                                                                       */
      /*      {                                                                */
      /*        FT_Glyph        glyph;                                         */
      /*        FT_BitmapGlyph  glyph_bitmap;                                  */
      /*                                                                       */
      /*                                                                       */
      /*        // load glyph                                                  */
      /*        error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT );     */
      /*                                                                       */
      /*        // extract glyph image                                         */
      /*        error = FT_Get_Glyph( face->glyph, &glyph );                   */
      /*                                                                       */
      /*        // convert to a bitmap (default render mode + destroy old)     */
      /*        if ( glyph->format != ft_glyph_format_bitmap )                 */
      /*        {                                                              */
      /*          error = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_default,  */
      /*                                      0, 1 );                          */
      /*          if ( error ) // glyph unchanged                              */
      /*            ...                                                        */
      /*        }                                                              */
      /*                                                                       */
      /*        // access bitmap content by typecasting                        */
      /*        glyph_bitmap = (FT_BitmapGlyph)glyph;                          */
      /*                                                                       */
      /*        // do funny stuff with it, like blitting/drawing               */
      /*        ...                                                            */
      /*                                                                       */
      /*        // discard glyph image (bitmap or not)                         */
      /*        FT_Done_Glyph( glyph );                                        */
      /*      }                                                                */
      /*                                                                       */
      /*                                                                       */
      /*    This function will always fail if the glyph's format isn't         */
      /*    scalable.                                                          */
      /*                                                                       */
      FT_EXPORT_FUNC( FT_Error )  FT_Glyph_To_Bitmap( FT_Glyph*   the_glyph,
                                                      FT_ULong    render_mode,
                                                      FT_Vector*  origin,
                                                      FT_Bool     destroy )
      {
        FT_GlyphSlotRec  dummy;
        FT_Error         error;
        FT_Glyph         glyph;
        FT_BitmapGlyph   bitmap;
    
        const FT_Glyph_Class*  clazz;
    
    
        /* check argument */
        if ( !the_glyph )
          goto Bad;
    
        /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
        /* then calling FT_Render_Glyph_Internal()                            */
    
        glyph = *the_glyph;
        if ( !glyph )
          goto Bad;
    
        clazz = glyph->clazz;
        if ( !clazz || !clazz->glyph_prepare )
          goto Bad;
    
        MEM_Set( &dummy, 0, sizeof ( dummy ) );
        dummy.library = glyph->library;
        dummy.format  = clazz->glyph_format;
    
        /* if `origin' is set, translate the glyph image */
        if ( origin )
          FT_Glyph_Transform( glyph, 0, origin );
    
        /* create result bitmap glyph */
        error = ft_new_glyph( glyph->library, &ft_bitmap_glyph_class,
                              (FT_Glyph*)&bitmap );
        if ( error )
          goto Exit;
    
        /* prepare dummy slot for rendering */
        error = clazz->glyph_prepare( glyph, &dummy ) ||
                FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
    
        if ( !destroy && origin )
        {
          FT_Vector  v;
    
    
          v.x = -origin->x;
          v.y = -origin->y;
          FT_Glyph_Transform( glyph, 0, &v );
        }
    
        /* in case of succes, copy the bitmap to the glyph bitmap */
        if ( !error )
        {
          error = ft_bitmap_glyph_init( bitmap, &dummy );
          if ( error )
          {
            /* this should never happen, but let's be safe */
            FT_Done_Glyph( FT_GLYPH( bitmap ) );
            goto Exit;
          }
    
          if ( destroy )
            FT_Done_Glyph( glyph );
    
          *the_glyph = FT_GLYPH( bitmap );
        }
    
      Exit:
        return error;
    
      Bad:
        error = FT_Err_Invalid_Argument;
        goto Exit;
      }
    
    
      /*************************************************************************/
      /*                                                                       */
      /* <Function>                                                            */
      /*    FT_Done_Glyph                                                      */
      /*                                                                       */
      /* <Description>                                                         */
      /*    Destroys a given glyph.                                            */
      /*                                                                       */
      /* <Input>                                                               */
      /*    glyph :: A handle to the target glyph object.                      */
      /*                                                                       */
      FT_EXPORT_FUNC( void )  FT_Done_Glyph( FT_Glyph  glyph )
      {
        if ( glyph )
        {
          FT_Memory              memory = glyph->library->memory;
          const FT_Glyph_Class*  clazz  = glyph->clazz;
    
    
          if ( clazz->glyph_done )
            clazz->glyph_done( glyph );
    
          FREE( glyph );
        }
      }
    
    
    #if 0
    
      /*************************************************************************/
      /*************************************************************************/
      /****                                                                 ****/
      /****   EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT                    ****/
      /****                                                                 ****/
      /*************************************************************************/
      /*************************************************************************/
    
      /* Compute the norm of a vector */
    
    #ifdef FT_CONFIG_OPTION_OLD_CALCS
    
      static
      FT_Pos  ft_norm( FT_Vector*  vec )
      {
        FT_Int64  t1, t2;
    
    
        MUL_64( vec->x, vec->x, t1 );
        MUL_64( vec->y, vec->y, t2 );
        ADD_64( t1, t2, t1 );
    
        return (FT_Pos)SQRT_64( t1 );
      }
    
    #else /* FT_CONFIG_OPTION_OLD_CALCS */
    
      static
      FT_Pos  ft_norm( FT_Vector*  vec )
      {
        FT_F26Dot6  u, v, d;
        FT_Int      shift;
        FT_ULong    H, L, L2, hi, lo, med;
    
    
        u = vec->x; if ( u < 0 ) u = -u;
        v = vec->y; if ( v < 0 ) v = -v;
    
        if ( u < v )
        {
          d = u;
          u = v;
          v = d;
        }
    
        /* check that we are not trying to normalize zero! */
        if ( u == 0 )
          return 0;
    
        /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */
        hi  = (FT_ULong)u >> 16;
        lo  = (FT_ULong)u & 0xFFFF;
        med = hi * lo;
    
        H     = hi * hi + ( med >> 15 );
        med <<= 17;
        L     = lo * lo + med;
        if ( L < med )
          H++;
    
        hi  = (FT_ULong)v >> 16;
        lo  = (FT_ULong)v & 0xFFFF;
        med = hi * lo;
    
        H    += hi * hi + ( med >> 15 );
        med <<= 17;
        L2    = lo * lo + med;
        if ( L2 < med )
          H++;
    
        L += L2;
        if ( L < L2 )
          H++;
    
        /* if the value is smaller than 32 bits */
        shift = 0;
        if ( H == 0 )
        {
          while ( ( L & 0xC0000000UL ) == 0 )
          {
            L <<= 2;
            shift++;
          }
          return ( FT_Sqrt32( L ) >> shift );
        }
        else
        {
          while ( H )
          {
            L   = ( L >> 2 ) | ( H << 30 );
            H >>= 2;
            shift++;
          }
          return ( FT_Sqrt32( L ) << shift );
        }
      }
    
    #endif /* FT_CONFIG_OPTION_OLD_CALCS */
    
    
      static
      int  ft_test_extrema( FT_Outline*  outline,
                            int          n )
      {
        FT_Vector  *prev, *cur, *next;
        FT_Pos      product;
        FT_Int      first, last;
    
    
        /* we need to compute the `previous' and `next' point */
        /* for these extrema.                                 */
        cur   = outline->points + n;
        prev  = cur - 1;
        next  = cur + 1;
    
        first = 0;
        for ( c = 0; c < outline->n_contours; c++ )
        {
          last  = outline->contours[c];
    
          if ( n == first )
            prev = outline->points + last;
    
          if ( n == last )
            next = outline->points + first;
    
          first = last + 1;
        }
    
        product = FT_MulDiv( cur->x - prev->x,   /* in.x  */
                             next->y - cur->y,   /* out.y */
                             0x40 )
                  -
                  FT_MulDiv( cur->y - prev->y,   /* in.y  */
                             next->x - cur->x,   /* out.x */
                             0x40 );
    
        if ( product )
          product = product > 0 ? 1 : -1;
    
        return product;
      }
    
    
      /* Compute the orientation of path filling.  It differs between TrueType */
      /* and Type1 formats.  We could use the `ft_outline_reverse_fill' flag,  */
      /* but it is better to re-compute it directly (it seems that this flag   */
      /* isn't correctly set for some weird composite glyphs currently).       */
      /*                                                                       */
      /* We do this by computing bounding box points, and computing their      */
      /* curvature.                                                            */
      /*                                                                       */
      /* The function returns either 1 or -1.                                  */
      /*                                                                       */
      static
      int  ft_get_orientation( FT_Outline*  outline )
      {
        FT_BBox  box;
        FT_BBox  indices;
        int      n, last;
    
    
        indices.xMin = -1;
        indices.yMin = -1;
        indices.xMax = -1;
        indices.yMax = -1;
    
        box.xMin = box.yMin = 32767;
        box.xMax = box.yMax = -32768;
    
        /* is it empty ? */
        if ( outline->n_contours < 1 )
          return 1;
    
        last = outline->contours[outline->n_contours - 1];
    
        for ( n = 0; n <= last; n++ )
        {
          FT_Pos  x, y;
    
    
          x = outline->points[n].x;
          if ( x < box.xMin )
          {
            box.xMin     = x;
            indices.xMin = n;
          }
          if ( x > box.xMax )
          {
            box.xMax     = x;
            indices.xMax = n;
          }
    
          y = outline->points[n].y;
          if ( y < box.yMin )
          {
            box.yMin     = y;
            indices.yMin = n;
          }
          if ( y > box.yMax )
          {
            box.yMax     = y;
            indices.yMax = n;
          }
        }
    
        /* test orientation of the xmin */
        return ft_test_extrema( outline, indices.xMin ) ||
               ft_test_extrema( outline, indices.yMin ) ||
               ft_test_extrema( outline, indices.xMax ) ||
               ft_test_extrema( outline, indices.yMax ) ||
               1;  /* this is an empty glyph? */
      }
    
    
      static
      FT_Error  ft_embolden( FT_Face      original,
                             FT_Outline*  outline,
                             FT_Pos*      advance )
      {
        FT_Vector  u, v;
        FT_Vector* points;
        FT_Vector  cur, prev, next;
        FT_Pos     distance;
        int        c, n, first, orientation;
    
        FT_UNUSED( advance );
    
    
        /* compute control distance */
        distance = FT_MulFix( original->em_size / 60,
                              original->size->metrics.y_scale );
    
        orientation = ft_get_orientation( &original->glyph->outline );
    
        points = original->glyph->outline.points;
    
        first = 0;
        for ( c = 0; c < outline->n_contours; c++ )
        {
          int  last = outline->contours[c];
    
    
          prev = points[last];
    
          for ( n = first; n <= last; n++ )
          {
            FT_Pos     norm, delta, d;
            FT_Vector  in, out;
    
    
            cur = points[n];
            if ( n < last ) next = points[n + 1];
            else            next = points[first];
    
            /* compute the in and out vectors */
            in.x  = cur.x - prev.x;
            in.y  = cur.y - prev.y;
    
            out.x = next.x - cur.x;
            out.y = next.y - cur.y;
    
            /* compute U and V */
            norm = ft_norm( &in );
            u.x = orientation *  FT_DivFix( in.y, norm );
            u.y = orientation * -FT_DivFix( in.x, norm );
    
            norm = ft_norm( &out );
            v.x = orientation *  FT_DivFix( out.y, norm );
            v.y = orientation * -FT_DivFix( out.x, norm );
    
            d = distance;
    
            if ( ( outline->flags[n] & FT_Curve_Tag_On ) == 0 )
              d *= 2;
    
            /* Check discriminant for parallel vectors */
            delta = FT_MulFix( u.x, v.y ) - FT_MulFix( u.y, v.x );
            if ( delta > FT_BOLD_THRESHOLD || delta < -FT_BOLD_THRESHOLD )
            {
              /* Move point -- compute A and B */
              FT_Pos  x, y, A, B;
    
    
              A = d + FT_MulFix( cur.x, u.x ) + FT_MulFix( cur.y, u.y );
              B = d + FT_MulFix( cur.x, v.x ) + FT_MulFix( cur.y, v.y );
    
              x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y );
              y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x );
    
              outline->points[n].x = distance + FT_DivFix( x, delta );
              outline->points[n].y = distance + FT_DivFix( y, delta );
            }
            else
            {
              /* Vectors are nearly parallel */
              FT_Pos  x, y;
    
    
              x = distance + cur.x + FT_MulFix( d, u.x + v.x ) / 2;
              y = distance + cur.y + FT_MulFix( d, u.y + v.y ) / 2;
    
              outline->points[n].x = x;
              outline->points[n].y = y;
            }
    
            prev = cur;
          }
    
          first = last + 1;
        }
    
        if ( advance )
          *advance = ( *advance + distance * 4 ) & -64;
    
        return 0;
      }
    
    #endif /* 0 -- EXPERIMENTAL STUFF! */
    
    
    /* END */