/*
 * Copyright © 2006 Novell, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Author: David Reveman <davidr@novell.com>
 */

#include <stdlib.h>
#include <string.h>

#include <librsvg/rsvg.h>
#include <librsvg/rsvg-cairo.h>

#include <beryl.h>

static int displayPrivateIndex;

typedef struct _SvgDisplay
{
	FileToImageProc fileToImage;
} SvgDisplay;

#define GET_SVG_DISPLAY(d)				    \
    ((SvgDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define SVG_DISPLAY(d)			 \
    SvgDisplay *sd = GET_SVG_DISPLAY (d)


static Bool
readSvgFileToImage(char *file, int *width, int *height, void **data)
{
	cairo_surface_t *surface;
	FILE *fp;
	GError *error = NULL;
	RsvgHandle *svgHandle;
	RsvgDimensionData svgDimension;

	fp = fopen(file, "r");
	if (!fp)
		return FALSE;

	fclose(fp);

	svgHandle = rsvg_handle_new_from_file(file, &error);
	if (!svgHandle)
		return FALSE;

	rsvg_handle_get_dimensions(svgHandle, &svgDimension);

	*width = svgDimension.width;
	*height = svgDimension.height;

	*data = malloc(svgDimension.width * svgDimension.height * 4);
	if (!*data)
	{
		rsvg_handle_free(svgHandle);
		return FALSE;
	}

	surface = cairo_image_surface_create_for_data(*data,
												  CAIRO_FORMAT_ARGB32,
												  svgDimension.width,
												  svgDimension.height,
												  svgDimension.width * 4);
	if (surface)
	{
		cairo_t *cr;

		cr = cairo_create(surface);

		cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
		cairo_paint(cr);
		cairo_set_operator(cr, CAIRO_OPERATOR_OVER);

		rsvg_handle_render_cairo(svgHandle, cr);

		cairo_destroy(cr);
		cairo_surface_destroy(surface);
	}

	rsvg_handle_free(svgHandle);

	return TRUE;
}

static char *svgExtension(const char *name)
{

	if (strlen(name) > 4)
	{
		if (strcasecmp(name + (strlen(name) - 4), ".svg") == 0)
			return "";
	}

	return ".svg";
}

static Bool
svgFileToImage(CompDisplay * d,
			   const char *path,
			   const char *name,
			   int *width, int *height, int *stride, void **data)
{
	Bool status = FALSE;
	char *extension = svgExtension(name);
	char *file;
	int len;

	SVG_DISPLAY(d);

	len = (path ? strlen(path) : 0) + strlen(name) + strlen(extension) + 2;

	file = malloc(len);
	if (file)
	{
		if (path)
			sprintf(file, "%s/%s%s", path, name, extension);
		else
			sprintf(file, "%s%s", name, extension);

		status = readSvgFileToImage(file, width, height, data);

		free(file);

		if (status)
		{
			*stride = *width * 4;
			return TRUE;
		}
	}

	UNWRAP(sd, d, fileToImage);
	status = (*d->fileToImage) (d, path, name, width, height, stride, data);
	WRAP(sd, d, fileToImage, svgFileToImage);

	return status;
}

static Bool svgInitDisplay(CompPlugin * p, CompDisplay * d)
{
	SvgDisplay *sd;
	CompScreen *s;

	sd = malloc(sizeof(SvgDisplay));
	if (!sd)
		return FALSE;

	WRAP(sd, d, fileToImage, svgFileToImage);

	d->privates[displayPrivateIndex].ptr = sd;

	for (s = d->screens; s; s = s->next)
		updateDefaultIcon(s);

	return TRUE;
}

static void svgFiniDisplay(CompPlugin * p, CompDisplay * d)
{
	CompScreen *s;

	SVG_DISPLAY(d);

	UNWRAP(sd, d, fileToImage);

	for (s = d->screens; s; s = s->next)
		updateDefaultIcon(s);

	free(sd);
}

static Bool svgInit(CompPlugin * p)
{
	displayPrivateIndex = allocateDisplayPrivateIndex();
	if (displayPrivateIndex < 0)
		return FALSE;

	return TRUE;
}

static void svgFini(CompPlugin * p)
{
	if (displayPrivateIndex >= 0)
		freeDisplayPrivateIndex(displayPrivateIndex);
}

CompPluginFeature svgFeatures[] = {
	{"imageext:svg"}
	,
	{"imagemime:image/svg+xml"}
	,
	{"imagemime:image/svg-xml"}
	,
};

CompPluginVTable svgVTable = {
	"svg",
	N_("Svg"),
	N_("Svg image loader"),
	svgInit,
	svgFini,
	svgInitDisplay,
	svgFiniDisplay,
	0,							/* InitScreen */
	0,							/* FiniScreen */
	0,							/* InitWindow */
	0,							/* FiniWindow */
	0,							/* GetDisplayOptions */
	0,							/* SetDisplayOption */
	0,							/* GetScreenOptions */
	0,							/* SetScreenOption */
	0,							/* Deps */
	0,							/* nDeps */
	svgFeatures,				/* Features */
	sizeof(svgFeatures) / sizeof(svgFeatures[0]),	/* nFeatures */
	BERYL_ABI_INFO,
	"beryl-plugins",
	"imageformat",
	0,
	0,
	True,
};

CompPluginVTable *getCompPluginInfo(void)
{
	return &svgVTable;
}


syntax highlighted by Code2HTML, v. 0.9.1