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