GSUB: resume in spurious ligature lookup
parent
5cfd6ae98a
commit
c1bc246b19
@ -0,0 +1,7 @@
|
||||
fontkit = require '../pdfkit/node_modules/fontkit'
|
||||
|
||||
fira_path = "../pitfall/test/assets/fira.ttf"
|
||||
f = fontkit.openSync(fira_path)
|
||||
console.log "*************************** start decode"
|
||||
thing = f.GSUB.lookupList.get(19)
|
||||
console.log thing
|
@ -0,0 +1,89 @@
|
||||
#lang fontkit/racket
|
||||
(require xenomorph br/cond "opentype.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/fontkit/blob/master/src/tables/GSUB.js
|
||||
|#
|
||||
|
||||
(define Sequence (+Array uint16be uint16be))
|
||||
(define AlternateSet Sequence)
|
||||
|
||||
(define Ligature (+Struct
|
||||
(dictify
|
||||
'glyph uint16be
|
||||
'compCount uint16be
|
||||
'components (+Array uint16be (λ (t) (sub1 (· t compCount)))))))
|
||||
|
||||
(define LigatureSet (+Array (+Pointer uint16be Ligature) uint16be))
|
||||
|
||||
(define-subclass VersionedStruct (GSUBLookup-VersionedStruct))
|
||||
(define GSUBLookup
|
||||
(+GSUBLookup-VersionedStruct
|
||||
'lookupType
|
||||
(dictify
|
||||
;; Single Substitution
|
||||
1 (+VersionedStruct uint16be
|
||||
(dictify
|
||||
1 (dictify
|
||||
'coverage (+Pointer uint16be Coverage)
|
||||
'deltaGlyphID int16be)
|
||||
2 (dictify
|
||||
'coverage (+Pointer uint16be Coverage)
|
||||
'glyphCount uint16be
|
||||
'substitute (+LazyArray uint16be 'glyphCount))))
|
||||
2 ;; Multiple Substitution
|
||||
(dictify
|
||||
'substFormat uint16be
|
||||
'coverage (+Pointer uint16be Coverage)
|
||||
'count uint16be
|
||||
'sequences (+LazyArray (+Pointer uint16be Sequence) 'count))
|
||||
|
||||
3 ;; Alternate Substitution
|
||||
(dictify
|
||||
'substFormat uint16be
|
||||
'coverage (+Pointer uint16be Coverage)
|
||||
'count uint16be
|
||||
'alternateSet (+LazyArray (+Pointer uint16be AlternateSet) 'count))
|
||||
|
||||
4 ;; Ligature Substitution
|
||||
(dictify
|
||||
'substFormat uint16be
|
||||
'coverage (+Pointer uint16be Coverage)
|
||||
'count uint16be
|
||||
'ligatureSets (+LazyArray (+Pointer uint16be LigatureSet) 'count))
|
||||
|
||||
5 Context ;; Contextual Substitution
|
||||
6 ChainingContext ;; Chaining Contextual Substitution
|
||||
|
||||
7 ;; Extension Substitution
|
||||
(dictify
|
||||
'substFormat uint16be
|
||||
'lookupType uint16be ; cannot also be 7
|
||||
'extension (+Pointer uint32be (λ () (error 'circular-reference-unfixed))))
|
||||
|
||||
8 ;; Reverse Chaining Contextual Single Substitution
|
||||
(dictify
|
||||
'substFormat uint16be
|
||||
'coverage (+Pointer uint16be Coverage)
|
||||
'backTrackCoverage (+Array (+Pointer uint16be Coverage) 'backtrackGlyphCount)
|
||||
'lookaheadGlyphCount uint16be
|
||||
'lookaheadCoverage (+Array (+Pointer uint16be Coverage) 'lookaheadGlyphCount)
|
||||
'glyphCount uint16be
|
||||
'substitute (+Array uint16be 'glyphCount)))))
|
||||
|
||||
;; Fix circular reference
|
||||
(ref*-set! GSUBLookup 'versions 7 'extension 'type GSUBLookup)
|
||||
|
||||
(define-subclass VersionedStruct (GSUB-MainVersionedStruct))
|
||||
(define GSUB (+GSUB-MainVersionedStruct uint32be
|
||||
(dictify
|
||||
'header (dictify 'scriptList (+Pointer uint16be ScriptList)
|
||||
'featureList (+Pointer uint16be FeatureList)
|
||||
'lookupList (+Pointer uint16be (LookupList GSUBLookup))
|
||||
)
|
||||
#x00010000 (dictify)
|
||||
#;#x00010001 #;(+Pointer uint32be FeatureVariations))))
|
||||
|
||||
(test-module)
|
@ -0,0 +1,160 @@
|
||||
#lang fontkit/racket
|
||||
(require "ot-processor.rkt" "glyphinfo.rkt" br/cond)
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/fontkit/blob/master/src/opentype/GSUBProcessor.js
|
||||
|#
|
||||
|
||||
(define-subclass OTProcessor (GSUBProcessor)
|
||||
|
||||
(define/override (applyLookup lookupType table)
|
||||
(report/file 'GSUBProcessor:applyLookup)
|
||||
(case lookupType
|
||||
[(1) ;; Single Substitution
|
||||
(report 'single-substitution)
|
||||
(define index (send this coverageIndex (· table coverage)))
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[else (define glyph (· this glyphIterator cur))
|
||||
(set-field! id glyph
|
||||
(case (· table version)
|
||||
[(1) (bitwise-and (+ (· glyph id) (· table deltaGlyphID)) #xffff)]
|
||||
[(2) (send (· table substitute) get index)]))
|
||||
#t])]
|
||||
[(2) ;; Multiple Substitution
|
||||
(report 'multiple-substitution)
|
||||
(define index (send this coverageIndex (· table coverage)))
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[else (define sequence (send (· table sequences) get index))
|
||||
(set-field! id (· this glyphIterator cur) (list-ref sequence 0))
|
||||
(set-field! ligatureComponent (· this glyphIterator cur) 0)
|
||||
|
||||
(define features (· this glyphIterator cur features))
|
||||
(define curGlyph (· this glyphIterator cur))
|
||||
(define replacement (for/list ([(gid i) (in-indexed (cdr sequence))])
|
||||
(define glyph (+GlyphInfo (· this font) gid #f features))
|
||||
(set-field! shaperInfo glyph (· curGlyph shaperInfo))
|
||||
(set-field! isLigated glyph (· curGlyph isLigated))
|
||||
(set-field! ligatureComponent glyph (add1 i))
|
||||
(set-field! substituted glyph #t)
|
||||
glyph))
|
||||
|
||||
(set-field! glyphs this (let-values ([(head tail) (split-at (· this glyphs) (add1 (· this glyphIterator index)))])
|
||||
(append head replacement tail)))
|
||||
#t])]
|
||||
|
||||
[(3) ;; Alternate substitution
|
||||
(report 'altnernate-substitution)
|
||||
(define index (send this coverageIndex (· table coverage)))
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[else (define USER_INDEX 0)
|
||||
(set-field! id (· this glyphIterator cur) (list-ref (send (· table alternateSet) get index) USER_INDEX))
|
||||
#t])]
|
||||
|
||||
[(4) ;; Ligature substitution
|
||||
(report 'ligature-substitution)
|
||||
(define index (report* (· table coverage) (send this coverageIndex (· table coverage))))
|
||||
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[(for* ([ligature (in-list (send (· table ligatureSets) get index))]
|
||||
[matched (in-value (send this sequenceMatchIndices 1 (report* ligature (· ligature components))))]
|
||||
#:when matched)
|
||||
(report*/file matched (· this glyphs) index)
|
||||
(define curGlyph (· this glyphIterator cur))
|
||||
|
||||
;; Concatenate all of the characters the new ligature will represent
|
||||
(define characters
|
||||
(append (· curGlyph codePoints)
|
||||
(append* (for/list ([index (in-list matched)])
|
||||
(get-field codePoints (list-ref (· this glyphs) index))))))
|
||||
|
||||
;; Create the replacement ligature glyph
|
||||
(define ligatureGlyph (+GlyphInfo (· this font) (· ligature glyph) characters (· curGlyph features)))
|
||||
(set-field! shaperInfo ligatureGlyph (· curGlyph shaperInfo))
|
||||
(set-field! ligated ligatureGlyph #t)
|
||||
(set-field! substituted ligatureGlyph #t)
|
||||
|
||||
(report 'from-harfbuzz)
|
||||
|
||||
;; From Harfbuzz:
|
||||
;; - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
|
||||
;; the ligature to keep its old ligature id. This will allow it to attach to
|
||||
;; a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
|
||||
;; and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
|
||||
;; ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
|
||||
;; later, we don't want them to lose their ligature id/component, otherwise
|
||||
;; GPOS will fail to correctly position the mark ligature on top of the
|
||||
;; LAM,LAM,HEH ligature. See https://bugzilla.gnome.org/show_bug.cgi?id=676343
|
||||
;;
|
||||
;; - If a ligature is formed of components that some of which are also ligatures
|
||||
;; themselves, and those ligature components had marks attached to *their*
|
||||
;; components, we have to attach the marks to the new ligature component
|
||||
;; positions! Now *that*'s tricky! And these marks may be following the
|
||||
;; last component of the whole sequence, so we should loop forward looking
|
||||
;; for them and update them.
|
||||
;;
|
||||
;; Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
|
||||
;; 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
|
||||
;; id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
|
||||
;; form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
|
||||
;; the new ligature with a component value of 2.
|
||||
;;
|
||||
;; This in fact happened to a font... See
|
||||
;; https://bugzilla.gnome.org/show_bug.cgi?id=437633
|
||||
|
||||
|
||||
(define isMarkLigature
|
||||
(and (· curGlyph isMark)
|
||||
(for/and ([match-idx (in-list matched)])
|
||||
(· (list-ref (· this glyphs) match-idx) isMark))))
|
||||
|
||||
(report isMarkLigature)
|
||||
|
||||
(set-field! ligatureID ligatureGlyph (cond
|
||||
[isMarkLigature #f]
|
||||
[else (define id (· this ligatureID))
|
||||
(increment-field! ligatureID this)
|
||||
id]))
|
||||
|
||||
(define lastLigID (· curGlyph ligatureID))
|
||||
(define lastNumComps (length (· curGlyph codePoints)))
|
||||
(define curComps lastNumComps)
|
||||
(define idx (add1 (· this glyphIterator index)))
|
||||
|
||||
(report/file 'set-ligature-id)
|
||||
;; Set ligatureID and ligatureComponent on glyphs that were skipped in the matched sequence.
|
||||
;; This allows GPOS to attach marks to the correct ligature components.
|
||||
(for ([matchIndex (in-list matched)])
|
||||
(report/file matchIndex)
|
||||
;; Don't assign new ligature components for mark ligatures (see above)
|
||||
(cond
|
||||
[isMarkLigature (set! idx matchIndex)]
|
||||
[else (while (< idx matchIndex)
|
||||
(define ligatureComponent (+ curComps (- lastNumComps) (min (or (get-field ligatureComponent (list-ref (· this glyphs) idx)) 1) lastNumComps)))
|
||||
(set-field! ligatureID (list-ref (· this glyphs) idx) (· ligatureGlyph ligatureID))
|
||||
(set-field! ligatureComponent (list-ref (· this glyphs) idx) ligatureComponent)
|
||||
(increment! idx))])
|
||||
|
||||
(define lastLigID (· (list-ref (· this glyphs) idx) ligatureID))
|
||||
(define lastNumComps (length (· (list-ref (· this glyphs) idx) codePoints)))
|
||||
(increment! curComps lastNumComps)
|
||||
(increment! idx)) ;; skip base glyph
|
||||
|
||||
;; Adjust ligature components for any marks following
|
||||
(when (and lastLigID (not isMarkLigature))
|
||||
(for ([i (in-range idx (length (· this glyphs)))]
|
||||
#:when (= (· (list-ref (· this glyphs) idx) ligatureID) lastLigID))
|
||||
(define ligatureComponent (+ curComps (- lastNumComps) (min (or (get-field ligatureComponent (list-ref (· this glyphs) i)) 1) lastNumComps)))
|
||||
(set-field! ligatureComponent (list-ref (· this glyphs) i) ligatureComponent)))
|
||||
|
||||
;; Delete the matched glyphs, and replace the current glyph with the ligature glyph
|
||||
(set-field! glyphs this (drop-right (· this glyphs) (length matched)))
|
||||
(set-field! glyphs this (list-set (· this glyphs) (· this glyphIterator index) ligatureGlyph))
|
||||
#t)]
|
||||
[else #f])])))
|
||||
|
@ -0,0 +1,60 @@
|
||||
#lang fontkit/racket
|
||||
(require fontkit "gsub-processor.rkt" rackunit xenomorph racket/serialize describe)
|
||||
|
||||
(define fira-path "../pitfall/test/assets/fira.ttf")
|
||||
(define f (openSync fira-path))
|
||||
(define gsub (· f GSUB))
|
||||
|
||||
(define proc (+GSUBProcessor f gsub))
|
||||
|
||||
;; liga lookupList
|
||||
(car (· (get (· gsub lookupList) 30) subTables)) ; f gid = 450
|
||||
(send (· (car (· (get (· gsub lookupList) 30) subTables)) ligatureSets) to-list) ; i gid = 480, l gid = 514
|
||||
;; fi glyph = 731 fl glyph = 732
|
||||
|
||||
(check-equal? (dump (· proc features))
|
||||
'((c2sc (lookupCount . 1) (lookupListIndexes 26) (featureParams . 0))
|
||||
(pnum (lookupCount . 1) (lookupListIndexes 23) (featureParams . 0))
|
||||
(liga (lookupCount . 1) (lookupListIndexes 30) (featureParams . 0))
|
||||
(tnum (lookupCount . 1) (lookupListIndexes 24) (featureParams . 0))
|
||||
(onum (lookupCount . 1) (lookupListIndexes 25) (featureParams . 0))
|
||||
(ss01 (lookupCount . 1) (lookupListIndexes 33) (featureParams . 0))
|
||||
(dlig (lookupCount . 1) (lookupListIndexes 29) (featureParams . 0))
|
||||
(lnum (lookupCount . 1) (lookupListIndexes 22) (featureParams . 0))
|
||||
(sups (lookupCount . 1) (lookupListIndexes 14) (featureParams . 0))
|
||||
(zero (lookupCount . 1) (lookupListIndexes 31) (featureParams . 0))
|
||||
(ss02 (lookupCount . 1) (lookupListIndexes 34) (featureParams . 0))
|
||||
(aalt (lookupCount . 2) (lookupListIndexes 0 1) (featureParams . 0))
|
||||
(subs (lookupCount . 1) (lookupListIndexes 13) (featureParams . 0))
|
||||
(ss03 (lookupCount . 1) (lookupListIndexes 35) (featureParams . 0))
|
||||
(ordn (lookupCount . 2) (lookupListIndexes 20 21) (featureParams . 0))
|
||||
(calt (lookupCount . 4) (lookupListIndexes 36 37 38 39) (featureParams . 0))
|
||||
(dnom (lookupCount . 1) (lookupListIndexes 16) (featureParams . 0))
|
||||
(smcp (lookupCount . 1) (lookupListIndexes 27) (featureParams . 0))
|
||||
(salt (lookupCount . 1) (lookupListIndexes 32) (featureParams . 0))
|
||||
(case (lookupCount . 1) (lookupListIndexes 28) (featureParams . 0))
|
||||
(numr (lookupCount . 1) (lookupListIndexes 15) (featureParams . 0))
|
||||
(frac (lookupCount . 3) (lookupListIndexes 17 18 19) (featureParams . 0))
|
||||
(mgrk (lookupCount . 1) (lookupListIndexes 12) (featureParams . 0))))
|
||||
|
||||
(check-equal? (dump (· proc script))
|
||||
'((count . 0)
|
||||
(defaultLangSys
|
||||
(featureIndexes 0 14 28 42 56 70 84 98 112 136 150 164 178 192 206 220 234 248 262 276 290 304 318)
|
||||
(reserved . 0)
|
||||
(reqFeatureIndex . 65535)
|
||||
(featureCount . 23))
|
||||
(langSysRecords)))
|
||||
|
||||
(check-equal? (dump (· proc scriptTag)) 'DFLT)
|
||||
|
||||
(check-equal? (dump (· proc language))
|
||||
'((featureIndexes 0 14 28 42 56 70 84 98 112 136 150 164 178 192 206 220 234 248 262 276 290 304 318)
|
||||
(reserved . 0)
|
||||
(reqFeatureIndex . 65535)
|
||||
(featureCount . 23)))
|
||||
|
||||
(check-equal? (dump (· proc languageTag)) #f)
|
||||
(check-equal? (dump (· proc lookups)) empty)
|
||||
(check-equal? (dump (· proc direction)) 'ltr)
|
||||
|
@ -1,11 +1,158 @@
|
||||
#lang fontkit/racket
|
||||
(require "ot-processor.rkt")
|
||||
(require "ot-processor.rkt" "glyphinfo.rkt" br/cond)
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/fontkit/blob/master/src/opentype/GSUBProcessor.js
|
||||
|#
|
||||
|
||||
(define-subclass OTProcessor (GSUBProcessor)
|
||||
|
||||
)
|
||||
(define/override (applyLookup lookupType table)
|
||||
(report* 'GSUBProcessor:applyLookup lookupType)
|
||||
(case lookupType
|
||||
[(1) ;; Single Substitution
|
||||
(report 'single-substitution)
|
||||
(define index (send this coverageIndex (· table coverage)))
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[else (define glyph (· this glyphIterator cur))
|
||||
(set-field! id glyph
|
||||
(case (· table version)
|
||||
[(1) (bitwise-and (+ (· glyph id) (· table deltaGlyphID)) #xffff)]
|
||||
[(2) (send (· table substitute) get index)]))
|
||||
#t])]
|
||||
[(2) ;; Multiple Substitution
|
||||
(report 'multiple-substitution)
|
||||
(define index (send this coverageIndex (· table coverage)))
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[else (define sequence (send (· table sequences) get index))
|
||||
(set-field! id (· this glyphIterator cur) (list-ref sequence 0))
|
||||
(set-field! ligatureComponent (· this glyphIterator cur) 0)
|
||||
|
||||
(define features (· this glyphIterator cur features))
|
||||
(define curGlyph (· this glyphIterator cur))
|
||||
(define replacement (for/list ([(gid i) (in-indexed (cdr sequence))])
|
||||
(define glyph (+GlyphInfo (· this font) gid #f features))
|
||||
(set-field! shaperInfo glyph (· curGlyph shaperInfo))
|
||||
(set-field! isLigated glyph (· curGlyph isLigated))
|
||||
(set-field! ligatureComponent glyph (add1 i))
|
||||
(set-field! substituted glyph #t)
|
||||
glyph))
|
||||
|
||||
(set-field! glyphs this (let-values ([(head tail) (split-at (· this glyphs) (add1 (· this glyphIterator index)))])
|
||||
(append head replacement tail)))
|
||||
#t])]
|
||||
|
||||
[(3) ;; Alternate substitution
|
||||
(report 'alternate-substitution)
|
||||
(define index (send this coverageIndex (· table coverage)))
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[else (define USER_INDEX 0)
|
||||
(set-field! id (· this glyphIterator cur) (list-ref (send (· table alternateSet) get index) USER_INDEX))
|
||||
#t])]
|
||||
|
||||
[(4) ;; Ligature substitution
|
||||
(report '---------------------------)
|
||||
(report 'ligature-substitution)
|
||||
(report* lookupType (· table coverage glyphs))
|
||||
(define index (send this coverageIndex (· table coverage)))
|
||||
(report index 'forker)
|
||||
(cond
|
||||
[(= index -1) #f]
|
||||
[(for*/or ([ligature (in-list (report (send (· table ligatureSets) get (report index 'starting-index))))]
|
||||
[matched (in-value (send this sequenceMatchIndices 1 (report (· ligature components))))]
|
||||
#:when (report matched))
|
||||
(define curGlyph (· this glyphIterator cur))
|
||||
|
||||
;; Concatenate all of the characters the new ligature will represent
|
||||
(define characters
|
||||
(append (· curGlyph codePoints)
|
||||
(append* (for/list ([index (in-list matched)])
|
||||
(report index)
|
||||
(get-field codePoints (list-ref (· this glyphs) index))))))
|
||||
|
||||
(report characters)
|
||||
;; Create the replacement ligature glyph
|
||||
(define ligatureGlyph (+GlyphInfo (· this font) (· ligature glyph) characters (· curGlyph features)))
|
||||
(report (· ligatureGlyph id))
|
||||
(set-field! shaperInfo ligatureGlyph (· curGlyph shaperInfo))
|
||||
(set-field! isLigated ligatureGlyph #t)
|
||||
(set-field! substituted ligatureGlyph #t)
|
||||
|
||||
;; From Harfbuzz:
|
||||
;; - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
|
||||
;; the ligature to keep its old ligature id. This will allow it to attach to
|
||||
;; a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
|
||||
;; and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
|
||||
;; ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
|
||||
;; later, we don't want them to lose their ligature id/component, otherwise
|
||||
;; GPOS will fail to correctly position the mark ligature on top of the
|
||||
;; LAM,LAM,HEH ligature. See https://bugzilla.gnome.org/show_bug.cgi?id=676343
|
||||
;;
|
||||
;; - If a ligature is formed of components that some of which are also ligatures
|
||||
;; themselves, and those ligature components had marks attached to *their*
|
||||
;; components, we have to attach the marks to the new ligature component
|
||||
;; positions! Now *that*'s tricky! And these marks may be following the
|
||||
;; last component of the whole sequence, so we should loop forward looking
|
||||
;; for them and update them.
|
||||
;;
|
||||
;; Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
|
||||
;; 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
|
||||
;; id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
|
||||
;; form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
|
||||
;; the new ligature with a component value of 2.
|
||||
;;
|
||||
;; This in fact happened to a font... See
|
||||
;; https://bugzilla.gnome.org/show_bug.cgi?id=437633
|
||||
|
||||
|
||||
(define isMarkLigature
|
||||
(and (· curGlyph isMark)
|
||||
(for/and ([match-idx (in-list matched)])
|
||||
(· (list-ref (· this glyphs) match-idx) isMark))))
|
||||
|
||||
(set-field! ligatureID ligatureGlyph (cond
|
||||
[isMarkLigature #f]
|
||||
[else (define id (· this ligatureID))
|
||||
(increment-field! ligatureID this)
|
||||
id]))
|
||||
|
||||
(define lastLigID (· curGlyph ligatureID))
|
||||
(define lastNumComps (length (· curGlyph codePoints)))
|
||||
(define curComps lastNumComps)
|
||||
(define idx (add1 (· this glyphIterator index)))
|
||||
|
||||
;; Set ligatureID and ligatureComponent on glyphs that were skipped in the matched sequence.
|
||||
;; This allows GPOS to attach marks to the correct ligature components.
|
||||
(for ([matchIndex (in-list matched)])
|
||||
;; Don't assign new ligature components for mark ligatures (see above)
|
||||
(cond
|
||||
[isMarkLigature (set! idx matchIndex)]
|
||||
[else (while (< idx matchIndex)
|
||||
(define ligatureComponent (+ curComps (- lastNumComps) (min (or (get-field ligatureComponent (list-ref (· this glyphs) idx)) 1) lastNumComps)))
|
||||
(set-field! ligatureID (list-ref (· this glyphs) idx) (· ligatureGlyph ligatureID))
|
||||
(set-field! ligatureComponent (list-ref (· this glyphs) idx) ligatureComponent)
|
||||
(increment! idx))])
|
||||
|
||||
(define lastLigID (· (list-ref (· this glyphs) idx) ligatureID))
|
||||
(define lastNumComps (length (· (list-ref (· this glyphs) idx) codePoints)))
|
||||
(increment! curComps lastNumComps)
|
||||
(increment! idx)) ;; skip base glyph
|
||||
|
||||
;; Adjust ligature components for any marks following
|
||||
(when (and lastLigID (not isMarkLigature))
|
||||
(for ([i (in-range idx (length (· this glyphs)))]
|
||||
#:when (= (· (list-ref (· this glyphs) idx) ligatureID) lastLigID))
|
||||
(define ligatureComponent (+ curComps (- lastNumComps) (min (or (get-field ligatureComponent (list-ref (· this glyphs) i)) 1) lastNumComps)))
|
||||
(set-field! ligatureComponent (list-ref (· this glyphs) i) ligatureComponent)))
|
||||
|
||||
;; Delete the matched glyphs, and replace the current glyph with the ligature glyph
|
||||
(set-field! glyphs this (drop-right (· this glyphs) (length matched)))
|
||||
(set-field! glyphs this (list-set (· this glyphs) (· this glyphIterator index) ligatureGlyph))
|
||||
#t)]
|
||||
[else #f])])))
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue