home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
fontutils-0.6-base.tgz
/
fontutils-0.6-base.tar
/
fsf
/
fontutils
/
lib
/
font.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-14
|
14KB
|
464 lines
/* font.c: define (more or less) format-independent font operations.
Copyright (C) 1992 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include <ctype.h>
#include "filename.h"
#include "font.h"
#include "gf.h"
#include "list.h"
#include "pk.h"
#include "tfm.h"
/* We want to allow reading of multiple fonts, so we keep some
information around for each font we read. */
typedef struct
{
bitmap_format_type bitmap_format;
boolean bitmap_only;
font_info_type info;
} internal_font_type;
/* The format of the bitmap file for this font. */
#define INTERNAL_BITMAP_FORMAT(i) ((i).bitmap_format)
/* If the font was opened with `get_bitmap_font', this field is true;
if with `get_font', false. */
#define INTERNAL_BITMAP_ONLY(i) ((i).bitmap_only)
/* The filename for the bitmap font. */
#define INTERNAL_BITMAP_NAME(i) ((i).bitmap_name)
/* The fontwide information. The parts of this that are found in the
TFM file are garbage if INTERNAL_BITMAP_ONLY (I) is true. */
#define INTERNAL_FONT_INFO(i) ((i).info)
static void delete_internal_font (string filename);
static internal_font_type *find_internal_font (string font_name);
static void save_internal_font (string font_name, internal_font_type);
/* Starting with FONT_NAME as the base filename, e.g., `cmr10', we try
various extensions to find a PK or GF file at resolution DPI. This
bitmap font defines the shapes of the characters. */
bitmap_font_type
get_bitmap_font (string font_name, unsigned dpi)
{
bitmap_font_type font;
internal_font_type internal_f;
internal_font_type *internal_font_ptr;
string pk_name, gf_name;
boolean found_pk = false, found_gf = false;
/* If we are passed a null pointer or the empty string, it's got to be
a mistake. */
assert (font_name && *font_name);
/* If we already have the font saved, we just return it, thus (1) saving
going out to the file system, and (2) causing multiple calls with
the same FONT_NAME not to open more and more bitmap files. */
internal_font_ptr = find_internal_font (font_name);
if (internal_font_ptr != NULL)
return FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*internal_font_ptr));
pk_name = find_pk_filename (font_name, dpi);
if (pk_name != NULL)
{ /* Found the PK file, so unless something strange is happening
(like the file being removed between the `find_path_filename'
call and the `pk_open_input_file' call), we will be able to
open it. */
found_pk = pk_open_input_file (pk_name);
if (!found_pk)
FATAL_PERROR (pk_name);
}
else if ((gf_name = find_gf_filename (font_name, dpi)) != NULL)
{
found_gf = gf_open_input_file (gf_name);
if (!found_gf)
{
perror (gf_name);
FATAL1 ("(I couldn't find the PK file `%s', either.)", pk_name);
}
}
else
FATAL2 ("%s.%d{gf,pk}: Nowhere in path", font_name, dpi);
/* We've opened the files; get the information we need to return. */
if (found_pk)
{
pk_preamble_type preamble = pk_get_preamble (pk_name);
BITMAP_FONT_DESIGN_SIZE (font)
= fix_to_real (PK_DESIGN_SIZE (preamble));
BITMAP_FONT_COMMENT (font) = PK_COMMENT (preamble);
BITMAP_FONT_CHECKSUM (font) = PK_CHECKSUM (preamble);
BITMAP_FONT_FILENAME (font) = pk_name;
INTERNAL_BITMAP_FORMAT (internal_f) = pk_format;
}
else if (found_gf)
{
gf_postamble_type postamble = gf_get_postamble ();
BITMAP_FONT_DESIGN_SIZE (font)
= fix_to_real (GF_DESIGN_SIZE (postamble));
BITMAP_FONT_COMMENT (font) = gf_get_preamble ();
BITMAP_FONT_CHECKSUM (font) = GF_CHECKSUM (postamble);
BITMAP_FONT_FILENAME (font) = gf_name;
INTERNAL_BITMAP_FORMAT (internal_f) = gf_format;
}
else
FATAL ("No bitmap file found, but I must have found one");
FONT_BITMAP_FONT (INTERNAL_FONT_INFO (internal_f)) = font;
INTERNAL_BITMAP_ONLY (internal_f) = true;
save_internal_font (font_name, internal_f);
return font;
}
/* Look for both a bitmap font named FONT_NAME, and for the TFM file
FONT_NAME.tfm. We call `get_bitmap_font' to find the bitmap font.
For the TFM file, we use the path in the environment variable
TEXFONTS; if TEXFONTS isn't set, we use the default defined above.
If FONT_NAME was previously opened with `get_bitmap_font', we give a
fatal error. */
font_info_type
get_font (string font_name, unsigned dpi)
{
unsigned bitmap_checksum;
font_info_type font;
internal_font_type internal_f;
internal_font_type *internal_font_ptr;
unsigned tfm_checksum;
string tfm_name;
/* If we are passed a null pointer or the empty string, it's got to be
a mistake. */
assert (font_name != NULL && *font_name);
/* If we already have the font saved, we just return it, thus (1) saving
going out to the file system, and (2) causing multiple calls with
the same FONT_NAME not to open more and more bitmap files. */
internal_font_ptr = find_internal_font (font_name);
if (internal_font_ptr != NULL)
if (INTERNAL_BITMAP_ONLY (*internal_font_ptr))
FATAL1 ("get_font: `%s' was opened with get_bitmap_font", font_name);
else
return INTERNAL_FONT_INFO (*internal_font_ptr);
/* If we don't have the font saved, we have to look for the TFM file. */
tfm_name = find_tfm_filename (font_name);
if (tfm_name == NULL)
FATAL1 ("%s.tfm: Nowhere in path", font_name);
if (!tfm_open_input_file (tfm_name))
FATAL_PERROR (tfm_name);
/* The TFM file is opened. Save some global information. */
FONT_TFM_FONT (font) = tfm_get_global_info ();
FONT_TFM_FILENAME (font) = tfm_name;
/* Read the (we hope) corresponding bitmap file. */
FONT_BITMAP_FONT (font) = get_bitmap_font (font_name, dpi);
/* We have found the bitmap font on the filesystem, so it should be in
our internal list now. We will overwrite it below. */
internal_font_ptr = find_internal_font (font_name);
assert (internal_font_ptr != NULL);
/* We've opened the files; now get the information we're supposed to
return. */
/* Let's check the checksums. */
tfm_checksum = tfm_get_checksum ();
bitmap_checksum = BITMAP_FONT_CHECKSUM (FONT_BITMAP_FONT (font));
if (tfm_checksum != 0 && bitmap_checksum != 0
&& tfm_checksum != bitmap_checksum)
WARNING1 ("%s: TFM and bitmap checksums don't match", font_name);
INTERNAL_FONT_INFO (internal_f) = font;
INTERNAL_BITMAP_ONLY (internal_f) = false;
INTERNAL_BITMAP_FORMAT (internal_f)
= INTERNAL_BITMAP_FORMAT (*internal_font_ptr);
save_internal_font (font_name, internal_f);
return font;
}
/* Close the files we have opened, for tidiness. */
void
close_font (string font_name)
{
internal_font_type *f = find_internal_font (font_name);
if (f == NULL)
FATAL1 ("close_font: Font `%s' not open", font_name);
switch (INTERNAL_BITMAP_FORMAT (*f))
{
case pk_format:
{
string pk_name
= BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
pk_close_input_file (pk_name);
}
break;
case gf_format:
gf_close_input_file ();
break;
default:
FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
}
if (!INTERNAL_BITMAP_ONLY (*f))
tfm_close_input_file ();
delete_internal_font (font_name);
}
/* Look for the character numbered CODE in the font FONT_NAME. If it
doesn't exist, return NULL. Otherwise, fill in a `char_info_type'
structure and return a pointer to it.
This merely calls the get-a-character routine in the appropriate
library. */
char_info_type *
get_char (string font_name, one_byte code)
{
char_info_type *c;
internal_font_type *f = find_internal_font (font_name);
if (f == NULL)
FATAL1 ("get_char: Font `%s' not open", font_name);
switch (INTERNAL_BITMAP_FORMAT (*f))
{
case pk_format:
{
string pk_name
= BITMAP_FONT_FILENAME (FONT_BITMAP_FONT (INTERNAL_FONT_INFO (*f)));
pk_char_type *pk_char = pk_get_char (code, pk_name);
if (pk_char == NULL) return NULL;
c = XTALLOC1 (char_info_type);
CHARCODE (*c) = PK_CHARCODE (*pk_char);
CHAR_SET_WIDTH (*c) = PK_H_ESCAPEMENT (*pk_char);
CHAR_TFM_WIDTH (*c) = PK_TFM_WIDTH (*pk_char);
CHAR_BB (*c) = PK_CHAR_BB (*pk_char);
CHAR_BITMAP (*c) = PK_BITMAP (*pk_char);
}
break;
case gf_format:
{
gf_char_type *gf_char = gf_get_char (code);
if (gf_char == NULL) return NULL;
c = XTALLOC1 (char_info_type);
CHARCODE (*c) = GF_CHARCODE (*gf_char);
CHAR_SET_WIDTH (*c) = GF_H_ESCAPEMENT (*gf_char);
CHAR_TFM_WIDTH (*c) = GF_TFM_WIDTH (*gf_char);
CHAR_BB (*c) = GF_CHAR_BB (*gf_char);
CHAR_BITMAP (*c) = GF_BITMAP (*gf_char);
}
break;
default:
FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
}
return c;
}
/* Look for the character numbered CODE in the font FONT_NAME. If it
doesn't exist, return NULL. Otherwise, fill in a `raw_char_type'
structure and return a pointer to it.
This merely calls the corresponding routine in the appropriate
library. */
raw_char_type *
get_raw_char (string font_name, one_byte code)
{
raw_char_type *c;
internal_font_type *f = find_internal_font (font_name);
if (f == NULL)
FATAL1 ("get_raw_char: Font `%s' not open", font_name);
switch (INTERNAL_BITMAP_FORMAT (*f))
{
case pk_format:
c = NULL;
break;
case gf_format:
c = gf_get_raw_char (code);
break;
default:
FATAL1 ("Impossible bitmap format (%d)", INTERNAL_BITMAP_FORMAT (*f));
}
if (c != NULL)
RAW_CHAR_BITMAP_FORMAT (*c) = INTERNAL_BITMAP_FORMAT (*f);
return c;
}
/* Free the information in the raw character RAW_CHAR, including the
character itself. */
void
free_raw_char (raw_char_type *raw_char)
{
free (RAW_CHAR_BYTES (*raw_char));
free (raw_char);
}
/* Print the character C to the file F, using ordinary characters. */
void
print_char (FILE *f, char_info_type c)
{
unsigned this_row, this_col;
bitmap_type b = CHAR_BITMAP (c);
fprintf (f, "Character 0x%x=%u", CHARCODE (c), CHARCODE (c));
if (isprint (CHARCODE (c)))
fprintf (f, " (%c)", CHARCODE (c));
fprintf (f, ":\n");
fprintf (f, " min/max col %d/%d, min/max row %d/%d, set width %d.\n",
CHAR_MIN_COL (c), CHAR_MAX_COL (c),
CHAR_MIN_ROW (c), CHAR_MAX_ROW (c), CHAR_SET_WIDTH (c));
/* We don't call `print_bitmap' because we want to print the Cartesian
row number, as well as the bitmap row number. */
for (this_row = 0; this_row < BITMAP_HEIGHT (b); this_row++)
{
for (this_col = 0; this_col < BITMAP_WIDTH (b); this_col++)
putc (BITMAP_PIXEL (b, this_row, this_col) ? '*' : ' ', f);
fprintf (f, "%3d\t%u\n", CHAR_MAX_ROW (c) - this_row, this_row);
}
}
/* We want to implement a typical key/value setup: here we are given the
key (FONT_NAME) and the value (F). We assign an index number to
FONT_NAME, and store it and F in parallel lists. If we are passed a
FONT_NAME that is already in the list, we overwrite the old value. */
static list_type font_name_list, internal_font_list;
static void
save_internal_font (string font_name, internal_font_type f)
{
string *new_name;
internal_font_type *new_font;
static boolean first_call = true;
if (first_call)
{ /* Have to construct our lists. */
font_name_list = list_init ();
internal_font_list = list_init ();
first_call = false;
}
new_font = find_internal_font (font_name);
if (new_font == NULL)
{
/* Add another pointer to the end of the lists. */
new_name = LIST_TAPPEND (&font_name_list, string);
new_font = LIST_TAPPEND (&internal_font_list, internal_font_type);
/* Save the information. */
*new_name = xstrdup (font_name);
}
/* Either update the existing font, or save the new one. */
*new_font = f;
}
/* This routine returns the font information previously stored with
FONT_NAME. If FONT_NAME hasn't been saved, we return NULL. */
static internal_font_type *
find_internal_font (string font_name)
{
unsigned e;
for (e = 0; e < LIST_SIZE (font_name_list); e++)
if (STREQ (*(string *) LIST_ELT (font_name_list, e), font_name))
return (internal_font_type *) LIST_ELT (internal_font_list, e);
return NULL;
}
/* Remove FILENAME from `font_name_list', by setting the name in
`font_name_list' to the empty string, so that the element is useless.
(We don't have any actual memory to free.) What a kludge. */
static void
delete_internal_font (string filename)
{
unsigned e;
/* We can't use `find_internal_font', since we need to know the list
element index, not just the internal font information. */
for (e = 0; e < LIST_SIZE (font_name_list); e++)
if (STREQ (*(string *) LIST_ELT (font_name_list, e), filename))
{
string *name = LIST_ELT (font_name_list, e);
internal_font_type *i
= (internal_font_type *) LIST_ELT (internal_font_list, e);
free (*name);
*name = "";
free (i);
return;
}
FATAL1 ("The font `%s' hasn't been saved", filename);
}