From c579f0b831210a5ece4ed52d5eea2e16fdaa6ec5 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Tue, 4 Feb 2020 13:28:10 -0800 Subject: [PATCH] allow em sizes for all dimension strings --- quad/quad/scribblings/quad.scrbl | 8 +++---- quad/quadwriter/attrs.rkt | 7 ++++-- quad/quadwriter/font.rkt | 39 ++++---------------------------- quad/quadwriter/render.rkt | 12 ++++------ 4 files changed, 19 insertions(+), 47 deletions(-) diff --git a/quad/quad/scribblings/quad.scrbl b/quad/quad/scribblings/quad.scrbl index ec7a1962..6f2cb10b 100644 --- a/quad/quad/scribblings/quad.scrbl +++ b/quad/quad/scribblings/quad.scrbl @@ -455,7 +455,7 @@ A section is a contiguous series of pages. Each section has its own @secref{Sect These are the attributes that can be used inside a @tech{Q-expression} passed to @racketmodname[quadwriter]. Inside a Q-expression, every attribute is a @tech[#:doc '(lib "scribblings/guide/guide.scrbl")]{symbol}, and every attribute value is a @tech[#:doc '(lib "scribblings/guide/guide.scrbl")]{string}. -A @deftech{dimension string} represents a distance in the plane. If unitless, it is treated as points (where 1 point = 1/72 of an inch). If the number has @racket[in], @racket[cm], or @racket[mm] as a suffix, it is treated as inches, centimeters, or millimeters respectively. +A @deftech{dimension string} represents a distance in the plane. If unitless, it is treated as points (where 1 point = 1/72 of an inch). If the number has @racket[in], @racket[cm], or @racket[mm] as a suffix, it is treated as inches, centimeters, or millimeters respectively. If the number has @racket[em] as a suffix, it is treated as an em measurement, which is a multiple of the current font size. @subsubsection{Document-level attributes} @@ -627,7 +627,7 @@ Sets the display type. Value is a string. Supply @racket["block"] as a value of } @defthing[#:kind "attribute" font-size symbol?]{ -Sets the point size for text. Value is a @tech{dimension string} or an em size (like @racket["1.2em"]). If an em size is provided, the font size is the size of the parent multiplied by the em. +Sets the point size for text. Value is a @tech{dimension string}. } @defthing[#:kind "attribute" font-family symbol?]{ @@ -654,7 +654,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 an em size (like @racket["0.15em"]). If an em size is provided, the font tracking is the current font size multiplied by the em. +Space between characters. Value is a @tech{dimension string}. } @defthing[#:kind "attribute" font-baseline-shift symbol?]{ @@ -667,7 +667,7 @@ Case transformation of string. Possibilities are @racket["uppercase"], @racket[" @defthing[#:kind "attribute" line-height symbol?]{ -Sets the distance between baselines. Value is a @tech{dimension string} or an em size (like @racket["1.2em"]). If an em size is provided, the line height is the current font size multiplied by em. +Sets the distance between baselines. Value is a @tech{dimension string}. } TK: OT feature attributes, bullet attributes diff --git a/quad/quadwriter/attrs.rkt b/quad/quadwriter/attrs.rkt index 15949be7..34e3df48 100644 --- a/quad/quadwriter/attrs.rkt +++ b/quad/quadwriter/attrs.rkt @@ -13,7 +13,7 @@ (define (in->pts x) (* 72 x)) (define (mm->cm x) (/ x 10.0)) -(define (parse-dimension x) +(define (parse-dimension x [em-resolution-attrs #false]) (match x [#false #false] [(? number? num) num] @@ -26,7 +26,10 @@ [(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 + [(regexp #rx"ems?$") (if em-resolution-attrs + (λ (num) (* (hash-ref em-resolution-attrs :font-size) num)) + ;; if we don't have attrs for resolving the em string, we leave it alone + (λ (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) diff --git a/quad/quadwriter/font.rkt b/quad/quadwriter/font.rkt index 06c32d29..a9946dbb 100644 --- a/quad/quadwriter/font.rkt +++ b/quad/quadwriter/font.rkt @@ -80,29 +80,19 @@ (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-adjustment pstr suffix) +(define (parse-em pstr) + (define em-suffix "em") (and pstr (string? pstr) - (string-suffix? pstr suffix) - (string->number (string-trim pstr suffix)))) - -(define (parse-em str) - (parse-adjustment str "em")) - -(define (parse-percentage pstr) - (match (parse-adjustment pstr "%") - [#false #false] - [res (/ res 100.0)])) - -(define (parse-percentage-or-em str) - (or (parse-percentage str) (parse-em str))) + (string-suffix? pstr em-suffix) + (string->number (string-trim pstr em-suffix)))) (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 val (parse-dimension (hash-ref attrs :font-size default-font-size))) (define adjustment (parse-em val)) ;; if our value represents an adjustment, we apply the adjustment to the previous value ;; otherwise we use our value directly @@ -113,22 +103,3 @@ ;; 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 ((make-updater-based-on-font-size attrs) val) - (define em-adjustment (parse-em val)) - (define base-height (if em-adjustment (hash-ref attrs :font-size) val)) - (and base-height (* base-height (or em-adjustment 1)))) - -(define (resolve-em attrs key) - (match (hash-ref attrs key #f) - [#false (void)] - [val - (define updater (make-updater-based-on-font-size attrs)) - (hash-set! attrs key (updater val))])) - -(define (resolve-line-height! attrs) - ;; convert line-height attributes into a simple line height - (resolve-em attrs :line-height)) - -(define (resolve-font-tracking! attrs) - (resolve-em attrs :font-tracking)) \ No newline at end of file diff --git a/quad/quadwriter/render.rkt b/quad/quadwriter/render.rkt index 4a9303b1..eb541ba1 100644 --- a/quad/quadwriter/render.rkt +++ b/quad/quadwriter/render.rkt @@ -94,7 +94,7 @@ ;; we parse them into the equivalent measurement in points. (for ([k (in-hash-keys attrs)] #:when (takes-dimension-string? k)) - (hash-update! attrs k parse-dimension)) + (hash-update! attrs k (λ (val) (parse-dimension val attrs)))) attrs) (define (downcase-values! attrs) @@ -119,14 +119,12 @@ (define (handle-cascading-attrs attrs) ;; various housekeeping on attributes as they are propagated downward during atomization. (for ([proc (in-list (list downcase-values! - parse-dimension-strings! complete-every-path! resolve-font-path! resolve-font-size! - ;; we resolve font tracking & line height after font size - ;; because they can be denoted relative to font size - resolve-font-tracking! - resolve-line-height! + ;; we resolve dimension strings after font size + ;; because they can be denoted relative to em size + parse-dimension-strings! parse-font-features!))]) (proc attrs))) @@ -329,7 +327,7 @@ (for* ([(page page-idx) (in-indexed (for*/list ([section (in-list (quad-elems doc))] [page (in-list (quad-elems section))]) page))] - ;; all inner / outer lines are initially filled as if they were right-aligned + ;; all inner / outer lines are initially filled as if they were right-aligned [zero-filler-side (in-value (if (odd? (add1 page-idx)) "inner" "outer"))] [col (in-list (quad-elems page))] [block (in-list (quad-elems col))]