Commit 340a2635 authored by Federico Mena Quintero's avatar Federico Mena Quintero

Merge branch 'pborelli/librsvg-cleanup'

parents 0133a696 184c10cb
......@@ -25,16 +25,15 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
librsvg/librsvg-features.c \
librsvg/librsvg-features.h \
librsvg/rsvg-attributes.h \
librsvg/rsvg-base-file-util.c \
librsvg/rsvg-base.c \
librsvg/rsvg-cairo.h \
librsvg/rsvg-css.h \
librsvg/rsvg-file-util.c \
librsvg/rsvg-handle.c \
librsvg/rsvg-io.c \
librsvg/rsvg-io.h \
librsvg/rsvg-load.c \
librsvg/rsvg-load.h \
librsvg/rsvg-pixbuf.c \
librsvg/rsvg-private.h \
librsvg/rsvg-size-callback.c \
librsvg/rsvg-size-callback.h \
......
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 sts=4 expandtab: */
/*
rsvg-file-util.c: SAX-based renderer for SVG files into a GdkPixbuf.
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002 Dom Lachowicz <cinamod@hotmail.com>
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.
Author: Raph Levien <raph@artofcode.com>
*/
#include "config.h"
#include "rsvg-private.h"
#include "rsvg-io.h"
static gboolean
rsvg_handle_fill_with_data (RsvgHandle * handle,
const char * data, gsize data_len, GError ** error)
{
gboolean rv;
rsvg_return_val_if_fail (data != NULL, FALSE, error);
rsvg_return_val_if_fail (data_len != 0, FALSE, error);
rv = rsvg_handle_write (handle, (guchar *) data, data_len, error);
return rsvg_handle_close (handle, rv ? error : NULL) && rv;
}
/**
* rsvg_handle_new_from_data:
* @data: (array length=data_len): The SVG data
* @data_len: The length of @data, in bytes
* @error: return location for errors
*
* Loads the SVG specified by @data.
*
* Returns: A #RsvgHandle or %NULL if an error occurs.
* Since: 2.14
*/
RsvgHandle *
rsvg_handle_new_from_data (const guint8 * data, gsize data_len, GError ** error)
{
RsvgHandle *handle;
handle = rsvg_handle_new ();
if (handle) {
if (!rsvg_handle_fill_with_data (handle, (char *) data, data_len, error)) {
g_object_unref (handle);
handle = NULL;
}
}
return handle;
}
/**
* rsvg_handle_new_from_file:
* @file_name: The file name to load. If built with gnome-vfs, can be a URI.
* @error: return location for errors
*
* Loads the SVG specified by @file_name.
*
* Returns: A #RsvgHandle or %NULL if an error occurs.
* Since: 2.14
*/
RsvgHandle *
rsvg_handle_new_from_file (const gchar * file_name, GError ** error)
{
gchar *base_uri;
char *data;
gsize data_len;
RsvgHandle *handle = NULL;
GFile *file;
char *scheme;
rsvg_return_val_if_fail (file_name != NULL, NULL, error);
scheme = g_uri_parse_scheme (file_name);
if (scheme) {
file = g_file_new_for_uri (file_name);
g_free (scheme);
} else {
file = g_file_new_for_path (file_name);
}
base_uri = g_file_get_uri (file);
if (!base_uri) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Cannot obtain URI from '%s'"), file_name);
g_object_unref (file);
return NULL;
}
data = _rsvg_io_acquire_data (base_uri, base_uri, NULL, &data_len, NULL, error);
if (data) {
handle = rsvg_handle_new ();
rsvg_handle_set_base_uri (handle, base_uri);
if (!rsvg_handle_fill_with_data (handle, data, data_len, error)) {
g_object_unref (handle);
handle = NULL;
}
g_free (data);
}
g_free (base_uri);
g_object_unref (file);
return handle;
}
......@@ -31,7 +31,6 @@
#include "rsvg-css.h"
#include "rsvg-styles.h"
#include "rsvg-io.h"
#include "rsvg-load.h"
#include <gio/gio.h>
......@@ -145,142 +144,6 @@ rsvg_set_default_dpi_x_y (double dpi_x, double dpi_y)
rsvg_internal_dpi_y = dpi_y;
}
/**
* rsvg_handle_write:
* @handle: an #RsvgHandle
* @buf: (array length=count) (element-type guchar): pointer to svg data
* @count: length of the @buf buffer in bytes
* @error: (allow-none): a location to store a #GError, or %NULL
*
* Loads the next @count bytes of the image. This will return %TRUE if the data
* was loaded successful, and %FALSE if an error occurred. In the latter case,
* the loader will be closed, and will not accept further writes. If %FALSE is
* returned, @error will be set to an error from the #RsvgError domain. Errors
* from #GIOErrorEnum are also possible.
*
* Returns: %TRUE on success, or %FALSE on error
**/
gboolean
rsvg_handle_write (RsvgHandle *handle, const guchar *buf, gsize count, GError **error)
{
RsvgHandlePrivate *priv;
rsvg_return_val_if_fail (handle, FALSE, error);
priv = handle->priv;
rsvg_return_val_if_fail (priv->hstate == RSVG_HANDLE_STATE_START
|| priv->hstate == RSVG_HANDLE_STATE_LOADING,
FALSE,
error);
if (priv->hstate == RSVG_HANDLE_STATE_START) {
priv->hstate = RSVG_HANDLE_STATE_LOADING;
priv->load = rsvg_load_new (handle, (priv->flags & RSVG_HANDLE_FLAG_UNLIMITED) != 0);
}
g_assert (priv->hstate == RSVG_HANDLE_STATE_LOADING);
return rsvg_load_write (priv->load, buf, count, error);
}
static gboolean
finish_load (RsvgHandle *handle, gboolean was_successful)
{
RsvgNode *treebase = rsvg_load_destroy (handle->priv->load);
handle->priv->load = NULL;
if (was_successful) {
handle->priv->hstate = RSVG_HANDLE_STATE_CLOSED_OK;
handle->priv->treebase = treebase;
} else {
handle->priv->hstate = RSVG_HANDLE_STATE_CLOSED_ERROR;
treebase = rsvg_node_unref (treebase);
}
return was_successful;
}
/**
* rsvg_handle_close:
* @handle: a #RsvgHandle
* @error: (allow-none): a location to store a #GError, or %NULL
*
* Closes @handle, to indicate that loading the image is complete. This will
* return %TRUE if the loader closed successfully. Note that @handle isn't
* freed until @g_object_unref is called.
*
* Returns: %TRUE on success, or %FALSE on error
**/
gboolean
rsvg_handle_close (RsvgHandle *handle, GError **error)
{
RsvgHandlePrivate *priv;
gboolean result;
rsvg_return_val_if_fail (handle, FALSE, error);
priv = handle->priv;
if (priv->hstate == RSVG_HANDLE_STATE_CLOSED_OK
|| priv->hstate == RSVG_HANDLE_STATE_CLOSED_ERROR) {
/* closing is idempotent */
return TRUE;
}
result = finish_load (handle, rsvg_load_close (priv->load, error));
return result;
}
/**
* rsvg_handle_read_stream_sync:
* @handle: a #RsvgHandle
* @stream: a #GInputStream
* @cancellable: (allow-none): a #GCancellable, or %NULL
* @error: (allow-none): a location to store a #GError, or %NULL
*
* Reads @stream and writes the data from it to @handle.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the
* operation was cancelled, the error %G_IO_ERROR_CANCELLED will be
* returned.
*
* Returns: %TRUE if reading @stream succeeded, or %FALSE otherwise
* with @error filled in
*
* Since: 2.32
*/
gboolean
rsvg_handle_read_stream_sync (RsvgHandle *handle,
GInputStream *stream,
GCancellable *cancellable,
GError **error)
{
RsvgHandlePrivate *priv;
gboolean result;
RsvgLoad *saved_load;
g_return_val_if_fail (RSVG_IS_HANDLE (handle), FALSE);
g_return_val_if_fail (G_IS_INPUT_STREAM (stream), FALSE);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
priv = handle->priv;
g_return_val_if_fail (priv->hstate == RSVG_HANDLE_STATE_START, FALSE);
priv->hstate = RSVG_HANDLE_STATE_LOADING;
saved_load = priv->load;
priv->load = rsvg_load_new (handle, (priv->flags & RSVG_HANDLE_FLAG_UNLIMITED) != 0);
result = finish_load (handle, rsvg_load_read_stream_sync (priv->load, stream, cancellable, error));
priv->load = saved_load;
return result;
}
/**
* rsvg_init:
*
......@@ -321,138 +184,12 @@ rsvg_cleanup (void)
xmlCleanupParser ();
}
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;
}
void
rsvg_return_if_fail_warning (const char *pretty_function, const char *expression, GError ** error)
{
g_set_error (error, RSVG_ERROR, 0, _("%s: assertion `%s' failed"), pretty_function, expression);
}
#ifdef HAVE_PANGOFT2
static void
create_font_config_for_testing (RsvgHandle *handle)
{
const char *font_paths[] = {
"resources/Roboto-Regular.ttf",
"resources/Roboto-Italic.ttf",
"resources/Roboto-Bold.ttf",
"resources/Roboto-BoldItalic.ttf",
};
int i;
if (handle->priv->font_config_for_testing != NULL)
return;
handle->priv->font_config_for_testing = FcConfigCreate ();
for (i = 0; i < G_N_ELEMENTS(font_paths); i++) {
char *font_path = g_test_build_filename (G_TEST_DIST, font_paths[i], NULL);
if (!FcConfigAppFontAddFile (handle->priv->font_config_for_testing, (const FcChar8 *) font_path)) {
g_error ("Could not load font file \"%s\" for tests; aborting", font_path);
}
g_free (font_path);
}
}
#endif
void
rsvg_handle_update_font_map_for_testing (RsvgHandle *handle)
{
#ifdef HAVE_PANGOFT2
if (handle->priv->is_testing) {
create_font_config_for_testing (handle);
if (handle->priv->font_map_for_testing == NULL) {
handle->priv->font_map_for_testing = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
pango_fc_font_map_set_config (PANGO_FC_FONT_MAP (handle->priv->font_map_for_testing),
handle->priv->font_config_for_testing);
pango_cairo_font_map_set_default (PANGO_CAIRO_FONT_MAP (handle->priv->font_map_for_testing));
}
}
#endif
}
gboolean
rsvg_allow_load (GFile *base_gfile,
const char *uri,
......@@ -534,86 +271,3 @@ rsvg_allow_load (GFile *base_gfile,
"File may not link to URI \"%s\"", uri);
return FALSE;
}
char *
rsvg_handle_resolve_uri (RsvgHandle *handle,
const char *uri)
{
RsvgHandlePrivate *priv = handle->priv;
char *scheme, *resolved_uri;
GFile *base, *resolved;
if (uri == NULL)
return NULL;
scheme = g_uri_parse_scheme (uri);
if (scheme != NULL ||
priv->base_gfile == NULL ||
(base = g_file_get_parent (priv->base_gfile)) == NULL) {
g_free (scheme);
return g_strdup (uri);
}
resolved = g_file_resolve_relative_path (base, uri);
resolved_uri = g_file_get_uri (resolved);
g_free (scheme);
g_object_unref (base);
g_object_unref (resolved);
return resolved_uri;
}
char *
_rsvg_handle_acquire_data (RsvgHandle *handle,
const char *url,
char **content_type,
gsize *len,
GError **error)
{
RsvgHandlePrivate *priv = handle->priv;
char *uri;
char *data;
uri = rsvg_handle_resolve_uri (handle, url);
if (rsvg_allow_load (priv->base_gfile, uri, error)) {
data = _rsvg_io_acquire_data (uri,
rsvg_handle_get_base_uri (handle),
content_type,
len,
handle->priv->cancellable,
error);
} else {
data = NULL;
}
g_free (uri);
return data;
}
GInputStream *
_rsvg_handle_acquire_stream (RsvgHandle *handle,
const char *url,
char **content_type,
GError **error)
{
RsvgHandlePrivate *priv = handle->priv;
char *uri;
GInputStream *stream;
uri = rsvg_handle_resolve_uri (handle, url);
if (rsvg_allow_load (priv->base_gfile, uri, error)) {
stream = _rsvg_io_acquire_stream (uri,
rsvg_handle_get_base_uri (handle),
content_type,
handle->priv->cancellable,
error);
} else {
stream = NULL;
}
g_free (uri);
return stream;
}
<
......@@ -120,6 +120,8 @@
#include "config.h"
#include <string.h>
#include "rsvg-io.h"
#include "rsvg-load.h"
#include "rsvg-private.h"
enum {
......@@ -425,6 +427,107 @@ rsvg_handle_new (void)
return RSVG_HANDLE (g_object_new (RSVG_TYPE_HANDLE, NULL));
}
static gboolean
rsvg_handle_fill_with_data (RsvgHandle *handle,
const char *data,
gsize data_len,
GError ** error)
{
gboolean rv;
rsvg_return_val_if_fail (data != NULL, FALSE, error);
rsvg_return_val_if_fail (data_len != 0, FALSE, error);
rv = rsvg_handle_write (handle, (guchar *) data, data_len, error);
return rsvg_handle_close (handle, rv ? error : NULL) && rv;
}
/**
* rsvg_handle_new_from_data:
* @data: (array length=data_len): The SVG data
* @data_len: The length of @data, in bytes
* @error: return location for errors
*
* Loads the SVG specified by @data.
*
* Returns: A #RsvgHandle or %NULL if an error occurs.
* Since: 2.14
*/
RsvgHandle *
rsvg_handle_new_from_data (const guint8 *data, gsize data_len, GError **error)
{
RsvgHandle *handle;
handle = rsvg_handle_new ();
if (handle) {
if (!rsvg_handle_fill_with_data (handle, (char *) data, data_len, error)) {
g_object_unref (handle);
handle = NULL;
}
}
return handle;
}
/**
* rsvg_handle_new_from_file:
* @file_name: The file name to load. If built with gnome-vfs, can be a URI.
* @error: return location for errors
*
* Loads the SVG specified by @file_name.
*
* Returns: A #RsvgHandle or %NULL if an error occurs.
* Since: 2.14
*/
RsvgHandle *
rsvg_handle_new_from_file (const gchar *file_name, GError **error)
{
gchar *base_uri;
char *data;
gsize data_len;
RsvgHandle *handle = NULL;
GFile *file;
char *scheme;
rsvg_return_val_if_fail (file_name != NULL, NULL, error);
scheme = g_uri_parse_scheme (file_name);
if (scheme) {
file = g_file_new_for_uri (file_name);
g_free (scheme);
} else {
file = g_file_new_for_path (file_name);
}
base_uri = g_file_get_uri (file);
if (!base_uri) {
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Cannot obtain URI from '%s'"), file_name);
g_object_unref (file);
return NULL;
}
data = _rsvg_io_acquire_data (base_uri, base_uri, NULL, &data_len, NULL, error);
if (data) {
handle = rsvg_handle_new ();
rsvg_handle_set_base_uri (handle, base_uri);
if (!rsvg_handle_fill_with_data (handle, data, data_len, error)) {
g_object_unref (handle);
handle = NULL;
}
g_free (data);
}
g_free (base_uri);
g_object_unref (file);
return handle;
}
/**
* rsvg_handle_new_with_flags:
......@@ -532,6 +635,142 @@ rsvg_handle_new_from_stream_sync (GInputStream *input_stream,
return handle;
}
/**
* rsvg_handle_write:
* @handle: an #RsvgHandle
* @buf: (array length=count) (element-type guchar): pointer to svg data
* @count: length of the @buf buffer in bytes
* @error: (allow-none): a location to store a #GError, or %NULL
*
* Loads the next @count bytes of the image. This will return %TRUE if the data
* was loaded successful, and %FALSE if an error occurred. In the latter case,
* the loader will be closed, and will not accept further writes. If %FALSE is
* returned, @error will be set to an error from the #RsvgError domain. Errors
* from #GIOErrorEnum are also possible.
*
* Returns: %TRUE on success, or %FALSE on error
**/
gboolean
rsvg_handle_write (RsvgHandle *handle, const guchar *buf, gsize count, GError **error)
{
RsvgHandlePrivate *priv;
rsvg_return_val_if_fail (handle, FALSE, error);
priv = handle->priv;
rsvg_return_val_if_fail (priv->hstate == RSVG_HANDLE_STATE_START
|| priv->hstate == RSVG_HANDLE_STATE_LOADING,
FALSE,
error);
if (priv->hstate == RSVG_HANDLE_STATE_START) {
priv->hstate = RSVG_HANDLE_STATE_LOADING;
priv->load = rsvg_load_new (handle, (priv->flags & RSVG_HANDLE_FLAG_UNLIMITED) != 0);
}
g_assert (priv->hstate == RSVG_HANDLE_STATE_LOADING);
return rsvg_load_write (priv->load, buf, count, error);
}
static gboolean
finish_load (RsvgHandle *handle, gboolean was_successful)
{
RsvgNode *treebase = rsvg_load_destroy (handle->priv->load);
handle->priv->load = NULL;
if (was_successful) {
handle->priv->hstate = RSVG_HANDLE_STATE_CLOSED_OK;
handle->priv->treebase = treebase;
} else {
handle->priv->hstate = RSVG_HANDLE_STATE_CLOSED_ERROR;
treebase = rsvg_node_unref (treebase);
}
return was_successful;
}
/**
* rsvg_handle_close:
* @handle: a #RsvgHandle
* @error: (allow-none): a location to store a #GError, or %NULL
*
* Closes @handle, to indicate that loading the image is complete. This will
* return %TRUE if the loader closed successfully. Note that @handle isn't
* freed until @g_object_unref is called.
*
* Returns: %TRUE on success, or %FALSE on error
**/
gboolean
rsvg_handle_close (RsvgHandle *handle, GError **error)
{
RsvgHandlePrivate *priv;
gboolean result;
rsvg_return_val_if_fail (handle, FALSE, error);
priv = handle->priv;
if (priv->hstate == RSVG_HANDLE_STATE_CLOSED_OK
|| priv->hstate == RSVG_HANDLE_STATE_CLOSED_ERROR) {
/* closing is idempotent */
return TRUE;
}
result = finish_load (handle, rsvg_load_close (priv->load, error));
return result;
}
/**
* rsvg_handle_read_stream_sync:
* @handle: a #RsvgHandle
* @stream: a #GInputStream
* @cancellable: (allow-none): a #GCancellable, or %NULL
* @error: (allow-none): a location to store a #GError, or %NULL
*
* Reads @stream and writes the data from it to @handle.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the
* operation was cancelled, the error %G_IO_ERROR_CANCELLED will be
* returned.
*
* Returns: %TRUE if reading @stream succeeded, or %FALSE otherwise
* with @error filled in
*
* Since: 2.32
*/
gboolean
rsvg_handle_read_stream_sync (RsvgHandle *handle,