diff --git a/quad/qtest/demo-footnotes.rkt b/quad/qtest/demo-footnotes.rkt new file mode 100644 index 00000000..7deeb47d --- /dev/null +++ b/quad/qtest/demo-footnotes.rkt @@ -0,0 +1,14 @@ +#lang quadwriter + +#:page-height "8in" +#:page-width "6in" + +"Hello" + +'(q ((flow "footnote")(font-size-adjust "80%")(line-height-adjust "70%")) "A convertible value in the sense of convertible? is used in a renderer-specific way, but values convertible to 'text renders the same as the resulting string. If a renderer is not able to convert the value to a known format, the value is converted to a string using write." (q ((break "para")))) + +" world." + +'(q ((flow "footnote")(font-size-adjust "80%")(line-height-adjust "70%")) "An instance of link-element has a tag for the target of the link." (q ((break "para")))) + +" I love you." \ No newline at end of file diff --git a/quad/quadwriter/attrs.rkt b/quad/quadwriter/attrs.rkt index a9fa7f76..19662fce 100644 --- a/quad/quadwriter/attrs.rkt +++ b/quad/quadwriter/attrs.rkt @@ -78,6 +78,7 @@ Naming guidelines link href line-height + line-height-adjust hyphenate list-index no-colbr diff --git a/quad/quadwriter/font.rkt b/quad/quadwriter/font.rkt index 5063eced..96789c34 100644 --- a/quad/quadwriter/font.rkt +++ b/quad/quadwriter/font.rkt @@ -75,10 +75,16 @@ (define (parse-percentage pstr) (/ (string->number (string-trim pstr "%")) 100.0)) -(define (resolve-font-size! attrs) - (define this-font-size (hash-ref! attrs :font-size default-font-size)) - (define this-font-size-adjust (parse-percentage (hash-ref! attrs :font-size-adjust "100%"))) - ;; we bake the adjustment into the font size... - (hash-set! attrs :font-size (* this-font-size this-font-size-adjust)) +(define (adjuster-base attrs key adjustment-key default-value) + (define this-val (hash-ref! attrs key default-value)) + (define this-val-adjust (parse-percentage (hash-ref! attrs adjustment-key "100%"))) + ;; we bake the adjustment into the val... + (hash-set! attrs key (and this-val (* this-val this-val-adjust))) ;; and then set the adjustment back to 100% (since it's now accounted for) - (hash-set! attrs :font-size-adjust "100%")) + (hash-set! attrs adjustment-key "100%")) + +(define (resolve-font-size! attrs) + (adjuster-base attrs :font-size :font-size-adjust default-font-size)) + +(define (resolve-line-height! attrs) + (adjuster-base attrs :line-height :line-height-adjust default-line-height)) diff --git a/quad/quadwriter/layout.rkt b/quad/quadwriter/layout.rkt index 06684267..a4e4abc3 100644 --- a/quad/quadwriter/layout.rkt +++ b/quad/quadwriter/layout.rkt @@ -670,7 +670,7 @@ [elems (from-parent (insert-blocks lns) 'nw)]))] [_ null])) -(define (column-wrap qs vertical-height column-gap [column-quad q:column]) +(define (column-wrap lines fn-lines vertical-height column-gap [column-quad q:column]) (unless (positive? vertical-height) (raise-argument-error 'column-wrap "positive number" vertical-height)) @@ -679,17 +679,27 @@ ;; could do it after, but it would require going back inside each col quad ;; which seems overly interdependent, because `insert-blocks` is used to determine break locations. ;; `col-wrap` should emit quads that are complete. + (define cols (wrap lines vertical-height + #:soft-break #true + #:hard-break column-break-quad? + #:no-break (λ (q) (quad-ref q :no-colbr)) ; cooperates with make-nobreak + #:distance (λ (q dist-so-far wrap-qs) + ;; do trial block insertions + (sum-y (insert-blocks (reverse wrap-qs)))) + #:finish-wrap (col-finish-wrap column-quad))) + (define reversed-fn-lines (match (reverse fn-lines) + [(? null?) null] + [reversed-fn-lines + (quad-update! (car reversed-fn-lines) + [from-parent 'sw]) + (for/list ([fn-line (in-list reversed-fn-lines)]) + (quad-update! fn-line + [from 'nw] + [to 'sw]))])) + (quad-update! (car cols) + [elems (append (quad-elems (car cols)) reversed-fn-lines)]) (define col-spacer (quad-copy q:column-spacer [size (pt column-gap 100)])) - (add-between - (wrap qs vertical-height - #:soft-break #true - #:hard-break column-break-quad? - #:no-break (λ (q) (quad-ref q :no-colbr)) ; cooperates with make-nobreak - #:distance (λ (q dist-so-far wrap-qs) - ;; do trial block insertions - (sum-y (insert-blocks (reverse wrap-qs)))) - #:finish-wrap (col-finish-wrap column-quad)) - col-spacer)) + (add-between cols col-spacer)) (define ((page-finish-wrap make-page-quad path) cols q0 q page-idx) (define page-quad (make-page-quad (+ (section-pages-used) page-idx))) diff --git a/quad/quadwriter/render.rkt b/quad/quadwriter/render.rkt index 2bfcd4fe..195593df 100644 --- a/quad/quadwriter/render.rkt +++ b/quad/quadwriter/render.rkt @@ -112,6 +112,7 @@ complete-every-path! resolve-font-path! resolve-font-size! + resolve-line-height! parse-font-features!))]) (proc attrs))) @@ -198,6 +199,8 @@ (hash-set! (pdf-info pdf) pdf-k (quad-ref (car qs) k ""))) (hash-set! (pdf-info pdf) 'Creator (format "Racket ~a (Quad library)" (version)))) +(define (footnote-flow? q) (equal? (quad-ref q 'flow) "footnote")) + (define/contract (render-pdf qx-arg pdf-path-arg [base-dir-arg #false] #:replace [replace-existing-file? #t] @@ -241,13 +244,16 @@ (define printable-height (- page-height top-margin bottom-margin)) (define column-count (setup-column-count qs)) (define column-gap (setup-column-gap qs)) + + (define-values (fn-qs main-qs) (partition footnote-flow? qs)) (define line-wrap-size (/ (- printable-width (* (sub1 column-count) column-gap)) column-count)) - (define line-qs (time-log line-wrap (apply-keeps (line-wrap qs line-wrap-size)))) + (define line-qs (time-log line-wrap (apply-keeps (line-wrap main-qs line-wrap-size)))) + (define fn-line-qs (time-log fn-line-wrap (apply-keeps (line-wrap fn-qs line-wrap-size)))) (define col-quad-prototype (quad-copy q:column [size (pt line-wrap-size printable-height)])) - (define column-qs (time-log column-wrap (column-wrap line-qs printable-height column-gap col-quad-prototype))) + (define column-qs (time-log column-wrap (column-wrap line-qs fn-line-qs printable-height column-gap col-quad-prototype))) (define page-quad-prototype (λ (page-count)