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