Commit 85d88d88 authored by Federico Mena Quintero's avatar Federico Mena Quintero

Merge branch 'pborelli/librsvg-draw-ctx'

parents a4ccc04a b0c74b91
......@@ -47,18 +47,21 @@ void rsvg_drawing_ctx_transformed_image_bounding_box (cairo_matrix_t *affine,
double *bbx, double *bby, double *bbw, double *bbh);
RsvgDrawingCtx *
rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle)
rsvg_drawing_ctx_new (cairo_t *cr,
guint width,
guint height,
double vb_width,
double vb_height,
double dpi_x,
double dpi_y,
RsvgDefs *defs,
gboolean testing)
{
RsvgDimensionData data;
RsvgDrawingCtx *draw;
cairo_matrix_t affine;
cairo_matrix_t scale;
double bbx, bby, bbw, bbh;
rsvg_handle_get_dimensions (handle, &data);
if (data.width == 0 || data.height == 0)
return NULL;
draw = g_new0 (RsvgDrawingCtx, 1);
cairo_get_matrix (cr, &affine);
......@@ -66,8 +69,7 @@ rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle)
/* find bounding box of image as transformed by the current cairo context
* The size of this bounding box determines the size of the intermediate
* surfaces allocated during drawing. */
rsvg_drawing_ctx_transformed_image_bounding_box (&affine,
data.width, data.height,
rsvg_drawing_ctx_transformed_image_bounding_box (&affine, width, height,
&bbx, &bby, &bbw, &bbh);
draw->initial_cr = cr;
......@@ -80,18 +82,18 @@ rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle)
draw->rect.width = bbw;
draw->rect.height = bbh;
draw->defs = handle->priv->defs;
draw->dpi_x = handle->priv->dpi_x;
draw->dpi_y = handle->priv->dpi_y;
draw->vb.rect.width = data.em;
draw->vb.rect.height = data.ex;
draw->defs = defs;
draw->dpi_x = dpi_x;
draw->dpi_y = dpi_y;
draw->vb.rect.width = vb_width;
draw->vb.rect.height = vb_height;
draw->vb_stack = NULL;
draw->drawsub_stack = NULL;
draw->acquired_nodes = NULL;
draw->is_testing = handle->priv->is_testing;
draw->is_testing = testing;
/* scale according to size set by size_func callback */
cairo_matrix_init_scale (&scale, data.width / data.em, data.height / data.ex);
cairo_matrix_init_scale (&scale, width / vb_width, height / vb_height);
cairo_matrix_multiply (&affine, &affine, &scale);
/* adjust transform so that the corner of the bounding box above is
......@@ -131,24 +133,6 @@ rsvg_drawing_ctx_get_cairo_context (RsvgDrawingCtx *ctx)
return ctx->cr;
}
/* FIXME: Usage of this function is more less a hack. Some code does this:
*
* save_cr = rsvg_drawing_ctx_get_cairo_context (ctx);
*
* some_surface = create_surface ();
*
* cr = cairo_create (some_surface);
*
* rsvg_drawing_ctx_set_cairo_context (ctx, cr);
*
* ... draw with ctx but to that temporary surface
*
* rsvg_drawing_ctx_set_cairo_context (ctx, save_cr);
*
* It would be better to have an explicit push/pop for the cairo_t, or
* pushing a temporary surface, or something that does not involve
* monkeypatching the cr directly.
*/
void
rsvg_drawing_ctx_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr)
{
......@@ -263,44 +247,6 @@ rsvg_drawing_ctx_acquire_node (RsvgDrawingCtx *ctx, const char *url)
return node;
}
/**
* rsvg_drawing_ctx_acquire_node_of_type:
* @ctx: The drawing context in use
* @url: The IRI to lookup
* @type: Type which the node must have
*
* Use this function when looking up urls to other nodes, and when you expect
* the node to be of a particular type. This function does proper recursion
* checking and thereby avoids infinite loops.
*
* Malformed SVGs, for example, may reference a marker by its IRI, but
* the object referenced by the IRI is not a marker.
*
* Nodes acquired by this function must be released using
* rsvg_drawing_ctx_release_node() in reverse acquiring order.
*
* Note that if you acquire a node, you have to release it before trying to
* acquire it again. If you acquire a node "#foo" and don't release it before
* trying to acquire "foo" again, you will obtain a %NULL the second time.
*
* Returns: The node referenced by @url or %NULL if the @url
* does not reference a node. Also returns %NULL if
* the node referenced by @url is not of the specified @type.
*/
RsvgNode *
rsvg_drawing_ctx_acquire_node_of_type (RsvgDrawingCtx *ctx, const char *url, RsvgNodeType type)
{
RsvgNode *node;
node = rsvg_drawing_ctx_acquire_node (ctx, url);
if (node == NULL || rsvg_node_get_type (node) != type) {
rsvg_drawing_ctx_release_node (ctx, node);
return NULL;
}
return node;
}
/*
* rsvg_drawing_ctx_release_node:
* @ctx: The drawing context the node was acquired from
......
......@@ -38,7 +38,6 @@ struct RsvgDrawingCtx {
cairo_t *initial_cr;
GList *cr_stack;
GList *surfaces_stack;
GError **error;
RsvgDefs *defs;
double dpi_x, dpi_y;
cairo_rectangle_t rect;
......@@ -52,7 +51,15 @@ struct RsvgDrawingCtx {
};
G_GNUC_INTERNAL
RsvgDrawingCtx *rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle);
RsvgDrawingCtx *rsvg_drawing_ctx_new (cairo_t *cr,
guint width,
guint height,
double vb_width,
double vb_height,
double dpi_x,
double dpi_y,
RsvgDefs *defs,
gboolean testing);
G_GNUC_INTERNAL
void rsvg_drawing_ctx_free (RsvgDrawingCtx *draw_ctx);
......
......@@ -788,6 +788,7 @@ rsvg_handle_cascade (RsvgHandle *handle)
gboolean
rsvg_handle_render_cairo_sub (RsvgHandle * handle, cairo_t * cr, const char *id)
{
RsvgDimensionData dimensions;
RsvgDrawingCtx *draw;
RsvgNode *drawsub = NULL;
cairo_status_t status;
......@@ -815,10 +816,17 @@ rsvg_handle_render_cairo_sub (RsvgHandle * handle, cairo_t * cr, const char *id)
return FALSE;
}
draw = rsvg_drawing_ctx_new (cr, handle);
if (!draw)
rsvg_handle_get_dimensions (handle, &dimensions);
if (dimensions.width == 0 || dimensions.height == 0)
return FALSE;
draw = rsvg_drawing_ctx_new (cr,
dimensions.width, dimensions.height,
dimensions.em, dimensions.ex,
handle->priv->dpi_x, handle->priv->dpi_y,
handle->priv->defs,
handle->priv->is_testing);
rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, drawsub);
cairo_save (cr);
......@@ -932,21 +940,24 @@ rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimensi
}
if (handle_subelement == TRUE) {
RsvgDimensionData dimensions;
RsvgBbox *bbox;
cairo_rectangle_t ink_rect;
rsvg_handle_get_dimensions (handle, &dimensions);
if (dimensions.width == 0 || dimensions.height == 0)
return FALSE;
target = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
1, 1);
cr = cairo_create (target);
draw = rsvg_drawing_ctx_new (cr, handle);
if (!draw) {
cairo_destroy (cr);
cairo_surface_destroy (target);
return FALSE;
}
draw = rsvg_drawing_ctx_new (cr,
dimensions.width, dimensions.height,
dimensions.em, dimensions.ex,
handle->priv->dpi_x, handle->priv->dpi_y,
handle->priv->defs,
handle->priv->is_testing);
g_assert (sself != NULL);
rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, sself);
......@@ -996,12 +1007,12 @@ rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_d
{
RsvgDrawingCtx *draw;
RsvgNode *node;
RsvgDimensionData dimension_data;
RsvgDimensionData dimensions;
RsvgBbox *bbox;
cairo_rectangle_t ink_rect;
cairo_surface_t *target = NULL;
cairo_t *cr = NULL;
gboolean ret = FALSE;
int width, height;
g_return_val_if_fail (handle, FALSE);
g_return_val_if_fail (position_data, FALSE);
......@@ -1017,23 +1028,31 @@ rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_d
}
memset (position_data, 0, sizeof (*position_data));
memset (&dimension_data, 0, sizeof (dimension_data));
node = rsvg_defs_lookup (handle->priv->defs, id);
if (!node) {
if (!node)
return FALSE;
} else if (rsvg_node_is_same (node, handle->priv->treebase)) {
if (rsvg_node_is_same (node, handle->priv->treebase)) {
/* Root node. */
position_data->x = 0;
position_data->y = 0;
return TRUE;
}
rsvg_handle_get_dimensions (handle, &dimensions);
if (dimensions.width == 0 || dimensions.height == 0)
return FALSE;
target = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
cr = cairo_create (target);
draw = rsvg_drawing_ctx_new (cr, handle);
if (!draw)
goto bail;
draw = rsvg_drawing_ctx_new (cr,
dimensions.width, dimensions.height,
dimensions.em, dimensions.ex,
handle->priv->dpi_x, handle->priv->dpi_y,
handle->priv->defs,
handle->priv->is_testing);
g_assert (node != NULL);
rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, node);
......@@ -1046,24 +1065,17 @@ rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_d
position_data->x = ink_rect.x;
position_data->y = ink_rect.y;
dimension_data.width = ink_rect.width;
dimension_data.height = ink_rect.height;
dimension_data.em = dimension_data.width;
dimension_data.ex = dimension_data.height;
if (handle->priv->size_func)
(*handle->priv->size_func) (&dimension_data.width, &dimension_data.height,
handle->priv->user_data);
width = ink_rect.width;
height = ink_rect.height;
ret = TRUE;
if (handle->priv->size_func)
(*handle->priv->size_func) (&width, &height, handle->priv->user_data);
bail:
if (cr)
cairo_destroy (cr);
if (target)
cairo_surface_destroy (target);
cairo_destroy (cr);
cairo_surface_destroy (target);
return ret;
return TRUE;
}
/**
......
......@@ -54,12 +54,6 @@ extern "C" {
url: *const libc::c_char,
) -> *mut RsvgNode;
fn rsvg_drawing_ctx_acquire_node_of_type(
draw_ctx: *const RsvgDrawingCtx,
url: *const libc::c_char,
node_type: NodeType,
) -> *mut RsvgNode;
fn rsvg_drawing_ctx_release_node(draw_ctx: *const RsvgDrawingCtx, node: *mut RsvgNode);
fn rsvg_drawing_ctx_get_offset(
......@@ -94,6 +88,11 @@ pub fn get_cairo_context(draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
}
}
// FIXME: Usage of this function is more less a hack... The caller
// manually saves and then restore the draw_ctx.cr.
// It would be better to have an explicit push/pop for the cairo_t, or
// pushing a temporary surface, or something that does not involve
// monkeypatching the cr directly.
pub fn set_cairo_context(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
unsafe {
let raw_cr = cr.to_glib_none().0;
......@@ -146,20 +145,28 @@ pub fn get_acquired_node(draw_ctx: *const RsvgDrawingCtx, url: &str) -> Option<A
}
}
// Use this function when looking up urls to other nodes, and when you expect
// the node to be of a particular type. This function does proper recursion
// checking and thereby avoids infinite loops.
//
// Malformed SVGs, for example, may reference a marker by its IRI, but
// the object referenced by the IRI is not a marker.
//
// Note that if you acquire a node, you have to release it before trying to
// acquire it again. If you acquire a node "#foo" and don't release it before
// trying to acquire "foo" again, you will obtain a None the second time.
pub fn get_acquired_node_of_type(
draw_ctx: *const RsvgDrawingCtx,
url: &str,
node_type: NodeType,
) -> Option<AcquiredNode> {
let raw_node = unsafe {
rsvg_drawing_ctx_acquire_node_of_type(draw_ctx, str::to_glib_none(url).0, node_type)
};
if raw_node.is_null() {
None
} else {
Some(AcquiredNode(draw_ctx, raw_node))
if let Some(acquired) = get_acquired_node(draw_ctx, url) {
if acquired.get().get_type() == node_type {
return Some(acquired);
}
}
None
}
pub fn push_discrete_layer(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues, clipping: bool) {
......
......@@ -1454,7 +1454,7 @@ pub extern "C" fn rsvg_parse_style_attrs(
// Sets the node's state from the attributes in the pbag. Also
// applies CSS rules in our limited way based on the node's
// tag/klazz/id.
fn parse_style_attrs(
pub fn parse_style_attrs(
handle: *const RsvgHandle,
node: &RsvgNode,
tag: &str,
......
use glib::translate::*;
use libc;
use std::cell::Cell;
......@@ -14,7 +13,7 @@ use length::*;
use node::*;
use parsers::{parse, Parse};
use property_bag::{OwnedPropertyBag, PropertyBag};
use state::Overflow;
use state::{self, Overflow};
use util::utf8_cstr_opt;
use viewbox::*;
use viewport::{draw_in_viewport, ClipMode};
......@@ -533,18 +532,6 @@ pub extern "C" fn rsvg_node_svg_get_view_box(raw_node: *const RsvgNode) -> RsvgV
RsvgViewBox::from(vbox)
}
#[allow(improper_ctypes)]
extern "C" {
fn rsvg_parse_style_attrs(
handle: *const RsvgHandle,
node: *const RsvgNode,
tag: *const libc::c_char,
class: *const libc::c_char,
id: *const libc::c_char,
pbag: *const PropertyBag,
);
}
#[no_mangle]
pub extern "C" fn rsvg_node_svg_apply_atts(raw_node: *const RsvgNode, handle: *const RsvgHandle) {
assert!(!raw_node.is_null());
......@@ -567,19 +554,7 @@ pub extern "C" fn rsvg_node_svg_apply_atts(raw_node: *const RsvgNode, handle: *c
}
}
let c_class = class.to_glib_none();
let c_id = id.to_glib_none();
unsafe {
rsvg_parse_style_attrs(
handle,
raw_node,
str::to_glib_none("svg").0,
c_class.0,
c_id.0,
pbag.ffi(),
);
}
state::parse_style_attrs(handle, node, "svg", class, id, &pbag);
}
});
}
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