bitscale.c revision 23a0898a
123a0898aSmrg/* $Xorg: bitscale.c,v 1.5 2001/02/09 02:04:02 xorgcvs Exp $ */
223a0898aSmrg/*
323a0898aSmrg
423a0898aSmrgCopyright 1991, 1994, 1998  The Open Group
523a0898aSmrg
623a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its
723a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that
823a0898aSmrgthe above copyright notice appear in all copies and that both that
923a0898aSmrgcopyright notice and this permission notice appear in supporting
1023a0898aSmrgdocumentation.
1123a0898aSmrg
1223a0898aSmrgThe above copyright notice and this permission notice shall be included
1323a0898aSmrgin all copies or substantial portions of the Software.
1423a0898aSmrg
1523a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1623a0898aSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1723a0898aSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1823a0898aSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1923a0898aSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2023a0898aSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2123a0898aSmrgOTHER DEALINGS IN THE SOFTWARE.
2223a0898aSmrg
2323a0898aSmrgExcept as contained in this notice, the name of The Open Group shall
2423a0898aSmrgnot be used in advertising or otherwise to promote the sale, use or
2523a0898aSmrgother dealings in this Software without prior written authorization
2623a0898aSmrgfrom The Open Group.
2723a0898aSmrg
2823a0898aSmrg*/
2923a0898aSmrg/* $XFree86: xc/lib/font/bitmap/bitscale.c,v 3.29tsi Exp $ */
3023a0898aSmrg
3123a0898aSmrg/*
3223a0898aSmrg * Author:  Keith Packard, MIT X Consortium
3323a0898aSmrg */
3423a0898aSmrg
3523a0898aSmrg#ifdef HAVE_CONFIG_H
3623a0898aSmrg#include <config.h>
3723a0898aSmrg#endif
3823a0898aSmrg
3923a0898aSmrg/*
4023a0898aSmrg * Translate monolithic #defines to modular definitions
4123a0898aSmrg */
4223a0898aSmrg
4323a0898aSmrg#ifdef PCFFORMAT
4423a0898aSmrg#define XFONT_PCFFORMAT 1
4523a0898aSmrg#endif
4623a0898aSmrg
4723a0898aSmrg#ifdef SNFFORMAT
4823a0898aSmrg#define XFONT_SNFFORMAT 1
4923a0898aSmrg#endif
5023a0898aSmrg
5123a0898aSmrg#ifdef BDFFORMAT
5223a0898aSmrg#define XFONT_BDFFORMAT 1
5323a0898aSmrg#endif
5423a0898aSmrg
5523a0898aSmrg#include <X11/fonts/fntfilst.h>
5623a0898aSmrg#include <X11/fonts/bitmap.h>
5723a0898aSmrg#include <X11/fonts/fontutil.h>
5823a0898aSmrg#ifndef FONTMODULE
5923a0898aSmrg#ifdef _XOPEN_SOURCE
6023a0898aSmrg#include <math.h>
6123a0898aSmrg#else
6223a0898aSmrg#define _XOPEN_SOURCE	/* to get prototype for hypot on some systems */
6323a0898aSmrg#include <math.h>
6423a0898aSmrg#undef _XOPEN_SOURCE
6523a0898aSmrg#endif
6623a0898aSmrg#endif
6723a0898aSmrg
6823a0898aSmrg#ifndef MAX
6923a0898aSmrg#define   MAX(a,b)    (((a)>(b)) ? a : b)
7023a0898aSmrg#endif
7123a0898aSmrg
7223a0898aSmrg/* Should get this from elsewhere */
7323a0898aSmrgextern unsigned long serverGeneration;
7423a0898aSmrg
7523a0898aSmrgstatic void bitmapUnloadScalable (FontPtr pFont);
7623a0898aSmrgstatic void ScaleBitmap ( FontPtr pFont, CharInfoPtr opci,
7723a0898aSmrg			  CharInfoPtr pci, double *inv_xform,
7823a0898aSmrg			  double widthMult, double heightMult );
7923a0898aSmrgstatic FontPtr BitmapScaleBitmaps(FontPtr pf, FontPtr opf,
8023a0898aSmrg				  double widthMult, double heightMult,
8123a0898aSmrg				  FontScalablePtr vals);
8223a0898aSmrgstatic FontPtr PrinterScaleBitmaps(FontPtr pf, FontPtr opf,
8323a0898aSmrg				   double widthMult, double heightMult,
8423a0898aSmrg				   FontScalablePtr vals);
8523a0898aSmrg
8623a0898aSmrgenum scaleType {
8723a0898aSmrg    atom, truncate_atom, pixel_size, point_size, resolution_x,
8823a0898aSmrg    resolution_y, average_width, scaledX, scaledY, unscaled, fontname,
8923a0898aSmrg    raw_ascent, raw_descent, raw_pixelsize, raw_pointsize,
9023a0898aSmrg    raw_average_width, uncomputed
9123a0898aSmrg};
9223a0898aSmrg
9323a0898aSmrgtypedef struct _fontProp {
9423a0898aSmrg    char       *name;
9523a0898aSmrg    Atom        atom;
9623a0898aSmrg    enum scaleType type;
9723a0898aSmrg} fontProp;
9823a0898aSmrg
9923a0898aSmrgtypedef FontPtr (*ScaleFunc) ( FontPtr /* pf */,
10023a0898aSmrg			       FontPtr /* opf */,
10123a0898aSmrg			       double /* widthMult */,
10223a0898aSmrg			       double /* heightMult */,
10323a0898aSmrg			       FontScalablePtr /* vals */);
10423a0898aSmrg
10523a0898aSmrg/* These next two arrays must be kept in step with the renderer array */
10623a0898aSmrgstatic const ScaleFunc scale[] =
10723a0898aSmrg{
10823a0898aSmrg#if XFONT_PCFFORMAT
10923a0898aSmrg    BitmapScaleBitmaps,
11023a0898aSmrg    BitmapScaleBitmaps,
11123a0898aSmrg#ifdef X_GZIP_FONT_COMPRESSION
11223a0898aSmrg    BitmapScaleBitmaps,
11323a0898aSmrg#endif
11423a0898aSmrg#endif
11523a0898aSmrg#if XFONT_SNFFORMAT
11623a0898aSmrg    BitmapScaleBitmaps,
11723a0898aSmrg    BitmapScaleBitmaps,
11823a0898aSmrg#ifdef X_GZIP_FONT_COMPRESSION
11923a0898aSmrg    BitmapScaleBitmaps,
12023a0898aSmrg#endif
12123a0898aSmrg#endif
12223a0898aSmrg#if XFONT_BDFFORMAT
12323a0898aSmrg    BitmapScaleBitmaps,
12423a0898aSmrg    BitmapScaleBitmaps,
12523a0898aSmrg#ifdef X_GZIP_FONT_COMPRESSION
12623a0898aSmrg    BitmapScaleBitmaps,
12723a0898aSmrg#endif
12823a0898aSmrg#endif
12923a0898aSmrg#if XFONT_PCFFORMAT
13023a0898aSmrg    PrinterScaleBitmaps,
13123a0898aSmrg#endif
13223a0898aSmrg};
13323a0898aSmrg
13423a0898aSmrgstatic FontEntryPtr FindBestToScale ( FontPathElementPtr fpe,
13523a0898aSmrg				      FontEntryPtr entry,
13623a0898aSmrg				      FontScalablePtr vals,
13723a0898aSmrg				      FontScalablePtr best,
13823a0898aSmrg				      double *dxp, double *dyp,
13923a0898aSmrg				      double *sdxp, double *sdyp,
14023a0898aSmrg				      FontPathElementPtr *fpep );
14123a0898aSmrgstatic FontEntryPtr FindPmfToScale ( FontPathElementPtr fpe,
14223a0898aSmrg				     FontEntryPtr entry,
14323a0898aSmrg				     FontScalablePtr vals,
14423a0898aSmrg				     FontScalablePtr best,
14523a0898aSmrg				     double *dxp, double *dyp,
14623a0898aSmrg				     double *sdxp, double *sdyp,
14723a0898aSmrg				     FontPathElementPtr *fpep );
14823a0898aSmrg
14923a0898aSmrgtypedef FontEntryPtr (*FindToScale) (FontPathElementPtr fpe,
15023a0898aSmrg				     FontEntryPtr entry,
15123a0898aSmrg				     FontScalablePtr vals,
15223a0898aSmrg				     FontScalablePtr best,
15323a0898aSmrg				     double *dxp, double *dyp,
15423a0898aSmrg				     double *sdxp, double *sdyp,
15523a0898aSmrg				     FontPathElementPtr *fpep);
15623a0898aSmrgstatic const FindToScale find_scale[] =
15723a0898aSmrg{
15823a0898aSmrg#if XFONT_PCFFORMAT
15923a0898aSmrg    FindBestToScale,
16023a0898aSmrg    FindBestToScale,
16123a0898aSmrg#ifdef X_GZIP_FONT_COMPRESSION
16223a0898aSmrg    FindBestToScale,
16323a0898aSmrg#endif
16423a0898aSmrg#endif
16523a0898aSmrg#if XFONT_SNFFORMAT
16623a0898aSmrg    FindBestToScale,
16723a0898aSmrg    FindBestToScale,
16823a0898aSmrg#ifdef X_GZIP_FONT_COMPRESSION
16923a0898aSmrg    FindBestToScale,
17023a0898aSmrg#endif
17123a0898aSmrg#endif
17223a0898aSmrg#if XFONT_BDFFORMAT
17323a0898aSmrg    FindBestToScale,
17423a0898aSmrg    FindBestToScale,
17523a0898aSmrg#ifdef X_GZIP_FONT_COMPRESSION
17623a0898aSmrg    FindBestToScale,
17723a0898aSmrg#endif
17823a0898aSmrg#endif
17923a0898aSmrg#if XFONT_PCFFORMAT
18023a0898aSmrg    FindPmfToScale,
18123a0898aSmrg#endif
18223a0898aSmrg};
18323a0898aSmrg
18423a0898aSmrgstatic unsigned long bitscaleGeneration = 0;	/* initialization flag */
18523a0898aSmrg
18623a0898aSmrgstatic fontProp fontNamePropTable[] = {
18723a0898aSmrg    { "FOUNDRY", 0, atom },
18823a0898aSmrg    { "FAMILY_NAME", 0, atom },
18923a0898aSmrg    { "WEIGHT_NAME", 0, atom },
19023a0898aSmrg    { "SLANT", 0, atom },
19123a0898aSmrg    { "SETWIDTH_NAME", 0, atom },
19223a0898aSmrg    { "ADD_STYLE_NAME", 0, atom },
19323a0898aSmrg    { "PIXEL_SIZE", 0, pixel_size },
19423a0898aSmrg    { "POINT_SIZE", 0, point_size },
19523a0898aSmrg    { "RESOLUTION_X", 0, resolution_x },
19623a0898aSmrg    { "RESOLUTION_Y", 0, resolution_y },
19723a0898aSmrg    { "SPACING", 0, atom },
19823a0898aSmrg    { "AVERAGE_WIDTH", 0, average_width },
19923a0898aSmrg    { "CHARSET_REGISTRY", 0, atom },
20023a0898aSmrg    { "CHARSET_ENCODING", 0, truncate_atom },
20123a0898aSmrg    { "FONT", 0, fontname },
20223a0898aSmrg    { "RAW_ASCENT", 0, raw_ascent },
20323a0898aSmrg    { "RAW_DESCENT", 0, raw_descent },
20423a0898aSmrg    { "RAW_PIXEL_SIZE", 0, raw_pixelsize },
20523a0898aSmrg    { "RAW_POINT_SIZE", 0, raw_pointsize },
20623a0898aSmrg    { "RAW_AVERAGE_WIDTH", 0, raw_average_width }
20723a0898aSmrg};
20823a0898aSmrg
20923a0898aSmrg#define TRANSFORM_POINT(matrix, x, y, dest) \
21023a0898aSmrg	((dest)[0] = (matrix)[0] * (x) + (matrix)[2] * (y), \
21123a0898aSmrg	 (dest)[1] = (matrix)[1] * (x) + (matrix)[3] * (y))
21223a0898aSmrg
21323a0898aSmrg#define CHECK_EXTENT(lsb, rsb, desc, asc, data) \
21423a0898aSmrg	((lsb) > (data)[0] ? (lsb) = (data)[0] : 0 , \
21523a0898aSmrg	 (rsb) < (data)[0] ? (rsb) = (data)[0] : 0, \
21623a0898aSmrg	 (-desc) > (data)[1] ? (desc) = -(data)[1] : 0 , \
21723a0898aSmrg	 (asc) < (data)[1] ? (asc) = (data)[1] : 0)
21823a0898aSmrg
21923a0898aSmrg#define NPROPS (sizeof(fontNamePropTable) / sizeof(fontProp))
22023a0898aSmrg
22123a0898aSmrg/* Warning: order of the next two tables is critically interdependent.
22223a0898aSmrg   Location of "unscaled" properties at the end of fontPropTable[]
22323a0898aSmrg   is important. */
22423a0898aSmrg
22523a0898aSmrgstatic fontProp fontPropTable[] = {
22623a0898aSmrg    { "MIN_SPACE", 0, scaledX },
22723a0898aSmrg    { "NORM_SPACE", 0, scaledX },
22823a0898aSmrg    { "MAX_SPACE", 0, scaledX },
22923a0898aSmrg    { "END_SPACE", 0, scaledX },
23023a0898aSmrg    { "AVG_CAPITAL_WIDTH", 0, scaledX },
23123a0898aSmrg    { "AVG_LOWERCASE_WIDTH", 0, scaledX },
23223a0898aSmrg    { "QUAD_WIDTH", 0, scaledX },
23323a0898aSmrg    { "FIGURE_WIDTH", 0, scaledX },
23423a0898aSmrg    { "SUPERSCRIPT_X", 0, scaledX },
23523a0898aSmrg    { "SUPERSCRIPT_Y", 0, scaledY },
23623a0898aSmrg    { "SUBSCRIPT_X", 0, scaledX },
23723a0898aSmrg    { "SUBSCRIPT_Y", 0, scaledY },
23823a0898aSmrg    { "SUPERSCRIPT_SIZE", 0, scaledY },
23923a0898aSmrg    { "SUBSCRIPT_SIZE", 0, scaledY },
24023a0898aSmrg    { "SMALL_CAP_SIZE", 0, scaledY },
24123a0898aSmrg    { "UNDERLINE_POSITION", 0, scaledY },
24223a0898aSmrg    { "UNDERLINE_THICKNESS", 0, scaledY },
24323a0898aSmrg    { "STRIKEOUT_ASCENT", 0, scaledY },
24423a0898aSmrg    { "STRIKEOUT_DESCENT", 0, scaledY },
24523a0898aSmrg    { "CAP_HEIGHT", 0, scaledY },
24623a0898aSmrg    { "X_HEIGHT", 0, scaledY },
24723a0898aSmrg    { "ITALIC_ANGLE", 0, unscaled },
24823a0898aSmrg    { "RELATIVE_SETWIDTH", 0, unscaled },
24923a0898aSmrg    { "RELATIVE_WEIGHT", 0, unscaled },
25023a0898aSmrg    { "WEIGHT", 0, unscaled },
25123a0898aSmrg    { "DESTINATION", 0, unscaled },
25223a0898aSmrg    { "PCL_FONT_NAME", 0, unscaled },
25323a0898aSmrg    { "_ADOBE_POSTSCRIPT_FONTNAME", 0, unscaled }
25423a0898aSmrg};
25523a0898aSmrg
25623a0898aSmrg/* sleazy way to shut up the compiler */
25723a0898aSmrg#define zerohack (enum scaleType)0
25823a0898aSmrg
25923a0898aSmrgstatic fontProp rawFontPropTable[] = {
26023a0898aSmrg    { "RAW_MIN_SPACE", 0, },
26123a0898aSmrg    { "RAW_NORM_SPACE", 0, },
26223a0898aSmrg    { "RAW_MAX_SPACE", 0, },
26323a0898aSmrg    { "RAW_END_SPACE", 0, },
26423a0898aSmrg    { "RAW_AVG_CAPITAL_WIDTH", 0, },
26523a0898aSmrg    { "RAW_AVG_LOWERCASE_WIDTH", 0, },
26623a0898aSmrg    { "RAW_QUAD_WIDTH", 0, },
26723a0898aSmrg    { "RAW_FIGURE_WIDTH", 0, },
26823a0898aSmrg    { "RAW_SUPERSCRIPT_X", 0, },
26923a0898aSmrg    { "RAW_SUPERSCRIPT_Y", 0, },
27023a0898aSmrg    { "RAW_SUBSCRIPT_X", 0, },
27123a0898aSmrg    { "RAW_SUBSCRIPT_Y", 0, },
27223a0898aSmrg    { "RAW_SUPERSCRIPT_SIZE", 0, },
27323a0898aSmrg    { "RAW_SUBSCRIPT_SIZE", 0, },
27423a0898aSmrg    { "RAW_SMALL_CAP_SIZE", 0, },
27523a0898aSmrg    { "RAW_UNDERLINE_POSITION", 0, },
27623a0898aSmrg    { "RAW_UNDERLINE_THICKNESS", 0, },
27723a0898aSmrg    { "RAW_STRIKEOUT_ASCENT", 0, },
27823a0898aSmrg    { "RAW_STRIKEOUT_DESCENT", 0, },
27923a0898aSmrg    { "RAW_CAP_HEIGHT", 0, },
28023a0898aSmrg    { "RAW_X_HEIGHT", 0, }
28123a0898aSmrg};
28223a0898aSmrg
28323a0898aSmrgstatic void
28423a0898aSmrginitFontPropTable(void)
28523a0898aSmrg{
28623a0898aSmrg    int         i;
28723a0898aSmrg    fontProp   *t;
28823a0898aSmrg
28923a0898aSmrg    i = sizeof(fontNamePropTable) / sizeof(fontProp);
29023a0898aSmrg    for (t = fontNamePropTable; i; i--, t++)
29123a0898aSmrg	t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
29223a0898aSmrg
29323a0898aSmrg    i = sizeof(fontPropTable) / sizeof(fontProp);
29423a0898aSmrg    for (t = fontPropTable; i; i--, t++)
29523a0898aSmrg	t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
29623a0898aSmrg
29723a0898aSmrg    i = sizeof(rawFontPropTable) / sizeof(fontProp);
29823a0898aSmrg    for (t = rawFontPropTable; i; i--, t++)
29923a0898aSmrg	t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
30023a0898aSmrg}
30123a0898aSmrg
30223a0898aSmrg#if 0
30323a0898aSmrgstatic FontEntryPtr
30423a0898aSmrgGetScalableEntry (FontPathElementPtr fpe, FontNamePtr name)
30523a0898aSmrg{
30623a0898aSmrg    FontDirectoryPtr	dir;
30723a0898aSmrg
30823a0898aSmrg    dir = (FontDirectoryPtr) fpe->private;
30923a0898aSmrg    return FontFileFindNameInDir (&dir->scalable, name);
31023a0898aSmrg}
31123a0898aSmrg#endif
31223a0898aSmrg
31323a0898aSmrgstatic double
31423a0898aSmrgget_matrix_horizontal_component(double *matrix)
31523a0898aSmrg{
31623a0898aSmrg    return hypot(matrix[0], matrix[1]);
31723a0898aSmrg}
31823a0898aSmrg
31923a0898aSmrgstatic double
32023a0898aSmrgget_matrix_vertical_component(double *matrix)
32123a0898aSmrg{
32223a0898aSmrg    return hypot(matrix[2], matrix[3]);
32323a0898aSmrg}
32423a0898aSmrg
32523a0898aSmrg
32623a0898aSmrgstatic Bool
32723a0898aSmrgComputeScaleFactors(FontScalablePtr from, FontScalablePtr to,
32823a0898aSmrg		    double *dx, double *dy, double *sdx, double *sdy,
32923a0898aSmrg		    double *rescale_x)
33023a0898aSmrg{
33123a0898aSmrg    double srcpixelset, destpixelset, srcpixel, destpixel;
33223a0898aSmrg
33323a0898aSmrg    srcpixelset = get_matrix_horizontal_component(from->pixel_matrix);
33423a0898aSmrg    destpixelset = get_matrix_horizontal_component(to->pixel_matrix);
33523a0898aSmrg    srcpixel = get_matrix_vertical_component(from->pixel_matrix);
33623a0898aSmrg    destpixel = get_matrix_vertical_component(to->pixel_matrix);
33723a0898aSmrg
33823a0898aSmrg    if (srcpixelset >= EPS)
33923a0898aSmrg    {
34023a0898aSmrg	*dx = destpixelset / srcpixelset;
34123a0898aSmrg	*sdx = 1000.0 / srcpixelset;
34223a0898aSmrg    }
34323a0898aSmrg    else
34423a0898aSmrg	*sdx = *dx = 0;
34523a0898aSmrg
34623a0898aSmrg    *rescale_x = 1.0;
34723a0898aSmrg
34823a0898aSmrg    /* If client specified a width, it overrides setsize; in this
34923a0898aSmrg       context, we interpret width as applying to the font before any
35023a0898aSmrg       rotation, even though that's not what is ultimately returned in
35123a0898aSmrg       the width field. */
35223a0898aSmrg    if (from->width > 0 && to->width > 0 && fabs(*dx) > EPS)
35323a0898aSmrg    {
35423a0898aSmrg	double rescale = (double)to->width / (double)from->width;
35523a0898aSmrg
35623a0898aSmrg	/* If the client specified a transformation matrix, the rescaling
35723a0898aSmrg	   for width does *not* override the setsize.  Instead, just check
35823a0898aSmrg	   for consistency between the setsize from the matrix and the
35923a0898aSmrg	   setsize that would result from rescaling according to the width.
36023a0898aSmrg	   This assumes (perhaps naively) that the width is correctly
36123a0898aSmrg	   reported in the name.  As an interesting side effect, this test
36223a0898aSmrg	   may result in choosing a different source bitmap (one that
36323a0898aSmrg	   scales consistently between the setsize *and* the width) than it
36423a0898aSmrg	   would choose if a width were not specified.  Sort of a hidden
36523a0898aSmrg	   multiple-master functionality. */
36623a0898aSmrg	if ((to->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
36723a0898aSmrg	    (to->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY)
36823a0898aSmrg	{
36923a0898aSmrg	    /* Reject if resulting width difference is >= 1 pixel */
37023a0898aSmrg	    if (fabs(rescale * from->width - *dx * from->width) >= 10)
37123a0898aSmrg		return FALSE;
37223a0898aSmrg	}
37323a0898aSmrg	else
37423a0898aSmrg	{
37523a0898aSmrg	    *rescale_x = rescale/(*dx);
37623a0898aSmrg	    *dx = rescale;
37723a0898aSmrg	}
37823a0898aSmrg    }
37923a0898aSmrg
38023a0898aSmrg    if (srcpixel >= EPS)
38123a0898aSmrg    {
38223a0898aSmrg	*dy = destpixel / srcpixel;
38323a0898aSmrg	*sdy = 1000.0 / srcpixel;
38423a0898aSmrg    }
38523a0898aSmrg    else
38623a0898aSmrg	*sdy = *dy = 0;
38723a0898aSmrg
38823a0898aSmrg    return TRUE;
38923a0898aSmrg}
39023a0898aSmrg
39123a0898aSmrg/* favor enlargement over reduction because of aliasing resulting
39223a0898aSmrg   from reduction */
39323a0898aSmrg#define SCORE(m,s) \
39423a0898aSmrgif (m >= 1.0) { \
39523a0898aSmrg    if (m == 1.0) \
39623a0898aSmrg        score += (16 * s); \
39723a0898aSmrg    else if (m == 2.0) \
39823a0898aSmrg        score += (4 * s); \
39923a0898aSmrg    else \
40023a0898aSmrg        score += (int)(((double)(3 * s)) / m); \
40123a0898aSmrg} else { \
40223a0898aSmrg        score += (int)(((double)(2 * s)) * m); \
40323a0898aSmrg}
40423a0898aSmrg
40523a0898aSmrg/* don't need to favor enlargement when looking for bitmap that can
40623a0898aSmrg   be used unscalable */
40723a0898aSmrg#define SCORE2(m,s) \
40823a0898aSmrgif (m >= 1.0) \
40923a0898aSmrg    score += (int)(((double)(8 * s)) / m); \
41023a0898aSmrgelse \
41123a0898aSmrg    score += (int)(((double)(8 * s)) * m);
41223a0898aSmrg
41323a0898aSmrgstatic FontEntryPtr
41423a0898aSmrgFindBestToScale(FontPathElementPtr fpe, FontEntryPtr entry,
41523a0898aSmrg		FontScalablePtr vals, FontScalablePtr best,
41623a0898aSmrg		double *dxp, double *dyp,
41723a0898aSmrg		double *sdxp, double *sdyp,
41823a0898aSmrg		FontPathElementPtr *fpep)
41923a0898aSmrg{
42023a0898aSmrg    FontScalableRec temp;
42123a0898aSmrg    int		    source, i;
42223a0898aSmrg    int		    best_score, best_unscaled_score,
42323a0898aSmrg		    score;
42423a0898aSmrg    double	    dx = 0.0, sdx = 0.0, dx_amount = 0.0,
42523a0898aSmrg		    dy = 0.0, sdy = 0.0, dy_amount = 0.0,
42623a0898aSmrg		    best_dx = 0.0, best_sdx = 0.0, best_dx_amount = 0.0,
42723a0898aSmrg		    best_dy = 0.0, best_sdy = 0.0, best_dy_amount = 0.0,
42823a0898aSmrg		    best_unscaled_sdx = 0.0, best_unscaled_sdy = 0.0,
42923a0898aSmrg		    rescale_x = 0.0, best_rescale_x = 0.0,
43023a0898aSmrg		    best_unscaled_rescale_x = 0.0;
43123a0898aSmrg    FontEntryPtr    zero;
43223a0898aSmrg    FontNameRec	    zeroName;
43323a0898aSmrg    char	    zeroChars[MAXFONTNAMELEN];
43423a0898aSmrg    FontDirectoryPtr	dir;
43523a0898aSmrg    FontScaledPtr   scaled;
43623a0898aSmrg    FontScalableExtraPtr   extra;
43723a0898aSmrg    FontScaledPtr   best_scaled, best_unscaled;
43823a0898aSmrg    FontPathElementPtr	best_fpe = NULL, best_unscaled_fpe = NULL;
43923a0898aSmrg    FontEntryPtr    bitmap = NULL;
44023a0898aSmrg    FontEntryPtr    result;
44123a0898aSmrg    int		    aliascount = 20;
44223a0898aSmrg    FontPathElementPtr	bitmap_fpe = NULL;
44323a0898aSmrg    FontNameRec	    xlfdName;
44423a0898aSmrg
44523a0898aSmrg    /* find the best match */
44623a0898aSmrg    rescale_x = 1.0;
44723a0898aSmrg    best_scaled = 0;
44823a0898aSmrg    best_score = 0;
44923a0898aSmrg    best_unscaled = 0;
45023a0898aSmrg    best_unscaled_score = -1;
45123a0898aSmrg    best_dx_amount = best_dy_amount = HUGE_VAL;
45223a0898aSmrg    memcpy (zeroChars, entry->name.name, entry->name.length);
45323a0898aSmrg    zeroChars[entry->name.length] = '\0';
45423a0898aSmrg    zeroName.name = zeroChars;
45523a0898aSmrg    FontParseXLFDName (zeroChars, &temp, FONT_XLFD_REPLACE_ZERO);
45623a0898aSmrg    zeroName.length = strlen (zeroChars);
45723a0898aSmrg    zeroName.ndashes = entry->name.ndashes;
45823a0898aSmrg    xlfdName.name = vals->xlfdName;
45923a0898aSmrg    xlfdName.length = strlen(xlfdName.name);
46023a0898aSmrg    xlfdName.ndashes = FontFileCountDashes(xlfdName.name, xlfdName.length);
46123a0898aSmrg    restart_bestscale_loop: ;
46223a0898aSmrg    /*
46323a0898aSmrg     * Look through all the registered bitmap sources for
46423a0898aSmrg     * the same zero name as ours; entries along that one
46523a0898aSmrg     * can be scaled as desired.
46623a0898aSmrg     */
46723a0898aSmrg    for (source = 0; source < FontFileBitmapSources.count; source++)
46823a0898aSmrg    {
46923a0898aSmrg	/* There might already be a bitmap that satisfies the request
47023a0898aSmrg	   but didn't have a zero name that was found by the scalable
47123a0898aSmrg	   font matching logic.  Keep track if there is.  */
47223a0898aSmrg	if (bitmap == NULL && vals->xlfdName != NULL)
47323a0898aSmrg	{
47423a0898aSmrg	    bitmap_fpe = FontFileBitmapSources.fpe[source];
47523a0898aSmrg	    dir = (FontDirectoryPtr) bitmap_fpe->private;
47623a0898aSmrg	    bitmap = FontFileFindNameInDir (&dir->nonScalable, &xlfdName);
47723a0898aSmrg	    if (bitmap && bitmap->type != FONT_ENTRY_BITMAP)
47823a0898aSmrg	    {
47923a0898aSmrg		if (bitmap->type == FONT_ENTRY_ALIAS && aliascount > 0)
48023a0898aSmrg		{
48123a0898aSmrg		    aliascount--;
48223a0898aSmrg		    xlfdName.name = bitmap->u.alias.resolved;
48323a0898aSmrg		    xlfdName.length = strlen(xlfdName.name);
48423a0898aSmrg		    xlfdName.ndashes = FontFileCountDashes(xlfdName.name,
48523a0898aSmrg							   xlfdName.length);
48623a0898aSmrg		    bitmap = NULL;
48723a0898aSmrg		    goto restart_bestscale_loop;
48823a0898aSmrg		}
48923a0898aSmrg		else
49023a0898aSmrg		    bitmap = NULL;
49123a0898aSmrg	    }
49223a0898aSmrg	}
49323a0898aSmrg
49423a0898aSmrg	if (FontFileBitmapSources.fpe[source] == fpe)
49523a0898aSmrg	    zero = entry;
49623a0898aSmrg	else
49723a0898aSmrg	{
49823a0898aSmrg	    dir = (FontDirectoryPtr) FontFileBitmapSources.fpe[source]->private;
49923a0898aSmrg	    zero = FontFileFindNameInDir (&dir->scalable, &zeroName);
50023a0898aSmrg	    if (!zero)
50123a0898aSmrg		continue;
50223a0898aSmrg	}
50323a0898aSmrg	extra = zero->u.scalable.extra;
50423a0898aSmrg	for (i = 0; i < extra->numScaled; i++)
50523a0898aSmrg	{
50623a0898aSmrg	    scaled = &extra->scaled[i];
50723a0898aSmrg	    if (!scaled->bitmap)
50823a0898aSmrg		continue;
50923a0898aSmrg	    if (!ComputeScaleFactors(&scaled->vals, vals, &dx, &dy, &sdx, &sdy,
51023a0898aSmrg				     &rescale_x))
51123a0898aSmrg		continue;
51223a0898aSmrg	    score = 0;
51323a0898aSmrg	    dx_amount = dx;
51423a0898aSmrg	    dy_amount = dy;
51523a0898aSmrg	    SCORE(dy_amount, 10);
51623a0898aSmrg	    SCORE(dx_amount, 1);
51723a0898aSmrg	    if ((score > best_score) ||
51823a0898aSmrg		    ((score == best_score) &&
51923a0898aSmrg		     ((dy_amount < best_dy_amount) ||
52023a0898aSmrg 		      ((dy_amount == best_dy_amount) &&
52123a0898aSmrg 		       (dx_amount < best_dx_amount)))))
52223a0898aSmrg	    {
52323a0898aSmrg		best_fpe = FontFileBitmapSources.fpe[source];
52423a0898aSmrg	    	best_scaled = scaled;
52523a0898aSmrg	    	best_score = score;
52623a0898aSmrg	    	best_dx = dx;
52723a0898aSmrg	    	best_dy = dy;
52823a0898aSmrg	    	best_sdx = sdx;
52923a0898aSmrg	    	best_sdy = sdy;
53023a0898aSmrg	    	best_dx_amount = dx_amount;
53123a0898aSmrg	    	best_dy_amount = dy_amount;
53223a0898aSmrg		best_rescale_x = rescale_x;
53323a0898aSmrg	    }
53423a0898aSmrg	    /* Is this font a candidate for use without ugly rescaling? */
53523a0898aSmrg	    if (fabs(dx) > EPS && fabs(dy) > EPS &&
53623a0898aSmrg		fabs(vals->pixel_matrix[0] * rescale_x -
53723a0898aSmrg		     scaled->vals.pixel_matrix[0]) < 1 &&
53823a0898aSmrg		fabs(vals->pixel_matrix[1] * rescale_x -
53923a0898aSmrg		     scaled->vals.pixel_matrix[1]) < EPS &&
54023a0898aSmrg		fabs(vals->pixel_matrix[2] -
54123a0898aSmrg		     scaled->vals.pixel_matrix[2]) < EPS &&
54223a0898aSmrg		fabs(vals->pixel_matrix[3] -
54323a0898aSmrg		     scaled->vals.pixel_matrix[3]) < 1)
54423a0898aSmrg	    {
54523a0898aSmrg		/* Yes.  The pixel sizes are close on the diagonal and
54623a0898aSmrg		   extremely close off the diagonal. */
54723a0898aSmrg		score = 0;
54823a0898aSmrg		SCORE2(vals->pixel_matrix[3] /
54923a0898aSmrg		       scaled->vals.pixel_matrix[3], 10);
55023a0898aSmrg		SCORE2(vals->pixel_matrix[0] * rescale_x /
55123a0898aSmrg		       scaled->vals.pixel_matrix[0], 1);
55223a0898aSmrg		if (score > best_unscaled_score)
55323a0898aSmrg		{
55423a0898aSmrg		    best_unscaled_fpe = FontFileBitmapSources.fpe[source];
55523a0898aSmrg	    	    best_unscaled = scaled;
55623a0898aSmrg	    	    best_unscaled_sdx = sdx / dx;
55723a0898aSmrg	    	    best_unscaled_sdy = sdy / dy;
55823a0898aSmrg		    best_unscaled_score = score;
55923a0898aSmrg		    best_unscaled_rescale_x = rescale_x;
56023a0898aSmrg		}
56123a0898aSmrg	    }
56223a0898aSmrg	}
56323a0898aSmrg    }
56423a0898aSmrg    if (best_unscaled)
56523a0898aSmrg    {
56623a0898aSmrg	*best = best_unscaled->vals;
56723a0898aSmrg	*fpep = best_unscaled_fpe;
56823a0898aSmrg	*dxp = 1.0;
56923a0898aSmrg	*dyp = 1.0;
57023a0898aSmrg	*sdxp = best_unscaled_sdx;
57123a0898aSmrg	*sdyp = best_unscaled_sdy;
57223a0898aSmrg	rescale_x = best_unscaled_rescale_x;
57323a0898aSmrg	result = best_unscaled->bitmap;
57423a0898aSmrg    }
57523a0898aSmrg    else if (best_scaled)
57623a0898aSmrg    {
57723a0898aSmrg	*best = best_scaled->vals;
57823a0898aSmrg	*fpep = best_fpe;
57923a0898aSmrg	*dxp = best_dx;
58023a0898aSmrg	*dyp = best_dy;
58123a0898aSmrg	*sdxp = best_sdx;
58223a0898aSmrg	*sdyp = best_sdy;
58323a0898aSmrg	rescale_x = best_rescale_x;
58423a0898aSmrg	result = best_scaled->bitmap;
58523a0898aSmrg    }
58623a0898aSmrg    else
58723a0898aSmrg	result = NULL;
58823a0898aSmrg
58923a0898aSmrg    if (bitmap != NULL && (result == NULL || *dxp != 1.0 || *dyp != 1.0))
59023a0898aSmrg    {
59123a0898aSmrg	*fpep = bitmap_fpe;
59223a0898aSmrg	FontParseXLFDName (bitmap->name.name, best, FONT_XLFD_REPLACE_NONE);
59323a0898aSmrg	if (ComputeScaleFactors(best, best, dxp, dyp, sdxp, sdyp, &rescale_x))
59423a0898aSmrg	    result = bitmap;
59523a0898aSmrg	else
59623a0898aSmrg	    result = NULL;
59723a0898aSmrg    }
59823a0898aSmrg
59923a0898aSmrg    if (result && rescale_x != 1.0)
60023a0898aSmrg    {
60123a0898aSmrg	/* We have rescaled horizontally due to an XLFD width field.  Change
60223a0898aSmrg	   the matrix appropriately */
60323a0898aSmrg	vals->pixel_matrix[0] *= rescale_x;
60423a0898aSmrg	vals->pixel_matrix[1] *= rescale_x;
60523a0898aSmrg#ifdef NOTDEF
60623a0898aSmrg	/* This would force the pointsize and pixelsize fields in the
60723a0898aSmrg	   FONT property to display as matrices to more accurately
60823a0898aSmrg	   report the font being supplied.  It might also break existing
60923a0898aSmrg	   applications that expect a single number in that field. */
61023a0898aSmrg	vals->values_supplied =
61123a0898aSmrg	    vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) |
61223a0898aSmrg	    PIXELSIZE_ARRAY;
61323a0898aSmrg#else /* NOTDEF */
61423a0898aSmrg	vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK;
61523a0898aSmrg#endif /* NOTDEF */
61623a0898aSmrg	/* Recompute and reround the FontScalablePtr values after
61723a0898aSmrg	   rescaling for the new width. */
61823a0898aSmrg	FontFileCompleteXLFD(vals, vals);
61923a0898aSmrg    }
62023a0898aSmrg
62123a0898aSmrg    return result;
62223a0898aSmrg}
62323a0898aSmrg
62423a0898aSmrgstatic FontEntryPtr
62523a0898aSmrgFindPmfToScale(FontPathElementPtr fpe, FontEntryPtr entry,
62623a0898aSmrg	       FontScalablePtr vals, FontScalablePtr best,
62723a0898aSmrg	       double *dxp, double *dyp,
62823a0898aSmrg	       double *sdxp, double *sdyp,
62923a0898aSmrg	       FontPathElementPtr *fpep)
63023a0898aSmrg{
63123a0898aSmrg    FontEntryPtr    result = NULL;
63223a0898aSmrg    FontScaledPtr   scaled;
63323a0898aSmrg    FontScalableExtraPtr   extra;
63423a0898aSmrg    int i;
63523a0898aSmrg
63623a0898aSmrg    extra = entry->u.scalable.extra;
63723a0898aSmrg    for (i = 0; i < extra->numScaled; i++)
63823a0898aSmrg    {
63923a0898aSmrg	double rescale_x;
64023a0898aSmrg
64123a0898aSmrg	scaled = &extra->scaled[i];
64223a0898aSmrg	if (!scaled->bitmap)
64323a0898aSmrg	    continue;
64423a0898aSmrg	if (!ComputeScaleFactors(&scaled->vals, vals, dxp, dyp, sdxp, sdyp,
64523a0898aSmrg				 &rescale_x))
64623a0898aSmrg	    continue;
64723a0898aSmrg	*best = scaled->vals;
64823a0898aSmrg	*fpep = fpe;
64923a0898aSmrg	result = scaled->bitmap;
65023a0898aSmrg	if (rescale_x != 1.0)
65123a0898aSmrg	{
65223a0898aSmrg	    /* We have rescaled horizontally due to an XLFD width field.  Change
65323a0898aSmrg	       the matrix appropriately */
65423a0898aSmrg	    vals->pixel_matrix[0] *= rescale_x;
65523a0898aSmrg	    vals->pixel_matrix[1] *= rescale_x;
65623a0898aSmrg#ifdef NOTDEF
65723a0898aSmrg	    /* This would force the pointsize and pixelsize fields in the
65823a0898aSmrg	       FONT property to display as matrices to more accurately
65923a0898aSmrg	       report the font being supplied.  It might also break existing
66023a0898aSmrg	       applications that expect a single number in that field. */
66123a0898aSmrg	    vals->values_supplied =
66223a0898aSmrg		vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) |
66323a0898aSmrg		PIXELSIZE_ARRAY;
66423a0898aSmrg#else /* NOTDEF */
66523a0898aSmrg	    vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK;
66623a0898aSmrg#endif /* NOTDEF */
66723a0898aSmrg	    /* Recompute and reround the FontScalablePtr values after
66823a0898aSmrg	       rescaling for the new width. */
66923a0898aSmrg	    FontFileCompleteXLFD(vals, vals);
67023a0898aSmrg	}
67123a0898aSmrg	break;
67223a0898aSmrg    }
67323a0898aSmrg    return result;
67423a0898aSmrg}
67523a0898aSmrg
67623a0898aSmrgstatic long
67723a0898aSmrgdoround(double x)
67823a0898aSmrg{
67923a0898aSmrg    return (x >= 0) ? (long)(x + .5) : (long)(x - .5);
68023a0898aSmrg}
68123a0898aSmrg
68223a0898aSmrgstatic int
68323a0898aSmrgcomputeProps(FontPropPtr pf, char *wasStringProp,
68423a0898aSmrg	     FontPropPtr npf, char *isStringProp,
68523a0898aSmrg	     unsigned int nprops, double xfactor, double yfactor,
68623a0898aSmrg	     double sXfactor, double sYfactor)
68723a0898aSmrg{
68823a0898aSmrg    int         n;
68923a0898aSmrg    int         count;
69023a0898aSmrg    fontProp   *t;
69123a0898aSmrg    double      rawfactor = 0.0;
69223a0898aSmrg
69323a0898aSmrg    for (count = 0; nprops > 0; nprops--, pf++, wasStringProp++) {
69423a0898aSmrg	n = sizeof(fontPropTable) / sizeof(fontProp);
69523a0898aSmrg	for (t = fontPropTable; n && (t->atom != pf->name); n--, t++);
69623a0898aSmrg	if (!n)
69723a0898aSmrg	    continue;
69823a0898aSmrg
69923a0898aSmrg	switch (t->type) {
70023a0898aSmrg	case scaledX:
70123a0898aSmrg	    npf->value = doround(xfactor * (double)pf->value);
70223a0898aSmrg	    rawfactor = sXfactor;
70323a0898aSmrg	    break;
70423a0898aSmrg	case scaledY:
70523a0898aSmrg	    npf->value = doround(yfactor * (double)pf->value);
70623a0898aSmrg	    rawfactor = sYfactor;
70723a0898aSmrg	    break;
70823a0898aSmrg	case unscaled:
70923a0898aSmrg	    npf->value = pf->value;
71023a0898aSmrg	    npf->name = pf->name;
71123a0898aSmrg	    npf++;
71223a0898aSmrg	    count++;
71323a0898aSmrg	    *isStringProp++ = *wasStringProp;
71423a0898aSmrg	    break;
71523a0898aSmrg	default:
71623a0898aSmrg	    break;
71723a0898aSmrg	}
71823a0898aSmrg	if (t->type != unscaled)
71923a0898aSmrg	{
72023a0898aSmrg	    npf->name = pf->name;
72123a0898aSmrg	    npf++;
72223a0898aSmrg	    count++;
72323a0898aSmrg	    npf->value = doround(rawfactor * (double)pf->value);
72423a0898aSmrg	    npf->name = rawFontPropTable[t - fontPropTable].atom;
72523a0898aSmrg	    npf++;
72623a0898aSmrg	    count++;
72723a0898aSmrg	    *isStringProp++ = *wasStringProp;
72823a0898aSmrg	    *isStringProp++ = *wasStringProp;
72923a0898aSmrg	}
73023a0898aSmrg    }
73123a0898aSmrg    return count;
73223a0898aSmrg}
73323a0898aSmrg
73423a0898aSmrg
73523a0898aSmrgstatic int
73623a0898aSmrgComputeScaledProperties(FontInfoPtr sourceFontInfo, /* the font to be scaled */
73723a0898aSmrg			char *name, 		/* name of resulting font */
73823a0898aSmrg			FontScalablePtr vals,
73923a0898aSmrg			double dx, double dy, 	/* scale factors in x and y */
74023a0898aSmrg			double sdx, double sdy, /* directions */
74123a0898aSmrg			long sWidth, 		/* 1000-pixel average width */
74223a0898aSmrg			FontPropPtr *pProps, 	/* returns properties;
74323a0898aSmrg						   preallocated */
74423a0898aSmrg			char **pIsStringProp) 	/* return booleans;
74523a0898aSmrg						   preallocated */
74623a0898aSmrg{
74723a0898aSmrg    int         n;
74823a0898aSmrg    char       *ptr1 = NULL, *ptr2 = NULL;
74923a0898aSmrg    char       *ptr3;
75023a0898aSmrg    FontPropPtr fp;
75123a0898aSmrg    fontProp   *fpt;
75223a0898aSmrg    char	*isStringProp;
75323a0898aSmrg    int		nProps;
75423a0898aSmrg
75523a0898aSmrg    if (bitscaleGeneration != serverGeneration) {
75623a0898aSmrg	initFontPropTable();
75723a0898aSmrg	bitscaleGeneration = serverGeneration;
75823a0898aSmrg    }
75923a0898aSmrg    nProps = NPROPS + 1 + sizeof(fontPropTable) / sizeof(fontProp) +
76023a0898aSmrg			  sizeof(rawFontPropTable) / sizeof(fontProp);
76123a0898aSmrg    fp = (FontPropPtr) xalloc(sizeof(FontPropRec) * nProps);
76223a0898aSmrg    *pProps = fp;
76323a0898aSmrg    if (!fp) {
76423a0898aSmrg	fprintf(stderr, "Error: Couldn't allocate font properties (%ld*%d)\n",
76523a0898aSmrg		(unsigned long)sizeof(FontPropRec), nProps);
76623a0898aSmrg	return 1;
76723a0898aSmrg    }
76823a0898aSmrg    isStringProp = (char *) xalloc (nProps);
76923a0898aSmrg    *pIsStringProp = isStringProp;
77023a0898aSmrg    if (!isStringProp)
77123a0898aSmrg    {
77223a0898aSmrg fprintf(stderr, "Error: Couldn't allocate isStringProp (%d)\n", nProps);
77323a0898aSmrg	xfree (fp);
77423a0898aSmrg	return 1;
77523a0898aSmrg    }
77623a0898aSmrg    ptr2 = name;
77723a0898aSmrg    for (fpt = fontNamePropTable, n = NPROPS;
77823a0898aSmrg	 n;
77923a0898aSmrg 	 fp++, fpt++, n--, isStringProp++)
78023a0898aSmrg    {
78123a0898aSmrg
78223a0898aSmrg	if (*ptr2)
78323a0898aSmrg	{
78423a0898aSmrg	    ptr1 = ptr2 + 1;
78523a0898aSmrg	    if (!(ptr2 = strchr(ptr1, '-'))) ptr2 = strchr(ptr1, '\0');
78623a0898aSmrg	}
78723a0898aSmrg
78823a0898aSmrg	*isStringProp = 0;
78923a0898aSmrg	switch (fpt->type) {
79023a0898aSmrg	case atom:
79123a0898aSmrg	    fp->value = MakeAtom(ptr1, ptr2 - ptr1, TRUE);
79223a0898aSmrg	    *isStringProp = 1;
79323a0898aSmrg	    break;
79423a0898aSmrg	case truncate_atom:
79523a0898aSmrg	    for (ptr3 = ptr1; *ptr3; ptr3++)
79623a0898aSmrg		if (*ptr3 == '[')
79723a0898aSmrg		    break;
79823a0898aSmrg	    if (!*ptr3) ptr3 = ptr2;
79923a0898aSmrg	    fp->value = MakeAtom(ptr1, ptr3 - ptr1, TRUE);
80023a0898aSmrg	    *isStringProp = 1;
80123a0898aSmrg	    break;
80223a0898aSmrg	case pixel_size:
80323a0898aSmrg	    fp->value = doround(vals->pixel_matrix[3]);
80423a0898aSmrg	    break;
80523a0898aSmrg	case point_size:
80623a0898aSmrg	    fp->value = doround(vals->point_matrix[3] * 10.0);
80723a0898aSmrg	    break;
80823a0898aSmrg	case resolution_x:
80923a0898aSmrg	    fp->value = vals->x;
81023a0898aSmrg	    break;
81123a0898aSmrg	case resolution_y:
81223a0898aSmrg	    fp->value = vals->y;
81323a0898aSmrg	    break;
81423a0898aSmrg	case average_width:
81523a0898aSmrg	    fp->value = vals->width;
81623a0898aSmrg	    break;
81723a0898aSmrg	case fontname:
81823a0898aSmrg	    fp->value = MakeAtom(name, strlen(name), TRUE);
81923a0898aSmrg	    *isStringProp = 1;
82023a0898aSmrg	    break;
82123a0898aSmrg	case raw_ascent:
82223a0898aSmrg	    fp->value = sourceFontInfo->fontAscent * sdy;
82323a0898aSmrg	    break;
82423a0898aSmrg	case raw_descent:
82523a0898aSmrg	    fp->value = sourceFontInfo->fontDescent * sdy;
82623a0898aSmrg	    break;
82723a0898aSmrg	case raw_pointsize:
82823a0898aSmrg	    fp->value = (long)(72270.0 / (double)vals->y + .5);
82923a0898aSmrg	    break;
83023a0898aSmrg	case raw_pixelsize:
83123a0898aSmrg	    fp->value = 1000;
83223a0898aSmrg	    break;
83323a0898aSmrg	case raw_average_width:
83423a0898aSmrg	    fp->value = sWidth;
83523a0898aSmrg	    break;
83623a0898aSmrg	default:
83723a0898aSmrg	    break;
83823a0898aSmrg	}
83923a0898aSmrg	fp->name = fpt->atom;
84023a0898aSmrg    }
84123a0898aSmrg    n = NPROPS;
84223a0898aSmrg    n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp,
84323a0898aSmrg		      fp, isStringProp, sourceFontInfo->nprops, dx, dy,
84423a0898aSmrg		      sdx, sdy);
84523a0898aSmrg    return n;
84623a0898aSmrg}
84723a0898aSmrg
84823a0898aSmrg
84923a0898aSmrgstatic int
85023a0898aSmrgcompute_xform_matrix(FontScalablePtr vals, double dx, double dy,
85123a0898aSmrg		     double *xform, double *inv_xform,
85223a0898aSmrg		     double *xmult, double *ymult)
85323a0898aSmrg{
85423a0898aSmrg    double det;
85523a0898aSmrg    double pixel = get_matrix_vertical_component(vals->pixel_matrix);
85623a0898aSmrg    double pixelset = get_matrix_horizontal_component(vals->pixel_matrix);
85723a0898aSmrg
85823a0898aSmrg    if (pixel < EPS || pixelset < EPS) return 0;
85923a0898aSmrg
86023a0898aSmrg    /* Initialize the transformation matrix to the scaling factors */
86123a0898aSmrg    xform[0] = dx / pixelset;
86223a0898aSmrg    xform[1] = xform[2] = 0.0;
86323a0898aSmrg    xform[3] = dy / pixel;
86423a0898aSmrg
86523a0898aSmrg/* Inline matrix multiply -- somewhat ugly to minimize register usage */
86623a0898aSmrg#define MULTIPLY_XFORM(a,b,c,d) \
86723a0898aSmrg{ \
86823a0898aSmrg  register double aa = (a), bb = (b), cc = (c), dd = (d); \
86923a0898aSmrg  register double temp; \
87023a0898aSmrg  temp =     aa * xform[0] + cc * xform[1]; \
87123a0898aSmrg  aa =       aa * xform[2] + cc * xform[3]; \
87223a0898aSmrg  xform[1] = bb * xform[0] + dd * xform[1]; \
87323a0898aSmrg  xform[3] = bb * xform[2] + dd * xform[3]; \
87423a0898aSmrg  xform[0] = temp; \
87523a0898aSmrg  xform[2] = aa; \
87623a0898aSmrg}
87723a0898aSmrg
87823a0898aSmrg    /* Rescale the transformation matrix for size of source font */
87923a0898aSmrg    MULTIPLY_XFORM(vals->pixel_matrix[0],
88023a0898aSmrg		   vals->pixel_matrix[1],
88123a0898aSmrg		   vals->pixel_matrix[2],
88223a0898aSmrg		   vals->pixel_matrix[3]);
88323a0898aSmrg
88423a0898aSmrg    *xmult = xform[0];
88523a0898aSmrg    *ymult = xform[3];
88623a0898aSmrg
88723a0898aSmrg
88823a0898aSmrg    if (inv_xform == NULL) return 1;
88923a0898aSmrg
89023a0898aSmrg    /* Compute the determinant for use in inverting the matrix. */
89123a0898aSmrg    det = xform[0] * xform[3] - xform[1] * xform[2];
89223a0898aSmrg
89323a0898aSmrg    /* If the determinant is tiny or zero, give up */
89423a0898aSmrg    if (fabs(det) < EPS) return 0;
89523a0898aSmrg
89623a0898aSmrg    /* Compute the inverse */
89723a0898aSmrg    inv_xform[0] = xform[3] / det;
89823a0898aSmrg    inv_xform[1] = -xform[1] / det;
89923a0898aSmrg    inv_xform[2] = -xform[2] / det;
90023a0898aSmrg    inv_xform[3] = xform[0] / det;
90123a0898aSmrg
90223a0898aSmrg    return 1;
90323a0898aSmrg}
90423a0898aSmrg
90523a0898aSmrg/*
90623a0898aSmrg *  ScaleFont
90723a0898aSmrg *  returns a pointer to the new scaled font, or NULL (due to AllocError).
90823a0898aSmrg */
90923a0898aSmrgstatic FontPtr
91023a0898aSmrgScaleFont(FontPtr opf,            /* originating font */
91123a0898aSmrg	  double widthMult, 	  /* glyphs width scale factor */
91223a0898aSmrg	  double heightMult, 	  /* glyphs height scale factor */
91323a0898aSmrg	  double sWidthMult, 	  /* scalable glyphs width scale factor */
91423a0898aSmrg	  double sHeightMult, 	  /* scalable glyphs height scale factor */
91523a0898aSmrg	  FontScalablePtr vals,
91623a0898aSmrg	  double *newWidthMult,   /* return: X component of glyphs width
91723a0898aSmrg				     scale factor */
91823a0898aSmrg	  double *newHeightMult,  /* return: Y component of glyphs height
91923a0898aSmrg				     scale factor */
92023a0898aSmrg	  long *sWidth)		  /* return: average 1000-pixel width */
92123a0898aSmrg{
92223a0898aSmrg    FontPtr     pf;
92323a0898aSmrg    FontInfoPtr pfi,
92423a0898aSmrg                opfi;
92523a0898aSmrg    BitmapFontPtr  bitmapFont,
92623a0898aSmrg                obitmapFont;
92723a0898aSmrg    CharInfoPtr pci,
92823a0898aSmrg                opci;
92923a0898aSmrg    int         nchars = 0;	/* how many characters in the font */
93023a0898aSmrg    int         i;
93123a0898aSmrg    int		firstCol, lastCol, firstRow, lastRow;
93223a0898aSmrg    double	xform[4], inv_xform[4];
93323a0898aSmrg    double	xmult, ymult;
93423a0898aSmrg    int		totalwidth = 0, totalchars = 0;
93523a0898aSmrg#define OLDINDEX(i) (((i)/(lastCol - firstCol + 1) + \
93623a0898aSmrg		      firstRow - opf->info.firstRow) * \
93723a0898aSmrg		     (opf->info.lastCol - opf->info.firstCol + 1) + \
93823a0898aSmrg		     (i)%(lastCol - firstCol + 1) + \
93923a0898aSmrg		     firstCol - opf->info.firstCol)
94023a0898aSmrg
94123a0898aSmrg    *sWidth = 0;
94223a0898aSmrg
94323a0898aSmrg    opfi = &opf->info;
94423a0898aSmrg    obitmapFont = (BitmapFontPtr) opf->fontPrivate;
94523a0898aSmrg
94623a0898aSmrg    bitmapFont = 0;
94723a0898aSmrg    if (!(pf = CreateFontRec())) {
94823a0898aSmrg	fprintf(stderr, "Error: Couldn't allocate FontRec (%ld)\n",
94923a0898aSmrg		(unsigned long)sizeof(FontRec));
95023a0898aSmrg	goto bail;
95123a0898aSmrg    }
95223a0898aSmrg    pf->refcnt = 0;
95323a0898aSmrg    pf->bit = opf->bit;
95423a0898aSmrg    pf->byte = opf->byte;
95523a0898aSmrg    pf->glyph = opf->glyph;
95623a0898aSmrg    pf->scan = opf->scan;
95723a0898aSmrg
95823a0898aSmrg    pf->get_glyphs = bitmapGetGlyphs;
95923a0898aSmrg    pf->get_metrics = bitmapGetMetrics;
96023a0898aSmrg    pf->unload_font = bitmapUnloadScalable;
96123a0898aSmrg    pf->unload_glyphs = NULL;
96223a0898aSmrg
96323a0898aSmrg    pfi = &pf->info;
96423a0898aSmrg    *pfi = *opfi;
96523a0898aSmrg    /* If charset subsetting specified in vals, determine what our range
96623a0898aSmrg       needs to be for the output font */
96723a0898aSmrg    if (vals->nranges)
96823a0898aSmrg    {
96923a0898aSmrg	int i;
97023a0898aSmrg
97123a0898aSmrg	pfi->allExist = 0;
97223a0898aSmrg	firstCol = 255;
97323a0898aSmrg	lastCol = 0;
97423a0898aSmrg	firstRow = 255;
97523a0898aSmrg	lastRow = 0;
97623a0898aSmrg
97723a0898aSmrg	for (i = 0; i < vals->nranges; i++)
97823a0898aSmrg	{
97923a0898aSmrg	    if (vals->ranges[i].min_char_high != vals->ranges[i].max_char_high)
98023a0898aSmrg	    {
98123a0898aSmrg		firstCol = opfi->firstCol;
98223a0898aSmrg		lastCol = opfi->lastCol;
98323a0898aSmrg	    }
98423a0898aSmrg	    if (firstCol > vals->ranges[i].min_char_low)
98523a0898aSmrg		firstCol = vals->ranges[i].min_char_low;
98623a0898aSmrg	    if (lastCol < vals->ranges[i].max_char_low)
98723a0898aSmrg		lastCol = vals->ranges[i].max_char_low;
98823a0898aSmrg	    if (firstRow > vals->ranges[i].min_char_high)
98923a0898aSmrg		firstRow = vals->ranges[i].min_char_high;
99023a0898aSmrg	    if (lastRow < vals->ranges[i].max_char_high)
99123a0898aSmrg		lastRow = vals->ranges[i].max_char_high;
99223a0898aSmrg	}
99323a0898aSmrg
99423a0898aSmrg	if (firstCol > lastCol || firstRow > lastRow)
99523a0898aSmrg	    goto bail;
99623a0898aSmrg
99723a0898aSmrg	if (firstCol < opfi->firstCol)
99823a0898aSmrg	    firstCol = opfi->firstCol;
99923a0898aSmrg	if (lastCol > opfi->lastCol)
100023a0898aSmrg	    lastCol = opfi->lastCol;
100123a0898aSmrg	if (firstRow < opfi->firstRow)
100223a0898aSmrg	    firstRow = opfi->firstRow;
100323a0898aSmrg	if (lastRow > opfi->lastRow)
100423a0898aSmrg	    lastRow = opfi->lastRow;
100523a0898aSmrg    }
100623a0898aSmrg    else
100723a0898aSmrg    {
100823a0898aSmrg	firstCol = opfi->firstCol;
100923a0898aSmrg	lastCol = opfi->lastCol;
101023a0898aSmrg	firstRow = opfi->firstRow;
101123a0898aSmrg	lastRow = opfi->lastRow;
101223a0898aSmrg    }
101323a0898aSmrg
101423a0898aSmrg    bitmapFont = (BitmapFontPtr) xalloc(sizeof(BitmapFontRec));
101523a0898aSmrg    if (!bitmapFont) {
101623a0898aSmrg	fprintf(stderr, "Error: Couldn't allocate bitmapFont (%ld)\n",
101723a0898aSmrg		(unsigned long)sizeof(BitmapFontRec));
101823a0898aSmrg	goto bail;
101923a0898aSmrg    }
102023a0898aSmrg    nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
102123a0898aSmrg    pfi->firstRow = firstRow;
102223a0898aSmrg    pfi->lastRow = lastRow;
102323a0898aSmrg    pfi->firstCol = firstCol;
102423a0898aSmrg    pfi->lastCol = lastCol;
102523a0898aSmrg    pf->fontPrivate = (pointer) bitmapFont;
102623a0898aSmrg    bitmapFont->version_num = obitmapFont->version_num;
102723a0898aSmrg    bitmapFont->num_chars = nchars;
102823a0898aSmrg    bitmapFont->num_tables = obitmapFont->num_tables;
102923a0898aSmrg    bitmapFont->metrics = 0;
103023a0898aSmrg    bitmapFont->ink_metrics = 0;
103123a0898aSmrg    bitmapFont->bitmaps = 0;
103223a0898aSmrg    bitmapFont->encoding = 0;
103323a0898aSmrg    bitmapFont->bitmapExtra = 0;
103423a0898aSmrg    bitmapFont->pDefault = 0;
103523a0898aSmrg    bitmapFont->metrics = (CharInfoPtr) xalloc(nchars * sizeof(CharInfoRec));
103623a0898aSmrg    if (!bitmapFont->metrics) {
103723a0898aSmrg	fprintf(stderr, "Error: Couldn't allocate metrics (%d*%ld)\n",
103823a0898aSmrg		nchars, (unsigned long)sizeof(CharInfoRec));
103923a0898aSmrg	goto bail;
104023a0898aSmrg    }
104123a0898aSmrg    bitmapFont->encoding =
104223a0898aSmrg        (CharInfoPtr **) xcalloc(NUM_SEGMENTS(nchars),
104323a0898aSmrg                                 sizeof(CharInfoPtr*));
104423a0898aSmrg    if (!bitmapFont->encoding) {
104523a0898aSmrg	fprintf(stderr, "Error: Couldn't allocate encoding (%d*%ld)\n",
104623a0898aSmrg		nchars, (unsigned long)sizeof(CharInfoPtr));
104723a0898aSmrg	goto bail;
104823a0898aSmrg    }
104923a0898aSmrg
105023a0898aSmrg#undef MAXSHORT
105123a0898aSmrg#define MAXSHORT    32767
105223a0898aSmrg#undef MINSHORT
105323a0898aSmrg#define MINSHORT    -32768
105423a0898aSmrg
105523a0898aSmrg    pfi->anamorphic = FALSE;
105623a0898aSmrg    if (heightMult != widthMult)
105723a0898aSmrg	pfi->anamorphic = TRUE;
105823a0898aSmrg    pfi->cachable = TRUE;
105923a0898aSmrg
106023a0898aSmrg    if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
106123a0898aSmrg			      inv_xform, &xmult, &ymult))
106223a0898aSmrg	goto bail;
106323a0898aSmrg
106423a0898aSmrg    pfi->fontAscent = opfi->fontAscent * ymult;
106523a0898aSmrg    pfi->fontDescent = opfi->fontDescent * ymult;
106623a0898aSmrg
106723a0898aSmrg    pfi->minbounds.leftSideBearing = MAXSHORT;
106823a0898aSmrg    pfi->minbounds.rightSideBearing = MAXSHORT;
106923a0898aSmrg    pfi->minbounds.ascent = MAXSHORT;
107023a0898aSmrg    pfi->minbounds.descent = MAXSHORT;
107123a0898aSmrg    pfi->minbounds.characterWidth = MAXSHORT;
107223a0898aSmrg    pfi->minbounds.attributes = MAXSHORT;
107323a0898aSmrg
107423a0898aSmrg    pfi->maxbounds.leftSideBearing = MINSHORT;
107523a0898aSmrg    pfi->maxbounds.rightSideBearing = MINSHORT;
107623a0898aSmrg    pfi->maxbounds.ascent = MINSHORT;
107723a0898aSmrg    pfi->maxbounds.descent = MINSHORT;
107823a0898aSmrg    pfi->maxbounds.characterWidth = MINSHORT;
107923a0898aSmrg    pfi->maxbounds.attributes = MINSHORT;
108023a0898aSmrg
108123a0898aSmrg    /* Compute the transformation and inverse transformation matrices.
108223a0898aSmrg       Can fail if the determinant is zero. */
108323a0898aSmrg
108423a0898aSmrg    pci = bitmapFont->metrics;
108523a0898aSmrg    for (i = 0; i < nchars; i++)
108623a0898aSmrg    {
108723a0898aSmrg	if ((opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i))))
108823a0898aSmrg	{
108923a0898aSmrg	    double newlsb, newrsb, newdesc, newasc, point[2];
109023a0898aSmrg
109123a0898aSmrg#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))
109223a0898aSmrg#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8))
109323a0898aSmrg
109423a0898aSmrg	    if (vals->nranges)
109523a0898aSmrg	    {
109623a0898aSmrg		int row = i / (lastCol - firstCol + 1) + firstRow;
109723a0898aSmrg		int col = i % (lastCol - firstCol + 1) + firstCol;
109823a0898aSmrg		int ch = (row << 8) + col;
109923a0898aSmrg		int j;
110023a0898aSmrg		for (j = 0; j < vals->nranges; j++)
110123a0898aSmrg		    if (ch >= minchar(vals->ranges[j]) &&
110223a0898aSmrg			ch <= maxchar(vals->ranges[j]))
110323a0898aSmrg			break;
110423a0898aSmrg		if (j == vals->nranges)
110523a0898aSmrg		{
110623a0898aSmrg		    continue;
110723a0898aSmrg		}
110823a0898aSmrg	    }
110923a0898aSmrg
111023a0898aSmrg	    if (opci->metrics.leftSideBearing == 0 &&
111123a0898aSmrg		opci->metrics.rightSideBearing == 0 &&
111223a0898aSmrg		opci->metrics.ascent == 0 &&
111323a0898aSmrg		opci->metrics.descent == 0 &&
111423a0898aSmrg		opci->metrics.characterWidth == 0)
111523a0898aSmrg	    {
111623a0898aSmrg		continue;
111723a0898aSmrg	    }
111823a0898aSmrg
111923a0898aSmrg            if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) {
112023a0898aSmrg                bitmapFont->encoding[SEGMENT_MAJOR(i)]=
112123a0898aSmrg                  (CharInfoPtr*)xcalloc(BITMAP_FONT_SEGMENT_SIZE,
112223a0898aSmrg                                        sizeof(CharInfoPtr));
112323a0898aSmrg                if(!bitmapFont->encoding[SEGMENT_MAJOR(i)])
112423a0898aSmrg                    goto bail;
112523a0898aSmrg            }
112623a0898aSmrg	    ACCESSENCODINGL(bitmapFont->encoding, i) = pci;
112723a0898aSmrg
112823a0898aSmrg	    /* Compute new extents for this glyph */
112923a0898aSmrg	    TRANSFORM_POINT(xform,
113023a0898aSmrg			    opci->metrics.leftSideBearing,
113123a0898aSmrg			    -opci->metrics.descent,
113223a0898aSmrg			    point);
113323a0898aSmrg	    newlsb = point[0];
113423a0898aSmrg	    newrsb = newlsb;
113523a0898aSmrg	    newdesc = -point[1];
113623a0898aSmrg	    newasc = -newdesc;
113723a0898aSmrg	    TRANSFORM_POINT(xform,
113823a0898aSmrg			    opci->metrics.leftSideBearing,
113923a0898aSmrg			    opci->metrics.ascent,
114023a0898aSmrg			    point);
114123a0898aSmrg	    CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
114223a0898aSmrg	    TRANSFORM_POINT(xform,
114323a0898aSmrg			    opci->metrics.rightSideBearing,
114423a0898aSmrg			    -opci->metrics.descent,
114523a0898aSmrg			    point);
114623a0898aSmrg	    CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
114723a0898aSmrg	    TRANSFORM_POINT(xform,
114823a0898aSmrg			    opci->metrics.rightSideBearing,
114923a0898aSmrg			    opci->metrics.ascent,
115023a0898aSmrg			    point);
115123a0898aSmrg	    CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
115223a0898aSmrg
115323a0898aSmrg	    pci->metrics.leftSideBearing = (int)floor(newlsb);
115423a0898aSmrg	    pci->metrics.rightSideBearing = (int)floor(newrsb + .5);
115523a0898aSmrg	    pci->metrics.descent = (int)ceil(newdesc);
115623a0898aSmrg	    pci->metrics.ascent = (int)floor(newasc + .5);
115723a0898aSmrg	    /* Accumulate total width of characters before transformation,
115823a0898aSmrg	       to ascertain predominant direction of font. */
115923a0898aSmrg	    totalwidth += opci->metrics.characterWidth;
116023a0898aSmrg	    pci->metrics.characterWidth =
116123a0898aSmrg		doround((double)opci->metrics.characterWidth * xmult);
116223a0898aSmrg	    pci->metrics.attributes =
116323a0898aSmrg		doround((double)opci->metrics.characterWidth * sWidthMult);
116423a0898aSmrg	    if (!pci->metrics.characterWidth)
116523a0898aSmrg	    {
116623a0898aSmrg		/* Since transformation may shrink width, height, and
116723a0898aSmrg		   escapement to zero, make sure existing characters
116823a0898aSmrg		   are not mistaken for undefined characters. */
116923a0898aSmrg
117023a0898aSmrg		if (pci->metrics.rightSideBearing ==
117123a0898aSmrg		    pci->metrics.leftSideBearing)
117223a0898aSmrg		    pci->metrics.rightSideBearing++;
117323a0898aSmrg		if (pci->metrics.ascent == -pci->metrics.descent)
117423a0898aSmrg		    pci->metrics.ascent++;
117523a0898aSmrg	    }
117623a0898aSmrg
117723a0898aSmrg	    pci++;
117823a0898aSmrg	}
117923a0898aSmrg    }
118023a0898aSmrg
118123a0898aSmrg
118223a0898aSmrg    /*
118323a0898aSmrg     * For each character, set the per-character metrics, scale the glyph, and
118423a0898aSmrg     * check per-font minbounds and maxbounds character information.
118523a0898aSmrg     */
118623a0898aSmrg
118723a0898aSmrg    pci = bitmapFont->metrics;
118823a0898aSmrg    for (i = 0; i < nchars; i++)
118923a0898aSmrg    {
119023a0898aSmrg	if ((pci = ACCESSENCODING(bitmapFont->encoding,i)) &&
119123a0898aSmrg	    (opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i))))
119223a0898aSmrg	{
119323a0898aSmrg	    totalchars++;
119423a0898aSmrg	    *sWidth += abs((int)(INT16)pci->metrics.attributes);
119523a0898aSmrg#define MINMAX(field) \
119623a0898aSmrg	    if (pfi->minbounds.field > pci->metrics.field) \
119723a0898aSmrg	    	pfi->minbounds.field = pci->metrics.field; \
119823a0898aSmrg	    if (pfi->maxbounds.field < pci->metrics.field) \
119923a0898aSmrg	    	pfi->maxbounds.field = pci->metrics.field
120023a0898aSmrg
120123a0898aSmrg	    MINMAX(leftSideBearing);
120223a0898aSmrg	    MINMAX(rightSideBearing);
120323a0898aSmrg	    MINMAX(ascent);
120423a0898aSmrg	    MINMAX(descent);
120523a0898aSmrg	    MINMAX(characterWidth);
120623a0898aSmrg
120723a0898aSmrg	    /* Hack: Cast attributes into a signed quantity.  Tread lightly
120823a0898aSmrg	       for now and don't go changing the global Xproto.h file */
120923a0898aSmrg	    if ((INT16)pfi->minbounds.attributes >
121023a0898aSmrg		(INT16)pci->metrics.attributes)
121123a0898aSmrg	    	pfi->minbounds.attributes = pci->metrics.attributes;
121223a0898aSmrg	    if ((INT16)pfi->maxbounds.attributes <
121323a0898aSmrg		(INT16)pci->metrics.attributes)
121423a0898aSmrg	    	pfi->maxbounds.attributes = pci->metrics.attributes;
121523a0898aSmrg#undef MINMAX
121623a0898aSmrg	}
121723a0898aSmrg    }
121823a0898aSmrg    pfi->ink_minbounds = pfi->minbounds;
121923a0898aSmrg    pfi->ink_maxbounds = pfi->maxbounds;
122023a0898aSmrg    if (totalchars)
122123a0898aSmrg    {
122223a0898aSmrg	*sWidth = (*sWidth * 10 + totalchars / 2) / totalchars;
122323a0898aSmrg	if (totalwidth < 0)
122423a0898aSmrg	{
122523a0898aSmrg	    /* Dominant direction is R->L */
122623a0898aSmrg	    *sWidth = -*sWidth;
122723a0898aSmrg	}
122823a0898aSmrg
122923a0898aSmrg	if (pfi->minbounds.characterWidth == pfi->maxbounds.characterWidth)
123023a0898aSmrg	    vals->width = pfi->minbounds.characterWidth * 10;
123123a0898aSmrg	else
123223a0898aSmrg	    vals->width = doround((double)*sWidth * vals->pixel_matrix[0] /
123323a0898aSmrg				  1000.0);
123423a0898aSmrg    }
123523a0898aSmrg    else
123623a0898aSmrg    {
123723a0898aSmrg	vals->width = 0;
123823a0898aSmrg	*sWidth = 0;
123923a0898aSmrg    }
124023a0898aSmrg    FontComputeInfoAccelerators (pfi);
124123a0898aSmrg
124223a0898aSmrg    if (pfi->defaultCh != (unsigned short) NO_SUCH_CHAR) {
124323a0898aSmrg	unsigned int r,
124423a0898aSmrg	            c,
124523a0898aSmrg	            cols;
124623a0898aSmrg
124723a0898aSmrg	r = pfi->defaultCh >> 8;
124823a0898aSmrg	c = pfi->defaultCh & 0xFF;
124923a0898aSmrg	if (pfi->firstRow <= r && r <= pfi->lastRow &&
125023a0898aSmrg		pfi->firstCol <= c && c <= pfi->lastCol) {
125123a0898aSmrg	    cols = pfi->lastCol - pfi->firstCol + 1;
125223a0898aSmrg	    r = r - pfi->firstRow;
125323a0898aSmrg	    c = c - pfi->firstCol;
125423a0898aSmrg	    bitmapFont->pDefault =
125523a0898aSmrg                ACCESSENCODING(bitmapFont->encoding, r * cols + c);
125623a0898aSmrg	}
125723a0898aSmrg    }
125823a0898aSmrg
125923a0898aSmrg    *newWidthMult = xmult;
126023a0898aSmrg    *newHeightMult = ymult;
126123a0898aSmrg    return pf;
126223a0898aSmrgbail:
126323a0898aSmrg    if (pf)
126423a0898aSmrg	xfree(pf);
126523a0898aSmrg    if (bitmapFont) {
126623a0898aSmrg	xfree(bitmapFont->metrics);
126723a0898aSmrg	xfree(bitmapFont->ink_metrics);
126823a0898aSmrg	xfree(bitmapFont->bitmaps);
126923a0898aSmrg        if(bitmapFont->encoding)
127023a0898aSmrg            for(i=0; i<NUM_SEGMENTS(nchars); i++)
127123a0898aSmrg                xfree(bitmapFont->encoding[i]);
127223a0898aSmrg	xfree(bitmapFont->encoding);
127323a0898aSmrg    }
127423a0898aSmrg    return NULL;
127523a0898aSmrg}
127623a0898aSmrg
127723a0898aSmrgstatic void
127823a0898aSmrgScaleBitmap(FontPtr pFont, CharInfoPtr opci, CharInfoPtr pci,
127923a0898aSmrg	    double *inv_xform, double widthMult, double heightMult)
128023a0898aSmrg{
128123a0898aSmrg    register char  *bitmap,		/* The bits */
128223a0898aSmrg               *newBitmap;
128323a0898aSmrg    register int   bpr,			/* Padding information */
128423a0898aSmrg		newBpr;
128523a0898aSmrg    int         width,			/* Extents information */
128623a0898aSmrg                height,
128723a0898aSmrg                newWidth,
128823a0898aSmrg                newHeight;
128923a0898aSmrg    register int row,			/* Loop variables */
129023a0898aSmrg		col;
129123a0898aSmrg    INT32	deltaX,			/* Increments for resampling loop */
129223a0898aSmrg		deltaY;
129323a0898aSmrg    INT32	xValue,			/* Subscripts for resampling loop */
129423a0898aSmrg		yValue;
129523a0898aSmrg    double	point[2];
129623a0898aSmrg    unsigned char *char_grayscale = 0;
129723a0898aSmrg    INT32	*diffusion_workspace = NULL, *thisrow = NULL,
129823a0898aSmrg                *nextrow = NULL, pixmult = 0;
129923a0898aSmrg    int		box_x = 0, box_y = 0;
130023a0898aSmrg
130123a0898aSmrg    static unsigned char masklsb[] =
130223a0898aSmrg	{ 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
130323a0898aSmrg    static unsigned char maskmsb[] =
130423a0898aSmrg	{ 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
130523a0898aSmrg    unsigned char	*mask = (pFont->bit == LSBFirst ? masklsb : maskmsb);
130623a0898aSmrg
130723a0898aSmrg
130823a0898aSmrg    bitmap = opci->bits;
130923a0898aSmrg    newBitmap = pci->bits;
131023a0898aSmrg    width = GLYPHWIDTHPIXELS(opci);
131123a0898aSmrg    height = GLYPHHEIGHTPIXELS(opci);
131223a0898aSmrg    newWidth = GLYPHWIDTHPIXELS(pci);
131323a0898aSmrg    newHeight = GLYPHHEIGHTPIXELS(pci);
131423a0898aSmrg    if (!newWidth || !newHeight || !width || !height)
131523a0898aSmrg	return;
131623a0898aSmrg
131723a0898aSmrg    bpr = BYTES_PER_ROW(width, pFont->glyph);
131823a0898aSmrg    newBpr = BYTES_PER_ROW(newWidth, pFont->glyph);
131923a0898aSmrg
132023a0898aSmrg    if (widthMult > 0.0 && heightMult > 0.0 &&
132123a0898aSmrg	(widthMult < 1.0 || heightMult < 1.0))
132223a0898aSmrg    {
132323a0898aSmrg	/* We are reducing in one or both dimensions.  In an attempt to
132423a0898aSmrg	   reduce aliasing, we'll antialias by passing the original
132523a0898aSmrg	   glyph through a low-pass box filter (which results in a
132623a0898aSmrg	   grayscale image), then use error diffusion to create bitonal
132723a0898aSmrg	   output in the resampling loop.  */
132823a0898aSmrg
132923a0898aSmrg	/* First compute the sizes of the box filter */
133023a0898aSmrg	widthMult = ceil(1.0 / widthMult);
133123a0898aSmrg	heightMult = ceil(1.0 / heightMult);
133223a0898aSmrg	box_x = width / 2;
133323a0898aSmrg	box_y = height / 2;
133423a0898aSmrg	if (widthMult < (double)box_x) box_x = (int)widthMult;
133523a0898aSmrg	if (heightMult < (double)box_y) box_y = (int)heightMult;
133623a0898aSmrg	/* The pixmult value (below) is used to darken the image before
133723a0898aSmrg	   we perform error diffusion: a necessary concession to the
133823a0898aSmrg	   fact that it's very difficult to generate readable halftoned
133923a0898aSmrg	   glyphs.  The degree of darkening is proportional to the size
134023a0898aSmrg	   of the blurring filter, hence inversely proportional to the
134123a0898aSmrg	   darkness of the lightest gray that results from antialiasing.
134223a0898aSmrg	   The result is that characters that exercise this logic (those
134323a0898aSmrg	   generated by reducing from a larger source font) tend to err
134423a0898aSmrg	   on the side of being too bold instead of being too light to
134523a0898aSmrg	   be readable. */
134623a0898aSmrg	pixmult = box_x * box_y * 192;
134723a0898aSmrg
134823a0898aSmrg	if (box_x > 1 || box_y > 1)
134923a0898aSmrg	{
135023a0898aSmrg	    /* Looks like we need to anti-alias.  Create a workspace to
135123a0898aSmrg	       contain the grayscale character plus an additional row and
135223a0898aSmrg	       column for scratch */
135323a0898aSmrg	    char_grayscale =
135423a0898aSmrg		(unsigned char *)xalloc((width + 1) * (height + 1));
135523a0898aSmrg	    if (char_grayscale)
135623a0898aSmrg	    {
135723a0898aSmrg		diffusion_workspace =
135823a0898aSmrg		    (INT32 *)xalloc((newWidth + 2) * 2 * sizeof(int));
135923a0898aSmrg		if (!diffusion_workspace)
136023a0898aSmrg		{
136123a0898aSmrg		    fprintf(stderr, "Warning: Couldn't allocate diffusion"
136223a0898aSmrg			    " workspace (%ld)\n",
136323a0898aSmrg			    (newWidth + 2) * 2 * (unsigned long)sizeof(int));
136423a0898aSmrg		    xfree(char_grayscale);
136523a0898aSmrg		    char_grayscale = (unsigned char *)0;
136623a0898aSmrg		}
136723a0898aSmrg		/* Initialize our error diffusion workspace for later use */
136823a0898aSmrg		bzero((char *)diffusion_workspace + sizeof(INT32),
136923a0898aSmrg		      (newWidth + 3) * sizeof(int));
137023a0898aSmrg		thisrow = diffusion_workspace + 1;
137123a0898aSmrg		nextrow = diffusion_workspace + newWidth + 3;
137223a0898aSmrg     } else {
137323a0898aSmrg  fprintf(stderr, "Warning: Couldn't allocate character grayscale (%d)\n", (width + 1) * (height + 1));
137423a0898aSmrg	    }
137523a0898aSmrg	}
137623a0898aSmrg    }
137723a0898aSmrg
137823a0898aSmrg    if (char_grayscale)
137923a0898aSmrg    {
138023a0898aSmrg	/* We will be doing antialiasing.  First copy the bitmap into
138123a0898aSmrg	   our buffer, mapping input range [0,1] to output range
138223a0898aSmrg	   [0,255].  */
138323a0898aSmrg	register unsigned char *srcptr, *dstptr;
138423a0898aSmrg	srcptr = (unsigned char *)bitmap;
138523a0898aSmrg	dstptr = char_grayscale;
138623a0898aSmrg	for (row = 0; row < height; row++)
138723a0898aSmrg	{
138823a0898aSmrg	    for (col = 0; col < width; col++)
138923a0898aSmrg		*dstptr++ = (srcptr[col >> 3] & mask[col & 0x7]) ? 255 : 0;
139023a0898aSmrg	    srcptr += bpr;	/* On to next row of source */
139123a0898aSmrg	    dstptr++;		/* Skip scratch column in dest */
139223a0898aSmrg	}
139323a0898aSmrg	if (box_x > 1)
139423a0898aSmrg	{
139523a0898aSmrg	    /* Our box filter has a width > 1... let's filter the rows */
139623a0898aSmrg
139723a0898aSmrg	    int right_width = box_x / 2;
139823a0898aSmrg	    int left_width = box_x - right_width - 1;
139923a0898aSmrg
140023a0898aSmrg	    for (row = 0; row < height; row++)
140123a0898aSmrg	    {
140223a0898aSmrg		int sum = 0;
140323a0898aSmrg		int left_size = 0, right_size = 0;
140423a0898aSmrg
140523a0898aSmrg		srcptr = char_grayscale + (width + 1) * row;
140623a0898aSmrg		dstptr = char_grayscale + (width + 1) * height; /* scratch */
140723a0898aSmrg
140823a0898aSmrg		/* We've computed the shape of our full box filter.  Now
140923a0898aSmrg		   compute the right-hand part of the moving sum */
141023a0898aSmrg		for (right_size = 0; right_size < right_width; right_size++)
141123a0898aSmrg		    sum += srcptr[right_size];
141223a0898aSmrg
141323a0898aSmrg		/* Now start moving the sum, growing the box filter, and
141423a0898aSmrg		   dropping averages into our scratch buffer */
141523a0898aSmrg		for (left_size = 0; left_size < left_width; left_size++)
141623a0898aSmrg		{
141723a0898aSmrg		    sum += srcptr[right_width];
141823a0898aSmrg		    *dstptr++ = sum / (left_size + right_width + 1);
141923a0898aSmrg		    srcptr++;
142023a0898aSmrg		}
142123a0898aSmrg
142223a0898aSmrg		/* The box filter has reached full width... continue
142323a0898aSmrg		   computation of moving average until the right side
142423a0898aSmrg		   hits the wall. */
142523a0898aSmrg		for (col = left_size; col + right_size < width; col++)
142623a0898aSmrg		{
142723a0898aSmrg		    sum += srcptr[right_width];
142823a0898aSmrg		    *dstptr++ = sum / box_x;
142923a0898aSmrg		    sum -= srcptr[-left_width];
143023a0898aSmrg		    srcptr++;
143123a0898aSmrg		}
143223a0898aSmrg
143323a0898aSmrg		/* Collapse the right side of the box filter */
143423a0898aSmrg		for (; right_size > 0; right_size--)
143523a0898aSmrg		{
143623a0898aSmrg		    *dstptr++ = sum / (left_width + right_size);
143723a0898aSmrg		    sum -= srcptr[-left_width];
143823a0898aSmrg		    srcptr++;
143923a0898aSmrg		}
144023a0898aSmrg
144123a0898aSmrg		/* Done with the row... copy dest back over source */
144223a0898aSmrg		memmove(char_grayscale + (width + 1) * row,
144323a0898aSmrg			char_grayscale + (width + 1) * height,
144423a0898aSmrg			width);
144523a0898aSmrg	    }
144623a0898aSmrg	}
144723a0898aSmrg	if (box_y > 1)
144823a0898aSmrg	{
144923a0898aSmrg	    /* Our box filter has a height > 1... let's filter the columns */
145023a0898aSmrg
145123a0898aSmrg	    int bottom_height = box_y / 2;
145223a0898aSmrg	    int top_height = box_y - bottom_height - 1;
145323a0898aSmrg
145423a0898aSmrg	    for (col = 0; col < width; col++)
145523a0898aSmrg	    {
145623a0898aSmrg		int sum = 0;
145723a0898aSmrg		int top_size = 0, bottom_size = 0;
145823a0898aSmrg
145923a0898aSmrg		srcptr = char_grayscale + col;
146023a0898aSmrg		dstptr = char_grayscale + width;	 /* scratch */
146123a0898aSmrg
146223a0898aSmrg		/* We've computed the shape of our full box filter.  Now
146323a0898aSmrg		   compute the bottom part of the moving sum */
146423a0898aSmrg		for (bottom_size = 0;
146523a0898aSmrg		     bottom_size < bottom_height;
146623a0898aSmrg		     bottom_size++)
146723a0898aSmrg		    sum += srcptr[bottom_size * (width + 1)];
146823a0898aSmrg
146923a0898aSmrg		/* Now start moving the sum, growing the box filter, and
147023a0898aSmrg		   dropping averages into our scratch buffer */
147123a0898aSmrg		for (top_size = 0; top_size < top_height; top_size++)
147223a0898aSmrg		{
147323a0898aSmrg		    sum += srcptr[bottom_height * (width + 1)];
147423a0898aSmrg		    *dstptr = sum / (top_size + bottom_height + 1);
147523a0898aSmrg		    dstptr += width + 1;
147623a0898aSmrg		    srcptr += width + 1;
147723a0898aSmrg		}
147823a0898aSmrg
147923a0898aSmrg		/* The box filter has reached full height... continue
148023a0898aSmrg		   computation of moving average until the bottom
148123a0898aSmrg		   hits the wall. */
148223a0898aSmrg		for (row = top_size; row + bottom_size < height; row++)
148323a0898aSmrg		{
148423a0898aSmrg		    sum += srcptr[bottom_height * (width + 1)];
148523a0898aSmrg		    *dstptr = sum / box_y;
148623a0898aSmrg		    dstptr += width + 1;
148723a0898aSmrg		    sum -= srcptr[-top_height * (width + 1)];
148823a0898aSmrg		    srcptr += width + 1;
148923a0898aSmrg		}
149023a0898aSmrg
149123a0898aSmrg		/* Collapse the bottom of the box filter */
149223a0898aSmrg		for (; bottom_size > 0; bottom_size--)
149323a0898aSmrg		{
149423a0898aSmrg		    *dstptr = sum / (top_height + bottom_size);
149523a0898aSmrg		    dstptr += width + 1;
149623a0898aSmrg		    sum -= srcptr[-top_height * (width + 1)];
149723a0898aSmrg		    srcptr += width + 1;
149823a0898aSmrg		}
149923a0898aSmrg
150023a0898aSmrg		/* Done with the column... copy dest back over source */
150123a0898aSmrg
150223a0898aSmrg		dstptr = char_grayscale + col;
150323a0898aSmrg		srcptr = char_grayscale + width;	 /* scratch */
150423a0898aSmrg		for (row = 0; row < height; row++)
150523a0898aSmrg		{
150623a0898aSmrg		    *dstptr = *srcptr;
150723a0898aSmrg		    dstptr += width + 1;
150823a0898aSmrg		    srcptr += width + 1;
150923a0898aSmrg		}
151023a0898aSmrg	    }
151123a0898aSmrg	}
151223a0898aSmrg
151323a0898aSmrg	/* Increase the grayvalue to increase ink a bit */
151423a0898aSmrg	srcptr = char_grayscale;
151523a0898aSmrg	for (row = 0; row < height; row++)
151623a0898aSmrg	{
151723a0898aSmrg	    for (col = 0; col < width; col++)
151823a0898aSmrg	    {
151923a0898aSmrg		register int pixvalue = (int)*srcptr * pixmult / 256;
152023a0898aSmrg		if (pixvalue > 255) pixvalue = 255;
152123a0898aSmrg		*srcptr = pixvalue;
152223a0898aSmrg		srcptr++;
152323a0898aSmrg	    }
152423a0898aSmrg	    srcptr++;
152523a0898aSmrg	}
152623a0898aSmrg    }
152723a0898aSmrg
152823a0898aSmrg    /* Compute the increment values for the resampling loop */
152923a0898aSmrg    TRANSFORM_POINT(inv_xform, 1, 0, point);
153023a0898aSmrg    deltaX = (INT32)(point[0] * 65536.0);
153123a0898aSmrg    deltaY = (INT32)(-point[1] * 65536.0);
153223a0898aSmrg
153323a0898aSmrg    /* Resampling loop:  resamples original glyph for generation of new
153423a0898aSmrg       glyph in transformed coordinate system. */
153523a0898aSmrg
153623a0898aSmrg    for (row = 0; row < newHeight; row++)
153723a0898aSmrg    {
153823a0898aSmrg	/* Compute inverse transformation for start of this row */
153923a0898aSmrg	TRANSFORM_POINT(inv_xform,
154023a0898aSmrg			(double)(pci->metrics.leftSideBearing) + .5,
154123a0898aSmrg			(double)(pci->metrics.ascent - row) - .5,
154223a0898aSmrg			point);
154323a0898aSmrg
154423a0898aSmrg	/* Adjust for coordinate system to get resampling point */
154523a0898aSmrg	point[0] -= opci->metrics.leftSideBearing;
154623a0898aSmrg	point[1] = opci->metrics.ascent - point[1];
154723a0898aSmrg
154823a0898aSmrg	/* Convert to integer coordinates */
154923a0898aSmrg	xValue = (INT32)(point[0] * 65536.0);
155023a0898aSmrg	yValue = (INT32)(point[1] * 65536.0);
155123a0898aSmrg
155223a0898aSmrg	if (char_grayscale)
155323a0898aSmrg	{
155423a0898aSmrg	    INT32 *temp;
155523a0898aSmrg	    for (col = 0; col < newWidth; col++)
155623a0898aSmrg	    {
155723a0898aSmrg		register int x = xValue >> 16, y = yValue >> 16;
155823a0898aSmrg		int pixvalue, error;
155923a0898aSmrg
156023a0898aSmrg		pixvalue = ((x >= 0 && x < width && y >= 0 && y < height) ?
156123a0898aSmrg			    char_grayscale[x + y * (width + 1)] : 0) +
156223a0898aSmrg			   thisrow[col] / 16;
156323a0898aSmrg		if (pixvalue > 255) pixvalue = 255;
156423a0898aSmrg		else if (pixvalue < 0) pixvalue = 0;
156523a0898aSmrg
156623a0898aSmrg		/* Choose the bit value and set resulting error value */
156723a0898aSmrg		if (pixvalue >= 128)
156823a0898aSmrg		{
156923a0898aSmrg		    newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7];
157023a0898aSmrg		    error = pixvalue - 255;
157123a0898aSmrg		}
157223a0898aSmrg		else
157323a0898aSmrg		    error = -pixvalue;
157423a0898aSmrg
157523a0898aSmrg		/* Diffuse the error */
157623a0898aSmrg		thisrow[col + 1] += error * 7;
157723a0898aSmrg		nextrow[col - 1] += error * 3;
157823a0898aSmrg		nextrow[col] += error * 5;
157923a0898aSmrg		nextrow[col + 1] = error;
158023a0898aSmrg
158123a0898aSmrg		xValue += deltaX;
158223a0898aSmrg		yValue += deltaY;
158323a0898aSmrg	    }
158423a0898aSmrg
158523a0898aSmrg	    /* Add in error values that fell off either end */
158623a0898aSmrg	    nextrow[0] += nextrow[-1];
158723a0898aSmrg	    nextrow[newWidth - 2] += thisrow[newWidth];
158823a0898aSmrg	    nextrow[newWidth - 1] += nextrow[newWidth];
158923a0898aSmrg	    nextrow[newWidth] = 0;
159023a0898aSmrg
159123a0898aSmrg	    temp = nextrow;
159223a0898aSmrg	    nextrow = thisrow;
159323a0898aSmrg	    thisrow = temp;
159423a0898aSmrg	    nextrow[-1] = nextrow[0] = 0;
159523a0898aSmrg	}
159623a0898aSmrg	else
159723a0898aSmrg	{
159823a0898aSmrg	    for (col = 0; col < newWidth; col++)
159923a0898aSmrg	    {
160023a0898aSmrg		register int x = xValue >> 16, y = yValue >> 16;
160123a0898aSmrg
160223a0898aSmrg		if (x >= 0 && x < width && y >= 0 && y < height)
160323a0898aSmrg		{
160423a0898aSmrg		    /* Use point-sampling for rescaling. */
160523a0898aSmrg
160623a0898aSmrg		    if (bitmap[(x >> 3) + y * bpr] & mask[x & 0x7])
160723a0898aSmrg			newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7];
160823a0898aSmrg		}
160923a0898aSmrg
161023a0898aSmrg		xValue += deltaX;
161123a0898aSmrg		yValue += deltaY;
161223a0898aSmrg	    }
161323a0898aSmrg	}
161423a0898aSmrg    }
161523a0898aSmrg
161623a0898aSmrg
161723a0898aSmrg    if (char_grayscale)
161823a0898aSmrg    {
161923a0898aSmrg	xfree(char_grayscale);
162023a0898aSmrg	xfree(diffusion_workspace);
162123a0898aSmrg    }
162223a0898aSmrg}
162323a0898aSmrg
162423a0898aSmrgstatic FontPtr
162523a0898aSmrgBitmapScaleBitmaps(FontPtr pf,          /* scaled font */
162623a0898aSmrg		   FontPtr opf,         /* originating font */
162723a0898aSmrg		   double widthMult,    /* glyphs width scale factor */
162823a0898aSmrg		   double heightMult,   /* glyphs height scale factor */
162923a0898aSmrg		   FontScalablePtr vals)
163023a0898aSmrg{
163123a0898aSmrg    register int i;
163223a0898aSmrg    int		nchars = 0;
163323a0898aSmrg    char       *glyphBytes;
163423a0898aSmrg    BitmapFontPtr  bitmapFont,
163523a0898aSmrg		   obitmapFont;
163623a0898aSmrg    CharInfoPtr pci,
163723a0898aSmrg		opci;
163823a0898aSmrg    FontInfoPtr pfi;
163923a0898aSmrg    int         glyph;
164023a0898aSmrg    unsigned    bytestoalloc = 0;
164123a0898aSmrg    int		firstCol, lastCol, firstRow, lastRow;
164223a0898aSmrg
164323a0898aSmrg    double	xform[4], inv_xform[4];
164423a0898aSmrg    double	xmult, ymult;
164523a0898aSmrg
164623a0898aSmrg    bitmapFont = (BitmapFontPtr) pf->fontPrivate;
164723a0898aSmrg    obitmapFont = (BitmapFontPtr) opf->fontPrivate;
164823a0898aSmrg
164923a0898aSmrg    if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
165023a0898aSmrg			      inv_xform, &xmult, &ymult))
165123a0898aSmrg	goto bail;
165223a0898aSmrg
165323a0898aSmrg    pfi = &pf->info;
165423a0898aSmrg    firstCol = pfi->firstCol;
165523a0898aSmrg    lastCol = pfi->lastCol;
165623a0898aSmrg    firstRow = pfi->firstRow;
165723a0898aSmrg    lastRow = pfi->lastRow;
165823a0898aSmrg
165923a0898aSmrg    nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
166023a0898aSmrg    glyph = pf->glyph;
166123a0898aSmrg    for (i = 0; i < nchars; i++)
166223a0898aSmrg    {
166323a0898aSmrg	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)))
166423a0898aSmrg	    bytestoalloc += BYTES_FOR_GLYPH(pci, glyph);
166523a0898aSmrg    }
166623a0898aSmrg
166723a0898aSmrg    /* Do we add the font malloc stuff for VALUE ADDED ? */
166823a0898aSmrg    /* Will need to remember to free in the Unload routine */
166923a0898aSmrg
167023a0898aSmrg
167123a0898aSmrg    bitmapFont->bitmaps = (char *) xalloc(bytestoalloc);
167223a0898aSmrg    if (!bitmapFont->bitmaps) {
167323a0898aSmrg fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc);
167423a0898aSmrg	goto bail;
167523a0898aSmrg    }
167623a0898aSmrg    bzero(bitmapFont->bitmaps, bytestoalloc);
167723a0898aSmrg
167823a0898aSmrg    glyphBytes = bitmapFont->bitmaps;
167923a0898aSmrg    for (i = 0; i < nchars; i++)
168023a0898aSmrg    {
168123a0898aSmrg	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) &&
168223a0898aSmrg	    (opci = ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i))))
168323a0898aSmrg	{
168423a0898aSmrg	    pci->bits = glyphBytes;
168523a0898aSmrg	    ScaleBitmap (pf, opci, pci, inv_xform,
168623a0898aSmrg			 widthMult, heightMult);
168723a0898aSmrg	    glyphBytes += BYTES_FOR_GLYPH(pci, glyph);
168823a0898aSmrg	}
168923a0898aSmrg    }
169023a0898aSmrg    return pf;
169123a0898aSmrg
169223a0898aSmrgbail:
169323a0898aSmrg    if (pf)
169423a0898aSmrg	xfree(pf);
169523a0898aSmrg    if (bitmapFont) {
169623a0898aSmrg	xfree(bitmapFont->metrics);
169723a0898aSmrg	xfree(bitmapFont->ink_metrics);
169823a0898aSmrg	xfree(bitmapFont->bitmaps);
169923a0898aSmrg        if(bitmapFont->encoding)
170023a0898aSmrg            for(i=0; i<NUM_SEGMENTS(nchars); i++)
170123a0898aSmrg                xfree(bitmapFont->encoding[i]);
170223a0898aSmrg	xfree(bitmapFont->encoding);
170323a0898aSmrg    }
170423a0898aSmrg    return NULL;
170523a0898aSmrg}
170623a0898aSmrg
170723a0898aSmrgstatic FontPtr
170823a0898aSmrgPrinterScaleBitmaps(FontPtr pf,         /* scaled font */
170923a0898aSmrg		    FontPtr opf, 	/* originating font */
171023a0898aSmrg		    double widthMult, 	/* glyphs width scale factor */
171123a0898aSmrg		    double heightMult, 	/* glyphs height scale factor */
171223a0898aSmrg		    FontScalablePtr vals)
171323a0898aSmrg{
171423a0898aSmrg    register int i;
171523a0898aSmrg    int		nchars = 0;
171623a0898aSmrg    char       *glyphBytes;
171723a0898aSmrg    BitmapFontPtr  bitmapFont,
171823a0898aSmrg		   obitmapFont;
171923a0898aSmrg    CharInfoPtr pci;
172023a0898aSmrg    FontInfoPtr pfi;
172123a0898aSmrg    int         glyph;
172223a0898aSmrg    unsigned    bytestoalloc = 0;
172323a0898aSmrg    int		firstCol, lastCol, firstRow, lastRow;
172423a0898aSmrg
172523a0898aSmrg    double	xform[4], inv_xform[4];
172623a0898aSmrg    double	xmult, ymult;
172723a0898aSmrg
172823a0898aSmrg    bitmapFont = (BitmapFontPtr) pf->fontPrivate;
172923a0898aSmrg    obitmapFont = (BitmapFontPtr) opf->fontPrivate;
173023a0898aSmrg
173123a0898aSmrg    if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
173223a0898aSmrg			      inv_xform, &xmult, &ymult))
173323a0898aSmrg	goto bail;
173423a0898aSmrg
173523a0898aSmrg    pfi = &pf->info;
173623a0898aSmrg    firstCol = pfi->firstCol;
173723a0898aSmrg    lastCol = pfi->lastCol;
173823a0898aSmrg    firstRow = pfi->firstRow;
173923a0898aSmrg    lastRow = pfi->lastRow;
174023a0898aSmrg
174123a0898aSmrg    nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
174223a0898aSmrg    glyph = pf->glyph;
174323a0898aSmrg    for (i = 0; i < nchars; i++)
174423a0898aSmrg    {
174523a0898aSmrg	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)))
174623a0898aSmrg	    bytestoalloc = MAX(bytestoalloc,BYTES_FOR_GLYPH(pci, glyph));
174723a0898aSmrg    }
174823a0898aSmrg
174923a0898aSmrg    /* Do we add the font malloc stuff for VALUE ADDED ? */
175023a0898aSmrg    /* Will need to remember to free in the Unload routine */
175123a0898aSmrg
175223a0898aSmrg
175323a0898aSmrg    bitmapFont->bitmaps = (char *) xalloc(bytestoalloc);
175423a0898aSmrg    if (!bitmapFont->bitmaps) {
175523a0898aSmrg fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc);
175623a0898aSmrg	goto bail;
175723a0898aSmrg    }
175823a0898aSmrg    bzero(bitmapFont->bitmaps, bytestoalloc);
175923a0898aSmrg
176023a0898aSmrg    glyphBytes = bitmapFont->bitmaps;
176123a0898aSmrg    for (i = 0; i < nchars; i++)
176223a0898aSmrg    {
176323a0898aSmrg	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) &&
176423a0898aSmrg	    (ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i))))
176523a0898aSmrg	{
176623a0898aSmrg	    pci->bits = glyphBytes;
176723a0898aSmrg	}
176823a0898aSmrg    }
176923a0898aSmrg    return pf;
177023a0898aSmrg
177123a0898aSmrgbail:
177223a0898aSmrg    if (pf)
177323a0898aSmrg	xfree(pf);
177423a0898aSmrg    if (bitmapFont) {
177523a0898aSmrg	xfree(bitmapFont->metrics);
177623a0898aSmrg	xfree(bitmapFont->ink_metrics);
177723a0898aSmrg	xfree(bitmapFont->bitmaps);
177823a0898aSmrg        if(bitmapFont->encoding)
177923a0898aSmrg            for(i=0; i<NUM_SEGMENTS(nchars); i++)
178023a0898aSmrg                xfree(bitmapFont->encoding[i]);
178123a0898aSmrg	xfree(bitmapFont->encoding);
178223a0898aSmrg    }
178323a0898aSmrg    return NULL;
178423a0898aSmrg}
178523a0898aSmrg
178623a0898aSmrg#ifdef NOTDEF
178723a0898aSmrg/*
178823a0898aSmrg *	exported interfaces
178923a0898aSmrg */
179023a0898aSmrg
179123a0898aSmrgFontFileLoadName(FontFileDirPtr *dirs, int ndirs, char *name, FontPtr *pfont,
179223a0898aSmrg		 fsBitmapFormat format, fsBitmapFormatMask fmask)
179323a0898aSmrg{
179423a0898aSmrg    FontFileNamePtr fname;
179523a0898aSmrg    char        full_name[1024];
179623a0898aSmrg    int         ret = BadFontName;
179723a0898aSmrg    int         i;
179823a0898aSmrg
179923a0898aSmrg    i = 0;
180023a0898aSmrg    while (i < ndirs) {
180123a0898aSmrg	if (fname = FontFileFindNameInDir(dirs[i], name)) {
180223a0898aSmrg	    if (!fname->alias) {
180323a0898aSmrg		if (!fname->font) {
180423a0898aSmrg		    strcpy(full_name, dirs[i]->dir);
180523a0898aSmrg		    strcat(full_name, fname->file);
180623a0898aSmrg		    ret = FontFileLoad(pfont, full_name, format, fmask);
180723a0898aSmrg		    if (ret == Successful) {
180823a0898aSmrg			fname->font = *pfont;
180923a0898aSmrg			(*pfont)->fpePrivate = (pointer) fname;
181023a0898aSmrg		    }
181123a0898aSmrg		    return ret;
181223a0898aSmrg		}
181323a0898aSmrg		*pfont = fname->font;
181423a0898aSmrg		return Successful;
181523a0898aSmrg	    }
181623a0898aSmrg	    name = fname->file;
181723a0898aSmrg	    i = 0;
181823a0898aSmrg	} else
181923a0898aSmrg	    i++;
182023a0898aSmrg    }
182123a0898aSmrg    return BadFontName;
182223a0898aSmrg}
182323a0898aSmrg#endif
182423a0898aSmrg
182523a0898aSmrg/* ARGSUSED */
182623a0898aSmrgint
182723a0898aSmrgBitmapOpenScalable (FontPathElementPtr fpe,
182823a0898aSmrg		    FontPtr *pFont,
182923a0898aSmrg		    int flags,
183023a0898aSmrg		    FontEntryPtr entry,
183123a0898aSmrg		    char *fileName, /* unused */
183223a0898aSmrg		    FontScalablePtr vals,
183323a0898aSmrg		    fsBitmapFormat format,
183423a0898aSmrg		    fsBitmapFormatMask fmask,
183523a0898aSmrg		    FontPtr non_cachable_font)	/* We don't do licensing */
183623a0898aSmrg{
183723a0898aSmrg    FontScalableRec	best;
183823a0898aSmrg    FontPtr		font = NullFont;
183923a0898aSmrg    double		dx, sdx,
184023a0898aSmrg			dy, sdy,
184123a0898aSmrg			savedX, savedY;
184223a0898aSmrg    FontPropPtr		props;
184323a0898aSmrg    char		*isStringProp = NULL;
184423a0898aSmrg    int			propCount;
184523a0898aSmrg    int			status;
184623a0898aSmrg    long		sWidth;
184723a0898aSmrg
184823a0898aSmrg    FontEntryPtr	scaleFrom;
184923a0898aSmrg    FontPathElementPtr	scaleFPE;
185023a0898aSmrg    FontPtr		sourceFont;
185123a0898aSmrg    char		fontName[MAXFONTNAMELEN];
185223a0898aSmrg
185323a0898aSmrg    /* Can't deal with mix-endian fonts yet */
185423a0898aSmrg
185523a0898aSmrg#ifdef NOTDEF /* XXX need better test */
185623a0898aSmrg    if ((format & BitmapFormatByteOrderMask) !=
185723a0898aSmrg	    (format & BitmapFormatBitOrderMask))
185823a0898aSmrg	return NullFontFileName;
185923a0898aSmrg#endif
186023a0898aSmrg
186123a0898aSmrg    /* Reject outrageously small font sizes to keep the math from
186223a0898aSmrg       blowing up. */
186323a0898aSmrg    if (get_matrix_vertical_component(vals->pixel_matrix) < 1.0 ||
186423a0898aSmrg	get_matrix_horizontal_component(vals->pixel_matrix) < 1.0)
186523a0898aSmrg	return BadFontName;
186623a0898aSmrg
186723a0898aSmrg    scaleFrom = (*find_scale[BitmapGetRenderIndex(entry->u.bitmap.renderer)])
186823a0898aSmrg		    (fpe, entry, vals, &best, &dx, &dy, &sdx, &sdy, &scaleFPE);
186923a0898aSmrg
187023a0898aSmrg    if (!scaleFrom)
187123a0898aSmrg	return BadFontName;
187223a0898aSmrg
187323a0898aSmrg    status = FontFileOpenBitmap(scaleFPE, &sourceFont, LoadAll, scaleFrom,
187423a0898aSmrg				format, fmask);
187523a0898aSmrg
187623a0898aSmrg    if (status != Successful)
187723a0898aSmrg	return BadFontName;
187823a0898aSmrg
187923a0898aSmrg    if (!vals->width)
188023a0898aSmrg	vals->width = best.width * dx;
188123a0898aSmrg
188223a0898aSmrg    /* Compute the scaled font */
188323a0898aSmrg
188423a0898aSmrg    savedX = dx;
188523a0898aSmrg    savedY = dy;
188623a0898aSmrg    font = ScaleFont(sourceFont, dx, dy, sdx, sdy, vals, &dx, &dy, &sWidth);
188723a0898aSmrg    if (font)
188823a0898aSmrg	font = (*scale[ BitmapGetRenderIndex(entry->u.bitmap.renderer) ])
188923a0898aSmrg			(font, sourceFont, savedX, savedY, vals);
189023a0898aSmrg
189123a0898aSmrg    if (!font)
189223a0898aSmrg    {
189323a0898aSmrg	if (!sourceFont->refcnt)
189423a0898aSmrg	    FontFileCloseFont((FontPathElementPtr) 0, sourceFont);
189523a0898aSmrg	return AllocError;
189623a0898aSmrg    }
189723a0898aSmrg
189823a0898aSmrg    /* Prepare font properties for the new font */
189923a0898aSmrg
190023a0898aSmrg    strcpy (fontName, scaleFrom->name.name);
190123a0898aSmrg    FontParseXLFDName (fontName, vals, FONT_XLFD_REPLACE_VALUE);
190223a0898aSmrg
190323a0898aSmrg    propCount = ComputeScaledProperties(&sourceFont->info, fontName, vals,
190423a0898aSmrg					dx, dy, sdx, sdy, sWidth, &props,
190523a0898aSmrg					&isStringProp);
190623a0898aSmrg
190723a0898aSmrg    if (!sourceFont->refcnt)
190823a0898aSmrg	FontFileCloseFont((FontPathElementPtr) 0, sourceFont);
190923a0898aSmrg
191023a0898aSmrg    if (propCount && (!props || !isStringProp))
191123a0898aSmrg    {
191223a0898aSmrg	font->info.nprops = 0;
191323a0898aSmrg	font->info.props = (FontPropPtr)0;
191423a0898aSmrg	font->info.isStringProp = (char *)0;
191523a0898aSmrg	bitmapUnloadScalable(font);
191623a0898aSmrg	return AllocError;
191723a0898aSmrg    }
191823a0898aSmrg
191923a0898aSmrg    font->info.props = props;
192023a0898aSmrg    font->info.nprops = propCount;
192123a0898aSmrg    font->info.isStringProp = isStringProp;
192223a0898aSmrg
192323a0898aSmrg    *pFont = font;
192423a0898aSmrg    return Successful;
192523a0898aSmrg}
192623a0898aSmrg
192723a0898aSmrgint
192823a0898aSmrgBitmapGetInfoScalable (FontPathElementPtr fpe,
192923a0898aSmrg		       FontInfoPtr pFontInfo,
193023a0898aSmrg		       FontEntryPtr entry,
193123a0898aSmrg		       FontNamePtr fontName,
193223a0898aSmrg		       char *fileName,
193323a0898aSmrg		       FontScalablePtr vals)
193423a0898aSmrg{
193523a0898aSmrg    FontPtr pfont;
193623a0898aSmrg    int flags = 0;
193723a0898aSmrg    long format = 0;  /* It doesn't matter what format for just info */
193823a0898aSmrg    long fmask = 0;
193923a0898aSmrg    int ret;
194023a0898aSmrg
194123a0898aSmrg    ret = BitmapOpenScalable(fpe, &pfont, flags, entry, fileName, vals,
194223a0898aSmrg			     format, fmask, NULL);
194323a0898aSmrg    if (ret != Successful)
194423a0898aSmrg        return ret;
194523a0898aSmrg    *pFontInfo = pfont->info;
194623a0898aSmrg
194723a0898aSmrg    pfont->info.nprops = 0;
194823a0898aSmrg    pfont->info.props = NULL;
194923a0898aSmrg    pfont->info.isStringProp = NULL;
195023a0898aSmrg
195123a0898aSmrg    (*pfont->unload_font)(pfont);
195223a0898aSmrg    return Successful;
195323a0898aSmrg}
195423a0898aSmrg
195523a0898aSmrgstatic void
195623a0898aSmrgbitmapUnloadScalable (FontPtr pFont)
195723a0898aSmrg{
195823a0898aSmrg    BitmapFontPtr   bitmapFont;
195923a0898aSmrg    FontInfoPtr	    pfi;
196023a0898aSmrg    int             i, nencoding;
196123a0898aSmrg
196223a0898aSmrg    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
196323a0898aSmrg    pfi = &pFont->info;
196423a0898aSmrg    xfree (pfi->props);
196523a0898aSmrg    xfree (pfi->isStringProp);
196623a0898aSmrg    if(bitmapFont->encoding) {
196723a0898aSmrg        nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
196823a0898aSmrg	    (pFont->info.lastRow - pFont->info.firstRow + 1);
196923a0898aSmrg        for(i=0; i<NUM_SEGMENTS(nencoding); i++)
197023a0898aSmrg            xfree(bitmapFont->encoding[i]);
197123a0898aSmrg    }
197223a0898aSmrg    xfree (bitmapFont->encoding);
197323a0898aSmrg    xfree (bitmapFont->bitmaps);
197423a0898aSmrg    xfree (bitmapFont->ink_metrics);
197523a0898aSmrg    xfree (bitmapFont->metrics);
197623a0898aSmrg    xfree (pFont->fontPrivate);
197723a0898aSmrg    DestroyFontRec (pFont);
197823a0898aSmrg}
1979