From 78debc7c4f6429351f7b29e9479a5db818bf6ddc Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Thu, 30 Jan 2020 08:55:23 -0800 Subject: [PATCH] support percentage & em for font-tracking attr --- quad/qtest/test-font-tracking-tester.pdf | Bin 0 -> 7847 bytes quad/qtest/test-font-tracking.rkt | 7 ++++ quad/quad/scribblings/quad.scrbl | 2 +- quad/quadwriter/font.rkt | 48 ++++++++++++----------- 4 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 quad/qtest/test-font-tracking-tester.pdf create mode 100644 quad/qtest/test-font-tracking.rkt diff --git a/quad/qtest/test-font-tracking-tester.pdf b/quad/qtest/test-font-tracking-tester.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dd0fbed1531635c142c3511224ab523f29a79c71 GIT binary patch literal 7847 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 literal 0 HcmV?d00001 diff --git a/quad/qtest/test-font-tracking.rkt b/quad/qtest/test-font-tracking.rkt new file mode 100644 index 00000000..f0926354 --- /dev/null +++ b/quad/qtest/test-font-tracking.rkt @@ -0,0 +1,7 @@ +#lang quadwriter + +'(q ((font-size "24")(font-tracking "6")) "we have the same tracking") +'(q ((break "para"))) +'(q ((font-size "24")(font-tracking "25%")) "we have the same tracking") +'(q ((break "para"))) +'(q ((font-size "24")(font-tracking "0.25em")) "we have the same tracking") diff --git a/quad/quad/scribblings/quad.scrbl b/quad/quad/scribblings/quad.scrbl index 16786ccf..d081a139 100644 --- a/quad/quad/scribblings/quad.scrbl +++ b/quad/quad/scribblings/quad.scrbl @@ -653,7 +653,7 @@ Sets OpenType layout features. @racket[font-features] takes a @deftech{feature s @defthing[#:kind "attribute" font-tracking symbol?]{ -Space between characters. Value is a @tech{dimension string} or a percentage (like @racket["12%"]), which is interpreted as a percentage of the font size. +Space between characters. Value is a @tech{dimension string}, a string representing a percentage (like @racket["15%"]), or an em size (like @racket["0.15em"]). If a percentage or em size is provided, the font tracking is the current font size multiplied by the percentage (or em). } @defthing[#:kind "attribute" font-baseline-shift symbol?]{ diff --git a/quad/quadwriter/font.rkt b/quad/quadwriter/font.rkt index 18b53793..12b20eee 100644 --- a/quad/quadwriter/font.rkt +++ b/quad/quadwriter/font.rkt @@ -40,21 +40,21 @@ #:when (directory-exists? font-family-subdir) [font-path (in-directory font-family-subdir)] #:when (member (path-get-extension font-path) font-file-extensions)) - (match-define (list font-path-string family-name) - (for/list ([x (list font-path font-family-subdir)]) - (path->string (find-relative-path fonts-dir x)))) - (define path-parts (for/list ([part (in-list (explode-path (string->path (string-downcase font-path-string))))]) - (path->string part))) - (define key - (cons (string-downcase family-name) - (cond - [(member "bold-italic" path-parts) 'bi] - [(member "bold" path-parts) 'b] - [(member "italic" path-parts) 'i] - [else 'r]))) - ;; only set value if there's not one there already. - ;; this means that we only use the first eligible font we find. - (hash-ref! font-paths key font-path))) + (match-define (list font-path-string family-name) + (for/list ([x (list font-path font-family-subdir)]) + (path->string (find-relative-path fonts-dir x)))) + (define path-parts (for/list ([part (in-list (explode-path (string->path (string-downcase font-path-string))))]) + (path->string part))) + (define key + (cons (string-downcase family-name) + (cond + [(member "bold-italic" path-parts) 'bi] + [(member "bold" path-parts) 'b] + [(member "italic" path-parts) 'i] + [else 'r]))) + ;; only set value if there's not one there already. + ;; this means that we only use the first eligible font we find. + (hash-ref! font-paths key font-path))) (define (font-attrs->path font-family bold italic) ;; find the font-path corresponding to a certain family name and style. @@ -92,12 +92,15 @@ [#false #false] [res (/ res 100.0)])) +(define (parse-percentage-or-em str) + (or (parse-percentage str) (parse-adjustment str "em"))) + (define (resolve-font-size! attrs) ;; convert font-size attributes into a simple 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"))) + (define adjustment (parse-percentage-or-em val)) ;; 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)) @@ -112,14 +115,15 @@ ;; convert line-height attributes into a simple line height (hash-update! attrs :line-height (λ (val) - (define adjustment (or (parse-percentage val) (parse-adjustment val "em"))) + (define adjustment (parse-percentage-or-em val)) (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. - ;; if it's anything else, we're done. - (match (parse-percentage (hash-ref attrs :font-tracking #false)) - [#false (void)] - [pct (hash-set! attrs :font-tracking (* pct (hash-ref attrs :font-size)))])) \ No newline at end of file + (hash-update! attrs :font-tracking + (λ (val) + (define adjustment (parse-percentage-or-em val)) + (define base-tracking (if adjustment (hash-ref attrs :font-size) val)) + (and base-tracking (* base-tracking (or adjustment 1)))) + 0)) \ No newline at end of file