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