main
Matthew Butterick 10 years ago
parent 0d6af821a2
commit d09c4f7192

@ -2,8 +2,8 @@
(require (for-syntax racket/base racket/syntax))
(require/typed sugar/list [slicef-after ((Listof Quad) (Quad . -> . Boolean) . -> . (Listof (Listof Quad)))]
;; shift: need False in type because shift fills with #f
[shift ((Listof Quad) (Listof Integer) . -> . (Listof (Listof (U False Quad))))]
[break-at ((Listof PieceQuad) (Listof Nonnegative-Integer) . -> . (Listof (Listof PieceQuad)))])
[shift ((Listof Quad) (Listof Integer) . -> . (List (Listof (U False Quad)) (Listof (U False Quad))))]
[break-at ((Listof PieceQuad) (Listof Breakpoint) . -> . (Listof (Listof PieceQuad)))])
(require math/flonum (except-in racket/list flatten) racket/vector math/statistics racket/bool)
(require/typed racket/list [flatten (All (A) (Rec as (U Any (Listof as))) -> (Listof Any))])
(require "ocm-typed.rkt" "quads-typed.rkt" "utils-typed.rkt" "measure-typed.rkt" "world-typed.rkt" "logger-typed.rkt" "core-types.rkt" "utils-typed.rkt")
@ -212,7 +212,7 @@
(define shifted-lists (shift exploded-line-quads '(1 -1)))
(define lefts (first shifted-lists))
(define rights (second shifted-lists))
(for/list : (Listof Quad) ([(q-left q q-right) (in-parallel lefts exploded-line-quads rights)])
(for/list : (Listof Quad) ([q-left (in-list lefts)][q (in-list exploded-line-quads)][q-right (in-list rights)])
(if (optical-kern? q)
(quad-attr-set q world:width-key (fl+ (overhang-width q-left) (overhang-width q-right)))
q))]
@ -251,12 +251,14 @@
(apply line (quad-attrs line-in)
(flatten-quadtree (let ([qs (quad-list line-in)])
(list (if before (copy-with-attrs before (first qs)) null)
(map (λ([q : Quad]) (if (and middle (takes-justification-space? q))
(let ([interleaver (copy-with-attrs middle q)])
(list interleaver q interleaver))
(list q))) qs)
(if after (copy-with-attrs after (last qs)) null))))))
(if (not (empty? qs))
(list (if before (copy-with-attrs before (first qs)) null)
(map (λ([q : Quad]) (if (and middle (takes-justification-space? q))
(let ([interleaver (copy-with-attrs middle q)])
(list interleaver q interleaver))
(list q))) qs)
(if after (copy-with-attrs after (last qs)) null))
qs)))))
;; installs the width in the quad.
@ -289,41 +291,39 @@
(define-type Compose-Line-Type ((Listof PieceQuad) (Quad . -> . Float) . -> . LineQuad))
(define/typed (pieces->line ps measure-quad-proc)
Compose-Line-Type
;; handle optical kerns here to avoid resplitting and rejoining later.
(define rendered-pieces (render-pieces ps))
(define split-pieces (map quad-list rendered-pieces))
(define line-quads (let ([result (append* split-pieces)])
(if (andmap Quad? result)
result
(error 'line-quads "bad result"))))
(define line-quads-maybe-with-opticals
(if (and world:use-optical-kerns? (> (length line-quads) 0))
(render-optical-kerns
(let ([my-ok (list (optical-kern (quad-attrs (car line-quads))))]) ; take attrs from line, incl measure
(append my-ok line-quads my-ok)))
line-quads))
(define merged-quads (join-quads line-quads-maybe-with-opticals))
(define merged-quad-widths (map measure-quad-proc merged-quads)) ; 10% of function time
(log-quad-debug "making pieces into line = ~v" (apply string-append (map quad->string merged-quads)))
;; if measure key isn't present, allow an error, because that's weird
(when (not (quad-has-attr? (first line-quads) world:measure-key))
(error 'pieces->line "quad has no measure key: ~a" (first line-quads)))
(define measure (let ([val (quad-attr-ref (first merged-quads) world:measure-key)])
(if (flonum? val)
val
(error "got bad value for measure"))))
(define looseness (calc-looseness (foldl fl+ 0.0 merged-quad-widths) measure))
;; quads->line function hoists common attributes into the line
(let* ([new-line-quads (map embed-width merged-quads merged-quad-widths)]
[new-line-quads (map record-ascent new-line-quads)]
[new-line (quads->line new-line-quads)]
[new-line (apply line (attr-change (quad-attrs new-line) (list world:line-looseness-key looseness)) (quad-list new-line))])
new-line))
(cond
[(not (empty? rendered-pieces))
;; handle optical kerns here to avoid resplitting and rejoining later.
(define line-quads (assert (append-map quad-list rendered-pieces) (λ(lqs) (not (empty? lqs)))))
(define line-quads-maybe-with-opticals
(if world:use-optical-kerns?
(render-optical-kerns
(let ([my-ok (list (optical-kern (quad-attrs (first line-quads))))]) ; take attrs from line, incl measure
(append my-ok line-quads my-ok)))
line-quads))
(define merged-quads (assert (join-quads line-quads-maybe-with-opticals) (λ(mqs) (not (empty? mqs)))))
(define merged-quad-widths (map measure-quad-proc merged-quads)) ; 10% of function time
(log-quad-debug "making pieces into line = ~v" (apply string-append (map quad->string merged-quads)))
;; if measure key isn't present, allow an error, because that's weird
(when (not (quad-has-attr? (first merged-quads) world:measure-key))
(error 'pieces->line "quad has no measure key: ~a" (first merged-quads)))
(define measure (let ([val (quad-attr-ref (first merged-quads) world:measure-key)])
(if (flonum? val)
val
(error "got bad value for measure"))))
(define looseness (calc-looseness (foldl fl+ 0.0 merged-quad-widths) measure))
;; quads->line function hoists common attributes into the line
(let* ([new-line-quads (map embed-width merged-quads merged-quad-widths)]
[new-line-quads (map record-ascent new-line-quads)]
[new-line (quads->line new-line-quads)]
[new-line (apply line (attr-change (quad-attrs new-line) (list world:line-looseness-key looseness)) (quad-list new-line))])
new-line)]
[else (line)]))
;; a faster line-measuring function used by the wrapping function to test lines.
@ -351,15 +351,17 @@
find-breakpoints-proc)
((Make-Pieces-Type Measure-Quad-Type Compose-Line-Type Find-Breakpoints-Type) () . ->* . Wrap-Proc-Type)
(λ(qs [measure #f])
(let* ([measure (or measure (assert (quad-attr-ref/parameter (car qs) world:measure-key) flonum?))]
[qs (if (quad-has-attr? (car qs) world:measure-key)
qs
((inst map Quad Quad) (λ(q) (quad-attr-set q world:measure-key measure)) qs))])
(log-quad-debug "wrapping on measure = ~a" measure)
(define pieces (make-pieces-proc qs))
(define bps (find-breakpoints-proc (list->vector pieces) measure))
(define broken-pieces (break-at pieces bps))
(map (λ([broken-piece : (Listof PieceQuad)]) (compose-line-proc broken-piece measure-quad-proc)) broken-pieces))))
(if (not (empty? qs))
(let* ([measure (or measure (assert (quad-attr-ref/parameter (car qs) world:measure-key) flonum?))]
[qs (if (quad-has-attr? (car qs) world:measure-key)
qs
((inst map Quad Quad) (λ(q) (quad-attr-set q world:measure-key measure)) qs))])
(log-quad-debug "wrapping on measure = ~a" measure)
(define pieces (make-pieces-proc qs))
(define bps (find-breakpoints-proc (list->vector pieces) measure))
(define broken-pieces (break-at pieces bps))
(map (λ([broken-piece : (Listof PieceQuad)]) (compose-line-proc broken-piece measure-quad-proc)) broken-pieces))
(list (line)))))
(define width? flonum?)
(define measure? flonum?)
@ -387,10 +389,10 @@
(vector
;; throw in 0.0 in case for/list returns empty
(foldl fl+ 0.0 (for/list : (Listof Float) ([q (in-list (quad-list p))])
(define str (quad->string q))
(if (equal? str "")
(assert (quad-attr-ref q world:width-key 0.0) flonum?)
(apply measure-text (quad->string q) (font-attributes-with-defaults q)))))
(define str (quad->string q))
(if (equal? str "")
(assert (quad-attr-ref q world:width-key 0.0) flonum?)
(apply measure-text (quad->string q) (font-attributes-with-defaults q)))))
(if wb (apply measure-text (assert (quad-attr-ref wb world:no-break-key) string?) (font-attributes-with-defaults wb)) 0.0)
(if wb (apply measure-text (assert (quad-attr-ref wb world:before-break-key) string?) (font-attributes-with-defaults wb)) 0.0))))
(values
@ -426,15 +428,21 @@
(define pieces-with-word-space (vector-map (λ([piece : PieceQuad]) (and (quad-has-attr? piece world:word-break-key) (equal? (quad-attr-ref (assert (quad-attr-ref piece world:word-break-key) quad?) 'nb) " "))) pieces))
(define (make-first-fit-bps-and-widths)
(define-values (folded-bps folded-widths)
(for/fold ([bps : (Listof Breakpoint) '(0)][line-widths : (Listof Float) empty])([j-1 : Breakpoint (in-range (vector-length pieces))])
(define-values (reversed-bps reversed-widths)
;; breakpoints get stacked onto bps, so (car bps) is always the next starting point
;; thus use '(0) as a starting value to indicate that the first line starts at bp 0
;; bps will end up with at least two values (if all pieces fit on first line, bps = 0 and last bp)
(for/fold ([bps : (Pairof Breakpoint (Listof Breakpoint)) '(0) ][line-widths : (Listof Float) empty])
([j-1 : Breakpoint (in-range (vector-length pieces))])
(define line-starting-bp (car bps))
(define line-width (get-line-width (make-trial-line pieces-rendered-widths
pieces-rendered-before-break-widths
(car bps) (add1 j-1))))
line-starting-bp (add1 j-1))))
(if (fl> line-width (fl* world:allowed-overfull-ratio measure))
(values (cons j-1 bps) (cons line-width line-widths))
(values bps line-widths))))
(values (cdr (reverse folded-bps)) (reverse folded-widths)))
(define bps (reverse reversed-bps))
(values (if (not (empty? bps)) (cdr bps) empty) (reverse reversed-widths)))
(define (fu-formula)
(define line-count (length trial-line-widths))
@ -506,7 +514,7 @@
;; 0 penalty means any length is ok.
;[(< (length pieces-to-test) (world:minimum-last-line-pieces)) 50000]
[else 0.0]))))))]))
(define ocm : OCM-Type (make-ocm penalty (cast $penalty->value Entry->Value-Type) initial-value))
;; starting from last position, ask ocm for position of row minimum (= new-pos)
@ -563,7 +571,7 @@
(define target-width (or target-width? (assert (quad-attr-ref starting-quad world:measure-key) flonum?)))
(define subquads (quad-list starting-quad))
(define-values (flexible-subquads fixed-subquads) (partition spacer? subquads)) ; only puts fill into spacers.
(define width-used (apply + ((inst map Float Quad) quad-width fixed-subquads)))
(define width-used (foldl fl+ 0.0 (map quad-width fixed-subquads)))
(define width-remaining (round-float (- target-width width-used)))
(cond
;; check for zero condition because we want to divide by this number

Loading…
Cancel
Save