| 1 | use crate::{ |
| 2 | interop::{self, AsStr}, |
| 3 | prelude::*, |
| 4 | FontMgr, FontStyleSet, Typeface, |
| 5 | }; |
| 6 | use skia_bindings as sb; |
| 7 | use std::{ |
| 8 | fmt, |
| 9 | mem::transmute, |
| 10 | ops::{Deref, DerefMut}, |
| 11 | ptr, |
| 12 | }; |
| 13 | |
| 14 | pub type TypefaceFontStyleSet = RCHandle<sb::skia_textlayout_TypefaceFontStyleSet>; |
| 15 | require_base_type!(sb::skia_textlayout_TypefaceFontStyleSet, sb::SkFontStyleSet); |
| 16 | |
| 17 | impl NativeRefCountedBase for sb::skia_textlayout_TypefaceFontStyleSet { |
| 18 | type Base = sb::SkRefCntBase; |
| 19 | } |
| 20 | |
| 21 | impl Deref for TypefaceFontStyleSet { |
| 22 | type Target = FontStyleSet; |
| 23 | fn deref(&self) -> &Self::Target { |
| 24 | unsafe { transmute_ref(self) } |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | impl DerefMut for TypefaceFontStyleSet { |
| 29 | fn deref_mut(&mut self) -> &mut Self::Target { |
| 30 | unsafe { transmute_ref_mut(self) } |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | impl fmt::Debug for TypefaceFontStyleSet { |
| 35 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 36 | f&mut DebugStruct<'_, '_>.debug_struct("TypefaceFontStyleSet" ) |
| 37 | .field("base" , self as &FontStyleSet) |
| 38 | .field("family_name" , &self.family_name()) |
| 39 | .field(name:"alias" , &self.alias()) |
| 40 | .finish() |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | impl TypefaceFontStyleSet { |
| 45 | pub fn new(family_name: impl AsRef<str>) -> Self { |
| 46 | let family: Handle = interop::String::from_str(family_name.as_ref()); |
| 47 | Self::from_ptr(unsafe { sb::C_TypefaceFontStyleSet_new(family_name:family.native()) }).unwrap() |
| 48 | } |
| 49 | |
| 50 | pub fn family_name(&self) -> &str { |
| 51 | self.native().fFamilyName.as_str() |
| 52 | } |
| 53 | |
| 54 | pub fn alias(&self) -> &str { |
| 55 | self.native().fAlias.as_str() |
| 56 | } |
| 57 | |
| 58 | pub fn append_typeface(&mut self, typeface: Typeface) -> &mut Self { |
| 59 | unsafe { sb::C_TypefaceFontStyleSet_appendTypeface(self.native_mut(), typeface.into_ptr()) } |
| 60 | self |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | pub type TypefaceFontProvider = RCHandle<sb::skia_textlayout_TypefaceFontProvider>; |
| 65 | require_base_type!(sb::skia_textlayout_TypefaceFontProvider, sb::SkFontMgr); |
| 66 | |
| 67 | impl NativeRefCountedBase for sb::skia_textlayout_TypefaceFontProvider { |
| 68 | type Base = sb::SkRefCntBase; |
| 69 | } |
| 70 | |
| 71 | impl Deref for TypefaceFontProvider { |
| 72 | type Target = FontMgr; |
| 73 | fn deref(&self) -> &Self::Target { |
| 74 | unsafe { transmute_ref(self) } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | impl DerefMut for TypefaceFontProvider { |
| 79 | fn deref_mut(&mut self) -> &mut Self::Target { |
| 80 | unsafe { transmute_ref_mut(self) } |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | impl Default for TypefaceFontProvider { |
| 85 | fn default() -> Self { |
| 86 | Self::new() |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | impl From<TypefaceFontProvider> for FontMgr { |
| 91 | fn from(provider: TypefaceFontProvider) -> Self { |
| 92 | unsafe { transmute(src:provider) } |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | impl fmt::Debug for TypefaceFontProvider { |
| 97 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 98 | f&mut DebugStruct<'_, '_>.debug_struct("TypefaceFontProvider" ) |
| 99 | .field(name:"base" , self as &FontMgr) |
| 100 | .finish() |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | impl TypefaceFontProvider { |
| 105 | pub fn new() -> Self { |
| 106 | Self::from_ptr(unsafe { sb::C_TypefaceFontProvider_new() }).unwrap() |
| 107 | } |
| 108 | |
| 109 | pub fn register_typeface<'a>( |
| 110 | &mut self, |
| 111 | typeface: Typeface, |
| 112 | alias: impl Into<Option<&'a str>>, |
| 113 | ) -> usize { |
| 114 | unsafe { |
| 115 | match alias.into() { |
| 116 | Some(alias) => { |
| 117 | let alias = interop::String::from_str(alias); |
| 118 | sb::C_TypefaceFontProvider_registerTypeface( |
| 119 | self.native_mut(), |
| 120 | typeface.into_ptr(), |
| 121 | alias.native(), |
| 122 | ) |
| 123 | } |
| 124 | None => sb::C_TypefaceFontProvider_registerTypeface( |
| 125 | self.native_mut(), |
| 126 | typeface.into_ptr(), |
| 127 | ptr::null(), |
| 128 | ), |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | #[cfg (test)] |
| 135 | mod tests { |
| 136 | use super::{TypefaceFontProvider, TypefaceFontStyleSet}; |
| 137 | use crate::{ |
| 138 | prelude::{NativeAccess, NativeRefCounted, NativeRefCountedBase}, |
| 139 | textlayout::FontCollection, |
| 140 | FontMgr, FontStyle, |
| 141 | }; |
| 142 | |
| 143 | #[test ] |
| 144 | #[serial_test::serial] |
| 145 | fn font_style_set_typeface_ref_counts() { |
| 146 | let mut style_set = TypefaceFontStyleSet::new("" ); |
| 147 | assert_eq!(style_set.native().ref_counted_base()._ref_cnt(), 1); |
| 148 | |
| 149 | let tf = FontMgr::new() |
| 150 | .legacy_make_typeface(None, FontStyle::default()) |
| 151 | .unwrap(); |
| 152 | let base_cnt = tf.native().ref_counted_base()._ref_cnt(); |
| 153 | |
| 154 | let tfclone = tf.clone(); |
| 155 | assert_eq!(tf.native().ref_counted_base()._ref_cnt(), base_cnt + 1); |
| 156 | |
| 157 | style_set.append_typeface(tfclone); |
| 158 | assert_eq!(tf.native().ref_counted_base()._ref_cnt(), base_cnt + 1); |
| 159 | |
| 160 | drop(style_set); |
| 161 | assert_eq!(tf.native().ref_counted_base()._ref_cnt(), base_cnt); |
| 162 | drop(tf); |
| 163 | } |
| 164 | |
| 165 | #[test ] |
| 166 | #[serial_test::serial] |
| 167 | fn treat_font_provider_as_font_mgr() { |
| 168 | let mut font_collection = FontCollection::new(); |
| 169 | let typeface = FontMgr::new() |
| 170 | .legacy_make_typeface(None, FontStyle::default()) |
| 171 | .unwrap(); |
| 172 | let mut manager = TypefaceFontProvider::new(); |
| 173 | manager.register_typeface(typeface, Some("AlArabiya" )); |
| 174 | assert_eq!(font_collection.font_managers_count(), 0); |
| 175 | font_collection.set_asset_font_manager(Some(manager.into())); |
| 176 | assert_eq!(font_collection.font_managers_count(), 1); |
| 177 | } |
| 178 | } |
| 179 | |