source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Implement font-switching for PostScript.
@ 2010-06-11 16:58 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2010-06-11 16:58 UTC (permalink / raw)
  To: source

Log Message:
-----------
Implement font-switching for PostScript.  -Tps now supports
TERMFONT_BOLD (Courier-Bold) and TERMFONT_UNDER (Courier-Oblique).  It
doesn't look half bad.  This accomplished through tricksy juggling of
the one-char back-buffer.

Modified Files:
--------------
    mdocml:
        term.h
        term_ps.c

Revision Data
-------------
Index: term.h
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/term.h,v
retrieving revision 1.62
retrieving revision 1.63
diff -Lterm.h -Lterm.h -u -p -r1.62 -r1.63
--- term.h
+++ term.h
@@ -51,6 +51,7 @@ struct	termp_ps {
 	size_t		  psmargcur;	/* current pos in margin buf */
 	size_t	 	  pspage;	/* current page */
 	char		  last;		/* character buffer */
+	enum termfont	  lastf;	/* last set font */
 };
 
 struct	termp {
Index: term_ps.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/term_ps.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -Lterm_ps.c -Lterm_ps.c -u -p -r1.8 -r1.9
--- term_ps.c
+++ term_ps.c
@@ -53,14 +53,18 @@
 		} \
 	} while (/* CONSTCOND */ 0)
 
+
 static	void		  ps_letter(struct termp *, char);
 static	void		  ps_begin(struct termp *);
 static	void		  ps_end(struct termp *);
 static	void		  ps_advance(struct termp *, size_t);
 static	void		  ps_endline(struct termp *);
+static	void		  ps_fclose(struct termp *);
+static	void		  ps_pclose(struct termp *);
 static	void		  ps_pletter(struct termp *, char);
 static	void		  ps_printf(struct termp *, const char *, ...);
 static	void		  ps_putchar(struct termp *, char);
+static	void		  ps_setfont(struct termp *, enum termfont);
 
 
 void *
@@ -175,56 +179,47 @@ static void
 ps_begin(struct termp *p)
 {
 
-	/*
-	 * Emit the standard PostScript prologue, set our initial page
-	 * position, then run pageopen() on the initial page.
+	/* 
+	 * Print margins into margin buffer.  Nothing gets output to the
+	 * screen yet, so we don't need to initialise the primary state.
 	 */
 
-	printf("%s\n", "%!PS");
-	printf("%s\n", "/Courier");
-	printf("%s\n", "10 selectfont");
-
-	p->engine.ps.psstate = 0;
-
 	if (p->engine.ps.psmarg) {
 		assert(p->engine.ps.psmargsz);
 		p->engine.ps.psmarg[0] = '\0';
 	}
 
 	p->engine.ps.psmargcur = 0;
-
-	/*
-	 * Now dump the margins into our margin buffer.  If we don't do
-	 * this, we'd break any current state to run the header and
-	 * footer with each and evern new page.
-	 */
-
+	p->engine.ps.psstate = PS_MARGINS;
 	p->engine.ps.pscol = PS_CHAR_LEFT;
 	p->engine.ps.psrow = PS_CHAR_TOPMARG;
 
-	p->engine.ps.psstate |= PS_MARGINS;
+	ps_setfont(p, TERMFONT_NONE);
 
 	(*p->headf)(p, p->argf);
 	(*p->endline)(p);
 
-	p->engine.ps.psstate &= ~PS_MARGINS;
-	assert(0 == p->engine.ps.psstate);
-
 	p->engine.ps.pscol = PS_CHAR_LEFT;
 	p->engine.ps.psrow = PS_CHAR_BOTMARG;
-	p->engine.ps.psstate |= PS_MARGINS;
 
 	(*p->footf)(p, p->argf);
 	(*p->endline)(p);
 
 	p->engine.ps.psstate &= ~PS_MARGINS;
+
 	assert(0 == p->engine.ps.psstate);
+	assert(p->engine.ps.psmarg);
+	assert('\0' != p->engine.ps.psmarg[0]);
+
+	/* 
+	 * Print header and initialise page state.  Following this,
+	 * stuff gets printed to the screen, so make sure we're sane.
+	 */
 
+	printf("%s\n", "%!PS");
+	ps_setfont(p, TERMFONT_NONE);
 	p->engine.ps.pscol = PS_CHAR_LEFT;
 	p->engine.ps.psrow = PS_CHAR_TOP;
-
-	assert(p->engine.ps.psmarg);
-	assert('\0' != p->engine.ps.psmarg[0]);
 }
 
 
@@ -232,11 +227,12 @@ static void
 ps_pletter(struct termp *p, char c)
 {
 	
+	/*
+	 * If we're not in a PostScript "word" context, then open one
+	 * now at the current cursor.
+	 */
+
 	if ( ! (PS_INLINE & p->engine.ps.psstate)) {
-		/*
-		 * If we're not in a PostScript "word" context, then
-		 * open one now at the current cursor.
-		 */
 		ps_printf(p, "%zu %zu moveto\n(", 
 				p->engine.ps.pscol, 
 				p->engine.ps.psrow);
@@ -263,59 +259,118 @@ ps_pletter(struct termp *p, char c)
 	}
 
 	/* Write the character and adjust where we are on the page. */
+
 	ps_putchar(p, c);
 	p->engine.ps.pscol += PS_CHAR_WIDTH;
 }
 
 
 static void
+ps_pclose(struct termp *p)
+{
+
+	/* 
+	 * Spit out that we're exiting a word context (this is a
+	 * "partial close" because we don't check the last-char buffer
+	 * or anything).
+	 */
+
+	if ( ! (PS_INLINE & p->engine.ps.psstate))
+		return;
+	
+	ps_printf(p, ") show\n");
+	p->engine.ps.psstate &= ~PS_INLINE;
+}
+
+
+static void
+ps_fclose(struct termp *p)
+{
+
+	/*
+	 * Strong closure: if we have a last-char, spit it out after
+	 * checking that we're in the right font mode.  This will of
+	 * course open a new scope, if applicable.
+	 *
+	 * Following this, close out any scope that's open.
+	 */
+
+	if ('\0' != p->engine.ps.last) {
+		if (p->engine.ps.lastf != TERMFONT_NONE) {
+			ps_pclose(p);
+			ps_setfont(p, TERMFONT_NONE);
+		}
+		ps_pletter(p, p->engine.ps.last);
+		p->engine.ps.last = '\0';
+	}
+
+	if ( ! (PS_INLINE & p->engine.ps.psstate))
+		return;
+
+	ps_pclose(p);
+}
+
+
+static void
 ps_letter(struct termp *p, char c)
 {
 	char		cc;
-	
+
+	/*
+	 * State machine dictates whether to buffer the last character
+	 * or not.  Basically, encoded words are detected by checking if
+	 * we're an "8" and switching on the buffer.  Then we put "8" in
+	 * our buffer, and on the next charater, flush both character
+	 * and buffer.  Thus, "regular" words are detected by having a
+	 * regular character and a regular buffer character.
+	 */
+
 	if ('\0' == p->engine.ps.last) {
 		assert(8 != c);
 		p->engine.ps.last = c;
 		return;
 	} else if (8 == p->engine.ps.last) {
 		assert(8 != c);
-		p->engine.ps.last = c;
-		return;
+		p->engine.ps.last = '\0';
 	} else if (8 == c) {
 		assert(8 != p->engine.ps.last);
+		if ('_' == p->engine.ps.last) {
+			if (p->engine.ps.lastf != TERMFONT_UNDER) {
+				ps_pclose(p);
+				ps_setfont(p, TERMFONT_UNDER);
+			}
+		} else if (p->engine.ps.lastf != TERMFONT_BOLD) {
+			ps_pclose(p);
+			ps_setfont(p, TERMFONT_BOLD);
+		}
 		p->engine.ps.last = c;
 		return;
 	} else {
+		if (p->engine.ps.lastf != TERMFONT_NONE) {
+			ps_pclose(p);
+			ps_setfont(p, TERMFONT_NONE);
+		}
 		cc = p->engine.ps.last;
 		p->engine.ps.last = c;
 		c = cc;
 	}
 
-	return(ps_pletter(p, c));
+	ps_pletter(p, c);
 }
 
 
 static void
 ps_advance(struct termp *p, size_t len)
 {
-	size_t		 i;
-
-	if ('\0' != p->engine.ps.last) {
-		ps_pletter(p, p->engine.ps.last);
-		p->engine.ps.last = '\0';
-	}
 
-	if (PS_INLINE & p->engine.ps.psstate) {
-		assert(8 != p->engine.ps.last);
-		if (p->engine.ps.last)
-			ps_letter(p, p->engine.ps.last);
-		p->engine.ps.last = '\0';
-		for (i = 0; i < len; i++) 
-			ps_letter(p, ' ');
-		return;
-	}
+	/*
+	 * Advance some spaces.  This can probably be made smarter,
+	 * i.e., to have multiple space-separated words in the same
+	 * scope, but this is easier:  just close out the current scope
+	 * and readjust our column settings.
+	 */
 
-	assert('\0' == p->engine.ps.last);
+	ps_fclose(p);
 	p->engine.ps.pscol += len ? len * PS_CHAR_WIDTH : 0;
 }
 
@@ -324,24 +379,24 @@ static void
 ps_endline(struct termp *p)
 {
 
-	if ('\0' != p->engine.ps.last) {
-		ps_pletter(p, p->engine.ps.last);
-		p->engine.ps.last = '\0';
-	}
+	/* Close out any scopes we have open: we're at eoln. */
 
-	if (PS_INLINE & p->engine.ps.psstate) {
-		assert(8 != p->engine.ps.last);
-		if (p->engine.ps.last)
-			ps_letter(p, p->engine.ps.last);
-		p->engine.ps.last = '\0';
-		ps_printf(p, ") show\n");
-		p->engine.ps.psstate &= ~PS_INLINE;
-	} else
-		assert('\0' == p->engine.ps.last);
+	ps_fclose(p);
+
+	/*
+	 * If we're in the margin, don't try to recalculate our current
+	 * row.  XXX: if the column tries to be fancy with multiple
+	 * lines, we'll do nasty stuff. 
+	 */
 
 	if (PS_MARGINS & p->engine.ps.psstate)
 		return;
 
+	/*
+	 * Put us down a line.  If we're at the page bottom, spit out a
+	 * showpage and restart our row.
+	 */
+
 	p->engine.ps.pscol = PS_CHAR_LEFT;
 	if (p->engine.ps.psrow >= PS_CHAR_HEIGHT + PS_CHAR_BOT) {
 		p->engine.ps.psrow -= PS_CHAR_HEIGHT;
@@ -353,3 +408,20 @@ ps_endline(struct termp *p)
 	printf("showpage\n");
 	p->engine.ps.psrow = PS_CHAR_TOP;
 }
+
+
+static void
+ps_setfont(struct termp *p, enum termfont f)
+{
+
+	if (TERMFONT_BOLD == f) 
+		ps_printf(p, "/Courier-Bold\n");
+	else if (TERMFONT_UNDER == f)
+		ps_printf(p, "/Courier-Oblique\n");
+	else
+		ps_printf(p, "/Courier\n");
+
+	ps_printf(p, "10 selectfont\n");
+	p->engine.ps.lastf = f;
+}
+
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-06-11 16:58 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-11 16:58 mdocml: Implement font-switching for PostScript kristaps

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).