SGML: DSSSL style sheet for HTML 3.2 print output

SGML: DSSSL style sheet for HTML 3.2 print output




Re: DSSSL style sheet for HTML 3.2 hardcopy
Subject: Re: DSSSL style sheet for HTML 3.2 hardcopy
Date: 21 Jul 1996 04:15:02 GMT
From: <a href="mailto:bosak@boethius.eng.sun.com">bosak@boethius.eng.sun.com (Jon Bosak)</a>

[from previous CTS message, July 19, 1996]

[***** Update NOTE ****
Update August 02: An updated/reworked version of the stylesheet is
available as "html32hc.dsl.960802" [or its successor], accessible
via FTP:
ftp://sunsite.unc.edu/pub/sun-info/standards/dsssl/stylesheets/html3_2. ]

Below is a first [second] attempt at a DSSSL (dsssl-o) style sheet for
producing hardcopy output from documents validated against the HTML
3.2 DTD.  It supports most of the features of HTML 3.2 that make any
sense in printed form and adds a couple of features of its own,
notably headers, footers, and the autonumbering of heads and table
captions.

The style sheet was tested using an alpha version of James Clark's
DSSSL engine.  Since precompiled binaries of the alpha were available
only for Windows 95, that was the platform for which the style sheet
was written.  Very minor and obvious adjustments should be sufficient
to adapt it to other platforms.  Thanks are due to Anders Berglund for
putting together the foundation of the style sheet, and of course to
James Clark for taking the time to answer a number of foolish
questions and for producing yet another basic piece of the Grand
Solution.

Since this style sheet is my first attempt to write in DSSSL, Scheme,
or any other functional language, I would be grateful for suggestions
on how to improve it.

Jon

---
Jon Bosak, Online Information Technology Architect
SunSoft, 2550 Garcia Ave., MPK17-101, Mountain View, CA 94043
A Davenport Group Sponsor -- see http://www.ora.com/davenport/

------------------------------- cut here -------------------------------

<!doctype style-sheet system "style-sh.dtd">

;; ######################################################################
;;
;; DSSSL style sheet for HTML 3.2 print output
;;
;; 1996.07.20 bis
;;
;; Jon Bosak, SunSoft, based on work by Anders Berglund, EBT,
;;    with critical assistance from James Clark
;;
;; ######################################################################


;; Features in HTML 3.2 that are not implemented in the style sheet:
;;
;;    automatic table column widths
;;    % on width attribute for TABLE
;;    attributes on TH and TD: align, valign, rowspan, colspan
;;    attributes on TABLE: width, align, border, cellspacing, cellpadding
;;    start attribute on OL
;;    value attribute on LI
;;    noshade attribute on HR
;;
;;    See also "Non-Printing Elements" below
;;
;; Features in the style sheet that are not in HTML 3.2:
;;
;;    page headers that display the HEAD TITLE content
;;    page footers that display the page number
;;    optional autonumbering of heads and table captions
;;    support for named units (pt, pi, cm, mm) in size attributes


;; ============================== UNITS ================================

(define-unit mm .001m)
(define-unit cm .01m)
(define-unit in 2.54cm)
(define-unit pi (/ 1in 6))
(define-unit pt (/ 1in 72))
(define-unit px (/ 1in 96))

;; see below for definition of "em"


;; =========================== PARAMETERS ==============================

;; Visual acuity levels are "normal", "presbyopic", and 
;;   "large-type"; set the line following to choose the level

(define *visual-acuity* "normal")
;; (define *visual-acuity* "presbyopic")
;; (define *visual-acuity* "large-type")

(define *bf-size*
  (case *visual-acuity*
	(("normal") 10pt)
	(("presbyopic") 12pt)
	(("large-type") 24pt)))
(define *mf-size* *bf-size*)
(define-unit em *bf-size*)

;; these font selections are for Windows 95

(define *title-font-family* "Arial")
(define *body-font-family* "Times New Roman")
(define *mono-font-family* "Courier New")
(define *dingbat-font-family* "Wingdings")

;; these "bullet strings" are a hack that is completely dependent on
;;    the Wingdings font family selected above; consider this a
;;    placeholder for suitable ISO 10646 characters

(define *disk-bullet* "l")
(define *circle-bullet* "¡")
(define *square-bullet* "o")
(define *small-diamond-bullet* "w")

(define *line-spacing-factor* 1.1)
(define *head-before-factor* 0.75)
(define *head-after-factor* 0.5)
(define *autonum-level* 6) ;; zero disables autonumbering

(define *page-width* 8.5in)
(define *page-height* 11in)

(define *left-right-margin* 6pi)
(define *top-margin* (if (equal? *visual-acuity* "large-type")
			 7.5pi
		         6pi))
(define *bottom-margin* (if (equal? *visual-acuity* "large-type")
			 7.5pi
		         6pi))
(define *header-margin* (if (equal? *visual-acuity* "large-type")
			    4.5pi
			    3pi))
(define *footer-margin* 3pi)

(define *text-width* (- *page-width* (* *left-right-margin* 2)))
(define *body-start-indent* 6pi)
(define *body-width* (- *text-width* *body-start-indent*))
(define *para-sep* (/ *bf-size* 2.0))
(define *block-sep* (* *para-sep* 2.0))
(define *hsize-bump-factor* 1.2)
(define *ss-size-factor* 0.6)
(define *ss-shift-factor* 0.4)


;; ============================ FUNCTIONS ==============================

(define (expt b n)
  (if (= n 0)
      1
      (* b (expt b (- n 1)))))

(define upperalpha
  (list #\A #\B #\C #\D #\E #\F #\G #\H #\I #\J #\K #\L #\M
	#\N #\O #\P #\Q #\R #\S #\T #\U #\V #\W #\X #\Y #\Z))

(define loweralpha
  (list #\a #\b #\c #\d #\e #\f #\g #\h #\i #\j #\k #\l #\m
	#\n #\o #\p #\q #\r #\s #\t #\u #\v #\w #\x #\y #\z))

(define (ISALPHA? c)
   (if (or (member c upperalpha) (member c loweralpha)) #t #f))

(define (EQUIVLOWER c a1 a2)
  (cond ((null? a1) '())
	((char=? c (car a1)) (car a2))
	((char=? c (car a2)) c)
	(else (EQUIVLOWER c (cdr a1) (cdr a2)))))

(define (char-downcase c)
  (EQUIVLOWER c upperalpha loweralpha))

(define (LOCASE slist)
  (if (null? slist)
      '()
      (cons (char-downcase (car slist)) (LOCASE (cdr slist)))))

(define (STR2LIST s)
  (let ((start 0)
	(len (string-length s)))
    (let loop ((i start) (l len))
	 (if (= i len)
	     '()
	      (cons (string-ref s i) (loop (+ i 1) l))))))

(define (LIST2STR x)
  (apply string x))

(define (STRING-DOWNCASE s)
  (LIST2STR (LOCASE (STR2LIST s))))

(define (UNAME-START-INDEX u last)
  (let ((c (string-ref u last)))
    (if (ISALPHA? c)
	(if (= last 0)
	    0
	    (UNAME-START-INDEX u (- last 1)))
        (+ last 1))))

;; this doesn't deal with "%" yet

(define (PARSEDUNIT u)
 (if (string? u)
  (let ((strlen (string-length u)))
    (if (> strlen 2)
	(let ((u-s-i (UNAME-START-INDEX u (- strlen 1))))
	  (if (= u-s-i 0) ;; there's no number here
	      1pi         ;; so return something that might work
	      (if (= u-s-i strlen)           ;; there's no unit name here
		  (* (string->number u) 1px) ;; so default to pixels (3.2)
		  (let* ((unum (string->number
			       (substring u 0 u-s-i)))
			 (uname (STRING-DOWNCASE
				 (substring u u-s-i strlen))))
		    (case uname
			  (("mm") (* unum 1mm))
			  (("cm") (* unum 1cm))
			  (("in") (* unum 1in))
			  (("pi") (* unum 1pi))
			  (("pc") (* unum 1pi))
			  (("pt") (* unum 1pt))
			  (("px") (* unum 1px))
			  (("barleycorn") (* unum 2pi)) ;; extensible!
			  (else
			   (cond 
			    ((number? unum)
			     (* unum 1px))
			    ((number? (string->number u))
			     (* (string->number u) 1px))
				 (else u))))))))
        (if (number? (string->number u))
	    (* (string->number u) 1px)
	    1pi)))
    1pi))

(define (INLIST?)
  (or
   (have-ancestor? "OL")
   (have-ancestor? "UL")
   (have-ancestor? "DIR")
   (have-ancestor? "MENU")
   (have-ancestor? "DL")))

(define (HSIZE n)
  (* *bf-size*
    (expt *hsize-bump-factor* n)))

(define (OLSTEP)
  (case (modulo (length (hierarchical-number-recursive "OL")) 4)
	((1) 1.2em)
	((2) 1.2em)
	((3) 1.6em)
	((0) 1.4em)))

(define (ULSTEP) 1em)

(define (PQUAD)
  (case (attribute-string "align")
	(("LEFT") 'start)
	(("CENTER") 'center)
	(("RIGHT") 'end)
	(else (inherited-quadding))))

(define (HQUAD)
  (cond
   ((string? (attribute-string "align")) (PQUAD))
   ((have-ancestor? "CENTER") 'center)
   ((have-ancestor? "DIV") (inherited-quadding))
   (else 'start)))

(define (BULLSTR sty)
  (case sty
	(("CIRCLE") *circle-bullet*)
	(("SQUARE") *square-bullet*)
	(else *disk-bullet*)))


;; ====================== NON-PRINTING ELEMENTS ========================

;; Note that HEAD includes TITLE, ISINDEX, BASE, META, STYLE,
;;   SCRIPT, and LINK as possible children

(element HEAD (empty-sosofo))
(element FORM (empty-sosofo))
(element APPLET (empty-sosofo))
(element PARAM (empty-sosofo))
(element TEXTFLOW (empty-sosofo))
(element MAP (empty-sosofo))
(element AREA (empty-sosofo))


;; ============================ TOP LEVEL ==============================

(element HTML
 (make simple-page-sequence
       font-family-name: *body-font-family*
       font-size: *bf-size*
       line-spacing: (* *bf-size* *line-spacing-factor*)
       left-header: (make sequence
			  font-size: (- *bf-size* 1pt)
			  line-spacing: (* (- *bf-size* 1pt)
					   *line-spacing-factor*)
			  font-posture: 'italic
			  (process-first-descendant "TITLE"))
       right-footer: (make sequence
			   font-size: (- *bf-size* 1pt)
			   line-spacing: (* (- *bf-size* 1pt)
					    *line-spacing-factor*)
			   (literal "Page ")
			   (page-number-sosofo))
       top-margin: *top-margin*
       bottom-margin: *bottom-margin*
       left-margin: *left-right-margin*
       right-margin: *left-right-margin*
       header-margin: *header-margin*
       footer-margin: *footer-margin*
       page-width: *page-width*
       page-height: *page-height*
       input-whitespace-treatment: 'collapse
       quadding: 'justify
       (process-children-trim)))

(element BODY
  (process-children-trim))


;; ========================= BLOCK ELEMENTS ==========================


;; .......................... Generic DIV ............................

(element DIV
 (let ((align (attribute-string "align")))
  (make display-group
	quadding: (case align
			(("LEFT") 'start)
			(("CENTER") 'center)
			(("RIGHT") 'end)
			(else 'justify))
	(process-children-trim))))

;; "CENTER is a shorthand for DIV with ALIGN=CENTER" (3.2 DTD)

(element CENTER
 (make display-group
       quadding: 'center
       (process-children-trim)))


;; ................ Headings  H1, H2, H3, H4, H5, H6 .................

(element H1
  (make paragraph
	font-family-name: *title-font-family*
	font-weight: 'bold
	font-size: (HSIZE 4)
	line-spacing: (* (HSIZE 4) *line-spacing-factor*)
	space-before: (* (HSIZE 4) *head-before-factor*)
	space-after: (* (HSIZE 4) *head-after-factor*)
	start-indent: *body-start-indent*
	first-line-start-indent: (- *body-start-indent*)
	quadding: (HQUAD)
	keep-with-next?: #t
	(process-children-trim)))

(element H2
  (make paragraph
	font-family-name: *title-font-family*
	font-weight: 'bold
	font-size: (HSIZE 3)
	line-spacing: (* (HSIZE 3) *line-spacing-factor*)
	space-before: (* (HSIZE 3) *head-before-factor*)
	space-after: (* (HSIZE 3) *head-after-factor*)
	start-indent: *body-start-indent*
	first-line-start-indent: (- *body-start-indent*)
	quadding: (HQUAD)
	keep-with-next?: #t
	(literal
	 (if (>= *autonum-level* 2)
	     (let ((x (element-number-list (list "H1" "H2"))))
	       (string-append
		(format-number (list-ref x 1) "1")
		". "))
	   (string-append "")))
	(process-children-trim)))

(element H3
  (make paragraph
	font-family-name: *title-font-family*
	font-weight: 'bold
	font-size: (HSIZE 2)
	line-spacing: (* (HSIZE 2) *line-spacing-factor*)
	space-before: (* (HSIZE 2) *head-before-factor*)
	space-after: (* (HSIZE 2) *head-after-factor*)
	start-indent: *body-start-indent*
	first-line-start-indent: (- *body-start-indent*)
	quadding: (HQUAD)
	keep-with-next?: #t
	(literal 
	 (if (>= *autonum-level* 3)
	     (let ((x (element-number-list (list "H1" "H2" "H3"))))
	       (string-append
		(format-number (list-ref x 1) "1")
		"."
		(format-number (list-ref x 2) "1")
		" "))
	   (string-append "")))
	 (process-children-trim)))

(element H4
  (make paragraph
	font-family-name: *title-font-family*
	font-weight: 'bold
	font-size: (HSIZE 1)
	line-spacing: (* (HSIZE 1) *line-spacing-factor*)
	space-before: (* (HSIZE 1) *head-before-factor*)
	space-after: (* (HSIZE 1) *head-after-factor*)
	start-indent: *body-start-indent*
	quadding: (HQUAD)
	keep-with-next?: #t
	(literal 
	 (if (>= *autonum-level* 4)
	     (let ((x (element-number-list (list "H1" "H2" "H3" "H4"))))
	       (string-append
		(format-number (list-ref x 1) "1")
		"."
		(format-number (list-ref x 2) "1")
		"."
		(format-number (list-ref x 3) "1")
		" "))
	   (string-append "")))
	(process-children-trim)))

(element H5
  (make paragraph
	font-family-name: *title-font-family*
	font-weight: 'bold
	font-size: (HSIZE 0)
	line-spacing: (* (HSIZE 0) *line-spacing-factor*)
	space-before: (* (HSIZE 0) *head-before-factor*)
	space-after: (* (HSIZE 0) *head-after-factor*)
	start-indent: *body-start-indent*
	quadding: (HQUAD)
	keep-with-next?: #t
	(literal 
	 (if (>= *autonum-level* 5)
	     (let ((x (element-number-list
		       (list "H1" "H2" "H3" "H4" "H5"))))
	       (string-append
		(format-number (list-ref x 1) "1")
		"."
		(format-number (list-ref x 2) "1")
		"."
		(format-number (list-ref x 3) "1")
		"."
		(format-number (list-ref x 4) "1")
		" "))
	   (string-append "")))
	(process-children-trim)))

(element H6
  (make paragraph
	font-family-name: *title-font-family*
	font-posture: 'italic
	font-size: (HSIZE 0)
	line-spacing: (* (HSIZE 0) *line-spacing-factor*)
	space-before: (* (HSIZE 0) *head-before-factor*)
	space-after: (* (HSIZE 0) *head-after-factor*)
	start-indent: *body-start-indent*
	quadding: (HQUAD)
	keep-with-next?: #t
	(literal 
	 (if (>= *autonum-level* 6)
	     (let ((x (element-number-list
		       (list "H1" "H2" "H3" "H4" "H5" "H6"))))
	       (string-append
		(format-number (list-ref x 1) "1")
		"."
		(format-number (list-ref x 2) "1")
		"."
		(format-number (list-ref x 3) "1")
		"."
		(format-number (list-ref x 4) "1")
		"."
		(format-number (list-ref x 5) "1")
		" "))
	   (string-append "")))
	(process-children-trim)))


;; .......................... Paragraphs .............................

(define p-style
  (style
   font-size: *bf-size*
   line-spacing: (* *bf-size* *line-spacing-factor*)))

(element P
 (make paragraph
       use: p-style
       space-before: *para-sep*
       start-indent: *body-start-indent*
       quadding: (PQUAD)
       (process-children-trim)))

(element ADDRESS
  (make paragraph
	use: p-style
	font-posture: 'italic
	space-before: *para-sep*
	start-indent: *body-start-indent*
	(process-children-trim)))

(element BLOCKQUOTE
  (make paragraph
	font-size: (* *bf-size* (/ 5.0 6.0))
	line-spacing: (* *bf-size* *line-spacing-factor* (/ 5.0 6.0))
	space-before: *para-sep*
	start-indent: (+ *body-start-indent* 1em)
	end-indent: 1em
	(process-children-trim)))

(define (MONOPARA)
  (make paragraph
	use: p-style
	space-before: *para-sep*
	start-indent: (+ *body-start-indent* 1em)
        lines: 'asis
	font-family-name: *mono-font-family*
	font-size: *mf-size*
	input-whitespace-treatment: 'preserve
        (process-children-trim)))

(element PRE (MONOPARA))
(element XMP (MONOPARA))
(element LISTING (MONOPARA))
(element PLAINTEXT (MONOPARA))

(element BR
  (make display-group
    (empty-sosofo)))


;; ................. Lists: UL, OL, DIR, MENU, DL ....................

(element UL
 (make display-group
       space-before: (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       space-after:  (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       start-indent: (if (INLIST?)
			 (inherited-start-indent)
		         *body-start-indent*)))

(element (UL LI)
 (make paragraph
       use: p-style
       space-before: (if (attribute-string "compact" (ancestor "UL"))
			 0
		         *para-sep*)
       start-indent: (+ (inherited-start-indent) (ULSTEP))
       first-line-start-indent: (- (ULSTEP))
       (make line-field
	     font-family-name: *dingbat-font-family*
	     font-size: (- *bf-size* 2pt)
	     field-width: (ULSTEP)
	     (literal
	      (let
		  ((litype
		    (attribute-string "type"))
		   (ultype
		     (attribute-string "type" (ancestor "UL"))))
		(cond
		 (litype (BULLSTR litype))
		 (ultype (BULLSTR ultype))
		 (else *disk-bullet*)))))
       (process-children-trim)))

(element (UL LI UL LI)
 (make paragraph
       use: p-style
       space-before: (if (attribute-string "compact" (ancestor "UL"))
			 0
		         *para-sep*)
       start-indent: (+ (inherited-start-indent) (ULSTEP))
       first-line-start-indent: (- (ULSTEP))
       (make line-field
	     font-family-name: *dingbat-font-family*
	     font-size: *bf-size*
	     field-width: (ULSTEP)
	     (literal
	      (let
		  ((litype
		    (attribute-string "type"))
		   (ultype
		     (attribute-string "type" (ancestor "UL"))))
		(cond
		 (litype (BULLSTR litype))
		 (ultype (BULLSTR ultype))
		 (else *small-diamond-bullet*)))))
       (process-children-trim)))

(element (UL LI P)
  (make paragraph
	use: p-style
	start-indent: (+ (inherited-start-indent) (OLSTEP))
	first-line-start-indent: (- (OLSTEP))
	(process-children-trim)))

(element OL
 (make display-group
       space-before: (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       space-after:  (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       start-indent: (if (INLIST?)
			 (inherited-start-indent)
		         *body-start-indent*)))

(element (OL LI)
 (make paragraph
       use: p-style
       space-before: (if (attribute-string "compact" (ancestor "OL"))
			 0
		         *para-sep*)
       start-indent: (+ (inherited-start-indent) (OLSTEP))
       first-line-start-indent: (- (OLSTEP))
       (make line-field
	     field-width: (OLSTEP)
	     (literal
	      (case (modulo (length
		(hierarchical-number-recursive "OL")) 4)
		    ((1) (string-append
			  (format-number 
			   (child-number) "1")
			  "."))
		    ((2) (string-append
			  (format-number
			   (child-number) "a")
			  "."))
		    ((3) (string-append
			  "("
			  (format-number
			   (child-number) "i")
			  ")"))
		    ((0) (string-append
			  "("
			  (format-number
			   (child-number) "a")
			  ")")))))
       (process-children-trim)))

(element (OL LI P)
  (make paragraph
	use: p-style
	start-indent: (+ (inherited-start-indent) (OLSTEP))
	first-line-start-indent: (- (OLSTEP))
	(process-children-trim)))

;; Note that DIR cannot properly have block children.  Here DIR is
;;   interpreted as an unmarked list without extra vertical
;;   spacing.

(element DIR
 (make display-group
       space-before: (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       space-after:  (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       start-indent: (if (INLIST?)
			 (inherited-start-indent)
		         *body-start-indent*)))

(element (DIR LI)
 (make paragraph
       use: p-style
       start-indent: (+ (inherited-start-indent) (* 2.0 (ULSTEP)))
       first-line-start-indent: (- (ULSTEP))
       (process-children-trim)))

;; Note that MENU cannot properly have block children.  Here MENU is
;;   interpreted as a small-bulleted list with no extra vertical
;;   spacing.

(element MENU
 (make display-group
       space-before: (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       space-after:  (if (INLIST?)
			 *para-sep*
		         *block-sep*)
       start-indent: (if (INLIST?)
			 (inherited-start-indent)
		         *body-start-indent*)))

(element (MENU LI)
 (make paragraph
       use: p-style
       start-indent: (+ (inherited-start-indent) (ULSTEP))
       first-line-start-indent: (- (ULSTEP))
       (make line-field
	     font-family-name: *dingbat-font-family*
	     font-size: *bf-size*
	     field-width: (ULSTEP)
	     (literal "w"))
       (process-children-trim)))

;; This treatment of DLs doesn't apply a "compact" attribute set at one
;;    level to any nested DLs.  To change this behavior so that nested
;;    DLs inherit the "compact" attribute from an ancestor DL, substitute
;;    "inherited-attribute-string" for "attribute-string" in the
;;    construction rules for DT and DD.


(element DL
  (make display-group
	space-before: (if (INLIST?)
			  *para-sep*
			  *block-sep*)
	space-after:  (if (INLIST?)
			  *para-sep*
			  *block-sep*)
	start-indent: (if (INLIST?)
			  (+ (inherited-start-indent) 2em)
			  (+ *body-start-indent* 2em))
	(make paragraph)))

(element DT
  (let ((compact (attribute-string "compact" (ancestor "DL"))))
    (if compact
	(make line-field
	      field-width: 3em
	      (process-children-trim))
        (make paragraph
	      use: p-style
	      space-before: *para-sep*
	      first-line-start-indent: -1em
	      (process-children-trim)))))

(element DD
  (let ((compact (attribute-string "compact" (ancestor "DL"))))
    (if compact
	(sosofo-append
	 (process-children-trim)
	 (make paragraph-break))
        (make paragraph
	      use: p-style
	      start-indent: (+ (inherited-start-indent) 2em)
	      (process-children-trim)))))


;; ======================== INLINE ELEMENTS ==========================

(define (BOLD-SEQUENCE)
  (make sequence
    font-posture: 'bold
    (process-children-trim)))

(element B (BOLD-SEQUENCE))
(element EM (BOLD-SEQUENCE))
(element STRONG (BOLD-SEQUENCE))

(define (ITALIC-SEQUENCE)
  (make sequence
    font-posture: 'italic
    (process-children-trim)))

(element I (ITALIC-SEQUENCE))
(element CITE (ITALIC-SEQUENCE))
(element VAR (ITALIC-SEQUENCE))

(define (MONO-SPACE-SEQUENCE)
  (make sequence
	font-family-name: *mono-font-family*
	font-size: *mf-size*
	(process-children-trim)))

(element TT (MONO-SPACE-SEQUENCE))
(element CODE (MONO-SPACE-SEQUENCE))
(element KBD (MONO-SPACE-SEQUENCE))
(element SAMP (MONO-SPACE-SEQUENCE))

(element DFN
  (make sequence
	font-weight: 'bold
	font-posture: 'italic
	(process-children-trim)))

(element STRIKE
  (make score
	type: 'through
	(process-children-trim)))

(element U
  (make score
	type: 'after
	(process-children-trim)))

(element SUP
  (make sequence
	font-size: (* (inherited-font-size)
		      *ss-size-factor*)
	position-point-shift: (+ (* (inherited-font-size)
				    *ss-shift-factor*))
	(process-children-trim)))

(element SUB
  (make sequence
	font-size: (* (inherited-font-size)
		      *ss-size-factor*)
	position-point-shift: (- (* (inherited-font-size)
				    *ss-shift-factor*))
	(process-children-trim)))

(element BIG
  (make sequence
	font-size: (/ (inherited-font-size)
		      *ss-size-factor*)
	line-spacing: (/ (inherited-line-spacing)
			 *ss-size-factor*)))

(element SMALL
  (make sequence
	font-size: (* (inherited-font-size) *ss-size-factor*)))

(element FONT
 (let ((fsize (attribute-string "SIZE")))
  (make sequence
    	font-size: (if fsize
		       (PARSEDUNIT fsize)
		       (inherited-font-size)))))


;; ============================= LINKS ===============================

(element A
  (make sequence
	font-weight: 'bold
	font-posture: 'italic
	(process-children-trim)))


;; ============================ TABLES ===============================

(element TABLE
	 (make display-group
	       content-map: '((caption #f))
	       (make table
		     start-indent: *body-start-indent*
		     (make sequence
			   start-indent: 0pt))))

(element CAPTION
 (make paragraph
       label: 'caption
       use: p-style
       font-weight: 'bold
       space-before: *para-sep*
       space-after: (/ *para-sep* 2.0)
       start-indent: *body-start-indent*
       (literal
	(string-append
	 "Table "
	 (format-number
	  (element-number) "1")
	 ". "))
       (process-children-trim)))


(element TR
	 (make table-row
	       (process-children-trim)))

(element TH
 (make table-cell
       (make paragraph
	     font-weight: 'bold
	     space-before: 0.25em
	     space-after: 0.25em
	     start-indent: 0.25em
	     end-indent: 0.25em
	     quadding: 'start
	     (process-children-trim))))

(element TD
 (make table-cell
       (make paragraph
	     space-before: 0.25em
	     space-after: 0.25em
	     start-indent: 0.25em
	     end-indent: 0.25em
	     quadding: 'start
	     (process-children-trim))))


;; ============================== RULES ================================

(element HR
 (let ((align (attribute-string "ALIGN"))
       (noshade (attribute-string "NOSHADE"))
       (size (attribute-string "SIZE"))
       (width (attribute-string "WIDTH")))
  (make rule
	orientation: 'horizontal
	space-before: *block-sep*
	space-after: *block-sep*
	line-thickness: (if size
			    (PARSEDUNIT size)
			    1pt)
	length: (if width
		    (PARSEDUNIT width)
		    *body-width*)
	display-alignment: (case align
				 (("LEFT") 'start)
				 (("CENTER") 'center)
				 (("RIGHT") 'end)
				 (else 'end)))))


;; ============================= GRAPHICS ===============================

;; Note that DSSSL does not currently support text flowed around an
;;   object, so the action of the ALIGN attribute is merely to shift the
;;   image to the left or right.  An extension to add runarounds to DSSSL
;;   has been proposed and should be incorporated here when it becomes
;;   final.

(element IMG
  (make external-graphic
	entity-system-id: (attribute-string "src")
	display?: #t
	space-before: 1em
	space-after: 1em
	display-alignment: (case (attribute-string "align")
				 (("LEFT") 'start)
				 (("RIGHT") 'end)
				 (else 'center))))