/*							dviout for Windows
 *
 *						Windows TrueType Japanese Font
 *							1996, written by SHIMA
 */

#ifdef	WIN32
#define	MY_WIN32
#endif

#include "dviout.h"
#ifdef MSVC
#include "msvcdir.h"
#else
#include <dir.h>
#endif
#include <time.h>
#include <math.h>
#include "vfont.h"
#include "err.h"
#include "cid2uni.h"

char *check_ftt(char *);

#define	KEEP_HDC		1

#if 0
struct PREAMBLE_REC {
	int width, height, pitch_offset, depth_offset;
	/*   the size of the character, and the offset for typesetting.
		 */
	unsigned char *raster;
	/*   the pointer of Raster-data buffer
		 */
	int tfm_width;
	int byte_width;
	/*   equal width/8, raised decimal
		 */
	int shift_up_ptex, shift_right_ptex;
	/*  the offset when lateral-Kanji used (when in pTeX tate mode)
		 */
	int rotate_ptex;
	/* the flag of rotation (when in pTeX tate mode)
		 */
};
#endif

#ifdef	WIN32C
HWND	hWndMain;
#else
#define	hWndMain	g_winData.dviwin.hWnd
#endif

extern V_FONT *vfont[MAX_VFONT];
extern GetBoundingBox(BYTE*, int, int, int, RECT*);
int C2Unicode(int, int);

static LOGFONT lf;          // フォント属性構造体。
static LPBYTE  lpBuf;

/*
 *    0xbf -> 0x2219 in format 4 table
 */
static unsigned char bakoma[34] = {
	0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
	0xa9, 0xaa, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2,
	0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
	0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2,
	0xc3, 0xc4
};

static unsigned char wintex[34] = {
	196, 197, 199, 201, 209, 214, 220, 225, 
	224, 226, 228, 227, 229, 231, 233, 232, 
	234, 235, 237, 236, 238, 239, 241, 243,
	242, 244, 246, 245, 250, 249, 251, 252,
	134, 176
};

#if 0
// MS Windows 1251 Latin 1 -> Unicode
static unsigned short TransOEM[32] = {
	8364, 000,8218, 402,8222,8230,8224,8225,	// 200
	710,8240, 352,8249, 338, 000, 000, 000, 	// 210
	000,8216,8217,8220,8221,8226,8211,8212, 	// 220
	732,8482, 353,8250, 339, 000, 000, 376, 	// 230
};
#endif


#if 0
// format 0 table (the code < 0x20 cannot be accessible) */
static unsigned char bakoma0[34] = {
	0xc1, 0xa2, 0xa3, 0xdb, 0xb4, 0x0e, 0xa4, 0xac,
	0xa9, 0xbb, 0x05, 0xa8, 0xf8, 0xa1, 0xb1, 0x1b,
	0x03, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0x01, 0xbc,
	0xc8, 0x04, 0x06, 0x0f, 0xc0, 0xcb, 0xe7, 0xe5,
	0xcc, 0x80
};
#endif

void FreeWinjTT(void)
{
	if(lpBuf){
		GlobalFree( lpBuf );
		lpBuf = NULL;
	}
}


static unsigned short *ToUniCode(int code_page, char *s)
{
	static unsigned short t[2];

	MultiByteToWideChar(code_page, 0, s, -1, (LPWSTR)t, 2);
	return t;
}


static int ToUniCodeNum(int code_page, int code)
{
	char tmp[4];

	if(code & 0xff00){
		tmp[0] = code >> 8;
		tmp[1] = code & 0xff;
		tmp[2] = 0;
	}else{
		tmp[0] = code;
		tmp[1] = 0;
	}
	return (int)ToUniCode(code_page, tmp);
}

int C2UniCode(int code_page, int code)
{
	return *(unsigned short *)ToUniCodeNum(code_page, code);
}

V_JFM *v_tfm;

int TransEuroTTCode(int code, int mode)
{
	int code2;


	if(mode == 2)
		mode = 1252;
	if(mode > 256)
		return C2UniCode(mode, code);

	if(code < 0 || (code >= 0x21 && code != 0x7f))
		return code;

	code2 = (code==0x7f)?0x21:code;
	switch(mode){
		case 0:
			code = bakoma[code2];
			break;
		case 1:
			code = wintex[code2];
			break;
#if 0
		case 3:
			code = bakoma0[code2];
			break;
#endif
		default:
			if(code <= 0x21)
				code ^= 0x80;
			else if (code == 0x7f)
				code = 0xa1;
	}
	return code;
}

int CID2Uni(int code)
{
	return (code < 0 || code > sizeof(cidtounicode)/sizeof(unsigned short))?
		0:cidtounicode[code];
}

void GetWinjTTGlyph(V_JFM *vjfm, int jis_code, int height, 
	struct PREAMBLE_REC *preamble, int mode, char *name)
{
	static HDC hDC;
	static HFONT hFont, hOldFont;
	static V_JFM *old_vjfm;
	static char f_unicode;
	static int code_page;
#ifdef	KEEP_HDC
	static char *old_t_name;
#endif
	UINT dwRet;
	static GLYPHMETRICS gm;
	int org_code, sjis_code, p_height, p_width, bs_width, bd_width, attr;
	char *t_name, *u;
	unsigned char *s, *d;
	MAT2 mat2;

	org_code = jis_code;
	if(jis_code <= 0x20 || jis_code == 0x7f)
		jis_code = TransEuroTTCode(jis_code, vjfm->thin);

	t_name = (vjfm == v_tfm)?
		check_ftt(name):(vfont[vjfm->font_no]->v_font_name + 1);
	if(mode == 1){
		FreeWinjTT();
#if	KEEP_HDC
		if(lf.lfHeight == -height && old_t_name == t_name && old_vjfm == vjfm)
			goto same;
		if(hDC != NULL){
			SelectObject( hDC, hOldFont );
			DeleteObject( hFont );
			ReleaseDC( hWndMain, hDC );
		}
		old_t_name = t_name;
#endif
		for(attr = 0; t_name[attr] && t_name[attr] != '/' && attr<32; attr++)
			lf.lfFaceName[attr] = t_name[attr];
		lf.lfFaceName[attr] = 0;
							// フォント書体名。32文字以下。

		old_vjfm = vjfm;
		lf.lfHeight = -height; 		  // フォントの高さ
		lf.lfWeight = strchr(s = t_name + attr, 'B')?700:0;
						// フォントの太さ（標準400, 太字700, 0=デフォルト）
		s = t_name + attr;
		d = strchr(s, '(');
		if(strchr(s, 'C')){
			f_unicode = 1;
			if( (u = strchr(s, '[')) != NULL ){
				code_page = atoi(u+1);	
			}
			else
				code_page = -1;
			lf.lfCharSet = (d)? atoi(d+1):0;
		}else{
			f_unicode = 0;
			if(!d)
				lf.lfCharSet = (jis_code < 0x100)?
					ANSI_CHARSET:SHIFTJIS_CHARSET;
			else
				lf.lfCharSet = atoi(d+1);
		}											// 文字セット
#if !KEEP_HDC
		lf.lfWidth  = 0;    // デバイスのアスペクト比。
#endif
		lf.lfItalic = strchr(s, 'I')?TRUE:FALSE;
							// 斜体フォント
#if	0
		lf.lfEscapement = 0; // テキスト行の角度。（1/10度単位）
#else
		lf.lfEscapement = -vjfm->rotation*900;
		if(  ptex_d 
		  && vjfm == v_tfm	// edefault
		  && !vjfm->rotation
		  && jis_code >= 0x100
		  && *t_name == '@')
			lf.lfEscapement = -900;
#endif
		if((hFont = CreateFontIndirect( &lf )) == NULL){
			preamble->width = preamble->byte_width = 0;
			return;
		}
		hDC    = GetDC( hWndMain );
		hOldFont = SelectObject( hDC, hFont );
same:
		if(f_osversion <= 0 || !(vjfm->rotation & 1)){
			mat2.eM11.value = vjfm->mat.eM11.value;
			mat2.eM11.fract = vjfm->mat.eM11.fract;
			mat2.eM22.value = vjfm->mat.eM22.value;
			mat2.eM22.fract = vjfm->mat.eM22.fract;
			mat2.eM12.value = vjfm->mat.eM12.value;
			mat2.eM12.fract = vjfm->mat.eM12.fract;
			mat2.eM21.value = vjfm->mat.eM21.value;
			mat2.eM21.fract = vjfm->mat.eM21.fract;
		}else{
			mat2.eM11.fract = vjfm->mat.eM22.fract;
			mat2.eM11.value = vjfm->mat.eM22.value;
			mat2.eM22.fract = vjfm->mat.eM11.fract;
			mat2.eM22.value = vjfm->mat.eM11.value;
			mat2.eM12.fract = -vjfm->mat.eM21.fract;
			mat2.eM12.value = -vjfm->mat.eM21.value;
			if(mat2.eM12.fract != 0)
				mat2.eM12.value--;
			mat2.eM21.fract = -vjfm->mat.eM12.fract;
			mat2.eM21.value = -vjfm->mat.eM12.value;
			if(mat2.eM21.fract != 0)
				mat2.eM21.value--;
		}
#if	0
	error(14, "(%d %d, %d %d)",
		mat2.eM11.value*0x10000 + mat2.eM11.fract,
		mat2.eM22.value*0x10000 + mat2.eM22.fract,
		mat2.eM12.value*0x10000 + mat2.eM12.fract,
		mat2.eM21.value*0x10000 + mat2.eM21.fract);
#endif
/* 
#ifdef	USE_SUBFONT
		if (lf.lfCharSet == SHIFTJIS_CHARSET)
#endif
 */
		sjis_code = (jis_code >= 0x100)?jistojms(jis_code):jis_code;
//	error(14, "%x %d %d", jis_code, f_unicode, code_page); 
		if(!f_unicode){
non_unicode:
			dwRet = GetGlyphOutline( hDC, sjis_code, GGO_BITMAP, 
				&gm, 0, NULL, &mat2 );
			lpBuf = GlobalAlloc( GPTR, dwRet );
			GetGlyphOutline( hDC, sjis_code, GGO_BITMAP, 
				&gm, dwRet, lpBuf, &mat2 );
		}else{
			int uni_code;

			uni_code = (code_page>=0)?ToUniCodeNum(code_page, sjis_code):
				((code_page == CID)?CID2Uni(org_code):org_code);
			dwRet = GetGlyphOutlineW( hDC, uni_code, GGO_BITMAP, &gm, 0, NULL, &mat2 );
			if( dwRet == 0 &&
			  !( uni_code == 0x0020 || uni_code == 0x00a0 || uni_code == 0x1680
				|| (0x2000 <= uni_code && uni_code <= 0x200b) || uni_code == 0x202f
				|| uni_code == 0x205f || uni_code == 0x3000 /* space */ ) ){
				int res;
				static int shown_message = FALSE;
				if( shown_message == FALSE )
				{
					if( (res = GetLastError()) == ERROR_CALL_NOT_IMPLEMENTED )
						error( WARNING, "The unicode version of "
						"GetGlyphOutline() is\nnot implemented in this OS." );
					else
						error( WARNING, "The OS returns the error code %d", 
						res );
					shown_message = TRUE;
				}
				uni_code = 0;
			}
			lpBuf = GlobalAlloc( GPTR, dwRet );
			GetGlyphOutlineW( hDC, uni_code, GGO_BITMAP, &gm, dwRet, lpBuf, &mat2 );
		}

#if	!KEEP_HDC
		SelectObject( hDC, hOldFont );
		DeleteObject( hFont );
		ReleaseDC( hWndMain, hDC );
#endif
		preamble->width = gm.gmBlackBoxX;
		preamble->byte_width = (gm.gmBlackBoxX+7)>>3;
		preamble->height = gm.gmBlackBoxY;
		preamble->pitch_offset = -gm.gmptGlyphOrigin.x;
		preamble->depth_offset = gm.gmptGlyphOrigin.y;
		if(sjis_code < 0x100){
			if(vjfm->_xfat != 0)
				preamble->pitch_offset -= vjfm->_xfat*height/1000;
			if(vjfm->_yfat != 0)
				preamble->depth_offset -= vjfm->_yfat*height/1000;
		}
#if 0
		error(13,
			"BBX %d, BBY %d, BBOX %d, BBOY %d",
			gm.gmBlackBoxX, gm.gmBlackBoxY, 
			gm.gmptGlyphOrigin.x, 
			gm.gmptGlyphOrigin.y); 
#endif
	}else if(mode == 2){
#if 0
		error(13, "CCX %d, CCY %d",
			gm.gmCellIncX,
			gm.gmCellIncY);
		// In \tate mode, the signature of gm.gmCellIncY is 
		//   negative for Windows95
		//   positive for WindowsNT
#endif
		preamble->shift_right_ptex = gm.gmCellIncX;

		// A bug for WindowsNT
		preamble->shift_up_ptex = 
			(gm.gmCellIncX || gm.gmCellIncY < 0)?
			gm.gmCellIncY:-gm.gmCellIncY;
		if(preamble->width != gm.gmBlackBoxX
		 || preamble->height != gm.gmBlackBoxY)
			return;
		bd_width = preamble->byte_width;
		bs_width = ((gm.gmBlackBoxX+31)>>5)<<2;
		s = lpBuf;
		d = preamble->raster;
		for(p_height = 0; p_height < gm.gmBlackBoxY; p_height++){
			for(p_width = 0; p_width < bd_width; p_width++)
				d[p_width] = s[p_width];
			s += bs_width;
			d += bd_width;
		}
	}
	return;
}

void GetWinjTTMetric(V_JFM *vjfm, int *width, int *height, char *name)
{
	HDC hDC;
	HFONT hFont, hOldFont;
//  GLYPHMETRICS gm;
	char *t_name, *s;
	int attr;
#ifdef	WIN32C
	char Buf[64];
	char Buf2[256];
#endif
	int fontno = vjfm->font_no;

#ifdef	WIN32C
	sprintf(Buf, "dviprt console %d", time(NULL));
	SetConsoleTitle(Buf);
	if( !hWndMain ){
		while (TRUE) {
			Sleep(10);
			if (!hWndMain) {
				if ((hWndMain = GetTopWindow(hWndMain)) == NULL) continue;
			} else if ((hWndMain = GetNextWindow(hWndMain, GW_HWNDNEXT))
				== NULL)	continue;
			GetWindowText(hWndMain, Buf2, 256);
			if(!strcmp(Buf, Buf2)) 
				break;
		}
	}
	SetConsoleTitle("dviprt console");
#endif

	/* LOGFONT（論理フォント）構造体の初期化 */

	t_name = (vjfm==v_tfm)?check_ftt(name): (vfont[fontno]->v_font_name + 1);
	 // フォント書体名。32文字以下。
	for(attr = 0; t_name[attr] && t_name[attr] != '/' && attr<32; ){
		if((lf.lfFaceName[attr] = t_name[attr]) & 0x80){
			attr++;
			lf.lfFaceName[attr] = t_name[attr];
		}
		attr++;
	}
	lf.lfFaceName[attr] = 0;
	lf.lfHeight = -*height;
	lf.lfWidth  = 0;     // デバイスのアスペクト比。
#if	0
	lf.lfEscapement = 0; // テキスト行の角度。（1/10度単位）
#else
	lf.lfEscapement = -vjfm->rotation*900; // テキスト行の角度。（1/10度単位）
	if(  ptex_d 
	  && vjfm == v_tfm	// edefault
	  && !vjfm->rotation
	  && *check_ftt(name) == '@')
		lf.lfEscapement = -900;
#endif
	lf.lfOrientation = 0; // ベースラインの角度。（1/10度単位）
	lf.lfWeight = strchr(s = t_name + attr, 'B')?700:0;
						 // フォントの太さ（標準400, 太字700, 0=デフォルト）
	lf.lfItalic = strchr(s, 'I')?TRUE:FALSE; // 斜体フォント
	lf.lfUnderline = FALSE; // 下線付きフォント
	lf.lfStrikeOut = FALSE; // 打ち消し線付きフォント
	lf.lfCharSet = SHIFTJIS_CHARSET; // 文字セット
	lf.lfOutPrecision = OUT_DEFAULT_PRECIS; // 出力精度
	lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; // クリッピング精度
	lf.lfQuality = PROOF_QUALITY; // 出力品質。最高級。サイズが一致しないことあり。
	lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;

	// Retrieve the device context,
	// select the font into it,
	// and create a compatible device context.
	//........................................
	if((hFont = CreateFontIndirect( &lf )) == NULL){
		*width = 0;
		goto quit;
	}
	hDC    = GetDC( hWndMain );
	hOldFont = SelectObject( hDC, hFont );
/*
	// Retrieve the size of the bitmap 
	// and allocate memory to hold it.
	// shift jis code of '亜' = 0x889f
	*width = (GetGlyphOutline( hDC, 0x889f, GGO_BITMAP, 
	  &gm, 0, NULL, &vjfm->mat) == GDI_ERROR)?
		*height:gm.gmBlackBoxX;
*/
	*width = *height;
quit:
	lf.lfHeight = 0;
	SelectObject( hDC, hOldFont );
	DeleteObject( hFont );
	ReleaseDC( hWndMain, hDC );
}

void ResetWinTTCache(void)
{
	lf.lfHeight = 0;
}

static int f_att;

static int CheckTSub(char *s, char *t)
{
	for(;tolower(*s)==tolower(*t);s++,t++){
		if(!*t)
			return 0;
	}
	return(!*s && *t=='/')?0:1;
}

static int CALLBACK EnumFontProc( ENUMLOGFONT* lpelf, NEWTEXTMETRIC* lpntm, 
						   int nFontType, LPARAM lParam )
{
   // Load only TrueType fonts into the list box.
   //............................................
	if ( // (nFontType & TRUETYPE_FONTTYPE) && 			April 20, 2002
	  !CheckTSub(lpelf->elfLogFont.lfFaceName, (char *)lParam))
		f_att = 0;
   return( TRUE );
}

int AccessTT(char *name)
{
	int pos;
	HDC hDC;

	if((pos = strlen(name) - 4) > 0 && !strcmp(name+pos, ".ttf"))
		return -1;
	f_att = -1;
	hDC = GetDC( hWndMain );
	EnumFontFamilies( hDC, NULL, (FARPROC)EnumFontProc, (LPARAM)name);
	return f_att;
}

#ifdef	MY_WIN32
/***************************************************************/
/*          direct output routines by WindowsAPI (patch2)      */
/***************************************************************/
int sptopixel(int);
void rotate_address(int *x, int *y);

BOOL f_ttout;						/* use this routine			*/
static LOGFONT lf2;					/* current TrueType			*/
static HDC hDCP;					/* device to output			*/
static int HH, VV;					/* offset of the origin		*/
static int XDiv, YDiv;				/* scaling factor			*/
static int colorTT;					/* current TEXT color		*/

BOOL PutWinTTChar(V_JFM *,int, int, int, int, int, struct PREAMBLE_REC *, char *);

/*
	ON  : give device, offset of the origin, scaling factor
	OFF : device=NULL
 */
void InitTTOut(HDC hDC, int h, int v, int xdiv, int ydiv)
{
	if(hDC){
		hDCP = hDC;
		SetTextAlign(hDCP, TA_BASELINE);
		SetTextColor(hDCP, RGB(0,0,0));
		SetBkMode(hDCP, TRANSPARENT);
		f_ttout = TRUE;
		colorTT = 0;
		lf2.lfWidth  = 0;	// デバイスのアスペクト比。
		lf2.lfOrientation = 0;	// ベースラインの角度。（1/10度単位）
		HH = h;
		VV = v;
		XDiv = xdiv;
		YDiv = ydiv;
	}else{
		PutWinTTChar(NULL, 0, 0, 0, 0, 0, NULL, NULL);
		hDCP = NULL;
		f_ttout = FALSE;
	}
	lf2.lfHeight = 0;
}

/*
 *	Output a character given by TrueType font
 *      character code: ASC or JIS
 *      rotation, scaling, color, tate mode are supported
 */
BOOL PutWinTTChar(V_JFM *vjfm, int code, int height, int x_pos, 
	int y_pos, int y_off, struct PREAMBLE_REC *preamble, char *name)
{
	static HFONT hFont, hOldFont;
	static V_JFM *old_vjfm;
	static char old_ptex_d, f_unicode;
	static int code_page;

#ifdef	KEEP_HDC
	static char *old_t_name;
#endif
	int mode, h_code, l_code, tmp, f_color, xx, yy, zz; 
	double scale, rad;
	char *t_name, out_char[4], out_uchar[4], *s, *t, *u;
	unsigned short *outs;
	SIZE size;
	int angle, f_rot, attr;

	if(vjfm == NULL){		/* Reset the definition of TrueType setting */
		if(hFont != NULL && hDCP != NULL){
			SelectObject( hDCP, hOldFont );
			DeleteObject( hFont );
			hFont = NULL;
		}
		return TRUE;
	}
	switch(get_rot_matrix(-2)){
		case 0:		/* identity matrix */
			f_rot = angle = 0;
			break;
		case 4:		/* only shift */
			f_rot = 4;
			angle = 0;
			break;
		case 1:		/* diagonal matrix but not identity */
			xx = get_rot_matrix(1);
			yy = get_rot_matrix(2);
			if(xx > 0 && yy > 0){
				f_rot = 2;
				angle = 0;
				break;
			}
		default:	/* otherwise => check if only rotation */
			angle = -get_rot_matrix(-1);
			if(angle <= -3600)	/* Not only rotations */
				return FALSE;
			f_rot = 1;
			break;
	}
	if(  vjfm->mat.eM11.fract != vjfm->mat.eM22.fract
	  || vjfm->mat.eM11.value != vjfm->mat.eM22.value
	  || XDiv != YDiv )
		f_rot |= 4;
	if( f_rot == 5 || vjfm->slant != 'a' /* || vjfm->thin != 0 */ )
		return FALSE;

		/* change color */
	f_color = (f_ccolor <= 0)?0:(f_ccolor & 0xffffff);
	if(f_color != colorTT){
		colorTT = f_color;
		SetTextColor(hDCP, 
			RGB((colorTT>>16), (colorTT>>8)&0xff, colorTT&0xff));
	}
	t_name = (vjfm == v_tfm)?
		check_ftt(name):(vfont[vjfm->font_no]->v_font_name + 1);
	scale = (((double)(vjfm->mat.eM22.value*65536 + vjfm->mat.eM22.fract))
				*height/(YDiv*65536));
	if(f_rot & 2)
		scale = scale*get_rot_matrix(ptex_d?1:2)/10000;
	height = (int)(scale + 0.5);
#if	KEEP_HDC
	if(  lf2.lfHeight == -height
		&& old_t_name == t_name
		&& old_vjfm == vjfm
		&& !(f_rot & 3)
		&& (ptex_d == old_ptex_d))
			goto same;
	if(hFont != NULL){
		SelectObject( hDCP, hOldFont );
		DeleteObject( hFont );
	}
	old_t_name = t_name;
#endif
	old_vjfm = vjfm;
	old_ptex_d = ptex_d;
	for(attr = 0; t_name[attr] && t_name[attr] != '/' && attr<32; attr++){
			if((lf2.lfFaceName[attr] = t_name[attr]) & 0x80){
				attr++;
				lf2.lfFaceName[attr] = t_name[attr];
			}
	}
	lf2.lfFaceName[attr] = 0;
							// フォント書体名。32文字以下。

	lf2.lfHeight = -height; 		  // フォントの高さ
	lf2.lfWeight = strchr(s = t_name + attr, 'B')?700:0;
			// フォントの太さ（標準400, 太字700, 0=デフォルト）
	t = strchr(s, '(');
	if(strchr(s, 'C')){
		f_unicode = 1;
		if( (u = strchr(s, '[')) != NULL ){
			code_page = atoi(u+1);
			if(code_page == CID)
				code = CID2Uni(code);
		}else
			code_page = -1;
		lf2.lfCharSet = (t)? atoi(t+1):0;
	}else{
		f_unicode = 0;
		if(!t)
			lf2.lfCharSet = (code < 0x1000)?ANSI_CHARSET:SHIFTJIS_CHARSET;
		else
			lf2.lfCharSet = atoi(t+1);
	}											// 文字セット

	lf2.lfEscapement = angle - vjfm->rotation*900;
	if(ptex_d && !vjfm->rotation)
		lf2.lfEscapement -= 900;
	else if(*t_name == '@' && !ptex_d)
		lf2.lfEscapement += 900;
	lf2.lfItalic = strchr(s, 'I')?TRUE:FALSE;	// 斜体フォント
	lf2.lfUnderline = strchr(s, 'U')?TRUE:FALSE;
	lf2.lfStrikeOut = strchr(s, 'O')?TRUE:FALSE;
	if((hFont = CreateFontIndirect( &lf2 )) == NULL)
		return 0;

	hOldFont = SelectObject( hDCP, hFont );
	if(f_rot & 6)		/* no rotation but changing aspect ratio */
	{
		TEXTMETRIC	tm;

		GetTextMetrics(hDCP, &tm);
		scale = ptex_d?
				((double)tm.tmAveCharWidth*YDiv*get_rot_matrix(2)*
				(vjfm->mat.eM11.value*65536 + vjfm->mat.eM11.fract)/
				((double)XDiv*get_rot_matrix(1)
				*(vjfm->mat.eM22.value*65536 + vjfm->mat.eM22.fract))):
				((double)tm.tmAveCharWidth*XDiv*get_rot_matrix(1)*
				(vjfm->mat.eM11.value*65536+ vjfm->mat.eM11.fract)/
				((double)YDiv*get_rot_matrix(2)
				*(vjfm->mat.eM22.value*65536 + vjfm->mat.eM22.fract)));
		lf2.lfWidth  = (int)(scale + .5);
		SelectObject( hDCP, hOldFont );
		DeleteObject( hFont );
		if((hFont = CreateFontIndirect( &lf2 )) == NULL)
			return 0;
		hOldFont = SelectObject( hDCP, hFont );
		lf2.lfWidth = 0;
	}
same:
		/* change code for Europian fonts */
	if(!f_unicode && (code <= 0x20 || code == 0x7f)){
		mode=(code == 0x7f)?0x21:code;
		switch(vjfm->thin){
			case 0: code = bakoma[mode];
					break;
			case 1: code = wintex[mode];
					break;
		}
	}
	mode = 0;
	out_uchar[0] = l_code = code & 0xff;
	if((out_uchar[1] = h_code = code >> 8) != 0){
		jis2sjis(&h_code, &l_code);
		out_char[mode++] = h_code;
	}
	out_char[mode++] = l_code;
	out_uchar[2] = out_uchar[3] = out_char[mode] = out_char[mode+1] = 0;
	if(f_unicode){
		outs = (code_page >= 0)?ToUniCode(code_page, out_char)
			:(unsigned short *)out_uchar;
		if(!GetTextExtentPoint32W(hDCP, outs, 2, &size))
			goto nonuni;
	}else
nonuni:	GetTextExtentPoint32(hDCP, out_char, 2, &size);
	if(f_rot)
		rotate_address(&x_pos, &y_pos);
	if(mode == 2){
		zz = preamble->tfm_width;
		if(f_rot & 2){
			if(ptex_d)
				zz = (double)zz*yy/10000;
			else
				zz = (double)zz*xx/10000;
		}
		tmp = size.cx*((ptex_d)?YDiv:XDiv) - sptopixel(zz);
//		error(C_MSG, "(%d), %d %d %d %x\n", f_unicode, code_page, tmp, size.cx, code);
		if(code_page < 0)
			tmp /= 2;
		else if (code <= 0x2125	/* 、。，．゛゜°′″*/
			|| (code <= 0x212c && code >= 0x212b)
			|| (code >= 0x216b && code <= 0x216d)) {
				tmp = 0;
		}
		else if (code <= 0x215b && code >= 0x2146) {
			if (code & 1)
				tmp = 0;		/* カッコ閉じ */
		}
		else
			tmp /= 2;
		if(f_unicode)	/* This is necessary becase size.cx is too big. Why ? */
			tmp = 0;
		if(angle)
			rad = 3.141592*angle/1800;
		if(ptex_d){
			if(vjfm->rotation || *t_name == '@'){
				zz = size.cy*XDiv*7/20;	// size.cy : haba
				if(angle){
					x_pos -= zz*cos(rad);
					y_pos += zz*sin(rad);
				}
				else
					x_pos -= zz;		
			}
			if(angle){
				x_pos -= tmp*sin(rad);
				y_pos -= tmp*cos(rad);
			}else
				y_pos -= tmp;
		}else{
			if(*t_name == '@')
				y_pos += size.cy*XDiv*7/20; 
			if(angle){
				x_pos -= tmp*cos(rad);
				y_pos += tmp*sin(rad);
			}else
				x_pos -= tmp;
		}
	}
	x_pos += ((ptex_d)?(-vjfm->_yfat):vjfm->_xfat) *height*XDiv/1000;
	y_pos += ((ptex_d)?vjfm->_xfat:(vjfm->_yfat-y_off)) *height*YDiv/1000;
/*
{ static int cc;

 if(!(cc++ & 15) )
	error(14, "([%x] %d %d:%d %d)", (unsigned short *)code, 
   x_pos/XDiv+HH, y_pos/YDiv+VV, f_unicode, code_page);
}
*/
	if(!f_unicode){
non_unicode:
		TextOut(hDCP, x_pos/XDiv+HH, y_pos/YDiv+VV, out_char, mode);
	}else /* unicode */
	{
		if( TextOutW(hDCP, x_pos/XDiv+HH, y_pos/YDiv+VV, outs, 1) == 0 )
		{
			int res;
			static int message_shown = FALSE;
			if( message_shown == FALSE )
			{
				if( (res = GetLastError()) == ERROR_CALL_NOT_IMPLEMENTED )
					error( WARNING, "The unicode version of TextOut() is\n"
									"not implemented in this OS." );
				else
					error( WARNING, "The OS returns the error code %d", res );
				message_shown = TRUE;
			}
			goto non_unicode;
		}
	}

#if	!KEEP_HDC
	SelectObject( hDCP, hOldFont );
	DeleteObject( hFont );
#endif
	if(f_rot & 3)
		lf2.lfHeight = 0;
	return TRUE;
}

/*
 *	line (x1, y1) - (x2, y2) with a given thickness
 *  (This is called by tpic specials)
 *      scaling, color and rotation are supported
 */
void WriteTTRule(int x1, int y1, int x2, int y2, int thick)
{
#define	MAX_THICK	4
	int f_color, tmp, xthick, ythick, f_rot, x_pos, y_pos;
	double scale;
	HPEN aPen, oldPen;
	POINT pt;
	POINT PointArray[4];
	HBRUSH hbr;
	HRGN region;

	f_color = (f_ccolor <= 0)?0:(f_ccolor & 0xffffff);
	f_color = RGB(f_color>>16, f_ccolor>>8, f_ccolor&0xff);
	if(f_color == 0xffffff)
		f_color = 0xfefefe;
	if(x1 > x2){
		tmp = x1;
		x1 = x2;
		x2 = tmp;
		tmp = y1;
		y1 = y2;
		y2 = tmp;
	}
	if(thick <= (MAX_THICK-1)*XDiv){
		thick /= XDiv;
		if(thick == 0)
			thick = 1;
pen:	if(y2 > y1){
			if(x2 - x1 > y2 - y1)
				x2++;
			else
				y2++;
		}else{
			if(x2 - x1 > y1 - y2)
				x2++;
			else
				y2--;
		}
		aPen = CreatePen(PS_SOLID, thick, f_color);
		oldPen = SelectObject(hDCP, aPen);

		if(get_rot_matrix(-2))
			rotate_address(&x1, &y1);
		MoveToEx(hDCP, x1/XDiv + HH, y1/YDiv + VV, &pt );
		if(get_rot_matrix(-2))
			rotate_address(&x2, &y2);
		LineTo(hDCP, x2/XDiv + HH, y2/YDiv + VV);
		SelectObject(hDCP, oldPen);
		DeleteObject(aPen);
	}else{
		if(f_color == 0)
			hbr = GetStockObject(BLACK_BRUSH);
		else if(f_color == 0xfefefe)
			hbr = GetStockObject(WHITE_BRUSH);
		else
			hbr = CreateSolidBrush(f_color);

		xthick = y1 - y2;
		if(xthick > 0)
			xthick++;
		else
			xthick--;
		ythick = x2 - x1 + 1;
		scale = xthick*xthick + ythick*ythick;
		if(scale == 0)
			goto pen;
		scale = (double)thick/sqrt(scale);
		xthick = (xthick>0)?ceil(xthick*scale):-ceil(-xthick*scale);
		ythick = ceil(ythick*scale);

		f_rot = get_rot_matrix(-2);

		x_pos = x1 - xthick/2;
		y_pos = y1 - ythick/2;
		if(f_rot)
			rotate_address(&x_pos, &y_pos);
		PointArray[0].x = x_pos/XDiv+HH;
		PointArray[0].y = y_pos/YDiv+VV;

		x_pos = x2 - xthick/2;
		y_pos = y2 - ythick/2;
		if(f_rot)
			rotate_address(&x_pos, &y_pos);
		rotate_address(&x_pos, &y_pos);
		PointArray[3].x = x_pos/XDiv+HH;
		PointArray[3].y = y_pos/YDiv+VV;

		xthick -= xthick/2;
		ythick -= ythick/2;

		x_pos = x1 + xthick;
		y_pos = y1 + ythick;
		if(f_rot)
			rotate_address(&x_pos, &y_pos);
		PointArray[1].x = x_pos/XDiv+HH;
		PointArray[1].y = y_pos/YDiv+VV;

		x_pos = x2 + xthick;
		y_pos = y2 + ythick;
		if(f_rot)
			rotate_address(&x_pos, &y_pos);
		PointArray[2].x = x_pos/XDiv+HH;
		PointArray[2].y = y_pos/YDiv+VV;

		region = CreatePolygonRgn(PointArray, 4, WINDING);
		FillRgn(hDCP, region, hbr);
		DeleteObject(region);
		if(f_color != 0 && f_color != 0xfefefe)
			DeleteObject(hbr);

	}
}

/*
 *	make the box (h,v) - (h+b-1, v+a-1)
 *  (This is called by box in a usual TEX -- underline etc)
 *    color, scaling and rotation are supported
 *    if pat != 0, erace the box area and the current color is ignored
 */
BOOL WinWriteRule(int h, int v, int b, int a, int pat)
{
#define	MAX_THICK	4
	RECT rect;
	HBRUSH hbr;
	HRGN region;
	int x_pos, y_pos;
	POINT PointArray[4];
	POINT pt;
	int f_color;
	int hd, vd, bd, ad, i;
	HPEN aPen, oldPen;

	f_color = f_ccolor & 0xffffff;
	if(f_ccolor < 0 || f_color == 0)
		f_color = (pat)?0:0xfffffff;
	else
		f_color = RGB(f_color>>16, f_ccolor>>8, f_ccolor&0xff);
	if(f_color == 0xffffff)
		f_color = 0xfefefe;
	hd = h/XDiv + HH;
	vd = v/YDiv + VV;
	if(!(ad = (a+YDiv-1)/YDiv))
		ad = 1;
	if(!(bd = (b+XDiv-1)/XDiv))
		bd = 1;
					/* fill box (hd, vd) - (hd+bd-1, vd+ad-1) */

	if(!get_rot_matrix(-2)){
		aPen = CreatePen(PS_SOLID, 1, f_color);
		oldPen = SelectObject(hDCP, aPen);
		if(ad <= bd){		/* horizontal line */
			for(i=vd+ad-1; i>=vd; i--){
				MoveToEx(hDCP, hd, i, &pt );
				LineTo(hDCP, hd + bd, i);
			}
		}else{				/* vertical line */
			for(i=hd+bd-1; i>=hd;i--){
				MoveToEx(hDCP, i, vd, &pt );
				LineTo(hDCP, i, vd + ad);
			}
		}
endpen:	
		SelectObject(hDCP, oldPen);
		DeleteObject(aPen);
		return TRUE;
	}
	if(ad<MAX_THICK){			/* horizontal line */
		aPen = CreatePen(PS_SOLID, ad, f_color);
		oldPen = SelectObject(hDCP, aPen);
		x_pos = h;
		y_pos = v + (a>>1);
		rotate_address(&x_pos, &y_pos);
		MoveToEx(hDCP, x_pos/XDiv + HH, y_pos/YDiv + VV, &pt );
		x_pos = h + b - 1;
		y_pos = v + (a>>1);
		rotate_address(&x_pos, &y_pos);
		LineTo(hDCP, x_pos/XDiv + HH, y_pos/YDiv + VV);
		goto endpen;
	}else if(bd<MAX_THICK){		/* vertical line */
		aPen = CreatePen(PS_SOLID, bd, f_color);
		oldPen = SelectObject(hDCP, aPen);
		x_pos = h + (b>>1);
		y_pos = v;
		rotate_address(&x_pos, &y_pos);
		MoveToEx(hDCP, x_pos/XDiv + HH, y_pos/YDiv + VV, &pt );
		x_pos = h + (b>>1);
		y_pos = v + a - 1;
		rotate_address(&x_pos, &y_pos);
		LineTo(hDCP, x_pos/XDiv + HH, y_pos/YDiv + VV);
		goto endpen;
	}
	if(f_color == 0)
		hbr = GetStockObject(BLACK_BRUSH);
	else if(f_color == 0xfefefe)
		hbr = GetStockObject(WHITE_BRUSH);
	else
		hbr = CreateSolidBrush(f_color);
	rect.left = h;
	rect.right = h+b-1;
	rect.top = v;
	rect.bottom = v+a-1;

	x_pos = rect.left;
	y_pos = rect.top;
	rotate_address(&x_pos, &y_pos);
	PointArray[0].x = x_pos/XDiv+HH;
	PointArray[0].y = y_pos/YDiv+VV;

	x_pos = rect.left;
	y_pos = rect.bottom;
	rotate_address(&x_pos, &y_pos);
	PointArray[1].x = x_pos/XDiv+HH;
	PointArray[1].y = y_pos/YDiv+VV;

	x_pos = rect.right;
	y_pos = rect.bottom;
	rotate_address(&x_pos, &y_pos);
	PointArray[2].x = x_pos/XDiv+HH;
	PointArray[2].y = y_pos/YDiv+VV;

	x_pos = rect.right;
	y_pos = rect.top;
	rotate_address(&x_pos, &y_pos);
	PointArray[3].x = x_pos/XDiv+HH;
	PointArray[3].y = y_pos/YDiv+VV;
	region = CreatePolygonRgn(PointArray, 4, WINDING);
	FillRgn(hDCP, region, hbr);
	DeleteObject(region);
	if(f_color != 0 && f_color != 0xfefefe)
		DeleteObject(hbr);
	return TRUE;
}

/*
 *	Output BMP/EMS/WMF stored in a given format
 *	(This is for characters except normal shaped TrueType, images etc)
 *		scaling are supported
 */
void TTBMPOut(int count)
{
	int x_pos, y_pos, x_size, y_size, type;
	int x_cutsize, y_cutsize, x_cut1, y_cut1, x_org, y_org, f_and, ws, hs;
	int x_cut1o;
	BYTE *pBMP;

	type = 0;
	pBMP = (BYTE *)GetBMPdata(count++, &x_pos, &y_pos, 
		&x_size, &y_size, &type);
	if(pBMP == NULL)
		return;

	x_pos = x_pos/XDiv + HH;
	y_pos = y_pos/YDiv + VV;
	x_size /= XDiv;
	y_size /= YDiv;
#ifdef	WMF
	if(type == F_WMF || type == F_EMF){
		DisplayMetaFile(hDCP, pBMP, x_pos, y_pos, x_size, y_size, type);
		return;
	}
#endif
	x_org    = GetDibWidth( pBMP );
	y_org    = GetDibHeight( pBMP );

	x_cut1   = - x_pos;
	if(x_cut1 < 0)
		x_cut1 = 0;
	y_cut1 = - y_pos;
	if(y_cut1 < 0)
		y_cut1 = 0;
	if(  (x_cutsize = x_size - x_cut1) <= 0
		|| (y_cutsize = y_size - y_cut1) <= 0)
		return;
	ws = x_org*x_cutsize/x_size;
	hs = y_org*y_cutsize/y_size;
	x_cut1o = x_cut1*x_org/x_size;
	if(ws + x_cut1o > x_org)
		ws = x_org - x_org;
	if(hs > y_org)
		hs = y_org;
	f_and = (type==1)?SRCCOPY:((type>-3)?SRCAND:SRCPAINT);
	PrintKeepBMP(hDCP, hMemDC, pBMP, type, f_and,
		x_pos + x_cut1,	y_pos + y_cut1, x_cutsize, y_cutsize,
		x_cut1o, 0, ws, hs, y_org);
}

/*
 *	Output bitmap_buf by DIB format cutting by the BoundingBox
 *	(This is called by the shading under tpic special)
 *		scaling and color are supported
 *      mode 0: merge (SRCAND)
 *		     1: erace (OR (NOT SRC)), the current color is ignored
 */
void PrintBitmapBuf(int mode)
{
	BYTE* pDib;
	BYTE* s;
	RECT bx;
	int x_pos, y_pos, x_org, y_org, x_cut1, y_cut1;
	int f_color;

	GetBoundingBox((BYTE*)(bitmap_buf_pointer->start),
		GetTextXSize(), (GetBufXSize() + 7)/8, GetTextYSize(), &bx);

	x_pos = bx.left + HH*XDiv;
	if((x_cut1 = -x_pos) < 0)
		x_cut1 = 0;
	y_pos = bx.top + VV*YDiv;
	if((y_cut1 = -y_pos) < 0)
		y_cut1 = 0;

	if((pDib = GetWindowBMP( bx.left, bx.top, 
		bx.right - bx.left + 1, bx.bottom - bx.top + 1, 1, 1, NULL )) == NULL)
			return;
	pDib += sizeof(BITMAPFILEHEADER);
	x_org = GetDibWidth( pDib );
	y_org = GetDibHeight( pDib );
	if(x_org <= x_cut1 || y_org <= y_cut1)
		return;
	s = pDib + sizeof(BITMAPINFOHEADER);
	if(mode){
		if(SetGamma(0)<0){
			s[0] = s[1] = s[2] = 0xff;
			s[4] = s[5] = s[6] = 0;
		}else{
			s[0] = s[1] = s[2] = 0;
			s[4] = s[5] = s[6] = 0xff;
		}
	}else{
		f_color = (f_ccolor <= 0)?0:(f_ccolor & 0xffffff);
		s[4] =  f_color & 0xff;
		s[5] = (f_color >> 8) & 0xff;
		s[6] = (f_color >> 16) & 0xff;
	}
	if(SetGamma(0) < 0)
		mode = !mode;
	PrintKeepBMP(hDCP, hMemDC, pDib, 0, (!mode)?SRCAND:SRCPAINT,
		(x_pos + x_cut1)/XDiv, (y_pos + y_cut1)/YDiv, 
		(x_org - x_cut1)/XDiv, (y_org - y_cut1)/YDiv,
		 x_cut1, 0, x_org - x_cut1, y_org - y_cut1, y_org);
	free_bmp(pDib - sizeof(BITMAPFILEHEADER));
}
#endif
