forked from old/legacy-imlib2
605 lines
18 KiB
C
605 lines
18 KiB
C
#include "common.h"
|
|
#ifdef BUILD_X11
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/extensions/XShm.h>
|
|
#include "colormod.h"
|
|
#include "image.h"
|
|
#include "scale.h"
|
|
#include "ximage.h"
|
|
#include "context.h"
|
|
#include "rgba.h"
|
|
#include "color.h"
|
|
#include "grab.h"
|
|
#include "blend.h"
|
|
#include "rend.h"
|
|
#include "rotate.h"
|
|
|
|
/* The maximum pixmap dimension is 65535. */
|
|
/* However, for now, use 46340 (46340^2 < 2^31) to avoid buffer overflow issues. */
|
|
#define X_MAX_DIM 46340
|
|
|
|
/* size of the lines per segment we scale / render at a time */
|
|
#define LINESIZE 16
|
|
|
|
DATA32
|
|
__imlib_RenderGetPixel(Display * d, Drawable w, Visual * v, Colormap cm,
|
|
int depth, DATA8 r, DATA8 g, DATA8 b)
|
|
{
|
|
Context *ct;
|
|
|
|
ct = __imlib_GetContext(d, v, cm, depth);
|
|
|
|
if (ct->palette)
|
|
{
|
|
switch (ct->palette_type)
|
|
{
|
|
case 0: /* 332 */
|
|
return ct->palette[((r >> 0) & 0xe0) |
|
|
((g >> 3) & 0x1b) | ((b >> 6) & 0x02)];
|
|
break;
|
|
case 1: /* 232 */
|
|
return ct->palette[((r >> 0) & 0xe0) |
|
|
((g >> 3) & 0x1b) | ((b >> 6) & 0x02)];
|
|
break;
|
|
case 2: /* 222 */
|
|
return ct->palette[((r >> 0) & 0xe0) |
|
|
((g >> 3) & 0x1b) | ((b >> 6) & 0x02)];
|
|
break;
|
|
case 3: /* 221 */
|
|
return ct->palette[((r >> 0) & 0xe0) |
|
|
((g >> 3) & 0x1b) | ((b >> 6) & 0x02)];
|
|
break;
|
|
case 4: /* 121 */
|
|
return ct->palette[((r >> 0) & 0xe0) |
|
|
((g >> 3) & 0x1b) | ((b >> 6) & 0x02)];
|
|
break;
|
|
case 5: /* 111 */
|
|
return ct->palette[((r >> 0) & 0xe0) |
|
|
((g >> 3) & 0x1b) | ((b >> 6) & 0x02)];
|
|
break;
|
|
case 6: /* 1 */
|
|
return ct->palette[((r >> 0) & 0xe0) |
|
|
((g >> 3) & 0x1b) | ((b >> 6) & 0x02)];
|
|
break;
|
|
case 7: /* 666 */
|
|
return ct->palette[((int)(((double)r / 255) * 5.0) * 36) +
|
|
((int)(((double)g / 255) * 5.0) * 6) +
|
|
((int)(((double)b / 255) * 5.0))];
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned int rm, gm, bm;
|
|
int i, rshift = 0, gshift = 0, bshift = 0;
|
|
DATA32 val;
|
|
|
|
rm = v->red_mask;
|
|
gm = v->green_mask;
|
|
bm = v->blue_mask;
|
|
if ((rm == 0xf800) && (gm == 0x7e0) && (bm == 0x1f)) /* 565 */
|
|
{
|
|
return (((r << 8) & 0xf800) |
|
|
((g << 3) & 0x07e0) | ((b >> 3) & 0x001f));
|
|
}
|
|
if ((rm == 0xff0000) && (gm == 0xff00) && (bm == 0xff)) /* 888 */
|
|
{
|
|
return (((r << 16) & 0xff0000) |
|
|
((g << 8) & 0x00ff00) | ((r) & 0x0000ff));
|
|
}
|
|
if ((rm == 0x7c00) && (gm == 0x3e0) && (bm == 0x1f)) /* 555 */
|
|
{
|
|
return (((r << 7) & 0x7c00) |
|
|
((g << 2) & 0x03e0) | ((b >> 3) & 0x001f));
|
|
}
|
|
for (i = 31; i >= 0; i--)
|
|
{
|
|
if (rm >= (1 << i))
|
|
{
|
|
rshift = i - 7;
|
|
break;
|
|
}
|
|
}
|
|
for (i = 31; i >= 0; i--)
|
|
{
|
|
if (gm >= (1 << i))
|
|
{
|
|
gshift = i - 7;
|
|
break;
|
|
}
|
|
}
|
|
for (i = 31; i >= 0; i--)
|
|
{
|
|
if (bm >= (1 << i))
|
|
{
|
|
bshift = i - 7;
|
|
break;
|
|
}
|
|
}
|
|
if (rshift >= 0)
|
|
val = ((r << rshift) & rm);
|
|
else
|
|
val = ((r >> (-rshift)) & rm);
|
|
if (gshift >= 0)
|
|
val |= ((g << gshift) & gm);
|
|
else
|
|
val |= ((g >> (-gshift)) & gm);
|
|
if (bshift >= 0)
|
|
val |= ((b << bshift) & bm);
|
|
else
|
|
val |= ((b >> (-bshift)) & bm);
|
|
return val;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
__hidden void
|
|
__imlib_generic_render(DATA32 * src, int jump, int w, int h, int dx, int dy,
|
|
XImage * xim, Visual * v,
|
|
Context * ct);
|
|
|
|
void
|
|
__imlib_generic_render(DATA32 * src, int jump, int w, int h, int dx, int dy,
|
|
XImage * xim, Visual * v, Context * ct)
|
|
{
|
|
unsigned int x, y, r, g, b, val, hh;
|
|
unsigned int rmask, gmask, bmask;
|
|
int i, rshift, gshift, bshift;
|
|
const DATA8 _dither_88[8][8] = {
|
|
{0, 32, 8, 40, 2, 34, 10, 42},
|
|
{48, 16, 56, 24, 50, 18, 58, 26},
|
|
{12, 44, 4, 36, 14, 46, 6, 38},
|
|
{60, 28, 52, 20, 62, 30, 54, 22},
|
|
{3, 35, 11, 43, 1, 33, 9, 41},
|
|
{51, 19, 59, 27, 49, 17, 57, 25},
|
|
{15, 47, 7, 39, 13, 45, 5, 37},
|
|
{63, 31, 55, 23, 61, 29, 53, 21}
|
|
};
|
|
|
|
if (xim->depth == 1)
|
|
{
|
|
hh = dy + h;
|
|
for (y = dy; y < hh; y++)
|
|
{
|
|
for (x = dx; x < w; x++)
|
|
{
|
|
r = R_VAL(src);
|
|
g = G_VAL(src);
|
|
b = B_VAL(src);
|
|
val = (R_VAL(src) + G_VAL(src) + B_VAL(src)) / 12;
|
|
if (val > _dither_88[x & 0x3][y & 0x3])
|
|
val = ct->palette[1];
|
|
else
|
|
val = ct->palette[0];
|
|
XPutPixel(xim, x, y, val);
|
|
src++;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
rmask = xim->red_mask;
|
|
gmask = xim->green_mask;
|
|
bmask = xim->blue_mask;
|
|
rshift = 0;
|
|
gshift = 0;
|
|
bshift = 0;
|
|
for (i = 31; i >= 0; i--)
|
|
{
|
|
if (rmask >= (1 << i))
|
|
{
|
|
rshift = i - 7;
|
|
break;
|
|
}
|
|
}
|
|
for (i = 31; i >= 0; i--)
|
|
{
|
|
if (gmask >= (1 << i))
|
|
{
|
|
gshift = i - 7;
|
|
break;
|
|
}
|
|
}
|
|
for (i = 31; i >= 0; i--)
|
|
{
|
|
if (bmask >= (1 << i))
|
|
{
|
|
bshift = i - 7;
|
|
break;
|
|
}
|
|
}
|
|
hh = dy + h;
|
|
for (y = dy; y < hh; y++)
|
|
{
|
|
for (x = dx; x < w; x++)
|
|
{
|
|
r = R_VAL(src);
|
|
if (rshift >= 0)
|
|
val = ((r << rshift) & rmask);
|
|
else
|
|
val = ((r >> (-rshift)) & rmask);
|
|
g = G_VAL(src);
|
|
if (gshift >= 0)
|
|
val |= ((g << gshift) & gmask);
|
|
else
|
|
val |= ((g >> (-gshift)) & gmask);
|
|
b = B_VAL(src);
|
|
if (bshift >= 0)
|
|
val |= ((b << bshift) & bmask);
|
|
else
|
|
val |= ((b >> (-bshift)) & bmask);
|
|
XPutPixel(xim, x, y, val);
|
|
src++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Display *disp = NULL;
|
|
static GC gc = NULL;
|
|
static GC gcm = NULL;
|
|
static int last_depth = 0;
|
|
|
|
void
|
|
__imlib_RenderDisconnect(Display * d)
|
|
{
|
|
if (d != disp)
|
|
return;
|
|
disp = NULL;
|
|
gc = gcm = NULL;
|
|
last_depth = 0;
|
|
}
|
|
|
|
void
|
|
__imlib_RenderImage(Display * d, ImlibImage * im,
|
|
Drawable w, Drawable m,
|
|
Visual * v, Colormap cm, int depth,
|
|
int sx, int sy, int sw, int sh,
|
|
int dx, int dy, int dw, int dh,
|
|
char antialias, char hiq, char blend, char dither_mask,
|
|
int mat, ImlibColorModifier * cmod, ImlibOp op)
|
|
{
|
|
XImage *xim = NULL, *mxim = NULL;
|
|
Context *ct;
|
|
DATA32 *buf = NULL, *pointer = NULL, *back = NULL;
|
|
int y, h, hh, jump;
|
|
XGCValues gcv;
|
|
ImlibScaleInfo *scaleinfo = NULL;
|
|
int psx, psy, psw, psh;
|
|
char shm = 0;
|
|
ImlibRGBAFunction rgbaer;
|
|
ImlibMaskFunction masker = NULL;
|
|
ImlibBlendFunction blender = NULL;
|
|
int do_mmx;
|
|
|
|
blender = __imlib_GetBlendFunction(op, 1, 0,
|
|
(!(im->flags & F_HAS_ALPHA)), NULL);
|
|
|
|
/* dont do anything if we have a 0 widht or height image to render */
|
|
if ((dw == 0) || (dh == 0))
|
|
return;
|
|
/* if the input rect size < 0 dont render either */
|
|
if ((sw <= 0) || (sh <= 0))
|
|
return;
|
|
/* if the output is too big (8k arbitrary limit here) dont bother */
|
|
if ((abs(dw) > X_MAX_DIM) || (abs(dh) > X_MAX_DIM))
|
|
return;
|
|
/* clip the source rect to be within the actual image */
|
|
psx = sx;
|
|
psy = sy;
|
|
psw = sw;
|
|
psh = sh;
|
|
CLIP(sx, sy, sw, sh, 0, 0, im->w, im->h);
|
|
/* clip output coords to clipped input coords */
|
|
if (psx != sx)
|
|
dx = (dx * sx) / psx;
|
|
if (psy != sy)
|
|
dy = (dy * sy) / psy;
|
|
if (psw != sw)
|
|
dw = (dw * sw) / psw;
|
|
if (psh != sh)
|
|
dh = (dh * sh) / psh;
|
|
/* do a second check to see if we now have invalid coords */
|
|
/* dont do anything if we have a 0 widht or height image to render */
|
|
if ((dw == 0) || (dh == 0))
|
|
return;
|
|
/* if the input rect size < 0 dont render either */
|
|
if ((sw <= 0) || (sh <= 0))
|
|
return;
|
|
/* if the output is too big (8k arbitrary limit here) dont bother */
|
|
if ((abs(dw) > X_MAX_DIM) || (abs(dh) > X_MAX_DIM))
|
|
return;
|
|
/* if we are scaling the image at all make a scaling buffer */
|
|
if (!((sw == dw) && (sh == dh)))
|
|
{
|
|
scaleinfo = __imlib_CalcScaleInfo(im, sw, sh, dw, dh, antialias);
|
|
if (!scaleinfo)
|
|
return;
|
|
}
|
|
/* Sign not needed anymore */
|
|
dw = abs(dw);
|
|
dh = abs(dh);
|
|
ct = __imlib_GetContext(d, v, cm, depth);
|
|
__imlib_RGBASetupContext(ct);
|
|
if ((blend) && (IMAGE_HAS_ALPHA(im)))
|
|
{
|
|
back = malloc(dw * dh * sizeof(DATA32));
|
|
if (!__imlib_GrabDrawableToRGBA
|
|
(back, 0, 0, dw, dh, d, w, 0, v, cm, depth, dx, dy, dw, dh, 0, 1))
|
|
{
|
|
free(back);
|
|
back = NULL;
|
|
}
|
|
}
|
|
/* get a new XImage - or get one from the cached list */
|
|
xim = __imlib_ProduceXImage(d, v, depth, dw, dh, &shm);
|
|
if (!xim)
|
|
{
|
|
__imlib_FreeScaleInfo(scaleinfo);
|
|
if (back)
|
|
free(back);
|
|
return;
|
|
}
|
|
if (m)
|
|
{
|
|
mxim = __imlib_ProduceXImage(d, v, 1, dw, dh, &shm);
|
|
if (!mxim)
|
|
{
|
|
__imlib_ConsumeXImage(d, xim);
|
|
__imlib_FreeScaleInfo(scaleinfo);
|
|
if (back)
|
|
free(back);
|
|
return;
|
|
}
|
|
memset(mxim->data, 0, mxim->bytes_per_line * mxim->height);
|
|
}
|
|
/* if we are scaling the image at all make a scaling buffer */
|
|
if (scaleinfo)
|
|
{
|
|
/* allocate a buffer to render scaled RGBA data into */
|
|
buf = malloc(dw * LINESIZE * sizeof(DATA32));
|
|
if (!buf)
|
|
{
|
|
__imlib_ConsumeXImage(d, xim);
|
|
if (m)
|
|
__imlib_ConsumeXImage(d, mxim);
|
|
__imlib_FreeScaleInfo(scaleinfo);
|
|
if (back)
|
|
free(back);
|
|
return;
|
|
}
|
|
}
|
|
/* setup h */
|
|
h = dh;
|
|
/* scale in LINESIZE Y chunks and convert to depth */
|
|
/* Get rgba and mask functions for XImage rendering */
|
|
rgbaer = __imlib_GetRGBAFunction(xim->bits_per_pixel,
|
|
v->red_mask, v->green_mask, v->blue_mask,
|
|
hiq, ct->palette_type);
|
|
if (m)
|
|
masker = __imlib_GetMaskFunction(dither_mask);
|
|
#ifdef DO_MMX_ASM
|
|
do_mmx = __imlib_get_cpuid() & CPUID_MMX;
|
|
#endif
|
|
for (y = 0; y < dh; y += LINESIZE)
|
|
{
|
|
hh = LINESIZE;
|
|
if (h < LINESIZE)
|
|
hh = h;
|
|
/* if we're scaling it */
|
|
if (scaleinfo)
|
|
{
|
|
/* scale the imagedata for this LINESIZE lines chunk of image data */
|
|
if (antialias)
|
|
{
|
|
#ifdef DO_MMX_ASM
|
|
if (do_mmx)
|
|
__imlib_Scale_mmx_AARGBA(scaleinfo, buf,
|
|
((sx * dw) / sw),
|
|
((sy * dh) / sh) + y,
|
|
0, 0, dw, hh, dw, im->w);
|
|
else
|
|
#endif
|
|
if (IMAGE_HAS_ALPHA(im))
|
|
__imlib_ScaleAARGBA(scaleinfo, buf, ((sx * dw) / sw),
|
|
((sy * dh) / sh) + y,
|
|
0, 0, dw, hh, dw, im->w);
|
|
else
|
|
__imlib_ScaleAARGB(scaleinfo, buf, ((sx * dw) / sw),
|
|
((sy * dh) / sh) + y,
|
|
0, 0, dw, hh, dw, im->w);
|
|
}
|
|
else
|
|
__imlib_ScaleSampleRGBA(scaleinfo, buf, ((sx * dw) / sw),
|
|
((sy * dh) / sh) + y, 0, 0, dw, hh, dw);
|
|
jump = 0;
|
|
pointer = buf;
|
|
if (cmod)
|
|
__imlib_DataCmodApply(buf, dw, hh, 0, NULL, cmod);
|
|
}
|
|
else
|
|
{
|
|
if (cmod)
|
|
{
|
|
if (!buf)
|
|
buf = malloc(im->w * LINESIZE * sizeof(DATA32));
|
|
if (!buf)
|
|
{
|
|
__imlib_ConsumeXImage(d, xim);
|
|
if (m)
|
|
__imlib_ConsumeXImage(d, mxim);
|
|
__imlib_FreeScaleInfo(scaleinfo);
|
|
if (back)
|
|
free(back);
|
|
return;
|
|
}
|
|
memcpy(buf, im->data + ((y + sy) * im->w),
|
|
im->w * hh * sizeof(DATA32));
|
|
__imlib_DataCmodApply(buf, im->w, hh, 0, NULL, cmod);
|
|
pointer = buf + sx;
|
|
jump = im->w - sw;
|
|
}
|
|
else
|
|
{
|
|
jump = im->w - sw;
|
|
pointer = im->data + ((y + sy) * im->w) + sx;
|
|
}
|
|
}
|
|
/* if we have a back buffer - we're blending to the bg */
|
|
if (back)
|
|
{
|
|
blender(pointer, jump + dw, back + (y * dw), dw, dw, hh, NULL);
|
|
pointer = back + (y * dw);
|
|
jump = 0;
|
|
}
|
|
/* once scaled... convert chunk to bit depth into XImage bufer */
|
|
if (rgbaer)
|
|
rgbaer(pointer, jump,
|
|
((DATA8 *) xim->data) + (y * (xim->bytes_per_line)),
|
|
xim->bytes_per_line, dw, hh, dx, dy + y);
|
|
else
|
|
__imlib_generic_render(pointer, jump, dw, hh, 0, y, xim, v, ct);
|
|
if (m)
|
|
masker(pointer, jump,
|
|
((DATA8 *) mxim->data) + (y * (mxim->bytes_per_line)),
|
|
mxim->bytes_per_line, dw, hh, dx, dy + y, mat);
|
|
h -= LINESIZE;
|
|
}
|
|
/* free up our buffers and poit tables */
|
|
if (buf)
|
|
free(buf);
|
|
if (scaleinfo)
|
|
__imlib_FreeScaleInfo(scaleinfo);
|
|
if (back)
|
|
free(back);
|
|
/* if we changed diplays or depth since last time... free old gc */
|
|
if ((gc) && ((last_depth != depth) || (disp != d)))
|
|
{
|
|
XFreeGC(disp, gc);
|
|
gc = 0;
|
|
}
|
|
/* if we didn't have a gc... create it */
|
|
if (!gc)
|
|
{
|
|
disp = d;
|
|
last_depth = depth;
|
|
gcv.graphics_exposures = False;
|
|
gc = XCreateGC(d, w, GCGraphicsExposures, &gcv);
|
|
}
|
|
if (m)
|
|
{
|
|
/* if we changed diplays since last time... free old gc */
|
|
if ((gcm) && (disp != d))
|
|
{
|
|
XFreeGC(disp, gcm);
|
|
gcm = 0;
|
|
}
|
|
if (!gcm)
|
|
{
|
|
gcv.graphics_exposures = False;
|
|
gcm = XCreateGC(d, m, GCGraphicsExposures, &gcv);
|
|
}
|
|
/* write the mask */
|
|
if (shm)
|
|
/* write shm XImage */
|
|
XShmPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh, False);
|
|
/* write regular XImage */
|
|
else
|
|
XPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh);
|
|
}
|
|
/* write the image */
|
|
if (shm)
|
|
/* write shm XImage */
|
|
XShmPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh, False);
|
|
/* write regular XImage */
|
|
else
|
|
XPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh);
|
|
/* free the XImage and put onto our free list */
|
|
/* wait for the write to be done */
|
|
if (shm)
|
|
XSync(d, False);
|
|
__imlib_ConsumeXImage(d, xim);
|
|
if (m)
|
|
__imlib_ConsumeXImage(d, mxim);
|
|
}
|
|
|
|
void
|
|
__imlib_RenderImageSkewed(Display * d, ImlibImage * im, Drawable w, Drawable m,
|
|
Visual * v, Colormap cm, int depth,
|
|
int sx, int sy, int sw, int sh, int dx, int dy,
|
|
int hsx, int hsy, int vsx, int vsy,
|
|
char antialias, char hiq, char blend,
|
|
char dither_mask, int mat, ImlibColorModifier * cmod,
|
|
ImlibOp op)
|
|
{
|
|
Context *ct;
|
|
int dx1, dy1, dx2, dy2, dw, dh, tsx, tsy;
|
|
ImlibImage *back;
|
|
|
|
dx1 = dx2 = dx;
|
|
dy1 = dy2 = dy;
|
|
|
|
if (hsx < 0)
|
|
dx1 += hsx;
|
|
else
|
|
dx2 += hsx;
|
|
if (hsy < 0)
|
|
dy1 += hsy;
|
|
else
|
|
dy2 += hsy;
|
|
tsx = vsx;
|
|
tsy = vsy;
|
|
if (!tsx && !tsy)
|
|
{
|
|
tsy = (hsx * im->h) / im->w;
|
|
tsx = -(hsy * im->h) / im->w;
|
|
}
|
|
if (tsx < 0)
|
|
dx1 += tsx;
|
|
else
|
|
dx2 += tsx;
|
|
if (tsy < 0)
|
|
dy1 += tsy;
|
|
else
|
|
dy2 += tsy;
|
|
|
|
if ((dx2 < 0) || (dy2 < 0))
|
|
return;
|
|
|
|
dw = dx2 - dx1;
|
|
dh = dy2 - dy1;
|
|
|
|
if ((dw <= 0) || (dh <= 0))
|
|
return;
|
|
|
|
if (dx1 < 0)
|
|
{
|
|
dw += dx1;
|
|
dx1 = 0;
|
|
}
|
|
if (dy1 < 0)
|
|
{
|
|
dh += dy1;
|
|
dy1 = 0;
|
|
}
|
|
|
|
ct = __imlib_GetContext(d, v, cm, depth);
|
|
|
|
back = __imlib_CreateImage(dw, dh, NULL);
|
|
back->data = calloc(dw * dh, sizeof(DATA32));
|
|
__imlib_GrabDrawableToRGBA(back->data, 0, 0, dw, dh, d, w, 0, v, cm,
|
|
depth, dx1, dy1, dw, dh, 0, 1);
|
|
|
|
__imlib_BlendImageToImageSkewed(im, back, antialias, 1, 0, sx, sy, sw, sh,
|
|
dx - dx1, dy - dy1, hsx, hsy, vsx, vsy,
|
|
cmod, op, 0, 0, 0, 0);
|
|
|
|
__imlib_RenderImage(d, back, w, m, v, cm, depth, 0, 0, dw, dh,
|
|
dx1, dy1, dw, dh, 0, hiq, 0, dither_mask, mat, 0,
|
|
OP_COPY);
|
|
__imlib_FreeImage(back);
|
|
}
|
|
|
|
#endif /* BUILD_X11 */
|