3 Copyright 1991, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
28 * Author: Keith Packard, MIT X Consortium
34 #include <X11/fonts/fntfilst.h>
38 FontFileAddScaledInstance (FontEntryPtr entry, FontScalablePtr vals,
39 FontPtr pFont, char *bitmapName)
41 FontScalableEntryPtr scalable;
42 FontScalableExtraPtr extra;
46 scalable = &entry->u.scalable;
47 extra = scalable->extra;
48 if (extra->numScaled == extra->sizeScaled)
50 newsize = extra->sizeScaled + 4;
51 new = realloc (extra->scaled, newsize * sizeof (FontScaledRec));
54 extra->sizeScaled = newsize;
57 new = &extra->scaled[extra->numScaled++];
60 new->bitmap = (FontEntryPtr) bitmapName;
62 pFont->fpePrivate = (pointer) entry;
66 /* Must call this after the directory is sorted */
69 FontFileSwitchStringsToBitmapPointers (FontDirectoryPtr dir)
74 FontEntryPtr scalable;
75 FontEntryPtr nonScalable;
77 FontScalableExtraPtr extra;
79 scalable = dir->scalable.entries;
80 nonScalable = dir->nonScalable.entries;
81 for (s = 0; s < dir->scalable.used; s++)
83 extra = scalable[s].u.scalable.extra;
84 scaled = extra->scaled;
85 for (i = 0; i < extra->numScaled; i++)
86 for (b = 0; b < dir->nonScalable.used; b++)
87 if (nonScalable[b].name.name == (char *) scaled[i].bitmap)
88 scaled[i].bitmap = &nonScalable[b];
93 FontFileRemoveScaledInstance (FontEntryPtr entry, FontPtr pFont)
95 FontScalableEntryPtr scalable;
96 FontScalableExtraPtr extra;
99 scalable = &entry->u.scalable;
100 extra = scalable->extra;
101 for (i = 0; i < extra->numScaled; i++)
103 if (extra->scaled[i].pFont == pFont)
105 if (extra->scaled[i].vals.ranges)
106 free (extra->scaled[i].vals.ranges);
108 for (; i < extra->numScaled; i++)
109 extra->scaled[i] = extra->scaled[i+1];
115 FontFileCompleteXLFD (FontScalablePtr vals, FontScalablePtr def)
117 FontResolutionPtr res;
119 double sx, sy, temp_matrix[4];
120 double pixel_setsize_adjustment = 1.0;
122 * If two of the three vertical scale values are specified, compute the
123 * third. If all three are specified, make sure they are consistent
126 * One purpose of this procedure is to complete XLFD names in a
127 * repeatable manner. That is, if the user partially specifies
128 * a name (say, pixelsize but not pointsize), the results generated
129 * here result in a fully specified name that will result in the
133 res = GetClientResolutions(&num_res);
135 if (!(vals->values_supplied & PIXELSIZE_MASK) ||
136 !(vals->values_supplied & POINTSIZE_MASK))
138 /* If resolution(s) unspecified and cannot be computed from
139 pixelsize and pointsize, get appropriate defaults. */
144 vals->x = res->x_resolution;
146 vals->y = res->y_resolution;
156 /* If needed, compute resolution values from the pixel and
157 pointsize information we were given. This problem is
158 overdetermined (four equations, two unknowns), but we don't
159 check for inconsistencies here. If they exist, they will
160 show up in later tests for the point and pixel sizes. */
164 double x = hypot(vals->pixel_matrix[1], vals->pixel_matrix[3]);
165 double y = hypot(vals->point_matrix[1], vals->point_matrix[3]);
166 if (y < EPS) return FALSE;
167 vals->y = (int)(x * 72.27 / y + .5);
171 /* If the pixelsize was given as an array, or as a scalar that
172 has been normalized for the pixel shape, we have enough
173 information to compute a separate horizontal resolution */
175 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
176 (vals->values_supplied & PIXELSIZE_MASK) ==
177 PIXELSIZE_SCALAR_NORMALIZED)
179 double x = hypot(vals->pixel_matrix[0], vals->pixel_matrix[2]);
180 double y = hypot(vals->point_matrix[0], vals->point_matrix[2]);
181 if (y < EPS) return FALSE;
182 vals->x = (int)(x * 72.27 / y + .5);
186 /* Not enough information in the pixelsize array. Just
187 assume the pixels are square. */
193 if (vals->x <= 0 || vals->y <= 0) return FALSE;
195 /* If neither pixelsize nor pointsize is defined, take the pointsize
196 from the defaults structure we've been passed. */
197 if (!(vals->values_supplied & PIXELSIZE_MASK) &&
198 !(vals->values_supplied & POINTSIZE_MASK))
202 vals->point_matrix[0] =
203 vals->point_matrix[3] = (double)res->point_size / 10.0;
204 vals->point_matrix[1] =
205 vals->point_matrix[2] = 0;
206 vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) |
209 else if (def->values_supplied & POINTSIZE_MASK)
211 vals->point_matrix[0] = def->point_matrix[0];
212 vals->point_matrix[1] = def->point_matrix[1];
213 vals->point_matrix[2] = def->point_matrix[2];
214 vals->point_matrix[3] = def->point_matrix[3];
215 vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) |
216 (def->values_supplied & POINTSIZE_MASK);
221 /* At this point, at least two of the three vertical scale values
222 should be specified. Our job now is to compute the missing ones
223 and check for agreement between overspecified values */
225 /* If pixelsize was specified by a scalar, we need to fix the matrix
226 now that we know the resolutions. */
227 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_SCALAR)
229 /* pixel_setsize_adjustment used below to modify permissible
230 error in pixel/pointsize matching, since multiplying a
231 number rounded to integer changes the amount of the error
232 caused by the rounding */
234 pixel_setsize_adjustment = (double)vals->x / (double)vals->y;
235 vals->pixel_matrix[0] *= pixel_setsize_adjustment;
236 vals->values_supplied = (vals->values_supplied & ~PIXELSIZE_MASK) |
237 PIXELSIZE_SCALAR_NORMALIZED;
240 sx = (double)vals->x / 72.27;
241 sy = (double)vals->y / 72.27;
243 /* If a pointsize was specified, make sure pixelsize is consistent
244 to within 1 pixel, then replace pixelsize with a consistent
245 floating-point value. */
247 if (vals->values_supplied & POINTSIZE_MASK)
249 recompute_pixelsize: ;
250 temp_matrix[0] = vals->point_matrix[0] * sx;
251 temp_matrix[1] = vals->point_matrix[1] * sy;
252 temp_matrix[2] = vals->point_matrix[2] * sx;
253 temp_matrix[3] = vals->point_matrix[3] * sy;
254 if (vals->values_supplied & PIXELSIZE_MASK)
256 if (fabs(vals->pixel_matrix[0] - temp_matrix[0]) >
257 pixel_setsize_adjustment ||
258 fabs(vals->pixel_matrix[1] - temp_matrix[1]) > 1 ||
259 fabs(vals->pixel_matrix[2] - temp_matrix[2]) > 1 ||
260 fabs(vals->pixel_matrix[3] - temp_matrix[3]) > 1)
263 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY &&
264 (vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
266 /* In the special case that pixelsize came as an array and
267 pointsize as a scalar, recompute the pointsize matrix
268 from the pixelsize matrix. */
269 goto recompute_pointsize;
272 /* Refresh pixel matrix with precise values computed from
273 pointsize and resolution. */
274 vals->pixel_matrix[0] = temp_matrix[0];
275 vals->pixel_matrix[1] = temp_matrix[1];
276 vals->pixel_matrix[2] = temp_matrix[2];
277 vals->pixel_matrix[3] = temp_matrix[3];
279 /* Set values_supplied for pixel to match that for point */
280 vals->values_supplied =
281 (vals->values_supplied & ~PIXELSIZE_MASK) |
282 (((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) ?
283 PIXELSIZE_ARRAY : PIXELSIZE_SCALAR_NORMALIZED);
287 /* Pointsize unspecified... compute from pixel size and
289 recompute_pointsize: ;
290 if (fabs(sx) < EPS || fabs(sy) < EPS) return FALSE;
291 vals->point_matrix[0] = vals->pixel_matrix[0] / sx;
292 vals->point_matrix[1] = vals->pixel_matrix[1] / sy;
293 vals->point_matrix[2] = vals->pixel_matrix[2] / sx;
294 vals->point_matrix[3] = vals->pixel_matrix[3] / sy;
296 /* Set values_supplied for pixel to match that for point */
297 vals->values_supplied =
298 (vals->values_supplied & ~POINTSIZE_MASK) |
299 (((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY) ?
300 POINTSIZE_ARRAY : POINTSIZE_SCALAR);
302 /* If we computed scalar pointsize from scalar pixelsize, round
303 pointsize to decipoints and recompute pixelsize so we end up
304 with a repeatable name */
305 if ((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
307 /* Off-diagonal elements should be zero since no matrix was
309 vals->point_matrix[0] =
310 (double)(int)(vals->point_matrix[0] * 10.0 + .5) / 10.0;
311 vals->point_matrix[3] =
312 (double)(int)(vals->point_matrix[3] * 10.0 + .5) / 10.0;
313 goto recompute_pixelsize;
317 /* We've succeeded. Round everything to a few decimal places
318 for repeatability. */
320 vals->pixel_matrix[0] = xlfd_round_double(vals->pixel_matrix[0]);
321 vals->pixel_matrix[1] = xlfd_round_double(vals->pixel_matrix[1]);
322 vals->pixel_matrix[2] = xlfd_round_double(vals->pixel_matrix[2]);
323 vals->pixel_matrix[3] = xlfd_round_double(vals->pixel_matrix[3]);
324 vals->point_matrix[0] = xlfd_round_double(vals->point_matrix[0]);
325 vals->point_matrix[1] = xlfd_round_double(vals->point_matrix[1]);
326 vals->point_matrix[2] = xlfd_round_double(vals->point_matrix[2]);
327 vals->point_matrix[3] = xlfd_round_double(vals->point_matrix[3]);
329 /* Fill in the deprecated fields for the benefit of rasterizers
330 that do not handle the matrices. */
331 vals->point = vals->point_matrix[3] * 10;
332 vals->pixel = vals->pixel_matrix[3];
338 MatchScalable (FontScalablePtr a, FontScalablePtr b)
342 /* Some asymmetry here: we assume that the first argument (a) is
343 the table entry and the second (b) the item we're trying to match
344 (the key). We'll consider the fonts matched if the relevant
345 metrics match *and* if a) the table entry doesn't have charset
346 subsetting or b) the table entry has identical charset subsetting
347 to that in the key. We could add logic to check if the table
348 entry has a superset of the charset required by the key, but
349 we'll resist the urge for now. */
351 #define EQUAL(a,b) ((a)[0] == (b)[0] && \
352 (a)[1] == (b)[1] && \
353 (a)[2] == (b)[2] && \
356 if (!(a->x == b->x &&
358 (a->width == b->width || a->width == 0 || b->width == 0 || b->width == -1) &&
359 (!(b->values_supplied & PIXELSIZE_MASK) ||
360 ((a->values_supplied & PIXELSIZE_MASK) ==
361 (b->values_supplied & PIXELSIZE_MASK) &&
362 EQUAL(a->pixel_matrix, b->pixel_matrix))) &&
363 (!(b->values_supplied & POINTSIZE_MASK) ||
364 ((a->values_supplied & POINTSIZE_MASK) ==
365 (b->values_supplied & POINTSIZE_MASK) &&
366 EQUAL(a->point_matrix, b->point_matrix))) &&
367 (a->nranges == 0 || a->nranges == b->nranges)))
370 for (i = 0; i < a->nranges; i++)
371 if (a->ranges[i].min_char_low != b->ranges[i].min_char_low ||
372 a->ranges[i].min_char_high != b->ranges[i].min_char_high ||
373 a->ranges[i].max_char_low != b->ranges[i].max_char_low ||
374 a->ranges[i].max_char_high != b->ranges[i].max_char_high)
381 FontFileFindScaledInstance (FontEntryPtr entry, FontScalablePtr vals,
384 FontScalableEntryPtr scalable;
385 FontScalableExtraPtr extra;
386 FontScalablePtr mvals;
390 register double temp, sum=0.0;
392 #define NORMDIFF(a, b) ( \
393 temp = (a)[0] - (b)[0], \
395 temp = (a)[1] - (b)[1], \
396 sum += temp * temp, \
397 temp = (a)[2] - (b)[2], \
398 sum += temp * temp, \
399 temp = (a)[3] - (b)[3], \
402 scalable = &entry->u.scalable;
403 extra = scalable->extra;
404 if (noSpecificSize && extra->numScaled)
407 mindist = NORMDIFF(extra->scaled[0].vals.point_matrix,
409 for (i = 1; i < extra->numScaled; i++)
411 if (extra->scaled[i].pFont &&
412 !extra->scaled[i].pFont->info.cachable) continue;
413 mvals = &extra->scaled[i].vals;
414 dist = NORMDIFF(mvals->point_matrix, vals->point_matrix);
421 if (extra->scaled[mini].pFont &&
422 !extra->scaled[mini].pFont->info.cachable) return 0;
423 return &extra->scaled[mini];
427 /* See if we've scaled to this value yet */
428 for (i = 0; i < extra->numScaled; i++)
430 if (extra->scaled[i].pFont &&
431 !extra->scaled[i].pFont->info.cachable) continue;
432 if (MatchScalable (&extra->scaled[i].vals, vals))
433 return &extra->scaled[i];