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