Skip to content

Commit

Permalink
enhance: Add API to allow print options
Browse files Browse the repository at this point in the history
  • Loading branch information
Mildred KiLya authored and mildred committed Jul 13, 2024
1 parent d1f1e7e commit 047d8cf
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 27 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exclude = [ "/.changes", "/.github", "/audits", "/wry-logo.svg" ]

[package.metadata.docs.rs]
no-default-features = true
features = [ "drag-drop", "protocol", "os-webview" ]
features = [ "drag-drop", "protocol", "os-webview", "serde" ]
targets = [
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
Expand All @@ -26,7 +26,7 @@ rustdoc-args = [ "--cfg", "docsrs" ]

[features]
default = [ "drag-drop", "objc-exception", "protocol", "os-webview" ]
serde = [ "dpi/serde" ]
serde = [ "dep:serde", "dpi/serde" ]
objc-exception = [ "objc/exception" ]
drag-drop = [ ]
protocol = [ ]
Expand All @@ -53,6 +53,7 @@ thiserror = "1.0"
http = "1.1"
raw-window-handle = { version = "0.6", features = [ "std" ] }
dpi = "0.1"
serde = { version = "1", features = ["serde_derive"], optional = true }

[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
javascriptcore-rs = { version = "=1.1.2", features = [ "v2_28" ], optional = true }
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/// Convenient type alias of Result type for wry.
pub type Result<T> = std::result::Result<T, Error>;

use crate::PrintOption;

/// Errors returned by wry.
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -61,4 +63,6 @@ pub enum Error {
CustomProtocolTaskInvalid,
#[error("Failed to register URL scheme: {0}, could be due to invalid URL scheme or the scheme is already registered.")]
UrlSchemeRegisterError(String),
#[error("Invalid print option {0}")]
PrintOptionError(PrintOption),
}
42 changes: 41 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,42 @@ impl<'a> WebViewBuilderExtUnix<'a> for WebViewBuilder<'a> {
}
}

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// Print margins in millimeters
#[derive(Debug, Default, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PrintMargin {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}

/// The print options
///
/// When printing, multiple options can be passed to the print function causing it to alter the
/// printing behavior. If a backend does not support a print option, it can return the option as an
/// error using: `return Err(Error::PrintOptionError(opt.clone()))`
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PrintOption {
Silent(bool),
Margins(PrintMargin),
GeneratePDF {
filename: String
}
}

impl std::fmt::Display for PrintOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

impl std::error::Error for PrintOption {}

/// The fundamental type to present a [`WebView`].
///
/// [`WebViewBuilder`] / [`WebView`] are the basic building blocks to construct WebView contents and
Expand Down Expand Up @@ -1358,7 +1394,11 @@ impl WebView {

/// Launch print modal for the webview content.
pub fn print(&self) -> Result<()> {
self.webview.print()
self.webview.print_with_options(&[])
}

pub fn print_with_options(&self, options: &[PrintOption]) -> Result<()> {
self.webview.print_with_options(options)
}

/// Open the web inspector which is usually called dev tool.
Expand Down
36 changes: 32 additions & 4 deletions src/webkitgtk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub use web_context::WebContextImpl;

use crate::{
proxy::ProxyConfig, web_context::WebContext, Error, PageLoadEvent, Rect, Result,
WebViewAttributes, RGBA,
WebViewAttributes, RGBA, PrintOption
};

use self::web_context::WebContextExt;
Expand Down Expand Up @@ -555,9 +555,37 @@ impl InnerWebView {
is_inspector_open
}

pub fn print(&self) -> Result<()> {
let print = webkit2gtk::PrintOperation::new(&self.webview);
print.run_dialog(None::<&gtk::Window>);
pub fn print_with_options(&self, options: &[PrintOption]) -> Result<()> {
let page_setup = gtk::PageSetup::new();
let print_settings = gtk::PrintSettings::new();
let mut silent: bool = false;

for opt in options.iter() {
match opt {
PrintOption::Silent(s) => {
silent = *s
},
PrintOption::GeneratePDF { filename } => {
print_settings.set(gtk::PRINT_SETTINGS_OUTPUT_URI, Some(filename))
},
PrintOption::Margins(m) => {
page_setup.set_left_margin(f64::from(m.left), gtk::Unit::Mm);
page_setup.set_right_margin(f64::from(m.right), gtk::Unit::Mm);
page_setup.set_top_margin(f64::from(m.top), gtk::Unit::Mm);
page_setup.set_bottom_margin(f64::from(m.bottom), gtk::Unit::Mm);
}
}
}

let mut print = webkit2gtk::PrintOperation::builder();
print = print.web_view(&self.webview);
print = print.page_setup(&page_setup);

if silent {
print.build().print();
} else {
print.build().run_dialog(None::<&gtk::Window>);
}
Ok(())
}

Expand Down
6 changes: 5 additions & 1 deletion src/webview2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,11 @@ impl InnerWebView {
Ok(())
}

pub fn print(&self) -> Result<()> {
pub fn print_with_options(&self, options: &[PrintOption]) -> Result<()> {
for opt in options.iter() {
return Err(Error::PrintOptionError(opt.clone()))
}

self.eval(
"window.print()",
None::<Box<dyn FnOnce(String) + Send + 'static>>,
Expand Down
39 changes: 20 additions & 19 deletions src/wkwebview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use crate::{
navigation::{add_navigation_mathods, drop_navigation_methods, set_navigation_methods},
},
Error, PageLoadEvent, Rect, RequestAsyncResponder, Result, WebContext, WebViewAttributes, RGBA,
PrintOption, PrintMargin
};

use http::{
Expand All @@ -84,17 +85,8 @@ const NS_JSON_WRITING_FRAGMENTS_ALLOWED: u64 = 4;
static COUNTER: Counter = Counter::new();
static WEBVIEW_IDS: Lazy<Mutex<HashSet<u32>>> = Lazy::new(Default::default);

#[derive(Debug, Default, Copy, Clone)]
pub struct PrintMargin {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}

#[derive(Debug, Default, Clone)]
pub struct PrintOptions {
pub margins: PrintMargin,
fn mm_to_printer_points(mm: f32) -> f32 {
mm * 2.8452755906
}

pub(crate) struct InnerWebView {
Expand Down Expand Up @@ -1173,11 +1165,20 @@ r#"Object.defineProperty(window, 'ipc', {
}
}

pub fn print(&self) -> crate::Result<()> {
self.print_with_options(&PrintOptions::default())
}
pub fn print_with_options(&self, options: &[WebViewPrintOption]) -> Result<()> {
let mut margins: PrintMargin = PrintMargin::default();

for opt in options.iter() {
match opt {
PrintOption::Margins(m) => {
margins = m;
},
_ => {
return Err(Error::PrintOptionError(opt.clone()))
}
}
}

pub fn print_with_options(&self, options: &PrintOptions) -> crate::Result<()> {
// Safety: objc runtime calls are unsafe
#[cfg(target_os = "macos")]
unsafe {
Expand All @@ -1189,10 +1190,10 @@ r#"Object.defineProperty(window, 'ipc', {
// Create a shared print info
let print_info: id = msg_send![class!(NSPrintInfo), sharedPrintInfo];
let print_info: id = msg_send![print_info, init];
let () = msg_send![print_info, setTopMargin:CGFloat::from(options.margins.top)];
let () = msg_send![print_info, setRightMargin:CGFloat::from(options.margins.right)];
let () = msg_send![print_info, setBottomMargin:CGFloat::from(options.margins.bottom)];
let () = msg_send![print_info, setLeftMargin:CGFloat::from(options.margins.left)];
let () = msg_send![print_info, setTopMargin:CGFloat::from(mm_to_printer_points(margins.top))];
let () = msg_send![print_info, setRightMargin:CGFloat::from(mm_to_printer_points(margins.right))];
let () = msg_send![print_info, setBottomMargin:CGFloat::from(mm_to_printer_points(margins.bottom))];
let () = msg_send![print_info, setLeftMargin:CGFloat::from(mm_to_printer_points(margins.left))];
// Create new print operation from the webview content
let print_operation: id = msg_send![self.webview, printOperationWithPrintInfo: print_info];
// Allow the modal to detach from the current thread and be non-blocker
Expand Down

0 comments on commit 047d8cf

Please sign in to comment.