summaryrefslogtreecommitdiff
path: root/dviware/umddvi/lib/rotate.c
blob: 3107ca986ffb20309dcf1b8daedf8e0eb4f4b693 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * Copyright (c) 1987 University of Maryland Department of Computer Science.
 * All rights reserved.  Permission to copy for any purpose is hereby granted
 * so long as this copyright notice remains intact.
 */

#ifndef lint
static char rcsid[] = "$Header: rotate.c,v 2.3 87/06/16 18:28:45 chris Exp $";
#endif

/*
 * Routines to generate rotated bitmaps given unrotated inputs.
 *
 * The rotated bitmap is indistinguishable from the unrotated one (aside
 * from being rotated of course!).
 */

#include "font.h"

extern	int errno;

char	*malloc();

/*
 * Rounding, but by powers of two only.
 */
#define ROUND(n,r) (((n) + ((r) - 1)) & ~((r) - 1))

/*
 * Set the rotation of glyph g to r.
 */
SetRotation(g, r)
	register struct glyph *g;
	int r;
{

	if (r < ROT_NORM || r > ROT_RIGHT)
		error(1, 0, "bad rotation value %d", r);

	/*
	 * The null glyph is trivial to rotate by any amount.
	 *
	 * Note that this assumes that any raster has been obtained
	 * BEFORE calling SetRotation()!
	 */
	if (g->g_raster == NULL) {
		g->g_rotation = r;
		return;
	}

	/*
	 * This is hardly efficient, but it *is* expedient....
	 */
	while (g->g_rotation != r) {
		RotateClockwise(g);
		g->g_rotation = (g->g_rotation - 1) & 3;
	}
}

/*
 * Rotation by 1/4 turn clockwise (from ROT_NORM to ROT_RIGHT, e.g.).
 */
static
RotateClockwise(glyph)
	struct glyph *glyph;
{
	register char *nrast;	/* new raster */
	register char *orast;	/* old raster */
	register int oheight;	/* old raster height, new raster width */
	register int owidth;	/* old raster width, new raster height */
	unsigned int size;	/* size of new raster (in bytes) */
	int nplus;		/* offset between rows in nrast */

	/*
	 * First, get a new raster.
	 */
	{
		register struct glyph *g = glyph;
		register int t;

		oheight = g->g_height;
		owidth = g->g_width;

		/*
		 * Offset is (new width) rounded to bytes.
		 */
		nplus = ROUND(oheight, 8) >> 3;

		/*
		 * Size of new raster is (new height) * (new rounded width,
		 * in bytes).
		 */
		size = nplus * owidth;
		if ((nrast = malloc(size)) == NULL)
			error(1, errno, "out of memory");
		bzero(nrast, size);

		/*
		 * New y origin is old x origin; new x origin is old height
		 * minus old y origin - 1.
		 */
		t = g->g_yorigin;
		g->g_yorigin = g->g_xorigin;
		g->g_xorigin = oheight - t - 1;

		/* While we are at it, exchange height & width... */
		g->g_height = owidth;
		g->g_width = oheight;

		/* and grab a pointer to the old raster. */
		orast = g->g_raster;
	}

	/*
	 * Now copy bits from the old raster to the new one.  The mapping
	 * function is
	 *
	 *	for i in [0..height)
	 *		for j in [0..width)
	 *			new[j, height-i-1] = old[i, j] 
	 *
	 * Thus i maps to height-i-1 and (since we have to do our own 2
	 * dimensional array indexing) j to nplus*j.  We call the mapped
	 * variables mapi and mapj, and, since we scan sequentially through
	 * the old raster, can discard the original i and j.
	 */
	{
		register int mapj, c, k, mapi;

		mapi = oheight;
		owidth *= nplus;
		while (--mapi >= 0) {
			k = 7;
			for (mapj = 0; mapj < owidth; mapj += nplus) {
				if (++k == 8)	/* get another byte */
					c = *orast++, k = 0;
				if (c & 0x80)	/* old[i,j] was set */
					nrast[mapj + (mapi >> 3)] |=
						1 << (7 - (mapi & 7));
				c <<= 1;
			}
		}
	}

	/*
	 * Finally, free the storage associated with the original raster.
	 */
	free(glyph->g_raster);
	glyph->g_raster = nrast;
}