summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/font/writefont.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/font/writefont.w')
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writefont.w1010
1 files changed, 1010 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/font/writefont.w b/Build/source/texk/web2c/luatexdir/font/writefont.w
new file mode 100644
index 00000000000..523cae59740
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/font/writefont.w
@@ -0,0 +1,1010 @@
+% writefont.w
+
+% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
+% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
+
+% This file is part of LuaTeX.
+
+% LuaTeX 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 of the License, or (at your
+% option) any later version.
+
+% LuaTeX 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 Lesser General Public
+% License for more details.
+
+% You should have received a copy of the GNU General Public License along
+% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+@ @c
+static const char _svn_version[] =
+ "$Id: writefont.w 3584 2010-04-02 17:45:55Z hhenkel $ "
+"$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/font/writefont.w $";
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f);
+static void create_cid_fontdictionary(PDF pdf, internal_font_number f);
+
+const key_entry font_key[FONT_KEYS_NUM] = {
+ {"Ascent", "Ascender", 1}
+ , {"CapHeight", "CapHeight", 1}
+ , {"Descent", "Descender", 1}
+ , {"ItalicAngle", "ItalicAngle", 1}
+ , {"StemV", "StdVW", 1}
+ , {"XHeight", "XHeight", 1}
+ , {"FontBBox", "FontBBox", 1}
+ , {"", "", 0}
+ , {"", "", 0}
+ , {"", "", 0}
+ , {"FontName", "FontName", 1}
+};
+
+@
+@c
+struct avl_table *fo_tree = NULL; /* tree of font dictionaries */
+struct avl_table *fd_tree = NULL; /* tree of font descriptor objects */
+
+static int comp_fo_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp(((const fo_entry *) pa)->fm->tfm_name,
+ ((const fo_entry *) pb)->fm->tfm_name);
+}
+
+static int comp_fd_entry(const void *pa, const void *pb, void *p)
+{
+ const fd_entry *p1 = (const fd_entry *) pa, *p2 = (const fd_entry *) pb;
+ (void) p;
+ assert(p1->fm != NULL && is_fontfile(p1->fm) &&
+ p2->fm != NULL && is_fontfile(p2->fm));
+ return strcmp(p1->fm->ff_name, p2->fm->ff_name);
+}
+
+@ initialize data structure for /Type /Font
+@c
+fo_entry *new_fo_entry(void)
+{
+ fo_entry *fo;
+ fo = xtalloc(1, fo_entry);
+ fo->fo_objnum = 0;
+ fo->tex_font = 0;
+ fo->fm = NULL;
+ fo->fd = NULL;
+ fo->fe = NULL;
+ fo->cw_objnum = 0;
+ fo->first_char = 1;
+ fo->last_char = 0;
+ fo->tx_tree = NULL;
+ fo->tounicode_objnum = 0;
+ return fo;
+}
+
+@ initialize data structure for /Type /FontDescriptor
+@c
+fd_entry *new_fd_entry(void)
+{
+ fd_entry *fd;
+ int i;
+ fd = xtalloc(1, fd_entry);
+ fd->fd_objnum = 0;
+ fd->fontname = NULL;
+ fd->subset_tag = NULL;
+ fd->ff_found = false;
+ fd->ff_objnum = 0;
+ fd->all_glyphs = false;
+ fd->write_ttf_glyph_names = false;
+ for (i = 0; i < FONT_KEYS_NUM; i++) {
+ fd->font_dim[i].val = 0;
+ fd->font_dim[i].set = false;
+ }
+ fd->fe = NULL;
+ fd->builtin_glyph_names = NULL;
+ fd->fm = NULL;
+ fd->tx_tree = NULL;
+ fd->gl_tree = NULL;
+ return fd;
+}
+
+@
+Only fallback values of font metrics are taken from the TFM info
+of |f| by |preset_fontmetrics|. During reading of the font file,
+these values are replaced by metrics from the font, if available.
+
+@c
+static void preset_fontmetrics(fd_entry * fd, internal_font_number f)
+{
+ int i;
+ fd->font_dim[ITALIC_ANGLE_CODE].val = 0;
+ fd->font_dim[ASCENT_CODE].val =
+ divide_scaled(char_height(f, 'h'), font_size(f), 3);
+ fd->font_dim[CAPHEIGHT_CODE].val =
+ divide_scaled(char_height(f, 'H'), font_size(f), 3);
+ i = -divide_scaled(char_depth(f, 'y'), font_size(f), 3);
+ fd->font_dim[DESCENT_CODE].val = i < 0 ? i : 0;
+ fd->font_dim[STEMV_CODE].val =
+ divide_scaled(char_width(f, '.') / 3, font_size(f), 3);
+ fd->font_dim[XHEIGHT_CODE].val =
+ divide_scaled(get_x_height(f), font_size(f), 3);
+ fd->font_dim[FONTBBOX1_CODE].val = 0;
+ fd->font_dim[FONTBBOX2_CODE].val = fd->font_dim[DESCENT_CODE].val;
+ fd->font_dim[FONTBBOX3_CODE].val =
+ divide_scaled(get_quad(f), font_size(f), 3);
+ fd->font_dim[FONTBBOX4_CODE].val =
+ fd->font_dim[CAPHEIGHT_CODE].val > fd->font_dim[ASCENT_CODE].val ?
+ fd->font_dim[CAPHEIGHT_CODE].val : fd->font_dim[ASCENT_CODE].val;
+ for (i = 0; i < INT_KEYS_NUM; i++)
+ fd->font_dim[i].set = true;
+}
+
+static void fix_fontmetrics(fd_entry * fd)
+{
+ int i;
+ intparm *p = (intparm *) fd->font_dim;
+ assert(p[FONTBBOX1_CODE].set && p[FONTBBOX2_CODE].set
+ && p[FONTBBOX3_CODE].set && p[FONTBBOX4_CODE].set);
+ /* make sure there is a rectangle */
+ if (p[FONTBBOX3_CODE].val < p[FONTBBOX1_CODE].val) {
+ i = p[FONTBBOX3_CODE].val;
+ p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val;
+ p[FONTBBOX1_CODE].val = i;
+ } else if (p[FONTBBOX3_CODE].val == p[FONTBBOX1_CODE].val)
+ p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val + 1;
+ if (p[FONTBBOX4_CODE].val < p[FONTBBOX2_CODE].val) {
+ i = p[FONTBBOX4_CODE].val;
+ p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val;
+ p[FONTBBOX2_CODE].val = i;
+ } else if (p[FONTBBOX4_CODE].val == p[FONTBBOX2_CODE].val)
+ p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val + 1;
+ if (!p[ASCENT_CODE].set) {
+ p[ASCENT_CODE].val = p[FONTBBOX4_CODE].val;
+ p[ASCENT_CODE].set = true;
+ }
+ if (!p[DESCENT_CODE].set) {
+ p[DESCENT_CODE].val = p[FONTBBOX2_CODE].val;
+ p[DESCENT_CODE].set = true;
+ }
+ if (!p[CAPHEIGHT_CODE].set) {
+ p[CAPHEIGHT_CODE].val = p[FONTBBOX4_CODE].val;
+ p[CAPHEIGHT_CODE].set = true;
+ }
+}
+
+static void write_fontmetrics(PDF pdf, fd_entry * fd)
+{
+ int i;
+ fix_fontmetrics(fd);
+ pdf_printf(pdf, "/%s [%i %i %i %i]\n", font_key[FONTBBOX1_CODE].pdfname,
+ (int) fd->font_dim[FONTBBOX1_CODE].val,
+ (int) fd->font_dim[FONTBBOX2_CODE].val,
+ (int) fd->font_dim[FONTBBOX3_CODE].val,
+ (int) fd->font_dim[FONTBBOX4_CODE].val);
+ for (i = 0; i < GEN_KEY_NUM; i++)
+ if (fd->font_dim[i].set)
+ pdf_printf(pdf, "/%s %i\n", font_key[i].pdfname,
+ fd->font_dim[i].val);
+}
+
+@
+@c
+static void preset_fontname(fo_entry * fo, internal_font_number f)
+{
+ if (fo->fm->ps_name != NULL)
+ fo->fd->fontname = xstrdup(fo->fm->ps_name); /* just fallback */
+ else if (font_fullname(f) != NULL)
+ fo->fd->fontname = xstrdup(font_fullname(f));
+ else
+ fo->fd->fontname = xstrdup(fo->fm->tfm_name);
+}
+
+static void write_fontname(PDF pdf, fd_entry * fd, const char *key)
+{
+ assert(fd->fontname != NULL);
+ pdf_puts(pdf, "/");
+ if (key != NULL)
+ pdf_printf(pdf, "%s /", key);
+ if (fd->subset_tag != NULL)
+ pdf_printf(pdf, "%s+", fd->subset_tag);
+ pdf_printf(pdf, "%s\n", fd->fontname);
+}
+
+@
+@c
+fd_entry *lookup_fd_entry(char *s)
+{
+ fd_entry fd;
+ fm_entry fm;
+ assert(s != NULL);
+ fm.ff_name = s;
+ fd.fm = &fm;
+ if (fd_tree == NULL) {
+ fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
+ assert(fd_tree != NULL);
+ }
+ return (fd_entry *) avl_find(fd_tree, &fd);
+}
+
+fd_entry *lookup_fontdescriptor(fo_entry * fo)
+{
+ assert(fo != NULL);
+ assert(fo->fm != NULL);
+ assert(is_fontfile(fo->fm));
+ return lookup_fd_entry(fo->fm->ff_name);
+}
+
+void register_fd_entry(fd_entry * fd)
+{
+ void **aa;
+ if (fd_tree == NULL) {
+ fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
+ assert(fd_tree != NULL);
+ }
+ assert(fd != NULL && fd->fm != NULL && is_fontfile(fd->fm));
+ assert(lookup_fd_entry(fd->fm->ff_name) == NULL); /* font descriptor not yet registered */
+ aa = avl_probe(fd_tree, fd);
+ assert(aa != NULL);
+}
+
+void create_fontdescriptor(fo_entry * fo, internal_font_number f)
+{
+ assert(fo != NULL);
+ assert(fo->fm != NULL);
+ assert(fo->fd == NULL);
+ fo->fd = new_fd_entry();
+ preset_fontname(fo, f);
+ preset_fontmetrics(fo->fd, f);
+ fo->fd->fe = fo->fe; /* encoding needed by TrueType writing */
+ fo->fd->fm = fo->fm; /* map entry needed by TrueType writing */
+ fo->fd->gl_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
+ assert(fo->fd->gl_tree != NULL);
+}
+
+@
+For all used characters of \TeX font |f|, get corresponding glyph names
+from external reencoding (.enc) file and collect these in the glyph
+tree |gl_tree| of font descriptor |fd| referenced by font dictionary |fo|.
+
+@c
+void mark_reenc_glyphs(fo_entry * fo, internal_font_number f)
+{
+ int i;
+ char **g;
+ void **aa;
+ assert(fo->fe != NULL);
+ if (is_subsetted(fo->fm)) {
+ assert(is_included(fo->fm));
+ /* mark glyphs from TeX (externally reencoded characters) */
+ g = fo->fe->glyph_names;
+ for (i = fo->first_char; i <= fo->last_char; i++) {
+ if (pdf_char_marked(f, i) && g[i] != notdef
+ && (char *) avl_find(fo->fd->gl_tree, g[i]) == NULL) {
+ aa = avl_probe(fo->fd->gl_tree, xstrdup(g[i]));
+ assert(aa != NULL);
+ }
+ }
+ }
+}
+
+@
+Function |mark_chars| has 2 uses:
+\item 1. Mark characters as chars on \TeX\ level.
+\item 2. Mark encoding pairs used by \TeX\ to optimize encoding vector.
+
+@c
+struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree,
+ internal_font_number f)
+{
+ int i, *j;
+ void **aa;
+ if (tx_tree == NULL) {
+ tx_tree = avl_create(comp_int_entry, NULL, &avl_xallocator);
+ assert(tx_tree != NULL);
+ }
+ for (i = fo->first_char; i <= fo->last_char; i++) {
+ if (pdf_char_marked(f, i) && (int *) avl_find(tx_tree, &i) == NULL) {
+ j = xtalloc(1, int);
+ *j = i;
+ aa = avl_probe(tx_tree, j);
+ assert(aa != NULL);
+ }
+ }
+ return tx_tree;
+}
+
+@
+@c
+void get_char_range(fo_entry * fo, internal_font_number f)
+{
+ int i;
+ assert(fo != NULL);
+ for (i = font_bc(f); i <= font_ec(f); i++) /* search for |first_char| and |last_char| */
+ if (pdf_char_marked(f, i))
+ break;
+ fo->first_char = i;
+ for (i = font_ec(f); i >= font_bc(f); i--)
+ if (pdf_char_marked(f, i))
+ break;
+ fo->last_char = i;
+ if ((fo->first_char > fo->last_char)
+ || !pdf_char_marked(f, fo->first_char)) { /* no character used from this font */
+ fo->last_char = 0;
+ fo->first_char = fo->last_char + 1;
+ }
+}
+
+static int font_has_subset(internal_font_number f)
+{
+ int i, s;
+ for (i = font_bc(f); i <= font_ec(f); i++) /* search for |first_char| and |last_char| */
+ if (pdf_char_marked(f, i))
+ break;
+ s = i;
+ for (i = font_ec(f); i >= font_bc(f); i--)
+ if (pdf_char_marked(f, i))
+ break;
+ if (s > i)
+ return 0;
+ else
+ return 1;
+}
+
+@
+@c
+static void write_charwidth_array(PDF pdf, fo_entry * fo,
+ internal_font_number f)
+{
+ int i, j, *ip, *fip;
+ struct avl_traverser t;
+ assert(fo->tx_tree != NULL);
+ assert(fo->cw_objnum == 0);
+ fo->cw_objnum = pdf_new_objnum(pdf);
+ pdf_begin_obj(pdf, fo->cw_objnum, 1);
+ avl_t_init(&t, fo->tx_tree);
+ fip = (int *) avl_t_first(&t, fo->tx_tree);
+ assert(fip != NULL);
+ pdf_puts(pdf, "[");
+ for (ip = fip, j = *ip; ip != NULL; ip = (int *) avl_t_next(&t)) {
+ if (ip != fip)
+ pdf_puts(pdf, " ");
+ i = *ip;
+ while (j < i - 1) {
+ pdf_puts(pdf, "0 ");
+ j++;
+ }
+ j = i;
+ pdf_print_charwidth(pdf, f, i);
+ }
+ pdf_puts(pdf, "]\n");
+ pdf_end_obj(pdf);
+}
+
+@ Remark: Font objects from embedded PDF files are never registered
+into |fo_tree|; they are individually written out.
+@c
+fo_entry *lookup_fo_entry(char *s)
+{
+ fo_entry fo;
+ fm_entry fm;
+ assert(s != NULL);
+ fm.tfm_name = s;
+ fo.fm = &fm;
+ if (fo_tree == NULL) {
+ fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
+ assert(fo_tree != NULL);
+ }
+ return (fo_entry *) avl_find(fo_tree, &fo);
+}
+
+void register_fo_entry(fo_entry * fo)
+{
+ void **aa;
+ if (fo_tree == NULL) {
+ fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
+ assert(fo_tree != NULL);
+ }
+ assert(fo != NULL);
+ assert(fo->fm != NULL);
+ assert(fo->fm->tfm_name != NULL);
+ assert(lookup_fo_entry(fo->fm->tfm_name) == NULL);
+ aa = avl_probe(fo_tree, fo);
+ assert(aa != NULL);
+}
+
+@
+@c
+static void write_fontfile(PDF pdf, fd_entry * fd)
+{
+ assert(is_included(fd->fm));
+ if (is_cidkeyed(fd->fm)) {
+ if (is_opentype(fd->fm))
+ writetype0(pdf, fd);
+ else if (is_truetype(fd->fm))
+ writetype2(pdf, fd);
+ else if (is_type1(fd->fm))
+ writetype1w(pdf, fd);
+ else
+ assert(0);
+ } else {
+ if (is_type1(fd->fm))
+ writet1(pdf, fd);
+ else if (is_truetype(fd->fm))
+ writettf(pdf, fd);
+ else if (is_opentype(fd->fm))
+ writeotf(pdf, fd);
+ else
+ assert(0);
+ }
+ if (!fd->ff_found)
+ return;
+ assert(fd->ff_objnum == 0);
+ fd->ff_objnum = pdf_new_objnum(pdf);
+ pdf_begin_dict(pdf, fd->ff_objnum, 0); /* font file stream */
+ if (is_cidkeyed(fd->fm)) {
+ /* No subtype is used for TrueType-based OpenType fonts */
+ if (is_opentype(fd->fm) || is_type1(fd->fm))
+ pdf_puts(pdf, "/Subtype /CIDFontType0C\n");
+#if 0
+ else
+ pdf_puts(pdf,"/Subtype /OpenType\n");
+#endif
+ } else {
+ if (is_type1(fd->fm))
+ pdf_printf(pdf, "/Length1 %i\n/Length2 %i\n/Length3 %i\n",
+ (int) t1_length1, (int) t1_length2, (int) t1_length3);
+ else if (is_truetype(fd->fm))
+ pdf_printf(pdf, "/Length1 %i\n", (int) ttf_length);
+ else if (is_opentype(fd->fm))
+ pdf_puts(pdf, "/Subtype /Type1C\n");
+ else
+ assert(0);
+ }
+ pdf_begin_stream(pdf);
+ fb_flush(pdf);
+ pdf_end_stream(pdf);
+}
+
+@
+@c
+static void write_fontdescriptor(PDF pdf, fd_entry * fd)
+{
+ static const int std_flags[] = {
+ /* indices for << start with 0, but bits start with 1, so the numbers
+ * for << are 1 lower than the bits in table 5.20 */
+ /* *INDENT-OFF* */
+ 1 + 2 + (1 << 5), /* Courier */
+ 1 + 2 + (1 << 5) + (1 << 18),/* Courier-Bold */
+ 1 + 2 + (1 << 5) + (1 << 6), /* Courier-Oblique */
+ 1 + 2 + (1 << 5) + (1 << 6) + (1 << 18),/* Courier-BoldOblique */
+ (1 << 5), /* Helvetica */
+ (1 << 5) + (1 << 18),/* Helvetica-Bold */
+ (1 << 5) + (1 << 6), /* Helvetica-Oblique */
+ (1 << 5) + (1 << 6) + (1 << 18),/* Helvetica-BoldOblique */
+ 4, /* Symbol */
+ 2 + (1 << 5), /* Times-Roman */
+ 2 + (1 << 5) + (1 << 18),/* Times-Bold */
+ 2 + (1 << 5) + (1 << 6), /* Times-Italic */
+ 2 + (1 << 5) + (1 << 6) + (1 << 18),/* Times-BoldItalic */
+ 4 /* ZapfDingbats */
+ /* *INDENT-ON* */
+ };
+ char *glyph;
+ struct avl_traverser t;
+ int fd_flags;
+ assert(fd != NULL && fd->fm != NULL);
+
+ if (is_fontfile(fd->fm) && is_included(fd->fm))
+ write_fontfile(pdf, fd); /* this will set |fd->ff_found| if font file is found */
+ if (fd->fd_objnum == 0)
+ fd->fd_objnum = pdf_new_objnum(pdf);
+ pdf_begin_dict(pdf, fd->fd_objnum, 1);
+ pdf_puts(pdf, "/Type /FontDescriptor\n");
+ write_fontname(pdf, fd, "FontName");
+ if (fd->fm->fd_flags != FD_FLAGS_NOT_SET_IN_MAPLINE)
+ fd_flags = (int) fd->fm->fd_flags;
+ else if (fd->ff_found)
+ fd_flags = FD_FLAGS_DEFAULT_EMBED;
+ else {
+ fd_flags = is_std_t1font(fd->fm)
+ ? std_flags[check_std_t1font(fd->fm->ps_name)]
+ : FD_FLAGS_DEFAULT_NON_EMBED;
+ pdftex_warn
+ ("No flags specified for non-embedded font `%s' (%s) (I'm using %i): "
+ "fix your map entry.",
+ fd->fm->ps_name != NULL ? fd->fm->ps_name : "No name given",
+ fd->fm->tfm_name, fd_flags);
+ }
+ pdf_printf(pdf, "/Flags %i\n", fd_flags);
+ write_fontmetrics(pdf, fd);
+ if (is_cidkeyed(fd->fm)) {
+ if (is_type1(fd->fm))
+ pdf_printf(pdf, "/FontFile3 %i 0 R\n", (int) fd->ff_objnum);
+ else if (is_truetype(fd->fm))
+ pdf_printf(pdf, "/FontFile2 %i 0 R\n", (int) fd->ff_objnum);
+ else if (is_opentype(fd->fm))
+ pdf_printf(pdf, "/FontFile3 %i 0 R\n", (int) fd->ff_objnum);
+ else
+ assert(0);
+ } else {
+ if (fd->ff_found) {
+ if (is_subsetted(fd->fm) && is_type1(fd->fm)) {
+ /* /CharSet is optional; names may appear in any order */
+ assert(fd->gl_tree != NULL);
+ avl_t_init(&t, fd->gl_tree);
+ pdf_puts(pdf, "/CharSet (");
+ for (glyph = (char *) avl_t_first(&t, fd->gl_tree);
+ glyph != NULL; glyph = (char *) avl_t_next(&t))
+ pdf_printf(pdf, "/%s", glyph);
+ pdf_puts(pdf, ")\n");
+ }
+ if (is_type1(fd->fm))
+ pdf_printf(pdf, "/FontFile %i 0 R\n", (int) fd->ff_objnum);
+ else if (is_truetype(fd->fm))
+ pdf_printf(pdf, "/FontFile2 %i 0 R\n", (int) fd->ff_objnum);
+ else if (is_opentype(fd->fm))
+ pdf_printf(pdf, "/FontFile3 %i 0 R\n", (int) fd->ff_objnum);
+ else
+ assert(0);
+ }
+ }
+ /* TODO: Optional keys for CID fonts.
+
+ The most interesting ones are
+ \.{/Style << /Panose <12-byte string>>>}
+ and
+ \.{/CIDSET <stream>}
+ the latter can be used in subsets, to give the included CIDs
+ as a bitmap on the whole list.
+ */
+ pdf_end_dict(pdf);
+}
+
+void write_fontdescriptors(PDF pdf)
+{
+ fd_entry *fd;
+ struct avl_traverser t;
+ if (fd_tree == NULL)
+ return;
+ avl_t_init(&t, fd_tree);
+ for (fd = (fd_entry *) avl_t_first(&t, fd_tree); fd != NULL;
+ fd = (fd_entry *) avl_t_next(&t))
+ write_fontdescriptor(pdf, fd);
+}
+
+@
+@c
+void write_fontdictionary(PDF pdf, fo_entry * fo)
+{
+ assert(fo != NULL);
+ assert(fo->fm != NULL);
+ assert(fo->fo_objnum != 0); /* reserved as |pdf_font_num(f)| elsewhere */
+
+ /* write ToUnicode entry if needed */
+ if (pdf->gen_tounicode > 0 && fo->fd != NULL) {
+ if (fo->fe != NULL) {
+ fo->tounicode_objnum =
+ write_tounicode(pdf, fo->fe->glyph_names, fo->fe->name);
+ } else if (is_type1(fo->fm)) {
+ assert(fo->fd->builtin_glyph_names != NULL);
+ fo->tounicode_objnum =
+ write_tounicode(pdf, fo->fd->builtin_glyph_names,
+ fo->fm->tfm_name);
+ }
+ }
+ pdf_begin_dict(pdf, fo->fo_objnum, 1);
+ pdf_puts(pdf, "/Type /Font\n");
+ pdf_puts(pdf, "/Subtype /");
+ if (is_type1(fo->fm))
+ pdf_printf(pdf, "%s\n", "Type1");
+ else if (is_truetype(fo->fm))
+ pdf_printf(pdf, "%s\n", "TrueType");
+ else if (is_opentype(fo->fm))
+ pdf_printf(pdf, "%s\n", "Type1");
+ else
+ assert(0);
+ assert(fo->fd != NULL && fo->fd->fd_objnum != 0);
+ write_fontname(pdf, fo->fd, "BaseFont");
+ pdf_printf(pdf, "/FontDescriptor %i 0 R\n", (int) fo->fd->fd_objnum);
+ assert(fo->cw_objnum != 0);
+ pdf_printf(pdf, "/FirstChar %i\n/LastChar %i\n/Widths %i 0 R\n",
+ (int) fo->first_char, (int) fo->last_char, (int) fo->cw_objnum);
+ if ((is_type1(fo->fm) || is_opentype(fo->fm)) && fo->fe != NULL
+ && fo->fe->fe_objnum != 0)
+ pdf_printf(pdf, "/Encoding %i 0 R\n", (int) fo->fe->fe_objnum);
+ if (fo->tounicode_objnum != 0)
+ pdf_printf(pdf, "/ToUnicode %i 0 R\n", (int) fo->tounicode_objnum);
+ if (pdf_font_attr(fo->tex_font) != get_nullstr() &&
+ pdf_font_attr(fo->tex_font) != 0) {
+ pdf_print(pdf, pdf_font_attr(fo->tex_font));
+ pdf_puts(pdf, "\n");
+ }
+ pdf_end_dict(pdf);
+}
+
+void write_fontdictionaries(PDF pdf)
+{
+ fo_entry *fo;
+ struct avl_traverser t;
+ if (fo_tree == NULL)
+ return;
+ avl_t_init(&t, fo_tree);
+ for (fo = (fo_entry *) avl_t_first(&t, fo_tree); fo != NULL;
+ fo = (fo_entry *) avl_t_next(&t))
+ write_fontdictionary(pdf, fo);
+}
+
+@ Final flush of all font related stuff by call from
+ \.{Output fonts definitions} elsewhere
+
+@c
+void write_fontstuff(PDF pdf)
+{
+ write_fontdescriptors(pdf);
+ write_fontencodings(pdf); /* see \.{writeenc.w} */
+ write_fontdictionaries(pdf);
+}
+
+@
+@c
+static void create_fontdictionary(PDF pdf, internal_font_number f)
+{
+ fo_entry *fo = new_fo_entry();
+ fm_entry *fm = font_map(f);
+ get_char_range(fo, f); /* set |fo->first_char| and |fo->last_char| from |f| */
+ if (fo->last_char > 255)
+ fo->last_char = 255; /* added 9-4-2008, mantis \#25 */
+ assert(fo->last_char >= fo->first_char);
+ fo->fm = fm;
+ fo->fo_objnum = pdf_font_num(f);
+ fo->tex_font = f;
+ if (is_reencoded(fo->fm)) { /* at least the map entry tells so */
+ fo->fe = get_fe_entry(fo->fm->encname); /* returns |NULL| if .enc file couldn't be opened */
+ if (fo->fe != NULL && (is_type1(fo->fm) || is_opentype(fo->fm))) {
+ if (fo->fe->fe_objnum == 0)
+ fo->fe->fe_objnum = pdf_new_objnum(pdf); /* then it will be written out */
+ /* mark encoding pairs used by TeX to optimize encoding vector */
+ fo->fe->tx_tree = mark_chars(fo, fo->fe->tx_tree, f);
+ }
+ }
+ fo->tx_tree = mark_chars(fo, fo->tx_tree, f); /* for |write_charwidth_array| */
+ write_charwidth_array(pdf, fo, f);
+ if (!is_builtin(fo->fm)) {
+ if (is_type1(fo->fm)) {
+ if ((fo->fd = lookup_fontdescriptor(fo)) == NULL) {
+ create_fontdescriptor(fo, f);
+ register_fd_entry(fo->fd);
+ }
+ } else
+ create_fontdescriptor(fo, f);
+ if (fo->fe != NULL) {
+ mark_reenc_glyphs(fo, f);
+ if (!is_type1(fo->fm)) {
+ /* mark reencoded characters as chars on TeX level */
+ assert(fo->fd->tx_tree == NULL);
+ fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
+ if (is_truetype(fo->fm))
+ fo->fd->write_ttf_glyph_names = true;
+ }
+ } else
+ /* mark non-reencoded characters as chars on TeX level */
+ fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
+ if (!is_type1(fo->fm))
+ write_fontdescriptor(pdf, fo->fd);
+ } else {
+ /* builtin fonts still need the /Widths array and /FontDescriptor
+ * (to avoid error 'font FOO contains bad /BBox')
+ */
+ create_fontdescriptor(fo, f);
+ write_fontdescriptor(pdf, fo->fd);
+ if (!is_std_t1font(fo->fm))
+ pdftex_warn("font `%s' is not a standard font; "
+ "I suppose it is available to your PDF viewer then",
+ fo->fm->ps_name);
+ }
+ if (is_type1(fo->fm))
+ register_fo_entry(fo);
+ else
+ write_fontdictionary(pdf, fo);
+}
+
+@
+@c
+static int has_ttf_outlines(fm_entry * fm)
+{
+ FILE *f = fopen(fm->ff_name, "rb");
+ if (f != NULL) {
+ int ch1 = getc(f);
+ int ch2 = getc(f);
+ int ch3 = getc(f);
+ int ch4 = getc(f);
+ fclose(f);
+ if (ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O')
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+void do_pdf_font(PDF pdf, internal_font_number f)
+{
+ int del_file = 0;
+ fm_entry *fm;
+ /* TODO This is not 100\% true: CID is actually needed whenever (and
+ only) there are more than 256 separate glyphs used. But for
+ now, just assume the user knows what he is doing;
+ */
+ if (!font_has_subset(f))
+ return;
+
+ if (font_encodingbytes(f) == 2) {
+ /* Create a virtual font map entry, as this is needed by the
+ rest of the font inclusion mechanism.
+ */
+ fm = font_map(f) = new_fm_entry();
+ fm->tfm_name = font_name(f); /* or whatever, not a real tfm */
+ fm->ff_name = font_filename(f); /* the actual file */
+ if (font_psname(f) != NULL)
+ fm->ps_name = font_psname(f); /* the true name */
+ else
+ fm->ps_name = font_fullname(f); /* the true name */
+ if (fm->ff_name
+ && strlen(fm->ff_name) >= 6
+ && strstr(fm->ff_name,
+ ".dfont") == (fm->ff_name + strlen(fm->ff_name) - 6)) {
+ /* In case of a .dfont, we will extract the correct ttf here,
+ and adjust |fm->ff_name| to point to the temporary file.
+ This file will be deleted later. Todo: keep a nicer name
+ somewhere for the terminal message.
+ */
+ char *s = FindResourceTtfFont(fm->ff_name, fm->ps_name);
+ if (s != NULL) {
+ fm->ff_name = s;
+ del_file = 1;
+ } else {
+ pdftex_fail
+ ("writefont.c: The file (%s) does not contain font `%s'",
+ fm->ff_name, fm->ps_name);
+ }
+ }
+ fm->encname = font_encodingname(f); /* for the CIDSystemInfo */
+ fm->slant = font_slant(f); /* slant factor */
+ set_slantset(fm);
+ fm->extend = font_extend(f); /* extension factor */
+ set_extendset(fm);
+ fm->fd_flags = 4; /* can perhaps be done better */
+ set_inuse(fm);
+
+ switch (font_format(f)) {
+ case opentype_format:
+ if (has_ttf_outlines(fm)) {
+ set_truetype(fm);
+ } else {
+ set_opentype(fm);
+ }
+ break;
+ case truetype_format:
+ set_truetype(fm);
+ break;
+ case type1_format:
+ set_type1(fm);
+ break;
+ default:
+ pdftex_fail
+ ("writefont.c: The file format (%s) for font `%s' is incompatible with wide characters\n",
+ font_format_name(f), font_name(f));
+ }
+ /* This makes "unknown" default to subsetted inclusion */
+ if (font_embedding(f) != no_embedding) {
+ set_included(fm);
+ if (font_embedding(f) != full_embedding) {
+ set_subsetted(fm);
+ }
+ }
+ set_cidkeyed(fm);
+ create_cid_fontdictionary(pdf, f);
+
+ if (del_file)
+ unlink(fm->ff_name);
+
+ } else {
+ /* by now |font_map(f)|, if any, should have been set via |pdf_init_font()| */
+ if ((fm = font_map(f)) == NULL
+ || (fm->ps_name == NULL && fm->ff_name == NULL))
+ writet3(pdf, f);
+ else
+ create_fontdictionary(pdf, f);
+ }
+}
+
+@ The glyph width is included in |glw_entry|, because that width
+ depends on the value it has in the font where it is actually
+ typeset from, not the font that is the 'owner' of the fd entry.
+
+ TODO: It is possible that the user messes with the metric width,
+ but handling that properly would require access to the 'hmtx' table
+ at this point in the program.
+
+@c
+int comp_glw_entry(const void *pa, const void *pb, void *p
+ __attribute__ ((unused)))
+{
+ unsigned short i, j;
+
+ i = (unsigned short) (*(const glw_entry *) pa).id;
+ j = (unsigned short) (*(const glw_entry *) pb).id;
+ cmp_return(i, j);
+ return 0;
+}
+
+void create_cid_fontdescriptor(fo_entry * fo, internal_font_number f)
+{
+ assert(fo != NULL);
+ assert(fo->fm != NULL);
+ assert(fo->fd == NULL);
+ fo->fd = new_fd_entry();
+ preset_fontname(fo, f);
+ preset_fontmetrics(fo->fd, f);
+ fo->fd->fe = fo->fe; /* encoding needed by TrueType writing */
+ fo->fd->fm = fo->fm; /* map entry needed by TrueType writing */
+ fo->fd->gl_tree = avl_create(comp_glw_entry, NULL, &avl_xallocator);
+ assert(fo->fd->gl_tree != NULL);
+}
+
+
+@ The values |font_bc()| and |font_ec()| are potentially large
+ character ids, but the strings that are written out use CID
+ indexes, and those are limited to 16-bit values.
+
+@c
+static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
+{
+ int i, k, l;
+ glw_entry *j;
+ void *aa;
+ for (k = 1; k <= max_font_id(); k++) {
+ if (k == f || -f == pdf_font_num(k)) {
+ l = font_size(k);
+ for (i = font_bc(k); i <= font_ec(k); i++) {
+ if (quick_char_exists(k, i) && char_used(k, i)) {
+ j = xtalloc(1, glw_entry);
+ j->id = (unsigned) char_index(k, i);
+ j->wd = divide_scaled_n(char_width(k, i), l, 10000.0);
+ if ((glw_entry *) avl_find(fo->fd->gl_tree, j) == NULL) {
+ aa = avl_probe(fo->fd->gl_tree, j);
+ assert(aa != NULL);
+ } else {
+ xfree(j);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+@ It is possible to compress the widths array even better, by using the
+ alternate 'range' syntax and possibly even using /DW to set
+ a default value.
+
+ There is a some optimization here already: glyphs that are
+ not used do not appear in the widths array at all.
+
+ We have to make sure that we do not output an (incorrect!)
+ width for a character that exists in the font, but is not used
+ in typesetting. An enormous negative width is used as sentinel value
+
+@c
+static void write_cid_charwidth_array(PDF pdf, fo_entry * fo)
+{
+ int i, j;
+ glw_entry *glyph;
+ struct avl_traverser t;
+
+ assert(fo->cw_objnum == 0);
+ fo->cw_objnum = pdf_new_objnum(pdf);
+ pdf_begin_obj(pdf, fo->cw_objnum, 1);
+ avl_t_init(&t, fo->fd->gl_tree);
+ glyph = (glw_entry *) avl_t_first(&t, fo->fd->gl_tree);
+ assert(glyph != NULL);
+ i = (int) glyph->id;
+ pdf_printf(pdf, "[ %i [", i);
+ for (; glyph != NULL; glyph = (glw_entry *) avl_t_next(&t)) {
+ j = glyph->wd;
+ if (glyph->id > (unsigned) (i + 1)) {
+ pdf_printf(pdf, "] %i [", glyph->id);
+ j = glyph->wd;
+ }
+ if (glyph->id == (unsigned) (i + 1))
+ pdf_puts(pdf, " ");
+
+ if (j < 0) {
+ pdf_puts(pdf, "-");
+ j = -j;
+ }
+
+ pdf_printf(pdf, "%i", (j / 10));
+ if ((j % 10) != 0)
+ pdf_printf(pdf, ".%i", (j % 10));
+
+ i = (int) glyph->id;
+ }
+ pdf_puts(pdf, "]]\n");
+ pdf_end_obj(pdf);
+}
+
+static void create_cid_fontdictionary(PDF pdf, internal_font_number f)
+{
+ fm_entry *fm = font_map(f);
+ fo_entry *fo = new_fo_entry();
+ get_char_range(fo, f); /* set |fo->first_char| and |fo->last_char| from |f| */
+ assert(fo->last_char >= fo->first_char);
+ fo->fm = fm;
+ fo->fo_objnum = pdf_font_num(f);
+ fo->tex_font = f;
+ create_cid_fontdescriptor(fo, f);
+ mark_cid_subset_glyphs(fo, f);
+ if (is_subsetted(fo->fm)) {
+ /*
+ this is a bit sneaky. |make_subset_tag()| actually expects the glyph tree
+ to contain strings instead of |glw_entry| items. However, all calculations
+ are done using explicit typecasts, so it works out ok.
+ */
+ make_subset_tag(fo->fd);
+ }
+ write_cid_charwidth_array(pdf, fo);
+ write_fontdescriptor(pdf, fo->fd);
+
+ write_cid_fontdictionary(pdf, fo, f);
+ xfree(fo);
+}
+
+@ @c
+void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f)
+{
+ int i;
+
+ fo->tounicode_objnum = write_cid_tounicode(pdf, fo, f);
+
+ pdf_begin_dict(pdf, fo->fo_objnum, 1);
+ pdf_puts(pdf, "/Type /Font\n");
+ pdf_puts(pdf, "/Subtype /Type0\n");
+ pdf_puts(pdf, "/Encoding /Identity-H\n");
+ write_fontname(pdf, fo->fd, "BaseFont");
+ i = pdf_new_objnum(pdf);
+ pdf_printf(pdf, "/DescendantFonts [%i 0 R]\n", i);
+ /* todo: the ToUnicode CMap */
+ if (fo->tounicode_objnum != 0)
+ pdf_printf(pdf, "/ToUnicode %i 0 R\n", (int) fo->tounicode_objnum);
+
+ pdf_end_dict(pdf);
+
+ pdf_begin_dict(pdf, i, 1);
+ pdf_puts(pdf, "/Type /Font\n");
+ if (is_opentype(fo->fm) || is_type1(fo->fm)) {
+ pdf_puts(pdf, "/Subtype /CIDFontType0\n");
+ } else {
+ pdf_puts(pdf, "/Subtype /CIDFontType2\n");
+ pdf_printf(pdf, "/CIDToGIDMap /Identity\n");
+ }
+ write_fontname(pdf, fo->fd, "BaseFont");
+ pdf_printf(pdf, "/FontDescriptor %i 0 R\n", (int) fo->fd->fd_objnum);
+ pdf_printf(pdf, "/W %i 0 R\n", (int) fo->cw_objnum);
+ pdf_printf(pdf, "/CIDSystemInfo <<\n");
+ pdf_printf(pdf, "/Registry (%s)\n",
+ (font_cidregistry(f) ? font_cidregistry(f) : "Adobe"));
+ pdf_printf(pdf, "/Ordering (%s)\n",
+ (font_cidordering(f) ? font_cidordering(f) : "Identity"));
+ pdf_printf(pdf, "/Supplement %u\n", (unsigned int) font_cidsupplement(f));
+ pdf_printf(pdf, ">>\n");
+
+ /* I doubt there is anything useful that could be written here */
+#if 0
+ if (pdf_font_attr(fo->tex_font) != get_nullstr()) {
+ pdf_print(pdf_font_attr(fo->tex_font));
+ pdf_puts(pdf,"\n");
+ }
+#endif
+ pdf_end_dict(pdf);
+}