/*
 *   ttflib.c
 *
 *   This file is part of the ttf2pk package.
 *
 *   Copyright 1997-1998 by
 *     Loyer Frederic <loyer@ensta.fr>
 *     Werner Lemberg <wl@gnu.org>
 */

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

#include "pklib.h"      /* for the `byte' type */
#include "freetype.h"
#include "ttfenc.h"
#include "ttflib.h"
#include "errormsg.h"
#include "newobj.h"
#include "ttf2tfm.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_Outline          outline;
TT_Glyph_Metrics    metrics;
TT_Face_Properties  properties;
TT_BBox             bbox;

TT_Raster_Map Bit, Bit2;
void          *Bitp, *Bit2p;

int dpi;
int ptsize;
int extend, slant;

int x_offset, y_offset;
int upem, ppem;

TT_Matrix matrix;
int       apply_matrix;



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


  temp1_x = bbox.xMin / 64;         /* scaling F16.6 -> int */
  temp1_y = bbox.yMin / 64;
  temp2_x = (bbox.xMax + 63) / 64;
  temp2_y = (bbox.yMax + 63) / 64;

  x_offset = 5 - temp1_x;
  y_offset = 5 - temp1_y;

  if (!quiet)
    printf("  off = (%d, %d)", x_offset, y_offset);

#if 0
  x_offset = y_offset = 0;
#endif


  if (!quiet)
    printf("  bbox = (%d, %d) <->  (%d, %d)\n",
           temp1_x, temp1_y, temp2_x, temp2_y);

  Bit.rows = temp2_y - temp1_y + 10;
  Bit.width = temp2_x - temp1_x + 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 */

  if (Bitp)
    free(Bitp);
  Bitp = mymalloc(Bit.size);
  Bit.bitmap = Bitp;

  Bit2 = Bit;

  if (Bit2p)
    free(Bit2p);
  Bit2p = mymalloc((int)Bit.size);
  Bit2.bitmap = Bit2p;
}


static void
SetMatrix(void)
{
  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(void)
{
  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,
        long fontindex, int platform, int encoding,
        Boolean quiet)
{
  unsigned short i, num_cmap;
  unsigned short cmap_plat;
  unsigned 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)
    oops("While initializing FreeType engine, error code = %d.", error);

  /*
   *   Load face.
   */

  error = TT_Open_Face(engine, filename, &face);
  if (error)
    oops("Cannot open `%s'.", filename);

  /*
   *   Get face properties and allocate preloaded arrays.
   */

  TT_Get_Face_Properties(face, &properties);

  /*
   *   Now we try to open the proper font in a collection.
   */

  if (fontindex != 0)
  {
    if(properties.num_Faces == 1)
      warning("This isn't a TrueType collection.\n"
              "Parameter `Fontindex' is ignored.");
    else
    {
      TT_Close_Face(face);
      if ((error = TT_Open_Collection(engine, filename, fontindex, &face)))
        oops("Cannot open font %lu in TrueType Collection `%s'.",
             fontindex, filename);
    }
  }

  /*
   *   Create instance.
   */
  
  error = TT_New_Instance(face, &instance);
  if (error)
    oops("Cannot create instance for `%s'.", filename);

  error = TT_Set_Instance_Resolutions(instance, dpi, dpi);
  if (error)
    oops("Cannot set device resolutions.");

  error = TT_Set_Instance_CharSize(instance, ptsize * 64);
  if (error)
    oops("Cannot reset instance, error code = %d.", error);

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

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

  /*
   *   Create glyph container.
   */

  error = TT_New_Glyph(face, &glyph);
  if (error)
    oops("Cannot create glyph container.");

  SetMatrix();

  num_cmap = properties.num_CharMaps;
  for (i = 0; i < num_cmap; i++)
  {
    error = TT_Get_CharMap_ID(face, i, &cmap_plat, &cmap_enc);
    if (error)
      oops("Cannot query cmap, error code = %d.", error);

    if (cmap_plat == platform && cmap_enc == encoding)
      break;
  }
  if (i == num_cmap)
    oops("Invalid platform and/or encoding ID.");
  
  error = TT_Get_CharMap(face, i, &char_map);
  if (error)
    oops("Cannot load cmap, error code = %d.", error);

  if (cmap_plat == Microsoft_platform &&
      cmap_enc == Microsoft_Unicode_encoding)
    set_encoding_scheme(encUnicode);
  else if (cmap_plat == Macintosh_platform &&
           cmap_enc == Macintosh_encoding)
    set_encoding_scheme(encMac);
  else
    set_encoding_scheme(encFontSpecific);
}


static TT_Error
LoadTrueTypeChar(int idx,
                 Boolean hint,
                 Boolean quiet)
{
  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);
    TT_Get_Outline_BBox(&outline, &bbox);
    SetRasterArea(quiet);
  }
  return error;
}


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


  if (Code >= 0x10000)
    Num = Code & 0xFFFF;
  else
    Num = TT_Char_Index(char_map, Code);
  if ((error = LoadTrueTypeChar(Num, hinting, quiet)) == 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 True;
  }
  else
    return False;
}


/*
 *   We collect first all glyphs addressed via the cmap.  Then we fill the
 *   array up with glyphs not in the cmap.
 */

void
TTFget_first_glyphs(long *array)
{
  int i, j, Num;
  int index_array[257];     /* we ignore glyph index 0 */


  for (i = 0; i < 257; i++)
    index_array[i] = 0;

  j = 0;
  for (i = 0; i <= 0xFFFF; i++)
  {
    Num = TT_Char_Index(char_map, i);
    if (Num < 0)
      oops("cmap mapping failure.");
    if (Num == 0)
      continue;
    if (Num <= 256)
      index_array[Num] = 1;
    if (strcmp(code_to_adobename(i), ".notdef") == 0)
      continue;
    if (j < 256)
      array[j] = i;
    else
      return;
    j++;
  }

  for (i = 1; i < properties.num_Glyphs; i++)
  {
    if (index_array[i] == 0)
    {
      if (j < 256)
        array[j] = i | 0x10000;
      else
        return;
      j++;
    }
  }
}


/*
 *   This routine fills `array' with the subfont character codes;
 *   additionally, it tests for valid glyph indices.
 */

void
TTFget_subfont(Font *fnt, long *array)
{
  int i, j, Num;


  for (i = 0; i <= 0xFF; i++)
  {
    j = fnt->sf_code[i];

    if (j < 0)
      array[i] = j;
    else
    {
      Num = TT_Char_Index(char_map, j);
      if (Num < 0)
        oops("cmap mapping failure.");
      else
        array[i] = j;
    }
  }
}


/* end */
