upload tizen2.0 source
[framework/uifw/xorg/lib/libxfont.git] / src / util / fontxlfd.c
1 /*
2
3 Copyright 1990, 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
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26
27 */
28
29 /*
30  * Author:  Keith Packard, MIT X Consortium
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 #include        <X11/fonts/fontmisc.h>
37 #include        <X11/fonts/fontstruct.h>
38 #include        <X11/fonts/fontxlfd.h>
39 #include        <X11/fonts/fontutil.h>
40 #include        <X11/Xos.h>
41 #include        <math.h>
42 #include        <stdlib.h>
43 #if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV)
44 #define NO_LOCALE
45 #endif
46 #ifndef NO_LOCALE
47 #include        <locale.h>
48 #endif
49 #include        <ctype.h>
50 #include        <stdio.h>       /* for sprintf() */
51
52 static char *
53 GetInt(char *ptr, int *val)
54 {
55     if (*ptr == '*') {
56         *val = -1;
57         ptr++;
58     } else
59         for (*val = 0; *ptr >= '0' && *ptr <= '9';)
60             *val = *val * 10 + *ptr++ - '0';
61     if (*ptr == '-')
62         return ptr;
63     return (char *) 0;
64 }
65
66 #define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))
67 #define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8))
68
69
70 #ifndef NO_LOCALE
71 static struct lconv *locale = 0;
72 #endif
73 static const char *radix = ".", *plus = "+", *minus = "-";
74
75 static char *
76 readreal(char *ptr, double *result)
77 {
78     char buffer[80], *p1, *p2;
79
80 #ifndef NO_LOCALE
81     /* Figure out what symbols apply in this locale */
82
83     if (!locale)
84     {
85         locale = localeconv();
86         if (locale->decimal_point && *locale->decimal_point)
87             radix = locale->decimal_point;
88         if (locale->positive_sign && *locale->positive_sign)
89             plus = locale->positive_sign;
90         if (locale->negative_sign && *locale->negative_sign)
91             minus = locale->negative_sign;
92     }
93 #endif
94     /* Copy the first 80 chars of ptr into our local buffer, changing
95        symbols as needed. */
96     for (p1 = ptr, p2 = buffer;
97          *p1 && (p2 - buffer) < sizeof(buffer) - 1;
98          p1++, p2++)
99     {
100         switch(*p1)
101         {
102             case '~': *p2 = *minus; break;
103             case '+': *p2 = *plus; break;
104             case '.': *p2 = *radix; break;
105             default: *p2 = *p1;
106         }
107     }
108     *p2 = 0;
109
110     /* Now we have something that strtod() can interpret... do it. */
111     *result = strtod(buffer, &p1);
112     /* Return NULL if failure, pointer past number if success */
113     return (p1 == buffer) ? (char *)0 : (ptr + (p1 - buffer));
114 }
115
116 static char *
117 xlfd_double_to_text(double value, char *buffer, int space_required)
118 {
119     register char *p1;
120     int ndigits, exponent;
121
122 #ifndef NO_LOCALE
123     if (!locale)
124     {
125         locale = localeconv();
126         if (locale->decimal_point && *locale->decimal_point)
127             radix = locale->decimal_point;
128         if (locale->positive_sign && *locale->positive_sign)
129             plus = locale->positive_sign;
130         if (locale->negative_sign && *locale->negative_sign)
131             minus = locale->negative_sign;
132     }
133 #endif
134
135     if (space_required)
136         *buffer++ = ' ';
137
138     /* Render the number using printf's idea of formatting */
139     sprintf(buffer, "%.*le", XLFD_NDIGITS, value);
140
141     /* Find and read the exponent value */
142     for (p1 = buffer + strlen(buffer);
143         *p1-- != 'e' && p1[1] != 'E';);
144     exponent = atoi(p1 + 2);
145     if (value == 0.0) exponent = 0;
146
147     /* Figure out how many digits are significant */
148     while (p1 >= buffer && (!isdigit(*p1) || *p1 == '0')) p1--;
149     ndigits = 0;
150     while (p1 >= buffer) if (isdigit(*p1--)) ndigits++;
151
152     /* Figure out notation to use */
153     if (exponent >= XLFD_NDIGITS || ndigits - exponent > XLFD_NDIGITS + 1)
154     {
155         /* Scientific */
156         sprintf(buffer, "%.*le", ndigits - 1, value);
157     }
158     else
159     {
160         /* Fixed */
161         ndigits -= exponent + 1;
162         if (ndigits < 0) ndigits = 0;
163         sprintf(buffer, "%.*lf", ndigits, value);
164         if (exponent < 0)
165         {
166             p1 = buffer;
167             while (*p1 && *p1 != '0') p1++;
168             while (*p1++) p1[-1] = *p1;
169         }
170     }
171
172     /* Last step, convert the locale-specific sign and radix characters
173        to our own. */
174     for (p1 = buffer; *p1; p1++)
175     {
176         if (*p1 == *minus) *p1 = '~';
177         else if (*p1 == *plus) *p1 = '+';
178         else if (*p1 == *radix) *p1 = '.';
179     }
180
181     return buffer - space_required;
182 }
183
184 double
185 xlfd_round_double(double x)
186 {
187    /* Utility for XLFD users to round numbers to XLFD_NDIGITS
188       significant digits.  How do you round to n significant digits on
189       a binary machine?  */
190
191 #if defined(i386) || defined(__i386__) || \
192     defined(ia64) || defined(__ia64__) || \
193     defined(__alpha__) || defined(__alpha) || \
194     defined(__hppa__) || \
195     defined(__amd64__) || defined(__amd64) || \
196     defined(sgi)
197 #include <float.h>
198
199 /* if we have IEEE 754 fp, we can round to binary digits... */
200
201 #if (FLT_RADIX == 2) && (DBL_DIG == 15) && (DBL_MANT_DIG == 53)
202
203 #ifndef M_LN2
204 #define M_LN2       0.69314718055994530942
205 #endif
206 #ifndef M_LN10
207 #define M_LN10      2.30258509299404568402
208 #endif
209
210 /* convert # of decimal digits to # of binary digits */
211 #define XLFD_NDIGITS_2 ((int)(XLFD_NDIGITS * M_LN10 / M_LN2 + 0.5))
212
213    union conv_d {
214       double d;
215       unsigned char b[8];
216    } d;
217    int i,j,k,d_exp;
218
219    if (x == 0)
220       return x;
221
222    /* do minor sanity check for IEEE 754 fp and correct byte order */
223    d.d = 1.0;
224    if (sizeof(double) == 8 && d.b[7] == 0x3f && d.b[6] == 0xf0) {
225
226       /*
227        * this code will round IEEE 754 double to XLFD_NDIGITS_2 binary digits
228        */
229
230       d.d = x;
231       d_exp = (d.b[7] << 4) | (d.b[6] >> 4);
232
233       i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
234       j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
235       for (; i<7; i++) {
236          k = d.b[i] + j;
237          d.b[i] = k;
238          if (k & 0x100) j = 1;
239          else break;
240       }
241       if ((i==7) && ((d.b[6] & 0xf0) != ((d_exp<<4) & 0xf0))) {
242          /* mantissa overflow: increment exponent */
243          d_exp = (d_exp & 0x800 ) | ((d_exp & 0x7ff) + 1);
244          d.b[7] = d_exp >> 4;
245          d.b[6] = (d.b[6] & 0x0f) | (d_exp << 4);
246       }
247
248       i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
249       j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
250       d.b[i] &= ~(j-1);
251       for (;--i>=0;) d.b[i] = 0;
252
253       return d.d;
254    }
255    else
256 #endif
257 #endif /* i386 || __i386__ */
258     {
259         /*
260          * If not IEEE 754:  Let printf() do it for you.
261          */
262
263         char buffer[40];
264
265         sprintf(buffer, "%.*lg", XLFD_NDIGITS, x);
266         return atof(buffer);
267     }
268 }
269
270 static char *
271 GetMatrix(char *ptr, FontScalablePtr vals, int which)
272 {
273     double *matrix;
274
275     if (which == PIXELSIZE_MASK)
276         matrix = vals->pixel_matrix;
277     else if (which == POINTSIZE_MASK)
278         matrix = vals->point_matrix;
279     else return (char *)0;
280
281     while (isspace(*ptr)) ptr++;
282     if (*ptr == '[')
283     {
284         /* This is a matrix containing real numbers.  It would be nice
285            to use strtod() or sscanf() to read the numbers, but those
286            don't handle '~' for minus and we cannot force them to use a
287            "."  for the radix.  We'll have to do the hard work ourselves
288            (in readreal()).  */
289
290         if ((ptr = readreal(++ptr, matrix + 0)) &&
291             (ptr = readreal(ptr, matrix + 1)) &&
292             (ptr = readreal(ptr, matrix + 2)) &&
293             (ptr = readreal(ptr, matrix + 3)))
294         {
295             while (isspace(*ptr)) ptr++;
296             if (*ptr != ']')
297                 ptr = (char *)0;
298             else
299             {
300                 ptr++;
301                 while (isspace(*ptr)) ptr++;
302                 if (*ptr == '-')
303                 {
304                     if (which == POINTSIZE_MASK)
305                         vals->values_supplied |= POINTSIZE_ARRAY;
306                     else
307                         vals->values_supplied |= PIXELSIZE_ARRAY;
308                 }
309                 else ptr = (char *)0;
310             }
311         }
312     }
313     else
314     {
315         int value;
316         if ((ptr = GetInt(ptr, &value)))
317         {
318             vals->values_supplied &= ~which;
319             if (value > 0)
320             {
321                 matrix[3] = (double)value;
322                 if (which == POINTSIZE_MASK)
323                 {
324                     matrix[3] /= 10.0;
325                     vals->values_supplied |= POINTSIZE_SCALAR;
326                 }
327                 else
328                     vals->values_supplied |= PIXELSIZE_SCALAR;
329                 /* If we're concocting the pixelsize array from a scalar,
330                    we will need to normalize element 0 for the pixel shape.
331                    This is done in FontFileCompleteXLFD(). */
332                 matrix[0] = matrix[3];
333                 matrix[1] = matrix[2] = 0.0;
334             }
335             else if (value < 0)
336             {
337                 if (which == POINTSIZE_MASK)
338                     vals->values_supplied |= POINTSIZE_WILDCARD;
339                 else
340                     vals->values_supplied |= PIXELSIZE_WILDCARD;
341             }
342         }
343     }
344     return ptr;
345 }
346
347
348 static void
349 append_ranges(char *fname, int nranges, fsRange *ranges)
350 {
351     if (nranges)
352     {
353         int i;
354
355         strcat(fname, "[");
356         for (i = 0; i < nranges && strlen(fname) < 1010; i++)
357         {
358             if (i) strcat(fname, " ");
359             sprintf(fname + strlen(fname), "%d",
360                     minchar(ranges[i]));
361             if (ranges[i].min_char_low ==
362                 ranges[i].max_char_low &&
363                 ranges[i].min_char_high ==
364                 ranges[i].max_char_high) continue;
365             sprintf(fname + strlen(fname), "_%d",
366                     maxchar(ranges[i]));
367         }
368         strcat(fname, "]");
369     }
370 }
371
372 Bool
373 FontParseXLFDName(char *fname, FontScalablePtr vals, int subst)
374 {
375     register char *ptr;
376     register char *ptr1,
377                *ptr2,
378                *ptr3,
379                *ptr4;
380     register char *ptr5;
381     FontScalableRec tmpvals;
382     char        replaceChar = '0';
383     char        tmpBuf[1024];
384     int         spacingLen;
385     int         l;
386     char        *p;
387
388     bzero(&tmpvals, sizeof(tmpvals));
389     if (subst != FONT_XLFD_REPLACE_VALUE)
390         *vals = tmpvals;
391
392     if (!(*(ptr = fname) == '-' || (*ptr++ == '*' && *ptr == '-')) ||  /* fndry */
393             !(ptr = strchr(ptr + 1, '-')) ||    /* family_name */
394             !(ptr1 = ptr = strchr(ptr + 1, '-')) ||     /* weight_name */
395             !(ptr = strchr(ptr + 1, '-')) ||    /* slant */
396             !(ptr = strchr(ptr + 1, '-')) ||    /* setwidth_name */
397             !(ptr = strchr(ptr + 1, '-')) ||    /* add_style_name */
398             !(ptr = strchr(ptr + 1, '-')) ||    /* pixel_size */
399             !(ptr = GetMatrix(ptr + 1, &tmpvals, PIXELSIZE_MASK)) ||
400             !(ptr2 = ptr = GetMatrix(ptr + 1, &tmpvals, POINTSIZE_MASK)) ||
401             !(ptr = GetInt(ptr + 1, &tmpvals.x)) ||     /* resolution_x */
402             !(ptr3 = ptr = GetInt(ptr + 1, &tmpvals.y)) ||  /* resolution_y */
403             !(ptr4 = ptr = strchr(ptr + 1, '-')) ||     /* spacing */
404             !(ptr5 = ptr = GetInt(ptr + 1, &tmpvals.width)) || /* average_width */
405             !(ptr = strchr(ptr + 1, '-')) ||    /* charset_registry */
406             strchr(ptr + 1, '-'))/* charset_encoding */
407         return FALSE;
408
409     /* Lop off HP charset subsetting enhancement.  Interpreting this
410        field requires allocating some space in which to return the
411        results.  So, to prevent memory leaks, this procedure will simply
412        lop off and ignore charset subsetting, and initialize the
413        relevant vals fields to zero.  It's up to the caller to make its
414        own call to FontParseRanges() if it's interested in the charset
415        subsetting.  */
416
417     if (subst != FONT_XLFD_REPLACE_NONE &&
418         (p = strchr(strrchr(fname, '-'), '[')))
419     {
420         tmpvals.values_supplied |= CHARSUBSET_SPECIFIED;
421         *p = '\0';
422     }
423
424     /* Fill in deprecated fields for the benefit of rasterizers that care
425        about them. */
426     tmpvals.pixel = (tmpvals.pixel_matrix[3] >= 0) ?
427                     (int)(tmpvals.pixel_matrix[3] + .5) :
428                     (int)(tmpvals.pixel_matrix[3] - .5);
429     tmpvals.point = (tmpvals.point_matrix[3] >= 0) ?
430                     (int)(tmpvals.point_matrix[3] * 10 + .5) :
431                     (int)(tmpvals.point_matrix[3] * 10 - .5);
432
433     spacingLen = ptr4 - ptr3 + 1;
434
435     switch (subst) {
436     case FONT_XLFD_REPLACE_NONE:
437         *vals = tmpvals;
438         break;
439     case FONT_XLFD_REPLACE_STAR:
440         replaceChar = '*';
441     case FONT_XLFD_REPLACE_ZERO:
442         strcpy(tmpBuf, ptr2);
443         ptr5 = tmpBuf + (ptr5 - ptr2);
444         ptr3 = tmpBuf + (ptr3 - ptr2);
445         ptr2 = tmpBuf;
446         ptr = ptr1 + 1;
447
448         ptr = strchr(ptr, '-') + 1;             /* skip weight */
449         ptr = strchr(ptr, '-') + 1;             /* skip slant */
450         ptr = strchr(ptr, '-') + 1;             /* skip setwidth_name */
451         ptr = strchr(ptr, '-') + 1;             /* skip add_style_name */
452
453         if ((ptr - fname) + spacingLen + strlen(ptr5) + 10 >= (unsigned)1024)
454             return FALSE;
455         *ptr++ = replaceChar;
456         *ptr++ = '-';
457         *ptr++ = replaceChar;
458         *ptr++ = '-';
459         *ptr++ = '*';
460         *ptr++ = '-';
461         *ptr++ = '*';
462         if (spacingLen > 2)
463         {
464             memmove(ptr, ptr3, spacingLen);
465             ptr += spacingLen;
466         }
467         else
468         {
469             *ptr++ = '-';
470             *ptr++ = '*';
471             *ptr++ = '-';
472         }
473         *ptr++ = replaceChar;
474         strcpy(ptr, ptr5);
475         *vals = tmpvals;
476         break;
477     case FONT_XLFD_REPLACE_VALUE:
478         if (vals->values_supplied & PIXELSIZE_MASK)
479         {
480             tmpvals.values_supplied =
481                 (tmpvals.values_supplied & ~PIXELSIZE_MASK) |
482                 (vals->values_supplied & PIXELSIZE_MASK);
483             tmpvals.pixel_matrix[0] = vals->pixel_matrix[0];
484             tmpvals.pixel_matrix[1] = vals->pixel_matrix[1];
485             tmpvals.pixel_matrix[2] = vals->pixel_matrix[2];
486             tmpvals.pixel_matrix[3] = vals->pixel_matrix[3];
487         }
488         if (vals->values_supplied & POINTSIZE_MASK)
489         {
490             tmpvals.values_supplied =
491                 (tmpvals.values_supplied & ~POINTSIZE_MASK) |
492                 (vals->values_supplied & POINTSIZE_MASK);
493             tmpvals.point_matrix[0] = vals->point_matrix[0];
494             tmpvals.point_matrix[1] = vals->point_matrix[1];
495             tmpvals.point_matrix[2] = vals->point_matrix[2];
496             tmpvals.point_matrix[3] = vals->point_matrix[3];
497         }
498         if (vals->x >= 0)
499             tmpvals.x = vals->x;
500         if (vals->y >= 0)
501             tmpvals.y = vals->y;
502         if (vals->width >= 0)
503             tmpvals.width = vals->width;
504         else if (vals->width < -1)      /* overload: -1 means wildcard */
505             tmpvals.width = -vals->width;
506
507
508         p = ptr1 + 1;                           /* weight field */
509         l = strchr(p, '-') - p;
510         sprintf(tmpBuf, "%*.*s", l, l, p);
511
512         p += l + 1;                             /* slant field */
513         l = strchr(p, '-') - p;
514         sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
515
516         p += l + 1;                             /* setwidth_name */
517         l = strchr(p, '-') - p;
518         sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
519
520         p += l + 1;                             /* add_style_name field */
521         l = strchr(p, '-') - p;
522         sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
523
524         strcat(tmpBuf, "-");
525         if ((tmpvals.values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY)
526         {
527             char buffer[80];
528             strcat(tmpBuf, "[");
529             strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[0],
530                    buffer, 0));
531             strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[1],
532                    buffer, 1));
533             strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[2],
534                    buffer, 1));
535             strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[3],
536                    buffer, 1));
537             strcat(tmpBuf, "]");
538         }
539         else
540         {
541             sprintf(tmpBuf + strlen(tmpBuf), "%d",
542                     (int)(tmpvals.pixel_matrix[3] + .5));
543         }
544         strcat(tmpBuf, "-");
545         if ((tmpvals.values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY)
546         {
547             char buffer[80];
548             strcat(tmpBuf, "[");
549             strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[0],
550                    buffer, 0));
551             strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[1],
552                    buffer, 1));
553             strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[2],
554                    buffer, 1));
555             strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[3],
556                    buffer, 1));
557             strcat(tmpBuf, "]");
558         }
559         else
560         {
561             sprintf(tmpBuf + strlen(tmpBuf), "%d",
562                     (int)(tmpvals.point_matrix[3] * 10.0 + .5));
563         }
564         sprintf(tmpBuf + strlen(tmpBuf), "-%d-%d%*.*s%d%s",
565                 tmpvals.x, tmpvals.y,
566                 spacingLen, spacingLen, ptr3, tmpvals.width, ptr5);
567         strcpy(ptr1 + 1, tmpBuf);
568         if ((vals->values_supplied & CHARSUBSET_SPECIFIED) && !vals->nranges)
569             strcat(fname, "[]");
570         else
571             append_ranges(fname, vals->nranges, vals->ranges);
572         break;
573     }
574     return TRUE;
575 }
576
577 fsRange *FontParseRanges(char *name, int *nranges)
578 {
579     int n;
580     unsigned long l;
581     char *p1, *p2;
582     fsRange *result = (fsRange *)0;
583
584     name = strchr(name, '-');
585     for (n = 1; name && n < 14; n++)
586         name = strchr(name + 1, '-');
587
588     *nranges = 0;
589     if (!name || !(p1 = strchr(name, '['))) return (fsRange *)0;
590     p1++;
591
592     while (*p1 && *p1 != ']')
593     {
594         fsRange thisrange;
595
596         l = strtol(p1, &p2, 0);
597         if (p2 == p1 || l > 0xffff) break;
598         thisrange.max_char_low = thisrange.min_char_low = l & 0xff;
599         thisrange.max_char_high = thisrange.min_char_high = l >> 8;
600
601         p1 = p2;
602         if (*p1 == ']' || *p1 == ' ')
603         {
604             while (*p1 == ' ') p1++;
605             if (add_range(&thisrange, nranges, &result, TRUE) != Successful)
606                 break;
607         }
608         else if (*p1 == '_')
609         {
610             l = strtol(++p1, &p2, 0);
611             if (p2 == p1 || l > 0xffff) break;
612             thisrange.max_char_low = l & 0xff;
613             thisrange.max_char_high = l >> 8;
614             p1 = p2;
615             if (*p1 == ']' || *p1 == ' ')
616             {
617                 while (*p1 == ' ') p1++;
618                 if (add_range(&thisrange, nranges, &result, TRUE) != Successful)
619                     break;
620             }
621         }
622         else break;
623     }
624
625     return result;
626 }