From 25e85e1b809ec58ecac0f2e8fe48f74836f8e131 Mon Sep 17 00:00:00 2001 From: Pixel Date: Tue, 15 Jun 2010 00:18:43 -0700 Subject: Upgrading to CD 5.3 --- cd/src/gdk/cdgdk.c | 1713 ++++++++++++++++++++++++++++++++++++++++++++++ cd/src/gdk/cdgdk.h | 75 ++ cd/src/gdk/cdgdkclp.c | 131 ++++ cd/src/gdk/cdgdkdbuf.c | 169 +++++ cd/src/gdk/cdgdkimg.c | 52 ++ cd/src/gdk/cdgdknative.c | 117 ++++ 6 files changed, 2257 insertions(+) create mode 100644 cd/src/gdk/cdgdk.c create mode 100644 cd/src/gdk/cdgdk.h create mode 100644 cd/src/gdk/cdgdkclp.c create mode 100644 cd/src/gdk/cdgdkdbuf.c create mode 100644 cd/src/gdk/cdgdkimg.c create mode 100644 cd/src/gdk/cdgdknative.c (limited to 'cd/src/gdk') diff --git a/cd/src/gdk/cdgdk.c b/cd/src/gdk/cdgdk.c new file mode 100644 index 0000000..b0c8ea8 --- /dev/null +++ b/cd/src/gdk/cdgdk.c @@ -0,0 +1,1713 @@ +/** \file + * \brief Gdk Base Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include +#include +#include + +#include "cdgdk.h" + +#include + +#define NUM_HATCHES 6 +#define HATCH_WIDTH 8 +#define HATCH_HEIGHT 8 + +/* +** 6 predefined patterns to be accessed through cdHatch( + CD_HORIZONTAL | CD_VERTICAL | CD_FDIAGONAL | CD_BDIAGONAL | + CD_CROSS | CD_DIAGCROSS) + +*/ +static char hatches[NUM_HATCHES][8] = { + {0x00,0x00,0xFF,0x00,0x00,0x00,0xFF,0x00}, /* HORIZONTAL */ + {0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22}, /* VERTICAL */ + {0x08,0x10,0x20,0x40,0x80,0x01,0x02,0x04}, /* FDIAGONAL */ + {0x10,0x08,0x04,0x02,0x01,0x80,0x40,0x20}, /* BDIAGONAL */ + {0x22,0x22,0xFF,0x22,0x22,0x22,0xFF,0x22}, /* CROSS */ + {0x18,0x18,0x24,0x42,0x81,0x81,0x42,0x24} /* DIAGCROSS */ +}; + +/******************************************************/ + +static int gdkStrIsAscii(const char* str) +{ + while(*str) + { + int c = *str; + if (c < 0) + return 0; + str++; + } + return 1; +} + +static char* gdkStrToUTF8(const char *str, const char* charset, int length) +{ + return g_convert(str, length, "UTF-8", charset, NULL, NULL, NULL); +} + +char* cdgdkStrConvertToUTF8(cdCtxCanvas *ctxcanvas, const char* str, int length) /* From CD to GTK/GDK */ +{ + const char *charset = NULL; + + if (!str || *str == 0) + return (char*)str; + + if (g_get_charset(&charset) == TRUE) /* current locale is already UTF-8 */ + { + if (g_utf8_validate(str, -1, NULL)) + { + return (char*)str; + } + else + { + ctxcanvas->gdkLastConvertUTF8 = gdkStrToUTF8(str, "ISO8859-1", length); /* if string is not UTF-8, assume ISO8859-1 */ + + if (!ctxcanvas->gdkLastConvertUTF8) + return (char*)str; + + return ctxcanvas->gdkLastConvertUTF8; + } + } + else + { + if (gdkStrIsAscii(str) || !charset) + { + return (char*)str; + } + else if (charset) + { + ctxcanvas->gdkLastConvertUTF8 = gdkStrToUTF8(str, charset, length); + + if (!ctxcanvas->gdkLastConvertUTF8) + return (char*)str; + + return ctxcanvas->gdkLastConvertUTF8; + } + } + return (char*)str; +} + +static GdkColor cdColorToGdk(unsigned long rgb) +{ + GdkColor clrRGB; + + clrRGB.red = cdCOLOR8TO16(cdRed(rgb)); + clrRGB.green = cdCOLOR8TO16(cdGreen(rgb)); + clrRGB.blue = cdCOLOR8TO16(cdBlue(rgb)); + + return clrRGB; +} + +/******************************************************/ + +void cdgdkKillCanvas(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->canvas->bpp <= 8) + { + if (ctxcanvas->colormap != gdk_gc_get_colormap(ctxcanvas->gc)) + g_object_unref(ctxcanvas->colormap); + } + + if (ctxcanvas->last_hatch) g_object_unref(ctxcanvas->last_hatch); + + 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->new_rgn) gdk_region_destroy(ctxcanvas->new_rgn); + if (ctxcanvas->clip_rgn) gdk_region_destroy(ctxcanvas->clip_rgn); + + if (ctxcanvas->last_pattern) + { + g_object_unref(ctxcanvas->last_pattern_gc); + g_object_unref(ctxcanvas->last_pattern); + } + + if (ctxcanvas->last_stipple) + { + g_object_unref(ctxcanvas->last_stipple_gc); + g_object_unref(ctxcanvas->last_stipple); + } + + g_object_unref(ctxcanvas->gc); + + free(ctxcanvas); +} + +/******************************************************/ + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + (void)ctxcanvas; + gdk_error_trap_push(); + gdk_flush(); + gdk_error_trap_pop(); +} + +/******************************************************/ + +static int cdclip(cdCtxCanvas *ctxcanvas, int clip_mode) +{ + switch (clip_mode) + { + case CD_CLIPOFF: + gdk_gc_set_clip_region(ctxcanvas->gc, NULL); + break; + case CD_CLIPAREA: + { + GdkRectangle rect; + rect.x = ctxcanvas->canvas->clip_rect.xmin; + rect.y = ctxcanvas->canvas->clip_rect.ymin; + rect.width = ctxcanvas->canvas->clip_rect.xmax - ctxcanvas->canvas->clip_rect.xmin; + rect.height = ctxcanvas->canvas->clip_rect.ymax - ctxcanvas->canvas->clip_rect.ymin; + gdk_gc_set_clip_rectangle(ctxcanvas->gc, &rect); + break; + } + case CD_CLIPPOLYGON: + if (ctxcanvas->clip_rgn) + gdk_gc_set_clip_region(ctxcanvas->gc, ctxcanvas->clip_rgn); + break; + case CD_CLIPREGION: + if (ctxcanvas->new_rgn) + gdk_gc_set_clip_region(ctxcanvas->gc, ctxcanvas->new_rgn); + break; + } + + return clip_mode; +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_rect.xmin = xmin; + ctxcanvas->canvas->clip_rect.ymin = ymin; + ctxcanvas->canvas->clip_rect.xmax = xmax; + ctxcanvas->canvas->clip_rect.ymax = ymax; + cdclip(ctxcanvas, CD_CLIPAREA); + } +} + +static void cdnewregion(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->new_rgn) + gdk_region_destroy(ctxcanvas->new_rgn); + + ctxcanvas->new_rgn = gdk_region_new(); +} + +static int cdispointinregion(cdCtxCanvas *ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_rgn) + return 0; + + if (gdk_region_point_in(ctxcanvas->new_rgn, x, y)) + return 1; + + return 0; +} + +static void cdoffsetregion(cdCtxCanvas *ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_rgn) + return; + + gdk_region_offset(ctxcanvas->new_rgn, x, y); +} + +static void cdgetregionbox(cdCtxCanvas *ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + GdkRectangle rect; + + if (!ctxcanvas->new_rgn) + return; + + gdk_region_get_clipbox(ctxcanvas->new_rgn, &rect); + + *xmin = rect.x; + *xmax = rect.x + rect.width; + *ymin = rect.y; + *ymax = rect.y + rect.height; +} + +static void sCombineRegion(cdCtxCanvas *ctxcanvas, GdkRegion* rgn) +{ + switch(ctxcanvas->canvas->combine_mode) + { + case CD_UNION: + gdk_region_union(ctxcanvas->new_rgn, rgn); + break; + case CD_INTERSECT: + gdk_region_intersect(ctxcanvas->new_rgn, rgn); + break; + case CD_DIFFERENCE: + gdk_region_subtract(ctxcanvas->new_rgn, rgn); + break; + case CD_NOTINTERSECT: + gdk_region_xor(ctxcanvas->new_rgn, rgn); + break; + } + + gdk_region_destroy(rgn); +} + +/******************************************************/ + +static int cdwritemode(cdCtxCanvas *ctxcanvas, int write_mode) +{ + switch (write_mode) + { + case CD_REPLACE: + gdk_gc_set_function(ctxcanvas->gc, GDK_COPY); + break; + case CD_XOR: + gdk_gc_set_function(ctxcanvas->gc, GDK_XOR); + break; + case CD_NOT_XOR: + gdk_gc_set_function(ctxcanvas->gc, GDK_EQUIV); + break; + } + + return write_mode; +} + +static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style) +{ + GdkFill sty = GDK_SOLID; + + switch (style) + { + case CD_SOLID: + sty = GDK_SOLID; + break; + + case CD_HATCH : + if (!ctxcanvas->last_hatch) + return ctxcanvas->canvas->interior_style; + + gdk_gc_set_stipple(ctxcanvas->gc, ctxcanvas->last_hatch); + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + sty = GDK_OPAQUE_STIPPLED; + else + sty = GDK_STIPPLED; + break; + + case CD_STIPPLE: + gdk_gc_set_stipple(ctxcanvas->gc, ctxcanvas->last_stipple); + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + sty = GDK_OPAQUE_STIPPLED; + else + sty = GDK_STIPPLED; + break; + + case CD_PATTERN: + gdk_gc_set_tile(ctxcanvas->gc, ctxcanvas->last_pattern); + sty = GDK_TILED; + break; + } + + gdk_gc_set_fill(ctxcanvas->gc, sty); + + return style; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int hatch_style) +{ + GdkColor fg, bg; + + if (ctxcanvas->last_hatch) + g_object_unref(ctxcanvas->last_hatch); + + fg.pixel = 1; + bg.pixel = 0; + + ctxcanvas->last_hatch = gdk_pixmap_create_from_data(ctxcanvas->wnd, hatches[hatch_style], + HATCH_WIDTH, HATCH_HEIGHT, 1, &fg, &bg); + + cdinteriorstyle(ctxcanvas, CD_HATCH); + + return hatch_style; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *data) +{ + int x, y; + + if (ctxcanvas->last_stipple == 0 || (ctxcanvas->last_stipple_w != w || ctxcanvas->last_stipple_h != h)) + { + if (ctxcanvas->last_stipple != 0) + { + g_object_unref(ctxcanvas->last_stipple); + g_object_unref(ctxcanvas->last_stipple_gc); + } + + ctxcanvas->last_stipple = gdk_pixmap_new(ctxcanvas->wnd, w, h, 1); + if (!ctxcanvas->last_stipple) + return; + + ctxcanvas->last_stipple_gc = gdk_gc_new((GdkDrawable*)ctxcanvas->last_stipple); + ctxcanvas->last_stipple_w = w; + ctxcanvas->last_stipple_h = h; + } + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + GdkColor clr; + + if(data[y*w+x]) + clr.pixel = 1; + else + clr.pixel = 0; + + gdk_gc_set_foreground(ctxcanvas->last_stipple_gc, &clr); + gdk_draw_point(ctxcanvas->last_stipple, ctxcanvas->last_stipple_gc, x, h-y-1); + } + } + + cdinteriorstyle(ctxcanvas, CD_STIPPLE); +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *colors) +{ + int x, y; + GdkColor color; + + if (ctxcanvas->last_pattern == 0 || (ctxcanvas->last_pattern_w != w || ctxcanvas->last_pattern_h != h)) + { + if (ctxcanvas->last_pattern != 0) + { + g_object_unref(ctxcanvas->last_pattern); + g_object_unref(ctxcanvas->last_pattern_gc); + } + + ctxcanvas->last_pattern = gdk_pixmap_new(ctxcanvas->wnd, w, h, ctxcanvas->depth); + if (!ctxcanvas->last_pattern) + return; + + ctxcanvas->last_pattern_gc = gdk_gc_new((GdkDrawable*)ctxcanvas->last_pattern); + ctxcanvas->last_pattern_w = w; + ctxcanvas->last_pattern_h = h; + } + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + color = cdColorToGdk(colors[y*w+x]); + gdk_gc_set_rgb_fg_color(ctxcanvas->last_pattern_gc, &color); + gdk_draw_point(ctxcanvas->last_pattern, ctxcanvas->last_pattern_gc, x, h-y-1); + } + } + + cdinteriorstyle(ctxcanvas, CD_PATTERN); +} + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + switch (style) + { + case CD_CONTINUOUS: + ctxcanvas->gcval.line_style = GDK_LINE_SOLID; + break; + case CD_DASHED: + case CD_DOTTED: + case CD_DASH_DOT: + case CD_DASH_DOT_DOT: + { + static struct { + int size; + signed char list[6]; + } dashes[4] = { + { 2, { 6, 2 } }, + { 2, { 2, 2 } }, + { 4, { 6, 2, 2, 2 } }, + { 6, { 6, 2, 2, 2, 2, 2 } } + }; + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + ctxcanvas->gcval.line_style = GDK_LINE_DOUBLE_DASH; + else + ctxcanvas->gcval.line_style = GDK_LINE_ON_OFF_DASH; + + gdk_gc_set_dashes(ctxcanvas->gc, 0, dashes[style-CD_DASHED].list, dashes[style-CD_DASHED].size); + break; + } + case CD_CUSTOM: + { + int i; + signed char* dash_style = (signed char*)malloc(ctxcanvas->canvas->line_dashes_count); + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + dash_style[i] = (char)ctxcanvas->canvas->line_dashes[i]; + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + ctxcanvas->gcval.line_style = GDK_LINE_DOUBLE_DASH; + else + ctxcanvas->gcval.line_style = GDK_LINE_ON_OFF_DASH; + + gdk_gc_set_dashes(ctxcanvas->gc, 0, dash_style, ctxcanvas->canvas->line_dashes_count); + free(dash_style); + break; + } + } + + gdk_gc_set_values(ctxcanvas->gc, &ctxcanvas->gcval, GDK_GC_LINE_STYLE); + + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + if (width == 1) + ctxcanvas->gcval.line_width = 0; + else + ctxcanvas->gcval.line_width = width; + + gdk_gc_set_values(ctxcanvas->gc, &ctxcanvas->gcval, GDK_GC_LINE_WIDTH); + + return width; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + int cd2x_cap[] = {GDK_CAP_BUTT, GDK_CAP_PROJECTING, GDK_CAP_ROUND}; + + ctxcanvas->gcval.cap_style = cd2x_cap[cap]; + gdk_gc_set_values(ctxcanvas->gc, &ctxcanvas->gcval, GDK_GC_CAP_STYLE); + + return cap; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + int cd2x_join[] = {GDK_JOIN_MITER, GDK_JOIN_BEVEL, GDK_JOIN_ROUND}; + + ctxcanvas->gcval.join_style = cd2x_join[join]; + gdk_gc_set_values(ctxcanvas->gc, &ctxcanvas->gcval, GDK_GC_JOIN_STYLE); + + return join; +} + +static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opaque) +{ + ctxcanvas->canvas->back_opacity = opaque; + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); + cdlinestyle(ctxcanvas, ctxcanvas->canvas->line_style); + return opaque; +} + +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; + + if (size < 0) + { + double res = ((double)gdk_screen_get_width(gdk_screen_get_default()) / + (double)gdk_screen_get_width_mm(gdk_screen_get_default())); /* pixels/mm */ + + /* 1 point = 1/72 inch 1 inch = 25.4 mm */ + /* pixel = ((point/72)*25.4)*pixel/mm */ + size = (int)((-size/res)*2.83464567 + 0.5); /* from pixels to points */ + } + + sprintf(font, "%s, %s%s%d", typeface, is_bold?"Bold ":"", is_italic?"Italic ":"", size); + + ctxcanvas->fontdesc = pango_font_description_from_string(font); + + if (!ctxcanvas->fontdesc) + return 0; + + 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); + + return 1; +} + +static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* nativefont) +{ + int size = 12, style = CD_PLAIN; + char typeface[1024]; + + /* parse the old Windows format first */ + if (!cdParseIupWinFont(nativefont, typeface, &style, &size)) + if (!cdParseXWinFont(nativefont, typeface, &style, &size)) + if (!cdParsePangoFont(nativefont, typeface, &style, &size)) + return 0; + + if (!cdfont(ctxcanvas, typeface, style, size)) + return 0; + + /* update cdfont parameters */ + ctxcanvas->canvas->font_style = style; + ctxcanvas->canvas->font_size = size; + strcpy(ctxcanvas->canvas->font_type_face, typeface); + + 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; + + 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 cdbackground(cdCtxCanvas *ctxcanvas, long int color) +{ + ctxcanvas->bg = cdColorToGdk(color); + gdk_gc_set_rgb_bg_color(ctxcanvas->gc, &ctxcanvas->bg); + return color; +} + +static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + ctxcanvas->fg = cdColorToGdk(color); + gdk_gc_set_rgb_fg_color(ctxcanvas->gc, &ctxcanvas->fg); + return color; +} + +static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode) +{ + int i; + GdkColor clr; + + if (mode == CD_FORCE) + { + /* if was POLITE then allocates own palette */ + if (ctxcanvas->colormap == gdk_gc_get_colormap(ctxcanvas->gc)) + ctxcanvas->colormap = gdk_colormap_new(ctxcanvas->vis, FALSE); + + /* allocate all the palette colors to the CD */ + for (i = 0; i < n; i++) + { + clr = cdColorToGdk(palette[i]); + gdk_colormap_alloc_color(ctxcanvas->colormap, &clr, FALSE, FALSE); + } + + /* set directly on the drawable */ + gdk_drawable_set_colormap(ctxcanvas->wnd, ctxcanvas->colormap); + } + else + { + /* if was FORCE, remove the own palette */ + if (ctxcanvas->colormap != gdk_gc_get_colormap(ctxcanvas->gc)) + { + g_object_unref(ctxcanvas->colormap); + ctxcanvas->colormap = gdk_gc_get_colormap(ctxcanvas->gc); + } + + /* if POLITE then just try to allocate all the colors of the palette */ + for (i = 0; i < n; i++) + { + clr = cdColorToGdk(palette[i]); + gdk_colormap_alloc_color(ctxcanvas->colormap, &clr, FALSE, TRUE); + } + } +} + +/******************************************************/ + +static void cdgdkCheckSolidStyle(cdCtxCanvas *ctxcanvas, int set) +{ + if (ctxcanvas->canvas->interior_style == CD_SOLID) + return; + + if (set) + gdk_gc_set_fill(ctxcanvas->gc, GDK_SOLID); + else + cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); +} + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + GdkColor clr; + + cdgdkCheckSolidStyle(ctxcanvas, 1); + + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + gdk_gc_set_clip_region(ctxcanvas->gc, NULL); + + clr = cdColorToGdk(ctxcanvas->canvas->background); + gdk_gc_set_rgb_fg_color(ctxcanvas->gc, &clr); + + gdk_draw_rectangle(ctxcanvas->wnd, ctxcanvas->gc, TRUE, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); + + clr = cdColorToGdk(ctxcanvas->canvas->foreground); + gdk_gc_set_rgb_fg_color(ctxcanvas->gc, &clr); + + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + cdclip(ctxcanvas, ctxcanvas->canvas->clip_mode); + + cdgdkCheckSolidStyle(ctxcanvas, 0); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdMatrixTransformPoint(ctxcanvas->xmatrix, x1, y1, &x1, &y1); + cdMatrixTransformPoint(ctxcanvas->xmatrix, x2, y2, &x2, &y2); + } + + cdgdkCheckSolidStyle(ctxcanvas, 1); + gdk_draw_line(ctxcanvas->wnd, ctxcanvas->gc, x1, y1, x2, y2); + cdgdkCheckSolidStyle(ctxcanvas, 0); +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdarcSIM(ctxcanvas, xc, yc, w, h, a1, a2); + return; + } + + cdgdkCheckSolidStyle(ctxcanvas, 1); + gdk_draw_arc(ctxcanvas->wnd, ctxcanvas->gc, FALSE, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64)); + cdgdkCheckSolidStyle(ctxcanvas, 0); +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2); + return; + } + + if (ctxcanvas->canvas->new_region) + { + cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2); + } + else + { + /* "filled parameter = TRUE" produces an 'pie slice' */ + gdk_draw_arc(ctxcanvas->wnd, ctxcanvas->gc, TRUE, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64)); + } +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdrectSIM(ctxcanvas, xmin, xmax, ymin, ymax); + return; + } + + cdgdkCheckSolidStyle(ctxcanvas, 1); + gdk_draw_rectangle(ctxcanvas->wnd, ctxcanvas->gc, FALSE, xmin, ymin, xmax-xmin, ymax-ymin); + cdgdkCheckSolidStyle(ctxcanvas, 0); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->use_matrix) + { + cdboxSIM(ctxcanvas, xmin, xmax, ymin, ymax); + return; + } + + if (ctxcanvas->canvas->new_region) + { + GdkRegion *rgn; + GdkRectangle rect; + + rect.x = xmin; rect.width = xmax-xmin; + rect.y = ymin; rect.height = ymax-ymin; + rgn = gdk_region_rectangle(&rect); + + sCombineRegion(ctxcanvas, rgn); + } + else + gdk_draw_rectangle(ctxcanvas->wnd, ctxcanvas->gc, TRUE, xmin, ymin, xmax-xmin+1, ymax-ymin+1); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s, int len) +{ + PangoFontMetrics* metrics; + int w, h, desc, dir = -1; + int ox = x, oy = y; + + ctxcanvas->gdkLastConvertUTF8 = cdgdkStrConvertToUTF8(ctxcanvas, s, len); + pango_layout_set_text(ctxcanvas->fontlayout, ctxcanvas->gdkLastConvertUTF8, -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); + + 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) + { + ctxcanvas->fontmatrix.xx = 1; ctxcanvas->fontmatrix.xy = 0; + ctxcanvas->fontmatrix.yx = 0; ctxcanvas->fontmatrix.yy = 1; + ctxcanvas->fontmatrix.x0 = 0; ctxcanvas->fontmatrix.y0 = 0; + } + + if (ctxcanvas->canvas->text_orientation != 0) + pango_matrix_rotate(&ctxcanvas->fontmatrix, (double)ctxcanvas->canvas->text_orientation); + + if (ctxcanvas->canvas->use_matrix || ctxcanvas->canvas->text_orientation != 0) + { + PangoRectangle rect; + double angle = CD_DEG2RAD*ctxcanvas->canvas->text_orientation; + double cos_angle = cos(angle); + double sin_angle = sin(angle); + + pango_context_set_matrix (ctxcanvas->fontcontext, &ctxcanvas->fontmatrix); + pango_layout_context_changed (ctxcanvas->fontlayout); + + pango_layout_get_pixel_extents(ctxcanvas->fontlayout, NULL, &rect); + pango_matrix_transform_pixel_rectangle(&ctxcanvas->fontmatrix, &rect); + + if (ctxcanvas->canvas->text_orientation) + cdRotatePoint(ctxcanvas->canvas, x, y, ox, oy, &x, &y, sin_angle, cos_angle); + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); + + /* Defines the new position (X,Y), considering the Pango rectangle transformed */ + x += (int)rect.x; + y += (int)rect.y; + } + + cdgdkCheckSolidStyle(ctxcanvas, 1); + + if (ctxcanvas->canvas->new_region) + { + GdkRegion *rgn; + gint *idx; + gint range; + + pango_layout_line_get_x_ranges(pango_layout_get_line(ctxcanvas->fontlayout, 0), 0, len, &idx, &range); + + /* TODO: this is only the bounding box of the layout, not the text itself, + must transform the text into a polygon. */ + rgn = gdk_pango_layout_get_clip_region(ctxcanvas->fontlayout, x, y, idx, range); + + sCombineRegion(ctxcanvas, rgn); + } + else + gdk_draw_layout(ctxcanvas->wnd, ctxcanvas->gc, x, y, ctxcanvas->fontlayout); + + pango_context_set_matrix(ctxcanvas->fontcontext, NULL); + + cdgdkCheckSolidStyle(ctxcanvas, 0); + + pango_font_metrics_unref(metrics); +} + +static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int len, int *width, int *height) +{ + if (!ctxcanvas->fontlayout) + return; + + ctxcanvas->gdkLastConvertUTF8 = cdgdkStrConvertToUTF8(ctxcanvas, s, len); + pango_layout_set_text(ctxcanvas->fontlayout, ctxcanvas->gdkLastConvertUTF8, -1); + 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_BEZIER) + { + for (i = 0; i < n; i++) + { + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, poly[i].x, poly[i].y, &(poly[i].x), &(poly[i].y)); + } + } + + switch( mode ) + { + case CD_FILL: + if (ctxcanvas->canvas->new_region) + { + GdkRegion* rgn = gdk_region_polygon((GdkPoint*)poly, n, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE); + sCombineRegion(ctxcanvas, rgn); + } + else + gdk_draw_polygon(ctxcanvas->wnd, ctxcanvas->gc, TRUE, (GdkPoint*)poly, n); + break; + + case CD_CLOSED_LINES: + cdgdkCheckSolidStyle(ctxcanvas, 1); + gdk_draw_polygon(ctxcanvas->wnd, ctxcanvas->gc, FALSE, (GdkPoint*)poly, n); + cdgdkCheckSolidStyle(ctxcanvas, 0); + break; + + case CD_OPEN_LINES: + cdgdkCheckSolidStyle(ctxcanvas, 1); + gdk_draw_lines(ctxcanvas->wnd, ctxcanvas->gc, (GdkPoint*)poly, n); + cdgdkCheckSolidStyle(ctxcanvas, 0); + break; + + case CD_CLIP: + ctxcanvas->clip_rgn = gdk_region_polygon((GdkPoint*)poly, n, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE); + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + cdclip(ctxcanvas, CD_CLIPPOLYGON); + break; + + case CD_BEZIER: + cdSimPolyBezier(ctxcanvas->canvas, poly, n); + break; + } +} + +/******************************************************/ + +static void cdgdkGetPixbufData(GdkPixbuf* pixbuf, unsigned char *r, unsigned char *g, unsigned char *b) +{ + int w, h, y, x, bpp; + guchar *pixdata, *pixline_data; + int rowstride, channels; + + w = gdk_pixbuf_get_width(pixbuf); + h = gdk_pixbuf_get_height(pixbuf); + bpp = gdk_pixbuf_get_bits_per_sample(pixbuf)*gdk_pixbuf_get_n_channels(pixbuf); + + if (bpp!=24 && bpp!=32) + return; + + pixdata = gdk_pixbuf_get_pixels(pixbuf); + rowstride = gdk_pixbuf_get_rowstride(pixbuf); + channels = gdk_pixbuf_get_n_channels(pixbuf); + + /* planes are separated in imgdata */ + for (y=0; ywnd, ctxcanvas->colormap, + x, y-h+1, + 0, 0, w, h); + if (!pixbuf) + { + fprintf(stderr, "CanvasDraw: error getting image\n"); + return; + } + + cdgdkGetPixbufData(pixbuf, r, g, b); +} + +static void cdputimagerectrgba_matrix(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 t_xmin, t_xmax, t_ymin, t_ymax, ew, eh, + t_x, t_y, dst_offset, size, nc, doff, rect[8]; + float i_x, i_y, xfactor, yfactor; + unsigned char *dst_r, *dst_g, *dst_b, *dst_a = NULL; + double inv_matrix[6]; + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, rect); + + /* Setup inverse transform (use the original transform here, NOT ctxcanvas->xmatrix) */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* create an image for the destination area */ + ew = (t_xmax-t_xmin+1); + eh = (t_ymax-t_ymin+1); + size = ew*eh; + nc = 3; + if (a) nc = 4; + dst_r = malloc(nc*size); + if (!dst_r) + { + fprintf(stderr, "CanvasDraw: no enough memory\n"); + return; + } + dst_g = dst_r + size; + dst_b = dst_g + size; + if (a) dst_a = dst_b + size; + memset(dst_r, 0, nc*size); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = (t_y-t_ymin) * ew; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + doff = (t_x-t_xmin) + dst_offset; + *(dst_r+doff) = cdBilinearInterpolation(iw, ih, r, i_x, i_y); + *(dst_g+doff) = cdBilinearInterpolation(iw, ih, g, i_x, i_y); + *(dst_b+doff) = cdBilinearInterpolation(iw, ih, b, i_x, i_y); + if (a) *(dst_a+doff) = cdBilinearInterpolation(iw, ih, a, i_x, i_y); + } + } + } + + { + int ex = t_xmin, + ey = t_ymin + eh-1; /* GdkPixbuf origin is at top-left */ + GdkPixbuf *pixbuf; + GdkRegion *clip_polygon; + GdkPoint* pnt = g_malloc(64); + + /* Since the transformation used was the original transformation, */ + /* must invert the Y axis here. */ + ey = _cdInvertYAxis(ctxcanvas->canvas, ey); + + /* use clipping to select only the transformed rectangle */ + pnt[0].x = (short)rect[0]; pnt[0].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[1]); + pnt[1].x = (short)rect[2]; pnt[1].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[3]); + pnt[2].x = (short)rect[4]; pnt[2].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[5]); + pnt[3].x = (short)rect[6]; pnt[3].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[7]); + clip_polygon = gdk_region_polygon(pnt, 4, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE); + + /* combine with the existing clipping */ + gdk_gc_set_function(ctxcanvas->gc, GDK_AND); + gdk_gc_set_clip_region(ctxcanvas->gc, clip_polygon); + + cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset gdk_gc_set_function */ + + pixbuf = cdgdkCreatePixbufRGBA(ew, eh, dst_r, dst_g, dst_b, dst_a, 0, 0, ew); + if (!pixbuf) + return; + + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + + /* reset clipping */ + gdk_region_destroy(clip_polygon); + cdclip(ctxcanvas, ctxcanvas->canvas->clip_mode); + + g_object_unref(pixbuf); + g_free(pnt); + } + + free(dst_r); +} + +static void cdputimagerectmap_matrix(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 t_xmin, t_xmax, t_ymin, t_ymax, ew, eh, + t_x, t_y, dst_offset, size, doff, rect[8]; + float i_x, i_y, xfactor, yfactor; + unsigned char *dst_index; + double inv_matrix[6]; + + /* calculate the destination limits */ + cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, rect); + + /* Setup inverse transform (use the original transform here, NOT ctxcanvas->xmatrix) */ + cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix); + + /* create an image for the destination area */ + ew = (t_xmax-t_xmin+1); + eh = (t_ymax-t_ymin+1); + size = ew*eh; + dst_index = malloc(size); + if (!dst_index) + { + fprintf(stderr, "CanvasDraw: no enough memory\n"); + return; + } + memset(dst_index, 0, size); + + /* for all pixels in the destiny area */ + for(t_y = t_ymin; t_y <= t_ymax; t_y++) + { + dst_offset = (t_y-t_ymin) * ew; + + for(t_x = t_xmin; t_x <= t_xmax; t_x++) + { + cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix); + + if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1) + { + doff = (t_x-t_xmin) + dst_offset; + *(dst_index+doff) = cdZeroOrderInterpolation(iw, ih, index, i_x, i_y); + } + } + } + + { + int ex = t_xmin, + ey = t_ymin + eh-1; /* GdkPixbuf* origin is at top-left */ + + GdkPixbuf *pixbuf; + GdkRegion *clip_polygon; + GdkPoint pnt[4]; + + /* Since the transformation used was the original transformation, */ + /* must invert the Y axis here. */ + ey = _cdInvertYAxis(ctxcanvas->canvas, ey); + + /* use clipping to select only the transformed rectangle */ + pnt[0].x = (short)rect[0]; pnt[0].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[1]); + pnt[1].x = (short)rect[2]; pnt[1].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[3]); + pnt[2].x = (short)rect[4]; pnt[2].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[5]); + pnt[3].x = (short)rect[6]; pnt[3].y = (short)_cdInvertYAxis(ctxcanvas->canvas, rect[7]); + clip_polygon = gdk_region_polygon(pnt, 4, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE); + + /* combine with the existing clipping */ + gdk_gc_set_function(ctxcanvas->gc, GDK_AND); + gdk_gc_set_clip_region(ctxcanvas->gc, clip_polygon); + + cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset gdk_gc_set_function */ + + pixbuf = cdgdkCreatePixbufMap(ew, eh, colors, dst_index, 0, 0, ew); + if (!pixbuf) + return; + + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + + /* reset clipping */ + gdk_region_destroy(clip_polygon); + cdclip(ctxcanvas, ctxcanvas->canvas->clip_mode); + + g_object_unref(pixbuf); + } + + free(dst_index); +} + +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 ew = w, eh = h, ex = x, ey = y; + int bw = iw, bh = ih, bx = 0, by = 0; + int rw, rh; + GdkPixbuf* pixbuf; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, NULL, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* GdkPixbuf origin is at top-left */ + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + pixbuf = cdgdkCreatePixbufRGBA(bw, bh, r, g, b, NULL, bx, by, iw); + if (!pixbuf) + return; + + if (bw!=ew || bh!=eh) + { + GdkPixbuf *pixbuf_scaled = gdk_pixbuf_scale_simple(pixbuf, ew, eh, ctxcanvas->img_interp); + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf_scaled, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + g_object_unref(pixbuf_scaled); + } + else + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + + g_object_unref(pixbuf); +} + +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) +{ + GdkPixbuf *pixbuf; + int ew = w, eh = h, ex = x, ey = y; + int bw = iw, bh = ih, bx = 0, by = 0; + int rw, rh; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* GdkPixbuf origin is at top-left */ + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + pixbuf = cdgdkCreatePixbufRGBA(bw, bh, r, g, b, a, bx, by, iw); + if (!pixbuf) + return; + + if (bw!=ew || bh!=eh) + { + GdkPixbuf *pixbuf_scaled = gdk_pixbuf_scale_simple(pixbuf, ew, eh, ctxcanvas->img_interp); + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf_scaled, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + g_object_unref(pixbuf_scaled); + } + else + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + + g_object_unref(pixbuf); +} + +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 ew = w, eh = h, ex = x, ey = y; + int bw = iw, bh = ih, bx = 0, by = 0; + int rw, rh; + GdkPixbuf* pixbuf; + + if (ctxcanvas->canvas->use_matrix) + { + cdputimagerectmap_matrix(ctxcanvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax); + return; + } + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* GdkPixbuf origin is at top-left */ + + if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) + return; + + if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0)) + return; + + pixbuf = cdgdkCreatePixbufMap(bw, bh, colors, index, bx, by, iw); + if (!pixbuf) + return; + + if (bw!=ew || bh!=eh) + { + GdkPixbuf *pixbuf_scaled = gdk_pixbuf_scale_simple(pixbuf, ew, eh, ctxcanvas->img_interp); + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf_scaled, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + g_object_unref(pixbuf_scaled); + } + else + gdk_draw_pixbuf(ctxcanvas->wnd, ctxcanvas->gc, pixbuf, 0, 0, ex, ey, -1, -1, ctxcanvas->img_dither, 0, 0); + + g_object_unref(pixbuf); +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + if (ctxcanvas->canvas->foreground != color) + { + GdkColor clr = cdColorToGdk(color); + gdk_gc_set_rgb_fg_color(ctxcanvas->gc, &clr); + } + + if (ctxcanvas->canvas->use_matrix) + cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y); + + /* Draw pixel */ + gdk_draw_point(ctxcanvas->wnd, ctxcanvas->gc, x, y); + + if (ctxcanvas->canvas->foreground != color) + gdk_gc_set_rgb_fg_color(ctxcanvas->gc, &ctxcanvas->fg); +} + +static cdCtxImage *cdcreateimage (cdCtxCanvas *ctxcanvas, int w, int h) +{ + GdkGC* gc; + cdCtxImage *ctximage = (cdCtxImage *)malloc(sizeof(cdCtxImage)); + GdkColor clr; + + ctximage->w = w; + ctximage->h = h; + ctximage->depth = ctxcanvas->depth; + ctximage->scr = ctxcanvas->scr; + ctximage->vis = ctxcanvas->vis; + + ctximage->img = gdk_pixmap_new(ctxcanvas->wnd, w, h, ctxcanvas->depth); + + if (!ctximage->img) + { + free(ctximage); + return (void *)0; + } + + gc = gdk_gc_new(ctximage->img); + + clr = cdColorToGdk(CD_WHITE); + + gdk_gc_set_rgb_fg_color(gc, &clr); + gdk_draw_rectangle(ctximage->img, gc, TRUE, 0, 0, ctximage->w, ctxcanvas->canvas->h); + + g_object_unref(gc); + + return (void*)ctximage; +} + +static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y) +{ + gdk_draw_drawable(ctximage->img, ctxcanvas->gc, + ctxcanvas->wnd, x, y - ctximage->h+1, 0, 0, + ctximage->w, ctximage->h); +} + +static void cdputimagerect (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + gdk_draw_drawable(ctxcanvas->wnd, ctxcanvas->gc, + ctximage->img, xmin, ctximage->h-ymax-1, x, y-(ymax-ymin+1)+1, + xmax-xmin+1, ymax-ymin+1); +} + +static void cdkillimage (cdCtxImage *ctximage) +{ + g_object_unref(ctximage->img); + free(ctximage); +} + +static void cdscrollarea (cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + gdk_draw_drawable(ctxcanvas->wnd, ctxcanvas->gc, + ctxcanvas->wnd, xmin, ymin, xmin+dx, ymin+dy, + xmax-xmin+1, ymax-ymin+1); +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + if (matrix) + { + PangoMatrix tmpMtx = PANGO_MATRIX_INIT; + + /* configure a bottom-up coordinate system */ + ctxcanvas->xmatrix[0] = 1; + ctxcanvas->xmatrix[1] = 0; + ctxcanvas->xmatrix[2] = 0; + ctxcanvas->xmatrix[3] = -1; + ctxcanvas->xmatrix[4] = 0; + ctxcanvas->xmatrix[5] = (ctxcanvas->canvas->h-1); + cdMatrixMultiply(matrix, ctxcanvas->xmatrix); + + /* Pango Matrix Transform */ + ctxcanvas->fontmatrix.xx = matrix[0] * tmpMtx.xx + matrix[1] * tmpMtx.xy; + ctxcanvas->fontmatrix.xy = matrix[0] * tmpMtx.yx + matrix[1] * tmpMtx.yy; + ctxcanvas->fontmatrix.yx = matrix[2] * tmpMtx.xx + matrix[3] * tmpMtx.xy; + ctxcanvas->fontmatrix.yy = matrix[2] * tmpMtx.yx + matrix[3] * tmpMtx.yy; + ctxcanvas->fontmatrix.x0 = 0; + ctxcanvas->fontmatrix.y0 = 0; + + ctxcanvas->canvas->invert_yaxis = 0; + } + else + { + ctxcanvas->canvas->invert_yaxis = 1; + } +} + +/******************************************************************/ + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + + cdCanvasTransformTranslate(ctxcanvas->canvas, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); + cdCanvasTransformRotate(ctxcanvas->canvas, ctxcanvas->rotate_angle); + cdCanvasTransformTranslate(ctxcanvas->canvas, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + + cdCanvasTransform(ctxcanvas->canvas, 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_imgdither_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data && cdStrEqualNoCase(data, "NORMAL")) + ctxcanvas->img_dither = GDK_RGB_DITHER_NORMAL; + else + ctxcanvas->img_dither = GDK_RGB_DITHER_NONE; +} + +static char* get_imgdither_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->img_dither) + return "NORMAL"; + else + return "NONE"; +} + +static cdAttribute imgdither_attrib = +{ + "IMGDITHER", + set_imgdither_attrib, + get_imgdither_attrib +}; + +static void set_interp_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data && cdStrEqualNoCase(data, "BILINEAR")) + ctxcanvas->img_interp = GDK_INTERP_BILINEAR; + else + ctxcanvas->img_interp = GDK_INTERP_NEAREST; +} + +static char* get_interp_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->img_interp) + return "BILINEAR"; + else + return "NEAREST"; +} + +static cdAttribute interp_attrib = +{ + "IMGINTERP", + set_interp_attrib, + get_interp_attrib +}; + +static char* get_gc_attrib(cdCtxCanvas *ctxcanvas) +{ + return (char*)ctxcanvas->gc; +} + +static cdAttribute gc_attrib = +{ + "GC", + NULL, + get_gc_attrib +}; + +static char* get_pangoversion_attrib(cdCtxCanvas* ctxcanvas) +{ + (void)ctxcanvas; + return (char*)pango_version_string(); +} + +static cdAttribute pangoversion_attrib = +{ + "PANGOVERSION", + NULL, + get_pangoversion_attrib +}; + +cdCtxCanvas *cdgdkCreateCanvas(cdCanvas* canvas, GdkDrawable* wnd, GdkScreen* scr, GdkVisual* vis) +{ + cdCtxCanvas *ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->scr = scr; + ctxcanvas->vis = vis; + ctxcanvas->wnd = wnd; + + ctxcanvas->gc = gdk_gc_new(wnd); + + if (!ctxcanvas->gc) + { + free(canvas); + return NULL; + } + + ctxcanvas->fontcontext = gdk_pango_context_get(); + pango_context_set_language(ctxcanvas->fontcontext, pango_language_get_default()); + ctxcanvas->gdkLastConvertUTF8 = NULL; + + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + gdk_drawable_get_size(wnd, &ctxcanvas->canvas->w, &ctxcanvas->canvas->h); + ctxcanvas->depth = gdk_drawable_get_depth(wnd); + + canvas->bpp = ctxcanvas->depth; + canvas->xres = ((double)gdk_screen_get_width(scr) / (double)gdk_screen_get_width_mm(scr)); + canvas->yres = ((double)gdk_screen_get_height(scr) / (double)gdk_screen_get_height_mm(scr)); + canvas->w_mm = ((double)canvas->w) / canvas->xres; + canvas->h_mm = ((double)canvas->h) / canvas->yres; + canvas->invert_yaxis = 1; + + if (canvas->bpp <= 8) + { + ctxcanvas->colormap = gdk_gc_get_colormap(ctxcanvas->gc); + if (!ctxcanvas->colormap) + { + ctxcanvas->colormap = gdk_colormap_get_system(); + gdk_gc_set_colormap(ctxcanvas->gc, ctxcanvas->colormap); + } + ctxcanvas->num_colors = ctxcanvas->colormap->size; + } + + cdRegisterAttribute(canvas, &gc_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + cdRegisterAttribute(canvas, &pangoversion_attrib); + cdRegisterAttribute(canvas, &imgdither_attrib); + cdRegisterAttribute(canvas, &interp_attrib); + + return ctxcanvas; +} + +void cdgdkInitTable(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 = cdchordSIM; + canvas->cxText = cdtext; + + canvas->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxWriteMode = cdwritemode; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxBackOpacity = cdbackopacity; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxNativeFont = cdnativefont; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPalette = cdpalette; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxTransform = cdtransform; + + canvas->cxScrollArea = cdscrollarea; + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + + canvas->cxGetImageRGB = cdgetimagergb; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; +} + +int cdBaseDriver(void) +{ + return CD_BASE_GDK; +} diff --git a/cd/src/gdk/cdgdk.h b/cd/src/gdk/cdgdk.h new file mode 100644 index 0000000..af3cdc0 --- /dev/null +++ b/cd/src/gdk/cdgdk.h @@ -0,0 +1,75 @@ +/** \file + * \brief Gdk Base Driver + * + * See Copyright Notice in cd.h + */ + +#ifndef __CDGDK_H +#define __CDGDK_H + +#include + +#include "cd.h" +#include "cd_private.h" + + +struct _cdCtxImage { + unsigned int w, h, depth; + GdkPixmap* img; + GdkScreen* scr; + GdkVisual* vis; +}; + +struct _cdCtxCanvas { + cdCanvas* canvas; + GdkVisual* vis; /* visual of the application */ + GdkScreen *scr; + GdkGC* gc; /* graphic context */ + GdkDrawable* wnd; /* drawable */ + GdkColor fg, bg; + + GdkGCValues gcval; + + GdkPixmap* last_hatch; /* last hatch set by user */ + GdkPixmap* last_stipple; /* last stipple set by user */ + GdkPixmap* last_pattern; /* last pattern set by user */ + GdkGC* last_stipple_gc; + int last_stipple_w; + int last_stipple_h; + + GdkGC* last_pattern_gc; + int last_pattern_w; + int last_pattern_h; + + unsigned int depth; /* canvas depth */ + long int *xidata; /* Image cache */ + int xisize; + GdkColormap* colormap; /* Color map */ + int num_colors; /* Size of the color table */ + double xmatrix[6]; /* Transformation matrix that includes axis inversion */ + float rotate_angle; + int rotate_center_x; + int rotate_center_y; + int img_dither, img_interp; + + GdkRegion* new_rgn; + GdkRegion* clip_rgn; + + PangoContext *fontcontext; + PangoFontDescription *fontdesc; + PangoLayout *fontlayout; + PangoMatrix fontmatrix; + char* gdkLastConvertUTF8; + + cdImage* image_dbuffer; /* Used by double buffer driver */ + cdCanvas* canvas_dbuffer; +}; + +#define cdCOLOR8TO16(_x) (_x*257) /* 65535/255 = 257 */ +#define cdCOLOR16TO8(_x) ((unsigned char)(_x/257)) + +cdCtxCanvas *cdgdkCreateCanvas(cdCanvas* canvas, GdkDrawable* wnd, GdkScreen* scr, GdkVisual* vis); +void cdgdkInitTable(cdCanvas* canvas); +void cdgdkKillCanvas(cdCtxCanvas *ctxcanvas); + +#endif diff --git a/cd/src/gdk/cdgdkclp.c b/cd/src/gdk/cdgdkclp.c new file mode 100644 index 0000000..22e7690 --- /dev/null +++ b/cd/src/gdk/cdgdkclp.c @@ -0,0 +1,131 @@ +/** \file + * \brief Gdk Clipboard Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include + +#include + +#include "cd.h" +#include "cd_private.h" +#include "cdclipbd.h" +#include "cdmf.h" +#include "cdmf_private.h" + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + char* buffer; + long dwSize; + FILE* file; + char filename[10240]; + cdCanvasMF* mfcanvas = (cdCanvasMF*)ctxcanvas; + GtkClipboard *clipboard = (GtkClipboard*)mfcanvas->data; + + /* guardar antes de remover o canvas */ + strcpy(filename, mfcanvas->filename); + + cdkillcanvasMF(mfcanvas); + + file = fopen(filename, "r"); + fseek(file, 0, SEEK_END); + dwSize = ftell(file); + fseek(file, 0, SEEK_SET); + + buffer = (char*)malloc(dwSize); + fread(buffer, dwSize, 1, file); + + fclose(file); + + remove(filename); + + gtk_clipboard_store(clipboard); +} + +static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data) +{ + char filename[1024]; + int dwSize; + FILE* file; + GdkAtom* buffer; + + gtk_clipboard_wait_for_targets((GtkClipboard*)data, &buffer, &dwSize); + if(!buffer) + return CD_ERROR; + + tmpnam(filename); + file = fopen(filename, "w"); + fwrite(buffer, dwSize, 1, file); + fclose(file); + + cdCanvasPlay(canvas, CD_METAFILE, xmin, xmax, ymin, ymax, filename); + + remove(filename); + + g_free(buffer); + + return CD_OK; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char tmpPath[512]; + char* str = (char*)data; + GtkClipboard* clp = NULL; + + /* Init parameters */ + if (str == NULL) + return; + + sscanf(str, "%p", &clp); + + if (!clp) + return; + + str = strstr(str, " "); + if (!str) + return; + + str++; + tmpnam(tmpPath); + + strcat(tmpPath, " "); + strcat(tmpPath, str); + + cdcreatecanvasMF(canvas, str); + if (!canvas->ctxcanvas) + return; + + { + cdCanvasMF* mfcanvas = (cdCanvasMF*)canvas->ctxcanvas; + mfcanvas->data = clp; + } +} + +static void cdinittable(cdCanvas* canvas) +{ + cdinittableMF(canvas); + canvas->cxKillCanvas = cdkillcanvas; +} + + +static cdContext cdClipboardContext = +{ + CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE), + 0, + cdcreatecanvas, + cdinittable, + cdplay, + NULL +}; + +cdContext* cdContextClipboard(void) +{ + return &cdClipboardContext; +} + + diff --git a/cd/src/gdk/cdgdkdbuf.c b/cd/src/gdk/cdgdkdbuf.c new file mode 100644 index 0000000..aa8d587 --- /dev/null +++ b/cd/src/gdk/cdgdkdbuf.c @@ -0,0 +1,169 @@ +/** \file + * \brief Gdk Double Buffer Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdgdk.h" +#include "cddbuf.h" +#include +#include + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdKillImage(ctxcanvas->image_dbuffer); + cdgdkKillCanvas(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 */ + gdk_flush(); + + /* 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 = cdgdkCreateCanvas(canvas, (GdkDrawable*)ctximage->img, ctximage->scr, ctximage->vis); + + if (!ctxcanvas) + return; + + ctxcanvas->image_dbuffer = image_dbuffer; + ctxcanvas->canvas_dbuffer = canvas_dbuffer; +} + +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); + cdgdkKillCanvas(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) +{ + cdgdkInitTable(canvas); + + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; + canvas->cxFlush = cdflush; + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdDBufferContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextDBuffer(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_DBUFFER); + if (ctx != NULL) + return ctx; + } + + return &cdDBufferContext; +} diff --git a/cd/src/gdk/cdgdkimg.c b/cd/src/gdk/cdgdkimg.c new file mode 100644 index 0000000..0c5e5dd --- /dev/null +++ b/cd/src/gdk/cdgdkimg.c @@ -0,0 +1,52 @@ +/** \file + * \brief Gdk Image Driver + * + * See Copyright Notice in cd.h + */ + +#include + +#include "cdgdk.h" +#include "cdimage.h" + + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + cdgdkKillCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxImage *ctximage = ((cdImage*)data)->ctximage; + cdgdkCreateCanvas(canvas, (GdkDrawable*)ctximage->img, ctximage->scr, ctximage->vis); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdgdkInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdImageContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + + +cdContext* cdContextImage(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_IMAGE); + if (ctx != NULL) + return ctx; + } + + return &cdImageContext; +} diff --git a/cd/src/gdk/cdgdknative.c b/cd/src/gdk/cdgdknative.c new file mode 100644 index 0000000..9f0c5ed --- /dev/null +++ b/cd/src/gdk/cdgdknative.c @@ -0,0 +1,117 @@ +/** \file + * \brief Gdk Native Window Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include + +#include "cdgdk.h" +#include "cdnative.h" + + +int cdGetScreenColorPlanes(void) +{ + static int first = 1; + static int bpp; + + if (first) + { + GdkVisual* info = gdk_visual_get_system(); + + if (info != NULL) + { + bpp = info->depth; + return bpp; + } + + bpp = 2; + first = 0; + } + + return bpp; +} + +void cdGetScreenSize(int *width, int *height, double *width_mm, double *height_mm) +{ + static int first = 1; + static int dpy_width, dpy_height, dpy_width_mm, dpy_height_mm; + + if (first) + { + GdkScreen* drv_screen = gdk_screen_get_default(); + + dpy_width = gdk_screen_get_width(drv_screen); + dpy_height = gdk_screen_get_height(drv_screen); + dpy_width_mm = gdk_screen_get_width_mm(drv_screen); + dpy_height_mm = gdk_screen_get_height_mm(drv_screen); + + first = 0; + } + + if (width) *width = dpy_width; + if (height) *height = dpy_height; + if (width_mm) *width_mm = dpy_width_mm; + if (height_mm) *height_mm = dpy_height_mm; +} + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + cdgdkKillCanvas(ctxcanvas); +} + +static int cdactivate(cdCtxCanvas *ctxcanvas) +{ + gdk_drawable_get_size(ctxcanvas->wnd, &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; + + if (ctxcanvas->canvas->use_matrix) + ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix); + + return CD_OK; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + GdkDrawable* wnd = (GdkDrawable*)data; + if (!wnd) + return; + + cdgdkCreateCanvas(canvas, wnd, gdk_drawable_get_screen(wnd), gdk_drawable_get_visual(wnd)); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdgdkInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; +} + +/******************************************************/ + +static cdContext cdNativeWindowContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + + +cdContext* cdContextNativeWindow(void) +{ + if (cdUseContextPlus(CD_QUERY)) + { + cdContext* ctx = cdGetContextPlus(CD_CTX_NATIVEWINDOW); + if (ctx != NULL) + return ctx; + } + + return &cdNativeWindowContext; +} -- cgit v1.2.3