]> git.cameronkatri.com Git - mandoc.git/blobdiff - term_ps.c
Do not confuse .Bl -column lists that just broken another block
[mandoc.git] / term_ps.c
index e9c23e72a955a36ff75248cb06a3db6207437303..12ca7d67165c3698ebdb095b2bd1ff7961b6b6ba 100644 (file)
--- a/term_ps.c
+++ b/term_ps.c
@@ -1,7 +1,7 @@
-/*     $Id: term_ps.c,v 1.65 2014/08/24 23:43:13 schwarze Exp $ */
+/*     $Id: term_ps.c,v 1.72 2015/01/21 19:40:54 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
 #include <unistd.h>
 
-#include "mandoc.h"
 #include "mandoc_aux.h"
 #include "out.h"
-#include "main.h"
 #include "term.h"
+#include "main.h"
 
 /* These work the buffer used by the header and footer. */
 #define        PS_BUFSLOP        128
@@ -60,12 +58,14 @@ struct      termp_ps {
 #define        PS_INLINE        (1 << 0)       /* we're in a word */
 #define        PS_MARGINS       (1 << 1)       /* we're in the margins */
 #define        PS_NEWPAGE       (1 << 2)       /* new page, no words yet */
+#define        PS_BACKSP        (1 << 3)       /* last character was backspace */
        size_t            pscol;        /* visible column (AFM units) */
+       size_t            pscolnext;    /* used for overstrike */
        size_t            psrow;        /* visible row (AFM units) */
        char             *psmarg;       /* margin buf */
        size_t            psmargsz;     /* margin buf size */
        size_t            psmargcur;    /* cur index in margin buf */
-       char              last;         /* character buffer */
+       char              last;         /* last non-backspace seen */
        enum termfont     lastf;        /* last set font */
        enum termfont     nextf;        /* building next font here */
        size_t            scale;        /* font scaling factor */
@@ -106,7 +106,7 @@ static      void              ps_printf(struct termp *, const char *, ...);
 static void              ps_putchar(struct termp *, char);
 static void              ps_setfont(struct termp *, enum termfont);
 static void              ps_setwidth(struct termp *, int, size_t);
-static struct termp     *pspdf_alloc(char *);
+static struct termp     *pspdf_alloc(const struct mchars *, char *);
 static void              pdf_obj(struct termp *, size_t);
 
 /*
@@ -507,29 +507,29 @@ static    const struct font fonts[TERMFONT__MAX] = {
 };
 
 void *
-pdf_alloc(char *outopts)
+pdf_alloc(const struct mchars *mchars, char *outopts)
 {
        struct termp    *p;
 
-       if (NULL != (p = pspdf_alloc(outopts)))
+       if (NULL != (p = pspdf_alloc(mchars, outopts)))
                p->type = TERMTYPE_PDF;
 
        return(p);
 }
 
 void *
-ps_alloc(char *outopts)
+ps_alloc(const struct mchars *mchars, char *outopts)
 {
        struct termp    *p;
 
-       if (NULL != (p = pspdf_alloc(outopts)))
+       if (NULL != (p = pspdf_alloc(mchars, outopts)))
                p->type = TERMTYPE_PS;
 
        return(p);
 }
 
 static struct termp *
-pspdf_alloc(char *outopts)
+pspdf_alloc(const struct mchars *mchars, char *outopts)
 {
        struct termp    *p;
        unsigned int     pagex, pagey;
@@ -539,7 +539,11 @@ pspdf_alloc(char *outopts)
        char            *v;
 
        p = mandoc_calloc(1, sizeof(struct termp));
+       p->symtab = mchars;
        p->enc = TERMENC_ASCII;
+       p->fontq = mandoc_reallocarray(NULL,
+           (p->fontsz = 8), sizeof(enum termfont));
+       p->fontq[0] = p->fontl = TERMFONT_NONE;
        p->ps = mandoc_calloc(1, sizeof(struct termp_ps));
 
        p->advance = ps_advance;
@@ -634,12 +638,14 @@ ps_setwidth(struct termp *p, int iop, size_t width)
        size_t   lastwidth;
 
        lastwidth = p->ps->width;
-       if (0 < iop)
+       if (iop > 0)
                p->ps->width += width;
-       else if (0 > iop)
+       else if (iop == 0)
+               p->ps->width = width ? width : p->ps->lastwidth;
+       else if (p->ps->width > width)
                p->ps->width -= width;
        else
-               p->ps->width = width ? width : p->ps->lastwidth;
+               p->ps->width = 0;
        p->ps->lastwidth = lastwidth;
 }
 
@@ -852,7 +858,6 @@ ps_end(struct termp *p)
 static void
 ps_begin(struct termp *p)
 {
-       time_t           t;
        int              i;
 
        /*
@@ -893,11 +898,8 @@ ps_begin(struct termp *p)
         * stuff gets printed to the screen, so make sure we're sane.
         */
 
-       t = time(NULL);
-
        if (TERMTYPE_PS == p->type) {
                ps_printf(p, "%%!PS-Adobe-3.0\n");
-               ps_printf(p, "%%%%CreationDate: %s", ctime(&t));
                ps_printf(p, "%%%%DocumentData: Clean7Bit\n");
                ps_printf(p, "%%%%Orientation: Portrait\n");
                ps_printf(p, "%%%%Pages: (atend)\n");
@@ -1052,7 +1054,7 @@ ps_fclose(struct termp *p)
         */
 
        if (p->ps->last != '\0') {
-               assert(p->ps->last != 8);
+               assert( ! (p->ps->flags & PS_BACKSP));
                if (p->ps->nextf != p->ps->lastf) {
                        ps_pclose(p);
                        ps_setfont(p, p->ps->nextf);
@@ -1071,25 +1073,30 @@ ps_fclose(struct termp *p)
 static void
 ps_letter(struct termp *p, int arg)
 {
+       size_t          savecol, wx;
        char            c;
 
        c = arg >= 128 || arg <= 0 ? '?' : arg;
 
        /*
-        * When receiving an initial character, merely buffer it,
-        * because a backspace might follow to specify formatting.
-        * When receiving a backspace, use the buffered character
-        * to build the font instruction and clear the buffer.
-        * Only when there are two non-backspace characters in a row,
-        * activate the font built so far and print the first of them;
-        * the second, again, merely gets buffered.
-        * The final character will get printed from ps_fclose().
+        * When receiving a backspace, merely flag it.
+        * We don't know yet whether it is
+        * a font instruction or an overstrike.
         */
 
-       if (c == 8) {
+       if (c == '\b') {
                assert(p->ps->last != '\0');
-               assert(p->ps->last != 8);
-               if ('_' == p->ps->last) {
+               assert( ! (p->ps->flags & PS_BACKSP));
+               p->ps->flags |= PS_BACKSP;
+               return;
+       }
+
+       /*
+        * Decode font instructions.
+        */
+
+       if (p->ps->flags & PS_BACKSP) {
+               if (p->ps->last == '_') {
                        switch (p->ps->nextf) {
                        case TERMFONT_BI:
                                break;
@@ -1099,7 +1106,11 @@ ps_letter(struct termp *p, int arg)
                        default:
                                p->ps->nextf = TERMFONT_UNDER;
                        }
-               } else {
+                       p->ps->last = c;
+                       p->ps->flags &= ~PS_BACKSP;
+                       return;
+               }
+               if (p->ps->last == c) {
                        switch (p->ps->nextf) {
                        case TERMFONT_BI:
                                break;
@@ -1109,16 +1120,81 @@ ps_letter(struct termp *p, int arg)
                        default:
                                p->ps->nextf = TERMFONT_BOLD;
                        }
+                       p->ps->flags &= ~PS_BACKSP;
+                       return;
                }
-       } else if (p->ps->last != '\0' && p->ps->last != 8) {
+
+               /*
+                * This is not a font instruction, but rather
+                * the next character.  Prepare for overstrike.
+                */
+
+               savecol = p->ps->pscol;
+       } else
+               savecol = SIZE_MAX;
+
+       /*
+        * We found the next character, so the font instructions
+        * for the previous one are complete.
+        * Use them and print it.
+        */
+
+       if (p->ps->last != '\0') {
                if (p->ps->nextf != p->ps->lastf) {
                        ps_pclose(p);
                        ps_setfont(p, p->ps->nextf);
                }
                p->ps->nextf = TERMFONT_NONE;
+
+               /*
+                * For an overstrike, if a previous character
+                * was wider, advance to center the new one.
+                */
+
+               if (p->ps->pscolnext) {
+                       wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx;
+                       if (p->ps->pscol + wx < p->ps->pscolnext)
+                               p->ps->pscol = (p->ps->pscol +
+                                   p->ps->pscolnext - wx) / 2;
+               }
+
                ps_pletter(p, p->ps->last);
+
+               /*
+                * For an overstrike, if a previous character
+                * was wider, advance to the end of the old one.
+                */
+
+               if (p->ps->pscol < p->ps->pscolnext) {
+                       ps_pclose(p);
+                       p->ps->pscol = p->ps->pscolnext;
+               }
        }
+
+       /*
+        * Do not print the current character yet because font
+        * instructions might follow; only remember it.
+        * For the first character, nothing else is done.
+        * The final character will get printed from ps_fclose().
+        */
+
        p->ps->last = c;
+
+       /*
+        * For an overstrike, back up to the previous position.
+        * If the previous character is wider than any it overstrikes,
+        * remember the current position, because it might also be
+        * wider than all that will overstrike it.
+        */
+
+       if (savecol != SIZE_MAX) {
+               if (p->ps->pscolnext < p->ps->pscol)
+                       p->ps->pscolnext = p->ps->pscol;
+               ps_pclose(p);
+               p->ps->pscol = savecol;
+               p->ps->flags &= ~PS_BACKSP;
+       } else
+               p->ps->pscolnext = 0;
 }
 
 static void