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 let locale = interop::String::from_str(locale.as_ref());
157 Typeface::from_ptr(unsafe {
158 sb::C_FontCollection_defaultFallback(
159 self.native_mut(),
160 unicode,
161 font_style.into_native(),
162 locale.native(),
163 font_args.into().native_ptr_or_null(),
164 )
165 })
166 }
167
168 pub fn default_fallback(&mut self) -> Option<Typeface> {
169 Typeface::from_ptr(unsafe { sb::C_FontCollection_defaultFallback2(self.native_mut()) })
170 }
171
172 pub fn default_emoji_fallback(
173 &mut self,
174 emoji_start: Unichar,
175 font_style: FontStyle,
176 locale: impl AsRef<str>,
177 ) -> Option<Typeface> {
178 let locale = interop::String::from_str(locale.as_ref());
179 Typeface::from_ptr(unsafe {
180 sb::C_FontCollection_defaultEmojiFallback(
181 self.native_mut(),
182 emoji_start,
183 font_style.into_native(),
184 locale.native(),
185 )
186 })
187 }
188
189 pub fn disable_font_fallback(&mut self) {
190 unsafe { self.native_mut().disableFontFallback() }
191 }
192
193 pub fn enable_font_fallback(&mut self) {
194 unsafe { self.native_mut().enableFontFallback() }
195 }
196
197 pub fn font_fallback_enabled(&self) -> bool {
198 unsafe { sb::C_FontCollection_fontFallbackEnabled(self.native()) }
199 }
200
201 pub fn paragraph_cache(&self) -> &ParagraphCache {
202 ParagraphCache::from_native_ref(unsafe {
203 &*sb::C_FontCollection_paragraphCache(self.native_mut_force())
204 })
205 }
206
207 pub fn paragraph_cache_mut(&mut self) -> &mut ParagraphCache {
208 ParagraphCache::from_native_ref_mut(unsafe {
209 &mut *sb::C_FontCollection_paragraphCache(self.native_mut())
210 })
211 }
212
213 pub fn clear_caches(&mut self) {
214 unsafe { self.native_mut().clearCaches() }
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use crate::prelude::*;
221 use crate::textlayout::FontCollection;
222 use crate::{FontMgr, FontStyle};
223
224 #[test]
225 #[serial_test::serial]
226 fn ref_counts() {
227 let mut fc = FontCollection::new();
228 assert_eq!(fc.native().ref_counted_base()._ref_cnt(), 1);
229
230 let fm = FontMgr::new();
231 let fm_base = fm.native().ref_counted_base()._ref_cnt();
232
233 fc.set_default_font_manager(fm.clone(), None);
234 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base + 1);
235
236 let cloned_fc = fc.clone();
237 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base + 1);
238 assert_eq!(fc.native().ref_counted_base()._ref_cnt(), 2);
239 drop(cloned_fc);
240 assert_eq!(fc.native().ref_counted_base()._ref_cnt(), 1);
241 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base + 1);
242
243 {
244 let fmc = fc.fallback_manager().unwrap();
245 assert_eq!(fmc.native().ref_counted_base()._ref_cnt(), fm_base + 2);
246 drop(fmc);
247 }
248
249 fc.set_default_font_manager(None, None);
250 assert_eq!(fm.native().ref_counted_base()._ref_cnt(), fm_base);
251 drop(fm);
252 drop(fc);
253 }
254
255 #[test]
256 #[serial_test::serial]
257 fn find_typefaces() {
258 let mut fc = FontCollection::new();
259 fc.set_default_font_manager(FontMgr::new(), None);
260 println!("find typeface:");
261 for typeface in fc.find_typefaces(
262 &[
263 "Arial",
264 "Tahoma",
265 "Fira Code",
266 "JetBrains Mono",
267 "Not Existing",
268 ],
269 FontStyle::default(),
270 ) {
271 println!("typeface: {}", typeface.family_name());
272 }
273 }
274}