1 /* $XConsortium: fontscale.c /main/15 1996/09/28 16:49:13 rws $ */
2 /* $XFree86: xc/lib/font/fontfile/fontscale.c,v 3.4 1996/12/24 02:23:08 dawes Exp $ */
6 Copyright (c) 1991 X Consortium
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of the X Consortium shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings
27 in this Software without prior written authorization from the X Consortium.
32 * Author: Keith Packard, MIT X Consortium
39 #define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
45 FontFileAddScaledInstance (entry, vals, pFont, bitmapName)
51 FontScalableEntryPtr scalable;
52 FontScalableExtraPtr extra;
56 scalable = &entry->u.scalable;
57 extra = scalable->extra;
58 if (extra->numScaled == extra->sizeScaled)
60 newsize = extra->sizeScaled + 4;
61 new = (FontScaledPtr) xrealloc (extra->scaled,
62 newsize * sizeof (FontScaledRec));
65 extra->sizeScaled = newsize;
68 new = &extra->scaled[extra->numScaled++];
71 new->bitmap = (FontEntryPtr) bitmapName;
73 pFont->fpePrivate = (pointer) entry;
77 /* Must call this after the directory is sorted */
79 FontFileSwitchStringsToBitmapPointers (dir)
85 FontEntryPtr scalable;
86 FontEntryPtr nonScalable;
88 FontScalableExtraPtr extra;
90 scalable = dir->scalable.entries;
91 nonScalable = dir->nonScalable.entries;
92 for (s = 0; s < dir->scalable.used; s++)
94 extra = scalable[s].u.scalable.extra;
95 scaled = extra->scaled;
96 for (i = 0; i < extra->numScaled; i++)
97 for (b = 0; b < dir->nonScalable.used; b++)
98 if (nonScalable[b].name.name == (char *) scaled[i].bitmap)
99 scaled[i].bitmap = &nonScalable[b];
104 FontFileRemoveScaledInstance (entry, pFont)
108 FontScalableEntryPtr scalable;
109 FontScalableExtraPtr extra;
112 scalable = &entry->u.scalable;
113 extra = scalable->extra;
114 for (i = 0; i < extra->numScaled; i++)
116 if (extra->scaled[i].pFont == pFont)
118 if (extra->scaled[i].vals.ranges)
119 xfree (extra->scaled[i].vals.ranges);
121 for (; i < extra->numScaled; i++)
122 extra->scaled[i] = extra->scaled[i+1];
128 FontFileCompleteXLFD (vals, def)
129 register FontScalablePtr vals;
133 FontResolutionPtr res;
135 double sx, sy, temp_matrix[4];
136 double pixel_setsize_adjustment = 1.0;
138 * If two of the three vertical scale values are specified, compute the
139 * third. If all three are specified, make sure they are consistent
142 * One purpose of this procedure is to complete XLFD names in a
143 * repeatable manner. That is, if the user partially specifies
144 * a name (say, pixelsize but not pointsize), the results generated
145 * here result in a fully specified name that will result in the
149 res = GetClientResolutions(&num_res);
151 if (!(vals->values_supplied & PIXELSIZE_MASK) ||
152 !(vals->values_supplied & POINTSIZE_MASK))
154 /* If resolution(s) unspecified and cannot be computed from
155 pixelsize and pointsize, get appropriate defaults. */
160 vals->x = res->x_resolution;
162 vals->y = res->y_resolution;
172 /* If needed, compute resolution values from the pixel and
173 pointsize information we were given. This problem is
174 overdetermined (four equations, two unknowns), but we don't
175 check for inconsistencies here. If they exist, they will
176 show up in later tests for the point and pixel sizes. */
180 double x = hypot(vals->pixel_matrix[1], vals->pixel_matrix[3]);
181 double y = hypot(vals->point_matrix[1], vals->point_matrix[3]);
182 if (y < EPS) return FALSE;
183 vals->y = (int)(x * 72.27 / y + .5);
187 /* If the pixelsize was given as an array, or as a scalar that
188 has been normalized for the pixel shape, we have enough
189 information to compute a separate horizontal resolution */
191 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
192 (vals->values_supplied & PIXELSIZE_MASK) ==
193 PIXELSIZE_SCALAR_NORMALIZED)
195 double x = hypot(vals->pixel_matrix[0], vals->pixel_matrix[2]);
196 double y = hypot(vals->point_matrix[0], vals->point_matrix[2]);
197 if (y < EPS) return FALSE;
198 vals->x = (int)(x * 72.27 / y + .5);
202 /* Not enough information in the pixelsize array. Just
203 assume the pixels are square. */
209 if (vals->x <= 0 || vals->y <= 0) return FALSE;
211 /* If neither pixelsize nor pointsize is defined, take the pointsize
212 from the defaults structure we've been passed. */
213 if (!(vals->values_supplied & PIXELSIZE_MASK) &&
214 !(vals->values_supplied & POINTSIZE_MASK))
218 vals->point_matrix[0] =
219 vals->point_matrix[3] = (double)res->point_size / 10.0;
220 vals->point_matrix[1] =
221 vals->point_matrix[2] = 0;
222 vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) |
225 else if (def->values_supplied & POINTSIZE_MASK)
227 vals->point_matrix[0] = def->point_matrix[0];
228 vals->point_matrix[1] = def->point_matrix[1];
229 vals->point_matrix[2] = def->point_matrix[2];
230 vals->point_matrix[3] = def->point_matrix[3];
231 vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) |
232 (def->values_supplied & POINTSIZE_MASK);
237 /* At this point, at least two of the three vertical scale values
238 should be specified. Our job now is to compute the missing ones
239 and check for agreement between overspecified values */
241 /* If pixelsize was specified by a scalar, we need to fix the matrix
242 now that we know the resolutions. */
243 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_SCALAR)
245 /* pixel_setsize_adjustment used below to modify permissible
246 error in pixel/pointsize matching, since multiplying a
247 number rounded to integer changes the amount of the error
248 caused by the rounding */
250 pixel_setsize_adjustment = (double)vals->x / (double)vals->y;
251 vals->pixel_matrix[0] *= pixel_setsize_adjustment;
252 vals->values_supplied = vals->values_supplied & ~PIXELSIZE_MASK |
253 PIXELSIZE_SCALAR_NORMALIZED;
256 sx = (double)vals->x / 72.27;
257 sy = (double)vals->y / 72.27;
259 /* If a pointsize was specified, make sure pixelsize is consistent
260 to within 1 pixel, then replace pixelsize with a consistent
261 floating-point value. */
263 if (vals->values_supplied & POINTSIZE_MASK)
265 recompute_pixelsize: ;
266 temp_matrix[0] = vals->point_matrix[0] * sx;
267 temp_matrix[1] = vals->point_matrix[1] * sy;
268 temp_matrix[2] = vals->point_matrix[2] * sx;
269 temp_matrix[3] = vals->point_matrix[3] * sy;
270 if (vals->values_supplied & PIXELSIZE_MASK)
272 if (fabs(vals->pixel_matrix[0] - temp_matrix[0]) >
273 pixel_setsize_adjustment ||
274 fabs(vals->pixel_matrix[1] - temp_matrix[1]) > 1 ||
275 fabs(vals->pixel_matrix[2] - temp_matrix[2]) > 1 ||
276 fabs(vals->pixel_matrix[3] - temp_matrix[3]) > 1)
279 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY &&
280 (vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
282 /* In the special case that pixelsize came as an array and
283 pointsize as a scalar, recompute the pointsize matrix
284 from the pixelsize matrix. */
285 goto recompute_pointsize;
288 /* Refresh pixel matrix with precise values computed from
289 pointsize and resolution. */
290 vals->pixel_matrix[0] = temp_matrix[0];
291 vals->pixel_matrix[1] = temp_matrix[1];
292 vals->pixel_matrix[2] = temp_matrix[2];
293 vals->pixel_matrix[3] = temp_matrix[3];
295 /* Set values_supplied for pixel to match that for point */
296 vals->values_supplied =
297 (vals->values_supplied & ~PIXELSIZE_MASK) |
298 (((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) ?
299 PIXELSIZE_ARRAY : PIXELSIZE_SCALAR_NORMALIZED);
303 /* Pointsize unspecified... compute from pixel size and
305 recompute_pointsize: ;
306 if (fabs(sx) < EPS || fabs(sy) < EPS) return FALSE;
307 vals->point_matrix[0] = vals->pixel_matrix[0] / sx;
308 vals->point_matrix[1] = vals->pixel_matrix[1] / sy;
309 vals->point_matrix[2] = vals->pixel_matrix[2] / sx;
310 vals->point_matrix[3] = vals->pixel_matrix[3] / sy;
312 /* Set values_supplied for pixel to match that for point */
313 vals->values_supplied =
314 (vals->values_supplied & ~POINTSIZE_MASK) |
315 (((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY) ?
316 POINTSIZE_ARRAY : POINTSIZE_SCALAR);
318 /* If we computed scalar pointsize from scalar pixelsize, round
319 pointsize to decipoints and recompute pixelsize so we end up
320 with a repeatable name */
321 if ((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
323 /* Off-diagonal elements should be zero since no matrix was
325 vals->point_matrix[0] =
326 (double)(int)(vals->point_matrix[0] * 10.0 + .5) / 10.0;
327 vals->point_matrix[3] =
328 (double)(int)(vals->point_matrix[3] * 10.0 + .5) / 10.0;
329 goto recompute_pixelsize;
333 /* We've succeeded. Round everything to a few decimal places
334 for repeatability. */
336 vals->pixel_matrix[0] = xlfd_round_double(vals->pixel_matrix[0]);
337 vals->pixel_matrix[1] = xlfd_round_double(vals->pixel_matrix[1]);
338 vals->pixel_matrix[2] = xlfd_round_double(vals->pixel_matrix[2]);
339 vals->pixel_matrix[3] = xlfd_round_double(vals->pixel_matrix[3]);
340 vals->point_matrix[0] = xlfd_round_double(vals->point_matrix[0]);
341 vals->point_matrix[1] = xlfd_round_double(vals->point_matrix[1]);
342 vals->point_matrix[2] = xlfd_round_double(vals->point_matrix[2]);
343 vals->point_matrix[3] = xlfd_round_double(vals->point_matrix[3]);
345 /* Fill in the deprecated fields for the benefit of rasterizers
346 that do not handle the matrices. */
347 vals->point = vals->point_matrix[3] * 10;
348 vals->pixel = vals->pixel_matrix[3];
355 FontScalablePtr a, b;
359 /* Some asymmetry here: we assume that the first argument (a) is
360 the table entry and the second (b) the item we're trying to match
361 (the key). We'll consider the fonts matched if the relevant
362 metrics match *and* if a) the table entry doesn't have charset
363 subsetting or b) the table entry has identical charset subsetting
364 to that in the key. We could add logic to check if the table
365 entry has a superset of the charset required by the key, but
366 we'll resist the urge for now. */
368 #define EQUAL(a,b) ((a)[0] == (b)[0] && \
369 (a)[1] == (b)[1] && \
370 (a)[2] == (b)[2] && \
373 if (!(a->x == b->x &&
375 (a->width == b->width || a->width == 0 || b->width == 0) &&
376 (!(b->values_supplied & PIXELSIZE_MASK) ||
377 (a->values_supplied & PIXELSIZE_MASK) ==
378 (b->values_supplied & PIXELSIZE_MASK) &&
379 EQUAL(a->pixel_matrix, b->pixel_matrix)) &&
380 (!(b->values_supplied & POINTSIZE_MASK) ||
381 (a->values_supplied & POINTSIZE_MASK) ==
382 (b->values_supplied & POINTSIZE_MASK) &&
383 EQUAL(a->point_matrix, b->point_matrix)) &&
384 (a->nranges == 0 || a->nranges == b->nranges)))
387 for (i = 0; i < a->nranges; i++)
388 if (a->ranges[i].min_char_low != b->ranges[i].min_char_low ||
389 a->ranges[i].min_char_high != b->ranges[i].min_char_high ||
390 a->ranges[i].max_char_low != b->ranges[i].max_char_low ||
391 a->ranges[i].max_char_high != b->ranges[i].max_char_high)
398 FontFileFindScaledInstance (entry, vals, noSpecificSize)
400 FontScalablePtr vals;
402 FontScalableEntryPtr scalable;
403 FontScalableExtraPtr extra;
404 FontScalablePtr mvals;
408 register double temp, sum=0.0;
410 #define NORMDIFF(a, b) ( \
411 temp = (a)[0] - (b)[0], \
413 temp = (a)[1] - (b)[1], \
414 sum += temp * temp, \
415 temp = (a)[2] - (b)[2], \
416 sum += temp * temp, \
417 temp = (a)[3] - (b)[3], \
420 scalable = &entry->u.scalable;
421 extra = scalable->extra;
422 if (noSpecificSize && extra->numScaled)
425 mindist = NORMDIFF(extra->scaled[0].vals.point_matrix,
427 for (i = 1; i < extra->numScaled; i++)
429 if (extra->scaled[i].pFont &&
430 !extra->scaled[i].pFont->info.cachable) continue;
431 mvals = &extra->scaled[i].vals;
432 dist = NORMDIFF(mvals->point_matrix, vals->point_matrix);
439 if (extra->scaled[mini].pFont &&
440 !extra->scaled[mini].pFont->info.cachable) return 0;
441 return &extra->scaled[mini];
445 /* See if we've scaled to this value yet */
446 for (i = 0; i < extra->numScaled; i++)
448 if (extra->scaled[i].pFont &&
449 !extra->scaled[i].pFont->info.cachable) continue;
450 if (MatchScalable (&extra->scaled[i].vals, vals))
451 return &extra->scaled[i];