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;
 }
openSUSE Build Service is sponsored by