/*
*               TeX Device Driver DVIOUT, DVIPRT で
*               書体倶楽部のアウトラインフォントを使う
*
*                             vfont.c
*
*     "本プログラムは、Hideki Yoshida 氏の vfondisp.c を元にして作製
*      されています。また、get_ten で吉澤氏のバッファリングのアイデ
*      アを使用し、更に、向内さんの書かれた dvii という dvi ドライバ
*      のアウトラインフォント展開アルゴリズムを使用して、展開されるフ
*      ォントの質の向上をはかった精細モードを設けました。"
*
*                      1991-92  by T.Minagawa
*
*	26 Jan 1993 : modified to utilize tpic functions for expansion by Oh-Yeah?
*	Note: Here the use of tpic is very tricky and deeply indebted to primitive
*	functions in tpic.c, so that even slight modification in tpic.c would
*	require some reconsideration for the routines.
*
*	1 Sept 1992 : slightly modified for version check by sempa.
*  12 Nov  1992 : modified for JGfont(3D-Bezier) by Naochan!
*  27 Nov  1992 : slightly modified for NTTjTeX by Yakumo
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <dir.h>
#include <string.h>
#include <dos.h>
#include <fcntl.h>

#define _DEF_STDIO_H_
#include "dd.h"
#include "err.h"
#include "vfont.h"
#include "vraster.h"
#ifdef	CC_JPN
#include <jctype.h>
#else
unsigned short jistojms(unsigned short);
int jisl1(unsigned short);
int jisl2(unsigned short);

#endif
int jislgaiji(unsigned short);

/* option.c */
int strlcmp(char*, char*);

/* グローバル変数 */
V_JFM *vjfm_top;	/* vjfm リストの先頭を示すポインタ */
struct _v_font dummy =
{
	"?",
	V_ERROR,
	-1, -1,
	0, 0, 0
};

#ifdef VFD
V_JFM *vfd_top;

#endif

V_FONT *vfont[MAX_VFONT] =
{&dummy, &dummy, &dummy, &dummy, &dummy};
const int s_ratio[3] =
{180, 372, 591};

/*
		tan(10) * ( MAX_VLUE + 1 )
		tan(20) * ( MAX_VLUE + 1 )
		tan(30) * ( MAX_VLUE + 1 )
	*/

#ifdef VFTPIC
/* bitmap.c */
void init_alter_bitmap(BUFFER *dest, PIXEL d_linewidth_byte);
void fin_alter_bitmap(void);

/* tpic.c */
#define TPIC_MI long	/* type of tpic milli-inches (x, y) */
typedef struct {
	PIXEL x, y;
} pixelpoint;

void set_grayscale(double gray);
void rasterize_line(pixelpoint start, pixelpoint end, BOOL mask_head,
					BOOL mask_tail);
void set_visible(PIXEL visible, PIXEL invisible);
void raster_draw(void);	/* draw pixels defined in stack */
void set_pensize(TPIC_MI pensize);
void raster_fill(void);
void clean_bucket(void);
void freeze_tpic_status(void);
void melt_tpic_status(void);

#endif

/* init.c prtinit.c */
extern int tategaki;
extern char ptex_mode;

/* buffer.c */
char *dup_string(char *);
char *marea(unsigned int);

/* fontdef.c */
KFONT *dup_kf(KFONT *);

/* loadpk.c */
int openf(char *, int);

/* vraster.c */
int draw_fine(VPARA_TBL *);

/* vdata.c */
int get_yofs(VPARA_TBL *);
int readdata(VPARA_TBL *, DRAW_MODE);
extern int linecount;
extern int itemcount;
extern Line *linebuf;

static int get_term(char *, char *, int, int);
static int far *get_novec(char *);
void bbox(BUFFER *, int);
void bigbox(BUFFER *, long, int);
V_JFM *get_vjfm(int vjfm_no);

#ifdef VFTPIC
int draw_character(VPARA_TBL *);
pixelpoint vf_to_abs(VPARA_TBL *, int x, int y);
/* convert font coord to bitmap coord */

#else
int draw_character(VPARA_TBL *);
static void trace_outline(VPARA_TBL *, int, int, int, int);
static void fill_edges(VPARA_TBL *, int, int, int, int);

#endif

/*************************************************************
*	get_vfont_name
*	vector font config file から情報を取得する
**************************************************************/
int get_vfont_name(char *cfg_name)
{
	FILE *fp;
	char buf1[BUFSIZE], buf2[BUFSIZE], buf3[BUFSIZE], jfm_name[NAMELEN];
	char version[VER_LEN + 1] = "?";
	V_JFM *vjfm;
	V_JFM *before = NULL;

#ifdef VFD
	V_JFM *vfd_before = NULL;
	int vfd_count = 0;

#endif
	int long_wide, slant, sw, threshold, thin, _xfat, _yfat, rotation;
	int i = 0, l = 0, job = 0, counter = 0;
	int f_goth, width_adj, height_adj;
	int far *novec;

	if ((fp = fopen(cfg_name, "rt")) == NULL)
		return (-1);

	while (l++, fgets(buf1, BUFSIZE - 1, fp) != NULL) {
		if (buf1[0] == '#')
			continue;			/* '#' はコメント行 */

		/* キーワードのチェック */
		if (buf1[0] == '%') {
			if (strlcmp(&buf1[1], "version") == NULL) {
				if (get_term(buf2, buf1, 2, '=') == 0)
					continue;
				strncpy(version, buf2, VER_LEN);
				continue;
			}
			else if (strlcmp(&buf1[1], "vfont_list") == NULL) {
				job = 1;
				continue;
			}
			else if (strlcmp(&buf1[1], "jfm_list") == NULL) {
				job = 2;
				continue;
			}
			else {
				return (l);
			}
		}

		if (job == 0) {
			/* エラー */
			return (l);
		}
		else if (job == 1) {
			/* ベクトルフォントの情報を取得 */
			if (get_term(buf2, buf1, 1, DELIM1) == 0)
				continue;
			i = atoi(buf2) - 1;
			if (i < 0 || MAX_VFONT - 1 < i) {
				return (l);
			}
			if (get_term(buf2, buf1, 2, DELIM1) == 0)
				continue;
			vfont[i] = (V_FONT *) marea(sizeof(V_FONT));
			strcpy((char *)vfont[i]->v_font_name, buf2);
			vfont[i]->status = V_CLOSE;
			vfont[i]->v_fh[0] = vfont[i]->v_fh[1] = NULL;

			/* 幅のアジャスト Tomiie */
			if (get_term(buf2, buf1, 3, DELIM1) == 0 ||
				(width_adj = atoi(buf2)) < 200 || 2000 < width_adj) {
				width_adj = 1000;
			}
			vfont[i]->width_adj = width_adj;

			/* 高さのアジャスト Tomiie */
			if (get_term(buf2, buf1, 4, DELIM1) == 0 ||
				(height_adj = atoi(buf2)) < 200 || 2000 < height_adj) {
				height_adj = 1000;
			}
			vfont[i]->height_adj = height_adj;

			if (get_term(buf2, buf1, 5, DELIM1) != 0 &&
				atoi(buf2) > 0)
				vfont[i]->v_fh[1] = -1;

			vfont[i]->yoffset = MAX_VALUE + 1;
		}
		else {
			/* 各 JFM に対応するベクトルフォントの番号、
				フォントの変形、およびフォント描画方法を取得 */
			if (get_term(buf2, buf1, 1, DELIM1) == 0)
				continue;
			strcpy(jfm_name, buf2);
			if (get_term(buf2, buf1, 2, DELIM1) == 0)
				continue;
			i = atoi(buf2) - 1;
#ifndef VFD
			if (i < 0 || MAX_VFONT - 1 < i) {
#else
			if (i < -1 || MAX_VFONT - 1 < i) {
#endif
				return (l);
			}

			/* 長／平体のチェック */
			if (get_term(buf2, buf1, 3, DELIM1) == 0 ||
				buf2[0] < 'a' || buf2[0] == 'f' || 'j' < buf2[0])
				buf2[0] = 'a';
			long_wide = (int)buf2[0];

			/* 斜体のチェック */
			if (get_term(buf2, buf1, 4, DELIM1) == 0 ||
				buf2[0] < 'a' || 'm' < buf2[0])
				buf2[0] = 'a';
			slant = (int)buf2[0];

			/* フォント描画方法のチェック */
			if (get_term(buf2, buf1, 5, DELIM1) == 0 ||
				(buf2[0] != 'n' && buf2[0] != 'o'
				 && buf2[0] != 'f')) {
				buf2[0] = 'n';
			}
			sw = (int)buf2[0];
			if (sw == (int)'n' || sw == (int)'f')
				threshold = atoi(&buf2[1]);

			/* フォント線幅調整パラメータの読み取り */
			get_term(buf2, buf1, 6, DELIM1);
			if (get_term(buf3, buf2, 1, DELIM2) == 0 ||
				(thin = atoi(buf3)) < -100 || 100 < thin) {
				thin = DEF_THIN;
			}
			if (get_term(buf3, buf2, 2, DELIM2) == 0 ||
				(_xfat = atoi(buf3)) < 0 || 100 < _xfat) {
				_xfat = 0;
			}
			if (get_term(buf3, buf2, 3, DELIM2) == 0 ||
				(_yfat = atoi(buf3)) < 0 || 100 < _yfat) {
				_yfat = 0;
			}

			/* vec font 不使用のサイズの読み取り */
			if (get_term(buf2, buf1, 7, DELIM1) == 0)
				novec = NULL;
			else
				novec = get_novec(buf2);

			/* 疑似ゴシックの変更 Tomiie */
			if (get_term(buf2, buf1, 8, DELIM1) == 0 ||
				(f_goth = atoi(buf2)) < 1 || 2 < f_goth) {
				f_goth = 0;
			}

			/* rotation の読み取り */
			if (get_term(buf2, buf1, 9, DELIM1) == 0)
				rotation = 0;
			else
				rotation = atoi(buf2) % 4;

			vjfm = (V_JFM *)marea(sizeof(V_JFM));

#ifndef VFD
			if (counter++ == 0)
				vjfm_top = vjfm;
			else
				before->next = vjfm;

			before = vjfm;
#else
			if (i == -1) {
				if (vfd_count++ == 0)
					vfd_top = vjfm;
				else
					vfd_before->next = vjfm;
				vfd_before = vjfm;
			}
			else {
				if (counter++ == 0)
					vjfm_top = vjfm;
				else
					before->next = vjfm;
				before = vjfm;
			}
#endif
			strcpy((char *)vjfm->name, jfm_name);
			vjfm->font_no = i;
			vjfm->long_wide = long_wide;
			vjfm->slant = slant;
			vjfm->draw_sw = sw;
			vjfm->threshold = threshold;
			vjfm->thin = thin;
			vjfm->_xfat = _xfat;
			vjfm->_yfat = _yfat;
			vjfm->novec = novec;
			vjfm->rotation = rotation;
			vjfm->f_goth = f_goth;
			vjfm->next = NULL;
		}
	}
	fclose(fp);
	get_term(buf2, VFN_VERSION, 1, '*');
	if (atoi(buf2) != atoi(version)) {
		/* vfnのバージョンは整数部のみでチェック */
		error(WARNING, "[vfont] vfn file version mismatch."
				" x(%s) -> o(%s)", version, buf2);
	}
	/* vjfmとvfont[]が対応しているかチェック */
	for (vjfm = vjfm_top; vjfm != NULL; vjfm = vjfm->next) {
		if (vfont[vjfm->font_no] == &dummy) 
			error(WARNING, "[vfont] vfn file error. "
					"JFM(%s) <-> Vector font No.%d.",
					(char *)vjfm->name, vjfm->font_no);
	}
	return (0);
}

/*************************************************************
*	get_term
*	*src から num番目の項目を取得して *dest に入れる
**************************************************************/
int get_term(char *dest, char *src, int num, int delimiter)
{
	int count = 0, i;

	num--;
	for (i = 0; i < num; i++) {
		src = strchr(src, delimiter);
		if (src == NULL)
			return (0);
		src++;
	}

	while (*src != '\0') {
		if (*src == '\n' || *src == delimiter) {
			break;
		}
		else if ((*src == '\t') || (*src == ' ')) {
			src++;
		}
		else {
			*dest++ = *src++;
			count++;
		}
	}
	*dest = '\0';
	return (count);
}

/*************************************************************
*	get_novec
*	ベクトルフォントを使わないサイズを取得する
**************************************************************/
int far *
    get_novec(char *src)
{
	int far *table;
	int i, num;
	char *tmp, buf[4];

	tmp = src;
	for (num = 1, i = 0; *tmp != '\0'; tmp++, i++) {
		if (*tmp == DELIM2) {
			num++;
			i = 0;
		}
		else if (i > 2) {
			error(WARNING, "[vfont] Novec size is too large.");
			return (NULL);
		}
	}
	table = (int far *)marea(sizeof(int) * num + 1);

	table[0] = num;
	for (i = 1; i <= num; i++) {
		get_term(buf, src, i, DELIM2);
		table[i] = atoi(buf);
	}
	return (table);
}

/*************************************************************
*	get_vjfm
*	vjfm のリストの vjfm_no番目の vjfmへのポインタを返す
**************************************************************/
V_JFM *
    get_vjfm(int vjfm_no)
{
	int i;
	V_JFM *vjfm_tmp;

	for (vjfm_tmp = vjfm_top, i = 0; i < vjfm_no;
		 vjfm_tmp = vjfm_tmp->next, i++);
	return (vjfm_tmp);
}

/*************************************************************
*	get_vfont_list
*	fontcをベクトルフォントで展開するかどうか判定し、
*	その結果およびその他の情報を設定する
**************************************************************/
KFONT *
    get_vfont_list(FONT_INFO *fontc, char *name)
{
	int i, j, font_no, v_tmp_fh, width, height, f_tate, fh;
	int far *table, far *wdthp, far *hghtp;
	int find_flg = 0;
	char v_name1[MAXPATH], v_name2[MAXPATH];

#ifdef BEZIERFONT
	char v_name0[MAXPATH];

#endif
	FONT_INFO *font;
	FONT_INFO *fontk;
	V_JFM *vjfm;
	V_JFM *vjfm_tmp;
	KFONT *kf;

	wdthp = &(fontc->k_width);
	hghtp = &(fontc->k_height);
	if (fontc->f_goth & F_TATE){
		wdthp = hghtp;
		hghtp = &(fontc->k_width);
	}

	width = fontc->k_width;
	height = fontc->k_height;
	f_tate = fontc->f_goth & F_TATE;

	for (vjfm = vjfm_top, i = 0; vjfm != NULL;
		 vjfm = vjfm->next, i++) {
		font_no = vjfm->font_no;
		if ((strcmpi((char *)vjfm->name, name)) == 0) {
			strcpy(tmp_buf, (char *)vfont[font_no]->v_font_name);
			for (font = first_font_info; font != NULL;
				 font = font->next_font) {
				if ((font->font_type == ZS_FONT
#ifdef BEZIERFONT
					 || font->font_type == JG_FONT
#endif
					)
					&& (font->f_goth & F_TATE == f_tate)
					&& (font->k_width == width)
					&& (font->k_height == height)
					&& (!strcmp((font->ext.kdir)->name, tmp_buf))) {
					vjfm_tmp = get_vjfm((font->ext.kdir)->fh);
					if (vjfm->long_wide == vjfm_tmp->long_wide
						&& vjfm->slant == vjfm_tmp->slant
						&& vjfm->draw_sw == vjfm_tmp->draw_sw
						&& vjfm->threshold == vjfm_tmp->threshold
						&& vjfm->thin == vjfm_tmp->thin
						&& vjfm->_xfat == vjfm_tmp->_xfat
						&& vjfm->_yfat == vjfm_tmp->_yfat
						&& vjfm->rotation == vjfm_tmp->rotation
						&& vjfm->f_goth == vjfm_tmp->f_goth && 0) {
						if (fontc->k_top == NULL) {
							for (fontk = font; fontk->k_next;
								 fontk = fontk->k_next);
							fontk->k_next = fontc;
							fontc->k_top = fontk->k_top;
						}
						fontc->font_type
#ifdef BEZIERFONT
							= font->font_type;
#else
							= ZS_FONT;
#endif
						return (dup_kf(font->ext.kdir));
					}
				}
			}

			/* ベクトルフォントを使わないサイズに該当していれば
			   NULLを返す */
			if ((table = vjfm->novec) != NULL) {
				for (j = 1; j <= table[0]; j++) {
					if (*wdthp == table[j])
						return (NULL);
				}
			}
			if (vfont[font_no]->status == V_ERROR) {
				return (NULL);
			}
			else if (vfont[font_no]->status == V_OPEN) {
				fh = i;
#ifdef BEZIERFONT
				vfont[font_no]->font_type =
#endif
					fontc->font_type = ZS_FONT;
				find_flg++;
				break;
#ifdef BEZIERFONT
			}
			else if (vfont[font_no]->status == V_JG_OPEN) {
				fh = i;
				vfont[font_no]->font_type = fontc->font_type = JG_FONT;
				find_flg++;
				break;
#endif
			}
			else {
				strcpy(v_name1, tmp_buf);
				strcpy(v_name2, tmp_buf);
				strcat(v_name1, ".vf1");
				strcat(v_name2, ".vf2");

				if ((v_tmp_fh = openf(v_name1, O_RDONLY | O_BINARY)) != -1) {
					vfont[font_no]->v_fh[0] = v_tmp_fh;

					if (vfont[font_no]->v_fh[1] != -1) {
						/* vf2 を使わない設定がされていないときのみ */
						/* vf2 をOPENする                           */
						if ((v_tmp_fh = openf(v_name2, O_RDONLY | O_BINARY))
							== -1)
							error(WARNING, "[vfont] %s not found.", v_name2);
							/* vf2 file がなくて、ignore した場合には第２水準 */
							/* だけ豆腐にして強行する                         */
						vfont[font_no]->v_fh[1] = v_tmp_fh;
					}
					vfont[font_no]->status = V_OPEN;
#ifdef BEZIERFONT
					vfont[font_no]->font_type =
#endif
						fontc->font_type = ZS_FONT;
					fh = i;
					/* vector font については fh は vjfm の
					   リストの位置を示し、実際のﾌｧｲﾙﾊﾝﾄﾞﾙは
					   fh 番目の vjfm.font_no が示すfont_noの
					   vfont[font_no].v_fh にある。       */
					find_flg++;
					break;
				}
#ifdef BEZIERFONT
				strcpy(v_name0, tmp_buf);
				strcpy(v_name1, tmp_buf);
				strcpy(v_name2, tmp_buf);
				strcat(v_name0, ".fn0");
				strcat(v_name1, ".fn1");
				strcat(v_name2, ".fn2");
				if ((v_tmp_fh = openf(v_name1, O_RDONLY | O_BINARY)) != -1) {
					vfont[font_no]->v_fh[0] = v_tmp_fh;
					if ((v_tmp_fh = openf(v_name0, O_RDONLY | O_BINARY)) != -1)
						vfont[font_no]->v_fh[2] = v_tmp_fh;
					else
						error(WARNING,  "[JGfont] %s not found.", v_name0);
					if (vfont[font_no]->v_fh[1] != -1) {
						/* fn2 を使わない設定がされていないときのみ */
						/* fn2 をOPENする                           */
						if ((v_tmp_fh = openf(v_name2, O_RDONLY | O_BINARY))
							== -1)
							error(WARNING, "[JGfont] %s not found.", v_name2);
							/* fn2 file がなくて、ignoreした場合には第２水準 */
							/* だけ豆腐にして強行する                        */
						vfont[font_no]->v_fh[1] = v_tmp_fh;
					}
					vfont[font_no]->status = V_JG_OPEN;
					vfont[font_no]->font_type = fontc->font_type = JG_FONT;
					fh = i;
					/* vector font については fh は vjfm の
					   リストの位置を示し、実際のﾌｧｲﾙﾊﾝﾄﾞﾙは
					   fh 番目の vjfm.font_no が示すfont_noの
					   vfont[font_no].v_fh にある。       */
					find_flg++;
					break;
				}
#endif
				vfont[font_no]->status = V_ERROR;
				error(WARNING, "[vfont] %s not found.", v_name1);
				/* vf1 file も fn1 file もなくて、ignore した場合には */
				/* ベクトルフォント・３次ベジェフォントは諦める       */
				return (NULL);
			}
		}
	}
	if (!find_flg)
		return (NULL);

	/* define Kanji Font file */
	fontc->k_top = fontc;
	kf = (KFONT *)marea(KFONT_SIZE);
	kf->name = (char *)dup_string(tmp_buf);
	width = *wdthp;
	height = *hghtp;
	if (fontc->font_type == ZS_FONT
#ifdef BEZIERFONT
		|| fontc->font_type == JG_FONT
#endif
		) {
		if (vfont[font_no]->width_adj != 1000) {
			width = ((long)width * vfont[font_no]->width_adj) / 1000;
		}
		if (vfont[font_no]->height_adj != 1000) {
			height = ((long)height * vfont[font_no]->height_adj) / 1000;
		}

		if ((int)'b' <= vjfm->long_wide
			&& vjfm->long_wide <= (int)'e') {
			height = (int)((long)width
						   * 10 / (10 - (vjfm->long_wide - (int)'a')));
		}
		else if ((int)'g' <= vjfm->long_wide
				 && vjfm->long_wide <= (int)'j') {
			height = (int)((long)width
						   * (10 - (vjfm->long_wide - (int)'f')) / 10);
		}
		if (vjfm->slant != (int)'a') {
			i = (vjfm->slant - (int)'b') % 3;
			if ((int)'b' <= vjfm->slant && vjfm->slant <= (int)'g') {
				width = (int)((long)width
							  * (MAX_VALUE + s_ratio[i]) / (MAX_VALUE + 1));

			}
			else {
				height = (int)((long)height
							   * (MAX_VALUE + s_ratio[i]) / (MAX_VALUE + 1));
			}
		}
	}
	*hghtp = height;
	kf->width = width;
	kf->height = height;
	kf->size = (width + 7) / 8 * height;
	kf->fh = fh;
	return (kf);
}

#ifndef	NOTATEGAKI
/*************************************************************
*	TateKanji_type(unsigned int jms_char_code)
*   sjisr_codeより疑似縦書きのフォントの座標変換タイプを
*   決定さすための関数 (vdata.c にある)
**************************************************************/
void TateKanji_type(unsigned int);

#endif

/*************************************************************
*	get_vfont
*	char_codeのフォントをベクトルフォントで展開する
**************************************************************/
void get_vfont(int char_code, PREAMBLE *preamble, FONT_INFO *font)
{
	int font_no, i, jis_level;
	long size_bytes;
	int max_width, max_height, max_shift;
	unsigned sjis_code, utmp;
	KFONT *kf;
	BUFFER *buffer;
	V_JFM *vjfm;
	VPARA_TBL v_table;

	kf = font->ext.kdir;
	vjfm = get_vjfm(kf->fh);
	font_no = vjfm->font_no;

	sjis_code = jistojms(char_code);
#ifndef	NOTATEGAKI
	TateKanji_type(sjis_code);
#endif

	v_table.v_font_name = vfont[font_no]->v_font_name;
#ifdef BEZIERFONT
	v_table.font_type = vfont[font_no]->font_type;
#endif
	if (vfont[font_no]->yoffset == 0x400) {
		/* フォントの垂直方向オフセットを求める */
		/* STD_CODE('亜')を基準にする  */
		/* 第１水準 */
		v_table.vfn_file = vfont[font_no]->v_fh[0];	/* vf1 file */
		v_table.char_code = STD_CODE;
		utmp = STD_CODE - (
#ifdef BEZIERFONT
			(v_table.font_type == JG_FONT)?0x3000:
#endif
			0x2100);
		v_table.v_code = (utmp >> 8) * 0x5e + (utmp & 0xff) - 0x21;
		v_table.long_wide = (int)'a';
		v_table.slant = (int)'a';
		vfont[font_no]->yoffset = get_yofs(&v_table);
	}

	v_table.char_code = char_code;
	if (jisl2(sjis_code) != 0 || jislgaiji(sjis_code) != 0) {
		/* 第２水準 */
		jis_level = 1;
		utmp = char_code - 0x5000;
	}
	else
#ifdef BEZIERFONT
		if (v_table.font_type == ZS_FONT)
#endif
	{

		/* 第１水準 */
		jis_level = 0;
		utmp = char_code - 0x2100;
	}
#ifdef BEZIERFONT
	else if (jisl1(sjis_code) != 0) {
		/* 第１水準 */
		jis_level = 0;
		utmp = char_code - 0x3000;
	}
	else {
		/* 漢字以外の文字 */
		jis_level = 2;
		utmp = char_code - 0x2100;
	}
#endif
	v_table.v_code = (utmp >> 8) * 0x5e + (utmp & 0xff) - 0x21;
	v_table.vfn_file = vfont[font_no]->v_fh[jis_level];

	if (preamble->rotate_ptex & 1){
		v_table.width = kf->height;
		v_table.height = kf->width;
	}
	else{
		v_table.width = kf->width;
		v_table.height = kf->height;
	}
	v_table.long_wide = vjfm->long_wide;
	v_table.slant = vjfm->slant;
	v_table.yoffset = vfont[font_no]->yoffset;
	v_table.thin = vjfm->thin;
	v_table.xfat = vjfm->_xfat;
	v_table.yfat = vjfm->_yfat;
	v_table.rotation = vjfm->rotation;

	max_width = MAX_VALUE;
	max_height = MAX_VALUE;
	max_shift = s_ratio[(v_table.slant - (int)'b') % 3];

	if ((int)'b' <= v_table.slant && v_table.slant <= (int)'g')
		max_width += max_shift;
	else if ((int)'h' <= v_table.slant && v_table.slant <= (int)'m')
		max_height += max_shift;

	v_table.max_width = max_width;
	v_table.max_height = max_height;

	size_bytes = (long)((v_table.width + 7) / 8) * v_table.height;
	v_table.buffer = buffer = preamble->raster;
	if (v_table.vfn_file == -1) {
		/* 第二水準フォントファイルがないのに，第二水準文字が使われた */
		error(WARNING, "[%sfont] JIS level 2 is used. %s(%XH)",
#ifdef BEZIERFONT
				(v_table.font_type == ZS_FONT)?"JG":
#endif
				"v",
				font->name, char_code);
		bigbox(buffer, size_bytes, 0xff);
		return;
	}

	bigbox(buffer, size_bytes, 0);

	if (vjfm->draw_sw == (int)'o')
		v_table.dtype = VTRACE;
	else if (vjfm->draw_sw == (int)'f')
		v_table.dtype = FILL;
	else
		v_table.dtype = BOTH;

	if (v_table.width < vjfm->threshold) {
		if (draw_fine(&v_table) == FAILURE)
			bigbox(buffer, size_bytes, 0xff);
	}
	else {
		if (draw_character(&v_table) == FAILURE)
			bigbox(buffer, size_bytes, 0xff);
	}
}

/* 疑似ゴシックモードの変更情報 Tomiie*/
int chk_vfont_goth(FONT_INFO *font)
{
	KFONT *kf;
	V_JFM *vjfm;

	kf = font->ext.kdir;
	vjfm = get_vjfm(kf->fh);

	return vjfm->f_goth;
}

/*************************************************************
*	bbox
*	フォントバッファを塗りつぶす	未使用
**************************************************************/
/*void bbox(BUFFER *buffer, int size)
{
	int i;

	for (i = 0; i < size; i++)
		buffer[i] = 0xff;
}*/

/*************************************************************
*	bigbox
*	フォントバッファを値で塗りつぶす
**************************************************************/
void bigbox(BUFFER *buffer, long size, int p)
{
	int i;
	HUGE_BUF *hbuffer;

	if (size < 0x7fff ) {
		for (i=size-1; i>=0; i--)
			buffer[i]=p;
	}
	else {
		for (hbuffer = buffer; size > 0; size--)
			*(hbuffer++) = p;
	}
}

#ifndef	CC_JPN
/*************************************************************
*	jistojms
**************************************************************/
unsigned short jistojms(unsigned short c)
{
	int hi, lo;

	hi = (c >> 8) & 0xFF;
	lo = c & 0xFF;
	if (hi & 1)
		lo += 0x1f;
	else
		lo += 0x7d;
	hi = ((hi - 0x21) >> 1) + 0x81;
	if (lo >= 0x7f)
		lo++;
	if (hi > 0x9f)
		hi += 0x40;
	return ((hi << 8) | lo);
}

/*************************************************************
*	jisl1, jisl2
**************************************************************/
int jisl1(unsigned short c)
{
	return (0x889F <= c) && (c <= 0x9872);
}

int jisl2(unsigned short c)
{
	return (0x989F <= c) && (c <= 0xEA9E);
}

/*************************************************************
*	jislgaiji
**************************************************************/
int jislgaiji(unsigned short c)
{
	return (0xEA9F <= c) && (c <= 0xEFFC);
	/* EFFC = JIS:7E7E */
}

#endif

#ifdef VFTPIC
/*************************************************************
*	draw_character
*	tpicでベクトルフォントを展開する by Oh-Yeah?氏
*		modified by T.Minagawa
**************************************************************/
int draw_character(VPARA_TBL *tbl_ptr)
{
	int y_factor = (tbl_ptr->width + 7) / 8;
	/* linewidth of font raster map */
	double gray = (double)(tbl_ptr->thin + 1) / 100;

	/* meaning changed to grayscale (0 - 1). negative value means zero */
	int x, y, h, i;
	int vcorrection, itemno;
	pixelpoint ptop, p1, p2;

	if (tbl_ptr->v_code > MAX_CODE)
		return (FAILURE);
	linecount = itemcount = 0;
	if (readdata(tbl_ptr, STD_MODE) == FAILURE)
		return (FAILURE);
	if (linecount == 0) return (TRUE);

	if (tbl_ptr->rotation == 0 && !tategaki && !ptex_mode) {
		/* 回転したときは処理が面倒なので y offset の調整は省略 */
		vcorrection = tbl_ptr->yoffset;
		for (i = h = 0; i < linecount; i++) {
			linebuf[i].yu += vcorrection;
			h = max(h, linebuf[i].yu - (tbl_ptr->max_height + 1));
		}
		if (h > 0) {
			for (i = 0; i < linecount; i++)
				linebuf[i].yu -= h;
		}
	}

	freeze_tpic_status();
	/* Note: It is assumed that
			(a) path stack is not used here, so it will not be frozen.
			(b) visible array, y-buckets and pixel stack are used immediately
			    both here and in tpic.c, so they will not be frozen.
			(c) tpic rotation (rt) is not used here, so rotation matrix and
			    flag will not be frozen.
		if not, rewrite freeze and melt functions in tpic.c. */
	init_alter_bitmap(tbl_ptr->buffer, y_factor);
	/* tricky: alter tpic destination bitmap to font raster data */
	/* Note: Be careful, width & height will not be checked in bitmap.c */
	set_pensize((TPIC_MI) 1);
	/* pensize = unit pixel. if not, this should be modified! */
	/* because tpic_pa cannot fill a doughnut, more primitive functions
	should be used ... (:_;) */
	switch (tbl_ptr->dtype) {
	  case VTRACE:				/* trace outline */
		  set_visible(1, 0);	/* all visible */
		  break;
	  case FILL:				/* fill interior */
		  set_visible(0, 1);	/* all invisible */
		  set_grayscale(gray);
		  break;
	  case BOTH:				/* trace and fill */
		  set_visible(1, 0);	/* all visible */
		  set_grayscale(gray);
		  break;
	}

	itemno = linebuf[0].itemno;
	x = linebuf[0].xl;
	y = linebuf[0].yu;
	ptop = p1 = vf_to_abs(tbl_ptr, x, y);
	for (i = 1; i < linecount; i++) {
		x = linebuf[i].xl;
		y = linebuf[i].yu;
		if (itemno != linebuf[i].itemno) {
			rasterize_line(p1, ptop, FALSE, FALSE);	/* assure it is closed */
			p1 = vf_to_abs(tbl_ptr, x, y);
			ptop = p1;
			itemno = linebuf[i].itemno;
		}
		else {
			rasterize_line(p1, p2 = vf_to_abs(tbl_ptr, x, y), FALSE, FALSE);
			p1 = p2;
		}
	}
	rasterize_line(p1, ptop, FALSE, FALSE);	/* assure it is closed */

	if (tbl_ptr->dtype != VTRACE)
		raster_fill();
	raster_draw();
	clean_bucket();

	fin_alter_bitmap();			/* recover original bitmap */
	melt_tpic_status();			/* recover tpic static variables */
	return (TRUE);
}

/*************************************************************
*	vf_to_abs
**************************************************************/
pixelpoint vf_to_abs(VPARA_TBL *tbl_ptr, int x, int y)
{	   /* convert font coord to bitmap coord */
	pixelpoint p;

	p.x = (int)(
				   ((long)x * tbl_ptr->width - (tbl_ptr->max_width + 1) / 2)
				   / (tbl_ptr->max_width + 1));
	p.y = (int)(
				 ((long)y * tbl_ptr->height - (tbl_ptr->max_height + 1) / 2)
				   / (tbl_ptr->max_height + 1));

	return (p);
}

#else /* if VFTPIC is not defined... */

/*************************************************************
*	draw_character
*     Original routine of vector font rasterizer.
**************************************************************/
int draw_character(VPARA_TBL *tbl_ptr)
{
	int x, y, x0, y0, x1, y1, h, i, j;
	int vcorrection, itemno, funcno;

	/*	static void_func_ptr draw_func[]( VPARA_TBL*, int, int, int, int ) = {*/
	static void (*draw_func[]) (VPARA_TBL *, int, int, int, int) =
	{
		fill_edges,
		trace_outline
	};

	if (tbl_ptr->v_code > MAX_CODE)
		return (FAILURE);
	linecount = itemcount = 0;
	if (readdata(tbl_ptr, STD_MODE) == FAILURE)
		return (FAILURE);

	vcorrection = tbl_ptr->yoffset;
	for (i = h = 0; i < linecount; i++) {
		linebuf[i].yu += vcorrection;
		h = max(h, linebuf[i].yu - (tbl_ptr->max_height + 1));
	}
	if (h > 0) {
		for (i = 0; i < linecount; i++)
			linebuf[i].yu -= h;
	}

	switch (tbl_ptr->dtype) {
	  case VTRACE:				/* trace outline */
		  h = 0;
		  j = 1;
		  break;
	  case FILL:				/* fill interior */
		  h = 1;
		  j = 2;
		  break;
	  case BOTH:				/* trace and fill */
		  h = 0;
		  j = 2;
		  break;
	}

	itemno = linebuf[0].itemno;
	x0 = x1 = linebuf[0].xl;
	y0 = y1 = linebuf[0].yu;
	for (funcno = h; funcno < j; funcno++) {
		for (i = 0; i < linecount; i++) {
			x = linebuf[i].xl;
			y = linebuf[i].yu;
			if (itemno != linebuf[i].itemno) {
				draw_func[funcno] (tbl_ptr, x1, y1, x0, y0);
				x0 = x1 = x;
				y0 = y1 = y;
				itemno = linebuf[i].itemno;
			}
			else {
				draw_func[funcno] (tbl_ptr, x1, y1, x, y);
				x1 = x;
				y1 = y;
			}
		}
		draw_func[funcno] (tbl_ptr, x1, y1, x0, y0);
	}

	return (TRUE);

}

/*************************************************************
*	trace_outline
*     Original routine of vector font rasterizer.
**************************************************************/
static void trace_outline
    (VPARA_TBL *tbl_ptr, int x1, int y1, int x2, int y2) {
	int dx, dy, dx2, dy2, e, i, tmp;
	BUFFER *address;
	BUFFER *buffer = tbl_ptr->buffer;
	int width = tbl_ptr->width;
	int height = tbl_ptr->height;
	int max_width = tbl_ptr->max_width;
	int max_height = tbl_ptr->max_height;
	int thin = tbl_ptr->thin;
	int y_factor = (width + 7) / 8;

	unsigned char mask;
	long offset_x, minus_offset_x, plus_offset_x;
	long offset_y, minus_offset_y, plus_offset_y;

	offset_x = (long)thin *(max_width + 1) / 100l / 2l;

	minus_offset_x = -(max_width + 1) / 2l - offset_x;
	plus_offset_x = -(max_width + 1) / 2l + offset_x;
	offset_y = (long)thin *(max_height + 1) / 100l / 2l;

	minus_offset_y = -(max_height + 1) / 2l - offset_y;
	plus_offset_y = -(max_height + 1) / 2l + offset_y;

	dx = x2 - x1;
	dy = y2 - y1;
	if (dy < 0) {
		x1 = (int)(((long)x1 * width + minus_offset_x) / (max_width + 1));
		x2 = (int)(((long)x2 * width + minus_offset_x) / (max_width + 1));
	}
	else if (dy == 0) {
		x1 = (int)(((long)x1 * width - (max_width + 1) / 2) / (max_width + 1));
		x2 = (int)(((long)x2 * width - (max_width + 1) / 2) / (max_width + 1));
	}
	else {
		x1 = (int)(((long)x1 * width + plus_offset_x) / (max_width + 1));
		x2 = (int)(((long)x2 * width + plus_offset_x) / (max_width + 1));
	}
	if (dx > 0) {
		y1 = (int)(((long)y1 * height + minus_offset_y) / (max_height + 1));
		y2 = (int)(((long)y2 * height + minus_offset_y) / (max_height + 1));
	}
	else if (dx == 0) {
		y1 = (int)(((long)y1 * height - (max_height + 1) / 2)
				   / (max_height + 1));
		y2 = (int)(((long)y2 * height - (max_height + 1) / 2)
				   / (max_height + 1));
	}
	else {
		y1 = (int)(((long)y1 * height + plus_offset_y) / (max_height + 1));
		y2 = (int)(((long)y2 * height + plus_offset_y) / (max_height + 1));
	}
	if (x1 < 0)
		x1 = 0;
	else if (x1 >= max_width)
		x1 = max_width - 1;
	if (x2 < 0)
		x2 = 0;
	else if (x2 >= max_width)
		x2 = max_width - 1;
	if (y1 < 0)
		y1 = 0;
	else if (y1 >= max_height)
		y1 = max_height - 1;
	if (y2 < 0)
		y2 = 0;
	else if (y2 >= max_height)
		y2 = max_height - 1;

	dy = y2 - y1;
	if (dy < 0) {
		tmp = x1;
		x1 = x2;
		x2 = tmp;
		tmp = y1;
		y1 = y2;
		y2 = tmp;
		dy = -dy;
	}
	dx = x2 - x1;
	if (dx < 0)
		dx = -dx;
	if (dx == 0 && dy == 0)
		return;
	address = &buffer[y1 * y_factor + x1 / 8];
	mask = 0x80 >> (x1 & 7);
	dx2 = 2 * dx;
	dy2 = 2 * dy;

	if (dx < dy) {
		e = dx2 - dy;
		if (x1 < x2) {
			for (i = 0; i <= dy; i++) {
				*address |= mask;
				while (e >= 0) {
					if ((mask >>= 1) == 0) {
						address++;
						mask = 0x80;
					}
					e -= dy2;
				}
				address += y_factor;
				e += dx2;
			}
		}
		else {
			for (i = 0; i <= dy; i++) {
				*address |= mask;
				while (e >= 0) {
					if ((mask <<= 1) == 0) {
						address--;
						mask = 0x1;
					}
					e -= dy2;
				}
				address += y_factor;
				e += dx2;
			}
		}
	}
	else {
		e = dy2 - dx;
		if (x1 < x2) {
			for (i = 0; i <= dx; i++) {
				*address |= mask;
				while (e >= 0) {
					address += y_factor;
					e -= dx2;
				}
				if ((mask >>= 1) == 0) {
					address++;
					mask = 0x80;
				}
				e += dy2;
			}
		}
		else {
			for (i = 0; i <= dx; i++) {
				*address |= mask;
				while (e >= 0) {
					address += y_factor;
					e -= dx2;
				}
				if ((mask <<= 1) == 0) {
					address--;
					mask = 0x1;
				}
				e += dy2;
			}
		}
	}
}

/*************************************************************
*	fill_edges
*     Original routine of vector font rasterizer.
**************************************************************/
static void fill_edges
    (VPARA_TBL *tbl_ptr, int x1, int y1, int x2, int y2) {
	static unsigned char mask_pattern[8] =
	{0xff, 0x7f, 0x3f, 0x1f, 0xf, 0x7, 0x3, 0x1};
	int dx, dy, dx2, dy2, sx, e, i, j, tmp;
	int width = tbl_ptr->width;
	int height = tbl_ptr->height;
	int max_width = tbl_ptr->max_width;
	int max_height = tbl_ptr->max_height;
	int y_factor = (width + 7) / 8;
	BUFFER *address;
	BUFFER *buffer = tbl_ptr->buffer;
	int bit, right_bytes;

	x1 = (int)(((long)x1 * width - (max_width + 1) / 2)
			   / (max_width + 1));
	y1 = (int)(((long)y1 * height - (max_height + 1) / 2)
			   / (max_height + 1));
	x2 = (int)(((long)x2 * width - (max_width + 1) / 2)
			   / (max_width + 1));
	y2 = (int)(((long)y2 * height - (max_height + 1) / 2)
			   / (max_height + 1));

	dy = y2 - y1;
	if (dy == 0)
		return;
	if (dy < 0) {
		tmp = x1;
		x1 = x2;
		x2 = tmp;
		tmp = y1;
		y1 = y2;
		y2 = tmp;
		dy = -dy;
	}
	dx = x2 - x1;
	sx = dx > 0 ? 1 : -1;
	if (dx < 0)
		dx = -dx;
	address = &buffer[y1 * y_factor + x1 / 8];
	right_bytes = (width - 1) / 8 - x1 / 8;
	bit = x1 & 7;
	dx2 = 2 * dx;
	dy2 = 2 * dy;
	e = dx2 - dy;

	for (i = 0; i < dy; i++) {
		/* Change right bits in this byte. */
		*address ^= mask_pattern[bit];
		/* Change all the bits in right bytes. */
		for (j = 1; j <= right_bytes; j++) {
			address[j] = ~address[j];
		}
		while (e >= 0) {
			bit += sx;
			if (bit & 0x8) {
				address += sx;
				right_bytes -= sx;
				bit &= 0x7;
			}
			e -= dy2;
		}
		address += y_factor;
		e += dx2;
	}
}

#endif /* end of ifdef VFTPIC ... else ... */

/* end of all */
