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