/* FreeTypeFace.cpp
   Copyright (C) 2008, 2009 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

GNU Classpath 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
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

#include "FreeTypeFace.h"
#include FT_SFNT_NAMES_H

#undef __FTERRORS_H__
#define FT_ERRORDEF( e, v, s )  { e, s },
#define FT_ERROR_START_LIST     {
#define FT_ERROR_END_LIST       { 0, 0 } };
const struct{       
  int          err_code;
  const char*  err_msg;
} ft_errors[] = 
#include FT_ERRORS_H

static FT_Library g_library; 


FreeTypeFace::FreeTypeFace()  : buffer(NULL), bufferSize(0)
{
}

FT_Error FreeTypeFace::loadFrom(const char* filename)
{
  FT_Error error = FT_New_Face(g_library, filename, 0, &this->face );
  if (error)
  {
    this->face = NULL;
  }
  return error;
}

FT_Error FreeTypeFace::loadFrom(unsigned char* buff, int bufflen)
{
  this->buffer = buff;
  this->bufferSize = bufflen;
  FT_Error error = FT_New_Memory_Face(g_library, this->buffer, this->bufferSize, 0, &this->face);
  if (error)
  {
    this->face = NULL;
  }
  return error;
}

FreeTypeFace::~FreeTypeFace()
{
  FT_Done_Face(getFace());
  free((void*) this->buffer);
  this->buffer = NULL;
}

int FreeTypeFace::initialize()
{
  return FT_Init_FreeType( &g_library );
}

void FreeTypeFace::setSize(FT_F26Dot6 size)
{
  HDC hdc = GetDC(NULL);
  const FT_UInt hres = GetDeviceCaps(hdc, LOGPIXELSX);
  const FT_UInt vres = GetDeviceCaps(hdc, LOGPIXELSY);
  ReleaseDC(NULL, hdc);
  FT_Error error = FT_Set_Char_Size(
                            getFace(),
			     0,
			     size,
			     hres, /* horizontal device resolution */
			     vres); /* vertical device resolution */ 
}

FT_F26Dot6 FreeTypeFace::getWidth(FT_F26Dot6 size, const _TCHAR* text, int textLen)
{
  setSize(size);
  FT_GlyphSlot slot = face->glyph;
  FT_Long use_kerning = FT_HAS_KERNING(face);
  FT_UInt previous = 0;
  FT_F26Dot6 pen_x = 0;

  for (int i = 0; i < textLen; ++i)
  {
    int error;
    _TCHAR c = text[i];
    FT_UInt glyph_index = FT_Get_Char_Index(face, c);
    if (use_kerning && previous && glyph_index)
    {
      FT_Vector delta;
      error = FT_Get_Kerning( face, previous, glyph_index, ft_kerning_default, &delta );
      pen_x += delta.x;
    }
    error = FT_Load_Glyph(face, glyph_index, FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME );
    if (error)
    {
      continue;
    }

    // Load the bitmap image.
    pen_x += slot->advance.x;
    previous = glyph_index;
  }

  return pen_x;
}

const char* FreeTypeFace::getErrorMessage(int errorcode) 
{
  int size = sizeof(ft_errors) / sizeof(ft_errors[0]);
  for (int i = 0; i < size; ++i)
  {
    if (ft_errors[i].err_code == errorcode)
    {
      return ft_errors[i].err_msg;
    }
  }
  return "Unknown error";
}

