Add link handling
This commit is contained in:
139
src/lib.rs
139
src/lib.rs
@@ -1,15 +1,17 @@
|
||||
use std::{
|
||||
cmp::{max, min},
|
||||
ffi::{CStr, OsStr, c_void},
|
||||
ffi::{CStr, CString, OsStr, c_void},
|
||||
fs,
|
||||
os::unix::ffi::OsStrExt,
|
||||
path::Path,
|
||||
ptr::NonNull,
|
||||
ptr::{self, NonNull},
|
||||
slice,
|
||||
};
|
||||
|
||||
use ::typst::{
|
||||
Document,
|
||||
layout::{Abs, FrameItem, Page, Point, Rect},
|
||||
model::Destination,
|
||||
text::{Glyph, TextItem},
|
||||
};
|
||||
use cairo::{Format, ImageSurface};
|
||||
@@ -17,11 +19,7 @@ use cairo::{Format, ImageSurface};
|
||||
use crate::{
|
||||
typst::FrameItemIterator,
|
||||
zathura::{
|
||||
ZathuraResult, cairo_t, girara_list_append, girara_list_new_with_free, girara_list_t,
|
||||
zathura_document_get_data, zathura_document_get_path, zathura_document_s,
|
||||
zathura_document_set_data, zathura_document_set_number_of_pages, zathura_page_get_document,
|
||||
zathura_page_get_index, zathura_page_set_data, zathura_page_set_height,
|
||||
zathura_page_set_width, zathura_page_t, zathura_rectangle_s,
|
||||
cairo_t, girara_list_t, zathura_document_get_data, zathura_document_get_path, zathura_document_s, zathura_document_set_data, zathura_document_set_number_of_pages, zathura_link_destination_type_e_ZATHURA_LINK_DESTINATION_UNKNOWN, zathura_link_destination_type_e_ZATHURA_LINK_DESTINATION_XYZ, zathura_link_free, zathura_link_new, zathura_link_target_s, zathura_link_type_e_ZATHURA_LINK_GOTO_DEST, zathura_link_type_e_ZATHURA_LINK_GOTO_REMOTE, zathura_link_type_e_ZATHURA_LINK_URI, zathura_page_get_document, zathura_page_get_index, zathura_page_set_data, zathura_page_set_height, zathura_page_set_width, zathura_page_t, zathura_rectangle_s, GiraraList, ZathuraResult
|
||||
},
|
||||
};
|
||||
|
||||
@@ -42,17 +40,17 @@ pub static zathura_plugin_6_7: zathura::zathura_plugin_definition_s =
|
||||
functions: zathura::zathura_plugin_functions_s {
|
||||
document_open: Some(document_open),
|
||||
document_free: Some(document_free),
|
||||
document_index_generate: None,
|
||||
document_index_generate: None, // TODO?
|
||||
document_save_as: Some(document_save_as),
|
||||
document_attachments_get: None,
|
||||
document_attachment_save: None,
|
||||
document_get_information: None,
|
||||
document_get_information: None, // TODO
|
||||
page_init: Some(page_init),
|
||||
page_clear: Some(page_clear),
|
||||
page_search_text: None,
|
||||
page_links_get: None,
|
||||
page_search_text: None, // TODO?
|
||||
page_links_get: Some(page_links_get),
|
||||
page_form_fields_get: None,
|
||||
page_images_get: None,
|
||||
page_images_get: None, // TODO?
|
||||
page_image_get_cairo: None,
|
||||
page_get_text: Some(page_get_text),
|
||||
page_get_selection: Some(page_get_selection),
|
||||
@@ -232,7 +230,6 @@ fn selected_glyphs(
|
||||
}))
|
||||
})
|
||||
.filter_map(move |(point, glyph)| {
|
||||
dbg!(&item.text[glyph.range()]);
|
||||
let bbox = item
|
||||
.font
|
||||
.ttf()
|
||||
@@ -326,30 +323,108 @@ unsafe extern "C" fn page_get_selection(
|
||||
}
|
||||
});
|
||||
|
||||
unsafe extern "C" fn drop_rect(data: *mut c_void) {
|
||||
drop(unsafe { Box::from_raw(data as *mut zathura_rectangle_s) });
|
||||
}
|
||||
*res = ZathuraResult::OK;
|
||||
rects
|
||||
.map(zathura_rectangle_s::from)
|
||||
.collect::<GiraraList<zathura_rectangle_s>>()
|
||||
.into_raw()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn page_links_get(
|
||||
zpage: *mut zathura_page_t,
|
||||
page: *mut c_void,
|
||||
res: *mut ZathuraResult,
|
||||
) -> *mut girara_list_t {
|
||||
let res = if let Some(mut r) = NonNull::new(res) {
|
||||
unsafe {
|
||||
r.write(ZathuraResult::Unknown);
|
||||
r.as_mut()
|
||||
}
|
||||
} else {
|
||||
&mut ZathuraResult::OK
|
||||
};
|
||||
let doc = unsafe {
|
||||
&mut (*(zathura_document_get_data(zathura_page_get_document(zpage)) as *mut TypstDocument))
|
||||
};
|
||||
|
||||
let page: &Page = unsafe { &*(page as *const _) };
|
||||
|
||||
let links = FrameItemIterator::new(&page.frame)
|
||||
.filter_map(|(point, item)| {
|
||||
if let FrameItem::Link(dst, size) = item {
|
||||
Some((Rect::from_pos_size(point, *size), dst))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|(rect, dst)| {
|
||||
let (ty, target) = match dst {
|
||||
Destination::Url(url) => (
|
||||
if url.starts_with("file://") {
|
||||
zathura_link_type_e_ZATHURA_LINK_GOTO_REMOTE
|
||||
} else {
|
||||
zathura_link_type_e_ZATHURA_LINK_URI
|
||||
},
|
||||
zathura_link_target_s {
|
||||
destination_type:
|
||||
zathura_link_destination_type_e_ZATHURA_LINK_DESTINATION_UNKNOWN,
|
||||
value: doc
|
||||
.cstring_cache
|
||||
.entry(url.to_string())
|
||||
.or_insert_with(|| {
|
||||
CString::new(url.as_bytes()).expect("URL shouldn't contain NUL")
|
||||
})
|
||||
.as_ptr() as *mut i8,
|
||||
page_number: 0,
|
||||
left: -1.,
|
||||
right: -1.,
|
||||
top: -1.,
|
||||
bottom: -1.,
|
||||
zoom: 0.,
|
||||
},
|
||||
),
|
||||
Destination::Position(position) => (
|
||||
zathura_link_type_e_ZATHURA_LINK_GOTO_DEST,
|
||||
zathura_link_target_s {
|
||||
destination_type:
|
||||
zathura_link_destination_type_e_ZATHURA_LINK_DESTINATION_XYZ,
|
||||
value: ptr::null_mut(),
|
||||
page_number: position.page.get() as u32 - 1,
|
||||
left: position.point.x.to_pt(),
|
||||
right: -1.,
|
||||
top: position.point.y.to_pt(),
|
||||
bottom: -1.,
|
||||
zoom: 0.,
|
||||
},
|
||||
),
|
||||
Destination::Location(location) => {
|
||||
let position = doc.doc.introspector().position(*location);
|
||||
(
|
||||
zathura_link_type_e_ZATHURA_LINK_GOTO_DEST,
|
||||
zathura_link_target_s {
|
||||
destination_type:
|
||||
zathura_link_destination_type_e_ZATHURA_LINK_DESTINATION_XYZ,
|
||||
value: ptr::null_mut(),
|
||||
page_number: position.page.get() as u32 - 1,
|
||||
left: position.point.x.to_pt(),
|
||||
right: -1.,
|
||||
top: position.point.y.to_pt(),
|
||||
bottom: -1.,
|
||||
zoom: 0.,
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
unsafe { zathura_link_new(ty, rect.into(), target) }
|
||||
});
|
||||
|
||||
unsafe {
|
||||
let list = girara_list_new_with_free(Some(drop_rect));
|
||||
|
||||
for rect in rects {
|
||||
girara_list_append(
|
||||
list,
|
||||
Box::into_raw(Box::new(zathura_rectangle_s {
|
||||
x1: rect.min.x.to_pt(),
|
||||
y1: rect.min.y.to_pt(),
|
||||
x2: rect.max.x.to_pt(),
|
||||
y2: rect.max.y.to_pt(),
|
||||
})) as *mut _,
|
||||
);
|
||||
}
|
||||
|
||||
let mut links_ = GiraraList::new_with_free(zathura_link_free);
|
||||
links_.extend_allocated(links);
|
||||
*res = ZathuraResult::OK;
|
||||
list
|
||||
links_.into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: render warnings
|
||||
// TODO: link/... handling
|
||||
// TODO: better caching
|
||||
|
||||
Reference in New Issue
Block a user