/* vi: set sw=4 ts=4: */
/*
 * CCE - Console Chinese Environment -
 * Copyright (C) 1998-2003 Rui He (rhe@3eti.com)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 */

#include	<stdio.h>
#include	<unistd.h>
#include	<stdlib.h>
#include	<errno.h>

#include	"defs.h"
#include	"vc.h"

#ifdef SUPPORT_FREETYPE_FONT

#include	"ftfont.h"
#include	"encfilter.h"

#ifdef HAVE_ICONV_H
#include	<iconv.h>
#endif

#define DEF_RENDER_MODE   FT_RENDER_MODE_NORMAL /* FT_RENDER_MODE_MONO */

int UseTTFont, TTFontSize;
char *TTFontPathName;

int DoAntiAlias = 1;  /* Set it to 0 if not doing Anti-Alias */
int ftXOrig, ftYOrig;  /* X/Y Origin offset */

static FT_Library 	ftLibrary;
static FT_Face 	    ftFace;

#ifdef USE_DYNAMIC_FREETYPELIB

static FT_Error (*p_FT_Init_FreeType)( FT_Library  *alibrary );
static FT_Error (*p_FT_New_Face)( FT_Library library, const char*  filepathname,
           FT_Long      face_index, FT_Face     *aface );
static FT_Error (*p_FT_Done_FreeType)( FT_Library  library );
static FT_Error (*p_FT_Set_Pixel_Sizes)( FT_Face  face,
           FT_UInt  pixel_width, FT_UInt  pixel_height );
static FT_Error (*p_FT_Select_Charmap)( FT_Face face, FT_Encoding  encoding );
static FT_UInt  (*p_FT_Get_Char_Index)( FT_Face face, FT_ULong charcode);
static FT_Error (*p_FT_Load_Glyph)( FT_Face face, FT_UInt  glyph_index, FT_Int32 load_flags);
static FT_Error (*p_FT_Render_Glyph)( FT_GlyphSlot    slot, FT_Render_Mode  render_mode );

static void *ftLibHandle;

static char *ftLibSearchPath[] = {
#if defined(__WINDOWS__)
	"freetype.dll",
#else
	"libfreetype.so",
	"libfreetype.so.6",  
	"/usr/local/lib/libfreetype.so",
	"/usr/local/lib/libfreetype.so.6",
#endif
	NULL,
};

static int LoadDynamicFreeTypeLibrary(void)
{
	int i;

	for(i = 0; ftLibSearchPath[i]; i++)
	{
		ftLibHandle = dlopen(ftLibSearchPath[i], RTLD_LAZY);
		if (ftLibHandle) break;
	}

	if (!ftLibHandle) 
	{
		message("Failed to load FREETYPE library %s.\r\n", ftLibSearchPath[0]);
		return FAILURE;
	}

    p_FT_Init_FreeType = dlsym(ftLibHandle,  SYMBOL_FT_INIT_FREETYPE   );
    p_FT_New_Face = dlsym(ftLibHandle,  SYMBOL_FT_NEW_FACE       );
    p_FT_Done_FreeType = dlsym(ftLibHandle,  SYMBOL_FT_DONE_FREETYPE );
    p_FT_Set_Pixel_Sizes = dlsym(ftLibHandle,  SYMBOL_FT_SET_PIXEL_SIZES);
    p_FT_Select_Charmap = dlsym(ftLibHandle,  SYMBOL_FT_SELECT_CHARMAP );
    p_FT_Get_Char_Index = dlsym(ftLibHandle,  SYMBOL_FT_GET_CHAR_INDEX );
    p_FT_Load_Glyph = dlsym(ftLibHandle,  SYMBOL_FT_LOAD_GLYPH    );
    p_FT_Render_Glyph = dlsym(ftLibHandle,  SYMBOL_FT_RENDER_GLYPH );

    if (!p_FT_Init_FreeType || !p_FT_New_Face || !p_FT_Done_FreeType || 
        !p_FT_Set_Pixel_Sizes || !p_FT_Select_Charmap || !p_FT_Get_Char_Index ||
        !p_FT_Load_Glyph || !p_FT_Render_Glyph)
	{
		warn("Can't resolve all the required FreeType routines.\r\n");
		dlclose(ftLibHandle);
		ftLibHandle = NULL;
		return FAILURE;
	}
	
	return SUCCESS;
}

static void UnloadDynamicFreeTypeLibrary(void)
{
	if (ftLibHandle) 
	{
		dlclose(ftLibHandle);
		ftLibHandle = NULL;
	}
}

#endif  /* USE_DYNAMIC_FREETYPELIB */

static iconv_t IconvCdAry[CODE_NUM];   /* converstion descriptor from encoding to Unicode */

#define TARGET_ICONV_ENCODING  "UTF-16BE"  /* UTF-16 may get LE or BE! */

int FreetypeGetGlyph(int encoding, int ch1, int ch2, FT_GlyphSlot *glyph)
{
	static char inbuf[8], outbuf[8], *inptr, *outptr;
	size_t inleft, outleft;
	FT_UInt glyph_index;
		
	*glyph = NULL;
	if (ch1 == 0) return -1; /* Empty box */
	
	if (ch2) /* double byte */
	{
#ifdef HAVE_ICONV
		if (!IconvCdAry[encoding])
		{
			int i;
			iconv_t cd;
			
			for(i = 0; IconvSrcEncoding[encoding][i]; i++)
			{
				if ((cd = iconv_open(TARGET_ICONV_ENCODING, 
						IconvSrcEncoding[encoding][i])) != (iconv_t)-1)
					break;
			}
					
			if (cd == (iconv_t)-1)
			{
				warn("Failed to iconv_open(%s,%s).\r\n", 
					TARGET_ICONV_ENCODING, IconvSrcEncoding[encoding][0]);
				return -1;
			}
			IconvCdAry[encoding] = cd;

			inbuf[0] = 0x20; /* ASCII SPACE */
			inptr = inbuf;
			outptr = outbuf;
			inleft = 1;
			outleft = sizeof(outbuf);
			iconv(cd, &inptr, &inleft, &outptr, &outleft); /* UTF prefix 0xFE 0xFF */
		}

		inbuf[0] = (u_char)(ch1);
		inbuf[1] = (u_char)(ch2);

		inptr = inbuf;
		outptr = outbuf;
		inleft = 2;
		outleft = sizeof(outbuf);

		if (iconv(IconvCdAry[encoding], &inptr, &inleft, &outptr, &outleft) == (size_t)-1)
		{
#ifdef DEBUG
			warn("iconv failed: encoding=%d char=0x%02X%02X errno=%d\n", encoding, ch1, ch2, errno);

#endif
			return -1;
		}
		ch1 = ((u_char)(outbuf[0]) << 8 | (u_char)(outbuf[1]));  /* BE! byte stream */

#else /* HAVE_ICONV */
		return -1;
#endif
	}

	glyph_index = FT_GET_CHAR_INDEX(ftFace, ch1); /* return 0 for undefined glyph */
			
	if (glyph_index == 0 || FT_LOAD_GLYPH(ftFace, glyph_index, FT_LOAD_DEFAULT) ||
	    FT_RENDER_GLYPH(ftFace->glyph,  DEF_RENDER_MODE))
	{
#ifdef DEBUG

   		warn("FT_Load_Glyph/Render_Glyph failed Unicode=0x%04X glyph=%d errno=%d\n",
			ch1, glyph_index, errno);
#endif
		return -1;
	}

	*glyph = ftFace->glyph;
	return 0;
}	

#define FT_ROUNDUP(n, f, EM) ((n)*(f)) % EM ? ((n)*(f))/EM+1 : ((n)*(f))/EM

int FreetypeInit (char *fontfile, int fontsize)
{
	
#ifdef USE_DYNAMIC_FREETYPELIB
    if (LoadDynamicFreeTypeLibrary() != SUCCESS) return FAILURE;
#endif
 
    if (FT_INIT_FREETYPE (&ftLibrary))
    {
		warn("Failed to initialize FreeType library.\r\n");
        goto err2;
    }

    if (FT_NEW_FACE (ftLibrary, fontfile, 0, &ftFace))
    {
        warn("Failed to open TrueType font %s, errno=%d\r\n", fontfile, errno);
		goto err;
    }

    if (!FT_IS_SCALABLE (ftFace))
    {
		warn("Font %s is not scalable, not TrueType font?\r\n", fontfile);
		goto err;
    }

	if (fontsize <= 0) fontsize = DEFAULT_TTFONT_SIZE;
	if (fontsize < MIN_TTFONT_SIZE) fontsize = MIN_TTFONT_SIZE;
	if (fontsize > MAX_TTFONT_SIZE) fontsize = MAX_TTFONT_SIZE;

    if (FT_SET_PIXEL_SIZES (ftFace, fontsize, fontsize)) /* square shape */
    {
        warn("Failed to do FT_Set_Pixel_Sizes(%d,%d)\r\n", fontsize, fontsize);
		goto err;
    }

	FT_SELECT_CHARMAP(ftFace, FT_ENCODING_UNICODE);  /* necessary ? */

	ftXOrig = 0;
    ftYOrig = FT_ROUNDUP(ftFace->bbox.yMax, fontsize, ftFace->units_per_EM);

	message("Using TrueType font %s, AntiAlias=%s\r\n", fontfile, DoAntiAlias ? "Yes" : "No");
#ifdef DEBUG
	message("Font family %s, %d glyphs, size %dx%d, yorig=%d.\r\n",
			 ftFace->family_name, ftFace->num_glyphs, fontsize, fontsize, ftYOrig);
#endif
	fontwidth = fontsize/2; 
	fontheight = fontsize; 

    return SUCCESS;

err:
	FT_DONE_FREETYPE (ftLibrary);
	ftLibrary = NULL;
err2:
#ifdef USE_DYNAMIC_FREETYPELIB
    UnloadDynamicFreeTypeLibrary();
#endif
    return FAILURE;
}
    
void FreetypeCleanup (void)
{
	int i;

#ifdef HAVE_ICONV
	for(i = 0; i < CODE_NUM; i++)
	{
		if (IconvCdAry[i]) iconv_close(IconvCdAry[i]);
		IconvCdAry[i] = NULL;
	}
#endif

    if (ftLibrary)
	{
		FT_DONE_FREETYPE (ftLibrary);
		ftLibrary = NULL;
	}

#ifdef USE_DYNAMIC_FREETYPELIB
    UnloadDynamicFreeTypeLibrary();
#endif

}

#endif  /* SUPPORT_FREETYPE_FONT */

