diff --git a/pitfall/fontkit/font.rkt b/pitfall/fontkit/font.rkt index c9826ddb..e123ea8a 100644 --- a/pitfall/fontkit/font.rkt +++ b/pitfall/fontkit/font.rkt @@ -44,11 +44,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js (define/public (_getTableStream tag) (define table (hash-ref (· this directory tables) tag)) - (cond - [table - (send stream pos (· table offset)) - stream] - [else #f])) + (and table (send stream pos (· table offset)) stream)) (define/public (_decodeTable table-tag) (define table-decoder (hash-ref table-codecs table-tag @@ -233,7 +229,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 . GlyphRun?) + ((string?) ((option/c (listof symbol?)) (option/c symbol?) (option/c symbol?)) . ->*m . GlyphRun?) (unless (· this _layoutEngine) (set-field! _layoutEngine this (make-object LayoutEngine this))) (report 'in-layout) @@ -257,7 +253,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js ;; Maps a single unicode code point to a Glyph object. ;; Does not perform any advanced substitutions (there is no context to do so). (define/contract (glyphForCodePoint this codePoint) - (index? . ->m . (is-a?/c Glyph)) + (index? . ->m . Glyph?) (define glyph-idx (FT_Get_Char_Index (· this ft-face) codePoint)) (send this getGlyph glyph-idx (list codePoint))) @@ -287,14 +283,14 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js (define/contract (openSync filename [postscriptName #f]) - ((string?) ((or/c string? #f)) . ->* . TTFFont?) + ((string?) ((option/c string?)) . ->* . TTFFont?) (define buffer (file->bytes filename)) (create buffer filename postscriptName)) (define/contract (create buffer [filename #f] [postscriptName #f]) - ((bytes?) ((or/c path-string? #f) (or/c string? #f)) . ->* . TTFFont?) + ((bytes?) ((option/c path-string?) (option/c string?)) . ->* . TTFFont?) (or (for*/first ([format (in-list formats)] ;; rather than use a `probe` function, diff --git a/pitfall/fontkit/glyph.rkt b/pitfall/fontkit/glyph.rkt index 8397da37..b804b1bf 100644 --- a/pitfall/fontkit/glyph.rkt +++ b/pitfall/fontkit/glyph.rkt @@ -1,6 +1,6 @@ #lang fontkit/racket (require "freetype-ffi.rkt") -(provide Glyph CFFGlyph) +(provide (all-defined-out)) (module+ test (require rackunit)) #| diff --git a/pitfall/fontkit/glyphrun.rkt b/pitfall/fontkit/glyphrun.rkt index 5dc0f8e8..4b43dd53 100644 --- a/pitfall/fontkit/glyphrun.rkt +++ b/pitfall/fontkit/glyphrun.rkt @@ -1,5 +1,5 @@ #lang fontkit/racket -(require "bbox.rkt" "script.rkt") +(require "bbox.rkt" (prefix-in Script- "script.rkt")) (provide (all-defined-out)) ;; Represents a run of Glyph and GlyphPosition objects. @@ -15,7 +15,7 @@ (field [positions #f]) ;; The directionality of the requested script (either ltr or rtl). - (field [direction (script-direction script)]) + (field [direction (Script-direction script)]) ;; The features requested during shaping. This is a combination of user ;; specified features and features chosen by the shaper. diff --git a/pitfall/fontkit/gpos-processor.rkt b/pitfall/fontkit/gpos-processor.rkt new file mode 100644 index 00000000..446b02ec --- /dev/null +++ b/pitfall/fontkit/gpos-processor.rkt @@ -0,0 +1,11 @@ +#lang fontkit/racket +(require "ot-processor.rkt") +(provide (all-defined-out)) + +#| +https://github.com/mbutterick/fontkit/blob/master/src/opentype/GPOSProcessor.js +|# + +(define-subclass OTProcessor (GPOSProcessor) + + ) \ No newline at end of file diff --git a/pitfall/fontkit/gsub-processor.rkt b/pitfall/fontkit/gsub-processor.rkt new file mode 100644 index 00000000..fc75692b --- /dev/null +++ b/pitfall/fontkit/gsub-processor.rkt @@ -0,0 +1,11 @@ +#lang fontkit/racket +(require "ot-processor.rkt") +(provide (all-defined-out)) + +#| +https://github.com/mbutterick/fontkit/blob/master/src/opentype/GSUBProcessor.js +|# + +(define-subclass OTProcessor (GSUBProcessor) + + ) \ No newline at end of file diff --git a/pitfall/fontkit/layout-engine.rkt b/pitfall/fontkit/layout-engine.rkt index 0043be59..0a6b6d48 100644 --- a/pitfall/fontkit/layout-engine.rkt +++ b/pitfall/fontkit/layout-engine.rkt @@ -1,6 +1,6 @@ #lang fontkit/racket -(require "script.rkt" "glyph.rkt" "glyphrun.rkt" "glyph-position.rkt") -(provide LayoutEngine) +(require (prefix-in Script- "script.rkt") "glyph.rkt" "glyphrun.rkt" "glyph-position.rkt" "ot-layout-engine.rkt") +(provide (all-defined-out)) #| approximates @@ -18,7 +18,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/layout/LayoutEngine.js (cond [(· this font has-morx-table?) (error 'morx-layout-unimplemented)] [(or (· this font has-gsub-table?) (· this font has-gpos-table?)) - (displayln 'warning:ot-layout-unimplemented) #f] + (+OTLayoutEngine (· this font))] [else #f])]) (as-methods @@ -30,11 +30,11 @@ https://github.com/mbutterick/fontkit/blob/master/src/layout/LayoutEngine.js (define/contract (layout this str-or-glyphs [features #f] ;; Attempt to detect the script if not provided. - [script (if (string? str-or-glyphs) - (script-for-string str-or-glyphs) - (script-for-codepoints (append-map (λ (g) (· g codePoints)) str-or-glyphs)))] + [script (report (if (string? str-or-glyphs) + (Script-forString str-or-glyphs) + (Script-forCodePoints (append-map (λ (g) (· g codePoints)) str-or-glyphs))))] [language #f]) - (((or/c string? (listof (is-a?/c Glyph)))) ((or/c list? #f) (or/c symbol? #f) (or/c symbol? #f)) . ->*m . (is-a?/c GlyphRun)) + (((or/c string? (listof Glyph?))) ((option/c list?) (option/c symbol?) (option/c symbol?)) . ->*m . GlyphRun?) (define glyphs (if (string? str-or-glyphs) diff --git a/pitfall/fontkit/ot-layout-engine.rkt b/pitfall/fontkit/ot-layout-engine.rkt new file mode 100644 index 00000000..3e214b84 --- /dev/null +++ b/pitfall/fontkit/ot-layout-engine.rkt @@ -0,0 +1,24 @@ +#lang fontkit/racket +(require "gsub-processor.rkt" "gpos-processor.rkt") +(provide (all-defined-out)) + +#| +https://github.com/mbutterick/fontkit/blob/master/src/opentype/OTLayoutEngine.js +|# + +(define-subclass object% (OTLayoutEngine font) + (field [glyphInfos #f] + [plan #f] + [GSUBProcessor #f] + [GPOSProcessor #f]) + + (report 'dingdong) + (when (· font has-gsub-table?) + (set-field! GSUBProcessor this (+GSUBProcessor font (· font GSUB)))) + + (when (· font has-gpos-table?) + (set-field! GPOSProcessor this (+GPOSProcessor font (· font GPOS)))) + + + + ) \ No newline at end of file diff --git a/pitfall/fontkit/ot-processor.rkt b/pitfall/fontkit/ot-processor.rkt new file mode 100644 index 00000000..56da5098 --- /dev/null +++ b/pitfall/fontkit/ot-processor.rkt @@ -0,0 +1,79 @@ +#lang fontkit/racket +(require (prefix-in Script- "script.rkt")) +(provide (all-defined-out)) + +#| +https://github.com/mbutterick/fontkit/blob/master/src/opentype/OTProcessor.js +|# + + +(define DEFAULT_SCRIPTS '(DFLT dflt latn)) + +(define-subclass object% (OTProcessor font table) + (field [script #f] + [scriptTag #f] + [language #f] + [languageTag #f] + [features (mhash)] + [lookups (mhash)]) + + ;; initialize to default script + language + (selectScript) + + ;; current context (set by applyFeatures) + (field [glyphs empty] + [positions empty] ; only used by GPOS + [ligatureID 1]) + + (define/public (findScript script) + (unless (script? script) + (raise-argument-error 'findScript "script" script)) + (and (· this table scriptList) + (let ([script (if (not (list? script)) (list script) script)]) + (for*/first ([entry (in-list (· this table scriptList))] + [s (in-list script)] + #:when (equal? (· entry tag) s)) + entry)))) + + + (define/public (selectScript script language) + (let/ec return! + (define changed #f) + (define entry #f) + (when (or (not (· this script)) (not (equal? script (· this scriptTag)))) + (set! entry (findScript script)) + (when script + (set! entry (findScript script))) ; ? why double dip + (when (not entry) + (set! entry (findScript DEFAULT_SCRIPTS))) + (when (not entry) + (return! (void))) + (set-field! scriptTag this (· entry tag)) + (set-field! script this (· entry script)) + (set-field! direction this (Script-direction script)) + (set-field! language this #f) + (set! changed #t)) + + (when (and (not language) (not (equal? language (· this languageTag)))) + (for/first ([lang (in-list (· this script langSysRecords))] + #:when (equal? (· lang tag) language)) + (set-field! language this (· lang langSys)) + (set-field! languageTag this (· lang tag)) + (set! changed #t))) + + (when (not (· this language)) + (set-field! language this (· this script defaultLangSys))) + + ;; Build a feature lookup table + (when changed + (set-field! features this (mhash)) + (when (· this language) + (for ([featureIndex (in-list (· this language featureIndexes))]) + (define record (hash-ref (· this table featureList) featureIndex)) + (hash-set! (· this features) (· record tag)) (· record feature)))))) + + + ) + + + diff --git a/pitfall/fontkit/racket.rkt b/pitfall/fontkit/racket.rkt index 5bb02fe4..fb510583 100644 --- a/pitfall/fontkit/racket.rkt +++ b/pitfall/fontkit/racket.rkt @@ -1,7 +1,7 @@ #lang racket/base (require (for-syntax racket/base br/syntax)) (provide (for-syntax (all-from-out racket/base br/syntax))) -(provide (all-from-out racket/base) r+p) +(provide (all-from-out racket/base) r+p (all-defined-out)) (define-syntax-rule (r+p id ...) (begin (require id ...) (provide (all-from-out id ...)))) @@ -21,7 +21,10 @@ sugar/js sugar/dict sugar/stub - sugar/port) + sugar/port + sugar/contract) + +(define script? symbol?) (module reader syntax/module-reader #:language 'fontkit/racket diff --git a/pitfall/fontkit/script.rkt b/pitfall/fontkit/script.rkt index dfdecfc8..6169a011 100644 --- a/pitfall/fontkit/script.rkt +++ b/pitfall/fontkit/script.rkt @@ -1,23 +1,182 @@ #lang fontkit/racket (provide (all-defined-out)) -;; approximates -;; https://github.com/devongovett/fontkit/blob/master/src/layout/Script.js +#| +https://github.com/mbutterick/fontkit/blob/master/src/layout/Script.js +|# -(define/contract (script-for-string str) - (string? . -> . symbol?) - ;; infers unicode script from string. - ;; todo: everything - 'latn) +;; This maps the Unicode Script property to an OpenType script tag +;; Data from http://www.microsoft.com/typography/otspec/scripttags.htm +;; and http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt. +(define UNICODE_SCRIPTS + (apply mhash + '(Caucasian_Albanian aghb + Arabic arab + Imperial_Aramaic armi + Armenian armn + Avestan avst + Balinese bali + Bamum bamu + Bassa_Vah bass + Batak batk + Bengali '(bng2 beng) + Bopomofo bopo + Brahmi brah + Braille brai + Buginese bugi + Buhid buhd + Chakma cakm + Canadian_Aboriginal cans + Carian cari + Cham cham + Cherokee cher + Coptic copt + Cypriot cprt + Cyrillic cyrl + Devanagari '(dev2 deva) + Deseret dsrt + Duployan dupl + Egyptian_Hieroglyphs egyp + Elbasan elba + Ethiopic ethi + Georgian geor + Glagolitic glag + Gothic goth + Grantha gran + Greek grek + Gujarati '(gjr2 gujr) + Gurmukhi '(gur2 guru) + Hangul hang + Han hani + Hanunoo hano + Hebrew hebr + Hiragana hira + Pahawh_Hmong hmng + Katakana_Or_Hiragana hrkt + Old_Italic ital + Javanese java + Kayah_Li kali + Katakana kana + Kharoshthi khar + Khmer khmr + Khojki khoj + Kannada '(knd2 knda) + Kaithi kthi + Tai_Tham lana + Lao lao + Latin latn + Lepcha lepc + Limbu limb + Linear_A lina + Linear_B linb + Lisu lisu + Lycian lyci + Lydian lydi + Mahajani mahj + Mandaic mand + Manichaean mani + Mende_Kikakui mend + Meroitic_Cursive merc + Meroitic_Hieroglyphs mero + Malayalam '(mlm2 mlym) + Modi modi + Mongolian mong + Mro mroo + Meetei_Mayek mtei + Myanmar '(mym2 mymr) + Old_North_Arabian narb + Nabataean nbat + Nko nko + Ogham ogam + Ol_Chiki olck + Old_Turkic orkh + Oriya orya + Osmanya osma + Palmyrene palm + Pau_Cin_Hau pauc + Old_Permic perm + Phags_Pa phag + Inscriptional_Pahlavi phli + Psalter_Pahlavi phlp + Phoenician phnx + Miao plrd + Inscriptional_Parthian prti + Rejang rjng + Runic runr + Samaritan samr + Old_South_Arabian sarb + Saurashtra saur + Shavian shaw + Sharada shrd + Siddham sidd + Khudawadi sind + Sinhala sinh + Sora_Sompeng sora + Sundanese sund + Syloti_Nagri sylo + Syriac syrc + Tagbanwa tagb + Takri takr + Tai_Le tale + New_Tai_Lue talu + Tamil taml + Tai_Viet tavt + Telugu '(tel2 telu) + Tifinagh tfng + Tagalog tglg + Thaana thaa + Thai thai + Tibetan tibt + Tirhuta tirh + Ugaritic ugar + Vai vai + Warang_Citi wara + Old_Persian xpeo + Cuneiform xsux + Yi yi + Inherited zinh + Common zyyy + Unknown zzzz))) -(define/contract (script-for-codepoints codepoints) - ((listof integer?) . -> . symbol?) - ;; infers unicode script from string. - ;; todo: everything - (error 'script-for-codepoints-unimplemented)) +(define/contract (fromUnicode script) + ((option/c script?) . -> . script?) + (hash-ref UNICODE_SCRIPTS script #f)) -(define/contract (script-direction script) - ((or/c symbol? #f) . -> . symbol?) - 'ltr) ; todo everything \ No newline at end of file +(define-stub-stop forString) + +(define-stub-stop forCodePoints) + +(define RTL '( arab ;; Arabic + hebr ;; Hebrew + syrc ;; Syriac + thaa ;; Thaana + cprt ;; Cypriot Syllabary + khar ;; Kharosthi + phnx ;; Phoenician + |nko | ;; N'Ko + lydi ;; Lydian + avst ;; Avestan + armi ;; Imperial Aramaic + phli ;; Inscriptional Pahlavi + prti ;; Inscriptional Parthian + sarb ;; Old South Arabian + orkh ;; Old Turkic, Orkhon Runic + samr ;; Samaritan + mand ;; Mandaic, Mandaean + merc ;; Meroitic Cursive + mero ;; Meroitic Hieroglyphs + + ;; Unicode 7.0 (not listed on http://www.microsoft.com/typography/otspec/scripttags.htm) + mani ;; Manichaean + mend ;; Mende Kikakui + nbat ;; Nabataean + narb ;; Old North Arabian + palm ;; Palmyrene + phlp ;; Psalter Pahlavi + )) + +(define/contract (direction script) + ((option/c script?) . -> . (or/c 'rtl 'ltr)) + (if (memq script RTL) 'rtl 'ltr)) \ No newline at end of file diff --git a/pitfall/pitfall/embedded.rkt b/pitfall/pitfall/embedded.rkt index 2dca7cb6..549abddb 100644 --- a/pitfall/pitfall/embedded.rkt +++ b/pitfall/pitfall/embedded.rkt @@ -32,7 +32,7 @@ https://github.com/mbutterick/pdfkit/blob/master/lib/font/embedded.coffee ((string? number?) ((option/c list?)) . ->*m . number?) (cond [features - (define run (send (· this font) layout string features)) ; todo: features would be passed here + (define run (send (· this font) layout string features)) (define width (· run advanceWidth)) (define scale (/ size (· this font unitsPerEm))) (* width scale)] diff --git a/pitfall/pitfall/test/test14rkt.pdf b/pitfall/pitfall/test/test14rkt.pdf index a2e57e9f..e69de29b 100644 Binary files a/pitfall/pitfall/test/test14rkt.pdf and b/pitfall/pitfall/test/test14rkt.pdf differ diff --git a/pitfall/pitfall/test/test15.rkt b/pitfall/pitfall/test/test15.rkt index 7257bc8c..e2295473 100644 --- a/pitfall/pitfall/test/test15.rkt +++ b/pitfall/pitfall/test/test15.rkt @@ -16,5 +16,5 @@ (define-runtime-path this "test15rkt.pdf") (make-doc this #f proc #:test #f) -#;(define-runtime-path that "test14crkt.pdf") +#;(define-runtime-path that "test15crkt.pdf") #;(make-doc that #t proc #:pdfkit #f) \ No newline at end of file