2 * AFM library public interface.
3 * Copyright (c) 1995-1999 Markku Rossi.
5 * Author: Markku Rossi <mtr@iki.fi>
9 * This program 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 2, or (at your option)
14 * This program 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 this program; see the file COPYING. If not, write to
21 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
32 static char *default_path = "/usr/local/lib/ps:/usr/lib/ps";
34 static char *error_names[] =
44 "file is not an AFM file",
48 * Prototypes for static functions.
51 static void read_font_map ___P ((AFMHandle handle, char *name));
52 static void apply_encoding ___P ((AFMFont font, AFMEncodingTable *enc,
61 afm_error_to_string (AFMError error, char *buf)
66 code = error & 0xffff;
67 syserrno = (error >> 16) & 0xffff;
70 syserr = strerror (syserrno);
74 if (code >= NUM_ERRORS)
76 sprintf (buf, "afm_error_to_string(): illegal error code: %d\n",
82 sprintf (buf, "AFM Success");
84 sprintf (buf, "%s%s%s", "AFM Error",
86 syserr ? syserr : "");
88 sprintf (buf, "AFM Error: %s%s%s", error_names[code],
90 syserr ? syserr : "");
95 afm_create (const char *path, unsigned int verbose_level,
96 AFMHandle *handle_return)
99 AFMError error = AFM_SUCCESS;
100 const char *cp, *cp2;
107 handle = (AFMHandle) calloc (1, sizeof (*handle));
110 error = AFM_ERROR_MEMORY;
114 handle->font_map = strhash_init ();
115 if (handle->font_map == NULL)
117 error = AFM_ERROR_MEMORY;
121 handle->verbose = verbose_level;
128 afm_message (handle, 1, "AFM: scanning path...\n");
129 for (cp = path; cp; cp = strchr (cp, PATH_SEPARATOR))
134 cp2 = strchr (cp, PATH_SEPARATOR);
140 memcpy (buf, cp, len);
142 if (len > 0 && buf[len - 1] == '/')
145 strcat (buf, "/font.map");
147 if (stat (buf, &stat_st) == 0)
148 read_font_map (handle, buf);
151 *handle_return = handle;
156 /* Error handling. */
160 (void) afm_destroy (handle);
167 afm_destroy (AFMHandle handle)
174 return AFM_ERROR_ARGUMENT;
176 /* Free filenames. */
177 while (strhash_get_first (handle->font_map, &key, &keylen, (void *) &cp))
180 strhash_free (handle->font_map);
188 afm_set_verbose (AFMHandle handle, unsigned int level)
191 return AFM_ERROR_ARGUMENT;
193 handle->verbose = level;
200 afm_font_prefix (AFMHandle handle, const char *fontname,
201 const char **prefix_return)
205 if (handle == NULL || fontname == NULL || prefix_return == NULL)
206 return AFM_ERROR_ARGUMENT;
209 if (!strhash_get (handle->font_map, fontname, strlen (fontname),
211 return AFM_ERROR_UNKNOWN_FONT;
213 *prefix_return = filename;
220 afm_open_font (AFMHandle handle, unsigned int info_level,
221 const char *fontname, AFMFont *font_return)
226 if (handle == NULL || fontname == NULL)
227 return AFM_ERROR_ARGUMENT;
230 if (!strhash_get (handle->font_map, fontname, strlen (fontname),
232 return AFM_ERROR_UNKNOWN_FONT;
234 /* Append suffix to the filename. */
235 sprintf (fname, "%s.afm", filename);
237 return afm_open_file (handle, info_level, fname, font_return);
242 afm_open_file (AFMHandle handle, unsigned int info_level,
243 const char *filename, AFMFont *font_return)
246 AFMError error = AFM_SUCCESS;
248 if (handle == NULL || filename == NULL)
249 return AFM_ERROR_ARGUMENT;
251 font = (AFMFont) calloc (1, sizeof (*font));
253 return AFM_ERROR_MEMORY;
256 = (struct afm_font_private_data_st *) calloc (1, sizeof (*font->private));
257 if (font->private == NULL)
259 error = AFM_ERROR_MEMORY;
262 font->private->fontnames = strhash_init ();
263 if (font->private->fontnames == NULL)
265 error = AFM_ERROR_MEMORY;
269 font->private->compositenames = strhash_init ();
270 if (font->private->compositenames == NULL)
272 error = AFM_ERROR_MEMORY;
276 font->info_level = info_level;
279 if (setjmp (handle->jmpbuf))
281 /* Error during parse. */
282 error = handle->parse_error;
287 afm_parse_file (handle, filename, font);
288 /* Parse successful. */
295 /* Error handling. */
299 (void) afm_close_font (font);
305 #define FREE(ptr) if (ptr) free (ptr)
307 afm_close_font (AFMFont font)
312 return AFM_ERROR_ARGUMENT;
315 FREE (font->global_info.FontName);
316 FREE (font->global_info.FullName);
317 FREE (font->global_info.FamilyName);
318 FREE (font->global_info.Weight);
319 FREE (font->global_info.Version);
320 FREE (font->global_info.Notice);
321 FREE (font->global_info.EncodingScheme);
322 FREE (font->global_info.CharacterSet);
324 /* Character metrics. */
325 for (i = 0; i < font->num_character_metrics; i++)
326 FREE (font->character_metrics[i].name);
327 FREE (font->character_metrics);
330 for (i = 0; i < font->num_composites; i++)
331 FREE (font->composites[i].name);
332 FREE (font->composites);
335 for (i = 0; i < font->num_kern_pairs; i++)
337 FREE (font->kern_pairs[i].name1);
338 FREE (font->kern_pairs[i].name2);
340 FREE (font->kern_pairs);
343 FREE (font->track_kerns);
346 strhash_free (font->private->fontnames);
347 strhash_free (font->private->compositenames);
355 #define STR(str) (str ? str : "")
356 #define BOOL(val) (val ? "true" : "false")
358 afm_font_dump (FILE *fp, AFMFont font)
362 fprintf (fp, "AFM Format Specification version: %g\n", font->version);
363 fprintf (fp, "Global Font Information\n");
364 fprintf (fp, " FontName:\t%s\n", STR (font->global_info.FontName));
365 fprintf (fp, " FullName:\t%s\n", STR (font->global_info.FullName));
366 fprintf (fp, " FamilyName:\t%s\n", STR (font->global_info.FamilyName));
367 fprintf (fp, " Weight:\t%s\n", STR (font->global_info.Weight));
368 fprintf (fp, " FontBBox:\t%g %g %g %g\n",
369 font->global_info.FontBBox_llx, font->global_info.FontBBox_lly,
370 font->global_info.FontBBox_urx, font->global_info.FontBBox_ury);
371 fprintf (fp, " Version:\t%s\n", STR (font->global_info.Version));
372 fprintf (fp, " Notice:\t%s\n", STR (font->global_info.Notice));
373 fprintf (fp, " EncodingScheme:\t%s\n",
374 STR (font->global_info.EncodingScheme));
375 fprintf (fp, " MappingScheme:\t%ld\n", font->global_info.MappingScheme);
376 fprintf (fp, " EscChar:\t%ld\n", font->global_info.EscChar);
377 fprintf (fp, " CharacterSet:\t%s\n", STR (font->global_info.CharacterSet));
378 fprintf (fp, " Characters:\t%ld\n", font->global_info.Characters);
379 fprintf (fp, " IsBaseFont:\t%s\n", BOOL(font->global_info.IsBaseFont));
380 fprintf (fp, " VVector:\t%g %g\n",
381 font->global_info.VVector_0, font->global_info.VVector_1);
382 fprintf (fp, " IsFixedV:\t%s\n", BOOL(font->global_info.IsFixedV));
383 fprintf (fp, " CapHeight:\t%g\n", font->global_info.CapHeight);
384 fprintf (fp, " XHeight:\t%g\n", font->global_info.XHeight);
385 fprintf (fp, " Ascender:\t%g\n", font->global_info.Ascender);
386 fprintf (fp, " Descender:\t%g\n", font->global_info.Descender);
388 for (i = 0; i < 2; i++)
389 if (font->writing_direction_metrics[i].is_valid)
391 fprintf (fp, "Writing Direction %d\n", i);
392 fprintf (fp, " UnderlinePosition: %g\n",
393 font->writing_direction_metrics[i].UnderlinePosition);
394 fprintf (fp, " UnderlineThickness: %g\n",
395 font->writing_direction_metrics[i].UnderlineThickness);
396 fprintf (fp, " ItalicAngle: %g\n",
397 font->writing_direction_metrics[i].ItalicAngle);
398 fprintf (fp, " CharWidth: %g %g\n",
399 font->writing_direction_metrics[i].CharWidth_x,
400 font->writing_direction_metrics[i].CharWidth_y);
401 fprintf (fp, " IsFixedPitch: %s\n",
402 BOOL (font->writing_direction_metrics[i].IsFixedPitch));
405 /* Individual Character Metrics. */
406 fprintf (fp, "Individual Character Metrics %ld\n",
407 font->num_character_metrics);
408 for (i = 0; i < font->num_character_metrics; i++)
410 AFMIndividualCharacterMetrics *cm;
411 cm = &font->character_metrics[i];
413 fprintf (fp, " C %ld ; N %s ; B %g %g %g %g\n",
414 cm->character_code, STR (cm->name),
415 cm->llx, cm->lly, cm->urx, cm->ury);
417 " W0X %g ; W0Y %g ; W1X %g ; W1Y %g ; VV %g %g\n",
418 cm->w0x, cm->w0y, cm->w1x, cm->w1y, cm->vv_x, cm->vv_y);
421 /* Composite Character Data. */
422 fprintf (fp, "Composite Character Data %ld\n", font->num_composites);
423 for (i = 0; i < font->num_composites; i++)
428 cm = &font->composites[i];
430 fprintf (fp, " CC %s %ld", cm->name, cm->num_components);
431 for (j = 0; j < cm->num_components; j++)
432 fprintf (fp, " ; PCC %s %g %g",
433 cm->components[j].name,
434 cm->components[j].deltax,
435 cm->components[j].deltay);
440 fprintf (fp, "Pair-Wise Kerning %ld\n", font->num_kern_pairs);
441 for (i = 0; i < font->num_kern_pairs; i++)
443 AFMPairWiseKerning *kp;
444 kp = &font->kern_pairs[i];
446 fprintf (fp, " KP %s %s %g %g\n", STR (kp->name1), STR (kp->name2),
450 fprintf (fp, "Track Kerning %ld\n", font->num_track_kerns);
451 for (i = 0; i < font->num_track_kerns; i++)
454 tk = &font->track_kerns[i];
456 fprintf (fp, " TrackKern %ld %g %g %g %g\n", tk->degree,
457 tk->min_ptsize, tk->min_kern,
458 tk->max_ptsize, tk->max_kern);
464 afm_font_stringwidth (AFMFont font, AFMNumber ptsize, char *string,
465 unsigned int stringlen, AFMNumber *w0x_return,
466 AFMNumber *w0y_return)
471 AFMIndividualCharacterMetrics *cm;
473 if (!font || !string || !font->writing_direction_metrics[0].is_valid)
474 return AFM_ERROR_ARGUMENT;
476 /* Check shortcut. */
477 if (font->writing_direction_metrics[0].IsFixedPitch)
479 /* This is the easy case. */
480 x = stringlen * font->writing_direction_metrics[0].CharWidth_x;
481 y = stringlen * font->writing_direction_metrics[0].CharWidth_y;
485 /* Count character by character. */
486 for (i = 0; i < stringlen; i++)
488 cm = font->encoding[(unsigned char) string[i]];
489 if (cm == AFM_ENC_NONE || cm == AFM_ENC_NON_EXISTENT)
491 /* Use the undef font. */
492 x += font->private->undef->w0x;
493 y += font->private->undef->w0y;
497 /* Font found and valid, take values. */
504 *w0x_return = x / UNITS_PER_POINT * ptsize;
505 *w0y_return = y / UNITS_PER_POINT * ptsize;
512 afm_font_charwidth (AFMFont font, AFMNumber ptsize, char ch,
513 AFMNumber *w0x_return, AFMNumber *w0y_return)
517 AFMIndividualCharacterMetrics *cm;
519 if (!font || !font->writing_direction_metrics[0].is_valid)
520 return AFM_ERROR_ARGUMENT;
522 /* Check shortcut. */
523 if (font->writing_direction_metrics[0].IsFixedPitch)
525 x = font->writing_direction_metrics[0].CharWidth_x;
526 y = font->writing_direction_metrics[0].CharWidth_y;
530 cm = font->encoding[(unsigned char) ch];
531 if (cm == AFM_ENC_NONE || cm == AFM_ENC_NON_EXISTENT)
533 /* Use the undef font. */
534 x = font->private->undef->w0x;
535 y = font->private->undef->w0y;
539 /* Font found and valid, take values. */
545 *w0x_return = x / UNITS_PER_POINT * ptsize;
546 *w0y_return = y / UNITS_PER_POINT * ptsize;
553 afm_font_encode (AFMFont font, unsigned char code, char *name,
556 AFMIndividualCharacterMetrics *cm;
560 return AFM_ERROR_ARGUMENT;
565 if (!strhash_get (font->private->fontnames, name, strlen (name),
568 /* Check composite characters. */
569 if ((flags & AFM_ENCODE_ACCEPT_COMPOSITES) == 0
570 || strhash_get (font->private->compositenames, name,
571 strlen (name), (void *) &comp) == 0)
572 cm = AFM_ENC_NON_EXISTENT;
576 * Ok, composite character found, now find the character
577 * specified by the first composite component.
579 if (!strhash_get (font->private->fontnames,
580 comp->components[0].name,
581 strlen (comp->components[0].name),
583 cm = AFM_ENC_NON_EXISTENT;
590 font->encoding[(unsigned int) code] = cm;
597 afm_font_encoding (AFMFont font, AFMEncoding enc, unsigned int flags)
600 AFMIndividualCharacterMetrics *cm;
603 return AFM_ERROR_ARGUMENT;
607 case AFM_ENCODING_DEFAULT:
608 /* Clear encoding. */
609 for (i = 0; i < 256; i++)
610 font->encoding[i] = AFM_ENC_NONE;
612 /* Apply font's default encoding. */
613 for (i = 0; i < font->num_character_metrics; i++)
615 cm = &font->character_metrics[i];
616 font->encoding[cm->character_code] = cm;
620 case AFM_ENCODING_ISO_8859_1:
621 apply_encoding (font, afm_88591_encoding, flags);
624 case AFM_ENCODING_ISO_8859_2:
625 apply_encoding (font, afm_88592_encoding, flags);
628 case AFM_ENCODING_ISO_8859_3:
629 apply_encoding (font, afm_88593_encoding, flags);
632 case AFM_ENCODING_ISO_8859_4:
633 apply_encoding (font, afm_88594_encoding, flags);
636 case AFM_ENCODING_ISO_8859_5:
637 apply_encoding (font, afm_88595_encoding, flags);
640 case AFM_ENCODING_ISO_8859_7:
641 apply_encoding (font, afm_88597_encoding, flags);
644 case AFM_ENCODING_ISO_8859_9:
645 apply_encoding (font, afm_88599_encoding, flags);
648 case AFM_ENCODING_ISO_8859_10:
649 apply_encoding (font, afm_885910_encoding, flags);
652 case AFM_ENCODING_IBMPC:
653 apply_encoding (font, afm_ibmpc_encoding, flags);
656 case AFM_ENCODING_ASCII:
658 * First apply one encoding (all have equal first 128 characters),
659 * then zap last 128 chars.
661 apply_encoding (font, afm_88591_encoding, flags);
662 for (i = 128; i < 256; i++)
663 font->encoding[i] = AFM_ENC_NONE;
666 case AFM_ENCODING_MAC:
667 apply_encoding (font, afm_mac_encoding, flags);
670 case AFM_ENCODING_VMS:
671 apply_encoding (font, afm_vms_encoding, flags);
674 case AFM_ENCODING_HP8:
675 apply_encoding (font, afm_hp8_encoding, flags);
678 case AFM_ENCODING_KOI8:
679 apply_encoding (font, afm_koi8_encoding, flags);
688 * Internal help functions.
693 afm_message (AFMHandle handle, unsigned int level, char *message)
695 if (handle->verbose < level)
698 fprintf (stderr, "%s", message);
703 afm_error (AFMHandle handle, char *message)
705 fprintf (stderr, "AFM Error: %s\n", message);
714 read_font_map (AFMHandle handle, char *name)
723 sprintf (msg, "AFM: reading font map \"%s\"\n", name);
724 afm_message (handle, 1, msg);
726 fp = fopen (name, "r");
729 sprintf (msg, "AFM: couldn't open font map \"%s\": %s\n", name,
731 afm_message (handle, 1, msg);
736 cp = strrchr (name, '/');
739 dirlen = cp - name + 1;
740 memcpy (fullname, name, dirlen);
745 memcpy (fullname, "./", dirlen);
748 while (fgets (buf, sizeof (buf), fp))
753 if (sscanf (buf, "%s %s", font, file) != 2)
755 sprintf (msg, "malformed line in font map \"%s\":\n%s",
757 afm_error (handle, msg);
761 /* Do we already have this font? */
762 if (strhash_get (handle->font_map, font, strlen (font), (void *) &cp))
765 /* Append file name. */
766 strcpy (fullname + dirlen, file);
767 cp = (char *) malloc (strlen (fullname) + 1);
770 afm_error (handle, "couldn't add font: out of memory");
773 strcpy (cp, fullname);
775 sprintf (msg, "AFM: font mapping: %s -> %s\n", font, cp);
776 afm_message (handle, 2, msg);
777 (void) strhash_put (handle->font_map, font, strlen (font), cp,
787 apply_encoding (AFMFont font, AFMEncodingTable *enc, unsigned int flags)
790 AFMIndividualCharacterMetrics *cm;
793 for (i = 0; enc[i].code >= 0; i++)
795 if (enc[i].character == AFM_ENC_NONE)
796 font->encoding[enc[i].code] = AFM_ENC_NONE;
797 else if (enc[i].character == AFM_ENC_NON_EXISTENT)
798 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
801 if (strhash_get (font->private->fontnames, enc[i].character,
802 strlen (enc[i].character), (void *) &cm))
803 font->encoding[enc[i].code] = cm;
806 /* Check composite characters. */
807 if ((flags & AFM_ENCODE_ACCEPT_COMPOSITES) == 0
808 || strhash_get (font->private->compositenames,
809 enc[i].character, strlen (enc[i].character),
810 (void *) &comp) == 0)
811 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;
814 /* Composite character found. */
815 if (strhash_get (font->private->fontnames,
816 comp->components[0].name,
817 strlen (comp->components[0].name),
819 font->encoding[enc[i].code] = cm;
821 font->encoding[enc[i].code] = AFM_ENC_NON_EXISTENT;