/*
 * TrueType to Type1 conversion
 *
 * interface:
	[j]tt_type1_prologue?, tt_type1_epilogue
	PS_CharString
 * The functions in this file are derived from ttf2pfb.c (see below)
 * which comes with the FreeType1 package.
 */
/*
 *  ttf2pfb.c -- TrueType to PostScript Type 1 Font converter.
 *
 * Author: Chun-Yu Lee <d791013@ce.ntu.edu.tw>
 * Maintainer: Werner Lemberg <wl@gnu.org>
 *
 * The generated output is in a raw Type 1 Font format. An encoder
 * (e.g. t1asm or t1binary) is needed to convert it into PFA or PFB format.
 *
 * This program was adapted from the ntu2cjk package (which was part of the
 * LaTeX2e CJK package (by Werner Lemberg <wl@gnu.org>)).
 *
 *
 * Modified by Joachim H. Kaiser <jhk@cmpnetmail.com> to include real glyph
 * names and other font infos (see PS_Head function).
 * The test programs of the FreeType distribution have been heavily used as
 * templates.
 *
 */

#include	"conf.h"
#ifdef FREETYPE

#include	"defs.h"
#include	"emit.h"
#include	"global.h"
#include	"freetype.h"
#include	"cscommands.h"

/*
 *  Header of Type1 font.
 */
static char *version_str="001.001";
/*static char *UniqueId="9876";*/

tt_type1_prologue1(fontname, fontfam)
char *fontname, *fontfam;
{
    /*time_t now = time((time_t *)NULL);*/
    int i;

    EMIT(outfp, "%%%%BeginFont: %s\n", fontname);

    EMIT(outfp, "%%!PS-AdobeFont-1.0: %s %s\n", fontname, version_str);
    /*EMIT(outfp, "%%%%Creation Date: %s", ctime(&now));*/
    EMIT(outfp, "%%%%VMusage: 100000 100000\n");	/* dummy */
    EMIT(outfp, "11 dict begin\n");
    EMIT(outfp, "/FontInfo 8 dict dup begin\n");
    EMIT(outfp, "/version (%s) readonly def\n", version_str);
    EMIT(outfp, "/FullName (%s) readonly def\n", fontname);
    EMIT(outfp, "/FamilyName (%s) readonly def\n", fontfam);
    EMIT(outfp, "/Weight (Regular) readonly def\n");
    EMIT(outfp, "/ItalicAngle 0 def\n");
    /* TODO */
    EMIT(outfp, "/isFixedPitch false def\n");
    EMIT(outfp, "/UnderlinePosition 0 def\n");
    EMIT(outfp, "/UnderlineThickness 0 def\n");
    EMIT(outfp, "end readonly def\n");
    EMIT(outfp, "/FontName /%s def\n", fontname);
}

tt_type1_prologue2()
{
    EMIT(outfp, "/PaintType 0 def\n");
    EMIT(outfp, "/FontType 1 def\n");
    EMIT(outfp, "/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n");
    /* TODO? */
    EMIT(outfp, "/FontBBox [0 0 0 0] readonly def\n");
    /* should not have Uniqueid */
    /*EMIT(outfp, "/UniqueId %s def\n", UniqueId);*/
    EMIT(outfp, "currentdict end\n");
    EMIT(outfp, "currentfile eexec\n");

    begin_eexec();
    e_printf("dup /Private 9 dict dup begin\n");
    e_printf("/-|{string currentfile exch readstring pop}executeonly def\n");
    e_printf("/|-{noaccess def}executeonly def\n");
    e_printf("/|{noaccess put}executeonly def\n");
    e_printf("/BlueValues [] |-\n");
    /* TODO? */
    e_printf("/ForceBold true def\n");
    e_printf("/MinFeature{16 16} |-\n");
    e_printf("/password 5839 def\n");
    /* should not have Uniqueid */
    /*e_printf("/UniqueId %s def\n", UniqueId);*/
}

tt_type1_prologue3()
{
    e_printf("/Subrs 4 array\n");

    e_printf("dup 0 ");
    charstring_start();
    charstring_int(3); charstring_int(0);
    charstring_com(callothersubr);
    charstring_com(pop);
    charstring_com(pop);
    charstring_com(setcurrentpoint);
    charstring_com(csreturn);
    charstring_end();
    e_printf(" |\n");

    e_printf("dup 1 ");
    charstring_start();
    charstring_int(0); charstring_int(1);
    charstring_com(callothersubr);
    charstring_com(csreturn);
    charstring_end();
    e_printf(" |\n");

    e_printf("dup 2 ");
    charstring_start();
    charstring_int(0); charstring_int(2);
    charstring_com(callothersubr);
    charstring_com(csreturn);
    charstring_end();
    e_printf(" |\n");

    e_printf("dup 3 ");
    charstring_start();
    charstring_com(csreturn);
    charstring_end();
    e_printf(" |\n");

    e_printf("|-\n");
    e_printf("2 index /CharStrings 257 dict dup begin\n");
}

jtt_type1_prologue1(fontname, fontfam)
char *fontname, *fontfam;
{
    /*time_t now = time((time_t *)NULL);*/
    int i;

    EMIT(outfp, "%%%%BeginFont: %s\n", fontname);

    EMIT(outfp, "%%!PS-AdobeFont-1.0: %s %s\n", fontname, version_str);
    /*EMIT(outfp, "%%%%Creation Date: %s", ctime(&now));*/
    EMIT(outfp, "%%%%VMusage: 100000 100000\n");	/* dummy */
    EMIT(outfp, "11 dict begin\n");
    EMIT(outfp, "/FontInfo 8 dict dup begin\n");
    EMIT(outfp, "/version (%s) readonly def\n", version_str);
    EMIT(outfp, "/FullName (%s) readonly def\n", fontname);
    EMIT(outfp, "/FamilyName (%s) readonly def\n", fontfam);
    EMIT(outfp, "/Weight (Regular) readonly def\n");
    EMIT(outfp, "/ItalicAngle 0 def\n");
    EMIT(outfp, "/isFixedPitch true def\n");
    EMIT(outfp, "/UnderlinePosition 0 def\n");
    EMIT(outfp, "/UnderlineThickness 0 def\n");
    EMIT(outfp, "end readonly def\n");
    EMIT(outfp, "/FontName /%s def\n", fontname);
}

jtt_type1_prologue2()
{
    EMIT(outfp, "/PaintType 0 def\n");
    EMIT(outfp, "/FontType 1 def\n");
    EMIT(outfp, "/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n");
    /* TODO? */
    EMIT(outfp, "/FontBBox [0 -300 1000 1000] readonly def\n");
    /* should not have Uniqueid */
    /*EMIT(outfp, "/UniqueId %s def\n", UniqueId);*/
    EMIT(outfp, "currentdict end\n");
    EMIT(outfp, "currentfile eexec\n");

    begin_eexec();
    e_printf("dup /Private 11 dict dup begin\n");
    e_printf("/-|{string currentfile exch readstring pop}executeonly def\n");
    e_printf("/|-{noaccess def}executeonly def\n");
    e_printf("/|{noaccess put}executeonly def\n");
    e_printf("/BlueValues [] |-\n");
    /* TODO? */
    e_printf("/ForceBold true def\n");
    e_printf("/LanguageGroup 1 def\n");
    e_printf("/RndStemUp false def\n");
    e_printf("/MinFeature{16 16} |-\n");
    e_printf("/password 5839 def\n");
    /* should not have Uniqueid */
    /*e_printf("/UniqueId %s def\n", UniqueId);*/
}

/*
 * tail of Type1 font
 */
tt_type1_epilogue(a)
int a;
{
    e_printf("/.notdef ");
    charstring_start();
    charstring_int(0); charstring_int(a);
    charstring_com(hsbw);
    charstring_com(endchar);
    charstring_end();
    e_printf(" |-\n");
    e_printf("end end readonly put noaccess put\n");
    e_printf("dup /FontName get exch definefont pop\n");
    e_printf("mark currentfile closefile\n");
    end_eexec();

    EMIT(outfp, "cleartomark\n");

    EMIT(outfp, "%%%%EndFont\n");
}

#define TT_Flag_On_Curve 1

/* Postscript font related defines and functions */
FT_F26Dot6 lastpsx, lastpsy;

#define Coord(x) (int)(x)
#define PS_LastPt(x,y)  lastpsx = x; lastpsy = y
#define PS_Moveto(x,y)  \
        {charstring_int(Coord(x-lastpsx)); charstring_int(Coord(y-lastpsy)); \
        charstring_com(rmoveto); \
        PS_LastPt(x,y);}
#define PS_Lineto(x,y)  \
        {charstring_int(Coord(x-lastpsx)); charstring_int(Coord(y-lastpsy)); \
        charstring_com(rlineto); \
        PS_LastPt(x,y);}

/*
 *  use the rrcurveto command on more than one off points
 */
static void
PS_Curveto(outline, x, y, s, e)
FT_Outline *outline;
FT_F26Dot6 x, y;
int s, e;
{
  int  N, i;
  FT_F26Dot6 sx[3], sy[3], cx[4], cy[4];

  N = e-s+1;
  cx[0] = lastpsx; cy[0] = lastpsy;
  if (s == e) {
    cx[1] = (2*outline->points[s].x+outline->points[s-1].x)/3;
    cy[1] = (2*outline->points[s].y+outline->points[s-1].y)/3;
    cx[2] = (2*outline->points[s].x+x)/3;
    cy[2] = (2*outline->points[s].y+y)/3;
    cx[3] = x;
    cy[3] = y;
    charstring_int(Coord(cx[1]-cx[0])); charstring_int(Coord(cy[1]-cy[0]));
    charstring_int(Coord(cx[2]-cx[1])); charstring_int(Coord(cy[2]-cy[1]));
    charstring_int(Coord(cx[3]-cx[2])); charstring_int(Coord(cy[3]-cy[2]));
    charstring_com(rrcurveto);
  } else {
    for(i=0; i<N; i++) {
      sx[0] = (i==0) ? outline->points[s-1].x :
        (outline->points[i+s].x+outline->points[i+s-1].x)/2;
      sy[0] = (i==0) ? outline->points[s-1].y :
        (outline->points[i+s].y+outline->points[i+s-1].y)/2;
      sx[1] = outline->points[s+i].x;
      sy[1] = outline->points[s+i].y;
      sx[2] = (i==N-1) ? x : (outline->points[s+i].x+outline->points[s+i+1].x)/2;
      sy[2] = (i==N-1) ? y : (outline->points[s+i].y+outline->points[s+i+1].y)/2;
      cx[1] = (2*sx[1]+sx[0])/3;
      cy[1] = (2*sy[1]+sy[0])/3;
      cx[2] = (2*sx[1]+sx[2])/3;
      cy[2] = (2*sy[1]+sy[2])/3;
      cx[3] = sx[2];
      cy[3] = sy[2];
      charstring_int(Coord(cx[1]-cx[0])); charstring_int(Coord(cy[1]-cy[0]));
      charstring_int(Coord(cx[2]-cx[1])); charstring_int(Coord(cy[2]-cy[1]));
      charstring_int(Coord(cx[3]-cx[2])); charstring_int(Coord(cy[3]-cy[2]));
      charstring_com(rrcurveto);
      cx[0] = cx[3]; cy[0] = cy[3];
    }
  }
  PS_LastPt(x,y);
}

PS_CharString(outline, cn, a)
FT_Outline *outline;
char *cn;
int a;
{
    int i, j;
    unsigned short start_offpt, end_offpt = 0, fst;

    /* Begin string */
    e_printf("/%s ", cn);
    charstring_start();

    /*  coordinates are all relative to (0,0) in FreeType */
    charstring_int(0); charstring_int(a);
    charstring_com(hsbw);

    /* Initialize ending contour point, relative coordinates */
    lastpsx = lastpsy = 0;

    for (i = 0, j = 0; i < outline->n_contours /*contours*/; i++) {
	fst = j;
	PS_Moveto (outline->points[j].x, outline->points[j].y);
	j++;

	start_offpt = 0; /*start at least 1*/
	/* data pts for all contours stored in one array.
	   each round j init at last j + 1 */

	/* start_offpt means start of off points.
	   0 means no off points in record.
	   N means the position of the off point.
	   end_offpt means the ending off point.
	   lastx, lasty is the last ON point from which Curve and Line
	   shall start.
	   */

	/* start with j=0. into loop, j=1.
	   if pt[1] off, if start_offpt == 0, toggle start_offpt
	   next j=2. if on, now start_off != 0, run Curveto.
	   if pt[1] on, start_off == 0, will run Lineto.
	   */
	for (; j <= outline->contours[i]; j++) {
	    if (!(outline->tags[j] & TT_Flag_On_Curve)) {
		if (!start_offpt) { start_offpt = end_offpt = j; }
		else end_offpt++;
	    }
	    else {                    /*On Curve*/
		if (start_offpt) {
		    /* start_offpt stuck at j, end_offpt++.
		       end_offpt - start_offpt gives no of off pts.
		       start_offpt gives start of sequence.
		       why need outline->xCoord[j] outline->yCoord[j]?
		       */
		    PS_Curveto(outline, outline->points[j].x, outline->points[j].y,
			       start_offpt, end_offpt);
		    start_offpt = 0;

		    /* also use start_offpt as indicator to save one variable!!
		       after curveto, reset condition. */
		}
		else PS_Lineto(outline->points[j].x, outline->points[j].y);
	    }
	}
	/* looks like closepath fst = first, i.e. go back to first */
	if (start_offpt)
	    PS_Curveto(outline, outline->points[fst].x, outline->points[fst].y,
		       start_offpt, end_offpt);
	else
	    charstring_com(closepath);
    }

    charstring_com(endchar);

    charstring_end();
    e_printf(" |-\n");
}

#endif
