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