/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */

/* $Header:apa_fontblt.c 12.0$ */
/* $ACIS:apa_fontblt.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/apa_fontblt.c,v $ */

#ifndef lint
static char *rcsid = "$Header:apa_fontblt.c 12.0$";
#endif

#include "apasixteen.h"
#include "apaeight.h"
#include "apaeightc.h"
#if ((NAPAEIGHT > 0) || (NAPAEIGHTC > 0) || (NAPASIXTEEN > 0))

/* 
 * This file contains all the routines necessary to put any font into the hidden
 * area of a bitmap display.  Its used by the APA-8, APA-8C and APA-16 terminal
 * drivers.
 *
 * NOTE: fontblt() has not been tested with fonts over 16 bits wide.
 */

/* Used to test tty drivers outside of kernel. */
#define CONS_APA8	0
#define CONS_APA8C	1
#define CONS_APA16	2

#include "apa_structs.h"

/*
 * Array of short masks used to compute the masks to mask out the edges
 * of the destination that should not be affected.  A one means that bit
 * in the destination can be changed.  The values in left_mask_values are
 * set up to be used with the left edge and the values in right_mask_values
 * are to be used in right edge. 
 */
static unsigned short left_mask_values[] = {
		0xffff,0x7fff,0x3fff,0x1fff,0x0fff,0x07ff,0x03ff,0x01ff,
		0x00ff,0x007f,0x003f,0x001f,0x000f,0x0007,0x0003,0x0001,
		0x0000
};

static unsigned short right_mask_values[] = {
		0xffff,0x8000,0xc000,0xe000,0xf000,0xf800,0xfc00,0xfe00,
		0xff00,0xff80,0xffc0,0xffe0,0xfff0,0xfff8,0xfffc,0xfffe,
		0x0000
};

/*
 * defines used to indicate whether or not to read from the source.
 * NOTE: Changing the value of MUST_PRIME may have bad side
 *	 effects because the variable "preload_src" is added to something in
 *	 calculateOffsets.
 */
#define MUST_PRIME 1
#define DONT_PRIME 0

/*
 * Global variables needed to put a character into the hidden font area.
 */
static int dst_nextline, src_nextline;	/* Increment to the next scan line
					   in the bitmap. */

static int height;	/* height of the blt area (number of scanlines)  */
static short dst_plus;	/* amount to move the pointer forward to the next word.
			   on the APA8 or APA8C this is 2. */

static unsigned short *dst_base,	/* ptr to dst bitmap data */
		      *src_base;	/* ptr to src bitmap data */

static short src_x, src_y,	/* source origin */
	     dst_x, dst_y;	/* destination origin */

static short width;		/* transfer width in pixels     */
static short nshorts;		/* number of shorts to be changed in the
				   destination. */
static short preload_src;	/* If set to then must use 2 source words to
				   make 1 destination word */
static short skew_src;		/* shift amount to align src with dst   */
static unsigned short left_mask,right_mask; /* edge masks for dst */

init_copyfont(bblt)
register fontbltstruct *bblt;	/* original data */
{
	/*
	 * Set up X and Y coordinates and convert to zero based.
	 */
	dst_x = bblt->dst_rect.origin_x - bblt->dst_bitmap.rect.origin_x;
	dst_y = bblt->dst_rect.origin_y - bblt->dst_bitmap.rect.origin_y;

	/*
	 * Figure the width and height of the blt.
	 */ 
	height = (bblt->dst_rect.corner_y - bblt->dst_rect.origin_y);
	width = (bblt->dst_rect.corner_x - bblt->dst_rect.origin_x);

	/*
	 * Set up the number of words across the destination that will be
	 * affected.
	 */
	nshorts = DIV_BPW(dst_x + width - 1) - DIV_BPW(dst_x) + 1;

	/*
	 * Set up the source X and Y coordinates and convert to zero based.
	 */
	src_x = bblt->src_rect.origin_x - bblt->src_bitmap.rect.origin_x;
	src_y = bblt->src_rect.origin_y - bblt->src_bitmap.rect.origin_y;
}

/*
 * The general scheme of the copyBits loop is this:
 *	Foreach row do
 *		Take care of the first word priming if necessary. (Done because
 *			the first word uses the LEFT edge mask.)
 *
 *		For each word between the first and last word do
 *			Shift the source word and source word +1 and
 *				write the word to the destination.
 *		endfor
 *
 *		Take care of the last word. (Done here and not in 
 *			the loop because the last word uses the 
 *			RIGHT edge mask.)
 * 
 *		INCREMENT the source and destination pointers to point to the
 *			next row.
 *	endfor
 *
 */
copyfont()
{
	register short wordnum;
	register short inv_skew_src;

	inv_skew_src = BPW - skew_src;

	/*
	 * foreach scanline do.
	 */
	while (height--) {
		wordnum = nshorts;

		/*
		 * We may need 2 source words to make up the destination word
		 * (called "priming").
		 */
		if (preload_src) {
			*dst_base = (*dst_base & ~left_mask) |
				    (((*src_base << skew_src) | 
				    (*(src_base+1) >> (inv_skew_src))) &
				    left_mask);
			src_base++;
		}
		else {
			*dst_base = (*dst_base & ~left_mask) |
	       		            ((*src_base >> (inv_skew_src)) & left_mask);
		}

		/*
		 * If there is more than one destination word changed then 
		 * fill in those words too.
		 */
		if (--wordnum != 0) {
			/*
			 * Increment to the next word.
			 */
			dst_base += dst_plus;

			/*
			 * Copy all but the last word this way.  If there
			 * was no skew we could optimize.
			 */
	 	  	while (wordnum-- > 1) {
				*dst_base = (*src_base << skew_src) |
					    (*(src_base+1) >> (inv_skew_src));
				dst_base += dst_plus;
	               		src_base++;
			}

			/*
			 * The last word is special because we must
			 * use the right mask to protect bits that are
			 * not to be changed.
			 */
			*dst_base = (*dst_base & ~right_mask) |
				    (((*src_base << skew_src) |
				    (*(src_base+1) >> (inv_skew_src))) &
				    right_mask);
			src_base++;
		}

		/*
		 * Increment the source and destination pointer to the next
		 * scanline.
		 */
		src_base += src_nextline;
		dst_base += dst_nextline;
	}
}

unsigned short *
apa_fontblt(bblt,screen_flag)
register fontbltstruct *bblt;
register int screen_flag;	/* indicates which screen is calling
				   apa_fontblt. */
{
	unsigned short *char_addr; /* used to store the address of the char
				      put on the screen so it can be returned */

	/*
	 * Set up to do this blt.
	 */
	init_copyfont(bblt);

	/*
	 * Calculate the edge masks for the destination.
	 */
	left_mask = left_mask_values[MOD_BPW(dst_x)];
	right_mask = right_mask_values[MOD_BPW(dst_x+width)];
	if (nshorts == 1) {
		left_mask &= right_mask;
		right_mask = left_mask;
	}

	/*
	 * Calculate the shift amount (skew) that is needed to align
	 * a word in the source with a word in the destination.
	 */
	if ((MOD_BPW(dst_x)) < (MOD_BPW(src_x))) {
		skew_src = MOD_BPW(src_x) - MOD_BPW(dst_x);
		preload_src = MUST_PRIME;
	}
	else {
		skew_src = BPW - (MOD_BPW(dst_x) - MOD_BPW(src_x));
		preload_src = DONT_PRIME;
	}

	/*
	 * Set up the pointer to the source bitmap and set up the increment
	 * to the next scan line for the source bitmap.
	 */
	src_base = (unsigned short *)((long)bblt->src_bitmap.base +
			MUL_2((src_y * bblt->src_bitmap.nshorts) +
			DIV_BPW(src_x)));
	src_nextline = bblt->src_bitmap.nshorts - (nshorts + preload_src) + 1;

	/*
	 * Set up the pointer to the destination bitmap and set up the
	 * increment to the next scan line for the destination bitmap.
	 */
	if (screen_flag == CONS_APA8 || screen_flag == CONS_APA8C) {
		dst_plus = 2;
		dst_base = (unsigned short *)((long)bblt->dst_bitmap.base +
			      MUL_2(MUL_2((dst_y * bblt->dst_bitmap.nshorts) +
				           DIV_BPW(dst_x))));
		dst_nextline = MUL_2(bblt->dst_bitmap.nshorts - nshorts + 1);
	}
	else {
		dst_plus = 1;
		dst_base = (unsigned short *)((long)bblt->dst_bitmap.base +
			      (MUL_2((dst_y * bblt->dst_bitmap.nshorts) +
				           DIV_BPW(dst_x))));
		dst_nextline = bblt->dst_bitmap.nshorts - nshorts + 1;
	}

	/*
	 * Keep this destination address to return to the user.
	 */
	char_addr = dst_base;

	copyfont();
	return(char_addr);
}
#endif

