From cc6f1fb148f951ff94d69ad73519d1f3129c6c09 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Thu, 6 Jul 2017 12:38:09 -0700 Subject: [PATCH] pass test15 (gpos kerning) --- pitfall/fontkit/glyph-iterator.rkt | 25 +++++-- pitfall/fontkit/gpos-processor.rkt | 65 +++++++++++-------- pitfall/fontkit/ot-processor.rkt | 22 +++++-- pitfall/pdfkit/node_modules/fontkit/index.js | 8 +-- pitfall/pitfall/alltest.rkt | 2 +- pitfall/pitfall/embedded.rkt | 3 +- pitfall/pitfall/test/out.bin | Bin 4054 -> 4144 bytes pitfall/pitfall/test/test14rkt.pdf | Bin 0 -> 6287 bytes pitfall/pitfall/test/test15.coffee | 2 +- pitfall/pitfall/test/test15.pdf | Bin 6029 -> 6118 bytes pitfall/pitfall/test/test15.rkt | 8 +-- pitfall/pitfall/test/test15crkt copy.pdf | Bin 0 -> 4154 bytes pitfall/pitfall/test/test15crkt.pdf | Bin 0 -> 4154 bytes pitfall/pitfall/test/test15rkt copy.pdf | Bin 0 -> 6118 bytes pitfall/pitfall/test/test15rkt.pdf | Bin 5993 -> 6118 bytes 15 files changed, 89 insertions(+), 46 deletions(-) create mode 100644 pitfall/pitfall/test/test15crkt copy.pdf create mode 100644 pitfall/pitfall/test/test15crkt.pdf create mode 100644 pitfall/pitfall/test/test15rkt copy.pdf diff --git a/pitfall/fontkit/glyph-iterator.rkt b/pitfall/fontkit/glyph-iterator.rkt index 05763069..f1e1c058 100644 --- a/pitfall/fontkit/glyph-iterator.rkt +++ b/pitfall/fontkit/glyph-iterator.rkt @@ -26,6 +26,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/GlyphIterator.js (and (· flags ignoreLigatures) (· glyph isLigature)))) (define/public (move dir) + (unless (= (abs dir) 1) + (raise-argument-error 'GlyphIterator:move "1 or -1" dir)) (increment-field! index this dir) (while (and (<= 0 (· this index)) (< (· this index) (length (· this glyphs))) @@ -55,7 +57,22 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/GlyphIterator.js res) (define/public (increment [count 1]) - (for ([i (in-range (abs count))]) - (send this move (if (negative? count) -1 1))) - (list-ref (· this glyphs) (· this index)))) - + (for/last ([i (in-range (abs count))]) + (send this move (if (negative? count) -1 1))))) + +(test-module + (define gi (+GlyphIterator '(a b c))) + (check-equal? (· gi index) 0) + (check-equal? (send gi cur) 'a) + (check-equal? (send gi move 1) 'b) + (check-equal? (send gi move 1) 'c) + (check-false (send gi move 1)) + (check-equal? (send gi increment -3) 'a) + (check-equal? (send gi cur) 'a) + (check-equal? (send gi peek 1) 'b) + (check-equal? (send gi peek 2) 'c) + (check-equal? (send gi peek 3) #f) + (check-equal? (send gi cur) 'a) + + + ) diff --git a/pitfall/fontkit/gpos-processor.rkt b/pitfall/fontkit/gpos-processor.rkt index 70d630d8..0b7f5e00 100644 --- a/pitfall/fontkit/gpos-processor.rkt +++ b/pitfall/fontkit/gpos-processor.rkt @@ -8,8 +8,18 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/GPOSProcessor.js (define-subclass OTProcessor (GPOSProcessor) + (define/public (applyPositionValue sequenceIndex value) + (define position (list-ref (· this positions) (send (· this glyphIterator) peekIndex sequenceIndex))) + (when (· value xAdvance) + (increment-field! xAdvance position (or (· value xAdvance) 0))) + (when (· value yAdvance) + (increment-field! yAdvance position (· value yAdvance))) + (when (· value xPlacement) + (increment-field! xOffset position (· value xPlacement))) + (when (· value yPlacement) + (increment-field! yOffset position (· value yPlacement)))) + (define/override (applyLookup lookupType table) - (report/file 'starting-applyLookup) (case lookupType [(1) ;; Single positioning value (report/file 'single-positioning-value) @@ -17,25 +27,26 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/GPOSProcessor.js (report/file index) (cond [(= index -1) #f] - [else (case (· table version) + [else (case (report (· table version)) [(1) (send this applyPositionValue 0 (· table value))] [(2) (send this applyPositionValue 0 (send (· table values) get index))]) #t])] [(2) ;; Pair Adjustment Positioning - (report/file 'pair-adjustment) + (report/file 'applyLookup:pair-adjustment) (define nextGlyph (· this glyphIterator peek)) - (report/file nextGlyph) (cond [(not nextGlyph) #f] [else + (report 'getting-pair-coverage-for) + (report* (· this glyphIterator cur id) (· this glyphIterator peek id) (· table coverage)) (define index (send this coverageIndex (· table coverage))) - (report/file index) + (report index) (cond [(= index -1) #f] [else - (case (· table version) + (case (report (· table version)) [(1) ;; Adjustments for glyph pairs - (report/file 'glyph-pair) + (report 'glyph-pair) (define set (send (· table pairSets) get index)) (for/first ([pair (in-list set)] #:when (= (· pair secondGlyph) (· nextGlyph id))) @@ -43,8 +54,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/GPOSProcessor.js (send this applyPositionValue 0 (· pair value2)))] [(2) ;; Class pair adjustment (report/file 'class-pair) - (define class1 (send this getClassId (· this glyphIterator cur id) (· table classDef1))) - (define class2 (send this getClassId (· nextGlyph id) (· table classDef2))) + (define class1 (send this getClassID (· this glyphIterator cur id) (· table classDef1))) + (define class2 (send this getClassID (· nextGlyph id) (· table classDef2))) (cond [(or (= class1 -1) (= class2 -1)) #f] [else (define pair (send (send (· table classRecords) get class1) get class2)) @@ -52,26 +63,26 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/GPOSProcessor.js (send this applyPositionValue 0 (· pair value2)) #t])])])])] [(3) ;; Cursive Attachment Positioning - (report/file 'cursive-attachment-positioning-unimplemented) - (error)] + #;(report/file 'cursive-attachment-positioning-unimplemented) + (void)] [(4) ;; Mark to base positioning - (report/file 'mark-to-base-positioning-unimplemented) - (error)] + #;(report/file 'mark-to-base-positioning-unimplemented) + (void)] [(5) ;; Mark to ligature positioning - (report/file 'mark-to-ligature-positioning-unimplemented) - (error)] + #;(report/file 'mark-to-ligature-positioning-unimplemented) + (void)] [(6) ;; Mark to mark positioning - (report/file 'mark-to-mark-positioning-unimplemented) - (error)] + #;(report/file 'mark-to-mark-positioning-unimplemented) + (void)] [(7) ;; Contextual positioning - (report/file 'contextual-positioning-unimplemented) - (error)] + #;(report/file 'contextual-positioning-unimplemented) + (void)] [(8) ;; Chaining contextual positioning - (report/file 'chaining-contextual-positioning-unimplemented) - (error)] + #;(report/file 'chaining-contextual-positioning-unimplemented) + (void)] [(9) ;; Extension positioning - (report/file 'extension-contextual-positioning-unimplemented) - (error)] + #;(report/file 'extension-contextual-positioning-unimplemented) + (void)] [else (raise-argument-error 'GPOSProcessor:applyLookup "supported GPOS table" lookupType)])) @@ -80,9 +91,11 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/GPOSProcessor.js (define/override (applyFeatures userFeatures glyphs advances) (super applyFeatures userFeatures glyphs advances) - (for ([i (in-range (length (· this glyphs)))]) - (send this fixCursiveAttachment i)) - (send this fixMarkAttachment)) + (report/file 'fixCursiveAttachment-unimplemented) + #;(for ([i (in-range (length (· this glyphs)))]) + (send this fixCursiveAttachment i)) + (report/file 'fixMarkAttachment-unimplemented) + #;(send this fixMarkAttachment)) ) \ No newline at end of file diff --git a/pitfall/fontkit/ot-processor.rkt b/pitfall/fontkit/ot-processor.rkt index 96761795..6c9849bb 100644 --- a/pitfall/fontkit/ot-processor.rkt +++ b/pitfall/fontkit/ot-processor.rkt @@ -105,7 +105,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/OTProcessor.js (send (· this glyphIterator) reset (· lookup flags)) (while (< (· this glyphIterator index) (length glyphs)) (when (dict-has-key? (· this glyphIterator cur features) feature) - (for/first ([table (in-list (· lookup subTables))]) + (for/or ([table (in-list (· lookup subTables))]) (send this applyLookup (· lookup lookupType) table))) (send (· this glyphIterator) next)))) @@ -118,13 +118,25 @@ https://github.com/mbutterick/fontkit/blob/master/src/opentype/OTProcessor.js (define/public (coverageIndex coverage [glyph #f]) (unless glyph (set! glyph (· this glyphIterator cur id))) - - (or (case (· coverage version) + (or (case (report (· coverage version)) [(1) (index-of (· coverage glyphs) glyph)] [(2) (for/first ([range (in-list (· coverage rangeRecords))] #:when (<= (· range start) glyph (· range end))) (+ (· range startCoverageIndex) glyph (- (· range start))))] [else #f]) -1)) - - ) \ No newline at end of file + (define/public (getClassID glyph classDef) + (or + (case (· classDef version) + [(1) ;; Class array + (define i (- glyph (· classDef startGlyph))) + (and (>= i 0) + (< i (length (· classDef classValueArray))) + (list-ref (· classDef classValueArray) i))] + [(2) + (for/first ([range (in-list (· classDef classRangeRecord))] + #:when (<= (· range start) glyph (· range end))) + (· range class))]) + 0))) + + \ No newline at end of file diff --git a/pitfall/pdfkit/node_modules/fontkit/index.js b/pitfall/pdfkit/node_modules/fontkit/index.js index 33c6e740..623240f4 100644 --- a/pitfall/pdfkit/node_modules/fontkit/index.js +++ b/pitfall/pdfkit/node_modules/fontkit/index.js @@ -2523,7 +2523,7 @@ var ValueRecord = function () { var fields = {}; fields.rel = function () { - console.log("struct._startOffset="+ struct._startOffset); + //console.log("struct._startOffset="+ struct._startOffset); return struct._startOffset; }; @@ -12417,9 +12417,9 @@ var TTFFont = (_class = function () { * @return {GlyphRun} */ TTFFont.prototype.layout = function layout(string, userFeatures, script, language) { - console.log("userFeatures="+userFeatures); - console.log("script="+script); - console.log("language="+language); + //console.log("userFeatures="+userFeatures); + //console.log("script="+script); + //console.log("language="+language); return this._layoutEngine.layout(string, userFeatures, script, language); }; diff --git a/pitfall/pitfall/alltest.rkt b/pitfall/pitfall/alltest.rkt index 870873e6..c5535978 100644 --- a/pitfall/pitfall/alltest.rkt +++ b/pitfall/pitfall/alltest.rkt @@ -15,6 +15,6 @@ pitfall/test/test12 ; ttf subset pitfall/test/test13 ; subset with composites pitfall/test/test14 ; Fira ttf with GPOS (no kerning) - ;pitfall/test/test15 ; Fira ttf with GPOS kerning + pitfall/test/test15 ; Fira ttf with GPOS kerning pitfall/page-test (submod pitfall/zlib test))) \ No newline at end of file diff --git a/pitfall/pitfall/embedded.rkt b/pitfall/pitfall/embedded.rkt index 1e62c480..c5928c37 100644 --- a/pitfall/pitfall/embedded.rkt +++ b/pitfall/pitfall/embedded.rkt @@ -49,7 +49,8 @@ https://github.com/mbutterick/pdfkit/blob/master/lib/font/embedded.coffee (for ([g (in-list glyphs)]) (· g id)) (define positions (· glyphRun positions)) - (report positions) + (report/file (for/list ([p (in-list positions)]) + (list (· p xAdvance) (· p xOffset)))) (define-values (subset-idxs new-positions) (for/lists (idxs posns) ([(glyph i) (in-indexed glyphs)] diff --git a/pitfall/pitfall/test/out.bin b/pitfall/pitfall/test/out.bin index 9a63036533a39080cb3e8fc648ebc5364eb8ff91..82c6a1c3f5d311cd482225e3bb1d8764427de123 100644 GIT binary patch delta 239 zcmca6zd>Pwbu3SAVnqQ17%(ycDTU;+5(Ow<2}oZmC`yINe*yA$rsq_qLFAd%GB7aS z$jB|JfbdybfwV|kL3%EfKXc-YSYcKmCy1ejVGhF?hBpk1KpyL6HbyU|Kt_gi1_ma3 zrVR|-42lkN49q~&m>CjT7@3$Ny;&I<8KW3|1VKQ6jY~?KQBhD?&{$9rh?N;%{JRa7})Kbu3qIVnqQ17%+lJh2*jl1u&O^5ky}qC`yINe**G%rsq_q0cjv$TFt<~ z*piW3QUT$!=mTkiw1V_pDBphKj95VyASZ~SiD41LAqJ2QESotPy_hCHV@{g9g4u4e U8;c9OH3J6|0|Wo&sVuX(0d->?4*&oF diff --git a/pitfall/pitfall/test/test14rkt.pdf b/pitfall/pitfall/test/test14rkt.pdf index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a2e57e9ff54b90fdec078efe227257a47151b71a 100644 GIT binary patch literal 6287 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 literal 0 HcmV?d00001 diff --git a/pitfall/pitfall/test/test15.coffee b/pitfall/pitfall/test/test15.coffee index 204591b8..53cbb1f9 100644 --- a/pitfall/pitfall/test/test15.coffee +++ b/pitfall/pitfall/test/test15.coffee @@ -9,7 +9,7 @@ make = (doc) -> # Set the font, draw some text doc.font('the-font') .fontSize(25) - .text('ATAVATA', 100, 100, {width: false}) + .text('HTAVATH', 100, 100, {width: false}) doc.end() diff --git a/pitfall/pitfall/test/test15.pdf b/pitfall/pitfall/test/test15.pdf index d91e9f3c7ff7654fa8128ec49bad8ca6bc015644..5ba4007e9a0475599ea03b8fb9bccf58869fe1d6 100644 GIT binary patch delta 549 zcmeCxf2Kd-36qK8#Aneu1_lO3b_!+&3N}ENv7Lg6DVSvfX92}bA+ko3D;cxd%?vG# z%?(W^zh<;#^N9-e3iX++#dI6S12Q z`cgqrDop+hkiRoMr!oy9&$O0-f$>I0Zb=1%&(aE{MbZk=bD{j1lmD~D3bO)vK@2qv za~RGrykTGj@>nvm^S>o$Efr-fMK!-m-FQ9oJo@- zxtzF{F{A_i!_Q>Rz_ED|*A;G2a|KY?7%1c^aDf>Hh9;I4le@+IQw`B&3`~IP&{dlm ln4pUpm{=NNh?yH0V~ANAnoqVDcj2-yFyK;Eb@g}S0s#NWc1r*N delta 462 zcmaE+->X0236rVu#AneKb_%8j3N{7?21a%YW)PO4oq~xeSj-sC0*axko1Dv-&2DOB zWMpn=KKVYQC7WY-V7QaVWI3kWFy?=zDt1$ILj_YqqscAIYE0&)o7XT)Fp2|BjRx6h zU0|R4AMs7(3gwLW6qy^Fn(sQAF`^o>zxvp@FS}1@VZ=jH;zy)R)7@AmG zPJSZhpK63I1N0q+n4y`0DTX>z0}~7}b3;sZmPV$NXNbFSnHw5%sj9mAyKw;k003lX diff --git a/pitfall/pitfall/test/test15.rkt b/pitfall/pitfall/test/test15.rkt index 2a3f8818..5452bd17 100644 --- a/pitfall/pitfall/test/test15.rkt +++ b/pitfall/pitfall/test/test15.rkt @@ -12,11 +12,11 @@ (send* doc [font "the-font"] [fontSize 25] - [text "ATAVATA" 100 100 (hash 'width #f)])) + [text "HTAVATH" 100 100 (hash 'width #f)])) (define-runtime-path this "test15rkt.pdf") -(make-doc this #f proc #:test #f) +(make-doc this #f proc) -#;(define-runtime-path that "test15crkt.pdf") -#;(make-doc that #t proc #:pdfkit #f) \ No newline at end of file +(define-runtime-path that "test15crkt.pdf") +(make-doc that #t proc #:pdfkit #f) \ No newline at end of file diff --git a/pitfall/pitfall/test/test15crkt copy.pdf b/pitfall/pitfall/test/test15crkt copy.pdf new file mode 100644 index 0000000000000000000000000000000000000000..325efa8bdbc03903d67f1b1c47f005170645fd9b GIT binary patch literal 4154 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 literal 0 HcmV?d00001 diff --git a/pitfall/pitfall/test/test15crkt.pdf b/pitfall/pitfall/test/test15crkt.pdf new file mode 100644 index 0000000000000000000000000000000000000000..325efa8bdbc03903d67f1b1c47f005170645fd9b GIT binary patch literal 4154 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 literal 0 HcmV?d00001 diff --git a/pitfall/pitfall/test/test15rkt copy.pdf b/pitfall/pitfall/test/test15rkt copy.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3158c59227300b6bde420c6649fe361fcc7472b5 GIT binary patch literal 6118 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 a;t!As&EhqxH7i=-sL!X2j3l2*DgOmhCuXkz literal 0 HcmV?d00001 diff --git a/pitfall/pitfall/test/test15rkt.pdf b/pitfall/pitfall/test/test15rkt.pdf index 74b79659b78ceae3b109dde31c85cd10e994d32c..3158c59227300b6bde420c6649fe361fcc7472b5 100644 GIT binary patch delta 537 zcmaE<_e_7n6DAYGiO=Fy>=eul6l@F(42xg`}){sJH^l97>`2<2}9(kei13Y32XNSmb< zq~}8T%zO+C+|!fGN)#Y`zNJ9=QbAEF)O`MO1_nNcoj}1Lh8l)B3}+bLOrFEEG?0-Y zoq>VLo@oOEH-n;s90N1ZS0F~jEqr?K7t@1z{Vw|&8R4-ENCpK2*k>a zFaBK(3uDv{4`+1yw~J}Rzk7^Ie*+jM&trC;?8uxn`7yH-BkN=}7J2Sv4Czb^4E#*i z3>=evSkxI=H04Xt0$W!0~GYm}4EKMe-i}|LTnwX=@8JGZ7qNz79u{1&# jGcmKUz!0;rv_uy(H8eDyEG_QBWno~zrK;-c@5TiHgdJ}r delta 464 zcmaE+|59(l6DC9RiO=GB3=9kmf!G*CPtIhV&SYRZnTbigo+~}4GK~QOmN76ew&W&O z6hOF4T0mMMBe$di%J%}&0vQ>piBNtNkX8Y5Q=t4hAZ?abke&1F{D2}W^aJB4T)pvMjD6o8b8A(%2X+3Y6T&M0nXXrTa-Gf>D=-~uxYOij%! zCqEJMtv4|;LYFfzHaEi%Gcm(3!^G6w1YMnpxrHf)n589>SV>W0W=?7mmyHdVzGvR# S4dOanX6B|`s;aL3Zd?G%Y+n!n