/*
 *  TEX Device Driver  ver 2.02-
 *  (c)copyright 1988, 1989 by TSG, 1990-93 by SHIMA
 *
 *  bitmap.c : to write characters and rules on bitmap buffer
 *             2nd edition
 *             2 January 1992 : modified for tpic by Oh-Yeah?
 *             22 July 1992 : modified for pTeX by Naochan!.
 */

#include <stdio.h>
#include <stdlib.h>

#include "dd.h"
#include "err.h"
#ifdef	WIN32G
#include "inter.h"
#ifdef MSVC
#include <memory.h>
#else
#include <mem.h>
#endif
#endif

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

/* bitblt.c */
extern void (*bitblt) (BUFFER *source_byte, int s_linewidth_byte,
					   int s_width_bit, int s_height_bit, BUFFER *dest_byte,
					   int d_linewidth_byte, int d_offset_x_bit,
					   int d_offset_y_bit);

#ifndef NOTPIC
void alter_bitblt_ow(BOOL flag);
#endif

/* size.c, prtsize.c */
PIXEL sptopixel(SCALED_PT);
PIXEL vtopixel(SCALED_PT);

static BUFFER *map_top_ptr;

/* pret.c */
#ifdef	HYPERTEX
void add_hyper_box(PIXEL x, PIXEL y, PIXEL width, PIXEL h, PIXEL d);
#endif

/*  bitmap のポインタ */
static PIXEL vmax, hmax, hmaxb, vmin, hmin;
BOOL draw_baseline = 0;
BOOL draw_boxpic = 0;
extern char ptex_d;
void bitmap_init(OUTPUT_INFO *out);
void bitmap_fill(uchar ch);

void boxpic(PIXEL h, PIXEL v, PIXEL w, PIXEL d);

void write_font(PIXEL h, PIXEL v, PREAMBLE *pxl);
void write_rule(PIXEL h, PIXEL v, PIXEL a, PIXEL b);

#ifndef NOTPIC
void init_tile(double grayscale);	/* initialize overriding for tiles */
void fin_tile(void);	/* finish tiling. recover original data */
void write_tile(PIXEL h, PIXEL v, PIXEL a, PIXEL b);
static void set_tile(double grayscale);
static void adjust_tile(PIXEL h, PIXEL v);	/* adjust pattern by (h, v) position */

#ifdef VFTPIC
/* called by draw_character() in vfont.c */
void init_alter_bitmap(BUFFER *dest, PIXEL d_linewidth_byte);
void fin_alter_bitmap(void);

#endif
#ifndef NOTPIC_EXTENSION
/* called by alter_bitblt_rt() in bitblt.c */
typedef struct {
	PIXEL x, y;
} pixelpoint;

pixelpoint turn_off_trimming(void);
void turn_on_trimming(void);

#endif
#endif

#ifdef	STR_SEARCH
extern uint n_found_pt;
#endif

#ifdef	WIN32G
extern int f_ccolor;
int get_rot_matrix(int);
#define	COLOR_ROT_SIZE	40
#endif

const uchar REV[256] =		/* MSB ... LSB  ->  LSB ... MSB */
{
	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};

BUFFER *rotate_raster(PREAMBLE *preamble);

void bitmap_init(OUTPUT_INFO *out)
	/*  変数のイニシャライズ  */
{
	extern PIXEL vmax, hmax, hmaxb, vmin, hmin;

	ENTER("bitmap_init");

	map_top_ptr = (BUFFER *)out->bitmap_ptr;
	hmax = out->width;
	vmax = out->height;
	vmin = hmin = 0;
	hmaxb = out->byte_width;

	END();
}

void bitmap_fill(uchar ch)
{
	memset(bitmap_buf_pointer->start, ch, bitmap_buf_pointer->size);
}

#define  WIDTH_OF_LINE  26214L	/* 線の太さ: 26214(scaled point) = 0.4pt */

void boxpic(PIXEL h, PIXEL v, PIXEL w, PIXEL d)
	/* 文字の代わりに「箱」で組版するための関数 （「白い箱」版 rput） */
{
	PIXEL w_h, w_v;

	w_h = vtopixel(WIDTH_OF_LINE);	/* 横線の太さ */
	if(!w_h) w_h = 1;
	w_v = sptopixel(WIDTH_OF_LINE);	/* 縦線の太さ */
	if(!w_v) w_v  =1;

	write_rule(h, v + (w_h - 1), w_h, w);	/* 横線 (上) */
	write_rule(h, v + d - 1, w_h, w);	/* 横線 (下) */
	write_rule(h, v + d - 1, d, w_v);	/* 縦線 (左) */
	write_rule(h + w - w_v, v + d - 1, d, w_v);	/* 縦線 (右) */
}

#if	defined(STR_SEARCH) || defined(HYPERTEX)

struct S_BOX *s_box;
int	s_box_pt;
static int s_box_max;
/*
 *   s_box will be expanded by the current box.
 *   If the box is in the same block of the former one and
 *      the baseline doesn't change together with TATE/YOKO mode, 
 *   then the box is connected to the former one to make one box.
 */
static void define_box(PIXEL x, PIXEL y, PIXEL width, PIXEL h, PIXEL d)
{
	int i;
	struct S_BOX *tmp;
	struct S_BOX *box;

	if(s_box_pt >= s_box_max){
		s_box_max += 0x100;
		tmp = (struct S_BOX *)marea((s_box_max+1) * sizeof(struct S_BOX));
		if(s_box_pt > 0){
			memcpy(tmp, s_box, s_box_pt*sizeof(struct S_BOX));
			Free(s_box);
			s_box = tmp;
		}else{
			s_box = tmp;
			goto new;
		}
		for(i = s_box_pt; i < s_box_max; i++)
			s_box[i].sub.found = 0;
	}
	box = &(s_box[s_box_pt-1]);
	if(box->sub.found == n_found_pt &&  box->dir == ptex_d){
		if(ptex_d){
			if(box->base != x)
				goto new;
			if(box->x0 > h)
				box->x0 = h;
			if(box->x1 < d)
				box->x1 = d;
			if(box->y0 > y)
				box->y0 = y;
			if(box->y1 < y + width)
				box->y1 = y + width;
		}else{
			if(box->base != y)
				goto new;
			if(box->y0 > h)
				box->y0 = h;
			if(box->y1 < d)
				box->y1 = d;
			if(box->x0 > x)
				box->x0 = x;
			if(box->x1 < x + width)
				box->x1 = x + width;
		}
	}else{
new:	box = &(s_box[s_box_pt++]);
		box->sub.found = n_found_pt;
		if((box->dir = ptex_d) == 1){
			box->base = x;
			box->x0 = h;
			box->x1 = d;
			box->y0 = y;
			box->y1 = y + width;
		}else{
			box->base = y;
			box->y0 = h;
			box->y1 = d;
			box->x0 = x;
			box->x1 = x + width;
		}
	}
}
#endif

static
int f_shift_EMS;

void write_font(PIXEL h0, PIXEL v0, PREAMBLE *pxl)
	/* キャラクターの書き込み */
	/* pTeX の「90度回転書き込み」に対応  by Naochan! 18 July 1992 */
{
	PIXEL h, v, he, ve;	/* end points */
	PIXEL haba, takasa;
	int byte_width;
	BUFFER *raster;

	haba = pxl->width;
	takasa = pxl->height;
	raster = pxl->raster;
	f_shift_EMS = pxl->shift_up_ptex;

	if (ptex_d == 1) {		/* 縦書きの場合 */
								/* 文字を右・上方向に補正 */
		v = v0 - pxl->pitch_offset - pxl->shift_up_ptex;
		h = h0 + pxl->depth_offset + pxl->shift_right_ptex;
		h -= ((pxl->rotate_ptex & 1)?takasa:haba);
rot:	if (pxl->rotate_ptex & 1) {	/* 文字を90度回転 */
			haba = takasa;
			takasa = pxl->width;
			raster = rotate_raster(pxl);
		}
		byte_width = (haba + 7) / 8;
	}else if(pxl->rotate_ptex & 4){		/* 横書きで縦書きフォン使用 */
		h = h0 - pxl->pitch_offset - pxl->shift_up_ptex;
		v = v0 - pxl->depth_offset - pxl->shift_right_ptex;
		goto rot;
	}
	else {
		h = h0 - pxl->pitch_offset;
		v = v0 - pxl->depth_offset;
		byte_width = pxl->byte_width;
	}

	if (v < vmax && h < hmax
		&& (he = h + haba) > hmin && (ve = v + takasa) > vmin) {
		/* キャラクターの１部でも表示範囲にはいったら... */

		if (he > hmax)
			he = hmax;			/* right trimmed */
		if (ve > vmax)
			ve = vmax;			/* bottom trimmed */

		if (draw_boxpic != 0) {
			v += (f_shift_EMS & 0x3fff);
			if ((he = h + haba - pxl->shift_right_ptex) > hmax)
				he = hmax;
			boxpic(h, v, he - h, ve - v);
		}
		else{
			bitblt((BUFFER*)raster, byte_width, he - h, ve - v, map_top_ptr, 
				hmaxb, h, v);		/* left and top will be trimmed */
#if	defined(STR_SEARCH)||defined(HYPERTEX)
			if(
# ifdef STR_SEARCH
				(n_found_pt & 1)
# endif
# if defined(STR_SEARCH) && defined(HYPERTEX)
				||
# endif
# ifdef	HYPERTEX
				(f_hyper & F_H_BOX)
# endif
				){
				if ((he = h + haba - pxl->shift_right_ptex) > hmax)
					he = hmax;
#ifdef	STR_SEARCH
				if(n_found_pt & 1){
					if(ptex_d == 1)
						define_box(h0, v0, vtopixel(pxl->tfm_width), h, he);
					else
						define_box(h0, v0, sptopixel(pxl->tfm_width), v, ve);
				}
#endif
#ifdef	HYPERTEX
				if(f_hyper & F_H_BOX){
					if(ptex_d == 1)
						add_hyper_box(h0, v0, vtopixel(pxl->tfm_width), h, he);
					else
						add_hyper_box(h0, v0, sptopixel(pxl->tfm_width),v, ve);
				}
			}
#endif
#endif
		}
	}
	if(raster != pxl->raster && raster != common_work)
		Free(raster);			/* by big rotate_raster */
}

#define LINE_LEN 64
#define ONEBYTE  8
static uchar box_data[LINE_LEN+2] =
{
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff
};	/* black */

/* used for overriding write_rule() by write_tile() for tpic */
static BUFFER *tile_ptr = (BUFFER *)box_data;
static int tile_width_bit = LINE_LEN * ONEBYTE;	/* pattern width */
static int tile_inc_byte = 0;
/* increment = 0; use same pattern repeatedly */
static int tile_height_bit = 30000;	/* actually infinite */

void write_rule(PIXEL h, PIXEL v, PIXEL a, PIXEL b)
	/*  長方形の書き込み */
{
	PIXEL he, ve;	/* end points */
	PIXEL hs, hspan, hrep, hres, vspan, vrep, vres, i;
	PIXEL push_w, push_h;
	BOOL  f_push;
	ENTER("write_rule");

	if (a >= 0)
		v -= a - 1;
	else
		a = -a;

	if (b < 0) {
		b = -b;
		h -= b - 1;				/* (h, v) = rule's top-left point */
	}
#ifdef	WIN32G
	if(f_ttout && tile_height_bit == 30000
	  && WinWriteRule(h, v, b, a, *tile_ptr))
		return;
#endif
	if (v < vmax && h < hmax
		&& (he = h + b) > hmin && (ve = v + a) > vmin) {
		/* キャラクターの１部でも表示範囲にはいったら... */

		if (he > hmax)
			he = hmax;			/* right trimmed */
		if (ve > vmax)
			ve = vmax;			/* bottom trimmed */
		/* left and top will be trimmed in bitblt() */
#ifdef	WIN32G
		if(f_ccolor										 /* color */
		  && (f_push = get_rot_matrix(0)) != 0 && f_push != 1	/* rotation */
		  &&  tile_height_bit == 30000 ){
			push_w = tile_width_bit;
			push_h = tile_height_bit;
			tile_width_bit = tile_height_bit = COLOR_ROT_SIZE;
		}else
			f_push = 0;
#endif
		vrep = (vspan = ve - v) / tile_height_bit;
		vres = vspan % tile_height_bit;
		hrep = (hspan = he - h) / tile_width_bit;
		hres = hspan % tile_width_bit;
		hs = h;

		while (vrep-- > 0) {
			i = hrep;
			h = hs;
			while (i-- > 0) {
				bitblt(tile_ptr, tile_inc_byte, tile_width_bit,
					   tile_height_bit, map_top_ptr, hmaxb, h, v);
				h += tile_width_bit;
			}
			if (hres > 0)
				bitblt(tile_ptr, tile_inc_byte, hres,
					   tile_height_bit, map_top_ptr, hmaxb, h, v);
			v += tile_height_bit;
		}
		if (vres > 0) {
			i = hrep;
			h = hs;
			while (i-- > 0) {
				bitblt(tile_ptr, tile_inc_byte, tile_width_bit,
					   vres, map_top_ptr, hmaxb, h, v);
				h += tile_width_bit;
			}
			if (hres > 0)
				bitblt(tile_ptr, tile_inc_byte, hres,
					   vres, map_top_ptr, hmaxb, h, v);
		}
		if(f_push){
			tile_width_bit  = push_w;
			tile_height_bit = push_h;
		}
	}
end:
	END();
}

#ifndef NOPS
void write_pbm( PIXEL h, PIXEL v, PIXEL w, PIXEL d, char *raster )
	/*  portable bit map の書き込み */
{
	PIXEL he, ve; /* end points */
	int   byte_width;

	byte_width = ( w + 7 ) / 8;
	if ( v < vmax && h < hmax
		&& (he = h + w) > hmin && (ve = v + d) > vmin ){
		/* キャラクターの１部でも表示範囲にはいったら... */
		if (he > hmax) he = hmax; /* right trimmed */
		if (ve > vmax) ve = vmax; /* bottom trimmed */
		/* left and top will be trimmed in bitblt() */
		bitblt(raster, byte_width, he - h, ve - v, 
				map_top_ptr, hmaxb, h, v); /* left and top will be trimmed */
	}
}

# ifdef	TILE
void write_tiled_pbm(PIXEL h, PIXEL v, PIXEL w, PIXEL d, char *raster, int tl)
{
	int i, j;

	if (tl) {
	for(j=v; j<vmax; j+=d)
		for(i=h; i<hmax; i+=w)
		write_pbm(i, j, w, 1, raster);
	}
	else write_pbm(h, v, w, 1, raster);
}
# endif
#endif

/* end of file : bitmap.c */

/* additional functions for tpic */

#ifndef NOTPIC

/* tiling functions */

static BUFFER *temp_tile;	/* just for keeping 'em */
static int temp_width, temp_inc, temp_height;

void init_tile(double grayscale)
{	   /* initialize overriding for tiles */
	temp_tile = tile_ptr;		/* just keep 'em */
	temp_width = tile_width_bit;
	temp_inc = tile_inc_byte;
	temp_height = tile_height_bit;

	alter_bitblt_ow((grayscale <= 0) ? TRUE : FALSE);	/* if white, ow */
	set_tile(grayscale);
}

void fin_tile(void)
{	   /* finish tiling. recover original data */
	tile_ptr = temp_tile;		/* just recover 'em */
	tile_width_bit = temp_width;
	tile_inc_byte = temp_inc;
	tile_height_bit = temp_height;
	alter_bitblt_ow(FALSE);		/* no overwriting */
}

void write_tile(PIXEL h, PIXEL v, PIXEL a, PIXEL b)
{
	adjust_tile(h, v);			/* modify pattern by position, if necessary */
	write_rule(h, v, a, b);
}

#ifndef TPIC_SCATTERED

#define PATTERN_BIT  4	/* maximum = 4 */
#define MAX_PATTERN  10	/* maximum = PATTERN_BIT^2, including full black */

static uchar pattern[MAX_PATTERN - 1][PATTERN_BIT * 2] =
{
/* 4 x 4 patterns (except for full black). lower 4 bits and last 4 bytes
	are just repeated patterns for avoiding rotation of bits */

/* these are rational but too dark because of dots emphasized by printers */
/*		{0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00},
		{0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88},
		{0x00, 0xaa, 0x00, 0x88, 0x00, 0xaa, 0x00, 0x88},
		{0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa},
		{0x00, 0xaa, 0x44, 0xaa, 0x00, 0xaa, 0x44, 0xaa},
		{0x11, 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa},
		{0x44, 0xaa, 0x55, 0xaa, 0x44, 0xaa, 0x55, 0xaa},
		{0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa},
		{0xbb, 0x55, 0xaa, 0x55, 0xbb, 0x55, 0xaa, 0x55},
		{0xee, 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55},
		{0xff, 0x55, 0xbb, 0x55, 0xff, 0x55, 0xbb, 0x55},
		{0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55},
		{0xff, 0x55, 0xff, 0x77, 0xff, 0x55, 0xff, 0x77},
		{0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff, 0x77},
		{0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff} */

/* these are from trial-and-errors */
	{0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00},
	{0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88},
	{0x00, 0x22, 0x44, 0x00, 0x00, 0x22, 0x44, 0x00},
	{0x00, 0x66, 0x44, 0x00, 0x00, 0x66, 0x44, 0x00},
	{0x00, 0xaa, 0x00, 0x88, 0x00, 0xaa, 0x00, 0x88},
	{0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00},
	{0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa},
	{0x11, 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa},
	{0xee, 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55}
};

static uchar tile_data[PATTERN_BIT+2];	/* selected pattern for gray tiling */
static int black;	/* selected pattern number */

static void set_tile(double grayscale)
	/* set static parameters: tile_ptr, tile_width_bit, tile_inc_byte and
	tile_height_bit */
	/* gray image is realized by periodic pattern */
{
	static uchar white_data[LINE_LEN+2] =
	{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00
	};	/* white */
	static double max_pat_d = MAX_PATTERN * 1.01;
	/* against float calc err */

	ENTER("set_tile");

	black = (int)(grayscale * max_pat_d);
	if (black >= MAX_PATTERN) {	/* black, fill by append (OR) */
		tile_ptr = (BUFFER *)box_data;
		tile_width_bit = LINE_LEN * ONEBYTE;
		tile_inc_byte = 0;
		tile_height_bit = 30000;
	}
	else if (black <= 0) {		/* white, fill by overwrite (AND) */
		tile_ptr = (BUFFER *)white_data;
		tile_width_bit = LINE_LEN * ONEBYTE;
		tile_inc_byte = 0;
		tile_height_bit = 30000;
	}
	else {						/* gray pattern (4x4), fill by append (OR) */
		tile_ptr = (BUFFER *)tile_data;	/* actual pattern is not copied yet */
		tile_width_bit = PATTERN_BIT;
		tile_inc_byte = 1;
		tile_height_bit = PATTERN_BIT;
	}

	END();
}

static void adjust_tile(PIXEL h, PIXEL v)
{	   /* adjust pattern by (h, v) position */
	int i, n, rot_x, rot_y;

	ENTER("adjust_tile");

	if (black > 0 && black < MAX_PATTERN) {	/* gray. rotate pattern */
		rot_x = (unsigned)h % PATTERN_BIT;
		rot_y = (unsigned)v % PATTERN_BIT;
		/* mod for rotation by (h, v) position */
		/* Note: if h or v is negative, this works correctly only for
		PATTERN_BIT = 2, 4, 8 (e.g. -1, -2, -3, -4, -5 -> 3, 2, 1, 0, 3) */

		n = black - 1;
		for (i = 0; i < PATTERN_BIT; i++)
			tile_data[i] = (pattern[n][i + rot_y] << rot_x);
	}
	END();
}

#else /* if TPIC_SCATTERED is defined ..... */

void set_tile(double grayscale)
	/* set static parameters: tile_ptr, tile_width_bit, tile_inc_byte and
	tile_height_bit */
	/* gray image is realized by randomly scattered pattern */
{
	static uchar white_data[LINE_LEN+2] =
	{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00};	/* white */
	static uchar tile_data[LINE_LEN+2];
	int black, i, j;

	ENTER("set_tile");

	black = (int)(grayscale * ONEBYTE);
	if (black >= ONEBYTE) {		/* black, fill by append (OR) */
		tile_ptr = (BUFFER *)box_data;
		tile_width_bit = LINE_LEN * ONEBYTE;
		tile_inc_byte = 0;
		tile_height_bit = 30000;
	}
	else if (black <= 0) {		/* white, fill by overwrite (AND) */
		tile_ptr = (BUFFER *)white_data;
		tile_width_bit = LINE_LEN * ONEBYTE;
		tile_inc_byte = 0;
		tile_height_bit = 30000;
	}
	else {						/* gray (8x4), fill by append (OR) */
		tile_ptr = (BUFFER *)tile_data;
		tile_width_bit = LINE_LEN * ONEBYTE;
		tile_inc_byte = 0;
		tile_height_bit = 30000;

		for (i = 0; i < LINE_LEN; i++) {	/* randomly scattered pattern */
			tile_data[i] = 0;
			for (j = 0; j < ONEBYTE; j++)
				if (rand() % ONEBYTE < black)
					tile_data[i] |= (0x01 << j);
		}
	}
	

	END();
}

void adjust_tile(PIXEL dummy1, PIXEL dummy2)
{
	return;
}

#endif /* end of ifndef TPIC_SCATTERED ... else ... */

#ifdef VFTPIC

/* vector-font support functions */

static BUFFER *temp_map_top_ptr;	/* keepings for overriding dest bitmap */
static PIXEL temp_hmaxb;

void init_alter_bitmap(BUFFER *dest, PIXEL d_linewidth_byte)
{
	ENTER("init_alter_bitmap");
	temp_map_top_ptr = map_top_ptr;	/* keep 'em */
	temp_hmaxb = hmaxb;
	map_top_ptr = dest;
	hmaxb = d_linewidth_byte;
	END();
}

void fin_alter_bitmap(void)
{
	ENTER("fin_alter_bitmap");
	map_top_ptr = temp_map_top_ptr;	/* recover 'em */
	hmaxb = temp_hmaxb;
	END();
}

#endif /* end of ifdef VFTPIC */

#ifndef NOTPIC_EXTENSION

/* rotation routines */

#define MAX_PIXEL 32766	/* max value of type int */
static PIXEL temp_hmax, temp_vmax;
static BOOL is_trimming_on = TRUE;

pixelpoint turn_off_trimming(void)
{	   /* stop trimming and ret hmax and vmax */
	pixelpoint answer;

	ENTER("turn_off_trimming");
	if (is_trimming_on) { /* record max and turn off */
		temp_hmax = hmax;
		temp_vmax = vmax;
		hmax = vmax = MAX_PIXEL;
		hmin = vmin = -MAX_PIXEL;	/* minimum is always zero, not kept */
		is_trimming_on = FALSE;
	}
	answer.x = temp_hmax;
	answer.y = temp_vmax;
	RETURN(answer);
}

void turn_on_trimming(void)
{
	ENTER("turn_on_trimming");
	if (!is_trimming_on) {
		hmax = temp_hmax;
		vmax = temp_vmax;
		hmin = vmin = 0;
		is_trimming_on = TRUE;
	}
	END();
}

#endif /* end of ifndef NOTPIC_EXTENSION */

#endif /* end of ifndef NOTPIC */

/* end of all */

char common_work[COMMON_SIZE];

/* COMMON_SIZE =  2048 -> 128ドットのフォントまで回転可能 */
/* EMS         = 32768 -> 512ドットのフォントまで回転可能 */
/*  2048 = 128^2 / 8, 17 = 128 / 8 + 1
 * 32768 = 512^2 / 8, 65 = 512 / 8 + 1
 * 65536 : 724^2 / 8, 91 = 724 / 8 + 1
	   * 118dpi: 128×128 → 78.4pt
	   * 360dpi: 128×128 → 25.7pt
	   * 640dpi: 128×128 → 14.4pt
	   */

BUFFER *
	rotate_raster(PREAMBLE *preamble)
	/* ラスタのデータを90度回転させます。 by Naochan! */
{
	uchar work2[256];
	uchar *work0;
	BUFFER *new_raster;
	BUFFER *old_raster;
	uint old_height, old_byte_width;
	uint new_width, new_height, new_byte_width;
	uint ix, iy, is, bit, start, mask, leftshift;
	long r_size;
	uchar c;
	uint ci;
	uint y_width;

	new_height = preamble->width;
	new_width = old_height = preamble->height;
	old_byte_width = preamble->byte_width;
	new_byte_width = (new_width + 7) / 8;

	old_raster = preamble->raster;
	if ( (r_size = ((long)new_byte_width) * new_height) <= COMMON_SIZE
		&& new_byte_width <= 256 ){
		new_raster = common_work;
		work0 = work2;
	}else{
		new_raster = (BUFFER*)marea(r_size + new_byte_width + 10);
				/* this memory will be recoverd */
		work0 = new_raster + r_size;
	}	
	for (iy = 0; iy < new_height; iy++) {
		y_width = iy * new_byte_width;
		for (ix = 0; ix < new_byte_width; ix++) {
			if(preamble->rotate_ptex & 4){
				mask = 0x0080>>(is = (new_height - iy - 1)%8);
				start = ix*8*old_byte_width + (new_height - iy - 1)/8;
				c = 0;
				for (bit = 0; bit < 8; bit++, start += old_byte_width)
				c += (((old_raster[start] & mask) << is) >> bit);
				new_raster[y_width + ix] = c;
			}else{
				mask = 0x0080 >> (is = iy % 8);
				start = (old_height - ix * 8 - 1) * old_byte_width + iy / 8;
				c = 0;
				for (bit = 0; bit < 8; bit++, start -= old_byte_width)
					c += (((old_raster[start] & mask) << is) >> bit);
				new_raster[y_width + ix] = c;
			}
		}
	}
	if (preamble->rotate_ptex & 2) {	/* 文字を左右反転 */
		leftshift = (8 - (new_width % 8)) % 8;
/*		mask = ((leftshift == 0) ? 0 : (0x00FF >> (8 - leftshift))); */
		for (iy = 0; iy < new_height; iy++) {
			y_width = iy * new_byte_width;
			for (ix = 0; ix < new_byte_width; ix++) {
				work0[new_byte_width - ix - 1]
					= REV[new_raster[y_width + ix]];
			}
			for (ix = 0; ix < new_byte_width; ix++) {
				ci = ((uint)work0[ix] << 8) + work0[ix+1];
				new_raster[y_width + ix] = (ci >> (8 - leftshift)) & 0xff;
			}
		}
	}
	RETURN(new_raster);
}
