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