summaryrefslogtreecommitdiff
path: root/cd/src/cairo
diff options
context:
space:
mode:
Diffstat (limited to 'cd/src/cairo')
-rw-r--r--cd/src/cairo/cdcairo.c2110
-rw-r--r--cd/src/cairo/cdcairo.def9
-rw-r--r--cd/src/cairo/cdcairoctx.h88
-rw-r--r--cd/src/cairo/cdcairodbuf.c169
-rw-r--r--cd/src/cairo/cdcairoemf.c122
-rw-r--r--cd/src/cairo/cdcairoimg.c51
-rw-r--r--cd/src/cairo/cdcairoirgb.c159
-rw-r--r--cd/src/cairo/cdcaironative_gdk.c80
-rw-r--r--cd/src/cairo/cdcaironative_win32.c160
-rw-r--r--cd/src/cairo/cdcaironative_x11.c98
-rw-r--r--cd/src/cairo/cdcairopdf.c122
-rw-r--r--cd/src/cairo/cdcairoplus.c30
-rw-r--r--cd/src/cairo/cdcairoprn_unix.c196
-rw-r--r--cd/src/cairo/cdcairoprn_win32.c194
-rw-r--r--cd/src/cairo/cdcairops.c172
-rw-r--r--cd/src/cairo/cdcairosvg.c83
16 files changed, 3843 insertions, 0 deletions
diff --git a/cd/src/cairo/cdcairo.c b/cd/src/cairo/cdcairo.c
new file mode 100644
index 0000000..b86c046
--- /dev/null
+++ b/cd/src/cairo/cdcairo.c
@@ -0,0 +1,2110 @@
+/** \file
+* \brief Cairo Base Driver
+*
+* See Copyright Notice in cd.h
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <math.h>
+
+#include <glib.h>
+#include <pango/pangocairo.h>
+
+#include "cdcairoctx.h"
+
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+static int sStrIsAscii(const char* str)
+{
+ while(*str)
+ {
+ int c = *str;
+ if (c < 0)
+ return 0;
+ str++;
+ }
+ return 1;
+}
+
+static char* sStrToUTF8(const char *str, const char* charset, int length)
+{
+ return g_convert(str, length, "UTF-8", charset, NULL, NULL, NULL);
+}
+
+static char* sStrConvertToUTF8(cdCtxCanvas *ctxcanvas, const char* str, int length)
+{
+ const char *charset = NULL;
+
+ if (!str || *str == 0)
+ return (char*)str;
+
+ if (g_get_charset(&charset)) /* current locale is already UTF-8 */
+ {
+ if (g_utf8_validate(str, -1, NULL))
+ {
+ return (char*)str;
+ }
+ else
+ {
+ ctxcanvas->strLastConvertUTF8 = sStrToUTF8(str, "ISO8859-1", length); /* if string is not UTF-8, assume ISO8859-1 */
+
+ if (!ctxcanvas->strLastConvertUTF8)
+ return (char*)str;
+
+ return ctxcanvas->strLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (sStrIsAscii(str) || !charset)
+ {
+ return (char*)str;
+ }
+ else if (charset)
+ {
+ ctxcanvas->strLastConvertUTF8 = sStrToUTF8(str, charset, length);
+
+ if (!ctxcanvas->strLastConvertUTF8)
+ return (char*)str;
+
+ return ctxcanvas->strLastConvertUTF8;
+ }
+ }
+
+ return (char*)str;
+}
+
+static void sUpdateFill(cdCtxCanvas *ctxcanvas, int fill)
+{
+ if (fill == 0 || ctxcanvas->canvas->interior_style == CD_SOLID)
+ {
+ if (ctxcanvas->last_source == 0)
+ return;
+
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->solid);
+ ctxcanvas->last_source = 0;
+ }
+ else
+ {
+ if (ctxcanvas->last_source == 1)
+ return;
+
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern);
+ ctxcanvas->last_source = 1;
+ }
+}
+
+/******************************************************/
+
+void cdcairoKillCanvas(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->solid)
+ cairo_pattern_destroy(ctxcanvas->solid);
+
+ if (ctxcanvas->pattern)
+ cairo_pattern_destroy(ctxcanvas->pattern);
+
+ if (ctxcanvas->fontdesc) pango_font_description_free(ctxcanvas->fontdesc);
+ if (ctxcanvas->fontlayout) g_object_unref(ctxcanvas->fontlayout);
+ if (ctxcanvas->fontcontext) g_object_unref(ctxcanvas->fontcontext);
+
+ if (ctxcanvas->strLastConvertUTF8)
+ g_free(ctxcanvas->strLastConvertUTF8);
+
+ cairo_destroy(ctxcanvas->cr);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+/******************************************************/
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ cairo_surface_flush(cairo_get_target(ctxcanvas->cr));
+ cairo_show_page(ctxcanvas->cr);
+}
+
+/******************************************************/
+
+static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA)
+ return;
+
+ cairo_reset_clip(ctxcanvas->cr);
+ cairo_rectangle(ctxcanvas->cr, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
+ cairo_clip(ctxcanvas->cr);
+}
+
+static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ cdfcliparea(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax);
+}
+
+static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
+{
+ cairo_reset_clip(ctxcanvas->cr);
+
+ switch (mode)
+ {
+ case CD_CLIPOFF:
+ cairo_rectangle(ctxcanvas->cr, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ break;
+ case CD_CLIPAREA:
+ cairo_rectangle(ctxcanvas->cr, ctxcanvas->canvas->clip_frect.xmin,
+ ctxcanvas->canvas->clip_frect.ymin,
+ ctxcanvas->canvas->clip_frect.xmax,
+ ctxcanvas->canvas->clip_frect.ymax);
+ break;
+ case CD_CLIPPOLYGON:
+ {
+ int hole_index = 0;
+ int i;
+
+ if (ctxcanvas->canvas->clip_poly)
+ {
+ cdPoint *poly = ctxcanvas->canvas->clip_poly;
+ cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y);
+ for (i=1; i<ctxcanvas->canvas->clip_poly_n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ }
+ }
+ else if (ctxcanvas->canvas->clip_fpoly)
+ {
+ cdfPoint *poly = ctxcanvas->canvas->clip_fpoly;
+ cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y);
+ for (i=1; i<ctxcanvas->canvas->clip_poly_n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ }
+ }
+ break;
+ }
+ case CD_CLIPREGION:
+ break;
+ }
+
+ cairo_clip(ctxcanvas->cr);
+
+ return mode;
+}
+
+/******************************************************/
+
+#define CD_ALPHAPRE(_src, _alpha) (((_src)*(_alpha))/255)
+
+static unsigned long sEncodeRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ /* Pre-multiplied alpha */
+ if (a != 255)
+ {
+ r = CD_ALPHAPRE(r, a);
+ g = CD_ALPHAPRE(g, a);
+ b = CD_ALPHAPRE(b, a);
+ }
+
+ return (((unsigned long)a) << 24) |
+ (((unsigned long)r) << 16) |
+ (((unsigned long)g) << 8) |
+ (((unsigned long)b) << 0);
+}
+
+static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* userdata, int (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* userdata, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a))
+{
+ int i, j, offset, ret;
+ unsigned char r, g, b, a;
+ cairo_surface_t* pattern_surface;
+ unsigned long* data;
+
+ pattern_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, n, m);
+
+ data = (unsigned long*)cairo_image_surface_get_data(pattern_surface);
+ offset = cairo_image_surface_get_stride(pattern_surface)/4 - n;
+
+ for (j = 0; j < m; j++)
+ {
+ for (i = 0; i < n; i++)
+ {
+ /* internal transform, affects also pattern orientation */
+ if (ctxcanvas->canvas->invert_yaxis)
+ ret = data2rgb(ctxcanvas, n, i, m-1-j, userdata, &r, &g, &b, &a);
+ else
+ ret = data2rgb(ctxcanvas, n, i, j, userdata, &r, &g, &b, &a);
+
+ if (ret == -1)
+ {
+ data++; /* already transparent */
+ continue;
+ }
+
+ *data++ = sEncodeRGBA(r, g, b, a);
+ }
+
+ if (offset)
+ data += offset;
+ }
+
+ if (ctxcanvas->pattern)
+ cairo_pattern_destroy(ctxcanvas->pattern);
+
+ ctxcanvas->pattern = cairo_pattern_create_for_surface(pattern_surface);
+ cairo_pattern_reference(ctxcanvas->pattern);
+ cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_surface_destroy(pattern_surface);
+}
+
+static int long2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a)
+{
+ long* long_data = (long*)data;
+ long c = long_data[j*n+i];
+ (void)ctxcanvas;
+ cdDecodeColor(c, r, g, b);
+ *a = cdDecodeAlpha(c);
+ return 1;
+}
+
+static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern)
+{
+ make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb);
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern);
+ ctxcanvas->last_source = 1;
+}
+
+static int uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a)
+{
+ unsigned char* uchar_data = (unsigned char*)data;
+ if (uchar_data[j*n+i])
+ {
+ cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b);
+ *a = cdDecodeAlpha(ctxcanvas->canvas->foreground);
+ }
+ else
+ {
+ if (ctxcanvas->canvas->back_opacity == CD_TRANSPARENT)
+ return -1;
+ else
+ {
+ cdDecodeColor(ctxcanvas->canvas->background, r, g, b);
+ *a = cdDecodeAlpha(ctxcanvas->canvas->background);
+ }
+ }
+
+ return 1;
+}
+
+static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple)
+{
+ make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb);
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern);
+ ctxcanvas->last_source = 1;
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int style)
+{
+ int hsize = ctxcanvas->hatchboxsize;
+ int hhalf = hsize / 2;
+ cairo_surface_t* hatch_surface;
+ cairo_t* cr;
+
+ hatch_surface = cairo_surface_create_similar(cairo_get_target(ctxcanvas->cr), CAIRO_CONTENT_COLOR_ALPHA, hsize, hsize);
+ cr = cairo_create(hatch_surface);
+
+ if (ctxcanvas->canvas->back_opacity == CD_OPAQUE)
+ {
+ cairo_set_source_rgba(cr, cdCairoGetRed(ctxcanvas->canvas->background), cdCairoGetGreen(ctxcanvas->canvas->background), cdCairoGetBlue(ctxcanvas->canvas->background), cdCairoGetAlpha(ctxcanvas->canvas->background));
+ cairo_rectangle(cr, 0, 0, hsize, hsize);
+ cairo_fill(cr);
+ }
+
+ cairo_set_source_rgba(cr, cdCairoGetRed(ctxcanvas->canvas->foreground), cdCairoGetGreen(ctxcanvas->canvas->foreground), cdCairoGetBlue(ctxcanvas->canvas->foreground), cdCairoGetAlpha(ctxcanvas->canvas->foreground));
+
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
+ cairo_set_line_width(cr, 1);
+
+ switch(style)
+ {
+ case CD_HORIZONTAL:
+ cairo_move_to(cr, 0.0, (double)hhalf);
+ cairo_line_to(cr, (double)hsize, (double)hhalf);
+ break;
+ case CD_VERTICAL:
+ cairo_move_to(cr, (double)hhalf, 0.0);
+ cairo_line_to(cr, (double)hhalf, (double)hsize);
+ break;
+ case CD_BDIAGONAL:
+ cairo_move_to(cr, 0.0, (double)hsize);
+ cairo_line_to(cr, (double)hsize, 0.0);
+ break;
+ case CD_FDIAGONAL:
+ cairo_move_to(cr, 0.0, 0.0);
+ cairo_line_to(cr, (double)hsize, (double)hsize);
+ break;
+ case CD_CROSS:
+ cairo_move_to(cr, (double)hsize, 0.0);
+ cairo_line_to(cr, (double)hsize, (double)hsize);
+ cairo_move_to(cr, 0.0, (double)hhalf);
+ cairo_line_to(cr, (double)hsize, (double)hhalf);
+ break;
+ case CD_DIAGCROSS:
+ cairo_move_to(cr, 0.0, 0.0);
+ cairo_line_to(cr, (double)hsize, (double)hsize);
+ cairo_move_to(cr, (double)hsize, 0.0);
+ cairo_line_to(cr, 0.0, (double)hsize);
+ break;
+ }
+
+ cairo_stroke(cr);
+
+ if (ctxcanvas->pattern)
+ cairo_pattern_destroy(ctxcanvas->pattern);
+
+ ctxcanvas->pattern = cairo_pattern_create_for_surface(hatch_surface);
+ cairo_pattern_reference(ctxcanvas->pattern);
+ cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_surface_destroy(hatch_surface);
+ cairo_destroy(cr);
+
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern);
+ ctxcanvas->last_source = 1;
+
+ return style;
+}
+
+/******************************************************/
+/* attributes */
+/******************************************************/
+
+static int cdinteriorstyle (cdCtxCanvas* ctxcanvas, int style)
+{
+ switch (style)
+ {
+ case CD_SOLID:
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->solid);
+ ctxcanvas->last_source = 0;
+ break;
+ /* must recriate the current pattern */
+ case CD_HATCH:
+ cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style);
+ break;
+ case CD_STIPPLE:
+ cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple);
+ break;
+ case CD_PATTERN:
+ cdpattern(ctxcanvas, ctxcanvas->canvas->pattern_w, ctxcanvas->canvas->pattern_h, ctxcanvas->canvas->pattern);
+ break;
+ }
+
+ return style;
+}
+
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ double dashes[10];
+
+ switch (style)
+ {
+ case CD_CONTINUOUS : /* empty dash */
+ cairo_set_dash(ctxcanvas->cr, 0, 0, 0);
+ break;
+ case CD_DASHED :
+ dashes[0] = 6.0; dashes[1] = 2.0;
+ cairo_set_dash(ctxcanvas->cr, dashes, 2, 0);
+ break;
+ case CD_DOTTED :
+ dashes[0] = 2.0; dashes[1] = 2.0;
+ cairo_set_dash(ctxcanvas->cr, dashes, 2, 0);
+ break;
+ case CD_DASH_DOT :
+ dashes[0] = 6.0; dashes[1] = 2.0;
+ dashes[2] = 2.0; dashes[3] = 2.0;
+ cairo_set_dash(ctxcanvas->cr, dashes, 4, 0);
+ break;
+ case CD_DASH_DOT_DOT :
+ dashes[0] = 6.0; dashes[1] = 2.0;
+ dashes[2] = 2.0; dashes[3] = 2.0;
+ dashes[4] = 2.0; dashes[5] = 2.0;
+ cairo_set_dash(ctxcanvas->cr, dashes, 6, 0);
+ break;
+ case CD_CUSTOM :
+ {
+ int i;
+ double* dash_style = (double*)malloc(sizeof(double)*ctxcanvas->canvas->line_dashes_count);
+
+ for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++)
+ dash_style[i] = (double)ctxcanvas->canvas->line_dashes[i];
+
+ cairo_set_dash(ctxcanvas->cr, dash_style, ctxcanvas->canvas->line_dashes_count, 0);
+
+ free(dash_style);
+ }
+ break;
+ }
+
+ return style;
+}
+
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ if(width == 0)
+ width = 1;
+
+ cairo_set_line_width(ctxcanvas->cr, (double)width);
+
+ return width;
+}
+
+static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join)
+{
+ int cd2ps_join[] = {CAIRO_LINE_JOIN_MITER, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_JOIN_ROUND};
+
+ cairo_set_line_join(ctxcanvas->cr, cd2ps_join[join]);
+
+ return join;
+}
+
+static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap)
+{
+ int cd2pdf_cap[] = {CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_SQUARE, CAIRO_LINE_CAP_ROUND};
+
+ cairo_set_line_cap(ctxcanvas->cr, cd2pdf_cap[cap]);
+
+ return cap;
+}
+
+static int cdfont(cdCtxCanvas *ctxcanvas, const char *typeface, int style, int size)
+{
+ int is_italic = 0, is_bold = 0; /* default is CD_PLAIN */
+ int is_strikeout = 0, is_underline = 0;
+ char font[256];
+ PangoAttrList *attrs;
+
+ if (cdStrEqualNoCase(typeface, "Courier") || cdStrEqualNoCase(typeface, "Courier New"))
+ typeface = "Monospace";
+ else if (cdStrEqualNoCase(typeface, "Times") || cdStrEqualNoCase(typeface, "Times New Roman"))
+ typeface = "Serif";
+ else if (cdStrEqualNoCase(typeface, "Helvetica") || cdStrEqualNoCase(typeface, "Arial"))
+ typeface = "Sans";
+
+ if (style & CD_BOLD)
+ is_bold = 1;
+
+ if (style & CD_ITALIC)
+ is_italic = 1;
+
+ if (style & CD_UNDERLINE)
+ is_underline = 1;
+
+ if (style & CD_STRIKEOUT)
+ is_strikeout = 1;
+
+ size = cdGetFontSizePoints(ctxcanvas->canvas, size);
+
+ sprintf(font, "%s, %s%s%d", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", size);
+
+ if (ctxcanvas->fontdesc)
+ pango_font_description_free(ctxcanvas->fontdesc);
+
+ ctxcanvas->fontdesc = pango_font_description_from_string(font);
+
+ if (!ctxcanvas->fontdesc)
+ return 0;
+
+ if (ctxcanvas->fontlayout)
+ g_object_unref(ctxcanvas->fontlayout);
+
+ ctxcanvas->fontlayout = pango_layout_new(ctxcanvas->fontcontext);
+ pango_layout_set_font_description(ctxcanvas->fontlayout, ctxcanvas->fontdesc);
+
+ attrs = pango_attr_list_new();
+ pango_attr_list_insert(attrs, pango_attribute_copy(pango_attr_strikethrough_new(is_strikeout ? TRUE : FALSE)));
+ pango_attr_list_insert(attrs, pango_attribute_copy(pango_attr_underline_new(is_underline ? PANGO_UNDERLINE_SINGLE : PANGO_UNDERLINE_NONE)));
+ pango_layout_set_attributes(ctxcanvas->fontlayout, attrs);
+
+ pango_attr_list_unref(attrs);
+
+ pango_cairo_update_layout(ctxcanvas->cr, ctxcanvas->fontlayout);
+
+ return 1;
+}
+
+static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ PangoFontMetrics* metrics;
+ int charwidth, charheight, charascent, chardescent;
+
+ if(!ctxcanvas->fontdesc)
+ return;
+
+ pango_cairo_update_layout(ctxcanvas->cr, ctxcanvas->fontlayout);
+ metrics = pango_context_get_metrics(ctxcanvas->fontcontext, ctxcanvas->fontdesc, pango_context_get_language(ctxcanvas->fontcontext));
+ charascent = pango_font_metrics_get_ascent(metrics);
+ chardescent = pango_font_metrics_get_descent(metrics);
+ charheight = charascent + chardescent;
+ charwidth = pango_font_metrics_get_approximate_char_width(metrics);
+
+ if (max_width) *max_width = (((charwidth) + PANGO_SCALE/2) / PANGO_SCALE);
+ if (height) *height = (((charheight) + PANGO_SCALE/2) / PANGO_SCALE);
+ if (ascent) *ascent = (((charascent) + PANGO_SCALE/2) / PANGO_SCALE);
+ if (descent) *descent = (((chardescent) + PANGO_SCALE/2) / PANGO_SCALE);
+
+ pango_font_metrics_unref(metrics);
+}
+
+static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ if (ctxcanvas->solid)
+ cairo_pattern_destroy(ctxcanvas->solid);
+
+ cairo_set_source_rgba(ctxcanvas->cr, cdCairoGetRed(color),
+ cdCairoGetGreen(color),
+ cdCairoGetBlue(color),
+ cdCairoGetAlpha(color));
+ ctxcanvas->solid = cairo_get_source(ctxcanvas->cr);
+ cairo_pattern_reference(ctxcanvas->solid);
+ ctxcanvas->last_source = 0;
+ return color;
+}
+
+
+/******************************************************/
+
+static void sSetTransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ if (matrix)
+ {
+ cairo_matrix_t mtx;
+
+ /* configure a bottom-up coordinate system */
+ mtx.xx = 1; mtx.yx = 0;
+ mtx.xy = 0; mtx.yy = -1;
+ mtx.x0 = 0; mtx.y0 = (ctxcanvas->canvas->h-1);
+ cairo_transform(ctxcanvas->cr, &mtx);
+
+ mtx.xx = matrix[0]; mtx.yx = matrix[1];
+ mtx.xy = matrix[2]; mtx.yy = matrix[3];
+ mtx.x0 = matrix[4]; mtx.y0 = matrix[5];
+ cairo_transform(ctxcanvas->cr, &mtx);
+ }
+ else if (ctxcanvas->rotate_angle)
+ {
+ /* rotation = translate to point + rotation + translate back */
+ /* the rotation must be corrected because of the Y axis orientation */
+ cairo_translate(ctxcanvas->cr, ctxcanvas->rotate_center_x, _cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y));
+ cairo_rotate(ctxcanvas->cr, (double)-ctxcanvas->rotate_angle * CD_DEG2RAD);
+ cairo_translate(ctxcanvas->cr, -ctxcanvas->rotate_center_x, -_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y));
+ }
+}
+
+static void cdclear(cdCtxCanvas* ctxcanvas)
+{
+ cairo_save (ctxcanvas->cr);
+ cairo_identity_matrix(ctxcanvas->cr);
+ cairo_reset_clip(ctxcanvas->cr);
+ cairo_rectangle(ctxcanvas->cr, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ cairo_clip(ctxcanvas->cr);
+ cairo_set_source_rgba(ctxcanvas->cr, cdCairoGetRed(ctxcanvas->canvas->background), cdCairoGetGreen(ctxcanvas->canvas->background), cdCairoGetBlue(ctxcanvas->canvas->background), cdCairoGetAlpha(ctxcanvas->canvas->background));
+ cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (ctxcanvas->cr); /* paints the current source everywhere within the current clip region. */
+ cairo_restore (ctxcanvas->cr);
+}
+
+static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2)
+{
+ sUpdateFill(ctxcanvas, 0);
+
+ cairo_move_to(ctxcanvas->cr, x1, y1);
+ cairo_line_to(ctxcanvas->cr, x2, y2);
+ cairo_stroke(ctxcanvas->cr);
+}
+
+static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ cdfline(ctxcanvas, (double)x1, (double)y1, (double)x2, (double)y2);
+}
+
+static void sFixAngles(cdCanvas* canvas, double *a1, double *a2, int swap)
+{
+ /* Cairo angles are clock-wise by default, in radians */
+
+ /* if NOT inverted means a transformation is set,
+ so the angle will follow the transformation that includes the axis invertion,
+ then it is already counter-clockwise */
+
+ if (canvas->invert_yaxis)
+ {
+ /* change orientation */
+ *a1 *= -1;
+ *a2 *= -1;
+
+ /* swap, so the start angle is the smaller */
+ if (swap)
+ {
+ double t = *a1;
+ *a1 = *a2;
+ *a2 = t;
+ }
+ }
+
+ /* convert to radians */
+ *a1 *= CD_DEG2RAD;
+ *a2 *= CD_DEG2RAD;
+}
+
+static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ sUpdateFill(ctxcanvas, 0);
+
+ sFixAngles(ctxcanvas->canvas, &a1, &a2, 1);
+
+ if (w == h)
+ {
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2);
+ cairo_stroke(ctxcanvas->cr);
+ }
+ else /* Ellipse: change the scale to create from the circle */
+ {
+ cairo_save(ctxcanvas->cr); /* save to use the local transform */
+
+ cairo_translate(ctxcanvas->cr, xc, yc);
+ cairo_scale(ctxcanvas->cr, w/h, 1.0);
+ cairo_translate(ctxcanvas->cr, -xc, -yc);
+
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+ cairo_stroke(ctxcanvas->cr);
+
+ cairo_restore(ctxcanvas->cr); /* restore from local */
+ }
+}
+
+static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ cdfarc(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2);
+}
+
+static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ sUpdateFill(ctxcanvas, 1);
+
+ sFixAngles(ctxcanvas->canvas, &a1, &a2, 1);
+
+ if (w == h)
+ {
+ cairo_move_to(ctxcanvas->cr, xc, yc);
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+ cairo_fill(ctxcanvas->cr);
+ }
+ else /* Ellipse: change the scale to create from the circle */
+ {
+ cairo_save(ctxcanvas->cr); /* save to use the local transform */
+
+ cairo_translate(ctxcanvas->cr, xc, yc);
+ cairo_scale(ctxcanvas->cr, w/h, 1.0);
+ cairo_translate(ctxcanvas->cr, -xc, -yc);
+
+ cairo_move_to(ctxcanvas->cr, xc, yc);
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+
+ cairo_fill(ctxcanvas->cr);
+
+ cairo_restore(ctxcanvas->cr); /* restore from local */
+ }
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ cdfsector(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2);
+}
+
+static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ sUpdateFill(ctxcanvas, 1);
+
+ sFixAngles(ctxcanvas->canvas, &a1, &a2, 1);
+
+ if (w == h)
+ {
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2);
+ cairo_fill(ctxcanvas->cr);
+ }
+ else /* Ellipse: change the scale to create from the circle */
+ {
+ cairo_save(ctxcanvas->cr); /* save to use the local transform */
+
+ /* local transform */
+ cairo_translate(ctxcanvas->cr, xc, yc);
+ cairo_scale(ctxcanvas->cr, w/h, 1.0);
+ cairo_translate(ctxcanvas->cr, -xc, -yc);
+
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+ cairo_fill(ctxcanvas->cr);
+
+ cairo_restore(ctxcanvas->cr); /* restore from local */
+ }
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ cdfchord(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2);
+}
+
+static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ sUpdateFill(ctxcanvas, 0);
+ cairo_rectangle(ctxcanvas->cr, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
+ cairo_stroke(ctxcanvas->cr);
+}
+
+static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ cdfrect(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax);
+}
+
+static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ sUpdateFill(ctxcanvas, 1);
+ cairo_rectangle(ctxcanvas->cr, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
+ cairo_fill(ctxcanvas->cr);
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ cdfbox(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax);
+}
+
+static void sGetTransformTextHeight(cdCanvas* canvas, int x, int y, int w, int h, int *hbox)
+{
+ int xmin, xmax, ymin, ymax;
+ int baseline, height, ascent;
+
+ /* distance from bottom to baseline */
+ cdgetfontdim(canvas->ctxcanvas, NULL, &height, &ascent, NULL);
+ baseline = height - ascent;
+
+ /* move to bottom-left */
+ cdTextTranslatePoint(canvas, x, y, w, h, baseline, &xmin, &ymin);
+
+ xmax = xmin + w-1;
+ ymax = ymin + h-1;
+
+ if (canvas->text_orientation)
+ {
+ double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD);
+ double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD);
+ int rectY[4];
+
+ cdRotatePointY(canvas, xmin, ymin, x, y, &rectY[0], sin_theta, cos_theta);
+ cdRotatePointY(canvas, xmax, ymin, x, y, &rectY[1], sin_theta, cos_theta);
+ cdRotatePointY(canvas, xmax, ymax, x, y, &rectY[2], sin_theta, cos_theta);
+ cdRotatePointY(canvas, xmin, ymax, x, y, &rectY[3], sin_theta, cos_theta);
+
+ ymin = ymax = rectY[0];
+ if (rectY[1] < ymin) ymin = rectY[1];
+ if (rectY[2] < ymin) ymin = rectY[2];
+ if (rectY[3] < ymin) ymin = rectY[3];
+ if (rectY[1] > ymax) ymax = rectY[1];
+ if (rectY[2] > ymax) ymax = rectY[2];
+ if (rectY[3] > ymax) ymax = rectY[3];
+ }
+
+ *hbox = ymax-ymin+1;
+}
+
+static void sSetTextTransform(cdCtxCanvas* ctxcanvas, double *x, double *y, int w, int h)
+{
+ int hbox;
+ cairo_matrix_t mtx;
+
+ sGetTransformTextHeight(ctxcanvas->canvas, (int)*x, (int)*y, w, h, &hbox);
+
+ /* move to (x,y) and remove a vertical offset since text reference point is top-left */
+ mtx.xx = 1; mtx.yx = 0;
+ mtx.xy = 0; mtx.yy = 1;
+ mtx.x0 = *x; mtx.y0 = *y - (hbox-1);
+ cairo_transform(ctxcanvas->cr, &mtx);
+
+ /* invert the text vertical orientation, relative to itself */
+ mtx.xx = 1; mtx.yx = 0;
+ mtx.xy = 0; mtx.yy = -1;
+ mtx.x0 = 0; mtx.y0 = hbox-1;
+ cairo_transform(ctxcanvas->cr, &mtx);
+
+ *x = 0;
+ *y = 0;
+}
+
+static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s, int len)
+{
+ PangoFontMetrics* metrics;
+ int w, h, desc, dir = -1, reset_transform = 0;
+
+ pango_layout_set_text(ctxcanvas->fontlayout, sStrConvertToUTF8(ctxcanvas, s, len), -1);
+
+ pango_layout_get_pixel_size(ctxcanvas->fontlayout, &w, &h);
+ metrics = pango_context_get_metrics(ctxcanvas->fontcontext, ctxcanvas->fontdesc, pango_context_get_language(ctxcanvas->fontcontext));
+ desc = (((pango_font_metrics_get_descent(metrics)) + PANGO_SCALE/2) / PANGO_SCALE);
+
+ if (ctxcanvas->canvas->text_orientation ||
+ ctxcanvas->canvas->use_matrix ||
+ ctxcanvas->rotate_angle)
+ reset_transform = 1;
+
+ if (reset_transform)
+ {
+ cairo_save (ctxcanvas->cr);
+ cairo_identity_matrix(ctxcanvas->cr);
+
+ if (ctxcanvas->job)
+ cairo_scale(ctxcanvas->cr, 0.25, 0.25); /* ??? */
+ }
+
+ if (ctxcanvas->canvas->text_orientation)
+ {
+ cairo_translate(ctxcanvas->cr, x, y);
+ cairo_rotate(ctxcanvas->cr, -ctxcanvas->canvas->text_orientation*CD_DEG2RAD);
+ cairo_translate(ctxcanvas->cr, -x, -y);
+ }
+
+ /* move to top-left corner of the text */
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_RIGHT:
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ x = x - w;
+ break;
+ case CD_BASE_CENTER:
+ case CD_CENTER:
+ case CD_NORTH:
+ case CD_SOUTH:
+ x = x - w/2;
+ break;
+ case CD_BASE_LEFT:
+ case CD_NORTH_WEST:
+ case CD_WEST:
+ case CD_SOUTH_WEST:
+ x = x;
+ break;
+ }
+
+ if (ctxcanvas->canvas->invert_yaxis)
+ dir = 1;
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_LEFT:
+ case CD_BASE_CENTER:
+ case CD_BASE_RIGHT:
+ y = y - (dir*h - desc);
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH_WEST:
+ case CD_SOUTH:
+ y = y - (dir*h);
+ break;
+ case CD_NORTH_EAST:
+ case CD_NORTH:
+ case CD_NORTH_WEST:
+ y = y;
+ break;
+ case CD_CENTER:
+ case CD_EAST:
+ case CD_WEST:
+ y = y - (dir*(h/2));
+ break;
+ }
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ double* matrix = ctxcanvas->canvas->matrix;
+ sSetTransform(ctxcanvas, matrix);
+ sSetTextTransform(ctxcanvas, &x, &y, w, h);
+ }
+ else
+ sSetTransform(ctxcanvas, NULL);
+
+ /* Inform Pango to re-layout the text with the new transformation */
+ pango_cairo_update_layout(ctxcanvas->cr, ctxcanvas->fontlayout);
+
+ sUpdateFill(ctxcanvas, 0);
+
+ cairo_move_to(ctxcanvas->cr, x, y);
+ pango_cairo_show_layout(ctxcanvas->cr, ctxcanvas->fontlayout);
+
+ if (reset_transform)
+ cairo_restore(ctxcanvas->cr);
+
+ pango_font_metrics_unref(metrics);
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s, int len)
+{
+ cdftext(ctxcanvas, (double)x, (double)y, s, len);
+}
+
+static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int len, int *width, int *height)
+{
+ if (!ctxcanvas->fontlayout)
+ return;
+
+ pango_cairo_update_layout(ctxcanvas->cr, ctxcanvas->fontlayout);
+ pango_layout_set_text(ctxcanvas->fontlayout, sStrConvertToUTF8(ctxcanvas, s, len), len);
+ pango_layout_get_pixel_size(ctxcanvas->fontlayout, width, height);
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_CLIP)
+ return;
+
+ if (mode == CD_PATH)
+ {
+ int p;
+
+ /* if there is any current path, remove it */
+ cairo_new_path(ctxcanvas->cr);
+
+ i = 0;
+ for (p=0; p<ctxcanvas->canvas->path_n; p++)
+ {
+ switch(ctxcanvas->canvas->path[p])
+ {
+ case CD_PATH_NEW:
+ cairo_new_path(ctxcanvas->cr);
+ break;
+ case CD_PATH_MOVETO:
+ if (i+1 > n) return;
+ cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ i++;
+ break;
+ case CD_PATH_LINETO:
+ if (i+1 > n) return;
+ cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ i++;
+ break;
+ case CD_PATH_ARC:
+ {
+ double xc, yc, w, h, a1, a2;
+
+ if (i+3 > n) return;
+
+ if (!cdCanvasGetArcPathF(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2))
+ return;
+
+ sFixAngles(ctxcanvas->canvas, &a1, &a2, 0); /* do not swap because we handle negative arcs here */
+
+ if (w == h)
+ {
+ if ((a2-a1)<0)
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2);
+ else
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2);
+ }
+ else /* Ellipse: change the scale to create from the circle */
+ {
+ cairo_save(ctxcanvas->cr); /* save to use the local transform */
+
+ cairo_translate(ctxcanvas->cr, xc, yc);
+ cairo_scale(ctxcanvas->cr, w/h, 1.0);
+ cairo_translate(ctxcanvas->cr, -xc, -yc);
+
+ if ((a2-a1)<0)
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+ else
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+
+ cairo_restore(ctxcanvas->cr); /* restore from local */
+ }
+
+ i += 3;
+ }
+ break;
+ case CD_PATH_CURVETO:
+ if (i+3 > n) return;
+ cairo_curve_to(ctxcanvas->cr, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y, poly[i+2].x, poly[i+2].y);
+ i += 3;
+ break;
+ case CD_PATH_CLOSE:
+ cairo_close_path(ctxcanvas->cr);
+ break;
+ case CD_PATH_FILL:
+ sUpdateFill(ctxcanvas, 1);
+ cairo_set_fill_rule(ctxcanvas->cr, ctxcanvas->canvas->fill_mode==CD_EVENODD? CAIRO_FILL_RULE_EVEN_ODD: CAIRO_FILL_RULE_WINDING);
+ cairo_fill(ctxcanvas->cr);
+ break;
+ case CD_PATH_STROKE:
+ sUpdateFill(ctxcanvas, 0);
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_PATH_FILLSTROKE:
+ sUpdateFill(ctxcanvas, 1);
+ cairo_set_fill_rule(ctxcanvas->cr, ctxcanvas->canvas->fill_mode==CD_EVENODD? CAIRO_FILL_RULE_EVEN_ODD: CAIRO_FILL_RULE_WINDING);
+ cairo_fill_preserve(ctxcanvas->cr);
+ sUpdateFill(ctxcanvas, 0);
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_PATH_CLIP:
+ cairo_set_fill_rule(ctxcanvas->cr, ctxcanvas->canvas->fill_mode==CD_EVENODD? CAIRO_FILL_RULE_EVEN_ODD: CAIRO_FILL_RULE_WINDING);
+ cairo_clip(ctxcanvas->cr);
+ break;
+ }
+ }
+ return;
+ }
+
+ if (mode == CD_FILL)
+ {
+ sUpdateFill(ctxcanvas, 1);
+
+ if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_EVEN_ODD);
+ else
+ cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_WINDING);
+ }
+ else
+ sUpdateFill(ctxcanvas, 0);
+
+ cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y);
+
+ if (mode == CD_BEZIER)
+ {
+ for (i=1; i<n; i+=3)
+ cairo_curve_to(ctxcanvas->cr, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y, poly[i+2].x, poly[i+2].y);
+ }
+ else
+ {
+ int hole_index = 0;
+
+ for (i=1; i<n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ }
+ }
+
+ switch (mode)
+ {
+ case CD_CLOSED_LINES :
+ cairo_close_path(ctxcanvas->cr);
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_OPEN_LINES :
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_BEZIER :
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_FILL :
+ cairo_fill(ctxcanvas->cr);
+ break;
+ }
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_CLIP)
+ return;
+
+ if (mode == CD_PATH)
+ {
+ int p;
+
+ /* if there is any current path, remove it */
+ cairo_new_path(ctxcanvas->cr);
+
+ i = 0;
+ for (p=0; p<ctxcanvas->canvas->path_n; p++)
+ {
+ switch(ctxcanvas->canvas->path[p])
+ {
+ case CD_PATH_NEW:
+ cairo_new_path(ctxcanvas->cr);
+ break;
+ case CD_PATH_MOVETO:
+ if (i+1 > n) return;
+ cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ i++;
+ break;
+ case CD_PATH_LINETO:
+ if (i+1 > n) return;
+ cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ i++;
+ break;
+ case CD_PATH_ARC:
+ {
+ double xc, yc, w, h, a1, a2;
+
+ if (i+3 > n) return;
+
+ if (!cdfCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2))
+ return;
+
+ sFixAngles(ctxcanvas->canvas, &a1, &a2, 0); /* do not swap because we handle negative arcs here */
+
+ if (w == h)
+ {
+ if ((a2-a1)<0)
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2);
+ else
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*w, a1, a2);
+ }
+ else /* Ellipse: change the scale to create from the circle */
+ {
+ cairo_save(ctxcanvas->cr); /* save to use the local transform */
+
+ cairo_translate(ctxcanvas->cr, xc, yc);
+ cairo_scale(ctxcanvas->cr, w/h, 1.0);
+ cairo_translate(ctxcanvas->cr, -xc, -yc);
+
+ if ((a2-a1)<0)
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+ else
+ cairo_arc(ctxcanvas->cr, xc, yc, 0.5*h, a1, a2);
+
+ cairo_restore(ctxcanvas->cr); /* restore from local */
+ }
+
+ i += 3;
+ }
+ break;
+ case CD_PATH_CURVETO:
+ if (i+3 > n) return;
+ cairo_curve_to(ctxcanvas->cr, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y, poly[i+2].x, poly[i+2].y);
+ i += 3;
+ break;
+ case CD_PATH_CLOSE:
+ cairo_close_path(ctxcanvas->cr);
+ break;
+ case CD_PATH_FILL:
+ sUpdateFill(ctxcanvas, 1);
+ cairo_set_fill_rule(ctxcanvas->cr, ctxcanvas->canvas->fill_mode==CD_EVENODD? CAIRO_FILL_RULE_EVEN_ODD: CAIRO_FILL_RULE_WINDING);
+ cairo_fill(ctxcanvas->cr);
+ break;
+ case CD_PATH_STROKE:
+ sUpdateFill(ctxcanvas, 0);
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_PATH_FILLSTROKE:
+ sUpdateFill(ctxcanvas, 1);
+ cairo_set_fill_rule(ctxcanvas->cr, ctxcanvas->canvas->fill_mode==CD_EVENODD? CAIRO_FILL_RULE_EVEN_ODD: CAIRO_FILL_RULE_WINDING);
+ cairo_fill_preserve(ctxcanvas->cr);
+ sUpdateFill(ctxcanvas, 0);
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_PATH_CLIP:
+ cairo_set_fill_rule(ctxcanvas->cr, ctxcanvas->canvas->fill_mode==CD_EVENODD? CAIRO_FILL_RULE_EVEN_ODD: CAIRO_FILL_RULE_WINDING);
+ cairo_clip(ctxcanvas->cr);
+ break;
+ }
+ }
+ return;
+ }
+
+ if (mode == CD_FILL)
+ {
+ sUpdateFill(ctxcanvas, 1);
+
+ if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_EVEN_ODD);
+ else
+ cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_WINDING);
+ }
+ else
+ sUpdateFill(ctxcanvas, 0);
+
+ cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y);
+
+ if (mode == CD_BEZIER)
+ {
+ for (i=1; i<n; i+=3)
+ cairo_curve_to(ctxcanvas->cr, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y, poly[i+2].x, poly[i+2].y);
+ }
+ else
+ {
+ int hole_index = 0;
+
+ for (i=1; i<n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y);
+ }
+ }
+
+ switch (mode)
+ {
+ case CD_CLOSED_LINES :
+ cairo_close_path(ctxcanvas->cr);
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_OPEN_LINES :
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_BEZIER :
+ cairo_stroke(ctxcanvas->cr);
+ break;
+ case CD_FILL :
+ cairo_fill(ctxcanvas->cr);
+ break;
+ }
+}
+
+/******************************************************/
+
+static void cdgetimagergb(cdCtxCanvas *ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h)
+{
+ int i, j, pos, offset;
+ unsigned long* data;
+ cairo_surface_t* image_surface;
+ cairo_t* cr;
+
+ cairo_save (ctxcanvas->cr);
+
+ /* reset to the identity. */
+ cairo_identity_matrix(ctxcanvas->cr);
+
+ if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */
+ y = _cdInvertYAxis(ctxcanvas->canvas, y);
+
+ /* y is the bottom-left of the image in CD, must be at upper-left */
+ y -= h-1;
+
+ image_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
+ cr = cairo_create(image_surface);
+
+ /* creates a pattern from the canvas and sets it as source in the image. */
+ cairo_set_source_surface(cr, cairo_get_target(ctxcanvas->cr), -x, -y);
+
+ cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_NONE);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr); /* paints the current source everywhere within the current clip region. */
+
+ data = (unsigned long*)cairo_image_surface_get_data(image_surface);
+ offset = cairo_image_surface_get_stride(image_surface)/4 - w;
+
+ for (i=0; i<h; i++)
+ {
+ for (j=0; j<w; j++)
+ {
+ pos = i*w+j;
+ r[pos] = cdRed(*data);
+ g[pos] = cdGreen(*data);
+ b[pos] = cdBlue(*data);
+ data++;
+ }
+
+ if (offset)
+ data += offset;
+ }
+
+ cairo_surface_destroy(image_surface);
+ cairo_destroy(cr);
+
+ cairo_restore(ctxcanvas->cr);
+}
+
+static void sFixImageY(cdCanvas* canvas, int *topdown, int *y, int h)
+{
+ if (canvas->invert_yaxis)
+ *topdown = 0;
+ else
+ *topdown = 1;
+
+ if (!(*topdown))
+ *y -= (h - 1); /* move Y to top-left corner, since it was at the bottom of the image */
+}
+
+static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int i, j, rw, rh, pos, offset, topdown;
+ unsigned long* data;
+ cairo_surface_t* image_surface;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ image_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, rw, rh);
+
+ data = (unsigned long*)cairo_image_surface_get_data(image_surface);
+ offset = cairo_image_surface_get_stride(image_surface)/4 - rw;
+
+ sFixImageY(ctxcanvas->canvas, &topdown, &y, h);
+
+ for (i=ymin; i<=ymax; i++)
+ {
+ for (j=xmin; j<=xmax; j++)
+ {
+ if (topdown)
+ pos = i*iw+j;
+ else
+ pos = (ymax+ymin - i)*iw+j;
+ *data++ = sEncodeRGBA(r[pos], g[pos], b[pos], 255);
+ }
+
+ if (offset)
+ data += offset;
+ }
+
+ cairo_save (ctxcanvas->cr);
+
+ cairo_rectangle(ctxcanvas->cr, x, y, w, h);
+ cairo_clip(ctxcanvas->cr);
+
+ if (w != rw || h != rh)
+ {
+ /* Scale *before* setting the source surface (1) */
+ cairo_translate(ctxcanvas->cr, x, y);
+ cairo_scale (ctxcanvas->cr, (double)w / rw, (double)h / rh);
+ cairo_translate(ctxcanvas->cr, -x, -y);
+ }
+
+ cairo_set_source_surface(ctxcanvas->cr, image_surface, x, y);
+ cairo_paint(ctxcanvas->cr);
+
+ cairo_surface_destroy(image_surface);
+ cairo_restore (ctxcanvas->cr);
+}
+
+static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int i, j, rw, rh, pos, offset, topdown;
+ unsigned long* data;
+ cairo_surface_t* image_surface;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rw, rh);
+
+ data = (unsigned long*)cairo_image_surface_get_data(image_surface);
+ offset = cairo_image_surface_get_stride(image_surface)/4 - rw;
+
+ sFixImageY(ctxcanvas->canvas, &topdown, &y, h);
+
+ for (i=ymin; i<=ymax; i++)
+ {
+ for (j=xmin; j<=xmax; j++)
+ {
+ if (topdown)
+ pos = i*iw+j;
+ else
+ pos = (ymax+ymin - i)*iw+j;
+ *data++ = sEncodeRGBA(r[pos], g[pos], b[pos], a[pos]);
+ }
+
+ if (offset)
+ data += offset;
+ }
+
+ cairo_save (ctxcanvas->cr);
+
+ cairo_rectangle(ctxcanvas->cr, x, y, w, h);
+ cairo_clip(ctxcanvas->cr);
+
+ if (w != rw || h != rh)
+ {
+ /* Scale *before* setting the source surface (1) */
+ cairo_translate(ctxcanvas->cr, x, y);
+ cairo_scale (ctxcanvas->cr, (double)w / rw, (double)h / rh);
+ cairo_translate(ctxcanvas->cr, -x, -y);
+ }
+
+ cairo_set_source_surface(ctxcanvas->cr, image_surface, x, y);
+ cairo_paint(ctxcanvas->cr);
+
+ cairo_surface_destroy(image_surface);
+ cairo_restore (ctxcanvas->cr);
+}
+
+static int sCalcPalSize(int size, const unsigned char *index)
+{
+ int i, pal_size = 0;
+
+ for (i = 0; i < size; i++)
+ {
+ if (index[i] > pal_size)
+ pal_size = index[i];
+ }
+
+ pal_size++;
+ return pal_size;
+}
+
+static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int i, j, rw, rh, pos, offset, pal_size, topdown;
+ unsigned long* data, cairo_colors[256], c;
+ cairo_surface_t* image_surface;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ image_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, rw, rh);
+
+ data = (unsigned long*)cairo_image_surface_get_data(image_surface);
+ offset = cairo_image_surface_get_stride(image_surface)/4 - rw;
+
+ pal_size = sCalcPalSize(iw*ih, index);
+ for (i=0; i<pal_size; i++)
+ {
+ c = colors[i];
+ cairo_colors[i] = sEncodeRGBA(cdRed(c), cdGreen(c), cdBlue(c), 255);
+ }
+
+ sFixImageY(ctxcanvas->canvas, &topdown, &y, h);
+
+ for (i=ymin; i<=ymax; i++)
+ {
+ for (j=xmin; j<=xmax; j++)
+ {
+ if (topdown)
+ pos = i*iw+j;
+ else
+ pos = (ymax+ymin - i)*iw+j;
+ *data++ = cairo_colors[index[pos]];
+ }
+
+ if (offset)
+ data += offset;
+ }
+
+ cairo_save (ctxcanvas->cr);
+
+ cairo_rectangle(ctxcanvas->cr, x, y, w, h);
+ cairo_clip(ctxcanvas->cr);
+
+ if (w != rw || h != rh)
+ {
+ /* Scale *before* setting the source surface (1) */
+ cairo_translate(ctxcanvas->cr, x, y);
+ cairo_scale (ctxcanvas->cr, (double)w / rw, (double)h / rh);
+ cairo_translate(ctxcanvas->cr, -x, -y);
+ }
+
+ cairo_set_source_surface(ctxcanvas->cr, image_surface, x, y);
+ cairo_paint(ctxcanvas->cr);
+
+ cairo_surface_destroy(image_surface);
+ cairo_restore (ctxcanvas->cr);
+}
+
+static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ cairo_pattern_t* old_source = cairo_get_source(ctxcanvas->cr);
+ cairo_set_source_rgba(ctxcanvas->cr, cdCairoGetRed(color), cdCairoGetGreen(color), cdCairoGetBlue(color), cdCairoGetAlpha(color));
+
+ cairo_move_to(ctxcanvas->cr, (double)x, (double)y);
+ cairo_arc(ctxcanvas->cr, (double)x, (double)y, 0.5, 0.0, 2 * M_PI);
+
+ cairo_fill(ctxcanvas->cr);
+ cairo_set_source(ctxcanvas->cr, old_source);
+}
+
+static cdCtxImage *cdcreateimage (cdCtxCanvas *ctxcanvas, int w, int h)
+{
+ cdCtxImage *ctximage = (cdCtxImage *)malloc(sizeof(cdCtxImage));
+ cairo_surface_t* img_surface;
+
+ ctximage->w = w;
+ ctximage->h = h;
+ ctximage->bpp = ctxcanvas->canvas->bpp;
+ ctximage->xres = ctxcanvas->canvas->xres;
+ ctximage->yres = ctxcanvas->canvas->yres;
+ ctximage->w_mm = ctximage->w / ctximage->xres;
+ ctximage->h_mm = ctximage->h / ctximage->yres;
+
+ img_surface = cairo_surface_create_similar(cairo_get_target(ctxcanvas->cr), CAIRO_CONTENT_COLOR_ALPHA, w, h);
+ ctximage->cr = cairo_create(img_surface);
+
+ if (!ctximage->cr)
+ {
+ free(ctximage);
+ return (void *)0;
+ }
+
+ cairo_rectangle(ctximage->cr, 0, 0, ctximage->w, ctximage->h);
+ cairo_set_source_rgba(ctximage->cr, 1.0, 0.0, 0.0, 1.0); /* white opaque */
+ cairo_fill(ctximage->cr);
+
+ cairo_surface_destroy(img_surface);
+
+ return (void*)ctximage;
+}
+
+static void cdkillimage (cdCtxImage *ctximage)
+{
+ cairo_destroy(ctximage->cr);
+ free(ctximage);
+}
+
+static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y)
+{
+ cairo_save (ctximage->cr);
+
+ /* reset to the identity. */
+ cairo_identity_matrix(ctximage->cr);
+
+ cairo_reset_clip(ctximage->cr);
+
+ if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */
+ y = _cdInvertYAxis(ctxcanvas->canvas, y);
+
+ /* y is the bottom-left of the image in CD, must be at upper-left */
+ y -= ctximage->h-1;
+
+ /* creates a pattern from the canvas and sets it as source in the image. */
+ cairo_set_source_surface(ctximage->cr, cairo_get_target(ctxcanvas->cr), -x, -y);
+
+ cairo_pattern_set_extend (cairo_get_source(ctximage->cr), CAIRO_EXTEND_NONE);
+ cairo_set_operator (ctximage->cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ctximage->cr); /* paints the current source everywhere within the current clip region. */
+
+ /* must restore matrix, clipping and source */
+ cairo_restore (ctximage->cr);
+}
+
+static void cdputimagerect (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax)
+{
+ cairo_save (ctxcanvas->cr);
+
+ /* y is the bottom-left of the image region in CD */
+ y -= (ymax-ymin+1)-1;
+
+ cairo_rectangle(ctxcanvas->cr, x, y, xmax-xmin+1, ymax-ymin+1);
+ cairo_clip(ctxcanvas->cr);
+
+ /* creates a pattern from the image and sets it as source in the canvas. */
+ cairo_set_source_surface(ctxcanvas->cr, cairo_get_target(ctximage->cr), x, y);
+
+ cairo_pattern_set_extend (cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE);
+ cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ctxcanvas->cr); /* paints the current source everywhere within the current clip region. */
+
+ /* must restore clipping and source */
+ cairo_restore (ctxcanvas->cr);
+}
+
+static void cdscrollarea (cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy)
+{
+ cairo_save (ctxcanvas->cr);
+
+ /* reset to identity */
+ cairo_identity_matrix(ctxcanvas->cr);
+
+ if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */
+ {
+ dy = -dy;
+ ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin);
+ ymax = _cdInvertYAxis(ctxcanvas->canvas, ymax);
+ _cdSwapInt(ymin, ymax);
+ }
+
+ cairo_rectangle(ctxcanvas->cr, xmin+dx, ymin+dy, xmax-xmin+1, ymax-ymin+1);
+ cairo_clip(ctxcanvas->cr);
+
+ /* creates a pattern from the canvas and sets it as source in the canvas. */
+ cairo_set_source_surface(ctxcanvas->cr, cairo_get_target(ctxcanvas->cr), xmin, ymin);
+
+ cairo_pattern_set_extend (cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE);
+ cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ctxcanvas->cr); /* paints the current source everywhere within the current clip region. */
+
+ /* must restore matrix, clipping and source */
+ cairo_restore (ctxcanvas->cr);
+}
+
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ /* reset to identity */
+ cairo_identity_matrix(ctxcanvas->cr);
+
+ if (ctxcanvas->job)
+ cairo_scale(ctxcanvas->cr, 0.25, 0.25); /* ??? */
+
+ if (matrix)
+ ctxcanvas->canvas->invert_yaxis = 0;
+ else
+ ctxcanvas->canvas->invert_yaxis = 1;
+
+ sSetTransform(ctxcanvas, matrix);
+}
+
+/******************************************************************/
+
+static void set_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ int hatchboxsize;
+
+ if (data == NULL)
+ {
+ ctxcanvas->hatchboxsize = 8;
+ return;
+ }
+
+ sscanf(data, "%d", &hatchboxsize);
+ ctxcanvas->hatchboxsize = hatchboxsize;
+}
+
+static char* get_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char size[10];
+ sprintf(size, "%d", ctxcanvas->hatchboxsize);
+ return size;
+}
+
+static cdAttribute hatchboxsize_attrib =
+{
+ "HATCHBOXSIZE",
+ set_hatchboxsize_attrib,
+ get_hatchboxsize_attrib
+};
+
+static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ int hole;
+
+ if (data == NULL)
+ {
+ ctxcanvas->holes = 0;
+ return;
+ }
+
+ sscanf(data, "%d", &hole);
+ ctxcanvas->poly_holes[ctxcanvas->holes] = hole;
+ ctxcanvas->holes++;
+}
+
+static char* get_poly_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char holes[10];
+ sprintf(holes, "%d", ctxcanvas->holes);
+ return holes;
+}
+
+static cdAttribute poly_attrib =
+{
+ "POLYHOLE",
+ set_poly_attrib,
+ get_poly_attrib
+};
+
+static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ /* ignore ROTATE if transform is set,
+ because there is native support for transformations */
+ if (ctxcanvas->canvas->use_matrix)
+ return;
+
+ if (data)
+ {
+ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle,
+ &ctxcanvas->rotate_center_x,
+ &ctxcanvas->rotate_center_y);
+ }
+ else
+ {
+ ctxcanvas->rotate_angle = 0;
+ ctxcanvas->rotate_center_x = 0;
+ ctxcanvas->rotate_center_y = 0;
+ }
+
+ cdtransform(ctxcanvas, NULL);
+}
+
+static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas)
+{
+ static char data[100];
+
+ if (!ctxcanvas->rotate_angle)
+ return NULL;
+
+ sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle,
+ ctxcanvas->rotate_center_x,
+ ctxcanvas->rotate_center_y);
+
+ return data;
+}
+
+static cdAttribute rotate_attrib =
+{
+ "ROTATE",
+ set_rotate_attrib,
+ get_rotate_attrib
+};
+
+static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (!data || data[0] == '0')
+ cairo_set_antialias(ctxcanvas->cr, CAIRO_ANTIALIAS_NONE);
+ else
+ cairo_set_antialias(ctxcanvas->cr, CAIRO_ANTIALIAS_DEFAULT);
+}
+
+static char* get_aa_attrib(cdCtxCanvas* ctxcanvas)
+{
+ if (cairo_get_antialias(ctxcanvas->cr) != CAIRO_ANTIALIAS_NONE)
+ return "1";
+ else
+ return "0";
+}
+
+static cdAttribute aa_attrib =
+{
+ "ANTIALIAS",
+ set_aa_attrib,
+ get_aa_attrib
+};
+
+static void set_pattern_image_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ if (data)
+ {
+ cdCtxImage *ctximage = (cdCtxImage *)data;
+
+ if (ctxcanvas->pattern)
+ cairo_pattern_destroy(ctxcanvas->pattern);
+
+ ctxcanvas->pattern = cairo_pattern_create_for_surface(cairo_get_target(ctximage->cr));
+ cairo_pattern_reference(ctxcanvas->pattern);
+ cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern);
+ ctxcanvas->last_source = 1;
+ }
+}
+
+static cdAttribute pattern_image_attrib =
+{
+ "PATTERNIMAGE",
+ set_pattern_image_attrib,
+ NULL
+};
+
+static void set_linegradient_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (data)
+ {
+ int x1, y1, x2, y2;
+ double offset;
+ int count = 1;
+
+ sscanf(data, "%d %d %d %d", &x1, &y1, &x2, &y2);
+
+ if (ctxcanvas->canvas->invert_yaxis)
+ {
+ y1 = _cdInvertYAxis(ctxcanvas->canvas, y1);
+ y2 = _cdInvertYAxis(ctxcanvas->canvas, y2);
+ }
+
+ if (ctxcanvas->pattern)
+ cairo_pattern_destroy(ctxcanvas->pattern);
+
+ ctxcanvas->pattern = cairo_pattern_create_linear((double)x1, (double)y1, (double)x2, (double)y2);
+ cairo_pattern_reference(ctxcanvas->pattern);
+
+ for(offset = 0.1; offset < 1.0; offset += 0.1)
+ {
+ if ( count % 2 )
+ {
+ cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset,
+ cdCairoGetRed(ctxcanvas->canvas->foreground),
+ cdCairoGetGreen(ctxcanvas->canvas->foreground),
+ cdCairoGetBlue(ctxcanvas->canvas->foreground));
+ }
+ else
+ {
+ cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset,
+ cdCairoGetRed(ctxcanvas->canvas->background),
+ cdCairoGetGreen(ctxcanvas->canvas->background),
+ cdCairoGetBlue(ctxcanvas->canvas->background));
+ }
+ count++;
+ }
+
+ cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern);
+ ctxcanvas->last_source = 1;
+ }
+}
+
+static char* get_linegradient_attrib(cdCtxCanvas* ctxcanvas)
+{
+ double x1, y1, x2, y2;
+
+ if (cairo_pattern_get_linear_points(ctxcanvas->pattern, &x1, &y1, &x2, &y2) == CAIRO_STATUS_SUCCESS)
+ {
+ static char data[100];
+ sprintf(data, "%d %d %d %d", (int)x1, (int)y1, (int)x2, (int)y2);
+ return data;
+ }
+ else
+ return NULL;
+}
+
+static cdAttribute linegradient_attrib =
+{
+ "LINEGRADIENT",
+ set_linegradient_attrib,
+ get_linegradient_attrib
+};
+
+static void set_radialgradient_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (data)
+ {
+ int cx1, cy1, cx2, cy2;
+ float rad1, rad2;
+ double offset;
+ int count = 1;
+
+ sscanf(data, "%d %d %g %d %d %g", &cx1, &cy1, &rad1, &cx2, &cy2, &rad2);
+
+ if (ctxcanvas->canvas->invert_yaxis)
+ {
+ cy1 = _cdInvertYAxis(ctxcanvas->canvas, cy1);
+ cy2 = _cdInvertYAxis(ctxcanvas->canvas, cy2);
+ }
+
+ if (ctxcanvas->pattern)
+ cairo_pattern_destroy(ctxcanvas->pattern);
+
+ ctxcanvas->pattern = cairo_pattern_create_radial((double)cx1, (double)cx1, (double)rad1, (double)cx2, (double)cx2, (double)rad2);
+ cairo_pattern_reference(ctxcanvas->pattern);
+
+ for(offset = 0.1; offset < 1.0; offset += 0.1)
+ {
+ if ( count % 2 )
+ {
+ cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset,
+ cdCairoGetRed(ctxcanvas->canvas->foreground),
+ cdCairoGetGreen(ctxcanvas->canvas->foreground),
+ cdCairoGetBlue(ctxcanvas->canvas->foreground));
+ }
+ else
+ {
+ cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset,
+ cdCairoGetRed(ctxcanvas->canvas->background),
+ cdCairoGetGreen(ctxcanvas->canvas->background),
+ cdCairoGetBlue(ctxcanvas->canvas->background));
+ }
+ count++;
+ }
+
+ cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern);
+ ctxcanvas->last_source = 1;
+ }
+}
+
+static char* get_radialgradient_attrib(cdCtxCanvas* ctxcanvas)
+{
+ double cx1, cy1, rad1, cx2, cy2, rad2;
+
+ if (cairo_pattern_get_radial_circles(ctxcanvas->pattern, &cx1, &cy1, &rad1, &cx2, &cy2, &rad2) == CAIRO_STATUS_SUCCESS)
+ {
+ static char data[100];
+ sprintf(data, "%d %d %g %d %d %g", (int)cx1, (int)cy1, (float)rad1, (int)cx2, (int)cy2, (float)rad2);
+ return data;
+ }
+ else
+ return NULL;
+}
+
+static cdAttribute radialgradient_attrib =
+{
+ "RADIALGRADIENT",
+ set_radialgradient_attrib,
+ get_radialgradient_attrib
+};
+
+static char* get_version_attrib(cdCtxCanvas* ctxcanvas)
+{
+ (void)ctxcanvas;
+ return (char*)cairo_version_string();
+}
+
+static cdAttribute version_attrib =
+{
+ "CAIROVERSION",
+ NULL,
+ get_version_attrib
+};
+
+static void set_interp_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (data && cdStrEqualNoCase(data, "BEST"))
+ cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_BEST);
+ else if (data && cdStrEqualNoCase(data, "NEAREST"))
+ cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_NEAREST);
+ else if (data && cdStrEqualNoCase(data, "FAST"))
+ cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_FAST);
+ else if (data && cdStrEqualNoCase(data, "BILINEAR"))
+ cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_BILINEAR);
+ else
+ cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_GOOD);
+}
+
+static char* get_interp_attrib(cdCtxCanvas* ctxcanvas)
+{
+ if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_BEST)
+ return "BEST";
+ else if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_NEAREST)
+ return "NEAREST";
+ else if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_FAST)
+ return "FAST";
+ else if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_BILINEAR)
+ return "BILINEAR";
+ else
+ return "GOOD";
+}
+
+static cdAttribute interp_attrib =
+{
+ "IMGINTERP",
+ set_interp_attrib,
+ get_interp_attrib
+};
+
+static char* get_cairodc_attrib(cdCtxCanvas *ctxcanvas)
+{
+ return (char*)ctxcanvas->cr;
+}
+
+static cdAttribute cairodc_attrib =
+{
+ "CAIRODC",
+ NULL,
+ get_cairodc_attrib
+};
+
+
+cdCtxCanvas *cdcairoCreateCanvas(cdCanvas* canvas, cairo_t* cr)
+{
+ cdCtxCanvas *ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ ctxcanvas->cr = cr;
+ ctxcanvas->canvas = canvas;
+ ctxcanvas->last_source = -1;
+ ctxcanvas->hatchboxsize = 8;
+
+ canvas->ctxcanvas = ctxcanvas;
+ canvas->invert_yaxis = 1;
+
+ ctxcanvas->fontcontext = pango_cairo_create_context(ctxcanvas->cr);
+ pango_context_set_language(ctxcanvas->fontcontext, pango_language_get_default());
+
+ cdRegisterAttribute(canvas, &rotate_attrib);
+ cdRegisterAttribute(canvas, &version_attrib);
+ cdRegisterAttribute(canvas, &poly_attrib);
+ cdRegisterAttribute(canvas, &aa_attrib);
+ cdRegisterAttribute(canvas, &linegradient_attrib);
+ cdRegisterAttribute(canvas, &radialgradient_attrib);
+ cdRegisterAttribute(canvas, &interp_attrib);
+ cdRegisterAttribute(canvas, &cairodc_attrib);
+ cdRegisterAttribute(canvas, &hatchboxsize_attrib);
+ cdRegisterAttribute(canvas, &pattern_image_attrib);
+
+ cairo_save(ctxcanvas->cr);
+ cairo_set_operator(ctxcanvas->cr, CAIRO_OPERATOR_OVER);
+
+ return ctxcanvas;
+}
+
+void cdcairoInitTable(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ canvas->cxClear = cdclear;
+
+ canvas->cxPixel = cdpixel;
+
+ canvas->cxLine = cdline;
+ canvas->cxPoly = cdpoly;
+ canvas->cxRect = cdrect;
+ canvas->cxBox = cdbox;
+ canvas->cxArc = cdarc;
+ canvas->cxSector = cdsector;
+ canvas->cxChord = cdchord;
+ canvas->cxText = cdtext;
+
+ canvas->cxFLine = cdfline;
+ canvas->cxFPoly = cdfpoly;
+ canvas->cxFRect = cdfrect;
+ canvas->cxFBox = cdfbox;
+ canvas->cxFArc = cdfarc;
+ canvas->cxFSector = cdfsector;
+ canvas->cxFChord = cdfchord;
+ canvas->cxFText = cdftext;
+
+ canvas->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxFClipArea = cdfcliparea;
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxLineCap = cdlinecap;
+ canvas->cxLineJoin = cdlinejoin;
+ canvas->cxInteriorStyle = cdinteriorstyle;
+ canvas->cxHatch = cdhatch;
+ canvas->cxStipple = cdstipple;
+ canvas->cxPattern = cdpattern;
+ canvas->cxFont = cdfont;
+ canvas->cxGetFontDim = cdgetfontdim;
+ canvas->cxGetTextSize = cdgettextsize;
+ canvas->cxTransform = cdtransform;
+ canvas->cxForeground = cdforeground;
+
+ canvas->cxGetImageRGB = cdgetimagergb;
+ canvas->cxScrollArea = cdscrollarea;
+
+ canvas->cxCreateImage = cdcreateimage;
+ canvas->cxGetImage = cdgetimage;
+ canvas->cxPutImageRect = cdputimagerect;
+ canvas->cxKillImage = cdkillimage;
+
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+}
diff --git a/cd/src/cairo/cdcairo.def b/cd/src/cairo/cdcairo.def
new file mode 100644
index 0000000..ad4dbeb
--- /dev/null
+++ b/cd/src/cairo/cdcairo.def
@@ -0,0 +1,9 @@
+EXPORTS
+ cdContextCairoImage
+ cdContextCairoImageRGB
+ cdContextCairoPS
+ cdContextCairoNativeWindow
+ cdContextCairoDBuffer
+ cdContextCairoSVG
+ cdContextCairoPDF
+ cdInitContextPlus
diff --git a/cd/src/cairo/cdcairoctx.h b/cd/src/cairo/cdcairoctx.h
new file mode 100644
index 0000000..8d1012c
--- /dev/null
+++ b/cd/src/cairo/cdcairoctx.h
@@ -0,0 +1,88 @@
+/** \file
+ * \brief Cairo Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __CDCAIROCTX_H
+#define __CDCAIROCTX_H
+
+#include <cairo.h>
+#include <pango/pango.h>
+
+#include "cd.h"
+#include "cd_private.h"
+
+#ifndef __GTK_PRINT_UNIX_DIALOG_H__
+typedef struct _GtkPrintJob GtkPrintJob;
+#endif
+
+struct _cdCtxImage {
+ unsigned int w, h;
+ double w_mm, h_mm; /* size in mm */
+ double xres, yres; /* resolution in pixels/mm */
+ int bpp;
+ cairo_t* cr;
+};
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ cairo_t* cr;
+
+ /* text attributes */
+ PangoContext *fontcontext;
+ PangoFontDescription *fontdesc;
+ PangoLayout *fontlayout;
+ char* strLastConvertUTF8;
+
+ /* fill attributes */
+ cairo_pattern_t *pattern, *solid;
+ int last_source;
+ int hatchboxsize;
+
+ /* custom attributes */
+
+ int img_format;
+
+ float rotate_angle;
+ int rotate_center_x;
+ int rotate_center_y;
+
+ int poly_holes[500];
+ int holes;
+
+ void* drawable; /* used in NativeWindow in GDK */
+
+#ifdef WIN32
+ void* hWnd; /* used in NativeWindow in Win32 */
+ void* hDC;
+ int isOwnedDC;
+#else
+ void* dpy; /* used in NativeWindow in X11 */
+ unsigned long wnd;
+#endif
+
+ int user_image; /* used in ImageRGB */
+ unsigned char *rgb;
+
+ int eps; /* used in PS */
+
+ cdImage* image_dbuffer; /* Used in double buffer driver */
+ cdCanvas* canvas_dbuffer;
+
+ GtkPrintJob* job; /* used in Printer (UNIX) */
+ char* printername; /* used in Printer (Win32) */
+};
+
+#define cdCairoGetRed(_) (((double)cdRed(_))/255.)
+#define cdCairoGetGreen(_) (((double)cdGreen(_))/255.)
+#define cdCairoGetBlue(_) (((double)cdBlue(_))/255.)
+#define cdCairoGetAlpha(_) (((double)cdAlpha(_))/255.)
+
+cdCtxCanvas *cdcairoCreateCanvas(cdCanvas* canvas, cairo_t* cr);
+void cdcairoInitTable(cdCanvas* canvas);
+void cdcairoKillCanvas(cdCtxCanvas *ctxcanvas);
+
+#endif
diff --git a/cd/src/cairo/cdcairodbuf.c b/cd/src/cairo/cdcairodbuf.c
new file mode 100644
index 0000000..1395e8c
--- /dev/null
+++ b/cd/src/cairo/cdcairodbuf.c
@@ -0,0 +1,169 @@
+/** \file
+ * \brief Cairo Double Buffer Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include "cdcairoctx.h"
+#include "cddbuf.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static void cdkillcanvas (cdCtxCanvas* ctxcanvas)
+{
+ cdKillImage(ctxcanvas->image_dbuffer);
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cddeactivate(cdCtxCanvas* ctxcanvas)
+{
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+ /* this is done in the canvas_dbuffer context */
+ cdCanvasDeactivate(canvas_dbuffer);
+}
+
+static void cdflush(cdCtxCanvas* ctxcanvas)
+{
+ int old_writemode;
+ cdImage* image_dbuffer = ctxcanvas->image_dbuffer;
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+
+ /* flush the writing in the image */
+ cairo_show_page(ctxcanvas->cr);
+
+ /* this is done in the canvas_dbuffer context */
+ /* Flush can be affected by Origin and Clipping, but not WriteMode */
+ old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE);
+ cdCanvasPutImageRect(canvas_dbuffer, image_dbuffer, 0, 0, 0, 0, 0, 0);
+ cdCanvasWriteMode(canvas_dbuffer, old_writemode);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, cdCanvas* canvas_dbuffer)
+{
+ int w, h;
+ cdCtxCanvas* ctxcanvas;
+ cdImage* image_dbuffer;
+ cdCtxImage* ctximage;
+
+ cdCanvasActivate(canvas_dbuffer);
+ w = canvas_dbuffer->w;
+ h = canvas_dbuffer->h;
+ if (w==0) w=1;
+ if (h==0) h=1;
+
+ /* this is done in the canvas_dbuffer context */
+ image_dbuffer = cdCanvasCreateImage(canvas_dbuffer, w, h);
+ if (!image_dbuffer)
+ return;
+
+ ctximage = image_dbuffer->ctximage;
+
+ /* Init the driver DBuffer */
+ ctxcanvas = cdcairoCreateCanvas(canvas, ctximage->cr);
+
+ if (!ctxcanvas)
+ return;
+
+ ctxcanvas->image_dbuffer = image_dbuffer;
+ ctxcanvas->canvas_dbuffer = canvas_dbuffer;
+
+ canvas->w = ctximage->w;
+ canvas->h = ctximage->h;
+ canvas->w_mm = ctximage->w_mm;
+ canvas->h_mm = ctximage->h_mm;
+ canvas->bpp = ctximage->bpp;
+ canvas->xres = ctximage->xres;
+ canvas->yres = ctximage->yres;
+}
+
+static int cdactivate(cdCtxCanvas* ctxcanvas)
+{
+ int w, h;
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+
+ /* this is done in the canvas_dbuffer context */
+ /* this will update canvas size */
+ cdCanvasActivate(canvas_dbuffer);
+ w = canvas_dbuffer->w;
+ h = canvas_dbuffer->h;
+ if (w==0) w=1;
+ if (h==0) h=1;
+
+ /* check if the size changed */
+ if (w != ctxcanvas->image_dbuffer->w ||
+ h != ctxcanvas->image_dbuffer->h)
+ {
+ cdCanvas* canvas = ctxcanvas->canvas;
+ /* save the current, if the rebuild fail */
+ cdImage* old_image_dbuffer = ctxcanvas->image_dbuffer;
+ cdCtxCanvas* old_ctxcanvas = ctxcanvas;
+
+ /* if the image is rebuild, the canvas that uses the image must be also rebuild */
+
+ /* rebuild the image and the canvas */
+ canvas->ctxcanvas = NULL;
+ canvas->context->cxCreateCanvas(canvas, canvas_dbuffer);
+ if (!canvas->ctxcanvas)
+ {
+ canvas->ctxcanvas = old_ctxcanvas;
+ return CD_ERROR;
+ }
+
+ /* remove the old image and canvas */
+ cdKillImage(old_image_dbuffer);
+ cdcairoKillCanvas(old_ctxcanvas);
+
+ ctxcanvas = canvas->ctxcanvas;
+
+ /* update canvas attributes */
+ canvas->cxBackground(ctxcanvas, canvas->background);
+ canvas->cxForeground(ctxcanvas, canvas->foreground);
+ canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity);
+ canvas->cxWriteMode(ctxcanvas, canvas->write_mode);
+ canvas->cxLineStyle(ctxcanvas, canvas->line_style);
+ canvas->cxLineWidth(ctxcanvas, canvas->line_width);
+ canvas->cxLineCap(ctxcanvas, canvas->line_cap);
+ canvas->cxLineJoin(ctxcanvas, canvas->line_join);
+ canvas->cxHatch(ctxcanvas, canvas->hatch_style);
+ if (canvas->stipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple);
+ if (canvas->pattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern);
+ canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style);
+ if (canvas->native_font[0] == 0) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size);
+ else canvas->cxNativeFont(ctxcanvas, canvas->native_font);
+/* canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment); */
+/* canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation); */
+ if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax);
+/* if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax); */
+ if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n);
+/* if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n); */
+ if (canvas->clip_mode != CD_CLIPOFF) canvas->cxClip(ctxcanvas, canvas->clip_mode);
+ }
+
+ return CD_OK;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxActivate = cdactivate;
+ canvas->cxDeactivate = cddeactivate;
+ canvas->cxFlush = cdflush;
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdDBufferContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextCairoDBuffer(void)
+{
+ return &cdDBufferContext;
+}
diff --git a/cd/src/cairo/cdcairoemf.c b/cd/src/cairo/cdcairoemf.c
new file mode 100644
index 0000000..979caa7
--- /dev/null
+++ b/cd/src/cairo/cdcairoemf.c
@@ -0,0 +1,122 @@
+/** \file
+ * \brief EMF Printer Driver (Win32 Only)
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+
+#include "cdcairoctx.h"
+#include "cdprint.h"
+
+#include "cairo-win32.h"
+
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ cairo_surface_t* surface = cairo_get_target(ctxcanvas->cr);
+ HDC hDC = cairo_win32_surface_get_dc(surface);
+ HENHMETAFILE hEMF;
+
+ cairo_surface_finish(surface);
+
+ hEMF = CloseEnhMetaFile (hDC);
+ DeleteEnhMetaFile (hEMF);
+
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ (void)ctxcanvas;
+ /* does nothing in EMF */
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char* strdata = (char*)data;
+ int w = 0, h = 0;
+ double xres, yres;
+ FILE* file;
+ char filename[10240] = "";
+ HDC ScreenDC, hDC;
+ RECT rect;
+ HRGN clip_hrgn;
+
+ /* Inicializa parametros */
+ if (strdata == NULL)
+ return;
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ sscanf(strdata,"%dx%d", &w, &h);
+ if (w == 0 || h == 0)
+ return;
+
+ /* Verifica se o arquivo pode ser aberto para escrita */
+ file = fopen(filename, "wb");
+ if (file == NULL) return;
+ fclose(file);
+
+ ScreenDC = GetDC(NULL);
+ /* LOGPIXELS can not be used for EMF */
+ xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE);
+ yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE);
+ /* The rectangle dimensions are given in hundredths of a millimeter */
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = (int)(100. * w / xres);
+ rect.bottom = (int)(100. * h / yres);
+ hDC = CreateEnhMetaFile(ScreenDC,filename,&rect,NULL);
+ ReleaseDC(NULL, ScreenDC);
+
+ if(!hDC)
+ return;
+
+ canvas->w = w;
+ canvas->h = h;
+ canvas->xres = xres;
+ canvas->yres = yres;
+ canvas->w_mm = ((double)w) / xres;
+ canvas->h_mm = ((double)h) / yres;
+ canvas->bpp = 24;
+
+ /* The DC will be queried for its initial clip extents, and this will be used as the size of the cairo surface. */
+ clip_hrgn = CreateRectRgn(0, 0, canvas->w, canvas->h);
+ SelectClipRgn(hDC, clip_hrgn);
+ DeleteObject(clip_hrgn);
+
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(cairo_win32_printing_surface_create(hDC)));
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxFlush = cdflush;
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdEMFCairoContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_GETIMAGERGB |
+ CD_CAP_WRITEMODE | CD_CAP_PALETTE | CD_CAP_IMAGESRV),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextCairoEMF(void)
+{
+ return &cdEMFCairoContext;
+}
+
diff --git a/cd/src/cairo/cdcairoimg.c b/cd/src/cairo/cdcairoimg.c
new file mode 100644
index 0000000..bc39129
--- /dev/null
+++ b/cd/src/cairo/cdcairoimg.c
@@ -0,0 +1,51 @@
+/** \file
+ * \brief Cairo Image Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+
+#include "cdcairoctx.h"
+#include "cdimage.h"
+
+
+static void cdkillcanvas(cdCtxCanvas* ctxcanvas)
+{
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxImage *ctximage = ((cdImage*)data)->ctximage;
+ cdcairoCreateCanvas(canvas, (cairo_t*)ctximage->cr);
+ canvas->w = ctximage->w;
+ canvas->h = ctximage->h;
+ canvas->w_mm = ctximage->w_mm;
+ canvas->h_mm = ctximage->h_mm;
+ canvas->bpp = ctximage->bpp;
+ canvas->xres = ctximage->xres;
+ canvas->yres = ctximage->yres;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdImageContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoImage(void)
+{
+ return &cdImageContext;
+}
diff --git a/cd/src/cairo/cdcairoirgb.c b/cd/src/cairo/cdcairoirgb.c
new file mode 100644
index 0000000..b326834
--- /dev/null
+++ b/cd/src/cairo/cdcairoirgb.c
@@ -0,0 +1,159 @@
+/** \file
+ * \brief Cairo IMAGERGB Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cd.h"
+#include "cdcairo.h"
+#include "cdcairoctx.h"
+
+
+static char* get_stride_attrib(cdCtxCanvas* ctxcanvas)
+{
+ static char data[100];
+ sprintf(data, "%d", cairo_image_surface_get_stride(cairo_get_target(ctxcanvas->cr)));
+ return data;
+}
+
+static cdAttribute stride_attrib =
+{
+ "STRIDE",
+ NULL,
+ get_stride_attrib
+};
+
+static void set_write2png_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ if (data)
+ cairo_surface_write_to_png(cairo_get_target(ctxcanvas->cr), data);
+}
+
+static cdAttribute write2png_attrib =
+{
+ "WRITE2PNG",
+ set_write2png_attrib,
+ NULL
+};
+
+static char* get_data_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->rgb;
+}
+
+static cdAttribute data_attrib =
+{
+ "RGBDATA",
+ NULL,
+ get_data_attrib
+};
+
+static void cdkillcanvas (cdCtxCanvas *ctxcanvas)
+{
+ if (!ctxcanvas->user_image)
+ free(ctxcanvas->rgb);
+
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void* data)
+{
+ cdCtxCanvas* ctxcanvas;
+ cairo_surface_t *surface;
+ int w = 0, h = 0, use_alpha = 0;
+ float res = (float)3.78;
+ unsigned char *rgb = NULL;
+ char* str_data = (char*)data;
+ char* res_ptr = NULL;
+ cairo_format_t format = CAIRO_FORMAT_RGB24;
+
+ /* Starting parameters */
+ if (str_data == NULL)
+ return;
+
+ if (strstr(str_data, "-a"))
+ use_alpha = 1;
+
+ res_ptr = strstr(str_data, "-r");
+ if (res_ptr)
+ sscanf(res_ptr+2, "%g", &res);
+
+ /* size and rgb */
+#ifdef SunOS_OLD
+ sscanf(str_data, "%dx%d %d", &w, &h, &rgb);
+#else
+ sscanf(str_data, "%dx%d %p", &w, &h, &rgb);
+#endif
+
+ if (w == 0 || h == 0)
+ return;
+
+ canvas->w = w;
+ canvas->h = h;
+ canvas->yres = res;
+ canvas->xres = res;
+ canvas->w_mm = ((double)w) / res;
+ canvas->h_mm = ((double)h) / res;
+ if (use_alpha)
+ {
+ canvas->bpp = 32;
+ format = CAIRO_FORMAT_ARGB32;
+ }
+ else
+ canvas->bpp = 24; /* fake value, image bpp is always 32 */
+
+ if (rgb)
+ surface = cairo_image_surface_create_for_data(rgb, format, w, h, w*32);
+ else
+ surface = cairo_image_surface_create(format, canvas->w, canvas->h);
+
+ /* Starting Cairo driver */
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface));
+ cairo_surface_destroy(surface);
+
+ if (rgb)
+ {
+ ctxcanvas->user_image = 1;
+ ctxcanvas->rgb = rgb;
+ }
+ else
+ {
+ ctxcanvas->user_image = 0;
+ ctxcanvas->rgb = cairo_image_surface_get_data(cairo_get_target(ctxcanvas->cr));
+
+ /* fill with white */
+ /* transparent, this is the normal alpha coding */
+ cairo_set_source_rgba(ctxcanvas->cr, 1.0, 1.0, 1.0, 0.0);
+ cairo_rectangle(ctxcanvas->cr, 0, 0, canvas->w, canvas->h);
+ cairo_fill(ctxcanvas->cr);
+ }
+
+ cdRegisterAttribute(canvas, &stride_attrib);
+ cdRegisterAttribute(canvas, &write2png_attrib);
+ cdRegisterAttribute(canvas, &data_attrib);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdCairoImageRGBContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoImageRGB(void)
+{
+ return &cdCairoImageRGBContext;
+}
diff --git a/cd/src/cairo/cdcaironative_gdk.c b/cd/src/cairo/cdcaironative_gdk.c
new file mode 100644
index 0000000..29be6c6
--- /dev/null
+++ b/cd/src/cairo/cdcaironative_gdk.c
@@ -0,0 +1,80 @@
+/** \file
+* \brief Cairo Native Window Driver
+*
+* See Copyright Notice in cd.h
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <gdk/gdk.h>
+
+#include "cdcairoctx.h"
+#include "cdnative.h"
+
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+int cdactivate(cdCtxCanvas *ctxcanvas)
+{
+ gdk_drawable_get_size(ctxcanvas->drawable, &ctxcanvas->canvas->w, &ctxcanvas->canvas->h);
+
+ ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres;
+ ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres;
+
+ return CD_OK;
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas *ctxcanvas;
+ cairo_t* cr;
+ GdkScreen* screen;
+ GdkDrawable* drawable = (GdkDrawable*)data;
+
+ cr = gdk_cairo_create(drawable);
+ if (!cr)
+ return;
+
+ screen = gdk_drawable_get_screen(drawable);
+ canvas->bpp = gdk_drawable_get_depth(drawable);
+ canvas->xres = ((double)gdk_screen_get_width(screen) / (double)gdk_screen_get_width_mm(screen));
+ canvas->yres = ((double)gdk_screen_get_height(screen) / (double)gdk_screen_get_height_mm(screen));
+ gdk_drawable_get_size(drawable, &canvas->w, &canvas->h);
+
+ canvas->w_mm = ((double)canvas->w) / canvas->xres;
+ canvas->h_mm = ((double)canvas->h) / canvas->yres;
+
+ ctxcanvas = cdcairoCreateCanvas(canvas, cr);
+
+ ctxcanvas->drawable = drawable;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxActivate = cdactivate;
+}
+
+/******************************************************/
+
+static cdContext cdNativeWindowContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE),
+ 1,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+
+cdContext* cdContextCairoNativeWindow(void)
+{
+ return &cdNativeWindowContext;
+}
diff --git a/cd/src/cairo/cdcaironative_win32.c b/cd/src/cairo/cdcaironative_win32.c
new file mode 100644
index 0000000..e0b860e
--- /dev/null
+++ b/cd/src/cairo/cdcaironative_win32.c
@@ -0,0 +1,160 @@
+/** \file
+* \brief Cairo Native Window Driver
+*
+* See Copyright Notice in cd.h
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdcairoctx.h"
+#include "cdnative.h"
+
+#include <windows.h>
+#include <cairo-win32.h>
+
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->hDC)
+ ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC);
+
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+int cdactivate(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->hWnd)
+ {
+ RECT rect;
+ GetClientRect(ctxcanvas->hWnd, &rect);
+ ctxcanvas->canvas->w = rect.right - rect.left;
+ ctxcanvas->canvas->h = rect.bottom - rect.top;
+
+ ctxcanvas->canvas->bpp = cdGetScreenColorPlanes();
+ }
+
+ /* Se nao e' ownwer, tem que restaurar o contexto */
+ if (!ctxcanvas->isOwnedDC)
+ {
+ cairo_surface_t *surface;
+
+ if (ctxcanvas->hDC) /* deactivate not called */
+ {
+ cairo_destroy(ctxcanvas->cr);
+ ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC);
+ }
+
+ ctxcanvas->hDC = GetDC(ctxcanvas->hWnd);
+ surface = cairo_win32_surface_create(ctxcanvas->hDC);
+ ctxcanvas->cr = cairo_create(surface);
+ cairo_surface_destroy(surface);
+ }
+
+ ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres;
+ ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres;
+
+ if (ctxcanvas->canvas->use_matrix)
+ ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix);
+
+ return CD_OK;
+}
+
+static void cddeactivate(cdCtxCanvas *ctxcanvas)
+{
+ /* If not owner, release the DC */
+ if (!ctxcanvas->isOwnedDC && ctxcanvas->hDC)
+ {
+ cairo_destroy(ctxcanvas->cr);
+ ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC);
+ ctxcanvas->cr = NULL;
+ ctxcanvas->hDC = NULL;
+ }
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ cairo_surface_t *surface;
+
+ HWND hWnd = (HWND)data;
+ HDC ScreenDC, hDC;
+ HRGN clip_hrgn;
+
+ ScreenDC = GetDC(NULL);
+ canvas->bpp = GetDeviceCaps(ScreenDC, BITSPIXEL);
+ canvas->xres = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSX)) / 25.4);
+ canvas->yres = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSY)) / 25.4);
+ ReleaseDC(NULL, ScreenDC);
+
+ if (!data)
+ {
+ hDC = GetDC(NULL);
+ canvas->w = GetDeviceCaps(hDC, HORZRES);
+ canvas->h = GetDeviceCaps(hDC, VERTRES);
+ }
+ else
+ {
+ RECT rect;
+ hWnd = (HWND)data;
+
+ hDC = GetDC(hWnd);
+
+ GetClientRect(hWnd, &rect);
+ canvas->w = rect.right - rect.left;
+ canvas->h = rect.bottom - rect.top;
+ }
+
+ /* initial clip extents controls size */
+ clip_hrgn = CreateRectRgn(0, 0, canvas->w, canvas->h);
+ SelectClipRgn(hDC, clip_hrgn);
+ DeleteObject(clip_hrgn);
+
+ surface = cairo_win32_surface_create(hDC);
+
+ canvas->w_mm = ((double)canvas->w) / canvas->xres;
+ canvas->h_mm = ((double)canvas->h) / canvas->yres;
+
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface));
+ cairo_surface_destroy(surface);
+
+ ctxcanvas->hDC = hDC;
+ ctxcanvas->hWnd = hWnd;
+
+ if (hWnd)
+ {
+ LONG style = GetClassLong(hWnd, GCL_STYLE);
+ ctxcanvas->isOwnedDC = (int) ((style & CS_OWNDC) || (style & CS_CLASSDC));
+ }
+ else
+ ctxcanvas->isOwnedDC = 1;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxActivate = cdactivate;
+ canvas->cxDeactivate = cddeactivate;
+}
+
+/******************************************************/
+
+static cdContext cdNativeWindowContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE),
+ 1,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+
+cdContext* cdContextCairoNativeWindow(void)
+{
+ return &cdNativeWindowContext;
+}
+
+// cairo_win32_printing_surface_create CD_PRINTER
diff --git a/cd/src/cairo/cdcaironative_x11.c b/cd/src/cairo/cdcaironative_x11.c
new file mode 100644
index 0000000..1030745
--- /dev/null
+++ b/cd/src/cairo/cdcaironative_x11.c
@@ -0,0 +1,98 @@
+/** \file
+* \brief Cairo Native Window Driver
+*
+* See Copyright Notice in cd.h
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdcairoctx.h"
+#include "cdnative.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <cairo-xlib.h>
+
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+int cdactivate(cdCtxCanvas *ctxcanvas)
+{
+ Window root;
+ int x, y;
+ unsigned int bw, d;
+ XGetGeometry(ctxcanvas->dpy, ctxcanvas->wnd, &root, &x, &y,
+ (unsigned int*)&ctxcanvas->canvas->w, (unsigned int*)&ctxcanvas->canvas->h, &bw, &d);
+
+ ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres;
+ ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres;
+
+ return CD_OK;
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ cairo_surface_t *surface;
+ char* data_str = (char*)data;
+ Window wnd, root;
+ Display *dpy;
+ XWindowAttributes wa;
+ int x, y;
+ unsigned int bw;
+
+#ifdef SunOS_OLD
+ sscanf(data_str, "%d %lu", &dpy, &wnd);
+#else
+ sscanf(data_str, "%p %lu", &dpy, &wnd);
+#endif
+ if (!dpy || !wnd)
+ return;
+
+ XGetWindowAttributes(dpy, wnd, &wa);
+
+ XGetGeometry(dpy, wnd, &root, &x, &y, (unsigned int*)&canvas->w, (unsigned int*)&canvas->h, &bw, (unsigned int*)&canvas->bpp);
+ canvas->xres = ((double)DisplayWidth(dpy, XScreenNumberOfScreen(wa.screen)) / (double)DisplayWidthMM(dpy, XScreenNumberOfScreen(wa.screen)));
+ canvas->yres = ((double)DisplayHeight(dpy, XScreenNumberOfScreen(wa.screen)) / (double)DisplayHeightMM(dpy, XScreenNumberOfScreen(wa.screen)));
+
+ surface = cairo_xlib_surface_create(dpy, wnd, wa.visual, canvas->w, canvas->h);
+
+ canvas->w_mm = ((double)canvas->w) / canvas->xres;
+ canvas->h_mm = ((double)canvas->h) / canvas->yres;
+
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface));
+ cairo_surface_destroy(surface);
+
+ ctxcanvas->dpy = dpy;
+ ctxcanvas->wnd = wnd;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxActivate = cdactivate;
+}
+
+/******************************************************/
+
+static cdContext cdNativeWindowContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE ),
+ 1,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+
+cdContext* cdContextCairoNativeWindow(void)
+{
+ return &cdNativeWindowContext;
+}
diff --git a/cd/src/cairo/cdcairopdf.c b/cd/src/cairo/cdcairopdf.c
new file mode 100644
index 0000000..f17fff4
--- /dev/null
+++ b/cd/src/cairo/cdcairopdf.c
@@ -0,0 +1,122 @@
+/** \file
+ * \brief Cairo PDF Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cd.h"
+#include "cdcairo.h"
+#include "cdcairoctx.h"
+
+#include <cairo-pdf.h>
+
+
+static void cdkillcanvas (cdCtxCanvas *ctxcanvas)
+{
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void* data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char* strdata = (char*)data;
+ char filename[10240] = "";
+ cairo_surface_t *surface;
+ int res = 300;
+ double w_pt; /* Largura do papel (points) */
+ double h_pt; /* Altura do papel (points) */
+ double scale; /* Fator de conversao de coordenadas (pixel2points) */
+ int landscape = 0; /* page orientation */
+
+ /* Starting parameters */
+ if (strdata == NULL)
+ return;
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ cdSetPaperSize(CD_A4, &w_pt, &h_pt);
+
+ while (*strdata != '\0')
+ {
+ while (*strdata != '\0' && *strdata != '-')
+ strdata++;
+
+ if (*strdata != '\0')
+ {
+ float num;
+ strdata++;
+ switch (*strdata++)
+ {
+ case 'p':
+ {
+ int paper;
+ sscanf(strdata, "%d", &paper);
+ cdSetPaperSize(paper, &w_pt, &h_pt);
+ break;
+ }
+ case 'w':
+ sscanf(strdata, "%g", &num);
+ w_pt = CD_MM2PT*num;
+ break;
+ case 'h':
+ sscanf(strdata, "%g", &num);
+ h_pt = CD_MM2PT*num;
+ break;
+ case 'o':
+ landscape = 1;
+ break;
+ case 's':
+ sscanf(strdata, "%d", &res);
+ break;
+ }
+ }
+
+ while (*strdata != '\0' && *strdata != ' ')
+ strdata++;
+ }
+
+ if (landscape)
+ _cdSwapDouble(w_pt, h_pt);
+
+ scale = 72.0/res;
+
+ canvas->w = (int)(w_pt/scale + 0.5); /* Converte p/ unidades do usuario */
+ canvas->h = (int)(h_pt/scale + 0.5); /* Converte p/ unidades do usuario */
+ canvas->w_mm = w_pt/CD_MM2PT; /* Converte p/ milimetros */
+ canvas->h_mm = h_pt/CD_MM2PT; /* Converte p/ milimetros */
+ canvas->bpp = 24;
+ canvas->xres = canvas->w / canvas->w_mm;
+ canvas->yres = canvas->h / canvas->h_mm;
+
+ surface = cairo_pdf_surface_create(filename, w_pt, h_pt);
+
+ /* Starting Cairo driver */
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface));
+ cairo_surface_destroy(surface);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdCairoPDFContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoPDF(void)
+{
+ return &cdCairoPDFContext;
+}
diff --git a/cd/src/cairo/cdcairoplus.c b/cd/src/cairo/cdcairoplus.c
new file mode 100644
index 0000000..a46d9f3
--- /dev/null
+++ b/cd/src/cairo/cdcairoplus.c
@@ -0,0 +1,30 @@
+/** \file
+ * \brief Cairo as Context Plus
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cdcairo.h"
+#include <stdlib.h>
+#include <memory.h>
+
+
+void cdInitContextPlus(void)
+{
+ cdContext* ctx_list[NUM_CONTEXTPLUS];
+ memset(ctx_list, 0, sizeof(ctx_list));
+
+ ctx_list[CD_CTX_NATIVEWINDOW] = cdContextCairoNativeWindow();
+ ctx_list[CD_CTX_IMAGE] = cdContextCairoImage();
+ ctx_list[CD_CTX_DBUFFER] = cdContextCairoDBuffer();
+#ifndef CAIRO_X11
+ ctx_list[CD_CTX_PRINTER] = cdContextCairoPrinter();
+#endif
+#ifdef WIN32
+ ctx_list[CD_CTX_EMF] = cdContextCairoEMF();
+#endif
+
+ cdInitContextPlusList(ctx_list);
+}
diff --git a/cd/src/cairo/cdcairoprn_unix.c b/cd/src/cairo/cdcairoprn_unix.c
new file mode 100644
index 0000000..fa13522
--- /dev/null
+++ b/cd/src/cairo/cdcairoprn_unix.c
@@ -0,0 +1,196 @@
+/** \file
+ * \brief Cairo/GTK Printer Driver (UNIX Only)
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <gtk/gtkprintunixdialog.h>
+
+#include "cdcairoctx.h"
+#include "cdprint.h"
+
+static gboolean print_enum(GtkPrinter *printer, GtkPrinter **ret_printer)
+{
+ if (gtk_printer_is_default(printer))
+ {
+ *ret_printer = printer;
+ g_object_ref(printer);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void finish_send(GtkPrintJob *job, GMainLoop* loop, GError *error)
+{
+ if (error != NULL)
+ {
+ GtkWidget *edialog;
+ edialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Error printing");
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (edialog), "%s", error->message);
+ gtk_window_set_modal (GTK_WINDOW (edialog), TRUE);
+ g_signal_connect(edialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_window_present(GTK_WINDOW(edialog));
+ }
+
+ g_main_loop_quit(loop);
+}
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ GMainLoop* loop = g_main_loop_new (NULL, FALSE);
+
+ cairo_surface_finish(cairo_get_target(ctxcanvas->cr));
+
+ gtk_print_job_send(ctxcanvas->job, (GtkPrintJobCompleteFunc)finish_send, loop, NULL);
+
+ g_main_loop_run(loop);
+ g_main_loop_unref(loop);
+
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static char* get_printername_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)gtk_printer_get_name(gtk_print_job_get_printer(ctxcanvas->job));
+}
+
+static cdAttribute printername_attrib =
+{
+ "PRINTERNAME",
+ NULL,
+ get_printername_attrib
+};
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char *data_str = (char*) data;
+ char docname[256] = "CD - Canvas Draw Document";
+ GtkPrintUnixDialog* dialog = NULL;
+ GtkPrinter* printer;
+ GtkPrintSettings* settings;
+ GtkPageSetup* page_setup;
+ GtkPrintJob* job;
+ int show_dialog = 0;
+
+ /* Starting parameters */
+ if (data_str == NULL)
+ return;
+
+ if (data_str[0] != 0)
+ {
+ char *ptr = strstr(data_str, "-d");
+
+ if (ptr != NULL)
+ show_dialog = 1;
+
+ if (data_str[0] != '-')
+ {
+ strcpy(docname, data_str);
+
+ if (show_dialog)
+ docname[ptr - data_str - 1] = 0;
+ }
+ }
+
+ if (show_dialog)
+ {
+ int response;
+
+ dialog = (GtkPrintUnixDialog*)gtk_print_unix_dialog_new(NULL, NULL);
+
+ gtk_print_unix_dialog_set_manual_capabilities(dialog,
+ GTK_PRINT_CAPABILITY_PAGE_SET |
+ GTK_PRINT_CAPABILITY_COPIES |
+ GTK_PRINT_CAPABILITY_COLLATE |
+ GTK_PRINT_CAPABILITY_REVERSE |
+ GTK_PRINT_CAPABILITY_SCALE);
+
+ gtk_widget_realize(GTK_WIDGET(dialog));
+
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+ if (response == GTK_RESPONSE_CANCEL)
+ {
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ return;
+ }
+
+ printer = gtk_print_unix_dialog_get_selected_printer(dialog);
+ settings = gtk_print_unix_dialog_get_settings(dialog);
+ page_setup = gtk_print_unix_dialog_get_page_setup(dialog);
+ }
+ else
+ {
+ printer = NULL;
+ gtk_enumerate_printers((GtkPrinterFunc)print_enum, &printer, NULL, TRUE);
+ if (!printer)
+ return;
+ page_setup = gtk_printer_get_default_page_size(printer);
+ if (!page_setup)
+ page_setup = gtk_page_setup_new(); /* ?????? */
+
+ settings = gtk_print_settings_new(); /* ?????? */
+ }
+
+ job = gtk_print_job_new(docname, printer, settings, page_setup);
+
+ canvas->w_mm = (int)gtk_page_setup_get_page_width(page_setup, GTK_UNIT_MM);
+ canvas->h_mm = (int)gtk_page_setup_get_page_height(page_setup, GTK_UNIT_MM);
+ canvas->bpp = 24;
+#if GTK_CHECK_VERSION(2, 16, 0)
+ canvas->xres = (double)gtk_print_settings_get_resolution_x(settings) / 25.4;
+ canvas->yres = (double)gtk_print_settings_get_resolution_y(settings) / 25.4;
+#else
+ canvas->xres = (double)gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_RESOLUTION) / 25.4;
+ canvas->yres = (double)gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_RESOLUTION) / 25.4;
+#endif
+ canvas->w = cdRound(canvas->w_mm*canvas->xres);
+ canvas->h = cdRound(canvas->h_mm*canvas->yres);
+
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(gtk_print_job_get_surface(job, NULL)));
+ ctxcanvas->job = job;
+
+ cairo_identity_matrix(ctxcanvas->cr);
+ cairo_scale(ctxcanvas->cr, 0.25, 0.25); /* TODO: why this is needed? */
+
+ cdRegisterAttribute(canvas, &printername_attrib);
+
+ if (dialog)
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+
+ g_object_unref(settings);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdPrinterCairoContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_GETIMAGERGB |
+ CD_CAP_WRITEMODE | CD_CAP_PALETTE | CD_CAP_IMAGESRV),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextCairoPrinter(void)
+{
+ return &cdPrinterCairoContext;
+}
diff --git a/cd/src/cairo/cdcairoprn_win32.c b/cd/src/cairo/cdcairoprn_win32.c
new file mode 100644
index 0000000..cbf4d66
--- /dev/null
+++ b/cd/src/cairo/cdcairoprn_win32.c
@@ -0,0 +1,194 @@
+/** \file
+ * \brief Cairo/GTK Printer Driver (Win32 Only)
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+
+#include "cdcairoctx.h"
+#include "cdprint.h"
+
+#include "cairo-win32.h"
+
+
+#ifndef DC_COLORDEVICE
+#define DC_COLORDEVICE 32 /* declared only if WINVER 0x0500 */
+#endif
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ cairo_surface_t* surface = cairo_get_target(ctxcanvas->cr);
+ HDC hDC = cairo_win32_surface_get_dc(surface);
+
+ cairo_surface_finish(surface);
+
+ EndDoc(hDC);
+ DeleteDC(hDC);
+
+ if (ctxcanvas->printername)
+ free(ctxcanvas->printername);
+
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ cairo_surface_t* surface = cairo_get_target(ctxcanvas->cr);
+ HDC hDC = cairo_win32_surface_get_dc(surface);
+
+ cairo_surface_flush(surface);
+ cairo_show_page(ctxcanvas->cr);
+
+ GdiFlush();
+ EndPage(hDC);
+
+ StartPage(hDC);
+}
+
+static char* get_printername_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return ctxcanvas->printername;
+}
+
+static cdAttribute printername_attrib =
+{
+ "PRINTERNAME",
+ NULL,
+ get_printername_attrib
+};
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char *data_str = (char*) data;
+ char docname[256] = "CD - Canvas Draw Document";
+ DOCINFO di;
+ HDC hDC;
+ int dialog = 0;
+ PRINTDLG pd;
+ HRGN clip_hrgn;
+
+ /* Inicializa parametros */
+ if (data_str == NULL)
+ return;
+
+ if (data_str[0] != 0)
+ {
+ char *ptr = strstr(data_str, "-d");
+
+ if (ptr != NULL)
+ dialog = 1;
+
+ if (data_str[0] != '-')
+ {
+ strcpy(docname, data_str);
+
+ if (dialog)
+ docname[ptr - data_str - 1] = 0;
+ }
+ }
+
+ ZeroMemory(&pd, sizeof(PRINTDLG));
+ pd.lStructSize = sizeof(PRINTDLG);
+ pd.nCopies = 1;
+
+ if (dialog)
+ {
+ pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIES | PD_COLLATE | PD_NOPAGENUMS | PD_NOSELECTION;
+ pd.hwndOwner = GetForegroundWindow();
+ }
+ else
+ {
+ pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
+ }
+
+ if (!PrintDlg(&pd))
+ {
+ if(pd.hDevMode)
+ GlobalFree(pd.hDevMode);
+ if(pd.hDevNames)
+ GlobalFree(pd.hDevNames);
+ return;
+ }
+
+ hDC = pd.hDC;
+
+ canvas->w = GetDeviceCaps(hDC, HORZRES);
+ canvas->h = GetDeviceCaps(hDC, VERTRES);
+ canvas->w_mm = (double)GetDeviceCaps(hDC, HORZSIZE);
+ canvas->h_mm = (double)GetDeviceCaps(hDC, VERTSIZE);
+ canvas->bpp = GetDeviceCaps(hDC, BITSPIXEL);
+ canvas->xres = (double)canvas->w / canvas->w_mm;
+ canvas->yres = (double)canvas->h / canvas->h_mm;
+
+ /* The DC will be queried for its initial clip extents, and this will be used as the size of the cairo surface. */
+ clip_hrgn = CreateRectRgn(0, 0, canvas->w, canvas->h);
+ SelectClipRgn(hDC, clip_hrgn);
+ DeleteObject(clip_hrgn);
+
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(cairo_win32_printing_surface_create(hDC)));
+
+ di.cbSize = sizeof(DOCINFO);
+ di.lpszDocName = docname;
+ di.lpszOutput = (LPTSTR) NULL;
+ di.lpszDatatype = (LPTSTR) NULL;
+ di.fwType = 0;
+
+ StartDoc(hDC, &di);
+
+ StartPage(hDC);
+
+ if (pd.hDevNames)
+ {
+ unsigned char* devnames = (unsigned char*)GlobalLock(pd.hDevNames);
+ DEVNAMES* dn = (DEVNAMES*)devnames;
+ char* device = (char*)(devnames + dn->wDeviceOffset);
+
+ ctxcanvas->printername = cdStrDup(device);
+ cdRegisterAttribute(canvas, &printername_attrib);
+
+ /* PDF Writer returns bpp=1, so we check if color is supported and overwrite this value */
+ if (canvas->bpp==1)
+ {
+ char* port = (char*)(devnames + dn->wOutputOffset);
+ if (DeviceCapabilities(device, port, DC_COLORDEVICE, NULL, NULL))
+ canvas->bpp = 24;
+ }
+
+ GlobalUnlock(pd.hDevNames);
+ }
+
+ if(pd.hDevMode)
+ GlobalFree(pd.hDevMode);
+ if(pd.hDevNames)
+ GlobalFree(pd.hDevNames);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+
+ canvas->cxFlush = cdflush;
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdPrinterCairoContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_GETIMAGERGB |
+ CD_CAP_WRITEMODE | CD_CAP_PALETTE | CD_CAP_IMAGESRV),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextCairoPrinter(void)
+{
+ return &cdPrinterCairoContext;
+}
diff --git a/cd/src/cairo/cdcairops.c b/cd/src/cairo/cdcairops.c
new file mode 100644
index 0000000..b08aee4
--- /dev/null
+++ b/cd/src/cairo/cdcairops.c
@@ -0,0 +1,172 @@
+/** \file
+ * \brief Cairo PS Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cd.h"
+#include "cdps.h"
+#include "cdcairo.h"
+#include "cdcairoctx.h"
+
+#include <cairo-ps.h>
+
+
+static void set_comment_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ if (data)
+ cairo_ps_surface_dsc_comment(cairo_get_target(ctxcanvas->cr), data);
+}
+
+static cdAttribute comment_attrib =
+{
+ "DSCCOMMENT",
+ set_comment_attrib,
+ NULL
+};
+
+static void cdkillcanvas (cdCtxCanvas *ctxcanvas)
+{
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ if (!ctxcanvas->eps)
+ cairo_show_page(ctxcanvas->cr);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void* data)
+{
+ cdCtxCanvas *ctxcanvas;
+ char* strdata = (char*)data;
+ char filename[10240] = "";
+ cairo_surface_t *surface;
+ int res = 300;
+ double w_pt; /* Largura do papel (points) */
+ double h_pt; /* Altura do papel (points) */
+ double scale; /* Fator de conversao de coordenadas (pixel2points) */
+ int eps = 0; /* Postscrip encapsulado? */
+ int level = 0;
+ int landscape = 0; /* page orientation */
+
+ /* Starting parameters */
+ if (strdata == NULL)
+ return;
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ cdSetPaperSize(CD_A4, &w_pt, &h_pt);
+
+ while (*strdata != '\0')
+ {
+ while (*strdata != '\0' && *strdata != '-')
+ strdata++;
+
+ if (*strdata != '\0')
+ {
+ float num;
+ strdata++;
+ switch (*strdata++)
+ {
+ case 'p':
+ {
+ int paper;
+ sscanf(strdata, "%d", &paper);
+ cdSetPaperSize(paper, &w_pt, &h_pt);
+ break;
+ }
+ case 'w':
+ sscanf(strdata, "%g", &num);
+ w_pt = CD_MM2PT*num;
+ break;
+ case 'h':
+ sscanf(strdata, "%g", &num);
+ h_pt = CD_MM2PT*num;
+ break;
+ case 'e':
+ eps = 1;
+ break;
+ case 'o':
+ landscape = 1;
+ break;
+ case '2':
+ level = 2;
+ break;
+ case '3':
+ level = 3;
+ break;
+ case 's':
+ sscanf(strdata, "%d", &res);
+ break;
+ }
+ }
+
+ while (*strdata != '\0' && *strdata != ' ')
+ strdata++;
+ }
+
+ if (landscape)
+ _cdSwapDouble(w_pt, h_pt);
+
+ scale = 72.0/res;
+
+ canvas->w = (int)(w_pt/scale + 0.5); /* Converte p/ unidades do usuario */
+ canvas->h = (int)(h_pt/scale + 0.5); /* Converte p/ unidades do usuario */
+ canvas->w_mm = w_pt/CD_MM2PT; /* Converte p/ milimetros */
+ canvas->h_mm = h_pt/CD_MM2PT; /* Converte p/ milimetros */
+ canvas->bpp = 24;
+ canvas->xres = canvas->w / canvas->w_mm;
+ canvas->yres = canvas->h / canvas->h_mm;
+
+ surface = cairo_ps_surface_create(filename, w_pt, h_pt);
+
+#if (CAIRO_VERSION_MAJOR>1 || (CAIRO_VERSION_MAJOR==1 && CAIRO_VERSION_MINOR>=6))
+ if (level == 2)
+ cairo_ps_surface_restrict_to_level(surface, CAIRO_PS_LEVEL_2);
+ else if (level == 3)
+ cairo_ps_surface_restrict_to_level(surface, CAIRO_PS_LEVEL_3);
+#endif
+
+ if (eps)
+ cairo_ps_surface_set_eps(surface, 1);
+
+ cairo_ps_surface_dsc_comment(surface, "%%Title: CanvasDraw");
+ cairo_ps_surface_dsc_begin_setup (surface);
+ cairo_ps_surface_dsc_begin_page_setup (surface);
+
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface));
+ ctxcanvas->eps = eps;
+
+ cairo_surface_destroy(surface);
+
+ cdRegisterAttribute(canvas, &comment_attrib);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxFlush = cdflush;
+}
+
+static cdContext cdCairoPSContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoPS(void)
+{
+ return &cdCairoPSContext;
+}
+
diff --git a/cd/src/cairo/cdcairosvg.c b/cd/src/cairo/cdcairosvg.c
new file mode 100644
index 0000000..d97cb24
--- /dev/null
+++ b/cd/src/cairo/cdcairosvg.c
@@ -0,0 +1,83 @@
+/** \file
+ * \brief Cairo SVG Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "cd.h"
+#include "cdcairo.h"
+#include "cdcairoctx.h"
+
+#include <cairo-svg.h>
+
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ (void)ctxcanvas;
+ /* does nothing in SVG */
+}
+
+static void cdkillcanvas (cdCtxCanvas *ctxcanvas)
+{
+ cdcairoKillCanvas(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void* data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char* strdata = (char*)data;
+ char filename[10240] = "";
+ double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78;
+ cairo_surface_t *surface;
+
+ /* Starting parameters */
+ if (strdata == NULL)
+ return;
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ sscanf(strdata, "%lgx%lg %lg", &w_mm, &h_mm, &res);
+
+ /* update canvas context */
+ canvas->w = (int)(w_mm * res);
+ canvas->h = (int)(h_mm * res);
+ canvas->w_mm = w_mm;
+ canvas->h_mm = h_mm;
+ canvas->bpp = 24;
+ canvas->xres = res;
+ canvas->yres = res;
+
+ surface = cairo_svg_surface_create(filename, CD_MM2PT*w_mm, CD_MM2PT*h_mm);
+
+ /* Starting Cairo driver */
+ ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface));
+ cairo_surface_destroy(surface);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdcairoInitTable(canvas);
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxFlush = cdflush;
+}
+
+static cdContext cdCairoSVGContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoSVG(void)
+{
+ return &cdCairoSVGContext;
+}