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