From 8a2462c45a539967d3ef9daef2a288f983c99488 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Mon, 4 Mar 2019 15:27:30 -0800 Subject: [PATCH] start cff read --- .../fontland/assets/fira-otf-directory.rktd | 114 ++++++++++++++++++ fontland/fontland/directory.rkt | 11 +- fontland/fontland/glyph.rkt | 12 +- fontland/fontland/helper.rkt | 3 +- fontland/fontland/struct.rkt | 4 +- fontland/fontland/subset.rkt | 24 +++- fontland/fontland/table/CFF_.rkt | 31 ++++- fontland/fontland/table/cff-index.rkt | 25 ++++ fontland/fontland/table/cff-top.rkt | 26 ++++ fontland/fontland/tables.rkt | 4 +- 10 files changed, 234 insertions(+), 20 deletions(-) create mode 100644 fontland/fontland/assets/fira-otf-directory.rktd create mode 100644 fontland/fontland/table/cff-index.rkt create mode 100644 fontland/fontland/table/cff-top.rkt diff --git a/fontland/fontland/assets/fira-otf-directory.rktd b/fontland/fontland/assets/fira-otf-directory.rktd new file mode 100644 index 00000000..8ea7518d --- /dev/null +++ b/fontland/fontland/assets/fira-otf-directory.rktd @@ -0,0 +1,114 @@ +((3) + 0 + () + 0 + () + () + (h + ! + () + (tag . OTTO) + (rangeShift . 64) + (searchRange . 128) + (numTables . 12) + (entrySelector . 3) + (tables + h + ! + (equal) + (maxp + h + ! + () + (tag . maxp) + (length . 6) + (checkSum . 172445696) + (offset . 204)) + (CFF_ + h + ! + () + (tag . |CFF |) + (length . 164604) + (checkSum . 516494622) + (offset . 33472)) + (hhea + h + ! + () + (tag . hhea) + (length . 36) + (checkSum . 101714507) + (offset . 10792)) + (post + h + ! + () + (tag . post) + (length . 32) + (checkSum . 4290248754) + (offset . 33440)) + (GDEF + h + ! + () + (tag . GDEF) + (length . 392) + (checkSum . 936918765) + (offset . 198076)) + (head + h + ! + () + (tag . head) + (length . 54) + (checkSum . 95220183) + (offset . 212)) + (GPOS + h + ! + () + (tag . GPOS) + (length . 78818) + (checkSum . 4027394566) + (offset . 198468)) + (cmap + h + ! + () + (tag . cmap) + (length . 20808) + (checkSum . 3634078005) + (offset . 12632)) + (name + h + ! + () + (tag . name) + (length . 1706) + (checkSum . 2142217964) + (offset . 10924)) + (GSUB + h + ! + () + (tag . GSUB) + (length . 19078) + (checkSum . 1205824848) + (offset . 277288)) + (hmtx + h + ! + () + (tag . hmtx) + (length . 10524) + (checkSum . 2729095083) + (offset . 268)) + (OS/2 + h + ! + () + (tag . OS/2) + (length . 96) + (checkSum . 1618270015) + (offset . 10828))))) diff --git a/fontland/fontland/directory.rkt b/fontland/fontland/directory.rkt index 39c5afee..b56b6dc9 100644 --- a/fontland/fontland/directory.rkt +++ b/fontland/fontland/directory.rkt @@ -65,7 +65,10 @@ https://github.com/mbutterick/fontkit/blob/master/src/tables/directory.js (define (file-directory-decode ps) (directory-decode (open-input-file ps))) -#;(test-module - (define ip (open-input-file charter-path)) - (define decoded-dir (deserialize (read (open-input-file charter-directory-path)))) - (check-equal? (directory-decode ip) decoded-dir)) \ No newline at end of file +#;(module+ test + (require rackunit "helper.rkt" racket/serialize racket/file racket/pretty) + (define ip (open-input-file fira-otf-path)) + (define dir (serialize (directory-decode ip))) + (pretty-write dir) + (with-output-to-file "assets/fira-otf-directory.rktd" + (λ () (pretty-write dir)) #:exists 'replace)) \ No newline at end of file diff --git a/fontland/fontland/glyph.rkt b/fontland/fontland/glyph.rkt index a01ab70c..b74e26da 100644 --- a/fontland/fontland/glyph.rkt +++ b/fontland/fontland/glyph.rkt @@ -44,15 +44,21 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/Glyph.js 'leftBearing (FT_Glyph_Metrics-horiBearingX ft-glyph-metrics))) (glyph-metrics g)) -;; Represents a TrueType glyph. - (define (+ttf-glyph . args) (apply +glyph #:constructor ttf-glyph args)) +(define (+cff-glyph . args) + (apply +glyph #:constructor cff-glyph args)) + +#| +approximates +https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFFont.js +|# + ;; Returns a glyph object for the given glyph id. ;; You can pass the array of code points this glyph represents for ;; your use later, and it will be stored in the glyph object. (define (get-glyph font gid [codepoints null]) ((if (has-table? font #"CFF_") - (error 'cff-fonts-unsupported) + +cff-glyph +ttf-glyph) gid codepoints font)) \ No newline at end of file diff --git a/fontland/fontland/helper.rkt b/fontland/fontland/helper.rkt index c1d15c9a..a51dab30 100644 --- a/fontland/fontland/helper.rkt +++ b/fontland/fontland/helper.rkt @@ -12,4 +12,5 @@ (define-runtime-path fira-path "assets/fira.ttf") (define-runtime-path fira-otf-path "assets/fira.otf") (define-runtime-path charter-directory-path "assets/charter-directory.rktd") -(define-runtime-path charter-italic-directory-path "assets/charter-italic-directory.rktd") \ No newline at end of file +(define-runtime-path charter-italic-directory-path "assets/charter-italic-directory.rktd") +(define-runtime-path fira-otf-directory-path "assets/fira-otf-directory.rktd") \ No newline at end of file diff --git a/fontland/fontland/struct.rkt b/fontland/fontland/struct.rkt index 130a49e5..1c41f03d 100644 --- a/fontland/fontland/struct.rkt +++ b/fontland/fontland/struct.rkt @@ -19,4 +19,6 @@ (struct glyph (id codepoints font is-mark? is-ligature? metrics) #:transparent #:mutable) -(struct ttf-glyph glyph () #:transparent) \ No newline at end of file +(struct ttf-glyph glyph () #:transparent) + +(struct cff-glyph glyph () #:transparent) \ No newline at end of file diff --git a/fontland/fontland/subset.rkt b/fontland/fontland/subset.rkt index 469c2b1f..2f720562 100644 --- a/fontland/fontland/subset.rkt +++ b/fontland/fontland/subset.rkt @@ -43,7 +43,9 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/Subset.js (define (encode-to-port ss) (define p (open-output-bytes)) - (subset-encode ss p) + ((if (cff-subset? ss) + cff-subset-encode + ttf-subset-encode) ss p) p) (define (subset-add-glyph! ss glyph-or-gid) ; fka `includeGlyph` @@ -64,7 +66,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/CFFSubset.js (struct cff-subset subset (cff strings charstrings gsubrs) #:transparent #:mutable) (define (+cff-subset font [glyphs empty] [mapping (mhash)] - [cff #f] + [cff (get-table font 'CFF_)] [strings #f] [charstrings #f] [gsubrs #f]) @@ -72,7 +74,21 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/CFFSubset.js (subset-add-glyph! ss 0) ss) -(module+ test +(define (subsetCharstrings this) + (set-cff-subset-charstrings! this null) + (define gsubrs (make-hash)) + #;(for ([gid (in-list (subset-glyphs this))]) + (define new-string (getCharString (cff-subset-cff this) gid)) + (set-cff-subset-charstrings! this (cons new-string (cff-subset-charstrings this)))) + (error 'subsetCharStrings-unfinished)) + +(define (cff-subset-encode ss port) + ;; ss = this + ;; port = stream + (subsetCharstrings ss) + (error 'cff-subset-encode-unfinished)) + +#;(module+ test (require "font.rkt" "helper.rkt") (define otf (open-font (path->string fira-otf-path))) (define cffss (+cff-subset otf)) @@ -137,7 +153,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js (define (clone-deep val) (deserialize (serialize val))) -(define (subset-encode ss port) +(define (ttf-subset-encode ss port) (set-ttf-subset-glyf! ss empty) (set-ttf-subset-offset! ss 0) (set-ttf-subset-loca! ss (mhash 'offsets empty)) diff --git a/fontland/fontland/table/CFF_.rkt b/fontland/fontland/table/CFF_.rkt index 1b8fd067..4c2a8814 100644 --- a/fontland/fontland/table/CFF_.rkt +++ b/fontland/fontland/table/CFF_.rkt @@ -1,6 +1,6 @@ -#lang racket/base -(require xenomorph) -(provide CFF_) +#lang debug racket/base +(require racket/class xenomorph "cff-top.rkt") +(provide (rename-out (CFFFont CFF_))) #| approximates @@ -8,7 +8,28 @@ https://github.com/mbutterick/fontkit/blob/master/src/cff/CFFFont.js |# ;; the CFFFont object acts as the decoder for the `CFF ` table. -;; no CFF support yet -(define CFF_ (x:buffer)) +(struct $CFFFont (stream) #:transparent #:mutable) +(define CFFFont + (make-object + (class xenobase% + (super-new) + + (define/augride (:decode port parent [len 0]) + (define stream port) + (define start (pos stream)) + (define top (decode CFFTop stream)) + top)))) + + +(module+ test + (require rackunit racket/serialize racket/stream "../helper.rkt") + (define dir (deserialize (read (open-input-file #R fira-otf-directory-path)))) + (define cff-offset (hash-ref (hash-ref (hash-ref dir 'tables) 'CFF_) 'offset)) + (define cff-length (hash-ref (hash-ref (hash-ref dir 'tables) 'CFF_) 'length)) + (define ip (open-input-file fira-otf-path)) + (define cff-bytes (peek-bytes #R cff-length #R cff-offset ip)) + (define cff-data (decode CFFFont cff-bytes)) + cff-data + ) \ No newline at end of file diff --git a/fontland/fontland/table/cff-index.rkt b/fontland/fontland/table/cff-index.rkt new file mode 100644 index 00000000..fd80f168 --- /dev/null +++ b/fontland/fontland/table/cff-index.rkt @@ -0,0 +1,25 @@ +#lang racket/base +(require racket/class xenomorph sugar/unstable/dict) +(provide CFFIndex) + +(define CFFIndex% + (class xenobase% + (super-new) + (init-field [type type]) + + (define (getCFFVersion ctx) + (let loop ([ctx ctx]) + (if (and ctx (not (hash-ref ctx 'hdrSize))) + (loop (hash-ref ctx 'parent)) + (if ctx (hash-ref ctx 'version) -1)))) + + (define/augride (:decode stream parent) + (define version (getCFFVersion parent)) + (define count (decode (if (>= version 2) + uint32be + uint16be) stream)) + count + ))) + +(define (CFFIndex type) + (new CFFIndex% [type type])) \ No newline at end of file diff --git a/fontland/fontland/table/cff-top.rkt b/fontland/fontland/table/cff-top.rkt new file mode 100644 index 00000000..e946a586 --- /dev/null +++ b/fontland/fontland/table/cff-top.rkt @@ -0,0 +1,26 @@ +#lang racket/base +(require xenomorph sugar/unstable/dict "cff-index.rkt") +(provide CFFTop) + +#| +approximates +https://github.com/mbutterick/fontkit/blob/master/src/cff/CFFTop.js +|# + +(define CFFTop + (x:versioned-struct + fixed16be + (dictify + 1 (dictify 'hdrSize uint8 + 'offSize uint8 + ;;'nameIndex (CFFIndex (x:string #:length 'length)) + ;;'topDictIndex (CFFIndex CFFTopDict) + ;;'stringIndex (CFFIndex (x:string #:length 'length)) + ;;'globalSubrIndex (CFFIndex) + ) + + 2 (dictify 'hdrSize uint8 + 'length uint16be + ;;'topDict CFF2TopDict + ;;'globalSubrIndex (CFFIndex) + )))) \ No newline at end of file diff --git a/fontland/fontland/tables.rkt b/fontland/fontland/tables.rkt index 7d6521bb..b0d56687 100644 --- a/fontland/fontland/tables.rkt +++ b/fontland/fontland/tables.rkt @@ -16,14 +16,14 @@ https://github.com/mbutterick/fontkit/blob/master/src/tables/index.js (r+p TABLE-ID-STRING ...) (define ID (make-hasheq (map cons (list 'TABLE-ID ...) (list TABLE-ID ...))))))])) -(define-table-codecs table-codecs head hhea hmtx maxp OS/2 post cvt_ fpgm loca prep glyf) +(define-table-codecs table-codecs head hhea hmtx maxp OS/2 post cvt_ fpgm loca prep glyf CFF_) #| Tables not supported: cmap name PostScript outlines: -CFF_ CFF2 VORG +CFF2 VORG Advanced OpenType Tables BASE GDEF GPOS GSUB JSTF |# \ No newline at end of file