/*
   (c) Copyright 2001-2009  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by Denis Oliver Kropp <dok@directfb.org>,
              Andreas Hundt <andi@fischlustig.de>,
              Sven Neumann <neo@directfb.org>,
              Ville Syrjälä <syrjala@sci.fi> and
              Claudio Ciccani <klan@users.sf.net>.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <config.h>
#include <stdarg.h>

#include <directfb.h>

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>


#include <core/fonts.h>
#include <core/gfxcard.h>
#include <core/surface.h>
#include <core/surface_buffer.h>

#include <gfx/convert.h>

#include <media/idirectfbfont.h>

#include <direct/hash.h>

#include <direct/interface.h>
#include <direct/mem.h>
#include <direct/memcpy.h>
#include <direct/utf8.h>

#include "mstar_bmpfont.h"

#define DEFAULT_FONT_ASCENDER   16
#define DEFAULT_FONT_DESCENDER  -4


typedef struct {
     int         fixed_advance;
     int       fixed_kerning_distance;

     u16        font_size;
     u16        u8FontBPP;
     bool       littleendian;

     FONT_BIN_HEADER header;
     u8 * pbboxaddr;        // address of bbox
     u8 * pcodemapaddr;     // address of codemap
     u8 * pglyphaddr;       // address of glyph
     int   linebytes;
     u32 *pstartline;

/***********************************/
//following is for linux mmap
     int fd;//font file hander
     size_t  filesize;
     void *p_mmap_ptr;

} MStarBmpFImplData;



static DFBResult
Probe( IDirectFBFont_ProbeContext *ctx );

static DFBResult
Construct( IDirectFBFont      *thiz,
	   ... );

#include <direct/interface_implementation.h>

DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBFont, MStarBmp )
 void AddFontMstarBmpInterface()
 {
 }

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

int _MStarBmp_Get_Char_Index(MStarBmpFImplData *data,int character)
{
     int find_left = 0,find_right,find_middle;
     u8 maxsearch = 0;
     CHAR_CODEMAP_BLOCK * pcharcodemapblock;

     if(data->header.u32CodemapBlockNum == 0 || data->pcodemapaddr == NULL)
     {
        printf("warning......... \n");
        return character;
     }

    // Guessing first block for ASCII
    // Special check for ASCII-255 to see if in the first block
     if(character <= 255)
     {
        pcharcodemapblock = (CHAR_CODEMAP_BLOCK*)data->pcodemapaddr;
        if(character >= pcharcodemapblock->u16StartCode && character <= pcharcodemapblock->u16EndCode)
        {//found
            return character - pcharcodemapblock->u16StartCode + pcharcodemapblock->u16StartIndex;
        }
        else
        {// not found, set the binary-search left to 1
            find_left = 1;
        }
     }

     find_right = data->header.u32CodemapBlockNum - 1;
     if(find_right == 0)
     {
        printf("do not found character %d \n",character);
        return ERR_NULL_INDEX;
     }

     while(find_left <= find_right)
     {
        find_middle = (find_left + find_right)/2;
        pcharcodemapblock = (CHAR_CODEMAP_BLOCK*)data->pcodemapaddr + find_middle;

        if(character < pcharcodemapblock->u16StartCode)
        {
            if(find_middle == 0)
                break;

            find_right = find_middle - 1;
        }
        else if(character <= pcharcodemapblock->u16EndCode)
        {
            return character - pcharcodemapblock->u16StartCode + pcharcodemapblock->u16StartIndex;
        }
        else
        {
            find_left = find_middle + 1;
        }

        if(maxsearch++ > 16)
        {
            break;
        }

     }

    return ERR_NULL_INDEX;
}

static DFBResult
MStarBmpUTF8GetCharacterIndex( CoreFont     *thiz,
                          unsigned int  character,
                          unsigned int *ret_index )
{
     MStarBmpFImplData *data = thiz->impl_data;

     *ret_index = _MStarBmp_Get_Char_Index(data,character);

     if(*ret_index == ERR_NULL_INDEX)
        return DFB_FAILURE;

     return DFB_OK;

}

static DFBResult
MStarBmpUTF8DecodeText( CoreFont       *thiz,
                   const void     *text,
                   int             length,
                   unsigned int   *ret_indices,
                   int            *ret_num )
{
     int pos = 0, num = 0;
     const u8 *bytes   = text;
     MStarBmpFImplData *data = thiz->impl_data;

     while (pos < length)
     {
         unsigned int c;
         //printf("bytes[%d] = %x \n",pos,bytes[pos]);
         if (bytes[pos] < 128)
            c = bytes[pos++];
         else {
            c = DIRECT_UTF8_GET_CHAR( &bytes[pos] );
            pos += DIRECT_UTF8_SKIP(bytes[pos]);
         }
         //printf("c = %x \n",c);

         ret_indices[num] = _MStarBmp_Get_Char_Index(data,c);
         if(ret_indices[num] == ERR_NULL_INDEX)
         {
            printf("[%s] cannot found character %d \n ",__FUNCTION__,c);
            return DFB_FAILURE;
         }

         num ++;
     }

     *ret_num = num;

     return DFB_OK;
}

static const CoreFontEncodingFuncs MStarBmpUTF8Funcs = {
     GetCharacterIndex:  MStarBmpUTF8GetCharacterIndex,
     DecodeText:         MStarBmpUTF8DecodeText
};

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

static DFBResult
MStarBmpUCSGetCharacterIndex( CoreFont     *thiz,
                          unsigned int  character,
                          unsigned int *ret_index )
{
     MStarBmpFImplData *data = thiz->impl_data;

     *ret_index = _MStarBmp_Get_Char_Index(data,character);

     if(*ret_index == ERR_NULL_INDEX)
        return DFB_FAILURE;

     return DFB_OK;

}

static DFBResult
MStarBmpUCSDecodeText( CoreFont       *thiz,
                   const void     *text,
                   int             length,
                   unsigned int   *ret_indices,
                   int            *ret_num )
{
     MStarBmpFImplData *data = thiz->impl_data;
     int pos = 0, num = 0;
     const u16 *words   = text;

     length >>= 1;

     while (pos < length)
     {
         unsigned int c;
         c = (unsigned int)words[pos];

         ret_indices[num] = _MStarBmp_Get_Char_Index(data,c);
         if(ret_indices[num] == ERR_NULL_INDEX)
         {
            printf("[%s] cannot foudn character %d \n ",__FUNCTION__,c);
            return DFB_FAILURE;
         }

         num ++;
     }

     *ret_num = num;

     return DFB_OK;
}

static const CoreFontEncodingFuncs MStarBmpUCS2Funcs = {
     GetCharacterIndex:  MStarBmpUCSGetCharacterIndex,
     DecodeText:         MStarBmpUCSDecodeText
};

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


static void
IDirectFBFont_MStarBmp_Destruct( IDirectFBFont *thiz )
{
     IDirectFBFont_data *data = (IDirectFBFont_data*)thiz->priv;


     if (data->font->impl_data)
     {
         MStarBmpFImplData *impl_data = (MStarBmpFImplData*) data->font->impl_data;
         //printf("iiiiiiiiiiiiiiiiiiin IDirectFBFont_MStarBmp_Destruct, impl_data = %p \n",impl_data);

         if(impl_data->p_mmap_ptr)
         {
             //D_ASSERT(impl_data->size);
             munmap(impl_data->p_mmap_ptr, impl_data->filesize);
             D_ASSERT(impl_data->fd >= 0);
             close(impl_data->fd);
         }

         if(impl_data->pbboxaddr)
         {
             D_FREE(impl_data->pbboxaddr);
             impl_data->pbboxaddr = NULL;
         }

         if(impl_data->pcodemapaddr)
         {
             D_FREE(impl_data->pcodemapaddr);
             impl_data->pcodemapaddr = NULL;
         }
         if(impl_data->pglyphaddr)
         {
             D_FREE(impl_data->pglyphaddr);
             impl_data->pglyphaddr = NULL;
         }
         if(impl_data->pstartline)
         {
             D_FREE(impl_data->pstartline);
             impl_data->pstartline = NULL;
         }

         D_FREE( impl_data );

         data->font->impl_data = NULL;
     }

     IDirectFBFont_Destruct( thiz );
}


static DirectResult
IDirectFBFont_MStarBmp_Release( IDirectFBFont *thiz )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFBFont)

     //printf("data = %p,data->ref = %d \n",data,data->ref);
     if (--data->ref == 0) {
          IDirectFBFont_MStarBmp_Destruct( thiz );
     }

     return DFB_OK;
}


void _memswapendian16(void * pData, u32 u32ByteLength)
{
    u16 * pu16Data = (u16*)pData;
    s32 s32Count = u32ByteLength/sizeof(u16);
    while( --s32Count >= 0 )
    {
        *pu16Data = BYTESWAP16(*pu16Data);
        pu16Data++;
    }
}

void _memswapendian32(void * pData, u32 u32ByteLength)
{
    u32 * pu32Data = (u32*)pData;
    s32 s32Count = u32ByteLength/sizeof(u32);
    while( --s32Count >= 0 )
    {
        *pu32Data = BYTESWAP32(*pu32Data);
        pu32Data++;
    }
}


static u32 _MStar_BmpFont_GetLineBytes(const FONT_BIN_HEADER *pfontbinheader)
{
    u32  u32pitchbits = pfontbinheader->u32Pitch * 8;
    return ((pfontbinheader->u32Width+u32pitchbits-1)/u32pitchbits) * pfontbinheader->u32Pitch * pfontbinheader->u32BPP;
}


static bool _Load_MStarBmp_FontData(MStarBmpFImplData *data)
{
    u32 len,linebytes;

    //load bbox info
    if(data->header.u32BBoxOffset)
    {
        len = data->header.u32CharNum * sizeof(FONT_GLYPH_BBOX);
        data->pbboxaddr = D_MALLOC(len);
        //printf("data->pbboxaddr = %p \n",data->pbboxaddr);
        if(NULL == data->pbboxaddr)
        {
            D_OOM();
            return false;
        }
        memcpy(data->pbboxaddr, data->p_mmap_ptr + data->header.u32BBoxOffset, len);
    }
    else
        data->pbboxaddr = NULL;

    //load codemap info
    if(data->header.u32CodemapBlockNum && data->header.u32CodemapOffset)
    {
        len = data->header.u32CodemapBlockNum * sizeof(CHAR_CODEMAP_BLOCK);
        data->pcodemapaddr = D_MALLOC(len);
        //printf("data->pcodemapaddr = %p \n",data->pcodemapaddr);

        if(NULL == data->pcodemapaddr)
        {
            D_OOM();
            return false;
        }
        memcpy(data->pcodemapaddr, data->p_mmap_ptr + data->header.u32CodemapOffset, len);
        if(data->littleendian)
            _memswapendian16(data->pcodemapaddr, len);
    }
    else
        data->pcodemapaddr = NULL;

    //prepare glyph data
    data->pglyphaddr = D_MALLOC(data->header.u32CharGlyphBytes);
    //printf("data->pglyphaddr = %p \n",data->pglyphaddr);
    if(NULL == data->pglyphaddr)
    {
        D_OOM();
        return false;
    }

    data->linebytes= _MStar_BmpFont_GetLineBytes(&data->header);
    //printf("data->linebytes = %d \n",data->linebytes);

    //speed up table search
    if(data->header.u32Compression  == FONT_COMPRESSION_BOUND_RECTANGLE)
    {
        data->pstartline = D_MALLOC(data->header.u32CharNum * sizeof(u32));
        //printf("data->pstartline = %p \n",data->pstartline);
        if(NULL == data->pstartline)
        {
            D_OOM();
            return false;
        }
        FONT_GLYPH_BBOX * pbbox = (FONT_GLYPH_BBOX*)data->pbboxaddr;
        D_ASSERT(pbbox != NULL);
        data->pstartline[0] = 0;
        int i = 0;
        for(i = 1 ; i < data->header.u32CharNum ; i ++)
        {
            data->pstartline[i] = data->pstartline[i - 1] + pbbox[i - 1].u8Height;
        }
    }
    return NULL;

}


static bool _MStarBmp_GetBBoxByIndex(MStarBmpFImplData *data,int index, FONT_GLYPH_BBOX * pbbox)
{
    D_ASSERT(data != NULL);
    D_ASSERT(index < data->header.u32CharNum);
    if(index >= data->header.u32CharNum)
    {
        printf("warning! cannot find the index %d ! just return!\n", index);
        return false;
    }
    D_ASSERT(pbbox != NULL);

    *pbbox = ((FONT_GLYPH_BBOX*)(u32)data->pbboxaddr)[index];
    return true;
}

static void * _MStarBmp_GetGlyphByIndex(MStarBmpFImplData *data,int index)
{
    u8 *pglyphdata;
    FONT_GLYPH_BBOX bbox;

    //printf("data = %p,  data->pglyphaddr = %p, index = %d \n",data,data->pglyphaddr,index);
    D_ASSERT(data != NULL);
    D_ASSERT(data->pglyphaddr != NULL);

    pglyphdata = data->p_mmap_ptr + data->header.u32FontGlyphOffset;

    switch(data->header.u32Compression)
    {
        case FONT_COMPRESSION_NONE:
            memcpy(data->pglyphaddr,pglyphdata + index * data->header.u32CharGlyphBytes,data->header.u32CharGlyphBytes);
            break;
        case FONT_COMPRESSION_BOUND_RECTANGLE:
            memset(data->pglyphaddr,0,data->header.u32CharGlyphBytes);

            if(data->pbboxaddr == NULL)
            {
                printf("warning..... bitmap font error compress bbox \n");
                break;
            }
            if(data->pstartline == NULL)
            {
                printf("warning: bitmap font error compress startline\n");
                break;
            }

            if(false == _MStarBmp_GetBBoxByIndex(data,index,&bbox))
            {
                return NULL;
            }
            //printf("bbox.u8Height=%d,bbox.u8Width=%d \n",bbox.u8Height,bbox.u8Width);
            if(bbox.u8Height)
            {
                int offset = bbox.u8Y0 * data->linebytes;
                int len = bbox.u8Height * data->linebytes;
                memcpy(data->pglyphaddr + offset, pglyphdata + data->linebytes * data->pstartline[index], len);
            }

            break;
        default:
            D_ASSERT(0);
            break;
    }

    return data->pglyphaddr;
}


#define KERNING_DISTANCE    4
static DFBResult
MStarBmp_get_kerning_info( CoreFont     *thiz,
             unsigned int  prev_glyph_id,
             unsigned int  current_glyph_id,
             int          *kern_x,
             int          *kern_y)
{
     MStarBmpFImplData *data = thiz->impl_data;
     FONT_GLYPH_BBOX bbox_pre,bbox_curr;
     int pre_right,cur_left;

     if(NULL == _MStarBmp_GetBBoxByIndex(data,prev_glyph_id,&bbox_pre))
        return DFB_FAILURE;

     if(NULL == _MStarBmp_GetBBoxByIndex(data,current_glyph_id,&bbox_curr))
        return DFB_FAILURE;

     pre_right = data->header.u32Width - (data->header.u32Width - bbox_pre.u8Width)/2 - bbox_pre.u8Width;
     cur_left = (data->header.u32Width - bbox_curr.u8Width)/2 ;

     if(kern_x)
     {
        //if(pre_right + cur_left > KERNING_DISTANCE)
            *kern_x =  4;//KERNING_DISTANCE - (pre_right + cur_left);
     }
     if(kern_y)
        *kern_y = 0;

    //printf("pre_id=%d,cur_id=%d : pre_right =%d,cur_left=%d, *ker_x = %d ,y = %d\n",prev_glyph_id,current_glyph_id,pre_right,cur_left,*kern_x,*kern_y);

    return DFB_OK;
}


static DFBResult
MStarBmp_get_glyph_info( CoreFont      *thiz,
                unsigned int   glyph_index,
                CoreGlyphData *info )
{
     MStarBmpFImplData *data = thiz->impl_data;

     FONT_GLYPH_BBOX bbox;
     if(false == _MStarBmp_GetBBoxByIndex(data,glyph_index,&bbox))
        return DFB_FAILURE;

     info->width = bbox.u8Width + data->fixed_kerning_distance;//data->header.u32Width;//data->linebytes;
     if(info->width > data->header.u32Width)
        info->width = data->header.u32Width;
     info->height = data->header.u32Height;
     //info->advance = data->fixed_advance ? data->fixed_advance : (data->header.u32Width+ 1);
     info->advance = info->width + 1;

     return DFB_OK;
}

static DFBResult
MStarBmp_render_glyph( CoreFont      *thiz,
              unsigned int   glyph_index,
              CoreGlyphData *info )
{
     DFBResult   ret = DFB_OK;
     MStarBmpFImplData *data = thiz->impl_data;
     u8 *pixels = NULL;
     FONT_GLYPH_BBOX bbox;
     CoreSurface *surface = info->surface;
     CoreSurfaceBufferLock  lock;
     int y,start,end;

//printf("in MStarBmp_render_glyph, data = %p, pglyphaddr = %p , index=%d \n",data,data->pglyphaddr,glyph_index);

     if(false == _MStarBmp_GetBBoxByIndex(data,glyph_index,&bbox))
        return DFB_FAILURE;

     pixels = (u8 *)_MStarBmp_GetGlyphByIndex(data,glyph_index);
     if(NULL == pixels)
     {
        return DFB_FAILURE;
     }

     ret = dfb_surface_lock_buffer( surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
     if(ret)
     {
        D_DERROR( ret, "DirectFB/MStarBmp: Unable to lock surface!\n" );
        return ret;
     }

     info->width = bbox.u8Width + data->fixed_kerning_distance;//data->header.u32Width;//data->linebytes;
     if(info->width > data->header.u32Width)
        info->width = data->header.u32Width;

     if (info->width + info->start > surface->config.size.w)
          info->width = surface->config.size.w - info->start;

     info->height = data->header.u32Height;
     if (info->height > surface->config.size.h)
          info->height = surface->config.size.h;
/*
     info->advance = data->fixed_advance;//bbox.u8Width + 1;//data->fixed_advance ? data->fixed_advance : (info->width + 1);
     //if(info->advance < data->fixed_advance)
        //info->advance = data->fixed_advance;

     info->left = 0;//bbox.u8X0;
     info->top = 0;//thiz->ascender - bbox.u8Y0;

 */
    info->left = 0;
    info->top = 0;

    info->advance = info->width + 1;
    if(info->advance > data->header.u32Width)
        info->advance = data->header.u32Width + data->fixed_kerning_distance;

    start = bbox.u8X0;//(24 - bbox.u8Width) / 2 -6;
    if(start < 0)
        start = 0;
    end = start + info->width + 1;
    if(end > data->header.u32Width)
        end = data->header.u32Width - 1;

     //printf("1left=%d, advance = %d format=%x,info->start= %d bytes_per_line = %d , lock.pitch =%d\n",info->left,info->advance,surface->config.format,info->start,DFB_BYTES_PER_LINE(surface->config.format, info->start),lock.pitch);
     lock.addr += DFB_BYTES_PER_LINE(surface->config.format, info->start);
     for (y = 0; y < info->height; y++) {
        int    i, j, n;
        u8  *dst8  = lock.addr;
        u16 *dst16 = lock.addr;
        u32 *dst32 = lock.addr;

        switch (surface->config.format) {
             case DSPF_A8:
             {
                  int k = 0;
                  for(i = 0, j = 0 ; i < data->linebytes ; ++i)
                  {
                        int value = 0;
                        for(n = 7 ; n >= 0 ; n --)
                        {
                            value = 0;
                            if(pixels[i] >> n & 0x1)
                                value = 255;
                            if(k >= start && k <= end)
                                dst8[j ++] = value;
                            //printf("dest8[%d] = %x \n",j - 1,value);
                            k++;
                        }
                        //if(glyph_index == 77)
                            //printf("************************** pixelx = %x \n",pixels[i]);
                  }
               }
                  break;
             default:
                  D_UNIMPLEMENTED();
                  break;
        }

        pixels += data->linebytes;

        lock.addr += lock.pitch;
     }

     dfb_surface_unlock_buffer( surface, &lock );

     return DFB_OK;
}



static DFBResult
Probe( IDirectFBFont_ProbeContext *ctx )
{
     DFBResult   ret = DFB_OK;
     int         fd;
     FONT_BIN_HEADER header;

     /* default font is created with a NULL filename */
     if (!ctx->filename)
          return DFB_UNSUPPORTED;

     /* Open the file. */
     fd = open( ctx->filename, O_RDONLY );
     if (fd < 0) {
          ret = errno2result( errno );
          D_PERROR( "mstar_bmpfont: Failure during open() of '%s'!\n", ctx->filename );
          goto out;
     }

     /* Read the header. */
     if (read( fd, &header, sizeof(header) ) != sizeof(header)) {
          ret = errno2result( errno );
          D_PERROR( "mstar_bmpfont: Failure reading %zu bytes from '%s'!\n", sizeof(header), ctx->filename );
          goto out;
     }

     //printf("font magic  = %x , FONT_MAGIC = %x \n",header.magic,FONT_MAGIC);


     /* Check the magic. */
     if (header.magic != FONT_MAGIC)
     {
        _memswapendian32(&header,sizeof(header));
        if (header.magic != FONT_MAGIC)
            ret = DFB_UNSUPPORTED;
     }
out:
     if (fd >= 0)
          close( fd );

     return ret;
}

static DFBResult
Construct( IDirectFBFont      *thiz,
	   ... )
{
     DFBResult         ret;
     CoreFont         *font;
     CoreSurface      *surface;
     CoreFontCacheRow *row;
     void             *ptr;
     int               i;
     u8               pitch;
     int fd;
     struct stat stat;

     CoreDFB *core;
     char *filename;
     DFBFontDescription *desc;
     MStarBmpFImplData *data;

     va_list tag;
     va_start(tag, thiz);
     core = va_arg(tag, CoreDFB *);
     filename = va_arg(tag, char *);
     desc = va_arg(tag, DFBFontDescription *);
     va_end( tag );

     D_DEBUG( "DirectFB/FontDefault: Construct default font");

     fd = open( filename, O_RDONLY );
     if (fd < 0) {
          ret = errno2result( errno );
          D_PERROR( "Font/MVF: Failure during open() of '%s'!\n", filename );
          return DFB_FAILURE;
     }

     /* Query file size etc. */
     if (fstat( fd, &stat ) < 0) {
          ret = errno2result( errno );
          D_PERROR( "Font/MVF: Failure during fstat() of '%s'!\n", filename );
	   close(fd);
	   return DFB_FAILURE;
     }

     /* Memory map the file. */
     ptr = mmap( NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0 );
     if (ptr == MAP_FAILED) {
          ret = errno2result( errno );
          D_PERROR( "Font/MVF: Failure during mmap() of '%s'!\n", filename );
	   close(fd);
	   return DFB_FAILURE;
     }


     ret = dfb_font_create( core, &font );
     if (ret) {
          DIRECT_DEALLOCATE_INTERFACE( thiz );
          goto unmap_out;
     }

     font->ascender  = DEFAULT_FONT_ASCENDER;
     font->descender = DEFAULT_FONT_DESCENDER;

     font->GetGlyphData = MStarBmp_get_glyph_info;
     font->RenderGlyph  = MStarBmp_render_glyph;
     //font->GetKerning = MStarBmp_get_kerning_info;

     D_ASSERT(
               font->pixel_format == DSPF_A8 ||
               font->pixel_format == DSPF_A4 ||
               font->pixel_format == DSPF_A1 );

     data = D_CALLOC( 1, sizeof(MStarBmpFImplData) );
     if(NULL == data)
     {
        goto unmap_out;
     }
     memset(data,0,sizeof(MStarBmpFImplData) );

     data->fd = fd;
     data->p_mmap_ptr = ptr;
     data->filesize = stat.st_size;
     memcpy(&data->header,ptr,sizeof(FONT_BIN_HEADER));

     //printf("......................dump fond bin header .........................\n");
     //printf("magic=%x,u32BPP=%d,u32CharNum=%d,u32Width=%d,u32Height=%d,u32Pitch=%d,u32Compression=%d,u32BBoxOffset=%d,u32CodemapOffset=%d,u32CodemapBlockNum=%d,u32CharGlyphBytes=%d,u32FontGlyphOffset=%d,u32FontGlyphBytes=%d \n",
     //data->header.magic,data->header.u32BPP,data->header.u32CharNum,data->header.u32Width,data->header.u32Height,data->header.u32Pitch,data->header.u32Compression,
     //data->header.u32BBoxOffset,data->header.u32CodemapOffset,data->header.u32CodemapBlockNum,data->header.u32CharGlyphBytes,data->header.u32FontGlyphOffset,data->header.u32FontGlyphBytes);
     //printf("data = %p \n",data);

     if (data->header.magic != FONT_MAGIC)
     {
        _memswapendian32(&data->header,sizeof(data->header));
        if (data->header.magic != FONT_MAGIC)
            D_ASSERT(0);
        data->littleendian = true;
     }


     font->height    = data->header.u32Height;
     font->impl_data = data;
     //font->pixel_format = DSPF_A1;
     data->fixed_advance = 24;//data->linebytes;

     data->fixed_kerning_distance = 2;
     //printf("desc->flags = %x \n",desc->flags);
     if(desc->flags & DFDESC_KERNING_DISTANCE)
     {
        data->fixed_kerning_distance = desc->kerning_advance;
        printf("kerning advance is %d \n",data->fixed_kerning_distance);
     }

     _Load_MStarBmp_FontData(data);

     dfb_font_register_encoding( font, "UTF8",   &MStarBmpUTF8Funcs,   DTEID_UTF8 );
     dfb_font_register_encoding( font, "UCS2",   &MStarBmpUCS2Funcs,   DTEID_OTHER);

     IDirectFBFont_Construct( thiz, font );

     thiz->Release = IDirectFBFont_MStarBmp_Release;

     ret = DFB_OK;
     goto out;


unmap_out:
        ret = DFB_FAILURE;
        munmap(ptr, stat.st_size);
        close(fd);

out:
     return ret;
}
