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