Back to index

texmacs  1.0.7.15
truetype.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/truetype.c,v 1.11 2009/08/28 00:26:17 matthias Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012     
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017     
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00021 */
00022 
00023 
00024 #if HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include "system.h"
00029 
00030 #include "numbers.h"
00031 #include "error.h"
00032 #include "mem.h"
00033 
00034 #include "dpxfile.h"
00035 #include "dpxutil.h"
00036 
00037 #include "pdfobj.h"
00038 #include "pdfresource.h"
00039 #include "pdffont.h"
00040 
00041 #include "pdfencoding.h"
00042 #include "unicode.h"
00043 #include "agl.h"
00044 
00045 /* TrueType */
00046 #include "sfnt.h"
00047 #include "tt_cmap.h"
00048 #include "tt_table.h"
00049 #include "tt_glyf.h"
00050 #include "tt_post.h"
00051 #include "tt_gsub.h"
00052 #include "tt_aux.h"
00053 
00054 #include "truetype.h"
00055 
00056 #include "tfm.h"
00057 
00058 /* Modifying this has no effect :P */
00059 #ifdef ENABLE_NOEMBED
00060 #  undef ENABLE_NOEMBED
00061 #endif
00062 
00063 int
00064 pdf_font_open_truetype (pdf_font *font)
00065 {
00066   char     *ident;
00067   int       index, encoding_id;
00068   pdf_obj  *fontdict, *descriptor;
00069   sfnt     *sfont;
00070   int       embedding = 1; /* Must be embedded. */
00071   FILE     *fp;
00072   int       length, error = 0;
00073 
00074   ASSERT( font );
00075 
00076   ident = pdf_font_get_ident(font);
00077   index = pdf_font_get_index(font);
00078 
00079   ASSERT( ident );
00080 
00081   fp = DPXFOPEN(ident, DPX_RES_TYPE_TTFONT);
00082   if (!fp) {
00083     fp = DPXFOPEN(ident, DPX_RES_TYPE_DFONT);
00084     if (!fp) return  -1;
00085     sfont = dfont_open(fp, index);
00086   } else {
00087     sfont = sfnt_open(fp);
00088   }
00089 
00090   if (!sfont) {
00091     WARN("Could not open TrueType font: %s", ident);
00092     DPXFCLOSE(fp);
00093     return  -1;
00094   }
00095 
00096   if (sfont->type == SFNT_TYPE_TTC) {
00097     unsigned long offset;
00098     offset = ttc_read_offset(sfont, index);
00099     if (offset == 0) ERROR("Invalid TTC index in %s.", ident);
00100     error = sfnt_read_table_directory(sfont, offset);
00101   } else {
00102     error = sfnt_read_table_directory(sfont, sfont->offset);
00103   }
00104 
00105   if (error) {
00106     sfnt_close(sfont);
00107     DPXFCLOSE(fp);
00108     return  -1; /* Silently */
00109   }
00110 
00111   /* Reading fontdict before checking fonttype conflicts with PKFONT
00112    * because pdf_font_get_resource() always makes a dictionary.
00113    */
00114   encoding_id = pdf_font_get_encoding(font);
00115   fontdict    = pdf_font_get_resource(font);
00116   descriptor  = pdf_font_get_descriptor(font);
00117 #ifdef  ENABLE_NOEMBED
00118   embedding   = pdf_font_get_flag(font, PDF_FONT_FLAG_NOEMBED) ? 0 : 1;
00119 #endif /* ENABLE_NOEMBED */
00120 
00121   ASSERT( fontdict && descriptor );
00122 
00123   {
00124     pdf_obj  *tmp;
00125     tmp  = tt_get_fontdesc(sfont, &embedding, -1, 1);
00126     if (!tmp) {
00127       ERROR("Could not obtain neccesary font info.");
00128       sfnt_close(sfont);
00129       DPXFCLOSE(fp);
00130       return  -1;
00131     }
00132     ASSERT(pdf_obj_typeof(tmp) == PDF_DICT);
00133 
00134     pdf_merge_dict(descriptor, tmp);
00135     pdf_release_obj(tmp);
00136   }
00137 
00138   if (!embedding) {
00139     if (encoding_id >= 0 &&
00140         !pdf_encoding_is_predefined(encoding_id)) {
00141       ERROR("Custom encoding not allowed for non-embedded TrueType font.");
00142       sfnt_close(sfont);
00143       return -1;
00144     } else {
00145       /* There are basically no guarantee for font substitution
00146        * can work with "symblic" fonts. At least all glyphs
00147        * contained in the font must be identified; glyphs covers
00148        * by this instance of font should contain glyphs only from
00149        * Adobe Standard Latin Set. We allow non-embedded font
00150        * only to predefined encodings for this reason. Note that
00151        * "builtin" encoding means "MacRoman" here.
00152        */
00153       pdf_obj  *tmp;
00154       long      flags;
00155 
00156 #ifndef  ENABLE_NOEMBED
00157       ERROR("Font file=\"%s\" can't be embedded due to liscence restrictions.", ident);
00158 #endif /* ENABLE_NOEMBED */
00159       pdf_font_set_flags(font, PDF_FONT_FLAG_NOEMBED);
00160       tmp = pdf_lookup_dict(descriptor, "Flags");
00161       if (tmp && pdf_obj_typeof(tmp) == PDF_NUMBER) {
00162         flags  = (long) pdf_number_value(tmp);
00163         flags &= (1 << 2); /* clear Symbolic */
00164         flags |= (1 << 5); /* set Nonsymbolic */
00165         pdf_add_dict(descriptor, pdf_new_name("Flags"), pdf_new_number(flags));
00166       }
00167     }
00168   }
00169 
00170   {
00171     char  fontname[256];
00172     int   n;
00173 
00174     memset(fontname, 0, 256);
00175     length = tt_get_ps_fontname(sfont, fontname, 255);
00176     if (length < 1) {
00177       length = MIN(strlen(ident), 255);
00178       strncpy(fontname, ident, length);
00179     }
00180     fontname[length] = '\0';
00181     for (n = 0; n < length; n++) {
00182       if (fontname[n] == 0) {
00183         memmove(fontname + n, fontname + n + 1, length - n - 1);
00184       }
00185     }
00186     if (strlen(fontname) == 0)
00187       ERROR("Can't find valid fontname for \"%s\".", ident);
00188     pdf_font_set_fontname(font, fontname);
00189   }
00190 
00191   sfnt_close(sfont);
00192   DPXFCLOSE(fp);
00193 
00194   pdf_add_dict(fontdict,
00195                pdf_new_name("Type"),    pdf_new_name("Font"));
00196   pdf_add_dict(fontdict,
00197                pdf_new_name("Subtype"), pdf_new_name("TrueType"));
00198 
00199   return  0;
00200 }
00201 
00202 /*
00203  * The 'name' table should be preserved since it contains copyright
00204  * information, but it might cause problem when there are invalid
00205  * table entries (wrongly encoded text which is often the case in
00206  * CJK fonts). Acrobat does not use 'name' table. Unicode TrueType
00207  * fonts may have 10K bytes 'name' table...
00208  *
00209  * We preserve the 'OS/2' table too, since it contains the license
00210  * information. PDF applications should use this table to decide
00211  * whether the font is embedded only for the purpose of preview &
00212  * printing. Otherwise, we must encrypt the document. Acrobat does
00213  * not use 'OS/2' table, though...
00214  */
00215 static struct
00216 {
00217   const char *name;
00218   int   must_exist;
00219 } required_table[] = {
00220   {"OS/2", 0}, {"head", 1}, {"hhea", 1}, {"loca", 1}, {"maxp", 1},
00221   {"name", 1}, {"glyf", 1}, {"hmtx", 1}, {"fpgm", 0}, {"cvt ", 0},
00222   {"prep", 0}, {"cmap", 1}, {NULL, 0}
00223 };
00224 
00225 static void
00226 do_widths (pdf_font *font, double *widths)
00227 {
00228   pdf_obj  *fontdict;
00229   pdf_obj  *tmparray;
00230   int       code, firstchar, lastchar, tfm_id;
00231   char     *usedchars;
00232 
00233   fontdict   = pdf_font_get_resource  (font);
00234   usedchars  = pdf_font_get_usedchars (font);
00235 
00236   tmparray = pdf_new_array();
00237   for (firstchar = 255, lastchar = 0, code = 0; code < 256; code++) {
00238     if (usedchars[code]) {
00239       if (code < firstchar) firstchar = code;
00240       if (code > lastchar)  lastchar  = code;
00241     }
00242   }
00243   if (firstchar > lastchar) {
00244     WARN("No glyphs actually used???");
00245     pdf_release_obj(tmparray);
00246     return;
00247   }
00248   { 
00249     char *tfmfile = pdf_font_get_tfmfile(font);
00250     if (tfmfile) 
00251       tfm_id = tfm_open(tfmfile, 0); 
00252     else 
00253       tfm_id = tfm_open(pdf_font_get_mapname(font), 0);       
00254   }
00255   for (code = firstchar; code <= lastchar; code++) {
00256     if (usedchars[code]) {
00257       double width;
00258       if (tfm_id < 0) /* tfm is not found */
00259         width = widths[code];
00260       else
00261         width = 1000. * tfm_get_width(tfm_id, code);
00262       pdf_add_array(tmparray,
00263                     pdf_new_number(ROUND(width, 0.1)));
00264     } else {
00265       pdf_add_array(tmparray, pdf_new_number(0.0));
00266     }
00267   }
00268 
00269   if (pdf_array_length(tmparray) > 0) {
00270     pdf_add_dict(fontdict,
00271                  pdf_new_name("Widths"), pdf_ref_obj(tmparray));
00272   }
00273   pdf_release_obj(tmparray);
00274 
00275   pdf_add_dict(fontdict,
00276                pdf_new_name("FirstChar"), pdf_new_number(firstchar));
00277   pdf_add_dict(fontdict,
00278                pdf_new_name("LastChar"),  pdf_new_number(lastchar));
00279 
00280   return;
00281 }
00282 
00283 static int verbose = 0;
00284 
00285 #define PDFUNIT(v) ((double) (ROUND(1000.0*(v)/(glyphs->emsize), 1)))
00286 
00287 /*
00288  * There are several issues in TrueType font support in PDF.
00289  * How PDF viewers select TrueType cmap table is not so clear.
00290  * Most reliable way seem to reencode font and sort glyphs as
00291  * charcode == gid and to use Mac-Roman format 0 subtable.
00292  * It does not work with encodings that uses full 256 range since
00293  * GID = 0 is reserved for .notdef, so GID = 256 is not accessible.
00294  */
00295 static int
00296 do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont)
00297 {
00298   struct tt_glyphs *glyphs;
00299   char             *cmap_table;
00300   tt_cmap          *ttcm;
00301   USHORT            gid, idx;
00302   int               code, count;
00303   double            widths[256];
00304 
00305   ttcm = tt_cmap_read(sfont, TT_MAC, TT_MAC_ROMAN);
00306   if (!ttcm) {
00307     WARN("Could not read Mac-Roman TrueType cmap table...");
00308     return  -1;
00309   }
00310 
00311   cmap_table = NEW(274, char);
00312   memset(cmap_table, 0, 274);
00313   sfnt_put_ushort(cmap_table,    0);            /* Version  */
00314   sfnt_put_ushort(cmap_table+2,  1);            /* Number of subtables */
00315   sfnt_put_ushort(cmap_table+4,  TT_MAC);       /* Platform ID */
00316   sfnt_put_ushort(cmap_table+6,  TT_MAC_ROMAN); /* Encoding ID */
00317   sfnt_put_ulong (cmap_table+8,  12);           /* Offset   */
00318   sfnt_put_ushort(cmap_table+12, 0);            /* Format   */
00319   sfnt_put_ushort(cmap_table+14, 262);          /* Length   */
00320   sfnt_put_ushort(cmap_table+16, 0);            /* Language */
00321 
00322   glyphs = tt_build_init();
00323 
00324   if (verbose > 2)
00325     MESG("[glyphs:/.notdef");
00326 
00327   count = 1; /* .notdef */
00328   for (code = 0; code < 256; code++) {
00329     if (!usedchars[code])
00330       continue;
00331 
00332     if (verbose > 2)
00333       MESG("/.c0x%02x", code);
00334 
00335     gid = tt_cmap_lookup(ttcm, code);
00336     if (gid == 0) {
00337       WARN("Glyph for character code=0x%02x missing in font font-file=\"%s\".",
00338            code, pdf_font_get_ident(font));
00339       idx = 0;
00340     } else {
00341       idx = tt_find_glyph(glyphs, gid);
00342       if (idx == 0)
00343         idx  = tt_add_glyph(glyphs, gid, count); /* count returned. */
00344     }
00345     cmap_table[18+code] = idx & 0xff; /* bug here */
00346     count++;
00347   }
00348   tt_cmap_release(ttcm);
00349 
00350   if (verbose > 2)
00351     MESG("]");
00352 
00353   if (tt_build_tables(sfont, glyphs) < 0) {
00354     WARN("Packing TrueType font into SFNT failed!");
00355     tt_build_finish(glyphs);
00356     RELEASE(cmap_table);
00357     return  -1;
00358   }
00359 
00360   for (code = 0; code < 256; code++) {
00361     if (usedchars[code]) {
00362       idx = tt_get_index(glyphs, (USHORT) cmap_table[18+code]);
00363       widths[code] = PDFUNIT(glyphs->gd[idx].advw);
00364     } else {
00365       widths[code] = 0.0;
00366     }
00367   }
00368   do_widths(font, widths);
00369 
00370   if (verbose > 1) 
00371     MESG("[%d glyphs]", glyphs->num_glyphs);
00372 
00373   tt_build_finish(glyphs);
00374 
00375   sfnt_set_table(sfont, "cmap", cmap_table, 274);
00376 
00377   return  0;
00378 }
00379 
00380 /* Order of lookup should be
00381  *  post, unicode+otl
00382  */
00383 struct glyph_mapper
00384 {
00385   tt_cmap  *codetogid;
00386   otl_gsub *gsub;
00387   sfnt     *sfont;
00388   struct tt_post_table *nametogid;
00389 };
00390 
00391 
00392 /* WARNING: This modifies glyphname itself */
00393 static int
00394 agl_decompose_glyphname (char *glyphname, char **nptrs, int size, char **suffix)
00395 {
00396   char  *q, *p = glyphname;
00397   int    n;
00398 
00399   q = strchr(p, '.'); /* chop every thing after *first* dot */
00400   if (!q)
00401     *suffix = NULL;
00402   else {
00403     *q = '\0'; q++;
00404     *suffix = q;
00405   }
00406 
00407   nptrs[0] = p;
00408   for (n = 1; p && *p; n++) {
00409     p = strchr(p, '_');
00410     if (!p || p[1] == '\0')
00411       break;
00412     if (n >= size)
00413       ERROR("Uh ah..."); /* _FIXME_ */
00414     *p = '\0'; p++;
00415     nptrs[n] = p;
00416   }
00417 
00418   return  n;
00419 }
00420 
00421 static int
00422 select_gsub (const char *feat, struct glyph_mapper *gm)
00423 {
00424   int    idx, error = 0;
00425 
00426   if (!feat || *feat == 0 || !gm || !gm->gsub)
00427     return  -1;
00428 
00429   /* First treat as is */
00430   idx = otl_gsub_select(gm->gsub, "*", "*", feat);
00431   if (idx >= 0)
00432     return  0;
00433 
00434   if (verbose > 1)
00435     MESG("\ntrutype>> Try loading OTL GSUB for \"*.*.%s\"...", feat);
00436   error = otl_gsub_add_feat(gm->gsub, "*", "*", feat, gm->sfont);
00437   if (!error) {
00438     idx = otl_gsub_select(gm->gsub, "*", "*", feat);
00439     return  (idx >= 0 ? 0 : -1);
00440   }
00441 
00442   return  -1;
00443 }
00444 
00445 static int findparanoiac (const char *glyph_name, USHORT *gid, struct glyph_mapper *gm);
00446 static int resolve_glyph (const char *glyph_name, USHORT *gid, struct glyph_mapper *gm);
00447 
00448 /* Apply GSUB. This is a bit tricky... */
00449 static int
00450 selectglyph (USHORT in, const char *suffix, struct glyph_mapper *gm, USHORT *out)
00451 {
00452   char  *s, *q, t[5];
00453   int    n, error = 0;
00454 
00455   ASSERT(suffix && gm && out);
00456   ASSERT(suffix && *suffix != 0);
00457 
00458   s = NEW(strlen(suffix) + 1, char);
00459   strcpy(s, suffix);
00460 
00461   /* First try converting suffix to feature tag.
00462    * agl.c currently only knows less ambiguos cases;
00463    * e.g., 'sc', 'superior', etc.
00464    */
00465   q = (char *) agl_suffix_to_otltag(s);
00466   if (q) { /* We found feature tag for 'suffix'. */
00467     error = select_gsub(q, gm); /* no fallback for this */
00468     if (!error)
00469       error = otl_gsub_apply(gm->gsub, &in);
00470   } else { /* 'suffix' may represent feature tag. */
00471     /* Try loading GSUB only when length of 'suffix' is less
00472      * than or equal to 4. tt_gsub give a warning otherwise.
00473      */
00474     if (strlen(s) > 4)
00475       error = -1; /* Uh */
00476     else if (strlen(s) == 4)
00477       error = select_gsub(s, gm);
00478     else { /* less than 4. pad ' '. */
00479       memset(t, ' ', 4); t[4] = '\0';
00480       memcpy(t, s, strlen(s));
00481       error = select_gsub(t, gm);
00482     }
00483     if (!error) /* 'suffix' represents feature tag. */
00484       error = otl_gsub_apply(gm->gsub, &in);
00485     else { /* other case: alt1, nalt10... (alternates) */
00486       for (q = s + strlen(s) - 1; q > s && *q >= '0' && *q <= '9'; q--);
00487       if (q == s)
00488         error = -1;
00489       else { /* starting at 1 */
00490         n = atoi(q + 1) - 1; q[1] = '\0';
00491         if (strlen(s) > 4)
00492           error = -1;
00493         else { /* This may be alternate substitution. */
00494           memset(t, ' ', 4); t[4] = '\0';
00495           memcpy(t, s, strlen(s));
00496           error = select_gsub(s, gm);
00497           if (!error)
00498             error = otl_gsub_apply_alt(gm->gsub, n, &in);
00499         }
00500       }
00501     }
00502   }
00503   RELEASE(s);
00504 
00505   *out = in;
00506   return  error;
00507 }
00508 
00509 
00510 /* Compose glyphs via ligature substitution. */
00511 static int
00512 composeglyph (USHORT *glyphs, int n_glyphs,
00513               const char *feat, struct glyph_mapper *gm, USHORT *gid)
00514 {
00515   int   error = 0;
00516   char  t[5] = {' ', ' ', ' ', ' ', 0};
00517 
00518   ASSERT(glyphs && n_glyphs > 0 && gm && gid);
00519 
00520   if (!feat || feat[0] == '\0') /* meaning "Unknown" */
00521       error = select_gsub("(?lig|lig?|?cmp|cmp?|frac|afrc)", gm);
00522   else {
00523     if (strlen(feat) > 4)
00524       error = -1;
00525     else {
00526       memcpy(t, feat, strlen(feat));
00527       error = select_gsub(t, gm);
00528     }
00529   }
00530 
00531   if (!error)
00532     error = otl_gsub_apply_lig(gm->gsub, glyphs, n_glyphs, gid);
00533 
00534   return  error;
00535 }
00536 
00537 /* This may be called by findparanoiac(). */
00538 static int
00539 composeuchar (long *unicodes, int n_unicodes,
00540               const char *feat, struct glyph_mapper *gm, USHORT *gid)
00541 {
00542   USHORT  *gids;
00543   int      i, error = 0;
00544 
00545   if (!gm->codetogid)
00546     return  -1;
00547 
00548   gids = NEW(n_unicodes, USHORT);
00549   for (i = 0;
00550        !error && i < n_unicodes; i++) {
00551     gids[i] = tt_cmap_lookup(gm->codetogid, unicodes[i]);
00552     error   = (gids[i] == 0) ? -1 : 0;
00553   }
00554 
00555   if (!error)
00556     error = composeglyph(gids, n_unicodes, feat, gm, gid);
00557 
00558   RELEASE(gids);
00559 
00560   return  error;
00561 }
00562 
00563 /* Search 'post' table. */
00564 static int
00565 findposttable (const char *glyph_name, USHORT *gid, struct glyph_mapper *gm)
00566 {
00567   if (!gm->nametogid)
00568     return -1;
00569 
00570   *gid = tt_lookup_post_table(gm->nametogid, glyph_name);
00571 #if  0
00572   if (verbose > 1)
00573   {
00574     if (*gid > 0)
00575       MESG("%s =post=> 0x%04X\n", glyph_name, *gid);
00576   }
00577 #endif
00578 
00579   return (*gid == 0 ? -1 : 0);
00580 }
00581 
00582 /* This is wrong. We must care about '.'. */
00583 #define is_comp(n) (strchr((n), '_') != NULL)
00584 
00585 /* Glyph names are concatinated with '_'. */
00586 static int
00587 findcomposite (const char *glyphname, USHORT *gid, struct glyph_mapper *gm)
00588 {
00589   char     *gname, *suffix = NULL;
00590   USHORT    gids[32];
00591   char     *nptrs[32];
00592   int       i, n_comp;
00593   int       error = 0;
00594 
00595   error = findposttable(glyphname, gid, gm);
00596   if (!error)
00597     return  0;
00598 
00599   gname = NEW(strlen(glyphname) + 1, char);
00600   strcpy(gname, glyphname);
00601 
00602   memset(gids, 0, 32 * sizeof(USHORT));
00603   n_comp = agl_decompose_glyphname(gname, nptrs, 32, &suffix);
00604   for (error = 0, i = 0; !error && i < n_comp; i++) {
00605     error = resolve_glyph(nptrs[i], &gids[i], gm);
00606     if (error)
00607       WARN("Could not resolve glyph \"%s\" (%dth component of glyph \"%s\").",
00608            nptrs[i], i, glyphname);
00609   }
00610 
00611   if (!error) {
00612     if (suffix &&
00613         (!strcmp(suffix, "liga") || !strcmp(suffix, "dlig") ||
00614          !strcmp(suffix, "hlig") || !strcmp(suffix, "frac") ||
00615          !strcmp(suffix, "ccmp") || !strcmp(suffix, "afrc")
00616         )
00617        ) {
00618       error = composeglyph(gids, n_comp, suffix, gm, gid);
00619     } else { /* first try composing glyph */
00620       error = composeglyph(gids, n_comp, NULL, gm, gid);
00621       if (!error && suffix) /* a_b_c.vert */
00622         error = selectglyph(*gid, suffix, gm, gid);
00623     }
00624   }
00625   RELEASE(gname);
00626 
00627   return  error;
00628 }
00629 
00630 /* glyphname should not have suffix here */
00631 static int
00632 findparanoiac (const char *glyphname, USHORT *gid, struct glyph_mapper *gm)
00633 {
00634   agl_name  *agln;
00635   USHORT     idx   = 0U;
00636   int        error = 0;
00637 
00638   agln = agl_lookup_list(glyphname);
00639   while (agln && idx == 0) {
00640     if (agln->suffix) {
00641       error = findparanoiac(agln->name, &idx, gm);
00642       if (error)
00643         return error;
00644 
00645       error = selectglyph(idx, agln->suffix, gm, &idx);
00646       if (error) {
00647         WARN("Variant \"%s\" for glyph \"%s\" might not be found.",
00648              agln->suffix, agln->name);
00649         WARN("Using glyph name without suffix instead...");
00650         error = 0; /* ignore */
00651       }
00652     } else {
00653       if (agln->n_components == 1)
00654         idx = tt_cmap_lookup(gm->codetogid, agln->unicodes[0]);
00655       else if (agln->n_components > 1) {
00656         if (verbose >= 0) /* give warning */
00657           WARN("Glyph \"%s\" looks like a composite glyph...",
00658                agln->name);
00659         error = composeuchar(agln->unicodes, agln->n_components, NULL, gm, &idx);
00660         if (verbose >= 0) {
00661           if (error)
00662             WARN("Not found...");
00663           else {
00664             int   _i, _n = 0;
00665             char *_p, _buf[256];
00666             WARN(">> Composite glyph glyph-name=\"%s\" found at glyph-id=\"%u\".",
00667                   agln->name, idx);
00668             for (_p = _buf, _i = 0; _i < agln->n_components && _n < 245; _i++) {
00669               _p[_n++] = _i == 0 ? '<' : ' ';
00670               if (agln->unicodes[_i] >= 0x10000)
00671                 _n += sprintf(_p+_n, "U+%06lX", agln->unicodes[_i]);
00672               else
00673                 _n += sprintf(_p+_n, "U+%04lX", agln->unicodes[_i]);
00674               _p[_n++] = _i == agln->n_components - 1 ? '>' : ',';
00675             }
00676             _p[_n++] = '\0';
00677             WARN(">> Input Unicode seq.=\"%s\" ==> glyph-id=\"%u\" in font-file=\"_please_try_-v_\".", _buf, idx);
00678           }
00679         }
00680       } else ASSERT(0); /* Boooo */
00681     }
00682     agln = agln->alternate;
00683   }
00684 
00685   *gid = idx;
00686   return (idx == 0 ? -1 : 0);
00687 }
00688 
00689 static int
00690 resolve_glyph (const char *glyphname, USHORT *gid, struct glyph_mapper *gm)
00691 {
00692   int    error = 0;
00693   char  *name, *suffix = NULL;
00694   long   ucv;
00695 
00696   ASSERT(glyphname);
00697 
00698   /*
00699    * First we try glyph name to GID mapping using post table if post table
00700    * is available. If post table is not available or glyph is not listed 
00701    * in the post table, then we try Unicode if Windows-Unicode TrueType
00702    * cmap is available.
00703    */
00704   error = findposttable(glyphname, gid, gm);
00705   if (!error)
00706     return  0;
00707 
00708   if (!gm->codetogid)
00709     return  -1;
00710 
00711   name = agl_chop_suffix(glyphname, &suffix);
00712   if (!name) /* .notdef, .foo */
00713     error = -1;
00714   else if (agl_name_is_unicode(name)) {
00715     ucv  = agl_name_convert_unicode(name);
00716     *gid = tt_cmap_lookup(gm->codetogid, ucv);
00717     error = (*gid == 0) ? -1 : 0;
00718   } else {
00719     error = findparanoiac(name, gid, gm);
00720   }
00721   if (!error && suffix) {
00722     error = selectglyph(*gid, suffix, gm, gid);
00723     if (error) {
00724       WARN("Variant \"%s\" for glyph \"%s\" might not be found.",
00725            suffix, name);
00726       WARN("Using glyph name without suffix instead...");
00727       error = 0; /* ignore */
00728     }
00729   }
00730   if (suffix)
00731     RELEASE(suffix);
00732   if (name)
00733     RELEASE(name);
00734 
00735   return  error;
00736 }
00737 
00738 /* Things are complicated. We still need to use PostScript
00739  * glyph names. But OpenType fonts may not have PS name to
00740  * glyph mapping. We use Unicode plus OTL GSUB for finding
00741  * glyphs in this case.
00742  */
00743 static int
00744 setup_glyph_mapper (struct glyph_mapper *gm, sfnt *sfont)
00745 {
00746   gm->sfont     = sfont;
00747   gm->nametogid = tt_read_post_table(sfont);
00748   gm->codetogid = tt_cmap_read(sfont, TT_WIN, TT_WIN_UCS4);
00749   if (!gm->codetogid)
00750     gm->codetogid = tt_cmap_read(sfont, TT_WIN, TT_WIN_UNICODE);
00751 
00752   if (!gm->nametogid && !gm->codetogid)
00753     return -1;
00754 
00755   gm->gsub = otl_gsub_new();
00756 
00757   return 0;
00758 }
00759 
00760 static void
00761 clean_glyph_mapper (struct glyph_mapper *gm)
00762 {
00763   if (gm->gsub)
00764     otl_gsub_release(gm->gsub);
00765   if (gm->codetogid)
00766     tt_cmap_release (gm->codetogid);
00767   if (gm->nametogid)
00768     tt_release_post_table(gm->nametogid);
00769 
00770   gm->gsub = NULL;
00771   gm->codetogid = NULL;
00772   gm->nametogid = NULL;
00773   gm->sfont = NULL;
00774 
00775   return;
00776 }
00777 
00778 static int
00779 do_custom_encoding (pdf_font *font,
00780                     char **encoding, const char *usedchars, sfnt *sfont)
00781 {
00782   struct tt_glyphs      *glyphs;
00783   char                  *cmap_table;
00784   int                    code, count;
00785   double                 widths[256];
00786   struct glyph_mapper    gm;
00787   USHORT                 idx, gid;
00788   int                    error = 0;
00789 
00790   ASSERT(font && encoding && usedchars && sfont);
00791 
00792   error = setup_glyph_mapper(&gm, sfont);
00793   if (error) {
00794     WARN("No post table nor Unicode cmap found in font: %s",
00795          pdf_font_get_ident(font));
00796     WARN(">> I can't find glyphs without this!");
00797     return  -1;
00798   }
00799 
00800   cmap_table = NEW(274, char);
00801   memset(cmap_table, 0, 274);
00802   sfnt_put_ushort(cmap_table,    0);            /* Version  */
00803   sfnt_put_ushort(cmap_table+2,  1);            /* Number of subtables */
00804   sfnt_put_ushort(cmap_table+4,  TT_MAC);       /* Platform ID */
00805   sfnt_put_ushort(cmap_table+6,  TT_MAC_ROMAN); /* Encoding ID */
00806   sfnt_put_ulong (cmap_table+8,  12);           /* Offset   */
00807   sfnt_put_ushort(cmap_table+12, 0);            /* Format   */
00808   sfnt_put_ushort(cmap_table+14, 262);          /* Length   */
00809   sfnt_put_ushort(cmap_table+16, 0);            /* Language */
00810 
00811   glyphs = tt_build_init();
00812 
00813   count = 1; /* +1 for .notdef */
00814   for (code = 0; code < 256; code++) {
00815     if (!usedchars[code])
00816       continue;
00817 
00818     if (!encoding[code] || !strcmp(encoding[code], ".notdef")) {
00819       WARN("Character code=\"0x%02X\" mapped to \".notdef\" glyph used in font font-file=\"%s\"",
00820            code, pdf_font_get_ident(font));
00821       WARN(">> Maybe incorrect encoding specified?");
00822       idx = 0;
00823     } else {
00824       if (is_comp(encoding[code]))
00825         error = findcomposite(encoding[code], &gid, &gm);
00826       else
00827         error = resolve_glyph(encoding[code], &gid, &gm);
00828 
00829       /*
00830        * Older versions of gs had problem with glyphs (other than .notdef)
00831        * mapped to gid = 0.
00832        */
00833       if (error) {
00834         WARN("Glyph \"%s\" not available in font \"%s\".",
00835              encoding[code], pdf_font_get_ident(font));
00836       } else {
00837         if (verbose > 1)
00838           MESG("truetype>> Glyph glyph-name=\"%s\" found at glyph-id=\"%u\".\n", encoding[code], gid);
00839       }
00840       idx = tt_find_glyph(glyphs, gid);
00841       if (idx == 0) {
00842         idx = tt_add_glyph(glyphs, gid, count); /* count returned. */
00843         count++;
00844       }
00845     }
00846     cmap_table[18 + code] = idx & 0xff; /* bug here */
00847   }
00848   clean_glyph_mapper(&gm);
00849 
00850   if (tt_build_tables(sfont, glyphs) < 0) {
00851     WARN("Packing TrueType font into SFNT file faild..."); /* _FIXME_: wrong message */
00852     tt_build_finish(glyphs);
00853     RELEASE(cmap_table);
00854     return  -1;
00855   }
00856 
00857   for (code = 0; code < 256; code++) {
00858     if (usedchars[code]) {
00859       idx = tt_get_index(glyphs, (USHORT) cmap_table[18+code]);
00860       widths[code] = PDFUNIT(glyphs->gd[idx].advw);
00861     } else {
00862       widths[code] = 0.0;
00863     }
00864   }
00865   do_widths(font, widths);
00866 
00867   if (verbose > 1) 
00868     MESG("[%d glyphs]", glyphs->num_glyphs);
00869 
00870   tt_build_finish(glyphs);
00871 
00872   sfnt_set_table(sfont, "cmap", cmap_table, 274);
00873 
00874   return  0;
00875 }
00876 
00877 int
00878 pdf_font_load_truetype (pdf_font *font)
00879 {
00880   pdf_obj   *descriptor  = pdf_font_get_descriptor(font);
00881   char      *ident       = pdf_font_get_ident(font);
00882   int        encoding_id = pdf_font_get_encoding(font);
00883   char      *usedchars   = pdf_font_get_usedchars(font);
00884 #ifdef  ENABLE_NOEMBED
00885   int        embedding   = pdf_font_get_flag(font, PDF_FONT_FLAG_NOEMBED) ? 0 : 1;
00886 #endif /* ENABLE_NOEMBED */
00887   int        index       = pdf_font_get_index(font);
00888   char     **enc_vec;
00889   pdf_obj   *fontfile;
00890   FILE      *fp;
00891   sfnt      *sfont;
00892   int        i, error = 0;
00893 
00894   if (!pdf_font_is_in_use(font))
00895     return  0;
00896 
00897   verbose = pdf_font_get_verbose();
00898 
00899   fp = DPXFOPEN(ident, DPX_RES_TYPE_TTFONT);
00900   if (!fp) {
00901     fp = DPXFOPEN(ident, DPX_RES_TYPE_DFONT);
00902     if (!fp) ERROR("Unable to open TrueType/dfont font file: %s", ident); /* Should find *truetype* here */
00903     sfont = dfont_open(fp, index);
00904   } else {
00905     sfont = sfnt_open(fp);
00906   }
00907 
00908   if (!sfont) {
00909     ERROR("Unable to open TrueType/dfont file: %s", ident);
00910     DPXFCLOSE(fp);
00911     return  -1;
00912   } else if (sfont->type != SFNT_TYPE_TRUETYPE &&
00913              sfont->type != SFNT_TYPE_TTC &&
00914              sfont->type != SFNT_TYPE_DFONT) { 
00915     ERROR("Font \"%s\" not a TrueType/dfont font?", ident);
00916     sfnt_close(sfont);
00917     DPXFCLOSE(fp);
00918     return  -1;
00919   }
00920 
00921   if (sfont->type == SFNT_TYPE_TTC) {
00922     unsigned long offset;
00923     offset = ttc_read_offset(sfont, index);
00924     if (offset == 0) ERROR("Invalid TTC index in %s.", ident);
00925     error = sfnt_read_table_directory(sfont, ttc_read_offset(sfont, offset));
00926   } else {
00927     error = sfnt_read_table_directory(sfont, sfont->offset);
00928   }
00929 
00930   if (error) {
00931     ERROR("Reading SFND table dir failed for font-file=\"%s\"... Not a TrueType font?", ident);
00932     sfnt_close(sfont);
00933     DPXFCLOSE(fp);
00934     return  -1;
00935   }
00936 
00937   /*
00938    * Create new TrueType cmap table with MacRoman encoding.
00939    */
00940   if (encoding_id < 0)
00941     error = do_builtin_encoding(font, usedchars, sfont);
00942   else {
00943     enc_vec  = pdf_encoding_get_encoding(encoding_id);
00944     error = do_custom_encoding(font, enc_vec, usedchars, sfont);
00945   }
00946   if (error) {
00947     ERROR("Error occured while creating font subfont for \"%s\"", ident);
00948     sfnt_close(sfont);
00949     DPXFCLOSE(fp);
00950     return  -1;
00951   }
00952 
00953 #if  ENABLE_NOEMBED
00954   if (!embedding) {
00955     sfnt_close(sfont);
00956     DPXFCLOSE(fp);
00957     return  0;
00958   }
00959 #endif /* ENABLE_NOEMBED */
00960 
00961   /*
00962    * TODO: post table?
00963    */
00964 
00965   for (i = 0; required_table[i].name != NULL; i++) {
00966     if (sfnt_require_table(sfont,
00967                            required_table[i].name,
00968                            required_table[i].must_exist) < 0) {
00969       ERROR("Required TrueType table \"%s\" does not exist in font: %s",
00970             required_table[i].name, ident);
00971       sfnt_close(sfont);
00972       DPXFCLOSE(fp);
00973       return  -1;
00974     }
00975   }
00976 
00977   /*
00978    * FontFile2
00979    */
00980   fontfile = sfnt_create_FontFile_stream(sfont);
00981   if (!fontfile)
00982     ERROR("Could not created FontFile stream for \"%s\".", ident);
00983 
00984   sfnt_close(sfont);
00985   DPXFCLOSE(fp);
00986 
00987   if (verbose > 1)
00988     MESG("[%ld bytes]", pdf_stream_length(fontfile));
00989 
00990   pdf_add_dict(descriptor,
00991                pdf_new_name("FontFile2"), pdf_ref_obj(fontfile)); /* XXX */
00992   pdf_release_obj(fontfile);
00993 
00994   return  0;
00995 }