structify glyph

main
Matthew Butterick 6 years ago
parent 6a7826c8b1
commit 5125ac1073

@ -244,13 +244,13 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js
;; Returns a glyph object for the given glyph id. ;; Returns a glyph object for the given glyph id.
;; You can pass the array of code points this glyph represents for ;; You can pass the array of code points this glyph represents for
;; your use later, and it will be stored in the glyph object. ;; your use later, and it will be stored in the glyph object.
(define/contract (getGlyph this glyph [characters null]) (define (getGlyph this glyph [characters null])
((index?) ((listof index?)) . ->*m . (is-a?/c Glyph)) #;((index?) ((listof index?)) . ->*m . glyph?)
;; no CFF ;; no CFF
#;(make-object (if (· this has-cff-table?) #;(make-object (if (· this has-cff-table?)
CFFGlyph CFFGlyph
TTFGlyph) glyph characters this) TTFGlyph) glyph characters this)
(make-object TTFGlyph glyph characters this)) (+ttf-glyph glyph characters this))
(define current-layout-caching (make-parameter #false)) (define current-layout-caching (make-parameter #false))
@ -340,8 +340,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js
;; This is only a one-to-one mapping from characters to glyphs. ;; This is only a one-to-one mapping from characters to glyphs.
;; For most uses, you should use font.layout (described below), which ;; For most uses, you should use font.layout (described below), which
;; provides a much more advanced mapping supporting AAT and OpenType shaping. ;; provides a much more advanced mapping supporting AAT and OpenType shaping.
(define/contract (glyphsForString this string) (define (glyphsForString this string)
(string? . ->m . (listof (is-a?/c Glyph))) #;(string? . ->m . (listof glyph?))
;; todo: make this handle UTF-16 with surrogate bytes ;; todo: make this handle UTF-16 with surrogate bytes
;; for now, just use UTF-8 ;; for now, just use UTF-8
@ -352,8 +352,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js
;; Maps a single unicode code point to a Glyph object. ;; Maps a single unicode code point to a Glyph object.
;; Does not perform any advanced substitutions (there is no context to do so). ;; Does not perform any advanced substitutions (there is no context to do so).
(define/contract (glyphForCodePoint this codePoint) (define (glyphForCodePoint this codePoint)
(index? . ->m . Glyph?) #;(index? . ->m . glyph?)
(define glyph-idx (FT_Get_Char_Index (· this ft-face) codePoint)) (define glyph-idx (FT_Get_Char_Index (· this ft-face) codePoint))
(send this getGlyph glyph-idx (list codePoint))) (send this getGlyph glyph-idx (list codePoint)))

@ -31,60 +31,64 @@ approximates
https://github.com/mbutterick/fontkit/blob/master/src/glyph/Glyph.js https://github.com/mbutterick/fontkit/blob/master/src/glyph/Glyph.js
|# |#
(define-subclass object% (Glyph id codePoints font) #;(define-subclass object% (Glyph id codePoints font)
(field [_font font] (field [_font font]
[isMark (andmap is-mark? codePoints)] [isMark (andmap is-mark? codePoints)]
[isLigature (> (length codePoints) 1)] [isLigature (> (length codePoints) 1)]
[_metrics #f]) [_metrics #f])
(as-methods (as-methods
_getPath advanceWidth
_getCBox _getMetrics))
_getBBox
_getTableMetrics (struct glyph (id codePoints font _font isMark isLigature _metrics) #:transparent #:mutable)
advanceWidth
_getMetrics)) (define (+glyph id codePoints font
[_font font]
(define-stub-stop _getPath) [isMark (andmap is-mark? codePoints)]
(define-stub-stop _getCBox) [isLigature (> (length codePoints) 1)]
(define-stub-stop _getBBox) [_metrics #f]
(define-stub-stop _getTableMetrics) #:constructor [constructor glyph])
(constructor id codePoints font _font isMark isLigature _metrics))
(define/contract (advanceWidth this)
(->m number?) #;(define-stub-stop _getPath)
(hash-ref (_getMetrics this) 'advanceWidth)) #;(define-stub-stop _getCBox)
#;(define-stub-stop _getBBox)
#;(define-stub-stop _getTableMetrics)
(define/contract (_getMetrics this)
(->m hash?) (define (glyph-advance-width g)
(unless (· this _metrics) (hash-ref (_getMetrics g) 'advanceWidth))
(define face (· this _font ft-face))
(FT_Load_Glyph face (· this id) FT_LOAD_NO_RECURSE)
(define (_getMetrics g)
(unless (glyph-_metrics g)
(define face (· (glyph-_font g) ft-face))
(FT_Load_Glyph face (glyph-id g) FT_LOAD_NO_RECURSE)
(define glyph (FT_FaceRec-glyph face)) (define glyph (FT_FaceRec-glyph face))
(define glyph-metrics (FT_GlyphSlotRec-metrics glyph)) (define glyph-metrics (FT_GlyphSlotRec-metrics glyph))
(set-field! _metrics this (mhash)) (set-glyph-_metrics! g (mhash))
(hash-set*! (· this _metrics) (hash-set*! (glyph-_metrics g)
'advanceWidth (FT_Glyph_Metrics-horiAdvance glyph-metrics) 'advanceWidth (FT_Glyph_Metrics-horiAdvance glyph-metrics)
'leftBearing (FT_Glyph_Metrics-horiBearingX glyph-metrics))) 'leftBearing (FT_Glyph_Metrics-horiBearingX glyph-metrics)))
(· this _metrics)) (glyph-_metrics g))
#| #|
approximates approximates
https://github.com/mbutterick/fontkit/blob/master/src/glyph/CFFGlyph.js https://github.com/mbutterick/fontkit/blob/master/src/glyph/CFFGlyph.js
|# |#
(define-subclass Glyph (CFFGlyph) #;(define-subclass Glyph (CFFGlyph)
(error 'cff-glyph-unimplemented) (error 'cff-glyph-unimplemented)
#;(define/override (_getName this) #;(define/override (_getName this)
(->m any/c) (->m any/c)
(if (send (· this _font) _getTable 'CFF2) (if (send (· this _font) _getTable 'CFF2)
(super _getName) (super _getName)
(send (send (· this _font) _getTable 'CFF_) getGlyphName (· this id)))) (send (send (· this _font) _getTable 'CFF_) getGlyphName (· this id))))
(as-methods (as-methods
#;_getName #;_getName
#;bias #;bias
#;_getPath)) #;_getPath))
@ -146,117 +150,125 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js
[scale10 0])) [scale10 0]))
;; Represents a TrueType glyph. ;; Represents a TrueType glyph.
(define-subclass Glyph (TTFGlyph) #;(define-subclass Glyph (TTFGlyph)
(inherit-field _font id) (inherit-field _font id))
;; Parses just the glyph header and returns the bounding box (struct ttf-glyph glyph () #:transparent)
(define/override (_getCBox internal)
(define (+ttf-glyph . args)
(apply +glyph #:constructor ttf-glyph args))
;; Parses just the glyph header and returns the bounding box
#;(define/override (_getCBox internal)
(unfinished)) (unfinished))
;; Parses a single glyph coordinate ;; Parses a single glyph coordinate
(define/public (_parseGlyphCoord port prev short same) (define (_parseGlyphCoord port prev short same)
(unless (input-port? port) (unless (input-port? port)
(raise-argument-error '_parseGlyphCoord "input port" port)) (raise-argument-error '_parseGlyphCoord "input port" port))
(unless (number? prev) (unless (number? prev)
(raise-argument-error '_parseGlyphCoord "number" prev)) (raise-argument-error '_parseGlyphCoord "number" prev))
(unless (and (boolean? short) (boolean? same)) (unless (and (boolean? short) (boolean? same))
(raise-argument-error '_parseGlyphCoord "booleans" (list short same))) (raise-argument-error '_parseGlyphCoord "booleans" (list short same)))
(+ prev (if short (+ prev (if short
((if (not same) - +) (decode uint8 port)) ((if (not same) - +) (decode uint8 port))
(if same 0 (decode int16be port))))) (if same 0 (decode int16be port)))))
;; Decodes the glyph data into points for simple glyphs, ;; Decodes the glyph data into points for simple glyphs,
;; or components for composite glyphs ;; or components for composite glyphs
(define/public (_decode) (define (glyph-decode ttfg)
(define offsets (· _font loca offsets)) (define offsets (· (glyph-_font ttfg) loca offsets))
(match-define (list glyfPos nextPos) (take (drop offsets id) 2)) (match-define (list glyfPos nextPos) (take (drop offsets (glyph-id ttfg)) 2))
;; Nothing to do if there is no data for this glyph ;; Nothing to do if there is no data for this glyph
(and (not (= glyfPos nextPos)) (and (not (= glyfPos nextPos))
(let () (let ()
(define port (send _font _getTableStream 'glyf)) (define port (send (glyph-_font ttfg) _getTableStream 'glyf))
(pos port (+ (pos port) glyfPos)) (pos port (+ (pos port) glyfPos))
(define startPos (pos port)) (define startPos (pos port))
(define glyph (decode GlyfHeader port)) (define glyph (decode GlyfHeader port))
(match (· glyph numberOfContours) (match (· glyph numberOfContours)
[(? positive?) (_decodeSimple glyph port)] [(? positive?) (_decodeSimple glyph port)]
[(? negative?) (_decodeComposite glyph port startPos)]) [(? negative?) (_decodeComposite glyph port startPos)])
glyph))) glyph)))
(define/public (_decodeSimple glyph port) (define (_decodeSimple glyph port)
(unless (dict? glyph) (unless (dict? glyph)
(raise-argument-error 'TTFGlyph-_decodeSimple "decoded RGlyfHeader" glyph)) (raise-argument-error 'TTFGlyph-_decodeSimple "decoded RGlyfHeader" glyph))
(unless (input-port? port) (unless (input-port? port)
(raise-argument-error 'TTFGlyph-_decodeSimple "input port" port)) (raise-argument-error 'TTFGlyph-_decodeSimple "input port" port))
;; this is a simple glyph ;; this is a simple glyph
(dict-set! glyph 'points empty) (dict-set! glyph 'points empty)
(define endPtsOfContours (decode (+Array uint16be (· glyph numberOfContours)) port)) (define endPtsOfContours (decode (+Array uint16be (· glyph numberOfContours)) port))
(dict-set! glyph 'instructions (decode (+Array uint8be uint16be) port)) (dict-set! glyph 'instructions (decode (+Array uint8be uint16be) port))
(define numCoords (add1 (last endPtsOfContours))) (define numCoords (add1 (last endPtsOfContours)))
(define flags (define flags
(for*/lists (flags) (for*/lists (flags)
([i (in-naturals)] ([i (in-naturals)]
#:break (= (length flags) numCoords) #:break (= (length flags) numCoords)
[flag (in-value (decode uint8 port))] [flag (in-value (decode uint8 port))]
[count (in-range (add1 (if (not (zero? (bitwise-and flag REPEAT))) [count (in-range (add1 (if (not (zero? (bitwise-and flag REPEAT)))
(decode uint8 port) (decode uint8 port)
0)))]) 0)))])
flag)) flag))
(match-define-values (match-define-values
(points _ _) (points _ _)
(for/fold ([points empty] [px 0] [py 0]) (for/fold ([points empty] [px 0] [py 0])
([(flag i) (in-indexed flags)]) ([(flag i) (in-indexed flags)])
(define point (+Point (zero? (bitwise-and flag ON_CURVE)) (and (index-of endPtsOfContours i) #t) 0 0)) (define point (+Point (zero? (bitwise-and flag ON_CURVE)) (and (index-of endPtsOfContours i) #t) 0 0))
(define next-px (_parseGlyphCoord port px (not (zero? (bitwise-and flag X_SHORT_VECTOR))) (not (zero? (bitwise-and flag SAME_X))))) (define next-px (_parseGlyphCoord port px (not (zero? (bitwise-and flag X_SHORT_VECTOR))) (not (zero? (bitwise-and flag SAME_X)))))
(define next-py (_parseGlyphCoord port py (not (zero? (bitwise-and flag Y_SHORT_VECTOR))) (not (zero? (bitwise-and flag SAME_Y))))) (define next-py (_parseGlyphCoord port py (not (zero? (bitwise-and flag Y_SHORT_VECTOR))) (not (zero? (bitwise-and flag SAME_Y)))))
(set-field! x point next-px) (set-field! x point next-px)
(set-field! y point next-py) (set-field! y point next-py)
(values (cons point points) next-px next-py))) (values (cons point points) next-px next-py)))
(dict-set! glyph 'points (reverse points))) (dict-set! glyph 'points (reverse points)))
(define/public (_decodeComposite glyph port [offset 0]) (define (_decodeComposite glyph port [offset 0])
;; this is a composite glyph ;; this is a composite glyph
(dict-set! glyph 'components empty) (dict-set! glyph 'components empty)
(define haveInstructions #f) (define haveInstructions #f)
(define flags MORE_COMPONENTS) (define flags MORE_COMPONENTS)
(dict-set! glyph 'components (dict-set! glyph 'components
(for/list ([i (in-naturals)] (for/list ([i (in-naturals)]
#:break (zero? (bitwise-and flags MORE_COMPONENTS))) #:break (zero? (bitwise-and flags MORE_COMPONENTS)))
(set! flags (send uint16be decode port)) (set! flags (send uint16be decode port))
(define gPos (- (pos port) offset)) (define gPos (- (pos port) offset))
(define glyphID (send uint16be decode port)) (define glyphID (send uint16be decode port))
(unless haveInstructions (unless haveInstructions
(set! haveInstructions (not (zero? (bitwise-and flags WE_HAVE_INSTRUCTIONS))))) (set! haveInstructions (not (zero? (bitwise-and flags WE_HAVE_INSTRUCTIONS)))))
(match-define (match-define
(list dx dy) (list dx dy)
(let ([decoder (if (not (zero? (bitwise-and flags ARG_1_AND_2_ARE_WORDS))) int16be int8)]) (let ([decoder (if (not (zero? (bitwise-and flags ARG_1_AND_2_ARE_WORDS))) int16be int8)])
(list (send decoder decode port) (send decoder decode port)))) (list (send decoder decode port) (send decoder decode port))))
(define component (+Component glyphID dx dy)) (define component (+Component glyphID dx dy))
(set-field! pos component gPos) (set-field! pos component gPos)
(cond (cond
[(not (zero? (bitwise-and flags WE_HAVE_A_SCALE))) [(not (zero? (bitwise-and flags WE_HAVE_A_SCALE)))
(define scale (read-fixed14 port)) (define scale (read-fixed14 port))
(set-field! scaleX component scale) (set-field! scaleX component scale)
(set-field! scaleY component scale)] (set-field! scaleY component scale)]
[(not (zero? (bitwise-and flags WE_HAVE_AN_X_AND_Y_SCALE))) [(not (zero? (bitwise-and flags WE_HAVE_AN_X_AND_Y_SCALE)))
(set-field! scaleX component (read-fixed14 port)) (set-field! scaleX component (read-fixed14 port))
(set-field! scaleY component (read-fixed14 port))] (set-field! scaleY component (read-fixed14 port))]
[(not (zero? (bitwise-and flags WE_HAVE_A_TWO_BY_TWO))) [(not (zero? (bitwise-and flags WE_HAVE_A_TWO_BY_TWO)))
(set-field! scaleX component (read-fixed14 port)) (set-field! scaleX component (read-fixed14 port))
(set-field! scale01 component (read-fixed14 port)) (set-field! scale01 component (read-fixed14 port))
(set-field! scale10 component (read-fixed14 port)) (set-field! scale10 component (read-fixed14 port))
(set-field! scaleY component (read-fixed14 port))]) (set-field! scaleY component (read-fixed14 port))])
component)) component))
haveInstructions)) haveInstructions)
(define (bytes->fixed14 b1 b2) (define (bytes->fixed14 b1 b2)

@ -8,4 +8,5 @@
"subset.rkt" "subset.rkt"
"bbox.rkt" "bbox.rkt"
"tables.rkt" "tables.rkt"
"glyphrun.rkt") "glyphrun.rkt"
"glyph.rkt")

@ -10,6 +10,7 @@
"table/loca.rkt" "table/loca.rkt"
"directory.rkt" "directory.rkt"
"helper.rkt" "helper.rkt"
fontland/glyph
xenomorph) xenomorph)
(provide Subset TTFSubset) (provide Subset TTFSubset)
@ -103,12 +104,12 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js
(index? . ->m . index?) (index? . ->m . index?)
(define glyph (send (· this font) getGlyph gid)) (define glyph (send (· this font) getGlyph gid))
;; _decode unpacks the `glyf` table data corresponding to a certin gid. ;; glyph-decode unpacks the `glyf` table data corresponding to a certin gid.
;; here, it's not necessary for non-composite glyphs ;; here, it's not necessary for non-composite glyphs
;; because they just get copied entirely into the subset. ;; because they just get copied entirely into the subset.
;; it's just used to detect composite glyphs and handle them specially. ;; it's just used to detect composite glyphs and handle them specially.
;; so an optimization would be to detect composite / noncomposite without full _decode. ;; so an optimization would be to detect composite / noncomposite without full glyph-decode.
(define glyf (send glyph _decode)) (define glyf (glyph-decode glyph))
;; get the offset to the glyph from the loca table ;; get the offset to the glyph from the loca table
(match-define (list curOffset nextOffset) (take (drop (· this font loca offsets) gid) 2)) (match-define (list curOffset nextOffset) (take (drop (· this font loca offsets) gid) 2))
@ -132,8 +133,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js
(append os (list (get-field offset this))))) (append os (list (get-field offset this)))))
(hash-update! (get-field hmtx this) 'metrics (λ (ms) (append ms (hash-update! (get-field hmtx this) 'metrics (λ (ms) (append ms
(list (mhash 'advance (· glyph advanceWidth) (list (mhash 'advance (glyph-advance-width glyph)
'bearing (· (send glyph _getMetrics) leftBearing)))))) 'bearing (· (_getMetrics glyph) leftBearing))))))
(increment-field! offset this (bytes-length buffer)) (increment-field! offset this (bytes-length buffer))
(sub1 (length (· this glyf)))) (sub1 (length (· this glyf))))

Loading…
Cancel
Save