skia_safe/modules/paragraph/
font_collection.rs1use crate::{
2 interop::{self, FromStrs, VecSink},
3 prelude::*,
4 textlayout::ParagraphCache,
5 FontMgr, FontStyle, Typeface, Unichar,
6};
7use skia_bindings::{self as sb, skia_textlayout_FontCollection};
8use std::{ffi, fmt, ptr};
9
10use super::FontArguments;
11
12pub type FontCollection = RCHandle<skia_textlayout_FontCollection>;
13
14impl NativeRefCountedBase for skia_textlayout_FontCollection {
15 type Base = sb::SkRefCntBase;
16}
17
18impl fmt::Debug for FontCollection {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 f.debug_struct("FontCollection")
21 .field("font_managers_count", &self.font_managers_count())
22 .field("fallback_manager", &self.fallback_manager())
23 .field("font_fallback_enabled", &self.font_fallback_enabled())
24 .field("paragraph_cache", &self.paragraph_cache())
25 .finish()
26 }
27}
28
29impl FontCollection {
30 pub fn new() -> Self {
31 Self::from_ptr(unsafe { sb::C_FontCollection_new() }).unwrap()
32 }
33
34 pub fn font_managers_count(&self) -> usize {
35 unsafe { self.native().getFontManagersCount() }
36 }
37
38 pub fn set_asset_font_manager(&mut self, font_manager: impl Into<Option<FontMgr>>) {
39 unsafe {
40 sb::C_FontCollection_setAssetFontManager(
41 self.native_mut(),
42 font_manager.into().into_ptr_or_null(),
43 )
44 }
45 }
46
47 pub fn set_dynamic_font_manager(&mut self, font_manager: impl Into<Option<FontMgr>>) {
48 unsafe {
49 sb::C_FontCollection_setDynamicFontManager(
50 self.native_mut(),
51 font_manager.into().into_ptr_or_null(),
52 )
53 }
54 }
55
56 pub fn set_test_font_manager(&mut self, font_manager: impl Into<Option<FontMgr>>) {
57 unsafe {
58 sb::C_FontCollection_setTestFontManager(
59 self.native_mut(),
60 font_manager.into().into_ptr_or_null(),
61 )
62 }
63 }
64
65 pub fn set_default_font_manager<'a>(
66 &mut self,
67 font_manager: impl Into<Option<FontMgr>>,
68 default_family_name: impl Into<Option<&'a str>>,
69 ) {
70 let font_manager = font_manager.into();
71 unsafe {
72 match default_family_name.into() {
73 Some(name) => {
74 let name = ffi::CString::new(name).unwrap();
75 sb::C_FontCollection_setDefaultFontManager2(
76 self.native_mut(),
77 font_manager.into_ptr_or_null(),
78 name.as_ptr(),
79 )
80 }
81 None => sb::C_FontCollection_setDefaultFontManager(
82 self.native_mut(),
83 font_manager.into_ptr_or_null(),
84 ),
85 }
86 }
87 }
88
89 pub fn set_default_font_manager_and_family_names(
90 &mut self,
91 font_manager: impl Into<Option<FontMgr>>,
92 family_names: &[impl AsRef<str>],
93 ) {
94 let font_manager = font_manager.into();
95 let family_names = interop::Strings::from_strs(family_names);
96 unsafe {
97 sb::C_FontCollection_setDefaultFontManager3(
98 self.native_mut(),
99 font_manager.into_ptr_or_null(),
100 family_names.native(),
101 )
102 }
103 }
104
105 pub fn fallback_manager(&self) -> Option<FontMgr> {
106 FontMgr::from_ptr(unsafe { sb::C_FontCollection_getFallbackManager(self.native()) })
107 }
108
109 pub fn find_typefaces(
110 &mut self,
111 family_names: &[impl AsRef<str>],
112 font_style: FontStyle,
113 ) -> Vec<Typeface> {
114 self.find_typefaces_with_font_arguments(family_names, font_style, None)
115 }
116
117 pub fn find_typefaces_with_font_arguments<'fa>(
118 &mut self,
119 family_names: &[impl AsRef<str>],
120 font_style: FontStyle,
121 font_args: impl Into<Option<&'fa FontArguments>>,
122 ) -> Vec<Typeface> {
123 let family_names = interop::Strings::from_strs(family_names);
124
125 let mut typefaces: Vec<Typeface> = Vec::new();
126 let mut set_typefaces = |tfs: &mut [sb::sk_sp<sb::SkTypeface>]| {
127 typefaces = tfs
128 .iter_mut()
129 .filter_map(|sp| {
130 let ptr = sp.fPtr;
131 sp.fPtr = ptr::null_mut();
132 Typeface::from_ptr(ptr)
133 })
134 .collect()
135 };
136
137 unsafe {
138 sb::C_FontCollection_findTypefaces(
139 self.native_mut(),
140 family_names.native(),
141 font_style.into_native(),
142 font_args.into().native_ptr_or_null(),
143 VecSink::new_mut(&mut set_typefaces).native_mut(),
144 )
145 };
146 typefaces
147 }
148
149 pub fn default_fallback_char<'fa>(
150 &mut self,
151 unicode: Unichar,
152 font_style: FontStyle,
153 locale: impl AsRef<str>,
154 font_args: impl Into<Option<&'fa FontArguments>>,
155 ) -> Option<Typeface> {
156 self.default_fallback_char_and_families(
157 unicode,
158 &[] as &[&str],
159 font_style,
160 locale,
161 font_args,
162 )
163 }
164
165 pub fn default_fallback_char_and_families<'fa>(
166 &mut self,
167 unicode: Unichar,
168 family_names: &[impl AsRef<str>],
169 font_style: FontStyle,
170 locale: impl AsRef<str>,
171 font_args: impl Into<Option<&'fa FontArguments>>,
172 ) -> Option<Typeface> {
173 let family_names = interop::Strings::from_strs(family_names);
174 let locale = interop::String::from_str(locale.as_ref());
175 Typeface::from_ptr(unsafe {
176 sb::C_FontCollection_defaultFallback(
177 self.native_mut(),
178 unicode,
179 family_names.native(),
180 font_style.into_native(),
181 locale.native(),
182 font_args.into().native_ptr_or_null(),
183 )
184 })
185 }
186
187 pub fn default_fallback(&mut self) -> Option<Typeface> {
188 Typeface::from_ptr(unsafe { sb::C_FontCollection_defaultFallback2(self.native_mut()) })
189 }
190
191 pub fn default_emoji_fallback(
192 &mut self,
193 emoji_start: Unichar,
194 font_style: FontStyle,
195 locale: impl AsRef<str>,
196 ) -> Option<Typeface> {
197 let locale = interop::String::from_str(locale.as_ref());
198 Typeface::from_ptr(unsafe {
199 sb::C_FontCollection_defaultEmojiFallback(
200 self.native_mut(),
201 emoji_start,
202 font_style.into_native(),
203 locale.native(),
204 )
205 })
206 }
207
208 pub fn disable_font_fallback(&mut self) {
209 unsafe { self.native_mut().disableFontFallback() }
210 }
211
212 pub fn enable_font_fallback(&mut self) {
213 unsafe { self.native_mut().enableFontFallback() }
214 }
215
216 pub fn font_fallback_enabled(&self) -> bool {
217 unsafe { sb::C_FontCollection_fontFallbackEnabled(self.native()) }
218 }
219
220 pub fn paragraph_cache(&self) -> &ParagraphCache {
221 ParagraphCache::from_native_ref(unsafe {
222 &*sb::C_FontCollection_paragraphCache(self.native_mut_force())
223 })
224 }
225
226 pub fn paragraph_cache_mut(&mut self) -> &mut ParagraphCache {
227 ParagraphCache::from_native_ref_mut(unsafe {
228 &mut *sb::C_FontCollection_paragraphCache(self.native_mut())
229 })
230 }
231
232 pub fn clear_caches(&mut self) {
233 unsafe { self.native_mut().clearCaches() }
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use crate::prelude::*;
240 use crate::textlayout::FontCollection;
241 use crate::{FontMgr, FontStyle};
242
243 #[test]
244 #[serial_test::serial]
245 fn ref_counts() {
246 let mut fc = FontCollection::new();
247 assert_eq!(fc.native().ref_counted_base()._ref_cnt(), 1);
248
249 let fm = FontMgr::new();
250 let fm_base = fm.native().ref_counted_base()._ref_cnt();
251
252 fc.set_default_font_manager(fm.clone(), None);
253 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base + 1);
254
255 let cloned_fc = fc.clone();
256 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base + 1);
257 assert_eq!(fc.native().ref_counted_base()._ref_cnt(), 2);
258 drop(cloned_fc);
259 assert_eq!(fc.native().ref_counted_base()._ref_cnt(), 1);
260 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base + 1);
261
262 {
263 let fmc = fc.fallback_manager().unwrap();
264 assert_eq!(fmc.native().ref_counted_base()._ref_cnt(), fm_base + 2);
265 drop(fmc);
266 }
267
268 fc.set_default_font_manager(None, None);
269 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base);
270 drop(fm);
271 drop(fc);
272 }
273
274 #[test]
275 #[serial_test::serial]
276 fn find_typefaces() {
277 let mut fc = FontCollection::new();
278 fc.set_default_font_manager(FontMgr::new(), None);
279 println!("find typeface:");
280 for typeface in fc.find_typefaces(
281 &[
282 "Arial",
283 "Tahoma",
284 "Fira Code",
285 "JetBrains Mono",
286 "Not Existing",
287 ],
288 FontStyle::default(),
289 ) {
290 println!("typeface: {}", typeface.family_name());
291 }
292 }
293}