legacy-imlib2/src/modules/loaders/loader_svg.c

220 lines
6.0 KiB
C

#include "loader_common.h"
#include <math.h>
#include <librsvg/rsvg.h>
#define DBG_PFX "LDR-svg"
#define DPI 96
#if LIBRSVG_CHECK_VERSION(2, 46, 0)
static double
u2pix(double x, int unit)
{
switch (unit)
{
default:
case RSVG_UNIT_PERCENT: /* 0 percentage values where 1.0 means 100% */
case RSVG_UNIT_PX: /* 1 pixels */
case RSVG_UNIT_EM: /* 2 em, or the current font size */
case RSVG_UNIT_EX: /* 3 x-height of the current font */
return x;
case RSVG_UNIT_IN: /* 4 inches */
return x * DPI;
case RSVG_UNIT_CM: /* 5 centimeters */
return x * DPI / 2.54;
case RSVG_UNIT_MM: /* 6 millimeters */
return x * DPI / 25.4;
case RSVG_UNIT_PT: /* 7 points, or 1/72 inch */
return x * DPI / 72;
case RSVG_UNIT_PC: /* 8 picas, or 1/6 inch (12 points) */
return x * DPI / 6;
}
}
#endif /* LIBRSVG need 2.46 */
static void
_handle_error(GError * error)
{
D("librsvg2: %s\n", error->message);
g_error_free(error);
}
int
load2(ImlibImage * im, int load_data)
{
int rc;
void *fdata;
RsvgHandle *rsvg;
GError *error;
gboolean ok;
cairo_surface_t *surface;
cairo_t *cr;
rc = LOAD_FAIL;
fdata = mmap(NULL, im->fsize, PROT_READ, MAP_SHARED, fileno(im->fp), 0);
if (fdata == MAP_FAILED)
return LOAD_BADFILE;
surface = NULL;
cr = NULL;
error = NULL;
rsvg = rsvg_handle_new_from_data(fdata, im->fsize, &error);
if (!rsvg)
goto quit;
rc = LOAD_BADIMAGE; /* Format accepted */
#if LIBRSVG_CHECK_VERSION(2, 46, 0)
{
gboolean out_has_width, out_has_height, out_has_viewbox;
RsvgLength out_width = { }, out_height = { };
RsvgRectangle out_viewbox = { };
rsvg_handle_get_intrinsic_dimensions(rsvg,
&out_has_width,
&out_width,
&out_has_height,
&out_height,
&out_has_viewbox, &out_viewbox);
D("WH:%d%d %.1fx%.1f (%d/%d: %.1fx%.1f) VB:%d %.1f,%.1f %.1fx%.1f\n",
out_has_width, out_has_height,
out_width.length, out_height.length, out_width.unit, out_height.unit,
u2pix(out_width.length, out_width.unit),
u2pix(out_height.length, out_height.unit),
out_has_viewbox,
out_viewbox.x, out_viewbox.y, out_viewbox.width, out_viewbox.height);
if (out_has_width && out_has_height)
{
im->w = lrint(u2pix(out_width.length, out_width.unit));
im->h = lrint(u2pix(out_height.length, out_height.unit));
D("Choose rsvg_handle_get_intrinsic_dimensions width/height\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
if (out_has_viewbox && (im->w <= 0 || im->w <= 0))
{
im->w = ceil(out_viewbox.width);
im->h = ceil(out_viewbox.height);
D("Choose rsvg_handle_get_intrinsic_dimensions viewbox\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
}
#endif /* LIBRSVG need 2.46 */
#if 0
#if LIBRSVG_CHECK_VERSION(2, 52, 0)
{
gdouble dw = 0, dh = 0;
ok = rsvg_handle_get_intrinsic_size_in_pixels(rsvg, &dw, &dh);
D("ok=%d WxH=%.1fx%.1f\n", ok, dw, dh);
if (ok && (im->w <= 0 || im->w <= 0))
{
im->w = ceil(dw);
im->h = ceil(dh);
D("Choose rsvg_handle_get_intrinsic_size_in_pixels width/height\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
}
#endif
#endif /* LIBRSVG need 2.52 */
#if LIBRSVG_CHECK_VERSION(2, 46, 0)
{
RsvgRectangle out_ink_rect = { }, out_logical_rect = { };
ok = rsvg_handle_get_geometry_for_element(rsvg, NULL,
&out_ink_rect,
&out_logical_rect, &error);
D("ok=%d Ink: %.1f,%.1f %.1fx%.1f Log: %.1f,%.1f %.1fx%.1f\n", ok,
out_ink_rect.x, out_ink_rect.y, out_ink_rect.width, out_ink_rect.height,
out_logical_rect.x, out_logical_rect.y, out_logical_rect.width,
out_logical_rect.height);
if (ok && (im->w <= 0 || im->w <= 0))
{
im->w = ceil(out_ink_rect.width);
im->h = ceil(out_ink_rect.height);
D("Choose rsvg_handle_get_geometry_for_element ink rect width/height\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
}
#endif /* LIBRSVG need 2.46 */
#if !IMLIB2_DEBUG
got_size:
#endif
if (!IMAGE_DIMENSIONS_OK(im->w, im->h))
goto quit;
IM_FLAG_UPDATE(im, F_HAS_ALPHA, 1);
if (!load_data)
QUIT_WITH_RC(LOAD_SUCCESS);
/* Load data */
if (!__imlib_AllocateData(im))
QUIT_WITH_RC(LOAD_OOM);
memset(im->data, 0, im->w * im->h * sizeof(uint32_t));
surface =
cairo_image_surface_create_for_data((void *)im->data, CAIRO_FORMAT_ARGB32,
im->w, im->h,
im->w * sizeof(uint32_t));;
if (!surface)
QUIT_WITH_RC(LOAD_OOM);
cr = cairo_create(surface);
if (!cr)
QUIT_WITH_RC(LOAD_OOM);
#if LIBRSVG_CHECK_VERSION(2, 46, 0)
{
RsvgRectangle cvb;
cvb.x = cvb.y = 0;
cvb.width = im->w;
cvb.height = im->h;
rsvg_handle_render_document(rsvg, cr, &cvb, &error);
}
#endif /* LIBRSVG need 2.46 */
if (im->lc)
__imlib_LoadProgress(im, im->frame_x, im->frame_y, im->w, im->h);
rc = LOAD_SUCCESS;
quit:
if (error)
_handle_error(error);
if (surface)
cairo_surface_destroy(surface);
if (cr)
cairo_destroy(cr);
if (rsvg)
g_object_unref(rsvg);
munmap(fdata, im->fsize);
return rc;
}
void
formats(ImlibLoader * l)
{
static const char *const list_formats[] = { "svg" };
__imlib_LoaderSetFormats(l, list_formats, ARRAY_SIZE(list_formats));
}