1 /*******************************************************************************
2 * Adobe Font Metric (AFM) file parsing finctions for Wine PostScript driver.
3 * See http://partners.adobe.com/asn/developer/pdfs/tn/5004.AFM_Spec.pdf.
5 * Copyright 2001 Ian Pilcher
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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.
36 #include <limits.h> /* INT_MIN */
39 #include <float.h> /* FLT_MAX */
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(psdrv
);
50 /*******************************************************************************
53 * Reads a line from a text file into the buffer and trims trailing whitespace.
54 * Can handle DOS and Unix text files, including weird DOS EOF. Returns FALSE
55 * for unexpected I/O errors; otherwise returns TRUE and sets *p_result to
56 * either the number of characters in the returned string or one of the
59 * 0: Blank (or all whitespace) line. This is just a special case
60 * of the normal behavior.
62 * EOF: End of file has been reached.
64 * INT_MIN: Buffer overflow. Returned string is truncated (duh!) and
65 * trailing whitespace is *not* trimmed. Remaining text in
66 * line is discarded. (I.e. the file pointer is positioned at
67 * the beginning of the next line.)
70 static BOOL
ReadLine(FILE *file
, CHAR buffer
[], INT bufsize
, INT
*p_result
)
75 if (fgets(buffer
, bufsize
, file
) == NULL
)
77 if (feof(file
) == 0) /* EOF or error? */
79 ERR("%s\n", strerror(errno
));
87 cp
= strchr(buffer
, '\n');
92 if (i
== bufsize
- 1) /* max possible; was line truncated? */
95 i
= fgetc(file
); /* find the newline or EOF */
96 while (i
!= '\n' && i
!= EOF
);
100 if (feof(file
) == 0) /* EOF or error? */
102 ERR("%s\n", strerror(errno
));
106 WARN("No newline at EOF\n");
112 else /* no newline and not truncated */
114 if (strcmp(buffer
, "\x1a") == 0) /* test for DOS EOF */
120 WARN("No newline at EOF\n");
121 cp
= buffer
+ i
; /* points to \0 where \n should have been */
127 *cp
= '\0'; /* trim trailing whitespace */
129 break; /* don't underflow buffer */
132 while (isspace(*cp
));
134 *p_result
= strlen(buffer
);
138 /*******************************************************************************
141 * Finds a line in the file that begins with the given string. Returns FALSE
142 * for unexpected I/O errors; returns an empty (zero character) string if the
143 * requested line is not found.
145 * NOTE: The file pointer *MUST* be positioned at the beginning of a line when
146 * this function is called. Otherwise, an infinite loop can result.
149 static BOOL
FindLine(FILE *file
, CHAR buffer
[], INT bufsize
, LPCSTR key
)
151 INT len
= strlen(key
);
152 LONG start
= ftell(file
);
159 ok
= ReadLine(file
, buffer
, bufsize
, &result
);
163 if (result
> 0 && strncmp(buffer
, key
, len
) == 0)
170 else if (result
== INT_MIN
)
172 WARN("Line beginning '%32s...' is too long; ignoring\n", buffer
);
175 while (ftell(file
) != start
);
177 WARN("Couldn't find line '%s...' in AFM file\n", key
);
182 /*******************************************************************************
185 * Utility function to convert double to float while checking for overflow.
186 * Will also catch strtod overflows, since HUGE_VAL > FLT_MAX (at least on
190 inline static BOOL
DoubleToFloat(float *p_f
, double d
)
192 if (d
> (double)FLT_MAX
|| d
< -(double)FLT_MAX
)
199 /*******************************************************************************
202 * Utility function to add or subtract 0.5 before converting to integer type.
205 inline static float Round(float f
)
207 return (f
>= 0.0) ? (f
+ 0.5) : (f
- 0.5);
210 /*******************************************************************************
213 * Finds and parses a line of the form '<key> <value>', where value is a
214 * number. Sets *p_found to FALSE if a corresponding line cannot be found, or
215 * it cannot be parsed; also sets *p_ret to 0.0, so calling functions can just
216 * skip the check of *p_found if the item is not required.
219 static BOOL
ReadFloat(FILE *file
, CHAR buffer
[], INT bufsize
, LPCSTR key
,
220 FLOAT
*p_ret
, BOOL
*p_found
)
225 if (FindLine(file
, buffer
, bufsize
, key
) == FALSE
)
228 if (buffer
[0] == '\0') /* line not found */
235 cp
= buffer
+ strlen(key
); /* first char after key */
237 d
= strtod(cp
, &end_ptr
);
239 if (end_ptr
== cp
|| errno
!= 0 || DoubleToFloat(p_ret
, d
) == FALSE
)
241 WARN("Error parsing line '%s'\n", buffer
);
251 /*******************************************************************************
254 * See description of ReadFloat.
257 static BOOL
ReadInt(FILE *file
, CHAR buffer
[], INT bufsize
, LPCSTR key
,
258 INT
*p_ret
, BOOL
*p_found
)
263 retval
= ReadFloat(file
, buffer
, bufsize
, key
, &f
, p_found
);
264 if (retval
== FALSE
|| *p_found
== FALSE
)
272 if (f
> (FLOAT
)INT_MAX
|| f
< (FLOAT
)INT_MIN
)
274 WARN("Error parsing line '%s'\n", buffer
);
284 /*******************************************************************************
287 * Returns FALSE on I/O error or memory allocation failure; sets *p_str to NULL
288 * if line cannot be found or can't be parsed.
291 static BOOL
ReadString(FILE *file
, CHAR buffer
[], INT bufsize
, LPCSTR key
,
296 if (FindLine(file
, buffer
, bufsize
, key
) == FALSE
)
299 if (buffer
[0] == '\0')
305 cp
= buffer
+ strlen(key
); /* first char after key */
312 while (isspace(*cp
)) /* find first non-whitespace char */
315 *p_str
= HeapAlloc(PSDRV_Heap
, 0, strlen(cp
) + 1);
323 /*******************************************************************************
326 * Similar to ReadFloat above.
329 static BOOL
ReadBBox(FILE *file
, CHAR buffer
[], INT bufsize
, AFM
*afm
,
335 if (FindLine(file
, buffer
, bufsize
, "FontBBox") == FALSE
)
338 if (buffer
[0] == '\0')
346 cp
= buffer
+ sizeof("FontBBox");
347 d
= strtod(cp
, &end_ptr
);
348 if (end_ptr
== cp
|| errno
!= 0 ||
349 DoubleToFloat(&(afm
->FontBBox
.llx
), d
) == FALSE
)
353 d
= strtod(cp
, &end_ptr
);
354 if (end_ptr
== cp
|| errno
!= 0 ||
355 DoubleToFloat(&(afm
->FontBBox
.lly
), d
) == FALSE
)
359 d
= strtod(cp
, &end_ptr
);
360 if (end_ptr
== cp
|| errno
!= 0
361 || DoubleToFloat(&(afm
->FontBBox
.urx
), d
) == FALSE
)
365 d
= strtod(cp
, &end_ptr
);
366 if (end_ptr
== cp
|| errno
!= 0
367 || DoubleToFloat(&(afm
->FontBBox
.ury
), d
) == FALSE
)
374 WARN("Error parsing line '%s'\n", buffer
);
379 /*******************************************************************************
382 * Finds and parses the 'Weight' line of an AFM file. Only tries to determine
383 * if a font is bold (FW_BOLD) or not (FW_NORMAL) -- ignoring all those cute
384 * little FW_* typedefs in the Win32 doc. AFAICT, this is what the Windows
385 * PostScript driver does.
388 static const struct { LPCSTR keyword
; INT weight
; } afm_weights
[] =
390 { "REGULAR", FW_NORMAL
},
391 { "NORMAL", FW_NORMAL
},
392 { "ROMAN", FW_NORMAL
},
394 { "BOOK", FW_NORMAL
},
395 { "MEDIUM", FW_NORMAL
},
396 { "LIGHT", FW_NORMAL
},
397 { "BLACK", FW_BOLD
},
398 { "HEAVY", FW_BOLD
},
400 { "ULTRA", FW_BOLD
},
401 { "SUPER" , FW_BOLD
},
405 static BOOL
ReadWeight(FILE *file
, CHAR buffer
[], INT bufsize
, AFM
*afm
,
412 if (ReadString(file
, buffer
, bufsize
, "Weight", &sz
) == FALSE
)
421 for (cp
= sz
; *cp
!= '\0'; ++cp
)
424 for (i
= 0; afm_weights
[i
].keyword
!= NULL
; ++i
)
426 if (strstr(sz
, afm_weights
[i
].keyword
) != NULL
)
428 afm
->Weight
= afm_weights
[i
].weight
;
430 HeapFree(PSDRV_Heap
, 0, sz
);
435 WARN("Unknown weight '%s'; treating as Roman\n", sz
);
437 afm
->Weight
= FW_NORMAL
;
439 HeapFree(PSDRV_Heap
, 0, sz
);
443 /*******************************************************************************
447 static BOOL
ReadFixedPitch(FILE *file
, CHAR buffer
[], INT bufsize
, AFM
*afm
,
452 if (ReadString(file
, buffer
, bufsize
, "IsFixedPitch", &sz
) == FALSE
)
461 if (strcasecmp(sz
, "false") == 0)
463 afm
->IsFixedPitch
= FALSE
;
465 HeapFree(PSDRV_Heap
, 0, sz
);
469 if (strcasecmp(sz
, "true") == 0)
471 afm
->IsFixedPitch
= TRUE
;
473 HeapFree(PSDRV_Heap
, 0, sz
);
477 WARN("Can't parse line '%s'\n", buffer
);
480 HeapFree(PSDRV_Heap
, 0, sz
);
484 /*******************************************************************************
487 * Allocates space for the AFM on the driver heap and reads basic font metrics.
488 * Returns FALSE for memory allocation failure; sets *p_afm to NULL if AFM file
492 static BOOL
ReadFontMetrics(FILE *file
, CHAR buffer
[], INT bufsize
, AFM
**p_afm
)
497 *p_afm
= afm
= HeapAlloc(PSDRV_Heap
, 0, sizeof(*afm
));
501 retval
= ReadWeight(file
, buffer
, bufsize
, afm
, &found
);
502 if (retval
== FALSE
|| found
== FALSE
)
505 retval
= ReadFloat(file
, buffer
, bufsize
, "ItalicAngle",
506 &(afm
->ItalicAngle
), &found
);
507 if (retval
== FALSE
|| found
== FALSE
)
510 retval
= ReadFixedPitch(file
, buffer
, bufsize
, afm
, &found
);
511 if (retval
== FALSE
|| found
== FALSE
)
514 retval
= ReadBBox(file
, buffer
, bufsize
, afm
, &found
);
515 if (retval
== FALSE
|| found
== FALSE
)
518 retval
= ReadFloat(file
, buffer
, bufsize
, "UnderlinePosition",
519 &(afm
->UnderlinePosition
), &found
);
520 if (retval
== FALSE
|| found
== FALSE
)
523 retval
= ReadFloat(file
, buffer
, bufsize
, "UnderlineThickness",
524 &(afm
->UnderlineThickness
), &found
);
525 if (retval
== FALSE
|| found
== FALSE
)
528 retval
= ReadFloat(file
, buffer
, bufsize
, "Ascender", /* optional */
529 &(afm
->Ascender
), &found
);
533 retval
= ReadFloat(file
, buffer
, bufsize
, "Descender", /* optional */
534 &(afm
->Descender
), &found
);
538 afm
->WinMetrics
.usUnitsPerEm
= 1000;
539 afm
->WinMetrics
.sTypoAscender
= (SHORT
)Round(afm
->Ascender
);
540 afm
->WinMetrics
.sTypoDescender
= (SHORT
)Round(afm
->Descender
);
542 if (afm
->WinMetrics
.sTypoAscender
== 0)
543 afm
->WinMetrics
.sTypoAscender
= (SHORT
)Round(afm
->FontBBox
.ury
);
545 if (afm
->WinMetrics
.sTypoDescender
== 0)
546 afm
->WinMetrics
.sTypoDescender
= (SHORT
)Round(afm
->FontBBox
.lly
);
548 afm
->WinMetrics
.sTypoLineGap
= 1200 -
549 (afm
->WinMetrics
.sTypoAscender
- afm
->WinMetrics
.sTypoDescender
);
550 if (afm
->WinMetrics
.sTypoLineGap
< 0)
551 afm
->WinMetrics
.sTypoLineGap
= 0;
555 cleanup_afm
: /* handle fatal or non-fatal errors */
556 HeapFree(PSDRV_Heap
, 0, afm
);
561 /*******************************************************************************
564 * Fatal error: return FALSE (none defined)
566 * Non-fatal error: leave metrics->C set to INT_MAX
569 static BOOL
ParseC(LPSTR sz
, OLD_AFMMETRICS
*metrics
)
584 l
= strtol(cp
, &end_ptr
, base
);
585 if (end_ptr
== cp
|| errno
!= 0 || l
> INT_MAX
|| l
< INT_MIN
)
587 WARN("Error parsing character code '%s'\n", sz
);
595 /*******************************************************************************
598 * Fatal error: return FALSE (none defined)
600 * Non-fatal error: leave metrics->WX set to FLT_MAX
603 static BOOL
ParseW(LPSTR sz
, OLD_AFMMETRICS
*metrics
)
624 d
= strtod(cp
, &end_ptr
);
625 if (end_ptr
== cp
|| errno
!= 0 ||
626 DoubleToFloat(&(metrics
->WX
), d
) == FALSE
)
632 /* Make sure that Y component of vector is zero */
634 d
= strtod(cp
, &end_ptr
); /* errno == 0 */
635 if (end_ptr
== cp
|| errno
!= 0 || d
!= 0.0)
637 metrics
->WX
= FLT_MAX
;
644 WARN("Error parsing character width '%s'\n", sz
);
648 /*******************************************************************************
652 * Fatal error: return FALSE (none defined)
654 * Non-fatal error: leave metrics->B.ury set to FLT_MAX
657 static BOOL
ParseB(LPSTR sz
, OLD_AFMMETRICS
*metrics
)
665 d
= strtod(cp
, &end_ptr
);
666 if (end_ptr
== cp
|| errno
!= 0 ||
667 DoubleToFloat(&(metrics
->B
.llx
), d
) == FALSE
)
671 d
= strtod(cp
, &end_ptr
);
672 if (end_ptr
== cp
|| errno
!= 0 ||
673 DoubleToFloat(&(metrics
->B
.lly
), d
) == FALSE
)
677 d
= strtod(cp
, &end_ptr
);
678 if (end_ptr
== cp
|| errno
!= 0 ||
679 DoubleToFloat(&(metrics
->B
.urx
), d
) == FALSE
)
683 d
= strtod(cp
, &end_ptr
);
684 if (end_ptr
== cp
|| errno
!= 0 ||
685 DoubleToFloat(&(metrics
->B
.ury
), d
) == FALSE
)
691 WARN("Error parsing glyph bounding box '%s'\n", sz
);
695 /*******************************************************************************
698 * Fatal error: return FALSE (PSDRV_GlyphName failure)
700 * Non-fatal error: leave metrics-> set to NULL
703 static BOOL
ParseN(LPSTR sz
, OLD_AFMMETRICS
*metrics
)
705 CHAR save
, *cp
, *end_ptr
;
714 while (*end_ptr
!= '\0' && !isspace(*end_ptr
))
719 WARN("Error parsing glyph name '%s'\n", sz
);
726 metrics
->N
= PSDRV_GlyphName(cp
);
727 if (metrics
->N
== NULL
)
734 /*******************************************************************************
737 * Parses the metrics line for a single glyph in an AFM file. Returns FALSE on
738 * fatal error; sets *metrics to 'badmetrics' on non-fatal error.
741 static const OLD_AFMMETRICS badmetrics
=
747 { FLT_MAX
, FLT_MAX
, FLT_MAX
, FLT_MAX
}, /* B */
751 static BOOL
ParseCharMetrics(LPSTR buffer
, INT len
, OLD_AFMMETRICS
*metrics
)
755 *metrics
= badmetrics
;
764 case 'C': if (ParseC(cp
, metrics
) == FALSE
)
768 case 'W': if (ParseW(cp
, metrics
) == FALSE
)
772 case 'N': if (ParseN(cp
, metrics
) == FALSE
)
776 case 'B': if (ParseB(cp
, metrics
) == FALSE
)
781 cp
= strchr(cp
, ';');
784 WARN("No terminating semicolon\n");
791 if (metrics
->C
== INT_MAX
|| metrics
->WX
== FLT_MAX
|| metrics
->N
== NULL
||
792 metrics
->B
.ury
== FLT_MAX
)
794 *metrics
= badmetrics
;
801 /*******************************************************************************
804 * Checks whether Unicode value is part of Microsoft code page 1252
807 static const LONG ansiChars
[21] =
809 0x0152, 0x0153, 0x0160, 0x0161, 0x0178, 0x017d, 0x017e, 0x0192, 0x02c6,
810 0x02c9, 0x02dc, 0x03bc, 0x2013, 0x2014, 0x2026, 0x2030, 0x2039, 0x203a,
811 0x20ac, 0x2122, 0x2219
814 static int cmpUV(const void *a
, const void *b
)
816 return (int)(*((const LONG
*)a
) - *((const LONG
*)b
));
819 inline static BOOL
IsWinANSI(LONG uv
)
821 if ((0x0020 <= uv
&& uv
<= 0x007e) || (0x00a0 <= uv
&& uv
<= 0x00ff) ||
822 (0x2018 <= uv
&& uv
<= 0x201a) || (0x201c <= uv
&& uv
<= 0x201e) ||
823 (0x2020 <= uv
&& uv
<= 0x2022))
826 if (bsearch(&uv
, ansiChars
, 21, sizeof(INT
), cmpUV
) != NULL
)
832 /*******************************************************************************
835 * Determines Unicode value (UV) for each glyph, based on font encoding.
837 * FontSpecific: Usable encodings (0x20 - 0xff) are mapped into the
838 * Unicode private use range U+F020 - U+F0FF.
840 * other: UV determined by glyph name, based on Adobe Glyph List.
842 * Also does some font metric calculations that require UVs to be known.
845 static int UnicodeGlyphByNameIndex(const void *a
, const void *b
)
847 return ((const UNICODEGLYPH
*)a
)->name
->index
-
848 ((const UNICODEGLYPH
*)b
)->name
->index
;
851 static VOID
Unicodify(AFM
*afm
, OLD_AFMMETRICS
*metrics
)
855 if (strcmp(afm
->EncodingScheme
, "FontSpecific") == 0)
857 for (i
= 0; i
< afm
->NumofMetrics
; ++i
)
859 if (metrics
[i
].C
>= 0x20 && metrics
[i
].C
<= 0xff)
861 metrics
[i
].UV
= ((LONG
)(metrics
[i
].C
)) | 0xf000L
;
865 TRACE("Unencoded glyph '%s'\n", metrics
[i
].N
->sz
);
870 afm
->WinMetrics
.sAscender
= (SHORT
)Round(afm
->FontBBox
.ury
);
871 afm
->WinMetrics
.sDescender
= (SHORT
)Round(afm
->FontBBox
.lly
);
873 else /* non-FontSpecific encoding */
875 UNICODEGLYPH ug
, *p_ug
;
877 PSDRV_IndexGlyphList(); /* for fast searching of glyph names */
879 afm
->WinMetrics
.sAscender
= afm
->WinMetrics
.sDescender
= 0;
881 for (i
= 0; i
< afm
->NumofMetrics
; ++i
)
883 ug
.name
= metrics
[i
].N
;
884 p_ug
= bsearch(&ug
, PSDRV_AGLbyName
, PSDRV_AGLbyNameSize
,
885 sizeof(ug
), UnicodeGlyphByNameIndex
);
888 TRACE("Glyph '%s' not in Adobe Glyph List\n", ug
.name
->sz
);
893 metrics
[i
].UV
= p_ug
->UV
;
895 if (IsWinANSI(p_ug
->UV
))
897 SHORT ury
= (SHORT
)Round(metrics
[i
].B
.ury
);
898 SHORT lly
= (SHORT
)Round(metrics
[i
].B
.lly
);
900 if (ury
> afm
->WinMetrics
.sAscender
)
901 afm
->WinMetrics
.sAscender
= ury
;
902 if (lly
< afm
->WinMetrics
.sDescender
)
903 afm
->WinMetrics
.sDescender
= lly
;
908 if (afm
->WinMetrics
.sAscender
== 0)
909 afm
->WinMetrics
.sAscender
= (SHORT
)Round(afm
->FontBBox
.ury
);
910 if (afm
->WinMetrics
.sDescender
== 0)
911 afm
->WinMetrics
.sDescender
= (SHORT
)Round(afm
->FontBBox
.lly
);
914 afm
->WinMetrics
.sLineGap
=
915 1150 - (afm
->WinMetrics
.sAscender
- afm
->WinMetrics
.sDescender
);
916 if (afm
->WinMetrics
.sLineGap
< 0)
917 afm
->WinMetrics
.sLineGap
= 0;
919 afm
->WinMetrics
.usWinAscent
= (afm
->WinMetrics
.sAscender
> 0) ?
920 afm
->WinMetrics
.sAscender
: 0;
921 afm
->WinMetrics
.usWinDescent
= (afm
->WinMetrics
.sDescender
< 0) ?
922 -(afm
->WinMetrics
.sDescender
) : 0;
925 /*******************************************************************************
928 * Reads metrics for all glyphs. *p_metrics will be NULL on non-fatal error.
931 static int OldAFMMetricsByUV(const void *a
, const void *b
)
933 return ((const OLD_AFMMETRICS
*)a
)->UV
- ((const OLD_AFMMETRICS
*)b
)->UV
;
936 static BOOL
ReadCharMetrics(FILE *file
, CHAR buffer
[], INT bufsize
, AFM
*afm
,
937 AFMMETRICS
**p_metrics
)
940 OLD_AFMMETRICS
*old_metrics
, *encoded_metrics
;
944 retval
= ReadInt(file
, buffer
, bufsize
, "StartCharMetrics",
945 &(afm
->NumofMetrics
), &found
);
946 if (retval
== FALSE
|| found
== FALSE
)
952 old_metrics
= HeapAlloc(PSDRV_Heap
, 0,
953 afm
->NumofMetrics
* sizeof(*old_metrics
));
954 if (old_metrics
== NULL
)
957 for (i
= 0; i
< afm
->NumofMetrics
; ++i
)
959 retval
= ReadLine(file
, buffer
, bufsize
, &len
);
961 goto cleanup_old_metrics
;
965 retval
= ParseCharMetrics(buffer
, len
, old_metrics
+ i
);
966 if (retval
== FALSE
|| old_metrics
[i
].C
== INT_MAX
)
967 goto cleanup_old_metrics
;
977 case INT_MIN
: WARN("Ignoring long line '%32s...'\n", buffer
);
978 goto cleanup_old_metrics
; /* retval == TRUE */
980 case EOF
: WARN("Unexpected EOF\n");
981 goto cleanup_old_metrics
; /* retval == TRUE */
985 Unicodify(afm
, old_metrics
); /* wait until glyph names have been read */
987 qsort(old_metrics
, afm
->NumofMetrics
, sizeof(*old_metrics
),
990 for (i
= 0; old_metrics
[i
].UV
== -1; ++i
); /* count unencoded glyphs */
992 afm
->NumofMetrics
-= i
;
993 encoded_metrics
= old_metrics
+ i
;
995 afm
->Metrics
= *p_metrics
= metrics
= HeapAlloc(PSDRV_Heap
, 0,
996 afm
->NumofMetrics
* sizeof(*metrics
));
997 if (afm
->Metrics
== NULL
)
998 goto cleanup_old_metrics
; /* retval == TRUE */
1000 for (i
= 0; i
< afm
->NumofMetrics
; ++i
, ++metrics
, ++encoded_metrics
)
1002 metrics
->C
= encoded_metrics
->C
;
1003 metrics
->UV
= encoded_metrics
->UV
;
1004 metrics
->WX
= encoded_metrics
->WX
;
1005 metrics
->N
= encoded_metrics
->N
;
1008 HeapFree(PSDRV_Heap
, 0, old_metrics
);
1010 afm
->WinMetrics
.sAvgCharWidth
= PSDRV_CalcAvgCharWidth(afm
);
1014 cleanup_old_metrics
: /* handle fatal or non-fatal errors */
1015 HeapFree(PSDRV_Heap
, 0, old_metrics
);
1020 /*******************************************************************************
1023 * Builds the AFM for a PostScript font and adds it to the driver font list.
1024 * Returns FALSE only on an unexpected error (memory allocation or I/O error).
1027 static BOOL
BuildAFM(FILE *file
)
1029 CHAR buffer
[258]; /* allow for <cr>, <lf>, and <nul> */
1031 AFMMETRICS
*metrics
;
1032 LPSTR font_name
, full_name
, family_name
, encoding_scheme
;
1035 retval
= ReadFontMetrics(file
, buffer
, sizeof(buffer
), &afm
);
1036 if (retval
== FALSE
|| afm
== NULL
)
1039 retval
= ReadString(file
, buffer
, sizeof(buffer
), "FontName", &font_name
);
1040 if (retval
== FALSE
|| font_name
== NULL
)
1043 retval
= ReadString(file
, buffer
, sizeof(buffer
), "FullName", &full_name
);
1044 if (retval
== FALSE
|| full_name
== NULL
)
1045 goto cleanup_font_name
;
1047 retval
= ReadString(file
, buffer
, sizeof(buffer
), "FamilyName",
1049 if (retval
== FALSE
|| family_name
== NULL
)
1050 goto cleanup_full_name
;
1052 retval
= ReadString(file
, buffer
, sizeof(buffer
), "EncodingScheme",
1054 if (retval
== FALSE
|| encoding_scheme
== NULL
)
1055 goto cleanup_family_name
;
1057 afm
->FontName
= font_name
;
1058 afm
->FullName
= full_name
;
1059 afm
->FamilyName
= family_name
;
1060 afm
->EncodingScheme
= encoding_scheme
;
1062 retval
= ReadCharMetrics(file
, buffer
, sizeof(buffer
), afm
, &metrics
);
1063 if (retval
== FALSE
|| metrics
== FALSE
)
1064 goto cleanup_encoding_scheme
;
1066 retval
= PSDRV_AddAFMtoList(&PSDRV_AFMFontList
, afm
, &added
);
1067 if (retval
== FALSE
|| added
== FALSE
)
1068 goto cleanup_encoding_scheme
;
1072 /* clean up after fatal or non-fatal errors */
1074 cleanup_encoding_scheme
:
1075 HeapFree(PSDRV_Heap
, 0, encoding_scheme
);
1076 cleanup_family_name
:
1077 HeapFree(PSDRV_Heap
, 0, family_name
);
1079 HeapFree(PSDRV_Heap
, 0, full_name
);
1081 HeapFree(PSDRV_Heap
, 0, font_name
);
1083 HeapFree(PSDRV_Heap
, 0, afm
);
1088 /*******************************************************************************
1091 * Reads font metrics from Type 1 AFM file. Only returns FALSE for
1092 * unexpected errors (memory allocation or I/O).
1095 static BOOL
ReadAFMFile(LPCSTR filename
)
1100 TRACE("%s\n", filename
);
1102 f
= fopen(filename
, "r");
1105 WARN("%s: %s\n", filename
, strerror(errno
));
1109 retval
= BuildAFM(f
);
1115 /*******************************************************************************
1118 * Reads all Type 1 AFM files in a directory.
1121 static BOOL
ReadAFMDir(LPCSTR dirname
)
1123 struct dirent
*dent
;
1127 dir
= opendir(dirname
);
1130 WARN("%s: %s\n", dirname
, strerror(errno
));
1134 while ((dent
= readdir(dir
)) != NULL
)
1136 CHAR
*file_extension
= strchr(dent
->d_name
, '.');
1139 if (file_extension
== NULL
|| strcasecmp(file_extension
, ".afm") != 0)
1142 fn_len
= snprintf(filename
, 256, "%s/%s", dirname
, dent
->d_name
);
1143 if (fn_len
< 0 || fn_len
> sizeof(filename
) - 1)
1145 WARN("Path '%s/%s' is too long\n", dirname
, dent
->d_name
);
1149 if (ReadAFMFile(filename
) == FALSE
)
1160 /*******************************************************************************
1161 * PSDRV_GetType1Metrics
1163 * Reads font metrics from Type 1 AFM font files in directories listed in the
1164 * [afmdirs] section of the Wine configuration file.
1166 * If this function fails (returns FALSE), the dirver will fail to initialize
1167 * and the driver heap will be destroyed, so it's not necessary to HeapFree
1168 * everything in that event.
1171 BOOL
PSDRV_GetType1Metrics(void)
1173 CHAR name_buf
[256], value_buf
[256];
1176 DWORD type
, name_len
, value_len
;
1178 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE
,
1179 "Software\\Wine\\Wine\\Config\\afmdirs",
1180 0, KEY_READ
, &hkey
) != ERROR_SUCCESS
)
1183 name_len
= sizeof(name_buf
);
1184 value_len
= sizeof(value_buf
);
1186 while (RegEnumValueA(hkey
, i
++, name_buf
, &name_len
, NULL
, &type
, value_buf
,
1187 &value_len
) == ERROR_SUCCESS
)
1189 value_buf
[sizeof(value_buf
) - 1] = '\0';
1191 if (ReadAFMDir(value_buf
) == FALSE
)
1197 /* initialize lengths for new iteration */
1199 name_len
= sizeof(name_buf
);
1200 value_len
= sizeof(value_buf
);