[librsvg: 1/2] support <a> links for PDF output
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/2] support <a> links for PDF output
- Date: Fri, 23 Feb 2018 20:06:18 +0000 (UTC)
commit 0b6297030db215a2cfebee55540e151e8d863afc
Author: Dmitry Kontsevoy <dmitry kontsevoy gmail com>
Date: Wed Feb 21 10:17:42 2018 +0300
support <a> links for PDF output
Makefile.am | 1 +
librsvg/rsvg-base.c | 2 +-
librsvg/rsvg-private.h | 1 +
librsvg/rsvg-structure.h | 4 ++
rsvg_internals/src/lib.rs | 5 ++
rsvg_internals/src/link.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++
rsvg_internals/src/node.rs | 1 +
7 files changed, 142 insertions(+), 1 deletion(-)
---
diff --git a/Makefile.am b/Makefile.am
index 72241dbd..a5a16220 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -82,6 +82,7 @@ RUST_SRC = \
rsvg_internals/src/image.rs \
rsvg_internals/src/length.rs \
rsvg_internals/src/lib.rs \
+ rsvg_internals/src/link.rs \
rsvg_internals/src/marker.rs \
rsvg_internals/src/mask.rs \
rsvg_internals/src/node.rs \
diff --git a/librsvg/rsvg-base.c b/librsvg/rsvg-base.c
index cb74f54f..94990400 100644
--- a/librsvg/rsvg-base.c
+++ b/librsvg/rsvg-base.c
@@ -263,7 +263,7 @@ typedef struct {
* Lines in comments are elements that we don't support.
*/
static const NodeCreator node_creators[] = {
- { "a", TRUE, rsvg_node_group_new }, /* treat anchors as groups for now */
+ { "a", TRUE, rsvg_node_link_new },
/* "altGlyph", TRUE, */
/* "altGlyphDef", FALSE, */
/* "altGlyphItem", FALSE, */
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index 3e557b37..a3c981b9 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -303,6 +303,7 @@ typedef enum {
RSVG_NODE_TYPE_LIGHT_SOURCE,
RSVG_NODE_TYPE_LINE,
RSVG_NODE_TYPE_LINEAR_GRADIENT,
+ RSVG_NODE_TYPE_LINK,
RSVG_NODE_TYPE_MARKER,
RSVG_NODE_TYPE_MASK,
RSVG_NODE_TYPE_PATH,
diff --git a/librsvg/rsvg-structure.h b/librsvg/rsvg-structure.h
index 356f448d..61a1c105 100644
--- a/librsvg/rsvg-structure.h
+++ b/librsvg/rsvg-structure.h
@@ -38,6 +38,10 @@ G_BEGIN_DECLS
G_GNUC_INTERNAL
RsvgNode *rsvg_node_group_new (const char *element_name, RsvgNode *parent);
+/* Implemented in rust/src/link.rs */
+G_GNUC_INTERNAL
+RsvgNode *rsvg_node_link_new (const char *element_name, RsvgNode *parent);
+
/* Implemented in rust/src/structure.rs */
G_GNUC_INTERNAL
RsvgNode *rsvg_node_defs_new (const char *element_name, RsvgNode *parent);
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 30e4ed52..aedebebf 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -73,6 +73,10 @@ pub use image::{
rsvg_node_image_new,
};
+pub use link::{
+ rsvg_node_link_new,
+};
+
pub use marker::{
rsvg_node_marker_new,
};
@@ -195,6 +199,7 @@ mod gradient;
mod handle;
mod image;
mod length;
+mod link;
mod marker;
mod mask;
mod node;
diff --git a/rsvg_internals/src/link.rs b/rsvg_internals/src/link.rs
new file mode 100644
index 00000000..cfcb546c
--- /dev/null
+++ b/rsvg_internals/src/link.rs
@@ -0,0 +1,129 @@
+use cairo;
+use cairo_sys;
+use glib::translate::*;
+use libc;
+
+use std::borrow::Cow;
+use std::cell::RefCell;
+use regex::{Regex, Captures};
+
+use attributes::Attribute;
+use drawing_ctx::{self, RsvgDrawingCtx};
+use handle::RsvgHandle;
+use node::*;
+use property_bag::PropertyBag;
+
+struct NodeLink {
+ link: RefCell<Option<String>>,
+}
+
+impl NodeLink {
+ fn new() -> NodeLink {
+ NodeLink { link: RefCell::new(None) }
+ }
+}
+
+impl NodeTrait for NodeLink {
+ fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
+ for (_key, attr, value) in pbag.iter() {
+ match attr {
+ Attribute::XlinkHref => *self.link.borrow_mut() = Some(value.to_owned()),
+
+ _ => (),
+ }
+ }
+
+ Ok(())
+ }
+
+ fn draw(&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
+ let link = self.link.borrow();
+
+ if link.is_some() && link.as_ref().unwrap() != "" {
+ const CAIRO_TAG_LINK: &str = "Link";
+
+ let attributes = link.as_ref().map(|i| format!("uri='{}'", escape_value(i)));
+
+ drawing_ctx::get_cairo_context(draw_ctx).with_tag(
+ CAIRO_TAG_LINK,
+ attributes.as_ref().map(|i| i.as_str()),
+ || node.draw_children(draw_ctx, dominate),
+ )
+ } else {
+ node.draw_children(draw_ctx, dominate)
+ }
+ }
+
+ fn get_c_impl(&self) -> *const RsvgCNodeImpl {
+ unreachable!();
+ }
+}
+
+/// escape quotes and backslashes with backslash
+fn escape_value(value: &str) -> Cow<str> {
+ lazy_static! {
+ static ref REGEX: Regex = Regex::new(r"['\\]").unwrap();
+ }
+
+ REGEX.replace_all(
+ value,
+ |caps: &Captures| match caps.get(0).unwrap().as_str() {
+ "'" => "\\'".to_owned(),
+ "\\" => "\\\\".to_owned(),
+ _ => unreachable!(),
+ },
+ )
+}
+
+extern "C" {
+ fn cairo_tag_begin(
+ cr: *mut cairo_sys::cairo_t,
+ tag_name: *const libc::c_char,
+ attibutes: *const libc::c_char,
+ );
+ fn cairo_tag_end(cr: *mut cairo_sys::cairo_t, tag_name: *const libc::c_char);
+}
+
+/// Bindings that aren't supported by `cairo-rs` for now
+trait CairoTagging {
+ fn tag_begin(&self, tag_name: &str, attributes: Option<&str>);
+ fn tag_end(&self, tag_name: &str);
+ fn with_tag<U, T>(&self, tag_name: &str, attributes: Option<&str>, f: U) -> T
+ where
+ U: Fn() -> T,
+ {
+ self.tag_begin(tag_name, attributes);
+ let result = f();
+ self.tag_end(tag_name);
+
+ result
+ }
+}
+
+impl CairoTagging for cairo::Context {
+ fn tag_begin(&self, tag_name: &str, attributes: Option<&str>) {
+ unsafe {
+ cairo_tag_begin(
+ self.to_glib_none().0,
+ tag_name.to_glib_none().0,
+ attributes.to_glib_none().0,
+ );
+ }
+ }
+
+ fn tag_end(&self, tag_name: &str) {
+ unsafe {
+ cairo_tag_end(self.to_glib_none().0, tag_name.to_glib_none().0);
+ }
+ }
+}
+
+/***** C Prototypes *****/
+
+#[no_mangle]
+pub extern "C" fn rsvg_node_link_new(
+ _: *const libc::c_char,
+ raw_parent: *const RsvgNode,
+) -> *const RsvgNode {
+ boxed_node_new(NodeType::Link, raw_parent, Box::new(NodeLink::new()))
+}
diff --git a/rsvg_internals/src/node.rs b/rsvg_internals/src/node.rs
index d3058c12..16718157 100644
--- a/rsvg_internals/src/node.rs
+++ b/rsvg_internals/src/node.rs
@@ -83,6 +83,7 @@ pub enum NodeType {
LightSource,
Line,
LinearGradient,
+ Link,
Marker,
Mask,
Path,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]