diff options
author | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
---|---|---|
committer | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
commit | 7b52cc13af4e85f1ca2deb6b6c77de9c95ea0dcf (patch) | |
tree | d0857278bde2eff784227c57dcaf930346ceb7ac /src/x11 |
First commit - moving from LuaForge to SourceForge
Diffstat (limited to 'src/x11')
-rw-r--r-- | src/x11/cdx11.c | 2447 | ||||
-rw-r--r-- | src/x11/cdx11.h | 85 | ||||
-rw-r--r-- | src/x11/cdxclp.c | 136 | ||||
-rw-r--r-- | src/x11/cdxdbuf.c | 156 | ||||
-rw-r--r-- | src/x11/cdximg.c | 52 | ||||
-rw-r--r-- | src/x11/cdxnative.c | 165 | ||||
-rw-r--r-- | src/x11/xvertex.c | 1440 | ||||
-rw-r--r-- | src/x11/xvertex.h | 31 |
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_ */ |