summaryrefslogtreecommitdiff
path: root/src/x11
diff options
context:
space:
mode:
Diffstat (limited to 'src/x11')
-rw-r--r--src/x11/cdx11.c2447
-rw-r--r--src/x11/cdx11.h85
-rw-r--r--src/x11/cdxclp.c136
-rw-r--r--src/x11/cdxdbuf.c156
-rw-r--r--src/x11/cdximg.c52
-rw-r--r--src/x11/cdxnative.c165
-rw-r--r--src/x11/xvertex.c1440
-rw-r--r--src/x11/xvertex.h31
8 files changed, 4512 insertions, 0 deletions
diff --git a/src/x11/cdx11.c b/src/x11/cdx11.c
new file mode 100644
index 0000000..62e81ed
--- /dev/null
+++ b/src/x11/cdx11.c
@@ -0,0 +1,2447 @@
+/** \file
+ * \brief X-Windows Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <math.h>
+
+#include "cdx11.h"
+#include "xvertex.h"
+
+#include <X11/Xproto.h>
+
+unsigned long (*cdxGetPixel)(cdCtxCanvas *ctxcanvas, unsigned long rgb); /* acesso a tabela de cores */
+void (*cdxGetRGB)(cdCtxCanvas *ctxcanvas, unsigned long pixel,
+ unsigned char* red,
+ unsigned char* green,
+ unsigned char* blue); /* acesso a tabela de cores */
+static XGCValues gcval;
+
+static int cdxDirectColorTable[256]; /* used with directColor visuals */
+
+#define NUM_HATCHES 6
+#define HATCH_WIDTH 8
+#define HATCH_HEIGHT 8
+/*
+** 6 padroes pre-definidos a serem acessados atraves de cdHatch(
+ CD_HORIZONTAL | CD_VERTICAL | CD_FDIAGONAL | CD_BDIAGONAL |
+ CD_CROSS | CD_DIAGCROSS)
+
+*/
+static char hatches[NUM_HATCHES][8] = {
+ {0x00,0x00,0xFF,0x00,0x00,0x00,0xFF,0x00}, /* HORIZONTAL */
+ {0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22}, /* VERTICAL */
+ {0x08,0x10,0x20,0x40,0x80,0x01,0x02,0x04}, /* FDIAGONAL */
+ {0x10,0x08,0x04,0x02,0x01,0x80,0x40,0x20}, /* BDIAGONAL */
+ {0x22,0x22,0xFF,0x22,0x22,0x22,0xFF,0x22}, /* CROSS */
+ {0x18,0x18,0x24,0x42,0x81,0x81,0x42,0x24} /* DIAGCROSS */
+};
+
+/******************************************************/
+
+static int cdxErrorHandler(Display* dpy, XErrorEvent *err)
+{
+ char msg[80];
+
+ /* Se for erro de BadMatch em XGetImage, tudo bem */
+ if (err->request_code==X_GetImage && err->error_code==BadMatch)
+ return 0;
+
+ /* Se for erro de BadAcess em XFreeColors, tudo bem */
+ if (err->request_code==X_FreeColors && err->error_code==BadAccess)
+ return 0;
+
+ XGetErrorText(dpy, err->error_code, msg, 80 );
+ fprintf(stderr,"CanvasDraw: Xlib request %d: %s\n", err->request_code, msg);
+
+ return 0;
+}
+
+static void update_colors(cdCtxCanvas *ctxcanvas)
+{
+ XQueryColors(ctxcanvas->dpy, ctxcanvas->colormap, ctxcanvas->color_table, ctxcanvas->num_colors);
+}
+
+static int find_color(cdCtxCanvas *ctxcanvas, XColor* xc1)
+{
+ int pos = 0, i;
+ unsigned long min_dist = ULONG_MAX, this_dist;
+ int dr, dg, db;
+ XColor* 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;
+}
+
+/* Busca o RGB mais proximo na tabela de cores */
+static unsigned long nearest_rgb(cdCtxCanvas *ctxcanvas, XColor* xc)
+{
+ static int nearest_try = 0;
+
+ int pos = find_color(ctxcanvas, xc);
+
+ /* verifico se a cor ainda esta alocada */
+ /* Try to allocate the closest match color.
+ This should fail only if the cell is read/write.
+ Otherwise, we're incrementing the cell's reference count.
+ (comentario extraido da biblioteca Mesa) */
+ if (!XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &(ctxcanvas->color_table[pos])))
+ {
+ /* nao esta, preciso atualizar a tabela e procurar novamente */
+ /* isto acontece porque a cor encontrada pode ter sido de uma aplicacao que nao existe mais */
+ /* uma vez atualizada, o problema nao ocorrera' na nova procura */
+ /* ou a celula e' read write */
+
+ if (nearest_try == 1)
+ {
+ nearest_try = 0;
+ return ctxcanvas->color_table[pos].pixel;
+ }
+
+ /* o que e' mais lento?
+ Dar um query colors em todo o nearest, --> Isso deve ser mais lento
+ ou fazer a busca acima antes e arriscar uma repeticao? */
+
+ update_colors(ctxcanvas);
+
+ nearest_try = 1; /* garante que so' vai tentar isso uma vez */
+ return nearest_rgb(ctxcanvas, xc);
+ }
+
+ return ctxcanvas->color_table[pos].pixel;
+}
+
+/* Funcao get_pixel usando tabela de conversao. \
+ Usada quando nao estamos em TrueColor. */
+static unsigned long not_truecolor_get_pixel(cdCtxCanvas *ctxcanvas, unsigned long rgb)
+{
+ unsigned long pixel;
+ XColor xc;
+ xc.red = cdCOLOR8TO16(cdRed(rgb));
+ xc.green = cdCOLOR8TO16(cdGreen(rgb));
+ xc.blue = cdCOLOR8TO16(cdBlue(rgb));
+ xc.flags = DoRed | DoGreen | DoBlue;
+
+ /* verificamos se a nova cor ja' esta' disponivel */
+ if (!XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &xc))
+ {
+ /* nao estava disponivel, procuro pela mais proxima na tabela de cores */
+ pixel = nearest_rgb(ctxcanvas, &xc);
+ }
+ else
+ {
+ /* ja' estava disponivel */
+ /* atualizo a tabela de cores */
+ ctxcanvas->color_table[xc.pixel] = xc;
+ pixel = xc.pixel;
+ }
+
+ return pixel;
+}
+
+/*
+%F Funcao usando tabela de conversao. \
+ Usada quando nao estamos em TrueColor.
+*/
+static void not_truecolor_get_rgb(cdCtxCanvas *ctxcanvas, unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue)
+{
+ XColor xc;
+ xc.pixel = pixel;
+ XQueryColor(ctxcanvas->dpy, ctxcanvas->colormap, &xc);
+ *red = cdCOLOR16TO8(xc.red);
+ *green = cdCOLOR16TO8(xc.green);
+ *blue = cdCOLOR16TO8(xc.blue);
+}
+
+/*
+%F Funcao get_rgb usada quando estamos em TrueColor.
+*/
+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);
+}
+
+/*
+%F Funcao get_pixel usada quando estamos em TrueColor.
+*/
+static unsigned long truecolor_get_pixel(cdCtxCanvas *ctxcanvas, unsigned long rgb)
+{
+ unsigned long r = cdCOLOR8TO16(cdRed(rgb));
+ unsigned long g = cdCOLOR8TO16(cdGreen(rgb));
+ unsigned long b = cdCOLOR8TO16(cdBlue(rgb));
+
+ 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;
+
+ r = r & ctxcanvas->vis->red_mask;
+ g = g & ctxcanvas->vis->green_mask;
+ b = b & ctxcanvas->vis->blue_mask;
+
+ return r | g | b;
+}
+
+static int highbit(unsigned long ul)
+{
+/* returns position of highest set bit in 'ul' as an integer (0-31),
+ or -1 if none */
+ 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, Colormap cmap)
+{
+ int i, cmaplen, numgot;
+ unsigned char origgot[256];
+ XColor 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->map_entries;
+ if (cmaplen>256) cmaplen=256;
+
+ /* try to alloc a 'cmaplen' long grayscale colormap. May not get all
+ entries for whatever reason. Build table 'cdxDirectColorTable[]' that
+ maps range [0..(cmaplen-1)] into set of colors we did get */
+
+ for (i=0; i<256; i++) { origgot[i] = 0; cdxDirectColorTable[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);
+ c.flags = DoRed | DoGreen | DoBlue;
+
+ if (XAllocColor(ctxcanvas->dpy, cmap, &c))
+ {
+ origgot[i] = 1;
+ numgot++;
+ }
+ }
+
+ if (numgot == 0)
+ return;
+
+ /* cdxDirectColorTable 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) cdxDirectColorTable[i] = cdxDirectColorTable[i-numbak];
+ else if (numfwd<999) cdxDirectColorTable[i] = cdxDirectColorTable[i+numfwd];
+ }
+ }
+}
+
+/******************************************************/
+
+void cdxKillCanvas(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->canvas->bpp <= 8)
+ {
+ unsigned long pixels[256];
+ int i;
+
+ /* libera todas as cores usadas na palette */
+ for(i = 0; i < ctxcanvas->num_colors; i++)
+ pixels[i] = ctxcanvas->color_table[i].pixel;
+
+ if (ctxcanvas->colormap != DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr))
+ XFreeColormap(ctxcanvas->dpy, ctxcanvas->colormap);
+ }
+
+ if (ctxcanvas->xidata) free(ctxcanvas->xidata);
+ if (ctxcanvas->font) XFreeFont(ctxcanvas->dpy, ctxcanvas->font);
+ if (ctxcanvas->last_hatch) XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_hatch);
+ if (ctxcanvas->clip_polygon) XFreePixmap(ctxcanvas->dpy, ctxcanvas->clip_polygon);
+
+ if (ctxcanvas->new_region)
+ {
+ XFreeGC(ctxcanvas->dpy, ctxcanvas->region_aux_gc);
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->region_aux);
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->new_region);
+ }
+
+ if (ctxcanvas->last_pattern)
+ {
+ XFreeGC(ctxcanvas->dpy, ctxcanvas->last_pattern_gc);
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_pattern);
+ }
+
+ if (ctxcanvas->last_stipple)
+ {
+ XFreeGC(ctxcanvas->dpy, ctxcanvas->last_stipple_gc);
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_stipple);
+ }
+
+ XFreeGC(ctxcanvas->dpy, ctxcanvas->gc);
+
+ free(ctxcanvas);
+}
+
+/******************************************************/
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ XFlush(ctxcanvas->dpy);
+}
+
+/******************************************************/
+
+static Pixmap build_clip_polygon(cdCtxCanvas *ctxcanvas, XPoint* pnt, int n)
+{
+ Pixmap pix = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1);
+ GC gc = XCreateGC(ctxcanvas->dpy, pix, 0, NULL);
+
+ XSetForeground(ctxcanvas->dpy, gc, 0);
+ XFillRectangle(ctxcanvas->dpy, pix, gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ XSetForeground(ctxcanvas->dpy, gc, 1);
+ XSetFillRule(ctxcanvas->dpy, gc, ctxcanvas->canvas->fill_mode==CD_EVENODD?EvenOddRule:WindingRule);
+ XFillPolygon(ctxcanvas->dpy, pix, gc, pnt, n, Complex, CoordModeOrigin);
+
+ XFreeGC(ctxcanvas->dpy, gc);
+ return pix;
+}
+
+static void xsetclip_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);
+ }
+ else
+ {
+ XRectangle 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);
+ XSetClipRectangles(ctxcanvas->dpy, ctxcanvas->gc, 0, 0, &rect, 1, Unsorted);
+ }
+}
+
+int cdxClip(cdCtxCanvas *ctxcanvas, int clip_mode)
+{
+ switch (clip_mode)
+ {
+ case CD_CLIPOFF:
+ XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, None);
+ break;
+ case CD_CLIPAREA:
+ xsetclip_area(ctxcanvas);
+ break;
+ case CD_CLIPPOLYGON:
+ if (ctxcanvas->clip_polygon)
+ XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->clip_polygon);
+ break;
+ case CD_CLIPREGION:
+ if (ctxcanvas->new_region)
+ XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->new_region);
+ break;
+ }
+ return clip_mode;
+}
+
+static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA)
+ {
+ ctxcanvas->canvas->clip_rect.xmin = xmin;
+ ctxcanvas->canvas->clip_rect.ymin = ymin;
+ ctxcanvas->canvas->clip_rect.xmax = xmax;
+ ctxcanvas->canvas->clip_rect.ymax = ymax;
+ cdxClip(ctxcanvas, CD_CLIPAREA);
+ }
+}
+
+static void cdnewregion(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->new_region)
+ {
+ XFreeGC(ctxcanvas->dpy, ctxcanvas->region_aux_gc);
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->region_aux);
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->new_region);
+ }
+
+ ctxcanvas->new_region = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1);
+
+ {
+ GC gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->new_region, 0, NULL);
+ XSetForeground(ctxcanvas->dpy, gc, 0);
+ XFillRectangle(ctxcanvas->dpy, ctxcanvas->new_region, gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ XFreeGC(ctxcanvas->dpy, gc);
+ }
+
+ ctxcanvas->region_aux = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1);
+ ctxcanvas->region_aux_gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->region_aux, 0, NULL);
+ XSetBackground(ctxcanvas->dpy, ctxcanvas->region_aux_gc, 0);
+}
+
+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;
+ XImage* img = XGetImage(ctxcanvas->dpy, ctxcanvas->new_region, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 1, XYPixmap);
+ p = XGetPixel(img, x, y);
+ XDestroyImage(img);
+
+ if (p) return 1;
+ }
+
+ return 0;
+}
+
+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;
+ XImage* img = XGetImage(ctxcanvas->dpy, 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 = XGetPixel(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 = XGetPixel(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;
+ }
+ }
+ }
+ }
+
+ XDestroyImage(img);
+ }
+}
+
+static void sPrepareRegion(cdCtxCanvas *ctxcanvas)
+{
+ if (!ctxcanvas->new_region)
+ return;
+
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXcopy);
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->region_aux_gc, 0);
+ XFillRectangle(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->region_aux_gc, 1);
+}
+
+static void sCombineRegion(cdCtxCanvas *ctxcanvas)
+{
+ switch(ctxcanvas->canvas->combine_mode)
+ {
+ case CD_UNION:
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXor);
+ break;
+ case CD_INTERSECT:
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXand);
+ break;
+ case CD_DIFFERENCE:
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXandInverted);
+ break;
+ case CD_NOTINTERSECT:
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->region_aux_gc, GXxor);
+ break;
+ }
+
+ XCopyArea(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->new_region, ctxcanvas->region_aux_gc,
+ 0, 0,
+ ctxcanvas->canvas->w, ctxcanvas->canvas->h,
+ 0, 0);
+}
+
+static void cdoffsetregion(cdCtxCanvas *ctxcanvas, int x, int y)
+{
+ if (!ctxcanvas->new_region)
+ return;
+
+ sPrepareRegion(ctxcanvas);
+
+ XCopyArea(ctxcanvas->dpy, ctxcanvas->new_region, ctxcanvas->region_aux, ctxcanvas->region_aux_gc,
+ 0, 0,
+ ctxcanvas->canvas->w-x, ctxcanvas->canvas->h-y,
+ x, y);
+
+ XCopyArea(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->new_region, ctxcanvas->region_aux_gc,
+ 0, 0,
+ ctxcanvas->canvas->w, ctxcanvas->canvas->h,
+ 0, 0);
+}
+
+/******************************************************/
+
+static int cdwritemode(cdCtxCanvas *ctxcanvas, int write_mode)
+{
+ switch (write_mode)
+ {
+ case CD_REPLACE:
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXcopy);
+ break;
+ case CD_XOR:
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXxor);
+ break;
+ case CD_NOT_XOR:
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXequiv);
+ break;
+ }
+
+ return write_mode;
+}
+
+static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ int sty = FillSolid;
+
+ switch (style)
+ {
+ case CD_SOLID:
+ sty = FillSolid;
+ break;
+ case CD_HATCH :
+ if (!ctxcanvas->last_hatch)
+ return ctxcanvas->canvas->interior_style;
+
+ XSetStipple(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->last_hatch);
+
+ if (ctxcanvas->canvas->back_opacity == CD_OPAQUE)
+ sty = FillOpaqueStippled;
+ else
+ sty = FillStippled;
+ break;
+ case CD_STIPPLE:
+ XSetStipple(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->last_stipple);
+
+ if (ctxcanvas->canvas->back_opacity == CD_OPAQUE)
+ sty = FillOpaqueStippled;
+ else
+ sty = FillStippled;
+ break;
+ case CD_PATTERN:
+ XSetTile(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->last_pattern);
+ sty = FillTiled;
+ break;
+ }
+
+ XSetFillStyle(ctxcanvas->dpy, ctxcanvas->gc, sty);
+
+ return style;
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int hatch_style)
+{
+ if (ctxcanvas->last_hatch)
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_hatch);
+
+ ctxcanvas->last_hatch = XCreatePixmapFromBitmapData(ctxcanvas->dpy,
+ ctxcanvas->wnd, hatches[hatch_style],
+ HATCH_WIDTH, HATCH_HEIGHT, 1, 0, 1);
+
+ cdinteriorstyle(ctxcanvas, CD_HATCH);
+
+ return hatch_style;
+}
+
+static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *data)
+{
+ int x, y;
+
+ if (ctxcanvas->last_stipple == 0 || (ctxcanvas->last_stipple_w != w || ctxcanvas->last_stipple_h != h))
+ {
+ if (ctxcanvas->last_stipple != 0)
+ {
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_stipple);
+ XFreeGC(ctxcanvas->dpy, ctxcanvas->last_stipple_gc);
+ }
+
+ ctxcanvas->last_stipple = XCreatePixmap(ctxcanvas->dpy,ctxcanvas->wnd,w,h,1);
+ if (!ctxcanvas->last_stipple) return;
+ ctxcanvas->last_stipple_gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->last_stipple, 0, 0);
+ ctxcanvas->last_stipple_w = w;
+ ctxcanvas->last_stipple_h = h;
+ }
+
+ for (y=0; y<h; y++)
+ {
+ for (x=0; x<w; x++)
+ {
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->last_stipple_gc, data[y*w+x]? 1: 0);
+ XDrawPoint(ctxcanvas->dpy, ctxcanvas->last_stipple, ctxcanvas->last_stipple_gc, x, h-y-1);
+ }
+ }
+
+ cdinteriorstyle(ctxcanvas, CD_STIPPLE);
+}
+
+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;
+}
+
+static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *colors)
+{
+ int x, y, i;
+ int size = w*h;
+ unsigned long *pixels;
+
+ if (ctxcanvas->last_pattern == 0 || (ctxcanvas->last_pattern_w != w || ctxcanvas->last_pattern_h != h))
+ {
+ if (ctxcanvas->last_pattern != 0)
+ {
+ XFreePixmap(ctxcanvas->dpy, ctxcanvas->last_pattern);
+ XFreeGC(ctxcanvas->dpy, ctxcanvas->last_pattern_gc);
+ }
+
+ ctxcanvas->last_pattern = XCreatePixmap(ctxcanvas->dpy,ctxcanvas->wnd,w,h,ctxcanvas->depth);
+ if (!ctxcanvas->last_pattern) return;
+ ctxcanvas->last_pattern_gc = XCreateGC(ctxcanvas->dpy, ctxcanvas->last_pattern, 0, 0);
+ ctxcanvas->last_pattern_w = w;
+ ctxcanvas->last_pattern_h = h;
+ }
+
+ pixels = (unsigned long*)malloc(w*h*sizeof(long));
+
+ if (ctxcanvas->canvas->bpp <= 8)
+ {
+ long int match_table[256]; /* X colors */
+ unsigned long palette[256]; /* CD colors */
+ unsigned char *index = (unsigned char*)malloc(size), match;
+ int pal_size = 1;
+ palette[0] = colors[0];
+
+ /* encontra as n primeiras cores diferentes da imagem (ate 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;
+ }
+
+ /* de cores do CD para cores do X */
+ for (i = 0; i < pal_size; i++)
+ match_table[i] = cdxGetPixel(ctxcanvas, palette[i]);
+
+ /* de imagem do CD para imagem do X */
+ for(i=0;i<size;i++)
+ pixels[i] = match_table[index[i]];
+
+ free(index);
+ }
+ else
+ {
+ for(i=0;i<size;i++)
+ pixels[i] = cdxGetPixel(ctxcanvas, colors[i]);
+ }
+
+ for (y=0; y<h; y++)
+ {
+ for (x=0; x<w; x++)
+ {
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->last_pattern_gc, pixels[y*w+x]);
+ XDrawPoint(ctxcanvas->dpy, ctxcanvas->last_pattern, ctxcanvas->last_pattern_gc, x, h-y-1);
+ }
+ }
+
+ cdinteriorstyle(ctxcanvas, CD_PATTERN);
+
+ free(pixels);
+}
+
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ switch (style)
+ {
+ case CD_CONTINUOUS:
+ gcval.line_style = LineSolid;
+ break;
+ case CD_DASHED:
+ case CD_DOTTED:
+ case CD_DASH_DOT:
+ case CD_DASH_DOT_DOT:
+ {
+ static struct {
+ int size;
+ 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 = LineDoubleDash;
+ else
+ gcval.line_style = LineOnOffDash;
+
+ XSetDashes(ctxcanvas->dpy, ctxcanvas->gc, 0, dashes[style-CD_DASHED].list,
+ dashes[style-CD_DASHED].size);
+ break;
+ }
+ case CD_CUSTOM:
+ {
+ int i;
+ char* dash_style = (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 = LineDoubleDash;
+ else
+ gcval.line_style = LineOnOffDash;
+
+ XSetDashes(ctxcanvas->dpy, ctxcanvas->gc, 0, dash_style,
+ ctxcanvas->canvas->line_dashes_count);
+ free(dash_style);
+ break;
+ }
+ }
+ XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCLineStyle, &gcval);
+ return style;
+}
+
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ if (width == 1)
+ gcval.line_width = 0;
+ else
+ gcval.line_width = width;
+
+ XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCLineWidth, &gcval);
+
+ return width;
+}
+
+static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap)
+{
+ int cd2x_cap[] = {CapButt, CapProjecting, CapRound};
+
+ gcval.cap_style = cd2x_cap[cap];
+ XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCCapStyle, &gcval);
+
+ return cap;
+}
+
+static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join)
+{
+ int cd2x_join[] = {JoinMiter, JoinBevel, JoinRound};
+
+ gcval.join_style = cd2x_join[join];
+ XChangeGC(ctxcanvas->dpy, ctxcanvas->gc, GCJoinStyle, &gcval);
+
+ return join;
+}
+
+static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opaque)
+{
+ ctxcanvas->canvas->back_opacity = opaque;
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+ cdlinestyle(ctxcanvas, ctxcanvas->canvas->line_style);
+ return opaque;
+}
+
+static int cdxGetFontSize(char* font_name)
+{
+ int i = 0;
+ while (i < 8)
+ {
+ font_name = strchr(font_name, '-')+1;
+ i++;
+ }
+
+ *(strchr(font_name, '-')) = 0;
+ return atoi(font_name);
+}
+
+static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size)
+{
+ XFontStruct *font;
+ char **font_names_list;
+ char font_name[1024];
+ char* foundry = "*";
+ int i, num_fonts, font_size, near_size, change_italic = 0;
+
+ /* no underline or strikeout support */
+
+ static char * type[] =
+ {
+ "medium-r", /* CD_PLAIN */
+ "bold-r", /* CD_BOLD */
+ "medium-i", /* CD_ITALIC */
+ "bold-i" /* CD_BOLD_ITALIC */
+ };
+
+ 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";
+
+ sprintf(font_name,"-%s-%s-%s-*-*-*-*-*-*-*-*-*-*", foundry, type_face, type[style&3]);
+
+ font_names_list = XListFonts(ctxcanvas->dpy, font_name, 32767, &num_fonts);
+ if (!num_fonts)
+ {
+ /* try changing 'i' to 'o', for italic */
+ if (style&CD_ITALIC)
+ {
+ change_italic = 1;
+ strstr(font_name, "-i-")[1] = 'o';
+ font_names_list = XListFonts(ctxcanvas->dpy, font_name, 32767, &num_fonts);
+ }
+
+ if (!num_fonts)
+ return 0;
+ }
+
+ size = cdGetFontSizePoints(ctxcanvas->canvas, size);
+
+ size *= 10; /* convert to deci-points */
+
+ near_size = -1000;
+ for (i=0; i<num_fonts; i++)
+ {
+ font_size = cdxGetFontSize(font_names_list[i]);
+
+ if (font_size == size)
+ {
+ near_size = font_size;
+ break;
+ }
+
+ if (abs(font_size-size) < abs(near_size-size))
+ near_size = font_size;
+ }
+
+ XFreeFontNames(font_names_list);
+
+ sprintf(font_name,"-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*", foundry, type_face, type[style&3], near_size);
+ if (change_italic) strstr(font_name, "-i-")[1] = 'o';
+
+ font = XLoadQueryFont(ctxcanvas->dpy, font_name);
+ if (!font)
+ return 0;
+
+ if (ctxcanvas->font)
+ XFreeFont(ctxcanvas->dpy, ctxcanvas->font);
+
+ ctxcanvas->font = font;
+ XSetFont(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->font->fid);
+ return 1;
+}
+
+static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* nativefont)
+{
+ int size = 12, style = CD_PLAIN;
+ char type_face[1024];
+
+ if (nativefont[0] == '-')
+ {
+ XFontStruct *font = XLoadQueryFont(ctxcanvas->dpy, nativefont);
+ if (!font)
+ return 0;
+
+ if (!cdParseXWinFont(nativefont, type_face, &style, &size))
+ {
+ XFreeFont(ctxcanvas->dpy, font);
+ return 0;
+ }
+
+ if (ctxcanvas->font) XFreeFont(ctxcanvas->dpy, ctxcanvas->font);
+ ctxcanvas->font = font;
+ XSetFont(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->font->fid);
+ }
+ 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;
+}
+
+static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ if (!ctxcanvas->font) return;
+ if (max_width) *max_width = ctxcanvas->font->max_bounds.width;
+ if (height) *height = ctxcanvas->font->ascent + ctxcanvas->font->descent;
+ if (ascent) *ascent = ctxcanvas->font->ascent;
+ if (descent) *descent = ctxcanvas->font->descent;
+}
+
+static long int cdbackground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ XSetBackground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, color));
+ return color;
+}
+
+static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ ctxcanvas->fg = cdxGetPixel(ctxcanvas, color);
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->fg);
+ return color;
+}
+
+static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode)
+{
+ unsigned long pixels[256];
+ int i;
+
+ for(i = 0; i < ctxcanvas->num_colors; i++)
+ pixels[i] = ctxcanvas->color_table[i].pixel;
+
+ XFreeColors(ctxcanvas->dpy, ctxcanvas->colormap, pixels, ctxcanvas->num_colors, 0);
+
+ if (mode == CD_FORCE)
+ {
+ XColor xc;
+ int tokeep;
+
+ /* se antes era POLITE aloca palette propria */
+ if (ctxcanvas->colormap == DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr))
+ ctxcanvas->colormap = XCreateColormap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->vis, AllocNone);
+
+ /* se for FORCE ira' alocar todas as cores,
+ mas se o numero de cores desejado e' menor que o maximo
+ entao uso a diferenca para preservar as primeiras cores alocadas no colormap default. */
+ tokeep = ctxcanvas->num_colors - n;
+ if (tokeep)
+ {
+ for (i=0; i<tokeep; i++)
+ ctxcanvas->color_table[i].pixel=i;
+
+ XQueryColors(ctxcanvas->dpy, DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr), ctxcanvas->color_table, tokeep);
+
+ /* reservo estas cores para o CD tambem */
+ for (i=0; i<tokeep; i++)
+ XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &(ctxcanvas->color_table[i]));
+ }
+
+ /*aloco todas as cores da palette para o CD */
+ for (i=0; i<n; i++)
+ {
+ xc.red = cdCOLOR8TO16(cdRed(palette[i]));
+ xc.green = cdCOLOR8TO16(cdGreen(palette[i]));
+ xc.blue = cdCOLOR8TO16(cdBlue(palette[i]));
+ xc.flags = DoRed | DoGreen | DoBlue;
+ XAllocColor(ctxcanvas->dpy, ctxcanvas->colormap, &xc);
+ }
+
+ /* atualizo toda a tabela de cores */
+ XSetWindowColormap(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->colormap);
+ update_colors(ctxcanvas);
+ }
+ else
+ {
+ /* se antes era FORCE, remove palette propria */
+ if (ctxcanvas->colormap != DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr))
+ {
+ XFreeColormap(ctxcanvas->dpy, ctxcanvas->colormap);
+ ctxcanvas->colormap = DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr);
+ }
+
+ /* atualizo a tabela antes de acrescentar novas cores afinal liberamos todas as que podiamos antes disso */
+ update_colors(ctxcanvas);
+
+ /* se for POLITE apenas tento alocar todas as cores da palette */
+ for (i=0; i<n; i++)
+ cdxGetPixel(ctxcanvas, palette[i]);
+ }
+}
+
+/******************************************************/
+
+static void cdxCheckSolidStyle(cdCtxCanvas *ctxcanvas, int set)
+{
+ if (ctxcanvas->canvas->interior_style == CD_SOLID)
+ return;
+
+ if (set)
+ XSetFillStyle(ctxcanvas->dpy, ctxcanvas->gc, FillSolid);
+ else
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+}
+
+static void cdclear(cdCtxCanvas* ctxcanvas)
+{
+ cdxCheckSolidStyle(ctxcanvas, 1);
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, ctxcanvas->canvas->background));
+ XFillRectangle(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, ctxcanvas->canvas->foreground));
+ cdxCheckSolidStyle(ctxcanvas, 0);
+}
+
+static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x1, y1, &x1, &y1);
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x2, y2, &x2, &y2);
+ }
+
+ cdxCheckSolidStyle(ctxcanvas, 1);
+ XDrawLine(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, x1, y1, x2, y2);
+ cdxCheckSolidStyle(ctxcanvas, 0);
+}
+
+static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdarcSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+ return;
+ }
+
+ cdxCheckSolidStyle(ctxcanvas, 1);
+ XDrawArc(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64));
+ cdxCheckSolidStyle(ctxcanvas, 0);
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+ return;
+ }
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+ XSetArcMode(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ArcPieSlice);
+ XFillArc(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64));
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ {
+ XSetArcMode(ctxcanvas->dpy, ctxcanvas->gc, ArcPieSlice);
+ XFillArc(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64));
+ }
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+ return;
+ }
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+ XSetArcMode(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ArcChord);
+ XFillArc(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64));
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ {
+ XSetArcMode(ctxcanvas->dpy, ctxcanvas->gc, ArcChord);
+ XFillArc(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xc-w/2, yc-h/2, w, h, cdRound(a1*64), cdRound((a2 - a1)*64));
+ }
+}
+
+static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdrectSIM(ctxcanvas, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ cdxCheckSolidStyle(ctxcanvas, 1);
+ XDrawRectangle(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xmin, ymin, xmax-xmin, ymax-ymin);
+ cdxCheckSolidStyle(ctxcanvas, 0);
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdboxSIM(ctxcanvas, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+ XFillRectangle(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ XFillRectangle(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
+}
+
+static int cd2xvertex [12] = {XR_TCENTRE, XR_BCENTRE,
+ XR_MRIGHT, XR_MLEFT,
+ XR_TRIGHT, XR_TLEFT,
+ XR_BRIGHT, XR_BLEFT,
+ XR_MCENTRE, XR_LEFT,
+ XR_CENTRE, XR_RIGHT};
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ int w, h, n, dir = -1;
+
+ if (ctxcanvas->canvas->text_orientation != 0)
+ {
+ cdxCheckSolidStyle(ctxcanvas, 1);
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y);
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+ XRotDrawString(ctxcanvas->dpy, ctxcanvas->font, ctxcanvas->canvas->text_orientation,
+ ctxcanvas->region_aux, ctxcanvas->region_aux_gc, x, y, s,
+ cd2xvertex[ctxcanvas->canvas->text_alignment], 0);
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ XRotDrawString(ctxcanvas->dpy, ctxcanvas->font, ctxcanvas->canvas->text_orientation,
+ ctxcanvas->wnd, ctxcanvas->gc, x, y, s,
+ cd2xvertex[ctxcanvas->canvas->text_alignment], 0);
+
+ cdxCheckSolidStyle(ctxcanvas, 0);
+
+ return;
+ }
+
+ n = strlen(s);
+ w = XTextWidth(ctxcanvas->font, s, n);
+ h = ctxcanvas->font->ascent + ctxcanvas->font->descent;
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_RIGHT:
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ x = x - w;
+ break;
+ case CD_BASE_CENTER:
+ case CD_CENTER:
+ case CD_NORTH:
+ case CD_SOUTH:
+ x = x - w/2;
+ break;
+ case CD_BASE_LEFT:
+ case CD_NORTH_WEST:
+ case CD_WEST:
+ case CD_SOUTH_WEST:
+ x = x;
+ break;
+ }
+
+ if (ctxcanvas->canvas->invert_yaxis)
+ dir = 1;
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_LEFT:
+ case CD_BASE_CENTER:
+ case CD_BASE_RIGHT:
+ y = y;
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH_WEST:
+ case CD_SOUTH:
+ y = y - dir*ctxcanvas->font->descent;
+ break;
+ case CD_NORTH_EAST:
+ case CD_NORTH:
+ case CD_NORTH_WEST:
+ y = y + dir*(h - ctxcanvas->font->descent);
+ break;
+ case CD_CENTER:
+ case CD_EAST:
+ case CD_WEST:
+ y = y + dir*(h/2 - ctxcanvas->font->descent);
+ break;
+ }
+
+ cdxCheckSolidStyle(ctxcanvas, 1);
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y);
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ sPrepareRegion(ctxcanvas);
+ XSetFont(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ctxcanvas->font->fid);
+ XDrawString(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc, x, y+1, s, n);
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ XDrawString(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, x, y+1, s, n);
+
+ cdxCheckSolidStyle(ctxcanvas, 0);
+}
+
+static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height)
+{
+ if (!ctxcanvas->font) return;
+ if (width) *width = XTextWidth(ctxcanvas->font, s, strlen(s));
+ if (height) *height = ctxcanvas->font->ascent + ctxcanvas->font->descent;
+}
+
+void cdxPoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+ XPoint* pnt = NULL;
+
+ if (mode != CD_BEZIER)
+ {
+ pnt = (XPoint*)malloc((n+1) * sizeof(XPoint)); /* XPoint uses short for coordinates */
+
+ 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);
+ XSetFillRule(ctxcanvas->dpy, ctxcanvas->region_aux_gc, ctxcanvas->canvas->fill_mode==CD_EVENODD?EvenOddRule:WindingRule);
+ XFillPolygon(ctxcanvas->dpy, ctxcanvas->region_aux, ctxcanvas->region_aux_gc,
+ pnt, n, Complex, CoordModeOrigin);
+ sCombineRegion(ctxcanvas);
+ }
+ else
+ {
+ XSetFillRule(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->canvas->fill_mode==CD_EVENODD?EvenOddRule:WindingRule);
+ XFillPolygon(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc,
+ pnt, n, Complex, CoordModeOrigin);
+ }
+ break;
+ case CD_CLOSED_LINES:
+ pnt[n].x = pnt[0].x;
+ pnt[n].y = pnt[0].y;
+ n++;
+ /* continua */
+ case CD_OPEN_LINES:
+ {
+ cdxCheckSolidStyle(ctxcanvas, 1);
+ XDrawLines(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, pnt, n, CoordModeOrigin);
+ cdxCheckSolidStyle(ctxcanvas, 0);
+ break;
+ }
+ case CD_CLIP:
+ if (ctxcanvas->clip_polygon) XFreePixmap(ctxcanvas->dpy, ctxcanvas->clip_polygon);
+ ctxcanvas->clip_polygon = build_clip_polygon(ctxcanvas, pnt, n);
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) cdxClip(ctxcanvas, CD_CLIPPOLYGON);
+ break;
+ case CD_BEZIER:
+ cdSimPolyBezier(ctxcanvas->canvas, poly, n);
+ break;
+ }
+
+ if (pnt) free(pnt);
+}
+
+/******************************************************/
+
+static int byte_order(void)
+{
+ unsigned short us = 0xFF00;
+ unsigned char *uc = (unsigned char *)&us;
+ return (uc[0]==0xFF) ? MSBFirst : LSBFirst;
+}
+
+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;
+ XImage *xi = XGetImage(ctxcanvas->dpy, 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;
+ cdxGetRGB(ctxcanvas, XGetPixel(xi, col, lin), r+pos, g+pos, b+pos);
+ }
+ }
+
+ XDestroyImage(xi);
+}
+
+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;
+}
+
+static XImage *map2ximage(cdCtxCanvas *ctxcanvas, int ew, int eh, const unsigned char *index, const long int * colors, int by, int bx, int bw, int bh, int iw)
+{
+ long int match_table[256];
+ int i, j, pal_size;
+ unsigned long xcol;
+ XImage *xim;
+ int *fx, *fy, src, dst;
+ unsigned char idx;
+
+ xim = (XImage *) NULL;
+
+ /* Como nao sabemos o tamanho da palette a priori,
+ teremos que ver qual o maior indice usado na imagem. */
+ 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++)
+ match_table[i] = cdxGetPixel(ctxcanvas, colors[i]);
+
+ 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 scanline 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]];
+ }
+ }
+
+ xim = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 32, imew);
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+ }
+ break;
+
+ case 12:
+ case 15:
+ case 16:
+ {
+ unsigned char *imagedata;
+ unsigned short *ip, *tip;
+
+ /* Now get the image data - pad each scanline 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 = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 16, 0);
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ if (ctxcanvas->depth == 12 && xim->bits_per_pixel != 16)
+ {
+ xim->data = NULL;
+ XDestroyImage(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->bytes_per_line);
+
+ 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]];
+
+ if (xim->byte_order == MSBFirst)
+ {
+ *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 scanline 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 = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 32, 0);
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ do32 = (xim->bits_per_pixel == 32? 1: 0);
+
+ ip = imagedata + (eh-1)*xim->bytes_per_line;
+
+ 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]];
+
+ if (xim->byte_order == MSBFirst)
+ {
+ if (do32) *tip++ = 0;
+ *tip++ = (unsigned char)((xcol>>16) & 0xff);
+ *tip++ = (unsigned char)((xcol>>8) & 0xff);
+ *tip++ = (unsigned char)( xcol & 0xff);
+ }
+ else
+ { /* LSBFirst */
+ *tip++ = (unsigned char)( xcol & 0xff);
+ *tip++ = (unsigned char)((xcol>>8) & 0xff);
+ *tip++ = (unsigned char)((xcol>>16) & 0xff);
+ if (do32) *tip++ = 0;
+ }
+ }
+
+ ip -= xim->bytes_per_line;
+ }
+ }
+ break;
+ default:
+ {
+ /* Now get the image data - pad each scanline 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 = XCreateImage(ctxcanvas->dpy,ctxcanvas->vis,ctxcanvas->depth,ZPixmap,0, (char *) imagedata, ew, eh, 32, ew*4);
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ xim->bits_per_pixel = 32;
+ xim->bytes_per_line = 4 * iw;
+ xim->byte_order = byte_order();
+ xim->bitmap_bit_order = MSBFirst;
+
+ 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]];
+ }
+ }
+ }
+ break;
+ }
+
+ free(fx);
+ free(fy);
+
+ return(xim);
+}
+
+static XImage *rgb2ximage(cdCtxCanvas *ctxcanvas, int ew, int eh,
+ const unsigned char *red, const unsigned char *green, const unsigned char *blue,
+ const unsigned char *alpha, XImage *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;
+ XImage *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->map_entries;
+ if (maplen>256) maplen=256;
+ cshift = 7 - highbit((unsigned long) (maplen-1));
+
+ xim = XCreateImage(ctxcanvas->dpy, ctxcanvas->vis, ctxcanvas->depth, ZPixmap, 0, NULL, ew, eh, 32, 0);
+ if (!xim)
+ {
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ bperline = xim->bytes_per_line;
+ bperpix = xim->bits_per_pixel;
+ byte_order = xim->byte_order;
+
+ if (bperpix != 8 && bperpix != 16 && bperpix != 24 && bperpix != 32)
+ {
+ XDestroyImage(xim);
+ fprintf(stderr, "CanvasDraw: bpp=%d not supported!\n", bperpix);
+ return NULL;
+ }
+
+ imagedata = (unsigned char*)get_data_buffer(ctxcanvas, eh * bperline);
+ if (!imagedata)
+ {
+ XDestroyImage(xim);
+ fprintf(stderr, "CanvasDraw: not enough memory putting image\n");
+ return NULL;
+ }
+
+ fx = cdGetZoomTable(ew, bw, bx);
+ fy = cdGetZoomTable(eh, bh, by);
+
+ xim->data = (char *) imagedata;
+
+ 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)
+ {
+ cdxGetRGB(ctxcanvas, XGetPixel(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
+ */
+
+#ifdef __cplusplus
+ if (ctxcanvas->vis->c_class == DirectColor)
+#else
+ if (ctxcanvas->vis->class == DirectColor)
+#endif
+ {
+ r = (unsigned long) cdxDirectColorTable[(r>>cshift) & 0xff] << cshift;
+ g = (unsigned long) cdxDirectColorTable[(g>>cshift) & 0xff] << cshift;
+ b = (unsigned long) cdxDirectColorTable[(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 == MSBFirst) {
+ *ip++ = (unsigned char)((xcol>>24) & 0xff);
+ *ip++ = (unsigned char)((xcol>>16) & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)( xcol & 0xff);
+ }
+ else
+ { /* LSBFirst */
+ *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 == MSBFirst)
+ {
+ *ip++ = (unsigned char)((xcol>>16) & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)( xcol & 0xff);
+ }
+ else
+ { /* LSBFirst */
+ *ip++ = (unsigned char)( xcol & 0xff);
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)((xcol>>16) & 0xff);
+ }
+ }
+ else if (bperpix == 16)
+ {
+ if (byte_order == MSBFirst)
+ {
+ *ip++ = (unsigned char)((xcol>>8) & 0xff);
+ *ip++ = (unsigned char)( xcol & 0xff);
+ }
+ else { /* LSBFirst */
+ *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;
+}
+
+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; /* XImage origin is at top-left */
+ XImage *xi, *oxi = NULL;
+ Pixmap clip_polygon, clip_mask = 0;
+ XPoint 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;
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXand);
+ XCopyArea(ctxcanvas->dpy, clip_mask, clip_polygon, ctxcanvas->gc,
+ 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0);
+ XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, clip_polygon);
+ cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset XSetFunction */
+
+ if (a)
+ {
+ oxi = XGetImage(ctxcanvas->dpy, ctxcanvas->wnd, ex, ey, ew, eh, ULONG_MAX, ZPixmap);
+ if (!oxi)
+ {
+ fprintf(stderr, "CanvasDraw: error getting image\n");
+ free(dst_r);
+ return;
+ }
+ }
+
+ xi = rgb2ximage(ctxcanvas, ew, eh, dst_r, dst_g, dst_b, dst_a, oxi, 0, 0, ew, eh, ew);
+ if (!xi)
+ return;
+
+ XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ /* reset cliping */
+ XFreePixmap(ctxcanvas->dpy, clip_polygon);
+ cdxClip(ctxcanvas, ctxcanvas->canvas->clip_mode);
+
+ xi->data = NULL;
+ XDestroyImage(xi);
+ if (oxi) XDestroyImage(oxi);
+ }
+
+ free(dst_r);
+}
+
+static void cdputimagerectmap_matrix(cdCtxCanvas* ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int t_xmin, t_xmax, t_ymin, t_ymax, ew, eh,
+ t_x, t_y, dst_offset, size, doff, rect[8];
+ float i_x, i_y, xfactor, yfactor;
+ unsigned char *dst_index;
+ double inv_matrix[6];
+
+ /* calculate the destination limits */
+ cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, rect);
+
+ /* Setup inverse transform (use the original transform here, NOT ctxcanvas->xmatrix) */
+ cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix);
+
+ /* create an image for the destination area */
+ ew = (t_xmax-t_xmin+1);
+ eh = (t_ymax-t_ymin+1);
+ size = ew*eh;
+ dst_index = malloc(size);
+ if (!dst_index)
+ {
+ fprintf(stderr, "CanvasDraw: no enough memory\n");
+ return;
+ }
+ memset(dst_index, 0, size);
+
+ /* for all pixels in the destiny area */
+ for(t_y = t_ymin; t_y <= t_ymax; t_y++)
+ {
+ dst_offset = (t_y-t_ymin) * ew;
+
+ for(t_x = t_xmin; t_x <= t_xmax; t_x++)
+ {
+ cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix);
+
+ if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1)
+ {
+ doff = (t_x-t_xmin) + dst_offset;
+ *(dst_index+doff) = cdZeroOrderInterpolation(iw, ih, index, i_x, i_y);
+ }
+ }
+ }
+
+ {
+ int ex = t_xmin,
+ ey = t_ymin + eh-1; /* XImage origin is at top-left */
+ XImage *xi;
+ Pixmap clip_polygon, clip_mask = 0;
+ XPoint 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;
+ XSetFunction(ctxcanvas->dpy, ctxcanvas->gc, GXand);
+ XCopyArea(ctxcanvas->dpy, clip_mask, clip_polygon, ctxcanvas->gc,
+ 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0);
+ XSetClipMask(ctxcanvas->dpy, ctxcanvas->gc, clip_polygon);
+ cdwritemode(ctxcanvas, ctxcanvas->canvas->write_mode); /* reset XSetFunction */
+
+ xi = map2ximage(ctxcanvas, ew, eh, dst_index, colors, 0, 0, ew, eh, ew);
+ if (!xi)
+ return;
+
+ XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ /* reset cliping */
+ XFreePixmap(ctxcanvas->dpy, clip_polygon);
+ cdxClip(ctxcanvas, ctxcanvas->canvas->clip_mode);
+
+ xi->data = NULL;
+ XDestroyImage(xi);
+ }
+
+ free(dst_index);
+}
+
+static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax)
+{
+ int ew = w, eh = h, ex = x, ey = y;
+ int bw = iw, bh = ih, bx = 0, by = 0;
+ int rw, rh;
+ XImage *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); /* XImage 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 = rgb2ximage(ctxcanvas, ew, eh, r, g, b, NULL, NULL, by, bx, bw, bh, iw);
+ if (!xi)
+ return;
+
+ XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ xi->data = NULL;
+ XDestroyImage(xi);
+}
+
+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)
+{
+ XImage *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); /* XImage 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 = XGetImage(ctxcanvas->dpy, ctxcanvas->wnd, ex, ey, ew, eh, ULONG_MAX, ZPixmap);
+ if (!oxi)
+ {
+ fprintf(stderr, "CanvasDraw: error getting image\n");
+ return;
+ }
+
+ xi = rgb2ximage(ctxcanvas, ew, eh, r, g, b, a, oxi, by, bx, bw, bh, iw);
+ if (!xi)
+ return;
+
+ XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ xi->data = NULL;
+ XDestroyImage(xi);
+ XDestroyImage(oxi);
+}
+
+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;
+ XImage *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); /* XImage 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 = map2ximage(ctxcanvas, ew, eh, index, colors, by, bx, bw, bh, iw);
+ if (!xi)
+ return;
+
+ XPutImage(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, xi, 0, 0, ex, ey, ew, eh);
+
+ xi->data = NULL;
+ XDestroyImage(xi);
+}
+
+static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ if (ctxcanvas->canvas->foreground != color)
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, cdxGetPixel(ctxcanvas, color));
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->xmatrix, x, y, &x, &y);
+
+ XDrawPoint(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->gc, x, y);
+
+ if (ctxcanvas->canvas->foreground != color)
+ XSetForeground(ctxcanvas->dpy, ctxcanvas->gc, ctxcanvas->fg);
+}
+
+static cdCtxImage *cdcreateimage (cdCtxCanvas *ctxcanvas, int w, int h)
+{
+ GC gc;
+ cdCtxImage *ctximage = (cdCtxImage *)malloc(sizeof(cdCtxImage));
+
+ ctximage->w = w;
+ ctximage->h = h;
+ ctximage->depth = ctxcanvas->depth;
+ ctximage->dpy = ctxcanvas->dpy;
+ ctximage->scr = ctxcanvas->scr;
+ ctximage->vis = ctxcanvas->vis;
+
+ ctximage->img = XCreatePixmap(ctxcanvas->dpy, ctxcanvas->wnd, w, h, ctxcanvas->depth);
+ if (!ctximage->img)
+ {
+ free(ctximage);
+ return (void *)0;
+ }
+
+ gc = XCreateGC(ctximage->dpy, ctximage->img, 0, NULL);
+ XSetForeground(ctximage->dpy, gc, cdxGetPixel(ctxcanvas, CD_WHITE));
+ XFillRectangle(ctximage->dpy, ctximage->img, gc, 0, 0, ctximage->w, ctxcanvas->canvas->h);
+ XFreeGC(ctximage->dpy, gc);
+
+ return (void *)ctximage;
+}
+
+static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y)
+{
+ XCopyArea(ctxcanvas->dpy, ctxcanvas->wnd, ctximage->img, ctxcanvas->gc,
+ x, y - ctximage->h+1, ctximage->w, ctximage->h, 0, 0);
+}
+
+static void cdputimagerect (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax)
+{
+ XCopyArea(ctxcanvas->dpy, ctximage->img, ctxcanvas->wnd, ctxcanvas->gc,
+ xmin, ctximage->h-ymax-1, xmax-xmin+1, ymax-ymin+1, x, y-(ymax-ymin+1)+1);
+}
+
+static void cdkillimage (cdCtxImage *ctximage)
+{
+ XFreePixmap(ctximage->dpy, ctximage->img);
+ free(ctximage);
+}
+
+static void cdscrollarea (cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy)
+{
+ XCopyArea(ctxcanvas->dpy, ctxcanvas->wnd, ctxcanvas->wnd, ctxcanvas->gc,
+ xmin, ymin,
+ xmax-xmin+1, ymax-ymin+1,
+ xmin+dx, ymin+dy);
+}
+
+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
+};
+
+static void get_geometry(Display *dpy, Drawable wnd, cdCtxCanvas *ctxcanvas)
+{
+ Window root;
+ int x, y;
+ unsigned int w, h, b, d;
+ XGetGeometry(dpy, wnd, &root, &x, &y, &w, &h, &b, &d);
+ ctxcanvas->canvas->w = w;
+ ctxcanvas->canvas->h = h;
+ ctxcanvas->depth = d;
+}
+
+cdCtxCanvas *cdxCreateCanvas(cdCanvas* canvas, Display *dpy, int scr, Drawable wnd, Visual *vis)
+{
+ static int first = 1;
+ cdCtxCanvas *ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ ctxcanvas->dpy = dpy;
+ ctxcanvas->scr = scr;
+ ctxcanvas->wnd = wnd;
+ ctxcanvas->vis = vis;
+ ctxcanvas->gc = XCreateGC(dpy, wnd, 0, NULL);
+ if (ctxcanvas->gc == 0)
+ {
+ free(canvas);
+ return NULL;
+ }
+
+ ctxcanvas->canvas = canvas;
+ canvas->ctxcanvas = ctxcanvas;
+
+ get_geometry(dpy, wnd, ctxcanvas);
+
+ canvas->bpp = ctxcanvas->depth;
+ canvas->xres = ((double)DisplayWidth(dpy, scr) / (double)DisplayWidthMM(dpy, scr));
+ canvas->yres = ((double)DisplayHeight(dpy, scr) / (double)DisplayHeightMM(dpy, 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)
+ {
+ cdxGetRGB = truecolor_get_rgb;
+ cdxGetPixel = truecolor_get_pixel;
+
+ /* make linear colormap for DirectColor visual */
+#ifdef __cplusplus
+ if (ctxcanvas->vis->c_class == DirectColor)
+#else
+ if (ctxcanvas->vis->class == DirectColor)
+#endif
+ makeDirectCmap(ctxcanvas, DefaultColormap(ctxcanvas->dpy, ctxcanvas->scr));
+ }
+ else
+ {
+ cdxGetRGB = not_truecolor_get_rgb;
+ cdxGetPixel = 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 = (Colormap)0;
+
+ /* para canvas bpp <= 8 RGBA e' simulado com cdGetImageRGB */
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ }
+ else
+ {
+ int i;
+
+ ctxcanvas->colormap = DefaultColormap(dpy, scr);
+ ctxcanvas->num_colors = 1L << canvas->bpp;
+
+ for (i=0; i<ctxcanvas->num_colors; i++)
+ ctxcanvas->color_table[i].pixel = i;
+
+ update_colors(ctxcanvas);
+ }
+
+ if (first)
+ {
+ if(!getenv("CD_XERROR"))
+ XSetErrorHandler(cdxErrorHandler);
+ }
+
+ 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 = cdxPoly;
+ canvas->cxRect = cdrect;
+ 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 = cdxClip;
+ 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;
+}
diff --git a/src/x11/cdx11.h b/src/x11/cdx11.h
new file mode 100644
index 0000000..a68fdf9
--- /dev/null
+++ b/src/x11/cdx11.h
@@ -0,0 +1,85 @@
+/** \file
+ * \brief X-Windows Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __CDX11_H
+#define __CDX11_H
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "cd.h"
+#include "cd_private.h"
+
+
+/* Hidden declaration for the Context Plus driver */
+typedef struct _cdxContextPlus cdxContextPlus;
+
+struct _cdCtxImage {
+ unsigned int w, h, depth;
+ Pixmap img;
+ Display *dpy;
+ int scr;
+ Visual *vis;
+};
+
+struct _cdCtxCanvas {
+ cdCanvas* canvas;
+ Display* dpy; /* display da aplicacao no X */
+ Visual* vis; /* visual usado pela aplicacao */
+ int scr; /* screen da aplicacao */
+ GC gc; /* contexto grafico */
+ Drawable wnd; /* drawable */
+ long int fg;
+ Pixmap last_hatch; /* ultimo hatch setado pelo usuario */
+ Pixmap last_stipple; /* ultimo stipple setado pelo usuario */
+ Pixmap last_pattern; /* ultimo pattern setado pelo usuario */
+ GC last_stipple_gc;
+ int last_stipple_w;
+ int last_stipple_h;
+ GC last_pattern_gc;
+ int last_pattern_w;
+ int last_pattern_h;
+ XFontStruct *font; /* fonte de caracteres no X */
+ unsigned int depth; /* depth do canvas */
+ Pixmap clip_polygon; /* poligono de clipping */
+ Pixmap new_region, region_aux;
+ GC region_aux_gc;
+ void *data; /* informacoes especificas do driver */
+ long int *xidata; /* ximage cache */
+ int xisize;
+ Colormap colormap; /* colormap para todos os canvas */
+ XColor color_table[256]; /* 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;
+
+ cdImage* image_dbuffer; /* utilizado pelo driver de Double buffer */
+ cdCanvas* canvas_dbuffer;
+
+ cdxContextPlus* ctxplus;
+};
+
+#define cdCOLOR8TO16(_x) (_x*257) /* 65535/255 = 257 */
+#define cdCOLOR16TO8(_x) ((unsigned char)(_x/257))
+
+extern unsigned long (*cdxGetPixel)(cdCtxCanvas *ctxcanvas, unsigned long rgb);
+extern void (*cdxGetRGB)(cdCtxCanvas *ctxcanvas, unsigned long pixel,
+ unsigned char* red,
+ unsigned char* green,
+ unsigned char* blue);
+
+cdCtxCanvas *cdxCreateCanvas(cdCanvas* canvas, Display *dpy, int scr, Drawable wnd, Visual *vis);
+void cdxInitTable(cdCanvas* canvas);
+void cdxKillCanvas(cdCtxCanvas *ctxcanvas);
+int cdxClip(cdCtxCanvas *ctxcanvas, int clip_mode);
+void cdxPoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n);
+
+#endif
diff --git a/src/x11/cdxclp.c b/src/x11/cdxclp.c
new file mode 100644
index 0000000..d775fde
--- /dev/null
+++ b/src/x11/cdxclp.c
@@ -0,0 +1,136 @@
+/** \file
+ * \brief X-Windows Clipboard Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.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;
+ Display* dpy = (Display*)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);
+
+ XStoreBytes(dpy, buffer, dwSize);
+}
+
+static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data)
+{
+ char filename[1024];
+ char* buffer;
+ int dwSize;
+ FILE* file;
+
+ buffer = XFetchBytes((Display*)data, &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);
+
+ XFree(buffer);
+
+ return CD_OK;
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ char tmpPath[512];
+ char* str = (char*)data;
+ Display* dpy = NULL;
+
+ /* Inicializa parametros */
+ if (str == NULL)
+ return;
+
+#ifdef SunOS_OLD
+ sscanf(str, "%d", &dpy);
+#else
+ sscanf(str, "%p", &dpy);
+#endif
+
+ if (!dpy)
+ 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 = dpy;
+ }
+}
+
+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/x11/cdxdbuf.c b/src/x11/cdxdbuf.c
new file mode 100644
index 0000000..1c92da5
--- /dev/null
+++ b/src/x11/cdxdbuf.c
@@ -0,0 +1,156 @@
+/** \file
+ * \brief X-Windows Double Buffer Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include "cdx11.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 */
+ XFlush(ctxcanvas->dpy);
+
+ /* 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)
+{
+ cdCtxCanvas* ctxcanvas;
+ cdImage* image_dbuffer;
+ cdCtxImage* ctximage;
+
+ /* this is done in the canvas_dbuffer context */
+ image_dbuffer = cdCanvasCreateImage(canvas_dbuffer, canvas_dbuffer->w, canvas_dbuffer->h);
+ if (!image_dbuffer)
+ return;
+
+ ctximage = image_dbuffer->ctximage;
+
+ /* Inicializa driver DBuffer */
+ ctxcanvas = cdxCreateCanvas(canvas, ctximage->dpy, ctximage->scr, ctximage->img, ctximage->vis);
+ if (!ctxcanvas)
+ return;
+
+ ctxcanvas->image_dbuffer = image_dbuffer;
+ ctxcanvas->canvas_dbuffer = canvas_dbuffer;
+}
+
+static int cdactivate(cdCtxCanvas* ctxcanvas)
+{
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+
+ /* this is done in the canvas_dbuffer context */
+ /* this will update canvas size */
+ cdCanvasActivate(canvas_dbuffer);
+
+ /* check if the size changed */
+ if (canvas_dbuffer->w != ctxcanvas->image_dbuffer->w ||
+ canvas_dbuffer->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/x11/cdximg.c b/src/x11/cdximg.c
new file mode 100644
index 0000000..8131f78
--- /dev/null
+++ b/src/x11/cdximg.c
@@ -0,0 +1,52 @@
+/** \file
+ * \brief X-Windows Image Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+
+#include "cdx11.h"
+#include "cdimage.h"
+
+
+static void cdkillcanvas(cdCtxCanvas* ctxcanvas)
+{
+ cdxKillCanvas(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxImage *ctximage = ((cdImage*)data)->ctximage;
+ cdxCreateCanvas(canvas, ctximage->dpy, ctximage->scr, ctximage->img, 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/x11/cdxnative.c b/src/x11/cdxnative.c
new file mode 100644
index 0000000..c708d20
--- /dev/null
+++ b/src/x11/cdxnative.c
@@ -0,0 +1,165 @@
+/** \file
+ * \brief X-Windows Native Window Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdx11.h"
+#include "cdnative.h"
+
+
+int cdGetScreenColorPlanes(void)
+{
+ static int first = 1;
+ static int bpp;
+
+ if (first)
+ {
+ int nitems;
+ XVisualInfo info;
+ Display* drv_display = XOpenDisplay(NULL);
+
+ info.depth = 24;
+ if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL)
+ {
+ bpp = 24;
+ XCloseDisplay(drv_display);
+ return bpp;
+ }
+
+ info.depth = 16;
+ if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL)
+ {
+ bpp = 16;
+ XCloseDisplay(drv_display);
+ return bpp;
+ }
+
+ info.depth = 8;
+ if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL)
+ {
+ bpp = 8;
+ XCloseDisplay(drv_display);
+ return bpp;
+ }
+
+ info.depth = 4;
+ if (XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems) != NULL)
+ {
+ bpp = 4;
+ XCloseDisplay(drv_display);
+ return bpp;
+ }
+
+ bpp = 2;
+ XCloseDisplay(drv_display);
+
+ 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)
+ {
+ Display* drv_display = XOpenDisplay(NULL);
+ int drv_screen = DefaultScreen (drv_display);
+
+ dpy_width = DisplayWidth(drv_display,drv_screen);
+ dpy_height = DisplayHeight(drv_display,drv_screen);
+ dpy_width_mm = DisplayWidthMM(drv_display,drv_screen);
+ dpy_height_mm = DisplayHeightMM(drv_display,drv_screen);
+
+ XCloseDisplay(drv_display);
+
+ 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);
+}
+
+static int cdactivate(cdCtxCanvas *ctxcanvas)
+{
+ Window root;
+ int x, y;
+ unsigned int bw, d;
+ XGetGeometry(ctxcanvas->dpy, ctxcanvas->wnd, &root, &x, &y,
+ (unsigned int*)&ctxcanvas->canvas->w, (unsigned int*)&ctxcanvas->canvas->h, &bw, &d);
+
+ ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres;
+ ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres;
+
+ if (ctxcanvas->canvas->use_matrix)
+ ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix);
+
+ return CD_OK;
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ char* data_str = (char*)data;
+ Window wnd;
+ Display *dpy;
+ XWindowAttributes wa;
+
+#ifdef SunOS_OLD
+ sscanf(data_str, "%d %lu", &dpy, &wnd);
+#else
+ sscanf(data_str, "%p %lu", &dpy, &wnd);
+#endif
+
+ if (!dpy || !wnd)
+ return;
+
+ XGetWindowAttributes(dpy, wnd, &wa);
+ cdxCreateCanvas(canvas, dpy, XScreenNumberOfScreen(wa.screen), wnd, wa.visual);
+}
+
+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;
+}
diff --git a/src/x11/xvertex.c b/src/x11/xvertex.c
new file mode 100644
index 0000000..87a05e9
--- /dev/null
+++ b/src/x11/xvertex.c
@@ -0,0 +1,1440 @@
+/* ********************************************************************** */
+
+/* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma)
+*
+* Permission to use, copy, modify, and distribute this software and its
+* documentation for any purpose and without fee is hereby granted, provided
+* that the above copyright notice appear in all copies and that both the
+* copyright notice and this permission notice appear in supporting
+* documentation. All work developed as a consequence of the use of
+* this program should duly acknowledge such use. No representations are
+* made about the suitability of this software for any purpose. It is
+* provided "as is" without express or implied warranty.
+*/
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "xvertex.h"
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/* Make sure cache size is set */
+
+#ifndef CACHE_SIZE_LIMIT
+#define CACHE_SIZE_LIMIT 300
+#endif /*CACHE_SIZE_LIMIT */
+
+/* Make sure a cache method is specified */
+
+#ifndef CACHE_XIMAGES
+#ifndef CACHE_BITMAPS
+#define CACHE_BITMAPS
+#endif /*CACHE_BITMAPS*/
+#endif /*CACHE_XIMAGES*/
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/* Debugging macros */
+
+#ifdef DEBUG
+static int debug=1;
+#else
+static int debug=0;
+#endif /*DEBUG*/
+
+#define DEBUG_PRINT1(a) if (debug) printf (a)
+#define DEBUG_PRINT2(a, b) if (debug) printf (a, b)
+#define DEBUG_PRINT3(a, b, c) if (debug) printf (a, b, c)
+#define DEBUG_PRINT4(a, b, c, d) if (debug) printf (a, b, c, d)
+#define DEBUG_PRINT5(a, b, c, d, e) if (debug) printf (a, b, c, d, e)
+
+
+/* ---------------------------------------------------------------------- */
+
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/* A structure holding everything needed for a rotated string */
+
+typedef struct rotated_text_item_template {
+ Pixmap bitmap;
+ XImage *ximage;
+
+ char *text;
+ char *font_name;
+ Font fid;
+ double angle;
+ int align;
+ double magnify;
+
+ int cols_in;
+ int rows_in;
+ int cols_out;
+ int rows_out;
+
+ int nl;
+ int max_width;
+ double *corners_x;
+ double *corners_y;
+
+ long int size;
+ int cached;
+
+ struct rotated_text_item_template *next;
+} RotatedTextItem;
+
+static RotatedTextItem *first_text_item=NULL;
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/* A structure holding current magnification and bounding box padding */
+
+static struct style_template {
+ double magnify;
+ int bbx_pad;
+} style={
+ 1.,
+ 0
+};
+
+
+/* ---------------------------------------------------------------------- */
+
+static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, double angle, char *text, int align);
+static void XRotAddToLinkedList(Display *dpy, RotatedTextItem *item);
+static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage);
+static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item);
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Routine to mimic `strdup()' (some machines don't have it) */
+/**************************************************************************/
+
+static char *my_strdup(const char *str)
+{
+ char *s;
+
+ if(str==NULL)
+ return NULL;
+
+ s=(char *)malloc((unsigned)(strlen(str)+1));
+ if(s!=NULL)
+ strcpy(s, str);
+
+ return s;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Routine to replace `strtok' : this one returns a zero length string if */
+/* it encounters two consecutive delimiters */
+/**************************************************************************/
+
+static char *my_strtok(char *str1, const char *str2)
+{
+ char *ret;
+ int i, j, stop;
+ static int start, len;
+ static char *stext;
+
+ if(str2==NULL)
+ return NULL;
+
+ /* initialise if str1 not NULL */
+ if(str1!=NULL)
+ {
+ start=0;
+ stext=str1;
+ len=strlen(str1);
+ }
+
+ /* run out of tokens ? */
+ if(start>=len)
+ return NULL;
+
+ /* loop through characters */
+ for(i=start; i<len; i++)
+ {
+ /* loop through delimiters */
+ stop=0;
+ for(j=0; j<strlen(str2); j++)
+ if(stext[i]==str2[j])
+ stop=1;
+
+ if(stop)
+ break;
+ }
+
+ stext[i]='\0';
+
+ ret=stext+start;
+
+ start=i+1;
+
+ return ret;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Create an XImage structure and allocate memory for it */
+/**************************************************************************/
+
+static XImage *MakeXImage(Display *dpy, int w, int h)
+{
+ XImage *I;
+ char *data;
+
+ /* reserve memory for image */
+ data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1);
+ if(data==NULL)
+ return NULL;
+
+ /* create the XImage */
+ I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap, 0, data, w, h, 8, 0);
+ if(I==NULL)
+ return NULL;
+
+ I->byte_order=I->bitmap_bit_order=MSBFirst;
+ return I;
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Draw a horizontal string in a quick fashion */
+/**************************************************************************/
+
+static int XRotDrawHorizontalString(Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, const char *text, int align, int bg)
+{
+ GC my_gc;
+ int nl=1, i;
+ int height;
+ int xp, yp;
+ char *str1, *str2, *str3;
+ char *str2_a="\0", *str2_b="\n\0";
+ int dir, asc, desc;
+ XCharStruct overall;
+
+ DEBUG_PRINT1("**\nHorizontal text.\n");
+
+ /* this gc has similar properties to the user's gc (including stipple) */
+ my_gc=XCreateGC(dpy, drawable, 0, 0);
+ XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle| GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask, my_gc);
+ XSetFont(dpy, my_gc, font->fid);
+
+ /* count number of sections in string */
+ if(align!=XR_LEFT)
+ for(i=0; i<strlen(text)-1; i++)
+ if(text[i]=='\n')
+ nl++;
+
+ /* ignore newline characters if not doing alignment */
+ if(align==XR_LEFT)
+ str2=str2_a;
+ else
+ str2=str2_b;
+
+ /* overall font height */
+ height=font->ascent+font->descent;
+
+ /* y position */
+ if(align==XR_TLEFT || align==XR_TCENTRE || align==XR_TRIGHT)
+ yp=y+font->ascent;
+ else if(align==XR_MLEFT || align==XR_MCENTRE || align==XR_MRIGHT)
+ yp=y-nl*height/2+font->ascent;
+ else if(align==XR_BLEFT || align==XR_BCENTRE || align==XR_BRIGHT)
+ yp=y-nl*height+font->ascent;
+ else
+ yp=y;
+
+ str1=my_strdup(text);
+ if(str1==NULL)
+ return 1;
+
+ str3=my_strtok(str1, str2);
+
+ /* loop through each section in the string */
+ do {
+ XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
+ &overall);
+
+ /* where to draw section in x ? */
+ if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT)
+ xp=x;
+ else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE)
+ xp=x-overall.rbearing/2;
+ else
+ xp=x-overall.rbearing;
+
+ /* draw string onto bitmap */
+ if(!bg)
+ XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
+ else
+ XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3));
+
+ /* move to next line */
+ yp+=height;
+
+ str3=my_strtok((char *)NULL, str2);
+ }
+ while(str3!=NULL);
+
+ free(str1);
+ XFreeGC(dpy, my_gc);
+
+ return 0;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Query cache for a match with this font/text/angle/alignment */
+/* request, otherwise arrange for its creation */
+/**************************************************************************/
+
+static RotatedTextItem *XRotRetrieveFromCache(Display *dpy, XFontStruct *font, double angle, const char *text, int align)
+{
+ Font fid;
+ char *font_name=NULL;
+ unsigned long name_value;
+ RotatedTextItem *item=NULL;
+ RotatedTextItem *i1=first_text_item;
+
+ /* get font name, if it exists */
+ if(XGetFontProperty(font, XA_FONT, &name_value)) {
+ DEBUG_PRINT1("got font name OK\n");
+ font_name=XGetAtomName(dpy, name_value);
+ fid=0;
+ }
+#ifdef CACHE_FID
+ /* otherwise rely (unreliably?) on font ID */
+ else {
+ DEBUG_PRINT1("can't get fontname, caching FID\n");
+ font_name=NULL;
+ fid=font->fid;
+ }
+#else
+ /* not allowed to cache font ID's */
+ else {
+ DEBUG_PRINT1("can't get fontname, can't cache\n");
+ font_name=NULL;
+ fid=0;
+ }
+#endif /*CACHE_FID*/
+
+ /* look for a match in cache */
+
+ /* matching formula:
+ identical text;
+ identical fontname (if defined, font ID's if not);
+ angles close enough (<0.00001 here, could be smaller);
+ HORIZONTAL alignment matches, OR it's a one line string;
+ magnifications the same */
+
+ while(i1 && !item)
+ {
+ /* match everything EXCEPT fontname/ID */
+ if(strcmp(text, i1->text)==0 &&
+ fabs(angle-i1->angle)<0.00001 &&
+ style.magnify==i1->magnify &&
+ (i1->nl==1 ||
+ ((align==0)?9:(align-1))%3==
+ ((i1->align==0)?9:(i1->align-1))%3))
+ {
+
+ /* now match fontname/ID */
+ if(font_name!=NULL && i1->font_name!=NULL)
+ {
+ if(strcmp(font_name, i1->font_name)==0)
+ {
+ item=i1;
+ DEBUG_PRINT1("Matched against font names\n");
+ }
+ else
+ i1=i1->next;
+ }
+#ifdef CACHE_FID
+ else if(font_name==NULL && i1->font_name==NULL)
+ {
+ if(fid==i1->fid)
+ {
+ item=i1;
+ DEBUG_PRINT1("Matched against FID's\n");
+ }
+ else
+ i1=i1->next;
+ }
+#endif /*CACHE_FID*/
+ else
+ i1=i1->next;
+ }
+ else
+ i1=i1->next;
+ }
+
+ if(item)
+ DEBUG_PRINT1("**\nFound target in cache.\n");
+ if(!item)
+ DEBUG_PRINT1("**\nNo match in cache.\n");
+
+ /* no match */
+ if(!item)
+ {
+ /* create new item */
+ item=XRotCreateTextItem(dpy, font, angle, text, align);
+ if(!item)
+ return NULL;
+
+ /* record what it shows */
+ item->text=my_strdup(text);
+
+ /* fontname or ID */
+ if(font_name!=NULL)
+ {
+ item->font_name=my_strdup(font_name);
+ item->fid=0;
+ }
+ else
+ {
+ item->font_name=NULL;
+ item->fid=fid;
+ }
+
+ item->angle=angle;
+ item->align=align;
+ item->magnify=style.magnify;
+
+ /* cache it */
+ XRotAddToLinkedList(dpy, item);
+ }
+
+ if(font_name)
+ XFree(font_name);
+
+ /* if XImage is cached, need to recreate the bitmap */
+
+#ifdef CACHE_XIMAGES
+ {
+ GC depth_one_gc;
+
+ /* create bitmap to hold rotated text */
+ item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
+ item->cols_out, item->rows_out, 1);
+
+ /* depth one gc */
+ depth_one_gc=XCreateGC(dpy, item->bitmap, 0, 0);
+ XSetBackground(dpy, depth_one_gc, 0);
+ XSetForeground(dpy, depth_one_gc, 1);
+
+ /* make the text bitmap from XImage */
+ XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0,
+ item->cols_out, item->rows_out);
+
+ XFreeGC(dpy, depth_one_gc);
+ }
+#endif /*CACHE_XIMAGES*/
+
+ return item;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Create a rotated text item */
+/**************************************************************************/
+
+static RotatedTextItem *XRotCreateTextItem(Display *dpy, XFontStruct *font, double angle, char *text, int align)
+{
+ RotatedTextItem *item=NULL;
+ Pixmap canvas;
+ GC font_gc;
+ XImage *I_in;
+ register int i, j;
+ char *str1, *str2, *str3;
+ char *str2_a="\0", *str2_b="\n\0";
+ int height;
+ int byte_w_in, byte_w_out;
+ int xp, yp;
+ double sin_angle, cos_angle;
+ int it, jt;
+ double di, dj;
+ int ic=0;
+ double xl, xr, xinc;
+ int byte_out;
+ int dir, asc, desc;
+ XCharStruct overall;
+ int old_cols_in=0, old_rows_in=0;
+
+ /* allocate memory */
+ item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem));
+ if(!item)
+ return NULL;
+
+ /* count number of sections in string */
+ item->nl=1;
+ if(align!=XR_LEFT)
+ for(i=0; i<strlen(text)-1; i++)
+ if(text[i]=='\n')
+ item->nl++;
+
+ /* ignore newline characters if not doing alignment */
+ if(align==XR_LEFT)
+ str2=str2_a;
+ else
+ str2=str2_b;
+
+ /* find width of longest section */
+ str1=my_strdup(text);
+ if(str1==NULL)
+ return NULL;
+
+ str3=my_strtok(str1, str2);
+
+ XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
+ &overall);
+
+ item->max_width=overall.rbearing;
+
+ /* loop through each section */
+ do
+ {
+ str3=my_strtok((char *)NULL, str2);
+
+ if(str3!=NULL)
+ {
+ XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
+ &overall);
+
+ if(overall.rbearing>item->max_width)
+ item->max_width=overall.rbearing;
+ }
+ } while(str3!=NULL);
+
+ free(str1);
+
+ /* overall font height */
+ height=font->ascent+font->descent;
+
+ /* dimensions horizontal text will have */
+ item->cols_in=item->max_width;
+ item->rows_in=item->nl*height;
+
+ /* bitmap for drawing on */
+ canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy),
+ item->cols_in, item->rows_in, 1);
+
+ /* create a GC for the bitmap */
+ font_gc=XCreateGC(dpy, canvas, 0, 0);
+ XSetBackground(dpy, font_gc, 0);
+ XSetFont(dpy, font_gc, font->fid);
+
+ /* make sure the bitmap is blank */
+ XSetForeground(dpy, font_gc, 0);
+ XFillRectangle(dpy, canvas, font_gc, 0, 0,
+ item->cols_in+1, item->rows_in+1);
+ XSetForeground(dpy, font_gc, 1);
+
+ /* pre-calculate sin and cos */
+ sin_angle=sin(angle);
+ cos_angle=cos(angle);
+
+ if (fabs(sin_angle)==1.0) cos_angle=0;
+ if (fabs(cos_angle)==1.0) sin_angle=0;
+
+ /* text background will be drawn using XFillPolygon */
+ item->corners_x=
+ (double *)malloc((unsigned)(4*item->nl*sizeof(double)));
+ if(!item->corners_x)
+ return NULL;
+
+ item->corners_y=
+ (double *)malloc((unsigned)(4*item->nl*sizeof(double)));
+ if(!item->corners_y)
+ return NULL;
+
+ /* draw text horizontally */
+
+ /* start at top of bitmap */
+ yp=font->ascent;
+
+ str1=my_strdup(text);
+ if(str1==NULL)
+ return NULL;
+
+ str3=my_strtok(str1, str2);
+
+ /* loop through each section in the string */
+ do
+ {
+ XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall);
+
+ /* where to draw section in x ? */
+ if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT)
+ xp=0;
+ else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE)
+ xp=(item->max_width-overall.rbearing)/2;
+ else
+ xp=item->max_width-overall.rbearing;
+
+ /* draw string onto bitmap */
+ XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3));
+
+ /* keep a note of corner positions of this string */
+ item->corners_x[ic]=((double)xp-(double)item->cols_in/2)*style.magnify;
+ item->corners_y[ic]=((double)(yp-font->ascent)-(double)item->rows_in/2)
+ *style.magnify;
+ item->corners_x[ic+1]=item->corners_x[ic];
+ item->corners_y[ic+1]=item->corners_y[ic]+(double)height*style.magnify;
+ item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+
+ (double)overall.rbearing*style.magnify;
+ item->corners_y[item->nl*4-1-ic]=item->corners_y[ic];
+ item->corners_x[item->nl*4-2-ic]=
+ item->corners_x[item->nl*4-1-ic];
+ item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1];
+
+ ic+=2;
+
+ /* move to next line */
+ yp+=height;
+
+ str3=my_strtok((char *)NULL, str2);
+ } while(str3!=NULL);
+
+ free(str1);
+
+ /* create image to hold horizontal text */
+ I_in=MakeXImage(dpy, item->cols_in, item->rows_in);
+ if(I_in==NULL)
+ return NULL;
+
+ /* extract horizontal text */
+ XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in,
+ 1, XYPixmap, I_in, 0, 0);
+ I_in->format=XYBitmap;
+
+ /* magnify horizontal text */
+ if(style.magnify!=1.)
+ {
+ I_in=XRotMagnifyImage(dpy, I_in);
+
+ old_cols_in=item->cols_in;
+ old_rows_in=item->rows_in;
+ item->cols_in=(double)item->cols_in*style.magnify;
+ item->rows_in=(double)item->rows_in*style.magnify;
+ }
+
+ /* how big will rotated text be ? */
+ item->cols_out=fabs((double)item->rows_in*sin_angle) +
+ fabs((double)item->cols_in*cos_angle) +0.99999 +2;
+
+ item->rows_out=fabs((double)item->rows_in*cos_angle) +
+ fabs((double)item->cols_in*sin_angle) +0.99999 +2;
+
+ if(item->cols_out%2==0)
+ item->cols_out++;
+
+ if(item->rows_out%2==0)
+ item->rows_out++;
+
+ /* create image to hold rotated text */
+ item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out);
+ if(item->ximage==NULL)
+ return NULL;
+
+ byte_w_in=(item->cols_in-1)/8+1;
+ byte_w_out=(item->cols_out-1)/8+1;
+
+ /* we try to make this bit as fast as possible - which is why it looks
+ a bit over-the-top */
+
+ /* vertical distance from centre */
+ dj=0.5-(double)item->rows_out/2;
+
+ /* where abouts does text actually lie in rotated image? */
+ if(angle==0 || angle==M_PI/2 || angle==M_PI || angle==3*M_PI/2)
+ {
+ xl=0;
+ xr=(double)item->cols_out;
+ xinc=0;
+ }
+ else if(angle<M_PI)
+ {
+ xl=(double)item->cols_out/2+
+ (dj-(double)item->rows_in/(2*cos_angle))/
+ tan(angle)-2;
+
+ xr=(double)item->cols_out/2+
+ (dj+(double)item->rows_in/(2*cos_angle))/
+ tan(angle)+2;
+
+ xinc=1./tan(angle);
+ }
+ else
+ {
+ xl=(double)item->cols_out/2+
+ (dj+(double)item->rows_in/(2*cos_angle))/
+ tan(angle)-2;
+
+ xr=(double)item->cols_out/2+
+ (dj-(double)item->rows_in/(2*cos_angle))/
+ tan(angle)+2;
+
+ xinc=1./tan(angle);
+ }
+
+ /* loop through all relevent bits in rotated image */
+ for(j=0; j<item->rows_out; j++)
+ {
+ /* no point re-calculating these every pass */
+ di=(double)((xl<0)?0:(int)xl)+0.5-(double)item->cols_out/2;
+ byte_out=(item->rows_out-j-1)*byte_w_out;
+
+ /* loop through meaningful columns */
+ for(i=((xl<0)?0:(int)xl);i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++)
+ {
+ /* rotate coordinates */
+ it=(double)item->cols_in/2 + ( di*cos_angle + dj*sin_angle);
+ jt=(double)item->rows_in/2 - (-di*sin_angle + dj*cos_angle);
+
+ /* set pixel if required */
+ if(it>=0 && it<item->cols_in && jt>=0 && jt<item->rows_in)
+ if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0)
+ item->ximage->data[byte_out+i/8]|=128>>i%8;
+
+ di+=1;
+ }
+
+ dj+=1;
+ xl+=xinc;
+ xr+=xinc;
+ }
+
+ XDestroyImage(I_in);
+
+ if(style.magnify!=1.)
+ {
+ item->cols_in=old_cols_in;
+ item->rows_in=old_rows_in;
+ }
+
+
+#ifdef CACHE_BITMAPS
+
+ /* create a bitmap to hold rotated text */
+ item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy),
+ item->cols_out, item->rows_out, 1);
+
+ /* make the text bitmap from XImage */
+ XPutImage(dpy, item->bitmap, font_gc, item->ximage, 0, 0, 0, 0,
+ item->cols_out, item->rows_out);
+
+ XDestroyImage(item->ximage);
+
+#endif /*CACHE_BITMAPS*/
+
+ XFreeGC(dpy, font_gc);
+ XFreePixmap(dpy, canvas);
+
+ return item;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Adds a text item to the end of the cache, removing as many items */
+/* from the front as required to keep cache size below limit */
+/**************************************************************************/
+
+static void XRotAddToLinkedList(Display *dpy, RotatedTextItem *item)
+{
+
+ static long int current_size=0;
+ static RotatedTextItem *last=NULL;
+ RotatedTextItem *i1=first_text_item, *i2=NULL;
+
+#ifdef CACHE_BITMAPS
+
+ /* I don't know how much memory a pixmap takes in the server -
+ probably this + a bit more we can't account for */
+
+ item->size=((item->cols_out-1)/8+1)*item->rows_out;
+
+#else
+
+ /* this is pretty much the size of a RotatedTextItem */
+
+ item->size=((item->cols_out-1)/8+1)*item->rows_out +
+ sizeof(XImage) + strlen(item->text) +
+ item->nl*8*sizeof(double) + sizeof(RotatedTextItem);
+
+ if(item->font_name!=NULL)
+ item->size+=strlen(item->font_name);
+ else
+ item->size+=sizeof(Font);
+
+#endif /*CACHE_BITMAPS */
+
+#ifdef DEBUG
+ /* count number of items in cache, for debugging */
+ {
+ int i=0;
+
+ while(i1) {
+ i++;
+ i1=i1->next;
+ }
+ DEBUG_PRINT2("Cache has %d items.\n", i);
+ i1=first_text_item;
+ }
+#endif
+
+ DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%d\n",
+ current_size, item->size, CACHE_SIZE_LIMIT*1024);
+
+ /* if this item is bigger than whole cache, forget it */
+ if(item->size>CACHE_SIZE_LIMIT*1024) {
+ DEBUG_PRINT1("Too big to cache\n\n");
+ item->cached=0;
+ return;
+ }
+
+ /* remove elements from cache as needed */
+ while(i1 && current_size+item->size>CACHE_SIZE_LIMIT*1024) {
+
+ DEBUG_PRINT2("Removed %ld bytes\n", i1->size);
+
+ if(i1->font_name!=NULL)
+ DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n",
+ i1->text, i1->font_name, i1->angle, i1->align);
+
+#ifdef CACHE_FID
+ if(i1->font_name==NULL)
+ DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n",
+ i1->text, i1->fid, i1->angle, i1->align);
+#endif /*CACHE_FID*/
+
+ current_size-=i1->size;
+
+ i2=i1->next;
+
+ /* free resources used by the unlucky item */
+ XRotFreeTextItem(dpy, i1);
+
+ /* remove it from linked list */
+ first_text_item=i2;
+ i1=i2;
+ }
+
+ /* add new item to end of linked list */
+ if(first_text_item==NULL) {
+ item->next=NULL;
+ first_text_item=item;
+ last=item;
+ }
+ else {
+ item->next=NULL;
+ last->next=item;
+ last=item;
+ }
+
+ /* new cache size */
+ current_size+=item->size;
+
+ item->cached=1;
+
+ DEBUG_PRINT1("Added item to cache.\n");
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Free the resources used by a text item */
+/**************************************************************************/
+
+static void XRotFreeTextItem(Display *dpy, RotatedTextItem *item)
+{
+ free(item->text);
+
+ if(item->font_name!=NULL)
+ free(item->font_name);
+
+ free((char *)item->corners_x);
+ free((char *)item->corners_y);
+
+#ifdef CACHE_BITMAPS
+ XFreePixmap(dpy, item->bitmap);
+#else
+ XDestroyImage(item->ximage);
+#endif /* CACHE_BITMAPS */
+
+ free((char *)item);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Magnify an XImage using bilinear interpolation */
+/**************************************************************************/
+
+static XImage *XRotMagnifyImage(Display *dpy, XImage *ximage)
+{
+ int i, j;
+ double x, y;
+ double u,t;
+ XImage *I_out;
+ int cols_in, rows_in;
+ int cols_out, rows_out;
+ register int i2, j2;
+ double z1, z2, z3, z4;
+ int byte_width_in, byte_width_out;
+ double mag_inv;
+
+ /* size of input image */
+ cols_in=ximage->width;
+ rows_in=ximage->height;
+
+ /* size of final image */
+ cols_out=(double)cols_in*style.magnify;
+ rows_out=(double)rows_in*style.magnify;
+
+ /* this will hold final image */
+ I_out=MakeXImage(dpy, cols_out, rows_out);
+ if(I_out==NULL)
+ return NULL;
+
+ /* width in bytes of input, output images */
+ byte_width_in=(cols_in-1)/8+1;
+ byte_width_out=(cols_out-1)/8+1;
+
+ /* for speed */
+ mag_inv=1./style.magnify;
+
+ y=0.;
+
+ /* loop over magnified image */
+ for(j2=0; j2<rows_out; j2++)
+ {
+ x=0;
+ j=y;
+
+ for(i2=0; i2<cols_out; i2++)
+ {
+ i=x;
+
+ /* bilinear interpolation - where are we on bitmap ? */
+ /* right edge */
+ if(i==cols_in-1 && j!=rows_in-1)
+ {
+ t=0;
+ u=y-(double)j;
+
+ z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
+ z2=z1;
+ z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
+ z4=z3;
+ }
+ /* top edge */
+ else if(i!=cols_in-1 && j==rows_in-1)
+ {
+ t=x-(double)i;
+ u=0;
+
+ z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
+ z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
+ z3=z2;
+ z4=z1;
+ }
+ /* top right corner */
+ else if(i==cols_in-1 && j==rows_in-1)
+ {
+ u=0;
+ t=0;
+
+ z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
+ z2=z1;
+ z3=z1;
+ z4=z1;
+ }
+ /* somewhere `safe' */
+ else
+ {
+ t=x-(double)i;
+ u=y-(double)j;
+
+ z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0;
+ z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0;
+ z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] &
+ 128>>((i+1)%8))>0;
+ z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0;
+ }
+
+ /* if interpolated value is greater than 0.5, set bit */
+ if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5)
+ I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8;
+
+ x+=mag_inv;
+ }
+ y+=mag_inv;
+ }
+
+ /* destroy original */
+ XDestroyImage(ximage);
+
+ /* return big image */
+ return I_out;
+}
+
+
+
+
+/**************************************************************************/
+/* Return version/copyright information */
+/**************************************************************************/
+
+double XRotVersion(char* str, int n)
+{
+ if(str!=NULL)
+ strncpy(str, XV_COPYRIGHT, n);
+ return XV_VERSION;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Set the font magnification factor for all subsequent operations */
+/**************************************************************************/
+
+void XRotSetMagnification(double m)
+{
+ if(m>0.)
+ style.magnify=m;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Set the padding used when calculating bounding boxes */
+/**************************************************************************/
+
+void XRotSetBoundingBoxPad(int p)
+{
+ if(p>=0)
+ style.bbx_pad=p;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/**************************************************************************/
+/* Calculate the bounding box some text will have when painted */
+/**************************************************************************/
+
+XPoint *XRotTextExtents(Display* dpy, XFontStruct* font, double angle, int x, int y, const char* text, int align)
+{
+ register int i;
+ char *str1, *str2, *str3;
+ char *str2_a="\0", *str2_b="\n\0";
+ int height;
+ double sin_angle, cos_angle;
+ int nl, max_width;
+ int cols_in, rows_in;
+ double hot_x, hot_y;
+ XPoint *xp_in, *xp_out;
+ int dir, asc, desc;
+ XCharStruct overall;
+
+ /* manipulate angle to 0<=angle<360 degrees */
+ while(angle<0)
+ angle+=360;
+
+ while(angle>360)
+ angle-=360;
+
+ angle*=M_PI/180;
+
+ /* count number of sections in string */
+ nl=1;
+ if(align!=XR_LEFT)
+ for(i=0; i<strlen(text)-1; i++)
+ if(text[i]=='\n')
+ nl++;
+
+ /* ignore newline characters if not doing alignment */
+ if(align==XR_LEFT)
+ str2=str2_a;
+ else
+ str2=str2_b;
+
+ /* find width of longest section */
+ str1=my_strdup(text);
+ if(str1==NULL)
+ return NULL;
+
+ str3=my_strtok(str1, str2);
+
+ XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
+ &overall);
+
+ max_width=overall.rbearing;
+
+ /* loop through each section */
+ do
+ {
+ str3=my_strtok((char *)NULL, str2);
+
+ if(str3!=NULL)
+ {
+ XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc,
+ &overall);
+
+ if(overall.rbearing>max_width)
+ max_width=overall.rbearing;
+ }
+ } while(str3!=NULL);
+
+ free(str1);
+
+ /* overall font height */
+ height=font->ascent+font->descent;
+
+ /* dimensions horizontal text will have */
+ cols_in=max_width;
+ rows_in=nl*height;
+
+ /* pre-calculate sin and cos */
+ sin_angle=sin(angle);
+ cos_angle=cos(angle);
+
+ /* y position */
+ if(align==XR_TLEFT || align==XR_TCENTRE || align==XR_TRIGHT)
+ hot_y=(double)rows_in/2*style.magnify;
+ else if(align==XR_MLEFT || align==XR_MCENTRE || align==XR_MRIGHT)
+ hot_y=0;
+ else if(align==XR_BLEFT || align==XR_BCENTRE || align==XR_BRIGHT)
+ hot_y=-(double)rows_in/2*style.magnify;
+ else
+ hot_y=-((double)rows_in/2-(double)font->descent)*style.magnify;
+
+ /* x position */
+ if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT)
+ hot_x=-(double)max_width/2*style.magnify;
+ else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE)
+ hot_x=0;
+ else
+ hot_x=(double)max_width/2*style.magnify;
+
+ /* reserve space for XPoints */
+ xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
+ if(!xp_in)
+ return NULL;
+
+ xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint)));
+ if(!xp_out)
+ return NULL;
+
+ /* bounding box when horizontal, relative to bitmap centre */
+ xp_in[0].x=-(double)cols_in*style.magnify/2-style.bbx_pad;
+ xp_in[0].y= (double)rows_in*style.magnify/2+style.bbx_pad;
+ xp_in[1].x= (double)cols_in*style.magnify/2+style.bbx_pad;
+ xp_in[1].y= (double)rows_in*style.magnify/2+style.bbx_pad;
+ xp_in[2].x= (double)cols_in*style.magnify/2+style.bbx_pad;
+ xp_in[2].y=-(double)rows_in*style.magnify/2-style.bbx_pad;
+ xp_in[3].x=-(double)cols_in*style.magnify/2-style.bbx_pad;
+ xp_in[3].y=-(double)rows_in*style.magnify/2-style.bbx_pad;
+ xp_in[4].x=xp_in[0].x;
+ xp_in[4].y=xp_in[0].y;
+
+ /* rotate and translate bounding box */
+ for(i=0; i<5; i++)
+ {
+ xp_out[i].x=(double)x + ( ((double)xp_in[i].x-hot_x)*cos_angle +
+ ((double)xp_in[i].y+hot_y)*sin_angle);
+
+ xp_out[i].y=(double)y + (-((double)xp_in[i].x-hot_x)*sin_angle +
+ ((double)xp_in[i].y+hot_y)*cos_angle);
+ }
+
+ free((char *)xp_in);
+
+ return xp_out;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**************************************************************************/
+/* Aligns and paints a rotated string */
+/**************************************************************************/
+
+int XRotDrawString(Display* dpy, XFontStruct* font, double angle, Drawable drawable, GC gc, int x, int y, const char* text, int align, int bg)
+{
+ int i;
+ GC my_gc;
+ int xp, yp;
+ double hot_x, hot_y;
+ double hot_xp, hot_yp;
+ double sin_angle, cos_angle;
+ RotatedTextItem *item;
+ Pixmap bitmap_to_paint;
+
+ /* return early for NULL/empty strings */
+ if(text==NULL)
+ return 0;
+
+ if(strlen(text)==0)
+ return 0;
+
+ /* manipulate angle to 0<=angle<360 degrees */
+ while(angle<0)
+ angle+=360;
+
+ while(angle>=360)
+ angle-=360;
+
+ angle*=M_PI/180;
+
+ /* horizontal text made easy */
+ if(angle==0. && style.magnify==1.)
+ return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y, text, align, bg));
+
+ /* get a rotated bitmap */
+ item=XRotRetrieveFromCache(dpy, font, angle, text, align);
+ if(item==NULL)
+ return 0;
+
+ /* this gc has similar properties to the user's gc */
+ my_gc=XCreateGC(dpy, drawable, 0, 0);
+ XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask, my_gc);
+
+ /* alignment : which point (hot_x, hot_y) relative to bitmap centre
+ coincides with user's specified point? */
+
+ /* y position */
+ if(align==XR_TLEFT || align==XR_TCENTRE || align==XR_TRIGHT)
+ hot_y=(double)item->rows_in/2*style.magnify;
+ else if(align==XR_MLEFT || align==XR_MCENTRE || align==XR_MRIGHT)
+ hot_y=0;
+ else if(align==XR_BLEFT || align==XR_BCENTRE || align==XR_BRIGHT)
+ hot_y=-(double)item->rows_in/2*style.magnify;
+ else
+ hot_y=-((double)item->rows_in/2-(double)font->descent)*style.magnify;
+
+ /* x position */
+ if(align==XR_TLEFT || align==XR_MLEFT || align==XR_BLEFT || align==XR_LEFT)
+ hot_x=-(double)item->max_width/2*style.magnify;
+ else if(align==XR_TCENTRE || align==XR_MCENTRE || align==XR_BCENTRE || align==XR_CENTRE)
+ hot_x=0;
+ else
+ hot_x=(double)item->max_width/2*style.magnify;
+
+ /* pre-calculate sin and cos */
+ sin_angle=sin(angle);
+ cos_angle=cos(angle);
+
+ /* rotate hot_x and hot_y around bitmap centre */
+ hot_xp= hot_x*cos_angle - hot_y*sin_angle;
+ hot_yp= hot_x*sin_angle + hot_y*cos_angle;
+
+ /* text background will be drawn using XFillPolygon */
+ if(bg)
+ {
+ GC depth_one_gc;
+ XPoint *xpoints;
+ Pixmap empty_stipple;
+
+ /* reserve space for XPoints */
+ xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint)));
+ if(!xpoints)
+ return 1;
+
+ /* rotate corner positions */
+ for(i=0; i<4*item->nl; i++)
+ {
+ xpoints[i].x=(double)x + ( (item->corners_x[i]-hot_x)*cos_angle +
+ (item->corners_y[i]+hot_y)*sin_angle);
+
+ xpoints[i].y=(double)y + (-(item->corners_x[i]-hot_x)*sin_angle +
+ (item->corners_y[i]+hot_y)*cos_angle);
+ }
+
+ /* we want to swap foreground and background colors here;
+ XGetGCValues() is only available in R4+ */
+
+ empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1);
+
+ depth_one_gc=XCreateGC(dpy, empty_stipple, 0, 0);
+ XSetForeground(dpy, depth_one_gc, 0);
+ XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2);
+
+ XSetStipple(dpy, my_gc, empty_stipple);
+ XSetFillStyle(dpy, my_gc, FillOpaqueStippled);
+
+ XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex,
+ CoordModeOrigin);
+
+ /* free our resources */
+ free((char *)xpoints);
+ XFreeGC(dpy, depth_one_gc);
+ XFreePixmap(dpy, empty_stipple);
+ }
+
+ /* where should top left corner of bitmap go ? */
+ xp=(double)x-((double)item->cols_out/2 +hot_xp);
+ yp=(double)y-((double)item->rows_out/2 -hot_yp);
+
+ /* by default we draw the rotated bitmap, solid */
+ bitmap_to_paint=item->bitmap;
+
+ /* handle user stippling */
+#ifndef X11R3
+ {
+ GC depth_one_gc;
+ XGCValues values;
+ Pixmap new_bitmap, inverse;
+
+ /* try and get some GC properties */
+ if(XGetGCValues(dpy, gc,
+ GCStipple|GCFillStyle|GCForeground|GCBackground|
+ GCTileStipXOrigin|GCTileStipYOrigin,
+ &values))
+ {
+ /* only do this if stippling requested */
+ if((values.fill_style==FillStippled ||
+ values.fill_style==FillOpaqueStippled) && !bg)
+ {
+ /* opaque stipple: draw rotated text in background colour */
+ if(values.fill_style==FillOpaqueStippled)
+ {
+ XSetForeground(dpy, my_gc, values.background);
+ XSetFillStyle(dpy, my_gc, FillStippled);
+ XSetStipple(dpy, my_gc, item->bitmap);
+ XSetTSOrigin(dpy, my_gc, xp, yp);
+ XFillRectangle(dpy, drawable, my_gc, xp, yp,
+ item->cols_out, item->rows_out);
+ XSetForeground(dpy, my_gc, values.foreground);
+ }
+
+ /* this will merge the rotated text and the user's stipple */
+ new_bitmap=XCreatePixmap(dpy, drawable,
+ item->cols_out, item->rows_out, 1);
+
+ /* create a GC */
+ depth_one_gc=XCreateGC(dpy, new_bitmap, 0, 0);
+ XSetForeground(dpy, depth_one_gc, 1);
+ XSetBackground(dpy, depth_one_gc, 0);
+
+ /* set the relative stipple origin */
+ XSetTSOrigin(dpy, depth_one_gc,
+ values.ts_x_origin-xp, values.ts_y_origin-yp);
+
+ /* fill the whole bitmap with the user's stipple */
+ XSetStipple(dpy, depth_one_gc, values.stipple);
+ XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled);
+ XFillRectangle(dpy, new_bitmap, depth_one_gc,
+ 0, 0, item->cols_out, item->rows_out);
+
+ /* set stipple origin back to normal */
+ XSetTSOrigin(dpy, depth_one_gc, 0, 0);
+
+ /* this will contain an inverse copy of the rotated text */
+ inverse=XCreatePixmap(dpy, drawable,
+ item->cols_out, item->rows_out, 1);
+
+ /* invert text */
+ XSetFillStyle(dpy, depth_one_gc, FillSolid);
+ XSetFunction(dpy, depth_one_gc, GXcopyInverted);
+ XCopyArea(dpy, item->bitmap, inverse, depth_one_gc,
+ 0, 0, item->cols_out, item->rows_out, 0, 0);
+
+ /* now delete user's stipple everywhere EXCEPT on text */
+ XSetForeground(dpy, depth_one_gc, 0);
+ XSetBackground(dpy, depth_one_gc, 1);
+ XSetStipple(dpy, depth_one_gc, inverse);
+ XSetFillStyle(dpy, depth_one_gc, FillStippled);
+ XSetFunction(dpy, depth_one_gc, GXcopy);
+ XFillRectangle(dpy, new_bitmap, depth_one_gc,
+ 0, 0, item->cols_out, item->rows_out);
+
+ /* free resources */
+ XFreePixmap(dpy, inverse);
+ XFreeGC(dpy, depth_one_gc);
+
+ /* this is the new bitmap */
+ bitmap_to_paint=new_bitmap;
+ }
+ }
+ }
+#endif /*X11R3*/
+
+ /* paint text using stipple technique */
+ XSetFillStyle(dpy, my_gc, FillStippled);
+ XSetStipple(dpy, my_gc, bitmap_to_paint);
+ XSetTSOrigin(dpy, my_gc, xp, yp);
+ XFillRectangle(dpy, drawable, my_gc, xp, yp,
+ item->cols_out, item->rows_out);
+
+ /* free our resources */
+ XFreeGC(dpy, my_gc);
+
+ /* stippled bitmap no longer needed */
+ if(bitmap_to_paint!=item->bitmap)
+ XFreePixmap(dpy, bitmap_to_paint);
+
+#ifdef CACHE_XIMAGES
+ XFreePixmap(dpy, item->bitmap);
+#endif /*CACHE_XIMAGES*/
+
+ /* if item isn't cached, destroy it completely */
+ if(!item->cached)
+ XRotFreeTextItem(dpy,item);
+
+ /* we got to the end OK! */
+ return 0;
+}
+
+
diff --git a/src/x11/xvertex.h b/src/x11/xvertex.h
new file mode 100644
index 0000000..b1b4e3a
--- /dev/null
+++ b/src/x11/xvertex.h
@@ -0,0 +1,31 @@
+/* ************************************************************************ */
+/* Header file for the `xvertext 5.0' routines.
+
+ Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */
+/* ************************************************************************ */
+
+#ifndef __XVERTEXT_H
+#define __XVERTEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XV_VERSION 5.0
+#define XV_COPYRIGHT \
+ "xvertext routines Copyright (c) 1993 Alan Richardson"
+
+/* text alignment */
+enum {XR_LEFT, XR_CENTRE, XR_RIGHT, XR_TLEFT, XR_TCENTRE, XR_TRIGHT, XR_MLEFT, XR_MCENTRE, XR_MRIGHT, XR_BLEFT, XR_BCENTRE, XR_BRIGHT};
+
+double XRotVersion(char* str, int n);
+void XRotSetMagnification(double m);
+void XRotSetBoundingBoxPad(int p);
+XPoint *XRotTextExtents(Display* dpy, XFontStruct* font, double angle, int x, int y, const char* text, int align);
+int XRotDrawString(Display* dpy, XFontStruct* font, double angle, Drawable drawable, GC gc, int x, int y, const char* text, int align, int bg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XVERTEXT_INCLUDED_ */