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