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