[DSSSL style sheet for HTML 3.2 print output
Mirrored from:
ftp://sunsite.unc.edu:/pub/sun-info/standards/dsssl/stylesheets/html3_2/html32hc.dsl.960802. See also the README.]
;; ######################################################################
;;
;; DSSSL style sheet for HTML 3.2 print output
;;
;; 1996.08.02
;;
;; 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 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 *hf-size* (- *bf-size* 1pt))
(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 *bf-line-spacing* (* *bf-size* *line-spacing-factor*))
(define *mf-line-spacing* (* *mf-size* *line-spacing-factor*))
(define *hf-line-spacing* (* *hf-size* *line-spacing-factor*))
(define *head-before-factor* 1.0)
(define *head-after-factor* 0.6)
(define *autonum-level* 6) ;; zero disables autonumbering
(define *flushtext-headlevel* 4) ;; heads above this hang out on the left
(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)
(define *smaller-size-factor* 0.8)
;; ========================== COMMON 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 (char-downcase char)
(let loop ((c char) (a1 upperalpha) (a2 loweralpha))
(cond ((null? a1) '())
((char=? c (car a1)) (car a2))
((char=? c (car a2)) c)
(else (loop c (cdr a1) (cdr a2))))))
(define (LOCASE slist)
(if (null? slist)
'()
(cons (char-downcase (car slist)) (LOCASE (cdr slist)))))
(define (STR2LIST s)
(let ((len (string-length s)))
(let loop ((i 0) (ln len))
(if (= i len)
'()
(cons (string-ref s i) (loop (+ i 1) ln))))))
(define (STRING-DOWNCASE s)
(apply string (LOCASE (STR2LIST s))))
(define (UNAME-START-INDEX u last)
(let ((c (string-ref u last)))
(if (or (member c upperalpha) (member c loweralpha))
(if (= last 0)
0
(UNAME-START-INDEX u (- last 1)))
(+ last 1))))
(define (PARSEDUNIT u) ;; this doesn't deal with "%" yet
(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-line-spacing*
left-header:
(make sequence
font-size: *hf-size*
line-spacing: *hf-line-spacing*
font-posture: 'italic
(process-first-descendant "TITLE"))
right-footer:
(make sequence
font-size: *hf-size*
line-spacing: *hf-line-spacing*
(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))))
(element CENTER
(make display-group
quadding: 'center
(process-children-trim)))
;; .............................. Headings ..............................
(define *hlist* (list "H1" "H2" "H3" "H4" "H5" "H6"))
(define (NUMLABEL hlvl)
(let ((enl (element-number-list
(reverse (list-tail (reverse *hlist*) (- 6 hlvl))))))
(let loop ((idx 1))
(if (or (= idx *autonum-level*) (= idx hlvl))
(if (= idx 2) ". " " ")
(let ((thisnum (list-ref enl idx)))
(string-append
(if (> idx 1) "." "")
(format-number thisnum "1")
(loop (+ idx 1))))))))
(define ($heading$ headlevel)
(let ((headsize (if (= headlevel 6) 0 (- 5 headlevel))))
(make paragraph
font-family-name: *title-font-family*
font-weight: (if (< headlevel 6) 'bold 'medium)
font-posture: (if (< headlevel 6) 'upright 'italic)
font-size: (HSIZE headsize)
line-spacing: (* (HSIZE headsize) *line-spacing-factor*)
space-before: (* (HSIZE headsize) *head-before-factor*)
space-after: (* (HSIZE headsize) *head-after-factor*)
start-indent: *body-start-indent*
first-line-start-indent:
(if (< headlevel *flushtext-headlevel*)
(- *body-start-indent*)
0pt)
quadding: (HQUAD)
keep-with-next?: #t
(literal
(if (and (<= headlevel *autonum-level*) (> headlevel 1))
(NUMLABEL headlevel)
(string-append "")))
(process-children-trim))))
(element H1 ($heading$ 1))
(element H2 ($heading$ 2))
(element H3 ($heading$ 3))
(element H4 ($heading$ 4))
(element H5 ($heading$ 5))
(element H6 ($heading$ 6))
;; ............................ Paragraphs ..............................
(define p-style
(style
font-size: *bf-size*
line-spacing: *bf-line-spacing*))
(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* *smaller-size-factor*)
line-spacing: (* *bf-line-spacing* *smaller-size-factor*)
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 .....................
(define ($list-container$)
(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*)))
(define ($li-para$)
(make paragraph
use: p-style
start-indent: (+ (inherited-start-indent) (OLSTEP))
first-line-start-indent: (- (OLSTEP))
(process-children-trim)))
(element UL ($list-container$))
(element (UL LI)
(let ((isnested (> (length (hierarchical-number-recursive "UL")) 1)))
(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: (if isnested *bf-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 (if isnested
*small-diamond-bullet*
*disk-bullet*))))))
(process-children-trim))))
(element (UL LI P) ($li-para$))
(element OL ($list-container$))
(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) ($li-para$))
;; Note that DIR cannot properly have block children. Here DIR is
;; interpreted as an unmarked list without extra vertical
;; spacing.
(element DIR ($list-container$))
(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 ($list-container$))
(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-seq$)
(make sequence
font-weight: 'bold
(process-children-trim)))
(element B ($bold-seq$))
(element EM ($bold-seq$))
(element STRONG ($bold-seq$))
;; ------------
(define ($italic-seq$)
(make sequence
font-posture: 'italic
(process-children-trim)))
(element I ($italic-seq$))
(element CITE ($italic-seq$))
(element VAR ($italic-seq$))
;; ------------
(define ($bold-italic-seq$)
(make sequence
font-weight: 'bold
font-posture: 'italic
(process-children-trim)))
(element DFN ($bold-italic-seq$))
(element A ($bold-italic-seq$))
;; ------------
(define ($mono-seq$)
(make sequence
font-family-name: *mono-font-family*
font-size: *mf-size*
(process-children-trim)))
(element TT ($mono-seq$))
(element CODE ($mono-seq$))
(element KBD ($mono-seq$))
(element SAMP ($mono-seq$))
;; ------------
(define ($score-seq$ stype)
(make score
type: stype
(process-children-trim)))
(element STRIKE ($score-seq$ 'through))
(element U ($score-seq$ 'after))
;; ------------
(define ($ss-seq$ plus-or-minus)
(make sequence
font-size:
(* (inherited-font-size) *ss-size-factor*)
position-point-shift:
(plus-or-minus (* (inherited-font-size) *ss-shift-factor*))
(process-children-trim)))
(element SUP ($ss-seq$ +))
(element SUB ($ss-seq$ -))
;; ------------
(define ($bs-seq$ div-or-mult)
(make sequence
font-size:
(div-or-mult (inherited-font-size) *smaller-size-factor*)
line-spacing:
(div-or-mult (inherited-line-spacing) *smaller-size-factor*)))
(element BIG ($bs-seq$ /))
(element SMALL ($bs-seq$ *))
;; ------------
(element FONT
(let ((fsize (attribute-string "SIZE")))
(make sequence
font-size:
(if fsize (PARSEDUNIT fsize) (inherited-font-size)))))
;; ============================== TABLES ================================
(element TABLE
(make display-group
space-before: (* *block-sep* 2)
space-after: (* *block-sep* 2)
content-map: '((caption #f))
(make table
start-indent: *body-start-indent*
table-border: #t
(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))))