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