summaryrefslogtreecommitdiff
path: root/src/cairo
diff options
context:
space:
mode:
authorscuri <scuri>2010-05-12 20:38:46 +0000
committerscuri <scuri>2010-05-12 20:38:46 +0000
commitb7d97c7ed82f0d0472cf0c2ae5d61e99a73b33a8 (patch)
tree0da03500210df1ac835203e2bb83748564e67423 /src/cairo
parentafaff9e085b51c822f0ce31ac91cc8196bfa5113 (diff)
New Cairo driver
Diffstat (limited to 'src/cairo')
-rw-r--r--src/cairo/cdcairo.c1758
-rw-r--r--src/cairo/cdcairoctx.h77
-rw-r--r--src/cairo/cdcairodbuf.c170
-rw-r--r--src/cairo/cdcairoimg.c52
-rw-r--r--src/cairo/cdcairoirgb.c159
-rw-r--r--src/cairo/cdcaironative_gdk.c80
-rw-r--r--src/cairo/cdcaironative_win32.c160
-rw-r--r--src/cairo/cdcaironative_x11.c98
-rw-r--r--src/cairo/cdcairopdf.c122
-rw-r--r--src/cairo/cdcairoplus.c26
-rw-r--r--src/cairo/cdcairops.c170
-rw-r--r--src/cairo/cdcairosvg.c81
12 files changed, 2953 insertions, 0 deletions
diff --git a/src/cairo/cdcairo.c b/src/cairo/cdcairo.c
new file mode 100644
index 0000000..34fdef7
--- /dev/null
+++ b/src/cairo/cdcairo.c
@@ -0,0 +1,1758 @@
+/** \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 "cdcairoctx.h"
+
+#define HATCH_WIDTH 8
+#define HATCH_HEIGHT 8
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+static int StrIsAscii(const char* str)
+{
+ while(*str)
+ {
+ int c = *str;
+ if (c < 0)
+ return 0;
+ str++;
+ }
+ return 1;
+}
+
+static char* StrToUTF8(const char *str, const char* charset, int length)
+{
+ return g_convert(str, length, "UTF-8", charset, NULL, NULL, NULL);
+}
+
+char* StrConvertToUTF8(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->cairoLastConvertUTF8 = StrToUTF8(str, "ISO8859-1", length); /* if string is not UTF-8, assume ISO8859-1 */
+
+ if (!ctxcanvas->cairoLastConvertUTF8)
+ return (char*)str;
+
+ return ctxcanvas->cairoLastConvertUTF8;
+ }
+ }
+ else
+ {
+ if (StrIsAscii(str) || !charset)
+ {
+ return (char*)str;
+ }
+ else if (charset)
+ {
+ ctxcanvas->cairoLastConvertUTF8 = StrToUTF8(str, charset, length);
+
+ if (!ctxcanvas->cairoLastConvertUTF8)
+ return (char*)str;
+
+ return ctxcanvas->cairoLastConvertUTF8;
+ }
+ }
+
+ return (char*)str;
+}
+
+static void update_fill(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->font)
+ cairo_scaled_font_destroy(ctxcanvas->font);
+
+ if (ctxcanvas->cairoLastConvertUTF8)
+ g_free(ctxcanvas->cairoLastConvertUTF8);
+
+ cairo_destroy(ctxcanvas->cr);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+/******************************************************/
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ cairo_show_page(ctxcanvas->cr);
+}
+
+/******************************************************/
+
+static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax)
+{
+ 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)
+{
+ if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA)
+ return;
+
+ setcliprect(ctxcanvas, (double)xmin, (double)ymin, (double)xmax, (double)ymax);
+}
+
+static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
+{
+ switch (mode)
+ {
+ case CD_CLIPOFF:
+ cairo_reset_clip(ctxcanvas->cr);
+ break;
+ case CD_CLIPAREA:
+ ctxcanvas->canvas->clip_mode = CD_CLIPAREA;
+ setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin,
+ (double)ctxcanvas->canvas->clip_rect.ymin,
+ (double)ctxcanvas->canvas->clip_rect.xmax,
+ (double)ctxcanvas->canvas->clip_rect.ymax);
+ break;
+ case CD_CLIPPOLYGON:
+ {
+ int hole_index = 0;
+ int i;
+ cairo_reset_clip(ctxcanvas->cr);
+
+ 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);
+ }
+ }
+ cairo_clip(ctxcanvas->cr);
+ break;
+ }
+ case CD_CLIPREGION:
+ break;
+ }
+
+ return mode;
+}
+
+/******************************************************/
+
+static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, int (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a))
+{
+ int i, j;
+ unsigned char r, g, b, a;
+ cairo_surface_t* pattern_surface;
+ cairo_t* cr;
+
+ pattern_surface = cairo_surface_create_similar(cairo_get_target(ctxcanvas->cr), CAIRO_CONTENT_COLOR_ALPHA, n, m);
+
+ cr = cairo_create(pattern_surface);
+
+ for (j = 0; j < m; j++)
+ {
+ for (i = 0; i < n; i++)
+ {
+ int ret = data2rgb(ctxcanvas, n, i, j, data, &r, &g, &b, &a);
+ if (ret == -1)
+ continue;
+
+ cairo_set_source_rgba(cr, (double)r/255.0, (double)g/255.0, (double)b/255.0, (double)a/255.0);
+
+ cairo_rectangle(cr, i, m-1-j, 1.0, 1.0);
+ cairo_fill(cr);
+ }
+ }
+
+ if (ctxcanvas->pattern)
+ cairo_pattern_destroy(ctxcanvas->pattern);
+
+ ctxcanvas->pattern = cairo_pattern_create_for_surface(pattern_surface);
+ cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_surface_destroy(pattern_surface);
+ cairo_destroy(cr);
+}
+
+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 = HATCH_WIDTH - 1;
+ 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, HATCH_WIDTH, HATCH_HEIGHT);
+
+ 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));
+
+ 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 cdwritemode(cdCtxCanvas *ctxcanvas, int write_mode)
+{
+ switch (write_mode)
+ {
+ case CD_REPLACE:
+ cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_OVER);
+ break;
+ case CD_XOR:
+ cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_XOR);
+ break;
+ }
+
+ return write_mode;
+}
+
+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)
+{
+ //TODO:pango
+ cairo_scaled_font_t *font;
+ cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL; /* default is */
+ cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL; /* CD_PLAIN */
+
+ if (cdStrEqualNoCase(typeface, "Courier") || cdStrEqualNoCase(typeface, "Monospace"))
+ typeface = "Courier New";
+ else if (cdStrEqualNoCase(typeface, "Times") || cdStrEqualNoCase(typeface, "Serif"))
+ typeface = "Times New Roman";
+ else if (cdStrEqualNoCase(typeface, "Helvetica") || cdStrEqualNoCase(typeface, "Sans"))
+ typeface = "Arial";
+
+ /* no support to underline and strikeout */
+ switch(style&3)
+ {
+ case CD_BOLD:
+ weight = CAIRO_FONT_WEIGHT_BOLD;
+ break;
+ case CD_ITALIC:
+ slant = CAIRO_FONT_SLANT_ITALIC;
+ break;
+ case CD_BOLD_ITALIC:
+ weight = CAIRO_FONT_WEIGHT_BOLD;
+ slant = CAIRO_FONT_SLANT_ITALIC;
+ break;
+ }
+
+ cairo_select_font_face(ctxcanvas->cr, typeface, slant, weight);
+ cairo_set_font_size(ctxcanvas->cr, (double)cdGetFontSizePixels(ctxcanvas->canvas, size));
+
+ font = cairo_get_scaled_font(ctxcanvas->cr);
+
+ if (!font)
+ return 0;
+
+ font = cairo_scaled_font_reference(font);
+ ctxcanvas->font = font;
+
+ return 1;
+}
+
+static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ cairo_font_extents_t extents;
+
+ if (!ctxcanvas->font)
+ return;
+
+ cairo_set_scaled_font(ctxcanvas->cr, ctxcanvas->font);
+ cairo_font_extents(ctxcanvas->cr, &extents);
+
+ if (ascent) *ascent = (int)extents.ascent;
+ if (descent) *descent = (int)extents.descent;
+ if (height) *height = (int)extents.height;
+ if (max_width) *max_width = (int)extents.max_x_advance;
+}
+
+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 cdclear(cdCtxCanvas* ctxcanvas)
+{
+ cairo_save (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)
+{
+ update_fill(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 cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ update_fill(ctxcanvas, 0);
+
+ if (w == h)
+ {
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD);
+ 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_negative(ctxcanvas->cr, xc, yc, 0.5*h, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD);
+ 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)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w == h)
+ {
+ cairo_move_to(ctxcanvas->cr, xc, yc);
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD);
+ 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_negative(ctxcanvas->cr, xc, yc, 0.5*h, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD);
+
+ if (ctxcanvas->canvas->interior_style == CD_SOLID ||
+ ctxcanvas->canvas->interior_style == CD_PATTERN)
+ cairo_fill(ctxcanvas->cr);
+ else
+ {
+ cairo_line_to(ctxcanvas->cr, xc, yc);
+ cairo_stroke(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)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w == h)
+ {
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD);
+ cairo_fill_preserve(ctxcanvas->cr);
+ cairo_stroke(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, 1.0, w/h);
+
+ cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD);
+ cairo_fill_preserve(ctxcanvas->cr);
+ cairo_stroke(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)
+{
+ update_fill(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)
+{
+ update_fill(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 cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s, int len)
+{
+ cairo_text_extents_t extents;
+ cairo_font_extents_t font_extents;
+ int dir = -1;
+ double x_origin = x;
+ double y_origin = y;
+
+ s = StrConvertToUTF8(ctxcanvas, s, len);
+
+ cairo_set_scaled_font(ctxcanvas->cr, ctxcanvas->font);
+ cairo_font_extents(ctxcanvas->cr, &font_extents);
+ cairo_text_extents(ctxcanvas->cr, s, &extents);
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_RIGHT:
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ x = x - (int)extents.width;
+ break;
+ case CD_BASE_CENTER:
+ case CD_CENTER:
+ case CD_NORTH:
+ case CD_SOUTH:
+ x = x - (int)(extents.width/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;
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH_WEST:
+ case CD_SOUTH:
+ y = y - dir*(int)font_extents.descent;
+ break;
+ case CD_NORTH_EAST:
+ case CD_NORTH:
+ case CD_NORTH_WEST:
+ y = y + dir*(int)(extents.height - font_extents.descent);
+ break;
+ case CD_CENTER:
+ case CD_EAST:
+ case CD_WEST:
+ y = y + dir*(int)(extents.height/2 - font_extents.descent);
+ break;
+ }
+
+ if (ctxcanvas->canvas->text_orientation != 0)
+ {
+ cairo_matrix_t matrix;
+ double angle = CD_DEG2RAD * ctxcanvas->canvas->text_orientation;
+ double cos_angle = cos(angle);
+ double sin_angle = sin(angle);
+
+ cdfRotatePoint(ctxcanvas->canvas, x, y, x_origin, y_origin, &x, &y, sin_angle, cos_angle);
+
+ cairo_get_font_matrix(ctxcanvas->cr, &matrix);
+ cairo_matrix_rotate(&matrix, -angle);
+ cairo_set_font_matrix(ctxcanvas->cr, &matrix);
+ }
+
+ update_fill(ctxcanvas, 0);
+
+ cairo_move_to(ctxcanvas->cr, x, y);
+ cairo_show_text(ctxcanvas->cr, s);
+ cairo_fill(ctxcanvas->cr);
+}
+
+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)
+{
+ cairo_text_extents_t extents;
+
+ if (!ctxcanvas->font)
+ return;
+
+ s = StrConvertToUTF8(ctxcanvas, s, len);
+
+ cairo_set_scaled_font(ctxcanvas->cr, ctxcanvas->font);
+ cairo_text_extents(ctxcanvas->cr, s, &extents);
+
+ if (width)
+ *width = (int)extents.width;
+
+ if (height)
+ *height = (int)extents.height;
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_CLIP)
+ return;
+
+ if (mode == CD_FILL)
+ {
+ update_fill(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
+ update_fill(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_FILL)
+ {
+ update_fill(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
+ update_fill(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 col, lin, pos;
+ double red, green, blue;
+ cairo_pattern_t *pattern;
+
+ 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);
+
+ //TODO:fix
+ pattern = cairo_get_source(ctxcanvas->cr);
+ if (!pattern)
+ return;
+
+ for (lin = (y-h+1); lin < h; lin++)
+ {
+ for (col = x; col < w; col++)
+ {
+ pos = (h-lin-1) * w + col;
+ cairo_pattern_get_color_stop_rgba(pattern, pos, NULL, &red, &green, &blue, NULL);
+ *r = (unsigned char)(red*255.0);
+ *g = (unsigned char)(green*255.0);
+ *b = (unsigned char)(blue*255.0);
+ }
+ }
+
+ cairo_pattern_destroy(pattern);
+ cairo_restore (ctxcanvas->cr);
+}
+
+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, d, rw, rh;
+ unsigned char* rgb_data;
+ int stride;
+ cairo_surface_t* surface, *new_surface;
+ cairo_t* cr;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+ y -= (h - 1); /* Cairo image origin is at top-left */
+
+ stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, rw);
+ rgb_data = (unsigned char*)malloc(sizeof(unsigned char)*(stride * rh));
+
+ if (!rgb_data) return;
+
+ surface = cairo_image_surface_create_for_data(rgb_data, CAIRO_FORMAT_RGB24, rw, rh, stride);
+
+ d = 0;
+ for (i=ymax; i>=ymin; i--)
+ {
+ for (j=xmin; j<=xmax; j++)
+ {
+ rgb_data[d] = b[i*iw+j]; d++;
+ rgb_data[d] = g[i*iw+j]; d++;
+ rgb_data[d] = r[i*iw+j]; d++;
+ rgb_data[d] = (unsigned char)0; d++;
+ }
+ }
+
+ /* Scaling surface to fit into the image */
+// if (w != rw || h != rh)
+ {
+ new_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, w, h);
+ cr = cairo_create (new_surface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale (cr, (double)w / rw, (double)h / rh);
+ cairo_set_source_surface (cr, surface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0 alpha,
+ * which would occur with the default EXTEND_NONE */
+ cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of overlaying */
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+ }
+
+ /* Put image rect */
+ cairo_set_source_surface(ctxcanvas->cr, new_surface, x, y);
+ cairo_pattern_set_extend(cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE);
+ cairo_paint(ctxcanvas->cr);
+
+ cairo_surface_destroy(surface);
+ cairo_surface_destroy(new_surface);
+ free(rgb_data);
+}
+
+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, d, rw, rh;
+ unsigned char* rgba_data;
+ int stride;
+ cairo_surface_t* surface, *new_surface, *new_alpha_surface;
+ cairo_t* cr;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+ y -= (h - 1); /* Cairo image origin is at top-left */
+
+ stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, rw);
+ rgba_data = (unsigned char*)malloc(sizeof(unsigned char)*(stride * rh));
+
+ if (!rgba_data) return;
+
+ surface = cairo_image_surface_create_for_data(rgba_data, CAIRO_FORMAT_ARGB32, rw, rh, stride);
+
+ d = 0;
+ for (i=ymax; i>=ymin; i--)
+ {
+ for (j=xmin; j<=xmax; j++)
+ {
+ rgba_data[d] = b[i*iw+j]; d++;
+ rgba_data[d] = g[i*iw+j]; d++;
+ rgba_data[d] = r[i*iw+j]; d++;
+ rgba_data[d] = a[i*iw+j]; d++;
+ }
+ }
+
+ // TODO: use only one surface ?????
+
+ /* Scaling RGB surface to fit into the image */
+// if (w != rw || h != rh)
+ {
+ new_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, w, h);
+ cr = cairo_create (new_surface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale (cr, (double)w / rw, (double)h / rh);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+ }
+
+ /* Scaling ALPHA surface to fit into the image */
+ {
+ new_alpha_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_ALPHA, w, h);
+ cr = cairo_create (new_alpha_surface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale (cr, (double)w / rw, (double)h / rh);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+ }
+
+ /* Put image rect */
+ cairo_set_source_surface(ctxcanvas->cr, new_surface, x, y);
+ cairo_mask_surface(ctxcanvas->cr, new_alpha_surface, x, y);
+// cairo_pattern_set_extend(cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE);
+// cairo_paint(ctxcanvas->cr);
+
+ cairo_surface_destroy(surface);
+ cairo_surface_destroy(new_surface);
+ cairo_surface_destroy(new_alpha_surface);
+ free(rgba_data);
+}
+
+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, d, rw, rh;
+ unsigned char* rgb_data;
+ int stride;
+ cairo_surface_t* surface, *new_surface;
+ cairo_t* cr;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+ y -= (h - 1); /* Cairo image origin is at top-left */
+
+ stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, rw);
+ rgb_data = (unsigned char*)malloc(sizeof(unsigned char)*(stride * rh));
+
+ if (!rgb_data) return;
+
+ surface = cairo_image_surface_create_for_data(rgb_data, CAIRO_FORMAT_RGB24, rw, rh, stride);
+
+ d = 0;
+ for (i=ymax; i>=ymin; i--)
+ {
+ for (j=xmin; j<=xmax; j++)
+ {
+ long c = colors[index[i*iw+j]];
+ rgb_data[d] = cdRed(c); d++;
+ rgb_data[d] = cdGreen(c); d++;
+ rgb_data[d] = cdBlue(c); d++;
+ rgb_data[d] = (unsigned char)0; d++;
+ }
+ }
+
+ /* Scaling surface to fit into the image */
+// if (w != rw || h != rh)
+ {
+ new_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, w, h);
+ cr = cairo_create (new_surface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale (cr, (double)w / rw, (double)h / rh);
+ cairo_set_source_surface (cr, surface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0 alpha,
+ * which would occur with the default EXTEND_NONE */
+ cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of overlaying */
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+ }
+
+ cairo_set_source_surface(ctxcanvas->cr, surface, x, y);
+ cairo_pattern_set_extend(cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE);
+ cairo_paint(ctxcanvas->cr);
+
+ cairo_surface_destroy(surface);
+ cairo_surface_destroy(new_surface);
+ free(rgb_data);
+}
+
+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->img = cairo_create(img_surface);
+
+ if (!ctximage->img)
+ {
+ free(ctximage);
+ return (void *)0;
+ }
+
+ cairo_rectangle(ctximage->img, 0, 0, ctximage->w, ctximage->h);
+ cairo_set_source_rgba(ctximage->img, 1.0, 1.0, 1.0, 1.0); /* white opaque */
+ cairo_fill(ctximage->img);
+
+ cairo_surface_destroy(img_surface);
+
+ return (void*)ctximage;
+}
+
+static void cdkillimage (cdCtxImage *ctximage)
+{
+ cairo_destroy(ctximage->img);
+ free(ctximage);
+}
+
+static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y)
+{
+ cairo_save (ctximage->img);
+
+ /* reset to the identity. */
+ cairo_identity_matrix(ctximage->img);
+
+ cairo_reset_clip(ctximage->img);
+
+ 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->img, cairo_get_target(ctxcanvas->cr), x, y);
+
+ cairo_pattern_set_extend (cairo_get_source(ctximage->img), CAIRO_EXTEND_NONE);
+ cairo_set_operator (ctximage->img, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(ctximage->img); /* paints the current source everywhere within the current clip region. */
+
+ /* must restore matrix, clipping and source */
+ cairo_restore (ctximage->img);
+}
+
+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_reset_clip(ctxcanvas->cr);
+ cairo_rectangle(ctxcanvas->cr, x, y, xmax-xmin+1, ymax-ymin+1);
+ cairo_clip(ctxcanvas->cr);
+
+ ymin = (ctximage->h-1) - ymax; /* ymin starts at the bottom of the image in CD, we want ymax, but oriented top-down */
+
+ /* creates a pattern from the image and sets it as source in the canvas. */
+ cairo_set_source_surface(ctxcanvas->cr, cairo_get_target(ctximage->img), 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 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_reset_clip(ctxcanvas->cr);
+ 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);
+ ctxcanvas->canvas->invert_yaxis = 1;
+
+ 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);
+ ctxcanvas->canvas->invert_yaxis = 0;
+
+ 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 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)
+{
+ cairo_font_options_t* options = NULL;
+ cairo_scaled_font_get_font_options(ctxcanvas->font, options);
+
+ if (!data || data[0] == '0')
+ {
+ cairo_set_antialias(ctxcanvas->cr, CAIRO_ANTIALIAS_NONE);
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_NONE);
+ }
+ else
+ {
+ cairo_set_antialias(ctxcanvas->cr, CAIRO_ANTIALIAS_DEFAULT);
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_DEFAULT);
+ }
+
+ cairo_font_options_destroy(options);
+}
+
+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_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;
+
+ canvas->ctxcanvas = ctxcanvas;
+ canvas->invert_yaxis = 1;
+
+ 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);
+
+ 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->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->cxWriteMode = cdwritemode;
+ 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;
+}
+
+/*
+cairo_arc (cr, 128.0, 128.0, 76.8, 0, 2*M_PI);
+cairo_clip (cr);
+cairo_new_path (cr); // path not consumed by clip()
+*/
diff --git a/src/cairo/cdcairoctx.h b/src/cairo/cdcairoctx.h
new file mode 100644
index 0000000..266cfb3
--- /dev/null
+++ b/src/cairo/cdcairoctx.h
@@ -0,0 +1,77 @@
+/** \file
+ * \brief Cairo Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __CDCAIROCTX_H
+#define __CDCAIROCTX_H
+
+#include <cairo.h>
+
+#include "cd.h"
+#include "cd_private.h"
+
+
+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* img;
+};
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ cairo_t* cr;
+
+ cairo_scaled_font_t* font;
+
+ cairo_pattern_t *pattern, *solid;
+ int last_source;
+
+ char* cairoLastConvertUTF8;
+
+ /* 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 by double buffer driver */
+ cdCanvas* canvas_dbuffer;
+};
+
+#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/src/cairo/cdcairodbuf.c b/src/cairo/cdcairodbuf.c
new file mode 100644
index 0000000..0e23f06
--- /dev/null
+++ b/src/cairo/cdcairodbuf.c
@@ -0,0 +1,170 @@
+/** \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->img);
+
+ 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_FPRIMTIVES ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextCairoDBuffer(void)
+{
+ return &cdDBufferContext;
+}
diff --git a/src/cairo/cdcairoimg.c b/src/cairo/cdcairoimg.c
new file mode 100644
index 0000000..54c2fa7
--- /dev/null
+++ b/src/cairo/cdcairoimg.c
@@ -0,0 +1,52 @@
+/** \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->img);
+ 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_FPRIMTIVES ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+
+cdContext* cdContextCairoImage(void)
+{
+ return &cdImageContext;
+}
diff --git a/src/cairo/cdcairoirgb.c b/src/cairo/cdcairoirgb.c
new file mode 100644
index 0000000..1bb9698
--- /dev/null
+++ b/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_FPRIMTIVES),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoImageRGB(void)
+{
+ return &cdCairoImageRGBContext;
+}
diff --git a/src/cairo/cdcaironative_gdk.c b/src/cairo/cdcaironative_gdk.c
new file mode 100644
index 0000000..98face0
--- /dev/null
+++ b/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 | CD_CAP_FPRIMTIVES),
+ 1,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+
+cdContext* cdContextCairoNativeWindow(void)
+{
+ return &cdNativeWindowContext;
+}
diff --git a/src/cairo/cdcaironative_win32.c b/src/cairo/cdcaironative_win32.c
new file mode 100644
index 0000000..b685d12
--- /dev/null
+++ b/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 | CD_CAP_FPRIMTIVES),
+ 1,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+
+cdContext* cdContextCairoNativeWindow(void)
+{
+ return &cdNativeWindowContext;
+}
+
+// cairo_win32_printing_surface_create CD_PRINTER
diff --git a/src/cairo/cdcaironative_x11.c b/src/cairo/cdcaironative_x11.c
new file mode 100644
index 0000000..027de4e
--- /dev/null
+++ b/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 | CD_CAP_FPRIMTIVES),
+ 1,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+
+cdContext* cdContextCairoNativeWindow(void)
+{
+ return &cdNativeWindowContext;
+}
diff --git a/src/cairo/cdcairopdf.c b/src/cairo/cdcairopdf.c
new file mode 100644
index 0000000..880a2e5
--- /dev/null
+++ b/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_FPRIMTIVES),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoPDF(void)
+{
+ return &cdCairoPDFContext;
+}
diff --git a/src/cairo/cdcairoplus.c b/src/cairo/cdcairoplus.c
new file mode 100644
index 0000000..c50f1ec
--- /dev/null
+++ b/src/cairo/cdcairoplus.c
@@ -0,0 +1,26 @@
+/** \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();
+#ifdef WIN32
+// ctx_list[CD_CTX_PRINTER] = cdContextCairoPrinter();
+#endif
+
+ cdInitContextPlusList(ctx_list);
+}
diff --git a/src/cairo/cdcairops.c b/src/cairo/cdcairops.c
new file mode 100644
index 0000000..ed58723
--- /dev/null
+++ b/src/cairo/cdcairops.c
@@ -0,0 +1,170 @@
+/** \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 (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);
+
+ 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_FPRIMTIVES),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoPS(void)
+{
+ return &cdCairoPSContext;
+}
+
diff --git a/src/cairo/cdcairosvg.c b/src/cairo/cdcairosvg.c
new file mode 100644
index 0000000..ce36758
--- /dev/null
+++ b/src/cairo/cdcairosvg.c
@@ -0,0 +1,81 @@
+/** \file
+ * \brief Cairo SVG Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cd.h"
+#include "cdcairo.h"
+#include "cdcairoctx.h"
+
+#include <cairo-svg.h>
+
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ (void)ctxcanvas; /* Nothing to do */
+}
+
+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_FPRIMTIVES),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextCairoSVG(void)
+{
+ return &cdCairoSVGContext;
+}