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 custom_empty() -> Option<Self> {
120 FontMgr::from_ptr(unsafe { sb::C_SkFontMgr_NewCustomEmpty() })
121 }
122
123 pub fn count_families(&self) -> usize {
124 unsafe { self.native().countFamilies().try_into().unwrap() }
125 }
126
127 pub fn family_name(&self, index: usize) -> String {
128 assert!(index < self.count_families());
129 let mut family_name = interop::String::default();
130 unsafe {
131 self.native()
132 .getFamilyName(index.try_into().unwrap(), family_name.native_mut())
133 }
134 family_name.as_str().into()
135 }
136
137 pub fn family_names(&self) -> impl Iterator<Item = String> + use<'_> {
138 (0..self.count_families()).map(move |i| self.family_name(i))
139 }
140
141 #[deprecated(since = "0.41.0", note = "Use new_style_set")]
142 pub fn new_styleset(&self, index: usize) -> FontStyleSet {
143 self.new_style_set(index)
144 }
145
146 pub fn new_style_set(&self, index: usize) -> FontStyleSet {
147 assert!(index < self.count_families());
148 FontStyleSet::from_ptr(unsafe {
149 sb::C_SkFontMgr_createStyleSet(self.native(), index.try_into().unwrap())
150 })
151 .unwrap()
152 }
153
154 pub fn match_family(&self, family_name: impl AsRef<str>) -> FontStyleSet {
155 let family_name = CString::new(family_name.as_ref()).unwrap();
156 FontStyleSet::from_ptr(unsafe {
157 sb::C_SkFontMgr_matchFamily(self.native(), family_name.as_ptr())
158 })
159 .unwrap()
160 }
161
162 pub fn match_family_style(
163 &self,
164 family_name: impl AsRef<str>,
165 style: FontStyle,
166 ) -> Option<Typeface> {
167 let family_name = CString::new(family_name.as_ref()).unwrap();
168 Typeface::from_ptr(unsafe {
169 sb::C_SkFontMgr_matchFamilyStyle(self.native(), family_name.as_ptr(), style.native())
170 })
171 }
172
173 pub fn match_family_style_character(
175 &self,
176 family_name: impl AsRef<str>,
177 style: FontStyle,
178 bcp_47: &[&str],
179 character: Unichar,
180 ) -> Option<Typeface> {
181 let family_name = CString::new(family_name.as_ref()).unwrap();
182 let bcp_47: Vec<CString> = bcp_47.iter().map(|s| CString::new(*s).unwrap()).collect();
184 let mut bcp_47: Vec<*const c_char> = bcp_47.iter().map(|cs| cs.as_ptr()).collect();
186
187 Typeface::from_ptr(unsafe {
188 sb::C_SkFontMgr_matchFamilyStyleCharacter(
189 self.native(),
190 family_name.as_ptr(),
191 style.native(),
192 bcp_47.as_mut_ptr(),
193 bcp_47.len().try_into().unwrap(),
194 character,
195 )
196 })
197 }
198
199 #[deprecated(since = "0.35.0", note = "Removed without replacement")]
200 pub fn match_face_style(&self, _typeface: impl AsRef<Typeface>, _style: FontStyle) -> ! {
201 panic!("Removed without replacement")
202 }
203
204 pub fn new_from_data(
220 &self,
221 bytes: &[u8],
222 ttc_index: impl Into<Option<usize>>,
223 ) -> Option<Typeface> {
224 let mut stream = DynamicMemoryWStream::from_bytes(bytes);
225 let mut stream = stream.detach_as_stream();
226 Typeface::from_ptr(unsafe {
227 let stream_ptr = stream.native_mut() as *mut _;
228 mem::forget(stream);
230 sb::C_SkFontMgr_makeFromStream(
231 self.native(),
232 stream_ptr,
233 ttc_index.into().unwrap_or_default().try_into().unwrap(),
234 )
235 })
236 }
237
238 pub fn legacy_make_typeface<'a>(
239 &self,
240 family_name: impl Into<Option<&'a str>>,
241 style: FontStyle,
242 ) -> Option<Typeface> {
243 let family_name: Option<CString> = family_name
244 .into()
245 .and_then(|family_name| CString::new(family_name).ok());
246
247 Typeface::from_ptr(unsafe {
248 sb::C_SkFontMgr_legacyMakeTypeface(
249 self.native(),
250 family_name
251 .as_ref()
252 .map(|n| n.as_ptr())
253 .unwrap_or(ptr::null()),
254 style.into_native(),
255 )
256 })
257 }
258
259 }
261
262#[cfg(test)]
263mod tests {
264 use crate::FontMgr;
265
266 #[test]
267 #[serial_test::serial]
268 fn create_all_typefaces() {
269 let font_mgr = FontMgr::default();
270 let families = font_mgr.count_families();
271 println!("FontMgr families: {families}");
272 assert!(families > 0);
274 for i in 0..families {
276 let name = font_mgr.family_name(i);
277 println!("font_family: {name}");
278 let mut style_set = font_mgr.new_style_set(i);
279 for style_index in 0..style_set.count() {
280 let (_, style_name) = style_set.style(style_index);
281 if let Some(style_name) = style_name {
282 println!(" style: {style_name}");
283 }
284 let face = style_set.new_typeface(style_index);
285 drop(face);
286 }
287 }
288 }
289}