/* * Copyright (C) 2018 Vito Caputo - * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 as published * by the Free Software Foundation. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include /* this is needed by cairo headers of all things */ #include #ifdef HAVE_SVG_CAIRO #include #else #include #endif #include "macros.h" typedef struct whale_svg_t { #ifdef HAVE_SVG_CAIRO svg_cairo_t *cairo_svg; unsigned width, height; #else RsvgHandle *rsvg; RsvgDimensionData dimensions; #endif } whale_svg_t; whale_svg_t * whale_svg_new_file(const char *file) { whale_svg_t *svg; svg = calloc(1, sizeof(whale_svg_t)); fatal_if(!svg, "Unable to create svg"); #ifdef HAVE_SVG_CAIRO fatal_if(svg_cairo_create(&svg->cairo_svg) != 0, "Unable to create svg-cairo context"); fatal_if(svg_cairo_parse(svg->cairo_svg, file) != 0, "Unable to parse \"%s\"", file); svg_cairo_get_size(svg->cairo_svg, &svg->width, &svg->height); #else //rsvg_init(); svg->rsvg = rsvg_handle_new_from_file(file, NULL); fatal_if(!svg->rsvg, "Unable to create rsvg handle from file \"%s\"", file); rsvg_handle_get_dimensions(svg->rsvg, &svg->dimensions); #endif return svg; } whale_svg_t * whale_svg_new_buffer(const char *buf, size_t count) { whale_svg_t *svg; svg = calloc(1, sizeof(whale_svg_t)); fatal_if(!svg, "Unable to create svg"); #ifdef HAVE_SVG_CAIRO fatal_if(svg_cairo_create(&svg->cairo_svg) != 0, "Unable to create svg-cairo context"); fatal_if(svg_cairo_parse_buffer(svg->cairo_svg, buf, count) != 0, "Unable to parse svg buffer"); svg_cairo_get_size(svg->cairo_svg, &svg->width, &svg->height); #else //rsvg_init(); svg->rsvg = rsvg_handle_new_from_data(buf, count, NULL); fatal_if(!svg->rsvg, "Unable to create rsvg handle from buffer"); rsvg_handle_get_dimensions(svg->rsvg, &svg->dimensions); #endif return svg; } SDL_Surface * whale_svg_render(whale_svg_t *svg, int width, int height) { cairo_surface_t *cairo_surface; SDL_Surface *sdl_surface; cairo_t *cairo; double xscale, yscale, scale, tx, ty, svg_width, svg_height; #ifdef HAVE_SVG_CAIRO svg_width = svg->width; svg_height = svg->height; #else svg_width = svg->dimensions.width; svg_height = svg->dimensions.height; #endif /* cached size is different so redo the costly SVG render */ sdl_surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_ARGB8888); fatal_if(!sdl_surface, "Unable to create sdl surface"); cairo_surface = cairo_image_surface_create_for_data(sdl_surface->pixels, CAIRO_FORMAT_ARGB32, width, height, sdl_surface->pitch); fatal_if(!cairo_surface, "Unable to create cairo surface"); #if 0 /* useful for debugging */ SDL_FillRect(sdl_surface, NULL, 0xffff0000); #endif cairo = cairo_create(cairo_surface); fatal_if(!cairo, "Unable to create cairo target"); /* XXX: this scaling attempts to preserve the svg's aspect ratio, * while filling the destination surface */ xscale = (double)width / svg_width; yscale = (double)height / svg_height; scale = xscale < yscale ? xscale : yscale; /* if we have a mismatch between the desired width/height aspect ratio, * and the svg's aspect ratio, we need to translate to center the rendering * in the resulting surface */ tx = scale * svg_width; ty = scale * svg_height; if ((int)((double)tx + 0.5) < width) tx = ((double)width - tx + 0.5) / 2.0; else tx = 0; if ((int)((double)ty + 0.5) < height) ty = ((double)height - ty + 0.5) / 2.0; else ty = 0; cairo_translate(cairo, tx, ty); cairo_scale(cairo, scale, scale); #ifdef HAVE_SVG_CAIRO svg_cairo_render(svg->cairo_svg, cairo); #else rsvg_handle_render_cairo(svg->rsvg, cairo); #endif cairo_surface_flush(cairo_surface); cairo_surface_destroy(cairo_surface); cairo_destroy(cairo); return sdl_surface; } void whale_svg_free(whale_svg_t *svg) { #ifdef HAVE_SVG_CAIRO svg_cairo_destroy(svg->cairo_svg); #else rsvg_handle_free(svg->rsvg); #endif free(svg); }