diff options
author | scuri <scuri> | 2009-07-07 00:13:40 +0000 |
---|---|---|
committer | scuri <scuri> | 2009-07-07 00:13:40 +0000 |
commit | ad9b34e834fc762ca63073e9865526125644edaa (patch) | |
tree | d6ec0ab8a80313e4cb2f314a416d74276c25f2f4 /src/gdk | |
parent | c8f1fb92adb9acfd3271a3e5e8f4abacfa609572 (diff) |
*** empty log message ***
Diffstat (limited to 'src/gdk')
-rw-r--r-- | src/gdk/cdgdk.c | 2631 | ||||
-rw-r--r-- | src/gdk/cdgdk.h | 82 | ||||
-rw-r--r-- | src/gdk/cdgdkclp.c | 131 | ||||
-rw-r--r-- | src/gdk/cdgdkdbuf.c | 169 | ||||
-rw-r--r-- | src/gdk/cdgdkimg.c | 52 | ||||
-rw-r--r-- | src/gdk/cdgdknative.c | 119 |
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; +} |