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