skia_safe/core/
font_mgr.rs1use skia_bindings::{self as sb, SkFontMgr, SkFontStyleSet, SkRefCntBase};
2use std::{ffi::CString, fmt, mem, os::raw::c_char, ptr};
3
4use crate::{
5 interop::{self, DynamicMemoryWStream},
6 prelude::*,
7 FontStyle, Typeface, Unichar,
8};
9
10pub type FontStyleSet = RCHandle<SkFontStyleSet>;
11
12impl NativeBase<SkRefCntBase> for SkFontStyleSet {}
13
14impl NativeRefCountedBase for SkFontStyleSet {
15 type Base = SkRefCntBase;
16}
17
18impl Default for FontStyleSet {
19 fn default() -> Self {
20 FontStyleSet::new_empty()
21 }
22}
23
24impl fmt::Debug for FontStyleSet {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 f.debug_struct("FontStyleSet")
27 .finish()
30 }
31}
32
33impl FontStyleSet {
34 pub fn count(&mut self) -> usize {
35 unsafe {
36 sb::C_SkFontStyleSet_count(self.native_mut())
37 .try_into()
38 .unwrap()
39 }
40 }
41
42 pub fn style(&mut self, index: usize) -> (FontStyle, Option<String>) {
43 assert!(index < self.count());
44
45 let mut font_style = FontStyle::default();
46 let mut style = interop::String::default();
47 unsafe {
48 sb::C_SkFontStyleSet_getStyle(
49 self.native_mut(),
50 index.try_into().unwrap(),
51 font_style.native_mut(),
52 style.native_mut(),
53 )
54 }
55
56 let name = style
58 .as_str()
59 .is_empty()
60 .if_false_then_some(|| style.as_str().into());
61
62 (font_style, name)
63 }
64
65 pub fn new_typeface(&mut self, index: usize) -> Option<Typeface> {
66 assert!(index < self.count());
67
68 Typeface::from_ptr(unsafe {
69 sb::C_SkFontStyleSet_createTypeface(self.native_mut(), index.try_into().unwrap())
70 })
71 }
72
73 pub fn match_style(&mut self, pattern: FontStyle) -> Option<Typeface> {
74 Typeface::from_ptr(unsafe {
75 sb::C_SkFontStyleSet_matchStyle(self.native_mut(), pattern.native())
76 })
77 }
78
79 pub fn new_empty() -> Self {
80 FontStyleSet::from_ptr(unsafe { sb::C_SkFontStyleSet_CreateEmpty() }).unwrap()
81 }
82}
83
84pub type FontMgr = RCHandle<SkFontMgr>;
85
86impl NativeBase<SkRefCntBase> for SkFontMgr {}
87
88impl NativeRefCountedBase for SkFontMgr {
89 type Base = SkRefCntBase;
90}
91
92impl Default for FontMgr {
93 fn default() -> Self {
94 Self::new()
95 }
96}
97
98impl fmt::Debug for FontMgr {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 let names: Vec<_> = self.family_names().collect();
101 f.debug_struct("FontMgr")
102 .field("family_names", &names)
103 .finish()
104 }
105}
106
107impl FontMgr {
108 pub fn new() -> Self {
111 FontMgr::from_ptr(unsafe { sb::C_SkFontMgr_NewSystem() }).unwrap()
112 }
113
114 pub fn empty() -> Self {
115 FontMgr::from_ptr(unsafe { sb::C_SkFontMgr_RefEmpty() }).unwrap()
116 }
117
118 pub fn count_families(&self) -> usize {
119 unsafe { self.native().countFamilies().try_into().unwrap() }
120 }
121
122 pub fn family_name(&self, index: usize) -> String {
123 assert!(index < self.count_families());
124 let mut family_name = interop::String::default();
125 unsafe {
126 self.native()
127 .getFamilyName(index.try_into().unwrap(), family_name.native_mut())
128 }
129 family_name.as_str().into()
130 }
131
132 pub fn family_names(&self) -> impl Iterator<Item = String> + use<'_> {
133 (0..self.count_families()).map(move |i| self.family_name(i))
134 }
135
136 #[deprecated(since = "0.41.0", note = "Use new_style_set")]
137 pub fn new_styleset(&self, index: usize) -> FontStyleSet {
138 self.new_style_set(index)
139 }
140
141 pub fn new_style_set(&self, index: usize) -> FontStyleSet {
142 assert!(index < self.count_families());
143 FontStyleSet::from_ptr(unsafe {
144 sb::C_SkFontMgr_createStyleSet(self.native(), index.try_into().unwrap())
145 })
146 .unwrap()
147 }
148
149 pub fn match_family(&self, family_name: impl AsRef<str>) -> FontStyleSet {
150 let family_name = CString::new(family_name.as_ref()).unwrap();
151 FontStyleSet::from_ptr(unsafe {
152 sb::C_SkFontMgr_matchFamily(self.native(), family_name.as_ptr())
153 })
154 .unwrap()
155 }
156
157 pub fn match_family_style(
158 &self,
159 family_name: impl AsRef<str>,
160 style: FontStyle,
161 ) -> Option<Typeface> {
162 let family_name = CString::new(family_name.as_ref()).unwrap();
163 Typeface::from_ptr(unsafe {
164 sb::C_SkFontMgr_matchFamilyStyle(self.native(), family_name.as_ptr(), style.native())
165 })
166 }
167
168 pub fn match_family_style_character(
170 &self,
171 family_name: impl AsRef<str>,
172 style: FontStyle,
173 bcp_47: &[&str],
174 character: Unichar,
175 ) -> Option<Typeface> {
176 let family_name = CString::new(family_name.as_ref()).unwrap();
177 let bcp_47: Vec<CString> = bcp_47.iter().map(|s| CString::new(*s).unwrap()).collect();
179 let mut bcp_47: Vec<*const c_char> = bcp_47.iter().map(|cs| cs.as_ptr()).collect();
181
182 Typeface::from_ptr(unsafe {
183 sb::C_SkFontMgr_matchFamilyStyleCharacter(
184 self.native(),
185 family_name.as_ptr(),
186 style.native(),
187 bcp_47.as_mut_ptr(),
188 bcp_47.len().try_into().unwrap(),
189 character,
190 )
191 })
192 }
193
194 #[deprecated(since = "0.35.0", note = "Removed without replacement")]
195 pub fn match_face_style(&self, _typeface: impl AsRef<Typeface>, _style: FontStyle) -> ! {
196 panic!("Removed without replacement")
197 }
198
199 pub fn new_from_data(
215 &self,
216 bytes: &[u8],
217 ttc_index: impl Into<Option<usize>>,
218 ) -> Option<Typeface> {
219 let mut stream = DynamicMemoryWStream::from_bytes(bytes);
220 let mut stream = stream.detach_as_stream();
221 Typeface::from_ptr(unsafe {
222 let stream_ptr = stream.native_mut() as *mut _;
223 mem::forget(stream);
225 sb::C_SkFontMgr_makeFromStream(
226 self.native(),
227 stream_ptr,
228 ttc_index.into().unwrap_or_default().try_into().unwrap(),
229 )
230 })
231 }
232
233 pub fn legacy_make_typeface<'a>(
234 &self,
235 family_name: impl Into<Option<&'a str>>,
236 style: FontStyle,
237 ) -> Option<Typeface> {
238 let family_name: Option<CString> = family_name
239 .into()
240 .and_then(|family_name| CString::new(family_name).ok());
241
242 Typeface::from_ptr(unsafe {
243 sb::C_SkFontMgr_legacyMakeTypeface(
244 self.native(),
245 family_name
246 .as_ref()
247 .map(|n| n.as_ptr())
248 .unwrap_or(ptr::null()),
249 style.into_native(),
250 )
251 })
252 }
253
254 }
256
257#[cfg(test)]
258mod tests {
259 use crate::FontMgr;
260
261 #[test]
262 #[serial_test::serial]
263 fn create_all_typefaces() {
264 let font_mgr = FontMgr::default();
265 let families = font_mgr.count_families();
266 println!("FontMgr families: {families}");
267 assert!(families > 0);
269 for i in 0..families {
271 let name = font_mgr.family_name(i);
272 println!("font_family: {name}");
273 let mut style_set = font_mgr.new_style_set(i);
274 for style_index in 0..style_set.count() {
275 let (_, style_name) = style_set.style(style_index);
276 if let Some(style_name) = style_name {
277 println!(" style: {style_name}");
278 }
279 let face = style_set.new_typeface(style_index);
280 drop(face);
281 }
282 }
283 }
284}