-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
font_context.rs
141 lines (126 loc) · 4.33 KB
/
font_context.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_Library;
use freetype::freetype::FT_Library;
use freetype::freetype::FT_Memory;
use freetype::freetype::FT_MemoryRec_;
use freetype::freetype::FT_New_Library;
use freetype::succeeded;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use servo_allocator::libc_compat::{malloc, realloc, free};
use servo_allocator::usable_size;
use std::os::raw::{c_long, c_void};
use std::ptr;
use std::rc::Rc;
// We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is
// created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to
// record the memory usage of each FreeType instance.
pub struct User {
size: usize,
}
extern "C" fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
unsafe {
let ptr = malloc(req_size as usize);
let ptr = ptr as *mut c_void; // libc::c_void vs std::os::raw::c_void
let actual_size = usable_size(ptr);
let user = (*mem).user as *mut User;
(*user).size += actual_size;
ptr
}
}
extern "C" fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
unsafe {
let actual_size = usable_size(ptr);
let user = (*mem).user as *mut User;
(*user).size -= actual_size;
free(ptr as *mut _);
}
}
extern "C" fn ft_realloc(
mem: FT_Memory,
_old_size: c_long,
new_req_size: c_long,
old_ptr: *mut c_void,
) -> *mut c_void {
unsafe {
let old_actual_size = usable_size(old_ptr);
let new_ptr = realloc(old_ptr as *mut _, new_req_size as usize);
let new_ptr = new_ptr as *mut c_void;
let new_actual_size = usable_size(new_ptr);
let user = (*mem).user as *mut User;
(*user).size += new_actual_size;
(*user).size -= old_actual_size;
new_ptr
}
}
// A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from
// rustc. But using a typedef avoids this, so...
pub type UserPtr = *mut User;
// WARNING: We need to be careful how we use this struct. See the comment about Rc<> in
// FontContextHandle.
#[derive(Clone, Debug)]
pub struct FreeTypeLibraryHandle {
pub ctx: FT_Library,
mem: FT_Memory,
user: UserPtr,
}
impl Drop for FreeTypeLibraryHandle {
fn drop(&mut self) {
assert!(!self.ctx.is_null());
unsafe {
FT_Done_Library(self.ctx);
Box::from_raw(self.mem);
Box::from_raw(self.user);
}
}
}
impl MallocSizeOf for FreeTypeLibraryHandle {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
unsafe {
(*self.user).size +
ops.malloc_size_of(self.ctx as *const _) +
ops.malloc_size_of(self.mem as *const _) +
ops.malloc_size_of(self.user as *const _)
}
}
}
#[derive(Clone, Debug)]
pub struct FontContextHandle {
// WARNING: FreeTypeLibraryHandle contains raw pointers, is clonable, and also implements
// `Drop`. This field needs to be Rc<> to make sure that the `drop` function is only called
// once, otherwise we'll get crashes. Yuk.
pub ctx: Rc<FreeTypeLibraryHandle>,
}
impl MallocSizeOf for FontContextHandle {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.ctx.size_of(ops)
}
}
impl FontContextHandle {
pub fn new() -> FontContextHandle {
let user = Box::into_raw(Box::new(User { size: 0 }));
let mem = Box::into_raw(Box::new(FT_MemoryRec_ {
user: user as *mut c_void,
alloc: Some(ft_alloc),
free: Some(ft_free),
realloc: Some(ft_realloc),
}));
unsafe {
let mut ctx: FT_Library = ptr::null_mut();
let result = FT_New_Library(mem, &mut ctx);
if !succeeded(result) {
panic!("Unable to initialize FreeType library");
}
FT_Add_Default_Modules(ctx);
FontContextHandle {
ctx: Rc::new(FreeTypeLibraryHandle {
ctx: ctx,
mem: mem,
user: user,
}),
}
}
}
}