File dia-cairo-0.5.patch of Package dia
--- plug-ins/cairo/diacairo.c
+++ plug-ins/cairo/diacairo.c
@@ -29,8 +29,24 @@
#include <glib.h>
#include <errno.h>
+/*
+ * To me the following looks rather suspicious. Why do we need to compile
+ * the Cairo plug-in at all if we don't have Cairo? As a result we'll
+ * show it in the menus/plugin details and the user expects something
+ * although there isn't any functionality behind it. Urgh. --hb
+ */
#ifdef HAVE_CAIRO
-#include <cairo.h>
+# include <cairo.h>
+/* some backend headers, win32 missing in official Cairo */
+# ifdef CAIRO_HAS_PNG_SURFACE_FEATURE
+# include <cairo-png.h>
+# endif
+# ifdef CAIRO_HAS_PS_SURFACE
+# include <cairo-ps.h>
+# endif
+# ifdef CAIRO_HAS_PDF_SURFACE
+# include <cairo-pdf.h>
+# endif
#endif
#include "intl.h"
@@ -67,6 +83,7 @@
DiagramData *dia;
real scale;
+ gboolean with_alpha;
};
struct _DiaCairoRendererClass
@@ -95,28 +112,42 @@
{
DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (self);
- renderer->cr = cairo_create ();
+ renderer->cr = cairo_create (renderer->surface);
cairo_scale (renderer->cr, renderer->scale, renderer->scale);
cairo_translate (renderer->cr, -renderer->dia->extents.left, -renderer->dia->extents.top);
- cairo_set_target_surface (renderer->cr, renderer->surface);
-
- /*FIXME: I'd like this to clear the alpha background, but it doesn't work
- * cairo_set_alpha (renderer->cr, 0.0);
- */
/* clear background */
- cairo_set_rgb_color (renderer->cr,
- renderer->dia->bg_color.red,
- renderer->dia->bg_color.green,
- renderer->dia->bg_color.blue);
+ if (renderer->with_alpha)
+ {
+ cairo_set_operator (renderer->cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba (renderer->cr,
+ renderer->dia->bg_color.red,
+ renderer->dia->bg_color.green,
+ renderer->dia->bg_color.blue,
+ 0.0);
+ }
+ else
+ {
+ cairo_set_source_rgba (renderer->cr,
+ renderer->dia->bg_color.red,
+ renderer->dia->bg_color.green,
+ renderer->dia->bg_color.blue,
+ 1.0);
+ }
cairo_rectangle (renderer->cr,
renderer->dia->extents.left, renderer->dia->extents.top,
renderer->dia->extents.right, renderer->dia->extents.bottom);
cairo_fill (renderer->cr);
- /*FIXME : how is this supposed to work ?
- * cairo_set_operator (renderer->cr, DIA_CAIRO_OPERATOR_SRC);
- * cairo_set_alpha (renderer->cr, 1.0);
- */
+ if (renderer->with_alpha)
+ {
+ /* restore to default drawing */
+ cairo_set_operator (renderer->cr, CAIRO_OPERATOR_OVER);
+ (renderer->cr,
+ renderer->dia->bg_color.red,
+ renderer->dia->bg_color.green,
+ renderer->dia->bg_color.blue,
+ 1.0);
+ }
DIAG_STATE(renderer->cr)
}
@@ -276,11 +307,12 @@
family_name = dia_font_get_family(font);
- cairo_select_font (renderer->cr,
- family_name,
- DIA_FONT_STYLE_GET_SLANT(style) == DIA_FONT_NORMAL ? CAIRO_FONT_SLANT_NORMAL : CAIRO_FONT_SLANT_ITALIC,
- DIA_FONT_STYLE_GET_WEIGHT(style) < DIA_FONT_MEDIUM ? CAIRO_FONT_WEIGHT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
- cairo_scale_font (renderer->cr, height * 0.7); /* same magic factor as in lib/font.c */
+ cairo_select_font_face (
+ renderer->cr,
+ family_name,
+ DIA_FONT_STYLE_GET_SLANT(style) == DIA_FONT_NORMAL ? CAIRO_FONT_SLANT_NORMAL : CAIRO_FONT_SLANT_ITALIC,
+ DIA_FONT_STYLE_GET_WEIGHT(style) < DIA_FONT_MEDIUM ? CAIRO_FONT_WEIGHT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size (renderer->cr, height * 0.7); /* same magic factor as in lib/font.c */
DIAG_STATE(renderer->cr)
}
@@ -295,7 +327,7 @@
DIAG_NOTE(g_message("draw_line %f,%f -> %f, %f",
start->x, start->y, end->x, end->y));
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_move_to (renderer->cr, start->x, start->y);
cairo_line_to (renderer->cr, end->x, end->y);
cairo_stroke (renderer->cr);
@@ -315,7 +347,7 @@
g_return_if_fail(1 < num_points);
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_new_path (renderer->cr);
/* point data */
@@ -343,7 +375,7 @@
g_return_if_fail(1 < num_points);
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_new_path (renderer->cr);
/* point data */
@@ -389,7 +421,7 @@
fill ? "fill" : "draw",
ul_corner->x, ul_corner->y, lr_corner->x, lr_corner->y));
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_rectangle (renderer->cr,
ul_corner->x, ul_corner->y,
@@ -432,7 +464,7 @@
DIAG_NOTE(g_message("draw_arc %fx%f <%f,<%f",
width, height, angle1, angle2));
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
/* Dia and Cairo don't agree on arc definitions, so it needs
* to be converted, i.e. mirrored at the x axis
@@ -465,7 +497,7 @@
DIAG_NOTE(g_message("draw_arc %fx%f <%f,<%f",
width, height, angle1, angle2));
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_new_path (renderer->cr);
start.x = center->x + (width / 2.0) * cos((M_PI / 180.0) * angle1);
@@ -497,7 +529,7 @@
DIAG_NOTE(g_message("%s_ellipse %fx%f center @ %f,%f",
fill ? "fill" : "draw", width, height, center->x, center->y));
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
/* FIXME: how to make a perfect ellipse from a bezier ? */
co = sqrt(pow(width,2)/4 + pow(height,2)/4);
@@ -551,7 +583,7 @@
DIAG_NOTE(g_message("%s_bezier n:%d %fx%f ...",
fill ? "fill" : "draw", numpoints, points->p1.x, points->p1.y));
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_new_path (renderer->cr);
for (i = 0; i < numpoints; i++)
@@ -616,7 +648,7 @@
if (len < 1) return; /* shouldn't this be handled by Dia's core ? */
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_text_extents (renderer->cr,
text,
&extents);
@@ -662,34 +694,27 @@
/* we need to make a copy to rearrange channels
* (also need to use malloc, cause Cairo insists to free() it)
*/
- guint8 *p2 = data = malloc (h * rs);
+ guint8 *p2 = data = g_malloc (h * rs);
int i;
for (i = 0; i < (h * rs) / 4; i++)
{
-#if 0
- /* premultiply alpha */
- guint alpha = p1[3];
- p2[0] = (guint8)((p1[2] * alpha) / 255);
- p2[1] = (guint8)((p1[1] * alpha) / 255);
- p2[2] = (guint8)((p1[0] * alpha) / 255);
- p2[3] = (guint8)alpha;
-#else
+# if G_BYTE_ORDER == G_LITTLE_ENDIAN
p2[0] = p1[2]; /* b */
p2[1] = p1[1]; /* g */
p2[2] = p1[0]; /* r */
p2[3] = p1[3]; /* a */
-#endif
+# else
+ p2[3] = p1[2]; /* b */
+ p2[2] = p1[1]; /* g */
+ p2[1] = p1[0]; /* r */
+ p2[0] = p1[3]; /* a */
+# endif
p1+=4;
p2+=4;
}
- surface = cairo_surface_create_for_image (data,
- CAIRO_FORMAT_ARGB32,
- w, h, rs);
- /* DON'T it's owned by cairo/pixman now
- free (data);
- */
+ surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, w, h, rs);
}
else
{
@@ -700,36 +725,47 @@
*/
int x, y;
- p = p2 = malloc(h*w*4);
+ p = p2 = g_malloc(h*w*4);
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
/* apparently BGR is required */
p2[x*4 ] = p1[x*3+2];
p2[x*4+1] = p1[x*3+1];
p2[x*4+2] = p1[x*3 ];
p2[x*4+3] = 0x80; /* should not matter */
+#else
+ p2[x*4+3] = p1[x*3+2];
+ p2[x*4+2] = p1[x*3+1];
+ p2[x*4+1] = p1[x*3 ];
+ p2[x*4+0] = 0x80; /* should not matter */
+#endif
}
p2 += (w*4);
p1 += rs;
}
- surface = cairo_surface_create_for_image (p,
- CAIRO_FORMAT_RGB24,
- w, h, w*4);
+ surface = cairo_image_surface_create_for_data (p, CAIRO_FORMAT_RGB24, w, h, w*4);
g_free (data);
+ data = p;
}
cairo_save (renderer->cr);
cairo_translate (renderer->cr, point->x, point->y);
cairo_scale (renderer->cr, width/w, height/h);
cairo_move_to (renderer->cr, 0.0, 0.0);
/* maybe just the second set_filter is required */
+#if 0
cairo_surface_set_filter (renderer->surface, CAIRO_FILTER_BEST);
cairo_surface_set_filter (surface, CAIRO_FILTER_BEST);
- cairo_show_surface (renderer->cr, surface, w, h);
+#endif
+ cairo_set_source_surface (renderer->cr, surface, point->x, point->y);
+ cairo_paint (renderer->cr);
cairo_restore (renderer->cr);
cairo_surface_destroy (surface);
+ g_free (data);
+
DIAG_STATE(renderer->cr);
}
@@ -750,7 +786,7 @@
fill ? "fill" : "draw",
topleft->x, topleft->y, bottomright->x, bottomright->y, radius));
- cairo_set_rgb_color (renderer->cr, color->red, color->green, color->blue);
+ cairo_set_source_rgba (renderer->cr, color->red, color->green, color->blue, 1.0);
cairo_new_path (renderer->cr);
cairo_move_to (renderer->cr,
@@ -801,6 +837,7 @@
}
/* gobject boiler plate */
+static void cairo_renderer_init (DiaCairoRenderer *r, void *p);
static void cairo_renderer_class_init (DiaCairoRendererClass *klass);
static gpointer parent_class = NULL;
@@ -822,7 +859,7 @@
NULL, /* class_data */
sizeof (DiaCairoRenderer),
0, /* n_preallocs */
- NULL /* init */
+ (GInstanceInitFunc)cairo_renderer_init /* init */
};
object_type = g_type_register_static (DIA_TYPE_RENDERER,
@@ -834,6 +871,19 @@
}
static void
+cairo_renderer_init (DiaCairoRenderer *renderer, void *p)
+{
+ /*
+ * Initialize fields where 0 init isn't good enough. Bug #151716
+ * appears to show that we are sometimes called to render a line
+ * without setting the linestyle first. Probably a bug elsewhere
+ * but it's this plug-in which hangs ;)
+ */
+ renderer->dash_length = 1.0;
+ renderer->scale = 1.0;
+}
+
+static void
cairo_renderer_finalize (GObject *object)
{
DiaCairoRenderer *renderer = DIA_CAIRO_RENDERER (object);
@@ -895,6 +945,11 @@
{
OUTPUT_PS = 1,
OUTPUT_PNG,
+ OUTPUT_PNGA,
+ OUTPUT_PDF,
+ OUTPUT_WMF,
+ OUTPUT_EMF,
+ OUTPUT_CB
} OutputKind;
/* dia export funtion */
@@ -913,9 +968,10 @@
message_error(_("Can't open output file %s: %s\n"), filename, strerror(errno));
return;
}
-
+ fclose (file);
renderer = g_object_new (DIA_CAIRO_TYPE_RENDERER, NULL);
renderer->dia = data; /* FIXME: not sure if this a good idea */
+ renderer->scale = 1.0;
switch (kind) {
#ifdef CAIRO_HAS_PS_SURFACE
@@ -924,24 +980,52 @@
height = data->paper.height / 2.54;
renderer->scale = data->paper.scaling;
DIAG_NOTE(g_message ("PS Surface %dx%d\n", (int)width, (int)height));
- renderer->surface = cairo_ps_surface_create (file,
- width, height, /* inches */
- 75, 75); /* pixels per inch */
+ renderer->surface = cairo_ps_surface_create (filename,
+ width*72, height*72); /* in points? */
break;
#endif
-#ifdef CAIRO_HAS_PNG_SURFACE
+#if defined CAIRO_HAS_PNG_SURFACE || defined CAIRO_HAS_PNG_FUNCTIONS
+ case OUTPUT_PNGA :
+ renderer->with_alpha = TRUE;
+ /* fall through */
case OUTPUT_PNG :
/* quite arbitrary, but consistent with ../pixbuf ;-) */
renderer->scale = 20.0 * data->paper.scaling;
width = (data->extents.right - data->extents.left) * renderer->scale;
height = (data->extents.bottom - data->extents.top) * renderer->scale;
- DIAG_NOTE(g_message ("PNG Surface %dx%d\n", (int)width, (int)height));
- renderer->surface = cairo_png_surface_create (file,
- CAIRO_FORMAT_ARGB32,
- (int)width, (int)height);
- /* although it is slow enough with out this prefer quality over speed */
- cairo_surface_set_filter (renderer->surface, CAIRO_FILTER_BEST);
+ DIAG_NOTE(g_message ("PNG Surface %dx%d\n", (int)width, (int)height));
+ /* use case screwed by API shakeup. We need to special case */
+ renderer->surface = cairo_image_surface_create(
+ CAIRO_FORMAT_ARGB32,
+ (int)width, (int)height);
+ /* an extra refernce to make it survive end_render():cairo_surface_destroy() */
+ cairo_surface_reference(renderer->surface);
+ break;
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+ case OUTPUT_PDF :
+ /* I just don't get how the scalin is supposed to work, dpi versus page size ? */
+ renderer->scale = 20.0 * data->paper.scaling;
+ DIAG_NOTE(g_message ("PDF Surface %dx%d\n", (int)width, (int)height));
+ renderer->surface = cairo_pdf_surface_create (filename,
+ data->paper.width / 2.54, data->paper.height / 2.54);
+ break;
+#endif
+ /* the default Cairo/win32 surface isn't able to do such ... */
+#ifdef CAIRO_HAS_WIN32X_SURFACE
+ case OUTPUT_EMF :
+ renderer->scale = 72.0;
+ renderer->surface = cairo_win32_surface_create (filename, NULL, CAIRO_WIN32_TARGET_EMF, 0, 0);
+ break;
+ case OUTPUT_WMF :
+ renderer->scale = 72.0;
+ renderer->surface = cairo_win32_surface_create (filename, NULL, CAIRO_WIN32_TARGET_WMF, 0, 0);
+ break;
+ case OUTPUT_CB :
+ /* just testing, does not create a file but puts content in the clpboard */
+ renderer->scale = 72.0;
+ renderer->surface = cairo_win32_surface_create (filename, NULL, CAIRO_WIN32_TARGET_CLIPBOARD, 0, 0);
break;
#endif
default :
@@ -958,7 +1042,13 @@
data->extents.left, data->extents.top, data->extents.right, data->extents.bottom));
data_render(data, DIA_RENDERER(renderer), NULL, NULL, NULL);
- fclose (file);
+#if defined CAIRO_HAS_PNG_FUNCTIONS
+ if (OUTPUT_PNGA == kind || OUTPUT_PNG == kind)
+ {
+ cairo_surface_write_to_png(renderer->surface, filename);
+ cairo_surface_destroy(renderer->surface);
+ }
+#endif
g_object_unref(renderer);
}
@@ -968,7 +1058,16 @@
ps_extensions,
export_data,
(void*)OUTPUT_PS,
- NULL
+ "cairo-ps" /* unique name */
+};
+
+static const gchar *pdf_extensions[] = { "pdf", NULL };
+static DiaExportFilter pdf_export_filter = {
+ N_("Cairo Portable Document Format"),
+ pdf_extensions,
+ export_data,
+ (void*)OUTPUT_PDF,
+ "cairo-pdf"
};
static const gchar *png_extensions[] = { "png", NULL };
@@ -977,20 +1076,70 @@
png_extensions,
export_data,
(void*)OUTPUT_PNG,
- NULL
+ "cairo-png"
};
-#endif
+static DiaExportFilter pnga_export_filter = {
+ N_("Cairo PNG (with alpha)"),
+ png_extensions,
+ export_data,
+ (void*)OUTPUT_PNGA,
+ "cairo-alpha-png"
+};
+
+static const gchar *emf_extensions[] = { "wmf", NULL };
+static DiaExportFilter emf_export_filter = {
+ N_("Cairo WMF"),
+ emf_extensions,
+ export_data,
+ (void*)OUTPUT_EMF,
+ "cairo-emf"
+};
+
+static const gchar *wmf_extensions[] = { "wmf", NULL };
+static DiaExportFilter wmf_export_filter = {
+ N_("Cairo old WMF"),
+ wmf_extensions,
+ export_data,
+ (void*)OUTPUT_WMF,
+ "cairo-wmf"
+};
+
+static const gchar *cb_extensions[] = { "cb", NULL };
+static DiaExportFilter cb_export_filter = {
+ N_("Cairo Clipboard"),
+ cb_extensions,
+ export_data,
+ (void*)OUTPUT_CB,
+ "cairo-clipboard"
+};
+
+#endif /* HAVE_CAIRO */
static gboolean
_plugin_can_unload (PluginInfo *info)
{
- return FALSE;
+ return TRUE;
}
static void
_plugin_unload (PluginInfo *info)
{
+#ifdef CAIRO_HAS_PS_SURFACE
+ filter_unregister_export(&ps_export_filter);
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+ filter_unregister_export(&pdf_export_filter);
+#endif
+#if defined CAIRO_HAS_PNG_SURFACE || defined CAIRO_HAS_PNG_FUNCTIONS
+ filter_unregister_export(&png_export_filter);
+ filter_unregister_export(&pnga_export_filter);
+#endif
+#ifdef CAIRO_HAS_WIN32X_SURFACE
+ filter_unregister_export(&emf_export_filter);
+ filter_unregister_export(&wmf_export_filter);
+ filter_unregister_export(&cb_export_filter);
+#endif
}
/* --- dia plug-in interface --- */
@@ -1006,13 +1155,21 @@
_plugin_unload))
return DIA_PLUGIN_INIT_ERROR;
-#if HAVE_CAIRO
#ifdef CAIRO_HAS_PS_SURFACE
filter_register_export(&ps_export_filter);
#endif
-#ifdef CAIRO_HAS_PNG_SURFACE
+#ifdef CAIRO_HAS_PDF_SURFACE
+ filter_register_export(&pdf_export_filter);
+#endif
+#if defined CAIRO_HAS_PNG_SURFACE || defined CAIRO_HAS_PNG_FUNCTIONS
filter_register_export(&png_export_filter);
+ filter_register_export(&pnga_export_filter);
#endif
+#ifdef CAIRO_HAS_WIN32X_SURFACE
+ filter_register_export(&emf_export_filter);
+ filter_register_export(&wmf_export_filter);
+ filter_register_export(&cb_export_filter);
#endif
+
return DIA_PLUGIN_INIT_OK;
}