/* 	$NetBSD: rasops_bitops.h,v 1.12 2010/04/08 16:45:53 macallan Exp $	*/

/*-
 * Copyright (c) 1999 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Andrew Doran.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _RASOPS_BITOPS_H_
#define _RASOPS_BITOPS_H_ 1

/*
 * Erase columns.
 */
static void
NAME(erasecols)(void *cookie, int row, int col, int num, long attr)
{
	int lmask, rmask, lclr, rclr, clr;
	struct rasops_info *ri;
	int32_t *dp, *rp, *hrp = NULL, *hp = NULL, tmp;
	int height, cnt;

	ri = (struct rasops_info *)cookie;

#ifdef RASOPS_CLIPPING
	if ((unsigned)row >= (unsigned)ri->ri_rows)
		return;

	if (col < 0) {
		num += col;
		col = 0;
	}

	if ((col + num) > ri->ri_cols)
		num = ri->ri_cols - col;

	if (num <= 0)
		return;
#endif
	col *= ri->ri_font->fontwidth << PIXEL_SHIFT;
	num *= ri->ri_font->fontwidth << PIXEL_SHIFT;
	height = ri->ri_font->fontheight;
	clr = ri->ri_devcmap[(attr >> 16) & 0xf];
	rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + ((col >> 3) & ~3));
	if (ri->ri_hwbits)
		hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale +
		    ((col >> 3) & ~3));
	if ((col & 31) + num <= 32) {
		lmask = ~rasops_pmask[col & 31][num];
		lclr = clr & ~lmask;

		while (height--) {
			dp = rp;
			DELTA(rp, ri->ri_stride, int32_t *);

			tmp = (*dp & lmask) | lclr;
			*dp = tmp;
			if (ri->ri_hwbits) {
				*hrp = tmp;
				DELTA(hrp, ri->ri_stride, int32_t *);
			}
		}
	} else {
		lmask = rasops_rmask[col & 31];
		rmask = rasops_lmask[(col + num) & 31];

		if (lmask)
			num = (num - (32 - (col & 31))) >> 5;
		else
			num = num >> 5;

		lclr = clr & ~lmask;
		rclr = clr & ~rmask;

		while (height--) {
			dp = rp;
			DELTA(rp, ri->ri_stride, int32_t *);
			if (ri->ri_hwbits) {
				hp = hrp;
				DELTA(hrp, ri->ri_stride, int32_t *);
			}

			if (lmask) {
				tmp = (*dp & lmask) | lclr;
				*dp = tmp;
				dp++;
				if (ri->ri_hwbits) {
					*hp = tmp;
					hp++;
				}
			}

			for (cnt = num; cnt > 0; cnt--)
				*dp++ = clr;
			if (ri->ri_hwbits) {
				for (cnt = num; cnt > 0; cnt--)
					*hp++ = clr;
			}

			if (rmask) {
				tmp = (*dp & rmask) | rclr;
				*dp = tmp;
				if (ri->ri_hwbits)
					*hp = tmp;
			}
		}
	}
}

/*
 * Actually paint the cursor.
 */
static void
NAME(do_cursor)(struct rasops_info *ri)
{
	int lmask, rmask, height, row, col, num;
	int32_t *dp, *rp, *hp = NULL, *hrp = NULL, tmp;

	row = ri->ri_crow;
	col = ri->ri_ccol * ri->ri_font->fontwidth << PIXEL_SHIFT;
	height = ri->ri_font->fontheight;
	num = ri->ri_font->fontwidth << PIXEL_SHIFT;
	rp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale + ((col >> 3) & ~3));
	if (ri->ri_hwbits)
		hrp = (int32_t *)(ri->ri_hwbits + row * ri->ri_yscale +
		    ((col >> 3) & ~3));

	if ((col & 31) + num <= 32) {
		lmask = rasops_pmask[col & 31][num];

		while (height--) {
			dp = rp;
			DELTA(rp, ri->ri_stride, int32_t *);
			*dp ^= lmask;
		}
		if (ri->ri_hwbits) {
			height = ri->ri_font->fontheight;
			while (height--) {
				hp = hrp;
				DELTA(hrp, ri->ri_stride, int32_t *);
				*hp ^= lmask;
			}
		}
	} else {
		lmask = ~rasops_rmask[col & 31];
		rmask = ~rasops_lmask[(col + num) & 31];

		while (height--) {
			dp = rp;
			DELTA(rp, ri->ri_stride, int32_t *);
			if (ri->ri_hwbits) {
				hp = hrp;
				DELTA(hrp, ri->ri_stride, int32_t *);
			}
			if (lmask != -1) {
				tmp = *dp ^ lmask;
				*dp = tmp;
				dp++;
				if (ri->ri_hwbits) {
					*hp = tmp;
					hp++;
				}
			}

			if (rmask != -1) {
				tmp = *dp ^ rmask;
				*dp = tmp;
				if (ri->ri_hwbits)
					*hp = tmp;
			}
		}
	}
}

/*
 * Copy columns. Ick!
 */
static void
NAME(copycols)(void *cookie, int row, int src, int dst, int num)
{
	int tmp, lmask, rmask, height, lnum, rnum, sb, db, cnt, full;
	int32_t *sp, *dp, *srp, *drp, *dhp = NULL, *hp = NULL;
	struct rasops_info *ri;

	sp = NULL;	/* XXX gcc */

	ri = (struct rasops_info *)cookie;

#ifdef RASOPS_CLIPPING
	if (dst == src)
		return;

	/* Catches < 0 case too */
	if ((unsigned)row >= (unsigned)ri->ri_rows)
		return;

	if (src < 0) {
		num += src;
		src = 0;
	}

	if ((src + num) > ri->ri_cols)
		num = ri->ri_cols - src;

	if (dst < 0) {
		num += dst;
		dst = 0;
	}

	if ((dst + num) > ri->ri_cols)
		num = ri->ri_cols - dst;

	if (num <= 0)
		return;
#endif

	cnt = ri->ri_font->fontwidth << PIXEL_SHIFT;
	src *= cnt;
	dst *= cnt;
	num *= cnt;
	row *= ri->ri_yscale;
	height = ri->ri_font->fontheight;
	db = dst & 31;

	if (db + num <= 32) {
		/* Destination is contained within a single word */
		srp = (int32_t *)(ri->ri_bits + row + ((src >> 3) & ~3));
		drp = (int32_t *)(ri->ri_bits + row + ((dst >> 3) & ~3));
		if (ri->ri_hwbits)
			dhp = (int32_t *)(ri->ri_hwbits + row +
			    ((dst >> 3) & ~3));
		sb = src & 31;

		while (height--) {
			GETBITS(srp, sb, num, tmp);
			PUTBITS(tmp, db, num, drp);
			if (ri->ri_hwbits) {
				PUTBITS(tmp, db, num, dhp);
				DELTA(dhp, ri->ri_stride, int32_t *);
			}	
			DELTA(srp, ri->ri_stride, int32_t *);
			DELTA(drp, ri->ri_stride, int32_t *);
		}

		return;
	}

	lmask = rasops_rmask[db];
	rmask = rasops_lmask[(dst + num) & 31];
	lnum = (32 - db) & 31;
	rnum = (dst + num) & 31;

	if (lmask)
		full = (num - (32 - (dst & 31))) >> 5;
	else
		full = num >> 5;

	if (src < dst && src + num > dst) {
		/* Copy right-to-left */
		sb = src & 31;
		src = src + num;
		dst = dst + num;
		srp = (int32_t *)(ri->ri_bits + row + ((src >> 3) & ~3));
		drp = (int32_t *)(ri->ri_bits + row + ((dst >> 3) & ~3));
		if (ri->ri_hwbits)
			dhp = (int32_t *)(ri->ri_hwbits + row +
			    ((dst >> 3) & ~3));

		src = src & 31;
		rnum = 32 - lnum;
		db = dst & 31;

		if ((src -= db) < 0) {
			sp--;
			src += 32;
		}

		while (height--) {
			sp = srp;
			dp = drp;
			if (ri->ri_hwbits) {
				hp = dhp;
				DELTA(dhp, ri->ri_stride, int32_t *);
			}
			DELTA(srp, ri->ri_stride, int32_t *);
			DELTA(drp, ri->ri_stride, int32_t *);

			if (db) {
				GETBITS(sp, src, db, tmp);
				PUTBITS(tmp, 0, db, dp);
				if (ri->ri_hwbits) {
					PUTBITS(tmp, 0, db, hp);
					hp++;
				}
				dp--;
				sp--;
			}

			/* Now aligned to 32-bits wrt dp */
			for (cnt = full; cnt; cnt--, sp--) {
				GETBITS(sp, src, 32, tmp);
				*dp-- = tmp;
				if (ri->ri_hwbits)
					*hp-- = tmp;
			}

			if (lmask) {
#if 0
				if (src > sb)
					sp++;
#endif
				GETBITS(sp, sb, lnum, tmp);
				PUTBITS(tmp, rnum, lnum, dp);
				if (ri->ri_hwbits)
					PUTBITS(tmp, rnum, lnum, hp);
 			}
 		}
	} else {
		/* Copy left-to-right */
		srp = (int32_t *)(ri->ri_bits + row + ((src >> 3) & ~3));
		drp = (int32_t *)(ri->ri_bits + row + ((dst >> 3) & ~3));
		if (ri->ri_hwbits)
			dhp = (int32_t *)(ri->ri_hwbits + row +
			    ((dst >> 3) & ~3));
		db = dst & 31;

		while (height--) {
			sb = src & 31;
			sp = srp;
			dp = drp;
			if (ri->ri_hwbits) {
				hp = dhp;
				DELTA(dhp, ri->ri_stride, int32_t *);
			}
			DELTA(srp, ri->ri_stride, int32_t *);
			DELTA(drp, ri->ri_stride, int32_t *);

			if (lmask) {
				GETBITS(sp, sb, lnum, tmp);
				PUTBITS(tmp, db, lnum, dp);
				dp++;
				if (ri->ri_hwbits) {
					PUTBITS(tmp, db, lnum, hp);
					hp++;
				}	

				if ((sb += lnum) > 31) {
					sp++;
					sb -= 32;
				}
			}

			/* Now aligned to 32-bits wrt dp */
			for (cnt = full; cnt; cnt--, sp++) {
				GETBITS(sp, sb, 32, tmp);
				*dp++ = tmp;
				if (ri->ri_hwbits)
					*hp++ = tmp;
			}

			if (rmask) {
				GETBITS(sp, sb, rnum, tmp);
				PUTBITS(tmp, 0, rnum, dp);
				if (ri->ri_hwbits)
					PUTBITS(tmp, 0, rnum, hp);
 			}
 		}
 	}
}

#endif /* _RASOPS_BITOPS_H_ */
