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 $ */
3
4 /*
5
6 Copyright (c) 1991 X Consortium
7
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:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
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.
24
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.
28
29 */
30
31 /*
32 * Author: Keith Packard, MIT X Consortium
33 */
34
35 #include "fntfilst.h"
36 #ifdef _XOPEN_SOURCE
37 #include <math.h>
38 #else
39 #define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
40 #include <math.h>
41 #undef _XOPEN_SOURCE
42 #endif
43
44 Bool
FontFileAddScaledInstance(entry,vals,pFont,bitmapName)45 FontFileAddScaledInstance (entry, vals, pFont, bitmapName)
46 FontEntryPtr entry;
47 FontScalablePtr vals;
48 FontPtr pFont;
49 char *bitmapName;
50 {
51 FontScalableEntryPtr scalable;
52 FontScalableExtraPtr extra;
53 FontScaledPtr new;
54 int newsize;
55
56 scalable = &entry->u.scalable;
57 extra = scalable->extra;
58 if (extra->numScaled == extra->sizeScaled)
59 {
60 newsize = extra->sizeScaled + 4;
61 new = (FontScaledPtr) xrealloc (extra->scaled,
62 newsize * sizeof (FontScaledRec));
63 if (!new)
64 return FALSE;
65 extra->sizeScaled = newsize;
66 extra->scaled = new;
67 }
68 new = &extra->scaled[extra->numScaled++];
69 new->vals = *vals;
70 new->pFont = pFont;
71 new->bitmap = (FontEntryPtr) bitmapName;
72 if (pFont)
73 pFont->fpePrivate = (pointer) entry;
74 return TRUE;
75 }
76
77 /* Must call this after the directory is sorted */
78
FontFileSwitchStringsToBitmapPointers(dir)79 FontFileSwitchStringsToBitmapPointers (dir)
80 FontDirectoryPtr dir;
81 {
82 int s;
83 int b;
84 int i;
85 FontEntryPtr scalable;
86 FontEntryPtr nonScalable;
87 FontScaledPtr scaled;
88 FontScalableExtraPtr extra;
89
90 scalable = dir->scalable.entries;
91 nonScalable = dir->nonScalable.entries;
92 for (s = 0; s < dir->scalable.used; s++)
93 {
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];
100 }
101 }
102
103 void
FontFileRemoveScaledInstance(entry,pFont)104 FontFileRemoveScaledInstance (entry, pFont)
105 FontEntryPtr entry;
106 FontPtr pFont;
107 {
108 FontScalableEntryPtr scalable;
109 FontScalableExtraPtr extra;
110 int i;
111
112 scalable = &entry->u.scalable;
113 extra = scalable->extra;
114 for (i = 0; i < extra->numScaled; i++)
115 {
116 if (extra->scaled[i].pFont == pFont)
117 {
118 if (extra->scaled[i].vals.ranges)
119 xfree (extra->scaled[i].vals.ranges);
120 extra->numScaled--;
121 for (; i < extra->numScaled; i++)
122 extra->scaled[i] = extra->scaled[i+1];
123 }
124 }
125 }
126
127 Bool
FontFileCompleteXLFD(vals,def)128 FontFileCompleteXLFD (vals, def)
129 register FontScalablePtr vals;
130 FontScalablePtr def;
131 {
132 int best;
133 FontResolutionPtr res;
134 int num_res;
135 double sx, sy, temp_matrix[4];
136 double pixel_setsize_adjustment = 1.0;
137 /*
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
140 * (within a pixel)
141 *
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
146 * same font.
147 */
148
149 res = GetClientResolutions(&num_res);
150
151 if (!(vals->values_supplied & PIXELSIZE_MASK) ||
152 !(vals->values_supplied & POINTSIZE_MASK))
153 {
154 /* If resolution(s) unspecified and cannot be computed from
155 pixelsize and pointsize, get appropriate defaults. */
156
157 if (num_res)
158 {
159 if (vals->x <= 0)
160 vals->x = res->x_resolution;
161 if (vals->y <= 0)
162 vals->y = res->y_resolution;
163 }
164
165 if (vals->x <= 0)
166 vals->x = def->x;
167 if (vals->y <= 0)
168 vals->y = def->y;
169 }
170 else
171 {
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. */
177
178 if (vals->y <= 0)
179 {
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);
184 }
185 if (vals->x <= 0)
186 {
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 */
190
191 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
192 (vals->values_supplied & PIXELSIZE_MASK) ==
193 PIXELSIZE_SCALAR_NORMALIZED)
194 {
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);
199 }
200 else
201 {
202 /* Not enough information in the pixelsize array. Just
203 assume the pixels are square. */
204 vals->x = vals->y;
205 }
206 }
207 }
208
209 if (vals->x <= 0 || vals->y <= 0) return FALSE;
210
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))
215 {
216 if (num_res)
217 {
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) |
223 POINTSIZE_SCALAR;
224 }
225 else if (def->values_supplied & POINTSIZE_MASK)
226 {
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);
233 }
234 else return FALSE;
235 }
236
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 */
240
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)
244 {
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 */
249
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;
254 }
255
256 sx = (double)vals->x / 72.27;
257 sy = (double)vals->y / 72.27;
258
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. */
262
263 if (vals->values_supplied & POINTSIZE_MASK)
264 {
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)
271 {
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)
277 return FALSE;
278 }
279 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY &&
280 (vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
281 {
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;
286 }
287
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];
294
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);
300 }
301 else
302 {
303 /* Pointsize unspecified... compute from pixel size and
304 resolutions */
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;
311
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);
317
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)
322 {
323 /* Off-diagonal elements should be zero since no matrix was
324 specified. */
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;
330 }
331 }
332
333 /* We've succeeded. Round everything to a few decimal places
334 for repeatability. */
335
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]);
344
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];
349
350 return TRUE;
351 }
352
353 static Bool
MatchScalable(a,b)354 MatchScalable (a, b)
355 FontScalablePtr a, b;
356 {
357 int i;
358
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. */
367
368 #define EQUAL(a,b) ((a)[0] == (b)[0] && \
369 (a)[1] == (b)[1] && \
370 (a)[2] == (b)[2] && \
371 (a)[3] == (b)[3])
372
373 if (!(a->x == b->x &&
374 a->y == b->y &&
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)))
385 return FALSE;
386
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)
392 return FALSE;
393
394 return TRUE;
395 }
396
397 FontScaledPtr
FontFileFindScaledInstance(entry,vals,noSpecificSize)398 FontFileFindScaledInstance (entry, vals, noSpecificSize)
399 FontEntryPtr entry;
400 FontScalablePtr vals;
401 {
402 FontScalableEntryPtr scalable;
403 FontScalableExtraPtr extra;
404 FontScalablePtr mvals;
405 int dist, i;
406 int mini;
407 double mindist;
408 register double temp, sum=0.0;
409
410 #define NORMDIFF(a, b) ( \
411 temp = (a)[0] - (b)[0], \
412 sum = temp * temp, \
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], \
418 sum + temp * temp )
419
420 scalable = &entry->u.scalable;
421 extra = scalable->extra;
422 if (noSpecificSize && extra->numScaled)
423 {
424 mini = 0;
425 mindist = NORMDIFF(extra->scaled[0].vals.point_matrix,
426 vals->point_matrix);
427 for (i = 1; i < extra->numScaled; i++)
428 {
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);
433 if (dist < mindist)
434 {
435 mindist = dist;
436 mini = i;
437 }
438 }
439 if (extra->scaled[mini].pFont &&
440 !extra->scaled[mini].pFont->info.cachable) return 0;
441 return &extra->scaled[mini];
442 }
443 else
444 {
445 /* See if we've scaled to this value yet */
446 for (i = 0; i < extra->numScaled; i++)
447 {
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];
452 }
453 }
454 return 0;
455 }
456