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
initFontPropTable()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
GetScalableEntry(fpe,name)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
get_matrix_horizontal_component(matrix)227 get_matrix_horizontal_component(matrix)
228 double *matrix;
229 {
230 return hypot(matrix[0], matrix[1]);
231 }
232
233 static double
get_matrix_vertical_component(matrix)234 get_matrix_vertical_component(matrix)
235 double *matrix;
236 {
237 return hypot(matrix[2], matrix[3]);
238 }
239
240
241 static Bool
ComputeScaleFactors(from,to,dx,dy,sdx,sdy,rescale_x)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
FindBestToScale(fpe,entry,vals,best,dxp,dyp,sdxp,sdyp,fpep)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
FindPmfToScale(fpe,entry,vals,best,dxp,dyp,sdxp,sdyp,fpep)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
doround(x)601 doround(x)
602 double x;
603 {
604 return (x >= 0) ? (long)(x + .5) : (long)(x - .5);
605 }
606
607 static int
computeProps(pf,wasStringProp,npf,isStringProp,nprops,xfactor,yfactor,sXfactor,sYfactor)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
ComputeScaledProperties(sourceFontInfo,name,vals,dx,dy,sdx,sdy,sWidth,pProps,pIsStringProp)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
compute_xform_matrix(vals,dx,dy,xform,inv_xform,xmult,ymult)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
ScaleFont(opf,widthMult,heightMult,sWidthMult,sHeightMult,vals,newWidthMult,newHeightMult,sWidth)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
lcm(a,b)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
ScaleBitmap(pFont,opci,pci,inv_xform,widthMult,heightMult)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
BitmapScaleBitmaps(pf,opf,widthMult,heightMult,vals)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
PrinterScaleBitmaps(pf,opf,widthMult,heightMult,vals)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
FontFileLoadName(dirs,ndirs,name,pfont,format,fmask)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 */
BitmapOpenScalable(fpe,pFont,flags,entry,fileName,vals,format,fmask,non_cachable_font)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
BitmapGetInfoScalable(fpe,pFontInfo,entry,fontName,fileName,vals)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
bitmapUnloadScalable(pFont)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 }
1915