Skip to content

Commit

Permalink
Start implementing custom devices
Browse files Browse the repository at this point in the history
  • Loading branch information
ginnyTheCat committed Feb 6, 2025
1 parent b25d1bd commit abe3fc7
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 1 deletion.
10 changes: 10 additions & 0 deletions mupdf-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@
#![allow(clippy::all)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

pub unsafe fn mupdf_new_derived_device<T>(
ctx: *mut fz_context,
label: *const std::ffi::c_char,
) -> *mut T {
let size = std::ffi::c_int::try_from(size_of::<T>()).unwrap();
let device = fz_new_device_of_size(ctx, size);
let label = Memento_label(device.cast(), label);
label.cast()
}
7 changes: 7 additions & 0 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use crate::{
Shade, StrokeState, Text, TextPage, TextPageOptions,
};

mod custom;
pub use custom::CustomDevice;

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub enum BlendMode {
Expand Down Expand Up @@ -42,6 +45,10 @@ impl Device {
Self { dev, list }
}

pub fn from_custom<D: CustomDevice>(device: D) -> Self {
custom::create(device)
}

pub fn from_pixmap_with_clip(pixmap: &Pixmap, clip: IRect) -> Result<Self, Error> {
let dev = unsafe { ffi_try!(mupdf_new_draw_device(context(), pixmap.inner, clip.into())) };
Ok(Self {
Expand Down
225 changes: 225 additions & 0 deletions src/device/custom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
use std::{ffi::c_int, mem, ptr, slice};

use mupdf_sys::*;

use crate::{context, ColorParams, Colorspace, Device, Matrix, Path, StrokeState, Text};

#[allow(unused_variables)]
pub trait CustomDevice {
fn close_device(&mut self) {}

fn fill_path(
&mut self,
path: &Path,
even_odd: bool,
cmt: Matrix,
color_space: Colorspace,
color: &[f32],
alpha: f32,
cp: ColorParams,
) {
}

fn stroke_path(
&mut self,
path: &Path,
stroke_state: &StrokeState,
cmt: Matrix,
color_space: Colorspace,
color: &[f32],
alpha: f32,
cp: ColorParams,
) {
}

fn fill_text(
&mut self,
text: &Text,
cmt: Matrix,
color_space: Colorspace,
color: &[f32],
alpha: f32,
cp: ColorParams,
) {
}
}

impl<T: CustomDevice + ?Sized> CustomDevice for &mut T {
fn close_device(&mut self) {
(**self).close_device();
}

fn fill_path(
&mut self,
path: &Path,
even_odd: bool,
cmt: Matrix,
color_space: Colorspace,
color: &[f32],
alpha: f32,
cp: ColorParams,
) {
(**self).fill_path(path, even_odd, cmt, color_space, color, alpha, cp);
}

fn stroke_path(
&mut self,
path: &Path,
stroke_state: &StrokeState,
cmt: Matrix,
color_space: Colorspace,
color: &[f32],
alpha: f32,
cp: ColorParams,
) {
(**self).stroke_path(path, stroke_state, cmt, color_space, color, alpha, cp);
}

fn fill_text(
&mut self,
text: &Text,
cmt: Matrix,
color_space: Colorspace,
color: &[f32],
alpha: f32,
cp: ColorParams,
) {
(**self).fill_text(text, cmt, color_space, color, alpha, cp);
}
}

pub(crate) fn create<D: CustomDevice>(device: D) -> Device {
let d = unsafe {
let c_device = mupdf_new_derived_device::<CDevice<D>>(context(), c"RustDevice".as_ptr());
ptr::write(&raw mut (*c_device).rust_device, device);

(*c_device).base.close_device = Some(close_device::<D>);
(*c_device).base.drop_device = Some(drop_device::<D>);
(*c_device).base.fill_path = Some(fill_path::<D>);
(*c_device).base.stroke_path = Some(stroke_path::<D>);
(*c_device).base.fill_text = Some(fill_text::<D>);

Device::from_raw(c_device.cast(), ptr::null_mut())
};
d
}

#[repr(C)]
struct CDevice<D> {
base: fz_device,
rust_device: D,
}

unsafe fn with_rust_device<'a, D: CustomDevice>(dev: *mut fz_device, f: impl FnOnce(&mut D)) {
let c_device: *mut CDevice<D> = dev.cast();
let rust_device = &mut (*c_device).rust_device;
f(rust_device);
let _ = rust_device;
}

unsafe extern "C" fn close_device<D: CustomDevice>(_ctx: *mut fz_context, dev: *mut fz_device) {
with_rust_device::<D>(dev, |dev| dev.close_device());
}

unsafe extern "C" fn drop_device<D: CustomDevice>(_ctx: *mut fz_context, dev: *mut fz_device) {
let c_device: *mut CDevice<D> = dev.cast();
let rust_device = &raw mut (*c_device).rust_device;

ptr::drop_in_place(rust_device);
}

unsafe extern "C" fn fill_path<D: CustomDevice>(
_ctx: *mut fz_context,
dev: *mut fz_device,
path: *const fz_path,
even_odd: c_int,
cmt: fz_matrix,
color_space: *mut fz_colorspace,
color: *const f32,
alpha: f32,
color_params: fz_color_params,
) {
with_rust_device::<D>(dev, |dev| {
let cs = Colorspace::from_raw(color_space);
let cs_n = cs.n() as usize;

let path = Path::from_raw(path.cast_mut());

dev.fill_path(
&path,
even_odd != 0,
cmt.into(),
cs,
slice::from_raw_parts(color, cs_n),
alpha,
color_params.into(),
);

mem::forget(path);
});
}

unsafe extern "C" fn stroke_path<D: CustomDevice>(
_ctx: *mut fz_context,
dev: *mut fz_device,
path: *const fz_path,
stroke_state: *const fz_stroke_state,
cmt: fz_matrix,
color_space: *mut fz_colorspace,
color: *const f32,
alpha: f32,
color_params: fz_color_params,
) {
with_rust_device::<D>(dev, |dev| {
let cs = Colorspace::from_raw(color_space);
let cs_n = cs.n() as usize;

let path = Path::from_raw(path.cast_mut());
let stroke_state = StrokeState {
inner: stroke_state.cast_mut(),
};

dev.stroke_path(
&path,
&stroke_state,
cmt.into(),
cs,
slice::from_raw_parts(color, cs_n),
alpha,
color_params.into(),
);

mem::forget(stroke_state);
mem::forget(path);
});
}

unsafe extern "C" fn fill_text<D: CustomDevice>(
_ctx: *mut fz_context,
dev: *mut fz_device,
text: *const fz_text,
cmt: fz_matrix,
color_space: *mut fz_colorspace,
color: *const f32,
alpha: f32,
color_params: fz_color_params,
) {
with_rust_device::<D>(dev, |dev| {
let text = Text {
inner: text.cast_mut(),
};

let cs = Colorspace::from_raw(color_space);
let cs_n = cs.n() as usize;
dev.fill_text(
&text,
cmt.into(),
cs,
slice::from_raw_parts(color, cs_n),
alpha,
color_params.into(),
);

mem::forget(text);
});
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub(crate) use context::context;
pub use context::Context;
pub use cookie::Cookie;
pub use destination::{Destination, DestinationKind};
pub use device::{BlendMode, Device};
pub use device::{BlendMode, CustomDevice, Device};
pub use display_list::DisplayList;
pub use document::{Document, MetadataName};
pub use document_writer::DocumentWriter;
Expand Down

0 comments on commit abe3fc7

Please sign in to comment.