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