There's no need to reset the font every line if it hasn't changed. This saves
[sgt/halibut] / bk_pdf.c
index bd705eb..0a36ad9 100644 (file)
--- a/bk_pdf.c
+++ b/bk_pdf.c
@@ -38,6 +38,9 @@ static void pdf_string(void (*add)(object *, char const *),
 static void pdf_string_len(void (*add)(object *, char const *),
                           object *, char const *, int);
 static void objref(object *o, object *dest);
+static char *pdf_outline_convert(wchar_t *s, int *len);
+
+static int is_std_font(char const *name);
 
 static void make_pages_node(object *node, object *parent, page_data *first,
                            page_data *last, object *resources,
@@ -57,7 +60,7 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords,
     char *filename;
     paragraph *p;
     objlist olist;
-    object *o, *cat, *outlines, *pages, *resources, *mediabox;
+    object *o, *info, *cat, *outlines, *pages, *resources, *mediabox;
     int fileoff;
 
     IGNORE(keywords);
@@ -76,6 +79,29 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords,
     olist.head = olist.tail = NULL;
     olist.number = 1;
 
+    {
+       char buf[256];
+
+       info = new_object(&olist);
+       objtext(info, "<<\n");
+       if (doc->n_outline_elements > 0) {
+           char *title;
+           int titlelen;
+
+           title =
+              pdf_outline_convert(doc->outline_elements->pdata->outline_title,
+                                       &titlelen);
+           objtext(info, "/Title ");
+           pdf_string_len(objtext, info, title, titlelen);
+           sfree(title);
+           objtext(info, "\n");
+       }
+       objtext(info, "/Producer ");
+       sprintf(buf, "Halibut, %s", version);
+       pdf_string(objtext, info, buf);
+       objtext(info, "\n>>\n");
+    }
+
     cat = new_object(&olist);
     if (doc->n_outline_elements > 0)
        outlines = new_object(&olist);
@@ -124,7 +150,7 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords,
        objtext(font, "<<\n/Type /Font\n/Subtype /Type1\n/Name /");
        objtext(font, fe->name);
        objtext(font, "\n/BaseFont /");
-       objtext(font, fe->font->name);
+       objtext(font, fe->font->info->name);
        objtext(font, "\n/Encoding <<\n/Type /Encoding\n/Differences [");
 
        for (i = 0; i < 256; i++) {
@@ -138,26 +164,87 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords,
 
        objtext(font, "\n]\n>>\n");
 
-       {
+#define FF_FIXEDPITCH  0x00000001
+#define FF_SERIF       0x00000002
+#define FF_SYMBOLIC    0x00000004
+#define FF_SCRIPT      0x00000008
+#define FF_NONSYMBOLIC 0x00000020
+#define FF_ITALIC      0x00000040
+#define FF_ALLCAP      0x00010000
+#define FF_SMALLCAP    0x00020000
+#define FF_FORCEBOLD   0x00040000
+
+       if (!is_std_font(fe->font->info->name)){
            object *widths = new_object(&olist);
-           objtext(font, "/FirstChar 0\n/LastChar 255\n/Widths ");
+           object *fontdesc = new_object(&olist);
+           int firstchar = -1, lastchar = -1;
+           char buf[80];
+           font_info const *fi = fe->font->info;
+           int flags;
+           for (i = 0; i < 256; i++)
+               if (fe->indices[i] >= 0) {
+                   if (firstchar < 0) firstchar = i;
+                   lastchar = i;
+               }
+           sprintf(buf, "/FirstChar %d\n/LastChar %d\n/Widths ",
+                   firstchar, lastchar);
+           objtext(font, buf);
            objref(font, widths);
            objtext(font, "\n");
            objtext(widths, "[\n");
-           for (i = 0; i < 256; i++) {
-               char buf[80];
+           for (i = firstchar; i <= lastchar; i++) {
                double width;
                if (fe->indices[i] < 0)
                    width = 0.0;
                else
-                   width = fe->font->widths[fe->indices[i]];
+                   width = fi->widths[fe->indices[i]];
                sprintf(buf, "%g\n", 1000.0 * width / FUNITS_PER_PT);
                objtext(widths, buf);
            }
            objtext(widths, "]\n");
+           objtext(font, "/FontDescriptor ");
+           objref(font, fontdesc);
+           objtext(fontdesc, "<<\n/Type /FontDescriptor\n/Name /");
+           objtext(fontdesc, fi->name);
+           flags = 0;
+           if (fi->italicangle) flags |= FF_ITALIC;
+           flags |= FF_NONSYMBOLIC;
+           sprintf(buf, "\n/Flags %d\n", flags);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/FontBBox [%g %g %g %g]\n", fi->fontbbox[0],
+                   fi->fontbbox[1], fi->fontbbox[2], fi->fontbbox[3]);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/ItalicAngle %g\n", fi->italicangle);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/Ascent %g\n", fi->ascent);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/Descent %g\n", fi->descent);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/CapHeight %g\n", fi->capheight);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/XHeight %g\n", fi->xheight);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/StemH %g\n", fi->stemh);
+           objtext(fontdesc, buf);
+           sprintf(buf, "/StemV %g\n", fi->stemv);
+           objtext(fontdesc, buf);
+           if (fi->fp) {
+               object *fontfile = new_object(&olist);
+               char buf[513];
+               size_t len;
+               rewind(fi->fp);
+               do {
+                   len = fread(buf, 1, sizeof(buf)-1, fi->fp);
+                   buf[len] = 0;
+                   objstream(fontfile, buf);
+               } while (len == sizeof(buf)-1);
+               objtext(fontdesc, "/FontFile ");
+               objref(fontdesc, fontfile);
+           }
+           objtext(fontdesc, "\n>>\n");
        }
 
-       objtext(font, ">>\n");
+       objtext(font, "\n>>\n");
     }
     objtext(resources, ">>\n>>\n");
 
@@ -463,8 +550,8 @@ void pdf_backend(paragraph *sourceform, keywordlist *keywords,
     /*
      * Trailer
      */
-    fprintf(fp, "trailer\n<<\n/Size %d\n/Root %d 0 R\n>>\n",
-           olist.tail->number + 1, cat->number);
+    fprintf(fp, "trailer\n<<\n/Size %d\n/Root %d 0 R\n/Info %d 0 R\n>>\n",
+           olist.tail->number + 1, cat->number, info->number);
     fprintf(fp, "startxref\n%d\n%%%%EOF\n", fileoff);
 
     fclose(fp);
@@ -515,6 +602,21 @@ static void objref(object *o, object *dest)
     rdaddsc(&o->main, buf);
 }
 
+static char const * const stdfonts[] = {
+    "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
+    "Helvetica", "Helvetica-Bold", "Helvetica-Oblique","Helvetica-BoldOblique",
+    "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
+    "Symbol", "ZapfDingbats"
+};
+
+static int is_std_font(char const *name) {
+    unsigned i;
+    for (i = 0; i < lenof(stdfonts); i++)
+       if (strcmp(name, stdfonts[i]) == 0)
+           return TRUE;
+    return FALSE;
+}
+
 static void make_pages_node(object *node, object *parent, page_data *first,
                            page_data *last, object *resources,
                            object *mediabox)
@@ -665,6 +767,7 @@ static int make_outline(object *parent, outline_element *items, int n,
        last = curr;
        objtext(curr, "<<\n/Title ");
        pdf_string_len(objtext, curr, title, titlelen);
+       sfree(title);
        objtext(curr, "\n/Parent ");
        objref(curr, parent);
        objtext(curr, "\n/Dest [");