/*
 * 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: scaletfm.c,v 2.5 87/06/16 18:28:49 chris Exp $";
#endif

#include "types.h"
#include "font.h"

/*
 * From DVITYPE.WEB:
 *
 * ``The most important part of in_TFM is the width computation, which
 *   involvles multiplying the relative widths in the TFM file by the scaling
 *   factor in the DVI file.  This fixed-point multiplication must be done with
 *   precisely the same accuracy by all DVI-reading programs, in order to
 *   validate the assumptions made by DVI-writing programs like \TeX 82.
 *
 *   Let us therefore summarize what needs to be done.  Each width in a TFM
 *   file appears as a four-byte quantity called a fix_word.  A fix_word whose
 *   respective bytes are (a,b,c,d) represents the number
 *
 *	   {{ b * 2^{-4} + c * 2^{-12} + d * 2^{-20},        if a = 0;
 *    x = {{
 *	   {{ -16 + b * 2^{-4} + c * 2^{-12} + d * 2^{-20},  if a = 255.
 *
 *   (No other choices of a are allowed, since the magnitude of a TFM dimension
 *   must be less than 16.)  We want to multiply this quantity by the integer
 *   z, which is known to be less than 2^{27}.  Let \alpha = 16z.  If z <
 *   2^{23}, the individual multiplications b * z, c * z, d * z cannot
 *   overflow; otherwise we will divide z by 2, 4, 8, or 16, to obtain a
 *   multiplier less than 2^{23}, and we can compensate for this later.  If z
 *   has thereby been replaced by z' = z/2^e, let \beta = 2^{4-e}; we shall
 *   compute
 *
 *	\lfloor (b + c * 2^{-8} + d * 2^{-16})z' / \beta \rfloor
 *
 *   if a = 0, or the same quantity minus \alpha if a = 255.  This calculation
 *   must be done exactly, for the reasons stated above; the following program
 *   does the job in a system-independent way, assuming that arithmetic is
 *   exact on numbers less than 2^{31} in magnitude.''
 */

/*
 * Scale the single TFM width t by z.
 */
i32
ScaleOneWidth(t, z)
	register i32 t, z;
{
	register i32 alpha, log2beta;

	/* First compute \alpha, \beta, and z': */
	alpha = 16 * z;
	log2beta = 4;
	while (z >= (1 << 23)) {
		z >>= 1;
		log2beta--;
	}

	/* The four values 'a', 'b', 'c', and 'd' are fields within t: */
#define	a	(UnSign8(t >> 24))
#define	b	(UnSign8(t >> 16))
#define	c	(UnSign8(t >> 8))
#define	d	(UnSign8(t))
	if (t) {
		t = (((((d * z) >> 8) + c * z) >> 8) + b * z) >> log2beta;
		if (a) {
			if (a != 255)
				error(0, 0, "bad TFM width! [ScaleOneWidth]");
			t -= alpha;
		}
	}
	return (t);
}

/*
 * Scale a set of glyphs [l..h) in font f according to f->f_dvimag.
 */
ScaleGlyphs(f, l, h)
	register struct font *f;
	int l, h;
{
	register int i;
	register i32 t, z, alpha, log2beta;

	z = f->f_dvimag;
	alpha = 16 * z;
	log2beta = 4;
	while (z >= (1 << 23)) {
		z >>= 1;
		log2beta--;
	}

	for (i = l; i < h; i++) {
		if ((t = f->f_gly[i]->g_tfmwidth) == 0)
			continue;
		t = (((((d * z) >> 8) + c * z) >> 8) + b * z) >> log2beta;
		if (a) {
			if (a != 255)
				error(0, 0, "\"%s\", glyph %d: bad TFM width",
					f->f_path, i);
			t -= alpha;
		}
		f->f_gly[i]->g_tfmwidth = t;
	}
}
