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