/*
*                 TeX Device Driver DVIOUT, DVIPRT で
*                書体倶楽部のアウトラインフォントを使う
*
*                               vdata.c
*
*                       "Vector Font ReadData"
*
*    "本プログラムは、向内さんの書かれた dvii という dvi ドライバの
*    アウトラインフォント展開アルゴリズムと、ソースコードの大部分を
*    使用しています。
*
*
*                         1992  by T.Minagawa
*
*        12 Nov 1992 : modified for JGfont(3D-Bezier) by Naochan!
*        27 Nov 1992 : slightly modified by Yakumo
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>

#ifdef UNIX
#include <unistd.h>
#else
#include <io.h>
#ifdef MSVC
#include "msvcdir.h"
#else
#include <dir.h>
#endif
#endif

#ifdef	CC_JPN
#include <jctype.h>
#else

unsigned short jistojms(unsigned short);
int jisl1(unsigned short);
int jisl2(unsigned short);

#endif

#include "dd.h"
#include "err.h"
#include "vfont.h"
#include "vraster.h"
#ifdef BEZIERFONT
#include "jgfont.h"
#endif

/* グローバル変数 */
Line *linebuf = NULL;	/* draw_fine用のバッファ */
Line *linebuf_end;

int linecount;
int itemcount;

/* vfont.c */
extern int s_ratio[];
extern V_FONT *vfont[];

/* vraster.c */
void get_vindexbuf(int far*, int);

#ifdef BEZIERFONT
/* jgfont.c */
int get_twelve(VPARA_TBL *, GET_TEN_SW);
BEZ_LOCATE bez_emulate(VPARA_TBL *);
#endif

#ifdef TTFONT
/* ttfont.c */
int seek_to_tt_data(VPARA_TBL *);
int get_tt_glyph(VPARA_TBL *);
int get_tt_xy(LOCATE *);
#endif

static void slsort(_Setflag far *, int);
static int seek_to_vf_data(VPARA_TBL *);
static int get_ten(VPARA_TBL *, GET_TEN_SW);
static int get_ten_fep(VPARA_TBL *, GET_TEN_SW, LOCATE *);

#ifdef VFD
int get_ten_vfd();

#endif

#ifdef VFTOBM
static void size_adj(int *, int *, int, int);

#endif
void TateKanji_type(unsigned int code);
int readdata(VPARA_TBL *, DRAW_MODE);

static void arrange(int *, int *, int);
static void rotate(int *, int *, int);
static void setline(int, int, int, int, int, DRAW_MODE);
static long get_cross_point(Line *, int);
static void setopenclose(int, int);
static long search_hpair(int, int, int);
static long search_vpair(int, int, int);

/* buffer.c */
void *marea(unsigned int);

static int line_bufsize;	/* バッファサイズ記憶用変数 */
static int lcount_save;		/* バッファサイズ記憶用変数 */
static int icount_save;		/* バッファサイズ記憶用変数 */

static uchar *near_linebuf;
static int f_far_work;

static uchar *near_sl;
static _Setflag far *sl;
static int *oc;
short bufx[VF_BUF_SIZE];	/* データ先読みバッファ */

void free_vdata(void)
{
	Free0(near_sl);
	if (icount_save) Free(oc);
	Free0(near_linebuf);

	oc = NULL;
	near_linebuf = near_sl = NULL;
	linebuf = NULL;
	line_bufsize = lcount_save = icount_save = 0;
}


/*************************************************************
*	seek_to_vf_data
*	vfn_file のデータ位置までシークする
**************************************************************/
int seek_to_vf_data(VPARA_TBL *tbl_ptr)
{
#ifdef BEZIERFONT
	int preamblesize, max, v_code;

#endif
	long pointer;

	if (tbl_ptr->font_type == ZS_FONT) {
		lseek(tbl_ptr->vfn_file, tbl_ptr->v_code * 4 + 2, SEEK_SET);
		if (read(tbl_ptr->vfn_file, &pointer, sizeof(pointer))
			!= sizeof(pointer)) {
			error(WARNING, "[vfont] read pointer error.(%#x) %s",
					tbl_ptr->char_code, tbl_ptr->v_font_name);
			return (FAILURE);
		}
		if (pointer == 0xffffffffl)
			return (FAILURE);

		lseek(tbl_ptr->vfn_file, pointer + 2 + (MAX_CODE + 1) * 4, SEEK_SET);
	}
#ifdef BEZIERFONT
	else if (tbl_ptr->font_type == JG_FONT) {		/* JG_FONT */
		if (tbl_ptr->char_code < 0x3000)
			max = 1410;
		else if (tbl_ptr->char_code < 0x5000)
			max = 3008;
		else
			max = 3478;

		lseek(tbl_ptr->vfn_file, 8L, SEEK_SET);
		if (read(tbl_ptr->vfn_file, &preamblesize, 2)
			!= sizeof(preamblesize)) {
			error(WARNING, "[JGfont] preamble error.(%#x) %s",
					tbl_ptr->char_code, tbl_ptr->v_font_name);
			return (FAILURE);
		}
		lseek(tbl_ptr->vfn_file, 10L + preamblesize + tbl_ptr->v_code * 4,
			  SEEK_SET);
		if (read(tbl_ptr->vfn_file, &pointer, sizeof(pointer))
			!= sizeof(pointer)) {
			error(WARNING, "[JGfont] read pointer error.(%#x) %s",
					tbl_ptr->char_code, tbl_ptr->v_font_name);
			return (FAILURE);
		}
		if (pointer == 0xffffffffl)
			return (FAILURE);
		lseek(tbl_ptr->vfn_file,
			  10L + preamblesize + max * 4 + pointer, SEEK_SET);
	}
#endif
#ifdef TTFONT
	else if (tbl_ptr->font_type == TT_FONT) {		/* TT_FONT */
		return (seek_to_tt_data(tbl_ptr));
	}
	else if (tbl_ptr->font_type == CMTTF
#ifdef	USE_ETF
		|| tbl_ptr->font_type == ETF_FONT
#endif
		) {			/* 欧文 TT font */
		return (TRUE);			/* metrics を得るために既に seek 済み */
	}
#endif
	else {
		return (FAILURE);
	}
	return (TRUE);
}

/*************************************************************
*	get_ten
*	10bit の座標データを取得する
**************************************************************/
int get_ten(VPARA_TBL *tbl_ptr, GET_TEN_SW get_ten_sw)
{
	static int remaining_bits;
	static int remaining_words;
	static int remaining_words_save;
	static int buf_pos;
	static union {
		short s[2];
		long l;
	}
	d;
	static int buffering = 0;

	if (get_ten_sw == GET_DATA) {
		if (remaining_bits < 10) {
			d.s[1] = d.s[0];
			if (remaining_words == 0) {
				remaining_words
					= (read(tbl_ptr->vfn_file, bufx, VF_BUF_SIZE * 2)) / 2;
				remaining_words_save = remaining_words;
				buffering++;
				if (remaining_words == 0) {
					error(WARNING,
							"[vfont] 10 bits data error.(%#x) %s",
							tbl_ptr->char_code, tbl_ptr->v_font_name);
					return (-1);
				}
				buf_pos = 0;
			}
			d.s[0] = bufx[buf_pos++];
			remaining_words--;
			remaining_bits += 16;
		}
		remaining_bits -= 10;
		return ((int)((d.l >> remaining_bits) & MAX_VALUE));
	}
	else if (get_ten_sw == KEEP_BUF && buffering == 1) {
		remaining_words = remaining_words_save;
		buf_pos = 0;
		buffering = 0;
		return (-1);
	}
	else {
		remaining_bits = 0;
		remaining_words = 0;
		buffering = 0;
		return (-1);
	}
}

/*************************************************************
*	get_ten_fep
*	get_tenやget_twelveへの橋渡し処理
**************************************************************/
int get_ten_fep(VPARA_TBL *tbl_ptr, GET_TEN_SW get_ten_sw, LOCATE * locate)
{
	int tmp1, tmp2;

#ifdef BEZIERFONT
	BEZ_LOCATE bl;

	if (tbl_ptr->font_type == JG_FONT) {
		if (get_ten_sw == GET_DATA) {
			bl = bez_emulate(tbl_ptr);
			switch (bl.type) {
			  case BEZ_LINE:
				  locate->x = bl.x;
				  locate->y = bl.y;
				  return (TRUE);
			  case BEZ_STOP:
				  return (NOMORE);
			  default:
				  return (FAILURE);
			}
		}
		else {
			get_twelve(tbl_ptr, get_ten_sw);
			return (TRUE);
		}
	}
	else
#endif
#ifdef TTFONT
	if (tbl_ptr->font_type == TT_FONT ||
		tbl_ptr->font_type == CMTTF
#ifdef	USE_ETF
	  ||tbl_ptr->font_type == ETF_FONT
#endif
	) {
		if (get_ten_sw == GET_DATA) {
			tmp1 = get_tt_xy(locate);
			if (tmp1 == FALSE) {		/* composite glyph */
				if (get_tt_glyph(tbl_ptr) == FAILURE)
					return (FAILURE);
				return (NOMORE);
			}
			return (tmp1);
		} else if (get_ten_sw == CLEAR_BUF){
			return (get_tt_glyph(tbl_ptr));
		}
		return (FAILURE);
	}
	else
#endif
#ifdef VFD
	if (tbl_ptr->font_type == VFD_FONT) {
		if (get_ten_sw == GET_DATA) {
			tmp1 = get_ten_vfd();
			tmp2 = get_ten_vfd();
			if (tmp1 == MAX_VALUE) {
				return (NOMORE);
			}
			else {
				locate->x = tmp1;
				locate->y = tmp2;
				return (TRUE);
			}
		}
		else
			return (TRUE);
	}
	else
#endif
	if (tbl_ptr->font_type == ZS_FONT) {
		if (get_ten_sw == GET_DATA) {
			tmp1 = get_ten(tbl_ptr, GET_DATA);
			tmp2 = get_ten(tbl_ptr, GET_DATA);
			if (tmp1 == MAX_VALUE) {
				return (NOMORE);
			}
			else {
				locate->x = tmp1;
				locate->y = tmp2;
				return (TRUE);
			}
		}
		else {
			get_ten(tbl_ptr, get_ten_sw);
			return (TRUE);
		}
	}
	return (FAILURE);
}

#ifdef VFTOBM
/*************************************************************
*	size_adj
*	書体倶楽部のフォントの大きさを調整する
**************************************************************/
static void size_adj(int *xptr, int *yptr, int width_adj, int height_adj)
{
	int x, y;

	x = *xptr;
	y = *yptr;
	x = (int)((long)x * (MAX_VALUE + 1) * width_adj / 1000L);
	if (x > MAX_VALUE) {
		error(WARNING, "[vfont] expand error X. (%d)", x);
		x = MAX_VALUE;
	}
	y = (int)((long)y * (MAX_VALUE + 1) * height_adj / 1000L);
	if (y > MAX_VALUE) {
		error(WARNING, "[vfont] expand error Y. (%d)", y);
		y = MAX_VALUE;
	}
	*xptr = x;
	*yptr = y;
}

#endif /* end of ifdef VFTOBM */

/*************************************************************
*	arrange
*	フォントの変形を行なう
**************************************************************/
void arrange(int *xptr, int *yptr, int slant)
{
	int x, y, max_shift;

	x = *xptr;
	y = *yptr;

	max_shift = s_ratio[(slant - (int)'b') % 3];
	/* 斜体の処理 */
	if ((int)'b' <= slant && slant <= (int)'d') {
		x += (int)((long)(MAX_VALUE - y) * max_shift / (MAX_VALUE + 1));
	}
	else if ((int)'e' <= slant && slant <= (int)'g') {
		x += (int)((long)y * max_shift / (MAX_VALUE + 1));
	}
	else if ((int)'h' <= slant && slant <= (int)'j') {
		y += (int)(max_shift - (long)x * max_shift / (MAX_VALUE + 1));
	}
	else if ((int)'k' <= slant && slant <= (int)'m') {
		y += (int)(max_shift
				   - (long)(MAX_VALUE - x) * max_shift / (MAX_VALUE + 1));
	}
	*xptr = x;
	*yptr = y;
}

/*************************************************************
*	rotate
*	フォントを回転させる
**************************************************************/
static void rotate(int *xptr, int *yptr, int flag)
{
	int tmp;

	switch (flag) {
	  case 1:
		  tmp = *yptr;
		  *yptr = *xptr;
		  *xptr = MAX_VALUE - tmp;
		  break;
	  case 2:
		  *yptr = MAX_VALUE - *yptr;
		  *xptr = MAX_VALUE - *xptr;
		  break;
	  case 3:
		  tmp = *xptr;
		  *xptr = *yptr;
		  *yptr = MAX_VALUE - tmp;
		  break;
	}
}

#ifndef	NOTATEGAKI
/*************************************************************
*	疑似縦書き用のフォントを回転させる関数群
*   +-----> X
*   |
*   Y
***************************************************************/
static void TateKanji_Miteigi(int *xptr, int *yptr)
{
	error(DIRECT, 
#ifdef	JAPANESE
	"縦漢字未定義\n"
#else
	"Undefined Tate Kanji\n"
#endif
	);
}

static void (*TateKanji) (int *, int *) = TateKanji_Miteigi;

static void TateKanji_non(int *xptr, int *yptr)
{
};

static void TateKanji_n(int *xptr, int *yptr)
{
	int x;

	x = *xptr;
	*xptr = *yptr;
	*yptr = MAX_VALUE - x;
}

static void TateKanji_m(int *xptr, int *yptr)
{
	int x;

	x = *xptr;
	*xptr = *yptr - (MAX_VALUE * 11 / 20);
	*yptr = (MAX_VALUE - (MAX_VALUE * 12 / 20)) - x;
	if (*xptr < 0)
		*xptr = 0;				/* これが発生するようだったら*12/20を変更 */
	if (*yptr < 0)
		*yptr = 0;				/* すべきである */
}

static void TateKanji_mr(int *xptr, int *yptr)
{
	int x;

	x = *xptr;
	*xptr = *yptr;
	*yptr = (MAX_VALUE - (MAX_VALUE * 3 / 20)) - x;
	if (*yptr < 0)
		*yptr = 0;
}

static void TateKanji_r(int *xptr, int *yptr)
{

	*yptr = MAX_VALUE - *yptr;

}

extern int tategaki;

#ifdef VFD
extern BOOL tatevfd;

#endif

void TateKanji_type(unsigned int code)
{

#ifndef VFD
	if (!tategaki) {
#else
	if (!tategaki && !tatevfd) {
#endif
		TateKanji = TateKanji_non; 
		return;
	}

	if (code >= 0x8141 && code <= 0x8142)	/*、,。*/
		TateKanji = TateKanji_m;
	else if (code >= 0x815b && code <= 0x815d)	/*ー , ‐*/
		TateKanji = TateKanji_r;
	else if (code == 0x8160)	/*〜*/
		TateKanji = TateKanji_r;
	else if ((code >= 0x8169 && code <= 0x817a)	/*（,】*/
			 ||(code >= 0x8163 && code <= 0x8164))	/* …,‥ */
		TateKanji = TateKanji_non;
	else if (code >= 0x829f && code <= 0x82ec) {	/*かな小文字*/
		switch (code - (unsigned)0x829f) {
		  case (0x9f) - (0x9f):
		  case (0xa1) - (0x9f):
		  case (0xa3) - (0x9f):
		  case (0xa5) - (0x9f):
		  case (0xa7) - (0x9f):
		  case (0xc1) - (0x9f):
		  case (0xe1) - (0x9f):
		  case (0xe3) - (0x9f):
		  case (0xe5) - (0x9f):
		  case (0xec) - (0x9f):
			  TateKanji = TateKanji_mr;
			  break;
		  default:
			  TateKanji = TateKanji_n;
		}
	}
	else if (code >= 0x8340 && code <= 0x8396) {	/*カナ小文字*/
		switch (code - (unsigned)0x8340) {
		  case (0x40) - (0x40):
		  case (0x42) - (0x40):
		  case (0x44) - (0x40):
		  case (0x46) - (0x40):
		  case (0x48) - (0x40):
		  case (0x62) - (0x40):
		  case (0x83) - (0x40):
		  case (0x85) - (0x40):
		  case (0x87) - (0x40):
		  case (0x8e) - (0x40):
		  case (0x95) - (0x40):
		  case (0x96) - (0x40):
			  TateKanji = TateKanji_mr;
			  break;
		  default:
			  TateKanji = TateKanji_n;
		}
	}
	else
		TateKanji = TateKanji_n;
}

#endif

/*************************************************************
*	get_yofs
*	v_table をもとに垂直方向のオフセットを求める
**************************************************************/
int get_yofs(VPARA_TBL *tbl_ptr)
{
	int j;
	Line *c_line;

	linecount = itemcount = 0;
	linebuf_end = linebuf;

	if (readdata(tbl_ptr, FINE_MODE) == FAILURE)
		return (0);
	for (c_line = linebuf, j = -1; c_line < linebuf_end; c_line++) {
		if (c_line->yl > j) {
			j = c_line->yl;
		}
	}
	return (0x400 - j - Y_BASE);
}

/*************************************************************
*	readdata
*	アウトラインデ−タを読み取り、linebuf[]に格納する
**************************************************************/
int readdata(VPARA_TBL *tbl_ptr, DRAW_MODE sw)
{
	int x, y, x0, y0, xl, yl, r;
	LOCATE z;

	if (tbl_ptr->char_code == 0x2121)
		return (TRUE);
#ifdef TTFONT
	if (tbl_ptr->font_type != TT_FONT
#ifdef	USE_ETF
		&& tbl_ptr->font_type != ETF_FONT
#endif
	)
#endif
	if (tbl_ptr->v_code > MAX_CODE)
		return (FAILURE);
	/* Get pointer to character data. */
#ifndef VFD
	if (seek_to_vf_data(tbl_ptr) == FAILURE)
#else
	if (tbl_ptr->font_type != VFD_FONT && seek_to_vf_data(tbl_ptr) == FAILURE)
#endif
		return (FAILURE);
#ifdef	USE_ETF
	if((f_make_etf && tbl_ptr->font_type == CMTTF) ||
		(f_make_jttetf && tbl_ptr->font_type == TT_FONT))
		SetETFindex(NULL, 0, 0, 0, 0, 3);
#endif
	if (get_ten_fep(tbl_ptr, CLEAR_BUF, &z) == FAILURE)
		return (FAILURE);
	while ((r = get_ten_fep(tbl_ptr, GET_DATA, &z)) != NOMORE) {
		x = z.x;
		y = z.y;
		if (r == FAILURE)
			return (FAILURE);
#ifndef	NOTATEGAKI
		(*TateKanji) (&x, &y);
#endif
#ifdef VFTOBM
		if (tbl_ptr->club_flag == TRUE) {
			size_adj(&x, &y, tbl_ptr->width_adj, tbl_ptr->height_adj);
		}
#endif
		if (tbl_ptr->rotation != 0)
			rotate(&x, &y, tbl_ptr->rotation);
		if (tbl_ptr->slant != (int)'a')
			arrange(&x, &y, tbl_ptr->slant);
		x0 = xl = x;
		y0 = yl = y;
		while ((r = get_ten_fep(tbl_ptr, GET_DATA, &z)) != NOMORE) {
			x = z.x;
			y = z.y;
			if (r == FAILURE)
				return (FAILURE);
#ifndef	NOTATEGAKI
			(*TateKanji) (&x, &y);
#endif
#ifdef VFTOBM
			if (tbl_ptr->club_flag == TRUE) {
				size_adj(&x, &y, tbl_ptr->width_adj, tbl_ptr->height_adj);
			}
#endif
			if (tbl_ptr->rotation != 0)
				rotate(&x, &y, tbl_ptr->rotation);
			if (tbl_ptr->slant != (int)'a')
				arrange(&x, &y, tbl_ptr->slant);
			setline(xl, yl, x, y, itemcount, sw);	/* 線分を記録 */
			xl = x;
			yl = y;
		}						/* 折れ線を閉じる */
		setline(xl, yl, x0, y0, itemcount, sw);	/* 線分を記録 */
		itemcount++;
	}
	return (TRUE);
}

/*************************************************************
*	setline
*	linebuf[]にデ−タを実際に格納する
**************************************************************/
static void setline
	(int x1, int y1, int x2, int y2, int no, DRAW_MODE sw) {
	int i, dx, dy;
	int tmp;
	uchar *near_tmp;
	Line *tmp_line;
	Line *c_line;

	/* Line 用のバッファエリアとして、Line * MIN_LINE ずつ確保していく */
	if (linebuf == NULL) {
		line_bufsize = INIT_LINE;
		near_linebuf = (uchar *)marea(sizeof(Line) * line_bufsize);
		linebuf = (Line *)near_linebuf;
	}
	if (linecount == line_bufsize) {
		/* データがバッファをオーバーフローしたら領域を追加確保 */
		line_bufsize += MIN_LINE;
		near_tmp = near_linebuf;
		tmp_line = linebuf;
		if (f_far_work == 1){
			error(WARNING, "Working buffer overflow for vfont");
			f_far_work = -1;
		}
		near_linebuf = (uchar *)marea(sizeof(Line) * line_bufsize);
		linebuf = (Line *)near_linebuf;
		for (i = 0; i < line_bufsize - MIN_LINE; i++) {
			linebuf[i] = tmp_line[i];
			/* このコピーのオーバーヘッドは大きそう ^^;; */
		}
		Free0(near_tmp);
	}
	c_line = linebuf + linecount;

	c_line->flag = 0;
	c_line->itemno = no;

	if (sw == FINE_MODE) {
		dx = x2 - x1;
		dy = y2 - y1;

		if (dx < 0) {
			dx = -dx;
			c_line->flag |= XREV;
			c_line->flag ^= XYREV;
			tmp = x1;
			x1 = x2;
			x2 = tmp;
		}
		if (dy < 0) {
			dy = -dy;
			c_line->flag |= YREV;
			c_line->flag ^= XYREV;
			tmp = y1;
			y1 = y2;
			y2 = tmp;
		}
		c_line->xl = x1;
		c_line->xr = x2;
		c_line->yu = y1;
		c_line->yl = y2;
		c_line->dx = dx;
		c_line->dy = dy;
	}
	else {
		c_line->xl = x1;
		c_line->yu = y1;
	}
	linecount++;
	linebuf_end = c_line + 1;
}

/*************************************************************
*	slsort
*	sl をソートするための関数（中身は挿入法）
**************************************************************/
static void slsort(_Setflag far *sl, int n)
{
	int i, j, x;
	long y1, y2;
	_Setflag sltmp;

	for (i = 1; i < n; i++) {
		sltmp = sl[i];
		for (j = i - 1; j >= 0; j--) {
			if (sl[j].v < sltmp.v)
				break;
			else if (sl[j].v == sltmp.v) {
				x = max((sl[j].lp)->xl, (sltmp.lp)->xl);
				y1 = get_cross_point(sl[j].lp, x);
				y2 = get_cross_point(sltmp.lp, x);
				if (y1 < y2)
					break;
			}
			sl[j + 1] = sl[j];
		}
		sl[j + 1] = sltmp;
	}
}

/*************************************************************
*	get_cross_point
*	与えられた x座標に対応する y座標をTIMES倍して返す
**************************************************************/
long get_cross_point(Line *lbuf, int x)
{
	if (lbuf->dy == 0)
		return ((long)(lbuf->yu * TIMES));
	else if (lbuf->flag & XYREV)
		return (((long)(lbuf->xr - x) * lbuf->dy * TIMES) / lbuf->dx
				+ (long)lbuf->yu * TIMES);
	else
		return (((long)(x - lbuf->xl) * lbuf->dy * TIMES) / lbuf->dx
				+ (long)lbuf->yu * TIMES);
}

/*************************************************************
*	setopenclose
*	setflag から呼ばれて、実際に OPEN, CLOSE を linebufに
*	設定する
**************************************************************/
static void setopenclose(int itemno, int isanticlock)
{
	int dx, dy, flag;
	Line *c_line;

	for (c_line = linebuf; c_line < linebuf_end; c_line++) {
		if (c_line->itemno == itemno) {
			dx = c_line->dx;
			dy = c_line->dy;
			flag = c_line->flag;
			if (dx == 0) {
				c_line->flag |= VERTLINE;
			}
			else if (flag & XREV) {
				c_line->flag |= (isanticlock) ? VOPEN : VCLOSE;
			}
			else {
				c_line->flag |= (isanticlock) ? VCLOSE : VOPEN;
			}

			if (dy == 0) {
				c_line->flag |= HORILINE;
			}
			else if (flag & YREV) {
				c_line->flag |= (isanticlock) ? HCLOSE : HOPEN;
			}
			else {
				c_line->flag |= (isanticlock) ? HOPEN : HCLOSE;
			}
		}
	}
}

/*********************************************************
*	setflag
*	(1)OPEN, CLOSE のフラグを linebuf[] にセットする
*	(2)itemno を閉曲線の番号から部品の番号に付け換える
**********************************************************/
void setflag(VPARA_TBL *tbl_ptr, int itemflag)
{
	int i, j, v, it1, it2, c1item, c2item;
	int slcount;
	Line *c_line;
	Line *c1_line;
	Line *c2_line;

	if (linecount > lcount_save) {
		if (near_sl){
			Free(near_sl);
			near_sl = NULL;
		}
		near_sl = (uchar *)marea((sizeof(_Setflag)) * linecount);
		sl = (_Setflag far *)near_sl;
		lcount_save = linecount;
	}
	if (itemcount > icount_save) {
		if (icount_save)
			Free(oc);
		oc = (int *)marea(sizeof(int) * itemcount);
		icount_save = itemcount;
	}

	for (i = 0; i < itemcount; i++)
		oc[i] = FALSE;

	for (i = 0; i < linecount; i++) {
		if (linebuf[i].flag & FMASK) {
			continue;
		}
		v = CENTER(linebuf[i].xl, linebuf[i].xr);

		slcount = 0;
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			if (c_line->xl < v && v <= c_line->xr) {
				sl[slcount].v = get_cross_point(c_line, v);
				sl[slcount++].lp = c_line;
			}
		}
		if (slcount > 0) {
			slsort(sl, slcount);

			if (slcount % 2) {
				error(DIRECT, "[vfont] data error. (%#x) %s\n",
						tbl_ptr->char_code, tbl_ptr->v_font_name);
				slcount &= ~1;
			}
			for (j = 0; j < slcount; j += 2) {
				c1item = (c1_line = sl[j].lp) ->itemno;
				if (!oc[c1item]) {
					oc[c1item] = TRUE;

					/*					if (c1_line->dx == 0)
						it1 = (!(c1_line->flag&YREV)) ? TRUE : FALSE;
					else
					*/
					it1 = (c1_line->flag & XREV) ? TRUE : FALSE;
					setopenclose(c1item, it1);
				}

				c2item = (c2_line = sl[j+1].lp)->itemno;
				if (!oc[c2item]) {
					oc[c2item] = TRUE;

					/*					if (c2_line->dx == 0 )
						it1 = (c2_line->flag&YREV)? TRUE : FALSE;
					else
					*/
					it1 = (!(c2_line->flag & XREV)) ? TRUE : FALSE;
					setopenclose(c2item, it1);
				}

				if (c1item != c2item) {
					if (c1item < c2item) {
						it1 = c1item;
						it2 = c2item;
					}
					else {
						it1 = c2item;
						it2 = c1item;
					}
					for (c_line = linebuf; c_line < linebuf_end; c_line++) {
						if (c_line->itemno == it2) {
							c_line->itemno = it1;
						}
					}
				}
			}
		}
	}

	if (itemflag) {
		for (i = 0; i < itemcount; i++) {
			oc[i] = FALSE;
		}
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			oc[c_line->itemno] = TRUE;
		}
		for (i = it1 = 0; i < itemcount; i++) {
			if (oc[i]) {
				oc[i] = it1++;
			}
		}
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			c_line->itemno = oc[c_line->itemno];
		}
		itemcount = it1;
	}
	else {
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			c_line->itemno = 0;
		}
		itemcount = 1;
	}
}

/*************************************************************
*	search_hpair
*	与えられた (x,y) の座標を通る線分とペアの線分を求めて、
*	2本の線分の距離を返す。
**************************************************************/
static long search_hpair(int x, int y, int flag)
{
	int itmp = 0, ftmp = 0;
	int dx, dy;
	long vy, vy0, ltmp, distance;
	Line *c_line;

	distance = NOHV;
	vy0 = y * TIMES;
	if (flag & VOPEN) {
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			if (c_line->xl < x && x <= c_line->xr) {
				if (c_line->flag & VCLOSE) {
					dx = c_line->dx;
					dy = c_line->dy;
					if (c_line->flag & XYREV) {
						vy = ((long)(c_line->xr - x) * dy * TIMES) / dx
							+ (long)c_line->yu * TIMES;
					}
					else {
						vy = ((long)(x - c_line->xl) * dy * TIMES) / dx
							+ (long)c_line->yu * TIMES;
					}
					if (vy > vy0) {
						ltmp = vy - vy0;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = c_line->flag;
							itmp = dx;
						}
					}
				}
			}
		}
	}
	else {
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			if (c_line->xl < x && x <= c_line->xr) {
				if (c_line->flag & VOPEN) {
					dx = c_line->dx;
					dy = c_line->dy;
					if (c_line->flag & XYREV) {
						vy = ((long)(c_line->xr - x) * dy * TIMES) / dx
							+ (long)c_line->yu * TIMES;
					}
					else {
						vy = ((long)(x - c_line->xl) * dy * TIMES) / dx
							+ (long)c_line->yu * TIMES;
					}
					if (vy < vy0) {
						ltmp = vy0 - vy;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = c_line->flag;
							itmp = dx;
						}
					}
				}
			}
		}
	}
	return ((ftmp & HORILINE && itmp > XTHICKLINEWIDTHDOUBLE) ? distance : NOHV);
}

/*************************************************************
*	search_vpair
*	与えられた (x,y) の座標を通る線分とペアの線分を求めて、
*	2本の線分の距離を返す。
**************************************************************/
static long search_vpair(int x, int y, int flag)
{
	int itmp = 0, ftmp = 0;
	int dx, dy;
	long vx0, vx, ltmp, distance;
	Line *c_line;

	distance = NOHV;
	vx0 = x * TIMES;
	if (flag & HOPEN) {
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			if (c_line->yu < y && y <= c_line->yl) {
				if (c_line->flag & HCLOSE) {
					dx = c_line->dx;
					dy = c_line->dy;
					if (c_line->flag & XYREV) {
						vx = ((long)(c_line->yl - y) * dx * TIMES) / dy
							+ (long)c_line->xl * TIMES;
					}
					else {
						vx = ((long)(y - c_line->yu) * dx * TIMES) / dy
							+ (long)c_line->xl * TIMES;
					}
					if (vx > vx0) {
						ltmp = vx - vx0;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = c_line->flag;
							itmp = dy;
						}
					}
				}
			}
		}
	}
	else {
		for (c_line = linebuf; c_line < linebuf_end; c_line++) {
			if (c_line->yu < y && y <= c_line->yl) {
				if (c_line->flag & HOPEN) {
					dx = c_line->dx;
					dy = c_line->dy;
					if (c_line->flag & XYREV) {
						vx = ((long)(c_line->yl - y) * dx * TIMES) / dy
							+ (long)c_line->xl * TIMES;
					}
					else {
						vx = ((long)(y - c_line->yu) * dx * TIMES) / dy
							+ (long)c_line->xl * TIMES;
					}
					if (vx < vx0) {
						ltmp = vx0 - vx;
						if (distance > ltmp) {
							distance = ltmp;
							ftmp = c_line->flag;
							itmp = dy;
						}
					}
				}
			}
		}
	}
	return ((ftmp & VERTLINE && itmp > YTHICKLINEWIDTHDOUBLE) ? distance : NOHV);
}

/*************************************************************
*	getthinwidth
*	xthin, ythin を求める
**************************************************************/
void getthinwidth(int *xthin, int *ythin)
{
	int dx, dy, cx, cy, flag;
	long xt, yt, tmp1;
	Line *c_line;

	xt = yt = NOHV;

	for (c_line = linebuf; c_line < linebuf_end; c_line++) {
		flag = c_line->flag;
		if (flag & HORILINE) {
			dx = c_line->dx;
			if (dx > XTHICKLINEWIDTHDOUBLE) {
				cx = CENTER(c_line->xl, c_line->xr);
				tmp1 = search_hpair(cx, c_line->yu, flag);
				if (yt > tmp1)
					yt = tmp1;
			}
		}
		else if (flag & VERTLINE) {
			dy = c_line->dy;
			if (dy > YTHICKLINEWIDTHDOUBLE) {
				cy = CENTER(c_line->yu, c_line->yl);
				tmp1 = search_vpair(c_line->xl, cy, flag);
				if (xt > tmp1)
					xt = tmp1;
			}
		}
	}
	if (xt < NOHV) {
		*xthin = (int)(xt / TIMES);
	}
	else {
		*xthin = 0;
	}

	if (yt < NOHV) {
		*ythin = (int)(yt / TIMES);
	}
	else {
		*ythin = 0;
	}
}

/* end of all */
