Back to index

tetex-bin  3.0
ttf.c
Go to the documentation of this file.
00001 /*  $Header$
00002 
00003     This is dvipdfm, a DVI to PDF translator.
00004     Copyright (C) 1998, 1999 by Mark A. Wicks
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019     
00020     The author may be contacted via the e-mail address
00021 
00022        mwicks@kettering.edu
00023 */
00024 
00025 /* This is tailored for PDF */
00026 
00027 #include "config.h"
00028 
00029 #ifdef HAVE_TTF_FORMATS
00030 #include "ttf.h"
00031 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <time.h>
00035 #include "system.h"
00036 #include "mem.h"
00037 #include "error.h"
00038 #include "mfileio.h"
00039 #include "pdfobj.h"
00040 #include "numbers.h"
00041 #include "tfm.h"
00042 #include "pdflimits.h"
00043 #include "twiddle.h"
00044 #include "encodings.h"
00045 
00046 static unsigned char verbose = 0;
00047 
00048 void ttf_set_verbose(void)
00049 {
00050   if (verbose < 255) {
00051     verbose += 1;
00052   }
00053 }
00054 
00055 static char partial_enabled = 0;
00056 
00057 void ttf_disable_partial (void)
00058 {
00059   partial_enabled = 0;
00060 }
00061 
00062 
00063 /* Convert ttf "fixed" type to double */
00064 
00065 #define fixed(a) ((double)((a)%0x10000L)/(double)(0x10000L)+ \
00066  (((a)/0x10000L) > 0x8000L? 0x10000L - ((a)/0x10000L): ((a)/0x10000L)))
00067 
00068 /* Convert four-byte number to big endianess in a machine independent
00069    way */
00070 static void convert_tag (char *tag, unsigned long u_tag)
00071 {
00072   int i;
00073   for (i=3; i>= 0; i--) {
00074     tag[i] = u_tag % 256;
00075     u_tag /= 256;
00076   }
00077   tag[4] = 0;
00078 }
00079 
00080 struct table_header
00081 { 
00082   char tag[5];
00083   UNSIGNED_QUAD check_sum, offset, length;
00084   int omit;   /* If an application call sets omit=1, this table will
00085                  not be written to the output by ttf_build_font() */
00086   void *table_data;
00087 };
00088 
00089 struct table_directory
00090 {
00091   SIGNED_QUAD version;
00092   UNSIGNED_PAIR num_tables, search_range,
00093     entry_selector, range_shift;
00094   struct table_header *tables;
00095 };
00096 
00097 static void release_directory (struct table_directory *r) 
00098 {
00099   if (r && r->tables) {
00100     RELEASE (r->tables);
00101   }
00102   if (r)
00103     RELEASE (r);
00104 }
00105 
00106 static int put_big_endian (char *s, UNSIGNED_QUAD q, int n)
00107 {
00108   int i;
00109   for (i=n-1; i>=0; i--) {
00110     s[i] = (char) q%256;
00111     q/=256L;
00112   }
00113   return n;
00114 }
00115 
00116 static unsigned max2floor(unsigned n)
00117 /* Computes the max power of 2 <= n */
00118 {
00119   int i = 1;
00120   while (n > 1) {
00121     n /= 2;
00122     i *= 2;
00123   }
00124   return i;
00125 }
00126 
00127 static unsigned log2floor(unsigned  n)
00128 /* Computes the log2 of the max power of 2 <= n */
00129 {
00130   unsigned i = 0;
00131   while (n > 1) {
00132     n /= 2;
00133     i += 1;
00134   }
00135   return i;
00136 }
00137 
00138 
00139 static char *ttf_build_font (FILE *ttf_file, struct table_directory
00140                           *td, long *size) 
00141 {
00142   char *result, *p;
00143   long font_size = 0, offset = 0;
00144   int i, num_kept_tables = 0, new_search_range;
00145   for (i=0; i<(td->num_tables); i++) {
00146     if (!(td->tables)[i].omit) {
00147       font_size += (td->tables[i].length);
00148       num_kept_tables += 1;
00149     }
00150   }
00151   font_size += (td->num_tables)*16; /* 16 bytes per table entry */
00152   font_size += 12; /* 12 bytes for the directory */
00153   *size = font_size;
00154   result = NEW (font_size, char);
00155   p = result;
00156   { /* Header */
00157     p += put_big_endian (p, td->version, 4);
00158     p += put_big_endian (p, num_kept_tables, 2);
00159     new_search_range = max2floor(num_kept_tables) * 16;
00160     p += put_big_endian (p, new_search_range, 2);
00161     p += put_big_endian (p, log2floor(num_kept_tables), 2);
00162     p += put_big_endian (p, num_kept_tables*16-new_search_range, 2);
00163   }
00164   /* Computer start of actual tables (after headers) */
00165   offset = 12 + 16 * num_kept_tables;
00166   for (i=0; i<(td->num_tables); i++) {
00167     if (!(td->tables)[i].omit) {
00168       sprintf (p, "%4s", (td->tables)[i].tag);
00169       p += strlen (p);
00170       p += put_big_endian (p, (td->tables)[i].check_sum, 4);
00171       p += put_big_endian (p, offset, 4);
00172       p += put_big_endian (p, (td->tables)[i].length, 4);
00173       /* Be careful here.  Offset to the right place in the file
00174         using the old offset and read the data into the right
00175         place in the buffer using the new offset */
00176       seek_absolute (ttf_file, (td->tables)[i].offset);
00177       fread (result+offset, (td->tables)[i].length, sizeof(char), ttf_file);
00178       /* Set offset for next table */
00179       offset += (td->tables)[i].length;
00180       if (offset > font_size )
00181        ERROR ("Uh oh");
00182     }
00183   }
00184   return result;
00185 }
00186 
00187 
00188 static struct table_directory *read_directory(FILE *ttf_file)
00189 {
00190   unsigned long i;
00191   struct table_directory *td = NEW (1, struct table_directory);
00192   rewind (ttf_file);
00193   td -> version = get_unsigned_quad(ttf_file);
00194   td -> num_tables = get_unsigned_pair (ttf_file);
00195   td -> search_range = get_unsigned_pair (ttf_file);
00196   td -> entry_selector = get_unsigned_pair (ttf_file);
00197   td -> range_shift = get_unsigned_pair (ttf_file);
00198   if (verbose > 3) {
00199     fprintf (stdout, "File Header\n");
00200     fprintf (stdout, "\tVersion: %.5f\n", fixed(td -> version));
00201     fprintf (stdout, "\tNumber of tables: %d\n",
00202             td -> num_tables);
00203     fprintf (stdout, "\tSearch Range: %d\n", td -> search_range);
00204     fprintf (stdout, "\tEntry Selector: %d\n",
00205             td -> entry_selector);
00206     fprintf (stdout, "\tRange Shift: %d\n",
00207             td -> range_shift);
00208   }
00209   td->tables = NEW (td -> num_tables, struct table_header);
00210   for (i=0; i < td->num_tables; i++) {
00211     unsigned long u_tag;
00212     if (verbose > 3) {
00213       fprintf (stdout, "New Table\n");
00214     }
00215     u_tag = get_unsigned_quad (ttf_file);
00216     convert_tag ((td->tables)[i].tag, u_tag);
00217     (td->tables)[i].check_sum = get_unsigned_quad (ttf_file);
00218     (td->tables)[i].offset = get_unsigned_quad (ttf_file);
00219     (td->tables)[i].length = get_unsigned_quad (ttf_file);
00220     if (verbose) {
00221       fprintf (stdout, "\tTag: %4s\n", (td->tables)[i].tag);
00222       fprintf (stdout, "\tChecksum: %lx\n", (td->tables)[i].check_sum);
00223       fprintf (stdout, "\tOffset: %lx\n", (td->tables)[i].offset);
00224       fprintf (stdout, "\tLength: %lx\n", (td->tables)[i].length);
00225     }
00226     (td->tables)[i].omit = 0;
00227     (td->tables)[i].table_data = NULL;
00228   }
00229   return td;
00230 }
00231 
00232 static int find_table_index (struct table_directory *td, char *tag)
00233 {
00234   int result, i;
00235   for (i=0; i < td->num_tables; i++) {
00236     if (!strncmp ((td->tables)[i].tag, tag, 4)) {
00237       break;
00238     }
00239   }
00240   if (i < td-> num_tables)
00241     result = i;
00242   else 
00243     result = -1;
00244   return result;
00245 }
00246 
00247 
00248 static long find_table_pos (FILE *ttf_file, struct table_directory *td, char *tag) 
00249 {
00250   int i;
00251   long result = -1;
00252   if ((i=find_table_index (td, tag)) >= 0) {
00253     result = (td->tables)[i].offset;
00254   }
00255   return result;
00256 }
00257 
00258 static struct post_header
00259 {
00260   UNSIGNED_QUAD format;
00261   UNSIGNED_QUAD italicAngle;
00262   SIGNED_PAIR underlinePosition;
00263   SIGNED_PAIR underlineThickness;
00264   UNSIGNED_QUAD isFixedPitch;
00265 } post_header;
00266 
00267 void read_post_table(FILE *ttf_file, struct table_directory *td)
00268 {
00269   long post_offset = find_table_pos (ttf_file, td, "post");
00270   seek_absolute (ttf_file, post_offset);
00271   if (verbose > 3) {
00272     fprintf (stdout, "Table type: post\n");
00273     fprintf (stderr, "post table @ %ld\n", post_offset);
00274   }
00275   post_header.format = get_unsigned_quad(ttf_file);
00276   post_header.italicAngle = get_unsigned_quad (ttf_file);
00277   post_header.underlinePosition = get_signed_pair (ttf_file);
00278   post_header.underlineThickness = get_signed_pair (ttf_file);
00279   post_header.isFixedPitch = get_unsigned_quad (ttf_file);
00280   if (verbose > 3) {
00281     fprintf (stdout, "\tVersion: %f(%lx)\n",
00282             fixed(post_header.format),
00283             post_header.format);
00284     fprintf (stdout, "\tItalic Angle: %f\n",
00285             fixed(post_header.italicAngle));
00286     fprintf (stdout, "\tUnderline Position: %d\n",
00287             post_header.underlinePosition);
00288     fprintf (stdout, "\tUnderline Thickness: %d\n",
00289             post_header.underlineThickness);
00290     fprintf (stdout, "\tIs Fixed Pitch?: %ld\n",
00291             post_header.isFixedPitch);
00292   }
00293   return;
00294 }
00295 
00296 struct horz_header
00297 {
00298   UNSIGNED_QUAD version;
00299   SIGNED_PAIR ascender, descender, line_gap;
00300   UNSIGNED_PAIR advanceWidthMax;
00301   SIGNED_PAIR minLeftSideBearing, minRightSideBearing, xMaxExtent;
00302   SIGNED_PAIR caretSlopeRise, caretSlopeRun;
00303   UNSIGNED_PAIR numberOfHMetrics;
00304 } horz_header;
00305 
00306 void read_hhea_table (FILE *ttf_file)
00307 {
00308   horz_header.version = get_unsigned_quad(ttf_file);
00309   horz_header.ascender = get_signed_pair (ttf_file);
00310   horz_header.descender = get_signed_pair (ttf_file);
00311   horz_header.line_gap = get_signed_pair (ttf_file);
00312   if (verbose > 3) {
00313     fprintf (stdout, "Table type: hhea\n");
00314     fprintf (stdout, "\tVersion: %f\n", fixed(horz_header.version));
00315     fprintf (stdout, "\tAscender: %d\n", horz_header.ascender);
00316     fprintf (stdout, "\tDescender: %d\n", horz_header.descender);
00317     fprintf (stdout, "\tLine Gap: %d\n", horz_header.line_gap);
00318   }
00319 }
00320 
00321 
00322 struct font_header 
00323 {
00324   double version, revision;
00325   UNSIGNED_QUAD check_sum;
00326   UNSIGNED_QUAD magic;
00327   UNSIGNED_PAIR flags, units_per_em;
00328   SIGNED_PAIR xMin, yMin, xMax, yMax;
00329   UNSIGNED_PAIR style, minsize;
00330   SIGNED_PAIR fontDirectionHint, indexToLocFormat;
00331   SIGNED_PAIR glyphDataFormat;
00332 };
00333 
00334 struct font_header *read_head_table(FILE *ttf_file, struct table_directory *td)
00335 {
00336   struct font_header *r;
00337   int i;
00338   unsigned long fw;
00339   long head_offset = find_table_pos (ttf_file, td, "head");
00340   seek_absolute (ttf_file, head_offset);
00341   r = NEW (1, struct font_header);
00342   fw = get_unsigned_quad(ttf_file);
00343   (r->version) = fixed(fw);
00344   fw = get_unsigned_quad(ttf_file);
00345   (r->revision) = fixed(fw);
00346   r->check_sum = get_unsigned_quad(ttf_file);
00347   r->magic = get_unsigned_quad(ttf_file);
00348   r->flags = get_unsigned_pair(ttf_file);
00349   r->units_per_em = get_unsigned_pair(ttf_file);
00350   if (verbose > 3) {
00351     fprintf (stdout, "Table type: head\n");
00352     fprintf (stdout, "\tVersion: %f\n", r->version);
00353     fprintf (stdout, "\tRevision: %f\n", r->revision);
00354     fprintf (stdout, "\tChecksum: %lx\n", r->check_sum);
00355     fprintf (stdout, "\tMagic: %lx\n", r->magic);
00356     fprintf (stdout, "\tFlags: %x\n", r->flags);
00357     fprintf (stdout, "\tunits_per_em: %d\n", r->units_per_em);
00358   }
00359   /* Skip Dates */
00360   for (i=0; i<4; i++) {
00361     get_unsigned_quad (ttf_file);
00362   }
00363   r->xMin = get_signed_pair(ttf_file);
00364   r->yMin = get_signed_pair(ttf_file);
00365   r->xMax = get_signed_pair(ttf_file);
00366   r->yMax = get_signed_pair(ttf_file);
00367   r->style = get_unsigned_pair(ttf_file);
00368   r->minsize = get_unsigned_pair(ttf_file);
00369   r->fontDirectionHint = get_signed_pair(ttf_file);
00370   r->indexToLocFormat = get_signed_pair(ttf_file);
00371   r->glyphDataFormat = get_signed_pair(ttf_file);
00372   if (verbose > 3) {
00373     fprintf (stdout, "\txMin: %d\n", r->xMin);
00374     fprintf (stdout, "\tyMin: %d\n", r->yMin);
00375     fprintf (stdout, "\txMax: %d\n", r->xMax);
00376     fprintf (stdout, "\tyMax: %d\n", r->yMax);
00377     fprintf (stdout, "\tyStyle: %d\n", r->style);
00378     fprintf (stdout, "\tyMin readable size (pixels): %d\n", r->minsize);
00379     fprintf (stdout, "\tDirection Hint: %d\n", r->fontDirectionHint);
00380     fprintf (stdout, "\tIndex Format: %d\n",
00381             r->indexToLocFormat);
00382     fprintf (stdout, "\tData Format: %d\n",
00383             r->glyphDataFormat);
00384   }
00385   return r;
00386 }
00387 
00388 
00389 static unsigned num_ttfs = 0;
00390 static unsigned max_ttfs = 0;
00391 struct a_ttf
00392 {
00393   char *ttf_name;
00394   char *fontname;
00395   struct table_directory *directory;
00396   pdf_obj *direct, *indirect, *descriptor;
00397   char **used_glyphs;
00398   char **int_encoding;
00399   char *used_def_enc_chars; /* The positions used from the default
00400                                encoding.  When a default encoding
00401                                is used, the glyph names will not
00402                                be known until the font is actually
00403                                read.  Since the glyph names are
00404                                unknown, only the positions of the
00405                                used chars are stored when the
00406                                default encoding is used */
00407   unsigned n_used_glyphs, max_used_glyphs;
00408 } *ttfs = NULL;
00409 
00410 static void init_a_ttf (struct a_ttf *ttf)
00411 {
00412   int i;
00413   ttf -> n_used_glyphs = 0;
00414   ttf -> max_used_glyphs = 0;
00415   ttf -> used_glyphs = NULL;
00416   ttf->ttf_name = NULL;
00417   ttf->fontname = NULL;
00418   ttf->direct = NULL;
00419   ttf->indirect = NULL;
00420   ttf->descriptor = NULL;
00421   ttf -> used_def_enc_chars = NULL;
00422   if (partial_enabled) {
00423     ttf -> int_encoding = NEW (256, char *);
00424     for (i=0; i<256; i++) {
00425       (ttf -> int_encoding)[i] = NULL;
00426     }
00427   } else {
00428     ttf -> int_encoding = NULL;
00429   }
00430 }
00431 
00432 #include "macglyphs.h"
00433 
00434 
00435 #define FIXED_WIDTH 1
00436 #define SERIF 2
00437 #define STANDARD 32
00438 #define ITALIC 64
00439 #define SYMBOLIC 4   /* Fonts that don't have Adobe encodings (e.g.,
00440                      cmr, should be set to be symbolic */
00441 #define STEMV 80
00442 
00443 
00444 extern int CDECL glyph_cmp(const void *v1, const void *v2);
00445 extern int CDECL glyph_match(const void *key, const void *v);
00446 
00447 
00448 static void dump_glyphs( char **glyphs, int n, int show_index)
00449 {
00450   int i;
00451   for (i=0; i<n; i++) {
00452     if (show_index)
00453       fprintf (stderr, "(%d", i);
00454     if (glyphs[i])
00455       fprintf (stderr, "/%s", glyphs[i]);
00456     else
00457       fprintf (stderr, "(null)");
00458     if (show_index)
00459       fprintf (stderr, ")");
00460   }
00461   return;
00462 }
00463 
00464 static void dump_used( char *used_chars)
00465 {
00466   int i;
00467   for (i=0; i<256; i++)
00468     fprintf (stderr, "(%d/%d)", i, used_chars[i]);
00469   return;
00470 }
00471 
00472 static unsigned int glyph_length (char **glyphs) 
00473 {
00474   int i;
00475   unsigned result = 0;
00476   for (i=0; i<256; i++) {
00477     result += strlen (glyphs[i]);
00478   }
00479   return result;
00480 }
00481 
00482 static char *ttf_find_name (FILE *ttf_file, struct table_directory *td)
00483 {
00484   char *result = NULL;
00485   unsigned num_names, string_offset;
00486   long name_offset;
00487   int i;
00488   name_offset = find_table_pos (ttf_file, td, "name");
00489   if (name_offset >= 0) {
00490     seek_absolute (ttf_file, name_offset);
00491     if (get_unsigned_pair (ttf_file)) 
00492       ERROR ("Expecting zero in ttf_find_name()");
00493     num_names = get_unsigned_pair (ttf_file);
00494     string_offset = get_unsigned_pair (ttf_file);
00495     for (i=0; i<num_names; i++) {
00496       unsigned platform_id, plat_encoding_id;
00497       unsigned language_id, name_id;
00498       unsigned length, offset;
00499       platform_id = get_unsigned_pair (ttf_file);
00500       plat_encoding_id = get_unsigned_pair (ttf_file);
00501       language_id = get_unsigned_pair (ttf_file);
00502       name_id = get_unsigned_pair (ttf_file);
00503       length = get_unsigned_pair (ttf_file);
00504       offset = get_unsigned_pair (ttf_file);
00505       if (platform_id == 1 &&
00506          name_id == 6) { /* For now, return the PS font name */
00507        seek_absolute (ttf_file, name_offset+string_offset+offset);
00508        result = NEW (length+1, char);
00509        fread (result, length, sizeof(char), ttf_file);
00510        result[length] = 0;
00511        if (verbose > 3) {
00512          fprintf (stdout, "TTF internal name is %s\n", result);
00513        }
00514        break;
00515       }
00516     }
00517     if (i == num_names) {
00518       ERROR ("Couldn't find ttf font name in a platform/encoding I could understand");
00519     }
00520   } else {
00521     fprintf (stdout, "Name table not found!\n");
00522   }
00523   return result;
00524 }
00525 
00526 static pdf_obj *ttf_fontfile (int ttf_id) 
00527 {
00528   if (ttf_id >= 0 && ttf_id < num_ttfs) 
00529     return pdf_link_obj (ttfs[ttf_id].indirect);
00530   else
00531     return NULL;
00532 }
00533 
00534 static char *ttf_fontname (int ttf_id) 
00535 {
00536   if (ttf_id >= 0 && ttf_id < num_ttfs) 
00537     return ttfs[ttf_id].fontname;
00538   else
00539     return NULL;
00540 }
00541 
00542 
00543 static void ttf_add_to_used_glyphs (int ttf_id, char *glyph)
00544 {
00545   if (ttf_id >= 0 && ttf_id < num_ttfs && glyph) {
00546     if (ttfs[ttf_id].n_used_glyphs == 0 ||
00547        !bsearch (glyph, ttfs[ttf_id].used_glyphs,
00548                 ttfs[ttf_id].n_used_glyphs,
00549                 sizeof (char *), glyph_match)) {
00550       if (ttfs[ttf_id].n_used_glyphs+1 >=
00551          ttfs[ttf_id].max_used_glyphs) {
00552        ttfs[ttf_id].max_used_glyphs += 16;
00553        ttfs[ttf_id].used_glyphs = RENEW (ttfs[ttf_id].used_glyphs,
00554                                      ttfs[ttf_id].max_used_glyphs,
00555                                      char *);
00556       }
00557       (ttfs[ttf_id].used_glyphs)[ttfs[ttf_id].n_used_glyphs] = 
00558        NEW (strlen(glyph)+1, char);
00559       strcpy((ttfs[ttf_id].used_glyphs)[ttfs[ttf_id].n_used_glyphs],
00560             glyph);
00561       ttfs[ttf_id].n_used_glyphs += 1;
00562       qsort (ttfs[ttf_id].used_glyphs, ttfs[ttf_id].n_used_glyphs, 
00563             sizeof (char *), glyph_cmp);
00564     }
00565   }
00566 }
00567 
00568 static char *new_used_chars (void)
00569 {
00570   char *result;
00571   int i;
00572   result = NEW (256, char);
00573   for (i=0; i<256; i++) {
00574     result[i] = 0;
00575   }
00576   return result;
00577 }
00578 
00579 /* Mark the character at position "code" as used in the ttf font
00580    corresponding to "ttf_id" */
00581 static void ttf_add_to_used_chars (int ttf_id, unsigned code)
00582 {
00583   if (ttf_id >= 0 && ttf_id < num_ttfs && code < 256) {
00584     if (!ttfs[ttf_id].used_def_enc_chars) {
00585       ttfs[ttf_id].used_def_enc_chars = new_used_chars();
00586     }
00587     (ttfs[ttf_id].used_def_enc_chars)[code] = 1;
00588   }
00589   if (code >= 256)
00590     ERROR ("ttf_add_to_used_chars(): code >= 256");
00591   return;
00592 }
00593 
00594 /* Mangle_fontname mangles the name in place.  fontname
00595    must be big enough to add seven characters */
00596 
00597 static void mangle_fontname(char *fontname)
00598 {
00599   int i;
00600   char ch;
00601   static char first = 1;
00602   memmove (fontname+7, fontname, strlen(fontname)+1);
00603   /* The following procedure isn't very random, but it
00604      doesn't need to be for this application. */
00605   if (first) {
00606     srand (time(NULL));
00607     first = 0;
00608   }
00609   for (i=0; i<6; i++) {
00610     ch = rand() % 26;
00611     fontname[i] = ch+'A';
00612   }
00613   fontname[6] = '+';
00614 }
00615 
00616 
00617 /* This routine builds a default font descriptor with dummy values
00618    filled in for the required keys.  As the ttf file is parsed,
00619    any values that are found are rewritten.  By doing this,
00620    all the required fields are found in the font descriptor
00621    even if the ttf is somewhat defective. This approach is
00622    conservative, with the cost of keeping the names around in memory 
00623    for a while.
00624 */
00625 
00626 static void ttf_start_font_descriptor (FILE *ttf_file, int ttf_id)
00627 {
00628   pdf_obj *tmp1;
00629   struct font_header *r;
00630   ttfs[ttf_id].descriptor = pdf_new_dict ();
00631   
00632   pdf_add_dict (ttfs[ttf_id].descriptor,
00633               pdf_new_name ("Type"),
00634               pdf_new_name ("FontDescriptor"));
00635   /* For now, insert dummy values */
00636   pdf_add_dict (ttfs[ttf_id].descriptor,
00637               pdf_new_name ("CapHeight"),
00638               pdf_new_number (850.0)); /* This number is arbitrary */
00639   pdf_add_dict (ttfs[ttf_id].descriptor,
00640               pdf_new_name ("Ascent"),
00641               pdf_new_number (850.0));    /* This number is arbitrary */
00642   pdf_add_dict (ttfs[ttf_id].descriptor,
00643               pdf_new_name ("Descent"),
00644               pdf_new_number (-200.0));
00645   r = read_head_table(ttf_file, ttfs[ttf_id].directory);
00646   tmp1 = pdf_new_array ();
00647   pdf_add_array (tmp1, pdf_new_number ((double) r->xMin));
00648   pdf_add_array (tmp1, pdf_new_number ((double) r->yMin));
00649   pdf_add_array (tmp1, pdf_new_number ((double) r->xMax));
00650   pdf_add_array (tmp1, pdf_new_number ((double) r->yMax));
00651   RELEASE (r);
00652   pdf_add_dict (ttfs[ttf_id].descriptor, pdf_new_name ("FontBBox"), tmp1);
00653   pdf_add_dict (ttfs[ttf_id].descriptor,
00654               pdf_new_name ("FontName"),
00655               pdf_new_name (ttf_fontname(ttf_id)));
00656 
00657   pdf_add_dict (ttfs[ttf_id].descriptor,
00658               pdf_new_name ("ItalicAngle"),
00659               pdf_new_number(0.0));
00660   pdf_add_dict (ttfs[ttf_id].descriptor,
00661               pdf_new_name ("StemV"),  /* StemV is required, StemH
00662                                        is not */
00663               pdf_new_number (STEMV)); /* Use a default value */
00664   /* You don't need a fontfile for the standard fonts */
00665   if (ttf_id >= 0)
00666     pdf_add_dict (ttfs[ttf_id].descriptor,
00667                 pdf_new_name ("FontFile2"),
00668                 ttf_fontfile (ttf_id));
00669 
00670   pdf_add_dict (ttfs[ttf_id].descriptor,
00671               pdf_new_name ("Flags"),
00672               pdf_new_number (SYMBOLIC));  /* Treat all fonts as symbolic */
00673   return;
00674 }
00675 
00676 static int ttf_get_id (const char *ttf_name)
00677 {
00678   int i;
00679   for (i=0; i<num_ttfs; i++) {
00680     if (ttfs[i].ttf_name && !strcmp (ttfs[i].ttf_name, ttf_name))
00681       break;
00682   }
00683   if (i == num_ttfs) { /* This font not previously called for */
00684     FILE *ttf_file;
00685     char *full_ttf_name, *short_fontname;
00686     if (!(full_ttf_name = kpse_find_file (ttf_name, kpse_truetype_format,
00687                                 1)) || 
00688        !(ttf_file = MFOPEN (full_ttf_name, FOPEN_RBIN_MODE))) {
00689       return -1;
00690     }
00691     if (num_ttfs >= max_ttfs) {
00692       max_ttfs += MAX_FONTS;
00693       ttfs = RENEW (ttfs, max_ttfs, struct a_ttf);
00694     }
00695     num_ttfs += 1;
00696     init_a_ttf (ttfs+i);
00697     ttfs[i].directory = read_directory (ttf_file);
00698     short_fontname = ttf_find_name (ttf_file, ttfs[i].directory);
00699     ttfs[i].ttf_name = NEW (strlen(ttf_name)+1, char);
00700     strcpy (ttfs[i].ttf_name, ttf_name);
00701     ttfs[i].direct = pdf_new_stream(STREAM_COMPRESS);
00702     ttfs[i].indirect = pdf_ref_obj (ttfs[i].direct);
00703     if (partial_enabled) {
00704       ttfs[i].fontname = NEW (strlen(short_fontname)+8, char);
00705       strcpy (ttfs[i].fontname, short_fontname);
00706       mangle_fontname(ttfs[i].fontname);
00707     }
00708     else {
00709       ttfs[i].fontname = NEW (strlen(short_fontname)+1, char);
00710       strcpy (ttfs[i].fontname, short_fontname);
00711     }
00712     ttf_start_font_descriptor(ttf_file, i);
00713     if (short_fontname)
00714       RELEASE (short_fontname);
00715     MFCLOSE (ttf_file);
00716   }
00717   return i;
00718 }
00719 
00720 static void ttf_release (int id)
00721 {
00722   if (id >= 0 && id < num_ttfs) {
00723     RELEASE (ttfs[id].ttf_name);
00724     pdf_release_obj (ttfs[id].indirect);
00725     release_directory (ttfs[id].directory);
00726     RELEASE (ttfs[id].fontname);
00727 
00728     if (ttfs[id].used_def_enc_chars)
00729       RELEASE (ttfs[id].used_def_enc_chars);
00730     if (ttfs[id].int_encoding){
00731       int i;
00732       for (i=0; i<256; i++) {
00733        if ((ttfs[id].int_encoding)[i])
00734          RELEASE ((ttfs[id].int_encoding)[i]);
00735       }
00736       RELEASE (ttfs[id].int_encoding);
00737     }
00738     if (ttfs[id].used_glyphs) {
00739       unsigned i;
00740       for (i=0; i<ttfs[id].n_used_glyphs; i++) {
00741        RELEASE ((ttfs[id].used_glyphs)[i]);
00742       }
00743       RELEASE (ttfs[id].used_glyphs);
00744     }
00745   }
00746 }
00747 
00748 static void release_glyphs (char **glyphs)
00749 {
00750   int i;
00751   for (i=0; i<256; i++) {
00752     RELEASE (glyphs[i]);
00753   }
00754 }
00755 
00756 static void omit_unecessary (struct table_directory *td) 
00757 {
00758   int omitindex;
00759   if ((omitindex = find_table_index (td, "kern")) >= 0)
00760     (td->tables)[omitindex].omit = 1;
00761 }
00762 
00763 static void do_ttf (int ttf_id)
00764 {
00765   char *full_ttf_name;
00766   FILE *ttf_file;
00767   pdf_obj *stream_dict;
00768   full_ttf_name = kpse_find_file (ttfs[ttf_id].ttf_name, kpse_truetype_format,
00769                               1);
00770   if (verbose == 1)
00771     fprintf (stderr, "(TTF:%s", ttfs[ttf_id].ttf_name);
00772   if (verbose > 1)
00773     fprintf (stderr, "(TTF:%s", full_ttf_name);
00774   if (full_ttf_name == NULL ||
00775       (ttf_file = MFOPEN (full_ttf_name, FOPEN_RBIN_MODE)) == NULL) {
00776     fprintf (stderr, "Unable to find or open binary font file (%s)",
00777             ttfs[ttf_id].ttf_name);
00778     ERROR ("This existed when I checked it earlier!");
00779     return;
00780   }
00781   /* Following section doesn't hide PDF stream structure very well */
00782 
00783   /* The following section seems determines which, if any,
00784      glyphs were used via the internal encoding, which hasn't
00785      been known until now.*/
00786   if (partial_enabled) {
00787     int j;
00788     if (verbose > 2) {
00789       fprintf (stderr, "Default encoding:\n");
00790       dump_glyphs (ttfs[ttf_id].int_encoding, 256, 1);
00791     }
00792     if (ttfs[ttf_id].used_def_enc_chars) {
00793       if (verbose > 2)
00794        fprintf (stderr, "\nRetaining portion of default encoding:\n");
00795       for (j=0; j<256; j++) {
00796        if ((ttfs[ttf_id].used_def_enc_chars)[j]) {
00797          if (verbose > 2)
00798            fprintf (stderr, "(%d/%s)", j, (ttfs[ttf_id].int_encoding)[j]);
00799          ttf_add_to_used_glyphs (ttf_id, (ttfs[ttf_id].int_encoding)[j]);
00800        }
00801       }
00802     }
00803   }
00804   {
00805     char *buffer;
00806     long size;
00807     omit_unecessary (ttfs[ttf_id].directory);
00808     buffer = ttf_build_font (ttf_file, ttfs[ttf_id].directory, &size);
00809     MFCLOSE (ttf_file);
00810     stream_dict = pdf_stream_dict (ttfs[ttf_id].direct);
00811     pdf_add_stream(ttfs[ttf_id].direct, buffer, size);
00812     RELEASE (buffer);
00813     pdf_add_dict (stream_dict, pdf_new_name ("Length1"),
00814                 pdf_new_number (size));
00815     pdf_release_obj (ttfs[ttf_id].direct);
00816   /* Finally, flush the descriptor */
00817     pdf_release_obj (ttfs[ttf_id].descriptor);
00818   }
00819   return;
00820 }
00821 
00822 void ttf_flush_all (void)
00823 {
00824   int i;
00825   for (i=0; i<num_ttfs; i++) {
00826     do_ttf(i);
00827     ttf_release (i);
00828   }
00829   if (ttfs)
00830     RELEASE (ttfs);
00831 }
00832 
00833 struct a_ttf_font
00834 {
00835   pdf_obj *indirect, *encoding;
00836   long ttf_id;
00837   int encoding_id;
00838   char *used_chars;
00839 } *ttf_fonts = NULL;
00840 int num_ttf_fonts = 0, max_ttf_fonts = 0;
00841 
00842 
00843 static void init_a_ttf_font (struct a_ttf_font *this_ttf_font) 
00844 {
00845   if (partial_enabled) {
00846     this_ttf_font -> used_chars = new_used_chars ();
00847   } else {
00848     this_ttf_font -> used_chars = NULL;
00849   }
00850 }
00851 
00852 pdf_obj *ttf_font_resource (int ttf_id)
00853 {
00854   if (ttf_id>=0 && ttf_id<max_ttf_fonts)
00855     return pdf_link_obj(ttf_fonts[ttf_id].indirect);
00856   else {
00857     ERROR ("Invalid font id in ttf_font_resource");
00858     return NULL;
00859   }
00860 }
00861 
00862 char *ttf_font_used (int ttf_id)
00863 {
00864   char *result;
00865   if (ttf_id>=0 && ttf_id<max_ttf_fonts) {
00866     result = ttf_fonts[ttf_id].used_chars;
00867   } else {
00868     fprintf (stderr, "ttf_font_used: ttf_id=%d\n", ttf_id);
00869     ERROR ("Invalid font id in ttf_font_used");
00870   }
00871   return result;
00872 }
00873 
00874 
00875 
00876 int ttf_font (const char *map_name, int tfm_font_id, char
00877              *resource_name, int encoding_id, int remap) 
00878 {
00879   int i, result = -1;
00880   int tfm_firstchar, tfm_lastchar;
00881   int pdf_firstchar, pdf_lastchar;
00882   int ttf_id = -1;
00883   pdf_obj *font_resource=NULL, *tmp1, *font_encoding_ref;
00884 
00885   if (num_ttf_fonts >= max_ttf_fonts) {
00886     max_ttf_fonts = MAX (max_ttf_fonts+MAX_FONTS, num_ttf_fonts+1);
00887     ttf_fonts = RENEW (ttf_fonts, max_ttf_fonts, struct
00888                       a_ttf_font);
00889   }
00890 
00891   if ((ttf_id = ttf_get_id(map_name)) >= 0) {
00892     /* Looks like we have a physical font (either a reader font or a
00893        Type 1 font binary file).  */
00894     init_a_ttf_font (ttf_fonts+num_ttf_fonts);
00895     ttf_fonts[num_ttf_fonts].ttf_id = ttf_id;
00896     ttf_fonts[num_ttf_fonts].encoding_id = encoding_id;
00897   /* Allocate a dictionary for the physical font */
00898     font_resource = pdf_new_dict ();
00899     if (ttf_fonts[num_ttf_fonts].encoding_id >= 0) {
00900       font_encoding_ref = encoding_ref (encoding_id);
00901       pdf_add_dict (font_resource,
00902                   pdf_new_name ("Encoding"),
00903                   font_encoding_ref);
00904     }
00905     pdf_add_dict (font_resource,
00906                 pdf_new_name ("Type"),
00907                 pdf_new_name ("Font"));
00908     pdf_add_dict (font_resource,
00909                 pdf_new_name ("Subtype"),
00910                 pdf_new_name ("TrueType"));
00911     pdf_add_dict (font_resource, 
00912                 pdf_new_name ("Name"),
00913                 pdf_new_name (resource_name));
00914     if (ttf_fonts[num_ttf_fonts].ttf_id >= 0) {
00915       pdf_add_dict (font_resource, 
00916                   pdf_new_name ("FontDescriptor"),
00917                   pdf_ref_obj(ttfs[ttf_fonts[num_ttf_fonts].ttf_id].descriptor));
00918     }
00919       /* If we are embedding this font, it may have been used by another virtual
00920         font and we need to use the same mangled name.  Mangled
00921         names are known only to the ttf module, so we call it to get
00922         the name */
00923     if (ttf_fonts[num_ttf_fonts].ttf_id >= 0) {
00924       pdf_add_dict (font_resource, 
00925                   pdf_new_name ("BaseFont"),
00926                   pdf_new_name
00927                   (ttf_fontname(ttf_fonts[num_ttf_fonts].ttf_id)));
00928        /* Otherwise we use the base name */
00929     } else {
00930       pdf_add_dict (font_resource,
00931                   pdf_new_name ("BaseFont"),
00932                   pdf_new_name (map_name));
00933     }
00934     tfm_firstchar = tfm_get_firstchar(tfm_font_id);
00935     tfm_lastchar = tfm_get_lastchar(tfm_font_id);
00936     if (partial_enabled && remap) {
00937       unsigned char t;
00938       pdf_firstchar=255; pdf_lastchar=0;
00939       for (i=tfm_firstchar; i<=tfm_lastchar; i++) {
00940        if ((t=twiddle(i)) < pdf_firstchar)
00941          pdf_firstchar = t;
00942        if (t > pdf_lastchar)
00943          pdf_lastchar = t;
00944       }
00945     } else {
00946       pdf_firstchar = tfm_firstchar;
00947       pdf_lastchar = tfm_lastchar;
00948     }
00949     pdf_add_dict (font_resource,
00950                 pdf_new_name ("FirstChar"),
00951                 pdf_new_number (pdf_firstchar));
00952     pdf_add_dict (font_resource,
00953                 pdf_new_name ("LastChar"),
00954                 pdf_new_number (pdf_lastchar));
00955     tmp1 = pdf_new_array ();
00956     for (i=pdf_firstchar; i<=pdf_lastchar; i++) {
00957       if (partial_enabled && remap) {
00958        int t;
00959        if ((t=untwiddle(i)) <= tfm_lastchar && t>=tfm_firstchar)
00960          pdf_add_array (tmp1,
00961                       pdf_new_number(ROUND(tfm_get_width
00962                                          (tfm_font_id,t)*1000.0,0.1)));
00963        else
00964          pdf_add_array (tmp1,
00965                       pdf_new_number(0.0));
00966       } else
00967        pdf_add_array (tmp1,
00968                      pdf_new_number(ROUND(tfm_get_width
00969                                        (tfm_font_id, i)*1000.0,0.1)));
00970     }
00971     pdf_add_dict (font_resource,
00972                 pdf_new_name ("Widths"),
00973                 tmp1);
00974     ttf_fonts[num_ttf_fonts].indirect = pdf_ref_obj(font_resource);
00975     pdf_release_obj (font_resource);
00976     result = num_ttf_fonts;
00977     num_ttf_fonts += 1;
00978   }
00979   return result;
00980 }
00981 
00982 
00983 void ttf_close_all (void)
00984 {
00985   int i, j;
00986   /* Three arrays are created by this module and need to be released */
00987   /* First, each TeX font name that ends up as a postscript font gets
00988      added to ttf_fonts (yes, even Times-Roman, etc.) */
00989   /* The first thing to do is to resolve all character references to 
00990      actual glyph references.  If an external encoding is specified,
00991      we simply look up the glyph name in the encoding.  If the internal
00992      encoding is being used, we add it to the used_chars array of
00993      the internal encoding */
00994   for (i=0; i<num_ttf_fonts; i++) {
00995     /* If font subsetting is enabled, each used character needs
00996        to be added to the used_glyphs array in the corresponding ttf
00997     */
00998     if (partial_enabled) {
00999       /* We always consider .notdef to be used */
01000       ttf_add_to_used_glyphs (ttf_fonts[i].ttf_id, ".notdef");
01001       for (j=0; j<256; j++) {
01002        char *glyph;
01003        if (ttf_fonts[i].ttf_id >= 0 &&
01004            ttf_fonts[i].encoding_id >= 0 &&
01005            (ttf_fonts[i].used_chars)[j]) {
01006          glyph = encoding_glyph (ttf_fonts[i].encoding_id,
01007                                    j);
01008          ttf_add_to_used_glyphs (ttf_fonts[i].ttf_id, glyph);
01009        }
01010        if (ttf_fonts[i].ttf_id >= 0 &&
01011            ttf_fonts[i].encoding_id < 0 &&
01012            (ttf_fonts[i].used_chars)[j])
01013          ttf_add_to_used_chars (ttf_fonts[i].ttf_id, j);
01014       }
01015     }
01016     if (ttf_fonts[i].used_chars)
01017       RELEASE (ttf_fonts[i].used_chars);
01018     pdf_release_obj (ttf_fonts[i].indirect);
01019   }
01020   if (ttf_fonts)
01021     RELEASE (ttf_fonts);
01022   /* Second every distinct ttf name ends up in ttfs.  It is possible
01023      that two distinct tex names map to the same ttf name.  That's why
01024      there is a separate array for ttfs */
01025   /* Read any necessary font files and flush them */
01026   ttf_flush_all();
01027 }
01028 
01029 
01030 #endif /* HAVE_TTF_FORMATS */
01031