/* Copyright (C) 1996, 2000 artofcode LLC.  All rights reserved.
  
  This program 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; either version 2 of the License, or (at your
  option) any later version.

  This program 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 this program; if not, write to the Free Software Foundation, Inc.,
  59 Temple Place, Suite 330, Boston, MA, 02111-1307.

*/

/*$Id: gstype42.c,v 1.12.2.2.2.1 2003/01/17 00:49:03 giles Exp $ */
/* Type 42 (TrueType) font library routines */
#include "memory_.h"
#include "gx.h"
#include "gserrors.h"
#include "gsstruct.h"
#include "gsccode.h"
#include "gsline.h"		/* for gs_imager_setflat */
#include "gsmatrix.h"
#include "gsutil.h"
#include "gxchrout.h"
#include "gxfixed.h"		/* for gxpath.h */
#include "gxpath.h"
#include "gxfont.h"
#include "gxfont42.h"
#include "gxistate.h"

/* Structure descriptor */
public_st_gs_font_type42();

/* Forward references */
private int append_outline(P4(uint glyph_index, const gs_matrix_fixed * pmat,
			      gx_path * ppath, gs_font_type42 * pfont));
private int default_get_outline(P3(gs_font_type42 *pfont, uint glyph_index,
				   gs_const_string *pgstr));
private int default_get_metrics(P4(gs_font_type42 *pfont, uint glyph_index,
				   int wmode, float sbw[4]));

/* Set up a pointer to a substring of the font data. */
/* Free variables: pfont, string_proc. */
#define ACCESS(base, length, vptr)\
  BEGIN\
    code = (*string_proc)(pfont, (ulong)(base), length, &vptr);\
    if ( code < 0 ) return code;\
  END

/* Get 2- or 4-byte quantities from a table. */
#define U8(p) ((uint)((p)[0]))
#define S8(p) (int)((U8(p) ^ 0x80) - 0x80)
#define U16(p) (((uint)((p)[0]) << 8) + (p)[1])
#define S16(p) (int)((U16(p) ^ 0x8000) - 0x8000)
#define u32(p) get_u32_msb(p)

/* ---------------- Font level ---------------- */

/* Initialize the cached values in a Type 42 font. */
/* Note that this initializes get_outline and the font procedures as well. */
int
gs_type42_font_init(gs_font_type42 * pfont)
{
    int (*string_proc)(P4(gs_font_type42 *, ulong, uint, const byte **)) =
	pfont->data.string_proc;
    const byte *OffsetTable;
    uint numTables;
    const byte *TableDirectory;
    uint i;
    int code;
    byte head_box[8];
    ulong loca_size = 0;

    ACCESS(0, 12, OffsetTable);
    {
	static const byte version1_0[4] = {0, 1, 0, 0};
	static const byte version_true[4] = {'t', 'r', 'u', 'e'};

	if (memcmp(OffsetTable, version1_0, 4) &&
	    memcmp(OffsetTable, version_true, 4))
	    return_error(gs_error_invalidfont);
    }
    numTables = U16(OffsetTable + 4);
    ACCESS(12, numTables * 16, TableDirectory);
    /* Clear optional entries. */
    memset(pfont->data.metrics, 0, sizeof(pfont->data.metrics));
    for (i = 0; i < numTables; ++i) {
	const byte *tab = TableDirectory + i * 16;
	ulong offset = u32(tab + 8);

	if (!memcmp(tab, "glyf", 4))
	    pfont->data.glyf = offset;
	else if (!memcmp(tab, "head", 4)) {
	    const byte *head;

	    ACCESS(offset, 54, head);
	    pfont->data.unitsPerEm = U16(head + 18);
	    memcpy(head_box, head + 36, 8);
	    pfont->data.indexToLocFormat = U16(head + 50);
	} else if (!memcmp(tab, "hhea", 4)) {
	    const byte *hhea;

	    ACCESS(offset, 36, hhea);
	    pfont->data.metrics[0].numMetrics = U16(hhea + 34);
	} else if (!memcmp(tab, "hmtx", 4)) {
	    pfont->data.metrics[0].offset = offset;
	    pfont->data.metrics[0].length = (uint)u32(tab + 12);
	} else if (!memcmp(tab, "loca", 4)) {
	    pfont->data.loca = offset;
	    loca_size = u32(tab + 12);
	} else if (!memcmp(tab, "vhea", 4)) {
	    const byte *vhea;

	    ACCESS(offset, 36, vhea);
	    pfont->data.metrics[1].numMetrics = U16(vhea + 34);
	} else if (!memcmp(tab, "vmtx", 4)) {
	    pfont->data.metrics[1].offset = offset;
	    pfont->data.metrics[1].length = (uint)u32(tab + 12);
	}
    }
    loca_size >>= pfont->data.indexToLocFormat + 1;
    pfont->data.numGlyphs = (loca_size == 0 ? 0 : loca_size - 1);
    /*
     * If the font doesn't have a valid FontBBox, compute one from the
     * 'head' information.  Since the Adobe PostScript driver sometimes
     * outputs garbage FontBBox values, we use a "reasonableness" check
     * here.
     */
    if (pfont->FontBBox.p.x >= pfont->FontBBox.q.x ||
	pfont->FontBBox.p.y >= pfont->FontBBox.q.y ||
	pfont->FontBBox.p.x < -0.5 || pfont->FontBBox.p.x > 0.5 ||
	pfont->FontBBox.p.y < -0.5 || pfont->FontBBox.p.y > 0.5
	) {
	float upem = pfont->data.unitsPerEm;

	pfont->FontBBox.p.x = S16(head_box) / upem;
	pfont->FontBBox.p.y = S16(head_box + 2) / upem;
	pfont->FontBBox.q.x = S16(head_box + 4) / upem;
	pfont->FontBBox.q.y = S16(head_box + 6) / upem;
    }
    pfont->data.get_outline = default_get_outline;
    pfont->data.get_metrics = default_get_metrics;
    pfont->procs.glyph_outline = gs_type42_glyph_outline;
    pfont->procs.glyph_info = gs_type42_glyph_info;
    pfont->procs.enumerate_glyph = gs_type42_enumerate_glyph;
    return 0;
}

/* ---------------- Glyph level ---------------- */

/* Define the bits in the component glyph flags. */
#define cg_argsAreWords 1
#define cg_argsAreXYValues 2
#define cg_roundXYToGrid 4
#define cg_haveScale 8
#define cg_moreComponents 32
#define cg_haveXYScale 64
#define cg_have2x2 128
#define cg_useMyMetrics 512

/*
 * Parse the definition of one component of a composite glyph.  We don't
 * bother to parse the component index, since the caller can do this so
 * easily.
 */
private void
parse_component(const byte **pdata, uint *pflags, gs_matrix_fixed *psmat,
		int *pmp /*[2], may be null*/, const gs_font_type42 *pfont,
		const gs_matrix_fixed *pmat)
{
    const byte *gdata = *pdata;
    uint flags;
    double factor = 1.0 / pfont->data.unitsPerEm;
    gs_matrix_fixed mat;
    gs_matrix scale_mat;

    flags = U16(gdata);
    gdata += 4;
    mat = *pmat;
    if (flags & cg_argsAreXYValues) {
	int arg1, arg2;
	gs_fixed_point pt;

	if (flags & cg_argsAreWords)
	    arg1 = S16(gdata), arg2 = S16(gdata + 2), gdata += 4;
	else
	    arg1 = S8(gdata), arg2 = S8(gdata + 1), gdata += 2;
	if (flags & cg_roundXYToGrid) {
	    /* We should do something here, but we don't. */
	}
	gs_point_transform2fixed(pmat, arg1 * factor,
				 arg2 * factor, &pt);
	/****** HACK: WE KNOW ABOUT FIXED MATRICES ******/
	mat.tx = fixed2float(mat.tx_fixed = pt.x);
	mat.ty = fixed2float(mat.ty_fixed = pt.y);
	if (pmp)
	    pmp[0] = pmp[1] = -1;
    } else {
	if (flags & cg_argsAreWords) {
	    if (pmp)
		pmp[0] = U16(gdata), pmp[1] = S16(gdata + 2);
	    gdata += 4;
	} else {
	    if (pmp)
		pmp[0] = U8(gdata), pmp[1] = U8(gdata + 1);
	    gdata += 2;
	}
    }
#define S2_14(p) (S16(p) / 16384.0)
    if (flags & cg_haveScale) {
	scale_mat.xx = scale_mat.yy = S2_14(gdata);
	scale_mat.xy = scale_mat.yx = 0;
	gdata += 2;
    } else if (flags & cg_haveXYScale) {
	scale_mat.xx = S2_14(gdata);
	scale_mat.yy = S2_14(gdata + 2);
	scale_mat.xy = scale_mat.yx = 0;
	gdata += 4;
    } else if (flags & cg_have2x2) {
	scale_mat.xx = S2_14(gdata);
	scale_mat.xy = S2_14(gdata + 2);
	scale_mat.yx = S2_14(gdata + 4);
	scale_mat.yy = S2_14(gdata + 6);
	gdata += 8;
    } else
	goto no_scale;
#undef S2_14
    scale_mat.tx = 0;
    scale_mat.ty = 0;
    /* The scale doesn't affect mat.t{x,y}, so we don't */
    /* need to update the fixed components. */
    gs_matrix_multiply(&scale_mat, (const gs_matrix *)&mat,
		       (gs_matrix *)&mat);
no_scale:
    *pdata = gdata;
    *pflags = flags;
    *psmat = mat;
}

/* Compute the total number of points in a (possibly composite) glyph. */
private int
total_points(gs_font_type42 *pfont, uint glyph_index)
{
    gs_const_string glyph_string;
    int code;
    int ocode = pfont->data.get_outline(pfont, glyph_index, &glyph_string);
    const byte *gdata = glyph_string.data;
    int total;

    if (ocode < 0)
	return ocode;
    if (glyph_string.size == 0)
	return 0;
    if (S16(gdata) != -1) {
	/* This is a simple glyph. */
	int numContours = S16(gdata);
	const byte *pends = gdata + 10;
	const byte *pinstr = pends + numContours * 2;

	total = (numContours == 0 ? 0 : U16(pinstr - 2) + 1);
    } else {
	/* This is a composite glyph.  Add up the components. */
	uint flags;
	gs_matrix_fixed mat;

	gdata += 10;
	memset(&mat, 0, sizeof(mat)); /* arbitrary */
	total = 0;
	do {
	    code = total_points(pfont, U16(gdata + 2));
	    if (code < 0)
		return code;
	    total += code;
	    parse_component(&gdata, &flags, &mat, NULL, pfont, &mat);
	}
	while (flags & cg_moreComponents);
    }
    if (ocode > 0)
	gs_free_const_string(pfont->memory, gdata, glyph_string.size,
			     "total_points");
    return total;
}

/* Define the default implementation for getting the outline data for */
/* a glyph, using indexToLocFormat and the loca and glyf tables. */
/* Set pglyph->data = 0 if the glyph is empty. */
private int
default_get_outline(gs_font_type42 * pfont, uint glyph_index,
		    gs_const_string * pglyph)
{
    int (*string_proc) (P4(gs_font_type42 *, ulong, uint, const byte **)) =
    pfont->data.string_proc;
    const byte *ploca;
    ulong glyph_start;
    uint glyph_length;
    int code;

    /*
     * We can't assume that consecutive loca entries are stored
     * contiguously in memory: we have to access each entry
     * individually.
     */
    if (pfont->data.indexToLocFormat) {
	ACCESS(pfont->data.loca + glyph_index * 4, 4, ploca);
	glyph_start = u32(ploca);
	ACCESS(pfont->data.loca + glyph_index * 4 + 4, 4, ploca);
	glyph_length = u32(ploca) - glyph_start;
    } else {
	ACCESS(pfont->data.loca + glyph_index * 2, 2, ploca);
	glyph_start = (ulong) U16(ploca) << 1;
	ACCESS(pfont->data.loca + glyph_index * 2 + 2, 2, ploca);
	glyph_length = ((ulong) U16(ploca) << 1) - glyph_start;
    }
    pglyph->size = glyph_length;
    if (glyph_length == 0)
	pglyph->data = 0;
    else
	ACCESS(pfont->data.glyf + glyph_start, glyph_length, pglyph->data);
    return 0;
}

/* Parse a glyph into pieces, if any. */
private int
parse_pieces(gs_font_type42 *pfont, gs_glyph glyph, gs_glyph *pieces,
	     int *pnum_pieces)
{
    uint glyph_index = glyph - gs_min_cid_glyph;
    gs_const_string glyph_string;
    int code = pfont->data.get_outline(pfont, glyph_index, &glyph_string);

    if (code < 0)
	return code;
    if (glyph_string.size != 0 && S16(glyph_string.data) == -1) {
	/* This is a composite glyph. */
	int i = 0;
	uint flags = cg_moreComponents;
	const byte *gdata = glyph_string.data + 10;
	gs_matrix_fixed mat;

	memset(&mat, 0, sizeof(mat)); /* arbitrary */
	for (i = 0; flags & cg_moreComponents; ++i) {
	    if (pieces)
		pieces[i] = U16(gdata + 2) + gs_min_cid_glyph;
	    parse_component(&gdata, &flags, &mat, NULL, pfont, &mat);
	}
	*pnum_pieces = i;
    } else
	*pnum_pieces = 0;
    if (code > 0)
	gs_free_const_string(pfont->memory, glyph_string.data,
			     glyph_string.size, "parse_pieces");
    return 0;
}

/* Define the font procedures for a Type 42 font. */
int
gs_type42_glyph_outline(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
			gx_path *ppath)
{
    gs_font_type42 *const pfont = (gs_font_type42 *)font;
    uint glyph_index = glyph - gs_min_cid_glyph;
    gs_fixed_point origin;
    int code;
    gs_glyph_info_t info;
    gs_matrix_fixed fmat;
    static const gs_matrix imat = { identity_matrix_body };

    if (pmat == 0)
	pmat = &imat;
    if ((code = gs_matrix_fixed_from_matrix(&fmat, pmat)) < 0 ||
	(code = gx_path_current_point(ppath, &origin)) < 0 ||
	(code = append_outline(glyph_index, &fmat, ppath, pfont)) < 0 ||
	(code = font->procs.glyph_info(font, glyph, pmat,
				       GLYPH_INFO_WIDTH, &info)) < 0
	)
	return code;
    return gx_path_add_point(ppath, origin.x + float2fixed(info.width[0].x),
			     origin.y + float2fixed(info.width[0].y));
}
int
gs_type42_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
		     int members, gs_glyph_info_t *info)
{
    gs_font_type42 *const pfont = (gs_font_type42 *)font;
    uint glyph_index = glyph - gs_min_cid_glyph;
    int default_members =
	members & ~(GLYPH_INFO_WIDTHS | GLYPH_INFO_NUM_PIECES |
		    GLYPH_INFO_PIECES);
    gs_const_string outline;
    int code = 0;

    if (default_members) {
	code = gs_default_glyph_info(font, glyph, pmat, default_members, info);

	if (code < 0)
	    return code;
    } else if ((code = pfont->data.get_outline(pfont, glyph_index, &outline)) < 0)
	return code;		/* non-existent glyph */
    else {
	if (code > 0)
	    gs_free_const_string(pfont->memory, outline.data, outline.size,
				 "gs_type42_glyph_info");
	info->members = 0;
    }
    if (members & GLYPH_INFO_WIDTH) {
	int i;

	for (i = 0; i < 2; ++i)
	    if (members & (GLYPH_INFO_WIDTH0 << i)) {
		float sbw[4];

		code = gs_type42_wmode_metrics(pfont, glyph_index, i, sbw);
		if (code < 0)
		    return code;
		if (pmat)
		    code = gs_point_transform(sbw[2], sbw[3], pmat,
					      &info->width[i]);
		else
		    info->width[i].x = sbw[2], info->width[i].y = sbw[3];
	    }
	info->members |= members & GLYPH_INFO_WIDTH;
    }
    if (members & (GLYPH_INFO_NUM_PIECES | GLYPH_INFO_PIECES)) {
	gs_glyph *pieces =
	    (members & GLYPH_INFO_PIECES ? info->pieces : (gs_glyph *)0);
	int code = parse_pieces(pfont, glyph, pieces, &info->num_pieces);

	if (code < 0)
	    return code;
	info->members |= members & (GLYPH_INFO_NUM_PIECES | GLYPH_INFO_PIECES);
    }
    return code;
}
int
gs_type42_enumerate_glyph(gs_font *font, int *pindex,
			  gs_glyph_space_t glyph_space, gs_glyph *pglyph)
{
    gs_font_type42 *const pfont = (gs_font_type42 *)font;

    while (++*pindex <= pfont->data.numGlyphs) {
	gs_const_string outline;
	uint glyph_index = *pindex - 1;
	int code = pfont->data.get_outline(pfont, glyph_index, &outline);

	if (code < 0)
	    return code;
	if (outline.data == 0)
	    continue;		/* empty (undefined) glyph */
	*pglyph = glyph_index + gs_min_cid_glyph;
	if (code > 0)
	    gs_free_const_string(pfont->memory, outline.data, outline.size,
				 "gs_type42_enumerate_glyph");
	return 0;
    }
    /* We are done. */
    *pindex = 0;
    return 0;
}

/* Get the metrics of a simple glyph. */
private int
simple_glyph_metrics(gs_font_type42 * pfont, uint glyph_index, int wmode,
		     float sbw[4])
{
    int (*string_proc)(P4(gs_font_type42 *, ulong, uint, const byte **)) =
	pfont->data.string_proc;
    double factor = 1.0 / pfont->data.unitsPerEm;
    uint width;
    int lsb;
    int code;

    {
	const gs_type42_mtx_t *pmtx = &pfont->data.metrics[wmode];
	uint num_metrics = pmtx->numMetrics;
	const byte *pmetrics;

	if (glyph_index < num_metrics) {
	    ACCESS(pmtx->offset + glyph_index * 4, 4, pmetrics);
	    width = U16(pmetrics);
	    lsb = S16(pmetrics + 2);
	} else {
	    uint offset = pmtx->offset + num_metrics * 4;
	    uint glyph_offset = (glyph_index - num_metrics) * 2;
	    const byte *plsb;

	    ACCESS(offset - 4, 4, pmetrics);
	    width = U16(pmetrics);
	    if (glyph_offset >= pmtx->length)
		glyph_offset = pmtx->length - 2;
	    ACCESS(offset + glyph_offset, 2, plsb);
	    lsb = S16(plsb);
	}
    }
    if (wmode) {
	factor = -factor;	/* lsb and width go down the page */
	sbw[0] = 0, sbw[1] = lsb * factor;
	sbw[2] = 0, sbw[3] = width * factor;
    } else {
	sbw[0] = lsb * factor, sbw[1] = 0;
	sbw[2] = width * factor, sbw[3] = 0;
    }
    return 0;
}

/* Get the metrics of a glyph. */
private int
default_get_metrics(gs_font_type42 * pfont, uint glyph_index, int wmode,
		    float sbw[4])
{
    gs_const_string glyph_string;
    int code = pfont->data.get_outline(pfont, glyph_index, &glyph_string);
    int result;

    if (code < 0)
	return code;
    if (glyph_string.size != 0 && S16(glyph_string.data) == -1) {
	/* This is a composite glyph. */
	uint flags;
	const byte *gdata = glyph_string.data + 10;
	gs_matrix_fixed mat;

	memset(&mat, 0, sizeof(mat)); /* arbitrary */
	do {
	    uint comp_index = U16(gdata + 2);

	    parse_component(&gdata, &flags, &mat, NULL, pfont, &mat);
	    if (flags & cg_useMyMetrics) {
		result = gs_type42_wmode_metrics(pfont, comp_index, wmode, sbw);
		goto done;
	    }
	}
	while (flags & cg_moreComponents);
    }
    result = simple_glyph_metrics(pfont, glyph_index, wmode, sbw);
 done:
    if (code > 0)
	gs_free_const_string(pfont->memory, glyph_string.data,
			     glyph_string.size, "default_get_metrics");
    return result;
}
int
gs_type42_wmode_metrics(gs_font_type42 * pfont, uint glyph_index, int wmode,
			float sbw[4])
{
    return pfont->data.get_metrics(pfont, glyph_index, wmode, sbw);
}
int
gs_type42_get_metrics(gs_font_type42 * pfont, uint glyph_index,
		      float sbw[4])
{
    return gs_type42_wmode_metrics(pfont, glyph_index, pfont->WMode, sbw);
}

/* Define the bits in the glyph flags. */
#define gf_OnCurve 1
#define gf_xShort 2
#define gf_yShort 4
#define gf_Repeat 8
#define gf_xPos 16		/* xShort */
#define gf_xSame 16		/* !xShort */
#define gf_yPos 32		/* yShort */
#define gf_ySame 32		/* !yShort */

/* Append a TrueType outline to a path. */
/* Note that this does not append the final moveto for the width. */
int
gs_type42_append(uint glyph_index, gs_imager_state * pis,
		 gx_path * ppath, const gs_log2_scale_point * pscale,
		 bool charpath_flag, int paint_type, gs_font_type42 * pfont)
{
    int code = append_outline(glyph_index, &pis->ctm, ppath, pfont);

    if (code < 0)
	return code;
    /* Set the flatness for curve rendering. */
    return gs_imager_setflat(pis, gs_char_flatness(pis, 1.0));
}

/* Add 2nd degree Bezier to the path */
private int
add_quadratic_curve(gx_path * const ppath, const gs_fixed_point * const a,
     const gs_fixed_point * const b, const gs_fixed_point * const c)
{
    return gx_path_add_curve(ppath, (a->x + 2*b->x)/3, (a->y + 2*b->y)/3,
	(c->x + 2*b->x)/3, (c->y + 2*b->y)/3, c->x, c->y);
}


/*
 * Append a simple glyph outline to a path (ppath != 0) and/or return
 * its list of points (ppts != 0).
 */
private int
append_simple(const byte *gdata, float sbw[4], const gs_matrix_fixed *pmat,
	      gx_path *ppath, gs_fixed_point *ppts, gs_font_type42 * pfont)
{
    int numContours = S16(gdata);
    const byte *pends = gdata + 10;
    const byte *pinstr = pends + numContours * 2;
    const byte *pflags;
    uint npoints;
    const byte *pxc, *pyc;
    int code;

    if (numContours == 0)
	return 0;
    /*
     * It appears that the only way to find the X and Y coordinate
     * tables is to parse the flags.  If this is true, it is an
     * incredible piece of bad design.
     */
    {
	const byte *pf = pflags = pinstr + 2 + U16(pinstr);
	uint xbytes = npoints = U16(pinstr - 2) + 1;
	uint np = npoints;

	while (np > 0) {
	    byte flags = *pf++;
	    uint reps = (flags & gf_Repeat ? *pf++ + 1 : 1);

	    if (!(flags & gf_xShort)) {
		if (flags & gf_xSame)
		    xbytes -= reps;
		else
		    xbytes += reps;
	    }
	    np -= reps;
	}
	pxc = pf;
	pyc = pxc + xbytes;
    }

    /* Interpret the contours. */

    {
	uint i, np;
	gs_fixed_point pt;
	double factor = 1.0 / pfont->data.unitsPerEm;
	/*
	 * Decode the first flag byte outside the loop, to avoid a
	 * compiler warning about uninitialized variables.
	 */
	byte flags = *pflags++;
	uint reps = (flags & gf_Repeat ? *pflags++ + 1 : 1);

	/*
	 * The TrueType documentation gives no clue as to how the lsb
	 * should affect placement of the outline.  Our best guess is
	 * that the outline should be translated by lsb - xMin.
	 */
	gs_point_transform2fixed(pmat, sbw[0] - S16(gdata + 2) * factor,
				 0.0, &pt);
	for (i = 0, np = 0; i < numContours; ++i) {
	    bool move = true;
	    bool off_curve = false;
            bool is_start_off = false;
            uint last_point = U16(pends + i * 2);
	    float dx, dy;
	    gs_fixed_point start,pt_start_off;
	    gs_fixed_point cpoints[2];

            if_debug1('1', "[1t]start %d\n", i);
            
            for (; np <= last_point; --reps, ++np) {
		gs_fixed_point dpt;

		if (reps == 0) {
		    flags = *pflags++;
		    reps = (flags & gf_Repeat ? *pflags++ + 1 : 1);
		}
		if (flags & gf_xShort) {
		    /*
		     * A bug in the Watcom compiler prevents us from doing
		     * the following with the obvious conditional expression.
		     */
		    if (flags & gf_xPos)
			dx = *pxc++ * factor;
		    else
			dx = -(int)*pxc++ * factor;
		} else if (!(flags & gf_xSame))
		    dx = S16(pxc) * factor, pxc += 2;
		else
		    dx = 0;
		if (flags & gf_yShort) {
		    /* See above under dx. */
		    if (flags & gf_yPos)
			dy = *pyc++ * factor;
		    else
			dy = -(int)*pyc++ * factor;
		} else if (!(flags & gf_ySame))
		    dy = S16(pyc) * factor, pyc += 2;
		else
		    dy = 0;
		code = gs_distance_transform2fixed(pmat, dx, dy, &dpt);
		if (code < 0)
		    return code;
		pt.x += dpt.x, pt.y += dpt.y;
		
                if (ppts)	/* return the points */
		    ppts[np] = pt;
		
                if (ppath) {
                    /* append to a path */
		    if_debug3('1', "[1t]%s (%g %g)\n",
		    	(flags & gf_OnCurve ? "on " : "off"), fixed2float(pt.x), fixed2float(pt.y));
                    
                    if (move) {
                        if(is_start_off) {
                            if(flags & gf_OnCurve)
                                start = pt;
                            else { 
                                start.x = (pt_start_off.x + pt.x)/2;
			        start.y = (pt_start_off.y + pt.y)/2;
                                cpoints[1]=pt;
			        off_curve=true;
                            }
                            move = false;
                            cpoints[0] = start;
                            code = gx_path_add_point(ppath, start.x, start.y);
                        } else { 
                            if(flags & gf_OnCurve) { 
                                cpoints[0] = start = pt;
			        code = gx_path_add_point(ppath, pt.x, pt.y);
			        move = false;
                            } else { 
                                is_start_off = true;
                                pt_start_off = pt;
                            }
                        }
		    } else if (flags & gf_OnCurve) {
                        if (off_curve)
			    code = add_quadratic_curve(ppath, cpoints, cpoints+1, &pt);
			else
			    code = gx_path_add_line(ppath, pt.x, pt.y);
			cpoints[0] = pt;
			off_curve = false;
		    } else {
                        if(off_curve) {
			    gs_fixed_point p;
                            p.x = (cpoints[1].x + pt.x)/2;
			    p.y = (cpoints[1].y + pt.y)/2;
			    code = add_quadratic_curve(ppath, cpoints, cpoints+1, &p);
			    cpoints[0] = p;
			}
                        off_curve = true;
		        cpoints[1] = pt;
		    }
		    if (code < 0)
			return code;
		}
	    }
	    if (ppath) {
		if (is_start_off) { 
                    if (off_curve) { 
                        gs_fixed_point p;
                        p.x = (cpoints[1].x + pt_start_off.x)/2;
	                p.y = (cpoints[1].y + pt_start_off.y)/2;
                        code = add_quadratic_curve(ppath, cpoints, cpoints+1, &p);
		        if (code < 0)
		            return code;
                        code = add_quadratic_curve(ppath, &p, &pt_start_off, &start);
		        if (code < 0)
		            return code;
                    } else { 
                        code = add_quadratic_curve(ppath, cpoints, &pt_start_off, &start);
		        if (code < 0)
		            return code;
                    }
                } else { 
                    if (off_curve) { 
                        code = add_quadratic_curve(ppath, cpoints, cpoints+1, &start);
		        if (code < 0)
		            return code;
                    }
                }
                code = gx_path_close_subpath(ppath);
		if (code < 0)
		    return code;
	    }
	}
    }
    return 0;
}

/* Append a glyph outline. */
private int
check_component(uint glyph_index, const gs_matrix_fixed *pmat,
		gx_path *ppath, gs_font_type42 *pfont, gs_fixed_point *ppts,
		gs_const_string *pgstr, bool *pfree_data)
{
    gs_const_string glyph_string;
    const byte *gdata;
    float sbw[4];
    int numContours;
    int ocode, code;

    ocode = pfont->data.get_outline(pfont, glyph_index, &glyph_string);
    if (ocode < 0)
	return ocode;
    gdata = glyph_string.data;
    if (gdata == 0 || glyph_string.size == 0)	/* empty glyph */
	return 0;
    numContours = S16(gdata);
    if (numContours >= 0) {
        /* Only sbw[0] is used in append_simple. 
	   In order to set sbw[0], 0 is passed to 
	   simple_glyph_metrics as wmode. */
	simple_glyph_metrics(pfont, glyph_index, 0, sbw);
	code = append_simple(gdata, sbw, pmat, ppath, ppts, pfont);
	if (ocode > 0)
	    gs_free_const_string(pfont->memory, gdata, glyph_string.size,
				 "check_component");
	return (code < 0 ? code : 0); /* simple */
    }
    if (numContours != -1)
	return_error(gs_error_rangecheck);
    *pgstr = glyph_string;
    *pfree_data = ocode > 0;
    return 1;			/* composite */
}
private int
append_component(uint glyph_index, const gs_matrix_fixed * pmat,
		 gx_path * ppath, gs_fixed_point *ppts, int point_index,
		 gs_font_type42 * pfont)
{
    gs_const_string gstr;
    bool free_data;
    int code;

    code = check_component(glyph_index, pmat, ppath, pfont, ppts + point_index,
			   &gstr, &free_data);
    if (code != 1)
	return code;
    /*
     * This is a composite glyph.  Because of the "point matching" feature,
     * we have to do an extra pass over each component to fill in the
     * table of points.
     */
    {
	uint flags;
	const byte *gdata = gstr.data + 10;

	do {
	    uint comp_index = U16(gdata + 2);
	    gs_matrix_fixed mat;
	    int mp[2];

	    parse_component(&gdata, &flags, &mat, mp, pfont, pmat);
	    if (mp[0] >= 0) {
		/* Match up points.  What a nuisance! */
		const gs_fixed_point *const pfrom = ppts + mp[0];
		/*
		 * Contrary to the TrueType documentation, mp[1] is not
		 * relative to the start of the compound glyph, but is
		 * relative to the start of the component.
		 */
		const gs_fixed_point *const pto = ppts + point_index + mp[1];
		gs_fixed_point diff;

		code = append_component(comp_index, &mat, NULL, ppts,
					point_index, pfont);
		if (code < 0)
		    break;
		diff.x = pfrom->x - pto->x;
		diff.y = pfrom->y - pto->y;
		mat.tx = fixed2float(mat.tx_fixed += diff.x);
		mat.ty = fixed2float(mat.ty_fixed += diff.y);
	    }
	    code = append_component(comp_index, &mat, ppath, ppts,
				    point_index, pfont);
	    if (code < 0)
		break;
	    point_index += total_points(pfont, comp_index);
	}
	while (flags & cg_moreComponents);
    }
    if (free_data)
	gs_free_const_string(pfont->memory, gstr.data, gstr.size,
			     "append_component");
    return code;
}
private int
append_outline(uint glyph_index, const gs_matrix_fixed * pmat,
	       gx_path * ppath, gs_font_type42 * pfont)
{
    gs_const_string gstr;
    bool free_data;
    int code =
	check_component(glyph_index, pmat, ppath, pfont, NULL, &gstr,
			&free_data);

    if (code != 1)
	return code;
    {
	/*
	 * Set up the points array (only needed for point matching, sigh).
	 * We use stack allocation if possible, to avoid creating a sandbar
	 * (pts will be allocated before, but also freed before, any path
	 * elements).
	 */
#define MAX_STACK_PTS 150	/* usually enough */
	int num_points = total_points(pfont, glyph_index);

	if (num_points <= MAX_STACK_PTS) {
	    gs_fixed_point pts[MAX_STACK_PTS];

	    code = append_component(glyph_index, pmat, ppath, pts, 0, pfont);
	} else {
	    gs_memory_t *mem = pfont->memory; /* any memory will do */
	    gs_fixed_point *ppts = (gs_fixed_point *)
		gs_alloc_byte_array(mem, num_points, sizeof(gs_fixed_point),
				    "append_outline");

	    if (ppts == 0)
		code = gs_note_error(gs_error_VMerror);
	    else {
		code = append_component(glyph_index, pmat, ppath, ppts, 0,
					pfont);
		gs_free_object(mem, ppts, "append_outline");
	    }
	}
#undef MAX_STACK_PTS
    }
    if (free_data)
	gs_free_const_string(pfont->memory, gstr.data, gstr.size,
			     "append_outline");
    return code;
}
