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