2 ;; Copyright (c) 2007, Cyrus Harmon
4 ;; typesetting.cl - cl-typesettng/cl-pdf output for smarkup
11 (defmacro with-paragraph
(style-designator &body body
)
12 (with-gensyms (top-margin bottom-margin first-line-indent
13 style new-style restore-style first-indent
)
14 `(let* ((,style
,style-designator
)
15 (,top-margin
(getf ,style
:top-margin
0))
16 (,bottom-margin
(getf ,style
:bottom-margin
0))
17 (,first-line-indent
(getf ,style
:first-line-indent
0))
18 (,new-style
(typecase ,style
20 (t (apply #'make-instance
'text-style
,style
))))
21 (,restore-style
(make-restore-style ,new-style
))
22 (,first-indent
,first-line-indent
))
24 (use-style ,new-style
)
25 (add-box (make-instance 'v-spacing
:dy
,top-margin
))
26 (unless (zerop ,first-indent
)
27 (add-box (make-instance 'h-spacing
:dx
,first-indent
)))
28 ,@(mapcar 'insert-stuff body
)
29 (unless (eq (first (boxes-tail *content
*)) :eol
)
31 (add-box (make-instance 'v-spacing
:dy
,bottom-margin
))
32 (add-box ,restore-style
)
33 (use-style ,restore-style
))))
37 (defgeneric %render-elt
(tag contents
))
39 (defun render-elts (sexp)
43 (defun put-smarkup-string (string)
45 (macrolet ((match-second-char (c1 c2 out-char
)
46 `(let ((n (peek-char nil in nil nil
)))
50 (write-char ,out-char out
))
51 (write-char ,c1 out
)))))
52 (with-output-to-string (out)
53 (with-input-from-string (in string
)
54 (loop for c
= (read-char in nil nil
) while c
57 (write-char #\No-Break_Space out
))
59 (match-second-char #\.
#\\ #\Space
))
61 (match-second-char #\
` #\
` (code-char #x93
)))
63 (match-second-char #\' #\' (code-char #x94
)))
65 (match-second-char #\-
#\-
(code-char #x97
)))
66 (t (write-char c out
)))))))))
68 (defun render-elt (elt)
69 #+nil
(print (car elt
))
71 (put-smarkup-string elt
))
73 (put-smarkup-string (car elt
))
74 (render-elt (cdr elt
)))
75 #+nil
((and elt
(atom elt
))
78 (%render-elt
(car elt
)
81 (render-elt (car elt
))
82 (render-elt (cdr elt
)))
85 (defun collect-elements (contents)
86 (apply #'concatenate
'string
(mapcar #'render-elt contents
)))
88 (defparameter *default-paragraph-font
*
95 (defmethod %render-elt
((tag (eql :p
)) contents
)
96 (tt::with-paragraph
*default-paragraph-font
*
97 (render-elt contents
)))
99 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
100 (defparameter *default-bold-font
*
101 '(:font
"Times-Bold")))
103 (defmacro highlight
(text)
104 `(tt:with-style
,*default-bold-font
*
107 (defmethod %render-elt
((tag (eql :b
)) contents
)
109 (render-elt contents
)))
111 (defparameter *default-h1-font
*
112 '(:h-align
:center
:font
"Helvetica-Bold" :font-size
14 :bottom-margin
3))
114 (defparameter *default-h2-font
*
115 '(:font
"Helvetica-Bold" :font-size
11 :bottom-margin
3 :top-margin
3))
117 (defmethod %render-elt
((tag (eql :h1
)) contents
)
118 (tt::with-paragraph
*default-h1-font
*
119 (render-elt contents
)))
121 (defmethod %render-elt
((tag (eql :h2
)) contents
)
122 (tt::with-paragraph
*default-h2-font
*
123 (render-elt contents
)))
125 (defmethod %render-elt
((tag (eql :span
)) contents
)
126 (render-elts contents
))
128 (defmethod %render-elt
((tag (eql :list
)) contents
)
129 (render-elts contents
))
131 (defparameter *item-decorator
*
132 (format nil
"~A " (code-char #x81
)))
134 (defparameter *default-item-font
*
138 *default-paragraph-font
*))
140 (defun get-item-decorator-width ()
141 (let ((font-size (or (getf *default-item-font
* :font-size
)
143 (let* ((item-font (getf *default-item-font
* :font
))
145 (pdf:get-font item-font
)
147 (loop for char across
*item-decorator
*
148 summing
(pdf:get-char-width char font font-size
)))))
150 (setf (getf *default-item-font
* :first-line-indent
)
151 (- (get-item-decorator-width)))
153 (defmethod %render-elt
((tag (eql :item
)) contents
)
154 (tt::with-paragraph
*default-item-font
*
155 (tt:put-string
*item-decorator
*)
156 (render-elt contents
)))
158 (defmethod %render-elt
(tag contents
)
159 (when contents
(render-elt (cdr contents
))))
161 (defmethod %render-elt
((tag (eql :eol
)) contents
)
163 (when contents
(render-elt contents
)))
165 (defparameter *pdf-header-function
* nil
)
167 (defmethod render-as ((type (eql :cl-pdf
)) sexp file
)
168 (setq nix
::*left-hyphen-minimum
* 999
169 nix
::*right-hyphen-minimum
* 999)
172 (tt::with-text-content
((make-instance 'tt
::text-content
) :dont-save-style t
)
173 (tt::add-box
(tt::copy-style
(tt::text-style tt
::*content
*)))
176 (apply #'tt
:draw-pages
179 :margins
'(72 72 72 72)
180 (when *pdf-header-function
*
181 `(:header
,(funcall *pdf-header-function
*))))
182 (when pdf
:*page
* (typeset:finalize-page pdf
:*page
*))
183 (tt:write-document file
))))