123a0898aSmrg/*
223a0898aSmrg
323a0898aSmrgCopyright 1991, 1998  The Open Group
423a0898aSmrg
523a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its
623a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that
723a0898aSmrgthe above copyright notice appear in all copies and that both that
823a0898aSmrgcopyright notice and this permission notice appear in supporting
923a0898aSmrgdocumentation.
1023a0898aSmrg
1123a0898aSmrgThe above copyright notice and this permission notice shall be included in
1223a0898aSmrgall copies or substantial portions of the Software.
1323a0898aSmrg
1423a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1523a0898aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1623a0898aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1723a0898aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1823a0898aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1923a0898aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2023a0898aSmrg
2123a0898aSmrgExcept as contained in this notice, the name of The Open Group shall not be
2223a0898aSmrgused in advertising or otherwise to promote the sale, use or other dealings
2323a0898aSmrgin this Software without prior written authorization from The Open Group.
2423a0898aSmrg
2523a0898aSmrg*/
2623a0898aSmrg
2723a0898aSmrg/*
2823a0898aSmrg * Author:  Keith Packard, MIT X Consortium
2923a0898aSmrg */
3023a0898aSmrg
3123a0898aSmrg#ifdef HAVE_CONFIG_H
3223a0898aSmrg#include <config.h>
3323a0898aSmrg#endif
3423a0898aSmrg#include    <X11/fonts/fntfilst.h>
3523a0898aSmrg#include <math.h>
3623a0898aSmrg
3723a0898aSmrgBool
3841c30155SmrgFontFileAddScaledInstance (FontEntryPtr entry, FontScalablePtr vals,
3923a0898aSmrg			   FontPtr pFont, char *bitmapName)
4023a0898aSmrg{
4123a0898aSmrg    FontScalableEntryPtr    scalable;
4223a0898aSmrg    FontScalableExtraPtr    extra;
4323a0898aSmrg    FontScaledPtr	    new;
4423a0898aSmrg    int			    newsize;
4523a0898aSmrg
4623a0898aSmrg    scalable = &entry->u.scalable;
4723a0898aSmrg    extra = scalable->extra;
4823a0898aSmrg    if (extra->numScaled == extra->sizeScaled)
4923a0898aSmrg    {
5023a0898aSmrg	newsize = extra->sizeScaled + 4;
517f7f5e4eSmrg	new = realloc (extra->scaled, newsize * sizeof (FontScaledRec));
5223a0898aSmrg	if (!new)
5323a0898aSmrg	    return FALSE;
5423a0898aSmrg	extra->sizeScaled = newsize;
5523a0898aSmrg	extra->scaled = new;
5623a0898aSmrg    }
5723a0898aSmrg    new = &extra->scaled[extra->numScaled++];
5823a0898aSmrg    new->vals = *vals;
5923a0898aSmrg    new->pFont = pFont;
6023a0898aSmrg    new->bitmap = (FontEntryPtr) bitmapName;
6123a0898aSmrg    if (pFont)
6223a0898aSmrg	pFont->fpePrivate = (pointer) entry;
6323a0898aSmrg    return TRUE;
6423a0898aSmrg}
6523a0898aSmrg
6623a0898aSmrg/* Must call this after the directory is sorted */
6723a0898aSmrg
6823a0898aSmrgvoid
6923a0898aSmrgFontFileSwitchStringsToBitmapPointers (FontDirectoryPtr dir)
7023a0898aSmrg{
7123a0898aSmrg    int	    s;
7223a0898aSmrg    int	    b;
7323a0898aSmrg    int	    i;
7423a0898aSmrg    FontEntryPtr	    scalable;
7523a0898aSmrg    FontEntryPtr	    nonScalable;
7623a0898aSmrg    FontScaledPtr	    scaled;
7723a0898aSmrg    FontScalableExtraPtr    extra;
7841c30155Smrg
7923a0898aSmrg    scalable = dir->scalable.entries;
8023a0898aSmrg    nonScalable = dir->nonScalable.entries;
8123a0898aSmrg    for (s = 0; s < dir->scalable.used; s++)
8223a0898aSmrg    {
8323a0898aSmrg	extra = scalable[s].u.scalable.extra;
8423a0898aSmrg	scaled = extra->scaled;
8523a0898aSmrg	for (i = 0; i < extra->numScaled; i++)
8623a0898aSmrg	    for (b = 0; b < dir->nonScalable.used; b++)
8723a0898aSmrg		if (nonScalable[b].name.name == (char *) scaled[i].bitmap)
8823a0898aSmrg		    scaled[i].bitmap = &nonScalable[b];
8923a0898aSmrg    }
9023a0898aSmrg}
9123a0898aSmrg
9223a0898aSmrgvoid
9323a0898aSmrgFontFileRemoveScaledInstance (FontEntryPtr entry, FontPtr pFont)
9423a0898aSmrg{
9523a0898aSmrg    FontScalableEntryPtr    scalable;
9623a0898aSmrg    FontScalableExtraPtr    extra;
9723a0898aSmrg    int			    i;
9823a0898aSmrg
9923a0898aSmrg    scalable = &entry->u.scalable;
10023a0898aSmrg    extra = scalable->extra;
10123a0898aSmrg    for (i = 0; i < extra->numScaled; i++)
10223a0898aSmrg    {
10323a0898aSmrg	if (extra->scaled[i].pFont == pFont)
10423a0898aSmrg	{
10523a0898aSmrg	    if (extra->scaled[i].vals.ranges)
1067f7f5e4eSmrg		free (extra->scaled[i].vals.ranges);
10723a0898aSmrg	    extra->numScaled--;
10823a0898aSmrg	    for (; i < extra->numScaled; i++)
10923a0898aSmrg		extra->scaled[i] = extra->scaled[i+1];
11023a0898aSmrg	}
11123a0898aSmrg    }
11223a0898aSmrg}
11323a0898aSmrg
11423a0898aSmrgBool
11523a0898aSmrgFontFileCompleteXLFD (FontScalablePtr vals, FontScalablePtr def)
11623a0898aSmrg{
11723a0898aSmrg    FontResolutionPtr res;
11823a0898aSmrg    int		num_res;
11923a0898aSmrg    double	sx, sy, temp_matrix[4];
12023a0898aSmrg    double	pixel_setsize_adjustment = 1.0;
12123a0898aSmrg    /*
12223a0898aSmrg     * If two of the three vertical scale values are specified, compute the
12323a0898aSmrg     * third.  If all three are specified, make sure they are consistent
12423a0898aSmrg     * (within a pixel)
12523a0898aSmrg     *
12623a0898aSmrg     * One purpose of this procedure is to complete XLFD names in a
12723a0898aSmrg     * repeatable manner.  That is, if the user partially specifies
12823a0898aSmrg     * a name (say, pixelsize but not pointsize), the results generated
12923a0898aSmrg     * here result in a fully specified name that will result in the
13023a0898aSmrg     * same font.
13123a0898aSmrg     */
13223a0898aSmrg
13323a0898aSmrg    res = GetClientResolutions(&num_res);
13423a0898aSmrg
13523a0898aSmrg    if (!(vals->values_supplied & PIXELSIZE_MASK) ||
13623a0898aSmrg	!(vals->values_supplied & POINTSIZE_MASK))
13723a0898aSmrg    {
13823a0898aSmrg	/* If resolution(s) unspecified and cannot be computed from
13923a0898aSmrg	   pixelsize and pointsize, get appropriate defaults. */
14023a0898aSmrg
14123a0898aSmrg	if (num_res)
14223a0898aSmrg	{
14323a0898aSmrg	    if (vals->x <= 0)
14423a0898aSmrg		vals->x = res->x_resolution;
14523a0898aSmrg	    if (vals->y <= 0)
14623a0898aSmrg		vals->y = res->y_resolution;
14723a0898aSmrg	}
14823a0898aSmrg
14923a0898aSmrg	if (vals->x <= 0)
15023a0898aSmrg	    vals->x = def->x;
15123a0898aSmrg	if (vals->y <= 0)
15223a0898aSmrg	    vals->y = def->y;
15323a0898aSmrg    }
15423a0898aSmrg    else
15523a0898aSmrg    {
15623a0898aSmrg	/* If needed, compute resolution values from the pixel and
15723a0898aSmrg	   pointsize information we were given.  This problem is
15823a0898aSmrg	   overdetermined (four equations, two unknowns), but we don't
15923a0898aSmrg	   check for inconsistencies here.  If they exist, they will
16023a0898aSmrg	   show up in later tests for the point and pixel sizes.  */
16123a0898aSmrg
16223a0898aSmrg	if (vals->y <= 0)
16323a0898aSmrg	{
16423a0898aSmrg	    double x = hypot(vals->pixel_matrix[1], vals->pixel_matrix[3]);
16523a0898aSmrg	    double y = hypot(vals->point_matrix[1], vals->point_matrix[3]);
16623a0898aSmrg	    if (y < EPS) return FALSE;
16723a0898aSmrg	    vals->y = (int)(x * 72.27 / y + .5);
16823a0898aSmrg	}
16923a0898aSmrg	if (vals->x <= 0)
17023a0898aSmrg	{
17123a0898aSmrg	    /* If the pixelsize was given as an array, or as a scalar that
17223a0898aSmrg	       has been normalized for the pixel shape, we have enough
17323a0898aSmrg	       information to compute a separate horizontal resolution */
17423a0898aSmrg
17523a0898aSmrg	    if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
17623a0898aSmrg	        (vals->values_supplied & PIXELSIZE_MASK) ==
17723a0898aSmrg		    PIXELSIZE_SCALAR_NORMALIZED)
17823a0898aSmrg	    {
17923a0898aSmrg		double x = hypot(vals->pixel_matrix[0], vals->pixel_matrix[2]);
18023a0898aSmrg		double y = hypot(vals->point_matrix[0], vals->point_matrix[2]);
18123a0898aSmrg		if (y < EPS) return FALSE;
18223a0898aSmrg		vals->x = (int)(x * 72.27 / y + .5);
18323a0898aSmrg	    }
18423a0898aSmrg	    else
18523a0898aSmrg	    {
18623a0898aSmrg		/* Not enough information in the pixelsize array.  Just
18723a0898aSmrg		   assume the pixels are square. */
18823a0898aSmrg		vals->x = vals->y;
18923a0898aSmrg	    }
19023a0898aSmrg	}
19123a0898aSmrg    }
19223a0898aSmrg
19323a0898aSmrg    if (vals->x <= 0 || vals->y <= 0) return FALSE;
19423a0898aSmrg
19523a0898aSmrg    /* If neither pixelsize nor pointsize is defined, take the pointsize
19623a0898aSmrg       from the defaults structure we've been passed. */
19723a0898aSmrg    if (!(vals->values_supplied & PIXELSIZE_MASK) &&
19823a0898aSmrg	!(vals->values_supplied & POINTSIZE_MASK))
19923a0898aSmrg    {
20023a0898aSmrg	if (num_res)
20123a0898aSmrg	{
20223a0898aSmrg	    vals->point_matrix[0] =
20323a0898aSmrg	    vals->point_matrix[3] = (double)res->point_size / 10.0;
20423a0898aSmrg	    vals->point_matrix[1] =
20523a0898aSmrg	    vals->point_matrix[2] = 0;
20623a0898aSmrg	    vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) |
20723a0898aSmrg				    POINTSIZE_SCALAR;
20823a0898aSmrg	}
20923a0898aSmrg	else if (def->values_supplied & POINTSIZE_MASK)
21023a0898aSmrg	{
21123a0898aSmrg	    vals->point_matrix[0] = def->point_matrix[0];
21223a0898aSmrg	    vals->point_matrix[1] = def->point_matrix[1];
21323a0898aSmrg	    vals->point_matrix[2] = def->point_matrix[2];
21423a0898aSmrg	    vals->point_matrix[3] = def->point_matrix[3];
21523a0898aSmrg	    vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) |
21623a0898aSmrg				    (def->values_supplied & POINTSIZE_MASK);
21723a0898aSmrg	}
21823a0898aSmrg	else return FALSE;
21923a0898aSmrg    }
22023a0898aSmrg
22123a0898aSmrg    /* At this point, at least two of the three vertical scale values
22223a0898aSmrg       should be specified.  Our job now is to compute the missing ones
22323a0898aSmrg       and check for agreement between overspecified values */
22423a0898aSmrg
22523a0898aSmrg    /* If pixelsize was specified by a scalar, we need to fix the matrix
22623a0898aSmrg       now that we know the resolutions.  */
22723a0898aSmrg    if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_SCALAR)
22823a0898aSmrg    {
22923a0898aSmrg	/* pixel_setsize_adjustment used below to modify permissible
23023a0898aSmrg	   error in pixel/pointsize matching, since multiplying a
23123a0898aSmrg	   number rounded to integer changes the amount of the error
23223a0898aSmrg	   caused by the rounding */
23323a0898aSmrg
23423a0898aSmrg	pixel_setsize_adjustment = (double)vals->x / (double)vals->y;
23523a0898aSmrg	vals->pixel_matrix[0] *= pixel_setsize_adjustment;
23623a0898aSmrg	vals->values_supplied  = (vals->values_supplied & ~PIXELSIZE_MASK) |
23723a0898aSmrg				 PIXELSIZE_SCALAR_NORMALIZED;
23823a0898aSmrg    }
23923a0898aSmrg
24023a0898aSmrg    sx = (double)vals->x / 72.27;
24123a0898aSmrg    sy = (double)vals->y / 72.27;
24223a0898aSmrg
24323a0898aSmrg    /* If a pointsize was specified, make sure pixelsize is consistent
24423a0898aSmrg       to within 1 pixel, then replace pixelsize with a consistent
24523a0898aSmrg       floating-point value.  */
24623a0898aSmrg
24723a0898aSmrg    if (vals->values_supplied & POINTSIZE_MASK)
24823a0898aSmrg    {
24923a0898aSmrg    recompute_pixelsize: ;
25023a0898aSmrg	temp_matrix[0] = vals->point_matrix[0] * sx;
25123a0898aSmrg	temp_matrix[1] = vals->point_matrix[1] * sy;
25223a0898aSmrg	temp_matrix[2] = vals->point_matrix[2] * sx;
25323a0898aSmrg	temp_matrix[3] = vals->point_matrix[3] * sy;
25423a0898aSmrg	if (vals->values_supplied & PIXELSIZE_MASK)
25523a0898aSmrg	{
25623a0898aSmrg	    if (fabs(vals->pixel_matrix[0] - temp_matrix[0]) >
25723a0898aSmrg		    pixel_setsize_adjustment ||
25823a0898aSmrg		fabs(vals->pixel_matrix[1] - temp_matrix[1]) > 1 ||
25923a0898aSmrg		fabs(vals->pixel_matrix[2] - temp_matrix[2]) > 1 ||
26023a0898aSmrg		fabs(vals->pixel_matrix[3] - temp_matrix[3]) > 1)
26123a0898aSmrg		return FALSE;
26223a0898aSmrg	}
26323a0898aSmrg	if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY &&
26423a0898aSmrg	    (vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
26523a0898aSmrg	{
26623a0898aSmrg	    /* In the special case that pixelsize came as an array and
26723a0898aSmrg	       pointsize as a scalar, recompute the pointsize matrix
26823a0898aSmrg	       from the pixelsize matrix. */
26923a0898aSmrg	    goto recompute_pointsize;
27023a0898aSmrg	}
27123a0898aSmrg
27223a0898aSmrg	/* Refresh pixel matrix with precise values computed from
27323a0898aSmrg	   pointsize and resolution.  */
27423a0898aSmrg	vals->pixel_matrix[0] = temp_matrix[0];
27523a0898aSmrg	vals->pixel_matrix[1] = temp_matrix[1];
27623a0898aSmrg	vals->pixel_matrix[2] = temp_matrix[2];
27723a0898aSmrg	vals->pixel_matrix[3] = temp_matrix[3];
27823a0898aSmrg
27923a0898aSmrg	/* Set values_supplied for pixel to match that for point */
28023a0898aSmrg	vals->values_supplied =
28123a0898aSmrg	    (vals->values_supplied & ~PIXELSIZE_MASK) |
28223a0898aSmrg	    (((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) ?
28323a0898aSmrg		PIXELSIZE_ARRAY : PIXELSIZE_SCALAR_NORMALIZED);
28423a0898aSmrg    }
28523a0898aSmrg    else
28623a0898aSmrg    {
28723a0898aSmrg	/* Pointsize unspecified...  compute from pixel size and
28823a0898aSmrg	   resolutions */
28923a0898aSmrg    recompute_pointsize: ;
29023a0898aSmrg	if (fabs(sx) < EPS || fabs(sy) < EPS) return FALSE;
29123a0898aSmrg	vals->point_matrix[0] = vals->pixel_matrix[0] / sx;
29223a0898aSmrg	vals->point_matrix[1] = vals->pixel_matrix[1] / sy;
29323a0898aSmrg	vals->point_matrix[2] = vals->pixel_matrix[2] / sx;
29423a0898aSmrg	vals->point_matrix[3] = vals->pixel_matrix[3] / sy;
29523a0898aSmrg
29623a0898aSmrg	/* Set values_supplied for pixel to match that for point */
29723a0898aSmrg	vals->values_supplied =
29823a0898aSmrg	    (vals->values_supplied & ~POINTSIZE_MASK) |
29923a0898aSmrg	    (((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY) ?
30023a0898aSmrg		POINTSIZE_ARRAY : POINTSIZE_SCALAR);
30123a0898aSmrg
30223a0898aSmrg	/* If we computed scalar pointsize from scalar pixelsize, round
30323a0898aSmrg	   pointsize to decipoints and recompute pixelsize so we end up
30423a0898aSmrg	   with a repeatable name */
30523a0898aSmrg	if ((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
30623a0898aSmrg	{
30723a0898aSmrg	    /* Off-diagonal elements should be zero since no matrix was
30823a0898aSmrg	       specified. */
30923a0898aSmrg	    vals->point_matrix[0] =
31023a0898aSmrg		(double)(int)(vals->point_matrix[0] * 10.0 + .5) / 10.0;
31123a0898aSmrg	    vals->point_matrix[3] =
31223a0898aSmrg		(double)(int)(vals->point_matrix[3] * 10.0 + .5) / 10.0;
31323a0898aSmrg	    goto recompute_pixelsize;
31423a0898aSmrg	}
31523a0898aSmrg    }
31623a0898aSmrg
31723a0898aSmrg    /* We've succeeded.  Round everything to a few decimal places
31823a0898aSmrg       for repeatability. */
31923a0898aSmrg
32023a0898aSmrg    vals->pixel_matrix[0] = xlfd_round_double(vals->pixel_matrix[0]);
32123a0898aSmrg    vals->pixel_matrix[1] = xlfd_round_double(vals->pixel_matrix[1]);
32223a0898aSmrg    vals->pixel_matrix[2] = xlfd_round_double(vals->pixel_matrix[2]);
32323a0898aSmrg    vals->pixel_matrix[3] = xlfd_round_double(vals->pixel_matrix[3]);
32423a0898aSmrg    vals->point_matrix[0] = xlfd_round_double(vals->point_matrix[0]);
32523a0898aSmrg    vals->point_matrix[1] = xlfd_round_double(vals->point_matrix[1]);
32623a0898aSmrg    vals->point_matrix[2] = xlfd_round_double(vals->point_matrix[2]);
32723a0898aSmrg    vals->point_matrix[3] = xlfd_round_double(vals->point_matrix[3]);
32823a0898aSmrg
32923a0898aSmrg    /* Fill in the deprecated fields for the benefit of rasterizers
33023a0898aSmrg       that do not handle the matrices. */
33123a0898aSmrg    vals->point = vals->point_matrix[3] * 10;
33223a0898aSmrg    vals->pixel = vals->pixel_matrix[3];
33323a0898aSmrg
33423a0898aSmrg    return TRUE;
33523a0898aSmrg}
33623a0898aSmrg
33723a0898aSmrgstatic Bool
33823a0898aSmrgMatchScalable (FontScalablePtr a, FontScalablePtr b)
33923a0898aSmrg{
34023a0898aSmrg    int i;
34123a0898aSmrg
34223a0898aSmrg    /* Some asymmetry here:  we assume that the first argument (a) is
34323a0898aSmrg       the table entry and the second (b) the item we're trying to match
34423a0898aSmrg       (the key).  We'll consider the fonts matched if the relevant
34523a0898aSmrg       metrics match *and* if a) the table entry doesn't have charset
34623a0898aSmrg       subsetting or b) the table entry has identical charset subsetting
34723a0898aSmrg       to that in the key.  We could add logic to check if the table
34823a0898aSmrg       entry has a superset of the charset required by the key, but
34923a0898aSmrg       we'll resist the urge for now.  */
35023a0898aSmrg
35123a0898aSmrg#define EQUAL(a,b) ((a)[0] == (b)[0] && \
35223a0898aSmrg                    (a)[1] == (b)[1] && \
35323a0898aSmrg                    (a)[2] == (b)[2] && \
35423a0898aSmrg                    (a)[3] == (b)[3])
35523a0898aSmrg
35623a0898aSmrg    if (!(a->x == b->x &&
35723a0898aSmrg	  a->y == b->y &&
35823a0898aSmrg	  (a->width == b->width || a->width == 0 || b->width == 0 || b->width == -1) &&
35923a0898aSmrg	  (!(b->values_supplied & PIXELSIZE_MASK) ||
36023a0898aSmrg	    ((a->values_supplied & PIXELSIZE_MASK) ==
36123a0898aSmrg	     (b->values_supplied & PIXELSIZE_MASK) &&
36223a0898aSmrg	    EQUAL(a->pixel_matrix, b->pixel_matrix))) &&
36323a0898aSmrg	  (!(b->values_supplied & POINTSIZE_MASK) ||
36423a0898aSmrg	    ((a->values_supplied & POINTSIZE_MASK) ==
36523a0898aSmrg	     (b->values_supplied & POINTSIZE_MASK) &&
36623a0898aSmrg	    EQUAL(a->point_matrix, b->point_matrix))) &&
36723a0898aSmrg	  (a->nranges == 0 || a->nranges == b->nranges)))
36823a0898aSmrg      return FALSE;
36923a0898aSmrg
37023a0898aSmrg    for (i = 0; i < a->nranges; i++)
37123a0898aSmrg	if (a->ranges[i].min_char_low != b->ranges[i].min_char_low ||
37223a0898aSmrg	    a->ranges[i].min_char_high != b->ranges[i].min_char_high ||
37323a0898aSmrg	    a->ranges[i].max_char_low != b->ranges[i].max_char_low ||
37423a0898aSmrg	    a->ranges[i].max_char_high != b->ranges[i].max_char_high)
37523a0898aSmrg		return FALSE;
37641c30155Smrg
37723a0898aSmrg    return TRUE;
37823a0898aSmrg}
37923a0898aSmrg
38023a0898aSmrgFontScaledPtr
38141c30155SmrgFontFileFindScaledInstance (FontEntryPtr entry, FontScalablePtr vals,
38223a0898aSmrg			    int noSpecificSize)
38323a0898aSmrg{
38423a0898aSmrg    FontScalableEntryPtr    scalable;
38523a0898aSmrg    FontScalableExtraPtr    extra;
38623a0898aSmrg    FontScalablePtr	    mvals;
38723a0898aSmrg    int			    dist, i;
38823a0898aSmrg    int			    mini;
38923a0898aSmrg    double		    mindist;
39023a0898aSmrg    register double	    temp, sum=0.0;
39123a0898aSmrg
39223a0898aSmrg#define NORMDIFF(a, b) ( \
39323a0898aSmrg    temp = (a)[0] - (b)[0], \
39423a0898aSmrg    sum = temp * temp, \
39523a0898aSmrg    temp = (a)[1] - (b)[1], \
39623a0898aSmrg    sum += temp * temp, \
39723a0898aSmrg    temp = (a)[2] - (b)[2], \
39823a0898aSmrg    sum += temp * temp, \
39923a0898aSmrg    temp = (a)[3] - (b)[3], \
40023a0898aSmrg    sum + temp * temp )
40123a0898aSmrg
40223a0898aSmrg    scalable = &entry->u.scalable;
40323a0898aSmrg    extra = scalable->extra;
40423a0898aSmrg    if (noSpecificSize && extra->numScaled)
40523a0898aSmrg    {
40623a0898aSmrg	mini = 0;
40723a0898aSmrg	mindist = NORMDIFF(extra->scaled[0].vals.point_matrix,
40823a0898aSmrg			   vals->point_matrix);
40923a0898aSmrg	for (i = 1; i < extra->numScaled; i++)
41023a0898aSmrg	{
41123a0898aSmrg	    if (extra->scaled[i].pFont &&
41223a0898aSmrg		!extra->scaled[i].pFont->info.cachable) continue;
41323a0898aSmrg	    mvals = &extra->scaled[i].vals;
41423a0898aSmrg	    dist = NORMDIFF(mvals->point_matrix, vals->point_matrix);
41523a0898aSmrg	    if (dist < mindist)
41623a0898aSmrg	    {
41723a0898aSmrg		mindist = dist;
41823a0898aSmrg		mini = i;
41923a0898aSmrg	    }
42023a0898aSmrg	}
42123a0898aSmrg	if (extra->scaled[mini].pFont &&
42223a0898aSmrg	    !extra->scaled[mini].pFont->info.cachable) return 0;
42323a0898aSmrg	return &extra->scaled[mini];
42423a0898aSmrg    }
42523a0898aSmrg    else
42623a0898aSmrg    {
42723a0898aSmrg    	/* See if we've scaled to this value yet */
42823a0898aSmrg    	for (i = 0; i < extra->numScaled; i++)
42923a0898aSmrg    	{
43023a0898aSmrg	    if (extra->scaled[i].pFont &&
43123a0898aSmrg		!extra->scaled[i].pFont->info.cachable) continue;
43223a0898aSmrg	    if (MatchScalable (&extra->scaled[i].vals, vals))
43323a0898aSmrg	    	return &extra->scaled[i];
43423a0898aSmrg    	}
43523a0898aSmrg    }
43623a0898aSmrg    return 0;
43723a0898aSmrg}
438