diff options
author | Nicolas "Pixel" Noble <pixel@nobis-crew.org> | 2010-09-09 01:48:52 +0200 |
---|---|---|
committer | Nicolas "Pixel" Noble <pixel@nobis-crew.org> | 2010-09-09 01:50:25 +0200 |
commit | e9a184546b18cf3b796bd560561f312934004c54 (patch) | |
tree | aa785af9a8d03f8ce276c9e9ecec78397005ec22 /cd/src/cairo | |
parent | 92efe73791d0998536042bfab5a1babc67d168c7 (diff) |
Upgrading to CD 5.4 - and cleaning up.
Diffstat (limited to 'cd/src/cairo')
-rw-r--r-- | cd/src/cairo/cdcairo.c | 2110 | ||||
-rw-r--r-- | cd/src/cairo/cdcairo.def | 9 | ||||
-rw-r--r-- | cd/src/cairo/cdcairoctx.h | 88 | ||||
-rw-r--r-- | cd/src/cairo/cdcairodbuf.c | 169 | ||||
-rw-r--r-- | cd/src/cairo/cdcairoemf.c | 122 | ||||
-rw-r--r-- | cd/src/cairo/cdcairoimg.c | 51 | ||||
-rw-r--r-- | cd/src/cairo/cdcairoirgb.c | 159 | ||||
-rw-r--r-- | cd/src/cairo/cdcaironative_gdk.c | 80 | ||||
-rw-r--r-- | cd/src/cairo/cdcaironative_win32.c | 160 | ||||
-rw-r--r-- | cd/src/cairo/cdcaironative_x11.c | 98 | ||||
-rw-r--r-- | cd/src/cairo/cdcairopdf.c | 122 | ||||
-rw-r--r-- | cd/src/cairo/cdcairoplus.c | 30 | ||||
-rw-r--r-- | cd/src/cairo/cdcairoprn_unix.c | 196 | ||||
-rw-r--r-- | cd/src/cairo/cdcairoprn_win32.c | 194 | ||||
-rw-r--r-- | cd/src/cairo/cdcairops.c | 172 | ||||
-rw-r--r-- | cd/src/cairo/cdcairosvg.c | 83 |
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; +} |