/*
   (c) Copyright 2001-2008  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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>

#include <directfb.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/mem.h>
#include <direct/memcpy.h>
#include <direct/messages.h>
#include <direct/utf8.h>
#include <direct/util.h>

#include <misc/conf.h>
#include <misc/util.h>

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

#include "mstar_mvf.h"


#ifndef FT_LOAD_TARGET_MONO
    /* FT_LOAD_TARGET_MONO was added in FreeType-2.1.3, we have to use (less good)
       FT_LOAD_MONOCHROME with older versions. Make it an alias for code simplicity. */
    #define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
#endif


static DFBResult
Probe( IDirectFBFont_ProbeContext *ctx );

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

#include <direct/interface_implementation.h>

DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBFont, MVF )
void AddFontMvfInterface()
{
}
static pthread_mutex_t mvf_library_mutex     = PTHREAD_MUTEX_INITIALIZER;


typedef struct {
     MVF_Face      face;
     //int          disable_charmap;
     int          fixed_advance;
     bool         fixed_clip;

     U16        font_size;
     U16        u8FontBPP;

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


static inline  int MVF_CHAR_INDEX(MVF_Face *pFace, int character)
{
   int ret_index;
   if(MVF_Query_Glyph_ID(pFace,  character, &ret_index) < 0)
   	ret_index = 0;
   return ret_index;
}

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

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

     D_MAGIC_ASSERT( thiz, CoreFont );


     pthread_mutex_lock ( &mvf_library_mutex );
     *ret_index = MVF_CHAR_INDEX(&data->face, character);
     pthread_mutex_unlock ( &mvf_library_mutex );


     return DFB_OK;
}

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

     D_MAGIC_ASSERT( thiz, CoreFont );
     D_ASSERT( text != NULL );
     D_ASSERT( length >= 0 );
     D_ASSERT( ret_indices != NULL );
     D_ASSERT( ret_num != NULL );

     pthread_mutex_lock ( &mvf_library_mutex );

     while (pos < length) {
          unsigned int c;

          if (bytes[pos] < 128)
               c = bytes[pos++];
          else {
               c = DIRECT_UTF8_GET_CHAR( &bytes[pos] );
               pos += DIRECT_UTF8_SKIP(bytes[pos]);
          }
          ret_indices[num++] = MVF_CHAR_INDEX(&data->face, c);
     }

     pthread_mutex_unlock ( &mvf_library_mutex );

     *ret_num = num;

     return DFB_OK;
}

static const CoreFontEncodingFuncs mvfUTF8Funcs = {
     GetCharacterIndex:  mvfUTF8GetCharacterIndex,
     DecodeText:         mvfUTF8DecodeText
};

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

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

     D_MAGIC_ASSERT( thiz, CoreFont );

     pthread_mutex_lock ( &mvf_library_mutex );
     *ret_index = MVF_CHAR_INDEX(&data->face, character);
      pthread_mutex_unlock ( &mvf_library_mutex );


     return DFB_OK;
}

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

     length >>= 1;

     D_MAGIC_ASSERT( thiz, CoreFont );
     D_ASSERT( text != NULL );
     D_ASSERT( length >= 0 );
     D_ASSERT( ret_indices != NULL );
     D_ASSERT( ret_num != NULL );
     pthread_mutex_lock ( &mvf_library_mutex );

     while (pos < length) {
          unsigned int c;

           c = (unsigned int)words[pos];

           ret_indices[pos++] = MVF_CHAR_INDEX(&data->face, c);
     }
    pthread_mutex_unlock ( &mvf_library_mutex );

     *ret_num = pos;

     return DFB_OK;
}

static const CoreFontEncodingFuncs mvfUCS2Funcs = {
     GetCharacterIndex:  mvfUCS2GetCharacterIndex,
     DecodeText:         mvfUCS2DecodeText
};

static DFBResult
MVF_render_glyph( CoreFont      *thiz,
              unsigned int   glyph_index,
              CoreGlyphData *info )
{
     MVF_Error     err;
     u8          *src;
     int          y;
     MVFImplData *data    = thiz->impl_data;
     CoreSurface *surface = info->surface;
     CoreSurfaceBufferLock  lock;

     MVF_Outline outline;
     MVF_Bitmap    font_bitmap;

     pthread_mutex_lock ( &mvf_library_mutex );


    // load_flags = (unsigned long) face->generic.data;
    // load_flags |= FT_LOAD_RENDER;
     if ((err = MVF_Load_Glyph_By_ID( &data->face, glyph_index, &outline))) {
          D_DEBUG( "DirectFB/FontMVF: Could not render glyph for character index #%d!\n", glyph_index );
          pthread_mutex_unlock ( &mvf_library_mutex );
          return DFB_FAILURE;
     }

     err = MVF_Render( &data->face, &outline,data->font_size, glyph_index,
                                 false, data->u8FontBPP, &font_bitmap);
     if (err) {
               D_ERROR( "DirectFB/FontMVF: Could not render glyph for character index #%d!\n", glyph_index );
               MVF_Done_Outline(&outline);
               pthread_mutex_unlock ( &mvf_library_mutex );

               return DFB_FAILURE;
     }

     err = dfb_surface_lock_buffer( surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
     if (err) {
          D_DERROR( err, "DirectFB/FontFT2: Unable to lock surface!\n" );
          MVF_Done_Outline(&outline);
          pthread_mutex_unlock ( &mvf_library_mutex );
          return err;
     }

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

     info->height = font_bitmap.rows;
     if (info->height > surface->config.size.h)
          info->height = surface->config.size.h;

     info->left = font_bitmap.x_shift;
     info->top  = thiz->ascender - font_bitmap.y_shift;

     if (data->fixed_clip) {
          while (info->left + info->width > data->fixed_advance)
               info->left--;

          if (info->left < 0)
               info->left = 0;

          if (info->width > data->fixed_advance)
               info->width = data->fixed_advance;
     }

     src = font_bitmap.buffer;
     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 (data->u8FontBPP) {
               case MVF_BITMAP_FORMAT_I8:
                    switch (surface->config.format) {
                         case DSPF_ARGB:
                              if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
                                   for (i=0; i<info->width; i++)
                                        dst32[i] = src[i] * 0x01010101;
                              }
                              else
                                   for (i=0; i<info->width; i++)
                                        dst32[i] = (src[i] << 24) | 0xFFFFFF;
                              break;
                         case DSPF_AiRGB:
                              for (i=0; i<info->width; i++)
                                   dst32[i] = ((src[i] ^ 0xFF) << 24) | 0xFFFFFF;
                              break;
                         case DSPF_ARGB4444:
                              if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
                                   for (i=0; i<info->width; i++)
                                        dst16[i] = (src[i] >> 4) * 0x1111;
                              }
                              else {
                                   for (i=0; i<info->width; i++)
                                        dst16[i] = (src[i] << 8) | 0xFFF;
                              }
                              break;
                         case DSPF_ARGB2554:
                              for (i=0; i<info->width; i++)
                                   dst16[i] = (src[i] << 8) | 0x3FFF;
                              break;
                         case DSPF_ARGB1555:
                              for (i=0; i<info->width; i++)
                                   dst16[i] = (src[i] << 8) | 0x7FFF;
                              break;
                         case DSPF_A8:
                              direct_memcpy( lock.addr, src, info->width );
                              break;
                         case DSPF_A4:
                              for (i=0, j=0; i<info->width; i+=2, j++)
                                   dst8[j] = (src[i] & 0xF0) | (src[i+1] >> 4);
                              break;
                         case DSPF_A1:
                              for (i=0, j=0; i < info->width; ++j) {
                                   register u8 p = 0;

                                   for (n=0; n<8 && i<info->width; ++i, ++n)
                                        p |= (src[i] & 0x80) >> n;

                                   dst8[j] = p;
                              }
                              break;
                         case DSPF_LUT2:
                              for (i=0, j=0; i < info->width; ++j) {
                                   register u8 p = 0;

                                   for (n=0; n<8 && i<info->width; ++i, n+=2)
                                        p |= (src[i] & 0xC0) >> n;

                                   dst8[j] = p;
                              }
                              break;
                         case DSPF_LUT4:
                              for (i=0, j=0; i<info->width; i+=2, j++)
                                   dst8[j] = (src[i] & 0xF0) | (src[i+1] >> 4);
                              break;
                         case DSPF_LUT1:
                              for (i=0, j=0; i < info->width; ++j) {
                                   register u8 p = 0;

                                   for (n=0; n<8 && i<info->width; ++i, ++n)
                                        p |= (src[i] & 0x80) >> n;

                                   dst8[j] = p;
                              }
                              break;
                         default:
                              D_UNIMPLEMENTED();
                              break;
                    }
                    break;

               case MVF_BITMAP_FORMAT_I1:
                    switch (surface->config.format) {
                         case DSPF_ARGB:
                              for (i=0; i<info->width; i++)
                                   dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
                                                0xFF : 0x00) << 24) | 0xFFFFFF;
                              break;
                         case DSPF_AiRGB:
                              for (i=0; i<info->width; i++)
                                   dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
                                                0x00 : 0xFF) << 24) | 0xFFFFFF;
                              break;
                         case DSPF_ARGB4444:
                              for (i=0; i<info->width; i++)
                                   dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
                                                0xF : 0x0) << 12) | 0xFFF;
                              break;
                         case DSPF_ARGB2554:
                              for (i=0; i<info->width; i++)
                                   dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
                                                0x3 : 0x0) << 14) | 0x3FFF;
                              break;
                         case DSPF_ARGB1555:
                              for (i=0; i<info->width; i++)
                                   dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
                                                0x1 : 0x0) << 15) | 0x7FFF;
                              break;
                         case DSPF_A8:
                              for (i=0; i<info->width; i++)
                                   dst8[i] = (src[i>>3] &
                                              (1<<(7-(i%8)))) ? 0xFF : 0x00;
                              break;
                         case DSPF_A4:
                              for (i=0, j=0; i<info->width; i+=2, j++)
                                   dst8[j] = ((src[i>>3] &
                                              (1<<(7-(i%8)))) ? 0xF0 : 0x00) |
                                             ((src[(i+1)>>3] &
                                              (1<<(7-((i+1)%8)))) ? 0x0F : 0x00);
                              break;
                         case DSPF_A1:
                              direct_memcpy( lock.addr, src, DFB_BYTES_PER_LINE(DSPF_A1, info->width) );
                              break;
                         default:
                              D_UNIMPLEMENTED();
                              break;
                    }
                    break;

               default:
                    break;

          }

          src += font_bitmap.pitch;

          lock.addr += lock.pitch;
     }

     MVF_Done_Outline(&outline);
     pthread_mutex_unlock ( &mvf_library_mutex );
     dfb_surface_unlock_buffer( surface, &lock );

     return DFB_OK;
}


static DFBResult
MVF_get_glyph_info( CoreFont      *thiz,
                unsigned int   glyph_index,
                CoreGlyphData *info )
{
     MVF_Error err;
     MVF_Outline outline;
     MVFImplData *data = (MVFImplData*) thiz->impl_data;
     MVF_Bitmap    font_bitmap;

     pthread_mutex_lock ( &mvf_library_mutex );


     if ((err = MVF_Load_Glyph_By_ID( &data->face, glyph_index, &outline ))) {
          D_DEBUG( "DirectFB/FontFT2: Could not load glyph for character index #%d!\n", glyph_index );

          pthread_mutex_unlock ( &mvf_library_mutex );

          return DFB_FAILURE;
     }

     err = MVF_Render( &data->face, &outline,data->font_size, glyph_index,
                                 true, data->u8FontBPP, &font_bitmap);
     if (err) {
               D_ERROR( "DirectFB/FontMVF: Could not render glyph for character index #%d!\n", glyph_index );

               pthread_mutex_unlock ( &mvf_library_mutex );
               MVF_Done_Outline(&outline);
               return DFB_FAILURE;
     }

     pthread_mutex_unlock ( &mvf_library_mutex );

     info->width   = font_bitmap.width;
     info->height  = font_bitmap.rows;
     info->advance = data->fixed_advance ?
                     data->fixed_advance : (font_bitmap.advance_x);

     if (data->fixed_clip && info->width > data->fixed_advance)
          info->width = data->fixed_advance;

     MVF_Done_Outline(&outline);
     return DFB_OK;
}


static DFBResult
MVF_get_kerning_info( CoreFont     *thiz,
             unsigned int  prev_glyph_id,
             unsigned int  current_glyph_id,
             int          *kern_x,
             int          *kern_y)
{
     MVF_Vector vector;
     MVFImplData *data = (MVFImplData*) thiz->impl_data;

     D_ASSUME( (kern_x != NULL) || (kern_y != NULL) );


     pthread_mutex_lock ( &mvf_library_mutex );

     /* Lookup kerning values for the character pair. */
     MVF_Get_Kerning( &data->face,
                     prev_glyph_id, current_glyph_id, data->font_size, &vector );

     pthread_mutex_unlock ( &mvf_library_mutex );

     /* Convert to integer. */
     if (kern_x)
          *kern_x = vector.x >> 6;

     if (kern_y)
          *kern_y = vector.y >> 6;

     return DFB_OK;
}


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

     if (data->font->impl_data) {
          MVFImplData *impl_data = (MVFImplData*) data->font->impl_data;

          pthread_mutex_lock ( &mvf_library_mutex );
          MVF_Done_Face(& impl_data->face );
          pthread_mutex_unlock ( &mvf_library_mutex );
	   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);
	   }
          D_FREE( impl_data );

          data->font->impl_data = NULL;
     }

     IDirectFBFont_Destruct( thiz );
}


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

     if (--data->ref == 0) {
          IDirectFBFont_MVF_Destruct( thiz );
     }

     return DFB_OK;
}

#define MVF_PEEK_USHORT(p) ((((U16)p[1])<<8)|p[0])

static DFBResult
Probe( IDirectFBFont_ProbeContext *ctx )
{
     U8 buf[4];

     struct stat stat;
     int fd;


     D_DEBUG( "DirectFB/FontMVF: Probe font `%s'.\n", ctx->filename );

     if (!ctx->filename)
          return DFB_UNSUPPORTED;
     fd = open( ctx->filename, O_RDONLY );
     if (fd < 0) {
          //D_PERROR( "Font/MVF Probe: Failure during open() of '%s'!\n", filename );
           return DFB_UNSUPPORTED;
     }

     /* Query file size etc. */
     if (fstat( fd, &stat ) < 0) {
          //D_PERROR( "Font/MVF Probe: Failure during fstat() of '%s'!\n", filename );
	   close(fd);
	   return DFB_UNSUPPORTED;
     }
     if(stat.st_size<= sizeof(U16)*2)
     	{
     	      close(fd);
	      return DFB_UNSUPPORTED;
     	}
	if(read(fd, buf, 4) < 4)
      {
             close(fd);
	      return DFB_UNSUPPORTED;
	}
	close(fd);

       if ( MVF_PEEK_USHORT(buf) != 0x0710 ) //magic number
               return DFB_UNSUPPORTED; //file format error



       if (MVF_PEEK_USHORT((buf+2)) != MVF_FILE_FORMAT_VERSION && //file format version
               MVF_PEEK_USHORT((buf+2)) != MVF_FILE_FORMAT_VERSION_7052) //backward compatible
        return DFB_UNSUPPORTED; //file format error

        return  DFB_OK;
}


static DFBResult
Construct( IDirectFBFont      *thiz,
	   ... )
{
     DFBResult              ret;
     CoreFont              *font;
     MVF_Face                face;
     MVF_Error               err;

     MVFImplData           *data;
     //bool                   disable_charmap = false;
     bool                   disable_kerning = false;
     bool                   load_mono = false;
     void *ptr;
     int fw,  fh;
     int fd;
     struct stat stat;

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

     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/FontMVF: "
              "Construct font from file `%s' (index %d) at pixel size %d x %d.\n",
              filename,
              (desc->flags & DFDESC_INDEX)  ? desc->index  : 0,
              (desc->flags & DFDESC_WIDTH)  ? desc->width  : 0,
              (desc->flags & DFDESC_HEIGHT) ? desc->height : 0 );


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

     pthread_mutex_lock ( &mvf_library_mutex );
     err = MVF_New_Face( (u8*)ptr, ((u8*)ptr)+stat.st_size, &face );
     pthread_mutex_unlock ( &mvf_library_mutex );
     if (err) {

         D_ERROR( "DirectFB/FontMVF: "
                              "Failed loading face %d from font file `%s'!\n",
                              (desc->flags & DFDESC_INDEX) ? desc->index : 0,
                              filename );

          DIRECT_DEALLOCATE_INTERFACE( thiz );
	   munmap(ptr, stat.st_size);
	   close(fd);
          return DFB_FAILURE;
     }

     if (dfb_config->font_format == DSPF_A1 || dfb_config->font_format == DSPF_ARGB1555)
          load_mono = true;

     if (desc->flags & DFDESC_ATTRIBUTES) {
        //  if (desc->attributes & DFFA_NOHINTING)
          //     load_flags |= FT_LOAD_NO_HINTING;
         // if (desc->attributes & DFFA_NOCHARMAP)
            //   disable_charmap = true;
          if (desc->attributes & DFFA_NOKERNING)
               disable_kerning = true;
          if (desc->attributes & DFFA_MONOCHROME)
               load_mono = true;
     }

     //if (load_mono)
      //    load_flags |= FT_LOAD_TARGET_MONO;


     if (desc->flags & (DFDESC_HEIGHT       | DFDESC_WIDTH |
                        DFDESC_FRACT_HEIGHT | DFDESC_FRACT_WIDTH))
     {
          fw=0,  fh=0;
          if (desc->flags & DFDESC_FRACT_HEIGHT)
               fh = desc->fract_height>>6;
          else if (desc->flags & DFDESC_HEIGHT)
               fh = desc->height;

          if (desc->flags & DFDESC_FRACT_WIDTH)
               fw = desc->fract_width>>6;
          else if (desc->flags & DFDESC_WIDTH)
               fw = desc->width;

     }
     else
     {
         //default value
          fw=17,  fh=17;
     }

     ret = dfb_font_create( core, &font );
     if (ret) {
          pthread_mutex_lock ( &mvf_library_mutex );
          MVF_Done_Face( &face );
          pthread_mutex_unlock ( &mvf_library_mutex );
          DIRECT_DEALLOCATE_INTERFACE( thiz );
          munmap(ptr, stat.st_size);
          close(fd);
          return ret;
     }

     D_ASSERT( font->pixel_format == DSPF_ARGB ||
               font->pixel_format == DSPF_AiRGB ||
               font->pixel_format == DSPF_ARGB4444 ||
               font->pixel_format == DSPF_ARGB2554 ||
               font->pixel_format == DSPF_ARGB1555 ||
               font->pixel_format == DSPF_A8 ||
               font->pixel_format == DSPF_A4 ||
               font->pixel_format == DSPF_A1 );


     font->GetGlyphData = MVF_get_glyph_info;
     font->RenderGlyph  = MVF_render_glyph;

     if (!disable_kerning) {
          font->GetKerning = MVF_get_kerning_info;
     	}

     data = D_CALLOC( 1, sizeof(MVFImplData) );
     if(data == NULL)
     {
              munmap(ptr, stat.st_size);
              close(fd);
		return DFB_FAILURE;
     }

     data->face            = face;
     //data->disable_charmap = disable_charmap;
     data->fd = fd;
     data->p_mmap_ptr = ptr;
     data->filesize = stat.st_size;
     data->font_size = ((fh> fw)?fh:fw);

     font->ascender   = MVF_BASE_EM_ROUND(face.ascender, data->font_size);
     font->descender  =  MVF_BASE_EM_ROUND(face.descender, data->font_size);
     font->height     = MVF_BASE_EM_ROUND(face.metrics_height, data->font_size);
     font->maxadvance = MVF_BASE_EM_ROUND(face.max_advance, data->font_size);

     D_DEBUG( "DirectFB/FontMVF: height = %d, ascender = %d, descender = %d, maxadvance = %d\n",
              font->height, font->ascender, font->descender, font->maxadvance );
     switch( font->pixel_format)
     {
          case DSPF_A8:
		 if(load_mono)
		 	data->u8FontBPP = MVF_BITMAP_FORMAT_I1;
		 else
		       data->u8FontBPP = MVF_BITMAP_FORMAT_I8;
		 break;
	//   case DSPF_A4:
	//   	 data->u8FontBPP = MVF_BITMAP_FORMAT_I2; break;
	//   case DSPF_A1:
	//   	 data->u8FontBPP = MVF_BITMAP_FORMAT_I1; break;
	   default:
               data->u8FontBPP = MVF_BITMAP_FORMAT_I1; break;
     }


     if (desc->flags & DFDESC_FIXEDADVANCE) {
          data->fixed_advance = desc->fixed_advance;
          font->maxadvance    = desc->fixed_advance;

          if ((desc->flags & DFDESC_ATTRIBUTES) && (desc->attributes & DFFA_FIXEDCLIP))
               data->fixed_clip = true;
     }
     font->impl_data = data;

     dfb_font_register_encoding( font, "UTF8",   &mvfUTF8Funcs,   DTEID_UTF8 );
     dfb_font_register_encoding( font, "UCS2",   &mvfUCS2Funcs,   DTEID_OTHER);

     IDirectFBFont_Construct( thiz, font );

     thiz->Release = IDirectFBFont_MVF_Release;

     return DFB_OK;
}
