image.rs: Move NodeImage over to Rust. Yay!

parent c058eb67
......@@ -79,6 +79,7 @@ RUST_SOURCES = \
rust/src/error.rs \
rust/src/gradient.rs \
rust/src/handle.rs \
rust/src/image.rs \
rust/src/length.rs \
rust/src/lib.rs \
rust/src/marker.rs \
......
......@@ -316,7 +316,7 @@ static const NodeCreator node_creators[] = {
/* "glyph", TRUE, */
/* "glyphRef", TRUE, */
/* "hkern", FALSE, */
{ "image", TRUE, rsvg_new_image },
{ "image", TRUE, rsvg_node_image_new },
{ "line", TRUE, rsvg_node_line_new },
{ "linearGradient", TRUE, rsvg_node_linear_gradient_new },
{ "marker", TRUE, rsvg_node_marker_new },
......@@ -336,7 +336,7 @@ static const NodeCreator node_creators[] = {
{ "stop", TRUE, rsvg_node_stop_new },
/* "style", FALSE, */
{ "subImage", FALSE, rsvg_node_group_new },
{ "subImageRef", FALSE, rsvg_new_image },
{ "subImageRef", FALSE, rsvg_node_image_new },
{ "svg", TRUE, rsvg_node_svg_new },
{ "switch", TRUE, rsvg_node_switch_new },
{ "symbol", TRUE, rsvg_node_symbol_new },
......
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 sts=4 expandtab: */
/*
rsvg-image.c: Image loading and displaying
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002, 2003, 2004, 2005 Dom Lachowicz <cinamod@hotmail.com>
Copyright (C) 2003, 2004, 2005 Caleb Moore <c.moore@student.unsw.edu.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors: Raph Levien <raph@artofcode.com>,
Dom Lachowicz <cinamod@hotmail.com>,
Caleb Moore <c.moore@student.unsw.edu.au>
*/
#include "config.h"
#include "rsvg-image.h"
#include <string.h>
#include <math.h>
#include <errno.h>
#include "rsvg-css.h"
#include "rsvg-io.h"
#include "rsvg-styles.h"
cairo_surface_t *
rsvg_cairo_surface_new_from_href (RsvgHandle *handle,
const char *href,
GError **error)
{
char *data;
gsize data_len;
char *mime_type = NULL;
GdkPixbufLoader *loader = NULL;
GdkPixbuf *pixbuf = NULL;
cairo_surface_t *surface = NULL;
data = _rsvg_handle_acquire_data (handle, href, &mime_type, &data_len, error);
if (data == NULL)
return NULL;
if (mime_type) {
loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, error);
} else {
loader = gdk_pixbuf_loader_new ();
}
if (loader == NULL)
goto out;
if (!gdk_pixbuf_loader_write (loader, (guchar *) data, data_len, error)) {
gdk_pixbuf_loader_close (loader, NULL);
goto out;
}
if (!gdk_pixbuf_loader_close (loader, error))
goto out;
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
if (!pixbuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
_("Failed to load image '%s': reason not known, probably a corrupt image file"),
href);
goto out;
}
surface = rsvg_cairo_surface_from_pixbuf (pixbuf);
if (mime_type == NULL) {
/* Try to get the information from the loader */
GdkPixbufFormat *format;
char **mime_types;
if ((format = gdk_pixbuf_loader_get_format (loader)) != NULL) {
mime_types = gdk_pixbuf_format_get_mime_types (format);
if (mime_types != NULL)
mime_type = g_strdup (mime_types[0]);
g_strfreev (mime_types);
}
}
if ((handle->priv->flags & RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA) != 0 &&
mime_type != NULL &&
cairo_surface_set_mime_data (surface, mime_type, (guchar *) data,
data_len, g_free, data) == CAIRO_STATUS_SUCCESS) {
data = NULL; /* transferred to the surface */
}
out:
if (loader)
g_object_unref (loader);
g_free (mime_type);
g_free (data);
return surface;
}
static void
rsvg_node_image_free (gpointer impl)
{
RsvgNodeImage *image = impl;
if (image->surface)
cairo_surface_destroy (image->surface);
g_free (image);
}
static void
rsvg_node_image_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
{
RsvgNodeImage *z = impl;
RsvgState *state;
unsigned int aspect_ratio = z->preserve_aspect_ratio;
gdouble x, y, w, h;
cairo_surface_t *surface = z->surface;
if (surface == NULL)
return;
x = rsvg_length_normalize (&z->x, ctx);
y = rsvg_length_normalize (&z->y, ctx);
w = rsvg_length_normalize (&z->w, ctx);
h = rsvg_length_normalize (&z->h, ctx);
state = rsvg_node_get_state (node);
rsvg_state_reinherit_top (ctx, state, dominate);
rsvg_push_discrete_layer (ctx);
if (!rsvg_current_state (ctx)->overflow && (aspect_ratio & RSVG_ASPECT_RATIO_SLICE)) {
rsvg_drawing_ctx_add_clipping_rect (ctx, x, y, w, h);
}
rsvg_aspect_ratio_compute (aspect_ratio,
(double) cairo_image_surface_get_width (surface),
(double) cairo_image_surface_get_height (surface),
&x, &y, &w, &h);
rsvg_render_surface (ctx, surface, x, y, w, h);
rsvg_pop_discrete_layer (ctx);
}
static void
rsvg_node_image_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
{
RsvgNodeImage *image = impl;
const char *value;
if ((value = rsvg_property_bag_lookup (atts, "x")))
image->x = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
if ((value = rsvg_property_bag_lookup (atts, "y")))
image->y = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
if ((value = rsvg_property_bag_lookup (atts, "width")))
image->w = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
if ((value = rsvg_property_bag_lookup (atts, "height")))
image->h = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
/* path is used by some older adobe illustrator versions */
if ((value = rsvg_property_bag_lookup (atts, "path"))
|| (value = rsvg_property_bag_lookup (atts, "xlink:href"))) {
image->surface = rsvg_cairo_surface_new_from_href (handle,
value,
NULL);
if (!image->surface) {
#ifdef G_ENABLE_DEBUG
g_warning ("Couldn't load image: %s\n", value);
#endif
}
}
if ((value = rsvg_property_bag_lookup (atts, "preserveAspectRatio")))
image->preserve_aspect_ratio = rsvg_aspect_ratio_parse (value);
}
RsvgNode *
rsvg_new_image (const char *element_name, RsvgNode *parent)
{
RsvgNodeImage *image;
image = g_new0 (RsvgNodeImage, 1);
image->surface = NULL;
image->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
image->x = image->y = image->w = image->h = rsvg_length_parse ("0", LENGTH_DIR_BOTH);
return rsvg_rust_cnode_new (RSVG_NODE_TYPE_IMAGE,
parent,
rsvg_state_new (),
image,
rsvg_node_image_set_atts,
rsvg_node_image_draw,
rsvg_node_image_free);
}
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 sts=4 expandtab: */
/*
rsvg-image.h: Image loading and displaying
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002, 2003, 2004, 2005 Dom Lachowicz <cinamod@hotmail.com>
Copyright (C) 2003, 2004, 2005 Caleb Moore <c.moore@student.unsw.edu.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors: Raph Levien <raph@artofcode.com>,
Dom Lachowicz <cinamod@hotmail.com>,
Caleb Moore <c.moore@student.unsw.edu.au>
*/
#ifndef RSVG_IMAGE_H
#define RSVG_IMAGE_H
#include "rsvg-structure.h"
#include <cairo.h>
G_BEGIN_DECLS
G_GNUC_INTERNAL
RsvgNode *rsvg_new_image (const char *element_name, RsvgNode *parent);
typedef struct _RsvgNodeImage RsvgNodeImage;
struct _RsvgNodeImage {
guint32 preserve_aspect_ratio;
RsvgLength x, y, w, h;
cairo_surface_t *surface; /* a cairo image surface */
};
G_GNUC_INTERNAL
cairo_surface_t *rsvg_cairo_surface_new_from_href (RsvgHandle *handle, const char *href, GError ** error);
G_END_DECLS
#endif /* RSVG_IMAGE_H */
use libc;
use cairo;
use cairo_sys;
use glib;
use glib::translate::*;
use glib_sys;
use std::cell::{Cell, RefCell};
use std::ptr;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use aspect_ratio::*;
use handle::RsvgHandle;
use length::*;
use node::*;
use property_bag;
use property_bag::RsvgPropertyBag;
struct NodeImage {
aspect: Cell<AspectRatio>,
x: Cell<RsvgLength>,
y: Cell<RsvgLength>,
w: Cell<RsvgLength>,
h: Cell<RsvgLength>,
surface: RefCell<Option<cairo::ImageSurface>>
}
impl NodeImage {
fn new () -> NodeImage {
NodeImage {
aspect: Cell::new (AspectRatio::default ()),
x: Cell::new (RsvgLength::default ()),
y: Cell::new (RsvgLength::default ()),
w: Cell::new (RsvgLength::default ()),
h: Cell::new (RsvgLength::default ()),
surface: RefCell::new (None)
}
}
}
impl NodeTrait for NodeImage {
fn set_atts (&self, _: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
self.x.set (property_bag::parse_or_default (pbag, "x", LengthDir::Horizontal, None)?);
self.y.set (property_bag::parse_or_default (pbag, "y", LengthDir::Vertical, None)?);
self.w.set (property_bag::parse_or_default (pbag, "width", LengthDir::Horizontal,
Some(RsvgLength::check_nonnegative))?);
self.h.set (property_bag::parse_or_default (pbag, "height", LengthDir::Vertical,
Some(RsvgLength::check_nonnegative))?);
self.aspect.set (property_bag::parse_or_default (pbag, "preserveAspectRatio", (), None)?);
let mut href = property_bag::lookup (pbag, "xlink:href");
if href.is_none() {
// "path" is used by some older adobe illustrator versions
href = property_bag::lookup (pbag, "path");
}
if let Some(href) = href {
extern "C" { fn rsvg_cairo_surface_new_from_href
(handle: *const RsvgHandle,
href: *const libc::c_char,
error: *mut *mut glib_sys::GError) -> *mut cairo_sys::cairo_surface_t;
}
let mut error = ptr::null_mut();
let raw_surface = unsafe { rsvg_cairo_surface_new_from_href (handle,
href.to_glib_none().0,
&mut error) };
if !raw_surface.is_null() {
*self.surface.borrow_mut() = Some(unsafe { cairo::ImageSurface::from_raw_full (raw_surface).unwrap() });
} else {
let _: glib::Error = unsafe { from_glib_full(error) }; // FIXME: we should note that the image couldn't be loaded
}
}
Ok (())
}
fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
if let Some(ref surface) = *self.surface.borrow() {
let x = self.x.get().normalize(draw_ctx);
let y = self.y.get().normalize(draw_ctx);
let w = self.w.get().normalize(draw_ctx);
let h = self.h.get().normalize(draw_ctx);
let state = node.get_state();
drawing_ctx::state_reinherit_top(draw_ctx, state, dominate);
drawing_ctx::push_discrete_layer(draw_ctx);
let aspect = self.aspect.get();
if !drawing_ctx::state_is_overflow(state) {
match aspect.align {
Align::Aligned { align: _,
fit: FitMode::Slice } => {
drawing_ctx::add_clipping_rect(draw_ctx, x, y, w, h);
},
_ => ()
}
}
let (x, y, w, h) = aspect.compute (surface.get_width() as f64,
surface.get_height() as f64,
x, y, w, h);
drawing_ctx::render_surface(draw_ctx, &surface, x, y, w, h);
drawing_ctx::pop_discrete_layer(draw_ctx);
}
}
fn get_c_impl (&self) -> *const RsvgCNodeImpl {
unreachable! ();
}
}
#[no_mangle]
pub extern fn rsvg_node_image_new (_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
boxed_node_new (NodeType::Image,
raw_parent,
Box::new (NodeImage::new ()))
}
......@@ -50,6 +50,10 @@ pub use length::{
rsvg_length_hand_normalize,
};
pub use image::{
rsvg_node_image_new,
};
pub use marker::{
rsvg_node_marker_new,
};
......@@ -132,6 +136,7 @@ mod drawing_ctx;
mod error;
mod gradient;
mod handle;
mod image;
mod length;
mod marker;
mod node;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment