From 3fd8cefdde32d68ba76ee35255be7cc0befa7ac1 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Tue, 20 Jun 2017 11:08:40 -0700 Subject: [PATCH] progress --- pitfall/fontkit/font.rkt | 2 +- pitfall/fontkit/glyph-position.rkt | 2 +- pitfall/fontkit/glyphrun.rkt | 2 +- pitfall/pitfall/embedded.rkt | 140 ++++++++++++---------- pitfall/pitfall/pdftest.rkt | 8 +- pitfall/pitfall/racket.rkt | 3 +- pitfall/pitfall/test/out.bin | Bin 4318 -> 4054 bytes pitfall/pitfall/test/test14rkt copy 2.pdf | Bin 0 -> 6452 bytes pitfall/pitfall/test/test15.pdf | Bin 6029 -> 6029 bytes pitfall/pitfall/test/test15.rkt | 19 +-- pitfall/pitfall/test/test15rkt.pdf | Bin 5993 -> 0 bytes pitfall/sugar/contract.rkt | 5 + 12 files changed, 95 insertions(+), 86 deletions(-) create mode 100644 pitfall/pitfall/test/test14rkt copy 2.pdf create mode 100644 pitfall/sugar/contract.rkt diff --git a/pitfall/fontkit/font.rkt b/pitfall/fontkit/font.rkt index fbc0ee2f..c9826ddb 100644 --- a/pitfall/fontkit/font.rkt +++ b/pitfall/fontkit/font.rkt @@ -233,7 +233,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js ;; Returns a GlyphRun object, which includes an array of Glyphs and GlyphPositions for the given string. (define/contract (layout this string [userFeatures #f] [script #f] [language #f]) - ((string?) ((or/c (listof symbol?) #f) (or/c symbol? #f) (or/c symbol? #f)) . ->*m . (is-a?/c GlyphRun)) + ((string?) ((or/c (listof symbol?) #f) (or/c symbol? #f) (or/c symbol? #f)) . ->*m . GlyphRun?) (unless (· this _layoutEngine) (set-field! _layoutEngine this (make-object LayoutEngine this))) (report 'in-layout) diff --git a/pitfall/fontkit/glyph-position.rkt b/pitfall/fontkit/glyph-position.rkt index 34b149ff..16b07f29 100644 --- a/pitfall/fontkit/glyph-position.rkt +++ b/pitfall/fontkit/glyph-position.rkt @@ -1,5 +1,5 @@ #lang fontkit/racket -(provide GlyphPosition) +(provide (all-defined-out)) ;; Represents positioning information for a glyph in a GlyphRun. (define-subclass object% (GlyphPosition diff --git a/pitfall/fontkit/glyphrun.rkt b/pitfall/fontkit/glyphrun.rkt index 07c7f520..5dc0f8e8 100644 --- a/pitfall/fontkit/glyphrun.rkt +++ b/pitfall/fontkit/glyphrun.rkt @@ -1,6 +1,6 @@ #lang fontkit/racket (require "bbox.rkt" "script.rkt") -(provide GlyphRun) +(provide (all-defined-out)) ;; Represents a run of Glyph and GlyphPosition objects. ;; Returned by the font layout method. diff --git a/pitfall/pitfall/embedded.rkt b/pitfall/pitfall/embedded.rkt index 87dd9a65..2dca7cb6 100644 --- a/pitfall/pitfall/embedded.rkt +++ b/pitfall/pitfall/embedded.rkt @@ -28,45 +28,47 @@ https://github.com/mbutterick/pdfkit/blob/master/lib/font/embedded.coffee embed toUnicodeCmap)) -(define/contract (widthOfString this str size [features #f]) - ((string? number?) ((or/c list? #f)) . ->*m . number?) - #| -PDFKit makes a whole layout here and measures that. -For now, we'll just measure width of the characters. -|# - #;(define run (send (· this font) layout string)) ; todo: features would be passed here - #;(define width (· run advanceWidth)) - #;(define scale (/ size (· this font unitsPerEm))) - #;(* width scale) - (send (· this font) measure-string str size)) +(define/contract (widthOfString this string size [features #f]) + ((string? number?) ((option/c list?)) . ->*m . number?) + (cond + [features + (define run (send (· this font) layout string features)) ; todo: features would be passed here + (define width (· run advanceWidth)) + (define scale (/ size (· this font unitsPerEm))) + (* width scale)] + [else (send (· this font) measure-string string size)])) ;; called from text.rkt (define/contract (encode this text [features #f]) - ((string?) ((or/c list? #f)) . ->*m . - (list/c (listof string?) (listof (is-a?/c GlyphPosition)))) + ((string?) ((option/c list?)) . ->*m . + (list/c (listof string?) (listof GlyphPosition?))) (define glyphRun (send (· this font) layout text features)) (define glyphs (· glyphRun glyphs)) (for ([g (in-list glyphs)]) - (· g id)) + (· g id)) (define positions (· glyphRun positions)) (define-values (subset-idxs new-positions) (for/lists (idxs posns) - ([(glyph i) (in-indexed glyphs)] - [posn (in-list positions)]) - (define gid (send (· this subset) includeGlyph (· glyph id))) - (define subset-idx (toHex gid)) - (set-field! advanceWidth posn (· glyph advanceWidth)) + ([(glyph i) (in-indexed glyphs)] + [posn (in-list positions)]) + (define gid (send (· this subset) includeGlyph (· glyph id))) + (define subset-idx (toHex gid)) + (set-field! advanceWidth posn (· glyph advanceWidth)) - (hash-ref! (· this widths) gid (λ () (· posn advanceWidth))) - (hash-ref! (· this unicode) gid (λ () (· glyph codePoints))) + (hash-ref! (· this widths) gid (λ () (· posn advanceWidth))) + (hash-ref! (· this unicode) gid (λ () (· glyph codePoints))) - (send posn scale (· this scale)) - (values subset-idx posn))) + (send posn scale (· this scale)) + (values subset-idx posn))) (list subset-idxs new-positions)) -(require racket/runtime-path) -(define-runtime-path charter-path "test/assets/charter.ttf") + +(define-macro (sum-flags [COND VAL] ...) + #'(for/sum ([c (in-list (list COND ...))] + [v (in-list (list VAL ...))] + #:when c) + v)) (define/contract (embed this) (->m void?) @@ -79,21 +81,25 @@ For now, we'll just measure width of the characters. (send fontFile end (send (send (· this subset) encodeStream) dump)) (define familyClass (let ([val (if (send (· this font) has-table? 'OS/2) - (· this font OS/2 sFamilyClass) - 0)]) + (· this font OS/2 sFamilyClass) + 0)]) (floor (/ val 256)))) ; equivalent to >> 8 - (define flags (+ - (if (not (zero? (· this font post isFixedPitch))) (expt 2 0) 0) - (if (<= 1 familyClass 7) (expt 2 1) 0) - (expt 2 2) ; assume the font uses non-latin characters - (if (= familyClass 10) (expt 2 3) 0) - (if (· this font head macStyle italic) (expt 2 6) 0))) + ;; font descriptor flags + (match-define (list FIXED_PITCH SERIF SYMBOLIC SCRIPT _UNUSED NONSYMBOLIC ITALIC) + (map (curry expt 2) (range 7))) + + (define flags (sum-flags + [(not (zero? (· this font post isFixedPitch))) FIXED_PITCH] + [(<= 1 familyClass 7) SERIF] + [#t SYMBOLIC] ; assume the font uses non-latin characters + [(= familyClass 10) SCRIPT] + [(· this font head macStyle italic) ITALIC])) ;; generate a random tag (6 uppercase letters. 65 is the char code for 'A') (when (test-mode) (random-seed 0)) (define tag (list->string (for/list ([i (in-range 6)]) - (integer->char (random 65 (+ 65 26)))))) + (integer->char (random 65 (+ 65 26)))))) (define name (string-append tag "+" (· this font postscriptName))) (define bbox (· this font bbox)) @@ -132,7 +138,7 @@ For now, we'll just measure width of the characters. 'Supplement 0) 'FontDescriptor descriptor 'W (list 0 (for/list ([idx (in-range (length (hash-keys (· this widths))))]) - (hash-ref (· this widths) idx (λ () (error 'embed (format "hash key ~a not found" idx))))))))) + (hash-ref (· this widths) idx (λ () (error 'embed (format "hash key ~a not found" idx))))))))) (· descendantFont end) #;(report (· descendantFont toString) 'descendantFont) @@ -152,35 +158,39 @@ For now, we'll just measure width of the characters. (define cmap (· this document ref)) (define entries (for/list ([idx (in-range (length (hash-keys (· this unicode))))]) - (define codePoints (hash-ref (· this unicode) idx)) - (define encoded ; encode codePoints to utf16 - ;; todo: full utf16 support. for now just utf8 - (for/list ([value (in-list codePoints)]) - (toHex value))) - (format "<~a>" (string-join encoded " ")))) - - (send cmap end @string-append{ - /CIDInit /ProcSet findresource begin - 12 dict begin - begincmap - /CIDSystemInfo << - /Registry (Adobe) - /Ordering (UCS) - /Supplement 0 - >> def - /CMapName /Adobe-Identity-UCS def - /CMapType 2 def - 1 begincodespacerange - <0000> - endcodespacerange - 1 beginbfrange - <0000> <@(toHex (sub1 (length entries)))> [@(string-join entries " ")] - endbfrange - endcmap - CMapName currentdict /CMap defineresource pop - end - end - }) + (define codePoints (hash-ref (· this unicode) idx)) + (define encoded ; encode codePoints to utf16 + ;; todo: full utf16 support. for now just utf8 + (for/list ([value (in-list codePoints)]) + (toHex value))) + (format "<~a>" (string-join encoded " ")))) + + (define unicode-cmap-str #<> def +/CMapName /Adobe-Identity-UCS def +/CMapType 2 def +1 begincodespacerange +<0000> +endcodespacerange +1 beginbfrange +<0000> <~a> [~a] +endbfrange +endcmap +CMapName currentdict /CMap defineresource pop +end +end +HERE + ) + + (send cmap end (format unicode-cmap-str (toHex (sub1 (length entries))) (string-join entries " "))) + #;(report (· cmap toString) 'cmap-id) cmap) @@ -188,7 +198,7 @@ For now, we'll just measure width of the characters. (() () #:rest (listof number?) . ->*m . string?) (string-append* (for/list ([code (in-list codePoints)]) - (~r code #:base 16 #:min-width 4 #:pad-string "0")))) + (~r code #:base 16 #:min-width 4 #:pad-string "0")))) (module+ test diff --git a/pitfall/pitfall/pdftest.rkt b/pitfall/pitfall/pdftest.rkt index 5ec9ad75..5d3316d9 100644 --- a/pitfall/pitfall/pdftest.rkt +++ b/pitfall/pitfall/pdftest.rkt @@ -16,10 +16,10 @@ (check-equal? (this->pdfkit-control (string->path "test1crkt.pdf")) (string->path "test1c.pdf"))) -(define-syntax-rule (check-copy-equal? this) - (check-true (for/and ([b1 (in-input-port-bytes (open-input-file this))] - [b2 (in-input-port-bytes (open-input-file (this->control this)))]) - (equal? b1 b2)))) +(define-macro (check-copy-equal? THIS) + (syntax/loc caller-stx (check-true (for/and ([b1 (in-input-port-bytes (open-input-file THIS))] + [b2 (in-input-port-bytes (open-input-file (this->control THIS)))]) + (equal? b1 b2))))) (define-syntax-rule (check-pdfkit? this) diff --git a/pitfall/pitfall/racket.rkt b/pitfall/pitfall/racket.rkt index 9cb42828..9a2246c9 100644 --- a/pitfall/pitfall/racket.rkt +++ b/pitfall/pitfall/racket.rkt @@ -23,7 +23,8 @@ sugar/js sugar/dict sugar/stub - sugar/port) + sugar/port + sugar/contract) (module reader syntax/module-reader #:language 'pitfall/racket diff --git a/pitfall/pitfall/test/out.bin b/pitfall/pitfall/test/out.bin index 6a2b7f04bf210127e73b73013028d41c255853d7..9a63036533a39080cb3e8fc648ebc5364eb8ff91 100644 GIT binary patch delta 387 zcmXwzu}i~H5XSHBrEQEu8#7pNFd>Ly1&5$Z2fK7hI*4LPiY=&^I#`KPq~cHz2RC(- zj$K8FcF|D>{{RQac64zP(W%8t)qA}A_;~Mr-*t`G$%|}Rsckd@7#2od-#V=8Lkk$` zOK`CL|Ng=Lp}KqIvvScj0G{sD>WyD7&9kQbpj!L$OP5z=RbsOOC(wo`h!UiZf;Ke? zWF}Y?LIM=X?0REMY;GWkpt0RZYc}bY{v(n3|=T(?Vc-@VV&r z_PXm%5QHIx{pD}mADnXxLXz9pkUx=26GsaVgzy}Qn9V|jlNg7l%4fmA_s8NhzLDQ= zk#9$UXhDMkabSRiJZBRx!~}p66vot)P{uQcDJ)I1Fkk6aZtq;);f7XuvIWPK1(^Vn XGz)SFb9xACZr;;%=N>x6*xBe0J+(*- delta 647 zcmXw0O=}ZT6utM&%!^E>+Nqg|29qY4$wW;dv6ByNLcSr(=&~ypA})iwroOT5g~NS^dpYMG-jDIU$m@Lbq_ecqhW~{; zYvGlr>)|7=v;M99$D3=1bMg^@yl6S=8;4v-vVLZ*Z97MNX8T=Jp^VJJ zbNB>5(LxK5ak@*fM0yA|Q@Bq0;Dv}40uBHCZ&o`H7B!~w4velX2)^1I!@tMvEYIP-t@XVE^fA3 zw(WxDY90(wB7a~6Vpi0P2v`z%j)Nj|#0Fs(EMtYeM?i{m%&w;z8967rHaS1l-d>)U z$4;M8!-h1KC0%iUOI2xJW{FZv_%};*4q`BE-B6Km3L*(nBJc!3;7c6B47-3AkY8aT zxdw3DYMG)S9On%NgR!7)Xqq1Ph-VYJ>i6^vBYqs$baO^M@vJ$iDhkbIw5XdOzbby; z`IMM`bi4k{sph7x&MFV)?k~PfmUk{CtK%o~f??dP73b;~ub9DWdVPLSSm?G>ru!4` gp+i1^O$v}l4VokbDU<;EFcI#g=2VH1$Z2$lO diff --git a/pitfall/pitfall/test/test14rkt copy 2.pdf b/pitfall/pitfall/test/test14rkt copy 2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..45b1154da7259f1bc20807993681951b8c5a4371 GIT binary patch literal 6452 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 Cwv$i* literal 0 HcmV?d00001 diff --git a/pitfall/pitfall/test/test15.pdf b/pitfall/pitfall/test/test15.pdf index a0eb07579dd1ac0a82272300ab981984c0a4ead7..26a36cda8d4a7db0385bfe9b4b025a696f11cb95 100644 GIT binary patch delta 49 vcmeCx@73S%jFHvMz`(?O@@qyb)*v5uN4LpZOm`rx&D_idOi*S6E3Xg$fh-P3 delta 49 vcmeCx@73S%jFHvU#MIDq@@qyb){qGAFqg?%Om`rx&D_idOi*S6E3Xg$iN6lH diff --git a/pitfall/pitfall/test/test15.rkt b/pitfall/pitfall/test/test15.rkt index 10912049..7257bc8c 100644 --- a/pitfall/pitfall/test/test15.rkt +++ b/pitfall/pitfall/test/test15.rkt @@ -1,6 +1,6 @@ #lang pitfall/pdftest -(define-runtime-path ttf-path "assets/eqbi.ttf") +(define-runtime-path ttf-path "assets/fira.ttf") (define (proc doc) ;; Register a font name for use later @@ -10,18 +10,11 @@ (send* doc [font "the-font"] [fontSize 25] - [text "Hello World" 100 100 (hash 'width #f)])) + [text "ATAVATA" 100 100 (hash 'width #f)])) ;; test against non-subsetted font version -(define-runtime-path this "test14rkt.pdf") -(make-doc this #f proc #:pdfkit #f) +(define-runtime-path this "test15rkt.pdf") +(make-doc this #f proc #:test #f) -(define-runtime-path that "test14crkt.pdf") -(make-doc that #t proc #:pdfkit #f) - -#;(module+ test - (define doc (make-object PDFDocument)) - (send doc registerFont "Charter" (path->string charter-path)) - (send* doc [font "Charter"]) - (send doc pipe (open-output-string)) - (send doc end)) +#;(define-runtime-path that "test14crkt.pdf") +#;(make-doc that #t proc #:pdfkit #f) \ No newline at end of file diff --git a/pitfall/pitfall/test/test15rkt.pdf b/pitfall/pitfall/test/test15rkt.pdf index 74b79659b78ceae3b109dde31c85cd10e994d32c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 GIT binary patch literal 0 HcmV?d00001 literal 5993 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 diff --git a/pitfall/sugar/contract.rkt b/pitfall/sugar/contract.rkt new file mode 100644 index 00000000..bc694cfd --- /dev/null +++ b/pitfall/sugar/contract.rkt @@ -0,0 +1,5 @@ +#lang racket/base +(require racket/contract) +(provide (all-defined-out)) + +(define (option/c x) (or/c #f x)) \ No newline at end of file