1
1
// SPDX-License-Identifier: MIT OR Apache-2.0
2
2
pub ( crate ) mod fallback;
3
3
4
- use alloc:: boxed:: Box ;
4
+ use core:: fmt;
5
+
5
6
use alloc:: sync:: Arc ;
6
7
8
+ use rustybuzz:: Face as RustybuzzFace ;
9
+ use self_cell:: self_cell;
10
+
7
11
pub use self :: system:: * ;
8
12
mod system;
9
13
10
- pub use font_inner:: Font ;
11
-
12
- /// Encapsulates the self-referencing `Font` struct to ensure all field accesses have to go through
13
- /// safe methods.
14
- mod font_inner {
15
- use super :: * ;
16
- use aliasable:: boxed:: AliasableBox ;
17
- use core:: fmt;
14
+ self_cell ! (
15
+ struct OwnedFace {
16
+ owner: Arc <dyn AsRef <[ u8 ] > + Send + Sync >,
18
17
19
- /// A font
20
- //
21
- // # Safety invariant
22
- //
23
- // `data` must never have a mutable reference taken, nor be modified during the lifetime of
24
- // this `Font`.
25
- pub struct Font {
26
- #[ cfg( feature = "swash" ) ]
27
- swash : ( u32 , swash:: CacheKey ) ,
28
- rustybuzz : rustybuzz:: Face < ' static > ,
29
- // Note: This field must be after rustybuzz to ensure that it is dropped later. Otherwise
30
- // there would be a dangling reference when dropping rustybuzz.
31
- data : aliasable:: boxed:: AliasableBox < Arc < dyn AsRef < [ u8 ] > + Send + Sync > > ,
32
- id : fontdb:: ID ,
18
+ #[ covariant]
19
+ dependent: RustybuzzFace ,
33
20
}
21
+ ) ;
34
22
35
- impl fmt:: Debug for Font {
36
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
37
- f. debug_struct ( "Font" )
38
- . field ( "id" , & self . id )
39
- . finish_non_exhaustive ( )
40
- }
41
- }
23
+ /// A font
24
+ pub struct Font {
25
+ #[ cfg( feature = "swash" ) ]
26
+ swash : ( u32 , swash:: CacheKey ) ,
27
+ rustybuzz : OwnedFace ,
28
+ data : Arc < dyn AsRef < [ u8 ] > + Send + Sync > ,
29
+ id : fontdb:: ID ,
30
+ }
42
31
43
- pub ( super ) struct FontTryBuilder <
44
- RustybuzzBuilder : for < ' this > FnOnce (
45
- & ' this Arc < dyn AsRef < [ u8 ] > + Send + Sync > ,
46
- ) -> Option < rustybuzz:: Face < ' this > > ,
47
- > {
48
- pub ( super ) id : fontdb:: ID ,
49
- pub ( super ) data : Arc < dyn AsRef < [ u8 ] > + Send + Sync > ,
50
- pub ( super ) rustybuzz_builder : RustybuzzBuilder ,
51
- #[ cfg( feature = "swash" ) ]
52
- pub ( super ) swash : ( u32 , swash:: CacheKey ) ,
32
+ impl fmt:: Debug for Font {
33
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
34
+ f. debug_struct ( "Font" )
35
+ . field ( "id" , & self . id )
36
+ . finish_non_exhaustive ( )
53
37
}
54
- impl <
55
- RustybuzzBuilder : for < ' this > FnOnce (
56
- & ' this Arc < dyn AsRef < [ u8 ] > + Send + Sync > ,
57
- ) -> Option < rustybuzz:: Face < ' this > > ,
58
- > FontTryBuilder < RustybuzzBuilder >
59
- {
60
- pub ( super ) fn try_build ( self ) -> Option < Font > {
61
- unsafe fn change_lifetime < ' old , ' new : ' old , T : ' new > ( data : & ' old T ) -> & ' new T {
62
- & * ( data as * const _ )
63
- }
64
-
65
- let data: AliasableBox < Arc < dyn AsRef < [ u8 ] > + Send + Sync > > =
66
- AliasableBox :: from_unique ( Box :: new ( self . data ) ) ;
67
-
68
- // Safety: We use AliasableBox to allow the references in rustybuzz::Face to alias with
69
- // the data stored behind the AliasableBox. In addition the entire public interface of
70
- // Font ensures that no mutable reference is given to data. And finally we use
71
- // for<'this> for the rustybuzz_builder to ensure it can't leak a reference. Combined
72
- // this ensures that it is sound to produce a self-referential type.
73
- let rustybuzz = ( self . rustybuzz_builder ) ( unsafe { change_lifetime ( & * data) } ) ?;
38
+ }
74
39
75
- Some ( Font {
76
- id : self . id ,
77
- data,
78
- rustybuzz,
79
- #[ cfg( feature = "swash" ) ]
80
- swash : self . swash ,
81
- } )
82
- }
40
+ impl Font {
41
+ pub fn id ( & self ) -> fontdb:: ID {
42
+ self . id
83
43
}
84
44
85
- impl Font {
86
- pub fn id ( & self ) -> fontdb:: ID {
87
- self . id
88
- }
89
-
90
- pub fn data ( & self ) -> & [ u8 ] {
91
- // Safety: This only gives an immutable access to `data`.
92
- ( * * self . data ) . as_ref ( )
93
- }
45
+ pub fn data ( & self ) -> & [ u8 ] {
46
+ ( * self . data ) . as_ref ( )
47
+ }
94
48
95
- pub fn rustybuzz ( & self ) -> & rustybuzz :: Face < ' _ > {
96
- & self . rustybuzz
97
- }
49
+ pub fn rustybuzz ( & self ) -> & RustybuzzFace < ' _ > {
50
+ self . rustybuzz . borrow_dependent ( )
51
+ }
98
52
99
- #[ cfg( feature = "swash" ) ]
100
- pub fn as_swash ( & self ) -> swash:: FontRef < ' _ > {
101
- let swash = & self . swash ;
102
- swash:: FontRef {
103
- data : self . data ( ) ,
104
- offset : swash. 0 ,
105
- key : swash. 1 ,
106
- }
53
+ #[ cfg( feature = "swash" ) ]
54
+ pub fn as_swash ( & self ) -> swash:: FontRef < ' _ > {
55
+ let swash = & self . swash ;
56
+ swash:: FontRef {
57
+ data : self . data ( ) ,
58
+ offset : swash. 0 ,
59
+ key : swash. 1 ,
107
60
}
108
61
}
109
62
}
110
63
111
64
impl Font {
112
65
pub fn new ( info : & fontdb:: FaceInfo ) -> Option < Self > {
113
- #[ allow( unused_variables) ]
114
66
let data = match & info. source {
115
67
fontdb:: Source :: Binary ( data) => Arc :: clone ( data) ,
116
68
#[ cfg( feature = "std" ) ]
@@ -121,16 +73,19 @@ impl Font {
121
73
#[ cfg( feature = "std" ) ]
122
74
fontdb:: Source :: SharedFile ( _path, data) => Arc :: clone ( data) ,
123
75
} ;
124
- font_inner:: FontTryBuilder {
76
+
77
+ Some ( Self {
125
78
id : info. id ,
126
79
#[ cfg( feature = "swash" ) ]
127
80
swash : {
128
81
let swash = swash:: FontRef :: from_index ( ( * data) . as_ref ( ) , info. index as usize ) ?;
129
82
( swash. offset , swash. key )
130
83
} ,
84
+ rustybuzz : OwnedFace :: try_new ( Arc :: clone ( & data) , |data| {
85
+ RustybuzzFace :: from_slice ( ( * * data) . as_ref ( ) , info. index ) . ok_or ( ( ) )
86
+ } )
87
+ . ok ( ) ?,
131
88
data,
132
- rustybuzz_builder : |data| rustybuzz:: Face :: from_slice ( ( * * data) . as_ref ( ) , info. index ) ,
133
- }
134
- . try_build ( )
89
+ } )
135
90
}
136
91
}
0 commit comments