/*
 * ttflib.c
 *
 * This file is part of the ttf2pk package.
 *
 * Code <-> Postscript tables
 *
 *    Loyer Frederic <loyer@ensta.fr>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>       /* libc ANSI */
#include <ctype.h>


#include "freetype.h"
#include "tterror.h"  /* for Panic() and Message() only */
#include "enclib.h"

typedef unsigned int byte;

#include "ttflib.h"

#define Macintosh_platform 1
#define Macintosh_encoding 0
#define Microsoft_platform 3
#define Microsoft_Symbol_encoding 0
#define Microsoft_Unicode_encoding 1

TT_Engine   engine;
TT_Face     face;
TT_Instance instance;
TT_Glyph    glyph;
TT_CharMap  char_map;

TT_Glyph_Metrics    metrics;
TT_Outline          outline;
TT_Face_Properties  properties;
TT_Instance_Metrics imetrics;

TT_Raster_Map Bit, Bit2;

int dpi;
int ptsize;
int extend, slant;

int x_offset, y_offset;
int upem, ppem;

TT_Matrix matrix;
int       apply_matrix;

extern char quiet;


static int
transform(x, y)
  register int x, y;
{
  register double acc;

  acc = (extend / 1024.0) * x + slant * y;
  return (int)(acc >= 0 ? floor(acc+0.5) : ceil(acc-0.5));
}


static void  
SetRasterArea()
{
  int temp1_x, temp1_y, temp2_x, temp2_y;


  upem = properties.header->Units_Per_EM;
  ppem = (dpi * ptsize + 36) / 72;

  if (!quiet)
    printf("dpi = %d, ptsize = %d, ppem = %d\n", dpi, ptsize, ppem);

  temp1_x = properties.header->xMin;
  temp1_y = properties.header->yMin;

  x_offset = 5 - transform(temp1_x, temp1_y) * ppem / upem;
  y_offset = 5 - temp1_y * ppem / upem;

  if (!quiet)
    printf("x_offset = %d, yoffset = %d\n", x_offset, y_offset);

  /*
  x_offset = y_offset = 0;
  */

  temp1_y = properties.header->yMin;
  temp2_y = properties.header->yMax;
  temp1_x = properties.header->xMin;
  temp2_x = properties.header->xMax;

  if (!quiet)
    printf("%d <-> %d  x  %d <-> %d  /  %d\n\n",
           temp1_y,
           temp2_y,
           transform(temp1_x, temp1_y),
           transform(temp2_x, temp2_y),
           properties.header->Units_Per_EM);

  Bit.rows = (temp2_y - temp1_y) * ppem / upem + 10;
  Bit.width = (transform(temp2_x, temp2_y) - transform(temp1_x, temp1_y))
              * ppem / upem + 10;

  Bit.cols = ( Bit.width + 7 ) / 8;    /* convert to # of bytes */
  Bit.flow = TT_Flow_Up;
  Bit.size = Bit.rows * Bit.cols;      /* number of bytes in buffer */

  Bit.bitmap = (void *)malloc((int)Bit.size);
  if (!Bit.bitmap) 
    Panic("ERROR: Not enough memory to allocate bitmap!\n");
  Bit2 = Bit;
  Bit2.bitmap = (void *)malloc((int)Bit.size);
  if (!Bit2.bitmap)
    Panic("ERROR: Not enough memory to allocate bitmap!\n");
}


static void
SetMatrix()
{
  TT_Error error;


  error = TT_Set_Instance_Transform_Flags(instance, 1, 0);

  matrix.xx = (TT_Fixed)(extend * (1<<16)/1024);
  matrix.xy = (TT_Fixed)(slant * (1<<16)/1024);
  matrix.yx = (TT_Fixed)0;
  matrix.yy = (TT_Fixed)(1<<16);

  apply_matrix = 1;
}


static void
FlipBit()
{
  int y;
  char *p1, *p2;

  p1 = (char *)Bit.bitmap;
  p2 = (char *)Bit2.bitmap + Bit2.cols * (Bit2.rows - 1);

  for (y = 0; y < Bit.rows; y++)
  {
    memcpy(p2, p1, Bit.cols);
    p1 += Bit.cols;
    p2 -= Bit.cols;
  }
}


#if 0

static void
Output(TT_Raster_Map Bit)
{
  int x;
  int y;
  int i;

  char *p, b;


  p = Bit.bitmap;
  printf("====\n");

  for (y = 0; y < Bit.rows; y++)
  {
    printf("%3d:", y);
    for (x = 0; x < Bit.cols; x++)
    {
      b = *p++;
      for(i = 0x80; i; i >>= 1)
        printf((b & i) ? "x" : ".");
    }
    printf("\n");
  }
}

#endif /* 0 */


void
TTFopen(char *filename, int new_dpi, int new_ptsize, 
        int new_extend, int new_slant)
{
  int platform = Microsoft_platform;
  int encoding = Microsoft_Unicode_encoding;
  int i, num_cmap;
  short cmap_plat;
  short cmap_enc;
  TT_Error error;


  dpi = new_dpi;
  ptsize = new_ptsize;
  extend = new_extend;
  slant = new_slant;

  error = TT_Init_FreeType(&engine);
  if (error)
    Panic("ERROR: While initializing engine, error code = %d\n", error);

  /* Load face */

  error = TT_Open_Face(engine, filename, &face);
  if (error)
    Panic("ERROR: could not open %s\n", filename);

  /* create instance */
  
  error = TT_New_Instance(face, &instance);
  if (error)
    Panic("ERROR: could not create instance for %s\n", filename);

  error = TT_Set_Instance_Resolutions(instance, dpi, dpi);
  if (error)
    Panic("ERROR: could not set device resolutions");

  error = TT_Set_Instance_CharSize(instance, ptsize * 64);
  if (error)
    Panic("ERROR: could not reset instance, error code = %d\n", error);

  /* get face properties and allocate preloaded arrays */
  
  TT_Get_Face_Properties(face, &properties);

  /* create glyph */

  error = TT_New_Glyph(face, &glyph);
  if (error)
    Panic("ERROR: could not create glyph container\n");

  SetMatrix();
  SetRasterArea();

  num_cmap = TT_Get_CharMap_Count(face);
  for (i = 0; i < num_cmap; i++)
  {
    error = TT_Get_CharMap_ID(face, i, &cmap_plat, &cmap_enc);
    if (error)
      Panic("ERROR: cannot query cmap, error code = %d\n", error);

    if (cmap_plat == platform && cmap_enc == encoding)
    {
      set_encoding_scheme(encUnicode);
      break;
    }
  }

  if (i == num_cmap)
    Panic("ERROR: invalid platform and/or encoding ID\n");
  
  error = TT_Get_CharMap(face, i, &char_map);
  if (error)
    Panic("ERROR: cannot load cmap, error code = %d\n", error);
}


static TT_Error
LoadTrueTypeChar(int idx, int hint)
{
  TT_Error error;
  int flags;

  
  flags = TTLOAD_SCALE_GLYPH;
  if (hint)
    flags |= TTLOAD_HINT_GLYPH;
  
  error = TT_Load_Glyph(instance, glyph, idx, flags);
  if (!error && apply_matrix)
  {
    TT_Get_Glyph_Outline(glyph, &outline);
    TT_Transform_Outline(&outline, &matrix);
  }
  return error;
}


int
TTFprocess(int Code, byte **bitmap,
           int *width, int *height, int *hoff, int *voff)
{
  int Num;
  TT_Error error;


  Num = TT_Char_Index(char_map, Code);
  if ((error = LoadTrueTypeChar(Num, 1)) == TT_Err_Ok)
  {
    memset(Bit.bitmap, 0, Bit.size);
    TT_Get_Glyph_Bitmap(glyph, &Bit, x_offset * 64, y_offset * 64);

    FlipBit();      
    *bitmap = Bit2.bitmap;
    *width = Bit2.width;
    *height = Bit2.rows;
    *hoff = x_offset;
    *voff = y_offset;
    /* *voff = Bit2.rows - y_offset;    */
    /* printf("%D %d\n", *hoff, *voff); */
    /* Output(Bit2);                    */
    return 1;
  }
  else
    return 0;
}


/* end */
