studying cmap

main
Matthew Butterick 7 years ago
parent d09e421406
commit fa79310464

@ -209,6 +209,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js
;; 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/contract (glyphsForString this string)
(string? . ->m . (listof (is-a?/c Glyph))) (string? . ->m . (listof (is-a?/c Glyph)))
(report string 'glyphs-for-string)
;; 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
@ -221,7 +222,9 @@ https://github.com/mbutterick/fontkit/blob/master/src/TTFFont.js
;; 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/contract (glyphForCodePoint this codePoint)
(index? . ->m . (is-a?/c Glyph)) (index? . ->m . (is-a?/c Glyph))
(report codePoint 'glyphs-for-codepoint-cp)
(define glyph-idx (FT_Get_Char_Index (· this ft-face) codePoint)) (define glyph-idx (FT_Get_Char_Index (· this ft-face) codePoint))
(report glyph-idx 'glyphs-for-codepoint-idx)
(send this getGlyph glyph-idx (list codePoint))) (send this getGlyph glyph-idx (list codePoint)))

@ -352,6 +352,11 @@
(define-freetype FT_Get_Sfnt_Table (_fun _FT_Face _FT_Gettable_Sfnt_Tag (define-freetype FT_Get_Sfnt_Table (_fun _FT_Face _FT_Gettable_Sfnt_Tag
-> (p : (_cpointer/null 'table-ptr)) -> (p : (_cpointer/null 'table-ptr))
-> (or p (error 'sfnt-table-not-loaded)))) -> (or p (error 'sfnt-table-not-loaded))))
(define-freetype FT_Select_Charmap (_fun _FT_Face _FT_Encoding
-> (err : _FT_Error)
-> (and (zero? err) #t)))
(provide tag->int) (provide tag->int)
(define (tag->int tag) (define (tag->int tag)
(define signed? #f) (define signed? #f)
@ -361,7 +366,7 @@
(module+ test (module+ test
(require rackunit) (require rackunit)
(define ft-library (FT_Init_FreeType)) (define ft-library (FT_Init_FreeType))
(define face (FT_New_Face ft-library "test/assets/charter.ttf" 0)) (define face (FT_New_Face ft-library "../pitfall/test/assets/charter.ttf" 0))
(check-equal? (FT_Get_Postscript_Name face) "Charter") (check-equal? (FT_Get_Postscript_Name face) "Charter")
(check-equal? (FT_FaceRec-units_per_EM face) 1000) (check-equal? (FT_FaceRec-units_per_EM face) 1000)
(check-true (FT_Load_Sfnt_Table face (tag->int #"cmap") 0 0 0)) (check-true (FT_Load_Sfnt_Table face (tag->int #"cmap") 0 0 0))

@ -2,6 +2,11 @@
(require "script.rkt" "glyph.rkt" "glyphrun.rkt" "glyph-position.rkt") (require "script.rkt" "glyph.rkt" "glyphrun.rkt" "glyph-position.rkt")
(provide LayoutEngine) (provide LayoutEngine)
#|
approximates
https://github.com/mbutterick/fontkit/blob/master/src/layout/LayoutEngine.js
|#
(define-subclass object% (LayoutEngine font) (define-subclass object% (LayoutEngine font)
(field [unicodeLayoutEngine #f] (field [unicodeLayoutEngine #f]
[kernProcessor #f] [kernProcessor #f]
@ -13,7 +18,7 @@
(cond (cond
[(· this font has-morx-table?) (error 'morx-layout-unimplemented)] [(· this font has-morx-table?) (error 'morx-layout-unimplemented)]
[(or (· this font has-gsub-table?) (· this font has-gpos-table?)) [(or (· this font has-gsub-table?) (· this font has-gpos-table?))
(error 'ot-layout-unimplemented)] (displayln 'warning:ot-layout-unimplemented) #f]
[else #f])]) [else #f])])
(as-methods (as-methods

@ -25,6 +25,7 @@ https://github.com/devongovett/fontkit/blob/master/src/subset/Subset.js
(define/contract (includeGlyph this glyph) (define/contract (includeGlyph this glyph)
((or/c object? index?) . ->m . index?) ((or/c object? index?) . ->m . index?)
(let ([glyph (if (object? glyph) (· glyph id) glyph)]) (let ([glyph (if (object? glyph) (· glyph id) glyph)])
(report* glyph (· this mapping))
(hash-ref! (· this mapping) glyph (hash-ref! (· this mapping) glyph
(λ () (λ ()
;; put the new glyph at the end of `glyphs`, ;; put the new glyph at the end of `glyphs`,

@ -16,29 +16,31 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js
'yMax int16be))) 'yMax int16be)))
;; Flags for simple glyphs ;; Flags for simple glyphs
(match-define (list ON_CURVE (define-macro (define-flag-series . IDS)
X_SHORT_VECTOR #`(match-define (list . IDS) (map (curry expt 2) (range #,(length (syntax->list #'IDS))))))
Y_SHORT_VECTOR
REPEAT ;; Flags for simple glyphs
SAME_X (define-flag-series ON_CURVE
SAME_Y) X_SHORT_VECTOR
(map (curry expt 2) (range 6))) Y_SHORT_VECTOR
REPEAT
SAME_X
SAME_Y)
;; Flags for composite glyphs ;; Flags for composite glyphs
(match-define (list ARG_1_AND_2_ARE_WORDS (define-flag-series ARG_1_AND_2_ARE_WORDS
ARGS_ARE_XY_VALUES ARGS_ARE_XY_VALUES
ROUND_XY_TO_GRID ROUND_XY_TO_GRID
WE_HAVE_A_SCALE WE_HAVE_A_SCALE
___NO-FLAG___ __EMPTY-FLAG___
MORE_COMPONENTS MORE_COMPONENTS
WE_HAVE_AN_X_AND_Y_SCALE WE_HAVE_AN_X_AND_Y_SCALE
WE_HAVE_A_TWO_BY_TWO WE_HAVE_A_TWO_BY_TWO
WE_HAVE_INSTRUCTIONS WE_HAVE_INSTRUCTIONS
USE_MY_METRICS USE_MY_METRICS
OVERLAP_COMPOUND OVERLAP_COMPOUND
SCALED_COMPONENT_OFFSET SCALED_COMPONENT_OFFSET
UNSCALED_COMPONENT_OFFSET) UNSCALED_COMPONENT_OFFSET)
(map (curry expt 2) (range 13)))
;; Represents a point in a simple glyph ;; Represents a point in a simple glyph
(define-subclass object% (Point onCurve endContour [x 0] [y 0]) (define-subclass object% (Point onCurve endContour [x 0] [y 0])
@ -52,8 +54,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js
[scaleX 1] [scaleX 1]
[scaleY 1] [scaleY 1]
[scale01 0] [scale01 0]
[scale10 0]) [scale10 0]))
)
;; Represents a TrueType glyph. ;; Represents a TrueType glyph.
(define-subclass Glyph (TTFGlyph) (define-subclass Glyph (TTFGlyph)
@ -65,6 +66,12 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js
;; Parses a single glyph coordinate ;; Parses a single glyph coordinate
(define/public (_parseGlyphCoord stream prev short same) (define/public (_parseGlyphCoord stream prev short same)
(unless (DecodeStream? stream)
(raise-argument-error '_parseGlyphCoord "DecodeStream" stream))
(unless (number? prev)
(raise-argument-error '_parseGlyphCoord "number" prev))
(unless (and (boolean? short) (boolean? same))
(raise-argument-error '_parseGlyphCoord "booleans" (list short same)))
(+ prev (if short (+ prev (if short
((if (not same) - +) (send uint8 decode stream)) ((if (not same) - +) (send uint8 decode stream))
(if same 0 (send int16be decode stream))))) (if same 0 (send int16be decode stream)))))
@ -73,28 +80,20 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js
;; 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/public (_decode)
(define offsets (hash-ref (send _font _getTable 'loca) 'offsets)) (define offsets (· (send _font _getTable 'loca) offsets))
(define glyfPos (list-ref offsets id)) (match-define (list glyfPos nextPos) (take (drop offsets id) 2))
(define nextPos (list-ref offsets (add1 id)))
;; Nothing to do if there is no data for this glyph ;; Nothing to do if there is no data for this glyph
(cond (and (not (= glyfPos nextPos))
[(= glyfPos nextPos) #f] (let ()
[else (define stream (send _font _getTableStream 'glyf))
(define stream (send _font _getTableStream 'glyf)) (send stream pos (+ (send stream pos) glyfPos))
(send stream pos (+ (send stream pos) glyfPos)) (define startPos (· stream pos))
(define startPos (· stream pos)) (define glyph (send GlyfHeader decode stream))
(match (· glyph numberOfContours)
(define glyph (send GlyfHeader decode stream)) [(? positive?) (_decodeSimple glyph stream)]
[(? negative?) (_decodeComposite glyph stream startPos)])
(let ([contour-count (· glyph numberOfContours)]) glyph)))
(cond
[(positive? contour-count)
(_decodeSimple glyph stream)]
[(negative? contour-count)
(_decodeComposite glyph stream startPos)]))
glyph]))
(define/public (_decodeSimple glyph stream) (define/public (_decodeSimple glyph stream)
(unless (hash? glyph) (unless (hash? glyph)
@ -105,49 +104,31 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js
;; this is a simple glyph ;; this is a simple glyph
(hash-set! glyph 'points empty) (hash-set! glyph 'points empty)
(define endPtsOfContours (send (+Array uint16be (· glyph numberOfContours)) decode stream)) (define endPtsOfContours (send (+Array uint16be (· glyph numberOfContours)) decode stream))
(hash-set! glyph 'instructions (send (+Array uint8be uint16be) decode stream)) (hash-set! glyph 'instructions (send (+Array uint8be uint16be) decode stream))
(define numCoords (add1 (last endPtsOfContours)))
(define numCoords (add1 (list-ref endPtsOfContours (sub1 (length endPtsOfContours)))))
(define flags (define flags
(reverse (for*/lists (flags)
(for/fold ([flags empty]) ([i (in-naturals)]
([i (in-naturals)] #:break (= (length flags) numCoords)
#:break (= (length flags) numCoords)) [flag (in-value (send uint8 decode stream))]
(define flag (send uint8 decode stream)) [count (in-range (add1 (if (not (zero? (bitwise-and flag REPEAT)))
(send uint8 decode stream)
;; check for repeat flag 0)))])
(define repeated-flags flag))
(cond
[(not (zero? (bitwise-and flag REPEAT))) (match-define-values
(define count (send uint8 decode stream)) (points _ _)
(make-list count flag)] (for/fold ([points empty] [px 0] [py 0])
[else empty])) ([(flag i) (in-indexed flags)])
(define point (+Point (zero? (bitwise-and flag ON_CURVE)) (and (index-of endPtsOfContours i) #t) 0 0))
(append repeated-flags (cons flag flags))))) (define next-px (_parseGlyphCoord stream px (not (zero? (bitwise-and flag X_SHORT_VECTOR))) (not (zero? (bitwise-and flag SAME_X)))))
(define next-py (_parseGlyphCoord stream py (not (zero? (bitwise-and flag Y_SHORT_VECTOR))) (not (zero? (bitwise-and flag SAME_Y)))))
(define glyph-points (mhash)) (set-field! x point next-px)
(for ([(flag i) (in-indexed flags)]) (set-field! y point next-py)
(define point (+Point (zero? (bitwise-and flag ON_CURVE)) (and (index-of endPtsOfContours i) #t) 0 0)) (values (cons point points) next-px next-py)))
(hash-set! glyph-points i point)) (hash-set! glyph 'points (reverse points)))
(for/fold ([px 0])
([(flag i) (in-indexed flags)])
(define next-px (_parseGlyphCoord stream px (bitwise-and flag X_SHORT_VECTOR) (bitwise-and flag SAME_X)))
(set-field! x (hash-ref glyph-points i) next-px)
next-px)
(for/fold ([py 0])
([(flag i) (in-indexed flags)])
(define next-py (_parseGlyphCoord stream py (bitwise-and flag Y_SHORT_VECTOR) (bitwise-and flag SAME_Y)))
(set-field! y (hash-ref glyph-points i) next-py)
next-py)
;; skip variations shit
)
(define/public (_decodeComposite glyph stream [offset 0]) (define/public (_decodeComposite glyph stream [offset 0])
;; this is a composite glyph ;; this is a composite glyph
@ -185,11 +166,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js
(set-field! scale01 component (read-fixed14 stream)) (set-field! scale01 component (read-fixed14 stream))
(set-field! scale10 component (read-fixed14 stream)) (set-field! scale10 component (read-fixed14 stream))
(set-field! scaleY component (read-fixed14 stream))]) (set-field! scaleY component (read-fixed14 stream))])
component)) component))
haveInstructions))
haveInstructions
))
(define (bytes->fixed14 b1 b2) (define (bytes->fixed14 b1 b2)

@ -12,7 +12,7 @@
pitfall/test/test09 pitfall/test/test09
pitfall/test/test10 pitfall/test/test10
pitfall/test/test11 pitfall/test/test11
pitfall/test/test12 pitfall/test/test12 ; ttf subset
pitfall/test/test13 pitfall/test/test13 ; subset with composites
pitfall/page-test pitfall/page-test
(submod pitfall/zlib test))) (submod pitfall/zlib test)))

@ -45,8 +45,10 @@ For now, we'll just measure width of the characters.
(define/contract (encode this text [features #f]) (define/contract (encode this text [features #f])
((string?) ((or/c list? #f)) . ->*m . ((string?) ((or/c list? #f)) . ->*m .
(list/c (listof string?) (listof (is-a?/c GlyphPosition)))) (list/c (listof string?) (listof (is-a?/c GlyphPosition))))
(define glyphRun (send (· this font) layout text features)) (define glyphRun (send (· this font) layout (report text) features))
(define glyphs (· glyphRun glyphs)) (define glyphs (· glyphRun glyphs))
(for ([g (in-list glyphs)])
(report (· g id)))
(define positions (· glyphRun positions)) (define positions (· glyphRun positions))
(define-values (subset-idxs new-positions) (define-values (subset-idxs new-positions)
(for/lists (idxs posns) (for/lists (idxs posns)
@ -74,7 +76,6 @@ For now, we'll just measure width of the characters.
(when isCFF (when isCFF
(hash-set! (· fontFile payload) 'Subtype "CIDFontType0C")) (hash-set! (· fontFile payload) 'Subtype "CIDFontType0C"))
#;(send (send (· this subset) encodeStream) pipe fontFile)
(send fontFile end (send (send (· this subset) encodeStream) dump)) (send fontFile end (send (send (· this subset) encodeStream) dump))
(define familyClass (let ([val (if (send (· this font) has-table? 'OS/2) (define familyClass (let ([val (if (send (· this font) has-table? 'OS/2)

@ -0,0 +1,27 @@
#lang pitfall/pdftest
(define-runtime-path ttf-path "assets/Tahoma.ttf")
(define (proc doc)
;; Register a font name for use later
(send doc registerFont "the-font" (path->string ttf-path))
;; Set the font, draw some text
(send* doc
[font "the-font"]
[fontSize 25]
[text "H" 100 100 (hash 'width #f)]))
;; test against non-subsetted font version
(define-runtime-path this "test14rkt.pdf")
(make-doc this #f proc #:test #f)
#;(define-runtime-path that "test14crkt.pdf")
#;(make-doc that #t proc #:test #f)
#;(module+ test
(define doc (make-object PDFDocument))
(send doc registerFont "Charter" (path->string charter-path))
(send* doc [font "Charter"])
(send doc pipe (open-output-string))
(send doc end))
Loading…
Cancel
Save