summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorscuri <scuri>2009-07-07 00:13:40 +0000
committerscuri <scuri>2009-07-07 00:13:40 +0000
commitad9b34e834fc762ca63073e9865526125644edaa (patch)
treed6ec0ab8a80313e4cb2f314a416d74276c25f2f4 /src
parentc8f1fb92adb9acfd3271a3e5e8f4abacfa609572 (diff)
*** empty log message ***
Diffstat (limited to 'src')
-rw-r--r--src/gdk/cdgdk.c2631
-rw-r--r--src/gdk/cdgdk.h82
-rw-r--r--src/gdk/cdgdkclp.c131
-rw-r--r--src/gdk/cdgdkdbuf.c169
-rw-r--r--src/gdk/cdgdkimg.c52
-rw-r--r--src/gdk/cdgdknative.c119
6 files changed, 3184 insertions, 0 deletions
diff --git a/src/gdk/cdgdk.c b/src/gdk/cdgdk.c
new file mode 100644
index 0000000..87a7a6c
--- /dev/null
+++ b/src/gdk/cdgdk.c
@@ -0,0 +1,2631 @@
+/** \file
+ * \brief Gdk 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 "cdgdk.h"
+
+#include <gdk/gdk.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+GdkColor (*cdgdkGetPixel)(cdCtxCanvas *ctxcanvas, unsigned long rgb); /* access to the color table */
+void (*cdgdkGetRGB)(cdCtxCanvas *ctxcanvas, unsigned long pixel,
+ unsigned char* red,
+ unsigned char* green,
+ unsigned char* blue); /* access to the color table */
+static GdkGCValues* gcval;
+
+static int cdgdkDirectColorTable[256]; /* used with directColor visuals */
+
+#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 */
+};
+
+/******************************************************/
+
+/* Done! */
+static void update_colors(cdCtxCanvas *ctxcanvas)
+{
+ gboolean success;
+ gdk_colormap_alloc_colors(ctxcanvas->colormap, ctxcanvas->color_table, ctxcanvas->num_colors, FALSE, TRUE, &success);
+}
+
+/* Done! */
+static int find_color(cdCtxCanvas *ctxcanvas, GdkColor xc1)
+{
+ int pos = 0, i;
+ unsigned long min_dist = ULONG_MAX, this_dist;
+ int dr, dg, db;
+ GdkColor xc2;
+
+ for (i = 0; i < ctxcanvas->num_colors; i++)
+ {
+ xc2 = ctxcanvas->color_table[i];
+
+ dr = (xc1.red - xc2.red) / 850; /* 0.30 / 255 */
+ dg = (xc1.green - xc2.green) / 432; /* 0.59 / 255 */
+ db = (xc1.blue - xc2.blue) / 2318; /* 0.11 / 255 */
+
+ this_dist = dr*dr + dg*dg + db*db;
+
+ if (this_dist < min_dist)
+ {
+ min_dist = this_dist;
+ pos = i;
+ }
+ }
+
+ return pos;
+}
+
+/* Done! */
+/* Search the nearest RGB in the color table */
+static unsigned long nearest_rgb(cdCtxCanvas *ctxcanvas, GdkColor clr)
+{
+ static int nearest_try = 0;
+
+ int pos = find_color(ctxcanvas, clr);
+
+ /* Is the color allocated? */
+ if (!gdk_colormap_alloc_color(ctxcanvas->colormap, &(ctxcanvas->color_table[pos]), FALSE, TRUE))
+ {
+ /* Not allocated = update the table and search again */
+ /* This is because the color can be found in an application that no longer exists */
+ /* Once updated, the problem doesn't occur during a new search */
+ /* or the cell is read write */
+
+ if (nearest_try == 1)
+ {
+ nearest_try = 0;
+ return ctxcanvas->color_table[pos].pixel;
+ }
+
+ /* What is slower?
+ Make a query colors across the nearest (probably, this should be slower)
+ or execute the previous search, firstly, and risking a repeat? */
+
+ update_colors(ctxcanvas);
+
+ nearest_try = 1; /* ensures that this will be done only once */
+ return nearest_rgb(ctxcanvas, clr);
+ }
+
+ return ctxcanvas->color_table[pos].pixel;
+}
+
+/* Done! */
+/* GetPixel using the conversion table. Used when the system is not True color. */
+static GdkColor not_truecolor_get_pixel(cdCtxCanvas *ctxcanvas, unsigned long rgb)
+{
+ GdkColor clr;
+
+ clr.red = cdCOLOR8TO16(cdRed(rgb));
+ clr.green = cdCOLOR8TO16(cdGreen(rgb));
+ clr.blue = cdCOLOR8TO16(cdBlue(rgb));
+
+ /* Is there a new color available? */
+ if (!gdk_colormap_alloc_color(ctxcanvas->colormap, &clr, FALSE, TRUE))
+ {
+ /* Not available: search the nearest rgb in color table */
+ clr.pixel = nearest_rgb(ctxcanvas, clr);
+ }
+ else
+ {
+ /* Available: update the color table */
+ ctxcanvas->color_table[clr.pixel] = clr;
+ }
+
+ return clr;
+}
+
+/* Done! */
+/* GetRGB using the conversion table. Used when the system is not True color. */
+static void not_truecolor_get_rgb(cdCtxCanvas *ctxcanvas, unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue)
+{
+ GdkColor clr;
+
+ gdk_colormap_query_color(ctxcanvas->colormap, pixel, &clr);
+
+ *red = cdCOLOR16TO8(clr.red);
+ *green = cdCOLOR16TO8(clr.green);
+ *blue = cdCOLOR16TO8(clr.blue);
+}
+
+/* Done! */
+/* GetRGB function used in True color system. */
+static void truecolor_get_rgb(cdCtxCanvas *ctxcanvas, unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue)
+{
+ unsigned long r = pixel & ctxcanvas->vis->red_mask;
+ unsigned long g = pixel & ctxcanvas->vis->green_mask;
+ unsigned long b = pixel & ctxcanvas->vis->blue_mask;
+
+ if (ctxcanvas->rshift < 0)
+ r = r >> (-ctxcanvas->rshift);
+ else
+ r = r << ctxcanvas->rshift;
+
+ if (ctxcanvas->gshift < 0)
+ g = g >> (-ctxcanvas->gshift);
+ else
+ g = g << ctxcanvas->gshift;
+
+ if (ctxcanvas->bshift < 0)
+ b = b >> (-ctxcanvas->bshift);
+ else
+ b = b << ctxcanvas->bshift;
+
+ *red = cdCOLOR16TO8(r);
+ *green = cdCOLOR16TO8(g);
+ *blue = cdCOLOR16TO8(b);
+}
+
+/* Done! */
+/* GetPixel function used in TrueColor mode. */
+static GdkColor truecolor_get_pixel(cdCtxCanvas *ctxcanvas, unsigned long rgb)
+{
+ GdkColor clrRGB;
+
+ clrRGB.red = cdCOLOR8TO16(cdRed(rgb));
+ clrRGB.green = cdCOLOR8TO16(cdGreen(rgb));
+ clrRGB.blue = cdCOLOR8TO16(cdBlue(rgb));
+
+ if (ctxcanvas->rshift < 0)
+ clrRGB.red = clrRGB.red << (-ctxcanvas->rshift);
+ else
+ clrRGB.red = clrRGB.red >> ctxcanvas->rshift;
+
+ if (ctxcanvas->gshift < 0)
+ clrRGB.green = clrRGB.green << (-ctxcanvas->gshift);
+ else
+ clrRGB.green = clrRGB.green >> ctxcanvas->gshift;
+
+ if (ctxcanvas->bshift < 0)
+ clrRGB.blue = clrRGB.blue << (-ctxcanvas->bshift);
+ else
+ clrRGB.blue = clrRGB.blue >> ctxcanvas->bshift;
+
+ clrRGB.red = clrRGB.red & ctxcanvas->vis->red_mask;
+ clrRGB.green = clrRGB.green & ctxcanvas->vis->green_mask;
+ clrRGB.blue = clrRGB.blue & ctxcanvas->vis->blue_mask;
+
+ return clrRGB;
+}
+
+/* Done! */
+/* Returns position of highest set bit in 'ul' as an integer (0-31), or -1 if none */
+static int highbit(unsigned long ul)
+{
+ int i;
+ unsigned long hb;
+
+ hb = 0x80;
+ hb = hb << 24; /* hb = 0x80000000UL */
+
+ for(i = 31; ((ul & hb) == 0) && i >= 0; i--, ul <<= 1);
+ return i;
+}
+
+static void makeDirectCmap(cdCtxCanvas *ctxcanvas, GdkColormap* cmap)
+{
+ int i, cmaplen, numgot;
+ unsigned char origgot[256];
+ GdkColor c;
+ unsigned long rmask, gmask, bmask;
+ int rshift, gshift, bshift;
+
+ rmask = ctxcanvas->vis->red_mask;
+ gmask = ctxcanvas->vis->green_mask;
+ bmask = ctxcanvas->vis->blue_mask;
+
+ rshift = highbit(rmask) - 15;
+ gshift = highbit(gmask) - 15;
+ bshift = highbit(bmask) - 15;
+
+ if (rshift < 0) rmask = rmask << (-rshift);
+ else rmask = rmask >> rshift;
+
+ if (gshift < 0) gmask = gmask << (-gshift);
+ else gmask = gmask >> gshift;
+
+ if (bshift < 0) bmask = bmask << (-bshift);
+ else bmask = bmask >> bshift;
+
+ cmaplen = ctxcanvas->vis->colormap_size;
+
+ if (cmaplen > 256)
+ cmaplen = 256;
+
+ /* try to alloc a 'cmaplen' long grayscale colormap. May not get all
+ entries for whatever reason. Build table 'cdgdkDirectColorTable[]' that
+ maps range [0..(cmaplen-1)] into set of colors we did get */
+
+ for (i = 0; i < 256; i++)
+ {
+ origgot[i] = 0;
+ cdgdkDirectColorTable[i] = i;
+ }
+
+ for (i = numgot = 0; i < cmaplen; i++)
+ {
+ c.red = c.green = c.blue = (unsigned short)((i * 0xffff) / (cmaplen - 1));
+ c.red = (unsigned short)(c.red & rmask);
+ c.green = (unsigned short)(c.green & gmask);
+ c.blue = (unsigned short)(c.blue & bmask);
+
+ if (gdk_colormap_alloc_color(cmap, &c, FALSE, TRUE))
+ {
+ origgot[i] = 1;
+ numgot++;
+ }
+ }
+
+ if (numgot == 0)
+ return;
+
+ /* cdgdkDirectColorTable may or may not have holes in it. */
+ for (i = 0; i < cmaplen; i++)
+ {
+ if (!origgot[i])
+ {
+ int numbak, numfwd;
+ numbak = numfwd = 0;
+ while ((i - numbak) >= 0 && !origgot[i-numbak]) numbak++;
+ while ((i + numfwd) < cmaplen && !origgot[i+numfwd]) numfwd++;
+
+ if (i-numbak < 0 || !origgot[i-numbak]) numbak = 999;
+ if (i+numfwd >= cmaplen || !origgot[i+numfwd]) numfwd = 999;
+
+ if (numbak < numfwd) cdgdkDirectColorTable[i] = cdgdkDirectColorTable[i-numbak];
+ else if (numfwd < 999) cdgdkDirectColorTable[i] = cdgdkDirectColorTable[i+numfwd];
+ }
+ }
+}
+
+/******************************************************/
+
+void cdxKillCanvas(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->canvas->bpp <= 8)
+ {
+ /* release all colors used in palette */
+ g_object_unref(ctxcanvas->color_table);
+
+ if (ctxcanvas->colormap != gdk_colormap_get_system())
+ g_object_unref(ctxcanvas->colormap);
+ }
+
+ if (ctxcanvas->xidata) free(ctxcanvas->xidata);
+ if (ctxcanvas->font) g_object_unref(ctxcanvas->font);
+ if (ctxcanvas->last_hatch) g_object_unref(ctxcanvas->last_hatch);
+ if (ctxcanvas->clip_polygon) g_object_unref(ctxcanvas->clip_polygon);
+
+ if (ctxcanvas->new_region)
+ {
+ g_object_unref(ctxcanvas->region_aux_gc);
+ g_object_unref(ctxcanvas->region_aux);
+ g_object_unref(ctxcanvas->new_region);
+ }
+
+ 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);
+}
+
+/******************************************************/
+
+/* done! */
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ (void)ctxcanvas;
+ gdk_flush();
+}
+
+/******************************************************/
+
+/* Done! */
+static GdkPixmap* build_clip_polygon(cdCtxCanvas *ctxcanvas, GdkPoint* pnt, int n)
+{
+ GdkPixmap *pix = gdk_pixmap_new(ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1);
+ GdkGC *gc = gdk_gc_new((GdkDrawable*)pix);
+ GdkGCValues values;
+
+ gdk_gc_get_values(gc, &values);
+
+ values.foreground.pixel = 0;
+ gdk_gc_set_foreground(gc, &values.foreground);
+ gdk_draw_rectangle(pix, gc, TRUE, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ values.foreground.pixel = 1;
+ gdk_gc_set_foreground(gc, &values.foreground);
+ gdk_region_polygon(pnt, n, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE);
+ gdk_draw_polygon(pix, gc, TRUE, pnt, n);
+
+ g_object_unref(gc);
+
+ return pix;
+}
+
+/* Done! */
+static void gdksetclip_area(cdCtxCanvas *ctxcanvas)
+{
+ cdRect* clip_rect = &ctxcanvas->canvas->clip_rect;
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdPoint poly[4];
+ poly[0].x = clip_rect->xmin; poly[0].y = clip_rect->ymin;
+ poly[1].x = clip_rect->xmin; poly[1].y = clip_rect->ymax;
+ poly[2].x = clip_rect->xmax; poly[2].y = clip_rect->ymax;
+ poly[3].x = clip_rect->xmax; poly[3].y = clip_rect->ymin;
+ ctxcanvas->canvas->cxPoly(ctxcanvas, CD_CLIP, poly, 4); // VER ISSO!!!!
+ }
+ else
+ {
+ GdkRectangle rect;
+ rect.x = (short)clip_rect->xmin;
+ rect.y = (short)clip_rect->ymin;
+ rect.width = (unsigned short)(clip_rect->xmax - clip_rect->xmin + 1);
+ rect.height = (unsigned short)(clip_rect->ymax - clip_rect->ymin + 1);
+ gdk_gc_set_clip_rectangle(ctxcanvas->gc, &rect);
+ }
+}
+
+/* Done! */
+int cdgdkClip(cdCtxCanvas *ctxcanvas, int clip_mode)
+{
+ switch (clip_mode)
+ {
+ case CD_CLIPOFF:
+ gdk_gc_set_clip_mask(ctxcanvas->gc, NULL);
+ break;
+ case CD_CLIPAREA:
+ gdksetclip_area(ctxcanvas);
+ break;
+ case CD_CLIPPOLYGON:
+ if (ctxcanvas->clip_polygon)
+ gdk_gc_set_clip_mask(ctxcanvas->gc, (GdkBitmap*)ctxcanvas->clip_polygon);
+ break;
+ case CD_CLIPREGION:
+ if (ctxcanvas->new_region)
+ gdk_gc_set_clip_mask(ctxcanvas->gc, (GdkBitmap*)ctxcanvas->new_region);
+ break;
+ }
+ return clip_mode;
+}
+
+/* Done! */
+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;
+ cdgdkClip(ctxcanvas, CD_CLIPAREA);
+ }
+}
+
+/* Done! */
+static void cdnewregion(cdCtxCanvas *ctxcanvas)
+{
+ GdkGCValues values;
+
+ if (ctxcanvas->new_region)
+ {
+ g_object_unref(ctxcanvas->region_aux_gc);
+ g_object_unref(ctxcanvas->region_aux);
+ g_object_unref(ctxcanvas->new_region);
+ }
+
+ ctxcanvas->new_region = gdk_pixmap_new(ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1);
+
+ {
+ GdkGC* gc = gdk_gc_new((GdkDrawable*)ctxcanvas->new_region);
+
+ gdk_gc_get_values(gc, &values);
+
+ values.foreground.pixel = 0;
+ gdk_gc_set_foreground(gc, &values.foreground);
+ gdk_draw_rectangle(ctxcanvas->new_region, gc, TRUE, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ g_object_unref(gc);
+ }
+
+ ctxcanvas->region_aux = gdk_pixmap_new(ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1);
+ ctxcanvas->region_aux_gc = gdk_gc_new((GdkDrawable*)ctxcanvas->region_aux);
+
+ gdk_gc_get_values(ctxcanvas->region_aux_gc, &values);
+ values.background.pixel = 0;
+ gdk_gc_set_background(ctxcanvas->region_aux_gc, &values.background);
+}
+
+/* Done! */
+static int cdispointinregion(cdCtxCanvas *ctxcanvas, int x, int y)
+{
+ if (!ctxcanvas->new_region)
+ return 0;
+
+ if (x >= 0 && y >= 0 && x < ctxcanvas->canvas->w && y < ctxcanvas->canvas->h)
+ {
+ long p;
+ GdkImage* img = gdk_drawable_get_image((GdkDrawable*)ctxcanvas->new_region, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); // 1, XYPixmap;
+
+ p = gdk_image_get_pixel(img, x, y);
+ g_object_unref(img);
+
+ if (p)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Done! */
+static void cdgetregionbox(cdCtxCanvas *ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax)
+{
+ if (!ctxcanvas->new_region)
+ return;
+
+ *xmin = ctxcanvas->canvas->w-1;
+ *xmax = 0;
+ *ymin = ctxcanvas->canvas->h-1;
+ *ymax = 0;
+
+ {
+ int x, y;
+ long p;
+ GdkImage* img = gdk_drawable_get_image((GdkDrawable*)ctxcanvas->new_region, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h); // 1, XYPixmap
+
+ for (y = 0; y < ctxcanvas->canvas->h; y++)
+ {
+ for (x = 0; x < ctxcanvas->canvas->w; x++)
+ {
+ p = gdk_image_get_pixel(img, x, y);
+
+ if (p)
+ {
+ if (x < *xmin) *xmin = x;
+ if (x > *xmax) *xmax = x;
+ if (y < *ymin) *ymin = y;
+ if (y > *ymax) *ymax = y;
+ break;
+ }
+ }
+
+ if (x != ctxcanvas->canvas->w-1)
+ {
+ for (x = ctxcanvas->canvas->w-1; x >= 0; x--)
+ {
+ p = gdk_image_get_pixel(img, x, y);
+
+ if (p)
+ {
+ if (x < *xmin) *xmin = x;
+ if (x > *xmax) *xmax = x;
+ if (y < *ymin) *ymin = y;
+ if (y > *ymax) *ymax = y;
+ break;
+ }
+ }
+ }
+ }
+
+ g_object_unref(img);
+ }
+}
+
+/* Done! */
+static void sPrepareRegion(cdCtxCanvas *ctxcanvas)
+{
+ GdkGCValues values;
+
+ if (!ctxcanvas->new_region)
+ return;
+
+ gdk_gc_get_values(ctxcanvas->region_aux_gc, &values);
+
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_COPY);
+
+ values.foreground.pixel = 0;
+ gdk_gc_set_foreground(ctxcanvas->region_aux_gc, &values.foreground);
+
+ gdk_draw_rectangle(ctxcanvas->region_aux, ctxcanvas->region_aux_gc, TRUE, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ values.foreground.pixel = 1;
+ gdk_gc_set_foreground(ctxcanvas->region_aux_gc, &values.foreground);
+}
+
+/* Done! */
+static void sCombineRegion(cdCtxCanvas *ctxcanvas)
+{
+ switch(ctxcanvas->canvas->combine_mode)
+ {
+ case CD_UNION:
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_OR);
+ break;
+ case CD_INTERSECT:
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_AND);
+ break;
+ case CD_DIFFERENCE:
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_AND_INVERT);
+ break;
+ case CD_NOTINTERSECT:
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_XOR);
+ break;
+ }
+
+ gdk_draw_drawable((GdkDrawable*)ctxcanvas->new_region, ctxcanvas->region_aux_gc,
+ (GdkDrawable*)ctxcanvas->region_aux, 0, 0, 0, 0,
+ ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+}
+
+/* Done! */
+static void cdoffsetregion(cdCtxCanvas *ctxcanvas, int x, int y)
+{
+ if (!ctxcanvas->new_region)
+ return;
+
+ sPrepareRegion(ctxcanvas);
+
+ gdk_draw_drawable((GdkDrawable*)ctxcanvas->new_region, ctxcanvas->region_aux_gc,
+ (GdkDrawable*)ctxcanvas->region_aux, 0, 0, x, y,
+ ctxcanvas->canvas->w-x, ctxcanvas->canvas->h-y);
+
+ gdk_draw_drawable((GdkDrawable*)ctxcanvas->region_aux, ctxcanvas->region_aux_gc,
+ (GdkDrawable*)ctxcanvas->new_region, 0, 0, 0, 0,
+ ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+}
+
+/******************************************************/
+
+/* Done! */
+static int cdwritemode(cdCtxCanvas *ctxcanvas, int write_mode)
+{
+ switch (write_mode)
+ {
+ case CD_REPLACE:
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_COPY);
+ break;
+ case CD_XOR:
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_XOR);
+ break;
+ case CD_NOT_XOR:
+ gdk_gc_set_function(ctxcanvas->region_aux_gc, GDK_EQUIV);
+ break;
+ }
+
+ return write_mode;
+}
+
+/* Done! */
+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;
+}
+
+/* Done! */
+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;
+}
+
+/* Done! */
+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++)
+ {
+ GdkGCValues values;
+
+ gdk_gc_get_values(ctxcanvas->last_stipple_gc, &values);
+
+ if(data[y*w+x])
+ values.foreground.pixel = 1;
+ else
+ values.foreground.pixel = 0;
+
+ gdk_gc_set_foreground(ctxcanvas->last_stipple_gc, &values.foreground);
+ gdk_draw_point(ctxcanvas->last_stipple, ctxcanvas->last_stipple_gc, x, h-y-1);
+ }
+ }
+
+ cdinteriorstyle(ctxcanvas, CD_STIPPLE);
+}
+
+/* Done! */
+static int find_match(unsigned long* palette, int pal_size, unsigned long color, unsigned char *match)
+{
+ int i;
+
+ for (i = 0; i < pal_size; i++)
+ {
+ if (palette[i] == color)
+ {
+ *match = (unsigned char)i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Done! */
+static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *colors)
+{
+ int x, y, i;
+ int size = w*h;
+ GdkColor *pixels = NULL;
+
+ 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_stipple_gc = gdk_gc_new((GdkDrawable*)ctxcanvas->last_pattern);
+ ctxcanvas->last_pattern_w = w;
+ ctxcanvas->last_pattern_h = h;
+ }
+
+ if (ctxcanvas->canvas->bpp <= 8)
+ {
+ GdkColor* match_table = NULL; /* GDK colors */
+ unsigned long palette[256]; /* CD colors */
+ unsigned char *index = (unsigned char*)malloc(size), match;
+ int pal_size = 1;
+ palette[0] = colors[0];
+
+ /* find the "n" first different colors of the image (to 256) */
+ for(i = 0; i < size; i++)
+ {
+ if (!find_match(palette, pal_size, colors[i], &match))
+ {
+ palette[pal_size] = colors[i];
+ index[i] = (unsigned char)pal_size;
+ pal_size++;
+
+ if (pal_size == 256)
+ break;
+ }
+ else
+ index[i] = match;
+ }
+
+ /* CD colors to GDK colors */
+ for (i = 0; i < pal_size; i++)
+ match_table[i] = cdgdkGetPixel(ctxcanvas, palette[i]);
+
+ /* CD image to GDK image */
+ for (i = 0; i < size; i++)
+ pixels[i] = match_table[index[i]];
+
+ free(index);
+ }
+ else
+ {
+ for(i=0;i<size;i++)
+ pixels[i] = cdgdkGetPixel(ctxcanvas, colors[i]);
+ }
+
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ GdkGCValues values;
+
+ gdk_gc_get_values(ctxcanvas->last_pattern_gc, &values);
+ values.foreground = pixels[y*w+x];
+
+ gdk_gc_set_foreground(ctxcanvas->last_pattern_gc, &values.foreground);
+ gdk_draw_point(ctxcanvas->last_pattern, ctxcanvas->last_pattern_gc, x, h-y-1);
+ }
+ }
+
+ cdinteriorstyle(ctxcanvas, CD_PATTERN);
+}
+
+/* Done! */
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ switch (style)
+ {
+ case CD_CONTINUOUS:
+ 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)
+ gcval->line_style = GDK_LINE_DOUBLE_DASH;
+ else
+ 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)
+ gcval->line_style = GDK_LINE_DOUBLE_DASH;
+ else
+ 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, gcval, GDK_GC_LINE_STYLE);
+
+ return style;
+}
+
+/* Done! */
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ if (width == 1)
+ gcval->line_width = 0;
+ else
+ gcval->line_width = width;
+
+ gdk_gc_set_values(ctxcanvas->gc, gcval, GDK_GC_LINE_WIDTH);
+
+ return width;
+}
+
+/* Done! */
+static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap)
+{
+ int cd2x_cap[] = {GDK_CAP_BUTT, GDK_CAP_PROJECTING, GDK_CAP_ROUND};
+
+ gcval->cap_style = cd2x_cap[cap];
+ gdk_gc_set_values(ctxcanvas->gc, gcval, GDK_GC_CAP_STYLE);
+
+ return cap;
+}
+
+/* Done! */
+static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join)
+{
+ int cd2x_join[] = {GDK_JOIN_MITER, GDK_JOIN_BEVEL, GDK_JOIN_ROUND};
+
+ gcval->join_style = cd2x_join[join];
+ gdk_gc_set_values(ctxcanvas->gc, gcval, GDK_GC_JOIN_STYLE);
+
+ return join;
+}
+
+/* Done! */
+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;
+}
+
+/* done! */
+static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size)
+{
+ cairo_t* crWnd = gdk_cairo_create(ctxcanvas->wnd);
+ cairo_font_face_t *font;
+ char font_name[1024];
+ char* foundry = "*";
+ cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL; /* default is */
+ cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL; /* CD_PLAIN */
+
+ if (cdStrEqualNoCase(type_face, "System"))
+ type_face = "fixed";
+ else if (cdStrEqualNoCase(type_face, "Monospace") || cdStrEqualNoCase(type_face, "Courier New"))
+ type_face = "courier";
+ else if (cdStrEqualNoCase(type_face, "Serif") || cdStrEqualNoCase(type_face, "Times New Roman"))
+ type_face = "times";
+ else if (cdStrEqualNoCase(type_face, "Sans") || cdStrEqualNoCase(type_face, "Arial"))
+ type_face = "helvetica";
+
+ if (cdStrEqualNoCase(type_face, "Fixed"))
+ foundry = "misc";
+
+ /* no underline or strikeout support */
+
+ if (style&CD_BOLD)
+ weight = CAIRO_FONT_WEIGHT_BOLD;
+
+ if (style&CD_ITALIC)
+ slant = CAIRO_FONT_SLANT_ITALIC;
+
+ if (style&CD_BOLD_ITALIC)
+ {
+ slant = CAIRO_FONT_SLANT_ITALIC;
+ weight = CAIRO_FONT_WEIGHT_BOLD;
+ }
+
+ size = cdGetFontSizePoints(ctxcanvas->canvas, size);
+ size *= 10; /* convert to deci-points */
+
+ sprintf(font_name,"-%s-%s-*-*-*-*-*-*-*-*-*-*-*", foundry, type_face);
+
+ font = cairo_toy_font_face_create(font_name, slant, weight);
+
+ if (!font)
+ return 0;
+
+ if (ctxcanvas->font)
+ cairo_font_face_destroy(ctxcanvas->font);
+
+ ctxcanvas->font = font;
+ cairo_set_font_face(crWnd, ctxcanvas->font);
+ cairo_set_font_size(crWnd, size);
+
+ return 1;
+}
+
+/* done! */
+static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* nativefont)
+{
+ int size = 12, style = CD_PLAIN;
+ char type_face[1024];
+ cairo_t* crWnd = gdk_cairo_create(ctxcanvas->wnd);
+
+ if (nativefont[0] == '-')
+ {
+ cairo_font_face_t *font = cairo_toy_font_face_create(nativefont, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+ if (!font)
+ return 0;
+
+ if (!cdParseXWinFont(nativefont, type_face, &style, &size))
+ {
+ cairo_font_face_destroy(font);
+ return 0;
+ }
+
+ if (ctxcanvas->font)
+ cairo_font_face_destroy(font);
+
+ ctxcanvas->font = font;
+ cairo_set_font_face(crWnd, ctxcanvas->font);
+ }
+ else
+ {
+ if (!cdParsePangoFont(nativefont, type_face, &style, &size))
+ return 0;
+
+ if (!cdfont(ctxcanvas, type_face, style, size))
+ return 0;
+ }
+
+ /* update cdfont parameters */
+ ctxcanvas->canvas->font_style = style;
+ ctxcanvas->canvas->font_size = size;
+ strcpy(ctxcanvas->canvas->font_type_face, type_face);
+
+ return 1;
+}
+
+/* done! */
+static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ cairo_t* crWnd = gdk_cairo_create(ctxcanvas->wnd);
+ cairo_font_extents_t extents;
+
+ if (!ctxcanvas->font)
+ return;
+
+ cairo_set_font_face(crWnd, ctxcanvas->font);
+ cairo_font_extents(crWnd, &extents);
+
+ if (max_width) *max_width = (int)extents.max_x_advance;
+ if (height) *height = (int)extents.height;
+ if (ascent) *ascent = (int)extents.ascent;
+ if (descent) *descent = (int)extents.descent;
+}
+
+/* done! */
+static long int cdbackground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ GdkColor clr = cdgdkGetPixel(ctxcanvas, color);
+ gdk_gc_set_background(ctxcanvas->gc, &clr);
+ return color;
+}
+
+/* done! */
+static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ ctxcanvas->fg = cdgdkGetPixel(ctxcanvas, color);
+ gdk_gc_set_foreground(ctxcanvas->gc, &ctxcanvas->fg);
+ return color;
+}
+
+/* done! */
+static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode)
+{
+ int i;
+
+ gdk_colormap_free_colors(ctxcanvas->colormap, ctxcanvas->color_table, ctxcanvas->num_colors);
+
+ if (mode == CD_FORCE)
+ {
+ GdkColor clr;
+ int tokeep;
+
+ /* if POLITE then allocates own palette */
+ if (ctxcanvas->colormap == gdk_colormap_get_system())
+ ctxcanvas->colormap = gdk_colormap_new(ctxcanvas->vis, FALSE);
+
+ /* if FORCE then it will allocate all colors...
+ but if the number of colors is less than the maximum
+ then the difference is used to preserve the first allocated colors in the default colormap. */
+ tokeep = ctxcanvas->num_colors - n;
+ if (tokeep)
+ {
+ gboolean success;
+
+ for (i=0; i<tokeep; i++)
+ ctxcanvas->color_table[i].pixel = i;
+
+ gdk_colormap_alloc_colors(gdk_colormap_get_system(), ctxcanvas->color_table, tokeep, FALSE, TRUE, &success);
+
+ /* reserve these colors to the CD use too */
+ for (i=0; i<tokeep; i++)
+ gdk_colormap_alloc_color(ctxcanvas->colormap, &(ctxcanvas->color_table[i]), FALSE, TRUE);
+ }
+
+ /* allocate all the palette colors to the CD */
+ for (i = 0; i < n; i++)
+ {
+ clr.red = cdCOLOR8TO16(cdRed(palette[i]));
+ clr.green = cdCOLOR8TO16(cdGreen(palette[i]));
+ clr.blue = cdCOLOR8TO16(cdBlue(palette[i]));
+ gdk_colormap_alloc_color(ctxcanvas->colormap, &clr, FALSE, TRUE);
+ }
+
+ /* update the entire color table */
+ gdk_drawable_set_colormap(ctxcanvas->wnd, ctxcanvas->colormap);
+ update_colors(ctxcanvas);
+ }
+ else
+ {
+ /* if was FORCE, remove the own palette */
+ if (ctxcanvas->colormap != gdk_colormap_get_system())
+ {
+ g_object_unref(ctxcanvas->colormap);
+ ctxcanvas->colormap = gdk_colormap_get_system();
+ }
+
+ /* Update the color table before adding new colors.
+ After all, all released before that we could. */
+ update_colors(ctxcanvas);
+
+ /* if POLITE then just try to allocate all the colors of the palette */
+ for (i = 0; i < n; i++)
+ cdgdkGetPixel(ctxcanvas, palette[i]);
+ }
+}
+
+/******************************************************/
+
+/* done! */
+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);
+}
+
+/* done! */
+static void cdclear(cdCtxCanvas* ctxcanvas)
+{
+ GdkColor clr;
+
+ cdgdkCheckSolidStyle(ctxcanvas, 1);
+
+ clr = cdgdkGetPixel(ctxcanvas, ctxcanvas->canvas->background);
+ gdk_gc_set_foreground(ctxcanvas->gc, &clr);
+
+ gdk_draw_rectangle(ctxcanvas->wnd, ctxcanvas->gc, TRUE, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ clr = cdgdkGetPixel(ctxcanvas, ctxcanvas->canvas->foreground);
+ gdk_gc_set_foreground(ctxcanvas->gc, &clr);
+
+ cdgdkCheckSolidStyle(ctxcanvas, 0);
+}
+
+/* done! */
+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);
+}
+
+/* Done! */
+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);
+}
+
+/* Done! */
+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)
+ {
+ sPrepareRegion(ctxcanvas);
+ /* "filled parameter = TRUE" produces an 'pie slice' */
+ gdk_draw_arc(ctxcanvas->region_aux, ctxcanvas->region_aux_gc, TRUE, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64));
+ sCombineRegion(ctxcanvas);
+ }
+ 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));
+ }
+}
+
+/* Done! */
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+ cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ {
+ cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+ }
+}
+
+/* Done! */
+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 cdrectCairo(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);
+ {
+ cairo_t* crWnd = gdk_cairo_create(ctxcanvas->wnd);
+ cairo_rectangle(crWnd, (double)xmin, (double)ymin, (double)(xmax-xmin), (double)(ymax-ymin));
+ }
+ cdgdkCheckSolidStyle(ctxcanvas, 0);
+}
+
+/* Done! */
+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)
+ {
+ sPrepareRegion(ctxcanvas);
+ gdk_draw_rectangle(ctxcanvas->region_aux, ctxcanvas->region_aux_gc, TRUE, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ gdk_draw_rectangle(ctxcanvas->wnd, ctxcanvas->gc, TRUE, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
+}
+
+/* done! */
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s, int len)
+{
+ int dir = -1;
+ cairo_t* crWnd = gdk_cairo_create(ctxcanvas->wnd);
+ cairo_t* crWndAux = gdk_cairo_create((GdkDrawable*)ctxcanvas->region_aux);
+ cairo_matrix_t matrix;
+ cairo_text_extents_t extents;
+ cairo_font_extents_t font_extents;
+
+ cairo_set_font_face(crWnd, ctxcanvas->font);
+ cairo_font_extents(crWnd, &font_extents);
+
+ cairo_text_extents (crWnd, s, &extents);
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_RIGHT:
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ x = x - (int)extents.width;
+ break;
+ case CD_BASE_CENTER:
+ case CD_CENTER:
+ case CD_NORTH:
+ case CD_SOUTH:
+ x = x - (int)extents.width/2;
+ break;
+ case CD_BASE_LEFT:
+ case CD_NORTH_WEST:
+ case CD_WEST:
+ case CD_SOUTH_WEST:
+ x = x;
+ break;
+ }
+
+ if (ctxcanvas->canvas->invert_yaxis)
+ dir = 1;
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_LEFT:
+ case CD_BASE_CENTER:
+ case CD_BASE_RIGHT:
+ y = y;
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH_WEST:
+ case CD_SOUTH:
+ y = y - dir*(int)font_extents.descent;
+ break;
+ case CD_NORTH_EAST:
+ case CD_NORTH:
+ case CD_NORTH_WEST:
+ y = y + dir*((int)extents.height - (int)font_extents.descent);
+ break;
+ case CD_CENTER:
+ case CD_EAST:
+ case CD_WEST:
+ y = y + dir*((int)extents.height/2 - (int)font_extents.descent);
+ break;
+ }
+
+ if (ctxcanvas->canvas->text_orientation != 0)
+ {
+ cdgdkCheckSolidStyle(ctxcanvas, 1);
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y);
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+
+ cairo_get_matrix(crWndAux, &matrix);
+
+ cairo_set_font_face(crWndAux, ctxcanvas->font);
+ cairo_move_to(crWndAux, (double)x, (double)(y));
+ cairo_rotate(crWndAux, ctxcanvas->canvas->text_orientation * (M_PI/180));
+ cairo_show_text(crWndAux, s);
+ cairo_set_matrix(crWndAux, &matrix);
+
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ {
+ cairo_get_matrix(crWnd, &matrix);
+
+ cairo_set_font_face(crWnd, ctxcanvas->font);
+ cairo_move_to(crWnd, (double)x, (double)(y));
+ cairo_rotate(crWnd, ctxcanvas->canvas->text_orientation * (M_PI/180));
+ cairo_show_text(crWnd, s);
+
+ cairo_set_matrix(crWnd, &matrix);
+ }
+
+ cdgdkCheckSolidStyle(ctxcanvas, 0);
+
+ return;
+ }
+
+ cdgdkCheckSolidStyle(ctxcanvas, 1);
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y);
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+
+ cairo_set_font_face(crWndAux, ctxcanvas->font);
+ cairo_move_to(crWndAux, (double)x, (double)(y+1));
+ cairo_show_text(crWndAux, s);
+
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ {
+ cairo_move_to(crWnd, (double)x, (double)(y+1));
+ cairo_show_text(crWnd, s);
+ }
+
+ cdgdkCheckSolidStyle(ctxcanvas, 0);
+
+ (void)len;
+}
+
+/* Done! */
+static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int len, int *width, int *height)
+{
+ cairo_t* crWnd = gdk_cairo_create(ctxcanvas->wnd);
+ cairo_text_extents_t extents;
+
+ if (!ctxcanvas->font)
+ return;
+
+ cairo_text_extents(crWnd, s, &extents);
+
+ if (width)
+ *width = (int)extents.width;
+
+ if (height)
+ *height = (int)extents.height;
+
+ (void)len;
+}
+
+/* Done! */
+void cdgdkPoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+ GdkPoint *pnt = NULL;
+
+ if (mode != CD_BEZIER)
+ {
+ for (i = 0; i < n; i++)
+ {
+ int x = poly[i].x,
+ y = poly[i].y;
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y);
+
+ pnt[i].x = (short)x;
+ pnt[i].y = (short)y;
+ }
+ }
+
+ switch( mode )
+ {
+ case CD_FILL:
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+ gdk_region_polygon(pnt, n, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE);
+ gdk_draw_polygon(ctxcanvas->region_aux, ctxcanvas->region_aux_gc, TRUE, pnt, n);
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ {
+ gdk_region_polygon(pnt, n, ctxcanvas->canvas->fill_mode == CD_EVENODD ? GDK_EVEN_ODD_RULE : GDK_WINDING_RULE);
+ gdk_draw_polygon(ctxcanvas->wnd, ctxcanvas->gc, TRUE, pnt, n);
+ }
+ break;
+
+ case CD_CLOSED_LINES:
+ pnt[n].x = pnt[0].x;
+ pnt[n].y = pnt[0].y;
+ n++;
+ /* continue... */
+
+ case CD_OPEN_LINES:
+ {
+ cdgdkCheckSolidStyle(ctxcanvas, 1);
+ gdk_draw_polygon(ctxcanvas->wnd, ctxcanvas->gc, FALSE, pnt, n);
+ cdgdkCheckSolidStyle(ctxcanvas, 0);
+ break;
+ }
+
+ case CD_CLIP:
+ if (ctxcanvas->clip_polygon)
+ g_object_unref(ctxcanvas->clip_polygon);
+
+ ctxcanvas->clip_polygon = build_clip_polygon(ctxcanvas, pnt, n);
+
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON)
+ cdgdkClip(ctxcanvas, CD_CLIPPOLYGON);
+
+ break;
+
+ case CD_BEZIER:
+ cdSimPolyBezier(ctxcanvas->canvas, poly, n);
+ break;
+ }
+
+ g_object_unref(pnt);
+}
+
+/******************************************************/
+
+/* done! */
+static void cdgetimagergb(cdCtxCanvas *ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h)
+{
+ int col, lin, pos;
+ GdkImage* xi = gdk_drawable_get_image(ctxcanvas->wnd, x, y-h+1, w, h); // ULONG_MAX, ZPixmap);
+ if (!xi)
+ {
+ fprintf(stderr, "CanvasDraw: error getting image\n");
+ return;
+ }
+
+ for (lin = 0; lin < h; lin++)
+ {
+ for (col = 0; col < w; col++)
+ {
+ pos = (h-lin-1) * w + col;
+ cdgdkGetRGB(ctxcanvas, gdk_image_get_pixel(xi, col, lin), r+pos, g+pos, b+pos);
+ }
+ }
+
+ g_object_unref(xi);
+}
+
+/* done */
+static long int* get_data_buffer(cdCtxCanvas *ctxcanvas, int size)
+{
+ if (!ctxcanvas->xidata)
+ {
+ ctxcanvas->xisize = size;
+ ctxcanvas->xidata = (long int *)malloc(ctxcanvas->xisize);
+ }
+ else if (ctxcanvas->xisize < size)
+ {
+ ctxcanvas->xisize = size;
+ ctxcanvas->xidata = (long int *)realloc(ctxcanvas->xidata, ctxcanvas->xisize);
+ }
+
+ if (!ctxcanvas->xidata)
+ ctxcanvas->xisize = 0;
+
+ return ctxcanvas->xidata;
+}
+
+/* done! */
+static GdkImage *map2gdkImage(cdCtxCanvas *ctxcanvas, int ew, int eh, const unsigned char *index, const long int * colors, int by, int bx, int bw, int bh, int iw)
+{
+ GdkColor** match_table = NULL;
+ int i, j, pal_size;
+ unsigned long xcol;
+ GdkImage *xim;
+ int *fx, *fy, src, dst;
+ unsigned char idx;
+ GdkColor tmpClr;
+
+ xim = (GdkImage*) NULL;
+
+ /* The size of the palette is unknown, a priori...
+ So, it is necessary to find the highest index used in image */
+ pal_size = 0;
+
+ for (i = 0; i < bh; i++)
+ {
+ for (j = 0; j < bw; j++)
+ {
+ src = (i+by)*iw + j+bx;
+ idx = index[src];
+ if (idx > pal_size)
+ pal_size = idx;
+ }
+ }
+
+ pal_size++;
+
+ for (i = 0; i < pal_size; i++)
+ {
+ tmpClr = cdgdkGetPixel(ctxcanvas, colors[i]);
+ match_table[i] = &tmpClr;
+ }
+
+ fx = cdGetZoomTable(ew, bw, bx);
+ fy = cdGetZoomTable(eh, bh, by);
+
+ switch (ctxcanvas->depth)
+ {
+ case 8:
+ {
+ unsigned char *imagedata, *ip;
+ int imew, nullCount;
+
+ nullCount = (4 - (ew % 4)) & 0x03; /* # of padding bytes per line */
+ imew = ew + nullCount;
+
+ /* Now get the image data - pad each scan line as necessary */
+ imagedata = (unsigned char*)get_data_buffer(ctxcanvas, eh * imew);
+ if (!imagedata)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ for (i = 0; i < eh; i++)
+ {
+ ip = imagedata + (eh-1-i)*imew;
+
+ for (j = 0; j < ew; j++, ip++)
+ {
+ src = (fy[i])*iw + fx[j];
+ ip = (unsigned char*) match_table[index[src]]->pixel;
+ }
+ }
+
+ xim = gdk_image_new(GDK_IMAGE_FASTEST, ctxcanvas->vis, ew, eh);
+
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ if(xim)
+ {
+ /* Conferir estes valores, ver se na hora da criação já não são eles próprios... */
+ xim->depth = (short)ctxcanvas->depth;
+ xim->bpp = 32;
+ xim->bpl = (short)imew;
+ // format = ZPixmap
+ // offset = 0;
+ // data = (char *)imagedata
+ }
+ }
+ break;
+
+ case 12:
+ case 15:
+ case 16:
+ {
+ unsigned char *imagedata;
+ unsigned short *ip, *tip;
+
+ /* Now get the image data - pad each scan line as necessary */
+ imagedata = (unsigned char*)get_data_buffer(ctxcanvas, 2*ew*eh);
+ if (!imagedata)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ xim = gdk_image_new(GDK_IMAGE_FASTEST, ctxcanvas->vis, ew, eh);
+
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ if(xim)
+ {
+ /* Conferir estes valores, ver se na hora da criação já não são eles próprios... */
+ xim->depth = (short)ctxcanvas->depth;
+ xim->bpp = 16;
+ xim->bpl = 0;
+ // format = ZPixmap
+ // offset = 0;
+ // data = (char *)imagedata
+ }
+
+ if (ctxcanvas->depth == 12 && xim->bits_per_pixel != 16)
+ {
+ g_object_unref(xim);
+ fprintf(stderr,"No code for this type of display (depth=%d, bperpix=%d)", ctxcanvas->depth, xim->bits_per_pixel);
+ return NULL;
+ }
+
+ ip = (unsigned short*)(imagedata + (eh-1)*xim->bpl);
+
+ for (i = 0; i < eh; i++)
+ {
+ for (j = 0, tip = ip; j < ew; j++)
+ {
+ src = (fy[i])*iw + fx[j];
+ xcol = match_table[index[src]]->pixel;
+
+ if (xim->byte_order == GDK_MSB_FIRST)
+ {
+ *tip++ = (unsigned short)(xcol & 0xffff);
+ }
+ else
+ {
+ /* WAS *tip++ = ((xcol>>8) & 0xff) | ((xcol&0xff) << 8); */
+ *tip++ = (unsigned short)(xcol);
+ }
+ }
+
+ ip -= ew;
+ }
+ }
+ break;
+
+ case 24:
+ case 32:
+ {
+ unsigned char *imagedata, *ip, *tip;
+ int do32;
+
+ /* Now get the image data - pad each scan line as necessary */
+ imagedata = (unsigned char*)get_data_buffer(ctxcanvas, 4*ew*eh);
+ if (!imagedata)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ xim = gdk_image_new(GDK_IMAGE_FASTEST, ctxcanvas->vis, ew, eh);
+
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ if(xim)
+ {
+ /* Conferir estes valores, ver se na hora da criação já não são eles próprios... */
+ xim->depth = (short)ctxcanvas->depth;
+ xim->bpp = 32;
+ xim->bpl = 0;
+ // format = ZPixmap
+ // offset = 0;
+ // data = (char *)imagedata
+ }
+
+ do32 = (xim->bits_per_pixel == 32 ? 1 : 0);
+
+ ip = imagedata + (eh-1)*xim->bpl;
+
+ for (i = 0; i < eh; i++)
+ {
+ for (j = 0, tip = ip; j < ew; j++)
+ {
+ src = (fy[i])*iw + fx[j];
+ xcol = match_table[index[src]]->pixel;
+
+ if (xim->byte_order == GDK_MSB_FIRST)
+ {
+ if (do32) *tip++ = 0;
+ *tip++ = (unsigned char)((xcol>>16) & 0xff);
+ *tip++ = (unsigned char)((xcol>>8) & 0xff);
+ *tip++ = (unsigned char)( xcol & 0xff);
+ }
+ else
+ { /* GDK_LSB_FIRST */
+ *tip++ = (unsigned char)( xcol & 0xff);
+ *tip++ = (unsigned char)((xcol>>8) & 0xff);
+ *tip++ = (unsigned char)((xcol>>16) & 0xff);
+ if (do32) *tip++ = 0;
+ }
+ }
+
+ ip -= xim->bpl;
+ }
+ }
+ break;
+ default:
+ {
+ /* Now get the image data - pad each scan line as necessary */
+ unsigned long* imagedata = (unsigned long*)get_data_buffer(ctxcanvas, 4*ew*eh);
+ if (!imagedata)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ xim = gdk_image_new(GDK_IMAGE_FASTEST, ctxcanvas->vis, ew, eh);
+
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ if(xim)
+ {
+ /* Conferir estes valores, ver se na hora da criação já não são eles próprios... */
+ xim->depth = (short)ctxcanvas->depth;
+ xim->bpp = 32;
+ xim->bpl = (short)ew*4;
+ // format = ZPixmap
+ // offset = 0;
+ // data = (char *)imagedata
+ }
+
+ xim->bits_per_pixel = 32;
+ xim->bpl = 4 * (short)iw;
+ xim->byte_order = GDK_MSB_FIRST;
+
+ for (i = 0; i < eh; i++)
+ {
+ for (j = 0; j < ew; j++)
+ {
+ src = (fy[i])*iw + fx[j];
+ dst = (eh-1 - i)*ew + j;
+ imagedata[dst] = match_table[index[src]]->pixel;
+ }
+ }
+ }
+ break;
+ }
+
+ free(fx);
+ free(fy);
+
+ return(xim);
+}
+
+/* done! */
+static GdkImage *rgb2gdkImage(cdCtxCanvas *ctxcanvas, int ew, int eh,
+ const unsigned char *red, const unsigned char *green, const unsigned char *blue,
+ const unsigned char *alpha, GdkImage *oxi,
+ int by, int bx, int bw, int bh, int iw)
+{
+/*
+* if we're displaying on a TrueColor
+* or DirectColor display, we've got all the colors we're going to need,
+* and 'all we have to do' is convert 24-bit RGB pixels into whatever
+* variation of RGB the X device in question wants. No color allocation
+* is involved.
+*/
+ int i,j;
+ GdkImage *xim;
+ unsigned long r, g, b, rmask, gmask, bmask, xcol;
+ int rshift, gshift, bshift, bperpix, bperline, byte_order, cshift;
+ int maplen, src;
+ unsigned char *lip, *ip, *imagedata, or, ob, og, al;
+ int *fx, *fy;
+
+ /* compute various shifting constants that we'll need... */
+ rmask = ctxcanvas->vis->red_mask;
+ gmask = ctxcanvas->vis->green_mask;
+ bmask = ctxcanvas->vis->blue_mask;
+ rshift = 7 - highbit(rmask);
+ gshift = 7 - highbit(gmask);
+ bshift = 7 - highbit(bmask);
+
+ maplen = ctxcanvas->vis->colormap_size;
+
+ if (maplen > 256)
+ maplen = 256;
+
+ cshift = 7 - highbit((unsigned long) (maplen-1));
+
+ xim = gdk_image_new(GDK_IMAGE_FASTEST, ctxcanvas->vis, ew, eh);
+
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ if(xim)
+ {
+ /* Conferir estes valores, ver se na hora da criação já não são eles próprios... */
+ xim->depth = (short)ctxcanvas->depth;
+ xim->bpp = 32;
+ xim->bpl = 0;
+ // format = ZPixmap
+ // offset = 0;
+ // data = NULL
+ }
+
+
+ bperline = xim->bpl;
+ bperpix = xim->bits_per_pixel;
+ byte_order = xim->byte_order;
+
+ if (bperpix != 8 && bperpix != 16 && bperpix != 24 && bperpix != 32)
+ {
+ g_object_unref(xim);
+ fprintf(stderr, "CanvasDraw: bpp=%d not supported!\n", bperpix);
+ return NULL;
+ }
+
+ imagedata = (unsigned char*)get_data_buffer(ctxcanvas, eh * bperline);
+ if (!imagedata)
+ {
+ g_object_unref(xim);
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ fx = cdGetZoomTable(ew, bw, bx);
+ fy = cdGetZoomTable(eh, bh, by);
+
+ lip = imagedata + (eh-1)*bperline;
+
+ for (i=0; i<eh; i++, lip -= bperline)
+ {
+ for (j=0, ip=lip; j<ew; j++)
+ {
+ src = fy[i]*iw + fx[j];
+
+ if (alpha)
+ {
+ cdgdkGetRGB(ctxcanvas, gdk_image_get_pixel(oxi, j, eh-i-1), &or, &og, &ob);
+ al = alpha[src];
+ r = CD_ALPHA_BLEND(red[src], or, al);
+ g = CD_ALPHA_BLEND(green[src], og, al);
+ b = CD_ALPHA_BLEND(blue[src], ob, al);
+ }
+ else
+ {
+ r = red[src];
+ g = green[src];
+ b = blue[src];
+ }
+
+ /* shift r,g,b so that high bit of 8-bit color specification is
+ * aligned with high bit of r,g,b-mask in visual,
+ * AND each component with its mask,
+ * and OR the three components together
+ */
+ if(gdk_visual_get_best_type() == GDK_VISUAL_DIRECT_COLOR)
+ {
+ r = (unsigned long) cdgdkDirectColorTable[(r>>cshift) & 0xff] << cshift;
+ g = (unsigned long) cdgdkDirectColorTable[(g>>cshift) & 0xff] << cshift;
+ b = (unsigned long) cdgdkDirectColorTable[(b>>cshift) & 0xff] << cshift;
+ }
+
+ /* shift the bits around */
+ if (rshift < 0) r = r << (-rshift);
+ else r = r >> rshift;
+
+ if (gshift < 0) g = g << (-gshift);
+ else g = g >> gshift;
+
+ if (bshift < 0) b = b << (-bshift);
+ else b = b >> bshift;
+
+ r = r & rmask;
+ g = g & gmask;
+ b = b & bmask;
+
+ xcol = r | g | b;
+
+ if (bperpix == 32)
+ {
+ if (byte_order == GDK_MSB_FIRST)
+ {
+ *ip++ = (unsigned char)((xcol>>24) & 0xff);
+ *ip++ = (unsigned char)((xcol>>16) & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)( xcol & 0xff);
+ }
+ else
+ { /* GDK_LSB_FIRST */
+ *ip++ = (unsigned char)( xcol & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)((xcol>>16) & 0xff);
+ *ip++ = (unsigned char)((xcol>>24) & 0xff);
+ }
+ }
+ else if (bperpix == 24)
+ {
+ if (byte_order == GDK_MSB_FIRST)
+ {
+ *ip++ = (unsigned char)((xcol>>16) & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)( xcol & 0xff);
+ }
+ else
+ { /* GDK_LSB_FIRST */
+ *ip++ = (unsigned char)( xcol & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)((xcol>>16) & 0xff);
+ }
+ }
+ else if (bperpix == 16)
+ {
+ if (byte_order == GDK_MSB_FIRST)
+ {
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)( xcol & 0xff);
+ }
+ else { /* GDK_LSB_FIRST */
+ *ip++ = (unsigned char)( xcol & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ }
+ }
+ else if (bperpix == 8)
+ {
+ *ip++ = (unsigned char)(xcol & 0xff);
+ }
+ }
+ }
+
+ free(fx);
+ free(fy);
+
+ return xim;
+}
+
+/* done! */
+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; /* gdkImage origin is at top-left */
+ GdkImage *xi, *oxi = NULL;
+ GdkPixmap *clip_polygon, *clip_mask = NULL;
+ GdkPoint* pnt = NULL;
+
+ /* 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 = build_clip_polygon(ctxcanvas, pnt, 4);
+
+ /* combine with the existing clipping */
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA || ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON)
+ clip_mask = ctxcanvas->clip_polygon;
+ else if (ctxcanvas->canvas->clip_mode == CD_CLIPREGION)
+ clip_mask = ctxcanvas->new_region;
+
+ gdk_gc_set_function(ctxcanvas->gc, GDK_AND);
+
+ gdk_draw_drawable((GdkDrawable*)clip_polygon, ctxcanvas->gc,
+ (GdkDrawable*)clip_mask, 0, 0, 0, 0,
+ ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ gdk_gc_set_clip_mask(ctxcanvas->gc, (GdkBitmap*)clip_polygon);
+
+ cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset gdk_gc_set_function */
+
+ if (a)
+ {
+ oxi = gdk_drawable_get_image(ctxcanvas->wnd, ex, ey, ew, eh); // ULONG_MAX, ZPixmap);
+
+ if (!oxi)
+ {
+ fprintf(stderr, "CanvasDraw: error getting image\n");
+ free(dst_r);
+ return;
+ }
+ }
+
+ xi = rgb2gdkImage(ctxcanvas, ew, eh, dst_r, dst_g, dst_b, dst_a, oxi, 0, 0, ew, eh, ew);
+ if (!xi)
+ return;
+
+ gdk_draw_image(ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ /* reset clipping */
+ g_object_unref(clip_polygon);
+ cdgdkClip(ctxcanvas, ctxcanvas->canvas->clip_mode);
+
+ g_object_unref(xi);
+ if (oxi)
+ g_object_unref(oxi);
+ }
+
+ free(dst_r);
+}
+
+/* done! */
+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; /* GdkImage* origin is at top-left */
+
+ GdkImage *xi;
+ GdkPixmap *clip_polygon, *clip_mask = NULL;
+ 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 = build_clip_polygon(ctxcanvas, pnt, 4);
+
+ /* combine with the existing clipping */
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA || ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON)
+ clip_mask = ctxcanvas->clip_polygon;
+ else if (ctxcanvas->canvas->clip_mode == CD_CLIPREGION)
+ clip_mask = ctxcanvas->new_region;
+
+ gdk_gc_set_function(ctxcanvas->gc, GDK_AND);
+
+ gdk_draw_drawable((GdkDrawable*)clip_polygon, ctxcanvas->gc,
+ (GdkDrawable*)clip_mask, 0, 0, 0, 0,
+ ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ gdk_gc_set_clip_mask(ctxcanvas->gc, (GdkBitmap*)clip_polygon);
+
+ cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset gdk_gc_set_function */
+
+ xi = map2gdkImage(ctxcanvas, ew, eh, dst_index, colors, 0, 0, ew, eh, ew);
+ if (!xi)
+ return;
+
+ gdk_draw_image(ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ /* reset clipping */
+ g_object_unref(clip_polygon);
+ cdgdkClip(ctxcanvas, ctxcanvas->canvas->clip_mode);
+
+ g_object_unref(xi);
+ }
+
+ free(dst_index);
+}
+
+/* done! */
+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;
+ GdkImage* xi;
+
+ 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); /* gdkImage 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;
+
+ xi = rgb2gdkImage(ctxcanvas, ew, eh, r, g, b, NULL, NULL, by, bx, bw, bh, iw);
+ if (!xi)
+ return;
+
+ gdk_draw_image(ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ g_object_unref(xi);
+}
+
+/* done! */
+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)
+{
+ GdkImage *xi, *oxi;
+ 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); /* gdkImage 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;
+
+ oxi = gdk_drawable_get_image(ctxcanvas->wnd, ex, ey, ew, eh); // ULONG_MAX, ZPixmap);
+
+ if (!oxi)
+ {
+ fprintf(stderr, "CanvasDraw: error getting image\n");
+ return;
+ }
+
+ xi = rgb2gdkImage(ctxcanvas, ew, eh, r, g, b, a, oxi, by, bx, bw, bh, iw);
+ if (!xi)
+ return;
+
+ gdk_draw_image(ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ g_object_unref(xi);
+ g_object_unref(oxi);
+}
+
+/* done! */
+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;
+ GdkImage* xi;
+
+ 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); /* gdkImage 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;
+
+ xi = map2gdkImage(ctxcanvas, ew, eh, index, colors, by, bx, bw, bh, iw);
+ if (!xi)
+ return;
+
+ gdk_draw_image(ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ g_object_unref(xi);
+}
+
+/* done! */
+static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ if (ctxcanvas->canvas->foreground != color)
+ {
+ GdkColor clr = cdgdkGetPixel(ctxcanvas, color);
+ gdk_gc_set_foreground(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_foreground(ctxcanvas->gc, &ctxcanvas->fg);
+}
+
+/* done! */
+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 = cdgdkGetPixel(ctxcanvas, CD_WHITE);
+
+ gdk_gc_set_foreground(gc, &clr);
+ gdk_draw_rectangle(ctximage->img, gc, TRUE, 0, 0, ctximage->w, ctxcanvas->canvas->h);
+
+ g_object_unref(gc);
+
+ return (void*)ctximage;
+}
+
+/* done! */
+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);
+}
+
+/* done! */
+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);
+}
+
+/* done! */
+static void cdkillimage (cdCtxImage *ctximage)
+{
+ g_object_unref(ctximage->img);
+ free(ctximage);
+}
+
+/* done! */
+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);
+}
+
+/* done! */
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ if (matrix)
+ {
+ /* 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);
+
+ 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 char* get_gc_attrib(cdCtxCanvas *ctxcanvas)
+{
+ return (char*)ctxcanvas->gc;
+}
+
+static cdAttribute gc_attrib =
+{
+ "GC",
+ NULL,
+ get_gc_attrib
+};
+
+cdCtxCanvas *cdgdkCreateCanvas(cdCanvas* canvas, GdkDrawable* wnd, GdkScreen* scr, GdkVisual* vis)
+{
+ static int first = 1;
+
+ 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->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(scr));
+ canvas->w_mm = ((double)canvas->w) / canvas->xres;
+ canvas->h_mm = ((double)canvas->h) / canvas->yres;
+ canvas->invert_yaxis = 1;
+
+ if (first)
+ {
+ if (canvas->bpp > 8)
+ {
+ cdgdkGetRGB = truecolor_get_rgb;
+ cdgdkGetPixel = truecolor_get_pixel;
+
+ /* make linear colormap for DirectColor visual */
+ if(gdk_visual_get_best_type() == GDK_VISUAL_DIRECT_COLOR)
+ makeDirectCmap(ctxcanvas, gdk_screen_get_default_colormap(ctxcanvas->scr));
+ }
+ else
+ {
+ cdgdkGetRGB = not_truecolor_get_rgb;
+ cdgdkGetPixel = not_truecolor_get_pixel;
+ }
+ }
+
+ if (canvas->bpp > 8)
+ {
+ ctxcanvas->rshift = 15 - highbit(ctxcanvas->vis->red_mask);
+ ctxcanvas->gshift = 15 - highbit(ctxcanvas->vis->green_mask);
+ ctxcanvas->bshift = 15 - highbit(ctxcanvas->vis->blue_mask);
+
+ ctxcanvas->num_colors = 0;
+ ctxcanvas->colormap = NULL;
+
+ /* For canvas bpp <= 8 RGBA is simulated with cdGetImageRGB */
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ }
+ else
+ {
+ int i;
+
+ ctxcanvas->colormap = gdk_screen_get_default_colormap(scr);
+ ctxcanvas->num_colors = 1L << canvas->bpp;
+
+ for (i = 0; i < ctxcanvas->num_colors; i++)
+ ctxcanvas->color_table[i].pixel = i;
+
+ update_colors(ctxcanvas);
+ }
+
+ cdRegisterAttribute(canvas, &gc_attrib);
+ cdRegisterAttribute(canvas, &rotate_attrib);
+
+ first = 0;
+
+ return ctxcanvas;
+}
+
+void cdxInitTable(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ canvas->cxClear = cdclear;
+
+ canvas->cxPixel = cdpixel;
+ canvas->cxLine = cdline;
+ canvas->cxPoly = cdgdkPoly;
+ canvas->cxRect = cdrect;
+// canvas->cxRect = cdrectCairo;
+ canvas->cxBox = cdbox;
+ canvas->cxArc = cdarc;
+ canvas->cxSector = cdsector;
+ canvas->cxChord = cdchord;
+ canvas->cxText = cdtext;
+
+ canvas->cxNewRegion = cdnewregion;
+ canvas->cxIsPointInRegion = cdispointinregion;
+ canvas->cxOffsetRegion = cdoffsetregion;
+ canvas->cxGetRegionBox = cdgetregionbox;
+ canvas->cxClip = cdgdkClip;
+ 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->cxGetImageRGB = cdgetimagergb;
+ canvas->cxScrollArea = cdscrollarea;
+
+ canvas->cxCreateImage = cdcreateimage;
+ canvas->cxGetImage = cdgetimage;
+ canvas->cxPutImageRect = cdputimagerect;
+ canvas->cxKillImage = cdkillimage;
+
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+
+ if (canvas->bpp > 8)
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+}
+
+/*
+- ver como ficará o desenho do chord (já que não tem no GDK e Cairo)
+- no final, ir convertendo o que der para Cairo
+- conferir funcionamento do gdk_gc_new
+- text e font = ver o comportamento
+- ver como funfa gdk_drawable_get_image // XPixmap, YPixmap, ZPixmap
+- conferir funções que usam gdk_image_new
+*/ \ No newline at end of file
diff --git a/src/gdk/cdgdk.h b/src/gdk/cdgdk.h
new file mode 100644
index 0000000..aea5e8a
--- /dev/null
+++ b/src/gdk/cdgdk.h
@@ -0,0 +1,82 @@
+/** \file
+ * \brief Gdk Cairo Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __CDGDK_H
+#define __CDGDK_H
+
+#include <gdk/gdk.h>
+
+#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 usado pela aplicacao */
+ GdkScreen *scr;
+ GdkGC* gc; /* graphic context */
+ GdkDrawable* wnd; /* drawable */
+ GdkColor fg;
+
+ GdkPixmap* last_hatch; /* ultimo hatch setado pelo usuario */
+ GdkPixmap* last_stipple; /* ultimo stipple setado pelo usuario */
+ GdkPixmap* last_pattern; /* ultimo pattern setado pelo usuario */
+ 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; /* depth do canvas */
+ GdkPixmap* clip_polygon; /* poligono de clipping */
+ GdkPixmap* new_region;
+ GdkPixmap* region_aux;
+ GdkGC* region_aux_gc;
+ void *data; /* informacoes especificas do driver */
+ long int *xidata; /* ximage cache */
+ int xisize;
+ GdkColormap* colormap; /* colormap para todos os canvas */
+ GdkColor* color_table; /* tabela de cores do colormap */
+ int num_colors; /* tamanho maximo da tabela de cores */
+ int rshift; /* constante red para calculo truecolor */
+ int gshift; /* constante green para calculo truecolor */
+ int bshift; /* constante blue para calculo truecolor */
+ double xmatrix[6]; /* transformation matrix that includes axis inversion */
+ float rotate_angle;
+ int rotate_center_x,
+ rotate_center_y;
+
+ cairo_font_face_t* font; /* fonte de caracteres no X */
+
+ cdImage* image_dbuffer; /* utilizado pelo driver de Double buffer */
+ cdCanvas* canvas_dbuffer;
+};
+
+#define cdCOLOR8TO16(_x) (_x*257) /* 65535/255 = 257 */
+#define cdCOLOR16TO8(_x) ((unsigned char)(_x/257))
+
+extern GdkColor (*cdgdkGetPixel)(cdCtxCanvas *ctxcanvas, unsigned long rgb);
+extern void (*cdxGetRGB)(cdCtxCanvas *ctxcanvas, unsigned long pixel,
+ unsigned char* red,
+ unsigned char* green,
+ unsigned char* blue);
+
+cdCtxCanvas *cdgdkCreateCanvas(cdCanvas* canvas, GdkDrawable* wnd, GdkScreen* scr, GdkVisual* vis);
+void cdxInitTable(cdCanvas* canvas);
+void cdxKillCanvas(cdCtxCanvas *ctxcanvas);
+int cdgdkClip(cdCtxCanvas *ctxcanvas, int clip_mode);
+void cdgdkPoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n);
+
+#endif
diff --git a/src/gdk/cdgdkclp.c b/src/gdk/cdgdkclp.c
new file mode 100644
index 0000000..fd80fc7
--- /dev/null
+++ b/src/gdk/cdgdkclp.c
@@ -0,0 +1,131 @@
+/** \file
+ * \brief Gdk/Cairo Clipboard Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#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/src/gdk/cdgdkdbuf.c b/src/gdk/cdgdkdbuf.c
new file mode 100644
index 0000000..03b49b4
--- /dev/null
+++ b/src/gdk/cdgdkdbuf.c
@@ -0,0 +1,169 @@
+/** \file
+ * \brief Gdk/Cairo Double Buffer Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include "cdgdk.h"
+#include "cddbuf.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static void cdkillcanvas (cdCtxCanvas* ctxcanvas)
+{
+ cdKillImage(ctxcanvas->image_dbuffer);
+ cdxKillCanvas(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);
+ cdxKillCanvas(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)
+{
+ cdxInitTable(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/src/gdk/cdgdkimg.c b/src/gdk/cdgdkimg.c
new file mode 100644
index 0000000..674792e
--- /dev/null
+++ b/src/gdk/cdgdkimg.c
@@ -0,0 +1,52 @@
+/** \file
+ * \brief Gdk/Cairo Image Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+
+#include "cdgdk.h"
+#include "cdimage.h"
+
+
+static void cdkillcanvas(cdCtxCanvas* ctxcanvas)
+{
+ cdxKillCanvas(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)
+{
+ cdxInitTable(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/src/gdk/cdgdknative.c b/src/gdk/cdgdknative.c
new file mode 100644
index 0000000..94577fa
--- /dev/null
+++ b/src/gdk/cdgdknative.c
@@ -0,0 +1,119 @@
+/** \file
+ * \brief Gdk/Cairo Native Window Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#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)
+{
+ cdxKillCanvas(ctxcanvas);
+ printf("cdkillcanvas\n");
+}
+
+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);
+
+ printf("cdactivate\n");
+ 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)
+{
+ cdxInitTable(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;
+}