~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/wineps.drv/type1afm.c

Version: ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*******************************************************************************
  2  *  Adobe Font Metric (AFM) file parsing functions for Wine PostScript driver.
  3  *  See http://partners.adobe.com/asn/developer/pdfs/tn/5004.AFM_Spec.pdf.
  4  *
  5  *  Copyright 2001  Ian Pilcher
  6  *
  7  * This library is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU Lesser General Public
  9  * License as published by the Free Software Foundation; either
 10  * version 2.1 of the License, or (at your option) any later version.
 11  *
 12  * This library is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this library; if not, write to the Free Software
 19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 20  *
 21  *  NOTE:  Many of the functions in this file can return either fatal errors
 22  *      (memory allocation failure) or non-fatal errors (unusable AFM file).
 23  *      Fatal errors are indicated by returning FALSE; see individual function
 24  *      descriptions for how they indicate non-fatal errors.
 25  *
 26  */
 27 
 28 #include "config.h"
 29 #include "wine/port.h"
 30 
 31 #include <string.h>
 32 #include <stdlib.h>
 33 #include <stdarg.h>
 34 #include <stdio.h>
 35 #ifdef HAVE_DIRENT_H
 36 # include <dirent.h>
 37 #endif
 38 #include <errno.h>
 39 #include <ctype.h>
 40 #include <limits.h>         /* INT_MIN */
 41 
 42 #ifdef HAVE_FLOAT_H
 43 #include <float.h>          /* FLT_MAX */
 44 #endif
 45 
 46 #include "windef.h"
 47 #include "winbase.h"
 48 #include "winerror.h"
 49 #include "winreg.h"
 50 #include "winnls.h"
 51 #include "psdrv.h"
 52 #include "wine/debug.h"
 53 
 54 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
 55 
 56 /*******************************************************************************
 57  *  ReadLine
 58  *
 59  *  Reads a line from a text file into the buffer and trims trailing whitespace.
 60  *  Can handle DOS and Unix text files, including weird DOS EOF.  Returns FALSE
 61  *  for unexpected I/O errors; otherwise returns TRUE and sets *p_result to
 62  *  either the number of characters in the returned string or one of the
 63  *  following:
 64  *
 65  *      0:          Blank (or all whitespace) line.  This is just a special case
 66  *                  of the normal behavior.
 67  *
 68  *      EOF:        End of file has been reached.
 69  *
 70  *      INT_MIN:    Buffer overflow.  Returned string is truncated (duh!) and
 71  *                  trailing whitespace is *not* trimmed.  Remaining text in
 72  *                  line is discarded.  (I.e. the file pointer is positioned at
 73  *                  the beginning of the next line.)
 74  *
 75  */
 76 static BOOL ReadLine(FILE *file, CHAR buffer[], INT bufsize, INT *p_result)
 77 {
 78      CHAR   *cp;
 79      INT    i;
 80 
 81      if (fgets(buffer, bufsize, file) == NULL)
 82      {
 83         if (feof(file) == 0)                            /* EOF or error? */
 84         {
 85             ERR("%s\n", strerror(errno));
 86             return FALSE;
 87         }
 88 
 89         *p_result = EOF;
 90         return TRUE;
 91     }
 92 
 93     cp = strchr(buffer, '\n');
 94     if (cp == NULL)
 95     {
 96         i = strlen(buffer);
 97 
 98         if (i == bufsize - 1)       /* max possible; was line truncated? */
 99         {
100             do
101                 i = fgetc(file);                /* find the newline or EOF */
102             while (i != '\n' && i != EOF);
103 
104             if (i == EOF)
105             {
106                 if (feof(file) == 0)                    /* EOF or error? */
107                 {
108                     ERR("%s\n", strerror(errno));
109                     return FALSE;
110                 }
111 
112                 WARN("No newline at EOF\n");
113             }
114 
115             *p_result = INT_MIN;
116             return TRUE;
117         }
118         else                            /* no newline and not truncated */
119         {
120             if (strcmp(buffer, "\x1a") == 0)        /* test for DOS EOF */
121             {
122                 *p_result = EOF;
123                 return TRUE;
124             }
125 
126             WARN("No newline at EOF\n");
127             cp = buffer + i;    /* points to \0 where \n should have been */
128         }
129     }
130 
131     do
132     {
133         *cp = '\0';                             /* trim trailing whitespace */
134         if (cp == buffer)
135             break;                              /* don't underflow buffer */
136         --cp;
137     }
138     while (isspace(*cp));
139 
140     *p_result = strlen(buffer);
141     return TRUE;
142 }
143 
144 /*******************************************************************************
145  *  FindLine
146  *
147  *  Finds a line in the file that begins with the given string.  Returns FALSE
148  *  for unexpected I/O errors; returns an empty (zero character) string if the
149  *  requested line is not found.
150  *
151  *  NOTE:  The file pointer *MUST* be positioned at the beginning of a line when
152  *      this function is called.  Otherwise, an infinite loop can result.
153  *
154  */
155 static BOOL FindLine(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key)
156 {
157     INT     len = strlen(key);
158     LONG    start = ftell(file);
159 
160     do
161     {
162         INT     result;
163         BOOL    ok;
164 
165         ok = ReadLine(file, buffer, bufsize, &result);
166         if (ok == FALSE)
167             return FALSE;
168 
169         if (result > 0 && strncmp(buffer, key, len) == 0)
170             return TRUE;
171 
172         if (result == EOF)
173         {
174             rewind(file);
175         }
176         else if (result == INT_MIN)
177         {
178             WARN("Line beginning '%32s...' is too long; ignoring\n", buffer);
179         }
180     }
181     while (ftell(file) != start);
182 
183     WARN("Couldn't find line '%s...' in AFM file\n", key);
184     buffer[0] = '\0';
185     return TRUE;
186 }
187 
188 /*******************************************************************************
189  *  DoubleToFloat
190  *
191  *  Utility function to convert double to float while checking for overflow.
192  *  Will also catch strtod overflows, since HUGE_VAL > FLT_MAX (at least on
193  *  Linux x86/gcc).
194  *
195  */
196 static inline BOOL DoubleToFloat(float *p_f, double d)
197 {
198     if (d > (double)FLT_MAX || d < -(double)FLT_MAX)
199         return FALSE;
200 
201     *p_f = (float)d;
202     return TRUE;
203 }
204 
205 /*******************************************************************************
206  *  Round
207  *
208  *  Utility function to add or subtract 0.5 before converting to integer type.
209  *
210  */
211 static inline float Round(float f)
212 {
213     return (f >= 0.0) ? (f + 0.5) : (f - 0.5);
214 }
215 
216 /*******************************************************************************
217  *  ReadFloat
218  *
219  *  Finds and parses a line of the form '<key> <value>', where value is a
220  *  number.  Sets *p_found to FALSE if a corresponding line cannot be found, or
221  *  it cannot be parsed; also sets *p_ret to 0.0, so calling functions can just
222  *  skip the check of *p_found if the item is not required.
223  *
224  */
225 static BOOL ReadFloat(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key,
226         FLOAT *p_ret, BOOL *p_found)
227 {
228     CHAR    *cp, *end_ptr;
229     double  d;
230 
231     if (FindLine(file, buffer, bufsize, key) == FALSE)
232         return FALSE;
233 
234     if (buffer[0] == '\0')          /* line not found */
235     {
236         *p_found = FALSE;
237         *p_ret = 0.0;
238         return TRUE;
239     }
240 
241     cp = buffer + strlen(key);                      /* first char after key */
242     errno = 0;
243     d = strtod(cp, &end_ptr);
244 
245     if (end_ptr == cp || errno != 0 || DoubleToFloat(p_ret, d) == FALSE)
246     {
247         WARN("Error parsing line '%s'\n", buffer);
248         *p_found = FALSE;
249         *p_ret = 0.0;
250         return TRUE;
251     }
252 
253     *p_found = TRUE;
254     return TRUE;
255 }
256 
257 /*******************************************************************************
258  *  ReadInt
259  *
260  *  See description of ReadFloat.
261  *
262  */
263 static BOOL ReadInt(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key,
264         INT *p_ret, BOOL *p_found)
265 {
266     BOOL    retval;
267     FLOAT   f;
268 
269     retval = ReadFloat(file, buffer, bufsize, key, &f, p_found);
270     if (retval == FALSE || *p_found == FALSE)
271     {
272         *p_ret = 0;
273         return retval;
274     }
275 
276     f = Round(f);
277 
278     if (f > (FLOAT)INT_MAX || f < (FLOAT)INT_MIN)
279     {
280         WARN("Error parsing line '%s'\n", buffer);
281         *p_ret = 0;
282         *p_found = FALSE;
283         return TRUE;
284     }
285 
286     *p_ret = (INT)f;
287     return TRUE;
288 }
289 
290 /*******************************************************************************
291  *  ReadString
292  *
293  *  Returns FALSE on I/O error or memory allocation failure; sets *p_str to NULL
294  *  if line cannot be found or can't be parsed.
295  *
296  */
297 static BOOL ReadString(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key,
298         LPSTR *p_str)
299 {
300     CHAR    *cp;
301 
302     if (FindLine(file, buffer, bufsize, key) == FALSE)
303         return FALSE;
304 
305     if (buffer[0] == '\0')
306     {
307         *p_str = NULL;
308         return TRUE;
309     }
310 
311     cp = buffer + strlen(key);                      /* first char after key */
312     if (*cp == '\0')
313     {
314         *p_str = NULL;
315         return TRUE;
316     }
317 
318     while (isspace(*cp))                /* find first non-whitespace char */
319         ++cp;
320 
321     *p_str = HeapAlloc(PSDRV_Heap, 0, strlen(cp) + 1);
322     if (*p_str == NULL)
323         return FALSE;
324 
325     strcpy(*p_str, cp);
326     return TRUE;
327 }
328 
329 /*******************************************************************************
330  *  ReadBBox
331  *
332  *  Similar to ReadFloat above.
333  *
334  */
335 static BOOL ReadBBox(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
336         BOOL *p_found)
337 {
338     CHAR    *cp, *end_ptr;
339     double  d;
340 
341     if (FindLine(file, buffer, bufsize, "FontBBox") == FALSE)
342         return FALSE;
343 
344     if (buffer[0] == '\0')
345     {
346         *p_found = FALSE;
347         return TRUE;
348     }
349 
350     errno = 0;
351 
352     cp = buffer + sizeof("FontBBox");
353     d = strtod(cp, &end_ptr);
354     if (end_ptr == cp || errno != 0 ||
355             DoubleToFloat(&(afm->FontBBox.llx), d) == FALSE)
356         goto parse_error;
357 
358     cp = end_ptr;
359     d = strtod(cp, &end_ptr);
360     if (end_ptr == cp || errno != 0 ||
361             DoubleToFloat(&(afm->FontBBox.lly), d) == FALSE)
362         goto parse_error;
363 
364     cp = end_ptr;
365     d = strtod(cp, &end_ptr);
366     if (end_ptr == cp || errno != 0
367             || DoubleToFloat(&(afm->FontBBox.urx), d) == FALSE)
368         goto parse_error;
369 
370     cp = end_ptr;
371     d = strtod(cp, &end_ptr);
372     if (end_ptr == cp || errno != 0
373             || DoubleToFloat(&(afm->FontBBox.ury), d) == FALSE)
374         goto parse_error;
375 
376     *p_found = TRUE;
377     return TRUE;
378 
379     parse_error:
380         WARN("Error parsing line '%s'\n", buffer);
381         *p_found = FALSE;
382         return TRUE;
383 }
384 
385 /*******************************************************************************
386  *  ReadWeight
387  *
388  *  Finds and parses the 'Weight' line of an AFM file.  Only tries to determine
389  *  if a font is bold (FW_BOLD) or not (FW_NORMAL) -- ignoring all those cute
390  *  little FW_* typedefs in the Win32 doc.  AFAICT, this is what the Windows
391  *  PostScript driver does.
392  *
393  */
394 static const struct { LPCSTR keyword; INT weight; } afm_weights[] =
395 {
396     { "REGULAR",        FW_NORMAL },
397     { "NORMAL",         FW_NORMAL },
398     { "ROMAN",          FW_NORMAL },
399     { "BOLD",           FW_BOLD },
400     { "BOOK",           FW_NORMAL },
401     { "MEDIUM",         FW_NORMAL },
402     { "LIGHT",          FW_NORMAL },
403     { "BLACK",          FW_BOLD },
404     { "HEAVY",          FW_BOLD },
405     { "DEMI",           FW_BOLD },
406     { "ULTRA",          FW_BOLD },
407     { "SUPER" ,         FW_BOLD },
408     { NULL,             0 }
409 };
410 
411 static BOOL ReadWeight(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
412         BOOL *p_found)
413 {
414     LPSTR   sz;
415     CHAR    *cp;
416     INT     i;
417 
418     if (ReadString(file, buffer, bufsize, "Weight", &sz) == FALSE)
419         return FALSE;
420 
421     if (sz == NULL)
422     {
423         *p_found = FALSE;
424         return TRUE;
425     }
426 
427     for (cp = sz; *cp != '\0'; ++cp)
428         *cp = toupper(*cp);
429 
430     for (i = 0; afm_weights[i].keyword != NULL; ++i)
431     {
432         if (strstr(sz, afm_weights[i].keyword) != NULL)
433         {
434             afm->Weight = afm_weights[i].weight;
435             *p_found = TRUE;
436             HeapFree(PSDRV_Heap, 0, sz);
437             return TRUE;
438         }
439     }
440 
441     WARN("Unknown weight '%s'; treating as Roman\n", sz);
442 
443     afm->Weight = FW_NORMAL;
444     *p_found = TRUE;
445     HeapFree(PSDRV_Heap, 0, sz);
446     return TRUE;
447 }
448 
449 /*******************************************************************************
450  *  ReadFixedPitch
451  *
452  */
453 static BOOL ReadFixedPitch(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
454         BOOL *p_found)
455 {
456     LPSTR   sz;
457 
458     if (ReadString(file, buffer, bufsize, "IsFixedPitch", &sz) == FALSE)
459         return FALSE;
460 
461     if (sz == NULL)
462     {
463         *p_found = FALSE;
464         return TRUE;
465     }
466 
467     if (strcasecmp(sz, "false") == 0)
468     {
469         afm->IsFixedPitch = FALSE;
470         *p_found = TRUE;
471         HeapFree(PSDRV_Heap, 0, sz);
472         return TRUE;
473     }
474 
475     if (strcasecmp(sz, "true") == 0)
476     {
477         afm->IsFixedPitch = TRUE;
478         *p_found = TRUE;
479         HeapFree(PSDRV_Heap, 0, sz);
480         return TRUE;
481     }
482 
483     WARN("Can't parse line '%s'\n", buffer);
484 
485     *p_found = FALSE;
486     HeapFree(PSDRV_Heap, 0, sz);
487     return TRUE;
488 }
489 
490 /*******************************************************************************
491  *  ReadFontMetrics
492  *
493  *  Allocates space for the AFM on the driver heap and reads basic font metrics.
494  *  Returns FALSE for memory allocation failure; sets *p_afm to NULL if AFM file
495  *  is unusable.
496  *
497  */
498 static BOOL ReadFontMetrics(FILE *file, CHAR buffer[], INT bufsize, AFM **p_afm)
499 {
500     AFM     *afm;
501     BOOL    retval, found;
502 
503     *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
504     if (afm == NULL)
505         return FALSE;
506 
507     retval = ReadWeight(file, buffer, bufsize, afm, &found);
508     if (retval == FALSE || found == FALSE)
509         goto cleanup_afm;
510 
511     retval = ReadFloat(file, buffer, bufsize, "ItalicAngle",
512             &(afm->ItalicAngle), &found);
513     if (retval == FALSE || found == FALSE)
514         goto cleanup_afm;
515 
516     retval = ReadFixedPitch(file, buffer, bufsize, afm, &found);
517     if (retval == FALSE || found == FALSE)
518         goto cleanup_afm;
519 
520     retval = ReadBBox(file, buffer, bufsize, afm, &found);
521     if (retval == FALSE || found == FALSE)
522         goto cleanup_afm;
523 
524     retval = ReadFloat(file, buffer, bufsize, "UnderlinePosition",
525             &(afm->UnderlinePosition), &found);
526     if (retval == FALSE || found == FALSE)
527         goto cleanup_afm;
528 
529     retval = ReadFloat(file, buffer, bufsize, "UnderlineThickness",
530             &(afm->UnderlineThickness), &found);
531     if (retval == FALSE || found == FALSE)
532         goto cleanup_afm;
533 
534     retval = ReadFloat(file, buffer, bufsize, "Ascender",       /* optional */
535             &(afm->Ascender), &found);
536     if (retval == FALSE)
537         goto cleanup_afm;
538 
539     retval = ReadFloat(file, buffer, bufsize, "Descender",      /* optional */
540             &(afm->Descender), &found);
541     if (retval == FALSE)
542         goto cleanup_afm;
543 
544     afm->WinMetrics.usUnitsPerEm = 1000;
545     afm->WinMetrics.sTypoAscender = (SHORT)Round(afm->Ascender);
546     afm->WinMetrics.sTypoDescender = (SHORT)Round(afm->Descender);
547 
548     if (afm->WinMetrics.sTypoAscender == 0)
549         afm->WinMetrics.sTypoAscender = (SHORT)Round(afm->FontBBox.ury);
550 
551     if (afm->WinMetrics.sTypoDescender == 0)
552         afm->WinMetrics.sTypoDescender = (SHORT)Round(afm->FontBBox.lly);
553 
554     afm->WinMetrics.sTypoLineGap = 1200 -
555             (afm->WinMetrics.sTypoAscender - afm->WinMetrics.sTypoDescender);
556     if (afm->WinMetrics.sTypoLineGap < 0)
557         afm->WinMetrics.sTypoLineGap = 0;
558 
559     return TRUE;
560 
561     cleanup_afm:                        /* handle fatal or non-fatal errors */
562         HeapFree(PSDRV_Heap, 0, afm);
563         *p_afm = NULL;
564         return retval;
565 }
566 
567 /*******************************************************************************
568  *  ParseC
569  *
570  *  Fatal error:        return FALSE (none defined)
571  *
572  *  Non-fatal error:    leave metrics->C set to INT_MAX
573  *
574  */
575 static BOOL ParseC(LPSTR sz, OLD_AFMMETRICS *metrics)
576 {
577     int     base = 10;
578     long    l;
579     CHAR    *cp, *end_ptr;
580 
581     cp = sz + 1;
582 
583     if (*cp == 'H')
584     {
585         base = 16;
586         ++cp;
587     }
588 
589     errno = 0;
590     l = strtol(cp, &end_ptr, base);
591     if (end_ptr == cp || errno != 0 || l > INT_MAX || l < INT_MIN)
592     {
593         WARN("Error parsing character code '%s'\n", sz);
594         return TRUE;
595     }
596 
597     metrics->C = (INT)l;
598     return TRUE;
599 }
600 
601 /*******************************************************************************
602  *  ParseW
603  *
604  *  Fatal error:        return FALSE (none defined)
605  *
606  *  Non-fatal error:    leave metrics->WX set to FLT_MAX
607  *
608  */
609 static BOOL ParseW(LPSTR sz, OLD_AFMMETRICS *metrics)
610 {
611     CHAR    *cp, *end_ptr;
612     BOOL    vector = TRUE;
613     double  d;
614 
615     cp = sz + 1;
616 
617     if (*cp == '')
618         ++cp;
619 
620     if (*cp == 'X')
621     {
622         vector = FALSE;
623         ++cp;
624     }
625 
626     if (!isspace(*cp))
627         goto parse_error;
628 
629     errno = 0;
630     d = strtod(cp, &end_ptr);
631     if (end_ptr == cp || errno != 0 ||
632             DoubleToFloat(&(metrics->WX), d) == FALSE)
633         goto parse_error;
634 
635     if (vector == FALSE)
636         return TRUE;
637 
638     /*  Make sure that Y component of vector is zero */
639 
640     d = strtod(cp, &end_ptr);                               /* errno == 0 */
641     if (end_ptr == cp || errno != 0 || d != 0.0)
642     {
643         metrics->WX = FLT_MAX;
644         goto parse_error;
645     }
646 
647     return TRUE;
648 
649     parse_error:
650         WARN("Error parsing character width '%s'\n", sz);
651         return TRUE;
652 }
653 
654 /*******************************************************************************
655  *
656  *  ParseB
657  *
658  *  Fatal error:        return FALSE (none defined)
659  *
660  *  Non-fatal error:    leave metrics->B.ury set to FLT_MAX
661  *
662  */
663 static BOOL ParseB(LPSTR sz, OLD_AFMMETRICS *metrics)
664 {
665     CHAR    *cp, *end_ptr;
666     double  d;
667 
668     errno = 0;
669 
670     cp = sz + 1;
671     d = strtod(cp, &end_ptr);
672     if (end_ptr == cp || errno != 0 ||
673             DoubleToFloat(&(metrics->B.llx), d) == FALSE)
674         goto parse_error;
675 
676     cp = end_ptr;
677     d = strtod(cp, &end_ptr);
678     if (end_ptr == cp || errno != 0 ||
679             DoubleToFloat(&(metrics->B.lly), d) == FALSE)
680         goto parse_error;
681 
682     cp = end_ptr;
683     d = strtod(cp, &end_ptr);
684     if (end_ptr == cp || errno != 0 ||
685             DoubleToFloat(&(metrics->B.urx), d) == FALSE)
686         goto parse_error;
687 
688     cp = end_ptr;
689     d = strtod(cp, &end_ptr);
690     if (end_ptr == cp || errno != 0 ||
691             DoubleToFloat(&(metrics->B.ury), d) == FALSE)
692         goto parse_error;
693 
694     return TRUE;
695 
696     parse_error:
697         WARN("Error parsing glyph bounding box '%s'\n", sz);
698         return TRUE;
699 }
700 
701 /*******************************************************************************
702  *  ParseN
703  *
704  *  Fatal error:        return FALSE (PSDRV_GlyphName failure)
705  *
706  *  Non-fatal error:    leave metrics-> set to NULL
707  *
708  */
709 static BOOL ParseN(LPSTR sz, OLD_AFMMETRICS *metrics)
710 {
711     CHAR    save, *cp, *end_ptr;
712 
713     cp = sz + 1;
714 
715     while (isspace(*cp))
716         ++cp;
717 
718     end_ptr = cp;
719 
720     while (*end_ptr != '\0' && !isspace(*end_ptr))
721         ++end_ptr;
722 
723     if (end_ptr == cp)
724     {
725         WARN("Error parsing glyph name '%s'\n", sz);
726         return TRUE;
727     }
728 
729     save = *end_ptr;
730     *end_ptr = '\0';
731 
732     metrics->N = PSDRV_GlyphName(cp);
733     if (metrics->N == NULL)
734         return FALSE;
735 
736     *end_ptr = save;
737     return TRUE;
738 }
739 
740 /*******************************************************************************
741  *  ParseCharMetrics
742  *
743  *  Parses the metrics line for a single glyph in an AFM file.  Returns FALSE on
744  *  fatal error; sets *metrics to 'badmetrics' on non-fatal error.
745  *
746  */
747 static const OLD_AFMMETRICS badmetrics =
748 {
749     INT_MAX,                                        /* C */
750     INT_MAX,                                        /* UV */
751     FLT_MAX,                                        /* WX */
752     NULL,                                           /* N */
753     { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX },         /* B */
754     NULL                                            /* L */
755 };
756 
757 static BOOL ParseCharMetrics(LPSTR buffer, INT len, OLD_AFMMETRICS *metrics)
758 {
759     CHAR    *cp = buffer;
760 
761     *metrics = badmetrics;
762 
763     while (*cp != '\0')
764     {
765         while (isspace(*cp))
766             ++cp;
767 
768         switch(*cp)
769         {
770             case 'C':   if (ParseC(cp, metrics) == FALSE)
771                             return FALSE;
772                         break;
773 
774             case 'W':   if (ParseW(cp, metrics) == FALSE)
775                             return FALSE;
776                         break;
777 
778             case 'N':   if (ParseN(cp, metrics) == FALSE)
779                             return FALSE;
780                         break;
781 
782             case 'B':   if (ParseB(cp, metrics) == FALSE)
783                             return FALSE;
784                         break;
785         }
786 
787         cp = strchr(cp, ';');
788         if (cp == NULL)
789         {
790             WARN("No terminating semicolon\n");
791             break;
792         }
793 
794         ++cp;
795     }
796 
797     if (metrics->C == INT_MAX || metrics->WX == FLT_MAX || metrics->N == NULL ||
798             metrics->B.ury == FLT_MAX)
799     {
800         *metrics = badmetrics;
801         return TRUE;
802     }
803 
804     return TRUE;
805 }
806 
807 /*******************************************************************************
808  *  IsWinANSI
809  *
810  *  Checks whether Unicode value is part of Microsoft code page 1252
811  *
812  */
813 static const LONG ansiChars[21] =
814 {
815     0x0152, 0x0153, 0x0160, 0x0161, 0x0178, 0x017d, 0x017e, 0x0192, 0x02c6,
816     0x02c9, 0x02dc, 0x03bc, 0x2013, 0x2014, 0x2026, 0x2030, 0x2039, 0x203a,
817     0x20ac, 0x2122, 0x2219
818 };
819 
820 static int cmpUV(const void *a, const void *b)
821 {
822     return (int)(*((const LONG *)a) - *((const LONG *)b));
823 }
824 
825 static inline BOOL IsWinANSI(LONG uv)
826 {
827     if ((0x0020 <= uv && uv <= 0x007e) || (0x00a0 <= uv && uv <= 0x00ff) ||
828             (0x2018 <= uv && uv <= 0x201a) || (0x201c <= uv && uv <= 0x201e) ||
829             (0x2020 <= uv && uv <= 0x2022))
830         return TRUE;
831 
832     if (bsearch(&uv, ansiChars, 21, sizeof(INT), cmpUV) != NULL)
833         return TRUE;
834 
835     return FALSE;
836 }
837 
838 /*******************************************************************************
839  *  Unicodify
840  *
841  *  Determines Unicode value (UV) for each glyph, based on font encoding.
842  *
843  *      FontSpecific:   Usable encodings (0x20 - 0xff) are mapped into the
844  *                      Unicode private use range U+F020 - U+F0FF.
845  *
846  *      other:          UV determined by glyph name, based on Adobe Glyph List.
847  *
848  *  Also does some font metric calculations that require UVs to be known.
849  *
850  */
851 static int UnicodeGlyphByNameIndex(const void *a, const void *b)
852 {
853     return ((const UNICODEGLYPH *)a)->name->index -
854             ((const UNICODEGLYPH *)b)->name->index;
855 }
856 
857 static VOID Unicodify(AFM *afm, OLD_AFMMETRICS *metrics)
858 {
859     INT     i;
860 
861     if (strcmp(afm->EncodingScheme, "FontSpecific") == 0)
862     {
863         for (i = 0; i < afm->NumofMetrics; ++i)
864         {
865             if (metrics[i].C >= 0x20 && metrics[i].C <= 0xff)
866             {
867                 metrics[i].UV = metrics[i].C | 0xf000L;
868             }
869             else
870             {
871                 TRACE("Unencoded glyph '%s'\n", metrics[i].N->sz);
872                 metrics[i].UV = -1L;
873             }
874         }
875 
876         afm->WinMetrics.sAscender = (SHORT)Round(afm->FontBBox.ury);
877         afm->WinMetrics.sDescender = (SHORT)Round(afm->FontBBox.lly);
878     }
879     else                                        /* non-FontSpecific encoding */
880     {
881         UNICODEGLYPH    ug, *p_ug;
882 
883         PSDRV_IndexGlyphList();         /* for fast searching of glyph names */
884 
885         afm->WinMetrics.sAscender = afm->WinMetrics.sDescender = 0;
886 
887         for (i = 0; i < afm->NumofMetrics; ++i)
888         {
889             ug.name = metrics[i].N;
890             p_ug = bsearch(&ug, PSDRV_AGLbyName, PSDRV_AGLbyNameSize,
891                     sizeof(ug), UnicodeGlyphByNameIndex);
892             if (p_ug == NULL)
893             {
894                 TRACE("Glyph '%s' not in Adobe Glyph List\n", ug.name->sz);
895                 metrics[i].UV = -1L;
896             }
897             else
898             {
899                 metrics[i].UV = p_ug->UV;
900 
901                 if (IsWinANSI(p_ug->UV))
902                 {
903                     SHORT   ury = (SHORT)Round(metrics[i].B.ury);
904                     SHORT   lly = (SHORT)Round(metrics[i].B.lly);
905 
906                     if (ury > afm->WinMetrics.sAscender)
907                         afm->WinMetrics.sAscender = ury;
908                     if (lly < afm->WinMetrics.sDescender)
909                         afm->WinMetrics.sDescender = lly;
910                 }
911             }
912         }
913 
914         if (afm->WinMetrics.sAscender == 0)
915             afm->WinMetrics.sAscender = (SHORT)Round(afm->FontBBox.ury);
916         if (afm->WinMetrics.sDescender == 0)
917             afm->WinMetrics.sDescender = (SHORT)Round(afm->FontBBox.lly);
918     }
919 
920     afm->WinMetrics.sLineGap =
921             1150 - (afm->WinMetrics.sAscender - afm->WinMetrics.sDescender);
922     if (afm->WinMetrics.sLineGap < 0)
923         afm->WinMetrics.sLineGap = 0;
924 
925     afm->WinMetrics.usWinAscent = (afm->WinMetrics.sAscender > 0) ?
926             afm->WinMetrics.sAscender : 0;
927     afm->WinMetrics.usWinDescent = (afm->WinMetrics.sDescender < 0) ?
928             -(afm->WinMetrics.sDescender) : 0;
929 }
930 
931 /*******************************************************************************
932  *  ReadCharMetrics
933  *
934  *  Reads metrics for all glyphs.  *p_metrics will be NULL on non-fatal error.
935  *
936  */
937 static int OldAFMMetricsByUV(const void *a, const void *b)
938 {
939     return ((const OLD_AFMMETRICS *)a)->UV - ((const OLD_AFMMETRICS *)b)->UV;
940 }
941 
942 static BOOL ReadCharMetrics(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
943         AFMMETRICS **p_metrics)
944 {
945     BOOL            retval, found;
946     OLD_AFMMETRICS  *old_metrics, *encoded_metrics;
947     AFMMETRICS      *metrics;
948     INT             i, len;
949 
950     retval = ReadInt(file, buffer, bufsize, "StartCharMetrics",
951             &(afm->NumofMetrics), &found);
952     if (retval == FALSE || found == FALSE)
953     {
954         *p_metrics = NULL;
955         return retval;
956     }
957 
958     old_metrics = HeapAlloc(PSDRV_Heap, 0,
959             afm->NumofMetrics * sizeof(*old_metrics));
960     if (old_metrics == NULL)
961         return FALSE;
962 
963     for (i = 0; i < afm->NumofMetrics; ++i)
964     {
965         retval = ReadLine(file, buffer, bufsize, &len);
966         if (retval == FALSE)
967             goto cleanup_old_metrics;
968 
969         if(len > 0)
970         {
971             retval = ParseCharMetrics(buffer, len, old_metrics + i);
972             if (retval == FALSE || old_metrics[i].C == INT_MAX)
973                 goto cleanup_old_metrics;
974 
975             continue;
976         }
977 
978         switch (len)
979         {
980             case 0:         --i;
981                             continue;
982 
983             case INT_MIN:   WARN("Ignoring long line '%32s...'\n", buffer);
984                             goto cleanup_old_metrics;       /* retval == TRUE */
985 
986             case EOF:       WARN("Unexpected EOF\n");
987                             goto cleanup_old_metrics;       /* retval == TRUE */
988         }
989     }
990 
991     Unicodify(afm, old_metrics);    /* wait until glyph names have been read */
992 
993     qsort(old_metrics, afm->NumofMetrics, sizeof(*old_metrics),
994             OldAFMMetricsByUV);
995 
996     for (i = 0; old_metrics[i].UV == -1; ++i);      /* count unencoded glyphs */
997 
998     afm->NumofMetrics -= i;
999     encoded_metrics = old_metrics + i;
1000 
1001     afm->Metrics = *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0,
1002             afm->NumofMetrics * sizeof(*metrics));
1003     if (afm->Metrics == NULL)
1004         goto cleanup_old_metrics;                           /* retval == TRUE */
1005 
1006     for (i = 0; i < afm->NumofMetrics; ++i, ++metrics, ++encoded_metrics)
1007     {
1008         metrics->C = encoded_metrics->C;
1009         metrics->UV = encoded_metrics->UV;
1010         metrics->WX = encoded_metrics->WX;
1011         metrics->N = encoded_metrics->N;
1012     }
1013 
1014     HeapFree(PSDRV_Heap, 0, old_metrics);
1015 
1016     afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
1017 
1018     return TRUE;
1019 
1020     cleanup_old_metrics:                /* handle fatal or non-fatal errors */
1021         HeapFree(PSDRV_Heap, 0, old_metrics);
1022         *p_metrics = NULL;
1023         return retval;
1024 }
1025 
1026 /*******************************************************************************
1027  *  BuildAFM
1028  *
1029  *  Builds the AFM for a PostScript font and adds it to the driver font list.
1030  *  Returns FALSE only on an unexpected error (memory allocation or I/O error).
1031  *
1032  */
1033 static BOOL BuildAFM(FILE *file)
1034 {
1035     CHAR        buffer[258];            /* allow for <cr>, <lf>, and <nul> */
1036     AFM         *afm;
1037     AFMMETRICS  *metrics;
1038     LPSTR       font_name, full_name, family_name, encoding_scheme;
1039     BOOL        retval, added;
1040 
1041     retval = ReadFontMetrics(file, buffer, sizeof(buffer), &afm);
1042     if (retval == FALSE || afm == NULL)
1043         return retval;
1044 
1045     retval = ReadString(file, buffer, sizeof(buffer), "FontName", &font_name);
1046     if (retval == FALSE || font_name == NULL)
1047         goto cleanup_afm;
1048 
1049     retval = ReadString(file, buffer, sizeof(buffer), "FullName", &full_name);
1050     if (retval == FALSE || full_name == NULL)
1051         goto cleanup_font_name;
1052 
1053     retval = ReadString(file, buffer, sizeof(buffer), "FamilyName",
1054             &family_name);
1055     if (retval == FALSE || family_name == NULL)
1056         goto cleanup_full_name;
1057 
1058     retval = ReadString(file, buffer, sizeof(buffer), "EncodingScheme",
1059             &encoding_scheme);
1060     if (retval == FALSE || encoding_scheme == NULL)
1061         goto cleanup_family_name;
1062 
1063     afm->FontName = font_name;
1064     afm->FullName = full_name;
1065     afm->FamilyName = family_name;
1066     afm->EncodingScheme = encoding_scheme;
1067 
1068     retval = ReadCharMetrics(file, buffer, sizeof(buffer), afm, &metrics);
1069     if (retval == FALSE || metrics == FALSE)
1070         goto cleanup_encoding_scheme;
1071 
1072     retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
1073     if (retval == FALSE || added == FALSE)
1074         goto cleanup_encoding_scheme;
1075 
1076     return TRUE;
1077 
1078     /* clean up after fatal or non-fatal errors */
1079 
1080     cleanup_encoding_scheme:
1081         HeapFree(PSDRV_Heap, 0, encoding_scheme);
1082     cleanup_family_name:
1083         HeapFree(PSDRV_Heap, 0, family_name);
1084     cleanup_full_name:
1085         HeapFree(PSDRV_Heap, 0, full_name);
1086     cleanup_font_name:
1087         HeapFree(PSDRV_Heap, 0, font_name);
1088     cleanup_afm:
1089         HeapFree(PSDRV_Heap, 0, afm);
1090 
1091     return retval;
1092 }
1093 
1094 /*******************************************************************************
1095  *  ReadAFMFile
1096  *
1097  *  Reads font metrics from Type 1 AFM file.  Only returns FALSE for
1098  *  unexpected errors (memory allocation or I/O).
1099  *
1100  */
1101 static BOOL ReadAFMFile(LPCSTR filename)
1102 {
1103     FILE    *f;
1104     BOOL    retval;
1105 
1106     TRACE("%s\n", filename);
1107 
1108     f = fopen(filename, "r");
1109     if (f == NULL)
1110     {
1111         WARN("%s: %s\n", filename, strerror(errno));
1112         return TRUE;
1113     }
1114 
1115     retval = BuildAFM(f);
1116 
1117     fclose(f);
1118     return retval;
1119 }
1120 
1121 /*******************************************************************************
1122  *  ReadAFMDir
1123  *
1124  *  Reads all Type 1 AFM files in a directory.
1125  *
1126  */
1127 static BOOL ReadAFMDir(LPCSTR dirname)
1128 {
1129     struct dirent   *dent;
1130     DIR             *dir;
1131     CHAR            filename[256];
1132 
1133     dir = opendir(dirname);
1134     if (dir == NULL)
1135     {
1136         WARN("%s: %s\n", dirname, strerror(errno));
1137         return TRUE;
1138     }
1139 
1140     while ((dent = readdir(dir)) != NULL)
1141     {
1142         CHAR    *file_extension = strchr(dent->d_name, '.');
1143         int     fn_len;
1144 
1145         if (file_extension == NULL || strcasecmp(file_extension, ".afm") != 0)
1146             continue;
1147 
1148         fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
1149         if (fn_len < 0 || fn_len > sizeof(filename) - 1)
1150         {
1151             WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
1152             continue;
1153         }
1154 
1155         if (ReadAFMFile(filename) == FALSE)
1156         {
1157             closedir(dir);
1158             return FALSE;
1159         }
1160     }
1161 
1162     closedir(dir);
1163     return TRUE;
1164 }
1165 
1166 /*******************************************************************************
1167  *  PSDRV_GetType1Metrics
1168  *
1169  *  Reads font metrics from Type 1 AFM font files in directories listed in the
1170  *  HKEY_CURRENT_USER\\Software\\Wine\\Fonts\\AFMPath registry string.
1171  *
1172  *  If this function fails (returns FALSE), the driver will fail to initialize
1173  *  and the driver heap will be destroyed, so it's not necessary to HeapFree
1174  *  everything in that event.
1175  *
1176  */
1177 BOOL PSDRV_GetType1Metrics(void)
1178 {
1179     static const WCHAR pathW[] = {'A','F','M','P','a','t','h',0};
1180     HKEY hkey;
1181     DWORD len;
1182     LPWSTR valueW;
1183     LPSTR valueA, ptr;
1184 
1185     /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1186     if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts", &hkey) != ERROR_SUCCESS)
1187         return TRUE;
1188 
1189     if (RegQueryValueExW( hkey, pathW, NULL, NULL, NULL, &len ) == ERROR_SUCCESS)
1190     {
1191         len += sizeof(WCHAR);
1192         valueW = HeapAlloc( PSDRV_Heap, 0, len );
1193         if (RegQueryValueExW( hkey, pathW, NULL, NULL, (LPBYTE)valueW, &len ) == ERROR_SUCCESS)
1194         {
1195             len = WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, NULL, 0, NULL, NULL );
1196             valueA = HeapAlloc( PSDRV_Heap, 0, len );
1197             WideCharToMultiByte( CP_UNIXCP, 0, valueW, -1, valueA, len, NULL, NULL );
1198             TRACE( "got AFM font path %s\n", debugstr_a(valueA) );
1199             ptr = valueA;
1200             while (ptr)
1201             {
1202                 LPSTR next = strchr( ptr, ':' );
1203                 if (next) *next++ = 0;
1204                 if (!ReadAFMDir( ptr ))
1205                 {
1206                     RegCloseKey(hkey);
1207                     return FALSE;
1208                 }
1209                 ptr = next;
1210             }
1211             HeapFree( PSDRV_Heap, 0, valueA );
1212         }
1213         HeapFree( PSDRV_Heap, 0, valueW );
1214     }
1215 
1216     RegCloseKey(hkey);
1217     return TRUE;
1218 }
1219 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.