diff --git a/quad/qtest/test-adjustment-sizing-tester.pdf b/quad/qtest/test-adjustment-sizing-tester.pdf new file mode 100644 index 00000000..4d1d1c75 Binary files /dev/null and b/quad/qtest/test-adjustment-sizing-tester.pdf differ diff --git a/quad/qtest/test-adjustment-sizing.rkt b/quad/qtest/test-adjustment-sizing.rkt new file mode 100644 index 00000000..65f48022 --- /dev/null +++ b/quad/qtest/test-adjustment-sizing.rkt @@ -0,0 +1,7 @@ +#lang quadwriter + + +'(q ((column-count "2")(font-size "18")(line-height "2em")) "The lines in both columns should be vertically aligned. The column on the left is font size 18pt with line height 2em, or 36pt. The right column is font size 50%, or 9pt, with line height 4em, or 36pt." +(q ((break "column"))) +(q ((break "para"))) +(q ((font-size "50%")(line-height "4em")) "The lines in both columns should be vertically aligned. The column on the left is font size 18pt with line height 2em, or 36pt. The right column is font size 50%, or 9pt, with line height 4em, or 36pt.")) \ No newline at end of file diff --git a/quad/quad/scribblings/quad.scrbl b/quad/quad/scribblings/quad.scrbl index 891bafe5..a993117e 100644 --- a/quad/quad/scribblings/quad.scrbl +++ b/quad/quad/scribblings/quad.scrbl @@ -118,7 +118,7 @@ Next, on the REPL enter this: You will see the actual input to Quadwriter, which is called a @tech{Q-expression}: @repl-output{ -'(q () (q ((page-margin-left "120") (page-margin-top "80") (page-margin-bottom "120") (font-family "text") (line-height "17")) (q ((keep-first-lines "2") (keep-last-lines "3") (font-size-adjust "100%") (character-tracking "0") (hyphenate "true") (display "g49598")) "Brennan and Dale like fancy sauce."))) +'(q () (q ((page-margin-left "120") (page-margin-top "80") (page-margin-bottom "120") (font-family "text") (line-height "17")) (q ((keep-first-lines "2") (keep-last-lines "3") (font-size "100%") (character-tracking "0") (hyphenate "true") (display "g49598")) "Brennan and Dale like fancy sauce."))) } In the demos that follow, the input language will change slightly. But the PDF will be rendered the same way (by running the source file) and you can always look at @racket[doc] or use @racket[view-output]. @@ -625,9 +625,8 @@ Specify a quad with an image (either @racket{.png} or @racket{.jpeg}). @racket[i Sets the display type. Value is a string. Supply @racket["block"] as a value of this attribute to make the quad behave as a block-level element. } -@deftogether[(@defthing[#:kind "attribute" font-size symbol?] - @defthing[#:kind "attribute" font-size-adjust symbol?])]{ -Two ways of setting the point size for text. @racket[font-size] takes a @tech{dimension string}. @racket[font-size-adjust] takes a string representing a percentage (like @racket["120%"]) and sets the font size to the size of the parent, multiplied by the percentage. +@defthing[#:kind "attribute" font-size symbol?]{ +Sets the point size for text. Value is a @tech{dimension string}, a string representing a percentage (like @racket["120%"]), or an em size (like @racket["1.2em"]). If a percentage or em size is provided, the font size is the size of the parent multiplied by the percentage (or em). } @defthing[#:kind "attribute" font-family symbol?]{ @@ -666,9 +665,9 @@ Vertical offset of font baseline (positive values move the baseline up, negative Case transformation of string. Possibilities are @racket["uppercase"], @racket["lowercase"], or @racket["capitalize"] (= first letter of each word is uppercase, the rest is lowercase). } -@deftogether[(@defthing[#:kind "attribute" line-height symbol?] - @defthing[#:kind "attribute" line-height-adjust symbol?])]{ -Two ways of setting the distance between baselines. @racket[line-height] takes a @tech{dimension string}. @racket[line-height-adjust] takes a string representing a percentage (like @racket["120%"]) and sets the line height to the line height of the parent, multiplied by the percentage. + +@defthing[#:kind "attribute" line-height symbol?]{ +Sets the distance between baselines. Value is a @tech{dimension string}, a string representing a percentage (like @racket["120%"]), or an em size (like @racket["1.2em"]). If a percentage or em size is provided, the line height is the current font size multiplied by the percentage (or em). } TK: OT feature attributes, bullet attributes diff --git a/quad/quadwriter/attrs.rkt b/quad/quadwriter/attrs.rkt index 2d534c6f..555166e4 100644 --- a/quad/quadwriter/attrs.rkt +++ b/quad/quadwriter/attrs.rkt @@ -22,10 +22,11 @@ [#false str] ; a string other than a dimension string, so leave it [(list _ num-string unit) ((match unit - [(regexp #rx"(pt|point)(s)?$") values] - [(regexp #rx"in(ch(es)?)?$") in->pts] - [(regexp #rx"cm$") (compose1 in->pts cm->in)] - [(regexp #rx"mm$") (compose1 in->pts cm->in mm->cm)] + [(regexp #rx"(pt|point)(s)?$") values] ; points + [(regexp #rx"in(ch(es)?)?$") in->pts] ; inches + [(regexp #rx"cms?$") (compose1 in->pts cm->in)] ; cm + [(regexp #rx"mms?$") (compose1 in->pts cm->in mm->cm)] ; mm + [(regexp #rx"ems?$") (λ (num) (format "~aem" num))] ; em [_ (raise-argument-error 'parse-dimension "dimension string" str)]) (string->number num-string))])])) (define (copy-block-attrs source-hash dest-hash) @@ -66,7 +67,6 @@ Naming guidelines (define-attrs (font-family font-path font-size - font-size-adjust font-color font-features font-features-adjust @@ -79,7 +79,6 @@ Naming guidelines link href line-height - line-height-adjust hyphenate list-index no-colbr @@ -226,4 +225,4 @@ Naming guidelines :pdf-keywords)) #true)) (define (takes-path? k) - (and (memq k (list :image-file)) #true)) \ No newline at end of file + (and (memq k (list :image-file)) #true)) diff --git a/quad/quadwriter/font.rkt b/quad/quadwriter/font.rkt index c2f42036..18b53793 100644 --- a/quad/quadwriter/font.rkt +++ b/quad/quadwriter/font.rkt @@ -80,31 +80,42 @@ (define this-italic (hash-ref! attrs :font-italic #false)) (hash-set! attrs :font-path (font-attrs->path this-font-family this-bold this-italic)))) -(define (parse-percentage pstr) +(define (parse-adjustment pstr suffix) (and + pstr (string? pstr) - (string-suffix? pstr "%") - (/ (string->number (string-trim pstr "%")) 100.0))) + (string-suffix? pstr suffix) + (string->number (string-trim pstr suffix)))) -(define (adjuster-base attrs key adjustment-key default-value) - ;; font size and line height use this helper. - ;; because they both can be specified directly, - ;; or as an "adjustment" to the parent value, in which case - ;; we get the parent value and perform the adjustment. - (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 adjustment-key "100%")) +(define (parse-percentage pstr) + (match (parse-adjustment pstr "%") + [#false #false] + [res (/ res 100.0)])) (define (resolve-font-size! attrs) ;; convert font-size attributes into a simple font size - (adjuster-base attrs :font-size :font-size-adjust default-font-size)) + ;; we stashed the previous size in private key 'font-size-previous + (define prev-font-size-key 'font-size-previous) + (define val (hash-ref attrs :font-size default-font-size)) + (define adjustment (or (parse-percentage val) (parse-adjustment val "em"))) + ;; if our value represents an adjustment, we apply the adjustment to the previous value + ;; otherwise we use our value directly + (define base-size (if adjustment (hash-ref attrs prev-font-size-key default-font-size) val)) + (define base-size-adjusted (and base-size (* base-size (or adjustment 1)))) + ;; we write our new value into both font-size and font-size-previous + ;; because as we cascade down, we're likely to come across superseding values + ;; of font-size (but font-size-previous will persist) + (hash-set! attrs :font-size base-size-adjusted) + (hash-set! attrs prev-font-size-key base-size-adjusted)) (define (resolve-line-height! attrs) ;; convert line-height attributes into a simple line height - (adjuster-base attrs :line-height :line-height-adjust default-line-height)) + (hash-update! attrs :line-height + (λ (val) + (define adjustment (or (parse-percentage val) (parse-adjustment val "em"))) + (define base-height (if adjustment (hash-ref attrs :font-size) val)) + (and base-height (* base-height (or adjustment 1)))) + default-line-height)) (define (resolve-font-tracking! attrs) ;; if it's a percentage, we need to look at the font size. diff --git a/quad/quadwriter/render.rkt b/quad/quadwriter/render.rkt index 6134c988..5c1e6317 100644 --- a/quad/quadwriter/render.rkt +++ b/quad/quadwriter/render.rkt @@ -105,7 +105,9 @@ resolve-font-path! resolve-font-size! resolve-font-tracking! - resolve-line-height! + ;; we resolve line height after font size + ;; because line height might be dependent + resolve-line-height! parse-font-features!))]) (proc attrs))) diff --git a/quad/quadwriter/tags.rkt b/quad/quadwriter/tags.rkt index 51aa714c..2d118d31 100644 --- a/quad/quadwriter/tags.rkt +++ b/quad/quadwriter/tags.rkt @@ -25,7 +25,7 @@ [_ (qexpr (append (list->attrs :keep-first-lines "2" :keep-last-lines "3" - :font-size-adjust "100%" + :font-size "100%" :hyphenate "true" :display (symbol->string (gensym))) attrs) exprs)])) @@ -77,7 +77,7 @@ (define-tag-function (strong attrs exprs) (qexpr (append (list->attrs :font-bold "true" - :font-size-adjust "100%") + :font-size "100%") attrs) exprs)) (define b strong) @@ -91,7 +91,7 @@ (qexpr (append (list->attrs :font-italic "true" - :font-size-adjust "100%") attrs) exprs)) + :font-size "100%") attrs) exprs)) (define i em)