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