2 * AFM library public interface.
3 * Copyright (c) 1995-1999 Markku Rossi.
5 * Author: Markku Rossi <mtr@iki.fi>
9 * Enscript is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * Enscript is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Enscript. If not, see <http://www.gnu.org/licenses/>.
30 static char *default_path = "/usr/local/lib/ps:/usr/lib/ps";
32 static char *error_names[] =
42 "file is not an AFM file",
46 * Prototypes for static functions.
49 static void read_font_map ___P ((AFMHandle handle, char *name));
50 static void apply_encoding ___P ((AFMFont font, AFMEncodingTable *enc,
59 afm_error_to_string (AFMError error, char *buf)
64 code = error & 0xffff;
65 syserrno = (error >> 16) & 0xffff;
68 syserr = strerror (syserrno);
72 if (code >= NUM_ERRORS)
74 sprintf (buf, "afm_error_to_string(): illegal error code: %d\n",
80 sprintf (buf, "AFM Success");
82 sprintf (buf, "%s%s%s", "AFM Error",
84 syserr ? syserr : "");
86 sprintf (buf, "AFM Error: %s%s%s", error_names[code],
88 syserr ? syserr : "");
93 afm_create (const char *path, unsigned int verbose_level,
94 AFMHandle *handle_return)
97 AFMError error = AFM_SUCCESS;
105 handle = (AFMHandle) calloc (1, sizeof (*handle));
108 error = AFM_ERROR_MEMORY;
112 handle->font_map = strhash_init ();
113 if (handle->font_map == NULL)
115 error = AFM_ERROR_MEMORY;
119 handle->verbose = verbose_level;
126 afm_message (handle, 1, "AFM: scanning path...\n");
127 for (cp = path; cp; cp = strchr (cp, PATH_SEPARATOR))
132 cp2 = strchr (cp, PATH_SEPARATOR);
138 memcpy (buf, cp, len);
140 if (len > 0 && buf[len - 1] == '/')
143 strcat (buf, "/font.map");
145 if (stat (buf, &stat_st) == 0)
146 read_font_map (handle, buf);
149 *handle_return = handle;
154 /* Error handling. */
158 (void) afm_destroy (handle);
165 afm_destroy (AFMHandle handle)
172 return AFM_ERROR_ARGUMENT;
174 /* Free filenames. */
175 while (strhash_get_first (handle->font_map, &key, &keylen, (void *) &cp))
178 strhash_free (handle->font_map);
186 afm_set_verbose (AFMHandle handle, unsigned int level)
189 return AFM_ERROR_ARGUMENT;
191 handle->verbose = level;
198 afm_font_prefix (AFMHandle handle, const char *fontname,
199 const char **prefix_return)
203 if (handle == NULL || fontname == NULL || prefix_return == NULL)
204 return AFM_ERROR_ARGUMENT;
207 if (!strhash_get (handle->font_map, fontname, strlen (fontname),
209 return AFM_ERROR_UNKNOWN_FONT;
211 *prefix_return = filename;
218 afm_open_font (AFMHandle handle, unsigned int info_level,
219 const char *fontname, AFMFont *font_return)
224 if (handle == NULL || fontname == NULL)
225 return AFM_ERROR_ARGUMENT;
228 if (!strhash_get (handle->font_map, fontname, strlen (fontname),
230 return AFM_ERROR_UNKNOWN_FONT;
232 /* Append suffix to the filename. */
233 sprintf (fname, "%s.afm", filename);
235 return afm_open_file (handle, info_level, fname, font_return);
240 afm_open_file (AFMHandle handle, unsigned int info_level,
241 const char *filename, AFMFont *font_return)
244 AFMError error = AFM_SUCCESS;
246 if (handle == NULL || filename == NULL)
247 return AFM_ERROR_ARGUMENT;
249 font = (AFMFont) calloc (1, sizeof (*font));
251 return AFM_ERROR_MEMORY;
254 = (struct afm_font_private_data_st *) calloc (1, sizeof (*font->private));
255 if (font->private == NULL)
257 error = AFM_ERROR_MEMORY;
260 font->private->fontnames = strhash_init ();
261 if (font->private->fontnames == NULL)
263 error = AFM_ERROR_MEMORY;
267 font->private->compositenames = strhash_init ();
268 if (font->private->compositenames == NULL)
270 error = AFM_ERROR_MEMORY;
274 font->info_level = info_level;
277 if (setjmp (handle->jmpbuf))
279 /* Error during parse. */
280 error = handle->parse_error;
285 afm_parse_file (handle, filename, font);
286 /* Parse successful. */
293 /* Error handling. */
297 (void) afm_close_font (font);
303 #define FREE(ptr) if (ptr) free (ptr)
305 afm_close_font (AFMFont font)
310 return AFM_ERROR_ARGUMENT;
313 FREE (font->global_info.FontName);
314 FREE (font->global_info.FullName);
315 FREE (font->global_info.FamilyName);
316 FREE (font->global_info.Weight);
317 FREE (font->global_info.Version);
318 FREE (font->global_info.Notice);
319 FREE (font->global_info.EncodingScheme);
320 FREE (font->global_info.CharacterSet);
322 /* Character metrics. */
323 for (i = 0; i < font->num_character_metrics; i++)
324 FREE (font->character_metrics[i].name);
325 FREE (font->character_metrics);
328 for (i = 0; i < font->num_composites; i++)
329 FREE (font->composites[i].name);
330 FREE (font->composites);
333 for (i = 0; i < font->num_kern_pairs; i++)
335 FREE (font->kern_pairs[i].name1);
336 FREE (font->kern_pairs[i].name2);
338 FREE (font->kern_pairs);
341 FREE (font->track_kerns);
344 strhash_free (font->private->fontnames);
345 strhash_free (font->private->compositenames);
353 #define STR(str) (str ? str : "")
354 #define BOOL(val) (val ? "true" : "false")
356 afm_font_dump (FILE *fp, AFMFont font)
360 fprintf (fp, "AFM Format Specification version: %g\n", font->version);
361 fprintf (fp, "Global Font Information\n");
362 fprintf (fp, " FontName:\t%s\n", STR (font->global_info.FontName));
363 fprintf (fp, " FullName:\t%s\n", STR (font->global_info.FullName));
364 fprintf (fp, " FamilyName:\t%s\n", STR (font->global_info.FamilyName));
365 fprintf (fp, " Weight:\t%s\n", STR (font->global_info.Weight));
366 fprintf (fp, " FontBBox:\t%g %g %g %g\n",
367 font->global_info.FontBBox_llx, font->global_info.FontBBox_lly,
368 font->global_info.FontBBox_urx, font->global_info.FontBBox_ury);
369 fprintf (fp, " Version:\t%s\n", STR (font->global_info.Version));
370 fprintf (fp, " Notice:\t%s\n", STR (font->global_info.Notice));
371 fprintf (fp, " EncodingScheme:\t%s\n",
372 STR (font->global_info.EncodingScheme));
373 fprintf (fp, " MappingScheme:\t%ld\n", font->global_info.MappingScheme);
374 fprintf (fp, " EscChar:\t%ld\n", font->global_info.EscChar);
375 fprintf (fp, " CharacterSet:\t%s\n", STR (font->global_info.CharacterSet));
376 fprintf (fp, " Characters:\t%ld\n", font->global_info.Characters);
377 fprintf (fp, " IsBaseFont:\t%s\n", BOOL(font->global_info.IsBaseFont));
378 fprintf (fp, " VVector:\t%g %g\n",
379 font->global_info.VVector_0, font->global_info.VVector_1);
380 fprintf (fp, " IsFixedV:\t%s\n", BOOL(font->global_info.IsFixedV));
381 fprintf (fp, " CapHeight:\t%g\n", font->global_info.CapHeight);
382 fprintf (fp, " XHeight:\t%g\n", font->global_info.XHeight);
383 fprintf (fp, " Ascender:\t%g\n", font->global_info.Ascender);
384 fprintf (fp, " Descender:\t%g\n", font->global_info.Descender);
386 for (i = 0; i < 2; i++)
387 if (font->writing_direction_metrics[i].is_valid)
389 fprintf (fp, "Writing Direction %d\n", i);
390 fprintf (fp, " UnderlinePosition: %g\n",
391 font->writing_direction_metrics[i].UnderlinePosition);
392 fprintf (fp, " UnderlineThickness: %g\n",
393 font->writing_direction_metrics[i].UnderlineThickness);
394 fprintf (fp, " ItalicAngle: %g\n",
395 font->writing_direction_metrics[i].ItalicAngle);
396 fprintf (fp, " CharWidth: %g %g\n",
397 font->writing_direction_metrics[i].CharWidth_x,
398 font->writing_direction_metrics[i].CharWidth_y);
399 fprintf (fp, " IsFixedPitch: %s\n",
400 BOOL (font->writing_direction_metrics[i].IsFixedPitch));
403 /* Individual Character Metrics. */
404 fprintf (fp, "Individual Character Metrics %ld\n",
405 font->num_character_metrics);
406 for (i = 0; i < font->num_character_metrics; i++)
408 AFMIndividualCharacterMetrics *cm;
409 cm = &font->character_metrics[i];
411 fprintf (fp, " C %ld ; N %s ; B %g %g %g %g\n",
412 cm->character_code, STR (cm->name),
413 cm->llx, cm->lly, cm->urx, cm->ury);
415 " W0X %g ; W0Y %g ; W1X %g ; W1Y %g ; VV %g %g\n",
416 cm->w0x, cm->w0y, cm->w1x, cm->w1y, cm->vv_x, cm->vv_y);
419 /* Composite Character Data. */
420 fprintf (fp, "Composite Character Data %ld\n", font->num_composites);
421 for (i = 0; i < font->num_composites; i++)
426 cm = &font->composites[i];
428 fprintf (fp, " CC %s %ld", cm->name, cm->num_components);
429 for (j = 0; j < cm->num_components; j++)
430 fprintf (fp, " ; PCC %s %g %g",
431 cm->components[j].name,
432 cm->components[j].deltax,
433 cm->components[j].deltay);
438 fprintf (fp, "Pair-Wise Kerning %ld\n", font->num_kern_pairs);
439 for (i = 0; i < font->num_kern_pairs; i++)
441 AFMPairWiseKerning *kp;
442 kp = &font->kern_pairs[i];
444 fprintf (fp, " KP %s %s %g %g\n", STR (kp->name1), STR (kp->name2),
448 fprintf (fp, "Track Kerning %ld\n", font->num_track_kerns);
449 for (i = 0; i < font->num_track_kerns; i++)
452 tk = &font->track_kerns[i];
454 fprintf (fp, " TrackKern %ld %g %g %g %g\n", tk->degree,
455 tk->min_ptsize, tk->min_kern,
456 tk->max_ptsize, tk->max_kern);
462 afm_font_stringwidth (AFMFont font, AFMNumber ptsize, char *string,
463 unsigned int stringlen, AFMNumber *w0x_return,
464 AFMNumber *w0y_return)
469 AFMIndividualCharacterMetrics *cm;
471 if (!font || !string || !font->writing_direction_metrics[0].is_valid)
472 return AFM_ERROR_ARGUMENT;
474 /* Check shortcut. */
475 if (font->writing_direction_metrics[0].IsFixedPitch)
477 /* This is the easy case. */
478 x = stringlen * font->writing_direction_metrics[0].CharWidth_x;
479 y = stringlen * font->writing_direction_metrics[0].CharWidth_y;
483 /* Count character by character. */
484 for (i = 0; i < stringlen; i++)
486 cm = font->encoding[(unsigned char) string[i]];
487 if (cm == AFM_ENC_NONE || cm == AFM_ENC_NON_EXISTENT)
489 /* Use the undef font. */
490 x += font->private->undef->w0x;
491 y += font->private->undef->w0y;
495 /* Font found and valid, take values. */
502 *w0x_return = x / UNITS_PER_POINT * ptsize;
503 *w0y_return = y / UNITS_PER_POINT * ptsize;
510 afm_font_charwidth (AFMFont font, AFMNumber ptsize, char ch,
511 AFMNumber *w0x_return, AFMNumber *w0y_return)
515 AFMIndividualCharacterMetrics *cm;
517 if (!font || !font->writing_direction_metrics[0].is_valid)
518 return AFM_ERROR_ARGUMENT;
520 /* Check shortcut. */
521 if (font->writing_direction_metrics[0].IsFixedPitch)
523 x = font->writing_direction_metrics[0].CharWidth_x;
524 y = font->writing_direction_metrics[0].CharWidth_y;
528 cm = font->encoding[(unsigned char) ch];
529 if (cm == AFM_ENC_NONE || cm == AFM_ENC_NON_EXISTENT)
531 /* Use the undef font. */
532 x = font->private->undef->w0x;
533 y = font->private->undef->w0y;
537 /* Font found and valid, take values. */
543 *w0x_return = x / UNITS_PER_POINT * ptsize;
544 *w0y_return = y / UNITS_PER_POINT * ptsize;
551 afm_font_encode (AFMFont font, unsigned char code, char *name,
554 AFMIndividualCharacterMetrics *cm;
558 return AFM_ERROR_ARGUMENT;
563 if (!strhash_get (font->private->fontnames, name, strlen (name),
566 /* Check composite characters. */
567 if ((flags & AFM_ENCODE_ACCEPT_COMPOSITES) == 0
568 || strhash_get (font->private->compositenames, name,
569 strlen (name), (void *) &comp) == 0)
570 cm = AFM_ENC_NON_EXISTENT;
574 * Ok, composite character found, now find the character
575 * specified by the first composite component.
577 if (!strhash_get (font->private->fontnames,
578 comp->components[0].name,
579 strlen (comp->components[0].name),
581 cm = AFM_ENC_NON_EXISTENT;
588 font->encoding[(unsigned int) code] = cm;
595 afm_font_encoding (AFMFont font, AFMEncoding enc, unsigned int flags)
598 AFMIndividualCharacterMetrics *cm;
601 return AFM_ERROR_ARGUMENT;
605 case AFM_ENCODING_DEFAULT:
606 /* Clear encoding. */
607 for (i = 0; i < 256; i++)
608 font->encoding[i] = AFM_ENC_NONE;
610 /* Apply font's default encoding. */
611 for (i = 0; i < font->num_character_metrics; i++)
613 cm = &font->character_metrics[i];
614 font->encoding[cm->character_code] = cm;
618 case AFM_ENCODING_ISO_8859_1:
619 apply_encoding (font, afm_88591_encoding, flags);
622 case AFM_ENCODING_ISO_8859_2:
623 apply_encoding (font, afm_88592_encoding, flags);
626 case AFM_ENCODING_ISO_8859_3:
627 apply_encoding (font, afm_88593_encoding, flags);
630 case AFM_ENCODING_ISO_8859_4:
631 apply_encoding (font, afm_88594_encoding, flags);
634 case AFM_ENCODING_ISO_8859_5:
635 apply_encoding (font, afm_88595_encoding, flags);
638 case AFM_ENCODING_ISO_8859_7:
639 apply_encoding (font, afm_88597_encoding, flags);
642 case AFM_ENCODING_ISO_8859_9:
643 apply_encoding (font, afm_88599_encoding, flags);
646 case AFM_ENCODING_ISO_8859_10:
647 apply_encoding (font, afm_885910_encoding, flags);
650 case AFM_ENCODING_ISO_8859_15:
651 apply_encoding (font, afm_885915_encoding, flags);
654 case AFM_ENCODING_IBMPC:
655 apply_encoding (font, afm_ibmpc_encoding, flags);
658 case AFM_ENCODING_ASCII:
660 * First apply one encoding (all have equal first 128 characters),
661 * then zap last 128 chars.
663 apply_encoding (font, afm_88591_encoding, flags);
664 for (i = 128; i < 256; i++)
665 font->encoding[i] = AFM_ENC_NONE;
668 case AFM_ENCODING_MAC:
669 apply_encoding (font, afm_mac_encoding, flags);
672 case AFM_ENCODING_VMS:
673 apply_encoding (font, afm_vms_encoding, flags);
676 case AFM_ENCODING_HP8:
677 apply_encoding (font, afm_hp8_encoding, flags);
680 case AFM_ENCODING_KOI8:
681 apply_encoding (font, afm_koi8_encoding, flags);
690 * Internal help functions.
695 afm_message (AFMHandle handle, unsigned int level, char *message)
697 if (handle->verbose < level)
700 fprintf (stderr, "%s", message);
705 afm_error (AFMHandle handle, char *message)
707 fprintf (stderr, "AFM Error: %s\n", message);
716 read_font_map (AFMHandle handle, char *name)
725 sprintf (msg, "AFM: reading font map \"%s\"\n", name);
726 afm_message (handle, 1, msg);
728 fp = fopen (name, "r");
731 sprintf (msg, "AFM: couldn't open font map \"%s\": %s\n", name,
733 afm_message (handle, 1, msg);
738 cp = strrchr (name, '/');
741 dirlen = cp - name + 1;
742 memcpy (fullname, name, dirlen);
747 memcpy (fullname, "./", dirlen);
750 while (fgets (buf, sizeof (buf), fp))
755 if (sscanf (buf, "%s %s", font, file) != 2)
757 sprintf (msg, "malformed line in font map \"%s\":\n%s",
759 afm_error (handle, msg);
763 /* Do we already have this font? */
764 if (strhash_get (handle->font_map, font, strlen (font), (void *) &cp))
767 /* Append file name. */
768 strcpy (fullname + dirlen, file);
769 cp = (char *) malloc (strlen (fullname) + 1);
772 afm_error (handle, "couldn't add font: out of memory");
775 strcpy (cp, fullname);
777 sprintf (msg, "AFM: font mapping: %s -> %s\n", font, cp);
778 afm_message (handle, 2, msg);
779 (void) strhash_put (handle->font_map, font, strlen (font), cp,
789 apply_encoding (AFMFont font, AFMEncodingTable *enc, unsigned int flags)
792 AFMIndividualCharacterMetrics *cm;
795 for (i = 0; enc[i].code >= 0; i++)
797 if (enc[i].character == AFM_ENC_NONE)
798 font->encoding[enc[i].code] = AFM_ENC_NONE;
799 else if (enc[i].character == AFM_ENC_NON_EXISTENT)
800 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
803 if (strhash_get (font->private->fontnames, enc[i].character,
804 strlen (enc[i].character), (void *) &cm))
805 font->encoding[enc[i].code] = cm;
808 /* Check composite characters. */
809 if ((flags & AFM_ENCODE_ACCEPT_COMPOSITES) == 0
810 || strhash_get (font->private->compositenames,
811 enc[i].character, strlen (enc[i].character),
812 (void *) &comp) == 0)
813 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
816 /* Composite character found. */
817 if (strhash_get (font->private->fontnames,
818 comp->components[0].name,
819 strlen (comp->components[0].name),
821 font->encoding[enc[i].code] = cm;
823 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;