upload tizen2.0 source
[framework/uifw/xorg/lib/libxfont.git] / src / fontfile / fontscale.c
1 /*
2
3 Copyright 1991, 1998  The Open Group
4
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
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
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.
20
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.
24
25 */
26
27 /*
28  * Author:  Keith Packard, MIT X Consortium
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 #include    <X11/fonts/fntfilst.h>
35 #include <math.h>
36
37 Bool
38 FontFileAddScaledInstance (FontEntryPtr entry, FontScalablePtr vals,
39                            FontPtr pFont, char *bitmapName)
40 {
41     FontScalableEntryPtr    scalable;
42     FontScalableExtraPtr    extra;
43     FontScaledPtr           new;
44     int                     newsize;
45
46     scalable = &entry->u.scalable;
47     extra = scalable->extra;
48     if (extra->numScaled == extra->sizeScaled)
49     {
50         newsize = extra->sizeScaled + 4;
51         new = realloc (extra->scaled, newsize * sizeof (FontScaledRec));
52         if (!new)
53             return FALSE;
54         extra->sizeScaled = newsize;
55         extra->scaled = new;
56     }
57     new = &extra->scaled[extra->numScaled++];
58     new->vals = *vals;
59     new->pFont = pFont;
60     new->bitmap = (FontEntryPtr) bitmapName;
61     if (pFont)
62         pFont->fpePrivate = (pointer) entry;
63     return TRUE;
64 }
65
66 /* Must call this after the directory is sorted */
67
68 void
69 FontFileSwitchStringsToBitmapPointers (FontDirectoryPtr dir)
70 {
71     int     s;
72     int     b;
73     int     i;
74     FontEntryPtr            scalable;
75     FontEntryPtr            nonScalable;
76     FontScaledPtr           scaled;
77     FontScalableExtraPtr    extra;
78
79     scalable = dir->scalable.entries;
80     nonScalable = dir->nonScalable.entries;
81     for (s = 0; s < dir->scalable.used; s++)
82     {
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];
89     }
90 }
91
92 void
93 FontFileRemoveScaledInstance (FontEntryPtr entry, FontPtr pFont)
94 {
95     FontScalableEntryPtr    scalable;
96     FontScalableExtraPtr    extra;
97     int                     i;
98
99     scalable = &entry->u.scalable;
100     extra = scalable->extra;
101     for (i = 0; i < extra->numScaled; i++)
102     {
103         if (extra->scaled[i].pFont == pFont)
104         {
105             if (extra->scaled[i].vals.ranges)
106                 free (extra->scaled[i].vals.ranges);
107             extra->numScaled--;
108             for (; i < extra->numScaled; i++)
109                 extra->scaled[i] = extra->scaled[i+1];
110         }
111     }
112 }
113
114 Bool
115 FontFileCompleteXLFD (FontScalablePtr vals, FontScalablePtr def)
116 {
117     FontResolutionPtr res;
118     int         num_res;
119     double      sx, sy, temp_matrix[4];
120     double      pixel_setsize_adjustment = 1.0;
121     /*
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
124      * (within a pixel)
125      *
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
130      * same font.
131      */
132
133     res = GetClientResolutions(&num_res);
134
135     if (!(vals->values_supplied & PIXELSIZE_MASK) ||
136         !(vals->values_supplied & POINTSIZE_MASK))
137     {
138         /* If resolution(s) unspecified and cannot be computed from
139            pixelsize and pointsize, get appropriate defaults. */
140
141         if (num_res)
142         {
143             if (vals->x <= 0)
144                 vals->x = res->x_resolution;
145             if (vals->y <= 0)
146                 vals->y = res->y_resolution;
147         }
148
149         if (vals->x <= 0)
150             vals->x = def->x;
151         if (vals->y <= 0)
152             vals->y = def->y;
153     }
154     else
155     {
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.  */
161
162         if (vals->y <= 0)
163         {
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);
168         }
169         if (vals->x <= 0)
170         {
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 */
174
175             if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
176                 (vals->values_supplied & PIXELSIZE_MASK) ==
177                     PIXELSIZE_SCALAR_NORMALIZED)
178             {
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);
183             }
184             else
185             {
186                 /* Not enough information in the pixelsize array.  Just
187                    assume the pixels are square. */
188                 vals->x = vals->y;
189             }
190         }
191     }
192
193     if (vals->x <= 0 || vals->y <= 0) return FALSE;
194
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))
199     {
200         if (num_res)
201         {
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) |
207                                     POINTSIZE_SCALAR;
208         }
209         else if (def->values_supplied & POINTSIZE_MASK)
210         {
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);
217         }
218         else return FALSE;
219     }
220
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 */
224
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)
228     {
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 */
233
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;
238     }
239
240     sx = (double)vals->x / 72.27;
241     sy = (double)vals->y / 72.27;
242
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.  */
246
247     if (vals->values_supplied & POINTSIZE_MASK)
248     {
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)
255         {
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)
261                 return FALSE;
262         }
263         if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY &&
264             (vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR)
265         {
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;
270         }
271
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];
278
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);
284     }
285     else
286     {
287         /* Pointsize unspecified...  compute from pixel size and
288            resolutions */
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;
295
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);
301
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)
306         {
307             /* Off-diagonal elements should be zero since no matrix was
308                specified. */
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;
314         }
315     }
316
317     /* We've succeeded.  Round everything to a few decimal places
318        for repeatability. */
319
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]);
328
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];
333
334     return TRUE;
335 }
336
337 static Bool
338 MatchScalable (FontScalablePtr a, FontScalablePtr b)
339 {
340     int i;
341
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.  */
350
351 #define EQUAL(a,b) ((a)[0] == (b)[0] && \
352                     (a)[1] == (b)[1] && \
353                     (a)[2] == (b)[2] && \
354                     (a)[3] == (b)[3])
355
356     if (!(a->x == b->x &&
357           a->y == b->y &&
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)))
368       return FALSE;
369
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)
375                 return FALSE;
376
377     return TRUE;
378 }
379
380 FontScaledPtr
381 FontFileFindScaledInstance (FontEntryPtr entry, FontScalablePtr vals,
382                             int noSpecificSize)
383 {
384     FontScalableEntryPtr    scalable;
385     FontScalableExtraPtr    extra;
386     FontScalablePtr         mvals;
387     int                     dist, i;
388     int                     mini;
389     double                  mindist;
390     register double         temp, sum=0.0;
391
392 #define NORMDIFF(a, b) ( \
393     temp = (a)[0] - (b)[0], \
394     sum = temp * temp, \
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], \
400     sum + temp * temp )
401
402     scalable = &entry->u.scalable;
403     extra = scalable->extra;
404     if (noSpecificSize && extra->numScaled)
405     {
406         mini = 0;
407         mindist = NORMDIFF(extra->scaled[0].vals.point_matrix,
408                            vals->point_matrix);
409         for (i = 1; i < extra->numScaled; i++)
410         {
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);
415             if (dist < mindist)
416             {
417                 mindist = dist;
418                 mini = i;
419             }
420         }
421         if (extra->scaled[mini].pFont &&
422             !extra->scaled[mini].pFont->info.cachable) return 0;
423         return &extra->scaled[mini];
424     }
425     else
426     {
427         /* See if we've scaled to this value yet */
428         for (i = 0; i < extra->numScaled; i++)
429         {
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];
434         }
435     }
436     return 0;
437 }