/***************************************************************************/

/*                                                                         */

/*  ftglyph.c                                                              */

/*                                                                         */

/*    FreeType convenience functions to handle glyphs (body).              */

/*                                                                         */

/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2007, 2008, 2010 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 <ft2build.h>

#include FT_GLYPH_H

#include FT_OUTLINE_H

#include FT_BITMAP_H

#include FT_INTERNAL_OBJECTS_H



#include "basepic.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





  /*************************************************************************/

  /*************************************************************************/

  /****                                                                 ****/

  /****   FT_BitmapGlyph support                                        ****/

  /****                                                                 ****/

  /*************************************************************************/

  /*************************************************************************/



  FT_CALLBACK_DEF( FT_Error )

  ft_bitmap_glyph_init( FT_Glyph      bitmap_glyph,

                        FT_GlyphSlot  slot )

  {

    FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;

    FT_Error        error   = FT_Err_Ok;

    FT_Library      library = FT_GLYPH( glyph )->library;





    if ( slot->format != FT_GLYPH_FORMAT_BITMAP )

    {

      error = FT_Err_Invalid_Glyph_Format;

      goto Exit;

    }



    glyph->left = slot->bitmap_left;

    glyph->top  = slot->bitmap_top;



    /* do lazy copying whenever possible */

    if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )

    {

      glyph->bitmap = slot->bitmap;

      slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;

    }

    else

    {

      FT_Bitmap_New( &glyph->bitmap );

      error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );

    }



  Exit:

    return error;

  }





  FT_CALLBACK_DEF( FT_Error )

  ft_bitmap_glyph_copy( FT_Glyph  bitmap_source,

                        FT_Glyph  bitmap_target )

  {

    FT_Library      library = bitmap_source->library;

    FT_BitmapGlyph  source  = (FT_BitmapGlyph)bitmap_source;

    FT_BitmapGlyph  target  = (FT_BitmapGlyph)bitmap_target;





    target->left = source->left;

    target->top  = source->top;



    return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap );

  }





  FT_CALLBACK_DEF( void )

  ft_bitmap_glyph_done( FT_Glyph  bitmap_glyph )

  {

    FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;

    FT_Library      library = FT_GLYPH( glyph )->library;





    FT_Bitmap_Done( library, &glyph->bitmap );

  }





  FT_CALLBACK_DEF( void )

  ft_bitmap_glyph_bbox( FT_Glyph  bitmap_glyph,

                        FT_BBox*  cbox )

  {

    FT_BitmapGlyph  glyph = (FT_BitmapGlyph)bitmap_glyph;





    cbox->xMin = glyph->left << 6;

    cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 );

    cbox->yMax = glyph->top << 6;

    cbox->yMin = cbox->yMax - ( glyph->bitmap.rows << 6 );

  }





  FT_DEFINE_GLYPH(ft_bitmap_glyph_class,

    sizeof ( FT_BitmapGlyphRec ),

    FT_GLYPH_FORMAT_BITMAP,



    ft_bitmap_glyph_init,

    ft_bitmap_glyph_done,

    ft_bitmap_glyph_copy,

    0,                          /* FT_Glyph_TransformFunc */

    ft_bitmap_glyph_bbox,

    0                           /* FT_Glyph_PrepareFunc   */

  )





  /*************************************************************************/

  /*************************************************************************/

  /****                                                                 ****/

  /****   FT_OutlineGlyph support                                       ****/

  /****                                                                 ****/

  /*************************************************************************/

  /*************************************************************************/





  FT_CALLBACK_DEF( FT_Error )

  ft_outline_glyph_init( FT_Glyph      outline_glyph,

                         FT_GlyphSlot  slot )

  {

    FT_OutlineGlyph  glyph   = (FT_OutlineGlyph)outline_glyph;

    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;



    FT_Outline_Copy( source, target );



  Exit:

    return error;

  }





  FT_CALLBACK_DEF( void )

  ft_outline_glyph_done( FT_Glyph  outline_glyph )

  {

    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;





    FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );

  }





  FT_CALLBACK_DEF( FT_Error )

  ft_outline_glyph_copy( FT_Glyph  outline_source,

                         FT_Glyph  outline_target )

  {

    FT_OutlineGlyph  source  = (FT_OutlineGlyph)outline_source;

    FT_OutlineGlyph  target  = (FT_OutlineGlyph)outline_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;

  }





  FT_CALLBACK_DEF( void )

  ft_outline_glyph_transform( FT_Glyph          outline_glyph,

                              const FT_Matrix*  matrix,

                              const FT_Vector*  delta )

  {

    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;





    if ( matrix )

      FT_Outline_Transform( &glyph->outline, matrix );



    if ( delta )

      FT_Outline_Translate( &glyph->outline, delta->x, delta->y );

  }





  FT_CALLBACK_DEF( void )

  ft_outline_glyph_bbox( FT_Glyph  outline_glyph,

                         FT_BBox*  bbox )

  {

    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;





    FT_Outline_Get_CBox( &glyph->outline, bbox );

  }





  FT_CALLBACK_DEF( FT_Error )

  ft_outline_glyph_prepare( FT_Glyph      outline_glyph,

                            FT_GlyphSlot  slot )

  {

    FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;





    slot->format         = FT_GLYPH_FORMAT_OUTLINE;

    slot->outline        = glyph->outline;

    slot->outline.flags &= ~FT_OUTLINE_OWNER;



    return FT_Err_Ok;

  }





  FT_DEFINE_GLYPH( ft_outline_glyph_class, 

    sizeof ( FT_OutlineGlyphRec ),

    FT_GLYPH_FORMAT_OUTLINE,



    ft_outline_glyph_init,

    ft_outline_glyph_done,

    ft_outline_glyph_copy,

    ft_outline_glyph_transform,

    ft_outline_glyph_bbox,

    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  = NULL;





     *aglyph = 0;



     if ( !FT_ALLOC( glyph, clazz->glyph_size ) )

     {

       glyph->library = library;

       glyph->clazz   = clazz;

       glyph->format  = clazz->glyph_format;



       *aglyph = glyph;

     }



     return error;

   }





  /* documentation is in ftglyph.h */



  FT_EXPORT_DEF( 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 )

    {

      error = FT_Err_Invalid_Argument;

      goto Exit;

    }



    *target = 0;



    if ( !source || !source->clazz )

    {

      error = FT_Err_Invalid_Argument;

      goto Exit;

    }



    clazz = source->clazz;

    error = ft_new_glyph( source->library, clazz, &copy );

    if ( error )

      goto Exit;



    copy->advance = source->advance;

    copy->format  = source->format;



    if ( clazz->glyph_copy )

      error = clazz->glyph_copy( source, copy );



    if ( error )

      FT_Done_Glyph( copy );

    else

      *target = copy;



  Exit:

    return error;

  }





  /* documentation is in ftglyph.h */



  FT_EXPORT_DEF( FT_Error )

  FT_Get_Glyph( FT_GlyphSlot  slot,

                FT_Glyph     *aglyph )

  {

    FT_Library  library;

    FT_Error    error;

    FT_Glyph    glyph;



    const FT_Glyph_Class*  clazz = 0;





    if ( !slot )

      return FT_Err_Invalid_Slot_Handle;



    library = slot->library;



    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_GET;



    /* if it is an outline */

    else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )

      clazz = FT_OUTLINE_GLYPH_CLASS_GET;



    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;

  }





  /* documentation is in ftglyph.h */



  FT_EXPORT_DEF( 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;

  }





  /* documentation is in ftglyph.h */



  FT_EXPORT_DEF( void )

  FT_Glyph_Get_CBox( FT_Glyph  glyph,

                     FT_UInt   bbox_mode,

                     FT_BBox  *acbox )

  {

    const FT_Glyph_Class*  clazz;





    if ( !acbox )

      return;



    acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;



    if ( !glyph || !glyph->clazz )

      return;

    else

    {

      clazz = glyph->clazz;

      if ( !clazz->glyph_bbox )

        return;

      else

      {

        /* retrieve bbox in 26.6 coordinates */

        clazz->glyph_bbox( glyph, acbox );



        /* perform grid fitting if needed */

        if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT ||

             bbox_mode == FT_GLYPH_BBOX_PIXELS  )

        {

          acbox->xMin = FT_PIX_FLOOR( acbox->xMin );

          acbox->yMin = FT_PIX_FLOOR( acbox->yMin );

          acbox->xMax = FT_PIX_CEIL( acbox->xMax );

          acbox->yMax = FT_PIX_CEIL( acbox->yMax );

        }



        /* convert to integer pixels if needed */

        if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE ||

             bbox_mode == FT_GLYPH_BBOX_PIXELS   )

        {

          acbox->xMin >>= 6;

          acbox->yMin >>= 6;

          acbox->xMax >>= 6;

          acbox->yMax >>= 6;

        }

      }

    }

    return;

  }





  /* documentation is in ftglyph.h */



  FT_EXPORT_DEF( FT_Error )

  FT_Glyph_To_Bitmap( FT_Glyph*       the_glyph,

                      FT_Render_Mode  render_mode,

                      FT_Vector*      origin,

                      FT_Bool         destroy )

  {

    FT_GlyphSlotRec           dummy;

    FT_GlyphSlot_InternalRec  dummy_internal;

    FT_Error                  error = FT_Err_Ok;

    FT_Glyph                  glyph;

    FT_BitmapGlyph            bitmap = NULL;



    const FT_Glyph_Class*     clazz;



#ifdef FT_CONFIG_OPTION_PIC

    FT_Library                library = FT_GLYPH( glyph )->library;

#endif





    /* 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;



    /* when called with a bitmap glyph, do nothing and return successfully */

    if ( clazz == FT_BITMAP_GLYPH_CLASS_GET )

      goto Exit;



    if ( !clazz || !clazz->glyph_prepare )

      goto Bad;



    FT_MEM_ZERO( &dummy, sizeof ( dummy ) );

    FT_MEM_ZERO( &dummy_internal, sizeof ( dummy_internal ) );

    dummy.internal = &dummy_internal;

    dummy.library  = glyph->library;

    dummy.format   = clazz->glyph_format;



    /* create result bitmap glyph */

    error = ft_new_glyph( glyph->library, FT_BITMAP_GLYPH_CLASS_GET,

                          (FT_Glyph*)(void*)&bitmap );

    if ( error )

      goto Exit;



#if 1

    /* if `origin' is set, translate the glyph image */

    if ( origin )

      FT_Glyph_Transform( glyph, 0, origin );

#else

    FT_UNUSED( origin );

#endif



    /* prepare dummy slot for rendering */

    error = clazz->glyph_prepare( glyph, &dummy );

    if ( !error )

      error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );



#if 1

    if ( !destroy && origin )

    {

      FT_Vector  v;





      v.x = -origin->x;

      v.y = -origin->y;

      FT_Glyph_Transform( glyph, 0, &v );

    }

#endif



    if ( error )

      goto Exit;



    /* in case of success, copy the bitmap to the glyph bitmap */

    error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy );

    if ( error )

      goto Exit;



    /* copy advance */

    bitmap->root.advance = glyph->advance;



    if ( destroy )

      FT_Done_Glyph( glyph );



    *the_glyph = FT_GLYPH( bitmap );



  Exit:

    if ( error && bitmap )

      FT_Done_Glyph( FT_GLYPH( bitmap ) );



    return error;



  Bad:

    error = FT_Err_Invalid_Argument;

    goto Exit;

  }





  /* documentation is in ftglyph.h */



  FT_EXPORT_DEF( 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 );



      FT_FREE( glyph );

    }

  }





/* END */

