/***************************************************************************/
/*                                                                         */
/*  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 "ftglyph.h"
#include "ftoutln.h"
#include "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 */
