1use std::ptr::NonNull;
3
4use fontconfig_sys as sys;
5
6use sys::ffi_dispatch;
7
8#[cfg(feature = "dlopen")]
9use sys::statics::LIB;
10#[cfg(not(feature = "dlopen"))]
11use sys::*;
12
13#[allow(deprecated)]
14use crate::Blanks;
15
16use crate::{FcTrue, OwnedPattern, Pattern};
17
18#[doc(alias = "FcFontSet")]
20#[repr(transparent)]
21pub struct FontSet<'pat> {
22 pub(crate) fcset: NonNull<sys::FcFontSet>,
23 pub(crate) _marker: ::std::marker::PhantomData<&'pat mut Pattern>,
24}
25
26impl<'pat> FontSet<'pat> {
27 #[doc(alias = "FcFontSetCreate")]
29 pub fn new() -> FontSet<'pat> {
30 let fcset = unsafe { ffi_dispatch!(LIB, FcFontSetCreate,) };
31 FontSet {
32 fcset: NonNull::new(fcset).unwrap(),
33 _marker: ::std::marker::PhantomData,
34 }
35 }
36
37 #[doc(alias = "FcFontSetAdd")]
39 pub fn push(&mut self, pat: OwnedPattern) {
40 unsafe {
41 assert_eq!(
42 ffi_dispatch!(LIB, FcFontSetAdd, self.as_mut_ptr(), pat.into_inner()),
43 FcTrue,
44 );
45 }
46 }
47
48 #[doc(alias = "FcFontSet->nfont")]
50 pub fn len(&self) -> usize {
51 unsafe { (*self.as_ptr()).nfont as _ }
52 }
53
54 pub fn is_empty(&self) -> bool {
56 self.len() == 0
57 }
58
59 #[doc(alias = "FcFontSetPrint")]
61 pub fn print(&mut self) {
62 unsafe { ffi_dispatch!(LIB, FcFontSetPrint, self.as_mut_ptr()) };
63 }
64
65 pub fn iter<'fs>(&'fs self) -> Iter<'fs, 'pat> {
67 Iter {
68 fcset: self,
69 index: 0,
70 }
71 }
72
73 pub fn iter_mut<'fs>(&'fs mut self) -> IterMut<'fs, 'pat> {
75 IterMut {
76 fcset: self,
77 index: 0,
78 }
79 }
80
81 #[doc(alias = "FcFreeTypeQuery")]
90 #[allow(deprecated)]
91 pub fn freetype_query_all(
92 &mut self,
93 _file: &std::path::Path,
94 _index: isize,
95 _blanks: Option<&mut Blanks>,
96 _count: Option<&mut usize>,
97 ) -> usize {
98 unimplemented!()
99 }
115
116 fn as_mut_ptr(&mut self) -> *mut sys::FcFontSet {
117 self.fcset.as_ptr()
118 }
119
120 fn as_ptr(&self) -> *const sys::FcFontSet {
121 self.fcset.as_ptr()
122 }
123}
124
125impl<'a> Default for FontSet<'a> {
126 fn default() -> FontSet<'a> {
127 FontSet::new()
128 }
129}
130
131impl Drop for FontSet<'_> {
132 fn drop(&mut self) {
133 unsafe { ffi_dispatch!(LIB, FcFontSetDestroy, self.as_mut_ptr()) }
134 }
135}
136
137pub struct Iter<'fs, 'pat> {
139 fcset: &'fs FontSet<'pat>,
140 index: usize,
141}
142
143impl<'fs, 'pat> Iterator for Iter<'fs, 'pat> {
144 type Item = &'pat Pattern;
145
146 fn next(&mut self) -> Option<Self::Item> {
147 let fcset = self.fcset.as_ptr();
148 let index = self.index;
149 self.index += 1;
150 if index >= unsafe { (*fcset).nfont } as usize {
151 return None;
152 }
153 let pat = unsafe {
154 let font = (*fcset).fonts.add(index);
155 if font.is_null() {
156 return None;
157 }
158 *font
159 };
160 if pat.is_null() {
161 return None;
162 }
163 Some(unsafe { &*(pat as *const sys::FcPattern as *const Pattern) })
164 }
165}
166
167pub struct IterMut<'fs, 'pat> {
169 fcset: &'fs mut FontSet<'pat>,
170 index: usize,
171}
172
173impl<'fs, 'pat> Iterator for IterMut<'fs, 'pat> {
174 type Item = &'pat mut Pattern;
175
176 fn next(&mut self) -> Option<Self::Item> {
177 let index = self.index;
178 let fcset = self.fcset.as_ptr();
179 self.index += 1;
180 if index >= unsafe { (*fcset).nfont } as usize {
181 return None;
182 }
183 let pat = unsafe {
184 let font = (*fcset).fonts.add(index);
185 if font.is_null() {
186 return None;
187 }
188 *font
189 };
190 if pat.is_null() {
191 return None;
192 }
193 Some(unsafe { &mut *(pat as *mut sys::FcPattern as *mut Pattern) })
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use crate::pattern::{properties, OwnedPattern};
201
202 #[test]
203 fn fontset_new() {
204 let fontset = FontSet::new();
205 assert_eq!(fontset.len(), 0);
206 }
207
208 #[test]
209 fn fontset_iter() {
210 let mut fontset = FontSet::new();
211 let mut pat = OwnedPattern::default();
212 pat.add(&properties::FC_FAMILY, "sans-serif".to_string());
213 fontset.push(pat);
214 assert_eq!(fontset.len(), 1);
215 let mut c = 0;
216 for pat in fontset.iter() {
217 c += 1;
218 assert_eq!(pat.get(&properties::FC_FAMILY, 0), Some("sans-serif"));
220 }
221
222 assert_eq!(c, fontset.len());
223 }
224
225 #[test]
226 fn fontset_iter_mut() {
227 let mut fontset = FontSet::new();
228 let mut pat = OwnedPattern::new();
229 pat.add(&properties::FC_FAMILY, "sans-serif".to_string());
230 fontset.push(pat);
231 assert_eq!(fontset.len(), 1);
232 let mut c = 0;
233 for pat in fontset.iter_mut() {
234 c += 1;
235 assert_eq!(pat.get(&properties::FC_DPI, 0), None);
236 assert!(pat.add(&properties::FC_DPI, 20.));
237 assert_eq!(pat.get(&properties::FC_FAMILY, 0), Some("sans-serif"));
238 assert_eq!(pat.get(&properties::FC_DPI, 0), Some(20.));
239 }
240
241 assert_eq!(c, fontset.len());
242 }
243}