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