From 50b2193782594b90e2884fb57119353c3776c6f9 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Sun, 19 Jun 2016 12:13:52 -0700 Subject: [PATCH] add ffi measuring; continuation-based linebreaking --- quad/quad/atomize.rkt | 5 +- quad/quad/charter.ttf | Bin 0 -> 42036 bytes quad/quad/freetype-ffi.rkt | 244 ++++++++++++++++++++++++++++++++++++ quad/quad/measure-chars.rkt | 64 ++++++++++ quad/quad/measure.rkt | 13 +- quad/quad/quads.rkt | 7 +- quad/quad/sc.otf | Bin 0 -> 90056 bytes quad/quad/typeset.rkt | 24 ++-- 8 files changed, 341 insertions(+), 16 deletions(-) create mode 100644 quad/quad/charter.ttf create mode 100644 quad/quad/freetype-ffi.rkt create mode 100644 quad/quad/measure-chars.rkt create mode 100644 quad/quad/sc.otf diff --git a/quad/quad/atomize.rkt b/quad/quad/atomize.rkt index abe2dcd5..cf93a10c 100644 --- a/quad/quad/atomize.rkt +++ b/quad/quad/atomize.rkt @@ -3,7 +3,8 @@ (provide (all-defined-out)) (define (atomize x) - (flatten + (apply vector-immutable + (flatten (let loop ([x x][loop-attrs default-attrs]) (cond [(symbol? x) ($shim (make-attrs) 0 x)] @@ -14,7 +15,7 @@ [(#\space #\newline #\return) ($white loop-attrs 0 c)] [else ($black loop-attrs 0 c)])))] [else - (map (λ(xi) (loop xi ((quad-attrs x) . override-with . loop-attrs))) (quad-val x))])))) + (map (λ(xi) (loop xi ((quad-attrs x) . override-with . loop-attrs))) (quad-val x))]))))) (module+ test (require rackunit) diff --git a/quad/quad/charter.ttf b/quad/quad/charter.ttf new file mode 100644 index 0000000000000000000000000000000000000000..33c6d7cbdd3a5d94f7065d4abc2bdcda68e12a42 GIT binary patch literal 42036 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 literal 0 HcmV?d00001 diff --git a/quad/quad/freetype-ffi.rkt b/quad/quad/freetype-ffi.rkt new file mode 100644 index 00000000..1749a904 --- /dev/null +++ b/quad/quad/freetype-ffi.rkt @@ -0,0 +1,244 @@ +#lang racket/base +(require ffi/unsafe + ffi/unsafe/define + racket/draw/private/libs) + +(define-syntax-rule (define+provide id val) + (begin + (define id val) + (provide id))) + +(define-runtime-lib freetype-lib + [(unix) #f] ; todo: get unix runtime path + [(macosx) (ffi-lib "libfreetype.6.dylib")] + [(windows) (ffi-lib "libfreetype-6.dll")]) + +(define-ffi-definer define-freetype freetype-lib #:provide provide) + +;; types +(define _void-pointer (_cpointer 'void-pointer)) +(define _char _byte) +(define _char-pointer (_cpointer 'char-pointer)) +(define _uchar _ubyte) +(define _FT_Byte _ubyte) +(define _FT_Bytes _bytes) +(define _FT_Char _char) +(define _FT_Int _int) +(define _FT_UInt _uint) +(define _FT_Int16 _short) +(define _FT_UInt16 _ushort) +(define _FT_Int32 _int32) +(define _FT_UInt32 _uint32) +(define _FT_Short _short) +(define _FT_UShort _ushort) +(define _FT_Long _long) +(define _FT_ULong _ulong) +(define _FT_Bool _byte) +(define _FT_Offset _size) ;; equivalent to _size_t? +(define _FT_PtrDist _ptrdiff) ;; equivalent to _longlong? +(define _FT_String _char) +(define _FT_String-pointer (_cpointer 'FT_String-pointer)) ;; char* +(define _FT_Tag _FT_UInt32) +(define _FT_Error _int) +(define _FT_Fixed _long) +(define _FT_Pointer _void-pointer) +(define _FT_Pos _long) +(define _FT_FWord _short) +(define _FT_UFWord _ushort) +(define _FT_F26Dot16 _short) +(define _FT_F26Dot6 _long) +(define _FT_Glyph_Format _int) +(define _FT_Encoding _int) +(define _FT_Generic_Finalizer (_cpointer '_FT_Generic_Finalizer (_fun _void-pointer -> _void))) + +(define _FT_LibraryRec (_cpointer 'FT_LibraryRec)) +(define _FT_Library (_cpointer 'FT_Library)) + +(define-cstruct _FT_Bitmap_Size + ([height _FT_Short] + [width _FT_Short] + [size _FT_Pos] + [x_ppem _FT_Pos] + [y_ppem _FT_Pos])) + +(define-cstruct _FT_CharMapRec + ([face _void-pointer] ; should be FT_Face + [encoding _FT_Encoding] + [platform_id _FT_UShort] + [encoding_id _FT_UShort])) + +(define _FT_Charmap _FT_CharMapRec-pointer) +(define _FT_CharMap-pointer (_cpointer 'FT_CharMap-pointer)) + +(define-cstruct _FT_Generic + ([data _void-pointer] + [finalizer _FT_Generic_Finalizer])) + +(define-cstruct _FT_BBox + ([xMin _FT_Pos] + [yMin _FT_Pos] + [xMax _FT_Pos] + [yMax _FT_Pos])) + +(define-cstruct _FT_Glyph_Metrics + ([width _FT_Pos] + [height _FT_Pos] + [horiBearingX _FT_Pos] + [horiBearingY _FT_Pos] + [horiAdvance _FT_Pos] + [vertBearingX _FT_Pos] + [vertBearingY _FT_Pos] + [vertAdvance _FT_Pos])) + +(define-cstruct _FT_Vector + ([x _FT_Pos] + [y _FT_Pos])) + +(provide (struct-out FT_Vector) + _FT_Vector _FT_Vector-pointer) + +(define-cstruct _FT_Bitmap + ([rows _int] + [width _int] + [pitch _int] + [buffer (_cpointer 'buffer)] + [num_grays _short] + [pixel_mode _ubyte] + [palette_mode _char] + [palette _void-pointer])) + +(define-cstruct _FT_Outline + ([n_contours _short] + [n_points _short] + [points _FT_Vector-pointer] + [tags (_cpointer 'tags)] + [contours (_cpointer 'contours)] + [flags _int])) + +(define-cstruct _FT_GlyphSlotRec + ([library _FT_Library] + [face _void-pointer] + [next _void-pointer] + [reserved _uint] + [generic _FT_Generic] + [metrics _FT_Glyph_Metrics] + [linearHoriAdvance _FT_Fixed] + [linearVertAdvance _FT_Fixed] + [advance _FT_Vector] + [format _FT_Glyph_Format] + [bitmap _FT_Bitmap] + [bitmap_left _FT_Int] + [bitmap_top _FT_Int] + [outline _FT_Outline] + [num_subglyphs _FT_UInt] + [subglyphs _void-pointer] + [control_data _void-pointer] + [control_len _long] + [lsb_delta _FT_Pos] + [rsb_delta _FT_Pos] + [other _void-pointer] + [internal _void-pointer])) + +(define _FT_GlyphSlot _FT_GlyphSlotRec-pointer) + +(provide (struct-out FT_GlyphSlotRec) + _FT_GlyphSlotRec _FT_GlyphSlotRec-pointer) + +(define-cstruct _FT_Size_Metrics + ([x_ppem _FT_UShort] + [y_ppem _FT_UShort] + [x_scale _FT_Fixed] + [y_scale _FT_Fixed] + [ascender _FT_Pos] + [descender _FT_Pos] + [height _FT_Pos] + [max_advance _FT_Pos])) + +(define-cstruct _FT_SizeRec + ([face _void-pointer] + [generic _FT_Generic] + [metrics _FT_Size_Metrics] + [internal _void-pointer])) + +(define _FT_Size _FT_SizeRec-pointer) + +(define-cstruct _FT_FaceRec + ([num_faces _FT_Long] + [face_index _FT_Long] + [face_flag _FT_Long] + [style_flags _FT_Long] + [num_glyphs _FT_Long] + [family_name _string] ; probably _string is a better choice + [style_name _string] + [num_fixed_sizes _FT_Int] + [available_sizes _FT_Bitmap_Size-pointer] + [num_charmaps _FT_Int] + [charmaps _FT_CharMap-pointer] + [generic _FT_Generic] + [bbox _FT_BBox] + [units_per_EM _FT_UShort] + [ascender _FT_Short] + [descender _FT_Short] + [height _FT_Short] + [max_advance_width _FT_Short] + [max_advance_height _FT_Short] + [underline_position _FT_Short] + [underline_thickness _FT_Short] + [glyph _FT_GlyphSlot] + [size _FT_Size] + [charmap _FT_Charmap] + [driver _void-pointer] + [memory _void-pointer] + [stream _void-pointer] + [sizes_list_head _void-pointer] + [sizes_list_tail _void-pointer] + [autohint _FT_Generic] + [extensions _void-pointer] + [internal _void-pointer])) + +(define _FT_Face _FT_FaceRec-pointer) +(provide (struct-out FT_FaceRec) + _FT_FaceRec _FT_FaceRec-pointer) + +(define _full-path + (make-ctype _path + path->complete-path + values)) + +(define-freetype FT_Init_FreeType (_fun (ftl : (_ptr o _FT_Library)) + -> (err : _FT_Error) + -> (if (zero? err) ftl (error 'FT_Init_FreeType)))) + +(define-freetype FT_New_Face (_fun _FT_Library _full-path _FT_Long + (ftf : (_ptr o (_or-null _FT_Face))) + -> (err : _FT_Error) + -> (if (zero? err) ftf (error 'FT_New_Face (format "error ~a" err))))) + +(define-freetype FT_Done_Face (_fun _FT_Face + -> (err : _FT_Error) + -> (unless (zero? err) (error 'FT_Done_Face (format "error ~a" err))))) + +(define-freetype FT_Done_FreeType (_fun _FT_Library -> (err : _FT_Error) -> (if (zero? err) (void) (error 'FT_Done_FreeType)))) + +(define-freetype FT_Get_Kerning (_fun _FT_Face _FT_UInt _FT_UInt _FT_UInt + (ftv : (_ptr o _FT_Vector)) + -> (err : _FT_Error) + -> (if (zero? err) ftv (error 'FT_Get_Kerning (format "error ~a" err))))) + +(define-freetype FT_Get_Char_Index (_fun _FT_Face _FT_ULong + -> _FT_UInt)) + +(define-freetype FT_Load_Glyph (_fun _FT_Face _FT_UInt _FT_Int32 + -> (err : _FT_Error))) + +(define-freetype FT_Load_Char (_fun _FT_Face _FT_ULong _FT_Int32 + -> (err : _FT_Error))) + +(define+provide FT_KERNING_UNSCALED 2) +(define+provide FT_LOAD_DEFAULT 0) +(define+provide FT_LOAD_RENDER (expt 2 2)) +(define+provide FT_LOAD_LINEAR_DESIGN (expt 2 13)) +(define+provide FT_LOAD_NO_RECURSE (expt 2 10)) + + + diff --git a/quad/quad/measure-chars.rkt b/quad/quad/measure-chars.rkt new file mode 100644 index 00000000..c8feafeb --- /dev/null +++ b/quad/quad/measure-chars.rkt @@ -0,0 +1,64 @@ +#lang quad/dev +(require "freetype-ffi.rkt") +(provide (all-defined-out)) + +(define measure-char + (let ([measure-cache (make-hash)] + [glyph-idx-cache (make-hash)] + [glyph-width-cache (make-hash)] + [em-size-cache (make-hash)]) + (λ (font-pathstring char) + (define (do-measure) + (define ft-library (FT_Init_FreeType)) + (define ft-face (FT_New_Face ft-library font-pathstring 0)) + (define prev-glyph-idx #f) + (define sum + (let ([glyph-idx (hash-ref! glyph-idx-cache (cons char font-pathstring) + (λ () (FT_Get_Char_Index ft-face (char->integer char))))]) + (hash-ref! glyph-width-cache (cons glyph-idx font-pathstring) + (λ () + (FT_Load_Glyph ft-face glyph-idx FT_LOAD_NO_RECURSE) ; loads into FTFace's 'glyph' slot + (FT_Vector-x (FT_GlyphSlotRec-advance (FT_FaceRec-glyph ft-face))))))) + (define em-size + (hash-ref! em-size-cache font-pathstring (λ () (+ (FT_FaceRec-units_per_EM ft-face) 0.0)))) + ; will anything bad happen if I skip these? + (FT_Done_Face ft-face) + (FT_Done_FreeType ft-library) + (/ sum em-size)) ; normalize to em size + (hash-ref! measure-cache (cons font-pathstring char) do-measure)))) + +(define measure-chars + (let ([measure-cache (make-hash)] + [glyph-idx-cache (make-hash)] + [glyph-width-cache (make-hash)] + [kern-cache (make-hash)]) + (λ (font-pathstring chars) + (define (do-measure) + (define ft-library (FT_Init_FreeType)) + (define ft-face (FT_New_Face ft-library font-pathstring 0)) + (define prev-glyph-idx #f) + (define sum + (for/sum ([char (in-list chars)]) + (define glyph-idx (hash-ref! glyph-idx-cache (cons char font-pathstring) + (λ () (FT_Get_Char_Index ft-face (char->integer char))))) + (define glyph-width (hash-ref! glyph-width-cache (cons glyph-idx font-pathstring) + (λ () + (FT_Load_Glyph ft-face glyph-idx FT_LOAD_NO_RECURSE) ; loads into FTFace's 'glyph' slot + (FT_Vector-x (FT_GlyphSlotRec-advance (FT_FaceRec-glyph ft-face)))))) + (define kern (if prev-glyph-idx + (hash-ref! kern-cache (cons prev-glyph-idx (cons glyph-idx font-pathstring)) + (λ () + (FT_Vector-x (FT_Get_Kerning ft-face prev-glyph-idx glyph-idx FT_KERNING_UNSCALED)))) + 0)) + (set! prev-glyph-idx glyph-idx) + (+ glyph-width kern))) + ; will anything bad happen if I skip these? + (FT_Done_Face ft-face) + (FT_Done_FreeType ft-library) + sum) + (hash-ref! measure-cache (cons font-pathstring chars) do-measure)))) + +(module+ test + (require rackunit) + (check-equal? (measure-chars "charter.ttf" '(#\f)) 321)) + diff --git a/quad/quad/measure.rkt b/quad/quad/measure.rkt index e6e56c66..17371b3a 100644 --- a/quad/quad/measure.rkt +++ b/quad/quad/measure.rkt @@ -1,6 +1,15 @@ #lang quad/dev +(require "measure-chars.rkt") (provide (all-defined-out)) (define (measure! q) - (when (or ($black? q) ($white? q)) - (quad-posn-set! q 12))) \ No newline at end of file + (quad-posn-set! q + (cond + [(or ($black? q) ($white? q)) + (* (measure-char (quad-font q) (quad-val q)) (quad-font-size q))] + [else 0]))) + +(module+ test + (require rackunit) + (define q ($black '#hasheq((size . 12) (font . "sc.otf")) 0 #\n)) + (check-equal? (measure-char (quad-font q) (quad-val q)) .6)) diff --git a/quad/quad/quads.rkt b/quad/quad/quads.rkt index 6cfd8422..ec35ee8b 100644 --- a/quad/quad/quads.rkt +++ b/quad/quad/quads.rkt @@ -27,7 +27,7 @@ position measure (line width) |# -(define default-attrs (hasheq 'size 12 'font "Courier")) +(define default-attrs (hasheq 'size 10 'font "sc.otf")) ; Source Code Pro, 12 pt, chars are 6pt wide (define (quad attr . xs) ($quad (or attr (make-attrs)) 0 xs)) @@ -40,6 +40,11 @@ measure (line width) (define (quad-posn q) ($quad-posn q)) +(define (quad-font q) + (hash-ref (quad-attrs q) 'font)) +(define (quad-font-size q) + (hash-ref (quad-attrs q) 'size)) + (define (quad-posn-set! q val) (set-$quad-posn! q val)) diff --git a/quad/quad/sc.otf b/quad/quad/sc.otf new file mode 100644 index 0000000000000000000000000000000000000000..8f031da9dd395e323c9da55941a2e0c89b96ce7f GIT binary patch literal 90056 zcmdqK33wA#+c11)(j;xBO_wwkT9Sr+FKN1i2whSrw6t`g?2xwULer)sX-nDnf`}lX zh$8zYpe!P?3W$gxARvk$tBB%?`xJxn-S;^OX%V02d7uA(ukZT*VlrpWoOAEnnaLS5 zb8|C^l1wEMGCCM7y4vn<|zJWZJ$gzKy)L@;FLbTim4 zoc)auE(^wwF03$BeSP6QA3~lQOo$?&)NCqpUag-9*S>>KY$>B%q5m`iX6iy`kU~VCi!q}&I;EMETM{XoBa60G}q&^Za3D0}MiJXvTNE7`_ zOi415-bCl*`5zw05F-~jnsAHpB6ovd0tX#viI7&@iih}(co9DM?N5xZHV=?X#8U+2?A@$!PMStL;rfxo)nu5Ao&FTy23g=ki=_zragerK_zZ zZB%_&8;A-~mAl#;5mYW*91rbhT>TQFRxJgdI4`gP^0aEJtIZK@aICA%6J>C&t1Thv z!3D0iSEDgfVheuV)h{ER)F>x}DJO^3{akHt5*?y&wS7plkf&U2ffzytx!QiMcZbYz zwUwlAch?x;rAznOte@jZNcWwtHV^IhU2O^J)csnrwW`imR#NKF8T66*F8FQGB^Fr= z%(|R9yTe>z*QHe!T5VNUo5^7=iqIumEV^u*VAo}v?PgmIbmmyAZG~oCvbD&p%d%Os z%_Y?qlPxkr9~svJjid(~fY;%2SJ!p8l$m54WVYGMtd%-8Ix7bodVP;ltE13bS%YU0 zarzz=rgF2@Q5<0@D=QQ<1sCWGmNMi~j{ny0S{0qtvX+ zt1JTsbvX{;6Q)-db+g)ZR=8r*6s7wlVz&5=u#qdePL*+!%@|}TesTU z+6WVhGNRC0(alj;W&R&ZTi4;SkUDnJ)s{I*AIe{sYOQqW20$#)wPylo|9Cy={

B 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 literal 0 HcmV?d00001 diff --git a/quad/quad/typeset.rkt b/quad/quad/typeset.rkt index 97c39e7b..6145054b 100644 --- a/quad/quad/typeset.rkt +++ b/quad/quad/typeset.rkt @@ -2,21 +2,23 @@ (provide (all-defined-out)) (require "measure.rkt") -(define line-start-k #f) +(define last-bp-k #f) +(define line-measure 60) (define (typeset qs) - (for-each measure! qs) (for/fold ([line-pos 0]) - ([q (in-list qs)]) - (unless line-start-k - (let/cc here-k (set! line-start-k here-k))) - (define next-line-pos (+ line-pos (quad-posn q))) - (if (and (> next-line-pos 84) ($white? q)) - (begin (quad-posn-set! q 'break-line) 0) - next-line-pos)) + ([q (in-vector qs)]) + (measure! q) + (when (and ($white? q) (let/cc bp-k (set! last-bp-k bp-k) #f)) + (quad-posn-set! q 'break-line)) + (cond + [(eq? 'break-line (quad-posn q)) 0] + [else (define next-line-pos (+ line-pos (quad-posn q))) + (if (> next-line-pos line-measure) + (last-bp-k #t) + next-line-pos)])) qs) (module+ test (require "atomize.rkt") - (define qs (atomize (quad #f "Meg is an ally."))) - (typeset qs)) \ No newline at end of file + (time (typeset (atomize (quad #f "Meg is an ally."))))) \ No newline at end of file