]> git.sesse.net Git - rdpsrv/blob - Xserver/lib/font/fontfile/fontscale.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / lib / font / fontfile / fontscale.c
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
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
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
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
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
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
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 }