diff --git a/fontland/fontland/charter.otf b/fontland/fontland/charter.otf new file mode 100644 index 00000000..d2314d35 Binary files /dev/null and b/fontland/fontland/charter.otf differ diff --git a/fontland/fontland/charter.ttf b/fontland/fontland/charter.ttf new file mode 100644 index 00000000..33c6d7cb Binary files /dev/null and b/fontland/fontland/charter.ttf differ diff --git a/fontland/fontland/fira.otf b/fontland/fontland/fira.otf new file mode 100644 index 00000000..20bc9a19 Binary files /dev/null and b/fontland/fontland/fira.otf differ diff --git a/fontland/fontland/fira.ttf b/fontland/fontland/fira.ttf new file mode 100644 index 00000000..4834eede Binary files /dev/null and b/fontland/fontland/fira.ttf differ diff --git a/fontland/fontland/freetype-ffi.rkt b/fontland/fontland/freetype-ffi.rkt index 23f62876..34f2fabb 100644 --- a/fontland/fontland/freetype-ffi.rkt +++ b/fontland/fontland/freetype-ffi.rkt @@ -202,7 +202,7 @@ (define _FT_Face _FT_FaceRec-pointer) (provide (struct-out FT_FaceRec) - _FT_FaceRec _FT_FaceRec-pointer) + _FT_FaceRec _FT_FaceRec-pointer _FT_Face) (define _FT_Sfnt_Tag _FT_ULong) @@ -376,7 +376,7 @@ (module+ test (require rackunit) (define ft-library (FT_Init_FreeType)) - (define face (FT_New_Face ft-library "../pitfall/test/assets/Charter.ttf" 0)) + (define face (FT_New_Face ft-library "charter.ttf" 0)) (check-equal? (FT_Get_Postscript_Name face) "Charter") (check-equal? (FT_FaceRec-units_per_EM face) 1000) (check-true (FT_Load_Sfnt_Table face (tag->int #"cmap") 0 0 0)) diff --git a/fontland/fontland/harfbuzz-ffi.rkt b/fontland/fontland/harfbuzz-ffi.rkt new file mode 100644 index 00000000..cfe49bf4 --- /dev/null +++ b/fontland/fontland/harfbuzz-ffi.rkt @@ -0,0 +1,124 @@ +#lang racket/base +(require ffi/unsafe + ffi/unsafe/define + racket/draw/private/libs + "harfbuzz-helper.rkt") + +(define-runtime-lib harfbuzz-lib + [(unix) (ffi-lib "libharfbuzz" '("1" ""))] + [(macosx) (ffi-lib "libharfbuzz.0.dylib")] + [(windows) (ffi-lib "libharfbuzz-0.dll")]) + +(define-ffi-definer define-harfbuzz harfbuzz-lib #:provide provide) + +;; simple example +;; https://harfbuzz.github.io/ch03s03.html + +;; types +(define _void-pointer (_cpointer 'void-pointer)) +(define _char _byte) +(define _char-pointer (_cpointer 'char-pointer)) +(define _uchar _ubyte) +(define _hb_buffer_t _pointer) +(define _single_char_array (make-array-type _char 1)) +(define-cstruct _hb_language_impl_t ([s _single_char_array])) +(define _hb_language_t _hb_language_impl_t-pointer) + +(define-harfbuzz hb_buffer_create (_fun -> _hb_buffer_t)) + +(define-harfbuzz hb_buffer_add_utf8 (_fun _hb_buffer_t _string/utf-8 _int _uint _int -> _void)) + +(define _hb_direction_t (_enum hb-direction-values)) +(define-harfbuzz hb_buffer_set_direction (_fun _hb_buffer_t _hb_direction_t -> _void)) +(define-harfbuzz hb_buffer_get_direction (_fun _hb_buffer_t -> _hb_direction_t)) + +(define _hb_script_t (_enum hb-script-values)) +(define-harfbuzz hb_buffer_set_script (_fun _hb_buffer_t _hb_script_t -> _void)) +(define-harfbuzz hb_buffer_get_script (_fun _hb_buffer_t -> _hb_script_t)) + +(define-harfbuzz hb_language_from_string (_fun _string _int -> _hb_language_t)) +(define-harfbuzz hb_buffer_set_language (_fun _hb_buffer_t _hb_language_t -> _void)) +(define-harfbuzz hb_buffer_get_language (_fun _hb_buffer_t -> _hb_language_t)) + +(require "freetype-ffi.rkt") +(define _hb_font_t _pointer) +(define _hb_destroy_func_t (_or-null _pointer)) +(define-harfbuzz hb_ft_font_create (_fun _FT_Face _hb_destroy_func_t -> _hb_font_t)) + +(define _hb_tag_t _uint32) + +(define-cstruct _hb_feature_t + ([_tag _hb_tag_t] + [value _uint32] + [start _uint] + [end _uint])) + +(define _hb_features_t (_or-null _hb_feature_t-pointer)) +(define-harfbuzz hb_shape (_fun _hb_font_t _hb_buffer_t _hb_features_t _uint -> _void)) + + +(define _hb_codepoint_t _uint32) +(define _hb_mask_t _uint32) +(define _hb_var_int_t _uint32) ; todo: union type at https://github.com/harfbuzz/harfbuzz/blob/04981ee05d83ed30c9f818106589a4de9c3e9b7f/src/hb-common.h#L96 + +(define-cstruct _hb_glyph_info_t + ([codepoint _hb_codepoint_t] + [mask _hb_mask_t] + [cluster _uint32] + [var1 _hb_var_int_t] + [var2 _hb_var_int_t])) + +(define-harfbuzz hb_buffer_get_glyph_infos (_fun _hb_buffer_t + (length : (_ptr o _uint)) + -> (res : _hb_glyph_info_t-pointer) + -> (ptr-ref res (_array/list _hb_glyph_info_t length) 0))) + +(define _hb_position_t _int32) + +(define-cstruct _hb_glyph_position_t + ([x_advance _hb_position_t] + [y_advance _hb_position_t] + [x_offset _hb_position_t] + [y_offset _hb_position_t] + [var _hb_var_int_t])) + +(define-harfbuzz hb_buffer_get_glyph_positions (_fun _hb_buffer_t + (length : (_ptr o _uint)) + -> (res : _hb_glyph_position_t-pointer) + -> (ptr-ref res (_array/list _hb_glyph_position_t length) 0))) + +(define-harfbuzz hb_buffer_destroy (_fun _hb_buffer_t -> _void)) +(define-harfbuzz hb_font_destroy (_fun _hb_font_t -> _void)) + +(module+ test + (require rackunit) + ;; Create a buffer and put your text in it. + (define buf (hb_buffer_create)) + (define text "Hello World") + (hb_buffer_add_utf8 buf text -1 0 -1) + + ;; Guess the script, language and direction of the buffer. + (hb_buffer_set_direction buf 'HB_DIRECTION_LTR) + (hb_buffer_set_script buf 'HB_SCRIPT_LATIN) + (hb_buffer_set_language buf (hb_language_from_string "en" -1)) + + ;; Create a face and a font, using FreeType for now. + (define ft-library (FT_Init_FreeType)) + (define face (FT_New_Face ft-library "fira.ttf" 0)) + (define font (hb_ft_font_create face #f)) + + ;; Shape! + (hb_shape font buf #f 0) + + ;; Get the glyph and position information. + (define glyph_infos (hb_buffer_get_glyph_infos buf)) + (map hb_glyph_info_t->list glyph_infos) + (check-equal? (map hb_glyph_info_t-codepoint glyph_infos) '(111 412 514 514 555 3 296 555 609 514 393)) + + (define glyph_positions (hb_buffer_get_glyph_positions buf)) + (map hb_glyph_position_t->list glyph_positions) ; todo: fix glyph positions + + ;; Tidy up. + (hb_buffer_destroy buf) + (hb_font_destroy font) + ) \ No newline at end of file diff --git a/fontland/fontland/harfbuzz-helper.rkt b/fontland/fontland/harfbuzz-helper.rkt new file mode 100644 index 00000000..fef903f6 --- /dev/null +++ b/fontland/fontland/harfbuzz-helper.rkt @@ -0,0 +1,163 @@ +#lang racket/base +(provide (all-defined-out)) + +(define hb-direction-values + '(HB_DIRECTION_INVALID + HB_DIRECTION_LTR + HB_DIRECTION_RTL + HB_DIRECTION_TTB + HB_DIRECTION_BTT)) + +(define hb-script-values + '(HB_SCRIPT_COMMON + HB_SCRIPT_INHERITED + HB_SCRIPT_UNKNOWN + HB_SCRIPT_ARABIC + HB_SCRIPT_ARMENIAN + HB_SCRIPT_BENGALI + HB_SCRIPT_CYRILLIC + HB_SCRIPT_DEVANAGARI + HB_SCRIPT_GEORGIAN + HB_SCRIPT_GREEK + HB_SCRIPT_GUJARATI + HB_SCRIPT_GURMUKHI + HB_SCRIPT_HANGUL + HB_SCRIPT_HAN + HB_SCRIPT_HEBREW + HB_SCRIPT_HIRAGANA + HB_SCRIPT_KANNADA + HB_SCRIPT_KATAKANA + HB_SCRIPT_LAO + HB_SCRIPT_LATIN + HB_SCRIPT_MALAYALAM + HB_SCRIPT_ORIYA + HB_SCRIPT_TAMIL + HB_SCRIPT_TELUGU + HB_SCRIPT_THAI + HB_SCRIPT_TIBETAN + HB_SCRIPT_BOPOMOFO + HB_SCRIPT_BRAILLE + HB_SCRIPT_CANADIAN_SYLLABICS + HB_SCRIPT_CHEROKEE + HB_SCRIPT_ETHIOPIC + HB_SCRIPT_KHMER + HB_SCRIPT_MONGOLIAN + HB_SCRIPT_MYANMAR + HB_SCRIPT_OGHAM + HB_SCRIPT_RUNIC + HB_SCRIPT_SINHALA + HB_SCRIPT_SYRIAC + HB_SCRIPT_THAANA + HB_SCRIPT_YI + HB_SCRIPT_DESERET + HB_SCRIPT_GOTHIC + HB_SCRIPT_OLD_ITALIC + HB_SCRIPT_BUHID + HB_SCRIPT_HANUNOO + HB_SCRIPT_TAGALOG + HB_SCRIPT_TAGBANWA + HB_SCRIPT_CYPRIOT + HB_SCRIPT_LIMBU + HB_SCRIPT_LINEAR_B + HB_SCRIPT_OSMANYA + HB_SCRIPT_SHAVIAN + HB_SCRIPT_TAI_LE + HB_SCRIPT_UGARITIC + HB_SCRIPT_BUGINESE + HB_SCRIPT_COPTIC + HB_SCRIPT_GLAGOLITIC + HB_SCRIPT_KHAROSHTHI + HB_SCRIPT_NEW_TAI_LUE + HB_SCRIPT_OLD_PERSIAN + HB_SCRIPT_SYLOTI_NAGRI + HB_SCRIPT_TIFINAGH + HB_SCRIPT_BALINESE + HB_SCRIPT_CUNEIFORM + HB_SCRIPT_NKO + HB_SCRIPT_PHAGS_PA + HB_SCRIPT_PHOENICIAN + HB_SCRIPT_CARIAN + HB_SCRIPT_CHAM + HB_SCRIPT_KAYAH_LI + HB_SCRIPT_LEPCHA + HB_SCRIPT_LYCIAN + HB_SCRIPT_LYDIAN + HB_SCRIPT_OL_CHIKI + HB_SCRIPT_REJANG + HB_SCRIPT_SAURASHTRA + HB_SCRIPT_SUNDANESE + HB_SCRIPT_VAI + HB_SCRIPT_AVESTAN + HB_SCRIPT_BAMUM + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS + HB_SCRIPT_IMPERIAL_ARAMAIC + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI + HB_SCRIPT_INSCRIPTIONAL_PARTHIAN + HB_SCRIPT_JAVANESE + HB_SCRIPT_KAITHI + HB_SCRIPT_LISU + HB_SCRIPT_MEETEI_MAYEK + HB_SCRIPT_OLD_SOUTH_ARABIAN + HB_SCRIPT_OLD_TURKIC + HB_SCRIPT_SAMARITAN + HB_SCRIPT_TAI_THAM + HB_SCRIPT_TAI_VIET + HB_SCRIPT_BATAK + HB_SCRIPT_BRAHMI + HB_SCRIPT_MANDAIC + HB_SCRIPT_CHAKMA + HB_SCRIPT_MEROITIC_CURSIVE + HB_SCRIPT_MEROITIC_HIEROGLYPHS + HB_SCRIPT_MIAO + HB_SCRIPT_SHARADA + HB_SCRIPT_SORA_SOMPENG + HB_SCRIPT_TAKRI + HB_SCRIPT_BASSA_VAH + HB_SCRIPT_CAUCASIAN_ALBANIAN + HB_SCRIPT_DUPLOYAN + HB_SCRIPT_ELBASAN + HB_SCRIPT_GRANTHA + HB_SCRIPT_KHOJKI + HB_SCRIPT_KHUDAWADI + HB_SCRIPT_LINEAR_A + HB_SCRIPT_MAHAJANI + HB_SCRIPT_MANICHAEAN + HB_SCRIPT_MENDE_KIKAKUI + HB_SCRIPT_MODI + HB_SCRIPT_MRO + HB_SCRIPT_NABATAEAN + HB_SCRIPT_OLD_NORTH_ARABIAN + HB_SCRIPT_OLD_PERMIC + HB_SCRIPT_PAHAWH_HMONG + HB_SCRIPT_PALMYRENE + HB_SCRIPT_PAU_CIN_HAU + HB_SCRIPT_PSALTER_PAHLAVI + HB_SCRIPT_SIDDHAM + HB_SCRIPT_TIRHUTA + HB_SCRIPT_WARANG_CITI + HB_SCRIPT_AHOM + HB_SCRIPT_ANATOLIAN_HIEROGLYPHS + HB_SCRIPT_HATRAN + HB_SCRIPT_MULTANI + HB_SCRIPT_OLD_HUNGARIAN + HB_SCRIPT_SIGNWRITING + HB_SCRIPT_ADLAM + HB_SCRIPT_BHAIKSUKI + HB_SCRIPT_MARCHEN + HB_SCRIPT_OSAGE + HB_SCRIPT_TANGUT + HB_SCRIPT_NEWA + HB_SCRIPT_MASARAM_GONDI + HB_SCRIPT_NUSHU + HB_SCRIPT_SOYOMBO + HB_SCRIPT_ZANABAZAR_SQUARE + HB_SCRIPT_DOGRA + HB_SCRIPT_GUNJALA_GONDI + HB_SCRIPT_HANIFI_ROHINGYA + HB_SCRIPT_MAKASAR + HB_SCRIPT_MEDEFAIDRIN + HB_SCRIPT_OLD_SOGDIAN + HB_SCRIPT_SOGDIAN + HB_SCRIPT_INVALID + _HB_SCRIPT_MAX_VALUE + _HB_SCRIPT_MAX_VALUE_SIGNED)) \ No newline at end of file