bitscale.c revision 23a0898a
1/* $Xorg: bitscale.c,v 1.5 2001/02/09 02:04:02 xorgcvs Exp $ */
2/*
3
4Copyright 1991, 1994, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included
13in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall
24not be used in advertising or otherwise to promote the sale, use or
25other dealings in this Software without prior written authorization
26from The Open Group.
27
28*/
29/* $XFree86: xc/lib/font/bitmap/bitscale.c,v 3.29tsi Exp $ */
30
31/*
32 * Author:  Keith Packard, MIT X Consortium
33 */
34
35#ifdef HAVE_CONFIG_H
36#include <config.h>
37#endif
38
39/*
40 * Translate monolithic #defines to modular definitions
41 */
42
43#ifdef PCFFORMAT
44#define XFONT_PCFFORMAT 1
45#endif
46
47#ifdef SNFFORMAT
48#define XFONT_SNFFORMAT 1
49#endif
50
51#ifdef BDFFORMAT
52#define XFONT_BDFFORMAT 1
53#endif
54
55#include <X11/fonts/fntfilst.h>
56#include <X11/fonts/bitmap.h>
57#include <X11/fonts/fontutil.h>
58#ifndef FONTMODULE
59#ifdef _XOPEN_SOURCE
60#include <math.h>
61#else
62#define _XOPEN_SOURCE	/* to get prototype for hypot on some systems */
63#include <math.h>
64#undef _XOPEN_SOURCE
65#endif
66#endif
67
68#ifndef MAX
69#define   MAX(a,b)    (((a)>(b)) ? a : b)
70#endif
71
72/* Should get this from elsewhere */
73extern unsigned long serverGeneration;
74
75static void bitmapUnloadScalable (FontPtr pFont);
76static void ScaleBitmap ( FontPtr pFont, CharInfoPtr opci,
77			  CharInfoPtr pci, double *inv_xform,
78			  double widthMult, double heightMult );
79static FontPtr BitmapScaleBitmaps(FontPtr pf, FontPtr opf,
80				  double widthMult, double heightMult,
81				  FontScalablePtr vals);
82static FontPtr PrinterScaleBitmaps(FontPtr pf, FontPtr opf,
83				   double widthMult, double heightMult,
84				   FontScalablePtr vals);
85
86enum scaleType {
87    atom, truncate_atom, pixel_size, point_size, resolution_x,
88    resolution_y, average_width, scaledX, scaledY, unscaled, fontname,
89    raw_ascent, raw_descent, raw_pixelsize, raw_pointsize,
90    raw_average_width, uncomputed
91};
92
93typedef struct _fontProp {
94    char       *name;
95    Atom        atom;
96    enum scaleType type;
97} fontProp;
98
99typedef FontPtr (*ScaleFunc) ( FontPtr /* pf */,
100			       FontPtr /* opf */,
101			       double /* widthMult */,
102			       double /* heightMult */,
103			       FontScalablePtr /* vals */);
104
105/* These next two arrays must be kept in step with the renderer array */
106static const ScaleFunc scale[] =
107{
108#if XFONT_PCFFORMAT
109    BitmapScaleBitmaps,
110    BitmapScaleBitmaps,
111#ifdef X_GZIP_FONT_COMPRESSION
112    BitmapScaleBitmaps,
113#endif
114#endif
115#if XFONT_SNFFORMAT
116    BitmapScaleBitmaps,
117    BitmapScaleBitmaps,
118#ifdef X_GZIP_FONT_COMPRESSION
119    BitmapScaleBitmaps,
120#endif
121#endif
122#if XFONT_BDFFORMAT
123    BitmapScaleBitmaps,
124    BitmapScaleBitmaps,
125#ifdef X_GZIP_FONT_COMPRESSION
126    BitmapScaleBitmaps,
127#endif
128#endif
129#if XFONT_PCFFORMAT
130    PrinterScaleBitmaps,
131#endif
132};
133
134static FontEntryPtr FindBestToScale ( FontPathElementPtr fpe,
135				      FontEntryPtr entry,
136				      FontScalablePtr vals,
137				      FontScalablePtr best,
138				      double *dxp, double *dyp,
139				      double *sdxp, double *sdyp,
140				      FontPathElementPtr *fpep );
141static FontEntryPtr FindPmfToScale ( FontPathElementPtr fpe,
142				     FontEntryPtr entry,
143				     FontScalablePtr vals,
144				     FontScalablePtr best,
145				     double *dxp, double *dyp,
146				     double *sdxp, double *sdyp,
147				     FontPathElementPtr *fpep );
148
149typedef FontEntryPtr (*FindToScale) (FontPathElementPtr fpe,
150				     FontEntryPtr entry,
151				     FontScalablePtr vals,
152				     FontScalablePtr best,
153				     double *dxp, double *dyp,
154				     double *sdxp, double *sdyp,
155				     FontPathElementPtr *fpep);
156static const FindToScale find_scale[] =
157{
158#if XFONT_PCFFORMAT
159    FindBestToScale,
160    FindBestToScale,
161#ifdef X_GZIP_FONT_COMPRESSION
162    FindBestToScale,
163#endif
164#endif
165#if XFONT_SNFFORMAT
166    FindBestToScale,
167    FindBestToScale,
168#ifdef X_GZIP_FONT_COMPRESSION
169    FindBestToScale,
170#endif
171#endif
172#if XFONT_BDFFORMAT
173    FindBestToScale,
174    FindBestToScale,
175#ifdef X_GZIP_FONT_COMPRESSION
176    FindBestToScale,
177#endif
178#endif
179#if XFONT_PCFFORMAT
180    FindPmfToScale,
181#endif
182};
183
184static unsigned long bitscaleGeneration = 0;	/* initialization flag */
185
186static fontProp fontNamePropTable[] = {
187    { "FOUNDRY", 0, atom },
188    { "FAMILY_NAME", 0, atom },
189    { "WEIGHT_NAME", 0, atom },
190    { "SLANT", 0, atom },
191    { "SETWIDTH_NAME", 0, atom },
192    { "ADD_STYLE_NAME", 0, atom },
193    { "PIXEL_SIZE", 0, pixel_size },
194    { "POINT_SIZE", 0, point_size },
195    { "RESOLUTION_X", 0, resolution_x },
196    { "RESOLUTION_Y", 0, resolution_y },
197    { "SPACING", 0, atom },
198    { "AVERAGE_WIDTH", 0, average_width },
199    { "CHARSET_REGISTRY", 0, atom },
200    { "CHARSET_ENCODING", 0, truncate_atom },
201    { "FONT", 0, fontname },
202    { "RAW_ASCENT", 0, raw_ascent },
203    { "RAW_DESCENT", 0, raw_descent },
204    { "RAW_PIXEL_SIZE", 0, raw_pixelsize },
205    { "RAW_POINT_SIZE", 0, raw_pointsize },
206    { "RAW_AVERAGE_WIDTH", 0, raw_average_width }
207};
208
209#define TRANSFORM_POINT(matrix, x, y, dest) \
210	((dest)[0] = (matrix)[0] * (x) + (matrix)[2] * (y), \
211	 (dest)[1] = (matrix)[1] * (x) + (matrix)[3] * (y))
212
213#define CHECK_EXTENT(lsb, rsb, desc, asc, data) \
214	((lsb) > (data)[0] ? (lsb) = (data)[0] : 0 , \
215	 (rsb) < (data)[0] ? (rsb) = (data)[0] : 0, \
216	 (-desc) > (data)[1] ? (desc) = -(data)[1] : 0 , \
217	 (asc) < (data)[1] ? (asc) = (data)[1] : 0)
218
219#define NPROPS (sizeof(fontNamePropTable) / sizeof(fontProp))
220
221/* Warning: order of the next two tables is critically interdependent.
222   Location of "unscaled" properties at the end of fontPropTable[]
223   is important. */
224
225static fontProp fontPropTable[] = {
226    { "MIN_SPACE", 0, scaledX },
227    { "NORM_SPACE", 0, scaledX },
228    { "MAX_SPACE", 0, scaledX },
229    { "END_SPACE", 0, scaledX },
230    { "AVG_CAPITAL_WIDTH", 0, scaledX },
231    { "AVG_LOWERCASE_WIDTH", 0, scaledX },
232    { "QUAD_WIDTH", 0, scaledX },
233    { "FIGURE_WIDTH", 0, scaledX },
234    { "SUPERSCRIPT_X", 0, scaledX },
235    { "SUPERSCRIPT_Y", 0, scaledY },
236    { "SUBSCRIPT_X", 0, scaledX },
237    { "SUBSCRIPT_Y", 0, scaledY },
238    { "SUPERSCRIPT_SIZE", 0, scaledY },
239    { "SUBSCRIPT_SIZE", 0, scaledY },
240    { "SMALL_CAP_SIZE", 0, scaledY },
241    { "UNDERLINE_POSITION", 0, scaledY },
242    { "UNDERLINE_THICKNESS", 0, scaledY },
243    { "STRIKEOUT_ASCENT", 0, scaledY },
244    { "STRIKEOUT_DESCENT", 0, scaledY },
245    { "CAP_HEIGHT", 0, scaledY },
246    { "X_HEIGHT", 0, scaledY },
247    { "ITALIC_ANGLE", 0, unscaled },
248    { "RELATIVE_SETWIDTH", 0, unscaled },
249    { "RELATIVE_WEIGHT", 0, unscaled },
250    { "WEIGHT", 0, unscaled },
251    { "DESTINATION", 0, unscaled },
252    { "PCL_FONT_NAME", 0, unscaled },
253    { "_ADOBE_POSTSCRIPT_FONTNAME", 0, unscaled }
254};
255
256/* sleazy way to shut up the compiler */
257#define zerohack (enum scaleType)0
258
259static fontProp rawFontPropTable[] = {
260    { "RAW_MIN_SPACE", 0, },
261    { "RAW_NORM_SPACE", 0, },
262    { "RAW_MAX_SPACE", 0, },
263    { "RAW_END_SPACE", 0, },
264    { "RAW_AVG_CAPITAL_WIDTH", 0, },
265    { "RAW_AVG_LOWERCASE_WIDTH", 0, },
266    { "RAW_QUAD_WIDTH", 0, },
267    { "RAW_FIGURE_WIDTH", 0, },
268    { "RAW_SUPERSCRIPT_X", 0, },
269    { "RAW_SUPERSCRIPT_Y", 0, },
270    { "RAW_SUBSCRIPT_X", 0, },
271    { "RAW_SUBSCRIPT_Y", 0, },
272    { "RAW_SUPERSCRIPT_SIZE", 0, },
273    { "RAW_SUBSCRIPT_SIZE", 0, },
274    { "RAW_SMALL_CAP_SIZE", 0, },
275    { "RAW_UNDERLINE_POSITION", 0, },
276    { "RAW_UNDERLINE_THICKNESS", 0, },
277    { "RAW_STRIKEOUT_ASCENT", 0, },
278    { "RAW_STRIKEOUT_DESCENT", 0, },
279    { "RAW_CAP_HEIGHT", 0, },
280    { "RAW_X_HEIGHT", 0, }
281};
282
283static void
284initFontPropTable(void)
285{
286    int         i;
287    fontProp   *t;
288
289    i = sizeof(fontNamePropTable) / sizeof(fontProp);
290    for (t = fontNamePropTable; i; i--, t++)
291	t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
292
293    i = sizeof(fontPropTable) / sizeof(fontProp);
294    for (t = fontPropTable; i; i--, t++)
295	t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
296
297    i = sizeof(rawFontPropTable) / sizeof(fontProp);
298    for (t = rawFontPropTable; i; i--, t++)
299	t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE);
300}
301
302#if 0
303static FontEntryPtr
304GetScalableEntry (FontPathElementPtr fpe, FontNamePtr name)
305{
306    FontDirectoryPtr	dir;
307
308    dir = (FontDirectoryPtr) fpe->private;
309    return FontFileFindNameInDir (&dir->scalable, name);
310}
311#endif
312
313static double
314get_matrix_horizontal_component(double *matrix)
315{
316    return hypot(matrix[0], matrix[1]);
317}
318
319static double
320get_matrix_vertical_component(double *matrix)
321{
322    return hypot(matrix[2], matrix[3]);
323}
324
325
326static Bool
327ComputeScaleFactors(FontScalablePtr from, FontScalablePtr to,
328		    double *dx, double *dy, double *sdx, double *sdy,
329		    double *rescale_x)
330{
331    double srcpixelset, destpixelset, srcpixel, destpixel;
332
333    srcpixelset = get_matrix_horizontal_component(from->pixel_matrix);
334    destpixelset = get_matrix_horizontal_component(to->pixel_matrix);
335    srcpixel = get_matrix_vertical_component(from->pixel_matrix);
336    destpixel = get_matrix_vertical_component(to->pixel_matrix);
337
338    if (srcpixelset >= EPS)
339    {
340	*dx = destpixelset / srcpixelset;
341	*sdx = 1000.0 / srcpixelset;
342    }
343    else
344	*sdx = *dx = 0;
345
346    *rescale_x = 1.0;
347
348    /* If client specified a width, it overrides setsize; in this
349       context, we interpret width as applying to the font before any
350       rotation, even though that's not what is ultimately returned in
351       the width field. */
352    if (from->width > 0 && to->width > 0 && fabs(*dx) > EPS)
353    {
354	double rescale = (double)to->width / (double)from->width;
355
356	/* If the client specified a transformation matrix, the rescaling
357	   for width does *not* override the setsize.  Instead, just check
358	   for consistency between the setsize from the matrix and the
359	   setsize that would result from rescaling according to the width.
360	   This assumes (perhaps naively) that the width is correctly
361	   reported in the name.  As an interesting side effect, this test
362	   may result in choosing a different source bitmap (one that
363	   scales consistently between the setsize *and* the width) than it
364	   would choose if a width were not specified.  Sort of a hidden
365	   multiple-master functionality. */
366	if ((to->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
367	    (to->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY)
368	{
369	    /* Reject if resulting width difference is >= 1 pixel */
370	    if (fabs(rescale * from->width - *dx * from->width) >= 10)
371		return FALSE;
372	}
373	else
374	{
375	    *rescale_x = rescale/(*dx);
376	    *dx = rescale;
377	}
378    }
379
380    if (srcpixel >= EPS)
381    {
382	*dy = destpixel / srcpixel;
383	*sdy = 1000.0 / srcpixel;
384    }
385    else
386	*sdy = *dy = 0;
387
388    return TRUE;
389}
390
391/* favor enlargement over reduction because of aliasing resulting
392   from reduction */
393#define SCORE(m,s) \
394if (m >= 1.0) { \
395    if (m == 1.0) \
396        score += (16 * s); \
397    else if (m == 2.0) \
398        score += (4 * s); \
399    else \
400        score += (int)(((double)(3 * s)) / m); \
401} else { \
402        score += (int)(((double)(2 * s)) * m); \
403}
404
405/* don't need to favor enlargement when looking for bitmap that can
406   be used unscalable */
407#define SCORE2(m,s) \
408if (m >= 1.0) \
409    score += (int)(((double)(8 * s)) / m); \
410else \
411    score += (int)(((double)(8 * s)) * m);
412
413static FontEntryPtr
414FindBestToScale(FontPathElementPtr fpe, FontEntryPtr entry,
415		FontScalablePtr vals, FontScalablePtr best,
416		double *dxp, double *dyp,
417		double *sdxp, double *sdyp,
418		FontPathElementPtr *fpep)
419{
420    FontScalableRec temp;
421    int		    source, i;
422    int		    best_score, best_unscaled_score,
423		    score;
424    double	    dx = 0.0, sdx = 0.0, dx_amount = 0.0,
425		    dy = 0.0, sdy = 0.0, dy_amount = 0.0,
426		    best_dx = 0.0, best_sdx = 0.0, best_dx_amount = 0.0,
427		    best_dy = 0.0, best_sdy = 0.0, best_dy_amount = 0.0,
428		    best_unscaled_sdx = 0.0, best_unscaled_sdy = 0.0,
429		    rescale_x = 0.0, best_rescale_x = 0.0,
430		    best_unscaled_rescale_x = 0.0;
431    FontEntryPtr    zero;
432    FontNameRec	    zeroName;
433    char	    zeroChars[MAXFONTNAMELEN];
434    FontDirectoryPtr	dir;
435    FontScaledPtr   scaled;
436    FontScalableExtraPtr   extra;
437    FontScaledPtr   best_scaled, best_unscaled;
438    FontPathElementPtr	best_fpe = NULL, best_unscaled_fpe = NULL;
439    FontEntryPtr    bitmap = NULL;
440    FontEntryPtr    result;
441    int		    aliascount = 20;
442    FontPathElementPtr	bitmap_fpe = NULL;
443    FontNameRec	    xlfdName;
444
445    /* find the best match */
446    rescale_x = 1.0;
447    best_scaled = 0;
448    best_score = 0;
449    best_unscaled = 0;
450    best_unscaled_score = -1;
451    best_dx_amount = best_dy_amount = HUGE_VAL;
452    memcpy (zeroChars, entry->name.name, entry->name.length);
453    zeroChars[entry->name.length] = '\0';
454    zeroName.name = zeroChars;
455    FontParseXLFDName (zeroChars, &temp, FONT_XLFD_REPLACE_ZERO);
456    zeroName.length = strlen (zeroChars);
457    zeroName.ndashes = entry->name.ndashes;
458    xlfdName.name = vals->xlfdName;
459    xlfdName.length = strlen(xlfdName.name);
460    xlfdName.ndashes = FontFileCountDashes(xlfdName.name, xlfdName.length);
461    restart_bestscale_loop: ;
462    /*
463     * Look through all the registered bitmap sources for
464     * the same zero name as ours; entries along that one
465     * can be scaled as desired.
466     */
467    for (source = 0; source < FontFileBitmapSources.count; source++)
468    {
469	/* There might already be a bitmap that satisfies the request
470	   but didn't have a zero name that was found by the scalable
471	   font matching logic.  Keep track if there is.  */
472	if (bitmap == NULL && vals->xlfdName != NULL)
473	{
474	    bitmap_fpe = FontFileBitmapSources.fpe[source];
475	    dir = (FontDirectoryPtr) bitmap_fpe->private;
476	    bitmap = FontFileFindNameInDir (&dir->nonScalable, &xlfdName);
477	    if (bitmap && bitmap->type != FONT_ENTRY_BITMAP)
478	    {
479		if (bitmap->type == FONT_ENTRY_ALIAS && aliascount > 0)
480		{
481		    aliascount--;
482		    xlfdName.name = bitmap->u.alias.resolved;
483		    xlfdName.length = strlen(xlfdName.name);
484		    xlfdName.ndashes = FontFileCountDashes(xlfdName.name,
485							   xlfdName.length);
486		    bitmap = NULL;
487		    goto restart_bestscale_loop;
488		}
489		else
490		    bitmap = NULL;
491	    }
492	}
493
494	if (FontFileBitmapSources.fpe[source] == fpe)
495	    zero = entry;
496	else
497	{
498	    dir = (FontDirectoryPtr) FontFileBitmapSources.fpe[source]->private;
499	    zero = FontFileFindNameInDir (&dir->scalable, &zeroName);
500	    if (!zero)
501		continue;
502	}
503	extra = zero->u.scalable.extra;
504	for (i = 0; i < extra->numScaled; i++)
505	{
506	    scaled = &extra->scaled[i];
507	    if (!scaled->bitmap)
508		continue;
509	    if (!ComputeScaleFactors(&scaled->vals, vals, &dx, &dy, &sdx, &sdy,
510				     &rescale_x))
511		continue;
512	    score = 0;
513	    dx_amount = dx;
514	    dy_amount = dy;
515	    SCORE(dy_amount, 10);
516	    SCORE(dx_amount, 1);
517	    if ((score > best_score) ||
518		    ((score == best_score) &&
519		     ((dy_amount < best_dy_amount) ||
520 		      ((dy_amount == best_dy_amount) &&
521 		       (dx_amount < best_dx_amount)))))
522	    {
523		best_fpe = FontFileBitmapSources.fpe[source];
524	    	best_scaled = scaled;
525	    	best_score = score;
526	    	best_dx = dx;
527	    	best_dy = dy;
528	    	best_sdx = sdx;
529	    	best_sdy = sdy;
530	    	best_dx_amount = dx_amount;
531	    	best_dy_amount = dy_amount;
532		best_rescale_x = rescale_x;
533	    }
534	    /* Is this font a candidate for use without ugly rescaling? */
535	    if (fabs(dx) > EPS && fabs(dy) > EPS &&
536		fabs(vals->pixel_matrix[0] * rescale_x -
537		     scaled->vals.pixel_matrix[0]) < 1 &&
538		fabs(vals->pixel_matrix[1] * rescale_x -
539		     scaled->vals.pixel_matrix[1]) < EPS &&
540		fabs(vals->pixel_matrix[2] -
541		     scaled->vals.pixel_matrix[2]) < EPS &&
542		fabs(vals->pixel_matrix[3] -
543		     scaled->vals.pixel_matrix[3]) < 1)
544	    {
545		/* Yes.  The pixel sizes are close on the diagonal and
546		   extremely close off the diagonal. */
547		score = 0;
548		SCORE2(vals->pixel_matrix[3] /
549		       scaled->vals.pixel_matrix[3], 10);
550		SCORE2(vals->pixel_matrix[0] * rescale_x /
551		       scaled->vals.pixel_matrix[0], 1);
552		if (score > best_unscaled_score)
553		{
554		    best_unscaled_fpe = FontFileBitmapSources.fpe[source];
555	    	    best_unscaled = scaled;
556	    	    best_unscaled_sdx = sdx / dx;
557	    	    best_unscaled_sdy = sdy / dy;
558		    best_unscaled_score = score;
559		    best_unscaled_rescale_x = rescale_x;
560		}
561	    }
562	}
563    }
564    if (best_unscaled)
565    {
566	*best = best_unscaled->vals;
567	*fpep = best_unscaled_fpe;
568	*dxp = 1.0;
569	*dyp = 1.0;
570	*sdxp = best_unscaled_sdx;
571	*sdyp = best_unscaled_sdy;
572	rescale_x = best_unscaled_rescale_x;
573	result = best_unscaled->bitmap;
574    }
575    else if (best_scaled)
576    {
577	*best = best_scaled->vals;
578	*fpep = best_fpe;
579	*dxp = best_dx;
580	*dyp = best_dy;
581	*sdxp = best_sdx;
582	*sdyp = best_sdy;
583	rescale_x = best_rescale_x;
584	result = best_scaled->bitmap;
585    }
586    else
587	result = NULL;
588
589    if (bitmap != NULL && (result == NULL || *dxp != 1.0 || *dyp != 1.0))
590    {
591	*fpep = bitmap_fpe;
592	FontParseXLFDName (bitmap->name.name, best, FONT_XLFD_REPLACE_NONE);
593	if (ComputeScaleFactors(best, best, dxp, dyp, sdxp, sdyp, &rescale_x))
594	    result = bitmap;
595	else
596	    result = NULL;
597    }
598
599    if (result && rescale_x != 1.0)
600    {
601	/* We have rescaled horizontally due to an XLFD width field.  Change
602	   the matrix appropriately */
603	vals->pixel_matrix[0] *= rescale_x;
604	vals->pixel_matrix[1] *= rescale_x;
605#ifdef NOTDEF
606	/* This would force the pointsize and pixelsize fields in the
607	   FONT property to display as matrices to more accurately
608	   report the font being supplied.  It might also break existing
609	   applications that expect a single number in that field. */
610	vals->values_supplied =
611	    vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) |
612	    PIXELSIZE_ARRAY;
613#else /* NOTDEF */
614	vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK;
615#endif /* NOTDEF */
616	/* Recompute and reround the FontScalablePtr values after
617	   rescaling for the new width. */
618	FontFileCompleteXLFD(vals, vals);
619    }
620
621    return result;
622}
623
624static FontEntryPtr
625FindPmfToScale(FontPathElementPtr fpe, FontEntryPtr entry,
626	       FontScalablePtr vals, FontScalablePtr best,
627	       double *dxp, double *dyp,
628	       double *sdxp, double *sdyp,
629	       FontPathElementPtr *fpep)
630{
631    FontEntryPtr    result = NULL;
632    FontScaledPtr   scaled;
633    FontScalableExtraPtr   extra;
634    int i;
635
636    extra = entry->u.scalable.extra;
637    for (i = 0; i < extra->numScaled; i++)
638    {
639	double rescale_x;
640
641	scaled = &extra->scaled[i];
642	if (!scaled->bitmap)
643	    continue;
644	if (!ComputeScaleFactors(&scaled->vals, vals, dxp, dyp, sdxp, sdyp,
645				 &rescale_x))
646	    continue;
647	*best = scaled->vals;
648	*fpep = fpe;
649	result = scaled->bitmap;
650	if (rescale_x != 1.0)
651	{
652	    /* We have rescaled horizontally due to an XLFD width field.  Change
653	       the matrix appropriately */
654	    vals->pixel_matrix[0] *= rescale_x;
655	    vals->pixel_matrix[1] *= rescale_x;
656#ifdef NOTDEF
657	    /* This would force the pointsize and pixelsize fields in the
658	       FONT property to display as matrices to more accurately
659	       report the font being supplied.  It might also break existing
660	       applications that expect a single number in that field. */
661	    vals->values_supplied =
662		vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) |
663		PIXELSIZE_ARRAY;
664#else /* NOTDEF */
665	    vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK;
666#endif /* NOTDEF */
667	    /* Recompute and reround the FontScalablePtr values after
668	       rescaling for the new width. */
669	    FontFileCompleteXLFD(vals, vals);
670	}
671	break;
672    }
673    return result;
674}
675
676static long
677doround(double x)
678{
679    return (x >= 0) ? (long)(x + .5) : (long)(x - .5);
680}
681
682static int
683computeProps(FontPropPtr pf, char *wasStringProp,
684	     FontPropPtr npf, char *isStringProp,
685	     unsigned int nprops, double xfactor, double yfactor,
686	     double sXfactor, double sYfactor)
687{
688    int         n;
689    int         count;
690    fontProp   *t;
691    double      rawfactor = 0.0;
692
693    for (count = 0; nprops > 0; nprops--, pf++, wasStringProp++) {
694	n = sizeof(fontPropTable) / sizeof(fontProp);
695	for (t = fontPropTable; n && (t->atom != pf->name); n--, t++);
696	if (!n)
697	    continue;
698
699	switch (t->type) {
700	case scaledX:
701	    npf->value = doround(xfactor * (double)pf->value);
702	    rawfactor = sXfactor;
703	    break;
704	case scaledY:
705	    npf->value = doround(yfactor * (double)pf->value);
706	    rawfactor = sYfactor;
707	    break;
708	case unscaled:
709	    npf->value = pf->value;
710	    npf->name = pf->name;
711	    npf++;
712	    count++;
713	    *isStringProp++ = *wasStringProp;
714	    break;
715	default:
716	    break;
717	}
718	if (t->type != unscaled)
719	{
720	    npf->name = pf->name;
721	    npf++;
722	    count++;
723	    npf->value = doround(rawfactor * (double)pf->value);
724	    npf->name = rawFontPropTable[t - fontPropTable].atom;
725	    npf++;
726	    count++;
727	    *isStringProp++ = *wasStringProp;
728	    *isStringProp++ = *wasStringProp;
729	}
730    }
731    return count;
732}
733
734
735static int
736ComputeScaledProperties(FontInfoPtr sourceFontInfo, /* the font to be scaled */
737			char *name, 		/* name of resulting font */
738			FontScalablePtr vals,
739			double dx, double dy, 	/* scale factors in x and y */
740			double sdx, double sdy, /* directions */
741			long sWidth, 		/* 1000-pixel average width */
742			FontPropPtr *pProps, 	/* returns properties;
743						   preallocated */
744			char **pIsStringProp) 	/* return booleans;
745						   preallocated */
746{
747    int         n;
748    char       *ptr1 = NULL, *ptr2 = NULL;
749    char       *ptr3;
750    FontPropPtr fp;
751    fontProp   *fpt;
752    char	*isStringProp;
753    int		nProps;
754
755    if (bitscaleGeneration != serverGeneration) {
756	initFontPropTable();
757	bitscaleGeneration = serverGeneration;
758    }
759    nProps = NPROPS + 1 + sizeof(fontPropTable) / sizeof(fontProp) +
760			  sizeof(rawFontPropTable) / sizeof(fontProp);
761    fp = (FontPropPtr) xalloc(sizeof(FontPropRec) * nProps);
762    *pProps = fp;
763    if (!fp) {
764	fprintf(stderr, "Error: Couldn't allocate font properties (%ld*%d)\n",
765		(unsigned long)sizeof(FontPropRec), nProps);
766	return 1;
767    }
768    isStringProp = (char *) xalloc (nProps);
769    *pIsStringProp = isStringProp;
770    if (!isStringProp)
771    {
772 fprintf(stderr, "Error: Couldn't allocate isStringProp (%d)\n", nProps);
773	xfree (fp);
774	return 1;
775    }
776    ptr2 = name;
777    for (fpt = fontNamePropTable, n = NPROPS;
778	 n;
779 	 fp++, fpt++, n--, isStringProp++)
780    {
781
782	if (*ptr2)
783	{
784	    ptr1 = ptr2 + 1;
785	    if (!(ptr2 = strchr(ptr1, '-'))) ptr2 = strchr(ptr1, '\0');
786	}
787
788	*isStringProp = 0;
789	switch (fpt->type) {
790	case atom:
791	    fp->value = MakeAtom(ptr1, ptr2 - ptr1, TRUE);
792	    *isStringProp = 1;
793	    break;
794	case truncate_atom:
795	    for (ptr3 = ptr1; *ptr3; ptr3++)
796		if (*ptr3 == '[')
797		    break;
798	    if (!*ptr3) ptr3 = ptr2;
799	    fp->value = MakeAtom(ptr1, ptr3 - ptr1, TRUE);
800	    *isStringProp = 1;
801	    break;
802	case pixel_size:
803	    fp->value = doround(vals->pixel_matrix[3]);
804	    break;
805	case point_size:
806	    fp->value = doround(vals->point_matrix[3] * 10.0);
807	    break;
808	case resolution_x:
809	    fp->value = vals->x;
810	    break;
811	case resolution_y:
812	    fp->value = vals->y;
813	    break;
814	case average_width:
815	    fp->value = vals->width;
816	    break;
817	case fontname:
818	    fp->value = MakeAtom(name, strlen(name), TRUE);
819	    *isStringProp = 1;
820	    break;
821	case raw_ascent:
822	    fp->value = sourceFontInfo->fontAscent * sdy;
823	    break;
824	case raw_descent:
825	    fp->value = sourceFontInfo->fontDescent * sdy;
826	    break;
827	case raw_pointsize:
828	    fp->value = (long)(72270.0 / (double)vals->y + .5);
829	    break;
830	case raw_pixelsize:
831	    fp->value = 1000;
832	    break;
833	case raw_average_width:
834	    fp->value = sWidth;
835	    break;
836	default:
837	    break;
838	}
839	fp->name = fpt->atom;
840    }
841    n = NPROPS;
842    n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp,
843		      fp, isStringProp, sourceFontInfo->nprops, dx, dy,
844		      sdx, sdy);
845    return n;
846}
847
848
849static int
850compute_xform_matrix(FontScalablePtr vals, double dx, double dy,
851		     double *xform, double *inv_xform,
852		     double *xmult, double *ymult)
853{
854    double det;
855    double pixel = get_matrix_vertical_component(vals->pixel_matrix);
856    double pixelset = get_matrix_horizontal_component(vals->pixel_matrix);
857
858    if (pixel < EPS || pixelset < EPS) return 0;
859
860    /* Initialize the transformation matrix to the scaling factors */
861    xform[0] = dx / pixelset;
862    xform[1] = xform[2] = 0.0;
863    xform[3] = dy / pixel;
864
865/* Inline matrix multiply -- somewhat ugly to minimize register usage */
866#define MULTIPLY_XFORM(a,b,c,d) \
867{ \
868  register double aa = (a), bb = (b), cc = (c), dd = (d); \
869  register double temp; \
870  temp =     aa * xform[0] + cc * xform[1]; \
871  aa =       aa * xform[2] + cc * xform[3]; \
872  xform[1] = bb * xform[0] + dd * xform[1]; \
873  xform[3] = bb * xform[2] + dd * xform[3]; \
874  xform[0] = temp; \
875  xform[2] = aa; \
876}
877
878    /* Rescale the transformation matrix for size of source font */
879    MULTIPLY_XFORM(vals->pixel_matrix[0],
880		   vals->pixel_matrix[1],
881		   vals->pixel_matrix[2],
882		   vals->pixel_matrix[3]);
883
884    *xmult = xform[0];
885    *ymult = xform[3];
886
887
888    if (inv_xform == NULL) return 1;
889
890    /* Compute the determinant for use in inverting the matrix. */
891    det = xform[0] * xform[3] - xform[1] * xform[2];
892
893    /* If the determinant is tiny or zero, give up */
894    if (fabs(det) < EPS) return 0;
895
896    /* Compute the inverse */
897    inv_xform[0] = xform[3] / det;
898    inv_xform[1] = -xform[1] / det;
899    inv_xform[2] = -xform[2] / det;
900    inv_xform[3] = xform[0] / det;
901
902    return 1;
903}
904
905/*
906 *  ScaleFont
907 *  returns a pointer to the new scaled font, or NULL (due to AllocError).
908 */
909static FontPtr
910ScaleFont(FontPtr opf,            /* originating font */
911	  double widthMult, 	  /* glyphs width scale factor */
912	  double heightMult, 	  /* glyphs height scale factor */
913	  double sWidthMult, 	  /* scalable glyphs width scale factor */
914	  double sHeightMult, 	  /* scalable glyphs height scale factor */
915	  FontScalablePtr vals,
916	  double *newWidthMult,   /* return: X component of glyphs width
917				     scale factor */
918	  double *newHeightMult,  /* return: Y component of glyphs height
919				     scale factor */
920	  long *sWidth)		  /* return: average 1000-pixel width */
921{
922    FontPtr     pf;
923    FontInfoPtr pfi,
924                opfi;
925    BitmapFontPtr  bitmapFont,
926                obitmapFont;
927    CharInfoPtr pci,
928                opci;
929    int         nchars = 0;	/* how many characters in the font */
930    int         i;
931    int		firstCol, lastCol, firstRow, lastRow;
932    double	xform[4], inv_xform[4];
933    double	xmult, ymult;
934    int		totalwidth = 0, totalchars = 0;
935#define OLDINDEX(i) (((i)/(lastCol - firstCol + 1) + \
936		      firstRow - opf->info.firstRow) * \
937		     (opf->info.lastCol - opf->info.firstCol + 1) + \
938		     (i)%(lastCol - firstCol + 1) + \
939		     firstCol - opf->info.firstCol)
940
941    *sWidth = 0;
942
943    opfi = &opf->info;
944    obitmapFont = (BitmapFontPtr) opf->fontPrivate;
945
946    bitmapFont = 0;
947    if (!(pf = CreateFontRec())) {
948	fprintf(stderr, "Error: Couldn't allocate FontRec (%ld)\n",
949		(unsigned long)sizeof(FontRec));
950	goto bail;
951    }
952    pf->refcnt = 0;
953    pf->bit = opf->bit;
954    pf->byte = opf->byte;
955    pf->glyph = opf->glyph;
956    pf->scan = opf->scan;
957
958    pf->get_glyphs = bitmapGetGlyphs;
959    pf->get_metrics = bitmapGetMetrics;
960    pf->unload_font = bitmapUnloadScalable;
961    pf->unload_glyphs = NULL;
962
963    pfi = &pf->info;
964    *pfi = *opfi;
965    /* If charset subsetting specified in vals, determine what our range
966       needs to be for the output font */
967    if (vals->nranges)
968    {
969	int i;
970
971	pfi->allExist = 0;
972	firstCol = 255;
973	lastCol = 0;
974	firstRow = 255;
975	lastRow = 0;
976
977	for (i = 0; i < vals->nranges; i++)
978	{
979	    if (vals->ranges[i].min_char_high != vals->ranges[i].max_char_high)
980	    {
981		firstCol = opfi->firstCol;
982		lastCol = opfi->lastCol;
983	    }
984	    if (firstCol > vals->ranges[i].min_char_low)
985		firstCol = vals->ranges[i].min_char_low;
986	    if (lastCol < vals->ranges[i].max_char_low)
987		lastCol = vals->ranges[i].max_char_low;
988	    if (firstRow > vals->ranges[i].min_char_high)
989		firstRow = vals->ranges[i].min_char_high;
990	    if (lastRow < vals->ranges[i].max_char_high)
991		lastRow = vals->ranges[i].max_char_high;
992	}
993
994	if (firstCol > lastCol || firstRow > lastRow)
995	    goto bail;
996
997	if (firstCol < opfi->firstCol)
998	    firstCol = opfi->firstCol;
999	if (lastCol > opfi->lastCol)
1000	    lastCol = opfi->lastCol;
1001	if (firstRow < opfi->firstRow)
1002	    firstRow = opfi->firstRow;
1003	if (lastRow > opfi->lastRow)
1004	    lastRow = opfi->lastRow;
1005    }
1006    else
1007    {
1008	firstCol = opfi->firstCol;
1009	lastCol = opfi->lastCol;
1010	firstRow = opfi->firstRow;
1011	lastRow = opfi->lastRow;
1012    }
1013
1014    bitmapFont = (BitmapFontPtr) xalloc(sizeof(BitmapFontRec));
1015    if (!bitmapFont) {
1016	fprintf(stderr, "Error: Couldn't allocate bitmapFont (%ld)\n",
1017		(unsigned long)sizeof(BitmapFontRec));
1018	goto bail;
1019    }
1020    nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
1021    pfi->firstRow = firstRow;
1022    pfi->lastRow = lastRow;
1023    pfi->firstCol = firstCol;
1024    pfi->lastCol = lastCol;
1025    pf->fontPrivate = (pointer) bitmapFont;
1026    bitmapFont->version_num = obitmapFont->version_num;
1027    bitmapFont->num_chars = nchars;
1028    bitmapFont->num_tables = obitmapFont->num_tables;
1029    bitmapFont->metrics = 0;
1030    bitmapFont->ink_metrics = 0;
1031    bitmapFont->bitmaps = 0;
1032    bitmapFont->encoding = 0;
1033    bitmapFont->bitmapExtra = 0;
1034    bitmapFont->pDefault = 0;
1035    bitmapFont->metrics = (CharInfoPtr) xalloc(nchars * sizeof(CharInfoRec));
1036    if (!bitmapFont->metrics) {
1037	fprintf(stderr, "Error: Couldn't allocate metrics (%d*%ld)\n",
1038		nchars, (unsigned long)sizeof(CharInfoRec));
1039	goto bail;
1040    }
1041    bitmapFont->encoding =
1042        (CharInfoPtr **) xcalloc(NUM_SEGMENTS(nchars),
1043                                 sizeof(CharInfoPtr*));
1044    if (!bitmapFont->encoding) {
1045	fprintf(stderr, "Error: Couldn't allocate encoding (%d*%ld)\n",
1046		nchars, (unsigned long)sizeof(CharInfoPtr));
1047	goto bail;
1048    }
1049
1050#undef MAXSHORT
1051#define MAXSHORT    32767
1052#undef MINSHORT
1053#define MINSHORT    -32768
1054
1055    pfi->anamorphic = FALSE;
1056    if (heightMult != widthMult)
1057	pfi->anamorphic = TRUE;
1058    pfi->cachable = TRUE;
1059
1060    if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
1061			      inv_xform, &xmult, &ymult))
1062	goto bail;
1063
1064    pfi->fontAscent = opfi->fontAscent * ymult;
1065    pfi->fontDescent = opfi->fontDescent * ymult;
1066
1067    pfi->minbounds.leftSideBearing = MAXSHORT;
1068    pfi->minbounds.rightSideBearing = MAXSHORT;
1069    pfi->minbounds.ascent = MAXSHORT;
1070    pfi->minbounds.descent = MAXSHORT;
1071    pfi->minbounds.characterWidth = MAXSHORT;
1072    pfi->minbounds.attributes = MAXSHORT;
1073
1074    pfi->maxbounds.leftSideBearing = MINSHORT;
1075    pfi->maxbounds.rightSideBearing = MINSHORT;
1076    pfi->maxbounds.ascent = MINSHORT;
1077    pfi->maxbounds.descent = MINSHORT;
1078    pfi->maxbounds.characterWidth = MINSHORT;
1079    pfi->maxbounds.attributes = MINSHORT;
1080
1081    /* Compute the transformation and inverse transformation matrices.
1082       Can fail if the determinant is zero. */
1083
1084    pci = bitmapFont->metrics;
1085    for (i = 0; i < nchars; i++)
1086    {
1087	if ((opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i))))
1088	{
1089	    double newlsb, newrsb, newdesc, newasc, point[2];
1090
1091#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))
1092#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8))
1093
1094	    if (vals->nranges)
1095	    {
1096		int row = i / (lastCol - firstCol + 1) + firstRow;
1097		int col = i % (lastCol - firstCol + 1) + firstCol;
1098		int ch = (row << 8) + col;
1099		int j;
1100		for (j = 0; j < vals->nranges; j++)
1101		    if (ch >= minchar(vals->ranges[j]) &&
1102			ch <= maxchar(vals->ranges[j]))
1103			break;
1104		if (j == vals->nranges)
1105		{
1106		    continue;
1107		}
1108	    }
1109
1110	    if (opci->metrics.leftSideBearing == 0 &&
1111		opci->metrics.rightSideBearing == 0 &&
1112		opci->metrics.ascent == 0 &&
1113		opci->metrics.descent == 0 &&
1114		opci->metrics.characterWidth == 0)
1115	    {
1116		continue;
1117	    }
1118
1119            if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) {
1120                bitmapFont->encoding[SEGMENT_MAJOR(i)]=
1121                  (CharInfoPtr*)xcalloc(BITMAP_FONT_SEGMENT_SIZE,
1122                                        sizeof(CharInfoPtr));
1123                if(!bitmapFont->encoding[SEGMENT_MAJOR(i)])
1124                    goto bail;
1125            }
1126	    ACCESSENCODINGL(bitmapFont->encoding, i) = pci;
1127
1128	    /* Compute new extents for this glyph */
1129	    TRANSFORM_POINT(xform,
1130			    opci->metrics.leftSideBearing,
1131			    -opci->metrics.descent,
1132			    point);
1133	    newlsb = point[0];
1134	    newrsb = newlsb;
1135	    newdesc = -point[1];
1136	    newasc = -newdesc;
1137	    TRANSFORM_POINT(xform,
1138			    opci->metrics.leftSideBearing,
1139			    opci->metrics.ascent,
1140			    point);
1141	    CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
1142	    TRANSFORM_POINT(xform,
1143			    opci->metrics.rightSideBearing,
1144			    -opci->metrics.descent,
1145			    point);
1146	    CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
1147	    TRANSFORM_POINT(xform,
1148			    opci->metrics.rightSideBearing,
1149			    opci->metrics.ascent,
1150			    point);
1151	    CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point);
1152
1153	    pci->metrics.leftSideBearing = (int)floor(newlsb);
1154	    pci->metrics.rightSideBearing = (int)floor(newrsb + .5);
1155	    pci->metrics.descent = (int)ceil(newdesc);
1156	    pci->metrics.ascent = (int)floor(newasc + .5);
1157	    /* Accumulate total width of characters before transformation,
1158	       to ascertain predominant direction of font. */
1159	    totalwidth += opci->metrics.characterWidth;
1160	    pci->metrics.characterWidth =
1161		doround((double)opci->metrics.characterWidth * xmult);
1162	    pci->metrics.attributes =
1163		doround((double)opci->metrics.characterWidth * sWidthMult);
1164	    if (!pci->metrics.characterWidth)
1165	    {
1166		/* Since transformation may shrink width, height, and
1167		   escapement to zero, make sure existing characters
1168		   are not mistaken for undefined characters. */
1169
1170		if (pci->metrics.rightSideBearing ==
1171		    pci->metrics.leftSideBearing)
1172		    pci->metrics.rightSideBearing++;
1173		if (pci->metrics.ascent == -pci->metrics.descent)
1174		    pci->metrics.ascent++;
1175	    }
1176
1177	    pci++;
1178	}
1179    }
1180
1181
1182    /*
1183     * For each character, set the per-character metrics, scale the glyph, and
1184     * check per-font minbounds and maxbounds character information.
1185     */
1186
1187    pci = bitmapFont->metrics;
1188    for (i = 0; i < nchars; i++)
1189    {
1190	if ((pci = ACCESSENCODING(bitmapFont->encoding,i)) &&
1191	    (opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i))))
1192	{
1193	    totalchars++;
1194	    *sWidth += abs((int)(INT16)pci->metrics.attributes);
1195#define MINMAX(field) \
1196	    if (pfi->minbounds.field > pci->metrics.field) \
1197	    	pfi->minbounds.field = pci->metrics.field; \
1198	    if (pfi->maxbounds.field < pci->metrics.field) \
1199	    	pfi->maxbounds.field = pci->metrics.field
1200
1201	    MINMAX(leftSideBearing);
1202	    MINMAX(rightSideBearing);
1203	    MINMAX(ascent);
1204	    MINMAX(descent);
1205	    MINMAX(characterWidth);
1206
1207	    /* Hack: Cast attributes into a signed quantity.  Tread lightly
1208	       for now and don't go changing the global Xproto.h file */
1209	    if ((INT16)pfi->minbounds.attributes >
1210		(INT16)pci->metrics.attributes)
1211	    	pfi->minbounds.attributes = pci->metrics.attributes;
1212	    if ((INT16)pfi->maxbounds.attributes <
1213		(INT16)pci->metrics.attributes)
1214	    	pfi->maxbounds.attributes = pci->metrics.attributes;
1215#undef MINMAX
1216	}
1217    }
1218    pfi->ink_minbounds = pfi->minbounds;
1219    pfi->ink_maxbounds = pfi->maxbounds;
1220    if (totalchars)
1221    {
1222	*sWidth = (*sWidth * 10 + totalchars / 2) / totalchars;
1223	if (totalwidth < 0)
1224	{
1225	    /* Dominant direction is R->L */
1226	    *sWidth = -*sWidth;
1227	}
1228
1229	if (pfi->minbounds.characterWidth == pfi->maxbounds.characterWidth)
1230	    vals->width = pfi->minbounds.characterWidth * 10;
1231	else
1232	    vals->width = doround((double)*sWidth * vals->pixel_matrix[0] /
1233				  1000.0);
1234    }
1235    else
1236    {
1237	vals->width = 0;
1238	*sWidth = 0;
1239    }
1240    FontComputeInfoAccelerators (pfi);
1241
1242    if (pfi->defaultCh != (unsigned short) NO_SUCH_CHAR) {
1243	unsigned int r,
1244	            c,
1245	            cols;
1246
1247	r = pfi->defaultCh >> 8;
1248	c = pfi->defaultCh & 0xFF;
1249	if (pfi->firstRow <= r && r <= pfi->lastRow &&
1250		pfi->firstCol <= c && c <= pfi->lastCol) {
1251	    cols = pfi->lastCol - pfi->firstCol + 1;
1252	    r = r - pfi->firstRow;
1253	    c = c - pfi->firstCol;
1254	    bitmapFont->pDefault =
1255                ACCESSENCODING(bitmapFont->encoding, r * cols + c);
1256	}
1257    }
1258
1259    *newWidthMult = xmult;
1260    *newHeightMult = ymult;
1261    return pf;
1262bail:
1263    if (pf)
1264	xfree(pf);
1265    if (bitmapFont) {
1266	xfree(bitmapFont->metrics);
1267	xfree(bitmapFont->ink_metrics);
1268	xfree(bitmapFont->bitmaps);
1269        if(bitmapFont->encoding)
1270            for(i=0; i<NUM_SEGMENTS(nchars); i++)
1271                xfree(bitmapFont->encoding[i]);
1272	xfree(bitmapFont->encoding);
1273    }
1274    return NULL;
1275}
1276
1277static void
1278ScaleBitmap(FontPtr pFont, CharInfoPtr opci, CharInfoPtr pci,
1279	    double *inv_xform, double widthMult, double heightMult)
1280{
1281    register char  *bitmap,		/* The bits */
1282               *newBitmap;
1283    register int   bpr,			/* Padding information */
1284		newBpr;
1285    int         width,			/* Extents information */
1286                height,
1287                newWidth,
1288                newHeight;
1289    register int row,			/* Loop variables */
1290		col;
1291    INT32	deltaX,			/* Increments for resampling loop */
1292		deltaY;
1293    INT32	xValue,			/* Subscripts for resampling loop */
1294		yValue;
1295    double	point[2];
1296    unsigned char *char_grayscale = 0;
1297    INT32	*diffusion_workspace = NULL, *thisrow = NULL,
1298                *nextrow = NULL, pixmult = 0;
1299    int		box_x = 0, box_y = 0;
1300
1301    static unsigned char masklsb[] =
1302	{ 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
1303    static unsigned char maskmsb[] =
1304	{ 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
1305    unsigned char	*mask = (pFont->bit == LSBFirst ? masklsb : maskmsb);
1306
1307
1308    bitmap = opci->bits;
1309    newBitmap = pci->bits;
1310    width = GLYPHWIDTHPIXELS(opci);
1311    height = GLYPHHEIGHTPIXELS(opci);
1312    newWidth = GLYPHWIDTHPIXELS(pci);
1313    newHeight = GLYPHHEIGHTPIXELS(pci);
1314    if (!newWidth || !newHeight || !width || !height)
1315	return;
1316
1317    bpr = BYTES_PER_ROW(width, pFont->glyph);
1318    newBpr = BYTES_PER_ROW(newWidth, pFont->glyph);
1319
1320    if (widthMult > 0.0 && heightMult > 0.0 &&
1321	(widthMult < 1.0 || heightMult < 1.0))
1322    {
1323	/* We are reducing in one or both dimensions.  In an attempt to
1324	   reduce aliasing, we'll antialias by passing the original
1325	   glyph through a low-pass box filter (which results in a
1326	   grayscale image), then use error diffusion to create bitonal
1327	   output in the resampling loop.  */
1328
1329	/* First compute the sizes of the box filter */
1330	widthMult = ceil(1.0 / widthMult);
1331	heightMult = ceil(1.0 / heightMult);
1332	box_x = width / 2;
1333	box_y = height / 2;
1334	if (widthMult < (double)box_x) box_x = (int)widthMult;
1335	if (heightMult < (double)box_y) box_y = (int)heightMult;
1336	/* The pixmult value (below) is used to darken the image before
1337	   we perform error diffusion: a necessary concession to the
1338	   fact that it's very difficult to generate readable halftoned
1339	   glyphs.  The degree of darkening is proportional to the size
1340	   of the blurring filter, hence inversely proportional to the
1341	   darkness of the lightest gray that results from antialiasing.
1342	   The result is that characters that exercise this logic (those
1343	   generated by reducing from a larger source font) tend to err
1344	   on the side of being too bold instead of being too light to
1345	   be readable. */
1346	pixmult = box_x * box_y * 192;
1347
1348	if (box_x > 1 || box_y > 1)
1349	{
1350	    /* Looks like we need to anti-alias.  Create a workspace to
1351	       contain the grayscale character plus an additional row and
1352	       column for scratch */
1353	    char_grayscale =
1354		(unsigned char *)xalloc((width + 1) * (height + 1));
1355	    if (char_grayscale)
1356	    {
1357		diffusion_workspace =
1358		    (INT32 *)xalloc((newWidth + 2) * 2 * sizeof(int));
1359		if (!diffusion_workspace)
1360		{
1361		    fprintf(stderr, "Warning: Couldn't allocate diffusion"
1362			    " workspace (%ld)\n",
1363			    (newWidth + 2) * 2 * (unsigned long)sizeof(int));
1364		    xfree(char_grayscale);
1365		    char_grayscale = (unsigned char *)0;
1366		}
1367		/* Initialize our error diffusion workspace for later use */
1368		bzero((char *)diffusion_workspace + sizeof(INT32),
1369		      (newWidth + 3) * sizeof(int));
1370		thisrow = diffusion_workspace + 1;
1371		nextrow = diffusion_workspace + newWidth + 3;
1372     } else {
1373  fprintf(stderr, "Warning: Couldn't allocate character grayscale (%d)\n", (width + 1) * (height + 1));
1374	    }
1375	}
1376    }
1377
1378    if (char_grayscale)
1379    {
1380	/* We will be doing antialiasing.  First copy the bitmap into
1381	   our buffer, mapping input range [0,1] to output range
1382	   [0,255].  */
1383	register unsigned char *srcptr, *dstptr;
1384	srcptr = (unsigned char *)bitmap;
1385	dstptr = char_grayscale;
1386	for (row = 0; row < height; row++)
1387	{
1388	    for (col = 0; col < width; col++)
1389		*dstptr++ = (srcptr[col >> 3] & mask[col & 0x7]) ? 255 : 0;
1390	    srcptr += bpr;	/* On to next row of source */
1391	    dstptr++;		/* Skip scratch column in dest */
1392	}
1393	if (box_x > 1)
1394	{
1395	    /* Our box filter has a width > 1... let's filter the rows */
1396
1397	    int right_width = box_x / 2;
1398	    int left_width = box_x - right_width - 1;
1399
1400	    for (row = 0; row < height; row++)
1401	    {
1402		int sum = 0;
1403		int left_size = 0, right_size = 0;
1404
1405		srcptr = char_grayscale + (width + 1) * row;
1406		dstptr = char_grayscale + (width + 1) * height; /* scratch */
1407
1408		/* We've computed the shape of our full box filter.  Now
1409		   compute the right-hand part of the moving sum */
1410		for (right_size = 0; right_size < right_width; right_size++)
1411		    sum += srcptr[right_size];
1412
1413		/* Now start moving the sum, growing the box filter, and
1414		   dropping averages into our scratch buffer */
1415		for (left_size = 0; left_size < left_width; left_size++)
1416		{
1417		    sum += srcptr[right_width];
1418		    *dstptr++ = sum / (left_size + right_width + 1);
1419		    srcptr++;
1420		}
1421
1422		/* The box filter has reached full width... continue
1423		   computation of moving average until the right side
1424		   hits the wall. */
1425		for (col = left_size; col + right_size < width; col++)
1426		{
1427		    sum += srcptr[right_width];
1428		    *dstptr++ = sum / box_x;
1429		    sum -= srcptr[-left_width];
1430		    srcptr++;
1431		}
1432
1433		/* Collapse the right side of the box filter */
1434		for (; right_size > 0; right_size--)
1435		{
1436		    *dstptr++ = sum / (left_width + right_size);
1437		    sum -= srcptr[-left_width];
1438		    srcptr++;
1439		}
1440
1441		/* Done with the row... copy dest back over source */
1442		memmove(char_grayscale + (width + 1) * row,
1443			char_grayscale + (width + 1) * height,
1444			width);
1445	    }
1446	}
1447	if (box_y > 1)
1448	{
1449	    /* Our box filter has a height > 1... let's filter the columns */
1450
1451	    int bottom_height = box_y / 2;
1452	    int top_height = box_y - bottom_height - 1;
1453
1454	    for (col = 0; col < width; col++)
1455	    {
1456		int sum = 0;
1457		int top_size = 0, bottom_size = 0;
1458
1459		srcptr = char_grayscale + col;
1460		dstptr = char_grayscale + width;	 /* scratch */
1461
1462		/* We've computed the shape of our full box filter.  Now
1463		   compute the bottom part of the moving sum */
1464		for (bottom_size = 0;
1465		     bottom_size < bottom_height;
1466		     bottom_size++)
1467		    sum += srcptr[bottom_size * (width + 1)];
1468
1469		/* Now start moving the sum, growing the box filter, and
1470		   dropping averages into our scratch buffer */
1471		for (top_size = 0; top_size < top_height; top_size++)
1472		{
1473		    sum += srcptr[bottom_height * (width + 1)];
1474		    *dstptr = sum / (top_size + bottom_height + 1);
1475		    dstptr += width + 1;
1476		    srcptr += width + 1;
1477		}
1478
1479		/* The box filter has reached full height... continue
1480		   computation of moving average until the bottom
1481		   hits the wall. */
1482		for (row = top_size; row + bottom_size < height; row++)
1483		{
1484		    sum += srcptr[bottom_height * (width + 1)];
1485		    *dstptr = sum / box_y;
1486		    dstptr += width + 1;
1487		    sum -= srcptr[-top_height * (width + 1)];
1488		    srcptr += width + 1;
1489		}
1490
1491		/* Collapse the bottom of the box filter */
1492		for (; bottom_size > 0; bottom_size--)
1493		{
1494		    *dstptr = sum / (top_height + bottom_size);
1495		    dstptr += width + 1;
1496		    sum -= srcptr[-top_height * (width + 1)];
1497		    srcptr += width + 1;
1498		}
1499
1500		/* Done with the column... copy dest back over source */
1501
1502		dstptr = char_grayscale + col;
1503		srcptr = char_grayscale + width;	 /* scratch */
1504		for (row = 0; row < height; row++)
1505		{
1506		    *dstptr = *srcptr;
1507		    dstptr += width + 1;
1508		    srcptr += width + 1;
1509		}
1510	    }
1511	}
1512
1513	/* Increase the grayvalue to increase ink a bit */
1514	srcptr = char_grayscale;
1515	for (row = 0; row < height; row++)
1516	{
1517	    for (col = 0; col < width; col++)
1518	    {
1519		register int pixvalue = (int)*srcptr * pixmult / 256;
1520		if (pixvalue > 255) pixvalue = 255;
1521		*srcptr = pixvalue;
1522		srcptr++;
1523	    }
1524	    srcptr++;
1525	}
1526    }
1527
1528    /* Compute the increment values for the resampling loop */
1529    TRANSFORM_POINT(inv_xform, 1, 0, point);
1530    deltaX = (INT32)(point[0] * 65536.0);
1531    deltaY = (INT32)(-point[1] * 65536.0);
1532
1533    /* Resampling loop:  resamples original glyph for generation of new
1534       glyph in transformed coordinate system. */
1535
1536    for (row = 0; row < newHeight; row++)
1537    {
1538	/* Compute inverse transformation for start of this row */
1539	TRANSFORM_POINT(inv_xform,
1540			(double)(pci->metrics.leftSideBearing) + .5,
1541			(double)(pci->metrics.ascent - row) - .5,
1542			point);
1543
1544	/* Adjust for coordinate system to get resampling point */
1545	point[0] -= opci->metrics.leftSideBearing;
1546	point[1] = opci->metrics.ascent - point[1];
1547
1548	/* Convert to integer coordinates */
1549	xValue = (INT32)(point[0] * 65536.0);
1550	yValue = (INT32)(point[1] * 65536.0);
1551
1552	if (char_grayscale)
1553	{
1554	    INT32 *temp;
1555	    for (col = 0; col < newWidth; col++)
1556	    {
1557		register int x = xValue >> 16, y = yValue >> 16;
1558		int pixvalue, error;
1559
1560		pixvalue = ((x >= 0 && x < width && y >= 0 && y < height) ?
1561			    char_grayscale[x + y * (width + 1)] : 0) +
1562			   thisrow[col] / 16;
1563		if (pixvalue > 255) pixvalue = 255;
1564		else if (pixvalue < 0) pixvalue = 0;
1565
1566		/* Choose the bit value and set resulting error value */
1567		if (pixvalue >= 128)
1568		{
1569		    newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7];
1570		    error = pixvalue - 255;
1571		}
1572		else
1573		    error = -pixvalue;
1574
1575		/* Diffuse the error */
1576		thisrow[col + 1] += error * 7;
1577		nextrow[col - 1] += error * 3;
1578		nextrow[col] += error * 5;
1579		nextrow[col + 1] = error;
1580
1581		xValue += deltaX;
1582		yValue += deltaY;
1583	    }
1584
1585	    /* Add in error values that fell off either end */
1586	    nextrow[0] += nextrow[-1];
1587	    nextrow[newWidth - 2] += thisrow[newWidth];
1588	    nextrow[newWidth - 1] += nextrow[newWidth];
1589	    nextrow[newWidth] = 0;
1590
1591	    temp = nextrow;
1592	    nextrow = thisrow;
1593	    thisrow = temp;
1594	    nextrow[-1] = nextrow[0] = 0;
1595	}
1596	else
1597	{
1598	    for (col = 0; col < newWidth; col++)
1599	    {
1600		register int x = xValue >> 16, y = yValue >> 16;
1601
1602		if (x >= 0 && x < width && y >= 0 && y < height)
1603		{
1604		    /* Use point-sampling for rescaling. */
1605
1606		    if (bitmap[(x >> 3) + y * bpr] & mask[x & 0x7])
1607			newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7];
1608		}
1609
1610		xValue += deltaX;
1611		yValue += deltaY;
1612	    }
1613	}
1614    }
1615
1616
1617    if (char_grayscale)
1618    {
1619	xfree(char_grayscale);
1620	xfree(diffusion_workspace);
1621    }
1622}
1623
1624static FontPtr
1625BitmapScaleBitmaps(FontPtr pf,          /* scaled font */
1626		   FontPtr opf,         /* originating font */
1627		   double widthMult,    /* glyphs width scale factor */
1628		   double heightMult,   /* glyphs height scale factor */
1629		   FontScalablePtr vals)
1630{
1631    register int i;
1632    int		nchars = 0;
1633    char       *glyphBytes;
1634    BitmapFontPtr  bitmapFont,
1635		   obitmapFont;
1636    CharInfoPtr pci,
1637		opci;
1638    FontInfoPtr pfi;
1639    int         glyph;
1640    unsigned    bytestoalloc = 0;
1641    int		firstCol, lastCol, firstRow, lastRow;
1642
1643    double	xform[4], inv_xform[4];
1644    double	xmult, ymult;
1645
1646    bitmapFont = (BitmapFontPtr) pf->fontPrivate;
1647    obitmapFont = (BitmapFontPtr) opf->fontPrivate;
1648
1649    if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
1650			      inv_xform, &xmult, &ymult))
1651	goto bail;
1652
1653    pfi = &pf->info;
1654    firstCol = pfi->firstCol;
1655    lastCol = pfi->lastCol;
1656    firstRow = pfi->firstRow;
1657    lastRow = pfi->lastRow;
1658
1659    nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
1660    glyph = pf->glyph;
1661    for (i = 0; i < nchars; i++)
1662    {
1663	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)))
1664	    bytestoalloc += BYTES_FOR_GLYPH(pci, glyph);
1665    }
1666
1667    /* Do we add the font malloc stuff for VALUE ADDED ? */
1668    /* Will need to remember to free in the Unload routine */
1669
1670
1671    bitmapFont->bitmaps = (char *) xalloc(bytestoalloc);
1672    if (!bitmapFont->bitmaps) {
1673 fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc);
1674	goto bail;
1675    }
1676    bzero(bitmapFont->bitmaps, bytestoalloc);
1677
1678    glyphBytes = bitmapFont->bitmaps;
1679    for (i = 0; i < nchars; i++)
1680    {
1681	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) &&
1682	    (opci = ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i))))
1683	{
1684	    pci->bits = glyphBytes;
1685	    ScaleBitmap (pf, opci, pci, inv_xform,
1686			 widthMult, heightMult);
1687	    glyphBytes += BYTES_FOR_GLYPH(pci, glyph);
1688	}
1689    }
1690    return pf;
1691
1692bail:
1693    if (pf)
1694	xfree(pf);
1695    if (bitmapFont) {
1696	xfree(bitmapFont->metrics);
1697	xfree(bitmapFont->ink_metrics);
1698	xfree(bitmapFont->bitmaps);
1699        if(bitmapFont->encoding)
1700            for(i=0; i<NUM_SEGMENTS(nchars); i++)
1701                xfree(bitmapFont->encoding[i]);
1702	xfree(bitmapFont->encoding);
1703    }
1704    return NULL;
1705}
1706
1707static FontPtr
1708PrinterScaleBitmaps(FontPtr pf,         /* scaled font */
1709		    FontPtr opf, 	/* originating font */
1710		    double widthMult, 	/* glyphs width scale factor */
1711		    double heightMult, 	/* glyphs height scale factor */
1712		    FontScalablePtr vals)
1713{
1714    register int i;
1715    int		nchars = 0;
1716    char       *glyphBytes;
1717    BitmapFontPtr  bitmapFont,
1718		   obitmapFont;
1719    CharInfoPtr pci;
1720    FontInfoPtr pfi;
1721    int         glyph;
1722    unsigned    bytestoalloc = 0;
1723    int		firstCol, lastCol, firstRow, lastRow;
1724
1725    double	xform[4], inv_xform[4];
1726    double	xmult, ymult;
1727
1728    bitmapFont = (BitmapFontPtr) pf->fontPrivate;
1729    obitmapFont = (BitmapFontPtr) opf->fontPrivate;
1730
1731    if (!compute_xform_matrix(vals, widthMult, heightMult, xform,
1732			      inv_xform, &xmult, &ymult))
1733	goto bail;
1734
1735    pfi = &pf->info;
1736    firstCol = pfi->firstCol;
1737    lastCol = pfi->lastCol;
1738    firstRow = pfi->firstRow;
1739    lastRow = pfi->lastRow;
1740
1741    nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1);
1742    glyph = pf->glyph;
1743    for (i = 0; i < nchars; i++)
1744    {
1745	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)))
1746	    bytestoalloc = MAX(bytestoalloc,BYTES_FOR_GLYPH(pci, glyph));
1747    }
1748
1749    /* Do we add the font malloc stuff for VALUE ADDED ? */
1750    /* Will need to remember to free in the Unload routine */
1751
1752
1753    bitmapFont->bitmaps = (char *) xalloc(bytestoalloc);
1754    if (!bitmapFont->bitmaps) {
1755 fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc);
1756	goto bail;
1757    }
1758    bzero(bitmapFont->bitmaps, bytestoalloc);
1759
1760    glyphBytes = bitmapFont->bitmaps;
1761    for (i = 0; i < nchars; i++)
1762    {
1763	if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) &&
1764	    (ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i))))
1765	{
1766	    pci->bits = glyphBytes;
1767	}
1768    }
1769    return pf;
1770
1771bail:
1772    if (pf)
1773	xfree(pf);
1774    if (bitmapFont) {
1775	xfree(bitmapFont->metrics);
1776	xfree(bitmapFont->ink_metrics);
1777	xfree(bitmapFont->bitmaps);
1778        if(bitmapFont->encoding)
1779            for(i=0; i<NUM_SEGMENTS(nchars); i++)
1780                xfree(bitmapFont->encoding[i]);
1781	xfree(bitmapFont->encoding);
1782    }
1783    return NULL;
1784}
1785
1786#ifdef NOTDEF
1787/*
1788 *	exported interfaces
1789 */
1790
1791FontFileLoadName(FontFileDirPtr *dirs, int ndirs, char *name, FontPtr *pfont,
1792		 fsBitmapFormat format, fsBitmapFormatMask fmask)
1793{
1794    FontFileNamePtr fname;
1795    char        full_name[1024];
1796    int         ret = BadFontName;
1797    int         i;
1798
1799    i = 0;
1800    while (i < ndirs) {
1801	if (fname = FontFileFindNameInDir(dirs[i], name)) {
1802	    if (!fname->alias) {
1803		if (!fname->font) {
1804		    strcpy(full_name, dirs[i]->dir);
1805		    strcat(full_name, fname->file);
1806		    ret = FontFileLoad(pfont, full_name, format, fmask);
1807		    if (ret == Successful) {
1808			fname->font = *pfont;
1809			(*pfont)->fpePrivate = (pointer) fname;
1810		    }
1811		    return ret;
1812		}
1813		*pfont = fname->font;
1814		return Successful;
1815	    }
1816	    name = fname->file;
1817	    i = 0;
1818	} else
1819	    i++;
1820    }
1821    return BadFontName;
1822}
1823#endif
1824
1825/* ARGSUSED */
1826int
1827BitmapOpenScalable (FontPathElementPtr fpe,
1828		    FontPtr *pFont,
1829		    int flags,
1830		    FontEntryPtr entry,
1831		    char *fileName, /* unused */
1832		    FontScalablePtr vals,
1833		    fsBitmapFormat format,
1834		    fsBitmapFormatMask fmask,
1835		    FontPtr non_cachable_font)	/* We don't do licensing */
1836{
1837    FontScalableRec	best;
1838    FontPtr		font = NullFont;
1839    double		dx, sdx,
1840			dy, sdy,
1841			savedX, savedY;
1842    FontPropPtr		props;
1843    char		*isStringProp = NULL;
1844    int			propCount;
1845    int			status;
1846    long		sWidth;
1847
1848    FontEntryPtr	scaleFrom;
1849    FontPathElementPtr	scaleFPE;
1850    FontPtr		sourceFont;
1851    char		fontName[MAXFONTNAMELEN];
1852
1853    /* Can't deal with mix-endian fonts yet */
1854
1855#ifdef NOTDEF /* XXX need better test */
1856    if ((format & BitmapFormatByteOrderMask) !=
1857	    (format & BitmapFormatBitOrderMask))
1858	return NullFontFileName;
1859#endif
1860
1861    /* Reject outrageously small font sizes to keep the math from
1862       blowing up. */
1863    if (get_matrix_vertical_component(vals->pixel_matrix) < 1.0 ||
1864	get_matrix_horizontal_component(vals->pixel_matrix) < 1.0)
1865	return BadFontName;
1866
1867    scaleFrom = (*find_scale[BitmapGetRenderIndex(entry->u.bitmap.renderer)])
1868		    (fpe, entry, vals, &best, &dx, &dy, &sdx, &sdy, &scaleFPE);
1869
1870    if (!scaleFrom)
1871	return BadFontName;
1872
1873    status = FontFileOpenBitmap(scaleFPE, &sourceFont, LoadAll, scaleFrom,
1874				format, fmask);
1875
1876    if (status != Successful)
1877	return BadFontName;
1878
1879    if (!vals->width)
1880	vals->width = best.width * dx;
1881
1882    /* Compute the scaled font */
1883
1884    savedX = dx;
1885    savedY = dy;
1886    font = ScaleFont(sourceFont, dx, dy, sdx, sdy, vals, &dx, &dy, &sWidth);
1887    if (font)
1888	font = (*scale[ BitmapGetRenderIndex(entry->u.bitmap.renderer) ])
1889			(font, sourceFont, savedX, savedY, vals);
1890
1891    if (!font)
1892    {
1893	if (!sourceFont->refcnt)
1894	    FontFileCloseFont((FontPathElementPtr) 0, sourceFont);
1895	return AllocError;
1896    }
1897
1898    /* Prepare font properties for the new font */
1899
1900    strcpy (fontName, scaleFrom->name.name);
1901    FontParseXLFDName (fontName, vals, FONT_XLFD_REPLACE_VALUE);
1902
1903    propCount = ComputeScaledProperties(&sourceFont->info, fontName, vals,
1904					dx, dy, sdx, sdy, sWidth, &props,
1905					&isStringProp);
1906
1907    if (!sourceFont->refcnt)
1908	FontFileCloseFont((FontPathElementPtr) 0, sourceFont);
1909
1910    if (propCount && (!props || !isStringProp))
1911    {
1912	font->info.nprops = 0;
1913	font->info.props = (FontPropPtr)0;
1914	font->info.isStringProp = (char *)0;
1915	bitmapUnloadScalable(font);
1916	return AllocError;
1917    }
1918
1919    font->info.props = props;
1920    font->info.nprops = propCount;
1921    font->info.isStringProp = isStringProp;
1922
1923    *pFont = font;
1924    return Successful;
1925}
1926
1927int
1928BitmapGetInfoScalable (FontPathElementPtr fpe,
1929		       FontInfoPtr pFontInfo,
1930		       FontEntryPtr entry,
1931		       FontNamePtr fontName,
1932		       char *fileName,
1933		       FontScalablePtr vals)
1934{
1935    FontPtr pfont;
1936    int flags = 0;
1937    long format = 0;  /* It doesn't matter what format for just info */
1938    long fmask = 0;
1939    int ret;
1940
1941    ret = BitmapOpenScalable(fpe, &pfont, flags, entry, fileName, vals,
1942			     format, fmask, NULL);
1943    if (ret != Successful)
1944        return ret;
1945    *pFontInfo = pfont->info;
1946
1947    pfont->info.nprops = 0;
1948    pfont->info.props = NULL;
1949    pfont->info.isStringProp = NULL;
1950
1951    (*pfont->unload_font)(pfont);
1952    return Successful;
1953}
1954
1955static void
1956bitmapUnloadScalable (FontPtr pFont)
1957{
1958    BitmapFontPtr   bitmapFont;
1959    FontInfoPtr	    pfi;
1960    int             i, nencoding;
1961
1962    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
1963    pfi = &pFont->info;
1964    xfree (pfi->props);
1965    xfree (pfi->isStringProp);
1966    if(bitmapFont->encoding) {
1967        nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
1968	    (pFont->info.lastRow - pFont->info.firstRow + 1);
1969        for(i=0; i<NUM_SEGMENTS(nencoding); i++)
1970            xfree(bitmapFont->encoding[i]);
1971    }
1972    xfree (bitmapFont->encoding);
1973    xfree (bitmapFont->bitmaps);
1974    xfree (bitmapFont->ink_metrics);
1975    xfree (bitmapFont->metrics);
1976    xfree (pFont->fontPrivate);
1977    DestroyFontRec (pFont);
1978}
1979