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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
use std::cell::RefCell; use std::ffi::{CStr, CString}; use std::ptr; use std::sync::Mutex; use mupdf_sys::*; use once_cell::sync::Lazy; use crate::Error; static BASE_CONTEXT: Lazy<Mutex<BaseContext>> = Lazy::new(|| { let ctx = unsafe { mupdf_new_base_context() }; Mutex::new(BaseContext(ctx)) }); thread_local! { static LOCAL_CONTEXT: RefCell<RawContext> = RefCell::new(RawContext(ptr::null_mut())); } #[derive(Debug)] struct BaseContext(*mut fz_context); unsafe impl Send for BaseContext {} impl Drop for BaseContext { fn drop(&mut self) { if !self.0.is_null() { unsafe { mupdf_drop_base_context(self.0); } } } } #[derive(Debug)] struct RawContext(*mut fz_context); impl Drop for RawContext { fn drop(&mut self) { if !self.0.is_null() { unsafe { fz_drop_context(self.0); } } } } #[derive(Debug)] pub struct Context { pub(crate) inner: *mut fz_context, } impl Context { pub fn get() -> Self { LOCAL_CONTEXT.with(|ctx| { { let local = ctx.borrow(); if !local.0.is_null() { return Self { inner: local.0 }; } } let base_ctx = BASE_CONTEXT.lock().unwrap(); let new_ctx = unsafe { fz_clone_context(base_ctx.0) }; if new_ctx.is_null() { panic!("failed to new fz_context"); } *ctx.borrow_mut() = RawContext(new_ctx); Self { inner: new_ctx } }) } pub fn enable_icc(&mut self) { unsafe { fz_enable_icc(self.inner); } } pub fn disable_icc(&mut self) { unsafe { fz_disable_icc(self.inner); } } pub fn aa_level(&self) -> i32 { unsafe { fz_aa_level(self.inner) } } pub fn set_aa_level(&mut self, bits: i32) { unsafe { fz_set_aa_level(self.inner, bits); } } pub fn text_aa_level(&self) -> i32 { unsafe { fz_text_aa_level(self.inner) } } pub fn set_text_aa_level(&mut self, bits: i32) { unsafe { fz_set_text_aa_level(self.inner, bits); } } pub fn graphics_aa_level(&self) -> i32 { unsafe { fz_graphics_aa_level(self.inner) } } pub fn set_graphics_aa_level(&mut self, bits: i32) { unsafe { fz_set_graphics_aa_level(self.inner, bits); } } pub fn graphics_min_line_width(&self) -> f32 { unsafe { fz_graphics_min_line_width(self.inner) } } pub fn set_graphics_min_line_width(&mut self, min_line_width: f32) { unsafe { fz_set_graphics_min_line_width(self.inner, min_line_width); } } pub fn use_document_css(&self) -> bool { unsafe { fz_use_document_css(self.inner) > 0 } } pub fn set_use_document_css(&mut self, should_use: bool) { let flag = if should_use { 1 } else { 0 }; unsafe { fz_set_use_document_css(self.inner, flag); } } pub fn user_css(&self) -> Option<&str> { let css = unsafe { fz_user_css(self.inner) }; if css.is_null() { return None; } let c_css = unsafe { CStr::from_ptr(css) }; c_css.to_str().ok() } pub fn set_user_css(&mut self, css: &str) -> Result<(), Error> { let c_css = CString::new(css)?; unsafe { fz_set_user_css(self.inner, c_css.as_ptr()); } Ok(()) } } impl Default for Context { fn default() -> Self { Self::get() } } pub(crate) fn context() -> *mut fz_context { Context::get().inner } #[cfg(test)] mod test { use super::Context; #[test] fn test_context() { let ctx = Context::get(); assert_eq!(ctx.aa_level(), 8); assert_eq!(ctx.text_aa_level(), 8); assert_eq!(ctx.graphics_aa_level(), 8); assert_eq!(ctx.graphics_min_line_width(), 0.0); assert!(ctx.use_document_css()); assert!(ctx.user_css().is_none()); } }