├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── ci └── ldd-grep ├── fontconfig-sys ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs └── src │ └── lib.rs └── fontconfig ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs └── src └── lib.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | tags: ["v[0-9]+.[0-9]+.[0-9]+", "yeslogic-fontconfig-sys-[0-9]+.[0-9]+.[0-9]+"] 7 | pull_request: 8 | branches: ["master"] 9 | workflow_dispatch: 10 | 11 | jobs: 12 | ci: 13 | strategy: 14 | matrix: 15 | rust: [stable, 1.77.0] 16 | os: [ubuntu-latest] 17 | runs-on: ${{ matrix.os }} 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: dtolnay/rust-toolchain@v1 21 | with: 22 | toolchain: ${{ matrix.rust }} 23 | - run: sudo apt-get -y install libfontconfig1-dev jq 24 | - run: cargo test 25 | - run: | 26 | if [ "${{matrix.rust}}" = "stable" ]; then 27 | ./ci/ldd-grep 28 | else 29 | true 30 | fi 31 | - run: cargo test --features dlopen --manifest-path fontconfig/Cargo.toml 32 | - run: | 33 | if [ "${{matrix.rust}}" = "stable" ]; then 34 | ./ci/ldd-grep -v -- --features dlopen 35 | else 36 | true 37 | fi 38 | - run: RUST_FONTCONFIG_DLOPEN=on cargo test 39 | - run: | 40 | if [ "${{matrix.rust}}" = "stable" ]; then 41 | RUST_FONTCONFIG_DLOPEN=on ./ci/ldd-grep -v 42 | else 43 | true 44 | fi 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | *.swp 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "fontconfig-sys", 5 | "fontconfig" 6 | ] 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2019 YesLogic Pty. Ltd. 4 | Copyright 2016 Manuel Reinhardt 5 | Copyright 2014 Austin Bonander 6 | Copyright 2013 The Servo Project Developers. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fontconfig 2 | ========== 3 | 4 |
5 | 6 | Build Status 7 | 8 | Documentation 9 | 10 | Version 11 | 12 | License 13 |
14 | 15 |
16 | 17 | A wrapper around [freedesktop.org's Fontconfig library][homepage], for locating fonts on UNIX-like systems such as Linux and BSD. Requires Fontconfig to be installed. 18 | 19 | Dependencies 20 | ------------ 21 | 22 | This crate is a wrapper around the Fontconfig C-library, thus it must be installed. If your OS has separate `dev`/`devel` packages, then you will need to install the that version of the package. Below is the package name for a few operating systems. If your system is not listed, a search of your package repository for `fontconfig` should find what you need. 23 | 24 | * Alpine Linux: `fontconfig-dev` 25 | * Arch Linux: `fontconfig` 26 | * Debian-based systems: `libfontconfig1-dev` 27 | * FreeBSD: `fontconfig` 28 | * Nix: `fontconfig`, `pkg-config` (tested on nixos-unstable) 29 | * Void Linux: `fontconfig-devel` 30 | 31 | Usage 32 | ----- 33 | 34 | `main.rs`: 35 | 36 | ```rust 37 | use fontconfig::Fontconfig; 38 | 39 | fn main() { 40 | let fc = Fontconfig::new().unwrap(); 41 | // `Fontconfig::find()` returns `Option` (will rarely be `None` but still could be) 42 | let font = fc.find("freeserif", None).unwrap(); 43 | // `name` is a `String`, `path` is a `Path` 44 | println!("Name: {}\nPath: {}", font.name, font.path.display()); 45 | } 46 | ``` 47 | 48 | You could then, for example, use `font.path` to create a `GlyphCache` from [`opengl_graphics`][gl] and pass it to [`conrod`][conrod]. 49 | 50 | ### Cargo Features 51 | 52 | | Feature | Description | Default Enabled | Extra Dependencies | 53 | |---------------|-----------------------------------|:---------------:|-----------------------| 54 | | `dlopen` | [dlopen] libfontconfig at runtime | ❌ | | 55 | 56 | The `dlopen` feature enables building this crate without dynamically linking to the Fontconfig C library at link time. Instead, Fontconfig will be dynamically loaded at runtime with the [dlopen] function. This can be useful in cross-compiling situations as you don't need to have a version of Fontcofig available for the target platform available at compile time. 57 | 58 | Other Fontconfig Crates 59 | ----------------------- 60 | 61 | * [servo-fontconfig] — This crate provides a low-level interface only. It 62 | depends on [servo-fontconfig-sys], which will fall back to building a 63 | vendored version of Fontconfig if a compatible version can't be found. It 64 | in-turn depends on [expat-sys], which does the same thing regarding a vendored 65 | version of Expat. This makes it easier if you are distributing a code base 66 | that needs Fontconfig, but provides less control over the libraries that will 67 | be used. 68 | * [fontconfig-sys] — superseded by [yeslogic-fontconfig-sys]. 69 | * [yeslogic-fontconfig] — This crate was previously published under this name before we were given access to publish it as [fontconfig]. 70 | 71 | For our needs in [Prince] we wanted higher-level bindings that did not fall back on vendored versions of libraries, which is what the crates in this repo provide. 72 | 73 | Credits 74 | ------- 75 | 76 | Thanks to [Austin Bonander][abonander] for originally creating the 77 | `fontconfig` crate and [allowing us to publish ours under that 78 | name](https://github.com/abonander/fontconfig-rs/issues/9). 79 | 80 | [conrod]: https://github.com/PistonDevelopers/conrod 81 | [expat-sys]: https://crates.io/crates/expat-sys 82 | [fontconfig-sys]: https://crates.io/crates/fontconfig-sys 83 | [fontconfig]: https://crates.io/crates/fontconfig 84 | [gl]: https://github.com/PistonDevelopers/opengl_graphics 85 | [homepage]: https://www.freedesktop.org/wiki/Software/fontconfig/ 86 | [Prince]: https://www.princexml.com/ 87 | [servo-fontconfig-sys]: https://crates.io/crates/servo-fontconfig-sys 88 | [servo-fontconfig]: https://crates.io/crates/servo-fontconfig 89 | [yeslogic-fontconfig]: https://crates.io/crates/yeslogic-fontconfig 90 | [yeslogic-fontconfig-sys]: https://crates.io/crates/yeslogic-fontconfig-sys 91 | [abonander]: https://github.com/abonander 92 | [dlopen]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html 93 | [dlib]: https://crates.io/crates/dlib 94 | -------------------------------------------------------------------------------- /ci/ldd-grep: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | INVERT_MATCH="" 6 | while getopts "v" opt; do 7 | case "$opt" in 8 | v) INVERT_MATCH=1;; 9 | *) ;; 10 | esac 11 | done 12 | 13 | shift $((OPTIND - 1)) 14 | 15 | EXE=$(cargo test --no-run --message-format=json "$@" | \ 16 | jq --raw-output 'select(.reason == "compiler-artifact" and .target.name == "fontconfig" and .target.test and .executable != null) | .executable') 17 | 18 | 19 | FOUND="" 20 | if ldd "$EXE" | grep --quiet libfontconfig ; then 21 | FOUND=1 22 | fi 23 | 24 | if [ -z $INVERT_MATCH ]; then 25 | if [ -z $FOUND ]; then 26 | echo "fail - libfontconfig not found when expected" 27 | exit 1 28 | else 29 | echo "ok - libfontconfig found" 30 | fi 31 | else 32 | if [ -z $FOUND ]; then 33 | echo "ok - libfontconfig not found" 34 | else 35 | echo "fail - libfontconfig found when not expected" 36 | exit 1 37 | fi 38 | fi 39 | -------------------------------------------------------------------------------- /fontconfig-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yeslogic-fontconfig-sys" 3 | version = "6.0.0" 4 | edition = "2021" 5 | rust-version = "1.77" 6 | authors = [ 7 | "Austin Bonander ", 8 | "The Servo Project Developers", 9 | "YesLogic Pty. Ltd. " 10 | ] 11 | license = "MIT" 12 | 13 | description = "Raw bindings to Fontconfig without a vendored C library" 14 | keywords = ["font", "bindings", "fontconfig", "sys"] 15 | categories = ["text-processing"] 16 | 17 | homepage = "https://github.com/yeslogic/fontconfig-rs" 18 | documentation = "https://docs.rs/crate/yeslogic-fontconfig-sys" 19 | repository = "https://github.com/yeslogic/fontconfig-rs" 20 | 21 | links = "fontconfig" 22 | 23 | [lib] 24 | name = "fontconfig_sys" 25 | 26 | [dependencies] 27 | dlib = "0.5.0" 28 | # This can't be optional because build.rs can't conditionally enable an 29 | # optional dependency: 30 | # 31 | # > Note that this does not affect Cargo's dependency resolution. This cannot 32 | # > be used to enable an optional dependency, or enable other Cargo features. 33 | # 34 | # - https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-cfg 35 | once_cell = "1.9.0" 36 | 37 | [features] 38 | dlopen = [] 39 | 40 | [build-dependencies] 41 | pkg-config = "0.3" 42 | -------------------------------------------------------------------------------- /fontconfig-sys/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /fontconfig-sys/README.md: -------------------------------------------------------------------------------- 1 | fontconfig-sys 2 | ============== 3 | 4 | Raw bindings to [freedesktop.org's Fontconfig library][fontconfig]. Used by the [fontconfig][fontconfig-rs] crate. 5 | 6 | [fontconfig]: https://www.freedesktop.org/wiki/Software/fontconfig/ 7 | [fontconfig-rs]: https://crates.io/crates/fontconfig 8 | -------------------------------------------------------------------------------- /fontconfig-sys/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rerun-if-env-changed=RUST_FONTCONFIG_DLOPEN"); 3 | let dlopen = std::env::var_os("RUST_FONTCONFIG_DLOPEN").is_some(); 4 | if dlopen { 5 | println!("cargo:rustc-cfg=feature=\"dlopen\""); 6 | } 7 | if !(dlopen || cfg!(feature = "dlopen")) { 8 | pkg_config::find_library("fontconfig").unwrap(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /fontconfig-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Servo Project Developers. See the LICENSE 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the the MIT license. This file may not be 5 | // copied, modified, or distributed except according to those terms. 6 | 7 | #![allow(non_upper_case_globals)] 8 | #![allow(non_camel_case_types)] 9 | #![allow(non_snake_case)] 10 | 11 | use std::os::raw::{c_char, c_double, c_int, c_uchar, c_uint, c_ushort, c_void}; 12 | 13 | pub use dlib::ffi_dispatch; 14 | 15 | #[cfg(feature = "dlopen")] 16 | pub mod statics { 17 | use super::Fc; 18 | use once_cell::sync::Lazy; 19 | 20 | static SONAME: &str = if cfg!(windows) { 21 | "libfontconfig.dll" 22 | } else if cfg!(target_vendor = "apple") { 23 | "libfontconfig.dylib.1" 24 | } else { 25 | "libfontconfig.so.1" 26 | }; 27 | 28 | pub static LIB_RESULT: Lazy> = 29 | Lazy::new(|| unsafe { Fc::open(SONAME) }); 30 | 31 | pub static LIB: Lazy<&'static Fc> = Lazy::new(|| LIB_RESULT.as_ref().unwrap()); 32 | } 33 | 34 | pub type FcChar8 = c_uchar; 35 | pub type FcChar16 = c_ushort; 36 | pub type FcChar32 = c_uint; 37 | pub type FcBool = c_int; 38 | 39 | pub type enum__FcType = c_uint; 40 | pub const FcTypeVoid: u32 = 0_u32; 41 | pub const FcTypeInteger: u32 = 1_u32; 42 | pub const FcTypeDouble: u32 = 2_u32; 43 | pub const FcTypeString: u32 = 3_u32; 44 | pub const FcTypeBool: u32 = 4_u32; 45 | pub const FcTypeMatrix: u32 = 5_u32; 46 | pub const FcTypeCharSet: u32 = 6_u32; 47 | pub const FcTypeFTFace: u32 = 7_u32; 48 | pub const FcTypeLangSet: u32 = 8_u32; 49 | 50 | pub type FcType = enum__FcType; 51 | 52 | pub mod constants { 53 | use std::ffi::CStr; 54 | 55 | use super::c_int; 56 | 57 | pub const FC_WEIGHT_THIN: c_int = 0; 58 | pub const FC_WEIGHT_EXTRALIGHT: c_int = 40; 59 | pub const FC_WEIGHT_ULTRALIGHT: c_int = FC_WEIGHT_EXTRALIGHT; 60 | pub const FC_WEIGHT_LIGHT: c_int = 50; 61 | pub const FC_WEIGHT_BOOK: c_int = 75; 62 | pub const FC_WEIGHT_REGULAR: c_int = 80; 63 | pub const FC_WEIGHT_NORMAL: c_int = FC_WEIGHT_REGULAR; 64 | pub const FC_WEIGHT_MEDIUM: c_int = 100; 65 | pub const FC_WEIGHT_DEMIBOLD: c_int = 180; 66 | pub const FC_WEIGHT_SEMIBOLD: c_int = FC_WEIGHT_DEMIBOLD; 67 | pub const FC_WEIGHT_BOLD: c_int = 200; 68 | pub const FC_WEIGHT_EXTRABOLD: c_int = 205; 69 | pub const FC_WEIGHT_ULTRABOLD: c_int = FC_WEIGHT_EXTRABOLD; 70 | pub const FC_WEIGHT_BLACK: c_int = 210; 71 | pub const FC_WEIGHT_HEAVY: c_int = FC_WEIGHT_BLACK; 72 | pub const FC_WEIGHT_EXTRABLACK: c_int = 215; 73 | pub const FC_WEIGHT_ULTRABLACK: c_int = FC_WEIGHT_EXTRABLACK; 74 | 75 | pub const FC_SLANT_ROMAN: c_int = 0; 76 | pub const FC_SLANT_ITALIC: c_int = 100; 77 | pub const FC_SLANT_OBLIQUE: c_int = 110; 78 | 79 | pub const FC_WIDTH_ULTRACONDENSED: c_int = 50; 80 | pub const FC_WIDTH_EXTRACONDENSED: c_int = 63; 81 | pub const FC_WIDTH_CONDENSED: c_int = 75; 82 | pub const FC_WIDTH_SEMICONDENSED: c_int = 87; 83 | pub const FC_WIDTH_NORMAL: c_int = 100; 84 | pub const FC_WIDTH_SEMIEXPANDED: c_int = 113; 85 | pub const FC_WIDTH_EXPANDED: c_int = 125; 86 | pub const FC_WIDTH_EXTRAEXPANDED: c_int = 150; 87 | pub const FC_WIDTH_ULTRAEXPANDED: c_int = 200; 88 | 89 | pub const FC_PROPORTIONAL: c_int = 0; 90 | pub const FC_DUAL: c_int = 90; 91 | pub const FC_MONO: c_int = 100; 92 | pub const FC_CHARCELL: c_int = 110; 93 | 94 | pub const FC_RGBA_UNKNOWN: c_int = 0; 95 | pub const FC_RGBA_RGB: c_int = 1; 96 | pub const FC_RGBA_BGR: c_int = 2; 97 | pub const FC_RGBA_VRGB: c_int = 3; 98 | pub const FC_RGBA_VBGR: c_int = 4; 99 | pub const FC_RGBA_NONE: c_int = 5; 100 | 101 | pub const FC_HINT_NONE: c_int = 0; 102 | pub const FC_HINT_SLIGHT: c_int = 1; 103 | pub const FC_HINT_MEDIUM: c_int = 2; 104 | pub const FC_HINT_FULL: c_int = 3; 105 | 106 | pub const FC_LCD_NONE: c_int = 0; 107 | pub const FC_LCD_DEFAULT: c_int = 1; 108 | pub const FC_LCD_LIGHT: c_int = 2; 109 | pub const FC_LCD_LEGACY: c_int = 3; 110 | 111 | pub const FC_CHARSET_MAP_SIZE: c_int = 8; 112 | pub const FC_CHARSET_DONE: u32 = u32::MAX; 113 | pub const FC_UTF8_MAX_LEN: c_int = 6; 114 | 115 | pub const FC_FAMILY: &CStr = c"family"; 116 | pub const FC_STYLE: &CStr = c"style"; 117 | pub const FC_SLANT: &CStr = c"slant"; 118 | pub const FC_WEIGHT: &CStr = c"weight"; 119 | pub const FC_SIZE: &CStr = c"size"; 120 | pub const FC_ASPECT: &CStr = c"aspect"; 121 | pub const FC_PIXEL_SIZE: &CStr = c"pixelsize"; 122 | pub const FC_SPACING: &CStr = c"spacing"; 123 | pub const FC_FOUNDRY: &CStr = c"foundry"; 124 | pub const FC_ANTIALIAS: &CStr = c"antialias"; 125 | pub const FC_HINTING: &CStr = c"hinting"; 126 | pub const FC_HINT_STYLE: &CStr = c"hintstyle"; 127 | pub const FC_VERTICAL_LAYOUT: &CStr = c"verticallayout"; 128 | pub const FC_AUTOHINT: &CStr = c"autohint"; 129 | pub const FC_GLOBAL_ADVANCE: &CStr = c"globaladvance"; 130 | pub const FC_WIDTH: &CStr = c"width"; 131 | pub const FC_FILE: &CStr = c"file"; 132 | pub const FC_INDEX: &CStr = c"index"; 133 | pub const FC_FT_FACE: &CStr = c"ftface"; 134 | pub const FC_RASTERIZER: &CStr = c"rasterizer"; 135 | pub const FC_OUTLINE: &CStr = c"outline"; 136 | pub const FC_SCALABLE: &CStr = c"scalable"; 137 | pub const FC_COLOR: &CStr = c"color"; 138 | pub const FC_VARIABLE: &CStr = c"variable"; 139 | pub const FC_SCALE: &CStr = c"scale"; 140 | pub const FC_SYMBOL: &CStr = c"symbol"; 141 | pub const FC_DPI: &CStr = c"dpi"; 142 | pub const FC_RGBA: &CStr = c"rgba"; 143 | pub const FC_MINSPACE: &CStr = c"minspace"; 144 | pub const FC_SOURCE: &CStr = c"source"; 145 | pub const FC_CHARSET: &CStr = c"charset"; 146 | pub const FC_LANG: &CStr = c"lang"; 147 | pub const FC_FONTVERSION: &CStr = c"fontversion"; 148 | pub const FC_FULLNAME: &CStr = c"fullname"; 149 | pub const FC_FAMILYLANG: &CStr = c"familylang"; 150 | pub const FC_STYLELANG: &CStr = c"stylelang"; 151 | pub const FC_FULLNAMELANG: &CStr = c"fullnamelang"; 152 | pub const FC_CAPABILITY: &CStr = c"capability"; 153 | pub const FC_FONTFORMAT: &CStr = c"fontformat"; 154 | pub const FC_EMBOLDEN: &CStr = c"embolden"; 155 | pub const FC_EMBEDDED_BITMAP: &CStr = c"embeddedbitmap"; 156 | pub const FC_DECORATIVE: &CStr = c"decorative"; 157 | pub const FC_LCD_FILTER: &CStr = c"lcdfilter"; 158 | pub const FC_FONT_FEATURES: &CStr = c"fontfeatures"; 159 | pub const FC_FONT_VARIATIONS: &CStr = c"fontvariations"; 160 | pub const FC_NAMELANG: &CStr = c"namelang"; 161 | pub const FC_PRGNAME: &CStr = c"prgname"; 162 | pub const FC_HASH: &CStr = c"hash"; 163 | pub const FC_POSTSCRIPT_NAME: &CStr = c"postscriptname"; 164 | pub const FC_FONT_HAS_HINT: &CStr = c"fonthashint"; 165 | pub const FC_CACHE_SUFFIX: &CStr = c".cache-"; 166 | pub const FC_DIR_CACHE_FILE: &CStr = c"fonts.cache-"; 167 | pub const FC_USER_CACHE_FILE: &CStr = c".fonts.cache-"; 168 | pub const FC_CHARWIDTH: &CStr = c"charwidth"; 169 | pub const FC_CHAR_WIDTH: &CStr = c"charwidth"; 170 | pub const FC_CHAR_HEIGHT: &CStr = c"charheight"; 171 | pub const FC_MATRIX: &CStr = c"matrix"; 172 | pub const FC_ORDER: &CStr = c"order"; 173 | } 174 | 175 | #[repr(C)] 176 | #[derive(Copy, Clone)] 177 | pub struct struct__FcMatrix { 178 | pub xx: c_double, 179 | pub xy: c_double, 180 | pub yx: c_double, 181 | pub yy: c_double, 182 | } 183 | 184 | pub type FcMatrix = struct__FcMatrix; 185 | 186 | pub type struct__FcCharSet = c_void; 187 | 188 | pub type FcCharSet = struct__FcCharSet; 189 | 190 | #[repr(C)] 191 | #[allow(missing_copy_implementations)] 192 | pub struct struct__FcObjectType { 193 | pub object: *mut c_char, 194 | pub _type: FcType, 195 | } 196 | 197 | pub type FcObjectType = struct__FcObjectType; 198 | 199 | #[repr(C)] 200 | #[allow(missing_copy_implementations)] 201 | pub struct struct__FcConstant { 202 | pub name: *mut FcChar8, 203 | pub object: *mut c_char, 204 | pub value: c_int, 205 | } 206 | 207 | pub type FcConstant = struct__FcConstant; 208 | 209 | pub type enum__FcResult = c_uint; 210 | pub const FcResultMatch: u32 = 0_u32; 211 | pub const FcResultNoMatch: u32 = 1_u32; 212 | pub const FcResultTypeMismatch: u32 = 2_u32; 213 | pub const FcResultNoId: u32 = 3_u32; 214 | pub const FcResultOutOfMemory: u32 = 4_u32; 215 | 216 | pub type FcResult = enum__FcResult; 217 | 218 | pub type struct__FcPattern = c_void; 219 | 220 | pub type FcPattern = struct__FcPattern; 221 | 222 | pub type struct__FcLangSet = c_void; 223 | 224 | pub type FcLangSet = struct__FcLangSet; 225 | 226 | #[repr(C)] 227 | #[allow(missing_copy_implementations)] 228 | pub struct struct__FcValue { 229 | pub _type: FcType, 230 | pub u: union_unnamed1, 231 | } 232 | 233 | pub type FcValue = struct__FcValue; 234 | 235 | #[repr(C)] 236 | #[allow(missing_copy_implementations)] 237 | pub struct struct__FcFontSet { 238 | pub nfont: c_int, 239 | pub sfont: c_int, 240 | pub fonts: *mut *mut FcPattern, 241 | } 242 | 243 | pub type FcFontSet = struct__FcFontSet; 244 | 245 | #[repr(C)] 246 | #[allow(missing_copy_implementations)] 247 | pub struct struct__FcObjectSet { 248 | pub nobject: c_int, 249 | pub sobject: c_int, 250 | pub objects: *mut *mut c_char, 251 | } 252 | 253 | pub type FcObjectSet = struct__FcObjectSet; 254 | 255 | pub type enum__FcMatchKind = c_uint; 256 | pub const FcMatchPattern: u32 = 0_u32; 257 | pub const FcMatchFont: u32 = 1_u32; 258 | pub const FcMatchScan: u32 = 2_u32; 259 | 260 | pub type FcMatchKind = enum__FcMatchKind; 261 | 262 | pub type enum__FcLangResult = c_uint; 263 | pub const FcLangEqual: u32 = 0_u32; 264 | pub const FcLangDifferentCountry: u32 = 1_u32; 265 | pub const FcLangDifferentTerritory: u32 = 1_u32; 266 | pub const FcLangDifferentLang: u32 = 2_u32; 267 | 268 | pub type FcLangResult = enum__FcLangResult; 269 | 270 | pub type enum__FcSetName = c_uint; 271 | pub const FcSetSystem: u32 = 0_u32; 272 | pub const FcSetApplication: u32 = 1_u32; 273 | 274 | pub type FcSetName = enum__FcSetName; 275 | 276 | pub type struct__FcAtomic = c_void; 277 | 278 | pub type FcAtomic = struct__FcAtomic; 279 | 280 | pub type FcEndian = c_uint; 281 | pub const FcEndianBig: u32 = 0_u32; 282 | pub const FcEndianLittle: u32 = 1_u32; 283 | 284 | pub type struct__FcConfig = c_void; 285 | 286 | pub type FcConfig = struct__FcConfig; 287 | 288 | pub type struct__FcGlobalCache = c_void; 289 | 290 | pub type FcFileCache = struct__FcGlobalCache; 291 | 292 | pub type struct__FcBlanks = c_void; 293 | 294 | pub type FcBlanks = struct__FcBlanks; 295 | 296 | pub type struct__FcStrList = c_void; 297 | 298 | pub type FcStrList = struct__FcStrList; 299 | 300 | pub type struct__FcStrSet = c_void; 301 | 302 | pub type FcStrSet = struct__FcStrSet; 303 | 304 | pub type struct__FcCache = c_void; 305 | 306 | pub type FcCache = struct__FcCache; 307 | 308 | pub type union_unnamed1 = c_void; 309 | 310 | dlib::external_library!(Fc, "fontconfig", 311 | functions: 312 | fn FcBlanksCreate() -> *mut FcBlanks, 313 | 314 | fn FcBlanksDestroy(*mut FcBlanks) -> (), 315 | 316 | fn FcBlanksAdd(*mut FcBlanks, FcChar32) -> FcBool, 317 | 318 | fn FcBlanksIsMember(*mut FcBlanks, FcChar32) -> FcBool, 319 | 320 | fn FcCacheDir(*mut FcCache) -> *const FcChar8, 321 | 322 | fn FcCacheCopySet(*const FcCache) -> *mut FcFontSet, 323 | 324 | fn FcCacheSubdir(*const FcCache, c_int) -> *const FcChar8, 325 | 326 | fn FcCacheNumSubdir(*const FcCache) -> c_int, 327 | 328 | fn FcCacheNumFont(*const FcCache) -> c_int, 329 | 330 | fn FcDirCacheUnlink(*const FcChar8, *mut FcConfig) -> FcBool, 331 | 332 | fn FcDirCacheValid(*const FcChar8) -> FcBool, 333 | 334 | fn FcConfigHome() -> *mut FcChar8, 335 | 336 | fn FcConfigEnableHome(FcBool) -> FcBool, 337 | 338 | fn FcConfigFilename(*const FcChar8) -> *mut FcChar8, 339 | 340 | fn FcConfigCreate() -> *mut FcConfig, 341 | 342 | fn FcConfigReference(*mut FcConfig) -> *mut FcConfig, 343 | 344 | fn FcConfigDestroy(*mut FcConfig) -> (), 345 | 346 | fn FcConfigSetCurrent(*mut FcConfig) -> FcBool, 347 | 348 | fn FcConfigGetCurrent() -> *mut FcConfig, 349 | 350 | fn FcConfigUptoDate(*mut FcConfig) -> FcBool, 351 | 352 | fn FcConfigBuildFonts(*mut FcConfig) -> FcBool, 353 | 354 | fn FcConfigGetFontDirs(*mut FcConfig) -> *mut FcStrList, 355 | 356 | fn FcConfigGetConfigDirs(*mut FcConfig) -> *mut FcStrList, 357 | 358 | fn FcConfigGetConfigFiles(*mut FcConfig) -> *mut FcStrList, 359 | 360 | fn FcConfigGetCache(*mut FcConfig) -> *mut FcChar8, 361 | 362 | fn FcConfigGetBlanks(*mut FcConfig) -> *mut FcBlanks, 363 | 364 | fn FcConfigGetCacheDirs(*const FcConfig) -> *mut FcStrList, 365 | 366 | fn FcConfigGetRescanInterval(*mut FcConfig) -> c_int, 367 | 368 | fn FcConfigSetRescanInterval(*mut FcConfig, c_int) -> FcBool, 369 | 370 | fn FcConfigGetFonts(*mut FcConfig, FcSetName) -> *mut FcFontSet, 371 | 372 | fn FcConfigAppFontAddFile(*mut FcConfig, *const FcChar8) -> FcBool, 373 | 374 | fn FcConfigAppFontAddDir(*mut FcConfig, *const FcChar8) -> FcBool, 375 | 376 | fn FcConfigAppFontClear(*mut FcConfig) -> (), 377 | 378 | fn FcConfigSubstituteWithPat( 379 | *mut FcConfig, 380 | *mut FcPattern, 381 | *mut FcPattern, 382 | FcMatchKind 383 | ) -> FcBool, 384 | 385 | fn FcConfigSubstitute( 386 | *mut FcConfig, 387 | *mut FcPattern, 388 | FcMatchKind 389 | ) -> FcBool, 390 | 391 | fn FcCharSetCreate() -> *mut FcCharSet, 392 | 393 | fn FcCharSetNew() -> *mut FcCharSet, 394 | 395 | fn FcCharSetDestroy(*mut FcCharSet) -> (), 396 | 397 | fn FcCharSetAddChar(*mut FcCharSet, FcChar32) -> FcBool, 398 | 399 | fn FcCharSetDelChar(*mut FcCharSet, FcChar32) -> FcBool, 400 | 401 | fn FcCharSetCopy(*mut FcCharSet) -> *mut FcCharSet, 402 | 403 | fn FcCharSetEqual(*const FcCharSet, *const FcCharSet) -> FcBool, 404 | 405 | fn FcCharSetIntersect(*const FcCharSet, *const FcCharSet) -> *mut FcCharSet, 406 | 407 | fn FcCharSetUnion(*const FcCharSet, *const FcCharSet) -> *mut FcCharSet, 408 | 409 | fn FcCharSetSubtract(*const FcCharSet, *const FcCharSet) -> *mut FcCharSet, 410 | 411 | fn FcCharSetMerge(*mut FcCharSet, *const FcCharSet, *mut FcBool) -> FcBool, 412 | 413 | fn FcCharSetHasChar(*const FcCharSet, FcChar32) -> FcBool, 414 | 415 | fn FcCharSetCount(*const FcCharSet) -> FcChar32, 416 | 417 | fn FcCharSetIntersectCount(*const FcCharSet, *const FcCharSet) -> FcChar32, 418 | 419 | fn FcCharSetSubtractCount(*const FcCharSet, *const FcCharSet) -> FcChar32, 420 | 421 | fn FcCharSetIsSubset(*const FcCharSet, *const FcCharSet) -> FcBool, 422 | 423 | fn FcCharSetFirstPage( 424 | *const FcCharSet, 425 | *mut FcChar32, 426 | *mut FcChar32 427 | ) -> FcChar32, 428 | 429 | fn FcCharSetNextPage( 430 | *const FcCharSet, 431 | *mut FcChar32, 432 | *mut FcChar32 433 | ) -> FcChar32, 434 | 435 | fn FcCharSetCoverage( 436 | *const FcCharSet, 437 | FcChar32, 438 | *mut FcChar32 439 | ) -> FcChar32, 440 | 441 | fn FcValuePrint(FcValue) -> (), 442 | 443 | fn FcPatternPrint(*const FcPattern) -> (), 444 | 445 | fn FcFontSetPrint(*mut FcFontSet) -> (), 446 | 447 | fn FcDefaultSubstitute(*mut FcPattern) -> (), 448 | 449 | fn FcFileIsDir(*const FcChar8) -> FcBool, 450 | 451 | fn FcFileScan( 452 | *mut FcFontSet, 453 | *mut FcStrSet, 454 | *mut FcFileCache, 455 | *mut FcBlanks, 456 | *const FcChar8, 457 | FcBool 458 | ) -> FcBool, 459 | 460 | fn FcDirScan( 461 | *mut FcFontSet, 462 | *mut FcStrSet, 463 | *mut FcFileCache, 464 | *mut FcBlanks, 465 | *const FcChar8, 466 | FcBool 467 | ) -> FcBool, 468 | 469 | fn FcDirSave(*mut FcFontSet, *const FcStrSet, *mut FcChar8) -> FcBool, 470 | 471 | fn FcDirCacheLoad( 472 | *const FcChar8, 473 | *mut FcConfig, 474 | *mut *mut FcChar8 475 | ) -> *mut FcCache, 476 | 477 | fn FcDirCacheRead( 478 | *const FcChar8, 479 | FcBool, 480 | *mut FcConfig 481 | ) -> *mut FcCache, 482 | 483 | // fn FcDirCacheLoadFile(*mut FcChar8, *mut struct_stat) -> *mut FcCache, 484 | 485 | fn FcDirCacheUnload(*mut FcCache) -> (), 486 | 487 | fn FcFreeTypeQuery( 488 | *const FcChar8, 489 | c_int, 490 | *mut FcBlanks, 491 | *mut c_int 492 | ) -> *mut FcPattern, 493 | 494 | fn FcFontSetCreate() -> *mut FcFontSet, 495 | 496 | fn FcFontSetDestroy(*mut FcFontSet) -> (), 497 | 498 | fn FcFontSetAdd(*mut FcFontSet, *mut FcPattern) -> FcBool, 499 | 500 | fn FcInitLoadConfig() -> *mut FcConfig, 501 | 502 | fn FcInitLoadConfigAndFonts() -> *mut FcConfig, 503 | 504 | fn FcInit() -> FcBool, 505 | 506 | fn FcFini() -> (), 507 | 508 | fn FcGetVersion() -> c_int, 509 | 510 | fn FcInitReinitialize() -> FcBool, 511 | 512 | fn FcInitBringUptoDate() -> FcBool, 513 | 514 | fn FcGetLangs() -> *mut FcStrSet, 515 | 516 | fn FcLangGetCharSet(*const FcChar8) -> *mut FcCharSet, 517 | 518 | fn FcLangSetCreate() -> *mut FcLangSet, 519 | 520 | fn FcLangSetDestroy(*mut FcLangSet) -> (), 521 | 522 | fn FcLangSetCopy(*const FcLangSet) -> *mut FcLangSet, 523 | 524 | fn FcLangSetAdd(*mut FcLangSet, *const FcChar8) -> FcBool, 525 | 526 | fn FcLangSetHasLang(*const FcLangSet, *const FcChar8) -> FcLangResult, 527 | 528 | fn FcLangSetCompare(*const FcLangSet, *const FcLangSet) -> FcLangResult, 529 | 530 | fn FcLangSetContains(*const FcLangSet, *const FcLangSet) -> FcBool, 531 | 532 | fn FcLangSetEqual(*const FcLangSet, *const FcLangSet) -> FcBool, 533 | 534 | fn FcLangSetHash(*const FcLangSet) -> FcChar32, 535 | 536 | fn FcLangSetGetLangs(*const FcLangSet) -> *mut FcStrSet, 537 | 538 | fn FcObjectSetCreate() -> *mut FcObjectSet, 539 | 540 | fn FcObjectSetAdd(*mut FcObjectSet, *const c_char) -> FcBool, 541 | 542 | fn FcObjectSetDestroy(*mut FcObjectSet) -> (), 543 | 544 | // fn FcObjectSetVaBuild(*mut c_char, *mut __va_list_tag) -> *mut FcObjectSet, 545 | 546 | fn FcFontSetList( 547 | *mut FcConfig, 548 | *mut *mut FcFontSet, 549 | c_int, 550 | *mut FcPattern, 551 | *mut FcObjectSet 552 | ) -> *mut FcFontSet, 553 | 554 | fn FcFontList( 555 | *mut FcConfig, 556 | *mut FcPattern, 557 | *mut FcObjectSet 558 | ) -> *mut FcFontSet, 559 | 560 | fn FcAtomicCreate(*const FcChar8) -> *mut FcAtomic, 561 | 562 | fn FcAtomicLock(*mut FcAtomic) -> FcBool, 563 | 564 | fn FcAtomicNewFile(*mut FcAtomic) -> *mut FcChar8, 565 | 566 | fn FcAtomicOrigFile(*mut FcAtomic) -> *mut FcChar8, 567 | 568 | fn FcAtomicReplaceOrig(*mut FcAtomic) -> FcBool, 569 | 570 | fn FcAtomicDeleteNew(*mut FcAtomic) -> (), 571 | 572 | fn FcAtomicUnlock(*mut FcAtomic) -> (), 573 | 574 | fn FcAtomicDestroy(*mut FcAtomic) -> (), 575 | 576 | fn FcFontSetMatch( 577 | *mut FcConfig, 578 | *mut *mut FcFontSet, 579 | c_int, 580 | *mut FcPattern, 581 | *mut FcResult 582 | ) -> *mut FcPattern, 583 | 584 | fn FcFontMatch( 585 | *mut FcConfig, 586 | *mut FcPattern, 587 | *mut FcResult 588 | ) -> *mut FcPattern, 589 | 590 | fn FcFontRenderPrepare( 591 | *mut FcConfig, 592 | *mut FcPattern, 593 | *mut FcPattern 594 | ) -> *mut FcPattern, 595 | 596 | fn FcFontSetSort( 597 | *mut FcConfig, 598 | *mut *mut FcFontSet, 599 | c_int, 600 | *mut FcPattern, 601 | FcBool, 602 | *mut *mut FcCharSet, 603 | *mut FcResult 604 | ) -> *mut FcFontSet, 605 | 606 | fn FcFontSort( 607 | *mut FcConfig, 608 | *mut FcPattern, 609 | FcBool, 610 | *mut *mut FcCharSet, 611 | *mut FcResult 612 | ) -> *mut FcFontSet, 613 | 614 | fn FcFontSetSortDestroy(*mut FcFontSet) -> (), 615 | 616 | fn FcMatrixCopy(*const FcMatrix) -> *mut FcMatrix, 617 | 618 | fn FcMatrixEqual(*const FcMatrix, *const FcMatrix) -> FcBool, 619 | 620 | fn FcMatrixMultiply(*mut FcMatrix, *const FcMatrix, *const FcMatrix) -> (), 621 | 622 | fn FcMatrixRotate(*mut FcMatrix, c_double, c_double) -> (), 623 | 624 | fn FcMatrixScale(*mut FcMatrix, c_double, c_double) -> (), 625 | 626 | fn FcMatrixShear(*mut FcMatrix, c_double, c_double) -> (), 627 | 628 | fn FcNameRegisterObjectTypes(*const FcObjectType, c_int) -> FcBool, 629 | 630 | fn FcNameUnregisterObjectTypes(*const FcObjectType, c_int) -> FcBool, 631 | 632 | fn FcNameGetObjectType(*const c_char) -> *const FcObjectType, 633 | 634 | fn FcNameRegisterConstants(*const FcConstant, c_int) -> FcBool, 635 | 636 | fn FcNameUnregisterConstants(*const FcConstant, c_int) -> FcBool, 637 | 638 | fn FcNameGetConstant(*mut FcChar8) -> *const FcConstant, 639 | 640 | fn FcNameConstant(*mut FcChar8, *mut c_int) -> FcBool, 641 | 642 | fn FcNameParse(*const FcChar8) -> *mut FcPattern, 643 | 644 | fn FcNameUnparse(*mut FcPattern) -> *mut FcChar8, 645 | 646 | fn FcPatternCreate() -> *mut FcPattern, 647 | 648 | fn FcPatternDuplicate(*const FcPattern) -> *mut FcPattern, 649 | 650 | fn FcPatternReference(*mut FcPattern) -> (), 651 | 652 | fn FcPatternFilter(*mut FcPattern, *const FcObjectSet) -> *mut FcPattern, 653 | 654 | fn FcValueDestroy(FcValue) -> (), 655 | 656 | fn FcValueEqual(FcValue, FcValue) -> FcBool, 657 | 658 | fn FcValueSave(FcValue) -> FcValue, 659 | 660 | fn FcPatternDestroy(*mut FcPattern) -> (), 661 | 662 | fn FcPatternEqual(*const FcPattern, *const FcPattern) -> FcBool, 663 | 664 | fn FcPatternEqualSubset( 665 | *const FcPattern, 666 | *const FcPattern, 667 | *const FcObjectSet 668 | ) -> FcBool, 669 | 670 | fn FcPatternHash(*const FcPattern) -> FcChar32, 671 | 672 | fn FcPatternAdd( 673 | *mut FcPattern, 674 | *const c_char, 675 | FcValue, 676 | FcBool 677 | ) -> FcBool, 678 | 679 | fn FcPatternAddWeak( 680 | *mut FcPattern, 681 | *const c_char, 682 | FcValue, 683 | FcBool 684 | ) -> FcBool, 685 | 686 | fn FcPatternGet( 687 | *mut FcPattern, 688 | *const c_char, 689 | c_int, 690 | *mut FcValue 691 | ) -> FcResult, 692 | 693 | fn FcPatternDel(*mut FcPattern, *const c_char) -> FcBool, 694 | 695 | fn FcPatternRemove(*mut FcPattern, *const c_char, c_int) -> FcBool, 696 | 697 | fn FcPatternAddInteger(*mut FcPattern, *const c_char, c_int) -> FcBool, 698 | 699 | fn FcPatternAddDouble(*mut FcPattern, *const c_char, c_double) -> FcBool, 700 | 701 | fn FcPatternAddString( 702 | *mut FcPattern, 703 | *const c_char, 704 | *const FcChar8 705 | ) -> FcBool, 706 | 707 | fn FcPatternAddMatrix( 708 | *mut FcPattern, 709 | *const c_char, 710 | *const FcMatrix 711 | ) -> FcBool, 712 | 713 | fn FcPatternAddCharSet( 714 | *mut FcPattern, 715 | *const c_char, 716 | *const FcCharSet 717 | ) -> FcBool, 718 | 719 | fn FcPatternAddBool(*mut FcPattern, *const c_char, FcBool) -> FcBool, 720 | 721 | fn FcPatternAddLangSet( 722 | *mut FcPattern, 723 | *const c_char, 724 | *const FcLangSet 725 | ) -> FcBool, 726 | 727 | fn FcPatternGetInteger( 728 | *mut FcPattern, 729 | *const c_char, 730 | c_int, 731 | *mut c_int 732 | ) -> FcResult, 733 | 734 | fn FcPatternGetDouble( 735 | *mut FcPattern, 736 | *const c_char, 737 | c_int, 738 | *mut c_double 739 | ) -> FcResult, 740 | 741 | fn FcPatternGetString( 742 | *mut FcPattern, 743 | *const c_char, 744 | c_int, 745 | *mut *mut FcChar8 746 | ) -> FcResult, 747 | 748 | fn FcPatternGetMatrix( 749 | *mut FcPattern, 750 | *const c_char, 751 | c_int, 752 | *mut *mut FcMatrix 753 | ) -> FcResult, 754 | 755 | fn FcPatternGetCharSet( 756 | *mut FcPattern, 757 | *const c_char, 758 | c_int, 759 | *mut *mut FcCharSet 760 | ) -> FcResult, 761 | 762 | fn FcPatternGetBool( 763 | *mut FcPattern, 764 | *const c_char, 765 | c_int, 766 | *mut FcBool 767 | ) -> FcResult, 768 | 769 | fn FcPatternGetLangSet( 770 | *mut FcPattern, 771 | *const c_char, 772 | c_int, 773 | *mut *mut FcLangSet 774 | ) -> FcResult, 775 | 776 | // The last argument is a pointer to a FreeType Face object (`FT_Face *`) 777 | // 778 | // 779 | fn FcPatternGetFTFace(*mut FcPattern, *const c_char, c_int, *mut *mut c_void) -> FcResult, 780 | 781 | // fn FcPatternVaBuild(*mut FcPattern, *mut __va_list_tag) -> *mut FcPattern, 782 | 783 | fn FcPatternFormat(*mut FcPattern, *const FcChar8) -> *mut FcChar8, 784 | 785 | fn FcStrCopy(*const FcChar8) -> *mut FcChar8, 786 | 787 | fn FcStrCopyFilename(*const FcChar8) -> *mut FcChar8, 788 | 789 | fn FcStrPlus(*const FcChar8, *const FcChar8) -> *mut FcChar8, 790 | 791 | fn FcStrFree(*mut FcChar8) -> (), 792 | 793 | fn FcStrDowncase(*const FcChar8) -> *mut FcChar8, 794 | 795 | fn FcStrCmpIgnoreCase(*const FcChar8, *const FcChar8) -> c_int, 796 | 797 | fn FcStrCmp(*const FcChar8, *const FcChar8) -> c_int, 798 | 799 | fn FcStrStrIgnoreCase(*const FcChar8, *const FcChar8) -> *mut FcChar8, 800 | 801 | fn FcStrStr(*const FcChar8, *const FcChar8) -> *mut FcChar8, 802 | 803 | fn FcUtf8ToUcs4(*mut FcChar8, *mut FcChar32, c_int) -> c_int, 804 | 805 | fn FcUtf8Len( 806 | *mut FcChar8, 807 | c_int, 808 | *mut c_int, 809 | *mut c_int 810 | ) -> FcBool, 811 | 812 | fn FcUcs4ToUtf8(FcChar32, *mut FcChar8) -> c_int, 813 | 814 | fn FcUtf16ToUcs4( 815 | *mut FcChar8, 816 | FcEndian, 817 | *mut FcChar32, 818 | c_int 819 | ) -> c_int, 820 | 821 | fn FcUtf16Len( 822 | *mut FcChar8, 823 | FcEndian, 824 | c_int, 825 | *mut c_int, 826 | *mut c_int 827 | ) -> FcBool, 828 | 829 | fn FcStrDirname(*const FcChar8) -> *mut FcChar8, 830 | 831 | fn FcStrBasename(*const FcChar8) -> *mut FcChar8, 832 | 833 | fn FcStrSetCreate() -> *mut FcStrSet, 834 | 835 | fn FcStrSetMember(*mut FcStrSet, *const FcChar8) -> FcBool, 836 | 837 | fn FcStrSetEqual(*mut FcStrSet, *mut FcStrSet) -> FcBool, 838 | 839 | fn FcStrSetAdd(*mut FcStrSet, *const FcChar8) -> FcBool, 840 | 841 | fn FcStrSetAddFilename(*mut FcStrSet, *const FcChar8) -> FcBool, 842 | 843 | fn FcStrSetDel(*mut FcStrSet, *const FcChar8) -> FcBool, 844 | 845 | fn FcStrSetDestroy(*mut FcStrSet) -> (), 846 | 847 | fn FcStrListCreate(*mut FcStrSet) -> *mut FcStrList, 848 | 849 | fn FcStrListNext(*mut FcStrList) -> *mut FcChar8, 850 | 851 | fn FcStrListDone(*mut FcStrList) -> (), 852 | 853 | fn FcConfigParseAndLoad( 854 | *mut FcConfig, 855 | *const FcChar8, 856 | FcBool 857 | ) -> FcBool, 858 | 859 | varargs: 860 | fn FcPatternBuild(*mut FcPattern) -> *mut FcPattern, 861 | fn FcObjectSetBuild(*mut c_char) -> *mut FcObjectSet, 862 | ); 863 | -------------------------------------------------------------------------------- /fontconfig/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fontconfig" 3 | version = "0.10.0" 4 | edition = "2021" 5 | rust-version = "1.77" 6 | authors = [ 7 | "Austin Bonander ", 8 | "Manuel Reinhardt ", 9 | "YesLogic Pty. Ltd. " 10 | ] 11 | license = "MIT" 12 | 13 | description = "Safe, higher-level wrapper around the Fontconfig library" 14 | keywords = ["font", "search", "wrapper", "fontconfig"] 15 | categories = ["text-processing"] 16 | 17 | homepage = "https://github.com/yeslogic/fontconfig-rs" 18 | documentation = "https://docs.rs/crate/fontconfig" 19 | repository = "https://github.com/yeslogic/fontconfig-rs" 20 | 21 | [dependencies.yeslogic-fontconfig-sys] 22 | version = "6.0.0" 23 | path = "../fontconfig-sys" 24 | 25 | [features] 26 | dlopen = [ "yeslogic-fontconfig-sys/dlopen" ] 27 | -------------------------------------------------------------------------------- /fontconfig/LICENSE: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /fontconfig/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /fontconfig/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rerun-if-env-changed=RUST_FONTCONFIG_DLOPEN"); 3 | let dlopen = std::env::var_os("RUST_FONTCONFIG_DLOPEN").is_some(); 4 | if dlopen { 5 | println!("cargo:rustc-cfg=feature=\"dlopen\""); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /fontconfig/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | 3 | //! A wrapper around [freedesktop.org's Fontconfig library][homepage], for locating fonts on a UNIX 4 | //! like systems such as Linux and FreeBSD. Requires Fontconfig to be installed. Alternatively, 5 | //! set the environment variable `RUST_FONTCONFIG_DLOPEN=on` or enable the `dlopen` Cargo feature 6 | //! to load the library at runtime rather than link at build time (useful for cross compiling). 7 | //! 8 | //! See the [Fontconfig developer reference][1] for more information. 9 | //! 10 | //! [1]: http://www.freedesktop.org/software/fontconfig/fontconfig-devel/t1.html 11 | //! [homepage]: https://www.freedesktop.org/wiki/Software/fontconfig/ 12 | //! 13 | //! Dependencies 14 | //! ============ 15 | //! 16 | //! * Arch Linux: `fontconfig` 17 | //! * Debian-based systems: `libfontconfig1-dev` 18 | //! * FreeBSD: `fontconfig` 19 | //! * Void Linux: `fontconfig-devel` 20 | //! 21 | //! Usage 22 | //! ----- 23 | //! 24 | //! ``` 25 | //! use fontconfig::Fontconfig; 26 | //! 27 | //! fn main() { 28 | //! let fc = Fontconfig::new().unwrap(); 29 | //! // `Fontconfig::find()` returns `Option` (will rarely be `None` but still could be) 30 | //! let font = fc.find("freeserif", None).unwrap(); 31 | //! // `name` is a `String`, `path` is a `Path` 32 | //! println!("Name: {}\nPath: {}", font.name, font.path.display()); 33 | //! } 34 | //! ``` 35 | //! 36 | //! ### Cargo Features 37 | //! 38 | //! | Feature | Description | Default Enabled | Extra Dependencies | 39 | //! |---------------|-----------------------------------|:---------------:|-----------------------| 40 | //! | `dlopen` | [dlopen] libfontconfig at runtime | ❌ | | 41 | //! 42 | //! The `dlopen` feature enables building this crate without dynamically linking to the Fontconfig C 43 | //! library at link time. Instead, Fontconfig will be dynamically loaded at runtime with the 44 | //! [dlopen] function. This can be useful in cross-compiling situations as you don't need to have a 45 | //! version of Fontcofig available for the target platform available at compile time. 46 | //! 47 | //! [dlopen]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html 48 | 49 | use fontconfig_sys as sys; 50 | use fontconfig_sys::ffi_dispatch; 51 | 52 | #[cfg(feature = "dlopen")] 53 | use sys::statics::{LIB, LIB_RESULT}; 54 | #[cfg(not(feature = "dlopen"))] 55 | use sys::*; 56 | 57 | use std::ffi::{c_int, CStr, CString}; 58 | use std::marker::PhantomData; 59 | use std::mem; 60 | use std::os::raw::c_char; 61 | use std::path::PathBuf; 62 | use std::ptr; 63 | use std::str::FromStr; 64 | 65 | pub use sys::constants::*; 66 | use sys::{FcBool, FcPattern}; 67 | 68 | #[allow(non_upper_case_globals)] 69 | const FcTrue: FcBool = 1; 70 | #[allow(non_upper_case_globals, dead_code)] 71 | const FcFalse: FcBool = 0; 72 | 73 | /// Handle obtained after Fontconfig has been initialised. 74 | pub struct Fontconfig { 75 | _initialised: (), 76 | } 77 | 78 | /// Error type returned from Pattern::format. 79 | /// 80 | /// The error holds the name of the unknown format. 81 | #[derive(Debug)] 82 | pub struct UnknownFontFormat(pub String); 83 | 84 | /// The format of a font matched by Fontconfig. 85 | #[derive(Eq, PartialEq)] 86 | #[allow(missing_docs)] 87 | pub enum FontFormat { 88 | TrueType, 89 | Type1, 90 | BDF, 91 | PCF, 92 | Type42, 93 | CIDType1, 94 | CFF, 95 | PFR, 96 | WindowsFNT, 97 | } 98 | 99 | impl Fontconfig { 100 | /// Initialise Fontconfig and return a handle allowing further interaction with the API. 101 | /// 102 | /// If Fontconfig fails to initialise, returns `None`. 103 | pub fn new() -> Option { 104 | #[cfg(feature = "dlopen")] 105 | if LIB_RESULT.is_err() { 106 | return None; 107 | } 108 | if unsafe { ffi_dispatch!(LIB, FcInit,) == FcTrue } { 109 | Some(Fontconfig { _initialised: () }) 110 | } else { 111 | None 112 | } 113 | } 114 | 115 | /// Find a font of the given `family` (e.g. Dejavu Sans, FreeSerif), 116 | /// optionally filtering by `style`. Both fields are case-insensitive. 117 | pub fn find(&self, family: &str, style: Option<&str>) -> Option { 118 | Font::find(self, family, style) 119 | } 120 | } 121 | 122 | /// A very high-level view of a font, only concerned with the name and its file location. 123 | /// 124 | /// ##Example 125 | /// ```rust 126 | /// use fontconfig::{Font, Fontconfig}; 127 | /// 128 | /// let fc = Fontconfig::new().unwrap(); 129 | /// let font = fc.find("sans-serif", Some("italic")).unwrap(); 130 | /// println!("Name: {}\nPath: {}", font.name, font.path.display()); 131 | /// ``` 132 | pub struct Font { 133 | /// The true name of this font 134 | pub name: String, 135 | /// The location of this font on the filesystem. 136 | pub path: PathBuf, 137 | /// The index of the font within the file. 138 | pub index: Option, 139 | } 140 | 141 | impl Font { 142 | fn find(fc: &Fontconfig, family: &str, style: Option<&str>) -> Option { 143 | let mut pat = Pattern::new(fc); 144 | let family = CString::new(family).ok()?; 145 | pat.add_string(FC_FAMILY, &family); 146 | 147 | if let Some(style) = style { 148 | let style = CString::new(style).ok()?; 149 | pat.add_string(FC_STYLE, &style); 150 | } 151 | 152 | let font_match = pat.font_match(); 153 | 154 | font_match.name().and_then(|name| { 155 | font_match.filename().map(|filename| Font { 156 | name: name.to_owned(), 157 | path: PathBuf::from(filename), 158 | index: font_match.face_index(), 159 | }) 160 | }) 161 | } 162 | 163 | #[allow(dead_code)] 164 | fn print_debug(&self) { 165 | println!( 166 | "Name: {}\nPath: {}\nIndex: {:?}", 167 | self.name, 168 | self.path.display(), 169 | self.index 170 | ); 171 | } 172 | } 173 | 174 | /// A safe wrapper around fontconfig's `FcPattern`. 175 | #[repr(C)] 176 | pub struct Pattern<'fc> { 177 | /// Raw pointer to `FcPattern` 178 | pat: *mut FcPattern, 179 | fc: &'fc Fontconfig, 180 | } 181 | 182 | impl<'fc> Pattern<'fc> { 183 | /// Create a new empty `Pattern`. 184 | pub fn new(fc: &Fontconfig) -> Pattern { 185 | let pat = unsafe { ffi_dispatch!(LIB, FcPatternCreate,) }; 186 | assert!(!pat.is_null()); 187 | 188 | Pattern { pat, fc } 189 | } 190 | 191 | /// Create a `Pattern` from a raw fontconfig FcPattern pointer. 192 | /// 193 | /// The pattern is referenced. 194 | /// 195 | /// **Safety:** The pattern pointer must be valid/non-null. 196 | pub unsafe fn from_pattern(fc: &Fontconfig, pat: *mut FcPattern) -> Pattern { 197 | ffi_dispatch!(LIB, FcPatternReference, pat); 198 | 199 | Pattern { pat, fc } 200 | } 201 | 202 | /// Add a key-value pair of type `String` to this pattern. 203 | /// 204 | /// See useful keys in the [fontconfig reference][1]. 205 | /// 206 | /// [1]: http://www.freedesktop.org/software/fontconfig/fontconfig-devel/x19.html 207 | pub fn add_string(&mut self, name: &CStr, val: &CStr) { 208 | unsafe { 209 | ffi_dispatch!( 210 | LIB, 211 | FcPatternAddString, 212 | self.pat, 213 | name.as_ptr(), 214 | val.as_ptr() as *const u8 215 | ); 216 | } 217 | } 218 | 219 | /// Add a key-value pair of type `Int` to this pattern 220 | /// 221 | /// See useful keys in the [fontconfig reference][1]. 222 | /// 223 | /// [1]: http://www.freedesktop.org/software/fontconfig/fontconfig-devel/x19.html 224 | pub fn add_integer(&mut self, name: &CStr, val: c_int) { 225 | unsafe { 226 | ffi_dispatch!(LIB, FcPatternAddInteger, self.pat, name.as_ptr(), val); 227 | } 228 | } 229 | 230 | /// Get string the value for a key from this pattern. 231 | pub fn get_string<'a>(&'a self, name: &'a CStr) -> Option<&'a str> { 232 | unsafe { 233 | let mut ret: *mut sys::FcChar8 = ptr::null_mut(); 234 | if ffi_dispatch!( 235 | LIB, 236 | FcPatternGetString, 237 | self.pat, 238 | name.as_ptr(), 239 | 0, 240 | &mut ret as *mut _ 241 | ) == sys::FcResultMatch 242 | { 243 | let cstr = CStr::from_ptr(ret as *const c_char); 244 | Some(cstr.to_str().unwrap()) 245 | } else { 246 | None 247 | } 248 | } 249 | } 250 | 251 | /// Get the integer value for a key from this pattern. 252 | pub fn get_int(&self, name: &CStr) -> Option { 253 | unsafe { 254 | let mut ret: i32 = 0; 255 | if ffi_dispatch!( 256 | LIB, 257 | FcPatternGetInteger, 258 | self.pat, 259 | name.as_ptr(), 260 | 0, 261 | &mut ret as *mut i32 262 | ) == sys::FcResultMatch 263 | { 264 | Some(ret) 265 | } else { 266 | None 267 | } 268 | } 269 | } 270 | 271 | /// Print this pattern to stdout with all its values. 272 | pub fn print(&self) { 273 | unsafe { 274 | ffi_dispatch!(LIB, FcPatternPrint, &*self.pat); 275 | } 276 | } 277 | 278 | /// Supplies default values for underspecified font patterns. 279 | /// 280 | /// * Patterns without a specified style or weight are set to Medium. 281 | /// * Patterns without a specified style or slant are set to Roman. 282 | /// * Patterns without a specified pixel size are given one computed from any specified point size 283 | /// (default 12), dpi (default 75) and scale (default 1). 284 | /// 285 | /// *Note:* [font_match][Self::font_match] and [sort_fonts][Self::sort_fonts] call this so you 286 | /// don't need to manually call it when using those methods. 287 | /// 288 | /// [Fontconfig reference](https://www.freedesktop.org/software/fontconfig/fontconfig-devel/fcdefaultsubstitute.html) 289 | pub fn default_substitute(&mut self) { 290 | unsafe { 291 | ffi_dispatch!(LIB, FcDefaultSubstitute, self.pat); 292 | } 293 | } 294 | 295 | /// Execute substitutions. 296 | /// 297 | /// *Note:* [font_match][Self::font_match] and [sort_fonts][Self::sort_fonts] call this so you 298 | /// don't need to manually call it when using those methods. 299 | /// 300 | /// [Fontconfig reference](https://www.freedesktop.org/software/fontconfig/fontconfig-devel/fcconfigsubstitute.html) 301 | pub fn config_substitute(&mut self) { 302 | unsafe { 303 | ffi_dispatch!( 304 | LIB, 305 | FcConfigSubstitute, 306 | ptr::null_mut(), 307 | self.pat, 308 | sys::FcMatchPattern 309 | ); 310 | } 311 | } 312 | 313 | /// Get the best available match for this pattern, returned as a new pattern. 314 | pub fn font_match(&mut self) -> Pattern { 315 | self.config_substitute(); 316 | self.default_substitute(); 317 | 318 | unsafe { 319 | let mut res = sys::FcResultNoMatch; 320 | Pattern::from_pattern( 321 | self.fc, 322 | ffi_dispatch!(LIB, FcFontMatch, ptr::null_mut(), self.pat, &mut res), 323 | ) 324 | } 325 | } 326 | 327 | /// Returns a [`FontSet`] containing fonts sorted by closeness to this pattern. 328 | /// 329 | /// If `trim` is true, elements in the list which don't include Unicode coverage not provided by 330 | /// earlier elements in the list are elided. 331 | /// 332 | /// See the [Fontconfig reference][1] for more details. 333 | /// 334 | /// [1]: https://www.freedesktop.org/software/fontconfig/fontconfig-devel/fcfontsort.html 335 | pub fn sort_fonts(&mut self, trim: bool) -> FontSet<'fc> { 336 | // Docs: This function should be called only after FcConfigSubstitute and FcDefaultSubstitute 337 | // have been called for p; otherwise the results will not be correct. 338 | self.config_substitute(); 339 | self.default_substitute(); 340 | 341 | // FcFontSort always returns a (possibly empty) set so we don't need to check this. 342 | let mut res = sys::FcResultNoMatch; 343 | let unicode_coverage = ptr::null_mut(); 344 | let config = ptr::null_mut(); 345 | unsafe { 346 | let raw_set = ffi_dispatch!( 347 | LIB, 348 | FcFontSort, 349 | config, 350 | self.pat, 351 | trim as FcBool, 352 | unicode_coverage, 353 | &mut res 354 | ); 355 | FontSet::from_raw(self.fc, raw_set) 356 | } 357 | } 358 | 359 | /// Get the "fullname" (human-readable name) of this pattern. 360 | pub fn name(&self) -> Option<&str> { 361 | self.get_string(FC_FULLNAME) 362 | } 363 | 364 | /// Get the "file" (path on the filesystem) of this font pattern. 365 | pub fn filename(&self) -> Option<&str> { 366 | self.get_string(FC_FILE) 367 | } 368 | 369 | /// Get the "index" (The index of the font within the file) of this pattern. 370 | pub fn face_index(&self) -> Option { 371 | self.get_int(FC_INDEX) 372 | } 373 | 374 | /// Get the "slant" (Italic, oblique or roman) of this pattern. 375 | pub fn slant(&self) -> Option { 376 | self.get_int(FC_SLANT) 377 | } 378 | 379 | /// Get the "weight" (Light, medium, demibold, bold or black) of this pattern. 380 | pub fn weight(&self) -> Option { 381 | self.get_int(FC_WEIGHT) 382 | } 383 | 384 | /// Get the "width" (Condensed, normal or expanded) of this pattern. 385 | pub fn width(&self) -> Option { 386 | self.get_int(FC_WIDTH) 387 | } 388 | 389 | /// Get the "fontformat" ("TrueType" "Type 1" "BDF" "PCF" "Type 42" "CID Type 1" "CFF" "PFR" "Windows FNT") of this pattern. 390 | pub fn format(&self) -> Result { 391 | self.get_string(FC_FONTFORMAT) 392 | .ok_or_else(|| UnknownFontFormat(String::new())) 393 | .and_then(|format| format.parse()) 394 | } 395 | 396 | /// Returns a raw pointer to underlying `FcPattern`. 397 | pub fn as_ptr(&self) -> *const FcPattern { 398 | self.pat 399 | } 400 | 401 | /// Returns an unsafe mutable pointer to the underlying `FcPattern`. 402 | pub fn as_mut_ptr(&mut self) -> *mut FcPattern { 403 | self.pat 404 | } 405 | } 406 | 407 | impl<'fc> std::fmt::Debug for Pattern<'fc> { 408 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 409 | let fcstr = unsafe { ffi_dispatch!(LIB, FcNameUnparse, self.pat) }; 410 | let fcstr = unsafe { CStr::from_ptr(fcstr as *const c_char) }; 411 | let result = write!(f, "{:?}", fcstr); 412 | unsafe { ffi_dispatch!(LIB, FcStrFree, fcstr.as_ptr() as *mut u8) }; 413 | result 414 | } 415 | } 416 | 417 | impl<'fc> Clone for Pattern<'fc> { 418 | fn clone(&self) -> Self { 419 | let clone = unsafe { ffi_dispatch!(LIB, FcPatternDuplicate, self.pat) }; 420 | Pattern { 421 | pat: clone, 422 | fc: self.fc, 423 | } 424 | } 425 | } 426 | 427 | impl<'fc> Drop for Pattern<'fc> { 428 | fn drop(&mut self) { 429 | unsafe { 430 | ffi_dispatch!(LIB, FcPatternDestroy, self.pat); 431 | } 432 | } 433 | } 434 | 435 | impl Pattern<'_> { 436 | /// Get the languages set of this pattern. 437 | pub fn lang_set(&self) -> Option> { 438 | unsafe { 439 | let mut ret: *mut sys::FcLangSet = ptr::null_mut(); 440 | if ffi_dispatch!( 441 | LIB, 442 | FcPatternGetLangSet, 443 | self.pat, 444 | FC_LANG.as_ptr(), 445 | 0, 446 | &mut ret as *mut _ 447 | ) == sys::FcResultMatch 448 | { 449 | let ss: *mut sys::FcStrSet = ffi_dispatch!(LIB, FcLangSetGetLangs, ret); 450 | let lang_strs: *mut sys::FcStrList = ffi_dispatch!(LIB, FcStrListCreate, ss); 451 | Some(StrList::from_raw(self.fc, lang_strs)) 452 | } else { 453 | None 454 | } 455 | } 456 | } 457 | } 458 | 459 | /// Wrapper around `FcStrList` 460 | /// 461 | /// The wrapper implements `Iterator` so it can be iterated directly, filtered etc. 462 | /// **Note:** Any entries in the `StrList` that are not valid UTF-8 will be skipped. 463 | /// 464 | /// ``` 465 | /// use fontconfig::{Fontconfig, Pattern}; 466 | /// 467 | /// let fc = Fontconfig::new().expect("unable to init Fontconfig"); 468 | /// 469 | /// // Find fonts that support japanese 470 | /// let fonts = fontconfig::list_fonts(&Pattern::new(&fc), None); 471 | /// let ja_fonts: Vec<_> = fonts 472 | /// .iter() 473 | /// .filter(|p| p.lang_set().map_or(false, |mut langs| langs.any(|l| l == "ja"))) 474 | /// .collect(); 475 | /// ``` 476 | pub struct StrList<'a> { 477 | list: *mut sys::FcStrList, 478 | _life: PhantomData<&'a sys::FcStrList>, 479 | } 480 | 481 | impl<'a> StrList<'a> { 482 | unsafe fn from_raw(_: &Fontconfig, raw_list: *mut sys::FcStrSet) -> Self { 483 | Self { 484 | list: raw_list, 485 | _life: PhantomData, 486 | } 487 | } 488 | } 489 | 490 | impl<'a> Drop for StrList<'a> { 491 | fn drop(&mut self) { 492 | unsafe { ffi_dispatch!(LIB, FcStrListDone, self.list) }; 493 | } 494 | } 495 | 496 | impl<'a> Iterator for StrList<'a> { 497 | type Item = &'a str; 498 | 499 | fn next(&mut self) -> Option<&'a str> { 500 | let lang_str: *mut sys::FcChar8 = unsafe { ffi_dispatch!(LIB, FcStrListNext, self.list) }; 501 | if lang_str.is_null() { 502 | None 503 | } else { 504 | match unsafe { CStr::from_ptr(lang_str as *const c_char) }.to_str() { 505 | Ok(s) => Some(s), 506 | _ => self.next(), 507 | } 508 | } 509 | } 510 | } 511 | 512 | /// Wrapper around `FcFontSet`. 513 | pub struct FontSet<'fc> { 514 | fcset: *mut sys::FcFontSet, 515 | fc: &'fc Fontconfig, 516 | } 517 | 518 | impl<'fc> FontSet<'fc> { 519 | /// Create a new, empty `FontSet`. 520 | pub fn new(fc: &Fontconfig) -> FontSet { 521 | let fcset = unsafe { ffi_dispatch!(LIB, FcFontSetCreate,) }; 522 | FontSet { fcset, fc } 523 | } 524 | 525 | /// Wrap an existing `FcFontSet`. 526 | /// 527 | /// The returned wrapper assumes ownership of the `FcFontSet`. 528 | /// 529 | /// **Safety:** The font set pointer must be valid/non-null. 530 | pub unsafe fn from_raw(fc: &Fontconfig, raw_set: *mut sys::FcFontSet) -> FontSet { 531 | FontSet { fcset: raw_set, fc } 532 | } 533 | 534 | /// Add a `Pattern` to this `FontSet`. 535 | pub fn add_pattern(&mut self, pat: Pattern) { 536 | unsafe { 537 | ffi_dispatch!(LIB, FcFontSetAdd, self.fcset, pat.pat); 538 | mem::forget(pat); 539 | } 540 | } 541 | 542 | /// Print this `FontSet` to stdout. 543 | pub fn print(&self) { 544 | unsafe { ffi_dispatch!(LIB, FcFontSetPrint, self.fcset) }; 545 | } 546 | 547 | /// Iterate the fonts (as `Patterns`) in this `FontSet`. 548 | pub fn iter(&self) -> impl Iterator> { 549 | let patterns = unsafe { 550 | let fontset = self.fcset; 551 | std::slice::from_raw_parts((*fontset).fonts, (*fontset).nfont as usize) 552 | }; 553 | patterns 554 | .iter() 555 | .map(move |&pat| unsafe { Pattern::from_pattern(self.fc, pat) }) 556 | } 557 | } 558 | 559 | impl<'fc> Drop for FontSet<'fc> { 560 | fn drop(&mut self) { 561 | unsafe { ffi_dispatch!(LIB, FcFontSetDestroy, self.fcset) } 562 | } 563 | } 564 | 565 | /// Return a `FontSet` containing Fonts that match the supplied `pattern` and `objects`. 566 | pub fn list_fonts<'fc>(pattern: &Pattern<'fc>, objects: Option<&ObjectSet>) -> FontSet<'fc> { 567 | let os = objects.map(|o| o.fcset).unwrap_or(ptr::null_mut()); 568 | unsafe { 569 | let raw_set = ffi_dispatch!(LIB, FcFontList, ptr::null_mut(), pattern.pat, os); 570 | FontSet::from_raw(pattern.fc, raw_set) 571 | } 572 | } 573 | 574 | /// Wrapper around `FcObjectSet`. 575 | pub struct ObjectSet { 576 | fcset: *mut sys::FcObjectSet, 577 | } 578 | 579 | impl ObjectSet { 580 | /// Create a new, empty `ObjectSet`. 581 | pub fn new(_: &Fontconfig) -> ObjectSet { 582 | let fcset = unsafe { ffi_dispatch!(LIB, FcObjectSetCreate,) }; 583 | assert!(!fcset.is_null()); 584 | 585 | ObjectSet { fcset } 586 | } 587 | 588 | /// Wrap an existing `FcObjectSet`. 589 | /// 590 | /// The `FcObjectSet` must not be null. This method assumes ownership of the `FcObjectSet`. 591 | /// 592 | /// **Safety:** The object set pointer must be valid/non-null. 593 | pub unsafe fn from_raw(_: &Fontconfig, raw_set: *mut sys::FcObjectSet) -> ObjectSet { 594 | ObjectSet { fcset: raw_set } 595 | } 596 | 597 | /// Add a string to the `ObjectSet`. 598 | pub fn add(&mut self, name: &CStr) { 599 | let res = unsafe { ffi_dispatch!(LIB, FcObjectSetAdd, self.fcset, name.as_ptr()) }; 600 | assert_eq!(res, FcTrue); 601 | } 602 | } 603 | 604 | impl Drop for ObjectSet { 605 | fn drop(&mut self) { 606 | unsafe { ffi_dispatch!(LIB, FcObjectSetDestroy, self.fcset) } 607 | } 608 | } 609 | 610 | impl FromStr for FontFormat { 611 | type Err = UnknownFontFormat; 612 | 613 | fn from_str(s: &str) -> Result { 614 | match s { 615 | "TrueType" => Ok(FontFormat::TrueType), 616 | "Type 1" => Ok(FontFormat::Type1), 617 | "BDF" => Ok(FontFormat::BDF), 618 | "PCF" => Ok(FontFormat::PCF), 619 | "Type 42" => Ok(FontFormat::Type42), 620 | "CID Type 1" => Ok(FontFormat::CIDType1), 621 | "CFF" => Ok(FontFormat::CFF), 622 | "PFR" => Ok(FontFormat::PFR), 623 | "Windows FNT" => Ok(FontFormat::WindowsFNT), 624 | _ => Err(UnknownFontFormat(s.to_string())), 625 | } 626 | } 627 | } 628 | 629 | #[cfg(test)] 630 | mod tests { 631 | use super::*; 632 | 633 | #[test] 634 | fn it_works() { 635 | assert!(Fontconfig::new().is_some()) 636 | } 637 | 638 | #[test] 639 | fn test_find_font() { 640 | let fc = Fontconfig::new().unwrap(); 641 | fc.find("dejavu sans", None).unwrap().print_debug(); 642 | fc.find("dejavu sans", Some("oblique")) 643 | .unwrap() 644 | .print_debug(); 645 | } 646 | 647 | #[test] 648 | fn test_iter_and_print() { 649 | let fc = Fontconfig::new().unwrap(); 650 | let fontset = list_fonts(&Pattern::new(&fc), None); 651 | for pattern in fontset.iter() { 652 | println!("{:?}", pattern.name()); 653 | } 654 | 655 | // Ensure that the set can be iterated again 656 | assert!(fontset.iter().count() > 0); 657 | } 658 | 659 | #[test] 660 | fn iter_lang_set() { 661 | let fc = Fontconfig::new().unwrap(); 662 | let mut pat = Pattern::new(&fc); 663 | let family = CString::new("dejavu sans").unwrap(); 664 | pat.add_string(FC_FAMILY, &family); 665 | let pattern = pat.font_match(); 666 | for lang in pattern.lang_set().unwrap() { 667 | println!("{:?}", lang); 668 | } 669 | 670 | // Test find 671 | assert!(pattern 672 | .lang_set() 673 | .unwrap() 674 | .find(|&lang| lang == "za") 675 | .is_some()); 676 | 677 | // Test collect 678 | let langs = pattern.lang_set().unwrap().collect::>(); 679 | assert!(langs.iter().find(|&&l| l == "ie").is_some()); 680 | } 681 | 682 | #[test] 683 | fn test_sort_fonts() { 684 | let fc = Fontconfig::new().unwrap(); 685 | let mut pat = Pattern::new(&fc); 686 | let family = CString::new("dejavu sans").unwrap(); 687 | pat.add_string(FC_FAMILY, &family); 688 | 689 | let style = CString::new("oblique").unwrap(); 690 | pat.add_string(FC_STYLE, &style); 691 | 692 | let font_set = pat.sort_fonts(false); 693 | 694 | for pattern in font_set.iter() { 695 | println!("{:?}", pattern.name()); 696 | } 697 | 698 | // Ensure that the set can be iterated again 699 | assert!(font_set.iter().count() > 0); 700 | } 701 | } 702 | --------------------------------------------------------------------------------