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